Flash Addresses
Internal flash is addressed by byte, but accessed by 32-bit values. That means that the first value is at address zero and the second is at address 4. (These are flash addresses—not to be confused with Modbus addresses.)
Following are some important flash addresses:
Address Name |
Address |
Length |
|
User Area |
0x0 |
2 MB |
Key: 0x6615E336 (1712710454 in decimal) |
Reserved Area |
0x200000 |
2 MB |
|
Calibration Constants (in Reserved Area) |
0x3C7000 |
4 kB |
Key: 0x43A24C42 (1134709826 in decimal) |
Reading
To read from flash, write the desired address to INTERNAL_FLASH_READ_POINTER and then read an even number of registers from INTERNAL_FLASH_READ:
Name |
Start Address |
Type |
Access |
INTERNAL_FLASH_READ_POINTER
The address in internal flash that reads will start from.
|
61810 |
UINT32 |
R/W
|
INTERNAL_FLASH_READ_POINTER
- Address: 61810
The address in internal flash that reads will start from.
- Data type: UINT32 (type index = 1)
-
Readable and writable
|
INTERNAL_FLASH_READ
Data read from internal flash.
|
61812 |
UINT32 |
R
|
INTERNAL_FLASH_READ
- Address: 61812
Data read from internal flash.
- Data type: UINT32 (type index = 1)
-
Read-only
|
To read a large number of registers from INTERNAL_FLASH_READ (such as more than ~25 registers), you must split the read into multiple packets while updating INTERNAL_FLASH_READ_POINTER each time. See the LJM explanation for how to perform large reads.
Writing and Erasing
Key
For a region to be written to or to be erased, the key for that region must be written to the INTERNAL_FLASH_KEY register:
Name |
Start Address |
Type |
Access |
INTERNAL_FLASH_KEY
Sets the region of internal flash to which access is allowed.
|
61800 |
UINT32 |
R/W
|
INTERNAL_FLASH_KEY
- Address: 61800
Sets the region of internal flash to which access is allowed.
- Data type: UINT32 (type index = 1)
-
Readable and writable
|
The key prevents accidental overwrites. The value in INTERNAL_FLASH_KEY will be cleared when the Modbus packet that wrote it has been fully processed, so INTERNAL_FLASH_KEY must be written in the same packet that does INTERNAL_FLASH_WRITE or INTERNAL_FLASH_ERASE. The LJM Multiple Value functions simplify this. The LJM Multiple Value functions do not correctly split large reads (such as more than ~15 registers), so see the LJM explanation for how to perform large writes.
Writing
To write to flash, the area to be written to must first be erased. Once erased, write the key for the desired region to INTERNAL_FLASH_KEY, write the desired address to INTERNAL_FLASH_WRITE_POINTER, and then write an even number of registers to INTERNAL_FLASH_WRITE:
Name |
Start Address |
Type |
Access |
INTERNAL_FLASH_WRITE_POINTER
Address in internal flash where writes will begin.
|
61830 |
UINT32 |
R/W
|
INTERNAL_FLASH_WRITE_POINTER
- Address: 61830
Address in internal flash where writes will begin.
- Data type: UINT32 (type index = 1)
-
Readable and writable
|
INTERNAL_FLASH_WRITE
Data written here will be written to internal flash. This register is a buffer.
|
61832 |
UINT32 |
W
|
INTERNAL_FLASH_WRITE
- Address: 61832
Data written here will be written to internal flash. This register is a buffer.
- Data type: UINT32 (type index = 1)
-
Write-only
- This register is a Buffer Register
|
Erasing
Flash is erased 4 kB at a time. Erasing sets all bits to 1. To erase a 4 kB region, write the key for the desired region to INTERNAL_FLASH_KEY and the desired address to INTERNAL_FLASH_ERASE:
Name |
Start Address |
Type |
Access |
INTERNAL_FLASH_ERASE
Erases a 4k section of internal flash starting at the specified address. This register is a buffer.
|
61820 |
UINT32 |
W
|
INTERNAL_FLASH_ERASE
- Address: 61820
Erases a 4k section of internal flash starting at the specified address. This register is a buffer.
- Data type: UINT32 (type index = 1)
-
Write-only
- This register is a Buffer Register
|
The address will be rounded down to the nearest 4 kB boundary. Boundaries are easy to identify when the address is displayed in hexadecimal because the lower three digits will be zero. 4 kB is hexadecimal is 0x1000.
Endurance
Flash memory can only be erased so many times before bit errors will start to occur; it is important not to erase or write flash needlessly. Typical life of flash memory is at least 10,000 cycles.
Examples
Erase address 0, write to address 0 and 4, and read address 0 and 4:
// Erase address 0
numFrames = 2
aNames[0] = "INTERNAL_FLASH_KEY"
aNames[1] = "INTERNAL_FLASH_ERASE"
aWrites[0] = LJM.CONSTANTS.WRITE
aWrites[1] = LJM.CONSTANTS.WRITE
aNumValues[0] = 1
aNumValues[1] = 1
aValues[0] = 1712710454
aValues[1] = 0
LJM.eNames(handle, numFrames, aNames, aWrites, aNumValues, aValues, errorAddress)
// Write address 0 = 1234,
// write address 4 = 5678
numFrames = 3
aNames[0] = "INTERNAL_FLASH_KEY"
aNames[1] = "INTERNAL_FLASH_WRITE_POINTER"
aNames[2] = "INTERNAL_FLASH_WRITE"
aWrites[0] = LJM.CONSTANTS.WRITE
aWrites[1] = LJM.CONSTANTS.WRITE
aWrites[2] = LJM.CONSTANTS.WRITE
aNumValues[0] = 1
aNumValues[1] = 1
aNumValues[2] = 2
aValues[0] = 1712710454
aValues[1] = 0
aValues[2] = 1234
aValues[3] = 5678
LJM.eNames(handle, numFrames, aNames, aWrites, aNumValues, aValues, errorAddress)
// Read address 0 and address 4
numFrames = 2
aNames[0] = "INTERNAL_FLASH_READ_POINTER"
aNames[1] = "INTERNAL_FLASH_READ"
aWrites[0] = LJM.CONSTANTS.WRITE
aWrites[1] = LJM.CONSTANTS.READ
aNumValues[0] = 1
aNumValues[1] = 2
aValues[0] = 0
aValues[1] = 9999
aValues[2] = 9999
LJM.eNames(handle, numFrames, aNames, aWrites, aNumValues, aValues, errorAddress)
Console.WriteLine(aValues[1], aValues[2])
// Output:
// 1234 5678
For an embedded Lua scripting example see write_read_flash.lua.