From d44174f372a80c5cd2420b682a2a0071ca336782 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 1 May 2024 22:33:22 +0200 Subject: [PATCH 1/3] Add SPI primitives --- platforms/Zephyr/prj.conf | 2 + src/Primitives/zephyr.cpp | 88 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/platforms/Zephyr/prj.conf b/platforms/Zephyr/prj.conf index 841702f5..da5f292a 100644 --- a/platforms/Zephyr/prj.conf +++ b/platforms/Zephyr/prj.conf @@ -24,6 +24,8 @@ CONFIG_UART_ASYNC_API=n CONFIG_UART_WIDE_DATA=y CONFIG_UART_USE_RUNTIME_CONFIGURE=y +CONFIG_SPI=y + CONFIG_CONSOLE_SUBSYS=y CONFIG_CONSOLE_GETCHAR=y CONFIG_CONSOLE_GETCHAR_BUFSIZE=4096 diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index ad1df59f..ca7efbfe 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,14 @@ def_prim(chip_delay, oneToNoneU32) { return true; } +def_prim(chip_delay_us, oneToNoneU32) { + debug("chip_delay_us(%u)\n", arg0.uint32); + k_yield(); + k_usleep(arg0.uint32); + pop_args(1); + return true; +} + struct gpio_dt_spec specs[] = {DT_FOREACH_PROP_ELEM_SEP( DT_PATH(zephyr_user), warduino_gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))}; @@ -82,7 +91,7 @@ def_prim(chip_pin_mode, twoToNoneU32) { std::unordered_map io_map; def_prim(chip_digital_write, twoToNoneU32) { - printf("chip_digital_write(%u,%u)\n", arg1.uint32, arg0.uint32); + debug("chip_digital_write(%u,%u)\n", arg1.uint32, arg0.uint32); gpio_dt_spec pin_spec = specs[arg1.uint32]; gpio_pin_set_raw(pin_spec.port, pin_spec.pin, arg0.uint32); io_map[arg1.uint32] = arg0.uint32; @@ -114,7 +123,7 @@ def_prim_reverse(chip_digital_write) { } def_prim(chip_digital_read, oneToOneU32) { - printf("chip_digital_read(%u)\n", arg0.uint32); + debug("chip_digital_read(%u)\n", arg0.uint32); gpio_dt_spec pin_spec = specs[arg0.uint32]; uint8_t res = gpio_pin_get_raw(pin_spec.port, pin_spec.pin); pop_args(1); @@ -377,12 +386,83 @@ def_prim(ev3_touch_sensor, oneToOneU32) { #endif +const struct device *const spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi0)); + +int write_spi_bytes(unsigned char *data, size_t len) { + if (!device_is_ready(spi_dev)) { + printk("%s: device not ready.\n", spi_dev->name); + return -1; + } + + struct spi_buf tx_buf = { .buf = data, .len = len }; + struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + + // Now write the buffer using SPI. + struct spi_config config; + config.frequency = DT_PROP(DT_NODELABEL(spi0), clock_frequency); + config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); + config.slave = 0; + config.cs = {}; + + return spi_write(spi_dev, &config, &tx_bufs); +} + +int write_spi_bytes_16_prim(int times, unsigned int color) { + unsigned char *data = new unsigned char[times * 2]; + unsigned char colorB = color >> 8; + for (int x = 0; x < times; x++) { + data[x * 2] = color; + data[x * 2 + 1] = colorB; + } + + int result = write_spi_bytes(data, times * 2); + delete[] data; + return result; +} + +def_prim(write_spi_byte, oneToNoneU32) { + debug("write_spi_byte(%d)\n", arg0.uint32); + unsigned char data = (char) arg0.uint32; + int result = write_spi_bytes(&data, 1); + pop_args(1); + return result == 0; +} + +def_prim(write_spi_bytes_16, twoToNoneU32) { + debug("write_spi_bytes_16(%d, %d)\n", arg1.uint32, arg0.uint32); + int result = write_spi_bytes_16_prim(arg1.uint32, arg0.uint32); + pop_args(2); + return result == 0; +} + +def_prim(read_spi_byte, NoneToOneU32) { + debug("read_spi_byte(%u)\n", arg0.uint32); + struct spi_config config; + + config.frequency = DT_PROP(DT_NODELABEL(spi0), clock_frequency); + config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(9); + config.slave = 0; + config.cs = {}; // TODO: Chip select line, maybe useful or can we do it manually not sure + + unsigned char data = 0; + struct spi_buf tx_buf = { .buf = &data, .len = 1 }; + struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + + printf("data= %c\n", data); + + int result = spi_read(spi_dev, &config, &tx_bufs); + printf("result= %d\n", result); + pushInt32(0); + return true; +} + //------------------------------------------------------ // Installing all the primitives //------------------------------------------------------ void install_primitives(Interpreter *interpreter) { dbg_info("INSTALLING PRIMITIVES\n"); install_primitive(chip_delay); + install_primitive(chip_delay_us); install_primitive(chip_pin_mode); install_reversible_primitive(chip_digital_write); install_primitive(chip_digital_read); @@ -405,6 +485,10 @@ void install_primitives(Interpreter *interpreter) { k_timer_init(&heartbeat_timer, heartbeat_timer_func, nullptr); k_timer_start(&heartbeat_timer, K_MSEC(500), K_MSEC(500)); #endif + + install_primitive(write_spi_byte); + install_primitive(write_spi_bytes_16); + install_primitive(read_spi_byte); } Memory external_mem = {0, 0, 0, nullptr}; From ad4742707a21c031837533b61c2730ce9bc74c39 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Mon, 16 Feb 2026 17:36:49 +0100 Subject: [PATCH 2/3] clang-format --- src/Primitives/zephyr.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index ca7efbfe..8c25ddb6 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -17,9 +17,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -394,8 +394,8 @@ int write_spi_bytes(unsigned char *data, size_t len) { return -1; } - struct spi_buf tx_buf = { .buf = data, .len = len }; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf tx_buf = {.buf = data, .len = len}; + struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1}; // Now write the buffer using SPI. struct spi_config config; @@ -422,7 +422,7 @@ int write_spi_bytes_16_prim(int times, unsigned int color) { def_prim(write_spi_byte, oneToNoneU32) { debug("write_spi_byte(%d)\n", arg0.uint32); - unsigned char data = (char) arg0.uint32; + unsigned char data = (char)arg0.uint32; int result = write_spi_bytes(&data, 1); pop_args(1); return result == 0; @@ -442,11 +442,12 @@ def_prim(read_spi_byte, NoneToOneU32) { config.frequency = DT_PROP(DT_NODELABEL(spi0), clock_frequency); config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(9); config.slave = 0; - config.cs = {}; // TODO: Chip select line, maybe useful or can we do it manually not sure + config.cs = {}; // TODO: Chip select line, maybe useful or can we do it + // manually not sure unsigned char data = 0; - struct spi_buf tx_buf = { .buf = &data, .len = 1 }; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 }; + struct spi_buf tx_buf = {.buf = &data, .len = 1}; + struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1}; printf("data= %c\n", data); From ecd8079d513c01ba4a7580740d34e218710f8ec2 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Tue, 17 Feb 2026 15:02:35 +0100 Subject: [PATCH 3/3] Use Big-Endian for sending data over SPI --- src/Primitives/zephyr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Primitives/zephyr.cpp b/src/Primitives/zephyr.cpp index 8c25ddb6..76945c4b 100644 --- a/src/Primitives/zephyr.cpp +++ b/src/Primitives/zephyr.cpp @@ -400,7 +400,7 @@ int write_spi_bytes(unsigned char *data, size_t len) { // Now write the buffer using SPI. struct spi_config config; config.frequency = DT_PROP(DT_NODELABEL(spi0), clock_frequency); - config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8); + config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB; config.slave = 0; config.cs = {}; @@ -411,8 +411,10 @@ int write_spi_bytes_16_prim(int times, unsigned int color) { unsigned char *data = new unsigned char[times * 2]; unsigned char colorB = color >> 8; for (int x = 0; x < times; x++) { - data[x * 2] = color; - data[x * 2 + 1] = colorB; + // Most SPI devices expect Big-Endian data, so we first write the most + // significant byte. + data[x * 2 + 1] = color; + data[x * 2] = colorB; } int result = write_spi_bytes(data, times * 2);