cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f429 - difference between SPI on APB1 and APB2?

thuber9
Associate
Posted on July 21, 2016 at 08:07

Dear All,

On STM32F4 (I'm using a stm32f429), is there any significant difference between using SPI peripherals on APB1 (SPI2, SPI3) or on APB2 (SPI1, SPI4, SPI5, SPI6)? I'm trying to read PDM data from digital MEMS microphones which are all clocked from the same master clock (generated by I2S2). Data is read correctly when using SPI3 in Rx slave mode, but when I try to use a SPI peripherials on APB2 (e.g. SPI1) the data transmitted by the DMA is zero. Important parts of my code is appended below. There's a single routine to setup all SPIs with DMA, and even if I have checked the setup several times now, I just can't find where the error could be. Any hints and help from the experts would be indeed much appreciated. Thanks!

/* SPI configuration structure */
typedef struct SPIconf {
uint32_t spi_sck_pin;
GPIO_TypeDef *spi_sck_gpio_port;
uint32_t spi_sck_gpio_clk;
uint8_t spi_sck_source;
uint8_t spi_sck_af;
uint32_t spi_mosi_pin; 

GPIO_TypeDef *spi_mosi_gpio_port;
uint32_t spi_mosi_gpio_clk;
uint8_t spi_mosi_source;
uint8_t spi_mosi_af; 
uint32_t dma_ahb1;
uint32_t dma_channel; 

DMA_Stream_TypeDef *dma_stream; 

IRQn_Type irqn_type; 

SPI_TypeDef* SPIx;
} SPIconf;
SPIconf spi1conf = {GPIO_Pin_5, /* spi_sck_pin */
GPIOA, /* spi_sck_gpio_port */
RCC_AHB1Periph_GPIOA, /* spi_sck_gpio_clk */
GPIO_PinSource5, /* spi_sck_source */
GPIO_AF_SPI1, /* spi_sck_af */
GPIO_Pin_7, /* spi_mosi_pin */
GPIOA, /* spi_mosi_gpio_port */
RCC_AHB1Periph_GPIOA, /* spi_mosi_gpio_clk */
GPIO_PinSource7, /* spi_mosi_source */
GPIO_AF_SPI1, /* spi_mosi_af */
RCC_AHB1Periph_DMA2, /* dma_ahb1 */
DMA_Channel_3, /* dma_channel */
DMA2_Stream0, /* dma_stream */
DMA2_Stream0_IRQn, /* irqn_type */
SPI1}; /* SPIx */ 
SPIconf spi3conf = {GPIO_Pin_3, /* spi_sck_pin */
GPIOB, /* spi_sck_gpio_port */ 
RCC_AHB1Periph_GPIOB, /* spi_sck_gpio_clk */ 
GPIO_PinSource3, /* spi_sck_source */ 
GPIO_AF_SPI3, /* spi_sck_af */ 
GPIO_Pin_5, /* spi_mosi_pin */ 
GPIOB, /* spi_mosi_gpio_port */ 
RCC_AHB1Periph_GPIOB, /* spi_mosi_gpio_clk */ 
GPIO_PinSource5, /* spi_mosi_source */ 
GPIO_AF_SPI3, /* spi_mosi_af */ 
RCC_AHB1Periph_DMA1, /* dma_ahb1 */ 
DMA_Channel_0, /* dma_channel */ 
DMA1_Stream2, /* dma_stream */ 
DMA1_Stream2_IRQn, /* irqn_type */ 
SPI3}; /* SPIx */ 
void SPI_DMA_Config(SPIconf *spiconf, uint32_t *indata1, uint32_t *indata2)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
SPI_TypeDef *SPIx = spiconf->SPIx;
/* Enable GPIO clocks */
RCC_AHB1PeriphClockCmd(spiconf->spi_sck_gpio_clk | spiconf->spi_mosi_gpio_clk, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = spiconf->spi_sck_pin;
GPIO_Init(spiconf->spi_sck_gpio_port, &GPIO_InitStructure);
/* Connect SPI pins to AF5 */ 
GPIO_PinAFConfig(spiconf->spi_sck_gpio_port, spiconf->spi_sck_source, spiconf->spi_sck_af);
/* SPI MOSI pin configuration */
GPIO_InitStructure.GPIO_Pin = spiconf->spi_mosi_pin;
// GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_Init(spiconf->spi_mosi_gpio_port, &GPIO_InitStructure);
GPIO_PinAFConfig(spiconf->spi_mosi_gpio_port, spiconf->spi_mosi_source, spiconf->spi_mosi_af);
/* Enable DMA clock */
RCC_AHB1PeriphClockCmd(spiconf->dma_ahb1, ENABLE);
// reset DMA stream to default values;
DMA_DeInit(spiconf->dma_stream);
while (DMA_GetCmdStatus (spiconf->dma_stream) != DISABLE) {}
/* SPIx_Rx double buffer DMA configuration */
DMA_InitStructure.DMA_Channel = spiconf->dma_channel; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(SPIx->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) indata1;
DMA_InitStructure.DMA_BufferSize = (uint32_t) PDM_BUFF_SIZE;
// Double buffer mode
DMA_DoubleBufferModeConfig(spiconf->dma_stream, (uint32_t) indata2, DMA_Memory_0); 
DMA_DoubleBufferModeCmd(spiconf->dma_stream, ENABLE);
DMA_Init(spiconf->dma_stream, &DMA_InitStructure);
/* enable DMA interrupt for half and full completion */
DMA_ITConfig(spiconf->dma_stream, DMA_IT_TC, ENABLE);
if (SPIx == SPI1)
DMA_ClearFlag(spiconf->dma_stream, DMA_FLAG_FEIF0|DMA_FLAG_DMEIF0|DMA_FLAG_TEIF0|DMA_FLAG_HTIF0|DMA_FLAG_TCIF0);
else if (SPIx == SPI3)
DMA_ClearFlag(spiconf->dma_stream, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
else if (SPIx == SPI4)
DMA_ClearFlag(spiconf->dma_stream, DMA_FLAG_FEIF3|DMA_FLAG_DMEIF3|DMA_FLAG_TEIF3|DMA_FLAG_HTIF3|DMA_FLAG_TCIF3);
else if (SPIx == SPI5)
DMA_ClearFlag(spiconf->dma_stream, DMA_FLAG_FEIF5|DMA_FLAG_DMEIF5|DMA_FLAG_TEIF5|DMA_FLAG_HTIF5|DMA_FLAG_TCIF5);
else if (SPIx == SPI6)
DMA_ClearFlag(spiconf->dma_stream, DMA_FLAG_FEIF6|DMA_FLAG_DMEIF6|DMA_FLAG_TEIF6|DMA_FLAG_HTIF6|DMA_FLAG_TCIF6);
else {
/* not valid SPI */
while (1) {}
}
// Enable DMA1 channel IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = spiconf->irqn_type;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* enable DMA transfer */
DMA_Cmd(spiconf->dma_stream, ENABLE);
while (DMA_GetCmdStatus(spiconf->dma_stream) != ENABLE) {}
/* initialize SPIx Rx slave */
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
/* this conditional doesn't seem to make any difference and can be deleted (??) */
if ((SPIx == SPI2) || (SPIx == SPI3)) /* APB1 */
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
else /* APB2 */
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPIx, &SPI_InitStructure);
SPI_CalculateCRC(SPIx, DISABLE);
SPI_TIModeCmd(SPIx, DISABLE);
// SPI_SSOutputCmd(SPIx, ENABLE);
// SPI_NSSInternalSoftwareConfig(SPIx, SPI_NSSInternalSoft_Set);
/* Enable SPIx */
SPI_Cmd(SPIx, ENABLE); 
/* enable SPIx-DMA interface */
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
}
extern uint8_t spi_ready;
/* spi1 DMA interrupt handler */
void DMA2_Stream0_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) {
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0 | DMA_IT_TEIF0);
spi_ready |= SPI1_MIC_READY;
}
}
/* spi3 DMA interrupt handler */
void DMA1_Stream2_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_Stream2, DMA_IT_TCIF2)) {
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_TCIF2 | DMA_IT_TEIF2);
spi_ready |= SPI3_MIC_READY;
}
}
and in main:
/* setup I2S2 to produce master clock for all microphones */
/* start SPI1 Rx */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* first SPI MIC */
SPI_DMA_Config(&spi1conf, (uint32_t *) &PDMBuffer[1*PDM_BUFF_SIZE],
(uint32_t *) &PDMBuffer[(NR_SPI+1)*PDM_BUFF_SIZE]);
/* start SPI3 Rx */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
/* first SPI MIC */
SPI_DMA_Config(&spi3conf, (uint32_t *) &PDMBuffer[2*PDM_BUFF_SIZE],
(uint32_t *) &PDMBuffer[(NR_SPI+2)*PDM_BUFF_SIZE]);
/* Enable SPI2 peripheral */
I2S_Cmd(SPI2, ENABLE); 

#spi #stm32f429
2 REPLIES 2
Posted on July 21, 2016 at 18:22

Well primarily that APB2 is clocked at twice the rate of APB1, and thus the USART and SPI peripheral on the faster bus can be used at higher baud/bit rates.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on July 21, 2016 at 21:10

> the data transmitted by the DMA is zero

Are they? So, you initialized the array to non-zero values and after a while, the array was all zero?

This is the kind of problem which is well debuggable with a debugger. Observe the GPIO (you may need to refresh the registers' view, depending on your toolchain) input register - you should see the changing level of the MISO pin. Then observe the DMA's NDTR, it should be changing. Don't attempt to look at the SPI registers though while expecting it to work, that would interfere with DMA.

And, of course, check the content of all relevant GPIO, DMA and SPI registers.

JW