user_diskio.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file user_diskio.c
  5. * @brief This file includes a diskio driver skeleton to be completed by the user.
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under Ultimate Liberty license
  13. * SLA0044, the "License"; You may not use this file except in compliance with
  14. * the License. You may obtain a copy of the License at:
  15. * www.st.com/SLA0044
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. #ifdef USE_OBSOLETE_USER_CODE_SECTION_0
  21. /*
  22. * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
  23. * To be suppressed in the future.
  24. * Kept to ensure backward compatibility with previous CubeMx versions when
  25. * migrating projects.
  26. * User code previously added there should be copied in the new user sections before
  27. * the section contents can be deleted.
  28. */
  29. /* USER CODE BEGIN 0 */
  30. /* USER CODE END 0 */
  31. #endif
  32. /* USER CODE BEGIN DECL */
  33. /* Includes ------------------------------------------------------------------*/
  34. #include "user_diskio.h"
  35. #include <furi_hal.h>
  36. #include "sector_cache.h"
  37. /* Private typedef -----------------------------------------------------------*/
  38. /* Private define ------------------------------------------------------------*/
  39. /* Private variables ---------------------------------------------------------*/
  40. /* Disk status */
  41. static volatile DSTATUS Stat = STA_NOINIT;
  42. static DSTATUS User_CheckStatus(BYTE lun) {
  43. UNUSED(lun);
  44. Stat = STA_NOINIT;
  45. if(sd_get_card_state() == SdSpiStatusOK) {
  46. Stat &= ~STA_NOINIT;
  47. }
  48. return Stat;
  49. }
  50. /* USER CODE END DECL */
  51. /* Private function prototypes -----------------------------------------------*/
  52. DSTATUS USER_initialize(BYTE pdrv);
  53. DSTATUS USER_status(BYTE pdrv);
  54. DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
  55. #if _USE_WRITE == 1
  56. DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
  57. #endif /* _USE_WRITE == 1 */
  58. #if _USE_IOCTL == 1
  59. DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff);
  60. #endif /* _USE_IOCTL == 1 */
  61. Diskio_drvTypeDef USER_Driver = {
  62. USER_initialize,
  63. USER_status,
  64. USER_read,
  65. #if _USE_WRITE
  66. USER_write,
  67. #endif /* _USE_WRITE == 1 */
  68. #if _USE_IOCTL == 1
  69. USER_ioctl,
  70. #endif /* _USE_IOCTL == 1 */
  71. };
  72. /* Private functions ---------------------------------------------------------*/
  73. static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
  74. uint8_t* cached_data = sector_cache_get(address);
  75. if(cached_data) {
  76. memcpy(data, cached_data, SD_BLOCK_SIZE);
  77. return true;
  78. }
  79. return false;
  80. }
  81. static inline void sd_cache_put(uint32_t address, uint32_t* data) {
  82. sector_cache_put(address, (uint8_t*)data);
  83. }
  84. static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) {
  85. sector_cache_invalidate_range(start_sector, end_sector);
  86. }
  87. static inline void sd_cache_invalidate_all() {
  88. sector_cache_init();
  89. }
  90. /**
  91. * @brief Initializes a Drive
  92. * @param pdrv: Physical drive number (0..)
  93. * @retval DSTATUS: Operation status
  94. */
  95. DSTATUS USER_initialize(BYTE pdrv) {
  96. /* USER CODE BEGIN INIT */
  97. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  98. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  99. DSTATUS status = User_CheckStatus(pdrv);
  100. furi_hal_sd_spi_handle = NULL;
  101. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  102. return status;
  103. /* USER CODE END INIT */
  104. }
  105. /**
  106. * @brief Gets Disk Status
  107. * @param pdrv: Physical drive number (0..)
  108. * @retval DSTATUS: Operation status
  109. */
  110. DSTATUS USER_status(BYTE pdrv) {
  111. /* USER CODE BEGIN STATUS */
  112. UNUSED(pdrv);
  113. return Stat;
  114. /* USER CODE END STATUS */
  115. }
  116. /**
  117. * @brief Reads Sector(s)
  118. * @param pdrv: Physical drive number (0..)
  119. * @param *buff: Data buffer to store read data
  120. * @param sector: Sector address (LBA)
  121. * @param count: Number of sectors to read (1..128)
  122. * @retval DRESULT: Operation result
  123. */
  124. DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
  125. /* USER CODE BEGIN READ */
  126. UNUSED(pdrv);
  127. DRESULT res = RES_ERROR;
  128. bool single_sector = count == 1;
  129. if(single_sector) {
  130. if(sd_cache_get(sector, (uint32_t*)buff)) {
  131. return RES_OK;
  132. }
  133. }
  134. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  135. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  136. if(sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
  137. SdSpiStatusOK) {
  138. FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
  139. /* wait until the read operation is finished */
  140. res = RES_OK;
  141. while(sd_get_card_state() != SdSpiStatusOK) {
  142. if(furi_hal_cortex_timer_is_expired(timer)) {
  143. res = RES_ERROR;
  144. break;
  145. }
  146. }
  147. }
  148. furi_hal_sd_spi_handle = NULL;
  149. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  150. if(single_sector && res == RES_OK) {
  151. sd_cache_put(sector, (uint32_t*)buff);
  152. }
  153. return res;
  154. /* USER CODE END READ */
  155. }
  156. /**
  157. * @brief Writes Sector(s)
  158. * @param pdrv: Physical drive number (0..)
  159. * @param *buff: Data to be written
  160. * @param sector: Sector address (LBA)
  161. * @param count: Number of sectors to write (1..128)
  162. * @retval DRESULT: Operation result
  163. */
  164. #if _USE_WRITE == 1
  165. DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
  166. /* USER CODE BEGIN WRITE */
  167. /* USER CODE HERE */
  168. UNUSED(pdrv);
  169. DRESULT res = RES_ERROR;
  170. sd_cache_invalidate_range(sector, sector + count);
  171. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  172. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  173. if(sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
  174. SdSpiStatusOK) {
  175. FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
  176. /* wait until the Write operation is finished */
  177. res = RES_OK;
  178. while(sd_get_card_state() != SdSpiStatusOK) {
  179. if(furi_hal_cortex_timer_is_expired(timer)) {
  180. sd_cache_invalidate_all();
  181. res = RES_ERROR;
  182. break;
  183. }
  184. }
  185. }
  186. furi_hal_sd_spi_handle = NULL;
  187. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  188. return res;
  189. /* USER CODE END WRITE */
  190. }
  191. #endif /* _USE_WRITE == 1 */
  192. /**
  193. * @brief I/O control operation
  194. * @param pdrv: Physical drive number (0..)
  195. * @param cmd: Control code
  196. * @param *buff: Buffer to send/receive control data
  197. * @retval DRESULT: Operation result
  198. */
  199. #if _USE_IOCTL == 1
  200. DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
  201. /* USER CODE BEGIN IOCTL */
  202. UNUSED(pdrv);
  203. DRESULT res = RES_ERROR;
  204. SD_CardInfo CardInfo;
  205. if(Stat & STA_NOINIT) return RES_NOTRDY;
  206. furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
  207. furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
  208. switch(cmd) {
  209. /* Make sure that no pending write process */
  210. case CTRL_SYNC:
  211. res = RES_OK;
  212. break;
  213. /* Get number of sectors on the disk (DWORD) */
  214. case GET_SECTOR_COUNT:
  215. sd_get_card_info(&CardInfo);
  216. *(DWORD*)buff = CardInfo.LogBlockNbr;
  217. res = RES_OK;
  218. break;
  219. /* Get R/W sector size (WORD) */
  220. case GET_SECTOR_SIZE:
  221. sd_get_card_info(&CardInfo);
  222. *(WORD*)buff = CardInfo.LogBlockSize;
  223. res = RES_OK;
  224. break;
  225. /* Get erase block size in unit of sector (DWORD) */
  226. case GET_BLOCK_SIZE:
  227. sd_get_card_info(&CardInfo);
  228. *(DWORD*)buff = CardInfo.LogBlockSize;
  229. res = RES_OK;
  230. break;
  231. default:
  232. res = RES_PARERR;
  233. }
  234. furi_hal_sd_spi_handle = NULL;
  235. furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
  236. return res;
  237. /* USER CODE END IOCTL */
  238. }
  239. #endif /* _USE_IOCTL == 1 */
  240. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/