2017-03-06 04:30 PM
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 SPI2static __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); // SPI2GPIO_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 enableDMA_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);}Solved! Go to Solution.
2017-03-07 02:09 PM
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);}2017-03-06 05:10 PM
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
2017-03-07 02:09 PM
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);}