aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Mignot <victor@vmignot.fr>2026-02-02 20:20:08 +0100
committerVictor Mignot <victor@vmignot.fr>2026-02-06 14:50:37 +0100
commit719538162cd390963b3ac8f2965a3e6546162b3b (patch)
tree6a291ffdb67cb530ce42b2c3af0d5f4e67cd8dc8
parentf19ca61f48710fab019f39bb87bf6fb15f4ae7da (diff)
downloadnanji-719538162cd390963b3ac8f2965a3e6546162b3b.tar.gz
[WIP] nrf52832: add interface for SPI Master devices
-rw-r--r--src/spi.c125
-rw-r--r--src/spi.h45
2 files changed, 170 insertions, 0 deletions
diff --git a/src/spi.c b/src/spi.c
new file mode 100644
index 0000000..8acbf19
--- /dev/null
+++ b/src/spi.c
@@ -0,0 +1,125 @@
+#include "spi.h"
+#include "gpio.h"
+#include "register.h"
+
+#define WRITE_SPI_REG(spi, reg, value) (WRITE_REGISTER(spi_base_addresses[spi], reg, value))
+#define READ_SPI_REG(spi, reg) (READ_REGISTER(spi_base_addresses[spi], reg))
+
+enum spi_register {
+ TASKS_START = 0x10,
+ TASKS_STOP = 0x14,
+ TASKS_SUSPEND = 0x1c,
+ TASKS_RESUME = 0x20,
+ EVENTS_STOPPED = 0x104,
+ EVENTS_ENDRX = 0x110,
+ EVENTS_END = 0x118,
+ EVENTS_ENDTX = 0x120,
+ EVENTS_STARTED = 0x14c,
+ SHORTS = 0x200,
+ INTENSET = 0x304,
+ INTENCLR = 0x308,
+ ENABLE = 0x500,
+ PSEL_SCK = 0x508,
+ PSEL_MOSI = 0x50c,
+ PSEL_MISO = 0x510,
+ FREQUENCY = 0x524,
+ RXD_PTR = 0x534,
+ RXD_MAXCNT = 0x538,
+ RXD_AMOUNT = 0x53c,
+ RXD_LIST = 0x540,
+ TXD_PTR = 0x544,
+ TXD_MAXCNT = 0x548,
+ TXD_AMOUNT = 0x54c,
+ TXD_LIST = 0x550,
+ CONFIG = 0x544,
+ ORC = 0x5c0,
+};
+
+static const hwaddr spi_base_addresses[] = {
+ [SPI_0] = 0x40003000,
+ [SPI_1] = 0x40004000,
+ [SPI_2] = 0x40023000,
+};
+
+static const u32 frequency_register_values[] = {
+ [K125] = 0x02000000,
+ [K250] = 0x04000000,
+ [K500] = 0x08000000,
+ [M1] = 0x10000000,
+ [M2] = 0x20000000,
+ [M4] = 0x40000000,
+ [M8] = 0x80000000,
+};
+
+void spi_master_init(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso, enum spi_bits_order order, enum spi_clock_polarity polarity, enum spi_clock_phase phase, enum spi_frequency frequency, char overread_char) {
+ /* Setup GPIO pins */
+ gpio_output_pin_init(clock, S0S1);
+ WRITE_SPI_REG(spi, PSEL_SCK, (0xffffffff >> 1) & (0xffffffe0 | clock));
+ gpio_output_pin_init(mosi, S0S1);
+ WRITE_SPI_REG(spi, PSEL_MOSI, (0xffffffff >> 1) & (0xffffffe0 | mosi));
+ gpio_input_pin_init(miso, PULL_DOWN, HIGH);
+ WRITE_SPI_REG(spi, PSEL_MISO, (0xffffffff >> 1) & (0xffffffe0 | miso));
+
+ /* Configure communication behaviour */
+ u32 spi_config = 0x0;
+ spi_config |= order;
+ spi_config |= phase << 1;
+ spi_config |= polarity << 2;
+ WRITE_SPI_REG(spi, CONFIG, spi_config);
+
+ WRITE_SPI_REG(spi, RXD_MAXCNT, MAX_TRANSFER_SIZE);
+ WRITE_SPI_REG(spi, TXD_MAXCNT, MAX_TRANSFER_SIZE);
+ WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[frequency]);
+ WRITE_SPI_REG(spi, ORC, overread_char);
+
+ /* Enable SPI Master */
+ WRITE_SPI_REG(spi, ENABLE, 0x7);
+}
+
+u8 spi_master_transfer(enum spi_interface spi, u8 tx_size, u8 tx[], u8 rx_size, u8 rx[]) {
+ u32 events_started_reg = 0;
+ u32 events_end_reg = 0;
+
+ WRITE_SPI_REG(spi, RXD_MAXCNT, rx_size & 0xff);
+ WRITE_SPI_REG(spi, TXD_MAXCNT, tx_size & 0xff);
+ WRITE_SPI_REG(spi, RXD_PTR, (hwaddr) rx);
+ WRITE_SPI_REG(spi, TXD_PTR, (hwaddr) tx);
+
+ WRITE_SPI_REG(spi, TASKS_START, 0x1);
+ do {
+ events_started_reg = READ_SPI_REG(spi, EVENTS_STARTED);
+ } while (events_started_reg == 0);
+
+ do {
+ events_end_reg = READ_SPI_REG(spi, EVENTS_END);
+ } while (events_end_reg == 0);
+
+ return 0;
+}
+
+void spi_master_stop(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso) {
+ u32 events_stopped_reg = 0;
+
+ WRITE_SPI_REG(spi, TASKS_STOP, 0x1);
+ do {
+ events_stopped_reg = READ_SPI_REG(spi, EVENTS_STOPPED);
+ } while (events_stopped_reg == 0);
+
+ /* Disable SPI*/
+ WRITE_SPI_REG(spi, ENABLE, 0x0);
+
+ /* Set configuration registers to reset values */
+ WRITE_SPI_REG(spi, CONFIG, 0x0);
+ WRITE_SPI_REG(spi, RXD_MAXCNT, 0x0);
+ WRITE_SPI_REG(spi, TXD_MAXCNT, 0x0);
+ WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[K250]);
+ WRITE_SPI_REG(spi, ORC, 0x0);
+
+ /* Free GPIO pins */
+ WRITE_SPI_REG(spi, PSEL_SCK, 0xffffffff);
+ gpio_pin_disable(clock);
+ WRITE_SPI_REG(spi, PSEL_MOSI, 0xffffffff);
+ gpio_pin_disable(mosi);
+ WRITE_SPI_REG(spi, PSEL_MISO, 0xffffffff);
+ gpio_pin_disable(miso);
+}
diff --git a/src/spi.h b/src/spi.h
new file mode 100644
index 0000000..b076bcb
--- /dev/null
+++ b/src/spi.h
@@ -0,0 +1,45 @@
+#ifndef SPI_H
+#define SPI_H
+
+#include "gpio.h"
+
+#define MAX_TRANSFER_SIZE 256
+
+enum spi_interface {
+ SPI_0,
+ SPI_1,
+ SPI_2,
+};
+
+enum spi_frequency {
+ K125,
+ K250,
+ K500,
+ M1,
+ M2,
+ M4,
+ M8,
+};
+
+enum spi_clock_polarity {
+ ACTIVE_HIGH = 0,
+ ACTIVE_LOW = 1,
+};
+
+enum spi_clock_phase {
+ LEADING = 0,
+ TRAILING = 1,
+};
+
+enum spi_bits_order {
+ MSB_FIRST = 0,
+ LSB_FIRST = 0,
+};
+
+void spi_master_init(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso, enum spi_bits_order order, enum spi_clock_polarity polarity, enum spi_clock_phase phase, enum spi_frequency frequency, char overread_char);
+
+u8 spi_master_transfer(enum spi_interface spi, u8 tx_size, u8 tx[], u8 rx_size, u8 rx[]);
+
+void spi_master_stop(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso);
+
+#endif