spi.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include <libopencm3/stm32/gpio.h>
  2. #include <libopencm3/stm32/spi.h>
  3. #include <libopencm3/stm32/rcc.h>
  4. #include <libopencm3/stm32/dma.h>
  5. #include "spi.h"
  6. #include "usbcdc.h"
  7. #define likely(x) __builtin_expect((x), 1)
  8. #define unlikely(x) __builtin_expect((x), 0)
  9. /* DMA channel and requests has fixed mapping, do not change */
  10. #define SPI_DMA_RX_CH DMA_CHANNEL2
  11. #define SPI_DMA_TX_CH DMA_CHANNEL3
  12. static uint8_t dma_rxbuf[USBCDC_PKT_SIZE_DAT];
  13. void spi_disable_pins(void) {
  14. /* Configure GPIOs: SS = PA4, SCK = PA5, MISO = PA6, MOSI = PA7 */
  15. #ifdef STM32F0
  16. gpio_mode_setup(GPIO_BANK_SPI1, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_SPI1_SCK | GPIO_SPI1_MOSI | GPIO_SPI1_MISO | GPIO_SPI1_NSS);
  17. #else
  18. gpio_set_mode(GPIO_BANK_SPI1, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_SPI1_SCK | GPIO_SPI1_MOSI | GPIO_SPI1_MISO | GPIO_SPI1_NSS);
  19. #endif
  20. }
  21. void spi_enable_pins(void) {
  22. /* Configure GPIOs: SS = PA4, SCK = PA5, MISO = PA6, MOSI = PA7 */
  23. #ifdef STM32F0
  24. gpio_mode_setup(GPIO_BANK_SPI1, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_SPI1_SCK | GPIO_SPI1_MOSI);
  25. gpio_mode_setup(GPIO_BANK_SPI1, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_SPI1_MISO);
  26. gpio_mode_setup(GPIO_BANK_SPI1, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_SPI1_NSS); /* SS is manual */
  27. gpio_set_af(GPIO_BANK_SPI1, GPIO_AF0, GPIO_SPI1_SCK | GPIO_SPI1_MOSI | GPIO_SPI1_MISO);
  28. gpio_set_output_options(GPIO_BANK_SPI1, GPIO_OTYPE_PP, GPIO_OSPEED_HIGH, GPIO_SPI1_SCK | GPIO_SPI1_MOSI | GPIO_SPI1_NSS);
  29. #else
  30. gpio_set_mode(GPIO_BANK_SPI1, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_SPI1_SCK | GPIO_SPI1_MOSI);
  31. gpio_set_mode(GPIO_BANK_SPI1, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_SPI1_MISO);
  32. gpio_set_mode(GPIO_BANK_SPI1, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_SPI1_NSS); /* SS is manual */
  33. gpio_set(GPIO_BANK_SPI1, GPIO_SPI1_MISO);
  34. #endif
  35. gpio_set(GPIO_BANK_SPI1, GPIO_SPI1_NSS);
  36. }
  37. uint32_t spi_setup(uint32_t speed_hz) {
  38. uint32_t clkdiv;
  39. uint32_t relspd;
  40. rcc_periph_clock_enable(RCC_SPI1);
  41. #ifdef STM32F0
  42. rcc_periph_clock_enable(RCC_DMA);
  43. #else
  44. rcc_periph_clock_enable(RCC_DMA1);
  45. #endif /* STM32F0 */
  46. /* SPI1 is on APB2 which runs at 72MHz. Assume f = f_PCLK / 2 = 36MHz (whereas datasheet says 18MHz max but reference manual has no such word). */
  47. /* Lowest available */
  48. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_256;
  49. relspd = rcc_apb2_frequency / 256;
  50. if(speed_hz >= rcc_apb2_frequency / 128) {
  51. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_128;
  52. relspd = rcc_apb2_frequency / 128;
  53. }
  54. if(speed_hz >= rcc_apb2_frequency / 64) {
  55. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_64;
  56. relspd = rcc_apb2_frequency / 64;
  57. }
  58. if(speed_hz >= rcc_apb2_frequency / 32) {
  59. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_32;
  60. relspd = rcc_apb2_frequency / 32;
  61. }
  62. if(speed_hz >= rcc_apb2_frequency / 16) {
  63. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_16;
  64. relspd = rcc_apb2_frequency / 16;
  65. }
  66. if(speed_hz >= rcc_apb2_frequency / 8) {
  67. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_8;
  68. relspd = rcc_apb2_frequency / 8;
  69. }
  70. if(speed_hz >= rcc_apb2_frequency / 4) {
  71. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_4;
  72. relspd = rcc_apb2_frequency / 4;
  73. }
  74. if(speed_hz >= rcc_apb2_frequency / 2) {
  75. clkdiv = SPI_CR1_BAUDRATE_FPCLK_DIV_2;
  76. relspd = rcc_apb2_frequency / 2;
  77. }
  78. spi_enable_pins();
  79. /* Reset SPI, SPI_CR1 register cleared, SPI is disabled */
  80. spi_reset(SPI1);
  81. /* Set up SPI in Master mode with:
  82. * Clock baud rate: 1/256 of peripheral clock frequency
  83. * Clock polarity: Idle Low
  84. * Clock phase: Data valid on rising edge (1st edge for idle low)
  85. * Data frame format: 8-bit
  86. * Frame format: MSB First
  87. */
  88. #ifdef STM32F0
  89. spi_init_master(SPI1, clkdiv, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_MSBFIRST);
  90. spi_set_data_size(SPI1, SPI_CR2_DS_8BIT);
  91. spi_fifo_reception_threshold_8bit(SPI1);
  92. #else
  93. spi_init_master(SPI1, clkdiv, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);
  94. #endif /* STM32F0 */
  95. /*
  96. * Set NSS management to software.
  97. *
  98. * NOTE:
  99. * Setting nss high is very important, even if we are controlling the GPIO
  100. * ourselves this bit needs to be at least set to 1, otherwise the spi
  101. * peripheral will not send any data out.
  102. */
  103. spi_enable_software_slave_management(SPI1);
  104. spi_set_nss_high(SPI1);
  105. /* Misc. */
  106. spi_disable_crc(SPI1);
  107. spi_disable_error_interrupt(SPI1);
  108. spi_disable_rx_buffer_not_empty_interrupt(SPI1);
  109. spi_disable_tx_buffer_empty_interrupt(SPI1);
  110. spi_set_full_duplex_mode(SPI1);
  111. spi_set_unidirectional_mode(SPI1);
  112. /* Enable SPI1 periph. */
  113. spi_enable(SPI1);
  114. /* Report actual clock speed selected */
  115. return relspd;
  116. }
  117. static void spi_dma_write(uint16_t len, char *buf) {
  118. static uint8_t tmp = 0;
  119. /* Reset DMA channels */
  120. dma_channel_reset(DMA1, SPI_DMA_RX_CH);
  121. dma_channel_reset(DMA1, SPI_DMA_TX_CH);
  122. /* Configure TX */
  123. dma_set_peripheral_address(DMA1, SPI_DMA_TX_CH, (uint32_t)&SPI1_DR);
  124. dma_set_memory_address(DMA1, SPI_DMA_TX_CH, (uint32_t)buf);
  125. dma_set_number_of_data(DMA1, SPI_DMA_TX_CH, len);
  126. dma_set_read_from_memory(DMA1, SPI_DMA_TX_CH);
  127. dma_enable_memory_increment_mode(DMA1, SPI_DMA_TX_CH);
  128. dma_set_peripheral_size(DMA1, SPI_DMA_TX_CH, DMA_CCR_PSIZE_8BIT);
  129. dma_set_memory_size(DMA1, SPI_DMA_TX_CH, DMA_CCR_MSIZE_8BIT);
  130. dma_set_priority(DMA1, SPI_DMA_TX_CH, DMA_CCR_PL_HIGH);
  131. /* Configure RX (for collecting garbage from SPI controller) */
  132. dma_set_peripheral_address(DMA1, SPI_DMA_RX_CH, (uint32_t)&SPI1_DR);
  133. dma_set_memory_address(DMA1, SPI_DMA_RX_CH, (uint32_t)(&tmp));
  134. dma_set_number_of_data(DMA1, SPI_DMA_RX_CH, len);
  135. dma_set_read_from_peripheral(DMA1, SPI_DMA_RX_CH);
  136. dma_disable_memory_increment_mode(DMA1, SPI_DMA_RX_CH); /* Do not pollute cache */
  137. dma_set_peripheral_size(DMA1, SPI_DMA_RX_CH, DMA_CCR_PSIZE_8BIT);
  138. dma_set_memory_size(DMA1, SPI_DMA_RX_CH, DMA_CCR_MSIZE_8BIT);
  139. dma_set_priority(DMA1, SPI_DMA_RX_CH, DMA_CCR_PL_VERY_HIGH);
  140. dma_enable_channel(DMA1, SPI_DMA_RX_CH);
  141. dma_enable_channel(DMA1, SPI_DMA_TX_CH);
  142. spi_enable_rx_dma(SPI1);
  143. spi_enable_tx_dma(SPI1);
  144. }
  145. static void spi_dma_read(uint16_t len) {
  146. static uint8_t tmp = 0;
  147. /* Reset DMA channels */
  148. dma_channel_reset(DMA1, SPI_DMA_RX_CH);
  149. dma_channel_reset(DMA1, SPI_DMA_TX_CH);
  150. /* Configure RX */
  151. dma_set_peripheral_address(DMA1, SPI_DMA_RX_CH, (uint32_t)&SPI1_DR);
  152. dma_set_memory_address(DMA1, SPI_DMA_RX_CH, (uint32_t)dma_rxbuf);
  153. dma_set_number_of_data(DMA1, SPI_DMA_RX_CH, len);
  154. dma_set_read_from_peripheral(DMA1, SPI_DMA_RX_CH);
  155. dma_enable_memory_increment_mode(DMA1, SPI_DMA_RX_CH);
  156. dma_set_peripheral_size(DMA1, SPI_DMA_RX_CH, DMA_CCR_PSIZE_8BIT);
  157. dma_set_memory_size(DMA1, SPI_DMA_RX_CH, DMA_CCR_MSIZE_8BIT);
  158. dma_set_priority(DMA1, SPI_DMA_RX_CH, DMA_CCR_PL_VERY_HIGH);
  159. /* Configure TX (for SPI clock) */
  160. dma_set_peripheral_address(DMA1, SPI_DMA_TX_CH, (uint32_t)&SPI1_DR);
  161. dma_set_memory_address(DMA1, SPI_DMA_TX_CH, (uint32_t)(&tmp));
  162. dma_set_number_of_data(DMA1, SPI_DMA_TX_CH, len);
  163. dma_set_read_from_memory(DMA1, SPI_DMA_TX_CH);
  164. dma_disable_memory_increment_mode(DMA1, SPI_DMA_TX_CH); /* Do not pollute cache */
  165. dma_set_peripheral_size(DMA1, SPI_DMA_TX_CH, DMA_CCR_PSIZE_8BIT);
  166. dma_set_memory_size(DMA1, SPI_DMA_TX_CH, DMA_CCR_MSIZE_8BIT);
  167. dma_set_priority(DMA1, SPI_DMA_TX_CH, DMA_CCR_PL_HIGH);
  168. dma_enable_channel(DMA1, SPI_DMA_RX_CH);
  169. dma_enable_channel(DMA1, SPI_DMA_TX_CH);
  170. spi_enable_rx_dma(SPI1);
  171. spi_enable_tx_dma(SPI1);
  172. }
  173. #ifdef GD32F103
  174. /* Old CPU copying code */
  175. static void spi_copy_to_usb(uint32_t len) {
  176. while (len) {
  177. spi_send(SPI1, 0x00);
  178. usbcdc_putc(spi_read(SPI1));
  179. len --;
  180. }
  181. }
  182. static void spi_copy_from_usb(uint32_t len) {
  183. while (len) {
  184. spi_send(SPI1, usbcdc_getc());
  185. spi_read(SPI1);
  186. len --;
  187. }
  188. }
  189. /* FIXME: Currently SPI does not work on GD32 under any clock... */
  190. void spi_bulk_read(uint32_t rlen) {
  191. spi_copy_to_usb(rlen);
  192. }
  193. void spi_bulk_write(uint32_t slen) {
  194. spi_copy_from_usb(slen);
  195. }
  196. #else
  197. void spi_bulk_read(uint32_t rlen) {
  198. while (likely(rlen >= USBCDC_PKT_SIZE_DAT)) {
  199. spi_dma_read(USBCDC_PKT_SIZE_DAT);
  200. rlen -= USBCDC_PKT_SIZE_DAT;
  201. while (unlikely(!dma_get_interrupt_flag(DMA1, SPI_DMA_RX_CH, DMA_TCIF))); /* It is likely, but we want to exit loop with low latency. */
  202. dma_clear_interrupt_flags(DMA1, SPI_DMA_RX_CH, DMA_TCIF);
  203. spi_disable_rx_dma(SPI1);
  204. spi_disable_tx_dma(SPI1);
  205. dma_disable_channel(DMA1, SPI_DMA_RX_CH);
  206. dma_disable_channel(DMA1, SPI_DMA_TX_CH);
  207. usbcdc_write(dma_rxbuf, USBCDC_PKT_SIZE_DAT);
  208. }
  209. /* Leftover only happens when reading individual registers. */
  210. if (unlikely(rlen > 0)) {
  211. spi_dma_read(rlen);
  212. while(unlikely(!dma_get_interrupt_flag(DMA1, SPI_DMA_RX_CH, DMA_TCIF)));
  213. dma_clear_interrupt_flags(DMA1, SPI_DMA_RX_CH, DMA_TCIF);
  214. spi_disable_rx_dma(SPI1);
  215. spi_disable_tx_dma(SPI1);
  216. dma_disable_channel(DMA1, SPI_DMA_RX_CH);
  217. dma_disable_channel(DMA1, SPI_DMA_TX_CH);
  218. usbcdc_write(dma_rxbuf, rlen);
  219. }
  220. }
  221. void spi_bulk_write(uint32_t slen) {
  222. uint8_t urlen;
  223. char *urbuf;
  224. urlen = usbcdc_get_remainder(&urbuf);
  225. /* Due to the characteristics of flashrom and serprog protocol, slen >= urlen. */
  226. if (urlen > 0) {
  227. spi_dma_write(urlen, urbuf);
  228. slen -= urlen;
  229. /* Always check RX flag to avoid leftovers in SPI_DR, which messes data up. */
  230. while (unlikely(!dma_get_interrupt_flag(DMA1, SPI_DMA_RX_CH, DMA_TCIF))); /* It is likely, but we want to exit loop with low latency. */
  231. dma_clear_interrupt_flags(DMA1, SPI_DMA_RX_CH, DMA_TCIF);
  232. spi_disable_rx_dma(SPI1);
  233. spi_disable_tx_dma(SPI1);
  234. dma_disable_channel(DMA1, SPI_DMA_RX_CH);
  235. dma_disable_channel(DMA1, SPI_DMA_TX_CH);
  236. }
  237. /* We have no control over packet size here. */
  238. while (likely(slen > 0)) {
  239. urlen = usbcdc_fetch_packet();
  240. spi_dma_write(urlen, usbcdc_rxbuf);
  241. slen -= urlen;
  242. while (unlikely(!dma_get_interrupt_flag(DMA1, SPI_DMA_RX_CH, DMA_TCIF))); /* It is likely, but we want to exit loop with low latency. */
  243. dma_clear_interrupt_flags(DMA1, SPI_DMA_RX_CH, DMA_TCIF);
  244. spi_disable_rx_dma(SPI1);
  245. spi_disable_tx_dma(SPI1);
  246. dma_disable_channel(DMA1, SPI_DMA_RX_CH);
  247. dma_disable_channel(DMA1, SPI_DMA_TX_CH);
  248. }
  249. /* Mark USB RX buffer as used. */
  250. usbcdc_get_remainder(&urbuf);
  251. }
  252. #endif /* GD32F103 */