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: "regular" and "compact". In the "regular" 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 mikroBasic PRO for dsPIC30/33 and PIC24 offers two sets of Flash handling functions: "regular" and "compact".
Using the "regular" 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" 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-instructions (1024 addresses, 1536 bytes) memory blocks, which means that the block start address should be a multiply of 1024 (i.e. have 10 lower bits set to zero).
- Data is read and written in 64-instructions (128 addresses, 192 bytes) blocks.This means that the block start address should be a multiply of 128 (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 mikroBasic PRO for dsPIC30/33 and PIC24 offers two sets of Flash handling functions: "regular" and "compact".
Using the "regular" 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" functions have_Compact
as name suffix.
24F04KA201 and 24F16KA102 Family Specifics :
- These MCU's have their Flash memory organized into memory blocks of 32 instructions (96 bytes), unlike other PIC24 devices.
- Erasing can be done only in 32-instructions (64 addresses, 96 bytes) memory blocks, which 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 32-instructions (64 addresses, 96 bytes) blocks. This means that the block start address should be a multiply of 64 (i.e. have 6 lower bits set to zero).
- Unlike other PIC24 devices, writing or erasing one block of data (32 instructions), is followed by erasing the memory block of the same size (32 instructions).
Library Routines
dsPIC30 Functions
- FLASH_Write_Block
- FLASH_Write_Compact
- FLASH_Write_Init
- FLASH_Write_Loadlatch4
- FLASH_Write_Loadlatch4_Compact
- FLASH_Write_DoWrite
PIC24 and dsPIC33 Functions
dsPIC30 Functions
FLASH_Erase32
Prototype |
sub procedure FLASH_Erase32(dim flash_address as longint) |
---|---|
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_Block
Prototype |
sub procedure FLASH_Write_Block(dim flash_address as longint, dim data_address as word) |
---|---|
Description |
Fills one writeable block of Flash memory (4 instructions, 8 addresses, 12 bytes) in the "regular" 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 |
dim flash_address as longint cArr as string[4] ptr_data as word ... flash_address = 0x006000 cArr = "ABCD" ptr_data = @cArr FLASH_Write_Block(flash_address, ptr_data) |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Compact
Prototype |
sub procedure FLASH_Write_Compact(dim flash_address as longint, dim data_address as word, dim bytes as word) |
---|---|
Description |
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. One latch block contains 4 instructions (8 addresses, 12 bytes). Up to 8 latch blocks can be written in one round, resulting in a total of 8*12 = 96 bytes. This method uses all available bytes of the program FLASH memory, including those that are not mapped to address space (every 3rd byte). |
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 |
dim flash_address as longint cArr as string[36] ptr_data as word ... flash_address = 0x006000 cArr = "mikroElektronika12mikroElektronika34" ptr_data = @cArr FLASH_Write_Compact(flash_address, ptr_data, 36) |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Init
Prototype |
sub procedure FLASH_Write_Init(dim flash_address as longint, dim data_address as word) |
---|---|
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 |
const iArr as word[8] = ("m", "i", "k", "r", "o", "E", "l", "e") dim ptr_data as word ... ptr_data = @iArr FLASH_Write_Init(0x006100, ptr_data) 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 |
sub procedure FLASH_Write_Loadlatch4() |
---|---|
Description |
Loads the current RTSP write latch with data (4 instructions, 8 addresses, 12 bytes). The data is filled in the "regular" 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 |
const iArr as word[8] = ("m", "i", "k", "r", "o", "E", "l", "e") dim ptr_data as word ... ptr_data = @iArr FLASH_Write_Init(0x006100, ptr_data) FLASH_Write_Loadlatch4() FLASH_Write_Loadlatch4() FLASH_Write_DoWrite() |
Notes |
None. |
FLASH_Write_Loadlatch4_Compact
Prototype |
sub procedure 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. |
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 |
const iArr as word[8] = ("m", "i", "k", "r", "o", "E", "l", "e") dim ptr_data as word ... ptr_data = @iArr FLASH_Write_Init(0x006100, ptr_data) FLASH_Write_Loadlatch4_Compact() FLASH_Write_Loadlatch4_Compact() FLASH_Write_DoWrite() |
Notes |
None. |
FLASH_Write_DoWrite
Prototype |
sub procedure 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 |
const iArr as word[8] = ("m", "i", "k", "r", "o", "E", "l", "e") dim ptr_data as word ... ptr_data = @iArr FLASH_Write_Init(0x006100, ptr_data) FLASH_Write_Loadlatch4() FLASH_Write_Loadlatch4() FLASH_Write_DoWrite() |
Notes |
None. |
FLASH_Read4
Prototype |
sub procedure FLASH_Read4(dim flash_address as longint, dim write_to as word) |
---|---|
Description |
Reads one latch row (4 instructions, 8 addresses) in the "regular" mode. |
Parameters |
|
Returns |
Starting address of RAM buffer for storing read data. |
Requires |
Nothing. |
Example |
dim flash_address as longint cArr as word[4] ptr_data as word ... flash_address = 0x006000 ptr_data = @cArr FLASH_Read4(flash_address, ptr_data) |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read4_Compact
Prototype |
sub procedure FLASH_Read4_Compact(dim flash_address as longint, dim write_to as word) |
---|---|
Description |
Reads one latch row (4 instructions, 8 addresses) in the "compact" mode. |
Parameters |
|
Returns |
Starting address of RAM buffer for storing read data. |
Requires |
Nothing. |
Example |
dim flash_address as longint cArr as word[8] ptr_data as word ... flash_address = 0x006000 ptr_data = @cArr FLASH_Read4_Compact(flash_address, ptr_data) |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
PIC24 and dsPIC33 Functions
FLASH_Erase
Prototype |
sub procedure FLASH_Erase(dim address as longint) |
---|---|
Description |
Erases one block (512 instructions, 1024 addresses, 1536 bytes) from the program FLASH memory. |
Parameters |
|
Returns |
Nothing. |
Requires |
Nothing. |
Example |
'--- erase the flash memory block, starting from address 0x006400 dim flash_address as longint ... flash_address = 0x006400 FLASH_Erase(flash_address) |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write
Prototype |
sub procedure FLASH_Write(dim address as longint, dim byref data_ as word[64]) |
---|---|
Description |
Fills one writeable block of Flash memory (64 instructions, 128 addresses, 192 bytes) in the "regular" 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 |
dim data_ as word[64] = {"m", "i", "k", "r", "o", "E", "l", "e", "k", "t", "r", "o", "n", "i", "k", "a"} ... FLASH_Write(0x006500, data_) |
Notes |
The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Compact
Prototype |
sub procedure FLASH_Write_Compact(dim address as longint, dim byref data_ as byte[192]) |
---|---|
Description |
Fills a portion of Flash memory (64 instructions, 128 addresses, 192 bytes) using the dsPIC33 and PIC24s RTSP (Run Time Self Programming) module, in the "compact" manner. This method uses all available bytes of the program FLASH memory, including those that are not mapped to address space (every 3rd byte). |
Parameters |
|
Returns |
Nothing. |
Requires |
The block to be written to must be erased first, either from the user code (FLASH_Erase), 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 |
dim data_ as string[192] ... data_ = "supercalifragillisticexpialidotiousABCDEFGHIJKLMNOPRSTUVWXYZ1234" FLASH_Write_Compact(0x006400, data_) |
Notes |
The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read
Prototype |
sub procedure FLASH_Read(dim address as longint, dim byref write_to as word[100], dim NoWords as word) |
---|---|
Description |
Reads required number of words from the flash memory in the "regular" mode. |
Parameters |
|
Returns |
Address of RAM buffer for storing read data. |
Requires | |
Example |
dim Buffer as word[10] start_address as longint ... FLASH_Write(0x006500, data) 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 |
sub procedure FLASH_Read_Compact(dim address as longint, dim byref write_to as byte[100], dim NoBytes as word) |
---|---|
Description |
Reads required number of bytes from the flash memory in the "compact" mode. |
Parameters |
|
Returns |
Address of RAM buffer for storing read data. |
Requires | |
Example |
dim Buffer as byte[10] start_address as longint ... FLASH_Write(0x006500, data) 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). |
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.
program Flash_Test dim WriteWordArr as word[8] WriteByteArr as byte[32] ReadByteArr as byte[40] RealongwordArr as word[20] pw as ^word pb as ^byte i as word temp_byte as byte main: ' Initialize arrays WriteWordArr[0] = "*" WriteWordArr[1] = "m" WriteWordArr[2] = "i" WriteWordArr[3] = "k" WriteWordArr[4] = "r" WriteWordArr[5] = "o" WriteWordArr[6] = "E" WriteWordArr[7] = "*" WriteByteArr[0] = "m" WriteByteArr[1] = "i" WriteByteArr[2] = "k" WriteByteArr[3] = "r" WriteByteArr[4] = "o" WriteByteArr[5] = "E" WriteByteArr[6] = "l" WriteByteArr[7] = "e" WriteByteArr[8] = "k" WriteByteArr[9] = "t" WriteByteArr[10] = "r" WriteByteArr[11] = "o" WriteByteArr[12] = "n" WriteByteArr[13] = "i" WriteByteArr[14] = "k" WriteByteArr[15] = "a" WriteByteArr[16] = " " WriteByteArr[17] = "F" WriteByteArr[18] = "l" WriteByteArr[19] = "a" WriteByteArr[20] = "s" WriteByteArr[21] = "h" WriteByteArr[22] = " " WriteByteArr[23] = "e" WriteByteArr[24] = "x" WriteByteArr[25] = "a" WriteByteArr[26] = "m" WriteByteArr[27] = "p" WriteByteArr[28] = "l" WriteByteArr[29] = "e" WriteByteArr[30] = "." WriteByteArr[31] = 0 pb = @WriteByteArr '--- erase the block first FLASH_Erase32(0x006000) pb = @WriteByteArr[0] FLASH_Write_Compact(0x006000, pb, 36) (* 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() *) '--- read compact format pb = @ReadByteArr FLASH_Read4_Compact(0x006000, pb) pb = pb + 12 FLASH_Read4_Compact(0x006008, pb) pb = pb + 12 FLASH_Read4_Compact(0x006010, pb) pb = pb + 12 pb^ = 0 'termination UART1_Init(9600) UART1_Write(10) UART1_Write(13) UART1_Write_Text("Start") UART1_Write(10) UART1_Write(13) i = 0 while(ReadByteArr[i]) temp_byte = ReadByteArr[i] UART1_Write(temp_byte) Inc(i) wend '--- now for some non-compact flash-write pw = @WriteWordArr '--- erase the block first FLASH_Erase32(0x006100) FLASH_Write_Init(0x006100, pw) FLASH_Write_Loadlatch4() FLASH_Write_Loadlatch4() FLASH_Write_DoWrite() '--- read non-compact format pw = @RealongwordArr[0] FLASH_Read4(0x006100, pw) pw = pw + 4 FLASH_Read4(0x006108, pw) pw = pw + 4 pw^ = 0 'termination '--- show what has been written UART1_Write(10) UART1_Write(13) i = 0 while(RealongwordArr[i]<>0) temp_byte = RealongwordArr[i] UART1_Write(temp_byte) i = i + 1 wend end.
What do you think about this topic ? Send us feedback!