Skip to content

Commit 6626319

Browse files
committed
Add SPI support
It uses both SPI and AUX SPI peripherals
1 parent b248cee commit 6626319

File tree

6 files changed

+230
-15
lines changed

6 files changed

+230
-15
lines changed

ports/broadcom/common-hal/busio/SPI.c

Lines changed: 210 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,104 @@
3434
#include "common-hal/microcontroller/Pin.h"
3535
#include "shared-bindings/microcontroller/Pin.h"
3636

37-
#define NO_INSTANCE 0xff
37+
#include "peripherals/broadcom/cpu.h"
38+
#include "peripherals/broadcom/defines.h"
39+
#include "peripherals/broadcom/gpio.h"
40+
#include "peripherals/broadcom/pins.h"
41+
#include "peripherals/broadcom/vcmailbox.h"
3842

39-
STATIC bool never_reset_spi[2];
43+
#if BCM_VERSION == 2711
44+
#define NUM_SPI (7)
45+
STATIC SPI0_Type *spi[NUM_SPI] = {SPI0, NULL, NULL, SPI3, SPI4, SPI5, SPI6};
46+
STATIC SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2, NULL, NULL, NULL, NULL};
47+
#else
48+
#define NUM_SPI (3)
49+
STATIC SPI0_Type *spi[NUM_SPI] = {SPI0, NULL, NULL};
50+
STATIC SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2};
51+
#endif
52+
53+
STATIC bool never_reset_spi[NUM_SPI];
54+
STATIC bool spi_in_use[NUM_SPI];
4055

4156
void reset_spi(void) {
42-
for (size_t i = 0; i < 2; i++) {
57+
for (size_t i = 0; i < NUM_SPI; i++) {
4358
if (never_reset_spi[i]) {
4459
continue;
4560
}
4661

47-
// TODO
62+
if (i == 1 || i == 2) {
63+
if (i == 1) {
64+
AUX->ENABLES_b.SPI_1 = false;
65+
} else {
66+
AUX->ENABLES_b.SPI_2 = false;
67+
}
68+
aux_spi[i]->CNTL0 = 0;
69+
} else {
70+
// Set CS back to default. All 0 except read enable.
71+
spi[i]->CS = SPI0_CS_REN_Msk;
72+
}
73+
74+
spi_in_use[i] = false;
4875
}
4976
}
5077

5178
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
5279
const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi,
5380
const mcu_pin_obj_t *miso) {
81+
size_t instance_index = NUM_SPI;
82+
BP_Function_Enum clock_alt = 0;
83+
BP_Function_Enum mosi_alt = 0;
84+
BP_Function_Enum miso_alt = 0;
85+
for (size_t i = 0; i < NUM_SPI; i++) {
86+
if (spi_in_use[i]) {
87+
continue;
88+
}
89+
if (!pin_find_alt(clock, PIN_FUNCTION_SPI, i, SPI_FUNCTION_SCLK, &clock_alt)) {
90+
continue;
91+
}
92+
if (mosi != NULL && !pin_find_alt(mosi, PIN_FUNCTION_SPI, i, SPI_FUNCTION_MOSI, &mosi_alt)) {
93+
continue;
94+
}
95+
if (miso != NULL && !pin_find_alt(miso, PIN_FUNCTION_SPI, i, SPI_FUNCTION_MISO, &miso_alt)) {
96+
continue;
97+
}
98+
instance_index = i;
99+
break;
100+
}
101+
if (instance_index == NUM_SPI) {
102+
mp_raise_ValueError(translate("Invalid pins"));
103+
}
104+
105+
self->clock = clock;
106+
self->MOSI = mosi;
107+
self->MISO = miso;
108+
self->index = instance_index;
109+
spi_in_use[instance_index] = true;
110+
111+
112+
if (instance_index == 1) {
113+
AUX->ENABLES_b.SPI_1 = true;
114+
} else if (instance_index == 2) {
115+
AUX->ENABLES_b.SPI_2 = true;
116+
}
117+
118+
common_hal_busio_spi_configure(self, 250000, 0, 0, 8);
54119

120+
COMPLETE_MEMORY_READS;
121+
gpio_set_pull(clock->number, BP_PULL_NONE);
122+
gpio_set_function(clock->number, clock_alt);
123+
if (mosi != NULL) {
124+
gpio_set_pull(mosi->number, BP_PULL_NONE);
125+
gpio_set_function(mosi->number, mosi_alt);
126+
}
127+
if (miso != NULL) {
128+
gpio_set_pull(miso->number, BP_PULL_NONE);
129+
gpio_set_function(miso->number, miso_alt);
130+
}
55131
}
56132

57133
void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) {
58-
// never_reset_spi[spi_get_index(self->peripheral)] = true;
134+
never_reset_spi[self->index] = true;
59135

60136
common_hal_never_reset_pin(self->clock);
61137
common_hal_never_reset_pin(self->MOSI);
@@ -70,12 +146,22 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
70146
if (common_hal_busio_spi_deinited(self)) {
71147
return;
72148
}
73-
// never_reset_spi[spi_get_index(self->peripheral)] = false;
149+
never_reset_spi[self->index] = false;
74150

75151
common_hal_reset_pin(self->clock);
76152
common_hal_reset_pin(self->MOSI);
77153
common_hal_reset_pin(self->MISO);
78154
self->clock = NULL;
155+
156+
if (self->index == 1 ||
157+
self->index == 2) {
158+
aux_spi[self->index]->CNTL0_b.ENABLE = false;
159+
if (self->index == 1) {
160+
AUX->ENABLES_b.SPI_1 = false;
161+
} else if (self->index == 2) {
162+
AUX->ENABLES_b.SPI_2 = false;
163+
}
164+
}
79165
}
80166

81167
bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
@@ -87,13 +173,40 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
87173
return true;
88174
}
89175

90-
// TODO
176+
if (self->index == 1 || self->index == 2) {
177+
SPI1_Type *p = aux_spi[self->index];
178+
uint32_t source_clock = vcmailbox_get_clock_rate_measured(VCMAILBOX_CLOCK_CORE);
179+
uint16_t clock_divider = source_clock / baudrate;
180+
if (source_clock % baudrate > 0) {
181+
clock_divider += 2;
182+
}
183+
184+
p->CNTL0 = (clock_divider / 2 - 1) << SPI1_CNTL0_SPEED_Pos |
185+
SPI1_CNTL0_ENABLE_Msk |
186+
SPI1_CNTL0_MSB_FIRST_Msk |
187+
(polarity == 1? SPI1_CNTL0_INVERT_CLK_Msk : 0) |
188+
(phase == polarity? SPI1_CNTL0_IN_RISING_Msk : SPI1_CNTL0_OUT_RISING_Msk) |
189+
8 << SPI1_CNTL0_SHIFT_LENGTH_Pos;
190+
p->CNTL1 = SPI1_CNTL1_MSB_FIRST_Msk;
191+
self->real_frequency = source_clock / clock_divider;
192+
} else {
193+
SPI0_Type *p = spi[self->index];
194+
p->CS = polarity << SPI0_CS_CPOL_Pos |
195+
phase << SPI0_CS_CPHA_Pos;
196+
uint32_t source_clock = vcmailbox_get_clock_rate_measured(VCMAILBOX_CLOCK_CORE);
197+
uint16_t clock_divider = source_clock / baudrate;
198+
if (source_clock % baudrate > 0) {
199+
clock_divider += 2;
200+
}
201+
202+
p->CLK = clock_divider;
203+
self->real_frequency = source_clock / clock_divider;
204+
}
91205

92206
self->polarity = polarity;
93207
self->phase = phase;
94208
self->bits = bits;
95209
self->target_frequency = baudrate;
96-
self->real_frequency = baudrate; // TODO
97210

98211
return true;
99212
}
@@ -115,18 +228,103 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
115228
self->has_lock = false;
116229
}
117230

231+
STATIC void _spi_transfer(SPI0_Type *p,
232+
const uint8_t *data_out, size_t out_len,
233+
uint8_t *data_in, size_t in_len) {
234+
size_t len = MAX(out_len, in_len);
235+
COMPLETE_MEMORY_READS;
236+
p->DLEN = len;
237+
p->CS |= SPI0_CS_TA_Msk | SPI0_CS_CLEAR_Msk;
238+
size_t in = 0;
239+
size_t out = 0;
240+
while (in < len) {
241+
while (out < len && p->CS_b.TXD == 1) {
242+
if (out_len == 1) {
243+
p->FIFO = data_out[0];
244+
} else {
245+
p->FIFO = data_out[out];
246+
}
247+
out++;
248+
}
249+
// Wait for data to read (also means data has been sent.)
250+
while (p->CS_b.RXD == 0) {
251+
RUN_BACKGROUND_TASKS;
252+
}
253+
while (p->CS_b.RXD == 1) {
254+
uint8_t data = p->FIFO;
255+
if (data_in != NULL) {
256+
data_in[in] = data;
257+
} else {
258+
(void)data;
259+
}
260+
in++;
261+
}
262+
}
263+
p->CS_b.TA = false;
264+
COMPLETE_MEMORY_READS;
265+
}
266+
267+
STATIC void _aux_spi_transfer(SPI1_Type *p,
268+
const uint8_t *data_out, size_t out_len,
269+
uint8_t *data_in, size_t in_len) {
270+
size_t len = MAX(out_len, in_len);
271+
p->CNTL0 |= SPI1_CNTL0_CLEAR_FIFOS_Msk;
272+
p->CNTL0 &= ~SPI1_CNTL0_CLEAR_FIFOS_Msk;
273+
size_t in = 0;
274+
size_t out = 0;
275+
while (in < len) {
276+
while (out < len && p->STAT_b.TX_FULL == 0) {
277+
if (out_len == 1) {
278+
p->TXHOLD0 = data_out[0] << 24;
279+
} else {
280+
p->TXHOLD0 = data_out[out] << 24;
281+
}
282+
out++;
283+
}
284+
// Wait for data to read (also means data has been sent.)
285+
while (p->STAT_b.RX_EMPTY == 1) {
286+
RUN_BACKGROUND_TASKS;
287+
}
288+
while (p->STAT_b.RX_EMPTY == 0) {
289+
uint8_t data = p->TXHOLD0;
290+
if (data_in != NULL) {
291+
data_in[in] = data;
292+
} else {
293+
(void)data;
294+
}
295+
in++;
296+
}
297+
}
298+
}
299+
118300
bool common_hal_busio_spi_write(busio_spi_obj_t *self,
119301
const uint8_t *data, size_t len) {
120-
return false;
302+
if (self->index == 1 || self->index == 2) {
303+
_aux_spi_transfer(aux_spi[self->index], data, len, NULL, 0);
304+
} else {
305+
_spi_transfer(spi[self->index], data, len, NULL, 0);
306+
}
307+
return true;
121308
}
122309

123310
bool common_hal_busio_spi_read(busio_spi_obj_t *self,
124311
uint8_t *data, size_t len, uint8_t write_value) {
125-
return false;
312+
if (self->index == 1 || self->index == 2) {
313+
_aux_spi_transfer(aux_spi[self->index], &write_value, 1, data, len);
314+
} else {
315+
_spi_transfer(spi[self->index], &write_value, 1, data, len);
316+
}
317+
return true;
126318
}
127319

128-
bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) {
129-
return false;
320+
bool common_hal_busio_spi_transfer(busio_spi_obj_t *self,
321+
const uint8_t *data_out, uint8_t *data_in, size_t len) {
322+
if (self->index == 1 || self->index == 2) {
323+
_aux_spi_transfer(aux_spi[self->index], data_out, len, data_in, len);
324+
} else {
325+
_spi_transfer(spi[self->index], data_out, len, data_in, len);
326+
}
327+
return true;
130328
}
131329

132330
uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) {

ports/broadcom/common-hal/busio/SPI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef struct {
4242
uint8_t polarity;
4343
uint8_t phase;
4444
uint8_t bits;
45+
uint8_t index;
4546
} busio_spi_obj_t;
4647

4748
void reset_spi(void);

ports/broadcom/common-hal/busio/UART.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ void UART5_IRQHandler(void) {
148148

149149
void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
150150
uart_status[self->uart_id] = STATUS_NEVER_RESET;
151+
common_hal_never_reset_pin(self->tx_pin);
152+
common_hal_never_reset_pin(self->rx_pin);
153+
common_hal_never_reset_pin(self->cts_pin);
154+
common_hal_never_reset_pin(self->rts_pin);
151155
}
152156

153157
void common_hal_busio_uart_construct(busio_uart_obj_t *self,

ports/broadcom/common-hal/microcontroller/Pin.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,15 @@ void never_reset_pin_number(uint8_t pin_number) {
4545
}
4646

4747
void reset_pin_number(uint8_t pin_number) {
48-
gpio_set_function(pin_number, GPIO_FUNCTION_INPUT);
4948
pin_in_use[pin_number] = false;
5049
never_reset_pin[pin_number] = false;
50+
// Reset JTAG pins back to JTAG.
51+
if (22 <= pin_number && pin_number <= 27) {
52+
gpio_set_function(pin_number, GPIO_FUNCTION_ALT4);
53+
return;
54+
} else {
55+
gpio_set_function(pin_number, GPIO_FUNCTION_INPUT);
56+
}
5157
// Set the pull to match the datasheet.
5258
BP_PULL_Enum pull = BP_PULL_NONE;
5359
if (pin_number < 9 ||
@@ -66,10 +72,16 @@ void reset_pin_number(uint8_t pin_number) {
6672
}
6773

6874
void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
75+
if (pin == NULL) {
76+
return;
77+
}
6978
never_reset_pin_number(pin->number);
7079
}
7180

7281
void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
82+
if (pin == NULL) {
83+
return;
84+
}
7385
reset_pin_number(pin->number);
7486
}
7587

ports/broadcom/supervisor/port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ void reset_port(void) {
106106
audio_dma_reset();
107107
#endif
108108

109-
// reset_all_pins();
109+
reset_all_pins();
110110
}
111111

112112
void reset_to_bootloader(void) {

0 commit comments

Comments
 (0)