I have 2 project codes to be placed in the same RL78G23, how to implement the following configuration1. Can I simultaneously load in debug mode?2. How do I jump from project 1 to project 2?
3. How to define the section of project 2?
Thanks and Regards,
Hello victor_rai, sorry for late response.
I’ll try to explain basic concepts of running 2 separate application code, inside an MCU, memory regions, how to substitute running code. And then we’ll dive deeper into our specific needs in RL78/G23 (768KB flash).
I apologize if I dive into basic concept that you’re already familiar with, but this might help other users. And I hope this weren’t so boring.
First of all, we have to consider that a running code inside an MCU is nothing more than some instructions that are running from flash memory (or sometimes RAM).
Inside the CPU of the MCU, there’s a register that called PC (Program Counter). It indicates the code must be executed from where (memory address) at the next clock cycle.
Figure below shows the Memory map of RL78 devices.
As the figure shows, code flash memory is started from 0x0000 address and varies based on device flash in RL78 devices.
Now let’s take a look at the interrupt vectors, interrupt vectors in RL78 CPU core are some hardware fixed addresses, which CPU will refer to them for getting data or instructions in specific cases e. g. Reset, timer interrupts, ADC interrupt etc.
The length of the data inside vector_table area (0 – 0x7F address) is 16bit. And can contain values (0 - 0xFFFF).
When MCU starts to run, it’ll jump to first block of ROM (0x0000 address) which is named reset_vector
Figure below shows how CPU deals with flash memory instructions. (After reset MCU in this example)
As you can see the data inside memory will be fetched by CPU from memory addresses, then PC register will increment and CPU continues to run instructions. Also, when we invoke a function inside the code, we’re setting the address of the code inside the function (By branching) to PC register, then code will jump into function and then returns back to the initial address in main code (Before calling function).
So, let’s dive deeper into practical examples.
Here we’ve a simple code snippet, it’s running in debug mode in e2studio IDE. You can add Disassembly viewer to debug mode and see where the code is running in memory and what’s the value of Program Counter (PC).
In this way we can determine where the code is running, even you can manipulate PC register to force CPU to jump to desired address (Pay attention to the address first, it might have unpredictable results). Even when the IDE doesn’t access the code inside other areas of the memory, it’ll show the data and address inside the MCU (for example When you’re debugging a dual program MCU)
Also, for jumping into specific address we can use this piece of code to command CPU where it should seek for next instructions.
void (*jump_instruction)(void) = (void*)(*((volatile uint32_t*) (0x04000))); //define function pointer for the address
Put above snippet inside your code and CPU will jump into the desired address in Memory. (0x4000 in example above)
So now, you can play with those and grasp the main concept. Next, I’ll demonstrate how we can do that for two individual codes
Inside the MCU and what the problems are.
You’ve asked about how we can determine where a code must be placed inside the flash memory.
The answer is: It’s related to the compiler that you’re using and linker scripts.
But don’t worry about that, you can always manipulate final binary files, that contains bare machine code, using a hex editor software (NEO hex editor is recommended).
Imagine you’ve written a program which is named code1 and you’ve compiled it and you can access to its binary files (.hex or .bin).
Also, you have written another individual program which is named code2, now you’ll have code2.bin file.
If you try to program those files by a programmer (like e2 lite), your codes will run as usual for each individual program. Now let’s do the trick.
You can migrate those .bin files using hex editor programs.
You can see the values of each block inside the file and its address. For example, in figure above you can see the first block (0x0000) contain 0xce value (Indicates the reset vector and where program must begin after a reset)
So, you can migrate those binary files based on your needs (e. g. offset code2 by 0x4000 then combine those two files).
In that way you can program a manipulated binary file that contains two individual codes inside the flash.
Then you can jump into whatever address you need. For example, 0x4000 which Is the first block of the second code.
Everything looks fine and will work! But there’s a problem! That’s all about interrupts.
This approach will be OK till you need to use an interrupt inside your codes. As I mentioned earlier, vector tables are hardware addresses which CPU refer to them when an interrupt arises. Below you can see the dedicated addresses for each interrupt in RL78/G23 devices: (G23 hardware user’s manual page 158)
So, whenever an interrupt occurs, CPU will fetch the value of its address and set the value to PC (Program Counter) and continues.
This will be problematic when we’ve jumped into second program. The code will jump back to the addresses of the first program and will hang when an interrupt occurs. (Because we’ve offset the second program and vector tables of the second program are not inside predicted area)
So how can we solve that problem?
In some microcontrollers Like ARM based MCUs there’s a dedicated register inside the CPU that indicates the offset of the vector table. And we can use that after jumping onto second code. But that’s not available in RL78 devices.
But there’s a remedy for that in RL78, that’s embedded inside the RL78 flash controller which is designed for self programing solution.
As you can see in RL78/G23 devices, there’s a memory region which is named Boot cluster 0 and Boot cluster 1
Those areas are fixed (0x0000 – 0x3fff) and (0x4000 – 0x7fff), and we can substitute those virtually (probably, internally inside flash unit).
Then when CPU starts to run, although we’ve programmed code1 and code2 in dedicated memory regions by programmer, when we swap those areas, after a reset it will be just like we’ve swapped those areas, like hex edition technique. And desired program will start at 0x0000 and we’ll have no problem with vector table area.
It seems nice for our need, because it’ll solve the interrupt vector issue. But you have to consider that, your first program (code1) must not exceed boot cluster 0 size (16KB).
If it meets your requirements, you can use Renesas Flash Driver RL78 library (RFD Type 01) for swapping those areas conveniently. You can refer to this link for more information about using Flash driver library:
By using boot swap, you won’t need jump instructions. And after boot swapping only a reset will change the running program.
For using Renesas flash driver you’ll need a great foundation of how it’s working and API functions etc.
But for now, I’ll try to explain most important notes and aspect of that, which you might find that useful:
Renesas flash driver is a convenient way to handle Writing, Erasing, and changing security setting of flash unit in RL78 devices.
Although just like other peripherals in MCU you can access to all of the features that flash driver provided, manually by registers which are demonstrated in RL78/G23 hardware user manual (section 33.6.2, page 1315).
Firstly, you need to consider that there’s a flag (boot flag) inside a protected area within flash memory which is called extra area, the flag determines which boot cluster is used as default when MCU starts to run.
At the other hand, the flash areas (code flash, data flash, extra area) are protected against user’s manipulation, so we’ll need to go through a specific procedure to write into flash memory areas. (That’s done by Renesas Flash driver)
Another important note in RL78 flash memory is, we cannot read from flash memory, or CPU cannot fetch instructions during writing into flash memory. (We have to write instructions into RAM then doing the unlocking procedure of flash areas)
So, those cautions show us, we need to use Flash driver prudently to reach our goal, which is swapping boot by changing Boot flag, which is inside flash extra area and we need to proceed through some procedure to change that bit.
How we should use Flash driver?
There’s a complete guide about that in the link that I provided earlier, so you’ll need to use that as reference. But there’s some useful tips about Renesas Flash driver.
-Make sure you’ve initialized flash driver by R_RFD_Init() function before using API functions.
-Make sure you’re using high-speed on chip oscillator during boot swapping.
It seems you’re working on this sample document which I provided below:
It’s using RFD (Renesas Flash Driver) API function in its base, and you’ll need to dive deeper into specific functions provided by sample code’s manual.
In your case you might need to consider specific functions provided by above document (Table4-10 List of Functions)
For example , r_rfd_initialize() for initialize Renesas flash driver. (It’s vital to call at the beginning, otherwise, you’ll face error in Bootswap function)
Also, I think It’s useful to take a look at the flowchart of r_RequestBootSwap() provided by the sample code, which is as follows :
/////////////////////////////////////////////r_RequestBootSwap() flow chart////////////////////////////////////////////////////////
1-obtain the information about securityFlag and boot Flag through R_RFD_GetSecurityAndBootFlags()
2-Check for What boot that is set (BTFLG1=bootCluster1/BTFLG0=bootCluster0)
3-Select next_boot_cluster to (R_RFD_ENUM_BOOT_CLUSTER_1 or R_RFD_ENUM_BOOT_CLUSTER_0)
4-Set access permission status of data flash memory through R_RFD_SetDataFlashAccessMode(R_RFD_ENUM_DF_ACC_ESS_ENABLE)
5-Place flash memory sequencer in flash programming mode through R_RFD_SetFlashMemoryMode(R_RFD_ENUM_FLASH_MODE_CODE_PROGRAMMING)
6-Request boot swapping after a reset through R_RFD_SetExtraBootAreaReq(next_boot_cluster)
7-sequence and processing for the extra area through r_CheckExtraSequencerEnd()
8-Place flash memory sequncer in normal operation mode through R_RFD_SetFlashMemoryMode(R_RFD_ENUM_FLASH_MODE_UNPROGRAMMABLE)
9-Set the access prohibition status for data flash memory through R_RFD_SetDataFlashAccessMode(R_RFD_ENUM_DF_ACCESS_DISABLE)
10-Check for error and if everything were normal operate an internal reset through R_RFD_ForceReset()
Eventually, I hope that you’re not being frustrated with the long content which might be very basic, and find it useful.
If you have any follow up question, don’t hesitate to ask, we’re grateful to help if we could, If it helped I'll appreciate your reply.
Also, if you’re interested in to dive deeper into these concepts you might consider assembly language and CPU instructions.
You can find RL78 core user’s manual in following link https://llvm-gcc-renesas.com/pdf/r01us0015ej0220_rl78.pdf
With best regards.