Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
flash_helpers.cpp
Go to the documentation of this file.
1/*
2 * flash_helpers.cpp
3 *
4 * Created on: 31.01.2020
5 * Author: Yannick
6 */
7#include "flash_helpers.h"
8#include "eeprom_addresses.h"
9#include <vector>
10#include "mutex.hpp"
11#include <span>
12
14// Flash helpers
15
16// TODO sometimes on F4 chips when writing HAL_FLASH_ERROR_PGS and HAL_FLASH_ERROR_PGP occur and it is not writing
17
18
19#ifdef USE_EEPROM_EMULATION
20
31 __HAL_FLASH_DATA_CACHE_DISABLE();
32 __HAL_FLASH_DATA_CACHE_RESET();
33 __HAL_FLASH_DATA_CACHE_ENABLE();
34}
35
37 HAL_FLASH_Unlock();
38 bool res = (EE_Format() == HAL_OK);
40 HAL_FLASH_Lock();
41 return res;
42}
43
46__weak bool Flash_Init(){
47 HAL_FLASH_Unlock();
48 // Clear all the error flags
49 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
50 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
51 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
52 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
53 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
54 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
55
56 bool state = (EE_Init() == EE_OK);
58 HAL_FLASH_Lock();
59 return state;
60}
61/*
62 * Writes a variable to eeprom emulation adr
63 * Returns true on success or false if variable is the same or error
64 */
65bool Flash_Write(uint16_t adr,uint16_t dat){
66 //flashMutex.Lock();
67 uint16_t buf;
68 uint16_t readRes = EE_ReadVariable(adr, &buf);
69 bool res = false;
70 if(readRes == 1 || (readRes == 0 && buf != dat) ){ // Only write if var updated
71 HAL_FLASH_Unlock();
72 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
73 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
74 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
75 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
76 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
77 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
78 Flash_InvalidateDataCache(); // Invalidate before writing because EE_ReadVariable just cached the flash page
79 if(EE_WriteVariable(adr, dat) == HAL_OK){
80 res = true;
81 }
83 HAL_FLASH_Lock();
84
85 }
86 //flashMutex.Unlock();
87 return res;
88
89}
90
91
92/*
93 * Reads a variable from eeprom emulation and returns true on success
94 */
95bool Flash_Read(uint16_t adr,uint16_t *buf,bool checkempty){
96 //flashMutex.Lock();
97 bool res = EE_ReadVariable(adr, buf) == 0;
98 //flashMutex.Unlock();
99 return res;
100}
101
102/*
103 * Reads a variable or if it does not exist default is written
104 */
105bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
106 if(EE_ReadVariable(adr, buf) != 0){
107 *buf = def;
108 HAL_FLASH_Unlock();
109 // Clear all the error flags
110 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
111 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
112 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
113 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
114 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
115 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
116 Flash_InvalidateDataCache(); // Invalidate before writing because EE_ReadVariable just cached the flash page
117 EE_WriteVariable(adr, def);
119 HAL_FLASH_Lock();
120 return false;
121 }
122 return true;
123}
124
125#elif defined(I2C_PORT_EEPROM)
126uint8_t i2cBufferEeprom[sizeof(uint16_t)] = {0};
127#include "string.h" // Memcpy
128#include "cassert"
129#include <array>
130#include "I2C.h"
132extern I2CPort i2cport_int;
133
137bool I2C_EEPROM_Write16(uint16_t devAdr,uint16_t adr, uint16_t dat){
138 uint16_t dataLength = sizeof(dat);
139 memcpy(i2cBufferEeprom,&dat, dataLength);
140 uint32_t adrAbs = adr;
141 adrAbs *= sizeof(dat)/I2C_EEPROM_DATA_SIZE;
142 uint32_t curAdr = adrAbs;
143 assert(adrAbs < I2C_EEPROM_SIZE);
144
145 // Do segmented writes
146
147 bool res = false;
148 while(curAdr < adrAbs+dataLength){
149// i2cport_int.isDeviceReady(i2cdeveeprom, I2C_EEPROM_ADR, 100, I2C_EEPROM_TIMEOUT,false)
150 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, devAdr, 100, I2C_EEPROM_TIMEOUT,false)){
151 vTaskDelay(1);
152 }
153 uint16_t i2cAdr = devAdr;
154 uint16_t writeAdr = curAdr;
155 if(curAdr > 0xffff){
156 writeAdr = curAdr & 0xffff;
157 i2cAdr |= 0x02; // A17 bit
158 }
159 uint16_t wLen = std::min<uint16_t>(dataLength,I2C_EEPROM_PAGEWRITE_SIZE - (adrAbs % I2C_EEPROM_PAGEWRITE_SIZE));
160 res = i2cport_int.writeMem(&i2cdeveeprom, i2cAdr, writeAdr, I2C_EEPROM_ADR_SIZE, i2cBufferEeprom, wLen, I2C_EEPROM_TIMEOUT, false);
161 curAdr+=wLen;
162 if(!res){
163 break;
164 }
165 }
166
167 return res;
168}
169
173bool I2C_EEPROM_Read16(uint16_t devAdr,uint16_t adr,uint16_t *buf, bool checkempty){
174 uint32_t adrAbs = (adr * sizeof(*buf)/I2C_EEPROM_DATA_SIZE);
175 assert(adrAbs < I2C_EEPROM_SIZE);
176 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, devAdr, 100, I2C_EEPROM_TIMEOUT,false)){
177 vTaskDelay(1);
178 }
179 uint16_t i2cAdr = devAdr;
180 uint16_t datAdr = adrAbs & 0xffff;
181 if(adrAbs > 0xffff){
182 i2cAdr |= 0x02; // If curAdr > 0xffff set bit 1 of addr high
183 }
184 bool res = i2cport_int.readMem(&i2cdeveeprom, i2cAdr, datAdr, I2C_EEPROM_ADR_SIZE, i2cBufferEeprom, 2, I2C_EEPROM_TIMEOUT, false);
185
186 if(checkempty){
187 bool empty = true;
188 for(uint8_t i = 0;i<sizeof(i2cBufferEeprom);i++){
189 if(i2cBufferEeprom[i] != I2C_EEPROM_ERASED){
190 empty = false;
191 break;
192 }
193 }
194 res = empty ? false : res;
195 }
196 if(res) // Only copy if success
198 return res;
199}
200
201bool Flash_Write(uint16_t adr,uint16_t dat){
202 return I2C_EEPROM_Write16(I2C_EEPROM_ADR,adr+I2C_EEPROM_OFS,dat);
203}
204bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
205 if(!Flash_Read(adr,buf)){
206 return Flash_Write(adr, def);
207 }
208 return true;
209}
210
213bool Flash_Read(uint16_t adr,uint16_t *buf, bool checkempty){
214 return I2C_EEPROM_Read16(I2C_EEPROM_ADR,adr+I2C_EEPROM_OFS,buf,checkempty);
215}
216
221 bool flag = true;
222 std::array<uint8_t,I2C_EEPROM_PAGEWRITE_SIZE> eraseBuf;
223 eraseBuf.fill(I2C_EEPROM_ERASED);
224 for(uint32_t i=I2C_EEPROM_OFS;i<I2C_EEPROM_SIZE;i+=I2C_EEPROM_PAGEWRITE_SIZE){
225 uint16_t datAdr = i & 0xffff;
226 uint16_t devAdr = I2C_EEPROM_ADR;
227 if(i > 0xffff){
228 devAdr |= 0x02;
229 }
230 bool res = i2cport_int.writeMem(&i2cdeveeprom, devAdr, datAdr, I2C_EEPROM_ADR_SIZE, eraseBuf.data(), std::min<int>(I2C_EEPROM_PAGEWRITE_SIZE,I2C_EEPROM_SIZE-i), I2C_EEPROM_TIMEOUT, false);
231 if(!res){
232 flag = false;
233 }else{
234 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, I2C_EEPROM_ADR, 100, I2C_EEPROM_TIMEOUT,false)){
235 vTaskDelay(1);
236 }
237 }
238 }
239 return flag;
240}
242 return i2cport_int.isDeviceReady(&i2cdeveeprom, I2C_EEPROM_ADR, 50, I2C_EEPROM_TIMEOUT,false);
243}
244
245#else
246// No flash mode defined
247
248__weak bool Flash_Write(uint16_t adr,uint16_t dat){
249 return true;
250}
251__weak bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
252 return true;
253}
254__weak bool Flash_Read(uint16_t adr,uint16_t *buf){
255 return false;
256}
257__weak bool Flash_Format(){
258 return false;
259}
260__weak bool Flash_Init(){
261 return true;
262}
263#endif
264/*
265 * Dumps all set variables from flash to a vector
266 * does by default not include certain calibration constants that could break something if imported on a different board
267 */
268void Flash_Dump(std::vector<std::tuple<uint16_t,uint16_t>> *result,bool includeAll){
269 uint16_t amount = NB_EXPORTABLE_ADR;
270 const uint16_t* list = exportableFlashAddresses;
271 if(includeAll){
272 amount = NB_OF_VAR;
273 list = VirtAddVarTab;
274 }
275 //extern uint16_t VirtAddVarTab[NB_OF_VAR];
276 //std::vector<std::pair<uint16_t,uint16_t>> result;
277
278 for(uint32_t i = 0;i<amount ; i++){
279 uint16_t v;
280 uint16_t adr = list[i];
281
282 if(Flash_Read(adr,&v)){
283 result->push_back(std::tuple<uint16_t,uint16_t>{adr,v});
284 }
285
286 }
287}
288
289
290/*
291 * OTP Helper functions.
292 * Some chips have internal OTP sections, others may need custom implementations
293 * Page size and address required
294 */
295#if defined(FLASH_OTP_BASE) && defined(FLASH_OTP_END) && defined(OTPMEMORY)
296// This chip has an OTP section in main flash.
297
298__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
299// FLASH_OTP_BASE
300// FLASH_OTP_END
301 uint32_t adr = (FLASH_OTP_BASE+adroffset*sizeof(uint64_t));
302 if(adr > FLASH_OTP_END){
303 return false; // Error
304 }
305 uint64_t curval = *(uint64_t*)adr;
306 if(curval != 0xffffffffffffffff){
307 return false;
308 }
309 if(HAL_FLASH_Unlock()!=HAL_OK) return false;
310 //bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, dat) == HAL_OK;
311 bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, (uint32_t)(dat)) == HAL_OK;
312 success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr+4, (uint32_t)(dat >> 32)) == HAL_OK && success;
313 HAL_FLASH_Lock();
314 return success;
315}
316
317
318__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
319 uint32_t adr = (FLASH_OTP_BASE+adroffset*sizeof(uint64_t));
320 if(adr > FLASH_OTP_END){
321 return false; // Error
322 }
323 uint64_t curval = *(uint64_t*)adr;
324 *dat = curval;
325 return true;
326}
327#elif defined(I2C_EEPROM_OTP_ADR) && defined(I2C_PORT_EEPROM)
328// I2C EEPROM OTP/ID memory
329__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
330 // Write 4 x 16b
331 for(uint8_t i = 0; i < 4; i++){
332 bool res = I2C_EEPROM_Write16(I2C_EEPROM_OTP_ADR, 4*adroffset + (i), (dat >> (i*16)) & 0xffff);
333 if(!res){
334 return false;
335 }
336 }
337
338 return true;
339}
340
341
342__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
343 uint64_t val = 0;
344 for(uint8_t i = 0; i < 4; i++){
345 uint16_t tdat = 0;
346 bool res = I2C_EEPROM_Read16(I2C_EEPROM_OTP_ADR, 4*adroffset + (i), &tdat,false);
347 val |= (uint64_t)tdat << (i*16);
348 if(!res){
349 return false;
350 }
351 }
352 *dat = val;
353 return true;
354}
355#else
356__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
357 return false;
358}
359
360
361__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
362 return false;
363}
364
365#endif
366
367#ifndef FLASH_FACTORY_DEFAULTS_OVERRIDE
373const std::array<const std::pair<uint16_t,uint16_t>,0> empty_flash_defaults; // Empty
374const std::span<const std::pair<uint16_t,uint16_t>> flash_factory_defaults = empty_flash_defaults;
375#endif
376
381 for(const std::pair<uint16_t,uint16_t> &kv : flash_factory_defaults){
382 Flash_Write(kv.first, kv.second); // Try to write values
383 }
384}
uint8_t adr
Definition I2C.h:43
I2CPort i2cport_int
const uint16_t VirtAddVarTab[NB_OF_VAR]
const uint16_t exportableFlashAddresses[NB_EXPORTABLE_ADR]
__weak bool Flash_Init()
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty)
static void Flash_InvalidateDataCache()
bool Flash_Format()
bool Flash_ReadWriteDefault(uint16_t adr, uint16_t *buf, uint16_t def)
bool Flash_Write(uint16_t adr, uint16_t dat)
bool I2C_EEPROM_Read16(uint16_t devAdr, uint16_t adr, uint16_t *buf, bool checkempty)
__weak bool OTP_Read(uint16_t adroffset, uint64_t *dat)
void Flash_Write_Defaults()
const std::array< const std::pair< uint16_t, uint16_t >, 0 > empty_flash_defaults
void Flash_Dump(std::vector< std::tuple< uint16_t, uint16_t > > *result, bool includeAll)
uint8_t i2cBufferEeprom[sizeof(uint16_t)]
I2CDevice i2cdeveeprom
cpp_freertos::MutexStandard flashMutex
__weak bool OTP_Write(uint16_t adroffset, uint64_t dat)
bool I2C_EEPROM_Write16(uint16_t devAdr, uint16_t adr, uint16_t dat)
const std::span< const std::pair< uint16_t, uint16_t > > flash_factory_defaults
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t *Data)
Returns the last stored variable data, if found, which correspond to the passed virtual address.
Definition eeprom.c:370
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
Writes/upadtes variable data in EEPROM.
Definition eeprom.c:429
HAL_StatusTypeDef EE_Format()
Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE.
Definition eeprom.c:453
uint16_t EE_Init(void)
Restore the pages to a known good state in case of page's status corruption after a power loss.
Definition eeprom.c:79
static void * memcpy(void *dst, const void *src, size_t n)
Definition ringbuffer.c:8