Skip to content

Commit e0f4d2b

Browse files
committed
*/*spi.c
*/*spi.h Support for odd bit lengths in SPI, per discussion at micropython#5225
1 parent 7c54b64 commit e0f4d2b

File tree

12 files changed

+81
-46
lines changed

12 files changed

+81
-46
lines changed

drivers/bus/softspi.c

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* The MIT License (MIT)
55
*
66
* Copyright (c) 2016-2018 Damien P. George
7+
* Copyright (c) 2019 "Eric Poulsen" <eric@zyxod.com>
78
*
89
* Permission is hereby granted, free of charge, to any person obtaining a copy
910
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +26,7 @@
2526
*/
2627

2728
#include "drivers/bus/spi.h"
29+
#include "py/runtime.h"
2830

2931
int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
3032
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
@@ -44,38 +46,63 @@ int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
4446
return 0;
4547
}
4648

47-
void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
49+
void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits) {
4850
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
4951
uint32_t delay_half = self->delay_half;
5052

53+
bits = bits ? bits : self->bits;
54+
if (bits == 0) {
55+
// Shoudln't be possible with soft SPI, but
56+
// just in case.
57+
mp_raise_ValueError("bits cannot be 0");
58+
}
59+
60+
int bytesPerChunk = (bits + 7) / 8;
61+
// round length down as needed (possibly to zero)
62+
len = len / bytesPerChunk * bytesPerChunk;
63+
if(len == 0) {
64+
return;
65+
}
66+
67+
uint8_t remBits = bits;
68+
5169
// only MSB transfer is implemented
5270

5371
// If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured
5472
// delay_half is equal to this value, then the software SPI implementation
5573
// will run as fast as possible, limited only by CPU speed and GPIO time.
5674
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
57-
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
58-
for (size_t i = 0; i < len; ++i) {
59-
uint8_t data_out = src[i];
75+
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY)
76+
{
77+
while (len--) {
78+
uint8_t bitsThisByte = remBits < 8 ? remBits : 8;
79+
uint8_t data_out = *src++;
6080
uint8_t data_in = 0;
61-
for (int j = 0; j < 8; ++j, data_out <<= 1) {
81+
82+
remBits -= bitsThisByte;
83+
for (; bitsThisByte; --bitsThisByte, data_out <<= 1) {
6284
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
6385
mp_hal_pin_write(self->sck, 1 - self->polarity);
6486
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
6587
mp_hal_pin_write(self->sck, self->polarity);
6688
}
89+
remBits = remBits ? remBits : bits;
6790
if (dest != NULL) {
68-
dest[i] = data_in;
91+
*dest++ = data_in;
6992
}
7093
}
7194
return;
7295
}
73-
#endif
96+
#endif
7497

75-
for (size_t i = 0; i < len; ++i) {
76-
uint8_t data_out = src[i];
98+
99+
while(len--) {
100+
uint8_t bitsThisByte = remBits < 8 ? remBits : 8;
101+
uint8_t data_out = *src++;
77102
uint8_t data_in = 0;
78-
for (int j = 0; j < 8; ++j, data_out <<= 1) {
103+
104+
remBits -= bitsThisByte;
105+
for(;bitsThisByte; --bitsThisByte, data_out <<= 1) {
79106
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
80107
if (self->phase == 0) {
81108
mp_hal_delay_us_fast(delay_half);
@@ -93,8 +120,9 @@ void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t
93120
mp_hal_delay_us_fast(delay_half);
94121
}
95122
}
123+
remBits = remBits ? remBits : bits;
96124
if (dest != NULL) {
97-
dest[i] = data_in;
125+
*dest++ = data_in;
98126
}
99127
}
100128
}

drivers/bus/spi.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ enum {
3535

3636
typedef struct _mp_spi_proto_t {
3737
int (*ioctl)(void *self, uint32_t cmd);
38-
void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest);
38+
void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits);
3939
} mp_spi_proto_t;
4040

4141
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 bits;
4546
mp_hal_pin_obj_t sck;
4647
mp_hal_pin_obj_t mosi;
4748
mp_hal_pin_obj_t miso;
@@ -50,6 +51,6 @@ typedef struct _mp_soft_spi_obj_t {
5051
extern const mp_spi_proto_t mp_soft_spi_proto;
5152

5253
int mp_soft_spi_ioctl(void *self, uint32_t cmd);
53-
void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest);
54+
void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits);
5455

5556
#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H

drivers/memory/spiflash.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t
7575
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
7676
// Note: len/data are unused for standard SPI
7777
mp_hal_pin_write(c->bus.u_spi.cs, 0);
78-
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
78+
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL, 8);
7979
mp_hal_pin_write(c->bus.u_spi.cs, 1);
8080
} else {
8181
c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data);
@@ -110,8 +110,8 @@ STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t le
110110
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
111111
uint32_t buf;
112112
mp_hal_pin_write(c->bus.u_spi.cs, 0);
113-
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
114-
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf);
113+
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL, 8);
114+
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf, 8);
115115
mp_hal_pin_write(c->bus.u_spi.cs, 1);
116116
return buf;
117117
} else {

extmod/machine_spi.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,41 +68,50 @@ STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src,
6868
STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) {
6969
vstr_t vstr;
7070
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
71-
memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);
72-
mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf);
71+
memset(vstr.buf, n_args >= 3 ? mp_obj_get_int(args[2]) : 0, vstr.len);
72+
uint8_t bits = n_args == 4 ? mp_obj_get_int(args[3]) : 0;
73+
mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf, bits);
7374
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
7475
}
75-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read);
76+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 4, mp_machine_spi_read);
7677

7778
STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) {
7879
mp_buffer_info_t bufinfo;
7980
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
80-
memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);
81-
mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf);
81+
memset(bufinfo.buf, n_args >= 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len);
82+
uint8_t bits = n_args == 4 ? mp_obj_get_int(args[3]) : 0;
83+
mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf, bits);
8284
return mp_const_none;
8385
}
84-
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto);
86+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 4, mp_machine_spi_readinto);
8587

86-
STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) {
88+
STATIC mp_obj_t mp_machine_spi_write(size_t n_args, const mp_obj_t *args) {
89+
mp_obj_t self = args[0];
90+
mp_obj_t wr_buf = args[1];
91+
uint8_t bits = n_args == 3 ? mp_obj_get_int(args[2]) : 0;
8792
mp_buffer_info_t src;
8893
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
8994
mp_machine_spi_transfer(self, src.len, (const uint8_t *)src.buf, NULL);
9095
return mp_const_none;
9196
}
92-
MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write);
97+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_write_obj, 2, 3, mp_machine_spi_write);
9398

94-
STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) {
99+
STATIC mp_obj_t mp_machine_spi_write_readinto(size_t n_args, const mp_obj_t *args) {
100+
mp_obj_t self = args[0];
101+
mp_obj_t wr_buf = args[1];
102+
mp_obj_t rd_buf = args[2];
103+
uint8_t bits = n_args == 4 ? mp_obj_get_int(args[3]) : 0;
95104
mp_buffer_info_t src;
96105
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
97106
mp_buffer_info_t dest;
98107
mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE);
99108
if (src.len != dest.len) {
100109
mp_raise_ValueError(MP_ERROR_TEXT("buffers must be the same length"));
101110
}
102-
mp_machine_spi_transfer(self, src.len, src.buf, dest.buf);
111+
mp_machine_spi_transfer(self, src.len, src.buf, dest.buf, bits);
103112
return mp_const_none;
104113
}
105-
MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto);
114+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_write_readinto_obj, 3, 4, mp_machine_spi_write_readinto);
106115

107116
STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {
108117
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) },
@@ -179,8 +188,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
179188
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
180189
self->spi.polarity = args[ARG_polarity].u_int;
181190
self->spi.phase = args[ARG_phase].u_int;
182-
if (args[ARG_bits].u_int != 8) {
183-
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 8"));
191+
self->spi.bits = args[ARG_bits].u_int;
192+
if (self->spi.bits == 0) {
193+
mp_raise_ValueError("bits must be > 0");
184194
}
185195
if (args[ARG_firstbit].u_int != MICROPY_PY_MACHINE_SPI_MSB) {
186196
mp_raise_ValueError(MP_ERROR_TEXT("firstbit must be MSB"));

extmod/machine_spi.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
typedef struct _mp_machine_spi_p_t {
4848
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
4949
void (*deinit)(mp_obj_base_t *obj); // can be NULL
50-
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
50+
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits);
5151
} mp_machine_spi_p_t;
5252

5353
typedef struct _mp_machine_soft_spi_obj_t {
@@ -60,10 +60,9 @@ extern const mp_obj_type_t mp_machine_soft_spi_type;
6060
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
6161

6262
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
63-
6463
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
6564
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj);
66-
MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj);
67-
MP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj);
65+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_write_obj);
66+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_write_readinto_obj);
6867

6968
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H

ports/esp8266/machine_hspi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ typedef struct _machine_hspi_obj_t {
4848
uint8_t phase;
4949
} machine_hspi_obj_t;
5050

51-
STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
51+
STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits) {
5252
(void)self_in;
5353

5454
if (dest == NULL) {

ports/nrf/modules/machine/spi.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ STATIC int spi_find(mp_obj_t id) {
151151
}
152152
}
153153

154-
void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) {
154+
void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest, uint8_t bits) {
155155
nrfx_spi_xfer_desc_t xfer_desc = {
156156
.p_tx_buffer = src,
157157
.tx_length = len,
@@ -377,9 +377,9 @@ STATIC void machine_hard_spi_deinit(mp_obj_t self_in) {
377377
nrfx_spi_uninit(self->p_spi);
378378
}
379379

380-
STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
380+
STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest, uint8_t bits) {
381381
const machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
382-
spi_transfer(self, len, src, dest);
382+
spi_transfer(self, len, src, dest, bits);
383383
}
384384

385385

ports/nrf/modules/machine/spi.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ void spi_init0(void);
3333
void spi_transfer(const machine_hard_spi_obj_t * self,
3434
size_t len,
3535
const void * src,
36-
void * dest);
36+
void * dest,
37+
uint8_t bits);

ports/nrf/mpconfigport.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,6 @@
160160
#define MICROPY_PY_MACHINE_I2C (0)
161161
#endif
162162

163-
#ifndef MICROPY_PY_MACHINE_HW_SPI
164-
#define MICROPY_PY_MACHINE_HW_SPI (1)
165-
#endif
166-
167163
#ifndef MICROPY_PY_MACHINE_HW_PWM
168164
#define MICROPY_PY_MACHINE_HW_PWM (0)
169165
#endif

ports/stm32/pyb_spi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
190190
pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
191191

192192
// send the data
193-
spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int);
193+
spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int, 8);
194194

195195
return mp_const_none;
196196
}
@@ -292,7 +292,7 @@ STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_ma
292292
}
293293

294294
// do the transfer
295-
spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int);
295+
spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int, 8);
296296

297297
// return the received data
298298
if (o_ret != MP_OBJ_NULL) {

0 commit comments

Comments
 (0)