cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F207 Uni Directional SPI - Rx using DMA

jm4ck3nz13
Associate II
Posted on March 07, 2017 at 01:30

Hi Everyone,

my set-up is an STM32F205 transmitting fixed length data ( < 64 bytes ) periodically to an STM32F207 via SPI. I am only interested in receiving data, nothing is sent on the 207's MISO line.

The 207 receives data Ok when using spi interrupts, but doesn't when using DMA. 

The DMA transfer complete interrupt fires (TCIF flag = 1, and I see HTIF = 1 that gives some confidence DMA is seeing something),  but data never appears in the memory buffer.

It is so close to working - there must be a bit I'm missing somewhere.  I've spent the last few days googling SPI configurations and reading the STM ref manual and I can't see why this shouldn't work!

Any ideas?

NB I haven't included the interrupt handler as it is just an empty function, but am breaking on it in the debugger to read registers etc.

#define SPIipc SPI2

static __IO uint8_t DMAbufferRx[64];

void ipc_spi_init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

// Enable peripheral clock

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

GPIO_Clk_Init(SPIipc_GPIO_Clk, ENABLE); // GPIOB

SPIipc_Clk_Init(SPIipc_Clk, ENABLE); // SPI2

GPIO_PinAFConfig(SPIipc_GPIO, SPIipc_SCK_Src, SPIipc_SCK_AF);

GPIO_PinAFConfig(SPIipc_GPIO, SPIipc_MOSI_Src, SPIipc_MOSI_AF);

GPIO_PinAFConfig(SPIipc_GPIO, SPIipc_MISO_Src, SPIipc_MISO_AF);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

GPIO_InitStructure.GPIO_Pin = SPIipc_SCK_Pin; // Pin 13

GPIO_Init(SPIipc_GPIO, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = SPIipc_MOSI_Pin; // Pin 15

GPIO_Init(SPIipc_GPIO, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = SPIipc_MISO_Pin; // Pin 14

GPIO_Init(SPIipc_GPIO, &GPIO_InitStructure);

// SPI configuration

SPI_StructInit(&SPI_InitStructure);

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Rx;

SPI_I2S_DeInit(SPIipc);

SPI_Init(SPIipc, &SPI_InitStructure);

while(SPI_I2S_GetFlagStatus(SPIipc, SPI_I2S_FLAG_TXE) == RESET);

// Configure Rx DMA

DMA_Cmd(DMA1_Stream3, DISABLE);

while (DMA1_Stream3->CR & DMA_SxCR_EN);

DMA_DeInit(DMA1_Stream3);

DMA_StructInit( &DMA_InitStructure );

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DMAbufferRx[0];

DMA_InitStructure.DMA_BufferSize = sizeof( DMAbufferRx );

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

DMA_Init(DMA1_Stream3, &DMA_InitStructure);

// Clear any pending (old) DMA1 Stream 3 Interrupts

DMA1->LIFCR = (uint32_t)0x0F400000;

while(DMA1->LISR & 0x0F400000 );

// DMA transfer complete interrupt enable

DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);

// Enable DMA interrupt

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

// Enable the DMA SPI RX Stream

DMA_Cmd(DMA1_Stream3, ENABLE);

// Enable SPI DMA RX Requsts

SPI_I2S_DMACmd(SPIipc, SPI_I2S_DMAReq_Rx, ENABLE);

// Enable the SPI peripheral

SPI_Cmd(SPIipc, ENABLE);

}
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on March 07, 2017 at 22:09

Clive,

thanks for your comments. Points about providing all code and using explicit defines noted.

The DMA IRQ does fire, but when it does there is no apparent data in DMAbufferRx (all zeros).

I reverted to no-DMA-SPI-with-interrupt-on-RXNE and received only zeros, so suspected the SPI direction config.

Must have had brain fade because I'd changed SPI_Direction_2Lines_FullDuplex to SPI_Direction_1Line_Rx. This doesn't mean 'Rx only on one line' as I thought, it means 1-line bidirectional mode! As an SPI slave in 1-line configuration uses the MISO pin, that explains the zeros read on the MOSI pin. The fix is change back to SPI_Direction_2Lines_FullDuplex; SPI_Direction_2Lines_RxOnly also works.

John

Updated code:

static __IO uint8_t DMAbufferRx[64];

void ipc_spi_init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

// Enable peripheral clocks

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

// Connect SPI pins to AF

GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

// SPI SCK pin configuration

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// SPI MOSI pin configuration

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// SPI MISO pin configuration

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

// SPI configuration

SPI_StructInit(&SPI_InitStructure);

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; <== changed from SPI_Direction_1Line_Rx

SPI_I2S_DeInit(SPI2);

SPI_Init(SPI2, &SPI_InitStructure);

while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

// Configure Rx DMA

DMA_Cmd(DMA1_Stream3, DISABLE);

while (DMA1_Stream3->CR & DMA_SxCR_EN);

DMA_DeInit(DMA1_Stream3);

DMA_StructInit( &DMA_InitStructure );

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DMAbufferRx[0];

DMA_InitStructure.DMA_BufferSize = sizeof( DMAbufferRx );

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

DMA_Init(DMA1_Stream3, &DMA_InitStructure);

// Clear any pending (old) DMA1 Stream 3 Interrupts

DMA1->LIFCR = (uint32_t)0x0F400000;

while(DMA1->LISR & 0x0F400000 );

// DMA transfer complete interrupt enable

DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);

// Enable DMA interrupt

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

// Enable the DMA SPI RX Stream

DMA_Cmd(DMA1_Stream3, ENABLE);

// Enable SPI DMA RX Requsts

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

// Enable the SPI peripheral

SPI_Cmd(SPI2, ENABLE);

}

View solution in original post

2 REPLIES 2
Posted on March 07, 2017 at 02:10

Can we please, please, please post sufficiently complete code. If you use defines, provide them ALL. Ideally it should compile. If you spend days on something, take the defines out, so the use case is explicit and not abstracted.

SPIipc_Clk_Init(SPIipc_Clk, ENABLE); // SPI2  Double check APB being used

The DMA IRQ not firing is odd. Make sure it is asserting the right TCIF3 bit. If the DMA is not generating an interrupt it is likely not working, which would explain the lack of data.

For the Slave data needs to be present on the MOSI pin

Can't say I've actively used Rx DMA in Slave SPI

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on March 07, 2017 at 22:09

Clive,

thanks for your comments. Points about providing all code and using explicit defines noted.

The DMA IRQ does fire, but when it does there is no apparent data in DMAbufferRx (all zeros).

I reverted to no-DMA-SPI-with-interrupt-on-RXNE and received only zeros, so suspected the SPI direction config.

Must have had brain fade because I'd changed SPI_Direction_2Lines_FullDuplex to SPI_Direction_1Line_Rx. This doesn't mean 'Rx only on one line' as I thought, it means 1-line bidirectional mode! As an SPI slave in 1-line configuration uses the MISO pin, that explains the zeros read on the MOSI pin. The fix is change back to SPI_Direction_2Lines_FullDuplex; SPI_Direction_2Lines_RxOnly also works.

John

Updated code:

static __IO uint8_t DMAbufferRx[64];

void ipc_spi_init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

// Enable peripheral clocks

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

// Connect SPI pins to AF

GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

// SPI SCK pin configuration

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// SPI MOSI pin configuration

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// SPI MISO pin configuration

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

// SPI configuration

SPI_StructInit(&SPI_InitStructure);

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; <== changed from SPI_Direction_1Line_Rx

SPI_I2S_DeInit(SPI2);

SPI_Init(SPI2, &SPI_InitStructure);

while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);

// Configure Rx DMA

DMA_Cmd(DMA1_Stream3, DISABLE);

while (DMA1_Stream3->CR & DMA_SxCR_EN);

DMA_DeInit(DMA1_Stream3);

DMA_StructInit( &DMA_InitStructure );

DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &DMAbufferRx[0];

DMA_InitStructure.DMA_BufferSize = sizeof( DMAbufferRx );

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

DMA_Init(DMA1_Stream3, &DMA_InitStructure);

// Clear any pending (old) DMA1 Stream 3 Interrupts

DMA1->LIFCR = (uint32_t)0x0F400000;

while(DMA1->LISR & 0x0F400000 );

// DMA transfer complete interrupt enable

DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);

// Enable DMA interrupt

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

// Enable the DMA SPI RX Stream

DMA_Cmd(DMA1_Stream3, ENABLE);

// Enable SPI DMA RX Requsts

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

// Enable the SPI peripheral

SPI_Cmd(SPI2, ENABLE);

}