diff --git a/rpi_spi/2023-12-29_pi-spi-rates.md b/rpi_spi/2023-12-29_pi-spi-rates.md index b4114ad6b840ce87ba71df1cd4754e447e9921b8..59c5b2fa21c888c93553b7fcfc306f6be5ddc41f 100644 --- a/rpi_spi/2023-12-29_pi-spi-rates.md +++ b/rpi_spi/2023-12-29_pi-spi-rates.md @@ -81,4 +81,8 @@ 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... + +There's another oddity in here... the RP2040 only uses SPI framing where the CS line is pulsed per frame (7-16 bits), so we need to handle it in software, though IDK exactly how to do this as a peripheral, though apparently [this lad](https://github.com/raspberrypi/pico-sdk/issues/88#issuecomment-1402204730) found [a workaround?](https://github.com/uwopus/pico-code/blob/3594e67c1ac34e5454eb4db8362b673bcc7c8862/opus_comms/opus_comms.c#L44-L46) which references 4.4.3.13 \ 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 0000000000000000000000000000000000000000..9ff9e8d48bc2dfcf6cb5e7741c9333373e285921 --- /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 0000000000000000000000000000000000000000..91fb08f0bd738345349813ee51aec5739694a9f9 --- /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 0000000000000000000000000000000000000000..1079bb86a959b08bdca022323aca275175e20372 --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino @@ -0,0 +1,30 @@ +#include "spipi.h" +#include "screen.h" + +// using a (basically raspberry pi pico) W5500-EVB-Pico +// with earle philhower core + +void setup(void){ + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // the display setup + displaySetup(); + + // the spi setup + spipi_begin(); +} + +uint32_t lastUpdate = 0; +uint32_t updateInterval = 200; + +void loop(void){ + if(lastUpdate + updateInterval < millis()){ + lastUpdate = millis(); + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); + displayPrint(spipi_print()); + // displayPrint(String(rxCount) + "\n" + + // String(rxSize) + // ); + } +} \ 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 0000000000000000000000000000000000000000..8dd0e27eb3ec6bdf81002c9f8eb1f0a30d58ba4e --- /dev/null +++ b/rpi_spi/code/spi_peripheral_bare/spipi.cpp @@ -0,0 +1,123 @@ +#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_DEBUG 1 + +#define PIN_CS 13 +#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) + +// some static buffs +uint8_t rxBuffer[255]; +volatile uint8_t rxPtr = 0; + +String spipi_print(void){ + return String(rxBuffer[0]) + ", " + String(rxBuffer[1]); +} + +uint8_t txBuffer[255]; +volatile uint8_t txPtr = 0; +volatile uint8_t txLen = 32; + +// we catch rising edges to delineate packet-end +void spipi_gpio_irq_handler(uint gpio, uint32_t events){ + if(gpio_get(PIN_CS)){ + txPtr = 0; + rxPtr = 0; + // gpio_put(PIN_DEBUG, !gpio_get_out_level(PIN_DEBUG)); + } +} + +void spipi_irq_handler(void){ + gpio_put(PIN_DEBUG, !gpio_get_out_level(PIN_DEBUG)); + // both have up to 8 bytes to read / write per interrupt ? + // get bytes while readable, + for(uint8_t c = 0; c < 8; c ++){ + if(spi_is_readable(SPI_INST) && rxPtr < txLen){ + rxBuffer[rxPtr] = SPI_HW->dr; + rxPtr ++; + } + } + // write bytes while writable + for(uint8_t c = 0; c < 8; c ++){ + if(spi_is_writable(SPI_INST) && txPtr < txLen){ + SPI_HW->dr = txBuffer[txPtr]; + txPtr ++; + } + } + // rx + // 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; +} + + +void spipi_begin(void){ + // dummy pin + gpio_init(PIN_DEBUG); + gpio_set_dir(PIN_DEBUG, GPIO_OUT); + + // dummy buffer + for(uint8_t i = 0; i < 255; i ++){ + txBuffer[i] = i; + } + + // 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, true, &spipi_gpio_irq_handler); + // gpio_set_input_hysteresis_enabled(PIN_CS, false); + + // 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); + // oddity where mode 0b11 allow continuous CS_LOW ? + // that's right, folks, we can only do this with 0b11 mode, insane: + // see https://github.com/raspberrypi/pico-sdk/issues/88#issuecomment-1402204730 + // and see RP2040 datasheet at 4.4.3.13 ! + spi_set_format(SPI_INST, 8, SPI_CPOL_1, SPI_CPHA_1, 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 + SPI_HW->imsc = SPI_IMSC_RXIM_ON | SPI_IMSC_TXIM_ON; + irq_set_exclusive_handler(SPI1_IRQ, &spipi_irq_handler); + irq_set_enabled(SPI1_IRQ, true); +} 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 0000000000000000000000000000000000000000..d941fcb287feef342f3372830ca96b52e4f011cc --- /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); +String spipi_print(void); + +#endif \ No newline at end of file