cancel
Showing results for 
Search instead for 
Did you mean: 

SPI master with DMA - problem

zoharr
Associate II
Posted on June 19, 2014 at 15:29

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-dma
9 REPLIES 9
stm322399
Senior
Posted on June 19, 2014 at 15:57

DMA data size should be set to halfword if you intend to transfer 16-bit word through SPI.

zoharr
Associate II
Posted on June 19, 2014 at 16:08

Thanks for your response.

I'm transferring 1 byte at a time, just using two transfer cycles.

stm322399
Senior
Posted on June 19, 2014 at 16:17

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.

zoharr
Associate II
Posted on June 19, 2014 at 16:29

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);

......

stm322399
Senior
Posted on June 19, 2014 at 16:55

You need to remove the extra character when RXNE is *SET*

zoharr
Associate II
Posted on June 19, 2014 at 17:01

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;

stm322399
Senior
Posted on June 19, 2014 at 17:10

Clearing TC flags is a good idea, and even better if you clear flags before re-enabling your DMA.

zoharr
Associate II
Posted on June 19, 2014 at 22:09

I want to add some info that maybe important to this issue.

When using SPI with polling, the first byte always return 0xFF (something like ACk) and the second byte returns the data I need.

When I'm trying to use SPI with DMA, I always get 0xFF.

I think, as gonzalez saied, that the first byte is revived OK,  but the second byte does not. Since the SPI rx is not empty, I receive for the second byte the same data.

I need to clear the SPI rx somehow.

I still can't understand how to do it.

Should I use interrupts? or there is another way?

I read in some other threads that disabling SPI can help. But I need the SPI enable for other communications as master, and I don't want to disable it. 

zzdz2
Associate II
Posted on June 21, 2014 at 09:58

How the SPI is actually started, normally you would write TX reg to start SPI and after successful transmit DMA request is generated.