W801单片机学习笔记——SDK的启动流程,例程使用
目录
1.前言
2.SDK的启动流程
3.挖坑
1.前言
W801的SDK需要配套的CDK集成开发环境进行开发,该SDK具有W801单片机所有硬件的驱动程序,FreeRTOS操作系统,基于蓝牙和WiFi功能的上层应用,以及各种功能的例程,可以通过例程测试硬件并模仿例程编写自己所需要的功能。
该篇文章主要以SDK启动的启动流程,例程的使用,以及SDK中部分文件在实际使用中的修改尝试。
2.SDK的启动流程
W801在上电后先通过复位电路复位,并使用内部振荡器开始工作。此后单片机先进入启动扇区即地址为0X0000_0000,启动扇区检测BOOT0引脚,若需要更新固件则开始从串口接收数据开始更新固件;若无需更新固件,则引导单片机从FLASH启动地址为0X0800_0000。至此就进入了汇编编写的启动文件。Start.S,这个文件与STM32的startup_stm32.s类似,主要有这几个部分:
- 罗列中断向量表(具体数量以处理器支持的中断数为准)
- DATA区域初始化(代码中给定初始值的全局变量和静态变量的初始值在FLASH中,这个操作将拷贝到SRAM中,以备使用)
- BBS区域初始化(代码中没有给的初值的全局变量和静态变量将在这个操作中清零)
- 系统初始化(一般调用SystemInit函数,设置中断向量寄存器指向中断向量表,设置FLASH延迟,设置倍频器的一些基础参数等等,不同芯片的SDK不同)
- 跳转到主函数(跳转到main函数开始运行)
至于start.S文件的具体内容后期将会单独出一篇文章介绍。
现在主要理清晰W801的启动过程,故现在只看如下图部分:
W801多了一个板级初始化(board_init)功能的调用 内容如下:
是串口的初始化,该功能是配合W801的SDK的控制台使用的,而且W801的SDK已经将printf函数重新定向到串口,在自己的程序中直接调用printf即可在串口助手上看到内容。
接下来看main函数,main函数的具体位置在wm_main.c文件中,内容如下:
int main(void){ u32 value = 0; /*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 uart0,sdadc,gpio,rfcfg*/ value = tls_reg_read32(HR_CLK_BASE_ADDR); value &= ~0x3fffff; value |= 0x1a02; tls_reg_write32(HR_CLK_BASE_ADDR, value); tls_sys_clk_set(CPU_CLK_240M); 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); /*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;}
这个文件无需全部看明白,只需要知道干了什么事情,和几句我们需要修改的着重了解一下即可。这个main函数干了如下事情:
- 初始化时钟
- 填写中断向量表(把中断函数地址填写到中断向量表,没有定义的中断函数将填写弱定义的中断服务函数地址,这个套路和STM32一样)
- 创建task_start进程并打开实时操作系统的调度器(后续将在此进程中执行)
上述代码中需要着重如下函数,其参数分别如下:
tls_sys_clk_set(CPU_CLK_240M);//设置处理器工作速度//参数如下enum CPU_CLK{CPU_CLK_240M = 2,CPU_CLK_160M = 3,CPU_CLK_80M = 6,CPU_CLK_40M = 12,CPU_CLK_2M = 240,};
这个函数将决定处理器的工作速度,此处在SDK中默认设置为80MHZ,故如果发现自己买的W801的CPU性能不佳不要怀疑国产芯片的实力,请来此处将其设置为240MHZ。
接下将会运行task_start进程,代码如下:
/* * Function Name // task_start * Descriptor // before create multi_task, we create a task_start task * // in this example, this task display the cpu usage * Input * Output * Return /void task_start (void *data){u8 enable = 0; u8 mac_addr[6] = {0x00, 0x25, 0x08, 0x09, 0x01, 0x0F};#if TLS_CONFIG_CRYSTAL_24M tls_wl_hw_using_24m_crystal();#endiftls_mem_get_init_available_size(); /* must call first to configure gpio Alternate functions according the hardware design */ wm_gpio_config(); tls_irq_init();#if TLS_CONFIG_HARD_CRYPTO tls_crypto_init();#endif#if (TLS_CONFIG_LS_SPI) tls_spi_init(); tls_spifls_init();#endif tls_fls_init(); tls_fls_sys_param_postion_init(); /*PARAM GAIN,MAC default*/ tls_ft_param_init(); tls_param_load_factory_default(); tls_param_init(); /*add param to init sysparam_lock sem*/ tls_get_tx_gain(&tx_gain_group[0]); TLS_DBGPRT_INFO("tx gain "); TLS_DBGPRT_DUMP((char *)(&tx_gain_group[0]), 27); if (tls_wifi_mem_cfg(WIFI_MEM_START_ADDR, 7, 7)) /*wifi tx&rx mem customized interface*/ { TLS_DBGPRT_INFO("wl mem initial failured\n"); } tls_get_mac_addr(&mac_addr[0]); TLS_DBGPRT_INFO("mac addr "); TLS_DBGPRT_DUMP((char *)(&mac_addr[0]), 6); if(tls_wl_init(NULL, &mac_addr[0], NULL) == NULL) { TLS_DBGPRT_INFO("wl driver initial failured\n"); } if (wpa_supplicant_init(mac_addr)) { TLS_DBGPRT_INFO("supplicant initial failured\n"); }/*wifi-temperature compensation,default:open*/tls_wifi_set_tempcomp_flag(0);tls_wifi_set_psm_chipsleep_flag(0);tls_wifi_psm_chipsleep_cb_register(tls_pmu_chipsleep_callback, NULL, NULL); tls_ethernet_init();#if TLS_CONFIG_BT tls_bt_entry();#endif tls_sys_init();#if TLS_CONFIG_ONLY_FACTORY_ATCMDfactory_atcmd_init();#else /*HOSTIF&UART*/#if TLS_CONFIG_HOSTIF tls_hostif_init();#if (TLS_CONFIG_HS_SPI) tls_hspi_init();#endif#if TLS_CONFIG_UART tls_uart_init();#endif#if TLS_CONFIG_HTTP_CLIENT_TASK http_client_task_init();#endif#endiftls_param_get(TLS_PARAM_ID_PSM, &enable, TRUE);if (enable != TRUE){ enable = TRUE; tls_param_set(TLS_PARAM_ID_PSM, &enable, TRUE); } UserMain(); tls_sys_auto_mode_run();#endif for (;;) {#if MAIN_TASK_DELETE_AFTER_START_FTRif (tststarthdl){ tls_os_task_del_by_task_handle(tststarthdl,task_start_free);} tls_os_time_delay(0x10000000);#else#if 1tls_os_time_delay(0x10000000);#else //printf("start up\n"); extern void tls_os_disp_task_stat_info(void); tls_os_disp_task_stat_info(); tls_os_time_delay(1000);#endif#endif }}
这个进程主要有中断及各类外设的初始化,其中包括W801的特色——蓝牙和WiFi功能的初始化。其初始化流程与STM32略有不同,STM32在初始化需要连接GPIO口的外设时,GPIO的设置将会与外设在同一个函数中初始化。而W801现在这个进程里单独初始化外设而不对应GPIO,在其后真的需要使用的时候再指定引脚(蓝牙和WiFi功能除外)。
此进程中的UserMain();是下一步,即用户进程,该函数再main.c文件中。具体路径如下:
该文件SDK中默认有且只有一个函数,即 UserMain();内容如下:
void UserMain(void){printf("\n user task \n");#if DEMO_CONSOLECreateDemoTask();#endif//用户自己的task}
可见此函数中,首先打印”user task“,然后创建例程进程,最后是用户自定义代码的编写处。至于例程进程,可参考文件链接如下:
链接:https://pan.baidu.com/s/173Ek7qeY0i3ibqt9vvfuUg
提取码:SYHT
W801单片机SDK例程使用手册-单片机文档类资源-CSDN下载
至此,W801的启动流程分析完毕。
3.挖坑
下期分享W801的SDK中一些让人不爽的地方,并提出修改建议。