drv_spi.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-2-27 YHKuo First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_SPI)
  14. #define LOG_TAG "drv.spi"
  15. #define DBG_ENABLE
  16. #define DBG_SECTION_NAME LOG_TAG
  17. #define DBG_LEVEL DBG_INFO
  18. #define DBG_COLOR
  19. #include <rtdbg.h>
  20. #include <rthw.h>
  21. #include <rtdevice.h>
  22. #include <rtdef.h>
  23. #include <drv_spi.h>
  24. /* Private define ---------------------------------------------------------------*/
  25. #ifndef NU_SPI_USE_PDMA_MIN_THRESHOLD
  26. #define NU_SPI_USE_PDMA_MIN_THRESHOLD (128)
  27. #endif
  28. enum
  29. {
  30. SPI_START = -1,
  31. #if defined(BSP_USING_SPI0)
  32. SPI0_IDX,
  33. #endif
  34. #if defined(BSP_USING_SPI1)
  35. SPI1_IDX,
  36. #endif
  37. #if defined(BSP_USING_SPI2)
  38. SPI2_IDX,
  39. #endif
  40. #if defined(BSP_USING_SPI3)
  41. SPI3_IDX,
  42. #endif
  43. SPI_CNT
  44. };
  45. /* Private typedef --------------------------------------------------------------*/
  46. /* Private functions ------------------------------------------------------------*/
  47. static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
  48. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
  49. static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name);
  50. static rt_uint32_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
  51. static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
  52. #if defined(BSP_USING_SPI_PDMA)
  53. static void nu_pdma_spi_rx_cb(void *pvUserData, uint32_t u32EventFilter);
  54. static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word);
  55. static rt_err_t nu_pdma_spi_tx_config(struct nu_spi *spi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word);
  56. static rt_size_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
  57. #endif
  58. /* Public functions -------------------------------------------------------------*/
  59. void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word);
  60. void nu_spi_drain_rxfifo(SPI_T *spi_base);
  61. /* Private variables ------------------------------------------------------------*/
  62. static struct rt_spi_ops nu_spi_poll_ops =
  63. {
  64. .configure = nu_spi_bus_configure,
  65. .xfer = nu_spi_bus_xfer,
  66. };
  67. static struct nu_spi nu_spi_arr [] =
  68. {
  69. #if defined(BSP_USING_SPI0)
  70. {
  71. .name = "spi0",
  72. .spi_base = SPI0,
  73. #if defined(BSP_USING_SPI_PDMA)
  74. #if defined(BSP_USING_SPI0_PDMA)
  75. .pdma_perp_tx = PDMA_SPI0_TX,
  76. .pdma_perp_rx = PDMA_SPI0_RX,
  77. #else
  78. .pdma_perp_tx = NU_PDMA_UNUSED,
  79. .pdma_perp_rx = NU_PDMA_UNUSED,
  80. #endif
  81. #endif
  82. },
  83. #endif
  84. #if defined(BSP_USING_SPI1)
  85. {
  86. .name = "spi1",
  87. .spi_base = SPI1,
  88. #if defined(BSP_USING_SPI_PDMA)
  89. #if defined(BSP_USING_SPI1_PDMA)
  90. .pdma_perp_tx = PDMA_SPI1_TX,
  91. .pdma_perp_rx = PDMA_SPI1_RX,
  92. #else
  93. .pdma_perp_tx = NU_PDMA_UNUSED,
  94. .pdma_perp_rx = NU_PDMA_UNUSED,
  95. #endif
  96. #endif
  97. },
  98. #endif
  99. #if defined(BSP_USING_SPI2)
  100. {
  101. .name = "spi2",
  102. .spi_base = SPI2,
  103. #if defined(BSP_USING_SPI_PDMA)
  104. #if defined(BSP_USING_SPI2_PDMA)
  105. .pdma_perp_tx = PDMA_SPI2_TX,
  106. .pdma_perp_rx = PDMA_SPI2_RX,
  107. #else
  108. .pdma_perp_tx = NU_PDMA_UNUSED,
  109. .pdma_perp_rx = NU_PDMA_UNUSED,
  110. #endif
  111. #endif
  112. },
  113. #endif
  114. #if defined(BSP_USING_SPI3)
  115. {
  116. .name = "spi3",
  117. .spi_base = SPI3,
  118. #if defined(BSP_USING_SPI_PDMA)
  119. #if defined(BSP_USING_SPI3_PDMA)
  120. .pdma_perp_tx = PDMA_SPI3_TX,
  121. .pdma_perp_rx = PDMA_SPI3_RX,
  122. #else
  123. .pdma_perp_tx = NU_PDMA_UNUSED,
  124. .pdma_perp_rx = NU_PDMA_UNUSED,
  125. #endif
  126. #endif
  127. },
  128. #endif
  129. {0}
  130. }; /* spi nu_spi */
  131. static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device,
  132. struct rt_spi_configuration *configuration)
  133. {
  134. struct nu_spi *spi_bus;
  135. uint32_t u32SPIMode;
  136. uint32_t u32BusClock;
  137. rt_err_t ret = RT_EOK;
  138. RT_ASSERT(device != RT_NULL);
  139. RT_ASSERT(configuration != RT_NULL);
  140. spi_bus = (struct nu_spi *) device->bus;
  141. /* Check mode */
  142. switch (configuration->mode & RT_SPI_MODE_3)
  143. {
  144. case RT_SPI_MODE_0:
  145. u32SPIMode = SPI_MODE_0;
  146. break;
  147. case RT_SPI_MODE_1:
  148. u32SPIMode = SPI_MODE_1;
  149. break;
  150. case RT_SPI_MODE_2:
  151. u32SPIMode = SPI_MODE_2;
  152. break;
  153. case RT_SPI_MODE_3:
  154. u32SPIMode = SPI_MODE_3;
  155. break;
  156. default:
  157. ret = RT_EIO;
  158. goto exit_nu_spi_bus_configure;
  159. }
  160. /* Check data width */
  161. if (!(configuration->data_width == 8 ||
  162. configuration->data_width == 16 ||
  163. configuration->data_width == 24 ||
  164. configuration->data_width == 32))
  165. {
  166. ret = RT_EINVAL;
  167. goto exit_nu_spi_bus_configure;
  168. }
  169. /* Try to set clock and get actual spi bus clock */
  170. u32BusClock = SPI_SetBusClock(spi_bus->spi_base, configuration->max_hz);
  171. if (configuration->max_hz > u32BusClock)
  172. {
  173. LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", spi_bus->name, u32BusClock, configuration->max_hz);
  174. configuration->max_hz = u32BusClock;
  175. }
  176. /* Need to initialize new configuration? */
  177. if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(*configuration)) != 0)
  178. {
  179. rt_memcpy(&spi_bus->configuration, configuration, sizeof(*configuration));
  180. SPI_Open(spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, u32BusClock);
  181. if (configuration->mode & RT_SPI_CS_HIGH)
  182. {
  183. /* Set CS pin to LOW */
  184. SPI_SET_SS_LOW(spi_bus->spi_base);
  185. }
  186. else
  187. {
  188. /* Set CS pin to HIGH */
  189. SPI_SET_SS_HIGH(spi_bus->spi_base);
  190. }
  191. if (configuration->mode & RT_SPI_MSB)
  192. {
  193. /* Set sequence to MSB first */
  194. SPI_SET_MSB_FIRST(spi_bus->spi_base);
  195. }
  196. else
  197. {
  198. /* Set sequence to LSB first */
  199. SPI_SET_LSB_FIRST(spi_bus->spi_base);
  200. }
  201. }
  202. /* Clear SPI RX FIFO */
  203. nu_spi_drain_rxfifo(spi_bus->spi_base);
  204. exit_nu_spi_bus_configure:
  205. return -(ret);
  206. }
  207. #if defined(BSP_USING_SPI_PDMA)
  208. static void nu_pdma_spi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
  209. {
  210. rt_err_t result;
  211. struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
  212. RT_ASSERT(spi_bus != RT_NULL);
  213. result = rt_sem_release(spi_bus->m_psSemBus);
  214. RT_ASSERT(result == RT_EOK);
  215. }
  216. static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
  217. {
  218. rt_err_t result = RT_EOK;
  219. rt_uint8_t *dst_addr = NULL;
  220. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  221. /* Get base address of spi register */
  222. SPI_T *spi_base = spi_bus->spi_base;
  223. rt_uint8_t spi_pdma_rx_chid = spi_bus->pdma_chanid_rx;
  224. result = nu_pdma_callback_register(spi_pdma_rx_chid,
  225. nu_pdma_spi_rx_cb,
  226. (void *)spi_bus,
  227. NU_PDMA_EVENT_TRANSFER_DONE);
  228. if (result != RT_EOK)
  229. {
  230. goto exit_nu_pdma_spi_rx_config;
  231. }
  232. if (pu8Buf == RT_NULL)
  233. {
  234. memctrl = eMemCtl_SrcFix_DstFix;
  235. dst_addr = (rt_uint8_t *) &spi_bus->dummy;
  236. }
  237. else
  238. {
  239. memctrl = eMemCtl_SrcFix_DstInc;
  240. dst_addr = pu8Buf;
  241. }
  242. result = nu_pdma_channel_memctrl_set(spi_pdma_rx_chid, memctrl);
  243. if (result != RT_EOK)
  244. {
  245. goto exit_nu_pdma_spi_rx_config;
  246. }
  247. result = nu_pdma_transfer(spi_pdma_rx_chid,
  248. bytes_per_word * 8,
  249. (uint32_t)&spi_base->RX,
  250. (uint32_t)dst_addr,
  251. i32RcvLen / bytes_per_word,
  252. 0);
  253. exit_nu_pdma_spi_rx_config:
  254. return result;
  255. }
  256. static rt_err_t nu_pdma_spi_tx_config(struct nu_spi *spi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word)
  257. {
  258. rt_err_t result = RT_EOK;
  259. rt_uint8_t *src_addr = NULL;
  260. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  261. /* Get base address of spi register */
  262. SPI_T *spi_base = spi_bus->spi_base;
  263. rt_uint8_t spi_pdma_tx_chid = spi_bus->pdma_chanid_tx;
  264. if (pu8Buf == RT_NULL)
  265. {
  266. spi_bus->dummy = 0;
  267. memctrl = eMemCtl_SrcFix_DstFix;
  268. src_addr = (rt_uint8_t *)&spi_bus->dummy;
  269. }
  270. else
  271. {
  272. memctrl = eMemCtl_SrcInc_DstFix;
  273. src_addr = (rt_uint8_t *)pu8Buf;
  274. }
  275. result = nu_pdma_channel_memctrl_set(spi_pdma_tx_chid, memctrl);
  276. if (result != RT_EOK)
  277. {
  278. goto exit_nu_pdma_spi_tx_config;
  279. }
  280. result = nu_pdma_transfer(spi_pdma_tx_chid,
  281. bytes_per_word * 8,
  282. (uint32_t)src_addr,
  283. (uint32_t)&spi_base->TX,
  284. i32SndLen / bytes_per_word,
  285. 0);
  286. exit_nu_pdma_spi_tx_config:
  287. return result;
  288. }
  289. /**
  290. * SPI PDMA transfer
  291. */
  292. static rt_size_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  293. {
  294. rt_err_t result = RT_EOK;
  295. rt_uint32_t u32Offset = 0;
  296. rt_uint32_t u32TransferCnt = length / bytes_per_word;
  297. rt_uint32_t u32TxCnt = 0;
  298. /* Get base address of spi register */
  299. SPI_T *spi_base = spi_bus->spi_base;
  300. do
  301. {
  302. u32TxCnt = (u32TransferCnt > NU_PDMA_MAX_TXCNT) ? NU_PDMA_MAX_TXCNT : u32TransferCnt;
  303. result = nu_pdma_spi_rx_config(spi_bus, (recv_addr == RT_NULL) ? recv_addr : &recv_addr[u32Offset], (u32TxCnt * bytes_per_word), bytes_per_word);
  304. RT_ASSERT(result == RT_EOK);
  305. result = nu_pdma_spi_tx_config(spi_bus, (send_addr == RT_NULL) ? send_addr : &send_addr[u32Offset], (u32TxCnt * bytes_per_word), bytes_per_word);
  306. RT_ASSERT(result == RT_EOK);
  307. /* Trigger TX/RX PDMA transfer. */
  308. SPI_TRIGGER_TX_RX_PDMA(spi_base);
  309. /* Wait RX-PDMA transfer done */
  310. result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
  311. RT_ASSERT(result == RT_EOK);
  312. /* Stop TX/RX DMA transfer. */
  313. SPI_DISABLE_TX_RX_PDMA(spi_base);
  314. u32TransferCnt -= u32TxCnt;
  315. u32Offset += u32TxCnt;
  316. }
  317. while (u32TransferCnt > 0);
  318. return length;
  319. }
  320. rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
  321. {
  322. /* Allocate SPI_TX nu_dma channel */
  323. if ((spi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(spi_bus->pdma_perp_tx)) < 0)
  324. {
  325. goto exit_nu_hw_spi_pdma_allocate;
  326. }
  327. /* Allocate SPI_RX nu_dma channel */
  328. else if ((spi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(spi_bus->pdma_perp_rx)) < 0)
  329. {
  330. nu_pdma_channel_free(spi_bus->pdma_chanid_tx);
  331. goto exit_nu_hw_spi_pdma_allocate;
  332. }
  333. spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
  334. RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
  335. return RT_EOK;
  336. exit_nu_hw_spi_pdma_allocate:
  337. return -(RT_ERROR);
  338. }
  339. #endif /* #if defined(BSP_USING_SPI_PDMA) */
  340. void nu_spi_drain_rxfifo(SPI_T *spi_base)
  341. {
  342. while (SPI_IS_BUSY(spi_base));
  343. // Drain SPI RX FIFO, make sure RX FIFO is empty
  344. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  345. {
  346. SPI_ClearRxFIFO(spi_base);
  347. }
  348. }
  349. static int nu_spi_read(SPI_T *spi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
  350. {
  351. int size = 0;
  352. // Read RX data
  353. if (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  354. {
  355. uint32_t val;
  356. // Read data from SPI RX FIFO
  357. switch (bytes_per_word)
  358. {
  359. case 4:
  360. val = SPI_READ_RX(spi_base);
  361. nu_set32_le(recv_addr, val);
  362. break;
  363. case 3:
  364. val = SPI_READ_RX(spi_base);
  365. nu_set24_le(recv_addr, val);
  366. break;
  367. case 2:
  368. val = SPI_READ_RX(spi_base);
  369. nu_set16_le(recv_addr, val);
  370. break;
  371. case 1:
  372. *recv_addr = SPI_READ_RX(spi_base);
  373. break;
  374. default:
  375. LOG_E("Data length is not supported.\n");
  376. break;
  377. }
  378. size = bytes_per_word;
  379. }
  380. return size;
  381. }
  382. static int nu_spi_write(SPI_T *spi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
  383. {
  384. // Wait SPI TX send data
  385. while (SPI_GET_TX_FIFO_FULL_FLAG(spi_base));
  386. // Input data to SPI TX
  387. switch (bytes_per_word)
  388. {
  389. case 4:
  390. SPI_WRITE_TX(spi_base, nu_get32_le(send_addr));
  391. break;
  392. case 3:
  393. SPI_WRITE_TX(spi_base, nu_get24_le(send_addr));
  394. break;
  395. case 2:
  396. SPI_WRITE_TX(spi_base, nu_get16_le(send_addr));
  397. break;
  398. case 1:
  399. SPI_WRITE_TX(spi_base, *((uint8_t *)send_addr));
  400. break;
  401. default:
  402. LOG_E("Data length is not supported.\n");
  403. break;
  404. }
  405. return bytes_per_word;
  406. }
  407. /**
  408. * @brief SPI bus polling
  409. * @param dev : The pointer of the specified SPI module.
  410. * @param send_addr : Source address
  411. * @param recv_addr : Destination address
  412. * @param length : Data length
  413. */
  414. static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
  415. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  416. {
  417. SPI_T *spi_base = spi_bus->spi_base;
  418. // Write-only
  419. if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
  420. {
  421. while (length > 0)
  422. {
  423. send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
  424. length -= bytes_per_word;
  425. }
  426. } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
  427. // Read-only
  428. else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
  429. {
  430. spi_bus->dummy = 0;
  431. while (length > 0)
  432. {
  433. /* Input data to SPI TX FIFO */
  434. length -= nu_spi_write(spi_base, (const uint8_t *)&spi_bus->dummy, bytes_per_word);
  435. /* Read data from RX FIFO */
  436. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  437. }
  438. } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
  439. // Read&Write
  440. else
  441. {
  442. while (length > 0)
  443. {
  444. /* Input data to SPI TX FIFO */
  445. send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
  446. length -= bytes_per_word;
  447. /* Read data from RX FIFO */
  448. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  449. }
  450. } // else
  451. /* Wait RX or drain RX-FIFO */
  452. if (recv_addr)
  453. {
  454. // Wait SPI transmission done
  455. while (SPI_IS_BUSY(spi_base))
  456. {
  457. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  458. {
  459. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  460. }
  461. }
  462. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  463. {
  464. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  465. }
  466. }
  467. else
  468. {
  469. /* Clear SPI RX FIFO */
  470. nu_spi_drain_rxfifo(spi_base);
  471. }
  472. }
  473. void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
  474. {
  475. RT_ASSERT(spi_bus != RT_NULL);
  476. #if defined(BSP_USING_SPI_PDMA)
  477. /* DMA transfer constrains */
  478. if ((spi_bus->pdma_chanid_rx >= 0) &&
  479. !((uint32_t)tx % bytes_per_word) &&
  480. !((uint32_t)rx % bytes_per_word) &&
  481. (bytes_per_word != 3) &&
  482. (length >= NU_SPI_USE_PDMA_MIN_THRESHOLD))
  483. nu_spi_pdma_transmit(spi_bus, tx, rx, length, bytes_per_word);
  484. else
  485. nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
  486. #else
  487. nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
  488. #endif
  489. }
  490. static rt_uint32_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  491. {
  492. struct nu_spi *spi_bus;
  493. struct rt_spi_configuration *configuration;
  494. uint8_t bytes_per_word;
  495. RT_ASSERT(device != RT_NULL);
  496. RT_ASSERT(device->bus != RT_NULL);
  497. RT_ASSERT(message != RT_NULL);
  498. spi_bus = (struct nu_spi *) device->bus;
  499. configuration = (struct rt_spi_configuration *)&spi_bus->configuration;
  500. bytes_per_word = configuration->data_width / 8;
  501. if ((message->length % bytes_per_word) != 0)
  502. {
  503. /* Say bye. */
  504. LOG_E("%s: error payload length(%d%%%d != 0).\n", spi_bus->name, message->length, bytes_per_word);
  505. return 0;
  506. }
  507. if (message->length > 0)
  508. {
  509. if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
  510. {
  511. if (configuration->mode & RT_SPI_CS_HIGH)
  512. {
  513. SPI_SET_SS_HIGH(spi_bus->spi_base);
  514. }
  515. else
  516. {
  517. SPI_SET_SS_LOW(spi_bus->spi_base);
  518. }
  519. }
  520. nu_spi_transfer(spi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
  521. if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
  522. {
  523. if (configuration->mode & RT_SPI_CS_HIGH)
  524. {
  525. SPI_SET_SS_LOW(spi_bus->spi_base);
  526. }
  527. else
  528. {
  529. SPI_SET_SS_HIGH(spi_bus->spi_base);
  530. }
  531. }
  532. }
  533. return message->length;
  534. }
  535. static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name)
  536. {
  537. return rt_spi_bus_register(&spi_bus->dev, name, &nu_spi_poll_ops);
  538. }
  539. /**
  540. * Hardware SPI Initial
  541. */
  542. static int rt_hw_spi_init(void)
  543. {
  544. int i;
  545. for (i = (SPI_START + 1); i < SPI_CNT; i++)
  546. {
  547. nu_spi_register_bus(&nu_spi_arr[i], nu_spi_arr[i].name);
  548. #if defined(BSP_USING_SPI_PDMA)
  549. nu_spi_arr[i].pdma_chanid_tx = -1;
  550. nu_spi_arr[i].pdma_chanid_rx = -1;
  551. if ((nu_spi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_spi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
  552. {
  553. if (nu_hw_spi_pdma_allocate(&nu_spi_arr[i]) != RT_EOK)
  554. {
  555. LOG_W("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_spi_arr[i].name);
  556. }
  557. }
  558. #endif
  559. }
  560. return 0;
  561. }
  562. INIT_DEVICE_EXPORT(rt_hw_spi_init);
  563. #endif //#if defined(BSP_USING_SPI)