1 /* USER CODE BEGIN Header */
2 /**
3 ******************************************************************************
4 * @file flash_manager.c
5 * @author MCD Application Team
6 * @brief The Flash Manager module provides an interface to write raw data
7 * from SRAM to FLASH
8 ******************************************************************************
9 * @attention
10 *
11 * Copyright (c) 2024 STMicroelectronics.
12 * All rights reserved.
13 *
14 * This software is licensed under terms that can be found in the LICENSE file
15 * in the root directory of this software component.
16 * If no LICENSE file comes with this software, it is provided AS-IS.
17 *
18 ******************************************************************************
19 */
20 /* USER CODE END Header */
21
22 /* Includes ------------------------------------------------------------------*/
23 #include <stdbool.h>
24 #include "flash_manager.h"
25 #include "rf_timing_synchro.h"
26 #include "flash_driver.h"
27 #include "utilities_conf.h"
28
29 #include "stm32wbaxx_hal.h"
30
31 /* Debug */
32 #include "log_module.h"
33
34 /* Global variables ----------------------------------------------------------*/
35 /* Private typedef -----------------------------------------------------------*/
36
37 /* State of the background process */
38 typedef enum FM_BackGround_States
39 {
40 FM_BKGND_NOWINDOW_FLASHOP,
41 FM_BKGND_WINDOWED_FLASHOP,
42 }FM_BackGround_States_t;
43
44 /* Flash operation type */
45 typedef enum
46 {
47 FM_WRITE_OP,
48 FM_ERASE_OP
49 } FM_FlashOp_t;
50
51 /**
52 * @brief Flash operation configuration struct
53 */
54 typedef struct FM_FlashOpConfig
55 {
56 uint32_t *writeSrc;
57 uint32_t *writeDest;
58 int32_t writeSize;
59 uint32_t eraseFirstSect;
60 uint32_t eraseNbrSect;
61 }FM_FlashOpConfig_t;
62
63 /* Private defines -----------------------------------------------------------*/
64 #define FLASH_PAGE_NBR (FLASH_SIZE / FLASH_PAGE_SIZE)
65 #define FLASH_WRITE_BLOCK_SIZE 4U
66 #define ALIGNMENT_32 0x00000003
67 #define ALIGNMENT_128 0x0000000F
68
69 /* Private macros ------------------------------------------------------------*/
70 /* Private variables ---------------------------------------------------------*/
71
72 /**
73 * @brief Semaphore on Flash
74 */
75 static bool busy_flash_sem = FALSE;
76
77 /**
78 * @brief Indicates if the flash manager module is available or not
79 */
80 static bool flash_manager_busy = FALSE;
81
82 /**
83 * @brief Parameters for Flash Write command
84 */
85 static bool fm_window_granted = FALSE;
86
87 /**
88 * @brief Callback node list for pending flash operation request
89 */
90 static tListNode fm_cb_pending_list;
91
92 /**
93 * @brief Flag indicating if pending node list has been initialized
94 */
95 static bool fm_cb_pending_list_init = FALSE;
96
97 /**
98 * @brief Pointer to current flash operation requester's callback
99 */
100 static void (*fm_running_cb)(FM_FlashOp_Status_t);
101
102 /**
103 * @brief Type of current flash operation (Write/Erase)
104 */
105 static FM_FlashOp_t fm_flashop;
106
107 /**
108 * @brief Parameters for Flash operation
109 */
110 static FM_FlashOpConfig_t fm_flashop_parameters;
111
112 /**
113 * @brief State of the Background process
114 */
115 static FM_BackGround_States_t FM_CurrentBackGroundState;
116
117 /* Private function prototypes -----------------------------------------------*/
118
119 static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode);
120 static void FM_WindowAllowed_Callback(void);
121
122 /* Functions Definition ------------------------------------------------------*/
123
124 /**
125 * @brief Request the Flash Manager module to initiate a Flash Write operation
126 * @param Src: Address of the data to be stored in FLASH. It shall be 32bits aligned
127 * @param Dest: Address where the data shall be written. It shall be 128bits aligned
128 * @param Size: This is the size of data to be written in Flash.
129 The size is a multiple of 32bits (size = 1 means 32bits)
130 * @param CallbackNode: Pointer to the callback node for storage in list
131 * @retval FM_Cmd_Status_t: Status of the Flash Manager module
132 */
FM_Write(uint32_t * Src,uint32_t * Dest,int32_t Size,FM_CallbackNode_t * CallbackNode)133 FM_Cmd_Status_t FM_Write(uint32_t *Src, uint32_t *Dest, int32_t Size, FM_CallbackNode_t *CallbackNode)
134 {
135 FM_Cmd_Status_t status;
136
137 if (((uint32_t)Dest < FLASH_BASE) || ((uint32_t)Dest > (FLASH_BASE + FLASH_SIZE))
138 || (((uint32_t)Dest + Size) > (FLASH_BASE + FLASH_SIZE)))
139 {
140 LOG_ERROR_SYSTEM("\r\nFM_Write - Destination address not part of the flash");
141
142 /* Destination address not part of the flash */
143 return FM_ERROR;
144 }
145
146 if (((uint32_t) Src & ALIGNMENT_32) || ((uint32_t) Dest & ALIGNMENT_128))
147 {
148 LOG_ERROR_SYSTEM("\r\nFM_Write - Source or destination address not properly aligned");
149
150 /* Source or destination address not properly aligned */
151 return FM_ERROR;
152 }
153
154 status = FM_CheckFlashManagerState(CallbackNode);
155
156 if (status == FM_OK)
157 { /* Flash manager is available */
158
159 /* Save Write parameters */
160 fm_flashop_parameters.writeSrc = Src;
161 fm_flashop_parameters.writeDest = Dest;
162 fm_flashop_parameters.writeSize = Size;
163
164 fm_flashop = FM_WRITE_OP;
165
166 FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
167
168 /* Window request to be executed in background */
169 FM_ProcessRequest();
170 }
171
172 LOG_INFO_SYSTEM("\r\nFM_Write - Returned value : %d", status);
173
174 return status;
175 }
176
177 /**
178 * @brief Request the Flash Manager module to initiate a Flash Erase operation
179 * @param FirstSect: Index of the first sector to erase
180 * @param NbrSect: Number of sector to erase
181 * @param CallbackNode: Pointer to the callback node for storage in list
182 * @retval FM_Cmd_Status_t: Status of the Flash Manager module
183 */
FM_Erase(uint32_t FirstSect,uint32_t NbrSect,FM_CallbackNode_t * CallbackNode)184 FM_Cmd_Status_t FM_Erase(uint32_t FirstSect, uint32_t NbrSect, FM_CallbackNode_t *CallbackNode)
185 {
186 FM_Cmd_Status_t status;
187
188 if ((FirstSect > FLASH_PAGE_NBR) || ((FirstSect + NbrSect) > FLASH_PAGE_NBR))
189 {
190 LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
191
192 /* Inconsistent request */
193 return FM_ERROR;
194 }
195
196 if (NbrSect == 0)
197 {
198 LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
199
200 /* Inconsistent request */
201 return FM_ERROR;
202 }
203
204 status = FM_CheckFlashManagerState(CallbackNode);
205
206 if (status == FM_OK)
207 { /* Flash manager is available */
208
209 /* Save Erase parameters */
210 fm_flashop_parameters.eraseFirstSect = FirstSect;
211 fm_flashop_parameters.eraseNbrSect = NbrSect;
212
213 fm_flashop = FM_ERASE_OP;
214
215 FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
216
217 /* Window request to be executed in background */
218 FM_ProcessRequest();
219 }
220
221 LOG_INFO_SYSTEM("\r\nFM_Erase - Returned value : %d", status);
222
223 return status;
224 }
225
226 /**
227 * @brief Execute Flash Manager background tasks
228 * @param None
229 * @retval None
230 */
FM_BackgroundProcess(void)231 void FM_BackgroundProcess (void)
232 {
233 static uint32_t duration;
234 bool flashop_complete = false;
235 FD_FlashOp_Status_t fdReturnValue = FD_FLASHOP_SUCCESS;
236 FM_CallbackNode_t *pCbNode = NULL;
237
238 switch (FM_CurrentBackGroundState)
239 {
240 case FM_BKGND_NOWINDOW_FLASHOP:
241 {
242 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP");
243
244 if (fm_flashop == FM_WRITE_OP)
245 {
246 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Write operation");
247
248 /* Update duration time value */
249 duration = TIME_WINDOW_WRITE_REQUEST;
250
251 /* Set the next possible state - App could stop at anytime no window operation */
252 FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
253
254 HAL_FLASH_Unlock();
255
256 while((fm_flashop_parameters.writeSize > 0) &&
257 (fdReturnValue == FD_FLASHOP_SUCCESS))
258 {
259 fdReturnValue = FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
260 (uint32_t) fm_flashop_parameters.writeSrc);
261
262 if (fdReturnValue == FD_FLASHOP_SUCCESS)
263 {
264 fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
265 fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
266 fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
267 }
268 }
269
270 HAL_FLASH_Lock();
271
272 /* Is write over ? */
273 if (fm_flashop_parameters.writeSize <= 0)
274 {
275 flashop_complete = true;
276 }
277 }
278 else
279 {
280 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Erase operation");
281
282 /* Update duration time value */
283 duration = TIME_WINDOW_ERASE_REQUEST;
284
285 /* Set the next possible state */
286 FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
287
288 HAL_FLASH_Unlock();
289
290 while((fm_flashop_parameters.eraseNbrSect > 0) &&
291 (fdReturnValue == FD_FLASHOP_SUCCESS))
292 {
293 fdReturnValue = FD_EraseSectors(fm_flashop_parameters.eraseFirstSect);
294
295 if (fdReturnValue == FD_FLASHOP_SUCCESS)
296 {
297 fm_flashop_parameters.eraseNbrSect--;
298 fm_flashop_parameters.eraseFirstSect++;
299 }
300 }
301
302 HAL_FLASH_Lock();
303
304 if (fm_flashop_parameters.eraseNbrSect == 0)
305 {
306 flashop_complete = true;
307 }
308 }
309 break;
310 }
311
312 case FM_BKGND_WINDOWED_FLASHOP:
313 {
314 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP");
315
316 if (fm_window_granted == false)
317 {
318 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - No time window granted yet, request one");
319
320 /* No time window granted yet, request one */
321 RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
322 }
323 else
324 {
325 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Time window granted");
326
327 if (fm_flashop == FM_WRITE_OP)
328 {
329 /* Flash Write operation */
330 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Write operation");
331
332 HAL_FLASH_Unlock();
333
334 while((fm_flashop_parameters.writeSize > 0) &&
335 (FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
336 (uint32_t) fm_flashop_parameters.writeSrc) == FD_FLASHOP_SUCCESS))
337 {
338 fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
339 fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
340 fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
341 }
342
343 if (fm_flashop_parameters.writeSize <= 0)
344 {
345 flashop_complete = true;
346 }
347
348 HAL_FLASH_Lock();
349
350 }
351 else
352 {
353 /* Flash Erase operation */
354 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Erase operation");
355
356 HAL_FLASH_Unlock();
357
358 /* Erase only one sector in a single time window */
359 if (FD_EraseSectors(fm_flashop_parameters.eraseFirstSect) == FD_FLASHOP_SUCCESS)
360 {
361 fm_flashop_parameters.eraseNbrSect--;
362 fm_flashop_parameters.eraseFirstSect++;
363 }
364
365 if (fm_flashop_parameters.eraseNbrSect == 0)
366 {
367 flashop_complete = true;
368 }
369
370 HAL_FLASH_Lock();
371 }
372
373 /* Release the time window */
374 RFTS_RelWindow();
375
376 /* Indicate that there is no more window */
377 fm_window_granted = false;
378 }
379
380 break;
381 }
382
383 default:
384 {
385 /* Nothing to do here */
386 break;
387 }
388 }
389
390 if (flashop_complete == true)
391 {
392 UTILS_ENTER_CRITICAL_SECTION();
393
394 /* Release semaphore on flash */
395 busy_flash_sem = false;
396
397 /* Set Flash Manager busy */
398 flash_manager_busy = false;
399
400 UTILS_EXIT_CRITICAL_SECTION();
401
402 /* Invoke the running callback if present */
403 if (fm_running_cb != NULL)
404 {
405 fm_running_cb(FM_OPERATION_COMPLETE);
406 }
407
408 /* notify pending requesters */
409 while((LST_is_empty (&fm_cb_pending_list) == false) &&
410 (busy_flash_sem == false) && (flash_manager_busy == false))
411 {
412 LST_remove_head (&fm_cb_pending_list, (tListNode**)&pCbNode);
413 pCbNode->Callback(FM_OPERATION_AVAILABLE);
414 }
415 }
416 else
417 {
418 /* Flash operation not complete yet */
419 LOG_INFO_SYSTEM("\r\nFM_BackgroundProcess - Flash operation not complete yet, request a new time window");
420
421 /* Request a new time window */
422 RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
423 }
424 }
425
426 /**
427 * @brief Check if the Flash Manager is busy or available
428 * @param CallbackNode: Pointer to the callback node for storage in list
429 * @retval FM_Cmd_Status_t: Status of the Flash Manager module
430 */
FM_CheckFlashManagerState(FM_CallbackNode_t * CallbackNode)431 static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode)
432 {
433 bool fm_process_cmd = false;
434 FM_Cmd_Status_t status = FM_ERROR;
435
436 /* Check if semaphore on flash is available */
437 UTILS_ENTER_CRITICAL_SECTION();
438
439 /* Initialize pending list if not done */
440 if (fm_cb_pending_list_init == false)
441 {
442 LST_init_head(&fm_cb_pending_list);
443 fm_cb_pending_list_init = true;
444 }
445 /* Check if semaphore on flash is available */
446 if (busy_flash_sem == false)
447 { /* Check if Flash Manager is already busy */
448 if (flash_manager_busy == false)
449 {
450 busy_flash_sem = true; /* Get semaphore on flash */
451 flash_manager_busy = true; /* Set Flash Manager busy */
452 fm_process_cmd = true;
453 }
454 else
455 {
456 fm_process_cmd = false;
457 }
458 }
459 else
460 {
461 fm_process_cmd = false;
462 }
463 UTILS_EXIT_CRITICAL_SECTION();
464
465 if (fm_process_cmd == false)
466 { /* Flash manager busy */
467
468 /* Append callback to the pending list */
469 if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
470 {
471 LST_insert_tail(&fm_cb_pending_list, &(CallbackNode->NodeList));
472 }
473
474 status = FM_BUSY;
475 }
476 else
477 { /* Flash manager is available */
478
479 if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
480 {
481 UTILS_ENTER_CRITICAL_SECTION();
482
483 fm_running_cb = CallbackNode->Callback;
484
485 UTILS_EXIT_CRITICAL_SECTION();
486 }
487 else
488 {
489 UTILS_ENTER_CRITICAL_SECTION();
490
491 fm_running_cb = NULL;
492
493 UTILS_EXIT_CRITICAL_SECTION();
494 }
495
496 status = FM_OK;
497 }
498 return status;
499 }
500
501 /**
502 * @brief Callback called by RF Timing Synchro module when a time window is available
503 * @param None
504 * @retval None
505 */
FM_WindowAllowed_Callback(void)506 static void FM_WindowAllowed_Callback(void)
507 {
508 fm_window_granted = true;
509
510 LOG_INFO_SYSTEM("\r\nFM_WindowAllowed_Callback");
511
512 /* Flash operation to be executed in background */
513 FM_ProcessRequest();
514 }
515