qspi.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2018 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <string.h>
  27. #include "py/mperrno.h"
  28. #include "py/mphal.h"
  29. #include "qspi.h"
  30. #if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)
  31. void qspi_init(void) {
  32. // Configure pins
  33. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10);
  34. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
  35. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
  36. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
  37. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
  38. mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9);
  39. // Bring up the QSPI peripheral
  40. __HAL_RCC_QSPI_CLK_ENABLE();
  41. QUADSPI->CR =
  42. 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz)
  43. | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write
  44. #if defined(QUADSPI_CR_FSEL_Pos)
  45. | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected
  46. #endif
  47. #if defined(QUADSPI_CR_DFM_Pos)
  48. | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled
  49. #endif
  50. | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift
  51. | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled
  52. | 1 << QUADSPI_CR_EN_Pos // enable the peripheral
  53. ;
  54. QUADSPI->DCR =
  55. (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos
  56. | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles
  57. | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state
  58. ;
  59. }
  60. void qspi_memory_map(void) {
  61. // Enable memory-mapped mode
  62. QUADSPI->ABR = 0; // disable continuous read mode
  63. QUADSPI->LPTR = 100; // to tune
  64. QUADSPI->CCR =
  65. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  66. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  67. | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode
  68. | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
  69. | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
  70. | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
  71. | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
  72. | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
  73. | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
  74. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  75. | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
  76. ;
  77. }
  78. STATIC int qspi_ioctl(void *self_in, uint32_t cmd) {
  79. (void)self_in;
  80. switch (cmd) {
  81. case MP_QSPI_IOCTL_INIT:
  82. qspi_init();
  83. break;
  84. case MP_QSPI_IOCTL_BUS_RELEASE:
  85. // Switch to memory-map mode when bus is idle
  86. qspi_memory_map();
  87. break;
  88. }
  89. return 0; // success
  90. }
  91. STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
  92. (void)self_in;
  93. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  94. if (len == 0) {
  95. QUADSPI->CCR =
  96. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  97. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  98. | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
  99. | 0 << QUADSPI_CCR_DMODE_Pos // no data
  100. | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
  101. | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
  102. | 0 << QUADSPI_CCR_ADMODE_Pos // no address
  103. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  104. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
  105. ;
  106. } else {
  107. QUADSPI->DLR = len - 1;
  108. QUADSPI->CCR =
  109. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  110. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  111. | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
  112. | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
  113. | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
  114. | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
  115. | 0 << QUADSPI_CCR_ADMODE_Pos // no address
  116. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  117. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
  118. ;
  119. // This assumes len==2
  120. *(uint16_t*)&QUADSPI->DR = data;
  121. }
  122. // Wait for write to finish
  123. while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
  124. }
  125. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  126. }
  127. STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
  128. (void)self_in;
  129. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  130. if (len == 0) {
  131. QUADSPI->CCR =
  132. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  133. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  134. | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
  135. | 0 << QUADSPI_CCR_DMODE_Pos // no data
  136. | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
  137. | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
  138. | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
  139. | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
  140. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  141. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
  142. ;
  143. QUADSPI->AR = addr;
  144. } else {
  145. QUADSPI->DLR = len - 1;
  146. QUADSPI->CCR =
  147. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  148. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  149. | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode
  150. | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
  151. | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
  152. | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
  153. | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
  154. | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line
  155. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  156. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode
  157. ;
  158. QUADSPI->AR = addr;
  159. // Write out the data 1 byte at a time
  160. while (len) {
  161. while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
  162. }
  163. *(volatile uint8_t*)&QUADSPI->DR = *src++;
  164. --len;
  165. }
  166. }
  167. // Wait for write to finish
  168. while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
  169. }
  170. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  171. }
  172. STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
  173. (void)self_in;
  174. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  175. QUADSPI->DLR = len - 1; // number of bytes to read
  176. QUADSPI->CCR =
  177. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  178. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  179. | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
  180. | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line
  181. | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles
  182. | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte
  183. | 0 << QUADSPI_CCR_ADMODE_Pos // no address
  184. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  185. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode
  186. ;
  187. // Wait for read to finish
  188. while (!(QUADSPI->SR & QUADSPI_SR_TCF)) {
  189. }
  190. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  191. // Read result
  192. return QUADSPI->DR;
  193. }
  194. STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
  195. (void)self_in;
  196. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  197. QUADSPI->DLR = len - 1; // number of bytes to read
  198. QUADSPI->CCR =
  199. 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled
  200. | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction
  201. | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode
  202. | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines
  203. | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles
  204. | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte
  205. | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines
  206. | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size
  207. | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines
  208. | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line
  209. | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode
  210. ;
  211. QUADSPI->ABR = 0; // alternate byte: disable continuous read mode
  212. QUADSPI->AR = addr; // addres to read from
  213. // Read in the data 4 bytes at a time if dest is aligned
  214. if (((uintptr_t)dest & 3) == 0) {
  215. while (len >= 4) {
  216. while (!(QUADSPI->SR & QUADSPI_SR_FTF)) {
  217. }
  218. *(uint32_t*)dest = QUADSPI->DR;
  219. dest += 4;
  220. len -= 4;
  221. }
  222. }
  223. // Read in remaining data 1 byte at a time
  224. while (len) {
  225. while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) {
  226. }
  227. *dest++ = *(volatile uint8_t*)&QUADSPI->DR;
  228. --len;
  229. }
  230. QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag
  231. }
  232. const mp_qspi_proto_t qspi_proto = {
  233. .ioctl = qspi_ioctl,
  234. .write_cmd_data = qspi_write_cmd_data,
  235. .write_cmd_addr_data = qspi_write_cmd_addr_data,
  236. .read_cmd = qspi_read_cmd,
  237. .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata,
  238. };
  239. #endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2)