Index: ctrl/firmware/Main/CubeMX/FATFS/App/fatfs.c
===================================================================
--- ctrl/firmware/Main/CubeMX/FATFS/App/fatfs.c	(revision 74)
+++ ctrl/firmware/Main/CubeMX/FATFS/App/fatfs.c	(revision 75)
@@ -38,4 +38,16 @@
 }
 
+/**
+  * @brief  Gets Time from RTC
+  * @param  None
+  * @retval Time in DWORD
+  */
+DWORD get_fattime(void)
+{
+  /* USER CODE BEGIN get_fattime */
+  return 0;
+  /* USER CODE END get_fattime */
+}
+
 /* USER CODE BEGIN Application */
 
Index: ctrl/firmware/Main/CubeMX/FATFS/Target/ffconf.h
===================================================================
--- ctrl/firmware/Main/CubeMX/FATFS/Target/ffconf.h	(revision 74)
+++ ctrl/firmware/Main/CubeMX/FATFS/Target/ffconf.h	(revision 75)
@@ -26,4 +26,5 @@
 #include "stm32h7xx_hal.h"
 #include "bsp_driver_sd.h"
+#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */
 
 /*-----------------------------------------------------------------------------/
@@ -46,5 +47,5 @@
 /   3: f_lseek() function is removed in addition to 2. */
 
-#define _USE_STRFUNC         2      /* 0:Disable or 1-2:Enable */
+#define _USE_STRFUNC         0      /* 0:Disable or 1-2:Enable */
 /* This option switches string functions, f_gets(), f_putc(), f_puts() and
 /  f_printf().
@@ -127,10 +128,10 @@
 /  ff_memfree(), must be added to the project. */
 
-#define _LFN_UNICODE    1 /* 0:ANSI/OEM or 1:Unicode */
+#define _LFN_UNICODE    0 /* 0:ANSI/OEM or 1:Unicode */
 /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
 /  To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
 /  This option also affects behavior of string I/O functions. */
 
-#define _STRF_ENCODE    3
+#define _STRF_ENCODE    0
 /* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
 /  be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
@@ -210,10 +211,10 @@
 /  buffer in the file system object (FATFS) is used for the file data transfer. */
 
-#define _FS_EXFAT	1
+#define _FS_EXFAT	0
 /* This option switches support of exFAT file system. (0:Disable or 1:Enable)
 /  When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
 /  Note that enabling exFAT discards C89 compatibility. */
 
-#define _FS_NORTC	1
+#define _FS_NORTC	0
 #define _NORTC_MON	1
 #define _NORTC_MDAY	1
@@ -239,7 +240,9 @@
 /      lock control is independent of re-entrancy. */
 
-#define _FS_REENTRANT    0  /* 0:Disable or 1:Enable */
+#define _FS_REENTRANT    1  /* 0:Disable or 1:Enable */
+
+#define _USE_MUTEX       1 /* 0:Disable or 1:Enable */
 #define _FS_TIMEOUT      1000 /* Timeout period in unit of time ticks */
-#define _SYNC_t          NULL
+#define _SYNC_t          osMutexId_t
 /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
 /  module itself. Note that regardless of this option, file access to different
@@ -259,9 +262,8 @@
 /  included somewhere in the scope of ff.h. */
 
-/* define the ff_malloc ff_free macros as standard malloc free */
+/* define the ff_malloc ff_free macros as FreeRTOS pvPortMalloc and vPortFree macros */
 #if !defined(ff_malloc) && !defined(ff_free)
-#include <stdlib.h>
-#define ff_malloc  malloc
-#define ff_free  free
+#define ff_malloc  pvPortMalloc
+#define ff_free  vPortFree
 #endif
 
Index: ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.c
===================================================================
--- ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.c	(revision 74)
+++ ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.c	(revision 75)
@@ -18,6 +18,6 @@
 /* USER CODE END Header */
 
-/* Note: code generation based on sd_diskio_dma_template_bspv1.c v2.1.4
-   as "Use dma template" is enabled. */
+/* Note: code generation based on sd_diskio_dma_rtos_template_bspv1.c v2.1.4
+   as FreeRTOS is enabled. */
 
 /* USER CODE BEGIN firstSection */
@@ -30,9 +30,25 @@
 
 #include <string.h>
+#include <stdio.h>
 
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 
- /*
+#define QUEUE_SIZE         (uint32_t) 10
+#define READ_CPLT_MSG      (uint32_t) 1
+#define WRITE_CPLT_MSG     (uint32_t) 2
+/*
+==================================================================
+enable the defines below to send custom rtos messages
+when an error or an abort occurs.
+Notice: depending on the HAL/SD driver the HAL_SD_ErrorCallback()
+may not be available.
+See BSP_SD_ErrorCallback() and BSP_SD_AbortCallback() below
+==================================================================
+
+#define RW_ERROR_MSG       (uint32_t) 3
+#define RW_ABORT_MSG       (uint32_t) 4
+*/
+/*
  * the following Timeout is useful to give the control back to the applications
  * in case of errors in either BSP_SD_ReadCpltCallback() or BSP_SD_WriteCpltCallback()
@@ -60,5 +76,5 @@
  */
 /* USER CODE BEGIN enableSDDmaCacheMaintenance */
-#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
+//#define ENABLE_SD_DMA_CACHE_MAINTENANCE  1
 /* USER CODE END enableSDDmaCacheMaintenance */
 
@@ -69,5 +85,5 @@
 */
 /* USER CODE BEGIN enableScratchBuffer */
-#define ENABLE_SCRATCH_BUFFER
+//#define ENABLE_SCRATCH_BUFFER
 /* USER CODE END enableScratchBuffer */
 
@@ -83,5 +99,9 @@
 static volatile DSTATUS Stat = STA_NOINIT;
 
-static volatile  UINT  WriteStatus = 0, ReadStatus = 0;
+#if (osCMSIS <= 0x20000U)
+static osMessageQId SDQueueID = NULL;
+#else
+static osMessageQueueId_t SDQueueID = NULL;
+#endif
 /* Private function prototypes -----------------------------------------------*/
 static DSTATUS SD_CheckStatus(BYTE lun);
@@ -118,7 +138,13 @@
 static int SD_CheckStatusWithTimeout(uint32_t timeout)
 {
-  uint32_t timer = HAL_GetTick();
-  /* block until SDIO IP is ready again or a timeout occur */
-  while(HAL_GetTick() - timer < timeout)
+  uint32_t timer;
+  /* block until SDIO peripheral is ready again or a timeout occur */
+#if (osCMSIS <= 0x20000U)
+  timer = osKernelSysTick();
+  while( osKernelSysTick() - timer < timeout)
+#else
+  timer = osKernelGetTickCount();
+  while( osKernelGetTickCount() - timer < timeout)
+#endif
   {
     if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
@@ -135,5 +161,5 @@
   Stat = STA_NOINIT;
 
-  if(BSP_SD_GetCardState() == MSD_OK)
+  if(BSP_SD_GetCardState() == SD_TRANSFER_OK)
   {
     Stat &= ~STA_NOINIT;
@@ -150,15 +176,50 @@
 DSTATUS SD_initialize(BYTE lun)
 {
-
+Stat = STA_NOINIT;
+
+  /*
+   * check that the kernel has been started before continuing
+   * as the osMessage API will fail otherwise
+   */
+#if (osCMSIS <= 0x20000U)
+  if(osKernelRunning())
+#else
+  if(osKernelGetState() == osKernelRunning)
+#endif
+  {
 #if !defined(DISABLE_SD_INIT)
 
-  if(BSP_SD_Init() == MSD_OK)
-  {
+    if(BSP_SD_Init() == MSD_OK)
+    {
+      Stat = SD_CheckStatus(lun);
+    }
+
+#else
     Stat = SD_CheckStatus(lun);
-  }
-
-#else
-  Stat = SD_CheckStatus(lun);
-#endif
+#endif
+
+    /*
+    * if the SD is correctly initialized, create the operation queue
+    * if not already created
+    */
+
+    if (Stat != STA_NOINIT)
+    {
+      if (SDQueueID == NULL)
+      {
+ #if (osCMSIS <= 0x20000U)
+      osMessageQDef(SD_Queue, QUEUE_SIZE, uint16_t);
+      SDQueueID = osMessageCreate (osMessageQ(SD_Queue), NULL);
+#else
+      SDQueueID = osMessageQueueNew(QUEUE_SIZE, 2, NULL);
+#endif
+      }
+
+      if (SDQueueID == NULL)
+      {
+        Stat |= STA_NOINIT;
+      }
+    }
+  }
 
   return Stat;
@@ -189,13 +250,16 @@
 DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
 {
+  uint8_t ret;
   DRESULT res = RES_ERROR;
-  uint32_t timeout;
-#if defined(ENABLE_SCRATCH_BUFFER)
-  uint8_t ret;
+  uint32_t timer;
+#if (osCMSIS < 0x20000U)
+  osEvent event;
+#else
+  uint16_t event;
+  osStatus_t status;
 #endif
 #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
   uint32_t alignedAddr;
 #endif
-
   /*
   * ensure the SDCard is ready for a new operation
@@ -211,44 +275,52 @@
   {
 #endif
-    if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
-                             (uint32_t) (sector),
-                             count) == MSD_OK)
+    /* Fast path cause destination buffer is correctly aligned */
+    ret = BSP_SD_ReadBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count);
+
+    if (ret == MSD_OK) {
+#if (osCMSIS < 0x20000U)
+    /* wait for a message from the queue or a timeout */
+    event = osMessageGet(SDQueueID, SD_TIMEOUT);
+
+    if (event.status == osEventMessage)
     {
-      ReadStatus = 0;
-      /* Wait that the reading process is completed or a timeout occurs */
-      timeout = HAL_GetTick();
-      while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
+      if (event.value.v == READ_CPLT_MSG)
       {
-      }
-      /* in case of a timeout return error */
-      if (ReadStatus == 0)
-      {
-        res = RES_ERROR;
-      }
-      else
-      {
-        ReadStatus = 0;
-        timeout = HAL_GetTick();
-
-        while((HAL_GetTick() - timeout) < SD_TIMEOUT)
-        {
-          if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
+        timer = osKernelSysTick();
+        /* block until SDIO IP is ready or a timeout occur */
+        while(osKernelSysTick() - timer <SD_TIMEOUT)
+#else
+          status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
+          if ((status == osOK) && (event == READ_CPLT_MSG))
           {
-            res = RES_OK;
+            timer = osKernelGetTickCount();
+            /* block until SDIO IP is ready or a timeout occur */
+            while(osKernelGetTickCount() - timer <SD_TIMEOUT)
+#endif
+            {
+              if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
+              {
+                res = RES_OK;
 #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
-            /*
-            the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
-            adjust the address and the D-Cache size to invalidate accordingly.
-            */
-            alignedAddr = (uint32_t)buff & ~0x1F;
-            SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
-#endif
-            break;
+                /*
+                the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
+                adjust the address and the D-Cache size to invalidate accordingly.
+                */
+                alignedAddr = (uint32_t)buff & ~0x1F;
+                SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
+#endif
+                break;
+              }
+            }
+#if (osCMSIS < 0x20000U)
           }
         }
+#else
       }
-    }
+#endif
+    }
+
 #if defined(ENABLE_SCRATCH_BUFFER)
-  }
+    }
     else
     {
@@ -256,20 +328,49 @@
       int i;
 
-      for (i = 0; i < count; i++) {
+      for (i = 0; i < count; i++)
+      {
         ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
-        if (ret == MSD_OK) {
+        if (ret == MSD_OK )
+        {
           /* wait until the read is successful or a timeout occurs */
-
-          timeout = HAL_GetTick();
-          while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
+#if (osCMSIS < 0x20000U)
+          /* wait for a message from the queue or a timeout */
+          event = osMessageGet(SDQueueID, SD_TIMEOUT);
+
+          if (event.status == osEventMessage)
           {
+            if (event.value.v == READ_CPLT_MSG)
+            {
+              timer = osKernelSysTick();
+              /* block until SDIO IP is ready or a timeout occur */
+              while(osKernelSysTick() - timer <SD_TIMEOUT)
+#else
+                status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
+              if ((status == osOK) && (event == READ_CPLT_MSG))
+              {
+                timer = osKernelGetTickCount();
+                /* block until SDIO IP is ready or a timeout occur */
+                ret = MSD_ERROR;
+                while(osKernelGetTickCount() - timer < SD_TIMEOUT)
+#endif
+                {
+                  ret = BSP_SD_GetCardState();
+
+                  if (ret == MSD_OK)
+                  {
+                    break;
+                  }
+                }
+
+                if (ret != MSD_OK)
+                {
+                  break;
+                }
+#if (osCMSIS < 0x20000U)
+              }
+            }
+#else
           }
-          if (ReadStatus == 0)
-          {
-            res = RES_ERROR;
-            break;
-          }
-          ReadStatus = 0;
-
+#endif
 #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
           /*
@@ -288,9 +389,8 @@
       }
 
-      if ((i == count) && (ret == MSD_OK))
+      if ((i == count) && (ret == MSD_OK ))
         res = RES_OK;
     }
 #endif
-
   return res;
 }
@@ -312,55 +412,66 @@
 {
   DRESULT res = RES_ERROR;
-  uint32_t timeout;
+  uint32_t timer;
+
+#if (osCMSIS < 0x20000U)
+  osEvent event;
+#else
+  uint16_t event;
+  osStatus_t status;
+#endif
+
 #if defined(ENABLE_SCRATCH_BUFFER)
-  uint8_t ret;
-  int i;
-#endif
-
-   WriteStatus = 0;
+  int32_t ret;
+#endif
+
+  /*
+  * ensure the SDCard is ready for a new operation
+  */
+
+  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
+  {
+    return res;
+  }
+
+#if defined(ENABLE_SCRATCH_BUFFER)
+  if (!((uint32_t)buff & 0x3))
+  {
+#endif
 #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
   uint32_t alignedAddr;
-#endif
-
-  if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
-  {
-    return res;
-  }
-
-#if defined(ENABLE_SCRATCH_BUFFER)
-  if (!((uint32_t)buff & 0x3))
-  {
-#endif
-#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
-
-    /*
+  /*
     the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
     adjust the address and the D-Cache size to clean accordingly.
-    */
-    alignedAddr = (uint32_t)buff &  ~0x1F;
-    SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
-#endif
-
-    if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
-                              (uint32_t)(sector),
-                              count) == MSD_OK)
+  */
+  alignedAddr = (uint32_t)buff & ~0x1F;
+  SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
+#endif
+
+  if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
+                           (uint32_t) (sector),
+                           count) == MSD_OK)
+  {
+#if (osCMSIS < 0x20000U)
+    /* Get the message from the queue */
+    event = osMessageGet(SDQueueID, SD_TIMEOUT);
+
+    if (event.status == osEventMessage)
     {
-      /* Wait that writing process is completed or a timeout occurs */
-
-      timeout = HAL_GetTick();
-      while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
+      if (event.value.v == WRITE_CPLT_MSG)
       {
-      }
-      /* in case of a timeout return error */
-      if (WriteStatus == 0)
-      {
-        res = RES_ERROR;
-      }
-      else
-      {
-        WriteStatus = 0;
-        timeout = HAL_GetTick();
-
-        while((HAL_GetTick() - timeout) < SD_TIMEOUT)
+#else
+    status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
+    if ((status == osOK) && (event == WRITE_CPLT_MSG))
+    {
+#endif
+ #if (osCMSIS < 0x20000U)
+        timer = osKernelSysTick();
+        /* block until SDIO IP is ready or a timeout occur */
+        while(osKernelSysTick() - timer  < SD_TIMEOUT)
+#else
+        timer = osKernelGetTickCount();
+        /* block until SDIO IP is ready or a timeout occur */
+        while(osKernelGetTickCount() - timer  < SD_TIMEOUT)
+#endif
         {
           if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
@@ -370,37 +481,70 @@
           }
         }
+#if (osCMSIS < 0x20000U)
       }
     }
+#else
+    }
+#endif
+  }
 #if defined(ENABLE_SCRATCH_BUFFER)
-  }
-    else
-    {
-      /* Slow path, fetch each sector a part and memcpy to destination buffer */
+  else {
+    /* Slow path, fetch each sector a part and memcpy to destination buffer */
+    int i;
+
 #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
-      /*
-      * invalidate the scratch buffer before the next write to get the actual data instead of the cached one
-      */
-      SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
-#endif
-
+    /*
+     * invalidate the scratch buffer before the next write to get the actual data instead of the cached one
+     */
+     SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
+#endif
       for (i = 0; i < count; i++)
       {
-        WriteStatus = 0;
-
-        memcpy((void *)scratch, (void *)buff, BLOCKSIZE);
+        memcpy((void *)scratch, buff, BLOCKSIZE);
         buff += BLOCKSIZE;
 
         ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
-        if (ret == MSD_OK) {
+        if (ret == MSD_OK )
+        {
+          /* wait until the read is successful or a timeout occurs */
+#if (osCMSIS < 0x20000U)
           /* wait for a message from the queue or a timeout */
-          timeout = HAL_GetTick();
-          while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
+          event = osMessageGet(SDQueueID, SD_TIMEOUT);
+
+          if (event.status == osEventMessage)
           {
+            if (event.value.v == READ_CPLT_MSG)
+            {
+              timer = osKernelSysTick();
+              /* block until SDIO IP is ready or a timeout occur */
+              while(osKernelSysTick() - timer <SD_TIMEOUT)
+#else
+                status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
+              if ((status == osOK) && (event == READ_CPLT_MSG))
+              {
+                timer = osKernelGetTickCount();
+                /* block until SDIO IP is ready or a timeout occur */
+                ret = MSD_ERROR;
+                while(osKernelGetTickCount() - timer < SD_TIMEOUT)
+#endif
+                {
+                  ret = BSP_SD_GetCardState();
+
+                  if (ret == MSD_OK)
+                  {
+                    break;
+                  }
+                }
+
+                if (ret != MSD_OK)
+                {
+                  break;
+                }
+#if (osCMSIS < 0x20000U)
+              }
+            }
+#else
           }
-          if (WriteStatus == 0)
-          {
-            break;
-          }
-
+#endif
         }
         else
@@ -409,11 +553,15 @@
         }
       }
-      if ((i == count) && (ret == MSD_OK))
+
+      if ((i == count) && (ret == MSD_OK ))
         res = RES_OK;
     }
-#endif
+
+  }
+#endif
+
   return res;
 }
-#endif /* _USE_WRITE == 1 */
+ #endif /* _USE_WRITE == 1 */
 
 /* USER CODE BEGIN beforeIoctlSection */
@@ -486,5 +634,14 @@
 {
 
-  WriteStatus = 1;
+  /*
+   * No need to add an "osKernelRunning()" check here, as the SD_initialize()
+   * is always called before any SD_Read()/SD_Write() call
+   */
+#if (osCMSIS < 0x20000U)
+   osMessagePut(SDQueueID, WRITE_CPLT_MSG, 0);
+#else
+   const uint16_t msg = WRITE_CPLT_MSG;
+   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
+#endif
 }
 
@@ -496,5 +653,14 @@
 void BSP_SD_ReadCpltCallback(void)
 {
-  ReadStatus = 1;
+  /*
+   * No need to add an "osKernelRunning()" check here, as the SD_initialize()
+   * is always called before any SD_Read()/SD_Write() call
+   */
+#if (osCMSIS < 0x20000U)
+   osMessagePut(SDQueueID, READ_CPLT_MSG, 0);
+#else
+   const uint16_t msg = READ_CPLT_MSG;
+   osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
+#endif
 }
 
Index: ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.h
===================================================================
--- ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.h	(revision 74)
+++ ctrl/firmware/Main/CubeMX/FATFS/Target/sd_diskio.h	(revision 75)
@@ -18,5 +18,5 @@
 /* USER CODE END Header */
 
-/* Note: code generation based on sd_diskio_dma_template.h */
+/* Note: code generation based on sd_diskio_dma_rtos_template.h */
 
 /* Define to prevent recursive inclusion -------------------------------------*/
