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单片机学习笔记——SDK的启动流程,例程使用_第1张图片

W801多了一个板级初始化(board_init)功能的调用 内容如下:

W801单片机学习笔记——SDK的启动流程,例程使用_第2张图片

 是串口的初始化,该功能是配合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();
#endif

	tls_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_ATCMD
	factory_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

#endif

	tls_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_FTR
		if (tststarthdl)
		{
    		tls_os_task_del_by_task_handle(tststarthdl,task_start_free);
		}
        tls_os_time_delay(0x10000000);
#else
#if 1
		tls_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文件中。具体路径如下:

W801单片机学习笔记——SDK的启动流程,例程使用_第3张图片

该文件SDK中默认有且只有一个函数,即 UserMain();内容如下:

void UserMain(void)
{
	printf("\n user task \n");
#if DEMO_CONSOLE
	CreateDemoTask();
#endif
//用户自己的task

}

可见此函数中,首先打印”user task“,然后创建例程进程,最后是用户自定义代码的编写处。至于例程进程,可参考文件链接如下:

链接:https://pan.baidu.com/s/173Ek7qeY0i3ibqt9vvfuUg 
提取码:SYHT

W801单片机SDK例程使用手册-单片机文档类资源-CSDN下载

至此,W801的启动流程分析完毕。

3.挖坑

下期分享W801的SDK中一些让人不爽的地方,并提出修改建议。

W801单片机学习笔记——SDK的启动流程,例程使用_第4张图片

 

你可能感兴趣的:(W801,单片机,嵌入式硬件,risc-v)