softqspi.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2017-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 "drivers/bus/qspi.h"
  27. #define CS_LOW(self) mp_hal_pin_write(self->cs, 0)
  28. #define CS_HIGH(self) mp_hal_pin_write(self->cs, 1)
  29. #ifdef MICROPY_HW_SOFTQSPI_SCK_LOW
  30. // Use externally provided functions for SCK control and IO reading
  31. #define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self)
  32. #define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self)
  33. #define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self)
  34. #else
  35. // Use generic pin functions for SCK control and IO reading
  36. #define SCK_LOW(self) mp_hal_pin_write(self->clk, 0)
  37. #define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1)
  38. #define NIBBLE_READ(self) ( \
  39. mp_hal_pin_read(self->io0) \
  40. | (mp_hal_pin_read(self->io1) << 1) \
  41. | (mp_hal_pin_read(self->io2) << 2) \
  42. | (mp_hal_pin_read(self->io3) << 3))
  43. #endif
  44. STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
  45. mp_hal_pin_write(self->io0, v & 1);
  46. mp_hal_pin_write(self->io1, (v >> 1) & 1);
  47. mp_hal_pin_write(self->io2, (v >> 2) & 1);
  48. mp_hal_pin_write(self->io3, (v >> 3) & 1);
  49. }
  50. STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
  51. mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
  52. switch (cmd) {
  53. case MP_QSPI_IOCTL_INIT:
  54. mp_hal_pin_high(self->cs);
  55. mp_hal_pin_output(self->cs);
  56. // Configure pins
  57. mp_hal_pin_write(self->clk, 0);
  58. mp_hal_pin_output(self->clk);
  59. //mp_hal_pin_write(self->clk, 1);
  60. mp_hal_pin_output(self->io0);
  61. mp_hal_pin_input(self->io1);
  62. mp_hal_pin_write(self->io2, 1);
  63. mp_hal_pin_output(self->io2);
  64. mp_hal_pin_write(self->io3, 1);
  65. mp_hal_pin_output(self->io3);
  66. break;
  67. }
  68. return 0; // success
  69. }
  70. STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
  71. // Will run as fast as possible, limited only by CPU speed and GPIO time
  72. mp_hal_pin_input(self->io1);
  73. mp_hal_pin_output(self->io0);
  74. if (self->io3) {
  75. mp_hal_pin_write(self->io2, 1);
  76. mp_hal_pin_output(self->io2);
  77. mp_hal_pin_write(self->io3, 1);
  78. mp_hal_pin_output(self->io3);
  79. }
  80. if (src) {
  81. for (size_t i = 0; i < len; ++i) {
  82. uint8_t data_out = src[i];
  83. uint8_t data_in = 0;
  84. for (int j = 0; j < 8; ++j, data_out <<= 1) {
  85. mp_hal_pin_write(self->io0, (data_out >> 7) & 1);
  86. mp_hal_pin_write(self->clk, 1);
  87. data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
  88. mp_hal_pin_write(self->clk, 0);
  89. }
  90. if (dest != NULL) {
  91. dest[i] = data_in;
  92. }
  93. }
  94. } else {
  95. for (size_t i = 0; i < len; ++i) {
  96. uint8_t data_in = 0;
  97. for (int j = 0; j < 8; ++j) {
  98. mp_hal_pin_write(self->clk, 1);
  99. data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
  100. mp_hal_pin_write(self->clk, 0);
  101. }
  102. if (dest != NULL) {
  103. dest[i] = data_in;
  104. }
  105. }
  106. }
  107. }
  108. STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {
  109. // Make all IO lines input
  110. mp_hal_pin_input(self->io2);
  111. mp_hal_pin_input(self->io3);
  112. mp_hal_pin_input(self->io0);
  113. mp_hal_pin_input(self->io1);
  114. // Will run as fast as possible, limited only by CPU speed and GPIO time
  115. while (len--) {
  116. SCK_HIGH(self);
  117. uint8_t data_in = NIBBLE_READ(self);
  118. SCK_LOW(self);
  119. SCK_HIGH(self);
  120. *buf++ = (data_in << 4) | NIBBLE_READ(self);
  121. SCK_LOW(self);
  122. }
  123. }
  124. STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {
  125. // Make all IO lines output
  126. mp_hal_pin_output(self->io2);
  127. mp_hal_pin_output(self->io3);
  128. mp_hal_pin_output(self->io0);
  129. mp_hal_pin_output(self->io1);
  130. // Will run as fast as possible, limited only by CPU speed and GPIO time
  131. for (size_t i = 0; i < len; ++i) {
  132. nibble_write(self, buf[i] >> 4);
  133. SCK_HIGH(self);
  134. SCK_LOW(self);
  135. nibble_write(self, buf[i]);
  136. SCK_HIGH(self);
  137. SCK_LOW(self);
  138. }
  139. //mp_hal_pin_input(self->io1);
  140. }
  141. STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
  142. mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
  143. uint32_t cmd_buf = cmd | data << 8;
  144. CS_LOW(self);
  145. mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL);
  146. CS_HIGH(self);
  147. }
  148. STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
  149. mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
  150. uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr};
  151. CS_LOW(self);
  152. mp_soft_qspi_transfer(self, 4, cmd_buf, NULL);
  153. mp_soft_qspi_transfer(self, len, src, NULL);
  154. CS_HIGH(self);
  155. }
  156. STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
  157. mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
  158. uint32_t cmd_buf = cmd;
  159. CS_LOW(self);
  160. mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);
  161. CS_HIGH(self);
  162. return cmd_buf >> 8;
  163. }
  164. STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
  165. mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
  166. uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr};
  167. CS_LOW(self);
  168. mp_soft_qspi_transfer(self, 1, cmd_buf, NULL);
  169. mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)
  170. mp_soft_qspi_qread(self, len, dest);
  171. CS_HIGH(self);
  172. }
  173. const mp_qspi_proto_t mp_soft_qspi_proto = {
  174. .ioctl = mp_soft_qspi_ioctl,
  175. .write_cmd_data = mp_soft_qspi_write_cmd_data,
  176. .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data,
  177. .read_cmd = mp_soft_qspi_read_cmd,
  178. .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata,
  179. };