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