1.HAL_Init();
HAL_StatusTypeDef HAL_Init(void)
{
HAL_StatusTypeDef status = HAL_OK;
/* Configure Flash prefetch, Instruction cache, Data cache */
/* Default configuration at reset is: */
/* - Prefetch disabled */
/* - Instruction cache enabled */
/* - Data cache enabled */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();//使能CPU1指令预取
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//4位全部用来做抢占优先级,也就是最多16级中断优先级
/* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */
if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
{
status = HAL_ERROR;
}
else
{
/* Init the low level hardware */
HAL_MspInit();//具体到函数内部初始化了HSEM以及它的中断, PendSV中断优先级设置为最低
}
/* Return function status */
return status;
}
2.MX_APPE_Config();
void MX_APPE_Config( void )
{
/**
* The OPTVERR flag is wrongly set at power on
* It shall be cleared before using any HAL_FLASH_xxx() api
*/
__HAL_FLASH_CLEAR_FLAG( FLASH_FLAG_OPTVERR );
/**
* Reset some configurations so that the system behave in the same way
* when either out of nReset or Power On
*/
Reset_Device( );//1.根据复位原因决定是否重置备份域,例如软复位不需要重置,还会保持上一次的配置。
//2.使能IPCC时钟,并且关闭CPU1和CPU2 IPCC所有的发送和接收中断
/* Configure HSE Tuning */
Config_HSE();//根据OTP存储的值,调节HSE的电容。采用官方模块的优势!
return;
}
3.时钟和外设配置
SystemClock_Config();//按照cube配置的时钟树进行时钟配置,详见对应的.ioc文件
PeriphCommonClock_Config();//配置SMPS 以及 配置RF 唤醒时钟源为LSE
MX_IPCC_Init();//配置IPCC时钟,使能cpu1 NVIC中IPCC发送和接收中断,但是屏蔽了IPCC外设的发送接收中断。
MX_GPIO_Init();
MX_RF_Init();//目前是个空函数!
UserRTCInit();//cube中设置不要自动生成MX_RTC_Init();否则会提前打开wakeup中断
4.MX_APPE_Init();
void MX_APPE_Init( void )
{
//里面的SMPS函数为空,Init_Exti使能了EXTI_LINE_36(IPCC用)和
//EXTI_LINE_38(HSEM用),Init_Rtc选择RTC唤醒时钟源
System_Init( );
//选择HSI作为stop唤醒后的系统时钟,LPM配置只是把两个标志位设置了下,
//CPU2进入深度睡眠的时候进入shutdown模式。
SystemPower_Config();
HW_TS_Init(hw_ts_InitMode_Full, &hrtc); //RTC做软定时器配置
/* USER CODE BEGIN APPE_Init_1 */
/**
* The Standby mode should not be entered before the initialization is over
* The default state of the Low Power Manager is to allow the Standby Mode so an request is needed here
*/
UTIL_LPM_SetOffMode(1 << CFG_LPM_APP, UTIL_LPM_DISABLE);
/* USER CODE END APPE_Init_1 */
appe_Tl_Init(); //传输层初始化,后面展开讲
/**
* From now, the application is waiting for the ready event ( VS_HCI_C2_Ready )
* received on the system channel before starting the Stack
* This system event is received with APPE_SysUserEvtRx()
*/
/* USER CODE BEGIN APPE_Init_2 */
/* USER CODE END APPE_Init_2 */
return;
}
static void appe_Tl_Init( void )
{
TL_MM_Config_t tl_mm_config;
SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf;
/**< Reference table initialization */
TL_Init();//TL_RefTable管理结构体赋值,CPU1 IPCC发送接收中断使能
//用来锁M4向M0+发起系统命令的调用
MtxShciId = osMutexNew( NULL );
/*当向M0+发起system hci调用,M0+接收后会产生一个IPCC通道空中断,
中断中释放该信号量通知应用程序发送完成。*/
SemShciId = osSemaphoreNew( 1, 0, NULL );
/** M0+协议栈核心准备完成后会通过IPCC_RX通道通知M4,M4会唤醒该任务进行处理 */
ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr);
/**< System channel initialization */
SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer;
SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot;
//赋值一些指针变量,IPCC通道2作为system event接收通道,后面展开讲
shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf);
/**< Memory Manager channel initialization */
tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer;
tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer;
tl_mm_config.p_AsynchEvtPool = EvtPool;
tl_mm_config.AsynchEvtPoolSize = POOL_SIZE;
/*初始化各种buf,主要用来接收缓存,调用该函数后
*TL_RefTable.p_mem_manager_table = {
.blepool = EvtPool,//[1340]
.blepoolsize = POOL_SIZE,//1340当CFG_TLBLE_EVT_QUEUE_LENGTH = 5
.pevt_free_buffer_queue = (uint8_t*)&FreeBufQueue,
.spare_ble_buffer = BleSpareEvtBuffer,//[266] = sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255
.p_mem_manager_table->spare_sys_buffer = SystemSpareEvtBuffer,//[266]
.traces_evt_pool = ?,//初始化后这个是个野值!
.tracespoolsize = ?,//初始化后这个是个野值!
}
*/
TL_MM_Init( &tl_mm_config );
//该函数调用HW_IPCC_Enable,使能CPU2的IPCC时钟以及相关中断,
//用__SEV通知cpu2,然后cpu1用__WFE等待掉这个事件,相当于清理该事件,
//最后启动无线处理器CPU2.
//__SEV解释:多处理器环境中向所有的处理器发送事件(包括自身)。在符合CMSIS的设备驱动库中,可以使用“__SEV()”实现该操作.
TL_Enable();
return;
}
void shci_init(void(* UserEvtRx)(void* pData), void* pConf)
{
//StatusNotCallBackFunction赋值为APPE_SysStatusNot,
//该函数利用MtxShciId互斥锁,来保证多线程system hci cmd调用互斥。
StatusNotCallBackFunction = ((SHCI_TL_HciInitConf_t *)pConf)->StatusNotCallBack;
//shciContext.UserEvtRx=APPE_SysUserEvtRx,
//当M0+准备完成后会通过IPCC RX通道通知M4调用该函数
shciContext.UserEvtRx = UserEvtRx;
//该函数会赋值shciContext.io.Init = TL_SYS_Init以及
//shciContext.io.Send = TL_SYS_SendCmd;
shci_register_io_bus (&shciContext.io);
//后面展开讲
TlInit((TL_CmdPacket_t *)(((SHCI_TL_HciInitConf_t *)pConf)->p_cmdbuffer));
return;
}
static void TlInit( TL_CmdPacket_t * p_cmdbuffer )
{
TL_SYS_InitConf_t Conf;
pCmdBuffer = p_cmdbuffer;//=SystemCmdBuffer
LST_init_head (&SHciAsynchEventQueue);
Cmd_SetStatus(SHCI_TL_CmdAvailable);//SHCICmdStatus = SHCI_TL_CmdAvailable;
SHCI_TL_UserEventFlow = SHCI_TL_UserEventFlow_Enable;
/* Initialize low level driver */
if (shciContext.io.Init)
{
Conf.p_cmdbuffer = (uint8_t *)p_cmdbuffer;//=SystemCmdBuffer
Conf.IoBusCallBackCmdEvt = TlCmdEvtReceived;
Conf.IoBusCallBackUserEvt = TlUserEvtReceived;
shciContext.io.Init(&Conf);//调用TL_SYS_Init
}
return;
}
int32_t TL_SYS_Init( void* pConf )
{
MB_SysTable_t * p_systable;
TL_SYS_InitConf_t *pInitHciConf = (TL_SYS_InitConf_t *) pConf;
LST_init_head (&SystemEvtQueue);
p_systable = TL_RefTable.p_sys_table;
//TL_RefTable.p_sys_table->pcmd_buffer = SystemCmdBuffer;
//M4利用该buffer发起系统HCI同步调用。
p_systable->pcmd_buffer = pInitHciConf->p_cmdbuffer;
//TL_RefTable.p_sys_table->sys_queue = (uint8_t*)&SystemEvtQueue;
//M0+利用该queue给M4发送异步事件
p_systable->sys_queue = (uint8_t*)&SystemEvtQueue;
HW_IPCC_SYS_Init();//使能system event 接收通道
//SYS_CMD_IoBusCallBackFunction=TlCmdEvtReceived
//该函数会在M4发送完系统HCI命令后,发送通道空中断中调用,通知M4命令已经发送完成
SYS_CMD_IoBusCallBackFunction = pInitHciConf->IoBusCallBackCmdEvt;
//SYS_EVT_IoBusCallBackFunction =TlUserEvtReceived
//该函数会在M0+发送了系统异步事件后,由IPCC接收中断函数调用
SYS_EVT_IoBusCallBackFunction = pInitHciConf->IoBusCallBackUserEvt;
return 0;
}
5.CPU2准备完成后
经过以上配置后,CPU2协议栈准备完成,CPU1会通过IPCC RX通道接收到事件,函数调用路径HW_IPCC_Rx_Handler->HW_IPCC_SYS_EvtHandler->HW_IPCC_SYS_EvtNot, HW_IPCC_SYS_EvtNot函数从SystemEvtQueue中取出事件,并且通过SYS_EVT_IoBusCallBackFunction(指向TlUserEvtReceived)函数将事件压入SHciAsynchEventQueue, 接着调用shci_notify_asynch_evt(虽然入参是SHciAsynchEventQueue的地址,但是并没有使用),该函数调用osThreadFlagsSet( ShciUserEvtProcessId, 1 ),触发ShciUserEvtProcess任务启动。
shci_user_evt_proc函数 发现SHciAsynchEventQueue不为空,则取出开头的事件进行处理,调用shciContext.UserEvtRx(指向APPE_SysUserEvtRx)函数,该函数首先获取无线协议栈版本号,然后根据subevtcode判断进入哪个处理分支,首次上电后,第一条一般是SHCI_SUB_EVT_CODE_READY,所以这里调用APPE_SysEvtReadyProcessing函数,正常情况下该ready指示的是WIRELESS_FW_RUNNING,所以进入该分支,配置CPU2 debug相关的功能后,调用APP_BLE_Init()。
BLE的事件接收通道HW_IPCC_BLE_EVENT_CHANNEL 为 1
void APP_BLE_Init( void )
{
SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet =
{
{{0,0,0}}, /**< Header unused */
{ 0, /** pBleBufferAddress not used */
0, /** BleBufferSize not used */
CFG_BLE_NUM_GATT_ATTRIBUTES,
CFG_BLE_NUM_GATT_SERVICES,
CFG_BLE_ATT_VALUE_ARRAY_SIZE,
CFG_BLE_NUM_LINK,
CFG_BLE_DATA_LENGTH_EXTENSION,
CFG_BLE_PREPARE_WRITE_LIST_SIZE,
CFG_BLE_MBLOCK_COUNT,
CFG_BLE_MAX_ATT_MTU,
CFG_BLE_SLAVE_SCA,
CFG_BLE_MASTER_SCA,
CFG_BLE_LSE_SOURCE,
CFG_BLE_MAX_CONN_EVENT_LENGTH,
CFG_BLE_HSE_STARTUP_TIME,
CFG_BLE_VITERBI_MODE,
CFG_BLE_OPTIONS,
0,
CFG_BLE_MAX_COC_INITIATOR_NBR,
CFG_BLE_MIN_TX_POWER,
CFG_BLE_MAX_TX_POWER,
CFG_BLE_RX_MODEL_CONFIG,
CFG_BLE_MAX_ADV_SET_NBR,
CFG_BLE_MAX_ADV_DATA_LEN,
CFG_BLE_TX_PATH_COMPENS,
CFG_BLE_RX_PATH_COMPENS}
}
};
/**
* Initialize Ble Transport Layer
*/
Ble_Tl_Init( );//和appe_Tl_Init的前半部分很像,这个初始化的是HCI相关
/**
* Do not allow standby in the application
*/
UTIL_LPM_SetOffMode(1 << CFG_LPM_APP_BLE, UTIL_LPM_DISABLE);
/**
* Register the hci transport layer to handle BLE User Asynchronous Events
*/
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
/**
* Starts the BLE Stack on CPU2
*/
if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success)//用ble_init_cmd_packet中的参数配置BLE
{
Error_Handler();
}
/**
* Initialization of HCI & GATT & GAP layer
*/
Ble_Hci_Gap_Gatt_Init();//配置各种秘钥,BLE角色设置,广播名,目前暂定“218A”,
/**
* Initialization of the BLE Services
*/
SVCCTL_Init();//主要调用SVCCTL_SvcInit函数,该函数调用如下函数
//BAS_Init(); BLS_Init(); CRS_STM_Init();//这三个直接为空
//DIS_Init();//初始化DIS(Device Information Service), 其中的2A29是厂商名称字符串UUID。
//EDS_STM_Init(); HIDS_Init(); //这两个直接为空
//HRS_Init();//初始化heart rate服务(180D),包含三个特性 NOTIFY(2A37)、read(2A38)、write(2A39)
//HTS_Init(); IAS_Init(); LLS_Init(); TPS_Init(); MOTENV_STM_Init(); P2PS_STM_Init(); ZDD_STM_Init(); OTAS_STM_Init(); BVOPUS_STM_Init(); 空
//MESH_Init(); SVCCTL_InitCustomSvc(); 空
/**
* Initialization of the BLE App Context
*/
BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0xFFFF;
/**
* From here, all initialization are BLE application specific
*/
AdvUpdateProcessId = osThreadNew(AdvUpdateProcess, NULL, &AdvUpdateProcess_attr);//创建广播任务,该任务非常简单就是等快速
//广播结束后切换到低功耗广播,最终程序需要考虑删掉,只用低功耗广播模式即可
/**
* Initialization of ADV - Ad Manufacturer Element - Support OTA Bit Mask
*/
#if(BLE_CFG_OTA_REBOOT_CHAR != 0)
manuf_data[sizeof(manuf_data)-8] = CFG_FEATURE_OTA_REBOOT;
#endif
/**
* Initialize DIS Application
*/
DISAPP_Init();//空
/**
* Initialize HRS Application
*/
HRSAPP_Init();//创建HrsProcess任务
/* USER CODE BEGIN APP_BLE_Init_3 */
/* USER CODE END APP_BLE_Init_3 */
/**
* Create timer to handle the connection state machine
*/
HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(BleApplicationContext.Advertising_mgr_timer_Id), hw_ts_SingleShot, Adv_Mgr);
/**
* Make device discoverable
*/
BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID;
BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1;
Add_Advertisment_Service_UUID(HEART_RATE_SERVICE_UUID);
/* Initialize intervals for reconnexion without intervals update */
AdvIntervalMin = CFG_FAST_CONN_ADV_INTERVAL_MIN;
AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX;
/**
* Start to Advertise to be connected by Collector
*/
Adv_Request(APP_BLE_FAST_ADV);//APP_BLE_FAST_ADV 会启动Advertising_mgr_timer_Id定时器,定时60s,然后触发AdvUpdateProcess任务切换到低功耗广播模式
/* USER CODE BEGIN APP_BLE_Init_2 */
/* USER CODE END APP_BLE_Init_2 */
return;
}
static void Ble_Tl_Init( void ) {
HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
MtxHciId = osMutexNew( NULL );
SemHciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */
Hci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&BleCmdBuffer;
Hci_Tl_Init_Conf.StatusNotCallBack = BLE_StatusNot;
hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
}
void hci_init(void(* UserEvtRx)(void* pData), void* pConf)
{
StatusNotCallBackFunction = ((HCI_TL_HciInitConf_t *)pConf)->StatusNotCallBack;
hciContext.UserEvtRx = UserEvtRx;
hci_register_io_bus (&hciContext.io);
TlInit((TL_CmdPacket_t *)(((HCI_TL_HciInitConf_t *)pConf)->p_cmdbuffer));
return;
}