|
/** Test project to try the four known modes of Code Flash self Programming of the RX family. **/ |
|
/** **/ |
|
/** This code is tested on the RX651 Test board, with the R5F565NEDDFP MCU. **/ |
|
/** Compiled using CC-RX v3.06.00, and using r_bsp 7.42 and r_flash_rx v5.11 **/ |
|
/** **/ |
|
/** It is expected that this code can be used on at least other RX MCU's from Renesas. **/ |
|
/** Not all of the tested features are expected to work on all of the various RX MCU's. **/ |
|
/** **/ |
|
/** The code is a heavily modified version of the flash_demo_rskrx65n example from Renesas. **/ |
|
/** **/ |
|
/** Four scenarios to modify code flash are tested: **/ |
|
/** * r_flash_rx functions executes in RAM - in blocking mode. **/ |
|
/** * r_flash_rx functions executes in RAM - in background mode (callback when finishing). **/ |
|
/** * r_flash_rx functions executes in ROM - in blocking mode. **/ |
|
/** * r_flash_rx functions executes in ROM - in background mode (callback when finishing). **/ |
|
/** Choose the mode by making modifications to the r_flash_rx component configuration **/ |
|
/** **/ |
|
/** NOTE: Debugging of the R_FLASH_Erase() and R_FLASH_Write() functions from r_flash_rx usually **/ |
|
/** results in some sort of crash. Stepping over the functions will work. **/ |
|
/** **/ |
|
/** 2024-05-07 Flemming Steffensen **/ |
|
|
|
#include "platform.h" |
|
#include "r_flash_rx_if.h" |
|
#include "r_flash_rx_config.h" |
|
|
|
|
|
/** The warnings section below reveals how r_flash_rx component are configured in the smart configurator. **/ |
|
#if (FLASH_CFG_CODE_FLASH_ENABLE == 1) |
|
#if (FLASH_CFG_CODE_FLASH_RUN_FROM_ROM == 0) |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 0) |
|
#warning "r_flash_rx functions executes in RAM, and blocks while executing. (BLOCK)" |
|
#else |
|
#warning "r_flash_rx functions executes in RAM, and runs in the background - calling a callback when finishing. (BGO)" |
|
#endif |
|
#else |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 0) |
|
#warning "r_flash_rx functions executes in ROM, and blocks while executing. (BLOCK)" |
|
#else |
|
#warning "r_flash_rx functions executes in ROM, and runs in the background - calling a callback when finishing. (BGO)" |
|
#endif |
|
#endif |
|
#else |
|
#warning "Upgrade of code flash is disabled." |
|
#endif |
|
|
|
|
|
/*********************************************************************************************************************** |
|
Private global variables and functions |
|
***********************************************************************************************************************/ |
|
static uint32_t ram_vector_table[256]; // RAM space to hold the vector table |
|
volatile uint8_t g_buf[FLASH_CF_MEDIUM_BLOCK_SIZE]; |
|
|
|
#if (FLASH_CFG_CODE_FLASH_BGO == 1) |
|
// Only needed for background operation. |
|
|
|
typedef enum { |
|
IDLE, |
|
RUNNING |
|
} flashOperation_t; |
|
|
|
// Declare the global variable |
|
volatile flashOperation_t flashBackgroundOperationCompleteFlag = IDLE; |
|
volatile flash_interrupt_event_t flash_interrupt_event; |
|
|
|
// Callback function for flash background operation. |
|
void cb_flashBackgroundOperationComplete(void *event) { |
|
flashBackgroundOperationCompleteFlag = IDLE; |
|
flash_interrupt_event = *((flash_interrupt_event_t*)event); |
|
} |
|
|
|
|
|
static flash_err_t setupFlashCallback(void){ |
|
static bool Initialized = false; |
|
flash_err_t err; |
|
|
|
if (Initialized){ |
|
return FLASH_SUCCESS; |
|
} |
|
flash_interrupt_config_t cb_func_info; |
|
cb_func_info.pcallback = cb_flashBackgroundOperationComplete; |
|
cb_func_info.int_priority = 15; |
|
err = R_FLASH_Control(FLASH_CMD_SET_BGO_CALLBACK, (void *)&cb_func_info); |
|
if(err != FLASH_SUCCESS) |
|
{ |
|
return err; |
|
} |
|
Initialized = true; |
|
return err; |
|
} |
|
// Only needed for background operation. |
|
#endif |
|
|
|
|
|
/*********************************************************************************************************************** |
|
* Function Name: flash_copy_vector_table |
|
* Description : Moves the relocatable vector table to RAM. This is only needed if ROM operations are performed. |
|
* ROM cannot be accessed during operations. The vector table is located in ROM and will be accessed |
|
* if an interrupt occurs. |
|
* Note : This is STRICTLY NEEDED for any ROM modification to function!! |
|
***********************************************************************************************************************/ |
|
static void flash_copy_vector_table(void) |
|
{ |
|
uint32_t * flash_vect; |
|
uint32_t i; |
|
|
|
/* Get address of variable vector table in ROM */ |
|
flash_vect = (uint32_t *)get_intb(); |
|
|
|
/* Copy over variable vector table to RAM */ |
|
for(i = 0; i < 256; i++ ) |
|
{ |
|
ram_vector_table[i] = *flash_vect; // Copy over entry |
|
flash_vect += 1; // Move pointer |
|
} |
|
|
|
/* Set INTB to ram address */ |
|
#if __RENESAS_VERSION__ >= 0x01010000 |
|
set_intb((void *)&ram_vector_table[0] ); |
|
#else |
|
set_intb( (uint32_t)&ram_vector_table[0] ); |
|
#endif |
|
} |
|
|
|
|
|
/** Wrap R_FLASH_Erase, so that the optional interrupt flag is updated correctly. **/ |
|
static flash_err_t R_FLASH_Erase_Operation(flash_block_address_t block_start_address, uint32_t num_blocks) { |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 0) |
|
// Blocking mode |
|
return R_FLASH_Erase(block_start_address, num_blocks); |
|
#else |
|
// Non blocking mode |
|
flash_err_t err; |
|
flashBackgroundOperationCompleteFlag = RUNNING; |
|
err = R_FLASH_Erase(block_start_address, num_blocks); |
|
if (err != FLASH_SUCCESS){ |
|
flashBackgroundOperationCompleteFlag = IDLE; |
|
} |
|
return err; |
|
#endif |
|
} |
|
|
|
/** Wrap R_FLASH_Write, so that the optional interrupt flag is updated correctly. **/ |
|
static flash_err_t R_FLASH_Write_Operation(uint32_t src_address, uint32_t dest_address, uint32_t num_bytes) { |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 0) |
|
// Blocking mode |
|
return R_FLASH_Write(src_address, dest_address, num_bytes); |
|
#else |
|
// Non blocking mode |
|
flash_err_t err; |
|
flashBackgroundOperationCompleteFlag = RUNNING; |
|
err = R_FLASH_Write(src_address, dest_address, num_bytes); |
|
if (err != FLASH_SUCCESS){ |
|
flashBackgroundOperationCompleteFlag = IDLE; |
|
} |
|
return err; |
|
#endif |
|
} |
|
|
|
|
|
/******************************************************************************* |
|
* Outline : Test of Blocking or nonBlocking code flash operations: erase, write, and read data back. |
|
* Description : Will run either in RAM or ROM, either blocking or nonBlocking, depending on FIT Component settings. |
|
* Note : Debugger cannot inspect ROM contents when in ROM P/E mode (P/E == Program/Erase) |
|
*******************************************************************************/ |
|
int main(void) |
|
{ |
|
uint32_t i; |
|
flash_err_t err; |
|
volatile uint32_t addr; |
|
flash_access_window_config_t accessInfo; |
|
|
|
|
|
/* Initialize test data to write */ |
|
for (i = 0; i < sizeof(g_buf); i++) |
|
{ |
|
g_buf[i] = (uint8_t)i; |
|
} |
|
|
|
/* Copy vector table to RAM if interrupts possible while erasing/writing ROM */ |
|
/* THIS IS CRUCIAL for ROM programming to function.*/ |
|
flash_copy_vector_table(); |
|
|
|
|
|
/* Open flash driver */ |
|
err = R_FLASH_Open(); |
|
if (err != FLASH_SUCCESS) |
|
while(1); // ERROR |
|
|
|
|
|
#if (FLASH_CFG_CODE_FLASH_BGO == 1) |
|
/* When running in BGO mode, a callback must be configures.*/ |
|
/* This function must be called after the R_FLASH_Open() call. */ |
|
err = setupFlashCallback(); |
|
if (err != FLASH_SUCCESS) |
|
{ |
|
while (1); // ERROR |
|
} |
|
#endif |
|
|
|
|
|
/* Specifically mark code flash address range as ok to erase/write */ |
|
accessInfo.start_addr = (uint32_t)FLASH_CF_BLOCK_9; // Lowest address |
|
accessInfo.end_addr = (uint32_t)FLASH_CF_BLOCK_8; // Highest address |
|
err = R_FLASH_Control(FLASH_CMD_ACCESSWINDOW_SET, (void *)&accessInfo); |
|
if (err != FLASH_SUCCESS) |
|
{ |
|
while (1); // ERROR |
|
} |
|
|
|
/* Overwrite the first 5 bytes of data */ |
|
g_buf[0] = 'H'; |
|
g_buf[1] = 'e'; |
|
g_buf[2] = 'l'; |
|
g_buf[3] = 'l'; |
|
g_buf[4] = 'o'; |
|
|
|
|
|
/* Erase code flash block - again */ |
|
err = R_FLASH_Erase_Operation(FLASH_CF_BLOCK_9, 1); |
|
if(err != FLASH_SUCCESS) |
|
{ |
|
while(1); // ERROR |
|
} |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 1) |
|
while (RUNNING == flashBackgroundOperationCompleteFlag){}; |
|
if(flash_interrupt_event != FLASH_INT_EVENT_ERASE_COMPLETE) |
|
{ |
|
while(1); // ERROR |
|
} |
|
#endif |
|
|
|
/* |
|
Note: The block size if defined in FLASH_CF_SMALL_BLOCK_SIZE and FLASH_CF_MEDIUM_BLOCK_SIZE. |
|
The first 8 blocks are always small. For dual bank, the first 8 blocks in each bank is small. |
|
Be aware that there's a minimum size to program at a time, defined in FLASH_CF_MIN_PGM_SIZE. |
|
*/ |
|
|
|
addr = (uint32_t)FLASH_CF_BLOCK_9; |
|
err = R_FLASH_Write_Operation((uint32_t)g_buf, addr, FLASH_CF_MIN_PGM_SIZE); |
|
if(err != FLASH_SUCCESS) |
|
{ |
|
while(1); // ERROR |
|
} |
|
#if (FLASH_CFG_CODE_FLASH_BGO == 1) |
|
while (RUNNING == flashBackgroundOperationCompleteFlag){}; |
|
if(flash_interrupt_event != FLASH_INT_EVENT_WRITE_COMPLETE) |
|
{ |
|
while(1); // ERROR |
|
} |
|
#endif |
|
|
|
/* Verify code flash write */ |
|
for (i = 0; i < FLASH_CF_MIN_PGM_SIZE; i++) { |
|
if (g_buf[i] != *((uint8_t *)(addr + i))) { |
|
while(1); // Verify ERROR |
|
} |
|
} |
|
|
|
|
|
/* Close flash driver */ |
|
err = R_FLASH_Close(); |
|
if (err != FLASH_SUCCESS) |
|
while(1); // ERROR |
|
|
|
|
|
while(1); // Everything worked! |
|
|
|
return(0); |
|
} |