目录
参考
正常的启动流程见图示。
startup.S文件的分析可参考
调试分析
进入调试模式:
Main()函数的主要内容
选择PMU时钟频率
设置主频及uart端口
OS INIT function 操作系统初始化函数
初始化的工作内容:
Tick 实现方式
外设中断唤醒设置
任务分配及释放
示例代码
官方WM_W800_SDK用户手册(V1.1版);
W800 SDK APIs说明文档
W801|XT804|启动|startup.S|内部中断|初始化|伪指令|学习(5-2):W801-SDK启动分析之startup.S_打酱油的工程师的博客-CSDN博客
W800 模块启动后通过 ROM 和 SECBOOT 程序运行后,最终会运行到 startup.S 开始执行,然后,跳转到 wm_main.c 文件进行一些初始化功能,最后,进入 main.c 打印 user task。
本次采用CKLINK进入调试模式,进行启动程序的相关分析。
CKLINK调试概述可参考:W806|CKLINK LITE|ICE调试|HardPoint|elf模板|CSDK|Debug|学习(4):CKLINK调试W806_打酱油的工程师的博客-CSDN博客
先进行编译:
编译完成后界面,预置了debug所需要的工具菜单和窗口:
从debug结果看,SDK启动时,会先运行sys目录下的系统主程序文件(wm_main.c):G:\bsp\W800_aos\W80X_SDK_v1.00.10\platform\sys\wm_main.c
int main(void)
{
u32 value = 0;
/*standby reason setting in here,because pmu irq will clear it.*/
if ((tls_reg_read32(HR_PMU_INTERRUPT_SRC)>>7)&0x1)
{
tls_sys_set_reboot_reason(REBOOT_REASON_STANDBY);
}
/*32K switch to use RC circuit & calibration*/
tls_pmu_clk_select(0);
#if (TLS_CONFIG_HOSTIF&&TLS_CONFIG_UART)
/*Configure uart port for user's AT Command*/
tls_uart_set_at_cmd_port(TLS_UART_1);
#endif
/*Switch to DBG*/
value = tls_reg_read32(HR_PMU_BK_REG);
value &= ~(BIT(19));
tls_reg_write32(HR_PMU_BK_REG, value);
value = tls_reg_read32(HR_PMU_PS_CR);
value &= ~(BIT(5));
tls_reg_write32(HR_PMU_PS_CR, value);
/*Close those not initialized clk except touchsensor/trng, uart0,sdadc,gpio,rfcfg*/
value = tls_reg_read32(HR_CLK_BASE_ADDR);
value &= ~0x3fffff;
value |= 0x201a02;
tls_reg_write32(HR_CLK_BASE_ADDR, value);
tls_sys_clk_set(CPU_CLK_80M);
tls_os_init(NULL);
/* before use malloc() function, must create mutex used by c_lib */
tls_os_sem_create(&libc_sem, 1);
/*configure wake up source begin*/
csi_vic_set_wakeup_irq(SDIO_IRQn);
csi_vic_set_wakeup_irq(MAC_IRQn);
csi_vic_set_wakeup_irq(SEC_IRQn);
csi_vic_set_wakeup_irq(DMA_Channel0_IRQn);
csi_vic_set_wakeup_irq(DMA_Channel1_IRQn);
csi_vic_set_wakeup_irq(DMA_Channel2_IRQn);
csi_vic_set_wakeup_irq(DMA_Channel3_IRQn);
csi_vic_set_wakeup_irq(DMA_Channel4_7_IRQn);
csi_vic_set_wakeup_irq(DMA_BRUST_IRQn);
csi_vic_set_wakeup_irq(I2C_IRQn);
csi_vic_set_wakeup_irq(ADC_IRQn);
csi_vic_set_wakeup_irq(SPI_LS_IRQn);
csi_vic_set_wakeup_irq(SPI_HS_IRQn);
csi_vic_set_wakeup_irq(GPIOA_IRQn);
csi_vic_set_wakeup_irq(GPIOB_IRQn);
csi_vic_set_wakeup_irq(UART0_IRQn);
csi_vic_set_wakeup_irq(UART1_IRQn);
csi_vic_set_wakeup_irq(UART24_IRQn);
csi_vic_set_wakeup_irq(BLE_IRQn);
csi_vic_set_wakeup_irq(BT_IRQn);
csi_vic_set_wakeup_irq(PWM_IRQn);
csi_vic_set_wakeup_irq(I2S_IRQn);
csi_vic_set_wakeup_irq(SIDO_HOST_IRQn);
csi_vic_set_wakeup_irq(SYS_TICK_IRQn);
csi_vic_set_wakeup_irq(RSA_IRQn);
csi_vic_set_wakeup_irq(CRYPTION_IRQn);
csi_vic_set_wakeup_irq(PMU_IRQn);
csi_vic_set_wakeup_irq(TIMER_IRQn);
csi_vic_set_wakeup_irq(WDG_IRQn);
/*should be here because main stack will be allocated and deallocated after task delete*/
tls_mem_get_init_available_size();
/*configure wake up source end*/
TaskStartStk = tls_mem_alloc(sizeof(u32)*TASK_START_STK_SIZE);
if (TaskStartStk)
{
tls_os_task_create(&tststarthdl, NULL,
task_start,
(void *)0,
(void *)TaskStartStk, /* 任务栈的起始地址 */
TASK_START_STK_SIZE * sizeof(u32), /* 任务栈的大小 */
1,
0);
tls_os_start_scheduler();
}
else
{
while(1);
}
return 0;
}
首先使用tls_reg_read32()函数从寄存器地址处读取值,
DEVICE_地址计算示例:
DEVICE_BASE_ADDR 0x40000000
HR_PMU_BASE_ADDR (DEVICE_BASE_ADDR + 0xD00)
HR_PMU_INTERRUPT_SRC (HR_PMU_BASE_ADDR + 0x14)
40000D14>>7=0X0080001A(8388634)
故:((tls_reg_read32(HR_PMU_INTERRUPT_SRC)>>7)&0x1)的值为0
This function is used to select pmu clk.
Parameters
[in] bypass pmu clk whether or not use bypass mode 1 pmu clk use 32K by 40MHZ other pmu clk 32K by calibration circuit
/*Configure uart port for user's AT Command*/
tls_uart_set_at_cmd_port(TLS_UART_1);
value = tls_reg_read32(HR_PMU_BK_REG);
define
HR_PMU_BK_REG (HR_PMU_BASE_ADDR + 0x20)
/*Close those not initialized clk except touchsensor/trng, uart0,sdadc,gpio,rfcfg*/
除了touchsensor/trng, uart0,sdadc,gpio,rfcfg*/ 关闭那些没有初始化的clk
#define
HR_CLK_BASE_ADDR (DEVICE_BASE_ADDR + 0xE00)
1)、tls_sys_clk_set(CPU_CLK_240M);
tls_os_init(NULL);
2)、为用户的AT命令配置uart端口
3)、切换到DBG
1)、OS scheduler start function
2)、get OS type(OS_FREERTOS = 1)
3)、OS tick handler
操作系统节拍处理程序,时间管理模块中执行最频繁的函数,每当 Tick 中断发生时就会调用该函数
void tls_os_time_tick(void *p){
}
static uint32_t CK_IN_INTRP(void)
{
uint32_t vec = 0;
asm volatile(
"mfcr %0, psr \n"
"lsri %0, 16\n"
"sextb %0\n"
:"=r"(vec):);
if (vec >= 32 || (vec == 10)) {
return 1;
} else {
return 0;
}
}
/**
* @brief get isr count
*
* @param[in] None
*
* @retval count
*
* @note None
*/
//extern int portGET_IPSR(void);
u8 tls_get_isr_count(void)
{
// return intr_counter;
//return (portGET_IPSR() > 13);
return (u8)CK_IN_INTRP();
}
int csi_kernel_intrpt_enter(void)
{
return 0;
}
int csi_kernel_intrpt_exit(void)
{
portYIELD_FROM_ISR(pdTRUE);
return 0;
}
#endif
任务删除后将分配和释放主堆栈。
/*configure wake up source end*/
TaskStartStk = tls_mem_alloc(sizeof(u32)*TASK_START_STK_SIZE);
if (TaskStartStk)
{
tls_os_task_create(&tststarthdl, NULL,
task_start,
(void *)0,
(void *)TaskStartStk, /* 任务栈的起始地址 */
TASK_START_STK_SIZE * sizeof(u32), /* 任务栈的大小 */
1,
0);
tls_os_start_scheduler();
}
else
{
while(1);
}
该步骤完成后进入用户main()函数自定义部分的流程。WM_SDK 的用户程序入口为: UserMain(void) ,用户可在此文件,基于 CreateDemoTask 函数中创建自己的 Task, 完成用户定制化功能。