drv_spi.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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-11-11 Wayne 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_event(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_ssize_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. .rstidx = SPI0_RST,
  74. #if defined(BSP_USING_SPI_PDMA)
  75. #if defined(BSP_USING_SPI0_PDMA)
  76. .pdma_perp_tx = PDMA_SPI0_TX,
  77. .pdma_perp_rx = PDMA_SPI0_RX,
  78. #else
  79. .pdma_perp_tx = NU_PDMA_UNUSED,
  80. .pdma_perp_rx = NU_PDMA_UNUSED,
  81. #endif
  82. #endif
  83. },
  84. #endif
  85. #if defined(BSP_USING_SPI1)
  86. {
  87. .name = "spi1",
  88. .spi_base = SPI1,
  89. .rstidx = SPI1_RST,
  90. #if defined(BSP_USING_SPI_PDMA)
  91. #if defined(BSP_USING_SPI1_PDMA)
  92. .pdma_perp_tx = PDMA_SPI1_TX,
  93. .pdma_perp_rx = PDMA_SPI1_RX,
  94. #else
  95. .pdma_perp_tx = NU_PDMA_UNUSED,
  96. .pdma_perp_rx = NU_PDMA_UNUSED,
  97. #endif
  98. #endif
  99. },
  100. #endif
  101. #if defined(BSP_USING_SPI2)
  102. {
  103. .name = "spi2",
  104. .spi_base = SPI2,
  105. .rstidx = SPI2_RST,
  106. #if defined(BSP_USING_SPI_PDMA)
  107. #if defined(BSP_USING_SPI2_PDMA)
  108. .pdma_perp_tx = PDMA_SPI2_TX,
  109. .pdma_perp_rx = PDMA_SPI2_RX,
  110. #else
  111. .pdma_perp_tx = NU_PDMA_UNUSED,
  112. .pdma_perp_rx = NU_PDMA_UNUSED,
  113. #endif
  114. #endif
  115. },
  116. #endif
  117. #if defined(BSP_USING_SPI3)
  118. {
  119. .name = "spi3",
  120. .spi_base = SPI3,
  121. .rstidx = SPI3_RST,
  122. #if defined(BSP_USING_SPI_PDMA)
  123. #if defined(BSP_USING_SPI3_PDMA)
  124. .pdma_perp_tx = PDMA_SPI3_TX,
  125. .pdma_perp_rx = PDMA_SPI3_RX,
  126. #else
  127. .pdma_perp_tx = NU_PDMA_UNUSED,
  128. .pdma_perp_rx = NU_PDMA_UNUSED,
  129. #endif
  130. #endif
  131. },
  132. #endif
  133. }; /* spi nu_spi */
  134. static rt_err_t nu_spi_bus_configure(struct rt_spi_device *device,
  135. struct rt_spi_configuration *configuration)
  136. {
  137. struct nu_spi *spi_bus;
  138. uint32_t u32SPIMode;
  139. rt_err_t ret = RT_EOK;
  140. void *pvUserData;
  141. RT_ASSERT(device != RT_NULL);
  142. RT_ASSERT(configuration != RT_NULL);
  143. spi_bus = (struct nu_spi *) device->bus;
  144. pvUserData = device->parent.user_data;
  145. /* Check mode */
  146. switch (configuration->mode & RT_SPI_MODE_3)
  147. {
  148. case RT_SPI_MODE_0:
  149. u32SPIMode = SPI_MODE_0;
  150. break;
  151. case RT_SPI_MODE_1:
  152. u32SPIMode = SPI_MODE_1;
  153. break;
  154. case RT_SPI_MODE_2:
  155. u32SPIMode = SPI_MODE_2;
  156. break;
  157. case RT_SPI_MODE_3:
  158. u32SPIMode = SPI_MODE_3;
  159. break;
  160. default:
  161. ret = -RT_EIO;
  162. goto exit_nu_spi_bus_configure;
  163. }
  164. /* Check data width */
  165. if (!(configuration->data_width == 8 ||
  166. configuration->data_width == 16 ||
  167. configuration->data_width == 24 ||
  168. configuration->data_width == 32))
  169. {
  170. ret = -RT_EINVAL;
  171. goto exit_nu_spi_bus_configure;
  172. }
  173. /* Need to initialize new configuration? */
  174. if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(*configuration)) != 0)
  175. {
  176. rt_memcpy(&spi_bus->configuration, configuration, sizeof(*configuration));
  177. SPI_Open(spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, configuration->max_hz);
  178. if (configuration->mode & RT_SPI_CS_HIGH)
  179. {
  180. /* Set CS pin to LOW */
  181. if (pvUserData != RT_NULL)
  182. {
  183. // set to LOW */
  184. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  185. }
  186. else
  187. {
  188. SPI_SET_SS_LOW(spi_bus->spi_base);
  189. }
  190. }
  191. else
  192. {
  193. /* Set CS pin to HIGH */
  194. if (pvUserData != RT_NULL)
  195. {
  196. // set to HIGH */
  197. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  198. }
  199. else
  200. {
  201. /* Set CS pin to HIGH */
  202. SPI_SET_SS_HIGH(spi_bus->spi_base);
  203. }
  204. }
  205. if (configuration->mode & RT_SPI_MSB)
  206. {
  207. /* Set sequence to MSB first */
  208. SPI_SET_MSB_FIRST(spi_bus->spi_base);
  209. }
  210. else
  211. {
  212. /* Set sequence to LSB first */
  213. SPI_SET_LSB_FIRST(spi_bus->spi_base);
  214. }
  215. }
  216. /* Clear SPI RX FIFO */
  217. nu_spi_drain_rxfifo(spi_bus->spi_base);
  218. exit_nu_spi_bus_configure:
  219. return -(ret);
  220. }
  221. #if defined(BSP_USING_SPI_PDMA)
  222. static void nu_pdma_spi_rx_cb_event(void *pvUserData, uint32_t u32EventFilter)
  223. {
  224. rt_err_t result = RT_EOK;
  225. struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
  226. RT_ASSERT(spi_bus != RT_NULL);
  227. result = rt_sem_release(spi_bus->m_psSemBus);
  228. RT_ASSERT(result == RT_EOK);
  229. }
  230. static void nu_pdma_spi_tx_cb_trigger(void *pvUserData, uint32_t u32UserData)
  231. {
  232. /* Get base address of spi register */
  233. SPI_T *spi_base = (SPI_T *)pvUserData;
  234. /* Trigger TX/RX PDMA transfer. */
  235. SPI_TRIGGER_TX_RX_PDMA(spi_base);
  236. }
  237. static void nu_pdma_spi_rx_cb_disable(void *pvUserData, uint32_t u32UserData)
  238. {
  239. /* Get base address of spi register */
  240. SPI_T *spi_base = (SPI_T *)pvUserData;
  241. /* Stop TX/RX DMA transfer. */
  242. SPI_DISABLE_TX_RX_PDMA(spi_base);
  243. }
  244. 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)
  245. {
  246. struct nu_pdma_chn_cb sChnCB;
  247. rt_err_t result = RT_EOK;
  248. rt_uint8_t *dst_addr = NULL;
  249. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  250. /* Get base address of spi register */
  251. SPI_T *spi_base = spi_bus->spi_base;
  252. rt_uint8_t spi_pdma_rx_chid = spi_bus->pdma_chanid_rx;
  253. nu_pdma_filtering_set(spi_pdma_rx_chid, NU_PDMA_EVENT_TRANSFER_DONE);
  254. /* Register ISR callback function */
  255. sChnCB.m_eCBType = eCBType_Event;
  256. sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_event;
  257. sChnCB.m_pvUserData = (void *)spi_bus;
  258. result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
  259. if (result != RT_EOK)
  260. {
  261. goto exit_nu_pdma_spi_rx_config;
  262. }
  263. /* Register Disable engine dma trigger callback function */
  264. sChnCB.m_eCBType = eCBType_Disable;
  265. sChnCB.m_pfnCBHandler = nu_pdma_spi_rx_cb_disable;
  266. sChnCB.m_pvUserData = (void *)spi_base;
  267. result = nu_pdma_callback_register(spi_pdma_rx_chid, &sChnCB);
  268. if (result != RT_EOK)
  269. {
  270. goto exit_nu_pdma_spi_rx_config;
  271. }
  272. if (pu8Buf == RT_NULL)
  273. {
  274. memctrl = eMemCtl_SrcFix_DstFix;
  275. dst_addr = (rt_uint8_t *) &spi_bus->dummy;
  276. }
  277. else
  278. {
  279. memctrl = eMemCtl_SrcFix_DstInc;
  280. dst_addr = pu8Buf;
  281. }
  282. result = nu_pdma_channel_memctrl_set(spi_pdma_rx_chid, memctrl);
  283. if (result != RT_EOK)
  284. {
  285. goto exit_nu_pdma_spi_rx_config;
  286. }
  287. result = nu_pdma_transfer(spi_pdma_rx_chid,
  288. bytes_per_word * 8,
  289. (uint32_t)&spi_base->RX,
  290. (uint32_t)dst_addr,
  291. i32RcvLen / bytes_per_word,
  292. 0);
  293. exit_nu_pdma_spi_rx_config:
  294. return result;
  295. }
  296. 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)
  297. {
  298. struct nu_pdma_chn_cb sChnCB;
  299. rt_err_t result = RT_EOK;
  300. rt_uint8_t *src_addr = NULL;
  301. nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
  302. /* Get base address of spi register */
  303. SPI_T *spi_base = spi_bus->spi_base;
  304. rt_uint8_t spi_pdma_tx_chid = spi_bus->pdma_chanid_tx;
  305. if (pu8Buf == RT_NULL)
  306. {
  307. spi_bus->dummy = 0;
  308. memctrl = eMemCtl_SrcFix_DstFix;
  309. src_addr = (rt_uint8_t *)&spi_bus->dummy;
  310. }
  311. else
  312. {
  313. memctrl = eMemCtl_SrcInc_DstFix;
  314. src_addr = (rt_uint8_t *)pu8Buf;
  315. }
  316. /* Register Disable engine dma trigger callback function */
  317. sChnCB.m_eCBType = eCBType_Trigger;
  318. sChnCB.m_pfnCBHandler = nu_pdma_spi_tx_cb_trigger;
  319. sChnCB.m_pvUserData = (void *)spi_base;
  320. result = nu_pdma_callback_register(spi_pdma_tx_chid, &sChnCB);
  321. if (result != RT_EOK)
  322. {
  323. goto exit_nu_pdma_spi_tx_config;
  324. }
  325. result = nu_pdma_channel_memctrl_set(spi_pdma_tx_chid, memctrl);
  326. if (result != RT_EOK)
  327. {
  328. goto exit_nu_pdma_spi_tx_config;
  329. }
  330. result = nu_pdma_transfer(spi_pdma_tx_chid,
  331. bytes_per_word * 8,
  332. (uint32_t)src_addr,
  333. (uint32_t)&spi_base->TX,
  334. i32SndLen / bytes_per_word,
  335. 0);
  336. exit_nu_pdma_spi_tx_config:
  337. return result;
  338. }
  339. /**
  340. * SPI PDMA transfer
  341. */
  342. static rt_ssize_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)
  343. {
  344. rt_err_t result = RT_EOK;
  345. result = nu_pdma_spi_rx_config(spi_bus, recv_addr, length, bytes_per_word);
  346. RT_ASSERT(result == RT_EOK);
  347. result = nu_pdma_spi_tx_config(spi_bus, send_addr, length, bytes_per_word);
  348. RT_ASSERT(result == RT_EOK);
  349. /* Wait RX-PDMA transfer done */
  350. result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
  351. RT_ASSERT(result == RT_EOK);
  352. return length;
  353. }
  354. rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
  355. {
  356. /* Allocate SPI_TX nu_dma channel */
  357. if ((spi_bus->pdma_chanid_tx = nu_pdma_channel_allocate(spi_bus->pdma_perp_tx)) < 0)
  358. {
  359. goto exit_nu_hw_spi_pdma_allocate;
  360. }
  361. /* Allocate SPI_RX nu_dma channel */
  362. else if ((spi_bus->pdma_chanid_rx = nu_pdma_channel_allocate(spi_bus->pdma_perp_rx)) < 0)
  363. {
  364. nu_pdma_channel_free(spi_bus->pdma_chanid_tx);
  365. goto exit_nu_hw_spi_pdma_allocate;
  366. }
  367. spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
  368. RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
  369. return RT_EOK;
  370. exit_nu_hw_spi_pdma_allocate:
  371. return -(RT_ERROR);
  372. }
  373. #endif /* #if defined(BSP_USING_SPI_PDMA) */
  374. void nu_spi_drain_rxfifo(SPI_T *spi_base)
  375. {
  376. while (SPI_IS_BUSY(spi_base));
  377. // Drain SPI RX FIFO, make sure RX FIFO is empty
  378. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  379. {
  380. SPI_ClearRxFIFO(spi_base);
  381. }
  382. }
  383. static int nu_spi_read(SPI_T *spi_base, uint8_t *recv_addr, uint8_t bytes_per_word)
  384. {
  385. int size = 0;
  386. // Read RX data
  387. if (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  388. {
  389. uint32_t val;
  390. // Read data from SPI RX FIFO
  391. switch (bytes_per_word)
  392. {
  393. case 4:
  394. val = SPI_READ_RX(spi_base);
  395. nu_set32_le(recv_addr, val);
  396. break;
  397. case 3:
  398. val = SPI_READ_RX(spi_base);
  399. nu_set24_le(recv_addr, val);
  400. break;
  401. case 2:
  402. val = SPI_READ_RX(spi_base);
  403. nu_set16_le(recv_addr, val);
  404. break;
  405. case 1:
  406. *recv_addr = SPI_READ_RX(spi_base);
  407. break;
  408. default:
  409. LOG_E("Data length is not supported.\n");
  410. break;
  411. }
  412. size = bytes_per_word;
  413. }
  414. return size;
  415. }
  416. static int nu_spi_write(SPI_T *spi_base, const uint8_t *send_addr, uint8_t bytes_per_word)
  417. {
  418. // Wait SPI TX send data
  419. while (SPI_GET_TX_FIFO_FULL_FLAG(spi_base));
  420. // Input data to SPI TX
  421. switch (bytes_per_word)
  422. {
  423. case 4:
  424. SPI_WRITE_TX(spi_base, nu_get32_le(send_addr));
  425. break;
  426. case 3:
  427. SPI_WRITE_TX(spi_base, nu_get24_le(send_addr));
  428. break;
  429. case 2:
  430. SPI_WRITE_TX(spi_base, nu_get16_le(send_addr));
  431. break;
  432. case 1:
  433. SPI_WRITE_TX(spi_base, *((uint8_t *)send_addr));
  434. break;
  435. default:
  436. LOG_E("Data length is not supported.\n");
  437. break;
  438. }
  439. return bytes_per_word;
  440. }
  441. /**
  442. * @brief SPI bus polling
  443. * @param dev : The pointer of the specified SPI module.
  444. * @param send_addr : Source address
  445. * @param recv_addr : Destination address
  446. * @param length : Data length
  447. */
  448. static void nu_spi_transmission_with_poll(struct nu_spi *spi_bus,
  449. uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
  450. {
  451. SPI_T *spi_base = spi_bus->spi_base;
  452. // Write-only
  453. if ((send_addr != RT_NULL) && (recv_addr == RT_NULL))
  454. {
  455. while (length > 0)
  456. {
  457. send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
  458. length -= bytes_per_word;
  459. }
  460. } // if (send_addr != RT_NULL && recv_addr == RT_NULL)
  461. // Read-only
  462. else if ((send_addr == RT_NULL) && (recv_addr != RT_NULL))
  463. {
  464. spi_bus->dummy = 0;
  465. while (length > 0)
  466. {
  467. /* Input data to SPI TX FIFO */
  468. length -= nu_spi_write(spi_base, (const uint8_t *)&spi_bus->dummy, bytes_per_word);
  469. /* Read data from RX FIFO */
  470. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  471. }
  472. } // else if (send_addr == RT_NULL && recv_addr != RT_NULL)
  473. // Read&Write
  474. else
  475. {
  476. while (length > 0)
  477. {
  478. /* Input data to SPI TX FIFO */
  479. send_addr += nu_spi_write(spi_base, send_addr, bytes_per_word);
  480. length -= bytes_per_word;
  481. /* Read data from RX FIFO */
  482. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  483. }
  484. } // else
  485. /* Wait RX or drain RX-FIFO */
  486. if (recv_addr)
  487. {
  488. // Wait SPI transmission done
  489. while (SPI_IS_BUSY(spi_base))
  490. {
  491. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  492. {
  493. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  494. }
  495. }
  496. while (!SPI_GET_RX_FIFO_EMPTY_FLAG(spi_base))
  497. {
  498. recv_addr += nu_spi_read(spi_base, recv_addr, bytes_per_word);
  499. }
  500. }
  501. else
  502. {
  503. /* Clear SPI RX FIFO */
  504. nu_spi_drain_rxfifo(spi_base);
  505. }
  506. }
  507. void nu_spi_transfer(struct nu_spi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
  508. {
  509. RT_ASSERT(spi_bus != RT_NULL);
  510. #if defined(BSP_USING_SPI_PDMA)
  511. /* DMA transfer constrains */
  512. if ((spi_bus->pdma_chanid_rx >= 0) &&
  513. !((uint32_t)tx % bytes_per_word) &&
  514. !((uint32_t)rx % bytes_per_word) &&
  515. (bytes_per_word != 3) &&
  516. (length >= NU_SPI_USE_PDMA_MIN_THRESHOLD))
  517. nu_spi_pdma_transmit(spi_bus, tx, rx, length, bytes_per_word);
  518. else
  519. nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
  520. #else
  521. nu_spi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word);
  522. #endif
  523. }
  524. static rt_uint32_t nu_spi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  525. {
  526. struct nu_spi *spi_bus;
  527. struct rt_spi_configuration *configuration;
  528. uint8_t bytes_per_word;
  529. void *pvUserData;
  530. RT_ASSERT(device != RT_NULL);
  531. RT_ASSERT(device->bus != RT_NULL);
  532. RT_ASSERT(message != RT_NULL);
  533. spi_bus = (struct nu_spi *) device->bus;
  534. configuration = (struct rt_spi_configuration *)&spi_bus->configuration;
  535. bytes_per_word = configuration->data_width / 8;
  536. pvUserData = device->parent.user_data;
  537. if ((message->length % bytes_per_word) != 0)
  538. {
  539. /* Say bye. */
  540. LOG_E("%s: error payload length(%d%%%d != 0).\n", spi_bus->name, message->length, bytes_per_word);
  541. return 0;
  542. }
  543. if (message->length > 0)
  544. {
  545. if (message->cs_take && !(configuration->mode & RT_SPI_NO_CS))
  546. {
  547. if (pvUserData != RT_NULL)
  548. {
  549. if (configuration->mode & RT_SPI_CS_HIGH)
  550. {
  551. // set to HIGH */
  552. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  553. }
  554. else
  555. {
  556. // set to LOW */
  557. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  558. }
  559. }
  560. else
  561. {
  562. if (configuration->mode & RT_SPI_CS_HIGH)
  563. {
  564. SPI_SET_SS_HIGH(spi_bus->spi_base);
  565. }
  566. else
  567. {
  568. SPI_SET_SS_LOW(spi_bus->spi_base);
  569. }
  570. }
  571. }
  572. nu_spi_transfer(spi_bus, (uint8_t *)message->send_buf, (uint8_t *)message->recv_buf, message->length, bytes_per_word);
  573. if (message->cs_release && !(configuration->mode & RT_SPI_NO_CS))
  574. {
  575. if (pvUserData != RT_NULL)
  576. {
  577. if (configuration->mode & RT_SPI_CS_HIGH)
  578. {
  579. // set to LOW */
  580. rt_pin_write(*((rt_base_t *)pvUserData), PIN_LOW);
  581. }
  582. else
  583. {
  584. // set to HIGH */
  585. rt_pin_write(*((rt_base_t *)pvUserData), PIN_HIGH);
  586. }
  587. }
  588. else
  589. {
  590. if (configuration->mode & RT_SPI_CS_HIGH)
  591. {
  592. SPI_SET_SS_LOW(spi_bus->spi_base);
  593. }
  594. else
  595. {
  596. SPI_SET_SS_HIGH(spi_bus->spi_base);
  597. }
  598. }
  599. }
  600. }
  601. return message->length;
  602. }
  603. static int nu_spi_register_bus(struct nu_spi *spi_bus, const char *name)
  604. {
  605. return rt_spi_bus_register(&spi_bus->dev, name, &nu_spi_poll_ops);
  606. }
  607. /**
  608. * Hardware SPI Initial
  609. */
  610. static int rt_hw_spi_init(void)
  611. {
  612. int i;
  613. for (i = (SPI_START + 1); i < SPI_CNT; i++)
  614. {
  615. nu_sys_ip_reset(nu_spi_arr[i].rstidx);
  616. nu_spi_register_bus(&nu_spi_arr[i], nu_spi_arr[i].name);
  617. #if defined(BSP_USING_SPI_PDMA)
  618. nu_spi_arr[i].pdma_chanid_tx = -1;
  619. nu_spi_arr[i].pdma_chanid_rx = -1;
  620. if ((nu_spi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_spi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
  621. {
  622. if (nu_hw_spi_pdma_allocate(&nu_spi_arr[i]) != RT_EOK)
  623. {
  624. LOG_W("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_spi_arr[i].name);
  625. }
  626. }
  627. #endif
  628. }
  629. return 0;
  630. }
  631. INIT_DEVICE_EXPORT(rt_hw_spi_init);
  632. #endif //#if defined(BSP_USING_SPI)