cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303 SPI alternative use of the NSS pin problem

gbigden
Associate III
Posted on May 12, 2015 at 17:52

When using SPI2 PB12 is the NSS pin. However, I want to use PB12 as an output and not have it set or reset by the NSS when using SPI2. I thought I had done that by this line of code: 

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

However, when I try to use PB12 something is pulling it hard low. Any suggestions?

#spi-protocol-stm32f303
2 REPLIES 2
Posted on May 12, 2015 at 18:22

Don't define it as an AF pin?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
michaeljulius9
Associate II
Posted on May 15, 2015 at 02:33

I've had the exact same issue!

I used the STM32CubeMX application to specify SPI2 with software controlled nSS and set the nSS pin (Port B Pin 12) as a GPIO output.  The auto-generated intialisation code looks fine (extracts below):

main()

...

 

  HAL_Init();

 

  /* Configure the system clock */

 

  SystemClock_Config();

 

  /* Initialize all configured peripherals */

 

  MX_GPIO_Init();

 

  MX_ADC1_Init();

 

  MX_SPI1_Init();

 

  MX_SPI2_Init();

 

  MX_TIM2_Init();

 

  MX_USART2_UART_Init();

 

...

MX_GPIO_Init()

...

  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_12|GPIO_PIN_4;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

...

MX_SPI2_Init

{

  hspi2.Instance = SPI2;

  hspi2.Init.Mode = SPI_MODE_MASTER;

  hspi2.Init.Direction = SPI_DIRECTION_2LINES;

  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;

  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;

  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;

  hspi2.Init.NSS = SPI_NSS_SOFT;

  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;

  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;

  hspi2.Init.TIMode = SPI_TIMODE_DISABLED;

  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;

  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLED;

  HAL_SPI_Init(&hspi2);

}

What I noticed is that after MX_GPIO_Init() the mode set for Port B pin 12 is “GPIO Ouptut�?, but after the call to MX_SPI2_Init() the mode is “Alternate Function�?.  This seems to be as a result of setting the SPI2 configuration registers (not any direct access to the Port’s MODER register), so the peripheral is taking control of the pin even though we specified a software driven nSS.  This doesn’t appear to happen to the nSS pin for SPI1.

The way I fixed it was to manually restore Port B Pin 12 to the correct mode after all the other initialisation:

#define STM32_PIN_MODE_BITS_PER_PIN  (2)     /**< Number of bits used to specify each pin's mode */

#define STM32_PIN_MODE_BITS_MASK     (3) /**< Selects all bits relative to the GPIO modes */

 

/** Mode that each GPIO pin can have.  Each pin can be one of these modes */

typedef enum

{

    STM32_PIN_MODE_GPIO_INPUT = 0,

    STM32_PIN_MODE_GPIO_OUTPUT = 1,

    STM32_PIN_MODE_ALTERNATE_FUNCTION = 2,

    STM32_PIN_MODE_ANALOG = 3,

}

Stm32GpioPinMode;

/** Function used to explicitly set the mode of any GPIO pin. Note that the pin number

* is an integer note a pin bit map, so use ''4'' not ''GPIO_PIN_4'' */

void stm32_set_pin_mode(GPIO_TypeDef * pGpio, uint8_t pinNumber, Stm32GpioPinMode mode)

{

    pGpio->MODER &= ~(STM32_PIN_MODE_BITS_MASK<<(pinNumber*STM32_PIN_MODE_BITS_PER_PIN));

    pGpio->MODER |= (mode<<(pinNumber*STM32_PIN_MODE_BITS_PER_PIN));

}

main()

...

 

  HAL_Init();

 

  /* Configure the system clock */

 

  SystemClock_Config();

 

  /* Initialize all configured peripherals */

 

  MX_GPIO_Init();

 

  MX_ADC1_Init();

 

  MX_SPI1_Init();

 

  MX_SPI2_Init();

 

  MX_TIM2_Init();

 

  MX_USART2_UART_Init();

 

  /* When SPI2 is initialised, the pin used for nSS is setup as an ''alternate function''

   * pin, which means the GPIO is claimed by the SPI peripheral as a dedicated nSS

   * pin, even though we request a software driven nSS.  This work around resets the

   * pin as an output.  This doesn't seem to happen with SPI1 */

    stm32_set_pin_mode(GPIOB, 12, STM32_PIN_MODE_GPIO_OUTPUT);

}

In my application, this issue came about because the SPI toggles the slave select pin between each byte, and my application requires that it is held low for the entire SPI command (4 bytes).  I thought disabling NSS pulse mode via “

SPI_NSS_PULSE_DISABLED

�? would be the solution, but I got no nSS behaviour at all when I disabled pulse mode (does anyone know why?), so I resorted to a manually controlling the nSS via the GPIO.