聯盛德 HLK-W806 (三): 免按鍵自動下載和復位


目錄

免按鍵自動復位下載

如果只是了解如何使用, 看這部分就可以了. 在項目中將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;
    }
    ...
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM