Lianshengde HLK-W806: key free automatic download and reset

catalogue

Key free automatic reset Download

If you only know how to use it, just look at this part. Update the SDK to the latest version in the project, and find the file include / arch / xt804 / CSI in the SDK_ Config. H, change the value of the following line from 0 to 1

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

Then compile and burn to the development board according to the normal operation process. The subsequent burning can be downloaded automatically without pressing the key. It will be reset automatically before downloading and after downloading

be careful:

  1. This function is only applicable to the development and test phase, and cannot be used in the production environment
  2. This function (and the default printf printing) will occupy UART0. If your project needs to use UART0 to communicate with other devices, this function must be turned off

Function analysis of key free download

Instruction analysis of burning and downloading

In tools/W806/rules.mk

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

You can see that make flash executes compilation first and then calls wm_. Tool downloads fls files to the device according to the preset download port and baud rate. In the normal download process, you need to Reset the development board to enter the download mode, and then start the actual download. After the download, the development board will still be in the download mode. At this time, you need to Reset the development board to enter the normal mode, Run the user program. Now these two steps are completed manually by pressing the Reset key

Burn download reset code

In the above command, one parameter is - rs at, and the description of this parameter is

-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

The corresponding option of at is to use the at command to restart the device. There are two corresponding restart actions, namely, the two time points at which the Reset button needs to be pressed manually

Reset before downloading

For pre download reset, WM_ The processing in tool is

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 */

You can see WM_ The actual operation of the tool is to send at + Z \ R \ ninstruction through the serial port, and then wait 500ms to detect whether it is reset

Reset after download

For the reset after downloading, only the rts option is processed in the code. There is no action to use the at option here

...

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");
    }
}
...

Realization of burning automatic reset of W806

According to the above analysis, the automatic reset of W806 needs to be realized in two places, one before downloading and the other after downloading

Reset before downloading

Before downloading, the development board is still running in the normal mode. At this time, the serial port is controlled by the user program. If you need to respond to the serial port command, you need to add the RX interrupt and command judgment of serial port 0 in the user program. For this step, you can refer to the implementation of UART0 as printf printout in SDK

Add UART0 initialization

In platform / arch / xt804 / BSP / board_ An initialization code is added in init. C. when it is configured to be enabled, UART0 receiving interrupt is enabled

...
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 receiving interrupt response and command detection are added

Add a new component under platform/component to realize interrupt response and command detection in the 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

Reset after successful download

After the download is successful, the development board is still running in the download mode, so find the corresponding reset command in the download mode. This command is

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

Corresponding, in WM_ Add this command constant in tool. C

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

And processing logic for AT mode

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;
    }
    ...
}

Posted on Fri, 26 Nov 2021 17:02:41 -0500 by jjoske