semf
stm32flash.cpp
Go to the documentation of this file.
1
12
13#if defined(STM32) && defined(HAL_FLASH_MODULE_ENABLED)
14extern FLASH_ProcessTypeDef pFlash;
15
16extern "C"
22 void
24{
26}
27
28namespace semf
29{
30Stm32Flash* Stm32Flash::m_flash;
31Stm32Flash::Stm32Flash(uint16_t size, uint32_t voltageRange, uint32_t bank)
32: m_voltageRange(voltageRange),
33 m_size(size),
34 m_bank(bank)
35{
36 Stm32Flash::m_flash = this;
37}
38
39Stm32Flash::Stm32Flash(uint16_t size, uint32_t bank)
40: m_voltageRange(0),
41 m_size(size),
42 m_bank(bank)
43{
44 Stm32Flash::m_flash = this;
45}
46
48: m_voltageRange(0),
49 m_size(size),
50 m_bank(0)
51{
52 Stm32Flash::m_flash = this;
53}
54
55void Stm32Flash::write(uint32_t address, const uint8_t data[], size_t dataSize)
56{
57 SEMF_INFO("address %u, data %p, size is %u", address, data, dataSize);
58 if (m_isBusy)
59 {
60 SEMF_ERROR("is busy");
61 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_IsBusy)));
62 return;
63 }
64 else if (data == nullptr)
65 {
66 SEMF_ERROR("data is nullptr");
67 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_DataIsNullptr)));
68 return;
69 }
70 else if (dataSize == 0)
71 {
72 SEMF_ERROR("size is 0");
73 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_DataSizeIsZero)));
74 return;
75 }
76
77 m_isBusy = true;
78 m_addressWrite = address;
79 m_dataWrite = const_cast<uint8_t*>(data);
80 m_bytesToWrite = dataSize;
81
82 HAL_FLASH_Unlock();
83 write();
84}
85
86void Stm32Flash::read(uint32_t address, uint8_t buffer[], size_t bufferSize)
87{
88 SEMF_INFO("address %u, data %p, size is %u", address, buffer, bufferSize);
89 if (m_isBusy)
90 {
91 SEMF_ERROR("is busy");
92 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Read_IsBusy)));
93 return;
94 }
95 else if (buffer == nullptr)
96 {
97 SEMF_ERROR("buffer is nullptr");
98 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Read_BufferIsNullptr)));
99 return;
100 }
101 else if (bufferSize == 0)
102 {
103 SEMF_ERROR("bufferSize is 0");
104 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Read_BufferSizeIsZero)));
105 }
106
107 if (m_dataAvailablePending)
108 {
109 m_addressRead = address;
110 m_dataRead = buffer;
111 m_sizeRead = bufferSize;
112 m_readIsPending = true;
113 return;
114 }
115 else
116 {
117 while (1)
118 {
119 for (size_t i = 0; i < bufferSize; i++)
120 {
121 buffer[i] = (*(__IO uint8_t*)(address));
122 address++;
123 }
124
125 m_dataAvailablePending = true;
126 m_isBusy = false;
128 m_dataAvailablePending = false;
129
130 if (m_readIsPending)
131 {
132 address = m_addressRead;
133 buffer = m_dataRead;
134 bufferSize = m_sizeRead;
135 m_readIsPending = false;
136 }
137 else
138 {
139 break;
140 }
141 }
142 }
143}
144
145void Stm32Flash::erase(size_t sector, size_t numOfSectors)
146{
147 SEMF_INFO("first sector index %u, number of sectors %u", sector, numOfSectors);
148 if (m_isBusy)
149 {
150 SEMF_ERROR("is busy");
151 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Erase_IsBusy)));
152 return;
153 }
154 if (sector >= numberOfSectors()) // bad error handeling
155 {
156 SEMF_ERROR("sector %u is out of range", sector);
157 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Erase_SectorOutOfBounds)));
158 return;
159 }
160
161 m_isBusy = true;
162 m_numOfSecotrsToErase = numOfSectors;
163 m_eraseIsRunning = true;
164
165 HAL_FLASH_Unlock();
166 FLASH_EraseInitTypeDef eraseinit;
167#if defined(STM32F0) || defined(STM32F1) || defined(STM32F3) || defined(STM32L0)
168 eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
169 eraseinit.PageAddress = address(sector);
170 eraseinit.NbPages = numOfSectors;
171#elif defined(STM32G0)
172 eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
173 eraseinit.Banks = m_bank;
174 eraseinit.Page = sector;
175 eraseinit.NbPages = numOfSectors;
176#else
177 eraseinit.TypeErase = FLASH_TYPEERASE_SECTORS;
178 eraseinit.Sector = sector;
179 eraseinit.NbSectors = numOfSectors;
180 eraseinit.VoltageRange = m_voltageRange;
181#endif
182 HAL_StatusTypeDef state = HAL_FLASHEx_Erase_IT(&eraseinit);
183 if (state != HAL_OK)
184 {
185 if (state == HAL_ERROR)
186 {
187 SEMF_ERROR("hal error");
188 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Erase_IsHalError)));
189 }
190 else if (state == HAL_BUSY)
191 {
192 SEMF_ERROR("hal busy");
193 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Erase_IsHalBusy)));
194 }
195 else if (state == HAL_TIMEOUT)
196 {
197 SEMF_ERROR("hal timeout");
198 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Erase_IsHalTimeout)));
199 }
200 m_isBusy = false;
201 return;
202 }
203}
204
206{
207 return m_isBusy;
208}
209
210void Stm32Flash::write()
211{
212#if defined(STM32G0)
213 if (m_bytesToWrite % 8 != 0)
214 {
215 m_isBusy = false;
216 SEMF_ERROR("write does not support less than 8 bytes");
217 error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_DataNot8ByteAligned)));
218 return;
219 }
220#endif
221#if defined(STM32L0) || defined(STM32F0)
222 if (m_bytesToWrite % 4 != 0)
223 {
224 m_isBusy = false;
225 SEMF_ERROR("write does not support less than 4 bytes");
226 error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_DataNot4ByteAligned)));
227 return;
228 }
229#endif
230#if defined(STM32F1) || defined(STM32F3)
231 if (m_bytesToWrite % 2 != 0)
232 {
233 SEMF_ERROR("write does not support less than 2 bytes");
234 m_isBusy = false;
235 error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_DataNot2ByteAligned)));
236 return;
237 }
238#endif
239
240 HAL_StatusTypeDef state = HAL_StatusTypeDef::HAL_OK;
241 if (m_bytesToWrite >= sizeof(uint64_t))
242 {
243 m_bytesToWrite -= sizeof(uint64_t);
244 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_DOUBLEWORD, m_addressWrite, *reinterpret_cast<uint32_t*>(m_dataWrite));
245 }
246#if !defined(STM32G0)
247 else if (m_bytesToWrite >= sizeof(uint32_t))
248 {
249 m_bytesToWrite -= sizeof(uint32_t);
250 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_WORD, m_addressWrite, *reinterpret_cast<uint32_t*>(m_dataWrite));
251 }
252#endif
253#if !defined(STM32L0) && !defined(STM32F0) && !defined(STM32G0)
254 else if (m_bytesToWrite >= sizeof(uint16_t))
255 {
256 m_bytesToWrite -= sizeof(uint16_t);
257 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_HALFWORD, m_addressWrite, *reinterpret_cast<uint16_t*>(m_dataWrite));
258 }
259#endif
260#if !defined(STM32L0) && !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F3) && !defined(STM32G0)
261 else if (m_bytesToWrite == sizeof(uint8_t))
262 {
263 m_bytesToWrite--;
264 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_BYTE, m_addressWrite, *m_dataWrite);
265 }
266#endif
267 if (state != HAL_StatusTypeDef::HAL_OK)
268 {
269 if (state == HAL_ERROR)
270 {
271 SEMF_ERROR("write hal error");
272 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_HalError)));
273 }
274 else if (state == HAL_BUSY)
275 {
276 SEMF_ERROR("write hal busy");
277 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_HalBusy)));
278 }
279 else if (state == HAL_TIMEOUT)
280 {
281 SEMF_ERROR("write hal timeout");
282 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Write_HalTimeout)));
283 }
284 return;
285 }
286}
287
289{
290 if (pFlash.ErrorCode)
291 {
293 return;
294 }
295
296 if (m_flash->m_eraseIsRunning)
297 {
298 if (--m_flash->m_numOfSecotrsToErase)
299 return;
300 m_flash->m_eraseIsRunning = false;
301 HAL_FLASH_Lock();
302 m_flash->m_isBusy = false;
303 m_flash->erased();
304 return;
305 }
306
307#if defined(STM32G0)
308 if (pFlash.ProcedureOnGoing != FLASH_TYPENONE)
309 return;
310#else
311 if (pFlash.ProcedureOnGoing != FLASH_PROC_NONE)
312 return;
313#endif
314
315 HAL_StatusTypeDef state = HAL_StatusTypeDef::HAL_OK;
316 if (m_flash->m_bytesToWrite >= sizeof(uint64_t))
317 {
318 m_flash->m_bytesToWrite -= sizeof(uint64_t);
319 m_flash->m_dataWrite += sizeof(uint64_t);
320 m_flash->m_addressWrite += sizeof(uint64_t);
321 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_DOUBLEWORD, m_flash->m_addressWrite, *reinterpret_cast<uint32_t*>(m_flash->m_dataWrite));
322 }
323#if !defined(STM32G0)
324 if (m_flash->m_bytesToWrite >= sizeof(uint32_t))
325 {
326 m_flash->m_bytesToWrite -= sizeof(uint32_t);
327 m_flash->m_dataWrite += sizeof(uint32_t);
328 m_flash->m_addressWrite += sizeof(uint32_t);
329 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_WORD, m_flash->m_addressWrite, *reinterpret_cast<uint32_t*>(m_flash->m_dataWrite));
330 }
331#endif
332#if !defined(STM32L0) && !defined(STM32F0) && !defined(STM32G0)
333 else if (m_flash->m_bytesToWrite >= sizeof(uint16_t))
334 {
335 m_flash->m_bytesToWrite -= sizeof(uint16_t);
336 m_flash->m_dataWrite += sizeof(uint16_t);
337 m_flash->m_addressWrite += sizeof(uint16_t);
338 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_HALFWORD, m_flash->m_addressWrite, *reinterpret_cast<uint16_t*>(m_flash->m_dataWrite));
339 }
340#endif
341#if !defined(STM32L0) && !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F3) && !defined(STM32G0)
342 else if (m_flash->m_bytesToWrite == sizeof(uint8_t))
343 {
344 m_flash->m_bytesToWrite--;
345 m_flash->m_dataWrite++;
346 m_flash->m_addressWrite++;
347 state = HAL_FLASH_Program_IT(FLASH_TYPEPROGRAM_BYTE, m_flash->m_addressWrite, *m_flash->m_dataWrite);
348 }
349#endif
350 else
351 {
352 HAL_FLASH_Lock();
353 m_flash->m_isBusy = false;
354
355 if (state == HAL_StatusTypeDef::HAL_OK)
356 {
357 SEMF_SINGLETON_INFO(m_flash, "data written");
358 m_flash->dataWritten();
359 }
360 else
361 {
362 if (state == HAL_ERROR)
363 {
364 SEMF_SINGLETON_ERROR(m_flash, "hal error");
365 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Isr_HalError)));
366 }
367 else if (state == HAL_BUSY)
368 {
369 SEMF_SINGLETON_ERROR(m_flash, "hal busy");
370 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Isr_HalBusy)));
371 }
372 else if (state == HAL_TIMEOUT)
373 {
374 SEMF_SINGLETON_ERROR(m_flash, "hal timeout");
375 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::Isr_HalTimeout)));
376 }
377 return;
378 }
379 }
380}
381
383{
384 m_flash->m_eraseIsRunning = false;
385 m_flash->m_isBusy = false;
386 SEMF_SINGLETON_ERROR(m_flash, "isr error");
387 m_flash->error(Error(kSemfClassId, static_cast<uint8_t>(ErrorCode::IsrError_InterruptError)));
388}
389
390uint16_t Stm32Flash::size() const
391{
392 return m_size;
393}
394} /* namespace semf */
395#endif
Class for representing errors. Every error should have a unique source code. As a user feel encourage...
Definition: error.h:22
void erase(size_t sector, size_t numOfSectors=1) override
Erase sector(s).
Definition: stm32flash.cpp:145
uint16_t size() const
Returns the size of the flash in kBytes.
Definition: stm32flash.cpp:390
void write(uint32_t address, const uint8_t data[], size_t dataSize) override
Writes data into the storage.
Definition: stm32flash.cpp:55
void read(uint32_t address, uint8_t buffer[], size_t bufferSize) override
Reads data from the storage into a given read buffer.
Definition: stm32flash.cpp:86
static void isr()
This function must be called from isr.
Definition: stm32flash.cpp:288
static void isrError()
This function is call from isr when an error has occurred.
Definition: stm32flash.cpp:382
Stm32Flash(uint16_t size, uint32_t voltageRange, uint32_t bank)
Constructor.
Definition: stm32flash.cpp:31
bool isBusy() const override
Returns if the storage is busy reading, writing or e.g. erasing.
Definition: stm32flash.cpp:205
virtual uint32_t address(size_t sector) const =0
Return on which address a sector starts.
virtual size_t sector(uint32_t address) const =0
Return in which sector an address is located.
Signal erased
Definition: flash.h:58
virtual size_t numberOfSectors() const =0
Return the number/amount of sectors of a flash memory.
Signal dataAvailable
Definition: storage.h:53
Signal< Error > error
Definition: storage.h:55
Signal dataWritten
Definition: storage.h:54
#define SEMF_ERROR(...)
Definition: debug.h:39
#define SEMF_SINGLETON_ERROR(object,...)
Definition: debug.h:45
#define SEMF_SINGLETON_INFO(object,...)
Definition: debug.h:47
#define SEMF_INFO(...)
Definition: debug.h:41
FLASH_ProcessTypeDef pFlash
void semfStm32FlashIsr()
This function must be called in the HAL_FLASH_EndOfOperationCallback().
Definition: stm32flash.cpp:23