• 联盛德 HLKW806 (三): 免按键自动下载和复位


    目录

    免按键自动复位下载

    如果只是了解如何使用, 看这部分就可以了. 在项目中将SDK更新到最新版本, 在SDK中找到这个文件 include/arch/xt804/csi_config.h, 将下面这行的值从0改成1

    #define USE_UART0_AUTO_DL          0 // Auto download, 0:OFF, 1:ON
    

    然后编译, 按正常的操作流程烧录到开发板. 之后的烧录就可以免按键自动下载了, 在下载前会自动复位, 下载后也会自动复位.

    注意:

    1. 这个功能仅仅适用于开发和测试阶段, 不能用在生产环境.
    2. 这个功能(以及默认的printf打印)会占用UART0, 如果你的项目需要使用UART0与其它设备通信, 必须关闭这个功能

    免按键下载的功能分析

    烧录下载的指令分析

    在tools/W806/rules.mk中

    flash:all
        @$(WM_TOOL) -c $(DL_PORT) -rs at -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls
    

    可以看到make flash会先执行编译, 然后调用 wm_tool 根据预设的下载端口, 下载波特率, 将fls文件下载到设备. 在正常的下载过程中, 需要先复位开发板进入下载模式, 这时候才开始实际的下载, 下载结束后开发板会依然处于下载模式, 此时需要复位开发板进入普通模式, 运行用户程序. 现在这两步都是手工按Reset键完成的.

    烧录下载复位的代码

    在上面的命令中, 有一个参数是-rs at, 这个参数的说明是

    -rs reset_action, set device reset method, default is manual control <none | at | rts>
             none - manual control device reset
             at   - use the at command to control the device reset
             rts  - use the serial port rts pin to control the device reset
    

    at对应的选项是使用AT命令去重启设备, 重启动作对应的有两处, 分别就是需要手工按Reset按钮的两个时间点.

    下载前复位

    对于下载前复位, wm_tool中的处理是

    if (WM_TOOL_DL_ACTION_AT == wm_tool_dl_action)
    {
        if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_normal_serial_rate)
            wm_tool_uart_set_speed(wm_tool_normal_serial_rate);
    
    #if 0 /* use erase option */
        if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type)
        {
            ret = wm_tool_uart_write("AT+&FLSW=8002000,0\r\n", strlen("AT+&FLSW=8002000,0\r\n"));
            if (ret <= 0)
            {
                wm_tool_printf("destroy secboot failed.\r\n");
                wm_tool_uart_close();
                return -3;
            }
            wm_tool_delay_ms(300);
        }
    #endif
    
        ret = wm_tool_uart_write("AT+Z\r\n", strlen("AT+Z\r\n"));
        if (ret <= 0)
        {
            wm_tool_printf("reset error.\r\n");
            wm_tool_uart_close();
            return -4;
        }
    
        if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_normal_serial_rate)
            wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE);
    }
    
    ...
    
    wm_tool_printf("wait serial sync...");
    wm_tool_send_esc2uart(500);/* used for delay */
    

    可以看到wm_tool的实际操作是通过串口发出AT+Z\r\n指令, 然后等待500ms再检测是否复位

    下载后复位

    对于下载后的复位, 在代码中只处理了rts选项, 这里使用at选项是无动作的

    ...
    
    if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type)
    {
        if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action)/* auto reset */
        {
            wm_tool_uart_set_dtr(0);
            wm_tool_uart_set_rts(1);
            wm_tool_delay_ms(50);
            wm_tool_uart_set_dtr(1);
            wm_tool_uart_set_rts(0);
            wm_tool_delay_ms(50);
            wm_tool_uart_set_dtr(0);
        }
        else
        {
            wm_tool_printf("please manually reset the device.\r\n");
        }
    }
    ...
    

    W806的烧录自动复位实现

    根据上面的分析, W806的自动复位需要实现两处, 一处是下载前, 一处是下载完成后

    下载前的复位实现

    下载前开发板还运行在普通模式, 此时串口由用户程序控制, 如果需要响应串口命令, 需要在用户程序中添加串口0的RX中断和命令判断. 这一步可以参考SDK中UART0作为printf打印输出的实现

    增加UART0初始化

    在 platform/arch/xt804/bsp/board_init.c 中增加初始化代码, 当配置为开启时, 开启UART0接收中断

    ...
    static void uart0Init (int bandrate)
    {
        unsigned int bd;
    
    #if USE_UART0_AUTO_DL
        WRITE_REG(UART0->INTM, ~UART_RX_INT_FLAG);
        NVIC_ClearPendingIRQ(UART0_IRQn);
        NVIC_EnableIRQ(UART0_IRQn);
    #else
        NVIC_DisableIRQ(UART0_IRQn);
        NVIC_ClearPendingIRQ(UART0_IRQn);
    #endif
    ...
    }
    

    增加UART0接收中断响应和命令检测

    在 platform/component 下新增一个组件, 在组件中实现中断响应和命令检测

    /******************************************************************************
    ** 
     * \file        auto_dl.c
     * \author      Xu Ruijun | 1687701765@qq.com
     * \date        
     * \brief       Reset device with UART0 AT+Z command
     * \note        Set USE_UART0_AUTO_DL = 1 to enable this feature
     * \version     
     * \ingroup     
     * \remarks     
     *
    ******************************************************************************/
    
    #include "wm_hal.h"
    
    #if USE_UART0_AUTO_DL
    
    #define __AUTO_DL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->INTS |= __FLAG__)
    #define __AUTO_DL_TIMEOUT 5
    #define __AUTO_DL_BUF_SIZE 32
    
    const static uint8_t auto_dl_cmd[] = {'A', 'T', '+', 'Z', '\r', '\n'};
    uint8_t auto_dl_buf[__AUTO_DL_BUF_SIZE] = {0}, auto_dl_buf_pt = 0, auto_dl_cmd_pt = 0;
    uint32_t auto_dl_act_ts = 0;
    
    void AUTO_DL_Reset(void)
    {
        CLEAR_REG(RCC->RST);                     // reset all peripherals
        uint32_t rv = *(uint32_t*)(0x00000000U); // get reset vector
        ((void (*)())(rv))();                    // go to ROM
    }
    
    __attribute__((weak)) void USER_UART0_RX(uint8_t ch)
    {
        UNUSED(ch);
    }
    
    void AUTO_DL_UART_IRQHandler(USART_TypeDef* huart)
    {
        uint8_t ch, count;
        uint32_t ts, isrflags = READ_REG(huart->INTS), isrmasks = READ_REG(huart->INTM);
        // Clear interrupts
        __AUTO_DL_UART_CLEAR_FLAG(huart, isrflags);
    
        if (((isrflags & UART_RX_INT_FLAG) != RESET) && ((isrmasks & UART_RX_INT_FLAG) == RESET))
        {
            /**
             *   1) Data always comes in as single bytes, so the count is always 1(or 0);
             *   2) Each byte will comes in twice, the second time with count=0 will be ignored;
             */
            count = ((READ_REG(huart->FIFOS) & UART_FIFOS_RFC) >> UART_FIFOS_RFC_Pos);
            while (count-- > 0)
            {
                // Write ch to ring buffer
                ch = (uint8_t)(huart->RDW);
                auto_dl_buf[auto_dl_buf_pt++] = ch;
                if (auto_dl_buf_pt == __AUTO_DL_BUF_SIZE) auto_dl_buf_pt = 0;
    
                // Command detection
                ts = HAL_GetTick();
                if ((ts - auto_dl_act_ts) > __AUTO_DL_TIMEOUT)
                {
                    // Restart the comparison if timeout
                    auto_dl_cmd_pt = 0;
                    if (auto_dl_cmd[auto_dl_cmd_pt] == ch)
                    {
                        auto_dl_cmd_pt++;
                    }
                }
                else
                {
                    // Avoid starting new comparison in the middle of RX
                    if ((auto_dl_cmd[auto_dl_cmd_pt] == ch) && (auto_dl_cmd_pt > 0))
                    {
                        auto_dl_cmd_pt++;
                        if (auto_dl_cmd_pt == sizeof(auto_dl_cmd))
                        {
                            AUTO_DL_Reset();
                        }
                    }
                    else
                    {
                        // Restart the comparison
                        auto_dl_cmd_pt = 0;
                    }
                }
                // Record last active timestamp
                auto_dl_act_ts = ts;
                USER_UART0_RX(ch);
            }
        }
    
        if (((isrflags & UART_INTS_TL) != RESET) && ((isrmasks & UART_INTM_RL) == RESET))
        {
            //UART_Transmit_IT(huart);
        }
    
        if (((isrflags & UART_INTS_TEMPT) != RESET) && ((isrmasks & UART_INTM_TEMPT) == RESET))
        {
            //UART_EndTransmit_IT(huart);
        }
    }
    
    __attribute__((isr)) void UART0_IRQHandler(void)
    {
        AUTO_DL_UART_IRQHandler(UART0);
    }
    
    #endif
    

    下载成功后的复位实现

    下载成功后, 开发板还运行在下载模式, 因此找到下载模式下对应复位的命令就可以了, 这个命令是

    0x21, 0x06, 0x00, 0xc7, 0x7c, 0x3f, 0x00, 0x00, 0x00
    

    对应的, 在 wm_tool.c中增加这个命令常量

    const static unsigned char wm_tool_chip_cmd_reset[]    = {0x21, 0x06, 0x00, 0xc7, 0x7c, 0x3f, 0x00, 0x00, 0x00};
    

    和对AT模式的处理逻辑

    if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type)
    {
        if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action) // Use UART RTS pin to control the device reset
        {
            ...
        }
        else if(WM_TOOL_DL_ACTION_AT == wm_tool_dl_action) // Use AT command to reset the device
        {
            wm_tool_delay_ms(500);
            ret = wm_tool_uart_write(wm_tool_chip_cmd_reset, sizeof(wm_tool_chip_cmd_reset));
            wm_tool_delay_ms(30);
            if(ret > 0){
                wm_tool_printf("reset command has been sent.\r\n");
            }else{
                wm_tool_printf("reset command sending failed.\r\n");
            }
            ret = 0;
        }
        ...
    }
    
  • 相关阅读:
    利用 .NET Framework 命令行工具
    和AI机器人Alice的一段聊天记录
    WINDOWS自启动程序的10大隐身之所
    开放式开发/开源项目TimeDog[C#WindowsApp]
    Microsoft月度中文速递
    新安装的VS2003出现了一个问题不能新建项目!
    实例构造器和类型构造器的一些比较
    C++ 模板里面的typename
    vim 折叠的用法
    Redis3:持久化
  • 原文地址:https://www.cnblogs.com/milton/p/15609031.html
Copyright © 2020-2023  润新知