2019-05-18 08:19 AM
Hello,
I'm learning to use the SPI module. I'm using an STM32F446RET development board. I want to configure the SPI1 module and send some message 'out into the world'(this means I only have one master devices which sends some bytes and no slave to recieve them).
I have configured the pins in this fasion:
I have written a code that's supposed to send 1's continuously.
main.c(please ignore my comments at the end :D)
#include "init_functions.h"
#include<string.h>
void SPI_SendData(uint8_t *strbuff, uint32_t len)
{
while(len > 0)
{
while( !(SPI1->SR & 2) ); // wait untill tx buffer is not empty
SPI1->DR = *strbuff;
len--;
strbuff++; // point to next byte
}
}
void SPI_SendOnes()
{
while( (SPI1->SR & 2) == 0 ); // wait untill tx buffer is not empty
SPI1->DR = 1;
int a = SPI1->DR;
}
int main()
{
char user_data[] = "Hello world";
init_GPIOS_SPI1();
config_SPI1();
while(1)
{
// send data
SPI_SendOnes();
while( (SPI1->SR & (1 << 7)) ) // wait till SPI is not busy
{
}
// disable spi
//SPI1->CR1 &= ~( 1 << 6 );
}
return 0;
}
//SPI1->SR[bit 7] -> busy flag(0 - not busy; 1 - SPI (or I2S) is busy in communication or Tx buffer is not empty ). set/cleared by hw
//SPI1->SR[bit 1] -> transmit buffer empty(1 - tx buffer empty; 0 not empty)
//SPI1->SR[bit 0] -> recieve buffer...
//SPI1->DR -> data register(data recieved or to be transmitted). A write to the data register will write into the Tx buffer and a read
// from the data register will return the value held in the Rx buffer.
int_functions.c
#include "init_functions.h"
void init_GPIOS_SPI1(void)
{
/*
SPI1 - APB2(90Mhz)
Address range SPI_1: 0x4001 3000 - 0x4001 33FF
PA4 - SPI1_NSS
PA5 - SPI1_SCK
PA6 - SPI1_MISO
PA7 - SPI1_MOSI
*/
/* Enable GPIOA bus clock */
RCC->AHB1ENR |= 1;
/* Configure SPI pins */
//SCLK(PA5)
GPIOA->MODER |= ( 1 << 11 ); // af mode
GPIOA->MODER &= ~( 1 << 10 );
GPIOA->OTYPER &= ~( 1 << 5 ); // push-pull
GPIOA->OSPEEDR |= ( 1 << 11 ); // fast speed
GPIOA->OSPEEDR &= ~( 1 << 10 );
GPIOA->PUPDR &= ~( 1 << 10 ); // no pull up/down
GPIOA->PUPDR &= ~( 1 << 11 );
GPIOA->AFR[0] |= ( 1 << 22 ); // AF5(SPI1_SCK)
GPIOA->AFR[0] |= ( 1 << 20 );
//MOSI(PA6)
GPIOA->MODER |= ( 1 << 13 ); // af mode
GPIOA->MODER &= ~( 1 << 12 );
GPIOA->OTYPER &= ~( 1 << 6 ); // push-pull
GPIOA->OSPEEDR |= ( 1 << 13 ); // fast speed
GPIOA->OSPEEDR &= ~( 1 << 12 );
GPIOA->PUPDR &= ~( 1 << 12 ); // no pull up/down
GPIOA->PUPDR &= ~( 1 << 13 );
GPIOA->AFR[0] |= ( 1 << 26 ); // AF5(SPI1_MOSI)
GPIOA->AFR[0] |= ( 1 << 24 );
//MISO(PA7)
//NSS(PA4)
}
void config_SPI1(void)
{
RCC->APB2ENR |= ( 1 << 12 ); //SPI1 clock enable
SPI1->CR1 |= ( 1 << 15 ); // 1 line bidirectional mode selected
SPI1->CR1 |= ( 1 << 14 ); // output enabled: transmit only mode
SPI1->CR1 &= ~( 1 << 11 ); // 8-bit data frame format for transmission/reception
SPI1->CR1 &= ~( 1 << 7 ); // MSB transmitted first
SPI1->CR1 |= ( 1 << 6 ); // SPI1 enabled
SPI1->CR1 |= ( 1 << 2 ); // master configuration
SPI1->CR1 |= ( 1 << 1 ); // CK to 1 when idle
SPI1->CR1 &= ~( 1 << 0 ); // first clock transition is the first data capture edge
}
I have checked with an oscilloscope and expected to see a continous clock signal as the application is supposed to continously send 1's to the outside world. I have put the probe on the PA5(CLK) pin but it just stays low.
I then inspected the code and I have discovered that the code halts when it gets to this line the second time:
while( (SPI1->SR & 2) == 0 ); // wait untill tx buffer is not empty
Which means the data I want to send gets put into the transmit/recieve buffer but then it does not get put into the TX buffer to get transmited through the bus into the 'world'.
I cannot see what I've configured wrong. Please if possible help me correct this. Thanks.
2019-05-20 10:45 AM
It tends to be that if the SPI drives the NSS-line, and it's driven in different state than the SPI tries to drive it, the SPI makes mode error and becomes a slave.
Just programming the pin output is not enough, because the SPI still listens to it. So, you might want to use the software slave management (SSM in CR1 = 1) and tell the SPI to stay master (SSI in CR1 = 1) and disable NSS output (SSOE in CR2 = 0) and handle the NSS by SW using a plain GPIO.
That is: IF there is a mode error (check the status register).
2019-05-21 11:41 PM
Hello,
I have configured the NSS pin as some people said and now it works.
2019-05-22 08:09 AM
You don't need to configure NSS *pin*. It's enough to set both SSM=1 and SSI=1, as turboscrew wrote above.
JW
2019-05-23 08:30 AM
thank you all for the quick and good answers :folded_hands:
2020-09-30 09:04 PM
I have the same SPI1 PA5 problems on stm32f730 and read the old thread on " STM32F7: SPI1 does not assert RXNE or RXDMA-request with the same settings SPI2 and SPI4 do." Conclusion was: "Some progress here: if I (in GPIO config) move SCK from PA5 to PB3, RXNE gets asserted! Any ideas what could be wrong with PA5? "
The "solution" was using PB3 instead of PA5 for the sclk. Had to spin new pcbs (bit-bang spi for initial workaround). I have not seen an errata on this though. It would be nice.
2020-10-02 12:33 AM
Please start a new thread, describing exactly your hardware/software, the symptoms, and give a readout of relevant SPI and GPIO registers, giving a link to this thread.
JW