drv_sd.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * File : drv_sd.c
  3. * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. *
  19. * Change Logs:
  20. * Date Author Notes
  21. * 2017-08-08 Yang the first version
  22. */
  23. #include <string.h>
  24. #include <board.h>
  25. #include "drv_sd.h"
  26. static struct mci_device *_mci_device;
  27. static uint8_t sdio_buffer[1024];
  28. static rt_err_t rt_mci_init(rt_device_t dev)
  29. {
  30. rt_err_t result = RT_EOK;
  31. return result;
  32. }
  33. static rt_err_t rt_mci_open(rt_device_t dev, rt_uint16_t oflag)
  34. {
  35. return RT_EOK;
  36. }
  37. static rt_err_t rt_mci_close(rt_device_t dev)
  38. {
  39. return RT_EOK;
  40. }
  41. static rt_size_t rt_mci_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  42. {
  43. rt_uint8_t status = kStatus_Success;
  44. struct mci_device *mci = (struct mci_device *)dev;
  45. rt_mutex_take(&mci->lock, RT_WAITING_FOREVER);
  46. {
  47. /* non-aligned. */
  48. uint32_t i;
  49. rt_size_t sector_adr;
  50. uint8_t* copy_buffer;
  51. sector_adr = pos;
  52. copy_buffer = (uint8_t*)buffer;
  53. for(i=0; i<size; i++)
  54. {
  55. status=SD_ReadBlocks(&mci->card, sdio_buffer, sector_adr, 1);
  56. memcpy(copy_buffer, sdio_buffer, mci->card.blockSize);
  57. sector_adr ++;
  58. copy_buffer += mci->card.blockSize;
  59. }
  60. }
  61. rt_mutex_release(&_mci_device->lock);
  62. if (status == kStatus_Success) return size;
  63. return 0;
  64. }
  65. static rt_size_t rt_mci_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  66. {
  67. rt_uint8_t status = kStatus_Success;
  68. struct mci_device *mci = (struct mci_device *)dev;
  69. rt_mutex_take(&mci->lock, RT_WAITING_FOREVER);
  70. {
  71. /* non-aligned. */
  72. uint32_t i;
  73. rt_size_t sector_adr;
  74. uint8_t* copy_buffer;
  75. sector_adr = pos;
  76. copy_buffer = (uint8_t*)buffer;
  77. for(i = 0; i < size; i++)
  78. {
  79. memcpy(sdio_buffer, copy_buffer, mci->card.blockSize);
  80. status = SD_WriteBlocks(&mci->card, sdio_buffer, sector_adr, 1);
  81. sector_adr ++;
  82. copy_buffer += mci->card.blockSize;
  83. }
  84. }
  85. /* release and exit */
  86. rt_mutex_release(&_mci_device->lock);
  87. if (status == kStatus_Success) return size;
  88. return 0;
  89. }
  90. static rt_err_t rt_mci_control(rt_device_t dev, int cmd, void *args)
  91. {
  92. struct mci_device *mci = (struct mci_device *)dev;
  93. RT_ASSERT(dev != RT_NULL);
  94. if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
  95. {
  96. struct rt_device_blk_geometry *geometry;
  97. geometry = (struct rt_device_blk_geometry *)args;
  98. if (geometry == RT_NULL) return -RT_ERROR;
  99. geometry->bytes_per_sector = mci->card.blockSize;
  100. geometry->block_size = mci->card.csd.eraseSectorSize;
  101. geometry->sector_count = mci->card.blockCount;
  102. }
  103. return RT_EOK;
  104. }
  105. void sdio_init_pins(void)
  106. {
  107. const uint32_t port2_pin10_config = (
  108. IOCON_PIO_FUNC2 | /* Pin is configured as SD_CARD_DET_N */
  109. IOCON_PIO_MODE_INACT | /* No addition pin function */
  110. IOCON_PIO_INV_DI | /* Input function is not inverted */
  111. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  112. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  113. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  114. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  115. );
  116. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN10_IDX, port2_pin10_config); /* PORT2 PIN10 (coords: P1) is configured as SD_CARD_DET_N */
  117. const uint32_t port2_pin3_config = (
  118. IOCON_PIO_FUNC2 | /* Pin is configured as SD_CLK */
  119. IOCON_PIO_MODE_INACT | /* No addition pin function */
  120. IOCON_PIO_INV_DI | /* Input function is not inverted */
  121. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  122. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  123. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  124. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  125. );
  126. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN3_IDX, port2_pin3_config); /* PORT2 PIN3 (coords: B1) is configured as SD_CLK */
  127. const uint32_t port2_pin4_config = (
  128. IOCON_PIO_FUNC2 | /* Pin is configured as SD_CMD */
  129. IOCON_PIO_MODE_INACT | /* No addition pin function */
  130. IOCON_PIO_INV_DI | /* Input function is not inverted */
  131. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  132. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  133. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  134. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  135. );
  136. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN4_IDX, port2_pin4_config); /* PORT2 PIN4 (coords: D3) is configured as SD_CMD */
  137. const uint32_t port2_pin5_config = (
  138. IOCON_PIO_FUNC2 | /* Pin is configured as SD_POW_EN */
  139. IOCON_PIO_MODE_INACT | /* No addition pin function */
  140. IOCON_PIO_INV_DI | /* Input function is not inverted */
  141. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  142. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  143. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  144. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  145. );
  146. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN5_IDX, port2_pin5_config); /* PORT2 PIN5 (coords: C1) is configured as SD_POW_EN */
  147. const uint32_t port2_pin6_config = (
  148. IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(0) */
  149. IOCON_PIO_MODE_INACT | /* No addition pin function */
  150. IOCON_PIO_INV_DI | /* Input function is not inverted */
  151. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  152. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  153. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  154. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  155. );
  156. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN6_IDX, port2_pin6_config); /* PORT2 PIN6 (coords: F3) is configured as SD_D(0) */
  157. const uint32_t port2_pin7_config = (
  158. IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(1) */
  159. IOCON_PIO_MODE_INACT | /* No addition pin function */
  160. IOCON_PIO_INV_DI | /* Input function is not inverted */
  161. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  162. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  163. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  164. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  165. );
  166. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN7_IDX, port2_pin7_config); /* PORT2 PIN7 (coords: J2) is configured as SD_D(1) */
  167. const uint32_t port2_pin8_config = (
  168. IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(2) */
  169. IOCON_PIO_MODE_INACT | /* No addition pin function */
  170. IOCON_PIO_INV_DI | /* Input function is not inverted */
  171. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  172. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  173. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  174. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  175. );
  176. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN8_IDX, port2_pin8_config); /* PORT2 PIN8 (coords: F4) is configured as SD_D(2) */
  177. const uint32_t port2_pin9_config = (
  178. IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(3) */
  179. IOCON_PIO_MODE_INACT | /* No addition pin function */
  180. IOCON_PIO_INV_DI | /* Input function is not inverted */
  181. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  182. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  183. IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
  184. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  185. );
  186. IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN9_IDX, port2_pin9_config); /* PORT2 PIN9 (coords: K2) is configured as SD_D(3) */
  187. const uint32_t port3_pin15_config = (
  188. IOCON_PIO_FUNC2 | /* Pin is configured as SD_WR_PRT */
  189. IOCON_PIO_MODE_INACT | /* No addition pin function */
  190. IOCON_PIO_INV_DI | /* Input function is not inverted */
  191. IOCON_PIO_DIGITAL_EN | /* Enables digital function */
  192. IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
  193. IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
  194. IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
  195. );
  196. IOCON_PinMuxSet(IOCON, PORT3_IDX, PIN15_IDX, port3_pin15_config); /* PORT3 PIN15 (coords: D2) is configured as SD_WR_PRT */
  197. }
  198. sd_card_t g_sd;
  199. /*! @brief Data written to the card */
  200. uint8_t g_dataWrite[FSL_SDMMC_DEFAULT_BLOCK_SIZE * 5U];
  201. /*! @brief Data read from the card */
  202. uint8_t g_dataRead[FSL_SDMMC_DEFAULT_BLOCK_SIZE * 5U];
  203. rt_err_t mci_hw_init(const char *device_name)
  204. #if 0
  205. {
  206. sd_card_t *card = &g_sd;
  207. bool isReadOnly;
  208. bool failedFlag = false;
  209. char ch = '0';
  210. /* attach main clock to SDIF */
  211. CLOCK_AttachClk(kMCLK_to_SDIO_CLK);
  212. /* need call this function to clear the halt bit in clock divider register */
  213. CLOCK_SetClkDiv(kCLOCK_DivSdioClk, 1U, true);
  214. sdio_init_pins();
  215. card->host.base = SDIF;
  216. card->host.sourceClock_Hz = CLOCK_GetFreq(kCLOCK_SDio);
  217. /* Init card. */
  218. if (SD_Init(card))
  219. {
  220. rt_kprintf("\r\nSD card init failed.\r\n");
  221. return -1;
  222. }
  223. rt_kprintf("\r\nRead/Write/Erase the card continuously until encounter error......\r\n");
  224. /* Check if card is readonly. */
  225. isReadOnly = SD_CheckReadOnly(card);
  226. if (isReadOnly)
  227. {
  228. //while (true)
  229. {
  230. /*if (failedFlag || (ch == 'q'))
  231. {
  232. break;
  233. }*/
  234. rt_kprintf("\r\nRead one data block......\r\n");
  235. if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 1U))
  236. {
  237. rt_kprintf("Read one data block failed.\r\n");
  238. failedFlag = true;
  239. //continue;
  240. }
  241. rt_kprintf("Read multiple data blocks......\r\n");
  242. if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 5U))
  243. {
  244. rt_kprintf("Read multiple data blocks failed.\r\n");
  245. failedFlag = true;
  246. //continue;
  247. }
  248. rt_kprintf(
  249. "\r\nInput 'q' to quit read process.\
  250. \r\nInput other char to read data blocks again.\r\n");
  251. //ch = GETCHAR();
  252. //PUTCHAR(ch);
  253. }
  254. }
  255. else
  256. {
  257. memset(g_dataWrite, 0x67U, sizeof(g_dataWrite));
  258. //while (true)
  259. {
  260. /*if (failedFlag || (ch == 'q'))
  261. {
  262. break;
  263. }*/
  264. rt_kprintf("\r\nWrite/read one data block......\r\n");
  265. if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, 2U, 1U))
  266. {
  267. rt_kprintf("Write one data block failed.\r\n");
  268. failedFlag = true;
  269. //continue;
  270. }
  271. memset(g_dataRead, 0U, sizeof(g_dataRead));
  272. if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 1U))
  273. {
  274. rt_kprintf("Read one data block failed.\r\n");
  275. failedFlag = true;
  276. //continue;
  277. }
  278. rt_kprintf("Compare the read/write content......\r\n");
  279. if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
  280. {
  281. rt_kprintf("The read/write content isn't consistent.\r\n");
  282. failedFlag = true;
  283. //continue;
  284. }
  285. rt_kprintf("The read/write content is consistent.\r\n");
  286. rt_kprintf("Write/read multiple data blocks......\r\n");
  287. if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, 2U, 5U))
  288. {
  289. rt_kprintf("Write multiple data blocks failed.\r\n");
  290. failedFlag = true;
  291. //continue;
  292. }
  293. memset(g_dataRead, 0U, sizeof(g_dataRead));
  294. if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 5U))
  295. {
  296. rt_kprintf("Read multiple data blocks failed.\r\n");
  297. failedFlag = true;
  298. //continue;
  299. }
  300. rt_kprintf("Compare the read/write content......\r\n");
  301. if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
  302. {
  303. rt_kprintf("The read/write content isn't consistent.\r\n");
  304. failedFlag = true;
  305. //continue;
  306. }
  307. rt_kprintf("The read/write content is consistent.\r\n");
  308. rt_kprintf("Erase multiple data blocks......\r\n");
  309. if (kStatus_Success != SD_EraseBlocks(card, 2U, 5U))
  310. {
  311. rt_kprintf("Erase multiple data blocks failed.\r\n");
  312. failedFlag = true;
  313. //continue;
  314. }
  315. rt_kprintf(
  316. "\r\nInput 'q' to quit read/write/erase process.\
  317. \r\nInput other char to read/write/erase data blocks again.\r\n");
  318. //ch = GETCHAR();
  319. //PUTCHAR(ch);
  320. }
  321. }
  322. rt_kprintf("\r\nThe example will not read/write data blocks again.\r\n");
  323. SD_Deinit(card);
  324. }
  325. #else
  326. {
  327. _mci_device = (struct mci_device *)rt_malloc(sizeof(struct mci_device));
  328. if (_mci_device == RT_NULL)
  329. {
  330. rt_kprintf("mci_hw_init _mci_device rt_malloc failed!\n");
  331. return -RT_ERROR;
  332. }
  333. rt_memset(_mci_device, 0, sizeof(struct mci_device));
  334. /* attach main clock to SDIF */
  335. CLOCK_AttachClk(kMCLK_to_SDIO_CLK);
  336. /* need call this function to clear the halt bit in clock divider register */
  337. CLOCK_SetClkDiv(kCLOCK_DivSdioClk, 1U, true);
  338. sdio_init_pins();
  339. /* Save host information. */
  340. _mci_device->card.host.base = SDIF;
  341. _mci_device->card.host.sourceClock_Hz = CLOCK_GetFreq(kCLOCK_SDio);
  342. if (kStatus_Success != SD_Init(&_mci_device->card))
  343. {
  344. SD_Deinit(&_mci_device->card);
  345. memset(&_mci_device->card, 0U, sizeof(_mci_device->card));
  346. rt_kprintf("SD_Init failed!\n");
  347. return -RT_ERROR;
  348. }
  349. /*
  350. follow the page: https://community.nxp.com/thread/454769
  351. The issue concerns sdmmc library bug (I finally solved) in SD_Init() in the file sdmmc/src/fsl_sd.c:SD_SelectBusTiming()
  352. calls SD_SwitchFunction() which sets block size to 64bytes (512bits).Therefore SD_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)
  353. should be called again before SD_Init() exits.
  354. */
  355. if (kStatus_Success != SDMMC_SetBlockSize(_mci_device->card.host.base, _mci_device->card.host.transfer, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
  356. {
  357. SD_Deinit(&_mci_device->card);
  358. memset(&_mci_device->card, 0U, sizeof(_mci_device->card));
  359. rt_kprintf("SD_Init failed!\n");
  360. return -RT_ERROR;
  361. }
  362. /* initialize mutex lock */
  363. rt_mutex_init(&_mci_device->lock, device_name, RT_IPC_FLAG_FIFO);
  364. /* create finish event */
  365. _mci_device->finish_event = rt_event_create(device_name, RT_IPC_FLAG_FIFO);
  366. /* register sdcard device */
  367. _mci_device->parent.type = RT_Device_Class_Block;
  368. _mci_device->geometry.bytes_per_sector = 0;
  369. _mci_device->geometry.sector_count = 0;
  370. _mci_device->geometry.block_size = 0;
  371. _mci_device->parent.init = rt_mci_init;
  372. _mci_device->parent.open = rt_mci_open;
  373. _mci_device->parent.close = rt_mci_close;
  374. _mci_device->parent.read = rt_mci_read;
  375. _mci_device->parent.write = rt_mci_write;
  376. _mci_device->parent.control = rt_mci_control;
  377. /* no private, no callback */
  378. _mci_device->parent.user_data = RT_NULL;
  379. _mci_device->parent.rx_indicate = RT_NULL;
  380. _mci_device->parent.tx_complete = RT_NULL;
  381. rt_device_register(&_mci_device->parent, device_name,
  382. RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE );
  383. return RT_EOK;
  384. }
  385. #endif