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