Renesas A4T1 Internal Flash Operations – Unified API Layer Packaging

Introduction

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThis article is a small explosion worth revisiting in the future. First, we will thoroughly understand the code flash and data flash of the A4T1 platform and provide a unified encapsulated function for operations.(We will not touch the OTP area as it is very dangerous according to official warnings.) In the future, operations on other platform flashes, such as Winbond SPI FLASH, can also be done this way.Then we will introduce a common embedded issue: changing blocking operations to non-blocking ones.Using a state machine + callback to turn it into asynchronous task execution.Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

Prerequisite Knowledge

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

Renesas A4T1 Internal Flash Operations

The code flash address is shown in the figure below, totaling 128K, which is (8*8K) + (2*32K).

The red box in the figure below is the experimental address for this article.

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThe data flash address is shown in the figure below, totaling 4K, which is (64*64 bytes).

The red box in the figure below is the experimental address for this article.

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingDirect library function operations on code flash.Direct library function operations on data flash.The test environment for this article is the above-mentionedD:\OTA\BOOT project The hardware only needs to connect MY89003 with JLINK.

Encapsulated Functions

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThree library functions will be encapsulated once, meaning that the APP will no longer call the library functions but will call the encapsulated functions as follows:

jq_ra4t1_inner_flash_read

jq_ra4t1_inner_flash_write

jq_ra4t1_inner_flash_erase

It must be noted that the three functions opened this time can be considered to have a low level of abstraction (they are blocking). They only solve the universal write issue. Further improvements can be made to turn them into asynchronous calls (non-blocking).

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

From memcpy to jq_ra4t1_inner_flash_read

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingRenesas A4T1 Internal Flash Operations - Unified API Layer Packaging

From R_FLASH_HP_Erase to jq_ra4t1_inner_flash_erase

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

From R_FLASH_HP_Write to jq_ra4t1_inner_flash_write

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

The blue box indicates blocking. It can be omitted in actual tests, but logically it is better to write it.

Real Machine Testing

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

Open the above-mentionedD:\OTA\BOOT project

Modify according to the figure below. The complete code is at the end of the article.

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingFirst, test code flash successfully (testing the last 8K block).What is granularity? Two types>Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

> One is Erase, which means erasing 8K or 32K (after erasing, it is expected to be all F, but not necessarily).

> The other is Write, which means calling R_FLASH_HP_Write must pass parameters that are multiples of 128.

This troublesome matter is encapsulated in jq_ra4t1_inner_flash_write.

Then test data flash, which fails (testing the first 64-byte block).This was actually expected Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingBecause it has been known that data flash cannot disable interrupts. It requires interrupts + callbacks to work together. The test code (at the end of the article) is in the style of code flash, which is blocking and disables interrupts, so the failure is quite normal!To unify the style, we found an astonishing setting! Renesas is really meticulous!The key is shown in the figure below: Disable the background operation mode of data flash.Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThis does not allow data flash to run in the background, which means it will work in a blocking synchronous mode, just like code flash.What is granularity? Two types>Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

> One is Erase, which means erasing 64 bytes (after erasing, it is expected to be all F, but not necessarily).

> The other is Write, which means calling R_FLASH_HP_Write must pass parameters that are multiples of 4.

This troublesome matter is encapsulated in jq_ra4t1_inner_flash_write.

Followed Follow Replay Share Like Watch MoreEngineer Jinhua

0/0

00:00/04:26Progress bar, 0 percentPlay00:00/04:2604:26Fullscreen Playing at 0.5x speed 0.5x 0.75x 1.0x 1.5x 2.0x HD Smooth

Continue Watching

Renesas A4T1 Internal Flash Operations – Unified API Layer Packaging

Reprint, Renesas A4T1 Internal Flash Operations – Unified API Layer PackagingEngineer JinhuaAdded to Top StoriesEnter comment Video Details

Summary

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThis article has completed the encapsulation of library functions (mainly writing).And the operation style is unified (mainly the data flash style should be the same as code flash).Please compare the code at the end of the article.The current similar effect of this article is the flash universal write function.Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingRenesas A4T1 Internal Flash Operations - Unified API Layer Packaging

Future Upgrade Plans

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingThe situation is as follows: The effect demonstrated in this article is that writing flash is blocking.

However, in many scenarios, the APP does not want blocking due to real-time requirements.

For example, can you write flash in an interrupt?

It is not possible to call the encapsulated functions in this article because they are blocking! How to solve this?

Please see the topic #Asynchronous

Transform synchronous calls into asynchronous calls – then use mpsc.h to write flash.

Resolve the issue of the timer linked list not being able to printf.

This article can also be modified accordingly.

Moreover, the code below has already been pre-embedded with callbacks.

The main idea is:

> Create a task A that runs a state machine. If there is data in the FIFO, it works; if there is no data, it rests.

> The APP or interrupt needs to write flash by throwing data or seq into the FIFO.

> When task A’s state machine completes a data or seq, it will callback to notify the APP.

This article will not practice this for now, and currently, it is also a bare metal connection without opening the hardware timer, which is inconvenient to say.

Renesas A4T1 Internal Flash Operations - Unified API Layer Packaging

In simple terms,

After the modification, the exposed API functions

are no longer library functions

nor the three functions of this article

but rather an API function that you abstract and encapsulate one more layer, which is asynchronous and non-blocking!

Code Display

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingRenesas A4T1 Internal Flash Operations - Unified API Layer PackagingCode for testing code flash

typedef void (*jq_flash_complete_callback_t)(void *user_data, int result);

 void flash_init(void){    /* Open the flash lp instance. */    err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);    assert(FSP_SUCCESS == err);}
/* * @param rAddr read address * @param rBuf read buffer * @param rLen read len * @param cb read complete callback function * @param user_data user data * @return int 0 success, other failed */ static int jq_ra4t1_inner_flash_read (  size_t rAddr,                                          void *rBuf,                                          size_t rLen,                                         jq_flash_complete_callback_t cb,                                         void *user_data) {
     memcpy (rBuf, rAddr, rLen);     if (cb) cb (user_data,0);
     return 0; }


/** * @brief flash write function *  *  * @param wAddr write address * @param wBuf write buffer * @param wLen write len * @param cb write complete callback function * @param user_data user data * @return int 0 success, other failed */static int jq_ra4t1_inner_flash_write ( size_t wAddr,                                         void *wBuf,                                         size_t wLen,                                        jq_flash_complete_callback_t cb,                                        void *user_data){    int err = 0;    int i = 0;    uint32_t programCount;    uint32_t programEndLen;    uint32_t off;    uint32_t len = 0;    flash_status_t status;
    #define MIN_WRITE_NUM 128    uint8_t alignBuf[MIN_WRITE_NUM];
    /** 128byte align */    programCount = wLen / MIN_WRITE_NUM;    programEndLen = wLen % MIN_WRITE_NUM;    off = 0;    __disable_irq();    if (programCount)    {        len = programCount * MIN_WRITE_NUM;//len must be a multiple of MIN_WRITE_NUM!        err = R_FLASH_HP_Write(&g_flash0_ctrl, wBuf, wAddr, len);

/*  Actually, it can be omitted. Wait until the current flash operation completes. */do	{        err = R_FLASH_HP_StatusGet(&g_flash0_ctrl, &status);    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));

        off += len;    }
    if ((err == 0) && programEndLen)    {        len = MIN_WRITE_NUM;//len must be a multiple of MIN_WRITE_NUM!        memcpy (alignBuf,wBuf + off,programEndLen);        err = R_FLASH_HP_Write(&g_flash0_ctrl, alignBuf, wAddr + off, len);
/*  Actually, it can be omitted. Wait until the current flash operation completes. */do	{        err = R_FLASH_HP_StatusGet(&g_flash0_ctrl, &status);    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));
    }    __enable_irq();    if (0 == err)    {        if (cb) cb(user_data,0);        return 0;    }
}


/** * @brief flash erase function *  *  * @param wAddr erase address * @param wLen erase len * @param cb write complete callback function * @param user_data user data * @return int 0 success, other failed */static int jq_ra4t1_inner_flash_erase(  size_t eAddr,                                         size_t eLen,                                        jq_flash_complete_callback_t cb,                                        void *user_data){    int err = -1;    uint8_t block_num; 
    block_num = (eLen + FLASH_HP_CF_BLOCK_SIZE_8KB - 1) / FLASH_HP_CF_BLOCK_SIZE_8KB;    LOG("jq_ra4t1_inner_flash_erase  block_num=%d\r\n",block_num);    __disable_irq();    err = R_FLASH_HP_Erase( &g_flash0_ctrl, (eAddr / FLASH_HP_CF_BLOCK_SIZE_8KB) * FLASH_HP_CF_BLOCK_SIZE_8KB, block_num);    __enable_irq();    if (0 == err)    {        if (cb) cb(user_data,0);        return 0;    }
    return err;}


void x_callback (void *user_data, int result){    LOG("x_callback result=%d\r\n",result);}
uint8_t  g_read_uint8[128]={0};uint8_t  g_write_uint8[4]={0x11,0x22,0x33,0x44};void flash_test(void){
#define TEST_ADDRESS    FLASH_HP_CF_BLOCK_7//Initialize OPEN        flash_init();//Read        jq_ra4t1_inner_flash_read (TEST_ADDRESS,             g_read_uint8,             128,            x_callback,            NULL);
        LOG_ARRY("g_src_uint8",g_read_uint8,10);

//Erase        jq_ra4t1_inner_flash_erase (TEST_ADDRESS,             128,            x_callback,            NULL);
//Write        jq_ra4t1_inner_flash_write (TEST_ADDRESS,             g_write_uint8,             4,//---Here cannot be 128! Because it is encapsulated internally!            x_callback,            NULL);
//Read        jq_ra4t1_inner_flash_read (TEST_ADDRESS,             g_read_uint8,             128,            x_callback,            NULL);
        LOG_ARRY("g_src_uint8",g_read_uint8,10);         
 }

Renesas A4T1 Internal Flash Operations - Unified API Layer PackagingCode for testing data flash

typedef void (*jq_flash_complete_callback_t)(void *user_data, int result);

 void flash_init(void){    /* Open the flash lp instance. */    err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);    assert(FSP_SUCCESS == err);}
/* * @param rAddr read address * @param rBuf read buffer * @param rLen read len * @param cb read complete callback function * @param user_data user data * @return int 0 success, other failed */ static int jq_ra4t1_inner_flash_read (  size_t rAddr,                                          void *rBuf,                                          size_t rLen,                                         jq_flash_complete_callback_t cb,                                         void *user_data) {
     memcpy (rBuf, rAddr, rLen);     if (cb) cb (user_data,0);
     return 0; }


/** * @brief flash write function *  *  * @param wAddr write address * @param wBuf write buffer * @param wLen write len * @param cb write complete callback function * @param user_data user data * @return int 0 success, other failed */static int jq_ra4t1_inner_flash_write ( size_t wAddr,                                         void *wBuf,                                         size_t wLen,                                        jq_flash_complete_callback_t cb,                                        void *user_data){    int err = 0;    int i = 0;    uint32_t programCount;    uint32_t programEndLen;    uint32_t off;    uint32_t len = 0;    flash_status_t status;
    #define MIN_WRITE_NUM 4    uint8_t alignBuf[MIN_WRITE_NUM];
    /** 4byte align */    programCount = wLen / MIN_WRITE_NUM;    programEndLen = wLen % MIN_WRITE_NUM;    off = 0;    __disable_irq();    if (programCount)    {        len = programCount * MIN_WRITE_NUM;//len must be a multiple of MIN_WRITE_NUM!        err = R_FLASH_HP_Write(&g_flash0_ctrl, wBuf, wAddr, len);

/*  Actually, it can be omitted. Wait until the current flash operation completes. */do	{        err = R_FLASH_HP_StatusGet(&g_flash0_ctrl, &status);    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));

        off += len;    }
    if ((err == 0) && programEndLen)    {        len = MIN_WRITE_NUM;//len must be a multiple of MIN_WRITE_NUM!        memcpy (alignBuf,wBuf + off,programEndLen);        err = R_FLASH_HP_Write(&g_flash0_ctrl, alignBuf, wAddr + off, len);
/*  Actually, it can be omitted. Wait until the current flash operation completes. */do	{        err = R_FLASH_HP_StatusGet(&g_flash0_ctrl, &status);    } while ((FSP_SUCCESS == err) && (FLASH_STATUS_BUSY == status));
    }    __enable_irq();    if (0 == err)    {        if (cb) cb(user_data,0);        return 0;    }
}


/** * @brief flash erase function *  *  * @param wAddr erase address * @param wLen erase len * @param cb write complete callback function * @param user_data user data * @return int 0 success, other failed */static int jq_ra4t1_inner_flash_erase(  size_t eAddr,                                         size_t eLen,                                        jq_flash_complete_callback_t cb,                                        void *user_data){    int err = -1;    uint8_t block_num; 
    block_num = (eLen + FLASH_HP_DF_BLOCK_SIZE_64B - 1) / FLASH_HP_DF_BLOCK_SIZE_64B;    LOG("jq_ra4t1_inner_flash_erase  block_num=%d\r\n",block_num);    __disable_irq();    err = R_FLASH_HP_Erase( &g_flash0_ctrl, (eAddr / FLASH_HP_DF_BLOCK_SIZE_64B) * FLASH_HP_DF_BLOCK_SIZE_64B, block_num);    __enable_irq();    if (0 == err)    {        if (cb) cb(user_data,0);        return 0;    }
    return err;}


void x_callback (void *user_data, int result){    LOG("x_callback result=%d\r\n",result);}
uint8_t  g_read_uint8[64]={0};uint8_t  g_write_uint8[5]={0x55,0x66,0x77,0x88};void flash_test(void){
#define TEST_ADDRESS    FLASH_HP_DF_BLOCK_0//Initialize OPEN        flash_init();//Read        jq_ra4t1_inner_flash_read (TEST_ADDRESS,             g_read_uint8,             64,            x_callback,            NULL);
        LOG_ARRY("g_src_uint8",g_read_uint8,10);

//Erase        jq_ra4t1_inner_flash_erase (TEST_ADDRESS,             64,            x_callback,            NULL);
//Write        jq_ra4t1_inner_flash_write (TEST_ADDRESS,             g_write_uint8,             5,//---Here cannot be 64! Because it is encapsulated internally!            x_callback,            NULL);
//Read        jq_ra4t1_inner_flash_read (TEST_ADDRESS,             g_read_uint8,             128,            x_callback,            NULL);
        LOG_ARRY("g_src_uint8",g_read_uint8,10);         
 }

Leave a Comment