polpla,
For more information about DMA in libmaple, your best bet is the libmaple docs and the LeafLabs wiki.
There are also a few threads in the forums, such as this one that go over basic configuration.
I also have a dataflash library for the Maple on github. In my benchmarks I configure basic DMA support and do some transfers.
In my case I am doing continuous reads. In order to accomplish this, I have DMA setup for both SPI RX and TX. I setup the TX to continuously send 0xFF, which tells the SPI device that I'm accepting a new byte of data and DMA RX captures it into the buffer. The basic configuration I used is:
#define SPI_DMA_DEV DMA1
#define SPI_RX_DMA_CHANNEL DMA_CH2
#define SPI_TX_DMA_CHANNEL DMA_CH3
#define SPI_BUFF_SIZE BYTES_PER_PAGE
uint8_t dma_rx_spi_buffer[SPI_BUFF_SIZE];
uint8_t dma_tx_spi_buffer[SPI_BUFF_SIZE];
memset(dma_rx_spi_buffer, 0x00, SPI_BUFF_SIZE);
memset(dma_tx_spi_buffer, 0xFF, SPI_BUFF_SIZE);
dma_init(SPI_DMA_DEV);
spi_rx_dma_enable(SPI1); // Enables RX DMA on SPI 1
spi_tx_dma_enable(SPI1); // Enables TX DMA on SPI 1
dma_setup_transfer(SPI_DMA_DEV, SPI_RX_DMA_CHANNEL,
&SPI1->regs->DR, DMA_SIZE_8BITS,
dma_rx_spi_buffer, DMA_SIZE_8BITS,
(DMA_MINC_MODE | DMA_CIRC_MODE | DMA_TRNS_CMPLT)
);
dma_attach_interrupt(SPI_DMA_DEV, SPI_RX_DMA_CHANNEL, spi_rx_dma_irq);
dma_setup_transfer(SPI_DMA_DEV, SPI_TX_DMA_CHANNEL,
&SPI1->regs->DR, DMA_SIZE_8BITS,
dma_tx_spi_buffer, DMA_SIZE_8BITS,
(DMA_MINC_MODE | DMA_CIRC_MODE| DMA_FROM_MEM)
);
// Sending "I want to read" command manually
dataflash.ContinuousArrayRead(START_PAGE, 0); // Unrelated to DMA
// Letting DMA rip!
dma_set_num_transfers(SPI_DMA_DEV, SPI_RX_DMA_CHANNEL, SPI_BUFF_SIZE);
dma_set_num_transfers(SPI_DMA_DEV, SPI_TX_DMA_CHANNEL, SPI_BUFF_SIZE);
pages_to_write = PAGES_TO_TEST;
spi_rx_dma_done = false;
dma_enable(SPI_DMA_DEV, SPI_TX_DMA_CHANNEL);
dma_enable(SPI_DMA_DEV, SPI_RX_DMA_CHANNEL);
while(spi_rx_dma_done == false);
dma_disable(SPI_DMA_DEV, SPI_TX_DMA_CHANNEL);
dma_disable(SPI_DMA_DEV, SPI_RX_DMA_CHANNEL);
I also have my interrupt configured:
volatile bool spi_rx_dma_done;
volatile uint16_t pages_to_write;
void spi_rx_dma_irq(void)
{
static uint8_t pages_done = 0;
pages_done++;
/*
* Realistically, DMA would not be set for continuous reads
* and we'd only read one page at a time then process those 528 bytes.
* We'd then manually enable DMA for another 528 bytes and repeat.
* Once we have enough bytes, we'd disable DMA and trigger our "flag."
* But this is just a simple test to see maximum possible read speeds.
*
*/
if(pages_done == pages_to_write)
{
pages_done = 0; // fixed bug not on github
spi_rx_dma_done = true;
}
}
A couple other things about the configuration:
- DMA_MINC_MODE will cause the memory address of my buffer to automatically increment when a byte of data is received/transferred.
- DMA_CIRC_MODE will cause the memory buffer to wrap around to the beginning once it's been completely written to or read from.
- DMA_FROM_MEM is used for the SPI TX because it's moving data from the memory buffer to the peripheral.
Since I only have a transfer complete flag, I don't have to worry about the cause of the DMA interrupt handler being called. Once the interrupt is triggered, I set a flag and unblock the main flow of the program then disable the DMA channels in order of importance (no RX if DMA is not TXing).
Hopefully this is a start.
EDIT:
Because you're doing SPI TX over DMA, you need to include the DMA_FROM_MEM setting so that the DMA controller knows you're moving data FROM memory TO the peripheral. I like how you don't use an array of 0xFF since you're just transferring that one byte of data over and over. I will have to try that out!
-robodude666