2011-08-01 01:17 AM
Please could someone post the details to manage the SPI NSS signal? I want to use the SPI as a full-duplex master (sending and receiving data simultaneously). I have read many posts about the NSS deficiencies in the STM32 implementation and I believe that although NSS may be asserted low automatically, it must be cleared high by interrupting on (SPI RX flag ?).
If someone has the detail of how to configure the SPI and make this work, please share. I have read and re-read the latest reference manual and it is still not clear how NSS works. thanks ... John F. #spi-nss2011-08-10 03:19 AM
Software nss example:
TRegister curReg; bit isWaitAnswer = 0;//Èíèöèàëèçàöèÿ SPI2 íà 34á 35á 36 (PB13,14,15), ñîôòîâîãî NSS íà PB12
//pin33 -- NSS -- PB12 -- OUT -- PP -- //pin34 -- SCK -- PB13 -- AF -- PP -- //pin35 -- MISO -- PB14 -- AF -- OD -- //pin36 -- MOSI -- PB15 -- AF -- PP -- void SPI_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; SPI_InitTypeDef SPI_InitStructure; /* Enable the SPI clock */ RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );/* Enable GPIO clocks */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE );/* Connect SPI pins to AF5 */
GPIO_PinAFConfig( GPIOB, GPIO_PinSource13, GPIO_AF_SPI2 ); GPIO_PinAFConfig( GPIOB, GPIO_PinSource14, GPIO_AF_SPI2 ); GPIO_PinAFConfig( GPIOB, GPIO_PinSource15, GPIO_AF_SPI2 ); //GPIO_PinAFConfig( GPIOB, GPIO_PinSource12, 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 MOSI pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_Init( GPIOB, &GPIO_InitStructure );/* SPI configuration -------------------------------------------------------*/
SPI_I2S_DeInit(SPI2); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_Init(SPI2, &SPI_InitStructure); SPI_SSOutputCmd(SPI2, ENABLE);SPI_Cmd(SPI2, ENABLE);
/* Configure the Priority Group to 1 bit */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Configure the SPI interrupt priority */ NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); SPI_I2S_ITConfig( SPI2, SPI_I2S_IT_RXNE, ENABLE ); //SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE); //SDN Config RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE ); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;/* SPI SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_Init( GPIOA, &GPIO_InitStructure ); //NSS Config RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE ); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 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_12; GPIO_Init( GPIOB, &GPIO_InitStructure ); }void SendData( uint16_t what );
void SendData( uint16_t what ){
GPIOB->BSRRH = GPIO_Pin_12; isWaitAnswer = 1; SPI_I2S_SendData ( SPI2, what ); while( isWaitAnswer == 1 ); // while( SPI_I2S_GetFlagStatus( SPI2, SPI_I2S_FLAG_BSY ) == SET ); GPIOB->BSRRL = GPIO_Pin_12; }void ForceReg( unsigned char rw, unsigned char addr, unsigned char what ){
uint16_t dataToSend; dataToSend = (rw << 15) | (addr << 8) | (what & 0xFF); SendData( dataToSend ); }/**
* @brief This function handles SPI interrupt request. * @param None * @retval None */ void SPI2_IRQHandler(void) { /* SPI in Slave Receiver mode--------------------------------------- */ if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET) { uint16_t result = SPI_I2S_ReceiveData(SPI2); isWaitAnswer = 0; curReg.dataFromReg = ( result ) & 0xFF; // }/* SPI in Master Tramitter mode--------------------------------------- */
if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) == SET) { // SendData( 0 ); } }2011-08-10 06:49 AM
thanks Vladimir.
2011-08-10 07:14 AM
Hello,
The NSS on the STM32 doens't act as a chip select thant can be used to synchronize the data exchange operations. The datasheet isn't clear and already has some errata but still not clear. As the STM32 doens't has a FIFO on it's receive/transmit buffer, I suggets you use the NSS pin as a standard GPIO and drive it with an interrupt routine for Tx, or to a hardware exterial IT for Rx (most of GPIO pins can be internally routed to interrupt line). If you wan to use the NSS as ''soft driving'' it won't work (excepted if you manually drive it with the library functions), and as ''hardware driving'', it will always output ''0'' when the SPI is master. NSS means ''non slave select'' (as i remember). Source : myself, I spend a lot of time on this SPI.2011-08-10 09:10 AM
Thanks Nolly. Anyone else have practical experience with the SPI? I am mostly interested in STM32 SPI as full duplex master. Can the NSS hardware mode be used where sending a frame sets NSS low and NSS is then reset high by an end of frame interrupt?
2011-08-17 04:23 AM
Yes, you can do that, by software.
You can make the pin high or low on an interrupt using the library functions. Do this like that : -When you send a frame, first put CS low and then use the library function ''SEND_SPI'' (or some name like that). -At the end of transmission, use an interrupt on the RXNE flag (not TXNE !) I explain why. You have three buffer on SPI (MISO and MISO) : -send -receive -latch (serialisation) TXNE will inform you that the send buffer has been pulled out to the latch buffer and can be filled again with the 32bit internal bus. BUT the bits are not yet all serially latched in the latch buffer ! This delay depend of the SPI latch clock. Your CS will go high to soon. RXNE will inform you that the receive buffer is full (8 or 16 bits are read) so it is ready to been pulled down to the receive buffer and then processed by the processor. Since you are in master mode, It mean that the latch buffer has sent all the bits. So, you know exactly when put CS high. And if it's not clear just trust me I have done like that :)2011-08-17 05:51 AM
Thanks Nolly. I understand the comment about the flags - I must wait until all bits have been clocked out and (in Master mode) this is the same as waiting for all bits to be clocked in - where RXNE flag will be set.