Skip to content

Commit ee10360

Browse files
robert-hhdpgeorge
authored andcommitted
extmod/machine_spi: Support firstbit=LSB for machine.SoftSPI.
Being able to send data out in LSB format can be useful, and having support in the low-level driver is much better than requiring Python code to reorder the bits before sending them / after receiving them. In particular if the hardware does not support the LSB format (eg RP2040) then one needs to use the SoftSPI in LSB mode. For this change a default definition of `MICROPY_PY_MACHINE_SPI_MSB/_LSB` was added to `py/mpconfig.h`, making them available to all ports. The identical defines in `esp32/mpconfigport.h` were deleted. Resolves issues #5340, #11404. Signed-off-by: robert-hh <robert@hammelrath.com>
1 parent 20b00ca commit ee10360

File tree

5 files changed

+35
-24
lines changed

5 files changed

+35
-24
lines changed

drivers/bus/softspi.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,39 +44,48 @@ int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
4444
return 0;
4545
}
4646

47+
static uint8_t swap_bits(uint8_t byte) {
48+
const static uint8_t swap_table[16] = {
49+
0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
50+
0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
51+
};
52+
return ((swap_table[byte & 0x0f] << 4) | swap_table[byte >> 4]);
53+
}
54+
4755
void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
4856
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
4957
uint32_t delay_half = self->delay_half;
5058

51-
// only MSB transfer is implemented
52-
5359
// If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured
5460
// delay_half is equal to this value, then the software SPI implementation
5561
// will run as fast as possible, limited only by CPU speed and GPIO time.
5662
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
5763
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
5864
for (size_t i = 0; i < len; ++i) {
59-
uint8_t data_out = src[i];
65+
uint8_t data_out = self->firstbit != MICROPY_PY_MACHINE_SPI_MSB ?
66+
src[i] : swap_bits(src[i]);
6067
uint8_t data_in = 0;
61-
for (int j = 0; j < 8; ++j, data_out <<= 1) {
62-
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
68+
for (int j = 0; j < 8; ++j, data_out >>= 1) {
69+
mp_hal_pin_write(self->mosi, data_out & 1);
6370
mp_hal_pin_write(self->sck, 1 - self->polarity);
6471
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
6572
mp_hal_pin_write(self->sck, self->polarity);
6673
}
6774
if (dest != NULL) {
68-
dest[i] = data_in;
75+
dest[i] = self->firstbit == MICROPY_PY_MACHINE_SPI_MSB ?
76+
data_in : swap_bits(data_in);
6977
}
7078
}
7179
return;
7280
}
7381
#endif
7482

7583
for (size_t i = 0; i < len; ++i) {
76-
uint8_t data_out = src[i];
84+
uint8_t data_out = self->firstbit != MICROPY_PY_MACHINE_SPI_MSB ?
85+
src[i] : swap_bits(src[i]);
7786
uint8_t data_in = 0;
78-
for (int j = 0; j < 8; ++j, data_out <<= 1) {
79-
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
87+
for (int j = 0; j < 8; ++j, data_out >>= 1) {
88+
mp_hal_pin_write(self->mosi, data_out & 1);
8089
if (self->phase == 0) {
8190
mp_hal_delay_us_fast(delay_half);
8291
mp_hal_pin_write(self->sck, 1 - self->polarity);
@@ -94,7 +103,8 @@ void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t
94103
}
95104
}
96105
if (dest != NULL) {
97-
dest[i] = data_in;
106+
dest[i] = self->firstbit == MICROPY_PY_MACHINE_SPI_MSB ?
107+
data_in : swap_bits(data_in);
98108
}
99109
}
100110
}

drivers/bus/spi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef struct _mp_soft_spi_obj_t {
4242
uint32_t delay_half; // microsecond delay for half SCK period
4343
uint8_t polarity;
4444
uint8_t phase;
45+
uint8_t firstbit;
4546
mp_hal_pin_obj_t sck;
4647
mp_hal_pin_obj_t mosi;
4748
mp_hal_pin_obj_t miso;

extmod/machine_spi.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@
3333

3434
#include "extmod/modmachine.h"
3535

36-
// if a port didn't define MSB/LSB constants then provide them
37-
#ifndef MICROPY_PY_MACHINE_SPI_MSB
38-
#define MICROPY_PY_MACHINE_SPI_MSB (0)
39-
#define MICROPY_PY_MACHINE_SPI_LSB (1)
40-
#endif
41-
4236
/******************************************************************************/
4337
// MicroPython bindings for generic machine.SPI
4438

@@ -154,9 +148,9 @@ static uint32_t baudrate_to_delay_half(uint32_t baudrate) {
154148

155149
static void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
156150
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
157-
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u,"
151+
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u, firstbit=%u,"
158152
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
159-
baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase,
153+
baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase, self->spi.firstbit,
160154
mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
161155
}
162156

@@ -185,9 +179,7 @@ static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
185179
if (args[ARG_bits].u_int != 8) {
186180
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 8"));
187181
}
188-
if (args[ARG_firstbit].u_int != MICROPY_PY_MACHINE_SPI_MSB) {
189-
mp_raise_ValueError(MP_ERROR_TEXT("firstbit must be MSB"));
190-
}
182+
self->spi.firstbit = args[ARG_firstbit].u_int;
191183
if (args[ARG_sck].u_obj == MP_OBJ_NULL
192184
|| args[ARG_mosi].u_obj == MP_OBJ_NULL
193185
|| args[ARG_miso].u_obj == MP_OBJ_NULL) {
@@ -206,11 +198,12 @@ static mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
206198
static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
207199
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t *)self_in;
208200

209-
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };
201+
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
210202
static const mp_arg_t allowed_args[] = {
211203
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
212204
{ MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },
213205
{ MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} },
206+
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
214207
{ MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
215208
{ MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
216209
{ MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
@@ -227,6 +220,9 @@ static void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
227220
if (args[ARG_phase].u_int != -1) {
228221
self->spi.phase = args[ARG_phase].u_int;
229222
}
223+
if (args[ARG_firstbit].u_int != -1) {
224+
self->spi.firstbit = args[ARG_firstbit].u_int;
225+
}
230226
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
231227
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
232228
}

ports/esp32/mpconfigport.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,6 @@
136136
#define MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1 (1)
137137
#define MICROPY_PY_MACHINE_SOFTI2C (1)
138138
#define MICROPY_PY_MACHINE_SPI (1)
139-
#define MICROPY_PY_MACHINE_SPI_MSB (0)
140-
#define MICROPY_PY_MACHINE_SPI_LSB (1)
141139
#define MICROPY_PY_MACHINE_SOFTSPI (1)
142140
#ifndef MICROPY_PY_MACHINE_DAC
143141
#define MICROPY_PY_MACHINE_DAC (SOC_DAC_SUPPORTED)

py/mpconfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,12 @@ typedef double mp_float_t;
17841784
#define MICROPY_PY_MACHINE_SOFTSPI (0)
17851785
#endif
17861786

1787+
// Values of SPI.MSB and SPI.LSB constants
1788+
#ifndef MICROPY_PY_MACHINE_SPI_MSB
1789+
#define MICROPY_PY_MACHINE_SPI_MSB (0)
1790+
#define MICROPY_PY_MACHINE_SPI_LSB (1)
1791+
#endif
1792+
17871793
// Whether to provide the "machine.Timer" class
17881794
#ifndef MICROPY_PY_MACHINE_TIMER
17891795
#define MICROPY_PY_MACHINE_TIMER (0)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy