From 677bd44b91a029eae3b34a29be8393b223851505 Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Sat, 30 Dec 2023 00:26:50 -0500 Subject: [PATCH] register hell, but we can detect pin edges now --- rpi_spi/2023-12-29_pi-spi-rates.md | 4 +- rpi_spi/code/spi_peripheral_bare/screen.cpp | 42 +++++++ rpi_spi/code/spi_peripheral_bare/screen.h | 9 ++ .../spi_peripheral_bare.ino | 85 +++++++++++++ rpi_spi/code/spi_peripheral_bare/spipi.cpp | 112 ++++++++++++++++++ rpi_spi/code/spi_peripheral_bare/spipi.h | 9 ++ 6 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 rpi_spi/code/spi_peripheral_bare/screen.cpp create mode 100644 rpi_spi/code/spi_peripheral_bare/screen.h create mode 100644 rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino create mode 100644 rpi_spi/code/spi_peripheral_bare/spipi.cpp create mode 100644 rpi_spi/code/spi_peripheral_bare/spipi.h diff --git a/rpi_spi/2023-12-29_pi-spi-rates.md b/rpi_spi/2023-12-29_pi-spi-rates.md index b4114ad..cc1acd0 100644 --- a/rpi_spi/2023-12-29_pi-spi-rates.md +++ b/rpi_spi/2023-12-29_pi-spi-rates.md @@ -81,4 +81,6 @@ We are normally pulling one byte at a time - if we want to be catching while we OK, so to see if we can get up to that 10Mbit real-transfer-rate target, I think I will start with an echo test - since SPI is transfer-based anyways (we always send data when we get it), I'll program some arduino to get packets and echo them, and we'll turn the speed up until we start making mistakes. -I have hello-worlded this with the Earle Core, but their SPI implementation is strange - since it's simple enough (I'm starting to see that... that's the pint), I'll just roll my own... listening to CS down / up interrupts to frame packets, stuffing buffers, you know the dealio. It's 730pm here but that's just time to put the embedded hardo hat on... \ No newline at end of file +I have hello-worlded this with the Earle Core, but their SPI implementation is strange - since it's simple enough (I'm starting to see that... that's the pint), I'll just roll my own... listening to CS down / up interrupts to frame packets, stuffing buffers, you know the dealio. It's 730pm here but that's just time to put the embedded hardo hat on... + +I'm going a bit mad with this; I can get GPIO interrupts to fire *just on a falling edge* but not *just on a rising edge* ... I should see if I can access some lower level masks, or something? But it's genuinely sending events *marked* as *rising edge* events on falling and rising edges... \ No newline at end of file diff --git a/rpi_spi/code/spi_peripheral_bare/screen.cpp b/rpi_spi/code/spi_peripheral_bare/screen.cpp new file mode 100644 index 0000000..9ff9e8d --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/screen.cpp @@ -0,0 +1,42 @@ +#include "screen.h" +#include <Adafruit_GFX.h> +#include <Adafruit_SSD1306.h> +#include <Wire.h> + +// OLED +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels + +#define X_POS 0 +#define Y_POS 0 +#define TXT_SIZE 1 + +// even for displays with i.e. "0x78" printed on the back, +// the address that works is 0x3C, IDK +#define SCREEN_ADDRESS 0x3C + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1); + +// warning: is blocking, takes ~ 33ms ! +void displayPrint(String msg){ + display.clearDisplay(); + display.setCursor(X_POS, Y_POS); + display.print(msg); + display.display(); +} + +void displaySetup(void){ + Wire1.setSDA(2); + Wire1.setSCL(3); + + // initialize the screen, + // oddly, SWITCHCAPVCC is the option that works even though OLED is hooked to 5V + display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS); + display.clearDisplay(); + display.display(); + display.setTextColor(SSD1306_WHITE); + display.setTextSize(TXT_SIZE); + display.setTextWrap(true); + display.dim(false); + displayPrint("bonjour..."); +} \ No newline at end of file diff --git a/rpi_spi/code/spi_peripheral_bare/screen.h b/rpi_spi/code/spi_peripheral_bare/screen.h new file mode 100644 index 0000000..91fb08f --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/screen.h @@ -0,0 +1,9 @@ +#ifndef SCREEN_H_ +#define SCREEN_H_ + +#include <Arduino.h> + +void displaySetup(void); +void displayPrint(String msg); + +#endif \ No newline at end of file diff --git a/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino b/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino new file mode 100644 index 0000000..2bdb72f --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino @@ -0,0 +1,85 @@ +#include "spipi.h" +#include "screen.h" + +// using a (basically raspberry pi pico) W5500-EVB-Pico +// with earle philhower core + +#define PIN_DEBUG 1 + +// SPI +// SPISettings settings(1000000, MSBFIRST, SPI_MODE0); + +uint8_t txBuffer[1024]; +volatile uint32_t rxCount = 0; +volatile uint32_t rxSize = 0; + +// fires when we get data, I presume ? +// byte rxBuffer[1024]; +// this *is unrelated to the CS pin* but should be ! +// it actually fires basically every data chunk... +// void onRx(uint8_t* data, size_t len){ +// // actually, for the echo we can copy +// // directly across, non ? +// // digitalWrite(PIN_DEBUG, HIGH); +// // memcpy(txBuffer, data, len); +// rxCount ++; +// if(len > rxSize) rxSize = len; + +// // shifty shifty +// // digitalWrite(PIN_DEBUG, LOW); +// } + +// fires at the end of a transaction ? +// void onTxComplete(void){ +// SPISlave1.setData((uint8_t*)txBuffer, 32); +// digitalWrite(PIN_DEBUG, !digitalRead(PIN_DEBUG)); +// } + +void setup(void){ + // a debug light and pin, + pinMode(PIN_DEBUG, OUTPUT); + digitalWrite(PIN_DEBUG, LOW); + + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // the display setup + displaySetup(); + + // the spi setup + spipi_begin(); + + // fill our demo buffer + for(uint16_t i = 0; i < 1024; i ++){ + txBuffer[i] = i; + } + + // SPISlave1.setData((uint8_t*)txBuffer, 32); + + // // pin config (2040 GPIO Nums) + // SPISlave1.setCS(13); + // SPISlave1.setSCK(10); + // SPISlave1.setRX(12); + // SPISlave1.setTX(11); + + // // callbacks + // SPISlave1.onDataRecv(onRx); + // SPISlave1.onDataSent(onTxComplete); + + // // startup + // SPISlave1.begin(settings); +} + +uint32_t lastUpdate = 0; +uint32_t updateInterval = 200; + +void loop(void){ + if(lastUpdate + updateInterval < millis()){ + lastUpdate = millis(); + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); + displayPrint(String(rxCount) + "\n" + + String(rxSize) + "\n" + + String(spipi_get_events()) + ); + } +} \ No newline at end of file diff --git a/rpi_spi/code/spi_peripheral_bare/spipi.cpp b/rpi_spi/code/spi_peripheral_bare/spipi.cpp new file mode 100644 index 0000000..0b06d2b --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/spipi.cpp @@ -0,0 +1,112 @@ +#include "spipi.h" +#include <hardware/spi.h> +#include <hardware/gpio.h> + +// the relevant functions are here: +// /jaker/AppData/Local/Arduino15/packages/rp2040/3.6.1/pico-sdk/src/ ... +// /rp2040/rp2_common/hardware_spi/include/hardware/spi.h + +// the registers we're interested in here: +// /jaker/AppData/Local/Arduino15/packages/rp2040/3.6.1/pico-sdk/src/ ... +// /rp2040/hardware_structs/include/hardware/structs/spi.h + +// for earle code reference, +// /jaker/AppData/Local/Arduino15/packages/rp2040/3.6.1/libraries/ ... +// /SPISlave/src/SPISlave.cpp (etc) + +// for gpio, +// /jaker/AppData/Local/Arduino15/packages/rp2040/3.6.1/pico-sdk/src/ ... +// /rp2040/rp2_common/hardware_gpio/include/hardware/gpio.h + + +#define PIN_CS 14 +#define PIN_SCK 10 +#define PIN_RX 12 +#define PIN_TX 11 + +#define BITRATE 1000000 + +#define SPI_INST spi1 +#define SPI_HW spi_get_hw(SPI_INST) + +#define SPI_IMSC_TXIM_ON (1 << 3) +#define SPI_IMSC_RXIM_ON (1 << 2) +#define SPI_IMSC_RTIM_ON (1 << 1) +#define SPI_IMSC_RORIM_ON (1) + + + +volatile uint32_t event_latest = 12; +uint32_t spipi_get_events(void){ + return event_latest; +} + +// we catch rising edges to delineate packet-end +void spipi_gpio_irq_handler(uint gpio, uint32_t events){ + if(gpio_get(PIN_CS)){ + gpio_put(1, !gpio_get_out_level(1)); + } + // event_latest = events; + // if(events & GPIO_IRQ_EDGE_RISE){ + // gpio_put(1, !gpio_get_out_level(1)); + // } else if (events & GPIO_IRQ_EDGE_FALL){ + // // gpio_put(1, !gpio_get_out_level(1)); + // } +} + + +// void spipi_gpio_raw_handler(void){ +// gpio_put(1, !gpio_get_out_level(1)); +// if(gpio_get_irq_event_mask(PIN_CS) & GPIO_IRQ_EDGE_RISE){ +// gpio_acknowledge_irq(PIN_CS, GPIO_IRQ_EDGE_RISE); +// gpio_put(1, !gpio_get_out_level(1)); +// } +// } + + +void spipi_begin(void){ + // uh ? + gpio_init(PIN_CS); + gpio_set_dir(PIN_CS, GPIO_IN); + + // let's actually just get the CS LOW/HI interrupt first, + // so we can reset our buffer states (etc) + // gpio_set_irq_enabled_with_callback(PIN_CS, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &spipi_gpio_irq_handler); + gpio_set_irq_enabled_with_callback(PIN_CS, GPIO_IRQ_EDGE_RISE, true, &spipi_gpio_irq_handler); + // gpio_set_input_hysteresis_enabled(PIN_CS, false); + + // or this simpler handler-thing ? + // gpio_set_irq_enabled(PIN_CS, GPIO_IRQ_EDGE_RISE, true); + // gpio_add_raw_irq_handler(PIN_CS, &spipi_gpio_raw_handler); + + // startup the peripheral ? + // spi_init(SPI_INST, BITRATE); + // spi_set_slave(SPI_INST, true); + // spi_set_format(SPI_INST, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); + + // assign pins to SPI peripheral, + // gpio_set_function(PIN_CS, GPIO_FUNC_SPI); + // gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); + // gpio_set_function(PIN_RX, GPIO_FUNC_SPI); + // gpio_set_function(PIN_TX, GPIO_FUNC_SPI); + + // hook up our (one?) interrupt... + // NOTE: changing SPI_INST requires hard-coded change here + // irq_set_exclusive_handler(SPI1_IRQ, spipi_irq_handler); +} + + +// void spipi_irq_handler(void){ +// // both have up to 8 bytes to read / write per interrupt ? +// // get bytes while readable, +// if(spi_is_readable(SPI_INST)){ +// uint8_t byte = SPI_HW->dr; +// } +// // write bytes while writable +// if(spi_is_writable(SPI_INST)){ +// SPI_HW->dr = 85; +// } +// // if we're out of data, we could turn interrupts off w/ this: +// // i.e. *just* turning the RX-interrupt on... ?? +// SPI_HW->imsc = 0 | SPI_IMSC_RXIM_ON; +// } diff --git a/rpi_spi/code/spi_peripheral_bare/spipi.h b/rpi_spi/code/spi_peripheral_bare/spipi.h new file mode 100644 index 0000000..6c97915 --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/spipi.h @@ -0,0 +1,9 @@ +#ifndef SPI_PI_H_ +#define SPI_PI_H_ + +#include <Arduino.h> + +void spipi_begin(void); +uint32_t spipi_get_events(void); + +#endif \ No newline at end of file -- GitLab