AnsweredAssumed Answered

STM32 SPI Hardware CS Generation

Question asked by haines.justin on Dec 17, 2012
Latest reply on Aug 5, 2013 by Amor.Ben_amor
I'm working with the STM32F407VG chip (both on the STM32F4Discovery board and a custom board) and having trouble with the SPI port chip select in master mode.  The following is the minimal code to demonstrate my problem:

int main(void)
{
    //
    // Enable the right clock domains
    //
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 
    //
    // Configure the Pin Muxes
    //
    GPIO_InitTypeDef GPIO_InitStructure;
 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource12,  GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,  GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,  GPIO_AF_SPI2);
 
 
    //
    // Configure SPI2
    //
    SPI_InitTypeDef SPI_InitStructure;
 
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    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_Hard;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
 
    SPI_Init(SPI2, &SPI_InitStructure);
    SPI_SSOutputCmd(SPI2, ENABLE);
    SPI_Cmd(SPI2, ENABLE);
 
    while(1)
    {
        SPI_I2S_SendData(SPI2, 0xC3C3);
        while(SPI_I2S_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);
        (void)SPI_I2S_ReceiveData(SPI2);
    }
}

I would expect this code to automatically generate the CS signal to properly frame the SPI transactions, but it doesn't.  The data and clock are correct, but there are no transitions on CS.

This code generates the desired signals:

int main(void)
{
    //
    // Enable the right clock domains
    //
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 
    //
    // Configure the Pin Muxes
    //
    GPIO_InitTypeDef GPIO_InitStructure;
 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,  GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,  GPIO_AF_SPI2);
 
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
 
    //
    // Configure SPI2
    //
    SPI_InitTypeDef SPI_InitStructure;
 
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    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_Hard;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
 
    SPI_Init(SPI2, &SPI_InitStructure);
    SPI_SSOutputCmd(SPI2, ENABLE);
    SPI_Cmd(SPI2, ENABLE);
 
    while(1)
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        SPI_I2S_SendData(SPI2, 0xC3C3);
        while(SPI_I2S_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        (void)SPI_I2S_ReceiveData(SPI2);
    }
}

The second implementation correctly controls the device on the SPI bus, but requires the busy wait.  In my application I have very few clock cycles to spare and would much prefer being able to simply write to the SPI2->DR register and allow the hardware to coordinate the rest.  Does anyone know if it is possible to achieve this?

Thanks,
Justin

Outcomes