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
25 HAL_FLASH_Unlock();
26 bool res = (EE_Format() == HAL_OK);
27 HAL_FLASH_Lock();
28 return res;
29}
30
33__weak bool Flash_Init(){
34 HAL_FLASH_Unlock();
35 // Clear all the error flags
36 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
37 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
38 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
39 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
40 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
41 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
42
43 bool state = (EE_Init() == EE_OK);
44 HAL_FLASH_Lock();
45 return state;
46}
47/*
48 * Writes a variable to eeprom emulation adr
49 * Returns true on success or false if variable is the same or error
50 */
51bool Flash_Write(uint16_t adr,uint16_t dat){
52 //flashMutex.Lock();
53 uint16_t buf;
54 uint16_t readRes = EE_ReadVariable(adr, &buf);
55 bool res = false;
56 if(readRes == 1 || (readRes == 0 && buf != dat) ){ // Only write if var updated
57 HAL_FLASH_Unlock();
58 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
59 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
60 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
61 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
62 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
63 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
64 if(EE_WriteVariable(adr, dat) == HAL_OK){
65 res = true;
66 }
67 HAL_FLASH_Lock();
68
69 }
70 //flashMutex.Unlock();
71 return res;
72
73}
74
75
76/*
77 * Reads a variable from eeprom emulation and returns true on success
78 */
79bool Flash_Read(uint16_t adr,uint16_t *buf,bool checkempty){
80 //flashMutex.Lock();
81 bool res = EE_ReadVariable(adr, buf) == 0;
82 //flashMutex.Unlock();
83 return res;
84}
85
86/*
87 * Reads a variable or if it does not exist default is written
88 */
89bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
90 if(EE_ReadVariable(adr, buf) != 0){
91 *buf = def;
92 HAL_FLASH_Unlock();
93 // Clear all the error flags
94 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
95 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPERR);
96 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
97 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
98 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGPERR);
99 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
100 EE_WriteVariable(adr, def);
101 HAL_FLASH_Lock();
102 return false;
103 }
104 return true;
105}
106
107#elif defined(I2C_PORT_EEPROM)
108uint8_t i2cBufferEeprom[sizeof(uint16_t)] = {0};
109#include "string.h" // Memcpy
110#include "cassert"
111#include <array>
112#include "I2C.h"
114extern I2CPort i2cport_int;
115
119bool I2C_EEPROM_Write16(uint16_t devAdr,uint16_t adr, uint16_t dat){
120 uint16_t dataLength = sizeof(dat);
121 memcpy(i2cBufferEeprom,&dat, dataLength);
122 uint32_t adrAbs = adr;
123 adrAbs *= sizeof(dat)/I2C_EEPROM_DATA_SIZE;
124 uint32_t curAdr = adrAbs;
125 assert(adrAbs < I2C_EEPROM_SIZE);
126
127 // Do segmented writes
128
129 bool res = false;
130 while(curAdr < adrAbs+dataLength){
131// i2cport_int.isDeviceReady(i2cdeveeprom, I2C_EEPROM_ADR, 100, I2C_EEPROM_TIMEOUT,false)
132 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, devAdr, 100, I2C_EEPROM_TIMEOUT,false)){
133 vTaskDelay(1);
134 }
135 uint16_t i2cAdr = devAdr;
136 uint16_t writeAdr = curAdr;
137 if(curAdr > 0xffff){
138 writeAdr = curAdr & 0xffff;
139 i2cAdr |= 0x02; // A17 bit
140 }
141 uint16_t wLen = std::min<uint16_t>(dataLength,I2C_EEPROM_PAGEWRITE_SIZE - (adrAbs % I2C_EEPROM_PAGEWRITE_SIZE));
142 res = i2cport_int.writeMem(&i2cdeveeprom, i2cAdr, writeAdr, I2C_EEPROM_ADR_SIZE, i2cBufferEeprom, wLen, I2C_EEPROM_TIMEOUT, false);
143 curAdr+=wLen;
144 if(!res){
145 break;
146 }
147 }
148
149 return res;
150}
151
155bool I2C_EEPROM_Read16(uint16_t devAdr,uint16_t adr,uint16_t *buf, bool checkempty){
156 uint32_t adrAbs = (adr * sizeof(*buf)/I2C_EEPROM_DATA_SIZE);
157 assert(adrAbs < I2C_EEPROM_SIZE);
158 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, devAdr, 100, I2C_EEPROM_TIMEOUT,false)){
159 vTaskDelay(1);
160 }
161 uint16_t i2cAdr = devAdr;
162 uint16_t datAdr = adrAbs & 0xffff;
163 if(adrAbs > 0xffff){
164 i2cAdr |= 0x02; // If curAdr > 0xffff set bit 1 of addr high
165 }
166 bool res = i2cport_int.readMem(&i2cdeveeprom, i2cAdr, datAdr, I2C_EEPROM_ADR_SIZE, i2cBufferEeprom, 2, I2C_EEPROM_TIMEOUT, false);
167
168 if(checkempty){
169 bool empty = true;
170 for(uint8_t i = 0;i<sizeof(i2cBufferEeprom);i++){
171 if(i2cBufferEeprom[i] != I2C_EEPROM_ERASED){
172 empty = false;
173 break;
174 }
175 }
176 res = empty ? false : res;
177 }
178 if(res) // Only copy if success
180 return res;
181}
182
183bool Flash_Write(uint16_t adr,uint16_t dat){
184 return I2C_EEPROM_Write16(I2C_EEPROM_ADR,adr+I2C_EEPROM_OFS,dat);
185}
186bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
187 if(!Flash_Read(adr,buf)){
188 return Flash_Write(adr, def);
189 }
190 return true;
191}
192
195bool Flash_Read(uint16_t adr,uint16_t *buf, bool checkempty){
196 return I2C_EEPROM_Read16(I2C_EEPROM_ADR,adr+I2C_EEPROM_OFS,buf,checkempty);
197}
198
203 bool flag = true;
204 std::array<uint8_t,I2C_EEPROM_PAGEWRITE_SIZE> eraseBuf;
205 eraseBuf.fill(I2C_EEPROM_ERASED);
206 for(uint32_t i=I2C_EEPROM_OFS;i<I2C_EEPROM_SIZE;i+=I2C_EEPROM_PAGEWRITE_SIZE){
207 uint16_t datAdr = i & 0xffff;
208 uint16_t devAdr = I2C_EEPROM_ADR;
209 if(i > 0xffff){
210 devAdr |= 0x02;
211 }
212 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);
213 if(!res){
214 flag = false;
215 }else{
216 while(!i2cport_int.isDeviceReady(&i2cdeveeprom, I2C_EEPROM_ADR, 100, I2C_EEPROM_TIMEOUT,false)){
217 vTaskDelay(1);
218 }
219 }
220 }
221 return flag;
222}
224 return i2cport_int.isDeviceReady(&i2cdeveeprom, I2C_EEPROM_ADR, 50, I2C_EEPROM_TIMEOUT,false);
225}
226
227#else
228// No flash mode defined
229
230__weak bool Flash_Write(uint16_t adr,uint16_t dat){
231 return true;
232}
233__weak bool Flash_ReadWriteDefault(uint16_t adr,uint16_t *buf,uint16_t def){
234 return true;
235}
236__weak bool Flash_Read(uint16_t adr,uint16_t *buf){
237 return false;
238}
239__weak bool Flash_Format(){
240 return false;
241}
242__weak bool Flash_Init(){
243 return true;
244}
245#endif
246/*
247 * Dumps all set variables from flash to a vector
248 * does by default not include certain calibration constants that could break something if imported on a different board
249 */
250void Flash_Dump(std::vector<std::tuple<uint16_t,uint16_t>> *result,bool includeAll){
251 uint16_t amount = NB_EXPORTABLE_ADR;
252 const uint16_t* list = exportableFlashAddresses;
253 if(includeAll){
254 amount = NB_OF_VAR;
255 list = VirtAddVarTab;
256 }
257 //extern uint16_t VirtAddVarTab[NB_OF_VAR];
258 //std::vector<std::pair<uint16_t,uint16_t>> result;
259
260 for(uint32_t i = 0;i<amount ; i++){
261 uint16_t v;
262 uint16_t adr = list[i];
263
264 if(Flash_Read(adr,&v)){
265 result->push_back(std::tuple<uint16_t,uint16_t>{adr,v});
266 }
267
268 }
269}
270
271
272/*
273 * OTP Helper functions.
274 * Some chips have internal OTP sections, others may need custom implementations
275 * Page size and address required
276 */
277#if defined(FLASH_OTP_BASE) && defined(FLASH_OTP_END) && defined(OTPMEMORY)
278// This chip has an OTP section in main flash.
279
280__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
281// FLASH_OTP_BASE
282// FLASH_OTP_END
283 uint32_t adr = (FLASH_OTP_BASE+adroffset*sizeof(uint64_t));
284 if(adr > FLASH_OTP_END){
285 return false; // Error
286 }
287 uint64_t curval = *(uint64_t*)adr;
288 if(curval != 0xffffffffffffffff){
289 return false;
290 }
291 if(HAL_FLASH_Unlock()!=HAL_OK) return false;
292 //bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, adr, dat) == HAL_OK;
293 bool success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, (uint32_t)(dat)) == HAL_OK;
294 success = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr+4, (uint32_t)(dat >> 32)) == HAL_OK && success;
295 HAL_FLASH_Lock();
296 return success;
297}
298
299
300__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
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 *dat = curval;
307 return true;
308}
309#elif defined(I2C_EEPROM_OTP_ADR) && defined(I2C_PORT_EEPROM)
310// I2C EEPROM OTP/ID memory
311__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
312 // Write 4 x 16b
313 for(uint8_t i = 0; i < 4; i++){
314 bool res = I2C_EEPROM_Write16(I2C_EEPROM_OTP_ADR, 4*adroffset + (i), (dat >> (i*16)) & 0xffff);
315 if(!res){
316 return false;
317 }
318 }
319
320 return true;
321}
322
323
324__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
325 uint64_t val = 0;
326 for(uint8_t i = 0; i < 4; i++){
327 uint16_t tdat = 0;
328 bool res = I2C_EEPROM_Read16(I2C_EEPROM_OTP_ADR, 4*adroffset + (i), &tdat,false);
329 val |= (uint64_t)tdat << (i*16);
330 if(!res){
331 return false;
332 }
333 }
334 *dat = val;
335 return true;
336}
337#else
338__weak bool OTP_Write(uint16_t adroffset,uint64_t dat){
339 return false;
340}
341
342
343__weak bool OTP_Read(uint16_t adroffset,uint64_t* dat){
344 return false;
345}
346
347#endif
348
349#ifndef FLASH_FACTORY_DEFAULTS_OVERRIDE
355const std::array<const std::pair<uint16_t,uint16_t>,0> empty_flash_defaults; // Empty
356const std::span<const std::pair<uint16_t,uint16_t>> flash_factory_defaults = empty_flash_defaults;
357#endif
358
363 for(const std::pair<uint16_t,uint16_t> &kv : flash_factory_defaults){
364 Flash_Write(kv.first, kv.second); // Try to write values
365 }
366}
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)
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