Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 82 additions & 83 deletions libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,118 +8,117 @@
#include "zephyrInternal.h"
#include <zephyr/kernel.h>

/* Serial Peripheral Control Register */
uint8_t SPCR;

arduino::ZephyrSPI::ZephyrSPI(const struct device *spi) : spi_dev(spi) {}
arduino::ZephyrSPI::ZephyrSPI(const struct device *spi) : spi_dev(spi) {
}

uint8_t arduino::ZephyrSPI::transfer(uint8_t data) {
int ret;
uint8_t rx;
const struct spi_buf tx_buf = {.buf = &data, .len = sizeof(data)};
const struct spi_buf_set tx_buf_set = {
.buffers = &tx_buf,
.count = 1,
};
const struct spi_buf rx_buf = {.buf = &rx, .len = sizeof(rx)};
const struct spi_buf_set rx_buf_set = {
.buffers = &rx_buf,
.count = 1,
};

ret = spi_transceive(spi_dev, &config, &tx_buf_set, &rx_buf_set);
if (ret < 0) {
return 0;
}

return rx;
uint8_t rx = data;
if (transfer(&rx, sizeof(rx), &config) < 0) {
return 0;
}
return rx;
}

uint16_t arduino::ZephyrSPI::transfer16(uint16_t data) {
int ret;
uint16_t rx;
const struct spi_buf tx_buf = {.buf = &data, .len = sizeof(data)};
const struct spi_buf_set tx_buf_set = {
.buffers = &tx_buf,
.count = 1,
};
const struct spi_buf rx_buf = {.buf = &rx, .len = sizeof(rx)};
const struct spi_buf_set rx_buf_set = {
.buffers = &rx_buf,
.count = 1,
};

ret = spi_transceive(spi_dev, &config, &tx_buf_set, &rx_buf_set);
if (ret < 0) {
return 0;
}

return rx;
uint16_t rx = data;
if (transfer(&rx, sizeof(rx), &config16) < 0) {
return 0;
}
return rx;
}

void arduino::ZephyrSPI::transfer(void *buf, size_t count) {
int ret;
const struct spi_buf tx_buf = {.buf = buf, .len = count};
const struct spi_buf_set tx_buf_set = {
.buffers = &tx_buf,
.count = 1,
};

ret = spi_write(spi_dev, &config, &tx_buf_set);
if (ret < 0) {
return;
}

ret = spi_read(spi_dev, &config, &tx_buf_set);
if (ret < 0) {
return;
}
int ret = transfer(buf, count, &config);
(void)ret;
}

int arduino::ZephyrSPI::transfer(void *buf, size_t len, const struct spi_config *config) {
int ret;

const struct spi_buf tx_buf = {.buf = buf, .len = len};
const struct spi_buf_set tx_buf_set = {
.buffers = &tx_buf,
.count = 1,
};

const struct spi_buf rx_buf = {.buf = buf, .len = len};
const struct spi_buf_set rx_buf_set = {
.buffers = &rx_buf,
.count = 1,
};

return spi_transceive(spi_dev, config, &tx_buf_set, &rx_buf_set);
}

void arduino::ZephyrSPI::usingInterrupt(int interruptNumber) {
interrupt[interrupt_pos++] = interruptNumber;
}

void arduino::ZephyrSPI::notUsingInterrupt(int interruptNumber) {
for (size_t i = 0; i < interrupt_pos; ++i) {
if (interrupt[i] == interruptNumber) {
memmove(&interrupt[i], &interrupt[i + 1], interrupt_pos - i - 1);
interrupt_pos--;
break;
}
}
}

void arduino::ZephyrSPI::beginTransaction(SPISettings settings) {
memset(&config, 0, sizeof(config));
config.frequency = settings.getClockFreq();
config.operation = ((settings.getBitOrder() ^ 1) << 4) |
(settings.getDataMode() << 1) | ((SPCR >> MSTR) & 1) |
SPI_WORD_SET(8);

detachInterrupt();
uint32_t mode = SPI_HOLD_ON_CS;

// Set bus mode
switch (settings.getBusMode()) {
case SPI_CONTROLLER:
break;
case SPI_PERIPHERAL:
mode |= SPI_OP_MODE_SLAVE;
break;
}

// Set data format
switch (settings.getBitOrder()) {
case LSBFIRST:
mode |= SPI_TRANSFER_LSB;
break;
case MSBFIRST:
mode |= SPI_TRANSFER_MSB;
break;
}

// Set data mode
switch (settings.getDataMode()) {
case SPI_MODE0:
break;
case SPI_MODE1:
mode |= SPI_MODE_CPHA;
break;
case SPI_MODE2:
mode |= SPI_MODE_CPOL;
break;
case SPI_MODE3:
mode |= SPI_MODE_CPOL | SPI_MODE_CPHA;
break;
}

// Set SPI configuration structure for 8-bit transfers
memset(&config, 0, sizeof(struct spi_config));
config.operation = mode | SPI_WORD_SET(8);
config.frequency = max(SPI_MIN_CLOCK_FREQUENCY, settings.getClockFreq());

// Set SPI configuration structure for 16-bit transfers
memset(&config16, 0, sizeof(struct spi_config));
config16.operation = mode | SPI_WORD_SET(16);
config16.frequency = max(SPI_MIN_CLOCK_FREQUENCY, settings.getClockFreq());
}

void arduino::ZephyrSPI::endTransaction(void) {
spi_release(spi_dev, &config);
attachInterrupt();
spi_release(spi_dev, &config);
}

void arduino::ZephyrSPI::attachInterrupt() {
for (size_t i = 0; i < interrupt_pos; ++i) {
enableInterrupt(interrupt[i]);
}
}

void arduino::ZephyrSPI::detachInterrupt() {
for (size_t i = 0; i < interrupt_pos; ++i) {
disableInterrupt(interrupt[i]);
}
}
Comment on lines 111 to 115
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attachInterrupt() / detachInterrupt() are now empty, so any interrupts registered via usingInterrupt() will never be enabled/disabled around SPI transactions. If interrupt masking is still intended to be supported for Arduino compatibility, restore the previous loop calling enableInterrupt()/disableInterrupt() (or document why this is intentionally a no-op).

Copilot uses AI. Check for mistakes.

void arduino::ZephyrSPI::begin() {}
void arduino::ZephyrSPI::begin() {
}

void arduino::ZephyrSPI::end() {}
void arduino::ZephyrSPI::end() {
}

#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), spis)
#if (DT_PROP_LEN(DT_PATH(zephyr_user), spis) > 1)
Expand Down
58 changes: 36 additions & 22 deletions libraries/SPI/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,63 @@
#include <api/HardwareSPI.h>
#include <zephyr/drivers/spi.h>

#undef SPI
#undef SPI1

#define SPR0 0
#define SPR1 1
#define CPHA 2
#define CPOL 3
#define MSTR 4
#define DORD 5
#define SPE 6
#define SPE 6
#define SPIE 7

#define SPI_HAS_PERIPHERAL_MODE (1)

// TODO:
// This depends on the clock settings, can't be used for all boards.
#ifndef SPI_MIN_CLOCK_FREQUENCY
#define SPI_MIN_CLOCK_FREQUENCY 1000000
#endif

/* Count the number of GPIOs for limit of number of interrupts */
#define INTERRUPT_HELPER(n, p, i) 1
#define INTERRUPT_COUNT \
DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, \
#define INTERRUPT_COUNT \
DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, \
INTERRUPT_HELPER, (+))

namespace arduino {
class ZephyrSPI : public HardwareSPI {
public:
ZephyrSPI(const struct device *spi);
ZephyrSPI(const struct device *spi);

virtual uint8_t transfer(uint8_t data);
virtual uint16_t transfer16(uint16_t data);
virtual void transfer(void *buf, size_t count);
virtual uint8_t transfer(uint8_t data);
virtual uint16_t transfer16(uint16_t data);
virtual void transfer(void *buf, size_t count);

// Transaction Functions
virtual void usingInterrupt(int interruptNumber);
virtual void notUsingInterrupt(int interruptNumber);
virtual void beginTransaction(SPISettings settings);
virtual void endTransaction(void);
// Transaction Functions
virtual void usingInterrupt(int interruptNumber);
virtual void notUsingInterrupt(int interruptNumber);
virtual void beginTransaction(SPISettings settings);
virtual void endTransaction(void);

// SPI Configuration methods
virtual void attachInterrupt();
virtual void detachInterrupt();
// SPI Configuration methods
virtual void attachInterrupt();
virtual void detachInterrupt();

virtual void begin();
virtual void end();
virtual void begin();
virtual void end();

private:
const struct device *spi_dev;
struct spi_config config;
int interrupt[INTERRUPT_COUNT];
size_t interrupt_pos = 0;
int transfer(void *buf, size_t len, const struct spi_config *config);

protected:
const struct device *spi_dev;
struct spi_config config;
struct spi_config config16;
int interrupt[INTERRUPT_COUNT];
size_t interrupt_pos = 0;
};

} // namespace arduino
Expand All @@ -75,7 +90,6 @@ extern arduino::ZephyrSPI SPI;
#endif

/* Serial Peripheral Control Register */
extern uint8_t SPCR;

using arduino::SPI_MODE0;
using arduino::SPI_MODE1;
Expand Down
Loading
Loading