From ffc164c25f65a74cdddb89f91101f710e6a5f778 Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Sat, 30 Dec 2023 01:23:36 -0500 Subject: [PATCH] defeat spi-oddity, transmit and rx data --- rpi_spi/2023-12-29_pi-spi-rates.md | 4 +- .../spi_peripheral_bare.ino | 63 +---------- rpi_spi/code/spi_peripheral_bare/spipi.cpp | 105 ++++++++++-------- rpi_spi/code/spi_peripheral_bare/spipi.h | 2 +- 4 files changed, 66 insertions(+), 108 deletions(-) diff --git a/rpi_spi/2023-12-29_pi-spi-rates.md b/rpi_spi/2023-12-29_pi-spi-rates.md index cc1acd0..59c5b2f 100644 --- a/rpi_spi/2023-12-29_pi-spi-rates.md +++ b/rpi_spi/2023-12-29_pi-spi-rates.md @@ -83,4 +83,6 @@ OK, so to see if we can get up to that 10Mbit real-transfer-rate target, I think 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 +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/spi_peripheral_bare.ino b/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino index 2bdb72f..1079bb8 100644 --- a/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino +++ b/rpi_spi/code/spi_peripheral_bare/spi_peripheral_bare.ino @@ -4,42 +4,7 @@ // 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); @@ -48,26 +13,6 @@ void setup(void){ // 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; @@ -77,9 +22,9 @@ 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()) - ); + 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 index 0b06d2b..8dd0e27 100644 --- a/rpi_spi/code/spi_peripheral_bare/spipi.cpp +++ b/rpi_spi/code/spi_peripheral_bare/spipi.cpp @@ -18,8 +18,9 @@ // /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 14 +#define PIN_CS 13 #define PIN_SCK 10 #define PIN_RX 12 #define PIN_TX 11 @@ -34,79 +35,89 @@ #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; - -volatile uint32_t event_latest = 12; -uint32_t spipi_get_events(void){ - return event_latest; +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)){ - gpio_put(1, !gpio_get_out_level(1)); + txPtr = 0; + rxPtr = 0; + // gpio_put(PIN_DEBUG, !gpio_get_out_level(PIN_DEBUG)); } - // 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_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 | 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_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); + 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); + 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); } - - -// 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 index 6c97915..d941fcb 100644 --- a/rpi_spi/code/spi_peripheral_bare/spipi.h +++ b/rpi_spi/code/spi_peripheral_bare/spipi.h @@ -4,6 +4,6 @@ #include <Arduino.h> void spipi_begin(void); -uint32_t spipi_get_events(void); +String spipi_print(void); #endif \ No newline at end of file -- GitLab