spi_hal_iram.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2015-2019 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. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // The HAL layer for SPI (common part, in iram)
  15. // make these functions in a seperate file to make sure all LL functions are in the IRAM.
  16. #include "hal/spi_hal.h"
  17. #include "hal/assert.h"
  18. #include "soc/soc_caps.h"
  19. //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
  20. #if SOC_GDMA_SUPPORTED
  21. #include "soc/gdma_struct.h"
  22. #include "hal/gdma_ll.h"
  23. #define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan)
  24. #define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan);
  25. #define spi_dma_ll_rx_start(dev, chan, addr) do {\
  26. gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
  27. gdma_ll_rx_start(&GDMA, chan);\
  28. } while (0)
  29. #define spi_dma_ll_tx_start(dev, chan, addr) do {\
  30. gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
  31. gdma_ll_tx_start(&GDMA, chan);\
  32. } while (0)
  33. #endif
  34. void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev)
  35. {
  36. //Configure clock settings
  37. spi_dev_t *hw = hal->hw;
  38. #if SOC_SPI_SUPPORT_AS_CS
  39. spi_ll_master_set_cksel(hw, dev->cs_pin_id, dev->as_cs);
  40. #endif
  41. spi_ll_master_set_pos_cs(hw, dev->cs_pin_id, dev->positive_cs);
  42. spi_ll_master_set_clock_by_reg(hw, &dev->timing_conf.clock_reg);
  43. //Configure bit order
  44. spi_ll_set_rx_lsbfirst(hw, dev->rx_lsbfirst);
  45. spi_ll_set_tx_lsbfirst(hw, dev->tx_lsbfirst);
  46. spi_ll_master_set_mode(hw, dev->mode);
  47. //Configure misc stuff
  48. spi_ll_set_half_duplex(hw, dev->half_duplex);
  49. spi_ll_set_sio_mode(hw, dev->sio);
  50. //Configure CS pin and timing
  51. spi_ll_master_set_cs_setup(hw, dev->cs_setup);
  52. spi_ll_master_set_cs_hold(hw, dev->cs_hold);
  53. spi_ll_master_select_cs(hw, dev->cs_pin_id);
  54. }
  55. void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
  56. {
  57. spi_dev_t *hw = hal->hw;
  58. //clear int bit
  59. spi_ll_clear_int_stat(hal->hw);
  60. //We should be done with the transmission.
  61. HAL_ASSERT(spi_ll_get_running_cmd(hw) == 0);
  62. //set transaction line mode
  63. spi_ll_master_set_line_mode(hw, trans->line_mode);
  64. int extra_dummy = 0;
  65. //when no_dummy is not set and in half-duplex mode, sets the dummy bit if RX phase exist
  66. if (trans->rcv_buffer && !dev->no_compensate && dev->half_duplex) {
  67. extra_dummy = dev->timing_conf.timing_dummy;
  68. }
  69. //SPI iface needs to be configured for a delay in some cases.
  70. //configure dummy bits
  71. spi_ll_set_dummy(hw, extra_dummy + trans->dummy_bits);
  72. uint32_t miso_delay_num = 0;
  73. uint32_t miso_delay_mode = 0;
  74. if (dev->timing_conf.timing_miso_delay < 0) {
  75. //if the data comes too late, delay half a SPI clock to improve reading
  76. switch (dev->mode) {
  77. case 0:
  78. miso_delay_mode = 2;
  79. break;
  80. case 1:
  81. miso_delay_mode = 1;
  82. break;
  83. case 2:
  84. miso_delay_mode = 1;
  85. break;
  86. case 3:
  87. miso_delay_mode = 2;
  88. break;
  89. }
  90. miso_delay_num = 0;
  91. } else {
  92. //if the data is so fast that dummy_bit is used, delay some apb clocks to meet the timing
  93. miso_delay_num = extra_dummy ? dev->timing_conf.timing_miso_delay : 0;
  94. miso_delay_mode = 0;
  95. }
  96. spi_ll_set_miso_delay(hw, miso_delay_mode, miso_delay_num);
  97. spi_ll_set_mosi_bitlen(hw, trans->tx_bitlen);
  98. if (dev->half_duplex) {
  99. spi_ll_set_miso_bitlen(hw, trans->rx_bitlen);
  100. } else {
  101. //rxlength is not used in full-duplex mode
  102. spi_ll_set_miso_bitlen(hw, trans->tx_bitlen);
  103. }
  104. //Configure bit sizes, load addr and command
  105. int cmdlen = trans->cmd_bits;
  106. int addrlen = trans->addr_bits;
  107. if (!dev->half_duplex && dev->cs_setup != 0) {
  108. /* The command and address phase is not compatible with cs_ena_pretrans
  109. * in full duplex mode.
  110. */
  111. cmdlen = 0;
  112. addrlen = 0;
  113. }
  114. spi_ll_set_addr_bitlen(hw, addrlen);
  115. spi_ll_set_command_bitlen(hw, cmdlen);
  116. spi_ll_set_command(hw, trans->cmd, cmdlen, dev->tx_lsbfirst);
  117. spi_ll_set_address(hw, trans->addr, addrlen, dev->tx_lsbfirst);
  118. //Configure keep active CS
  119. spi_ll_master_keep_cs(hw, trans->cs_keep_active);
  120. //Save the transaction attributes for internal usage.
  121. memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
  122. }
  123. void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
  124. {
  125. spi_dev_t *hw = hal->hw;
  126. //Fill DMA descriptors
  127. if (trans->rcv_buffer) {
  128. if (!hal->dma_enabled) {
  129. //No need to setup anything; we'll copy the result out of the work registers directly later.
  130. } else {
  131. lldesc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
  132. spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
  133. spi_ll_dma_rx_fifo_reset(hal->hw);
  134. spi_ll_infifo_full_clr(hal->hw);
  135. spi_ll_dma_rx_enable(hal->hw, 1);
  136. spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, hal->dmadesc_rx);
  137. }
  138. }
  139. #if CONFIG_IDF_TARGET_ESP32
  140. else {
  141. //DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
  142. if (hal->dma_enabled && !dev->half_duplex) {
  143. spi_ll_dma_rx_enable(hal->hw, 1);
  144. spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, 0);
  145. }
  146. }
  147. #endif
  148. if (trans->send_buffer) {
  149. if (!hal->dma_enabled) {
  150. //Need to copy data to registers manually
  151. spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen);
  152. } else {
  153. lldesc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
  154. spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
  155. spi_ll_dma_tx_fifo_reset(hal->hw);
  156. spi_ll_outfifo_empty_clr(hal->hw);
  157. spi_ll_dma_tx_enable(hal->hw, 1);
  158. spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, hal->dmadesc_tx);
  159. }
  160. }
  161. //in ESP32 these registers should be configured after the DMA is set
  162. if ((!dev->half_duplex && trans->rcv_buffer) || trans->send_buffer) {
  163. spi_ll_enable_mosi(hw, 1);
  164. } else {
  165. spi_ll_enable_mosi(hw, 0);
  166. }
  167. spi_ll_enable_miso(hw, (trans->rcv_buffer) ? 1 : 0);
  168. }
  169. void spi_hal_user_start(const spi_hal_context_t *hal)
  170. {
  171. spi_ll_master_user_start(hal->hw);
  172. }
  173. bool spi_hal_usr_is_done(const spi_hal_context_t *hal)
  174. {
  175. return spi_ll_usr_is_done(hal->hw);
  176. }
  177. void spi_hal_fetch_result(const spi_hal_context_t *hal)
  178. {
  179. const spi_hal_trans_config_t *trans = &hal->trans_config;
  180. if (trans->rcv_buffer && !hal->dma_enabled) {
  181. //Need to copy from SPI regs to result buffer.
  182. spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen);
  183. }
  184. }