AnsweredAssumed Answered

stm32f429 - difference between SPI on APB1 and APB2?

Question asked by huber.thomas.002 on Jul 21, 2016
Latest reply on Jul 21, 2016 by waclawek.jan
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);

Outcomes