Flash Memory Library
This library provides routines for accessing microcontroller's (internal) Flash memory.
On the dsPIC30/33 and PIC24, Flash memory is mapped to address space 3:2, which means that every 3 consecutive bytes of Flash have 2 consecutive address locations available. That is why mikroE's library allows data to be written to flash in two ways: "common" and "compact". In the "common" mode, which is used for word(16-bit) variables, the 3rd (un-addressable) flash memory byte remains unused. In the "compact" mode, which can be used for 1 byte-sized variables/arrays, all flash bytes are being used.
All dsPIC30/33 and PIC24 MCUs use the RTSP module to perform Read/Erase/Write operations on Flash memory. This, together with the internal structure of the Flash, imposes certain rules to be followed when working with Flash memory:
dsPIC30:
- Erasing can be done only in 32-instructions (64 addresses, 96 bytes) memory blocks. This means that the block start address should be a multiply of 64 (i.e. have 6 lower bits set to zero).
- Data is read and written in 4-instructions (8 addresses, 12 bytes) blocks.This means that the block start address should be a multiply of 8 (i.e. have 3 lower bits set to zero).
- On the dsPIC30s, 2 address locations are assigned on every 3 bytes of (flash) program memory. Due to this specific and non-one-to-one address mapping, the mikroC PRO for dsPIC30/33 and PIC24 offers two sets of Flash handling sub functions: "common" and "compact".
Using the "common" set, the user can write one byte of data to a single address, which means that each byte of written data has its own address, but on every 2 written bytes one byte of Flash memory remains empty.
Using the "compact" set, every byte of Flash memory, including those non-addressable, is filled with data; this method can only be used for data organized in bytes.
The "compact" sub functions have_Compact
as name suffix. - For run-time FLASH read/write, the dsPIC30's RTSP module is being used. It organizes data into rows and panels. Each row contains write latches that can hold 4 instructions (12 bytes). The number of panels varies from one dsPIC30 MCU model to another. Because of that, the flash write sequence has been split into several operations (
_Write_Init(), _Write_LoadLatch4(), _Write_DoWrite()
), in order to be usable on all dsPICs.
PIC24 and dsPIC33:
- Erasing can be done only in 512/1024-instruction (1024/2048 addresses, 1536/3072 bytes) memory blocks or 32-instruction (64 addresses, 96 bytes) rows, which means that the block start address should be a multiple of 1024, 1536 or 64 (i.e. have 10 lower bits set to zero).
- Data is read and written in 32/64/128 instruction (64/128/256 addresses, 96/192/384 bytes) memory blocks or 32 instruction (64 addresses, 96 bytes) rows. This means that the block start address should be a multiply of 128, 192 or 64 (i.e. have 7 lower bits set to zero).
- On the dsPIC33 and PIC24s, 2 address locations are assigned on every 3 bytes of (flash) program memory. Due to this specific and non-one-to-one address mapping, the mikroC PRO for dsPIC30/33 and PIC24 offers two sets of Flash handling sub functions: "common" and "compact".
Using the "common" set, the user can write one byte of data to a single address, which means that each byte of written data has its own address, but on every 2 written bytes one byte of Flash memory remains empty.
Using the "compact" set, every byte of Flash memory, including those non-addressable, is filled with data; this method can only be used for data organized in bytes.
The "compact" sub functions have_Compact
as name suffix.
Library Routines
- FLASH_Erase
- FLASH_Erase32
- FLASH_Write
- FLASH_Write_Block
- FLASH_Write_Compact
- FLASH_WriteDoubleWord
- FLASH_Write_Init
- FLASH_Write_Loadlatch4
- FLASH_Write_Loadlatch4_Compact
- FLASH_Write_DoWrite
- FLASH_Read
- FLASH_Read_Compact
- FLASH_ReadDoubleWord
- FLASH_Read4
- FLASH_Read4_Compact
FLASH_Erase
Prototype |
void FLASH_Erase(unsigned long address); |
---|---|
Description |
Erases one block (512/1024 instructions, 1024/2048 addresses, 1536/3072 bytes) or row (32 instructions, 64 addresses, 96 bytes) from the program FLASH memory. |
Parameters |
|
Returns |
Nothing. |
Requires |
Nothing. |
Example |
//--- erase the flash memory block, starting from address 0x006400 unsigned long flash_address = 0x006400; ... FLASH_Erase(flash_address); |
Notes |
|
FLASH_Erase32
Prototype |
void FLASH_Erase32(unsigned long address); |
---|---|
Description |
Erases one block (32 instructions, 64 addresses, 96 bytes)from the program FLASH memory. |
Parameters |
|
Returns |
Nothing. |
Requires |
Nothing. |
Example |
//--- erase the 32-instruction block, starting from address 0x006000 FLASH_Erase32(0x006000); |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write
Prototype |
void FLASH_Write(unsigned long address, unsigned int * data_); |
---|---|
Description |
Fills one writeable block of Flash memory in the "common" mode. Addresses and data are being mapped 1-on-1. This means that 3rd byte of each program location remains unaffected. |
Parameters |
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
Example |
unsigned int iArr[64] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k', 't', 'r', 'o', 'n', 'i', 'k', 'a'}; void * pv1; ... pv1 = iArr; FLASH_Write(0x006500, pv1); |
Notes |
|
FLASH_Write_Block
Prototype |
void FLASH_Write_Block(unsigned long flash_address, unsigned int *data_); |
---|---|
Description |
Fills one writeable block of Flash memory (4 instructions, 8 addresses, 12 bytes) in the "common" mode. Addresses and data are being mapped 1-on-1. This also means that 3rd byte of each program location remains unused. |
Parameters |
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
Example |
unsigned long flash_address = 0x006000; unsigned int Buffer[4] = {'A', 'B', 'C', 'D'}; ... FLASH_Write_Block(flash_address, Buffer); |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Compact
Prototype |
// dsPIC30 :
void FLASH_Write_Compact(unsigned long address, void * data_, unsigned bytes); // dsPIC33 and PIC24 :void FLASH_Write_Compact(unsigned long address, char * data_); |
---|---|
Description |
dsPIC30 Fills a portion of Flash memory using the dsPIC30 RTSP module, in the "compact" manner. In this way, several blocks of RTSP's latch can be written in one pass.
dsPIC33 and PIC24 Fills one writeable block (32/64/128 instructions, 64/128/256 addresses, 96/192/384 bytes) or row (32 instructions, 64 addresses, 96 bytes) in "compact" mode.
|
Parameters |
dsPIC30
dsPIC33 and PIC24
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
Example |
dsPIC30char cArr[] = "supercalifragillisticexpialidotiousABCDEFGHIJKLMNOPRSTUVWXYZ1234"; void * pv1; ... pv1 = cArr; FLASH_Write_Compact(0x006400, pv1); dsPIC33 and PIC24unsigned long flash_address = 0x006000; char Buffer[] = "supercalifragillisticexpialidotious"; ... FLASH_Write_Compact(flash_address, Buffer, 36); |
Notes |
|
FLASH_WriteDoubleWord
Prototype |
void FLASH_WriteDoubleWord(unsigned long address, unsigned long * data_) |
---|---|
Description |
Writes two instructions (6 bytes) of Flash memory in the "compact" mode. "Compact" means that all 3 bytes that exist on 2 consecutive addresses (1 even, 1 odd) are being used-up. |
Parameters |
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU.
|
Example |
|
Notes |
|
FLASH_Write_Init
Prototype |
void FLASH_Write_Init(unsigned long address, void *data_); |
---|---|
Description |
Initializes RTSP for write-to-FLASH operation. |
Parameters |
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
Example |
//--- Initializes the Flash to be written, starting from address 0x006100, the data is located at *pv1 void *pv1; ... FLASH_Write_Init(0x006100, pv1);FLASH_Write_Loadlatch4(); FLASH_Write_Loadlatch4(); FLASH_Write_DoWrite(); |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Loadlatch4
Prototype |
void FLASH_Write_Loadlatch4(); |
---|---|
Description |
Loads the current RTSP write latch with data (4 instructions, 8 addresses, 12 bytes). The data is filled in the "common" mode. |
Parameters |
None. |
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! This function is used as a part of the Flash write sequence, therefore the FLASH_Write_Init function must be called before this one. This function can be called several times before commiting the actual write-to-Flash operation FLASH_Write_DoWrite. This depends on the organization of the RTSP module for the certain dsPIC30. Please consult the Datasheet for particular dsPIC30 on this subject. |
Example |
//--- writes data from an array, in "regular" manner unsigned int iArr[16] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k'}; void * pv1; ... pv1 = iArr; FLASH_Write_Init(0x006100, pv1); FLASH_Write_Loadlatch4(); FLASH_Write_Loadlatch4(); FLASH_Write_DoWrite(); |
Notes |
None. |
FLASH_Write_Loadlatch4_Compact
Prototype |
void FLASH_Write_Loadlatch4_Compact(); |
---|---|
Description |
Loads the current RTSP write latch with data (4 instructions, 8 addresses, 12 bytes). The data is filled in the "compact" mode. "Compact" means that all 3 bytes that exist on 2 consecutive addresses (1 even, 1 odd) are being used-up. |
Parameters |
None. |
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! This function is used as a part of the Flash write sequence, therefore the FLASH_Write_Init function must be called before this one. This function can be called several times before committing actual write-to-Flash operation FLASH_Write_DoWrite. This depends on the organization of the RTSP module for the certain dsPIC30. Please consult the Datasheet for particular dsPIC30 on this subject. |
Example |
//--- writes data from an array of char, in "compact" manner char cArr[] = "supercalifragillisticexpialidotious"; //35+1 bytes void * pv1; ... pv1 = cArr; FLASH_Write_Init(0x006000, pv1); //init FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_DoWrite(); //commit write |
Notes |
None. |
FLASH_Write_DoWrite
Prototype |
void FLASH_Write_DoWrite(); |
---|---|
Description |
Commits the FLASH write operation. |
Parameters |
None. |
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! This function is used as a part of the Flash write sequence, therefore FLASH_Write_Init and certain number of FLASH_Write_Loadlatch4 or FLASH_Write_Loadlatch4_Compact function calls must be made before this one. This function is to be called once, at the and of the FLASH write sequence. |
Example |
//--- writes data from an array, in "regular" manner unsigned int iArr[16] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k'}; void * pv1; ... pv1 = iArr; FLASH_Write_Init(0x006100, pv1); FLASH_Write_Loadlatch4(); FLASH_Write_Loadlatch4(); FLASH_Write_DoWrite(); |
Notes |
None. |
FLASH_Read
Prototype |
unsigned int* FLASH_Read(unsigned long address, unsigned int *write_to, unsigned NoWords); |
---|---|
Description |
Reads required number of words from the Flash memory in the "common" mode. |
Parameters |
|
Returns |
Address of RAM buffer for storing read data. |
Requires | |
Example |
unsigned Buffer[64]; unsigned long start_address = 0x6500; ... FLASH_Read(start_address, Buffer, 10); |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read_Compact
Prototype |
void *FLASH_Read_Compact(unsigned long address, void *write_to, unsigned NoBytes); |
---|---|
Description |
Reads required number of bytes from the flash memory in the "compact" mode. "Compact" means that all 3 bytes that exist on 2 consecutive addresses (1 even, 1 odd) are being used-up. |
Parameters |
|
Returns |
Address of RAM buffer for storing read data. |
Requires |
Nothing. |
Example |
char Buffer[64]; unsigned long start_address = 0x6500; ... FLASH_Read_Compact(start_address, Buffer, 10); |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_ReadDoubleWord
Prototype |
unsigned long * FLASH_ReadDoubleWord(unsigned long address, unsigned long * write_to); |
---|---|
Description |
Reads two instructions (6 bytes) from Flash memory in the "compact" mode. "Compact" means that all 3 bytes that exist on 2 consecutive addresses (1 even, 1 odd) are being used-up. |
Parameters |
|
Returns |
Starting address of RAM buffer for storing read data. |
Requires | |
Example |
|
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read4
Prototype |
unsigned int* FLASH_Read4(unsigned long address, unsigned int *write_to); |
---|---|
Description |
Reads one latch row (4 instructions, 8 addresses) in the "common" mode. |
Parameters |
|
Returns |
Starting address of RAM buffer for storing read data. |
Requires |
Nothing. |
Example |
//--- reads 8 bytes (4 words) from location 0x006000 and stores it to *pv1; unsigned int *pv1; ... FLASH_Read4(0x006000, pv1); |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read4_Compact
Prototype |
void* FLASH_Read4_Compact(unsigned long address, void *write_to); |
---|---|
Description |
Reads one latch row (4 instructions, 8 addresses) in the "compact" mode. "Compact" means that all 3 bytes that exist on 2 consecutive addresses (1 even, 1 odd) are being used-up. |
Parameters |
|
Returns |
Starting address of RAM buffer for storing read data. |
Requires |
Nothing. |
Example |
//--- reads 12 bytes (4 words) from location 0x006000 and stores it to *pv1; unsigned int *pv1; ... FLASH_Read4_Compact(0x006000, pv1); |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
Library Example
In this example written for dsPIC30F4013, various read/write tecniques to/from the on-chip FLASH memory are shown. Flash memory is mapped to address space 3:2, meaning every 3 consecutive bytes of Flash have 2 consecutive address locations available.
That is why mikroE's library allows data to be written to Flash in two ways: 'regular' and 'compact'. In 'regular' mode, which is used for variables that are size of 2 bytes and more, the 3rd (un-addressable) byte remains unused.
In 'compact' mode, which can be used for 1 byte-sized variables/arrays, all bytes of flash are being used.
unsigned int iArr[8] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e'}; char cArr[] = "mikroElektronika Flash example"; char cArr2[40]; void * pv1; unsigned bb; void main() { unsigned i; pv1 = cArr; /* This is what FLASH_Write_Compact() does 'beneath the hood' * FLASH_Write_Init(0x006000, pv1); FLASH_Write_Loadlatch4_Compact(); FLASH_Write_Loadlatch4_Compact(); FLASH_Write_Loadlatch4_Compact(); FLASH_Write_DoWrite(); */ //--- erase the block first FLASH_Erase32(0x006000); //--- write compact format to flash FLASH_Write_Compact(0x006000, pv1, 36); //--- read compact format pv1 = cArr2; FLASH_Read4_Compact(0x006000, pv1); pv1 += 12; FLASH_Read4_Compact(0x006008, pv1); pv1 += 12; FLASH_Read4_Compact(0x006010, pv1); pv1 += 12; *pv1 = 0; //termination //--- show what has been written i = 0; UART1_Init(9600); // UART1_Write_Text("Start"); UART1_Write(10); UART1_Write(13); while(cArr2[i]) { bb = cArr2[i++]; UART1_Write(bb); } //--- now for some non-compact flash-write pv1 = iArr; //--- erase the block first FLASH_Erase32(0x006100); FLASH_Write_Init(0x006100, pv1); FLASH_Write_Loadlatch4(); FLASH_Write_Loadlatch4(); FLASH_Write_DoWrite(); }
What do you think about this topic ? Send us feedback!