6 Platform API 参考
本章节介绍 platform API。
6.1 配置与信息
6.1.1 platform_config
配置一些 platform 功能。
6.1.1.2 参数
const platform_cfg_item_t item
指定要配置的项目。可以是以下值之一:
PLATFORM_CFG_LOG_HCI
:打印主机控制器接口消息。默认:禁用。仅在 ING918 上可用。HCI 日志仅用于对 BLE 行为进行快速检查。请考虑使用跟踪(参见 调试与跟踪)。
PLATFORM_CFG_POWER_SAVING
:省电模式。默认:禁用。PLATFORM_CFG_TRACE_MASK
:选定的跟踪项的位图。默认:0
。typedef enum { = 0, PLATFORM_TRACE_ID_EVENT = 1, PLATFORM_TRACE_ID_HCI_CMD = 2, PLATFORM_TRACE_ID_HCI_EVENT = 3, PLATFORM_TRACE_ID_HCI_ACL = 4, PLATFORM_TRACE_ID_LLCP //.. } platform_trace_item_t;
PLATFORM_CFG_RT_RC_EN
:启用/禁用实时 RC 时钟。默认:启用。PLATFORM_CFG_RT_OSC_EN
:启用/禁用实时晶体振荡器。默认:启用。PLATFORM_CFG_RT_CLK
:实时时钟选择。标志为platform_rt_clk_src_t
。默认:PLATFORM_RT_RC
typedef enum { , // 外部实时晶体振荡器 PLATFORM_RT_OSC// 内部实时 RC 时钟 PLATFORM_RT_RC } platform_rt_clk_src_t;
对于 ING918,修改此配置时,RT_RC 和 RT_OSC 都应启用并运行:
* 对于 RT_OSC,等待直到 RT_OSC 的状态为 OK; * 对于 RT_RC,启用后等待 100μs。
并在禁用未使用的时钟之前再等待 100μs。
PLATFORM_CFG_RT_CLK_ACC
:配置实时时钟精度(ppm)。PLATFORM_CFG_RT_CALI_PERIOD
:实时时钟自动校准周期(秒)。默认:3600 * 2(2小时)。PLATFORM_CFG_DEEP_SLEEP_TIME_REDUCTION
:睡眠时间缩减(深度睡眠模式)(微秒)。ING918默认:~550μs。PLATFORM_CFG_SLEEP_TIME_REDUCTION
:睡眠时间缩减(其他睡眠模式)(微秒)。ING918默认:~450μs。PLATFORM_CFG_LL_DBG_FLAGS
:链路层标志。ll_cfg_flag_t
中的位组合。typedef enum { = 1, // 禁用 CTE 预处理 LL_FLAG_DISABLE_CTE_PREPROCESSING = 4, // 仅针对传统 ADV 进行发起 LL_FLAG_LEGACY_ONLY_INITIATING = 8, // 仅针对传统 ADV 进行扫描 LL_FLAG_LEGACY_ONLY_SCANNING } ll_cfg_flag_t;
PLATFORM_CFG_LL_LEGACY_ADV_INTERVAL
:链路层传统广告间隔,高占空比模式(高16位)和正常占空比模式(低16位)(微秒)。高占空比模式默认:1250;正常占空比模式默认:1500。PLATFORM_CFG_RTOS_ENH_TICK
:启用 RTOS 的增强型滴答。默认:禁用。启用后,当外设频繁生成中断请求时,可以保持滴答的准确性。PLATFORM_CFG_LL_DELAY_COMPENSATION
:链路层的延迟补偿。当系统以较低频率运行时,链路层需要更多时间(以 μs 为单位)来调度RF任务。例如,如果 ING916 以 24MHz 运行,则需要约 2500μs 的补偿。
PLATFORM_CFG_24M_OSC_TUNE
:24M OSC 调谐。不适用于ING918。对于 ING916,调谐值可能在 0x16~0x2d 之间。
PLATFORM_CFG_ALWAYS_CALL_WAKEUP
:无论深度睡眠过程是否完成或中止(失败),始终触发PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP
事件。ING918默认:禁用以保持向后兼容性。ING916默认:启用。PLATFORM_CFG_FAST_DEEP_SLEEP_TIME_REDUCTION
:快速深度睡眠模式的睡眠时间减少(微秒)。不适用于ING918。此配置必须小于或等于
PLATFORM_CFG_DEEP_SLEEP_TIME_REDUCTION
。当等于PLATFORM_CFG_DEEP_SLEEP_TIME_REDUCTION
时,不使用快速深度睡眠模式。ING916 默认:~2000μs。
PLATFORM_CFG_AUTO_REDUCE_CLOCK_FREQ
:在这些情况下自动降低 CPU 时钟频率:- 默认的 IDLE 过程,
- 进入睡眠模式时。
不适用于 ING918。ING916 默认:启用。
const uint32_t flag
用于禁用或启用项目。可以是以下值之一:
PLATFORM_CFG_ENABLE
PLATFORM_CFG_DISABLE
6.1.2 platform_get_version
获取 platform 的版本号。
6.1.3 platform_read_info
读取 platform 信息。
6.1.3.2 参数
const platform_info_item_t item
信息项。
PLATFORM_INFO_RT_OSC_STATUS
: 读取实时晶体振荡器的状态。值为 0:不正常;非 0:正常。
对于 ING916:此时钟在被选为实时时钟源之后才会开始运行。
PLATFORM_INFO_RT_CLK_CALI_VALUE
: 读取当前实时时钟校准结果。PLATFOFM_INFO_IRQ_NUMBER
: 获取 platform IRQ 的底层 IRQ 编号。例如,获取 UART0 的底层 IRQ 编号:
( platform_read_info+ PLATFORM_CB_IRQ_UART0) PLATFOFM_INFO_IRQ_NUMBER
6.2 事件与中断
6.2.1 platform_set_evt_callback_table
为所有 platform 事件注册一个回调函数表。
6.2.1.4 备注
此函数应仅在 app_main
中调用。如果使用了 platform_set_evt_callback
,则不应使用此函数。
与 platform_set_evt_callback
相比,使用此函数可以节省 sizeof(platform_evt_cb_table_t)
字节的 RAM 空间。
6.2.1.5 示例
static const platform_evt_cb_table_t evt_cb_table =
{
.callbacks = {
[PLATFORM_CB_EVT_HARD_FAULT] = {
.f = (f_platform_evt_cb)cb_hard_fault,
},
[PLATFORM_CB_EVT_PROFILE_INIT] = {
.f = setup_profile,
},
// ...
}
};
int app_main()
{
// ...
(&evt_cb_table);
platform_set_evt_callback_table// ...
}
6.2.2 platform_set_irq_callback_table
为所有 platform 中断请求注册一个回调函数表。
6.2.3 platform_set_evt_callback
注册回调函数以处理 platform 事件。
6.2.3.1 函数原型
void platform_set_evt_callback(platform_evt_callback_type_t type,
,
f_platform_evt_cb fvoid *user_data);
6.2.3.2 参数
platform_evt_callback_type_t type
指定要注册回调函数的事件类型。可以是以下值之一:
PLATFORM_CB_EVT_PUTC
:输出 ASCII 字符事件当 platform 想要输出 ASCII 字符用于日志记录时,会触发此事件。传递给回调函数的参数
void *data
是从char *
类型转换而来。如果在创建新项目时在
Common Function
中勾选了Print to UART
,ingWizard
可以自动生成将 platform 日志重定向到 UART 的代码。PLATFORM_CB_EVT_PROFILE_INIT
:配置文件初始化事件当主机初始化时,会触发此事件以请求应用程序初始化GATT配置文件。
在创建新项目时,
ingWizard
可以自动为此事件生成代码。PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP
:从深度睡眠唤醒事件当从深度睡眠唤醒时,会触发此事件。在深度睡眠期间,外设接口(如UART、I2C等)都已关闭。因此,唤醒时可能需要重新初始化这些接口。
如果在创建新项目时在
Common Function
中勾选了Deep Sleep
,ingWizard
可以自动为此事件生成代码。传递给回调函数的参数
void *data
是从platform_wakeup_call_info_t *
类型转换而来。此时 RTOS 尚未恢复,某些 RTOS API 不可用;某些 platform API(如
platform_get_us_time
)也可能不可用。PLATFORM_CB_EVT_ON_IDLE_TASK_RESUMED
:操作系统从节能模式完全恢复。如果唤醒原因是
PLATFORM_WAKEUP_REASON_NORMAL
,则在PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP
之后调用此回调。 对于 NoOS 变体,回调由platform_os_idle_resumed_hook()
调用。 此事件与PLATFORM_CB_EVT_ON_DEEP_SLEEP_WAKEUP
不同:- 所有操作系统功能都已恢复(对于NoOS变体,这取决于
platform_os_idle_resumed_hook()
的正确使用) - 所有 platform API都可用
- 回调在空闲任务中调用。
参数
void *data
始终为NULL
。- 所有操作系统功能都已恢复(对于NoOS变体,这取决于
PLATFORM_CB_EVT_QUERY_DEEP_SLEEP_ALLOWED
:查询是否允许深度睡眠事件当platform准备进入深度睡眠模式时,会触发此事件以查询应用程序当前是否允许深度睡眠。回调函数可以通过返回
0
拒绝深度睡眠,或通过返回非0
值允许深度睡眠。如果在创建新项目时在
Common Function
中勾选了Deep Sleep
,ingWizard
可以自动为此事件生成代码。PLATFORM_CB_EVT_HARD_FAULT
:硬件故障发生当硬件故障发生时,会触发此事件。传递给回调函数的参数
void *data
是从hard_fault_info_t *
类型转换而来。 如果未定义此回调,当硬件故障发生时,CPU将进入死循环。PLATFORM_CB_EVT_ASSERTION
:软件断言失败当软件断言失败时,会触发此事件。传递给回调函数的参数
void *data
是从assertion_info_t *
类型转换而来。 如果未定义此回调,当断言发生时,CPU将进入死循环。PLATFORM_CB_EVT_LLE_INIT
:链路层引擎初始化。当链路层引擎初始化时,会触发此事件。
PLATFORM_CB_EVT_HEAP_OOM
:内存不足。当堆分配失败(堆内存不足)时,会触发此事件。 如果触发此事件且未定义回调,CPU将进入死循环。
PLATFORM_CB_EVT_TRACE
:跟踪输出。当发出跟踪项时,会触发此事件。应用程序可以为此事件定义回调函数以保存或记录跟踪输出。回调的
param
是从platform_trace_evt_t *
类型转换而来(参见调试与跟踪)。typedef struct { const void *data1; const void *data2; uint16_t len1; uint16_t len2; } platform_evt_trace_t;
跟踪项是
data1
和data2
的组合。注意:len1
或len2
可能为0,但不能同时为0;如果回调函数发现无法输出大小为
len1
+len2
的数据,则应丢弃data1
和data2
以避免跟踪项损坏。
PLATFORM_CB_EVT_EXCEPTION
:硬件异常。参数
void *data
是从platform_exception_id_t *
类型转换而来。PLATFORM_CB_EVT_IDLE_PROC
:自定义IDLE过程。参见“Programmer’s Guide - Power Saving”21。
PLATFORM_CB_EVT_HCI_RECV
:接管 HCI 并完全隔离内置主机。当定义时:
- HCI事件和ACL数据传递给此回调;
PLATFORM_CB_EVT_PROFILE_INIT
被忽略。
参数
void *data
是从const platform_hci_recv_t *
类型转换而来。另请参见platform_get_link_layer_interf
。
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.2.4 platform_set_irq_callback
注册中断请求的回调函数。
开发者无需在应用中定义IRQ处理程序,而是使用回调函数代替。
6.2.4.1 函数原型
void platform_set_irq_callback(platform_irq_callback_type_t type,
,
f_platform_irq_cb fvoid *user_data);
6.2.4.2 参数
platform_irq_callback_type_t type
指定要注册回调函数的 IRQ 类型。不同芯片系列的值有所不同。以 ING918 为例:
, 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
f_platform_irq_cb f
注册到 IRQ
type
的回调函数。f_platform_irq_cb
定义为:typedef uint32_t (*f_platform_irq_cb)(void *user_data);
void *user_data
该参数将原封不动地传递给回调函数的
user_data
。
6.2.4.4 备注
当回调函数注册到 IRQ 时,IRQ 会自动启用。另请参见 platform_enable_irq
。
6.3 时钟
另请参阅“Programmer’s Guide - Power Saving”22中的“The Real-time Clock”23。
6.3.2 platform_rt_rc_auto_tune
自动调整内部实时RC时钟,并获取调整值。
对于ING918,此函数将内部实时RC时钟调整至50kHz24。 对于其他设备,它将内部实时RC时钟调整至32768Hz。
6.3.4 platform_rt_rc_tune
使用调谐值调整内部实时RC时钟。
6.3.4.2 参数
uint16_t value
用于调谐时钟的值(由
platform_rt_rc_auto_tune
或platform_rt_rc_auto_tune2
返回)
6.4 RF
6.5 内存与实时操作系统(RTOS)
6.5.1 platform_call_on_stack
在独立的专用堆栈上调用函数。当需要偶尔调用一个使用大量堆栈的函数时,可以使用此接口。
6.5.1.1 函数原型
void platform_call_on_stack(
,
f_platform_function fvoid *user_data,
void *stack_start,
uint32_t stack_size);
6.5.2 platform_get_current_task
获取调用此API的当前任务。
6.5.4 platform_get_heap_status
获取当前堆状态,例如可用大小等。
6.5.6 platform_install_task_stack
为特定 platform 任务安装一个新的RTOS堆栈。
当默认堆栈大小不足以满足内部任务需求时,使用此函数来扩大堆栈。例如,用户开发的 RTOS 定时器回调可能需要更大的堆栈空间。
开发者可以查阅 RTOS 文档以了解如何检查堆栈使用情况。例如,在FreeRTOS中,uxTaskGetStackHighWaterMark
用于查询任务接近溢出分配给它的堆栈空间的程度。
6.6 时间与定时器
读取当前时间(定时器计数器)的API:
platform_get_timer_counter
platform_get_us_time
使用625微秒分辨率的定时器的API:
platform_set_abs_timer
platform_set_timer
platform_delete_timer
使用1微秒分辨率的定时器的API:
platform_create_us_timer
platform_cancel_us_timer
这两种类型的定时器都可以在节能模式下使用,即当节能模式启用时,它们会按预期工作。表6.1比较了这两种定时器。
表: (#tab:ch-api-compare-timers) 两种 platform 定时器的比较
类型 | 625微秒分辨率 | 1微秒分辨率 |
---|---|---|
回调 | 从类似任务的上下文中调用 | 从中断服务例程(ISR)中调用 |
标识符 | 回调函数指针 | 定时器句柄 |
6.6.1 platform_cancel_us_timer
取消之前由 platform_create_us_timer
创建的 platform 定时器。
6.6.1.3 返回值
如果指定的定时器成功取消,该函数返回 0。否则,返回一个非 0 值,这也意味着定时器的回调函数正在执行中。
### platform_create_us_timer
设置一个具有1微秒(μs)分辨率的单次触发platform定时器。
6.6.1.4 函数原型
(
platform_us_timer_handle_t platform_create_us_timeruint64_t abs_time,
,
f_platform_us_timer_callback callbackvoid *param);
6.6.1.5 参数
uint64_t abs_time
当
platform_get_us_timer() == abs_time
时,回调函数将被调用。f_platform_us_timer_callback callback
回调函数。其签名为:
typedef void * (* f_platform_us_timer_callback)( , platform_us_timer_handle_t timer_handleuint64_t time_us, void *param);
其中,
timer_handle
是platform_create_us_timer
的返回值,time_us
是调用回调时platform_get_us_timer
的当前值,param
是创建此定时器时的用户参数。void *param
用户参数。
6.6.2 platform_get_timer_counter
读取platform定时器的计数器,分辨率为625微秒。
6.6.3 platform_set_abs_timer
设置一个单次触发的 platform 定时器,在绝对时间触发,分辨率为 625 微秒。
6.6.3.2 参数
f_platform_timer_callback callback
定时器到期时的回调函数,该函数在类似 RTOS 任务的上下文中调用,而不是在中断服务例程(ISR)中调用。
uint32_t abs_time
当
platform_get_timer_counter() == abs_time
时,callback
被调用。 如果abs_time
刚刚超过platform_get_timer_counter()
,callback
会立即被调用, 例如,abs_time
为platform_get_timer_counter() - 1
。
6.6.3.5 示例
使用此函数模拟一个周期性定时器。
#define PERIOD 100
static uint32_t last_timer = 0;
void platform_timer_callback(void)
{
+= PERIOD;
last_timer (platform_timer_callback, last_timer);
platform_set_abs_timer
// 执行周期性任务
// ...
}
= platform_get_timer_counter() + PERIOD;
last_timer (platform_timer_callback, last_timer); platform_set_abs_timer
6.6.4 platform_set_timer
设置一个单次触发的 platform 定时器,从“现在”开始延迟,分辨率为 625 微秒。
6.6.4.2 参数
f_platform_timer_callback callback
定时器到期时的回调函数,该函数在类似 RTOS 任务的上下文中调用,而非中断服务例程(ISR)。
uint32_t delay
定时器到期前的延迟时间(单位:625 微秒)。
有效范围:0~0x7fffffff。当
delay
为 0 时,定时器被清除。
6.6.4.4 备注
此函数总是成功,除非内存耗尽。
platform_set_timer(f, 100)
等同于:
(f,
platform_set_abs_timer() + 100); platform_get_timer_counter
platform_set_timer(f, 0)
等同于:
(f); platform_delete_timer
但不等同于:
(f,
platform_set_abs_timer() + 0); platform_get_timer_counter
由于 callback
也是定时器的标识符,以下两行代码仅定义了一个在 200 个单位后到期的定时器,而非两个独立的定时器:
(f, 100);
platform_set_timer(f, 200); // 更新定时器,而非创建新的 platform_set_timer
如果 f
再次用于platform_set_abs_timer
,则定时器再次被更新:
(f, ...); platform_set_abs_timer
6.7 实用工具
6.7.3 platform_read_persistent_reg
从持久寄存器中读取值。另请参阅
platform_write_persistent_reg
。
6.7.3.3 返回值
由
platform_write_persistent_reg
写入的值。
6.7.5 platform_shutdown
将整个系统置于关机状态,并在指定时间后重新启动。可选地,在关机期间可以保留一部分内存,重启后应用程序可以继续使用这部分内存。
请注意,除非关机过程无法启动,否则此函数不会返回。可能导致失败的原因包括:
- 外部唤醒信号被发出;
- 输入参数不正确;
- 内部组件繁忙。
6.7.5.1 函数原型
void platform_shutdown(const uint32_t duration_cycles,
const void *p_retention_data,
const uint32_t data_size);
6.7.6 platform_write_persistent_reg
向持久寄存器写入一个值。该值在省电模式、关机模式或切换到另一个应用程序时仍会保留。
只有少量位被保存,如表 6.2 所示。
表: (#tab:ch-api-reg-bits) 持久寄存器位大小
芯片系列 | 寄存器大小 (位) |
---|---|
ING918 | 4 |
ING916 | 5 |
6.8 调试与追踪
6.8.1 platform_printf
存储在 platform 二进制文件中的 printf
函数。
6.9 其他
6.9.2 sysSetPublicDeviceAddr
设置设备的公共地址。
BLE设备的公共地址是一个48位的扩展唯一标识符(EUI-48),按照IEEE 802-2014标准创建25。