1/21FR801xH如何构建系统BluetoothLowEnergySOCwww.
freqchip.
comFR801xH如何构建系统2/21Contents1概述32项目创建.
32.
1项目目录树结构.
32.
2项目配置.
42.
2.
1Device页面.
52.
2.
2Output页面.
52.
2.
3User页面.
62.
3项目头文件路径和编译选项.
62.
4链接设置.
82.
5调试设置.
93用户入口函数.
94程序运行流程.
114.
1概述.
114.
2回调函数.
124.
3Weak函数入口.
134.
4软件定时器.
144.
5任务.
154.
6硬件中断服务程序175错误处理.
185.
1概述.
185.
2错误码.
195.
3可恢复错误处理.
195.
4不可恢复错误.
196版本历史.
21FR801xH如何构建系统3/211概述本文档旨在指导用户了解801xH软件SDK基本开发框架.
一个801xH的项目可以看做是多个不同组件的集合.
801xHSDK包含以下组件:BLE5.
0协议栈和常见ProfileBLESIGMesh协议栈多个中间件组件非抢占式操作系统保持链接睡眠和关机睡眠调用接口多种外设驱动调试函数和错误处理系统常用辅助函数801xHSDK的工程在选择某个组件时,需要包含该组件的头文件到应用程序,调用组件的接口函数.
各组件在SDK软件包中的路径结构如下:BLE5.
0协议栈组件,components\ble\include\gap和components\ble\include\gattBLESIGMesh协议栈组件,components\ble\include\mesh常见Profile组件,components\ble\include\profile中间件组件,components\modules非抢占式操作系统,components\modules\os外设驱动,components\driver系统常用辅助函数和睡眠函数,components\modules\sys以上组件中,BLE5.
0协议栈组件,BLESIGMesh协议栈组件和非抢占式操作系统的源代码存在于lib库和romcode中,使用这些组件时只需要引用组件的头文件即可,不需要引用源代码.
2项目创建2.
1项目目录树结构一个示例项目的目录树结构可能如下:FR801xH如何构建系统4/21该示例项目myProject包含以下组成部分:1.
可选的component目录中包含了项目所需的组件,其中必须选取如下组件:library目录,该目录包含ble5.
0协议栈的romcode函数地址表和协议栈底层lib库.
中间件modules目录中platform组件和patch组件,2.
Example/none_evm/ble_simple_peripheral/code目录,包含项目的源代码.
3.
Example/none_evm/ble_simple_peripheral/keil目录,包含keil工程的链接脚本和工程启动文件.
接下来,需要创建Keil工程项目,项目创建后依次选中各组件的源代码加入到工程中,一切顺利的话,keil项目目录树应如下显示Keil工程项目的示例目录结构Keil项目和所需的源文件和lib库都已选择完毕了,接下来几小节会介绍如何对项目进行必要的配置工作.
2.
2项目配置依次点击keil工作界面最上面一栏菜单"Project"->"OptionsforTarget"开始进行项目配置,-myProject/-components/-ble/-profiles/-ble_simple_profile/-src1.
c-library/-fr8010h_stack.
lib-syscall.
txt-driver/-sr2c.
c-modules/-platform/-source/-core_cm3_isr.
c-app_boot_vectors.
s-patch/-patch.
c-button/-src5.
c-examples/-none_evm/-ble_simple_peripheral/-code/-proj_main.
c-ble_simple_peripheral.
c-user_task.
c-keil/-ble_5_0.
sct-ble_simple_peripheral.
uvprojxFR801xH如何构建系统5/212.
2.
1Device页面在device这一页面,选择项目针对的CPU.
Fr801xH采用Cotex-M3的CPU内核,这里需要选择ARMCM3的CPU核心,如下图所示Keil工程项目设备选择注解如果Device页面下拉框内找不到ARMCortexM3的设备,则需要安装keil工具针对Cotex-M3核支持的软件包:https://www.
keil.
com/dd2/arm/armcm3/2.
2.
2Output页面在Output页面,设置项目输出文件的名字和输出文件的类型,建议按如下设置Keil工程项目输出选择FR801xH如何构建系统6/212.
2.
3User页面在User页面,设置链接完成后的动作,这里需要执行2个window脚本命令,将链接完的文件生成可执行的bin文件和产生项目的反汇编代码.
Keil工程项目User页面配置#1运行命令语句产生反汇编文件,如下:fromelf.
exe--text-c-oOutput/ble_simple_peripheral.
txtObjects/ble_simple_peripheral.
axf#2运行命令语句产生可执行bin文件,如下:fromelf.
exe--bin-oOutput/ble_simple_peripheral.
binObjects/ble_simple_peripheral.
axf输出的反汇编和可执行文件的名字和路径通过更改语句中的路径实现.
例如fromelf.
exe--bin-o.
.
/bin/ble5.
0.
binObjects/ble_simple_peripheral.
axf使用该命令后,会在\examples\none_evm\ble_simple_peripheral\BIN\目录产生可执行文件ble5.
0.
bin2.
3项目头文件路径和编译选项应用工程所需用到的组件均通过引用组件的头文件来调用.
这里介绍如何设置组件头文件的相对路径,依次点击keil工作界面最上面一栏菜单"Project"->"OptionsforTarget"->"C/C++"进入C编译界面.
一般建议按下图设置编译选项FR801xH如何构建系统7/21Keil工程项目编译配置编译配置分为三个部分:预定义宏编译选项头文件路径预定义宏在PreprocessorSymbols栏,Define后面可以填写多个宏定义,这些宏定义的影响范围是整个项目所有文件.
例如MARCO1,MARCO2表示工程定义了宏变量MARCO1,MARCO2这两个宏变量.
编译选项在Language/CodeGeneration栏,建议按上图选择进行设置.
常用的选项解释如下.
Optimization,选择编译优化等级,一般来讲,优化等级越高,生成的代码空间越小.
OptimizeforTime,勾选表示编译以执行速度优先,编译的代码量会稍大.
OneELFSectionperFunction,勾选该选项表示以单个函数做为优化单元,对冗余函数进行优化,能极大的节省生成代码的空间,未被调用的函数不会被放置到最后生成的bin文件和反汇编文件中.
C99Mode,勾选该选项表示支持最新的C语言标准C99.
头文件路径在IncludePaths栏点击右边的()按钮进入项目头文件路径设置.
应如下图所示FR801xH如何构建系统8/21Keil工程项目头文件引用路径设置举例上图的示例中,示例工程一共引用了以下组件的头文件路径,分别为1.
BLE5.
0协议栈组件,components\ble\include\gapcomponents\ble\include\gattcomponents\ble\include2.
Profile组件,components\ble\profiles\ble_simple_profile3.
非抢占式操作系统,components\modules\os\include4.
外设驱动,components\driver\include5.
系统常用辅助函数和睡眠函数,components\modules\sys\include6.
中间件组件,必须包含的platform组件,components\modules\platform\includecomponents\modules\common\includecomponents\modules\lowpow\includeButton组件,components\modules\button7.
项目自身代码组件,.
.
\code上述的组件头文件路径均为相对路径.
相对路径的编写规则如下,以当前工程启动文件ble_simple_peripheral.
uvprojx(举例)为起点,符号.
.
\表示上一级目录,符号.
\表示下一级目录,均可连续使用多次例如有如下目录结构相对路径.
components\ble\profiles\ble_simple_profile表示ble_simple_profile组件的头文件引用路径.
2.
4链接设置应用工程编译成功后会进行链接操作对各个函数和变量赋予执行地址和分配大小.
这里介绍如何设置链接脚本文件,依次点击keil工作界面最上面一栏菜单"Project"->"OptionsforTarget"->"Linker"进入C编译界面.
一般建议按下图设置编译选项-Fr801xHSDK/-components/-ble/-profiles/-ble_simple_profile/-src1.
c-examples/-none_evm/-ble_simple_peripheral/-keil/-ble_simple_peripheral.
uvprojxFR801xH如何构建系统9/21Keil工程项目链接设置ScatterFile栏点击后面…按钮,选择默认的ble_5_0.
sct链接脚本.
每一个示例工程均有提供链接脚本,并且基本相同,做应用工程时可以从examples\none_evm下任一示例工程keil目录下拷贝一份链接脚本到应用工程文件夹中,然后选中该链接脚本即可.
Misccontrols栏,这里默认填如下字符串:--feedback=feedback.
txtcomponents/ble/library/syscall.
txt--entry=app_main--keep=_jump_table--datacompressor=off辅助控制字符串解释如下:components/ble/library/syscall.
txt,链接时会使用romcode里的函数地址进行链接.
注解关于链接脚本.
sct文件的编写,可以参考文档《Fr801xH如何编写链接脚本》2.
5调试设置Fr801xHSDK的keil工程支持J-link在线调试功能,该功能的设置介绍,参考《Fr801xH快速入门》章节:烧录到设备,小节:J-Link工具在线烧录.
恭喜,您已完成Fr801xH基于Keil开发工具的项目创建学习!
接下来,将介绍如何开始编写应用程序.
3用户入口函数Fr801xH软件开发框架下,应用程序开始于3个入口函数,入口函数本质是协议栈lib库内部定义的weak属性的函数,在Fr801xH程序启动时内部会依次进行调用.
应用层重新定义这些weak属性的函数,在编译时,编译器会将应用层定义的这3个同名,同类型的函数进行编译,而不会编译协议栈lib库内部定义的这3个weak属性的函数,那么Fr801xH程序启动时,内部代码就会依次运行应用层定义的这3个函数,此时,应用层的代码得到了执行.
使用Fr801xHSDK进行项目开发时,必须要定义了如下3个入口函数如下,入口函数一般需要定义在项目的proj_main.
c里面.
在FR801xH如何构建系统10/21exampl\no_evm文件夹下的所有示例工程内,均可在proj_main.
c内看到入口函数的定义.
下面分别介绍这3个入口函数.
voiduser_custom_parameters(void)该函数用于设置一些系统的重要参数,这些参数均保存于全局变量__jump_talbe内.
常见的设置项如下该函数在bootloader执行完毕,初始化程序开始运行之前被调用.
voiduser_entry_before_ble_init(void)该入口函数一般用于配置外围设备,可以初始化外设驱动,但不可调用ble5.
0协议栈和操作系统组件函数,常见的设置如下该函数在lib库初始化ble5.
0协议栈之前被调用.
voiduser_entry_after_ble_init(void)该函数是可以调用所有组件函数,包括ble5.
0协议栈和操作系统组件函数,常见的函数调用如下voiduser_custom_parameters(void)voiduser_entry_before_ble_init(void)voiduser_entry_after_ble_init(void)#include"jump_table.
h"voiduser_custom_parameters(void){memcpy(__jump_table.
addr.
addr,"\x0F\x09\x07\x09\x17\x20",6);//设置设备的本地静态mac地址__jump_table.
image_size=0x24000;//设置项目bin文件的最大size.
__jump_table.
firmware_version=0x00010000;//设置项目的固件版本号.
__jump_table.
system_clk=SYSTEM_SYS_CLK_12M;//设置CPU运行的频率__jump_table.
lp_clk_calib_cnt=50;//设置内部rtc时钟校准耗时时间.
}voiduser_entry_before_ble_init(void){pmu_set_sys_power_mode(PMU_SYS_POW_BUCK);//设置芯片供电选择pmu_enable_irq(PMU_ISR_BIT_LVD);//使能pmu的LVD中断NVIC_EnableIRQ(PMU_IRQn);//使能PMU中断system_set_port_mux(GPIO_PORT_A,GPIO_BIT_2,PORTA2_FUNC_UART1_RXD);//配置PA2做为UART1的RX脚system_set_port_mux(GPIO_PORT_A,GPIO_BIT_3,PORTA3_FUNC_UART1_TXD);//配置PA3做为UART1的TX脚uart_init(UART1,BAUD_RATE_115200);//初始化UART1做为log口输出ool_write(PMU_REG_ADKEY_ALDO_CTRL,ool_read(PMU_REG_ADKEY_ALDO_CTRL)&(~(1type){caseGAP_EVT_ALL_SVC_ADDED://在所有profile创建完毕后,协议栈会上传该消息.
sp_start_adv();//调用simpleprofile组件函数开始广播break;}}voiduser_entry_after_ble_init(void){uint8_tlocal_name[]="SimplePeripheral";gap_set_dev_name(local_name,sizeof(local_name));//设置本地设备的名字.
gap_set_cb_func(app_gap_evt_cb);//设置gap事件的接收处理回调函数app_gap_evt_cb.
gap_bond_manager_init(0x32000,0x33000,8,true);//初始化ble协议栈的绑定管理功能sp_gatt_add_service();//调用simpleprofile组件service创建函数,}FR801xH如何构建系统12/21Weak函数入口软件定时器任务硬件中断服务程序4.
2回调函数回调函数指,应用程序将自定义的某个函数指针做为参数传递给Fr801xHSDK的回调设置函数,在特定的事件或条件发生时,由Fr801xHSDK底层调用该指针来执行应用程序自定一的某个函数,这个应用层自定义的函数就是回调函数.
回调函数的执行时刻示意图如下回调函数设置与执行示意图图中蓝色方框是应用层程序.
Fr801XHSDK中BLE5.
0协议栈组件存在2个回调设置函数.
下面是GAP事件的应用代码示例Gap_set_cb_func将应用层定义的特定函数app_gap_evt_cb的函数指针做为参数传递给Gap事件回调设置函数,底层在接收到Gap特定事件时就会执行该特定函数app_gap_evt_cb,达到通知应用层消息的目的.
设置完Gap特定事件回调函数后,示例代码继续执行创建profile的代码.
然后等待协议栈底层执行profile创建过程,所有profile创建完毕后,底层协议栈会执行指定的应用层回调函数app_gap_evt_cb.
回调函数的定义示例代码如下#include"gap_api.
h"voiduser_entry_after_ble_init(void){gap_set_cb_func(app_gap_evt_cb);gatt_add_service(&simple_profile_svc);…}FR801xH如何构建系统13/21协议栈底层代码在所有profile创建完毕后会执行该回调函数,然后应用层在回调函数内在profile创建完毕事件处理分支之后继续执行其他的代码.
这里示例代码是开启了BLE的广播.
Fr801XHSDK中BLE5.
0协议组件中包含Gatt回调设置函数,原理与Gap回调设置函数相同,使用方式可以参见《Fr8010xHBLE协议栈组件使用说明》4.
3Weak函数入口Weak函数指,组件已经定义了同类型,同名的函数,但是该函数使用__attribute__((weak))修饰符,并且在组件内部已经存在调用关系,如果应用层重新定义相同类型,相同名字的函数,则在编译器编译的时候,会选择编译应用层定义的同名函数,而不会编译协议栈定义的weak函数,那么在组件内部程序调用到原有的weak函数的地方时,程序会执行应用层定义的同类型,同名字的函数.
Weak函数的调用示意图如下Weak函数设置与执行示意图应用层定义了与组件内部相同名字,相同类型的函数体Func1,在底层调用到Func1的函数时,就会直接执行应用层定的函数体Func1,而不执行组件内部定义的函数体Func1(用虚线标识).
在BLE协议栈组件中,低功耗睡眠时会使用到2个Weak函数,分别是__attribute__((section("ram_code")))__attribute__((weak))voiduser_entry_before_sleep_imp(void)__attribute__((section("ram_code")))__attribute__((weak))voiduser_entry_after_sleep_imp(void)第一个函数在协议栈进入睡眠之前会调用,第二个函数在协议栈睡眠唤醒之后会调用.
调用的代码入下#include"gap_api.
h"voidapp_gap_evt_cb(gap_event_t*p_event){switch(p_event->type){caseGAP_EVT_ALL_SVC_ADDED:sp_start_adv();break;}}FR801xH如何构建系统14/21如果应用层需要开启睡眠的功能,在应用层需要重新定义这两个函数,让BLE协议栈组件程序在睡眠前后能够执行应用层的代码.
Exampe\no_evm下的各示例程序的proj_main.
c内均有这两个weak函数重定义的使用示例.
一般在proj_main重定义的函数代码如下在voiduser_entry_after_sleep_imp(void)函数内重新初始化外设,因为睡眠时会关闭CPU和外设的电源,外设的寄存器值都会消失,所以在睡眠唤醒的函数内,需要重新初始化必要的外设,比如上面重新初始化了打印log的串口UART1到PA2&PA3.
4.
4软件定时器软件定时器指调用非抢占式操作系统组件的定时器函数来定义的定时器,从定时器启动开始时刻开始,到定时的时间到,系统会执行软件定时器指定的回调函数.
软件定时器在程序运行时的调用关系示意图如下__attribute__((section("ram_code")))voiduser_entry_before_sleep_imp(void){}__attribute__((section("ram_code")))voiduser_entry_after_sleep_imp(void){system_set_port_mux(GPIO_PORT_A,GPIO_BIT_2,PORTA2_FUNC_UART1_RXD);system_set_port_mux(GPIO_PORT_A,GPIO_BIT_3,PORTA3_FUNC_UART1_TXD);uart_init(UART1,BAUD_RATE_115200);NVIC_EnableIRQ(UART1_IRQn);NVIC_EnableIRQ(PMU_IRQn);}caseRWIP_DEEP_SLEEP:{ool_write(PMU_REG_SYSTEM_STATUS,PMU_SYS_WK_MAGIC);user_entry_before_sleep_imp();low_power_save();//进入睡眠low_power_restore();//睡眠唤醒恢复user_entry_after_sleep_imp();rf_init(&rwip_rf);ool_write(PMU_REG_SYSTEM_STATUS,PMU_SYS_PO_MAGIC);}break;FR801xH如何构建系统15/21软件定时器函数设置与执行示意图下面给出一个使用周期性1秒钟执行一次的软件定时器的代码示例,如下,在定时器启动的时刻起,每隔1秒钟,系统会执行软件定时器timA定义的执行函数voidtimA_fn(void*arg).
4.
5任务任务指的是应用层调用非抢占式操作系统组件的任务函数创建的一个能接收消息并能处理消息的回调函数,在指向该任务的消息被抛送之后很短的时间内,该任务回调函数会被系统执行,这样消息得到处理.
消息属于操作系统组件的内容,可以在第3个入口函数之后的任意应用层执行代码内抛送,包括任务自身也能给自己抛送消息.
任务在系统中执行的流程示意图如下:#include"os_timer.
h"os_timer_ttimA;voidtimA_fn(void*arg){co_printf("1slog\r\n");}voiduser_entry_after_ble_init(void){os_timer_init()&timA,timA_fn,NULL);os_timer_start(&timA,1000,1);…}FR801xH如何构建系统16/21任务函数设置与执行示意图上图的示意图中,应用程序在执行1s钟一次的软件定时器函数时,向早就创建好的任务task1,抛送了一个消息msg1.
底层系统的调度主循环分析抛送出来的msg1,发现该消息是指向任务ID为task_id1的,则会执行task_id1对应的任务函数task_func1().
下面给出一个使用软件定时器抛送消息给某个任务的代码示例,如下,在第3个入口函数处定义了一个1s钟执行一次的软件定时器timA,然后定一个了任务taskA.
在软件定时器执行函数内向taskA抛送一个消uint16_ttaskA_id;os_task_ttaskA;os_timer_ttimA;voidtaskA_fn(void*arg){Co_printf("1stimer\r\n");}voidtimA_fn(void*arg){os_event_tevt;os_msg_post(taskA_id,&evt);}voiduser_entry_after_ble_init(void){os_timer_init()&timA,timA_fn,NULL);os_timer_start(&timA,1000,1);taskA_id=os_task_craete(taskA_fn);…}FR801xH如何构建系统17/21息evt,那么taskA的执行函数taskA_fn会很快被到执行.
上面例子中,taskA_fn因为1s钟被抛送一次消息,所以会1s钟被系统执行一次.
4.
6硬件中断服务程序硬件中断服务程序指801xH芯片的硬件在需要通知软件执行时,会调用的函数.
在硬件需要执行中断服务程序时,CPU会中断正在运行的程序,保存当前程序执行的现场执行环境,然后跳转到硬件中断服务程序执行,执行完毕后,再恢复之前被保存的程序执行环境,重新跳转回原来程序运行.
Fr801xH在BLE协议栈组件和外设驱动组件时,会涉及到硬件中断服务程序.
其中BLE协议栈组件的硬件中断服务程序均在lib库内被执行,不需要应用层参与.
外设驱动组件的硬件中断程序,需要用户定义.
一般来讲,Fr801XHSDK内外设驱动组件的中断服务程序均有定义成一个weak函数.
应用层需要重新定义一次同类型,同名字的函数,保证硬件调用中断服务程序时,能执行应用层定义的函数.
中断执行服务程序的流程示意图如下中断服务函数设置与执行示意图示意图中,应用层重定义了中断服务程序(interruptserviceroutine),voidISR1(void).
系统执行到Function_A时,硬件需要调用中断服务程序ISR1,则直接中断执行Function_A,然后调用了应用层定义的中断服务程序ISR1()之后,在重新执行FunctionA的剩余代码.
外设驱动组件中,分为数字模块的中断服务程序,和pmu模块的中断服务程序.
前者有独立的中断向量表号码,后者公用一个中断向量表号码.
中断向量表是系统内部定义的一个32长度word类型的数组,该数组定义在app_boot_vectors.
s文件中,除数组0外,数组的每个序号的值都是中断服务程序的执行函数的地址值,用函数指针的值表示.
除数组0外,每个序号代表一个固定的中断类型.
硬件在需要通知软件执行中断服务程序时,会查找中断类型对应的数组值,即中断服务函数的指针值,然后执行该函数.
下面给出一个,使用数字模块UART(通用异步收发传输器)的中断服务程序设置与执行的代码示例.
FR801xH如何构建系统18/21向量中断表中的设置如下系统在接收到来自于PA2脚发送来的uart的数据时,会进入uart0对应的中断服务程序voiduart0_isr_ram(void).
另外,中断服务程序在软件设置了禁止中断的代码后,即使硬件通知软件执行,也不会立即执行中断服务程序,而要等到使能中断的代码运行后,才会执行.
全局的中断函数禁止使能函数如下:voidGLOBAL_INT_START(void)voidGLOBAL_INT_STOP(void)这两个函数定义在外设组件的头文件"driver_plf.
h"中.
注解关于外设驱动组件涉及到的详细中断服务函数,可以参考文档《Fr801xH外设驱动组件介绍》5错误处理5.
1概述在应用程序开发中,及时发现并处理在运行时期的错误,对于保证应用程序的健壮性非常重要.
常见的运行时的错误有如下几种:可恢复的错误:通过函数的返回值(错误码)标识的错误不可恢复的错误:断言失败(使用assert宏)造成的错误importuart0_isr_ram…DCDrwble_isr_patch;0DCDtimer0_isr_ram;1DCDtimer1_isr_ram;2DCDuart0_isr_ram;3DCDuart1_isr_ram;4__attribute__((section("ram_code")))voiduart0_isr_ram(void){…}voiduser_entry_after_ble_init(void){system_set_port_mux(GPIO_PORT_D,GPIO_BIT_6,PORTD6_FUNC_UART0_RXD);system_set_port_mux(GPIO_PORT_D,GPIO_BIT_7,PORTD7_FUNC_UART0_TXD);uart_init(UART0,BAUD_RATE_115200);NVIC_EnableIRQ(UART0_IRQn);…}FR801xH如何构建系统19/21CPU异常,访问非法地址、非法指令等系统级检查:看门狗超时、堆栈溢出等本章将介绍Fr801xH中针对可恢复错误的处理机制,并提供不可恢复错误的产生原因,方便查找问题.
5.
2错误码Fr801xHSDK中调用BLE协议栈组件的GAP和GATT函数时,会返回16bit整形的错误码,这些错误码如果开启BLE协议栈组件的lib库log的话,能直观的看到执行某项具体操作后执行的错误码结果,log采用"(hlcode):0x2A"形式将错误码打印出来.
错误码0表示成功.
其他的错误码在components\ble\inclue\ble_hl_error.
h文件中已经定义好.
而其他组件通常返回值就是错误码.
完整的错误代码列表,请见《Fr8010xH错误码参考》中查看.
5.
3可恢复错误处理可恢复错误指程序返回错误码,但是不会中断程序执行,程序可以做一些恢复措施,继续运行.
1.
尝试恢复示例:5.
4不可恢复错误断言失败系统出现一般断言失败错误时,会打印出错的代码所在的文件,和在文件中的行数,方便查找,打印完毕后,系统会一直执行死循环做为提醒,因为断言失败是不允许发生的,所以系统不会恢复.
示例:找到modules\os_timer.
c文件中的第142行代码为TIMER_ASSERT(0);该错误表示在未设置软件定时执行函数的情况下,启动了定时器,并uint16_ttask_id;task_id=os_task_create(func1);if(task_id==TASK_ID_FAIL){os_task_delete(task_id_delete);//删除不需要的task,释放task_idtask_id=os_task_create(func1);}FR801xH如何构建系统20/21且运行时间到,系统找不到可执行的定时器函数,导致错误.
CPU异常CPU异常指的是硬件错误,系统会进入硬件错误的中断服务程序,Fr801XH定义的硬件错误中断服务程序在中间件modules目录中platform组件的文件"core_cm3_isr.
c"中.
CPU异常是严重的硬件错误,系统不会恢复,需用重启.
示例:在该中断服务程序中,会打印进中断之前的PC(programcounter)程序计数指针和程序返回地址的值.
通过查找反汇编文件,可以找到出错之前程序运行的语句.
以上面示例为例进行错误查找,步骤1,找到PC指针指向地址是0x200060A4步骤2,在工程目录下找到ble_5_0.
txt,该文件是程序的反汇编文件,找到0x200060A4对应的汇编语句图2PC指针对应的汇编语句步骤3,找到汇编对应的c语言代码是0x80000000地址取值出错了.
看门狗超时应用层在使用了外设组件中的开门狗函数之后,如果程序因为某种原因,死循环,或者等硬件外设总线过长,导致开门狗超时时,会进入看门狗超时硬件中断服务程序.
硬件看门狗超时时是不可恢复错误,需要重启运行.
示例:在看门狗中断服务程序中,会打印进中断之前的PC(programcounter)程序计数指针和程序返回地址的值.
通过查找反汇编文件,可以找到出错之前程序运行的语句.
以上面示例为例进行错误查找,步骤1,找到PC指针指向地址是0x2000609EFR801xH如何构建系统21/21步骤2,在工程目录下找到ble_5_0.
txt,该文件是程序的反汇编文件,找到0x2000609E对应的汇编语句图4PC指针对应的汇编语句步骤3,找到汇编对应的c语言代码是汇编语言在0x20000609e反复跳转.
就是对应C语言这里的while(1)堆内存分配失败如果出现分配某个内存过大时,系统突然重启,表示内存分配失败,底层软件不允许内存分配情况出现,重启了系统,在重启之前,不会打印任何信息,这区别于以上3中不可恢复的错误.
一旦出现系统突然重启的情况时,需要在程序运行时调用剩余堆栈大小查询函数uint16_tos_get_free_heap_size(void),确认可分配内存的最大值.
该函数定于在非抢占式操作系统组件的头文件"os_mem.
h"中.
恭喜,您已完成Fr801xH项目软件程序调用组件时的流程控制!
接下来,将介绍分开介绍各个组件如何调用.
6版本历史VersionDateAuthorDescription0.
12020-03-11DongyoucaiDraft
Megalayer 商家主营业务是以独立服务器和站群服务器的,后来也陆续的有新增香港、菲律宾数据中心的VPS主机产品。由于其线路的丰富,还是深受一些用户喜欢的,有CN2优化直连线路,有全向国际线路,以及针对欧美的国际线路。这次有看到商家也有新增美国机房的VPS主机,也有包括15M带宽CN2优化带宽以及30M带宽的全向线路。Megalayer 商家提供的美国机房VPS产品,提供的配置方案也是比较多,...
我们很多老用户对于BuyVM商家还是相当熟悉的,也有翻看BuyVM相关的文章可以追溯到2014年的时候有介绍过,不过那时候介绍这个商家并不是很多,主要是因为这个商家很是刁钻。比如我们注册账户的信息是否完整,以及我们使用是否规范,甚至有其他各种问题导致我们是不能购买他们家机器的。以前你嚣张是很多人没有办法购买到其他商家的机器,那时候其他商家的机器不多。而如今,我们可选的商家比较多,你再也嚣张不起来。...
SugarHosts 糖果主机商我们算是比较熟悉的,早年学会建站的时候开始就用的糖果虚拟主机,目前他们家还算是为数不多提供虚拟主机的商家,有提供香港、美国、德国等虚拟主机机房。香港机房CN2速度比较快,美国机房有提供优化线路和普通线路适合外贸业务。德国欧洲机房适合欧洲业务的虚拟主机。糖果主机商一般是不会发布黑五活动的,他们在圣圣诞节促销活动是有的,我们看到糖果主机商发布的圣诞节促销虚拟主机低至6折...
shopex系统为你推荐
企业cms目前最好用的企业cms是哪个?2019支付宝五福支付宝5褔过了开奖时间怎么办linux防火墙设置怎样用iptables配置好Linux防火墙?搜狗360360浏览器为什么不能让我自动登录了ym.163.com免费企业邮箱重庆杨家坪猪肉摊主杀人重庆九龙坡区治安好么360arp防火墙在哪arp防火墙在哪开额- -360里是哪个?宜人贷官网我在宜人财富贷款2万元,下款的时候时候系统说银行卡号错误,然 我在宜人财富贷款2万我在宜人财富贷款宜人贷官网宜人贷是不是骗人的瑞东集团请问富源集团到底是一个怎么样的集团?
softlayer namecheap 搜狗抢票助手 tightvnc 中国电信测速112 200g硬盘 美国网站服务器 空间技术网 绍兴电信 搜索引擎提交入口 申请网站 数据库空间 电信网络测速器 阿里云邮箱登陆 登陆qq空间 双11促销 空间排行榜 web是什么意思 rewrite规则 海康流媒体服务器 更多