spi_slave.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <string.h>
  14. #include "driver/spi_common.h"
  15. #include "driver/spi_slave.h"
  16. #include "soc/dport_reg.h"
  17. #include "soc/spi_periph.h"
  18. #include "rom/ets_sys.h"
  19. #include "esp_types.h"
  20. #include "esp_attr.h"
  21. #include "esp_intr.h"
  22. #include "esp_intr_alloc.h"
  23. #include "esp_log.h"
  24. #include "esp_err.h"
  25. #include "esp_pm.h"
  26. #include "freertos/FreeRTOS.h"
  27. #include "freertos/semphr.h"
  28. #include "freertos/xtensa_api.h"
  29. #include "freertos/task.h"
  30. #include "soc/soc.h"
  31. #include "soc/soc_memory_layout.h"
  32. #include "soc/dport_reg.h"
  33. #include "rom/lldesc.h"
  34. #include "driver/gpio.h"
  35. #include "driver/periph_ctrl.h"
  36. #include "esp_heap_caps.h"
  37. static const char *SPI_TAG = "spi_slave";
  38. #define SPI_CHECK(a, str, ret_val) \
  39. if (!(a)) { \
  40. ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
  41. return (ret_val); \
  42. }
  43. #define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
  44. #ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
  45. #define SPI_SLAVE_ISR_ATTR IRAM_ATTR
  46. #else
  47. #define SPI_SLAVE_ISR_ATTR
  48. #endif
  49. #ifdef CONFIG_SPI_SLAVE_IN_IRAM
  50. #define SPI_SLAVE_ATTR IRAM_ATTR
  51. #else
  52. #define SPI_SLAVE_ATTR
  53. #endif
  54. typedef struct {
  55. int id;
  56. spi_slave_interface_config_t cfg;
  57. intr_handle_t intr;
  58. spi_dev_t *hw;
  59. spi_slave_transaction_t *cur_trans;
  60. lldesc_t *dmadesc_tx;
  61. lldesc_t *dmadesc_rx;
  62. uint32_t flags;
  63. int max_transfer_sz;
  64. QueueHandle_t trans_queue;
  65. QueueHandle_t ret_queue;
  66. int dma_chan;
  67. #ifdef CONFIG_PM_ENABLE
  68. esp_pm_lock_handle_t pm_lock;
  69. #endif
  70. } spi_slave_t;
  71. static spi_slave_t *spihost[3];
  72. static void IRAM_ATTR spi_intr(void *arg);
  73. static inline bool bus_is_iomux(spi_slave_t *host)
  74. {
  75. return host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS;
  76. }
  77. static void freeze_cs(spi_slave_t *host)
  78. {
  79. gpio_matrix_in(GPIO_FUNC_IN_HIGH, spi_periph_signal[host->id].spics_in, false);
  80. }
  81. // Use this function instead of cs_initial to avoid overwrite the output config
  82. // This is used in test by internal gpio matrix connections
  83. static inline void restore_cs(spi_slave_t *host)
  84. {
  85. if (bus_is_iomux(host)) {
  86. gpio_iomux_in(host->cfg.spics_io_num, spi_periph_signal[host->id].spics_in);
  87. } else {
  88. gpio_matrix_in(host->cfg.spics_io_num, spi_periph_signal[host->id].spics_in, false);
  89. }
  90. }
  91. esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan)
  92. {
  93. bool spi_chan_claimed, dma_chan_claimed;
  94. esp_err_t ret = ESP_OK;
  95. esp_err_t err;
  96. //We only support HSPI/VSPI, period.
  97. SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
  98. SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
  99. SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
  100. #ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
  101. SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
  102. #endif
  103. spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
  104. SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
  105. if ( dma_chan != 0 ) {
  106. dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
  107. if ( !dma_chan_claimed ) {
  108. spicommon_periph_free( host );
  109. SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
  110. }
  111. }
  112. spihost[host] = malloc(sizeof(spi_slave_t));
  113. if (spihost[host] == NULL) {
  114. ret = ESP_ERR_NO_MEM;
  115. goto cleanup;
  116. }
  117. memset(spihost[host], 0, sizeof(spi_slave_t));
  118. memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
  119. spihost[host]->id = host;
  120. err = spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags);
  121. if (err!=ESP_OK) {
  122. ret = err;
  123. goto cleanup;
  124. }
  125. spicommon_cs_initialize(host, slave_config->spics_io_num, 0, !bus_is_iomux(spihost[host]));
  126. // The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
  127. if (dma_chan != 0) freeze_cs(spihost[host]);
  128. spihost[host]->dma_chan = dma_chan;
  129. if (dma_chan != 0) {
  130. //See how many dma descriptors we need and allocate them
  131. int dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN;
  132. if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
  133. spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
  134. spihost[host]->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
  135. spihost[host]->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
  136. if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) {
  137. ret = ESP_ERR_NO_MEM;
  138. goto cleanup;
  139. }
  140. } else {
  141. //We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
  142. spihost[host]->max_transfer_sz = 16 * 4;
  143. }
  144. #ifdef CONFIG_PM_ENABLE
  145. err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
  146. &spihost[host]->pm_lock);
  147. if (err != ESP_OK) {
  148. ret = err;
  149. goto cleanup;
  150. }
  151. // Lock APB frequency while SPI slave driver is in use
  152. esp_pm_lock_acquire(spihost[host]->pm_lock);
  153. #endif //CONFIG_PM_ENABLE
  154. //Create queues
  155. spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
  156. spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
  157. if (!spihost[host]->trans_queue || !spihost[host]->ret_queue) {
  158. ret = ESP_ERR_NO_MEM;
  159. goto cleanup;
  160. }
  161. int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
  162. err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
  163. if (err != ESP_OK) {
  164. ret = err;
  165. goto cleanup;
  166. }
  167. spihost[host]->hw = spicommon_hw_for_host(host);
  168. //Configure slave
  169. spihost[host]->hw->clock.val = 0;
  170. spihost[host]->hw->user.val = 0;
  171. spihost[host]->hw->ctrl.val = 0;
  172. spihost[host]->hw->slave.wr_rd_buf_en = 1; //no sure if needed
  173. spihost[host]->hw->user.doutdin = 1; //we only support full duplex
  174. spihost[host]->hw->user.sio = 0;
  175. spihost[host]->hw->slave.slave_mode = 1;
  176. spihost[host]->hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST;
  177. spihost[host]->hw->dma_out_link.start = 0;
  178. spihost[host]->hw->dma_in_link.start = 0;
  179. spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
  180. spihost[host]->hw->dma_conf.out_data_burst_en = 1;
  181. spihost[host]->hw->slave.sync_reset = 1;
  182. spihost[host]->hw->slave.sync_reset = 0;
  183. spihost[host]->hw->ctrl.rd_bit_order = (slave_config->flags & SPI_SLAVE_RXBIT_LSBFIRST) ? 1 : 0;
  184. spihost[host]->hw->ctrl.wr_bit_order = (slave_config->flags & SPI_SLAVE_TXBIT_LSBFIRST) ? 1 : 0;
  185. const int mode = slave_config->mode;
  186. if (mode == 0) {
  187. //The timing needs to be fixed to meet the requirements of DMA
  188. spihost[host]->hw->pin.ck_idle_edge = 1;
  189. spihost[host]->hw->user.ck_i_edge = 0;
  190. spihost[host]->hw->ctrl2.miso_delay_mode = 0;
  191. spihost[host]->hw->ctrl2.miso_delay_num = 0;
  192. spihost[host]->hw->ctrl2.mosi_delay_mode = 2;
  193. spihost[host]->hw->ctrl2.mosi_delay_num = 2;
  194. } else if (mode == 1) {
  195. spihost[host]->hw->pin.ck_idle_edge = 1;
  196. spihost[host]->hw->user.ck_i_edge = 1;
  197. spihost[host]->hw->ctrl2.miso_delay_mode = 2;
  198. spihost[host]->hw->ctrl2.miso_delay_num = 0;
  199. spihost[host]->hw->ctrl2.mosi_delay_mode = 0;
  200. spihost[host]->hw->ctrl2.mosi_delay_num = 0;
  201. } else if (mode == 2) {
  202. //The timing needs to be fixed to meet the requirements of DMA
  203. spihost[host]->hw->pin.ck_idle_edge = 0;
  204. spihost[host]->hw->user.ck_i_edge = 1;
  205. spihost[host]->hw->ctrl2.miso_delay_mode = 0;
  206. spihost[host]->hw->ctrl2.miso_delay_num = 0;
  207. spihost[host]->hw->ctrl2.mosi_delay_mode = 1;
  208. spihost[host]->hw->ctrl2.mosi_delay_num = 2;
  209. } else if (mode == 3) {
  210. spihost[host]->hw->pin.ck_idle_edge = 0;
  211. spihost[host]->hw->user.ck_i_edge = 0;
  212. spihost[host]->hw->ctrl2.miso_delay_mode = 1;
  213. spihost[host]->hw->ctrl2.miso_delay_num = 0;
  214. spihost[host]->hw->ctrl2.mosi_delay_mode = 0;
  215. spihost[host]->hw->ctrl2.mosi_delay_num = 0;
  216. }
  217. /* Silicon issues exists in mode 0 and 2 with DMA, change clock phase to
  218. * avoid dma issue. This will cause slave output to appear at most half a
  219. * spi clock before
  220. */
  221. if (dma_chan != 0) {
  222. if (mode == 0) {
  223. spihost[host]->hw->pin.ck_idle_edge = 0;
  224. spihost[host]->hw->user.ck_i_edge = 1;
  225. spihost[host]->hw->ctrl2.miso_delay_mode = 0;
  226. spihost[host]->hw->ctrl2.miso_delay_num = 2;
  227. spihost[host]->hw->ctrl2.mosi_delay_mode = 0;
  228. spihost[host]->hw->ctrl2.mosi_delay_num = 3;
  229. } else if (mode == 2) {
  230. spihost[host]->hw->pin.ck_idle_edge = 1;
  231. spihost[host]->hw->user.ck_i_edge = 0;
  232. spihost[host]->hw->ctrl2.miso_delay_mode = 0;
  233. spihost[host]->hw->ctrl2.miso_delay_num = 2;
  234. spihost[host]->hw->ctrl2.mosi_delay_mode = 0;
  235. spihost[host]->hw->ctrl2.mosi_delay_num = 3;
  236. }
  237. }
  238. //Reset DMA
  239. spihost[host]->hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST;
  240. spihost[host]->hw->dma_out_link.start = 0;
  241. spihost[host]->hw->dma_in_link.start = 0;
  242. spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
  243. //Disable unneeded ints
  244. spihost[host]->hw->slave.rd_buf_done = 0;
  245. spihost[host]->hw->slave.wr_buf_done = 0;
  246. spihost[host]->hw->slave.rd_sta_done = 0;
  247. spihost[host]->hw->slave.wr_sta_done = 0;
  248. spihost[host]->hw->slave.rd_buf_inten = 0;
  249. spihost[host]->hw->slave.wr_buf_inten = 0;
  250. spihost[host]->hw->slave.rd_sta_inten = 0;
  251. spihost[host]->hw->slave.wr_sta_inten = 0;
  252. //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
  253. //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
  254. //any transactions that are queued.
  255. spihost[host]->hw->slave.trans_inten = 1;
  256. spihost[host]->hw->slave.trans_done = 1;
  257. return ESP_OK;
  258. cleanup:
  259. if (spihost[host]) {
  260. if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
  261. if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
  262. free(spihost[host]->dmadesc_tx);
  263. free(spihost[host]->dmadesc_rx);
  264. #ifdef CONFIG_PM_ENABLE
  265. if (spihost[host]->pm_lock) {
  266. esp_pm_lock_release(spihost[host]->pm_lock);
  267. esp_pm_lock_delete(spihost[host]->pm_lock);
  268. }
  269. #endif
  270. }
  271. free(spihost[host]);
  272. spihost[host] = NULL;
  273. spicommon_periph_free(host);
  274. spicommon_dma_chan_free(dma_chan);
  275. return ret;
  276. }
  277. esp_err_t spi_slave_free(spi_host_device_t host)
  278. {
  279. SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
  280. SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
  281. if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
  282. if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
  283. if ( spihost[host]->dma_chan > 0 ) {
  284. spicommon_dma_chan_free ( spihost[host]->dma_chan );
  285. }
  286. free(spihost[host]->dmadesc_tx);
  287. free(spihost[host]->dmadesc_rx);
  288. esp_intr_free(spihost[host]->intr);
  289. #ifdef CONFIG_PM_ENABLE
  290. esp_pm_lock_release(spihost[host]->pm_lock);
  291. esp_pm_lock_delete(spihost[host]->pm_lock);
  292. #endif //CONFIG_PM_ENABLE
  293. free(spihost[host]);
  294. spihost[host] = NULL;
  295. spicommon_periph_free(host);
  296. return ESP_OK;
  297. }
  298. esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
  299. {
  300. BaseType_t r;
  301. SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
  302. SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
  303. SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
  304. "txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
  305. SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL ||
  306. (esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
  307. (trans_desc->length%4==0)),
  308. "rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
  309. SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
  310. r = xQueueSend(spihost[host]->trans_queue, (void *)&trans_desc, ticks_to_wait);
  311. if (!r) return ESP_ERR_TIMEOUT;
  312. esp_intr_enable(spihost[host]->intr);
  313. return ESP_OK;
  314. }
  315. esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait)
  316. {
  317. BaseType_t r;
  318. SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
  319. SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
  320. r = xQueueReceive(spihost[host]->ret_queue, (void *)trans_desc, ticks_to_wait);
  321. if (!r) return ESP_ERR_TIMEOUT;
  322. return ESP_OK;
  323. }
  324. esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
  325. {
  326. esp_err_t ret;
  327. spi_slave_transaction_t *ret_trans;
  328. //ToDo: check if any spi transfers in flight
  329. ret = spi_slave_queue_trans(host, trans_desc, ticks_to_wait);
  330. if (ret != ESP_OK) return ret;
  331. ret = spi_slave_get_trans_result(host, &ret_trans, ticks_to_wait);
  332. if (ret != ESP_OK) return ret;
  333. assert(ret_trans == trans_desc);
  334. return ESP_OK;
  335. }
  336. #ifdef DEBUG_SLAVE
  337. static void dumpregs(spi_dev_t *hw)
  338. {
  339. ets_printf("***REG DUMP ***\n");
  340. ets_printf("mosi_dlen : %08X\n", hw->mosi_dlen.val);
  341. ets_printf("miso_dlen : %08X\n", hw->miso_dlen.val);
  342. ets_printf("slv_wrbuf_dlen : %08X\n", hw->slv_wrbuf_dlen.val);
  343. ets_printf("slv_rdbuf_dlen : %08X\n", hw->slv_rdbuf_dlen.val);
  344. ets_printf("slave : %08X\n", hw->slave.val);
  345. ets_printf("slv_rdata_bit : %x\n", hw->slv_rd_bit.slv_rdata_bit);
  346. ets_printf("dma_rx_status : %08X\n", hw->dma_rx_status);
  347. ets_printf("dma_tx_status : %08X\n", hw->dma_tx_status);
  348. }
  349. static void dumpll(lldesc_t *ll)
  350. {
  351. ets_printf("****LL DUMP****\n");
  352. ets_printf("Size %d\n", ll->size);
  353. ets_printf("Len: %d\n", ll->length);
  354. ets_printf("Owner: %s\n", ll->owner ? "dma" : "cpu");
  355. }
  356. #endif
  357. static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg)
  358. {
  359. spi_slave_t *host = (spi_slave_t *)arg;
  360. esp_intr_enable(host->intr);
  361. }
  362. //This is run in interrupt context and apart from initialization and destruction, this is the only code
  363. //touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
  364. //no muxes in this code.
  365. static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
  366. {
  367. BaseType_t r;
  368. BaseType_t do_yield = pdFALSE;
  369. spi_slave_transaction_t *trans = NULL;
  370. spi_slave_t *host = (spi_slave_t *)arg;
  371. #ifdef DEBUG_SLAVE
  372. dumpregs(host->hw);
  373. if (host->dmadesc_rx) dumpll(&host->dmadesc_rx[0]);
  374. #endif
  375. //Ignore all but the trans_done int.
  376. if (!host->hw->slave.trans_done) return;
  377. if (host->cur_trans) {
  378. // When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
  379. if (host->dma_chan != 0) freeze_cs(host);
  380. //when data of cur_trans->length are all sent, the slv_rdata_bit
  381. //will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
  382. //the length sent.
  383. host->cur_trans->trans_len = host->hw->slv_rd_bit.slv_rdata_bit;
  384. if (host->cur_trans->trans_len == host->cur_trans->length - 1) {
  385. host->cur_trans->trans_len++;
  386. }
  387. if (host->dma_chan == 0 && host->cur_trans->rx_buffer) {
  388. //Copy result out
  389. uint32_t *data = host->cur_trans->rx_buffer;
  390. for (int x = 0; x < host->cur_trans->trans_len; x += 32) {
  391. uint32_t word;
  392. int len = host->cur_trans->trans_len - x;
  393. if (len > 32) len = 32;
  394. word = host->hw->data_buf[(x / 32)];
  395. memcpy(&data[x / 32], &word, (len + 7) / 8);
  396. }
  397. } else if (host->dma_chan != 0 && host->cur_trans->rx_buffer) {
  398. int i;
  399. //In case CS goes high too soon, the transfer is aborted while the DMA channel still thinks it's going. This
  400. //leads to issues later on, so in that case we need to reset the channel. The state can be detected because
  401. //the DMA system doesn't give back the offending descriptor; the owner is still set to DMA.
  402. for (i = 0; host->dmadesc_rx[i].eof == 0 && host->dmadesc_rx[i].owner == 0; i++) ;
  403. if (host->dmadesc_rx[i].owner) {
  404. spicommon_dmaworkaround_req_reset(host->dma_chan, spi_slave_restart_after_dmareset, host);
  405. }
  406. }
  407. if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
  408. //Okay, transaction is done.
  409. //Return transaction descriptor.
  410. xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
  411. host->cur_trans = NULL;
  412. }
  413. if (host->dma_chan != 0) {
  414. spicommon_dmaworkaround_idle(host->dma_chan);
  415. if (spicommon_dmaworkaround_reset_in_progress()) {
  416. //We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
  417. esp_intr_disable(host->intr);
  418. if (do_yield) portYIELD_FROM_ISR();
  419. return;
  420. }
  421. }
  422. //Disable interrupt before checking to avoid concurrency issue.
  423. esp_intr_disable(host->intr);
  424. //Grab next transaction
  425. r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield);
  426. if (r) {
  427. //enable the interrupt again if there is packet to send
  428. esp_intr_enable(host->intr);
  429. //We have a transaction. Send it.
  430. host->hw->slave.trans_done = 0; //clear int bit
  431. host->cur_trans = trans;
  432. if (host->dma_chan != 0) {
  433. spicommon_dmaworkaround_transfer_active(host->dma_chan);
  434. host->hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST;
  435. host->hw->dma_out_link.start = 0;
  436. host->hw->dma_in_link.start = 0;
  437. host->hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
  438. host->hw->dma_conf.out_data_burst_en = 0;
  439. host->hw->dma_conf.indscr_burst_en = 0;
  440. host->hw->dma_conf.outdscr_burst_en = 0;
  441. //Fill DMA descriptors
  442. if (trans->rx_buffer) {
  443. host->hw->user.usr_miso_highpart = 0;
  444. spicommon_setup_dma_desc_links(host->dmadesc_rx, ((trans->length + 7) / 8), trans->rx_buffer, true);
  445. host->hw->dma_in_link.addr = (int)(&host->dmadesc_rx[0]) & 0xFFFFF;
  446. host->hw->dma_in_link.start = 1;
  447. }
  448. if (trans->tx_buffer) {
  449. spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length + 7) / 8, trans->tx_buffer, false);
  450. host->hw->user.usr_mosi_highpart = 0;
  451. host->hw->dma_out_link.addr = (int)(&host->dmadesc_tx[0]) & 0xFFFFF;
  452. host->hw->dma_out_link.start = 1;
  453. }
  454. host->hw->slave.sync_reset = 1;
  455. host->hw->slave.sync_reset = 0;
  456. } else {
  457. //No DMA. Turn off SPI and copy data to transmit buffers.
  458. host->hw->cmd.usr = 0;
  459. host->hw->slave.sync_reset = 1;
  460. host->hw->slave.sync_reset = 0;
  461. host->hw->user.usr_miso_highpart = 0;
  462. host->hw->user.usr_mosi_highpart = 0;
  463. if (trans->tx_buffer) {
  464. const uint32_t *data = host->cur_trans->tx_buffer;
  465. for (int x = 0; x < trans->length; x += 32) {
  466. uint32_t word;
  467. memcpy(&word, &data[x / 32], 4);
  468. host->hw->data_buf[(x / 32)] = word;
  469. }
  470. }
  471. }
  472. host->hw->slv_rd_bit.slv_rdata_bit = 0;
  473. host->hw->slv_wrbuf_dlen.bit_len = trans->length - 1;
  474. host->hw->slv_rdbuf_dlen.bit_len = trans->length - 1;
  475. host->hw->mosi_dlen.usr_mosi_dbitlen = trans->length - 1;
  476. host->hw->miso_dlen.usr_miso_dbitlen = trans->length - 1;
  477. host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
  478. host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;
  479. //The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready.
  480. if (host->dma_chan != 0) restore_cs(host);
  481. //Kick off transfer
  482. host->hw->cmd.usr = 1;
  483. if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
  484. }
  485. if (do_yield) portYIELD_FROM_ISR();
  486. }