2014-06-19 06:29 AM
Hello,
I'm trying to use SPI master with DMA in full duplex to communicate with accelerometer. I don't want to use DMA interrupts (or should I?).I've managed to activate the SPI with polling mode and got the correct reading from the accelerometer.I'm using STM32L152 discovery board, SPI1 and DMA1.The configurations are:void DMA_Configuration(void){ /* Enable the DMA peripheral */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /* DMA channel Rx of SPI Configuration */ DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Rx_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_Init(DMA1_Channel2, &DMA_InitStructure); /* DMA channel Tx Configuration */ DMA_InitStructure.DMA_BufferSize = (uint16_t)1; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Tx_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_Priority = DMA_Priority_Low; DMA_Init(DMA1_Channel3, &DMA_InitStructure);}The function handling the SPI comm is:void SPI_Comm(SPI_TypeDef* SPI_x, uint16_t inBuffer, uint16_t *outBuffer){ Tx_Buffer = inBuffer; /* Enable the SPI Rx and Tx DMA request */ SPI_DMACmd(SPI1, SPI_DMAReq_Tx, ENABLE); SPI_DMACmd(SPI1, SPI_DMAReq_Rx, ENABLE); /* Enable the DMA Rx and Tx channels */ DMA_Cmd(DMA1_Channel3, ENABLE); DMA_Cmd(DMA1_Channel2, ENABLE); while(DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET); while(DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET); *outBuffer = Rx_Buffer; // DMA_ClearFlag(DMA1_FLAG_TC3); // DMA_ClearFlag(DMA1_FLAG_TC2); SPI_DMACmd(SPI1, SPI_DMAReq_Tx, DISABLE); SPI_DMACmd(SPI1, SPI_DMAReq_Rx, DISABLE); DMA_Cmd(DMA1_Channel3, DISABLE); DMA_Cmd(DMA1_Channel2, DISABLE);}Rx_Buffer and Tx_Buffer are globally defined.The read register function that read the accelerometer is:void Acc_Read_Register(uint16_t cmd, uint16_t *val){ // Set CS to LOW ACC_CS_LOW(); // Transmit cmd, receive dummy data (0xFF) SPI_Comm(ACC_SPI, (cmd | READ_MASK), val); // Transmit dummy cmd, receive correct data SPI_Comm(ACC_SPI, SPI_READ_DUMMY_CMD, val); // Set CS to HIGH ACC_CS_HIGH();}I'm keep getting 0xff in the Rx_Buffer for every read.Can anyone help me?Thanks #stm32lxx-spi-master-with-dma2014-06-19 06:57 AM
DMA data size should be set to halfword if you intend to transfer 16-bit word through SPI.
2014-06-19 07:08 AM
Thanks for your response.
I'm transferring 1 byte at a time, just using two transfer cycles.2014-06-19 07:17 AM
Maybe that RXNE is set before starting your DMA (from a preceding transfer), check status and if needed read from SPI1->SR to make sure the RX buffer of SPI is empty prior to start DMA.
2014-06-19 07:29 AM
I've tried adding the following code, still same result.
...if (SPI_GetFlagStatus(SPI_x, SPI_FLAG_RXNE) == RESET)
{ *outBuffer = SPI_ReceiveData(SPI_x); } Tx_Buffer = inBuffer; /* Enable the SPI Rx DMA request */ SPI_DMACmd(SPI1, SPI_DMAReq_Tx, ENABLE); SPI_DMACmd(SPI1, SPI_DMAReq_Rx, ENABLE); ......2014-06-19 07:55 AM
You need to remove the extra character when RXNE is *SET*
2014-06-19 08:01 AM
Thanks gonzalez fro your help.
Unfortunately, that still doesn't work. if (SPI_GetFlagStatus(SPI_x, SPI_FLAG_RXNE) == SET) { *outBuffer = SPI_ReceiveData(SPI_x); } ..... Tx_Buffer = inBuffer;2014-06-19 08:10 AM
Clearing TC flags is a good idea, and even better if you clear flags before re-enabling your DMA.
2014-06-19 01:09 PM
2014-06-21 12:58 AM
How the SPI is actually started, normally you would write TX reg to start SPI and after successful transmit DMA request is generated.