Hi, I'm trying to implement a SPI Slave with DMA in a RP2040 to receive 16 bytes at 1MHz from a SPI Master.
The Master clears CSN before the transfer and sets it at the end. I cannot change the Master.
The RP2040 SPI slave example is working in single byte and in continous mode, both in polling (as per the example) and with interrupts.
The next step is now to have it feed a DMA and trigger an interrupt once all 16 bytes have been received.
Note that I only need to use it as slave RX, I don't need to output any data (TX unconnected). The 3 signals used are: RX, SCK and CSN.
The issue that I'm having is that although the DMA is triggered by the reception of a byte, it only copies a byte at once. This works when in single-byte mode, but not in continuous mode, where only the first byte is copied, see the console output below.
My test setup is as follows:
Arduino Mega 2560 setup as a SPI master and sending 10 bytes (00 to 09) every second, for test purposes. This is the code:Raspberry Pi Pico connected with its default GPIOs and setup as a SPI slave + DMA. This is the code:The output is this (duplicated lines removed):
Any idea how I could get the DMA to transfer more than 1 byte at a time, or what settings I need to change in the SPI peripheral?
I don't think I can change the SPI mode since I'm expecting 16 bytes at 1MHz from the Master, but all inputs are welcome!
Thanks
The Master clears CSN before the transfer and sets it at the end. I cannot change the Master.
The RP2040 SPI slave example is working in single byte and in continous mode, both in polling (as per the example) and with interrupts.
The next step is now to have it feed a DMA and trigger an interrupt once all 16 bytes have been received.
Note that I only need to use it as slave RX, I don't need to output any data (TX unconnected). The 3 signals used are: RX, SCK and CSN.
The issue that I'm having is that although the DMA is triggered by the reception of a byte, it only copies a byte at once. This works when in single-byte mode, but not in continuous mode, where only the first byte is copied, see the console output below.
My test setup is as follows:
Arduino Mega 2560 setup as a SPI master and sending 10 bytes (00 to 09) every second, for test purposes. This is the code:
Code:
/* SPI Master*/#include <SPI.h>#define BUF_LEN 10const int slaveSelectPin = 53;uint8_t out_buf[BUF_LEN];void setup() { Serial.begin(115200); Serial.println("SPI Master"); pinMode(slaveSelectPin, OUTPUT); SPI.begin();}void loop() { Serial.println("Sending"); // Must initialize buffer every time for (int i = 0; i < BUF_LEN; i++) { out_buf[i] = i; } SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); digitalWrite(slaveSelectPin, LOW); SPI.transfer(out_buf, BUF_LEN); digitalWrite(slaveSelectPin, HIGH); SPI.endTransaction(); delay(1000);}
Code:
// Example of using the SPI as a slave with DMA#include <stdio.h>#include <stdlib.h>#include "pico/stdlib.h"#include "pico/binary_info.h"#include "pico/sync.h"#include "hardware/spi.h"#include "hardware/dma.h"#include "hardware/irq.h"#define BUF_LEN 10uint dma_rx;static uint8_t rxbuf[BUF_LEN];bool dma_rx_done = false;void dma_rx_irq_handler() { dma_channel_acknowledge_irq0(dma_rx); // Re-initialize and trigger the DMA transfer dma_channel_set_trans_count(dma_rx, BUF_LEN, true); dma_channel_set_write_addr(dma_rx, rxbuf, true); printf("RX DMA IRQ\n"); dma_rx_done = true;}int main() { // Enable UART so we can print status output stdio_init_all(); //sleep_ms(2000); printf("SPI example\n"); // Enable SPI at 1 MHz and connect to GPIOs spi_init(spi_default, 1000 * 1000); spi_set_slave(spi_default, true); gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI); gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI); gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI); gpio_set_function(PICO_DEFAULT_SPI_CSN_PIN, GPIO_FUNC_SPI); // Grab some unused dma channels dma_rx = dma_claim_unused_channel(true); printf("Configure RX DMA\n"); // We set the inbound DMA to transfer from the SPI receive FIFO to a memory buffer paced by the SPI RX FIFO DREQ // We configure the read address to remain unchanged for each element, but the write // address to increment (so data is written throughout the buffer) dma_channel_config c = dma_channel_get_default_config(dma_rx); channel_config_set_transfer_data_size(&c, DMA_SIZE_8); channel_config_set_dreq(&c, spi_get_dreq(spi_default, false)); // RX DREQ channel_config_set_read_increment(&c, false); channel_config_set_write_increment(&c, true); dma_channel_configure(dma_rx, &c, rxbuf, // write address &spi_get_hw(spi_default)->dr, // read address BUF_LEN, // element count (each element is of size transfer_data_size) false); // don't start yet //Enable IRQ for RX DMA dma_channel_set_irq0_enabled(dma_rx, true); irq_set_exclusive_handler(DMA_IRQ_0, dma_rx_irq_handler); irq_set_enabled(DMA_IRQ_0, true); dma_channel_start(dma_rx); while(1) { if(dma_rx_done) { dma_rx_done = false; printf("RX DMA done\n"); for(int i = 0; i < BUF_LEN; i++) { printf("%02x ", rxbuf[i]); } printf("\n"); } if(spi_get_const_hw(spi_default)->sr & SPI_SSPSR_RNE_BITS) { printf("RX FIFO not empty\n"); } if(spi_get_const_hw(spi_default)->sr & SPI_SSPSR_RFF_BITS) { printf("RX FIFO full\n"); } printf("DMA transfer count=%02x\n", dma_channel_hw_addr(dma_rx)->transfer_count); sleep_ms(100); }}
Where I would expect something more like this:DMA transfer count=0a
DMA transfer count=09
DMA transfer count=08
DMA transfer count=07
DMA transfer count=06
DMA transfer count=05
DMA transfer count=04
DMA transfer count=03
DMA transfer count=02
DMA transfer count=01
RX DMA IRQ
RX DMA done
00 00 00 00 00 00 00 00 00 00
I went through the RP2040 TRM and the PL022 TRM but I couldn't find the details of the DMA implementation.DMA transfer count=0a
RX DMA IRQ
RX DMA done
00 01 02 03 04 05 06 07 08 09
Any idea how I could get the DMA to transfer more than 1 byte at a time, or what settings I need to change in the SPI peripheral?
I don't think I can change the SPI mode since I'm expecting 16 bytes at 1MHz from the Master, but all inputs are welcome!
Thanks
Statistics: Posted by romain145 — Sun Aug 25, 2024 7:45 pm — Replies 1 — Views 18