Skip to content

Commit 1a62325

Browse files
committed
SPI: fix: avoid locks with 8/16 bit transfers
When SPI_HOLD_ON_CS is set, Zephyr holds CS down until the 'spi_release' API is called, which is the behavior expected by Arduino users. However, this requires SPI_LOCK_ON to also be set, and that uses the pointer to 'spi_config' structure to identify the lock holder. Using two different structures for 8-bit and 16-bit transfers causes the lock to not work as intended, causing the sketch to hang. Rework code to only use a single 'spi_config' structure and update the 'operation' field as needed. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
1 parent 8862d4e commit 1a62325

File tree

2 files changed

+9
-16
lines changed

2 files changed

+9
-16
lines changed

libraries/SPI/SPI.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,26 @@ arduino::ZephyrSPI::ZephyrSPI(const struct device *spi) : spi_dev(spi) {
1313

1414
uint8_t arduino::ZephyrSPI::transfer(uint8_t data) {
1515
uint8_t rx = data;
16-
if (transfer(&rx, sizeof(rx), &config) < 0) {
16+
if (transfer(&rx, sizeof(rx), SPI_WORD_SET(8)) < 0) {
1717
return 0;
1818
}
1919
return rx;
2020
}
2121

2222
uint16_t arduino::ZephyrSPI::transfer16(uint16_t data) {
2323
uint16_t rx = data;
24-
if (transfer(&rx, sizeof(rx), &config16) < 0) {
24+
if (transfer(&rx, sizeof(rx), SPI_WORD_SET(16)) < 0) {
2525
return 0;
2626
}
2727
return rx;
2828
}
2929

3030
void arduino::ZephyrSPI::transfer(void *buf, size_t count) {
31-
int ret = transfer(buf, count, &config);
31+
int ret = transfer(buf, count, SPI_WORD_SET(8));
3232
(void)ret;
3333
}
3434

35-
int arduino::ZephyrSPI::transfer(void *buf, size_t len, const struct spi_config *config) {
36-
int ret;
37-
35+
int arduino::ZephyrSPI::transfer(void *buf, size_t len, uint32_t flags) {
3836
const struct spi_buf tx_buf = {.buf = buf, .len = len};
3937
const struct spi_buf_set tx_buf_set = {
4038
.buffers = &tx_buf,
@@ -47,6 +45,7 @@ int arduino::ZephyrSPI::transfer(void *buf, size_t len, const struct spi_config
4745
.count = 1,
4846
};
4947

48+
config.operation = mode | flags;
5049
return spi_transceive(spi_dev, config, &tx_buf_set, &rx_buf_set);
5150
}
5251

@@ -57,7 +56,7 @@ void arduino::ZephyrSPI::notUsingInterrupt(int interruptNumber) {
5756
}
5857

5958
void arduino::ZephyrSPI::beginTransaction(SPISettings settings) {
60-
uint32_t mode = SPI_HOLD_ON_CS | SPI_LOCK_ON;
59+
mode = SPI_HOLD_ON_CS | SPI_LOCK_ON;
6160

6261
// Set bus mode
6362
switch (settings.getBusMode()) {
@@ -93,15 +92,9 @@ void arduino::ZephyrSPI::beginTransaction(SPISettings settings) {
9392
break;
9493
}
9594

96-
// Set SPI configuration structure for 8-bit transfers
95+
// Set SPI configuration structure except for operation
9796
memset(&config, 0, sizeof(struct spi_config));
98-
config.operation = mode | SPI_WORD_SET(8);
9997
config.frequency = max(SPI_MIN_CLOCK_FREQUENCY, settings.getClockFreq());
100-
101-
// Set SPI configuration structure for 16-bit transfers
102-
memset(&config16, 0, sizeof(struct spi_config));
103-
config16.operation = mode | SPI_WORD_SET(16);
104-
config16.frequency = max(SPI_MIN_CLOCK_FREQUENCY, settings.getClockFreq());
10598
}
10699

107100
void arduino::ZephyrSPI::endTransaction(void) {

libraries/SPI/SPI.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ class ZephyrSPI : public HardwareSPI {
5959
virtual void end();
6060

6161
private:
62-
int transfer(void *buf, size_t len, const struct spi_config *config);
62+
int transfer(void *buf, size_t len, uint32_t flags);
6363

6464
protected:
6565
const struct device *spi_dev;
6666
struct spi_config config;
67-
struct spi_config config16;
67+
uint32_t mode;
6868
int interrupt[INTERRUPT_COUNT];
6969
size_t interrupt_pos = 0;
7070
};

0 commit comments

Comments
 (0)