I have been scratching my head over an unexpected behavior in how data is written and read from the flash memory using the FlashIAPBlockDevice.h library.
The read(), erase() and program() functions all take an address. The documentation is very vague about exactly how this is used. When I program them to 0 for erase(), program() and read() everything works fine. I am able to write data to this location and read it back.
However, if I want to read/write to somewhere else, it never works. I think the problem is how the address is interpreted in each of these functions. The erase uses 4K blocks (for RP2040), the program() uses 256Byte blocks, and the read uses 1Byte blocks. However, even adjusting for this I cannot make it work. When I run with addr_offset=0 I get the following output:
4096 256 1
0: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
48: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
64: 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
80: 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
96: 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
112: 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
128: 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
144: 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
160: 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
176: 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
192: 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
208: 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
224: 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
240: 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
Which is correct. I'm writing 256Bytes of data which is just the numbers from 0 to 255.
However, if I change addr_offset=1 I get garbage back. I've tried changing the addr_offset for the read() to offset in 4K blocks, 256Byte blocks, etc. I even scanned the first 1MByte of the flash memory and could not find the data I had written.
Can someone explain how the read(), program() and erase() routines use the address parameter?
Here is my code, which works (addr_offset=0). I've tried changing the value passed to erase(), program() and read() in many, many different possible ways with no success.
#include <mbed.h>
#include <Arduino.h>
#include <FlashIAP.h>
#include <FlashIAPBlockDevice.h>
#pragma once
using namespace mbed;
#define BUFFER_SIZE 256
uint8_t write_buffer[BUFFER_SIZE];
uint8_t read_buffer[BUFFER_SIZE];
uint32_t mFlashDeviceSize;
uint32_t mFlashMemBase;
uint32_t mFlashMemSize;
void getFlashIAPLimits()
{
// Alignment lambdas
auto align_down = [](uint64_t val, uint64_t size) {
return (((val) / size)) * size;
};
auto align_up = [](uint32_t val, uint32_t size) {
return (((val - 1) / size) + 1) * size;
};
size_t flash_size;
uint32_t flash_start_address;
uint32_t start_address;
uint32_t sector_size;
FlashIAP flash;
auto result = flash.init();
if (result != 0)
return;
// Find the start of first sector after text area
sector_size = flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR);
start_address = align_up(FLASHIAP_APP_ROM_END_ADDR, sector_size);//Where free flash starts in memory space
flash_start_address = flash.get_flash_start(); //where flash starts in memory space
flash_size = flash.get_flash_size(); //total size of flash
result = flash.deinit();
int available_size = flash_start_address + flash_size - start_address; //available flash above APP
if (available_size % (sector_size * 2)) //Align to 2X of sector size
{
available_size = align_down(available_size, sector_size * 2);
}
mFlashDeviceSize=flash_size;
mFlashMemBase= start_address;
mFlashMemSize= available_size;
}
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
delay(1500);
getFlashIAPLimits(); //
FlashIAPBlockDevice flashDevice(mFlashMemBase, mFlashMemSize);
flashDevice.init();
uint32_t mEraseBlockSize = flashDevice.get_erase_size();
uint32_t mProgramBlockSize = flashDevice.get_program_size();
uint32_t mReadBlockSize = flashDevice.get_read_size();
Serial.println(String(mEraseBlockSize)+" "+String(mProgramBlockSize)+" "+String(mReadBlockSize));
uint32_t requiredEraseBlocks = ceil((BUFFER_SIZE) / (float) mEraseBlockSize);
uint32_t requiredProgramBlocks = ceil((BUFFER_SIZE) / (float) mProgramBlockSize);
uint32_t actualDataSize = requiredProgramBlocks * mProgramBlockSize;
uint32_t requiredReadBlocks = ceil((BUFFER_SIZE) / (float) mReadBlockSize);
uint32_t addr_offset=0;
//setup up write buffer and clear read buffer
for(uint16_t i=0;i<BUFFER_SIZE;i++)
{
write_buffer[i]=i;
read_buffer[i]=0;
}
//erase flash and write buffer to location addr_offset
flashDevice.erase(addr_offset, requiredEraseBlocks * mEraseBlockSize);
flashDevice.program(write_buffer, addr_offset, actualDataSize);
//read back from location addr_offset
actualDataSize = requiredReadBlocks * mReadBlockSize;
flashDevice.read(read_buffer,addr_offset, actualDataSize);
//display result in rows of 16 values
for(uint16_t i=0;i<BUFFER_SIZE>>4;i++)
{
Serial.print(String(i*16)+": ");
for(uint8_t j=0;j<16;j++)
{
Serial.print(String((uint8_t)(read_buffer[i*16+j]))+" ");
}
Serial.println(" ");
}
}
void loop() {
// put your main code here, to run repeatedly:
}