Skip to content

Commit 1da2d45

Browse files
committed
drivers/bus: Add QSPI abstract type with software QSPI implementation.
A new directory drivers/bus/ is introduced, which can hold implementations of bus drivers. A software QSPI implementation is added.
1 parent 9884a2c commit 1da2d45

2 files changed

Lines changed: 260 additions & 0 deletions

File tree

drivers/bus/qspi.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
27+
#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
28+
29+
#include "py/mphal.h"
30+
31+
enum {
32+
MP_QSPI_IOCTL_INIT,
33+
MP_QSPI_IOCTL_DEINIT,
34+
MP_QSPI_IOCTL_BUS_ACQUIRE,
35+
MP_QSPI_IOCTL_BUS_RELEASE,
36+
};
37+
38+
typedef struct _mp_qspi_proto_t {
39+
int (*ioctl)(void *self, uint32_t cmd);
40+
void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
41+
void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
42+
uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len);
43+
void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);
44+
} mp_qspi_proto_t;
45+
46+
typedef struct _mp_soft_qspi_obj_t {
47+
mp_hal_pin_obj_t cs;
48+
mp_hal_pin_obj_t clk;
49+
mp_hal_pin_obj_t io0;
50+
mp_hal_pin_obj_t io1;
51+
mp_hal_pin_obj_t io2;
52+
mp_hal_pin_obj_t io3;
53+
} mp_soft_qspi_obj_t;
54+
55+
extern const mp_qspi_proto_t mp_soft_qspi_proto;
56+
57+
#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H

drivers/bus/softqspi.c

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
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+
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+
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+
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+
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+
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+
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+
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[4] = {cmd, addr >> 16, addr >> 8, addr};
172+
CS_LOW(self);
173+
mp_soft_qspi_transfer(self, 4, cmd_buf, NULL);
174+
mp_soft_qspi_transfer(self, len, src, NULL);
175+
CS_HIGH(self);
176+
}
177+
178+
STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
179+
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
180+
uint32_t cmd_buf = cmd;
181+
CS_LOW(self);
182+
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);
183+
CS_HIGH(self);
184+
return cmd_buf >> 8;
185+
}
186+
187+
STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
188+
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
189+
uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr};
190+
CS_LOW(self);
191+
mp_soft_qspi_transfer(self, 1, cmd_buf, NULL);
192+
mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)
193+
mp_soft_qspi_qread(self, len, dest);
194+
CS_HIGH(self);
195+
}
196+
197+
const mp_qspi_proto_t mp_soft_qspi_proto = {
198+
.ioctl = mp_soft_qspi_ioctl,
199+
.write_cmd_data = mp_soft_qspi_write_cmd_data,
200+
.write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data,
201+
.read_cmd = mp_soft_qspi_read_cmd,
202+
.read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata,
203+
};

0 commit comments

Comments
 (0)