6 Platform API 参考

6.1 platform_32k_rc_auto_tune

自动调谐内部的 32k RC 时钟,得到调谐参数。

6.1.1 原型

uint16_t platform_32k_rc_auto_tune(void);

6.1.2 参数表

无。

6.1.3 返回值

16 比特调谐参数。

6.1.4 备注

本操作需要花费 ~250ms。建议只调用一次本函数,记录调谐参数以备使用。

6.1.5 示例

uint16_t value = platform_32k_rc_auto_tune();

6.2 platform_32k_rc_tune

使用给定参数调谐内部的 32k RC 时钟。

6.2.1 原型

void platform_32k_rc_tune(uint16_t value);

6.2.2 参数表

6.2.3 返回值

无。

6.2.4 备注

void.

6.2.5 示例

platform_32k_rc_tune(value);

6.3 platform_config

配置平台功能。

6.3.1 原型

void platform_config(const platform_cfg_item_t item,
                     const uint32_t flag);

6.3.2 参数表

  • const platform_cfg_item_t item

    指定要配置的项。可以是下列值:

    • PLATFORM_CFG_LOG_HCI: HCI 消息的 printf 打印。默认值:关闭。

    • PLATFORM_CFG_POWER_SAVING: 省电功能。默认值:关闭。

    • PLATFORM_CFG_TRACE_MASK: Trace 数据项的比特图。默认值:0

      typedef enum
      {
          PLATFORM_TRACE_ID_EVENT                 = 0,
          PLATFORM_TRACE_ID_HCI_CMD               = 1,
          PLATFORM_TRACE_ID_HCI_EVENT             = 2,
          PLATFORM_TRACE_ID_HCI_ACL               = 3,
          PLATFORM_TRACE_ID_LLCP                  = 4
      } platform_trace_item_t;
    • PLATFORM_CFG_RC32K_EN: 使能/禁用内部 32k RC 时钟。默认值:使能。

    • PLATFORM_CFG_OSC32K_EN: 使能/禁用外部 32k 晶体。默认值:使能。

    • PLATFORM_CFG_32K_CLK: 32k 时钟源选择。参数为 platform_32k_clk_src_t 类型。默认值:PLATFORM_32K_RC

      typedef enum
      {
          PLATFORM_32K_OSC,           // 外部 32k 晶体
          PLATFORM_32K_RC             // 内部 32k RC 时钟
      } platform_32k_clk_src_t;

      当修改本配置时,RC32K 和 OSC32K 必须同时处理使能、运行状态:

      • 对于 OSC32K,等待直到 OSC32K 的状态变为 OK;
      • 对于 RC32K,使能后等待 100us。

      提示:在关闭不用的时钟前再等待 100us。

    • PLATFORM_CFG_32K_CLK_ACC: 声明 32k 时钟的精度(ppm)。

    • PLATFORM_CFG_32K_CALI_PERIOD: 32k 时钟的校准间隔(秒)。默认值:3600 * 2 (2 小时)。

    • PLATFORM_CFG_DEEP_SLEEP_TIME_REDUCTION: 睡眠时间预留量(深睡眠模式)(微秒)。默认值:~550us。

    • PLATFORM_CFG_SLEEP_TIME_REDUCTION: 睡眠时间预留量(其它睡眠模式)(微秒)。默认值: ~450us.

    • PLATFORM_CFG_LL_DBG_FLAGS: 链路层标志位,是 ll_cfg_flag_t 中各比特的组合。

      typedef enum
      {
          LL_FLAG_DISABLE_CTE_PREPROCESSING = 1,  // 关闭 CTE 预处理
          LL_FLAG_LEGACY_ONLY_INITIATING = 4,     // 仅使用 legacy 广播发起连接
          LL_FLAG_LEGACY_ONLY_SCANNING = 8,       // 仅扫描 legacy 广播
      } ll_cfg_flag_t;
    • PLATFORM_CFG_LL_LEGACY_ADV_INTERVAL: 链路层 legacy 广播内部间隔(微秒),其中高 16 比特用于高频度广播 (high duty cycle),低 16 比特用于正常频度广播(normal duty cycle)。高频度广播的默认值:1250, 正常频度的默认值:1500。

  • const uint32_t flag

    对于可以使能、禁用的配置,用下面的值进行控制:

    • PLATFORM_CFG_ENABLE
    • PLATFORM_CFG_DISABLE

6.3.3 返回值

无。

6.3.4 备注

无。

6.3.5 示例

// 使能 HCI 打印
platform_config(PLATFORM_CFG_LOG_HCI, PLATFORM_CFG_ENABLE);

6.4 platform_get_heap_status

得到堆当前的状态信息,如剩余空间等。

6.4.1 原型

void platform_get_heap_status(platform_heap_status_t *status);

6.4.2 参数表

  • platform_heap_status_t *status

    堆的状态。

6.4.3 返回值

无。

6.4.4 备注

堆的状态定义如下:

typedef struct
{
    uint32_t bytes_free;                // 剩余空间
    uint32_t bytes_minimum_ever_free;   // 自启动以来剩余空间的最小值
} platform_heap_status_t;

6.4.5 示例

platform_heap_status_t status;
platform_get_heap_status(&status);

6.5 platform_get_us_time

读取内部计时器的时间。该计时器从 BLE 初始化之后开始计时。

6.5.1 原型

int64_t platform_get_us_time(void);

6.5.2 参数表

无。

6.5.3 返回值

内部计时器的微秒计数值。

6.5.4 备注

关机后该计时器会归零,而 RTC 计时器则不会。

6.5.5 示例

platform_get_us_time();

6.6 platform_get_version

得到 platform 的版本号。

6.6.1 原型

const platform_ver_t *platform_get_version(void);

6.6.2 参数表

无。

6.6.3 返回值

指向 platform_ver_t 的指针。

6.6.4 备注

Platform 版本号包含 3 个部分,major,minor 和 patch:

typedef struct platform_ver
{
    unsigned short major;
    char  minor;
    char  patch;
} platform_ver_t;

6.6.5 示例

const platform_ver_t *ver = platform_get_version();
printf("Platform version: %d.%d.%d\n", ver->major, ver->minor, ver->patch);

6.7 platform_hrng

使用硬件真随机数发生器产生任意长度的随机数。

6.7.1 原型

void  platform_hrng(uint8_t *bytes, const uint32_t len);

6.7.2 参数表

  • uint8_t *bytes

    随机数输出。

  • const uint32_t len

    要产生的字节数。

6.7.3 返回值

无。

6.7.4 备注

产生一定长度的随机数所需要的时间是不确定的。

6.7.5 示例

uint32_t strong_random;
platform_hrng(&strong_random, sizeof(strong_random));

6.8 platform_install_isr_stack

为中断服务程序安装新的栈。

6.8.1 原型

void platform_install_isr_stack(void *top);

6.8.2 参数表

  • void *top

    新栈的栈顶,必须为 4 字节对齐。

6.8.3 返回值

无。

6.8.4 备注

当 app 需要使用比默认 ISR 栈更大的栈时,可以使用这个 API 安装一个新的栈,替换掉旧的。

这个函数只允许在 app_main 里调用。新栈在 app_main 函数返回后启用。

6.8.5 示例

uint32_t new_stack[2048];
...
platform_install_isr_stack(new_stack + sizeof(new_stack) / sizeof(new_stack[0]));

6.9 platform_printf

Platform 内部的 printf 函数。

6.9.1 原型

 void  platform_printf(const char *format, ...);

6.9.2 参数表

  • const char *format

    格式字符串。

  • ...

    变长参数。

6.9.3 返回值

无。

6.9.4 备注

使用这个函数既有优点也有缺点:

优点:

  • 这个函数位于 platform 内部,可以节省 app 程序空间

缺点:

  • 输出被定向到 PLATFORM_CB_EVT_PUTC 事件,所以必须为该事件设立回调。

6.9.5 示例

platform_printf("Hello world");

6.10 platform_raise_assertion

抛出软件断言。

6.10.1 原型

void  platform_raise_assertion(const char *file_name, int line_no);

6.10.2 参数表

  • const char *file_name

    断言发生的文件名。

  • int line_no

    断言发生的代码行。

6.10.3 返回值

无。

6.10.4 备注

无。

6.10.5 示例

  if (NULL == ptr)
    platform_raise_assertion(__FILE__, __LINE__);

6.11 platform_rand

使用 platform 内的伪随机数发生器(PRNG)生成伪随机整数。

6.11.1 原型

int platform_rand(void);

6.11.2 参数表

无。

6.11.3 返回值

一个在 0 和 RAND_MAX 之间均匀分布的随机数。

6.11.4 备注

上电时用硬件随机数发生数发生器为 PRNG 生成了种子。

6.11.5 示例

printf("rand: %d\n", platform_rand());

6.12 platform_read_info

读取 platform 信息。

6.12.1 原型

uint32_t platform_read_info(const platform_info_item_t item);

6.12.2 参数表

  • const platform_info_item_t item

    信息项:

    typedef enum
    {
        PLATFORM_INFO_OSC32K_STATUS,     // 外部 32k 晶体时钟的状态
                                         // 0: 不工作;非 0: 正常工作
    } platform_info_item_t;

6.12.3 返回值

信息项的值。

6.12.4 备注

无。

6.12.5 示例

platform_read_info(PLATFORM_INFO_OSC32K_STATUS);

6.13 platform_read_persistent_reg

读取持久化寄存器的值。参考 platform_write_persistent_reg

6.13.1 原型

uint32_t platform_read_persistent_reg(void);

6.13.2 参数表

无。

6.13.3 返回值

platform_write_persistent_reg 写入的 4 个比特。

6.13.4 备注

无。

6.13.5 示例

platform_read_persistent_reg();

6.14 platform_reset

复位整个系统(SoC)。

6.14.1 原型

void platform_reset(void);

6.14.2 参数表

无。

6.14.3 返回值

无。

6.14.4 备注

在这个函数之后的代码不会被执行。

6.14.5 示例

  if (out-of-memory)
    platform_reset();

6.15 platform_set_evt_callback

为 platform 事件设置回调函数。

6.15.1 原型

void platform_set_evt_callback(platform_evt_callback_type_t type,
                               f_platform_evt_cb f,
                               void *user_data);

6.15.2 参数表

  • platform_evt_callback_type_t type

    事件的类型。可以是下列值:

    • PLATFORM_CB_EVT_PUTC: ASCII 字符输出事件

      当 platform 要输出字符串日志时会触发该事件。传递到回调函数的参数 void *data 是从 char * 转换得来。

      ingWizard 创建新项目时,如果在 Common Function 页面选择了 Print to UART, 会自动生成相关代码。

    • PLATFORM_CB_EVT_PROFILE_INIT: BLE GATT profile 初始化事件

      当 Host 初始化时会触发该事件要求 app 初始化 GATT profile。

      ingWizard 创建新项目时,会自动生成相关代码。

    • PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP: 深睡眠唤醒事件

      深睡眠中唤醒时触发该事件。在深睡眠时,外部接口(如 UART,,I2C 等)都已掉电,所以当唤醒时, 可能需要再次初始化。

      ingWizard 创建新项目时,如果在 Common Function 页面选择了 Deep Sleep, 会自动生成相关代码。

    • PLATFORM_CB_EVT_QUERY_DEEP_SLEEP_ALLOWED: 深睡眠许可查询事件

      当 platform 准备进入深睡眠时,会触发该事件询问 app 当前是否允许进入深睡眠。 事件回调函数可通过返回 0 拒绝,返回非 0 允许。

      ingWizard 创建新项目时,如果在 Common Function 页面选择了 Deep Sleep, 会自动生成相关代码。

    • PLATFORM_CB_EVT_HARD_FAULT: Hard fault 事件

      Hard fault 发生时触发该事件。传入回调函数的 void *data 参数是从 hard_fault_info_t * 转换得来。 如果未定义该回调,当事件发生时,CPU 进入死循环。

    • PLATFORM_CB_EVT_ASSERTION: Software assertion fails

      软件断言失败时触发该事件。传入回调函数的 void *data 参数是从 assertion_info_t * 转换得来。 如果未定义该回调,当事件发生时,CPU 进入死循环。

    • PLATFORM_CB_EVT_LLE_INIT: 链路层引擎初始化完成事件

      每当链路层引擎初始化完成时触发该事件。

    • PLATFORM_CB_EVT_HEAP_OOM: 堆空间用完事件

      在堆上分配内存失败时触发该事件。 如果未定义该回调,当事件发生时,CPU 进入死循环。

    • PLATFORM_CB_EVT_TRACE: Trace 输出事件

      当有 trace 数据项要输出时,触发该事件。 Apps 可以为该事件设置回调函数以保存或者输出 trace 数据。传人回调函数的 void *data 参数是从 platform_trace_evt_t * 转换得来(参见 调试与跟踪)。

      typedef struct
      {
          const void *data1;
          const void *data2;
          uint16_t len1;
          uint16_t len2;
      } platform_evt_trace_t;

      一个 trace 数据项由 data1data2 组成。说明:

      1. len1 或者 len2 可能为 0,但不会同时为 0

      2. 如果回调函数发现无法存储或者输出长度为 len1 + len2 的数据,那么应该同时丢弃 data1data2 以防 trace 数据结构混乱。

  • f_platform_evt_cb f

    注册到事件 type 的回调函数。f_platform_evt_cb 的类型为:

    typedef uint32_t (*f_platform_evt_cb)(void *data, void *user_data);
  • void *user_data

    这个参数将原封不动地作为 user_data 传递给回调函数。

6.15.3 返回值

无。

6.15.4 备注

并不要求给所有事件都设置回调函数。

如果未给 PLATFORM_CB_EVT_PUTC 事件设置回调,所有用平台 printf 日志都会丢弃。

如果未给PLATFORM_CB_EVT_PROFILE_INIT 事件设置回调,BLE profile 为空。

如果未给 PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP 事件设置回调,从深睡眠唤醒时 app 无法获得通知。

如果未给 PLATFORM_CB_EVT_QUERY_DEEP_SLEEP_ALLOWED 事件设置回调,深睡眠模式为 禁用 状态。

6.15.5 示例

uint32_t cb_putc(char *c, void *dummy)
{
    // TODO: output char c to UART
    return 0;
}

......

platform_set_evt_callback(PLATFORM_CB_EVT_PUTC, (f_platform_evt_cb)cb_putc,
                          NULL);

6.16 platform_set_irq_callback

为中断请求设置回调函数。

开发者不需要定义 IRQ 处理函数,而是通过设置回调实现。两种芯片系列的中断请求总结于表 6.1 和表 6.2

Table 6.1: ING918xx IRQ 总结
外设类型 数量 备注
RTC 1 Real Time Clock
TIMER 3 Timer
GPIO 1 General Purpose Input/Output
SPI 2 Serial Peripheral Interface
UART 2 Universal Asynchronous Receiver-Transmitter
I2C 2 Inter-Integrated Circuit
Table 6.2: ING916xx IRQ 总结
外设类型 数量 备注
RTC 1 Real Time Clock
GPIO 2 General Purpose Input/Output
TIMER 3 Timer
WDT 1 Watch dog
PDM 1 Pulse Density Modulation
APBSPI 1 Serial Peripheral Interface on APB
QSPI 1 Quad serial peripheral interface
I2S 1 Inter-IC Sound
UART 2 Universal Asynchronous Receiver-Transmitter
I2C 2 Inter-Integrated Circuit
DMA 1 Direct Memory Access
KEYSCAN 1 Key Scanner
PWM 1 Pulse Width Modulation
IR INT 1 Infrared Interrupt
IR WAKEUP 1 Infrared Wake-up Interrupt
USB 1 Universal Serial Bus

6.16.1 原型

void platform_set_irq_callback(platform_irq_callback_type_t type,
                               f_platform_irq_cb f,
                               void *user_data);

6.16.2 参数表

  • platform_irq_callback_type_t type

    中断类型。

    • 对于 ING918xx,中断类型如下:

      PLATFORM_CB_IRQ_RTC,
      PLATFORM_CB_IRQ_TIMER0,
      PLATFORM_CB_IRQ_TIMER1,
      PLATFORM_CB_IRQ_TIMER2,
      PLATFORM_CB_IRQ_GPIO,
      PLATFORM_CB_IRQ_SPI0,
      PLATFORM_CB_IRQ_SPI1,
      PLATFORM_CB_IRQ_UART0,
      PLATFORM_CB_IRQ_UART1,
      PLATFORM_CB_IRQ_I2C0,
      PLATFORM_CB_IRQ_I2C1
    • 对于 ING916xx,中断类型如下:

      PLATFORM_CB_IRQ_RTC,
      PLATFORM_CB_IRQ_GPIO0,
      PLATFORM_CB_IRQ_GPIO1,
      PLATFORM_CB_IRQ_TIMER0,
      PLATFORM_CB_IRQ_TIMER1,
      PLATFORM_CB_IRQ_TIMER2,
      PLATFORM_CB_IRQ_WDT,
      PLATFORM_CB_IRQ_PDM,
      PLATFORM_CB_IRQ_APBSPI,
      PLATFORM_CB_IRQ_QSPI,
      PLATFORM_CB_IRQ_SADC,
      PLATFORM_CB_IRQ_I2S,
      PLATFORM_CB_IRQ_UART0,
      PLATFORM_CB_IRQ_UART1,
      PLATFORM_CB_IRQ_I2C0,
      PLATFORM_CB_IRQ_I2C1,
      PLATFORM_CB_IRQ_DMA,
      PLATFORM_CB_IRQ_KEYSCAN,
      PLATFORM_CB_IRQ_PWM,
      PLATFORM_CB_IRQ_IR_INT,
      PLATFORM_CB_IRQ_IR_WAKEUP,
      PLATFORM_CB_IRQ_IR_USB,
  • f_platform_irq_cb f

    注册到中断 type 的回调函数。 f_platform_irq_cb 的类型为:

    typedef uint32_t (*f_platform_irq_cb)(void *user_data);
  • void *user_data

    这个参数将原封不动地作为 user_data 传递给回调函数。

6.16.3 返回值

无。

6.16.4 备注

当为中断配置了回调函数后,对应的 IRQ 自动使能。

6.16.5 示例

uint32_t cb_irq_uart0(void *dummy)
{
    // TODO: add UART0 IRQ handling code
    return 0;
}

......

platform_set_irq_callback(PLATFORM_CB_IRQ_UART0, cb_irq_uart0,
                          NULL);

6.17 platform_shutdown

将整个系统(SoC)置于关机状态,并在一段指定时间后重新启动。可选地, 可以指定保持一段内存,重启之后,app 可继续使用其中的数据。

需要注意这个函数不会返回,除非无法进入关机状态。可能导致无法进入关机状态的原因有:

  1. 外部唤醒信号有效;
  2. 输入参数有误;
  3. 内部设备正忙。

6.17.1 原型

void platform_shutdown(const uint32_t duration_cycles,
                       const void *p_retention_data,
                       const uint32_t data_size);

6.17.2 参数表

  • const uint32_t duration_cycles

    关机状态的持续时间(以 32k 时钟周期数表示),超时后重启。 最小时间为 825 个周期(大约 25.18ms)。如果该参数为 0,则系统将一直保持关机状态,直到出现外部唤醒信号。

  • const void *p_retention_data

    指向需要保持的内存数据的地址。只有 SYSTEM 内存区域允许保持(ING918xx)。 当 data_size0 时,该参考可以为 NULL

  • data_size

    需要保持的内存数据的长度。如果不需要保存数据,将此参数设为 0

6.17.3 返回值

无。

6.17.4 备注

无。

6.17.5 示例

// 关闭系统,1s 之后重启
platform_shutdown(32768, NULL, 0);

6.18 platform_switch_app

切换到辅 app。

6.18.1 原型

void platform_switch_app(const uint32_t app_addr);

6.18.2 参数表

  • const uint32_t app_addr

    辅 app 的入口地址。

6.18.3 返回值

无。

6.18.4 备注

本函数之后的代码不会被执行。

6.18.5 示例

platform_switch_app(0x80000);

6.19 platform_write_persistent_reg

将值写入持久化寄存器。这个值在省电、关机、辅app切换等过程或者状态下都保持不变。

6.19.1 原型

void platform_write_persistent_reg(const uint8_t value);

6.19.2 参数表

  • const uint8_t value

    值。

6.19.3 返回值

无。

6.19.4 备注

只会保存 4 个比特。

6.19.5 示例

platform_write_persistent_reg(1);

6.20 sysSetPublicDeviceAddr

设置设备的公共地址(public address).

BLE 设备的公共地址是 48 比特的唯一标识(EUI-48),遵照 IEEE 802-2014 standard20 创建。

INGCHIPS 918xx/916xx 具备公共地址。 本函数 用于调试和测试,绝不可 用于最终产品。

6.20.1 原型

void sysSetPublicDeviceAddr(const unsigned char *addr);

6.20.2 参数表

  • const unsigned char *addr

    新的公共地址。

6.20.3 返回值

无。

6.20.4 备注

为了避免产生问题,本函数应该先于任何 GAP 函数调用。建议在 app_main 或者 PLATFORM_CB_EVT_PROFILE_INIT 事件的回调里使用。

6.20.5 示例

const unsigned char pub_addr[] = {1,2,3,4,5,6};
sysSetPublicDeviceAddr(pub_addr);