Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Introduction

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Based on the overall plan: Renesas A4T1 standard OTA solution / reset functionBy adding file transfer functionality to the core project, all OTA tasks can be completed.This article is not difficult, but there is a lot of content and some pitfalls; it is a small comprehensive guide.Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

File Transfer Host

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Key Points for C# Host

First, addControlCAN.dll, then you can directly call the functions in the dll with pure code.

This way, you can develop the CAN box.

The host code does not need to change!

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Experimental Environment of This Article

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)No changes: JLINK + CAN box + 5V power supplyComplete OTA Project for Renesas A4T1 (Without Data Flash Version)

Lower Machine Work Steps

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)First, start from the core projectThen add flash operation code to both BOOT and APPThenAdd file transfer code to both BOOT and APPAnd it’s done!The APP projectrecords the filesize to dataflash after receiving the file information frame and then resets, that’s all.The BOOT projectinteracts with the host to handle file request frames/file content frames, finally records the bin file to code flash and clears dataflash, then resets.Complete OTA Project for Renesas A4T1 (Without Data Flash Version)It must be noted

I did a simple test

Found that dataflash is really difficult to operate.

It’s inexplicable and confusing.

I plan to spend time researching it later.

This article places the filesize marker in the last 8K of code flash.

#define APPLICATION_CONFIG_ADDRESS FLASH_HP_CF_BLOCK_7

/* 8 KB: 0x0000E000 – 0x0000FFFF */

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Record of Pitfalls

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Environmental Issues

It seems I encountered this problem in the IAR environment.

After I burned ALL.bin to A4T1

Then I operated to debug the APP project independently, everything was normal.

Then I operated to debug the BOOT project independently and found that it would erase all subsequent flash space to FFFFF, which is a troublesome point.

In the IAR environment, there are two buttons.

One is for programming and debugging, and the other is for just debugging; choose the latter.

I don’t know how to set it in E2STUDIO.

Fortunately, the functionality of this article is not complex, and I succeeded quickly.

In the future, placing the filesize marker in dataflash would be better.

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Points to Note for Code Flash Operations

The minimum write granularity of code flash is 128 bytes.

The actual performance is that if the parameter of R_FLASH_HP_Write – write num bytes, if you pass 4 or 64, it will crash; it must be a multiple of 128, such as 128 or 1024.

So for the APP project, prepare a global 128-byte array uint8_t g_src_uint8[128] to maintain the minimum write, for example, copy to the array before writing U32.

So for the BOOT project, the last packet received from the host may not be exactly 1024; wewill write 1024 bytes forcefully in the last packet.code_flash_write(addr,data,OTA_ONE_STEP); to ensure the write functionR_FLASH_HP_Write does not crash (or the host packs app.bin in advance to fill to a multiple of 1024; of course, the lower machine should standardize it, which is this article).

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Code flash operations are blocking!

Interrupts need to be disabled before and after!

No need for lower-level callbacks!

This article does not operate dataflash, sono lower-level callback functions are written.

Dataflash will be discussed later.

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Hidden Details:

BOOT and APP are both anchored to a specific address 0X20001000.

So even though they are two projects,

the host RTT-VIEW can see the logs of both BOOT and APP.

No need to switch addresses.

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

Software Records

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)The merge script is a single line cp.bat

D:\OTA\merge\a.exe D:\OTA\BOOT\Debug\BOOT.bin D:\OTA\APP\Debug\APP.bin D:\OTA\merge\ALL.binpause

Below is the code for comparison and reading.Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

BOOT Code

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

// RX needs to rely heavily on the protocol to specify LEN to capture a complete data packet
#include "hal_data.h"
FSP_CPP_HEADER void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/************************************************LOG**************************************/
/************************************************LOG**************************************/
/************************************************LOG**************************************/
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "SEGGER_RTT.h"
#define LOG(...)  SEGGER_RTT_printf(0 ,##__VA_ARGS__);
#define SHOWME    LOG("[%s]\r\n",__FUNCTION__);
void LOG_ARRY(char *name,uint8_t *A,uint8_t len){    SEGGER_RTT_printf(0, "%s ",name);    for (size_t i = 0; i < len; i++) {       SEGGER_RTT_printf(0, "0X%02X ",A[i]);    }    SEGGER_RTT_printf(0, "\r\n");}
void LOG_INIT(void){    SEGGER_RTT_Init();	R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);    SEGGER_RTT_printf(0, "Hello MY89003 BOOT ");    LOG("World\r\n");}
/************************************************LED**************************************/
/************************************************LED**************************************/
/************************************************LED**************************************/
void Led_Ctl(uint8_t flag){    if(flag){        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, BSP_IO_LEVEL_LOW);    }else{        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, BSP_IO_LEVEL_HIGH);    }}
void Led_Blink(void){    static char flag=0;    Led_Ctl(flag);    flag = !flag;}
/************************************************CAN**************************************/
/************************************************CAN**************************************/
/************************************************CAN**************************************/
#define APP_ERR_TRAP()     __asm("BKPT #0\n")  /* trap upon the error  */fsp_err_t err = FSP_SUCCESS;/* Flags to be set in Callback function */bool b_canfd_tx_complete = false;bool b_canfd_rx_complete = false;bool b_canfd_err_status = false;/* CANFD RX and TX variables */can_frame_t g_can_tx_frame;can_frame_t g_can_rx_frame;
#define SAY_MY_NAME 0X60
/* Variable to store rx frame status info*/can_info_t can_rx_info ={ .error_code  = 0, .error_count_receive = 0, .error_count_transmit = 0, .rx_fifo_status = 0, .rx_mb_status = 0, .status = 0,};
//* Set filter: only messages with ID 0X0060 will be accepted by my MCU, otherwise the lower-level CAN will discard it directly!const canfd_afl_entry_t p_canfd0_afl[CANFD_CFG_AFL_CH0_RULE_NUM] ={ {     .id =     {         .id         = SAY_MY_NAME,         .frame_type = CAN_FRAME_TYPE_DATA,         .id_mode    = CAN_ID_MODE_STANDARD,     },     .mask =     {         .mask_id         = 0x7F0,         .mask_frame_type = 0,         .mask_id_mode    = 1,     },     .destination =     {         .minimum_dlc = CANFD_MINIMUM_DLC_0,         .fifo_select_flags = CANFD_RX_FIFO_0,     }, },};
void CAN_Init(void){SHOWME    err = R_CANFD_Open(&g_canfd0_ctrl, &g_canfd0_cfg);    if(FSP_SUCCESS != err) {        APP_ERR_TRAP();    }}
// The PC is agreed to transmit a maximum of 1K of file each time#define OTA_ONE_STEP 1024
// Each packet of data has 8 bytes (T and L) in front of the data#define HEADLEN 8
// The final container for a frame of datauint8_t  gloableCANRxBuf[OTA_ONE_STEP+HEADLEN];uint16_t gloableCANRxBufLen=0;
// How to send? Slow sending// MCU needs to send out a frame of data container considering that MCUTX is not very large, a container of 200 is sufficient; each time the lower-level CAN sends a maximum of 8 bytes#define CAN_TX_BUFFER_LENGTH 200uint8_t  gloableCANTxBuf[CAN_TX_BUFFER_LENGTH];uint16_t gloableNumNeedTxCAN = 0;uint8_t  gloableNumTxedCAN=0;
// How to receive? Use protocol to identify when a frame is completely received// Once the LEN is detected, process it; otherwise, do nothingvoid receive_timer_idle_isr(void){    handle_gloableCANRxBuf();}
void CANSend_Max_8Byte(uint8_t* data,uint8_t len){// Note for parameters: len<=8    memcpy((uint8_t*)&g_can_tx_frame.data[0], data, len);    g_can_tx_frame.id               = SAY_MY_NAME;    g_can_tx_frame.id_mode          = CAN_ID_MODE_STANDARD;    g_can_tx_frame.type             = CAN_FRAME_TYPE_DATA;    g_can_tx_frame.data_length_code = len;//8;    g_can_tx_frame.options          = 0;    err = R_CANFD_Write(&g_canfd0_ctrl, 0, &g_can_tx_frame);    if(FSP_SUCCESS != err) {        APP_ERR_TRAP();    }}
void send_task(void){    if(gloableNumNeedTxCAN==0) return;// No work to do    if(b_canfd_tx_complete != true) return;// Not finished sending, refuse to execute, wait for the next cycle to execute
    // Determine whether to send 8 or 4    uint8_t numAllLeft = gloableNumNeedTxCAN - gloableNumTxedCAN;    uint8_t numNowSend = 0;    if (numAllLeft >= 8) numNowSend = 8;    else numNowSend = numAllLeft;
    // Actually send out    uint8_t arr[8] = {0};    for (int i = 0;i < numNowSend;i++) arr[i] = gloableCANTxBuf[i+ gloableNumTxedCAN];    CANSend_Max_8Byte(arr, numNowSend);    b_canfd_tx_complete = false;
    // Update the number of TX sent    gloableNumTxedCAN += numNowSend;
    LOG("gloableNumNeedTxCAN = %d gloableNumTxedCAN=%d  numNowSend=%d\r\n",gloableNumNeedTxCAN,gloableNumTxedCAN,numNowSend);    if(gloableNumTxedCAN == gloableNumNeedTxCAN) {        gloableNumNeedTxCAN = 0;        gloableNumTxedCAN = 0;    }}
/******************* OTA Structured Function for RX Reception Service **********************/typedef struct  _otaStartType{    uint32_t    reboot;    uint32_t    filesize;}otaStartType;otaStartType otaStart;typedef struct  _otaStartingType{    int     addr;    int     len;}otaStartingType;otaStartingType otaStarting;bool sendOtaAsk(otaStartingType info){ // Process the Nth packet, publish request, pack data T is hardcoded to 0002      char body[100]={0};     char head[8]={0};     char bodylen=0;
     bodylen=sprintf(body,"%s%d,%s%d}","{\"addr\":",   \\ info.addr,      \\ "\"len\":",     \\ info.len);  
     LOG("bodylen=%d [%s]\r\n",bodylen,body);
     char *type="0002";     sprintf(head,"%s%04X",type,bodylen);
     LOG("head=[%s]\r\n",head);
    // Asynchronously send    memset(gloableCANTxBuf,0,CAN_TX_BUFFER_LENGTH);    // Don't know why, the following assignment always shows an exception, body is tampered with!! Not studying for now    //memcpy(&gloableCANTxBuf[0],head,8);    //memcpy(&gloableCANTxBuf[8],body,len);    // Still honestly repack TLV    sprintf(gloableCANTxBuf,"%s%04X%s%d,%s%d}",type,bodylen,"{\"addr\":",   \\ info.addr,   \\ "\"len\":",  \\ info.len);  
     LOG("gloableCANTxBuf=[%s]\r\n",gloableCANTxBuf);
     // Trigger send task     gloableNumNeedTxCAN = (bodylen+8);     b_canfd_tx_complete = true;     return true; }
char saveOtaData(uint8_t *data, uint16_t len);void ota_config_clear(void);
#define BHEX(A) ((A) <= '9'? (A) - '0' : ((A) >= 'A' && (A) <= 'F'? (A) + 10 - 'A' : (A) + 10 - 'a'))#define TYPE  (BHEX(gloableCANRxBuf[0])<<12) | (BHEX(gloableCANRxBuf[1])<<8) | (BHEX(gloableCANRxBuf[2])<<4) | (BHEX(gloableCANRxBuf[3]))#define LEN   (BHEX(gloableCANRxBuf[4])<<12) | (BHEX(gloableCANRxBuf[5])<<8) | (BHEX(gloableCANRxBuf[6])<<4) | (BHEX(gloableCANRxBuf[7]))#define VALUE &gloableCANRxBuf[8];
// Not using LENvoid handle_gloableCANRxBuf(void){    int needLen = gloableCANRxBufLen-HEADLEN;    int trueLen = LEN;    //LOG("needLen=%d trueLen=%d\r\n",needLen,trueLen);
    if(trueLen != needLen) return;// Length mismatch
    // Copy out and print    char headStr[HEADLEN+1] = {0};    memcpy(headStr,gloableCANRxBuf,8);    LOG("head [%s] \r\n",headStr);
    uint8_t *body = VALUE;    // MCU is an absolute slave; upon receiving a message, it must respond with a message    switch (TYPE){        case 0x0001:            LOG("\r\nNEVER IN BOOT WORLD\r\n");            break;
        case 0x0003:            saveOtaData(body,LEN);// Record 1024 bytes            otaStarting.addr += otaStarting.len;            int file_leave = otaStart.filesize - otaStarting.addr;            LOG("\r\notaStart.filesize=%d otaStarting.addr=%d\r\n",otaStart.filesize,otaStarting.addr);
            otaStarting.len = (file_leave > OTA_ONE_STEP)?OTA_ONE_STEP:file_leave;            if(otaStarting.len){                sendOtaAsk(otaStarting);            }else{                LOG("\r\nfile recve done\r\n");                ota_config_clear();                LOG("\r\nclear flag\r\n");                NVIC_SystemReset();            }              break;
    }    gloableCANRxBufLen=0;}
/* Callback function from GUI interrupt service function; CAN received will run in here; CAN sent will also run in here*/void canfd0_callback(can_callback_args_t *p_args){    /* TODO: add your own code here */
    //LOG("0X%04X \r\n",p_args->event);    Led_Blink();    switch (p_args->event)    {        case CAN_EVENT_TX_COMPLETE:        {            b_canfd_tx_complete = true;            LOG_ARRY("CAN_EVENT_TX_COMPLETE",g_can_tx_frame.data,g_can_tx_frame.data_length_code);            break;        }        case CAN_EVENT_RX_COMPLETE:        {
            b_canfd_rx_complete = true;            memcpy(&g_can_rx_frame, &p_args->frame, sizeof(can_frame_t));            LOG_ARRY("CAN_EVENT_RX_COMPLETE",g_can_rx_frame.data,g_can_rx_frame.data_length_code);
            memcpy(&gloableCANRxBuf[gloableCANRxBufLen],g_can_rx_frame.data,g_can_rx_frame.data_length_code);
            gloableCANRxBufLen+=g_can_rx_frame.data_length_code;
            //LOG_ARRY("gloableCANRxBuf",gloableCANRxBuf,gloableCANRxBufLen);            break;        }        case CAN_EVENT_ERR_WARNING:             // Error warning event        case CAN_EVENT_ERR_PASSIVE:             // Error passive event        case CAN_EVENT_ERR_BUS_OFF:             // Error Bus Off event        case CAN_EVENT_BUS_RECOVERY:            // Bus recovery error event        case CAN_EVENT_MAILBOX_MESSAGE_LOST:    // Overwrite/overrun error event        case CAN_EVENT_ERR_BUS_LOCK:            // Bus lock detected (32 consecutive dominant bits).        case CAN_EVENT_ERR_CHANNEL:             // Channel error has occurred.        case CAN_EVENT_TX_ABORTED:              // Transmit abort event.        case CAN_EVENT_ERR_GLOBAL:              // Global error has occurred.        case CAN_EVENT_FIFO_MESSAGE_LOST:      // Transmit FIFO is empty.        case CAN_EVENT_TX_FIFO_EMPTY:           // Transmit FIFO is empty.        {            b_canfd_err_status = true;          // Set flag bit            break;        }    }}
/************************************************FLASH**************************************/
/************************************************FLASH**************************************/
/************************************************FLASH**************************************/
/* Code Flash */#define FLASH_HP_CF_BLOCK_SIZE_32KB (32*1024U) /* Block Size 32 KB */#define FLASH_HP_CF_BLOCK_SIZE_8KB (8*1024U) /* Block Size 8KB */
#define FLASH_HP_CF_BLOCK_0 (0x00000000U) /* 8 KB: 0x00000000 - 0x00001FFF */#define FLASH_HP_CF_BLOCK_1 (0x00002000U) /* 8 KB: 0x00002000 - 0x00003FFF */#define FLASH_HP_CF_BLOCK_2 (0x00004000U) /* 8 KB: 0x00004000 - 0x00005FFF */#define FLASH_HP_CF_BLOCK_3 (0x00006000U) /* 8 KB: 0x00006000 - 0x00007FFF */#define FLASH_HP_CF_BLOCK_4 (0x00008000U) /* 8 KB: 0x00008000 - 0x00009FFF */#define FLASH_HP_CF_BLOCK_5 (0x0000A000U) /* 8 KB: 0x0000A000 - 0x0000BFFF */#define FLASH_HP_CF_BLOCK_6 (0x0000C000U) /* 8 KB: 0x0000C000 - 0x0000DFFF */#define FLASH_HP_CF_BLOCK_7 (0x0000E000U) /* 8 KB: 0x0000E000 - 0x0000FFFF */#define FLASH_HP_CF_BLOCK_8 (0x00010000U) /* 32 KB: 0x00010000 - 0x00017FFF */#define FLASH_HP_CF_BLOCK_9 (0x00018000U) /* 32 KB: 0x00018000 - 0x0001FFFF */
/* Data Flash */#define FLASH_HP_DF_BLOCK_SIZE_64B (64U) /* Block Size 64 Byte */#define FLASH_HP_DF_BLOCK_0 (0x08000000U) /* Size 64 B: 0x08000000U - 0x0800003F */#define FLASH_HP_DF_BLOCK_1 (0x08000040U) /* Size 64 B: 0x08000040U - 0x0800007F */#define FLASH_HP_DF_BLOCK_2 (0x08000080U) /* Size 64 B: 0x08000080U - 0x080000BF */#define FLASH_HP_DF_BLOCK_3 (0x080000C0U) /* Size 64 B: 0x080000C0U - 0x080000FF */#define FLASH_HP_DF_BLOCK_63 (0x08000FC0U) /* Size 64 B: 0x08000FCOU - 0x08000FFF */#define FLASH_HP_DF_BLOCK_64 (0x08001000U) /* Size 64 B: 0x08001000U - 0x0800103F */
// Data flash requires callbacks, is a state machine, needs interrupts, needs callbacks // Code flash is blocking, do not need interrupts, do not need callbacks // This article does not use data flash, so no need to write callback functionsvoid my_flash_callback(flash_callback_args_t *p_args){}
void flash_init(void){    /* Open the flash lp instance. */    err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);    assert(FSP_SUCCESS == err);}
#define             APPLICATION_CONFIG_ADDRESS    FLASH_HP_CF_BLOCK_7   /* 8 KB: 0x0000E000 - 0x0000FFFF */
// This article uses the last 8K of code flash; erasing it will make it all 0XFFFFFFFFvoid x_flash_erase(void){     flash_result_t blank_check_result;
    __disable_irq();
    err = R_FLASH_HP_Erase(&g_flash0_ctrl, APPLICATION_CONFIG_ADDRESS, 1);    assert(FSP_SUCCESS == err);    err = R_FLASH_HP_BlankCheck(&g_flash0_ctrl, APPLICATION_CONFIG_ADDRESS, FLASH_HP_CF_BLOCK_SIZE_8KB, &blank_check_result);    assert(FSP_SUCCESS == err);    assert(FLASH_RESULT_BLANK == blank_check_result);
    __enable_irq();}
// This article uses the last 8K of code flashvoid x_flash_read(void){     uint8_t  four_u8[4]={0};    memcpy(four_u8, (uint8_t *) APPLICATION_CONFIG_ADDRESS, 4);    LOG_ARRY("four_u8",four_u8,4);    otaStart.filesize = four_u8[3]<<24|four_u8[2]<<16|four_u8[1]<<8|four_u8[0];    LOG("otaStart.filesize=%d",otaStart.filesize);}
// Read U32 and assign otaStart.filesizevoid ota_config_read(void){     x_flash_read();}
// Clear the marker for the BOOT-APP bondvoid ota_config_clear(void){     x_flash_erase();}
// Erase 64K of APP, no loop, just do 32K once and then 32K oncevoid code_flash_erase(void){    flash_result_t blank_check_result;
    /* Disable interrupts to prevent vector table access while code flash is in P/E mode. */    __disable_irq();
    err = R_FLASH_HP_Erase(&g_flash0_ctrl, FLASH_HP_CF_BLOCK_8, 1);    assert(FSP_SUCCESS == err);    err = R_FLASH_HP_BlankCheck(&g_flash0_ctrl, FLASH_HP_CF_BLOCK_8, FLASH_HP_CF_BLOCK_SIZE_32KB, &blank_check_result);    assert(FSP_SUCCESS == err);    assert(FLASH_RESULT_BLANK == blank_check_result);
    err = R_FLASH_HP_Erase(&g_flash0_ctrl, FLASH_HP_CF_BLOCK_9, 1);    assert(FSP_SUCCESS == err);    err = R_FLASH_HP_BlankCheck(&g_flash0_ctrl, FLASH_HP_CF_BLOCK_9, FLASH_HP_CF_BLOCK_SIZE_32KB, &blank_check_result);    assert(FSP_SUCCESS == err);    assert(FLASH_RESULT_BLANK == blank_check_result);
    /* Enable interrupts after code flash operations are complete. */    __enable_irq();}
// Address write 1Kvoid code_flash_write(uint32_t addr ,uint8_t *data, uint16_t len){
    __disable_irq();
    /* Write 32 bytes to the first block of data flash. */    // Write data, 4 8-bit data [but parameter 3 must be a multiple of 128, such as 128 or 1024 (128 is the MIN granularity)]    err = R_FLASH_HP_Write(&g_flash0_ctrl, (uint32_t) data, addr, len);    assert(FSP_SUCCESS == err);
    __enable_irq();
    // Close Flash controller    // R_FLASH_HP_Close(&g_flash0_ctrl);}
/************************************************JUMP**************************************/
/************************************************JUMP**************************************/
/************************************************JUMP**************************************/
typedef  void       (*pFunction)(void);
#define             APPLICATION_DATA_ADDRESS    FLASH_HP_CF_BLOCK_8
void jump_application( void ){    uint32_t JumpAddress;    pFunction Jump_To_Application;
    /* Jump to user application */    JumpAddress = *(__IO uint32_t*) (APPLICATION_DATA_ADDRESS + 4);    Jump_To_Application = (pFunction) JumpAddress;
    __set_MSPLIM(0);    SCB->VTOR = ((int)APPLICATION_DATA_ADDRESS & 0x1FFFFF80);    __DSB();
    /* Initialize user application's Stack Pointer */    __set_MSP(*(__IO uint32_t*) APPLICATION_DATA_ADDRESS);    Jump_To_Application();}
char saveOtaData(uint8_t *data, uint16_t len){    LOG("saveOtaData len=%d\r\n",len);    LOG_ARRY("binFile",data,len);    uint32_t addr = (APPLICATION_DATA_ADDRESS + otaStarting.addr);    code_flash_write(addr,data,OTA_ONE_STEP);// Note: here must write 1024 forcefully because A4T1 requires granularity; if not a multiple of 128, it will crash; here directly write 1024    return 0;}/*******************************************************************************************************************//** * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function * is called by main() when no RTOS is used. **********************************************************************************************************************/void hal_entry(void){    /* TODO: add your own code here */    LOG_INIT();    CAN_Init();    flash_init();    ota_config_read();    if(0XFFFFFFFF==otaStart.filesize){        jump_application();        return;    }// If it enters IF, it goes directly to APP, ending the process// If it can go down, it enters the BOOT to receive firmware process
// 1> No backup firmware, collectively erase all 32K+32K   code_flash_erase();// 2> Actively send the first file request    otaStarting.addr=0;    otaStarting.len=(OTA_ONE_STEP>otaStart.filesize)?(otaStart.filesize):(OTA_ONE_STEP);    sendOtaAsk(otaStarting);// 3> Start TXRX process, loop to obtain firmware from the host    while(1){        R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);        receive_timer_idle_isr();// Professional RX--independent task        send_task();// Professional TX--independent task    }#if BSP_TZ_SECURE_BUILD    /* Enter non-secure code */    R_BSP_NonSecureEnter();#endif}
/*******************************************************************************************************************//** * This function is called at various points during the startup process.  This implementation uses the event that is * called right before main() to set up the pins. * * @param[in]  event    Where at in the start up process the code is currently at **********************************************************************************************************************/void R_BSP_WarmStart(bsp_warm_start_event_t event){    if (BSP_WARM_START_RESET == event)    {#if BSP_FEATURE_FLASH_LP_VERSION != 0
        /* Enable reading from data flash. */        R_FACI_LP->DFLCTL = 1U;
        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */#endif    }
    if (BSP_WARM_START_POST_C == event)    {        /* C runtime environment and system clocks are setup. */
        /* Configure pins. */        R_IOPORT_Open (&g_ioport_ctrl, &IOPORT_CFG_NAME);    }}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADERBSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable (){
}FSP_CPP_FOOTER
#endif

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

APP Code

Complete OTA Project for Renesas A4T1 (Without Data Flash Version)

// RX needs to rely heavily on the protocol to specify LEN to capture a complete data packet
#include "hal_data.h"
FSP_CPP_HEADER void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/************************************************LOG**************************************/
/************************************************LOG**************************************/
/************************************************LOG**************************************/
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "SEGGER_RTT.h"
#define LOG(...)  SEGGER_RTT_printf(0 ,##__VA_ARGS__);
#define SHOWME    LOG("[%s]\r\n",__FUNCTION__);
void LOG_ARRY(char *name,uint8_t *A,uint8_t len){    SEGGER_RTT_printf(0, "%s ",name);    for (size_t i = 0; i < len; i++) {       SEGGER_RTT_printf(0, "0X%02X ",A[i]);    }    SEGGER_RTT_printf(0, "\r\n");}
void LOG_INIT(void){    SEGGER_RTT_Init();    R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);    SEGGER_RTT_printf(0, "Hello MY89003 APP");    LOG("World\r\n");}
/************************************************LED**************************************/
/************************************************LED**************************************/
/************************************************LED**************************************/
void Led_Ctl(uint8_t flag){    if(flag){        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, BSP_IO_LEVEL_LOW);    }else{        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07, BSP_IO_LEVEL_HIGH);    }}
void Led_Blink(void){    static char flag=0;    Led_Ctl(flag);    flag = !flag;}
/************************************************CAN**************************************/
/************************************************CAN**************************************/
/************************************************CAN**************************************/
#define APP_ERR_TRAP()     __asm("BKPT #0\n")  /* trap upon the error  */fsp_err_t err = FSP_SUCCESS;/* Flags to be set in Callback function */bool b_canfd_tx_complete = false;bool b_canfd_rx_complete = false;bool b_canfd_err_status = false;/* CANFD RX and TX variables */can_frame_t g_can_tx_frame;can_frame_t g_can_rx_frame;
#define SAY_MY_NAME 0X60
/* Variable to store rx frame status info*/can_info_t can_rx_info ={ .error_code  = 0, .error_count_receive = 0, .error_count_transmit = 0, .rx_fifo_status = 0, .rx_mb_status = 0, .status = 0,};
//* Set filter: only messages with ID 0X0060 will be accepted by my MCU, otherwise the lower-level CAN will discard it directly!const canfd_afl_entry_t p_canfd0_afl[CANFD_CFG_AFL_CH0_RULE_NUM] ={ {     .id =     {         .id         = SAY_MY_NAME,         .frame_type = CAN_FRAME_TYPE_DATA,         .id_mode    = CAN_ID_MODE_STANDARD,     },     .mask =     {         .mask_id         = 0x7F0,         .mask_frame_type = 0,         .mask_id_mode    = 1,     },     .destination =     {         .minimum_dlc = CANFD_MINIMUM_DLC_0,         .fifo_select_flags = CANFD_RX_FIFO_0,     }, },};
void CAN_Init(void){SHOWME    err = R_CANFD_Open(&g_canfd0_ctrl, &g_canfd0_cfg);    if(FSP_SUCCESS != err) {        APP_ERR_TRAP();    }}
// The PC is agreed to transmit a maximum of 1K of file each time#define OTA_ONE_STEP 1024
// Each packet of data has 8 bytes (T and L) in front of the data#define HEADLEN 8
// The final container for a frame of datauint8_t  gloableCANRxBuf[OTA_ONE_STEP+HEADLEN];uint16_t gloableCANRxBufLen=0;
// How to send? Slow sending// MCU needs to send out a frame of data container considering that MCUTX is not very large, a container of 200 is sufficient; each time the lower-level CAN sends a maximum of 8 bytes#define CAN_TX_BUFFER_LENGTH 200uint8_t  gloableCANTxBuf[CAN_TX_BUFFER_LENGTH];uint16_t gloableNumNeedTxCAN = 0;uint8_t  gloableNumTxedCAN=0;
// How to receive? Use protocol to identify when a frame is completely received// Once the LEN is detected, process it; otherwise, do nothingvoid receive_timer_idle_isr(void){    handle_gloableCANRxBuf();}
void CANSend_Max_8Byte(uint8_t* data,uint8_t len){// Note for parameters: len<=8    memcpy((uint8_t*)&g_can_tx_frame.data[0], data, len);    g_can_tx_frame.id               = SAY_MY_NAME;    g_can_tx_frame.id_mode          = CAN_ID_MODE_STANDARD;    g_can_tx_frame.type             = CAN_FRAME_TYPE_DATA;    g_can_tx_frame.data_length_code = len;//8;    g_can_tx_frame.options          = 0;    err = R_CANFD_Write(&g_canfd0_ctrl, 0, &g_can_tx_frame);    if(FSP_SUCCESS != err) {        APP_ERR_TRAP();    }}
void send_task(void){    if(gloableNumNeedTxCAN==0) return;// No work to do    if(b_canfd_tx_complete != true) return;// Not finished sending, refuse to execute, wait for the next cycle to execute
    // Determine whether to send 8 or 4    uint8_t numAllLeft = gloableNumNeedTxCAN - gloableNumTxedCAN;    uint8_t numNowSend = 0;    if (numAllLeft >= 8) numNowSend = 8;    else numNowSend = numAllLeft;
    // Actually send out    uint8_t arr[8] = {0};    for (int i = 0;i < numNowSend;i++) arr[i] = gloableCANTxBuf[i+ gloableNumTxedCAN];    CANSend_Max_8Byte(arr, numNowSend);    b_canfd_tx_complete = false;
    // Update the number of TX sent    gloableNumTxedCAN += numNowSend;
    LOG("gloableNumNeedTxCAN = %d gloableNumTxedCAN=%d  numNowSend=%d\r\n",gloableNumNeedTxCAN,gloableNumTxedCAN,numNowSend);    if(gloableNumTxedCAN == gloableNumNeedTxCAN) {        gloableNumNeedTxCAN = 0;        gloableNumTxedCAN = 0;    }}
/******************* OTA Structured Function for RX Reception Service **********************/typedef struct  _otaStartType{    uint32_t    reboot;    uint32_t    filesize;}otaStartType;otaStartType otaStart;typedef struct  _otaStartingType{    int     addr;    int     len;}otaStartingType;otaStartingType otaStarting;bool sendOtaAsk(otaStartingType info){ // Process the Nth packet, publish request, pack data T is hardcoded to 0002      char body[100]={0};     char head[8]={0};     char bodylen=0;
     bodylen=sprintf(body,"%s%d,%s%d}","{\"addr\":",   \\ info.addr,      \\ "\"len\":",     \\ info.len);  
     LOG("bodylen=%d [%s]\r\n",bodylen,body);
     char *type="0002";     sprintf(head,"%s%04X",type,bodylen);
     LOG("head=[%s]\r\n",head);
    // Asynchronously send    memset(gloableCANTxBuf,0,CAN_TX_BUFFER_LENGTH);    // Don't know why, the following assignment always shows an exception, body is tampered with!! Not studying for now    //memcpy(&gloableCANTxBuf[0],head,8);    //memcpy(&gloableCANTxBuf[8],body,len);    // Still honestly repack TLV    sprintf(gloableCANTxBuf,"%s%04X%s%d,%s%d}",type,bodylen,"{\"addr\":",   \\ info.addr,   \\ "\"len\":",  \\ info.len);  
     LOG("gloableCANTxBuf=[%s]\r\n",gloableCANTxBuf);
     // Trigger send task     gloableNumNeedTxCAN = (bodylen+8);     b_canfd_tx_complete = true;     return true; }
char saveOtaData(uint8_t *data, uint16_t len);void ota_config_clear(void);
#define BHEX(A) ((A) <= '9'? (A) - '0' : ((A) >= 'A' && (A) <= 'F'? (A) + 10 - 'A' : (A) + 10 - 'a'))#define TYPE  (BHEX(gloableCANRxBuf[0])<<12) | (BHEX(gloableCANRxBuf[1])<<8) | (BHEX(gloableCANRxBuf[2])<<4) | (BHEX(gloableCANRxBuf[3]))#define LEN   (BHEX(gloableCANRxBuf[4])<<12) | (BHEX(gloableCANRxBuf[5])<<8) | (BHEX(gloableCANRxBuf[6])<<4) | (BHEX(gloableCANRxBuf[7]))#define VALUE &gloableCANRxBuf[8];
// Not using LENvoid handle_gloableCANRxBuf(void){    int needLen = gloableCANRxBufLen-HEADLEN;    int trueLen = LEN;    //LOG("needLen=%d trueLen=%d\r\n",needLen,trueLen);
    if(trueLen != needLen) return;// Length mismatch
    // Copy out and print    char headStr[HEADLEN+1] = {0};    memcpy(headStr,gloableCANRxBuf,8);    LOG("head [%s] \r\n",headStr);
    uint8_t *body = VALUE;    // MCU is an absolute slave; upon receiving a message, it must respond with a message    switch (TYPE){        case 0x0001:// Received file information frame A: record file size B: RESET            LOG("body=%s\r\n",body);/* body={   "filesize": 130012,   "md5": "XXX",   "ver": 4}*/            saveOtaCfg(body);            NVIC_SystemReset();            break;
        case 0x0003:            LOG("\r\nNEVER IN APP WORLD\r\n");            break;
    }    gloableCANRxBufLen=0;}
/* Callback function from GUI interrupt service function; CAN received will run in here; CAN sent will also run in here*/void canfd0_callback(can_callback_args_t *p_args){    /* TODO: add your own code here */
    //LOG("0X%04X \r\n",p_args->event);    Led_Blink();    switch (p_args->event)    {        case CAN_EVENT_TX_COMPLETE:        {            b_canfd_tx_complete = true;            LOG_ARRY("CAN_EVENT_TX_COMPLETE",g_can_tx_frame.data,g_can_tx_frame.data_length_code);            break;        }        case CAN_EVENT_RX_COMPLETE:        {
            b_canfd_rx_complete = true;            memcpy(&g_can_rx_frame, &p_args->frame, sizeof(can_frame_t));            LOG_ARRY("CAN_EVENT_RX_COMPLETE",g_can_rx_frame.data,g_can_rx_frame.data_length_code);
            memcpy(&gloableCANRxBuf[gloableCANRxBufLen],g_can_rx_frame.data,g_can_rx_frame.data_length_code);
            gloableCANRxBufLen+=g_can_rx_frame.data_length_code;
            //LOG_ARRY("gloableCANRxBuf",gloableCANRxBuf,gloableCANRxBufLen);            break;        }        case CAN_EVENT_ERR_WARNING:             // Error warning event        case CAN_EVENT_ERR_PASSIVE:             // Error passive event        case CAN_EVENT_ERR_BUS_OFF:             // Error Bus Off event        case CAN_EVENT_BUS_RECOVERY:            // Bus recovery error event        case CAN_EVENT_MAILBOX_MESSAGE_LOST:    // Overwrite/overrun error event        case CAN_EVENT_ERR_BUS_LOCK:            // Bus lock detected (32 consecutive dominant bits).        case CAN_EVENT_ERR_CHANNEL:             // Channel error has occurred.        case CAN_EVENT_TX_ABORTED:              // Transmit abort event.        case CAN_EVENT_ERR_GLOBAL:              // Global error has occurred.        case CAN_EVENT_FIFO_MESSAGE_LOST:      // Transmit FIFO is empty.        case CAN_EVENT_TX_FIFO_EMPTY:           // Transmit FIFO is empty.        {            b_canfd_err_status = true;          // Set flag bit            break;        }    }}
/************************************************FLASH**************************************/
/************************************************FLASH**************************************/
/************************************************FLASH**************************************/
/* Code Flash */#define FLASH_HP_CF_BLOCK_SIZE_32KB (32*1024U) /* Block Size 32 KB */#define FLASH_HP_CF_BLOCK_SIZE_8KB (8*1024U) /* Block Size 8KB */
#define FLASH_HP_CF_BLOCK_0 (0x00000000U) /* 8 KB: 0x00000000 - 0x00001FFF */#define FLASH_HP_CF_BLOCK_1 (0x00002000U) /* 8 KB: 0x00002000 - 0x00003FFF */#define FLASH_HP_CF_BLOCK_2 (0x00004000U) /* 8 KB: 0x00004000 - 0x00005FFF */#define FLASH_HP_CF_BLOCK_3 (0x00006000U) /* 8 KB: 0x00006000 - 0x00007FFF */#define FLASH_HP_CF_BLOCK_4 (0x00008000U) /* 8 KB: 0x00008000 - 0x00009FFF */#define FLASH_HP_CF_BLOCK_5 (0x0000A000U) /* 8 KB: 0x0000A000 - 0x0000BFFF */#define FLASH_HP_CF_BLOCK_6 (0x0000C000U) /* 8 KB: 0x0000C000 - 0x0000DFFF */#define FLASH_HP_CF_BLOCK_7 (0x0000E000U) /* 8 KB: 0x0000E000 - 0x0000FFFF */#define FLASH_HP_CF_BLOCK_8 (0x00010000U) /* 32 KB: 0x00010000 - 0x00017FFF */#define FLASH_HP_CF_BLOCK_9 (0x00018000U) /* 32 KB: 0x00018000 - 0x0001FFFF */
/* Data Flash */#define FLASH_HP_DF_BLOCK_SIZE_64B (64U) /* Block Size 64 Byte */#define FLASH_HP_DF_BLOCK_0 (0x08000000U) /* Size 64 B: 0x08000000U - 0x0800003F */#define FLASH_HP_DF_BLOCK_1 (0x08000040U) /* Size 64 B: 0x08000040U - 0x0800007F */#define FLASH_HP_DF_BLOCK_2 (0x08000080U) /* Size 64 B: 0x08000080U - 0x080000BF */#define FLASH_HP_DF_BLOCK_3 (0x080000C0U) /* Size 64 B: 0x080000C0U - 0x080000FF */#define FLASH_HP_DF_BLOCK_63 (0x08000FC0U) /* Size 64 B: 0x08000FCOU - 0x08000FFF */#define FLASH_HP_DF_BLOCK_64 (0x08001000U) /* Size 64 B: 0x08001000U - 0x0800103F */
// Note: The minimum write granularity of code flash is 128 bytes // If the parameter passed to R_FLASH_HP_Write is 4 or 64, it will crash! // So here prepare a 128 array to maintain the minimum write volatile uint8_t  g_src_uint8[128]={0};
// Data flash requires callbacks, is a state machine, needs interrupts, needs callbacks // Code flash is blocking, do not need interrupts, do not need callbacks // This article does not use data flash, so no need to write callback functionsvoid my_flash_callback(flash_callback_args_t *p_args){}
void flash_init(void){    /* Open the flash lp instance. */    err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);    assert(FSP_SUCCESS == err);}
#define APPLICATION_CONFIG_ADDRESS                FLASH_HP_CF_BLOCK_7   /* 8 KB: 0x0000E000 - 0x0000FFFF */
// This article uses the last 8K of code flash; erasing it will make it all 0XFFFFFFFF in writing a U32 void x_flash_write(void){          flash_result_t blank_check_result;
    __disable_irq();
    err = R_FLASH_HP_Erase(&g_flash0_ctrl, APPLICATION_CONFIG_ADDRESS, 1);    assert(FSP_SUCCESS == err);    err = R_FLASH_HP_BlankCheck(&g_flash0_ctrl, APPLICATION_CONFIG_ADDRESS, FLASH_HP_CF_BLOCK_SIZE_8KB, &blank_check_result);    assert(FSP_SUCCESS == err);    assert(FLASH_RESULT_BLANK == blank_check_result);
    memcpy(g_src_uint8, (uint8_t *)&otaStart.filesize,4);    err = R_FLASH_HP_Write(&g_flash0_ctrl, (uint32_t) g_src_uint8, APPLICATION_CONFIG_ADDRESS, 128);    assert(FSP_SUCCESS == err);
    __enable_irq();}
// Write U32 and write otaStart.filesize to flash as a bond void ota_config_write(void){     x_flash_write();}
/*******************************************************************************************************************//** * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function * is called by main() when no RTOS is used. **********************************************************************************************************************/void hal_entry(void){    /* TODO: add your own code here */    LOG_INIT();    CAN_Init();    flash_init();    while(1){#if 1        R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_MILLISECONDS);        receive_timer_idle_isr();// Professional RX--independent task 【This APP does not have TX functionality】#else            R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);        receive_timer_idle_isr();        Led_Blink();#endif            }#if BSP_TZ_SECURE_BUILD    /* Enter non-secure code */    R_BSP_NonSecureEnter();#endif}
/*******************************************************************************************************************//** * This function is called at various points during the startup process.  This implementation uses the event that is * called right before main() to set up the pins. * * @param[in]  event    Where at in the start up process the code is currently at **********************************************************************************************************************/void R_BSP_WarmStart(bsp_warm_start_event_t event){    if (BSP_WARM_START_RESET == event)    {#if BSP_FEATURE_FLASH_LP_VERSION != 0
        /* Enable reading from data flash. */        R_FACI_LP->DFLCTL = 1U;
        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */#endif    }
    if (BSP_WARM_START_POST_C == event)    {        /* C runtime environment and system clocks are setup. */
        /* Configure pins. */        R_IOPORT_Open (&g_ioport_ctrl, &IOPORT_CFG_NAME);    }}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADERBSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable (){
}FSP_CPP_FOOTER
#endif

Leave a Comment