Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: SPI Slave Mode on Teensy 4?

  1. #1
    Junior Member
    Join Date
    Jan 2020
    Posts
    17

    SPI Slave Mode on Teensy 4?

    Hi!
    I'm trying to establish a spi connection between a teensy 3.6 as master and a teensy 4 as a slave. I only would like to receive 16Bit of Data on the Teensy 4 side.
    Below is my Code on the Teensy 3.6 side and the code on the Teensy 4 side.
    The pin-connections are: Pin10->Pin10, Pin11->Pin11, Pin12->Pin12 and Pin13->Pin13.

    It doesn't seem like the DMA-Interrupt even gets triggered.
    Perhabs anyone of you can spot a mistake
    Thank you in advance!


    Code of Master:

    Code:
    #include <SPI.h> 
    #define CS 10
    // set up the speed, mode and endianness of each device
    SPISettings SPI_Settings(1000000, MSBFIRST, SPI_MODE0);
    
    
    void setup() {
      // set the Slave Select Pins as outputs:
      pinMode(CS, OUTPUT);
      digitalWrite(CS, HIGH);
      
      // initialize SPI:
      SPI.begin();
    }
    
    uint16_t val = 1235; //send anything
    
    void loop() {
      SPI.beginTransaction(SPI_Settings);
      digitalWrite(CS, LOW);
      SPI.transfer16(val);
      digitalWrite (CS, HIGH);
      SPI.endTransaction();
      delay(500);
    }
    Code of Slave:
    Code:
    //Inspired by Paul Stoffregen's SPI Lib and manitou48's spidma2.ino
    #include <DMAChannel.h>
    #include <SPI.h>
    #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,BIN)
    #define SAMPLES 10
    
    DMAMEM static uint8_t rx_buffer[SAMPLES];
    DMAChannel rx(false);
    //volatile int ticks = 0;
    
    
    void DMAChanneltransferCount() {
      if (!(rx.TCD->BITER & DMA_TCD_BITER_ELINK)) {
        rx.TCD->BITER = SAMPLES & 0x7fff;
      } else {
        rx.TCD->BITER = (rx.TCD->BITER & 0xFE00) | (SAMPLES & 0x1ff);
      }
      rx.TCD->CITER = rx.TCD->BITER;
    }
    
    void rxISR() {
      Serial.println("RX Interrupt");
      rx.clearInterrupt();
      rx.clearComplete();
      DMAChanneltransferCount();
      //ticks++;
      rx.enable();
      asm volatile ("dsb");
    }
    
    bool initSPISlaveDMA() {
      rx.disable();
      rx.source((uint8_t &) LPSPI4_RDR);
      rx.disableOnCompletion();
      rx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX);
      //rx.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
      rx.attachInterrupt(rxISR); //doesnt get called?
      rx.interruptAtCompletion(); //TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
      //rx.TCD->ATTR_SRC = 0; //8Bit Modus
      rx.destinationBuffer(rx_buffer, SAMPLES + 1);
      //rx.TCD->DLASTSGA = -SAMPLES;
      //LPSPI4_TCR = (LPSPI4_TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(15);
      //LPSPI4_TCR = LPSPI_TCR_FRAMESZ(7);
      LPSPI4_TCR = (LPSPI4_TCR & 0xfffff000) | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_CONT; //16Bit Modus
      LPSPI4_FCR = 0;
      //LPSPI4_IER = LPSPI_IER_RDIE; //Receive Data Inerruopt enable
      //LPSPI4_DER = LPSPI_IER_RDIE;
      LPSPI4_DER = LPSPI_DER_RDDE; //RX DMA Request Enable
      LPSPI4_SR = 0x3f00;  // clear out all of the other status...
      LPSPI4_CR |= LPSPI_CR_MEN; //SPI-Modul einschalten!
      rx.enable();
      return 1;
    }
    
    
    
    bool initSPISlave()
    {
      LPSPI4_CR &= ~LPSPI_CR_MEN; //Module disable
    
      CCM_CBCMR &= ~CCM_CCGR1_LPSPI4(CCM_CCGR_ON); //Clock ausschalten
      //return 1;
      //FAST-IO
      
        uint32_t fastio = IOMUXC_PAD_DSE(6) | IOMUXC_PAD_SPEED(1);
        IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_01 = fastio;
        IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_02 = fastio;
        IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_03 = fastio;
        CCM_CBCMR |= CCM_CCGR1_LPSPI4(CCM_CCGR_ON); //Clock reaktivieren
      
    
      //LPSPI Muxing:
      IOMUXC_LPSPI4_SCK_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_SDI_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_SDO_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_PCS0_SELECT_INPUT = 0;
    
      //Pad Muxing:
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 3; //SCK
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 3; //SDI (MISO)
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_02 = 3; //SDO (MOSI)
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 3; //LPSPI4 PCS0 (CS)
    
      //Master-Logic Reset:
      LPSPI4_CR = LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
    
      /*
        LPSPI4_CFGR1 &= ~LPSPI_CFGR1_MASTER; //Master Modus disable
        LPSPI4_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX
      */
    
      //FIFO Watermark for 16Bit?
      LPSPI4_FCR = LPSPI_FCR_RXWATER(15);
    
      LPSPI4_CR |= LPSPI_CR_RTF | LPSPI_CR_RRF | LPSPI_CR_MEN | LPSPI_CR_DBGEN | LPSPI_CR_DOZEN; //enable!
    
      return 1;
    }
    
    void setup()
    {
      Serial.begin(115200);
      SPI.begin();
    
      /*
      pinMode(10, INPUT);
      pinMode(11, INPUT);
      pinMode(12, OUTPUT);
      pinMode(13, INPUT);
      */
    
      rx.begin(true);
    
      while (!Serial);
      Serial.println("init SPI!");
    
      if (initSPISlave()) {
        Serial.println("SPI SLAVE init!");
      }
      if (initSPISlaveDMA()) {
        Serial.println("DMA Channel init!");
      }
      
      Serial.println(SPI.pinIsChipSelect(10));
      Serial.println(SPI.pinIsMOSI(11));
      Serial.println(SPI.pinIsMISO(12));
      Serial.println(SPI.pinIsSCK(13));
    
      rx_buffer[0] = 0;
      
      //Print Registers:
      /*
        PRREG(LPSPI4_CR);
        PRREG(LPSPI4_SR);
        PRREG(LPSPI4_DER);
        PRREG(LPSPI4_CFGR0);
        PRREG(LPSPI4_CFGR1);
        PRREG(LPSPI4_CCR);
        PRREG(LPSPI4_FCR);
        PRREG(LPSPI_FSR_RXCOUNT(4));
        PRREG(LPSPI4_TCR);
        PRREG(LPSPI_RSR_RXEMPTY);
        PRREG(LPSPI4_RDR);
      */
    }
    
    void loop()
    {
      Serial.println(rx_buffer[0]); //always Zero
    
      //PRREG(LPSPI_FSR_RXCOUNT(4));
      //PRREG(LPSPI4_SR);
      delay(1000);
    }
    Last edited by KurtE; 01-26-2020 at 12:18 PM.

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,363
    Sorry, I hope you don't mind I edited and added code tags. Lots easier to read when the indents are preserved (Select text and hit the # button)

    I have been meaning to take a look at SPI slave code on the T4, but have not done so yet.

    This morning, I may not have time to do a complete look over this. I would probably have a tendency, to look at this code along with some SPI DMA master side by side to see if anything jumps out at me. We do have some DMA SPI master code around in a few places, including SPI library itself, My display library (ILI9341_t3n) and a few other display library ILI9481_t3, ST7735_t3...

    In my first quick look through, one thing, that I know is wrong is:
    Code:
     //FIFO Watermark for 16Bit?
      LPSPI4_FCR = LPSPI_FCR_RXWATER(15);
    The Rx Water mark in this register is how many entries max in the FIFO queue before you get interrupts. I am not sure if you want the whole FIFO (16 words) full before you get notification.

    I will try to take a look soon, right now in the middle of looking at some stuff with Wire...

  3. #3
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    Thank you very very much for your answer! I am also trying to read through the datasheet section of the lpspi again. but as you can clearly see i'm no expert at all

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,363
    Sorry, again I don't have enough time (or energy) to go completely through all of this but again will try to give some hints...

    Your slave code starts off in setup, calling SPI.begin() so many of the things are already initialized, including setting MOSI, MISO, SCK into the proper SPI mode.

    So you can remove most of the stuff in your initSPISlave code, including

    turning off enable the clock as this was done SPI.begin.

    Also setting of the pins in the right configurations (minus the CS)
    Code:
      uint32_t fastio = IOMUXC_PAD_DSE(6) | IOMUXC_PAD_SPEED(1);
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_01 = fastio;
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_02 = fastio;
      IOMUXC_SW_PAD_CTL_PAD_GPIO_B0_03 = fastio;
      CCM_CBCMR |= CCM_CCGR1_LPSPI4(CCM_CCGR_ON); //Clock reaktivieren
    
    
      //LPSPI Muxing:
      IOMUXC_LPSPI4_SCK_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_SDI_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_SDO_SELECT_INPUT = 0;
      IOMUXC_LPSPI4_PCS0_SELECT_INPUT = 0;
    
      //Pad Muxing:
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 3; //SCK
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_01 = 3; //SDI (MISO)
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_02 = 3; //SDO (MOSI)
      IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 3; //LPSPI4 PCS0 (CS)
    But if you are going to do your own. then you probably need to change lines like:
    Code:
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 3; //SCK
    to
    Code:
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_03 = 3 | 0x10 ; //SCK
    As I said this should take care of MOSI, MISO, SCK

    Now for SCK you can do it your way (need the 0x10) ... Or let SPI library do it for you, by adding a call to setCS like:
    Code:
    SPI.setCS(10);
    Setting up DMA...

    Note: I see your buffer is setup: DMAMEM static uint8_t rx_buffer[SAMPLES];
    Simple warning about DMAMEM (or memory allocated using malloc). Uses the upper memory that has caching and unless you handle it, you may find that what your program sees is not what was received by DMA. As DMA writes directly to physical memory and your code will read from cache if it is cached...
    Some details up on main product page: https://www.pjrc.com/store/teensy40.html
    More up in the thread: https://forum.pjrc.com/threads/57326...ferent-regions
    You may want to look around for threads that talk about arm_dcache_delete and the like.
    Example in SPI library it does: arm_dcache_delete(retbuf, count);

    Also I noticed that you have not set it up to be slave mode. That is you have the line:
    Code:
        LPSPI4_CFGR1 &= ~LPSPI_CFGR1_MASTER; //Master Modus disable
    commented out
    Likewise you have the line to turn on NOSTALL disabled, but I think that one is a MASTER flag so probably wont do anything.

    That is all for now.

    Hope that helps
    Kurt

  5. #5
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    Thank you for your help I'm getting Interrupts now! But I'm reading always Zero at the moment?!




    Code:
    #include <DMAChannel.h>
    #include <SPI.h>
    #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,BIN)
    #define SAMPLES 10
    
    
    DMAMEM static uint16_t rx_buffer[SAMPLES];
    DMAChannel rx(false);
    volatile int ticks = 0;
    
    
    void DMAChanneltransferCount() {
      if (!(rx.TCD->BITER & DMA_TCD_BITER_ELINK)) {
        rx.TCD->BITER = SAMPLES & 0x7fff;
      } else {
        rx.TCD->BITER = (rx.TCD->BITER & 0xFE00) | (SAMPLES & 0x1ff);
      }
      rx.TCD->CITER = rx.TCD->BITER;
    }
    
    void rxISR() {
      Serial.println("RX Interrupt");
      PRREG(LPSPI4_RDR);
    
      rx.clearInterrupt();
      rx.clearComplete();
    
      DMAChanneltransferCount();
      //ticks++;
    
      rx.enable();
      asm volatile ("dsb");
    }
    
    bool initSPISlaveDMA() {
      rx.disable();
      rx.source((uint8_t &) LPSPI4_RDR);
      //rx.disableOnCompletion();
    
      rx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX);
      //rx.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
      rx.attachInterrupt(rxISR); //doesnt get called?
      rx.interruptAtCompletion(); //TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
    
      
      rx.TCD->ATTR_SRC = 0; //8Bit Modus
      rx.destinationBuffer(rx_buffer, SAMPLES + 1);
      rx.TCD->DLASTSGA = -SAMPLES;
    
      
      //LPSPI4_TCR = (LPSPI4_TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(15);
      //LPSPI4_TCR = LPSPI_TCR_FRAMESZ(7);
      //LPSPI4_TCR = (LPSPI4_TCR & 0xfffff000) | LPSPI_TCR_FRAMESZ(15) | LPSPI_TCR_CONT; //16Bit Modus
    
    
      LPSPI4_TCR = LPSPI_TCR_FRAMESZ(15); // | LPSPI_TCR_CONT; //16Bit Modus
    
      LPSPI4_FCR = 0;
    
    
      LPSPI4_DER = LPSPI_DER_RDDE; //RX DMA Request Enable
    
      LPSPI4_SR = 0x3f00;  // clear out all of the other status...
      LPSPI4_CR |= LPSPI_CR_MEN; //SPI-Modul einschalten!
      rx.enable();
      return 1;
    }
    
    
    
    bool initSPISlave()
    {
      LPSPI4_CR &= ~LPSPI_CR_MEN; //Modul ausschalten
      /*
        //Fast-IO for CS:
        IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = IOMUXC_PAD_DSE(6) | IOMUXC_PAD_SPEED(1);
        //LPSPI Muxing:
        IOMUXC_LPSPI4_PCS0_SELECT_INPUT = 0; //CS
        //Pad Muxing:
        IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 3 | 0x10; //CS
      */
    
      //Master-Logic Reset:
      LPSPI4_CR = LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CR &=  ~LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CFGR1 |= LPSPI_CFGR1_NOSTALL;
      
      /*
        LPSPI4_CFGR1 &= ~LPSPI_CFGR1_MASTER; //Master Modus deaktivieren
        LPSPI4_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX
      */
    
      //FIFO Watermark einstellen für (FIFOSize-1) --> hier: ab 16Bit empfangen triggern!
      LPSPI4_FCR = LPSPI_FCR_RXWATER(0);
      //LPSPI4_CR |= LPSPI_CR_RTF | LPSPI_CR_RRF | LPSPI_CR_MEN | LPSPI_CR_DBGEN | LPSPI_CR_DOZEN; //SPI-Modul einschalten!
      LPSPI4_CR |= LPSPI_CR_MEN | LPSPI_CR_DBGEN | LPSPI_CR_DOZEN;
    
      return 1;
      //initSPISlaveDMA();
    }
    
    void setup()
    {
      Serial.begin(2000000);
      SPI.begin();
      SPI.setCS(10);
      rx.begin(true);
    
      while (!Serial);
      Serial.println("initialisiere SPI!");
    
      if (initSPISlave()) {
        Serial.println("SPI SLAVE initialisiert!");
      }
      if (initSPISlaveDMA()) {
        Serial.println("DMA Channel initialisiert!");
      }
      rx_buffer[0] = 0;
    
      //NVIC_ENABLE_IRQ(IRQ_LPSPI4);
    
      PRREG(LPSPI4_CR);
      PRREG(LPSPI4_SR);
      PRREG(LPSPI4_DER);
      PRREG(LPSPI4_CFGR0);
      PRREG(LPSPI4_CFGR1);
      PRREG(LPSPI4_CCR);
      PRREG(LPSPI4_FCR);
      //PRREG(LPSPI_FSR_RXCOUNT(4));
      PRREG(LPSPI4_TCR);
      //PRREG(LPSPI_RSR_RXEMPTY);
      //PRREG(LPSPI4_RDR);
    
    }
    
    void loop()
    {
      arm_dcache_delete(rx_buffer, SAMPLES); //delete Cache!
      Serial.println(rx_buffer[0]);
      //PRREG(LPSPI_FSR_RXCOUNT(4));
      PRREG(LPSPI4_SR); //Statusregister
      delay(1000);
    }

  6. #6
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    Actually that's not right I'm getting values, but much lower ones than the send values... For example I sent the uint16_t val = 200 and received 34. Strange!

  7. #7
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    This is the current Slave Code:

    Code:
    #include <DMAChannel.h>
    #include <SPI.h>
    #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x, BIN) //Serial.println(x,BIN)
    #define SAMPLES 2
    
    
    DMAMEM static uint16_t rx_buffer[SAMPLES];
    DMAChannel rx(false);
    volatile int ticks = 0;
    
    
    void DMAChanneltransferCount() {
      if (!(rx.TCD->BITER & DMA_TCD_BITER_ELINK)) {
        rx.TCD->BITER = SAMPLES & 0x7fff;
      } else {
        rx.TCD->BITER = (rx.TCD->BITER & 0xFE00) | (SAMPLES & 0x1ff);
      }
      rx.TCD->CITER = rx.TCD->BITER;
    }
    
    void rxISR() {
      rx.clearInterrupt();
      rx.clearComplete();
      //DMAChanneltransferCount();
      rx.enable();
      asm volatile ("dsb");
      Serial.println("RX Interrupt");
    }
    
    bool initSPISlaveDMA() {
      rx.disable();
      rx.source((uint8_t &) LPSPI4_RDR);
      
      rx.disableOnCompletion();
      rx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX);
      rx.attachInterrupt(rxISR);
      rx.interruptAtCompletion(); //TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
    
      rx.TCD->ATTR_SRC = 1; //16Bit Mode
      rx.destinationBuffer(rx_buffer, SAMPLES + 1);
      rx.TCD->DLASTSGA = -(SAMPLES);
    
      LPSPI4_TCR = LPSPI_TCR_FRAMESZ(15); // | LPSPI_TCR_CONT; //16Bit Modus
      LPSPI4_FCR = 0;
      LPSPI4_DER = LPSPI_DER_RDDE; //RX DMA Request Enable
      LPSPI4_SR = 0x3f00;  // clear out all of the other status...
      LPSPI4_CR |= LPSPI_CR_MEN; //SPI-Modul einschalten!
      rx.enable();
      return 1;
    }
    
    
    
    bool initSPISlave()
    {
      LPSPI4_CR &= ~LPSPI_CR_MEN; //Modul ausschalten
      //Master-Logic Reset:
      LPSPI4_CR = LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CR &=  ~LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CFGR1 |= LPSPI_CFGR1_NOSTALL;
      LPSPI4_FCR = LPSPI_FCR_RXWATER(0);
      LPSPI4_CR |= LPSPI_CR_MEN | LPSPI_CR_DBGEN | LPSPI_CR_DOZEN; //enable
      return 1;
    }
    
    void setup()
    {
      Serial.begin(2000000);
      SPI.begin();
      SPI.setCS(10);
      rx.begin(true);
    
      while (!Serial);
      Serial.println("initialisiere SPI!");
    
      if (initSPISlave()) {
        Serial.println("SPI SLAVE initialisiert!");
      }
      if (initSPISlaveDMA()) {
        Serial.println("DMA Channel initialisiert!");
      }
      rx_buffer[0] = 0;
    
      //NVIC_ENABLE_IRQ(IRQ_LPSPI4);
    
      PRREG(LPSPI4_CR);
      PRREG(LPSPI4_SR);
      PRREG(LPSPI4_DER);
      PRREG(LPSPI4_CFGR0);
      PRREG(LPSPI4_CFGR1);
      PRREG(LPSPI4_CCR);
      PRREG(LPSPI4_FCR);
      //PRREG(LPSPI_FSR_RXCOUNT(4));
      PRREG(LPSPI4_TCR);
      //PRREG(LPSPI_RSR_RXEMPTY);
      //PRREG(LPSPI4_RDR);
    }
    
    void loop()
    {
      arm_dcache_delete(rx_buffer, SAMPLES); //delete Cache!
      PRREG(rx_buffer[0]);
      PRREG(rx_buffer[1]);
      Serial.println(rx_buffer[0]);
    
      //PRREG(LPSPI_FSR_RXCOUNT(4));
      //PRREG(LPSPI4_SR); //Statusregister
      delay(1000);
    }

  8. #8
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    So it turns out that the code above is working now!

    Thank you again very much @KurtE

  9. #9
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    For anyone who's interested: this is my polished version of the code.
    (Sets up T4 in SPI Slave Mode and receives 16Bit Values with DMA)

    Code:
    #include <DMAChannel.h>
    #include <SPI.h>
    #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x, BIN) //Serial.println(x,BIN)
    #define SAMPLES 1
    #define ChipSelectSlave 10
    
    DMAMEM static uint16_t rx_buffer[SAMPLES];
    DMAChannel rx(false);
    
    void rxISR() {
      rx.clearInterrupt();
      asm volatile ("dsb");
      Serial.print("RX Interrupt --> Val = "); Serial.println(rx_buffer[0]);
    }
    
    bool initSPISlaveDMA() {
      rx.begin(true);
      rx.source((uint16_t &) LPSPI4_RDR);
      rx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX);
      rx.attachInterrupt(rxISR);
      rx.interruptAtCompletion(); //TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
      rx.destinationBuffer(rx_buffer, SAMPLES + 1);
      rx.enable();
      return 1;
    }
    
    bool initSPISlave() {
      LPSPI4_CR &= ~LPSPI_CR_MEN; //Modul ausschalten
      LPSPI4_CR = LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CR &=  ~LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_TCR = LPSPI_TCR_FRAMESZ(15); //16Bit Mode
      LPSPI4_DER = LPSPI_DER_RDDE; //RX DMA Request Enable
      LPSPI4_CR |= LPSPI_CR_MEN; //Enable SPI Module!
      return 1;
    }
    
    void setup() {
      Serial.begin(115200);
      SPI.begin();
      SPI.setCS(ChipSelectSlave);
      while (!Serial);
    
      Serial.println("Init SPI!");
      if (initSPISlave()) {
        Serial.println("SPI SLAVE init!");
      }
      if (initSPISlaveDMA()) {
        Serial.println("DMA Channel init!");
      }
    }
    
    void loop() {
      arm_dcache_delete(rx_buffer, SAMPLES); //delete Cache!
    }
    Last edited by MartyBrown; 01-26-2020 at 09:38 PM. Reason: Deleted some unnecessary lines

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,363
    You are welcome, glad you got it working.. I may have to play with it, when I am done with some other distractions

  11. #11
    Junior Member
    Join Date
    Jan 2020
    Posts
    17
    A implementation in the SPI-Lib would be pretty nice i think.. For other users too I'm pretty sure my code can be improved too

  12. #12
    I think there is a mistake on the line:
    Code:
    rx.destinationBuffer(rx_buffer, SAMPLES + 1);
    I think it should be:
    Code:
    rx.destinationBuffer(rx_buffer, SAMPLES * 2);
    .

    The + 1 only works when SAMPLES is 1. One sample at 16 bits per sample is 2 bytes (SAMPLES + 1). But when SAMPLES is bigger, this falls apart.

    I also wonder if there is an easy way to allow the Teensy slave to send data back to the master with this implementation. Any help would be greatly appreciated.

  13. #13
    Junior Member
    Join Date
    Jan 2015
    Posts
    7
    Quote Originally Posted by MartyBrown View Post
    For anyone who's interested: this is my polished version of the code.
    (Sets up T4 in SPI Slave Mode and receives 16Bit Values with DMA)

    Code:
    #include <DMAChannel.h>
    #include <SPI.h>
    #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x, BIN) //Serial.println(x,BIN)
    #define SAMPLES 1
    #define ChipSelectSlave 10
    
    DMAMEM static uint16_t rx_buffer[SAMPLES];
    DMAChannel rx(false);
    
    void rxISR() {
      rx.clearInterrupt();
      asm volatile ("dsb");
      Serial.print("RX Interrupt --> Val = "); Serial.println(rx_buffer[0]);
    }
    
    bool initSPISlaveDMA() {
      rx.begin(true);
      rx.source((uint16_t &) LPSPI4_RDR);
      rx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX);
      rx.attachInterrupt(rxISR);
      rx.interruptAtCompletion(); //TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
      rx.destinationBuffer(rx_buffer, SAMPLES + 1);
      rx.enable();
      return 1;
    }
    
    bool initSPISlave() {
      LPSPI4_CR &= ~LPSPI_CR_MEN; //Modul ausschalten
      LPSPI4_CR = LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_CR &=  ~LPSPI_CR_RST; //Master Logic reset! (Control Register => Software Reset)
      LPSPI4_TCR = LPSPI_TCR_FRAMESZ(15); //16Bit Mode
      LPSPI4_DER = LPSPI_DER_RDDE; //RX DMA Request Enable
      LPSPI4_CR |= LPSPI_CR_MEN; //Enable SPI Module!
      return 1;
    }
    
    void setup() {
      Serial.begin(115200);
      SPI.begin();
      SPI.setCS(ChipSelectSlave);
      while (!Serial);
    
      Serial.println("Init SPI!");
      if (initSPISlave()) {
        Serial.println("SPI SLAVE init!");
      }
      if (initSPISlaveDMA()) {
        Serial.println("DMA Channel init!");
      }
    }
    
    void loop() {
      arm_dcache_delete(rx_buffer, SAMPLES); //delete Cache!
    }
    This code works great as a test for me, but how can we measure between CS low and high, then get an entire buffer of all of the bytes?

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •