[SOLVED] SPI slave with DMA
Vicolaships Fri Apr 20, 2018 4:50 pm
I want to be able to receive 2 bytes (2x 8 bits) without managing each byte, I want to DMA to do that stuff for me and trigger an interruption when the two bytes are transferred. I also need the transfer to be full-duplex, the slave must respond to the master (in this example master should receive: 123 and 87).
With the code below nothing happens when I transfer 2 bytes, the interruption does not fire. The master receives a response where all bits are zeroes. I’m sure that the cables are correctly connected because a simple SPI slave like viewtopic.php?f=18&t=3525 works.
#include <SPI.h>
#include <cstdint>
#include <libmaple/dma.h>
#define DATA_BUFFER_SIZE 2
// Tx / Rx buffer
volatile uint8_t data_buffer[DATA_BUFFER_SIZE];
// If true a transfer is complete: data_bufer contains new and valid data
volatile bool dma_transfer_complete(false);
// DMA interrupt handler
void rxDMAirq(void)
{
if (dma_get_irq_cause(DMA1, DMA_CH2) == DMA_TRANSFER_COMPLETE)
dma_transfer_complete = true;
}
void setupDMA(void)
{
dma_init(DMA1);
// DMA tube configuration for SPI1 Rx - channel 2
dma_tube_config tube_cfg =
{
&SPI1->regs->DR, // Source of data
DMA_SIZE_8BITS, // Source transfer size
&data_buffer, // Destination of data
DMA_SIZE_8BITS, // Destination transfer size
DATA_BUFFER_SIZE, // Number of data to transfer
// Flags: auto increment destination address, circular buffer, set tube full IRQ, very high priority
(DMA_CFG_DST_INC | DMA_CFG_CIRC | DMA_CFG_CMPLT_IE), // FIXME Do I need DMA_CCR_PL_VERY_HIGH?
0, // Un-used
DMA_REQ_SRC_SPI1_RX, // Hardware DMA request source
};
// Configure DMA channel
// SPI1 Rx channel is nr. 2
const int ret(dma_tube_cfg(DMA1, DMA_CH2, &tube_cfg));
if (ret != DMA_TUBE_CFG_SUCCESS)
{
while (1)
{
Serial.print("DMA configuration error: ");
Serial.println(ret, HEX);
Serial.println("Reset is needed!");
delay(100);
}
}
dma_attach_interrupt(DMA1, DMA_CH2, rxDMAirq);
dma_enable(DMA1, DMA_CH2);
}
void setupSPI(void)
{
// MOSI, MISO, SCK PINs are set by the library
pinMode(BOARD_SPI_DEFAULT_SS, INPUT); // SS
// The clock value is not used
// SPI1 is selected by default
SPI.beginTransactionSlave(SPISettings(18000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT));
}
void setup()
{
Serial.begin(115200);
delay(100);
// Data that will be sent
data_buffer[0] = 123;
data_buffer[1] = 87;
setupSPI();
setupDMA();
}
unsigned count_1(0);
unsigned count_2(0);
void loop()
{
if (dma_transfer_complete)
{
dma_transfer_complete = false;
Serial.println("DMA transfer complete");
Serial.print("data_buffer[0] = ");
Serial.println((unsigned)data_buffer[0]);
Serial.print("data_buffer[1] = ");
Serial.println((unsigned)data_buffer[1]);
// Data that will be sent (for next transfer)
// Assumes that a transfer has not yet been initiated
data_buffer[0] = 123;
data_buffer[1] = 87;
}
delayMicroseconds(10);
if (++count_1 > 50000)
{
count_1 = 0;
Serial.print("Waiting... ");
Serial.println(++count_2);
}
}
