AnsweredAssumed Answered

stm32f100 SPI RX DMA, TX no dma, possible?

Question asked by kledtke.steve on Nov 15, 2017
Latest reply on Nov 16, 2017 by kledtke.steve

Hey.

 

I have a board with the smallest STM32F100, with 4K RAM and 16K flash.
It has only DMA1. I am using CH3 for circular DAC output already.
So, for the only SPI(1) on that MCU, the DMA map in the refman tells me, only DMA1 Ch2, for SPI1 RX, is free, for TX it collides with DAC.
This *could* be okay, depending on what I want to do generally works.

 

I am using the standard periph lib.
I am using a tiny FAT implementation to read from SDcard via SPI, reading directly into the currently "inactive" half of the DMA doublebuffer (no processing necessary, just straightforward playing).
(elm chan PetitFAT, I changed the mmc example to use HW SPI instead bit bang)
So far configured as software, i.e. byte per byte, SPI, it sorta works, but is way too slow. SPI is confgured @ div2, i.e. 12 MHz on this MCU, I get valid data, so in general the sdcard seems to be fine with the speed, so it should be able to be sped up by using DMA.

 

Now the question: Can I configure things such that I can use SPI TX in software, bytewise mode, whereas RX is done via DMA?

 

I have seen that, in theory, everything can be configured in a separate way.
My attempt at doing that failed so far: Initializing SPI, then DMA channel and DMA, then giving SPI I2S DMA command for RX, I the wait for the channel2 TransferComplete flag - forever... it never comes.

 

Here some code: (at "wait until data is received", Line 47, never finishes)
SPI is configured as SPI_Direction_2Lines_FullDuplex - but I also tried to change that shortly to "2Lines RX only" before doing RX, didn't help.

void init()
{
// ...
// ... SPI / GPIO init as before - works without DMA
// ...

// DMA Init

     DMA_DeInit( MMC_DMA_CHANNEL );

     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) 0; // later...
     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
     DMA_InitStructure.DMA_BufferSize = 0; // later...
     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & MMC_SPI->DR;
     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

     DMA_Init( MMC_DMA_CHANNEL, &DMA_InitStructure );
     DMA_Cmd(  MMC_DMA_CHANNEL, ENABLE );
}     

     
static void     dma_spi_do_one_rx_transfer(uint8_t* buf, uint32_t len)
{
     //
     // Update the buffer settings
     //
     DMA_Cmd(  MMC_DMA_CHANNEL, DISABLE );
     //
     MMC_DMA_CHANNEL->CMAR = (uint32_t) buf;
     MMC_DMA_CHANNEL->CNDTR = len;
     //
     DMA_Cmd(  MMC_DMA_CHANNEL, ENABLE );

     DMA_ClearFlag( MMC_DMA_CHANNEL_FLAG_TC ); // TC2, for SPI1 RX
     
    SPI_I2S_DMACmd( MMC_SPI , SPI_I2S_DMAReq_Rx, ENABLE );

     // Wait until the data is received
     while ( ! (MMC_DMA->ISR & MMC_DMA_CHANNEL_FLAG_TC ) );

     SPI_I2S_DMACmd( MMC_SPI , SPI_I2S_DMAReq_Rx, DISABLE );
}

Outcomes