Skip to main content
KSchr.11
Associate III
February 22, 2020
Solved

Not able to send 8-bit data on SPI.

  • February 22, 2020
  • 4 replies
  • 2900 views

I am learning bare-metal programming on STM32F411RE (Nucleo board). I am trying to implement a SPI driver.

Reference manual

Even though I have set the Data Frame Format to 8-bit, My SCK consists of 16 clock cycles. Sending 8 bit data on this has weird behavior(I am trying to send 0x9D below):

0690X00000DC8Y2QAL.png

Here's my code:

#include "stm32f4xx.h" // Device header
 
void SPI1_init(void);
void SPI_write(uint8_t data);
 
 
int main()
{
	SPI1_init();
	
	GPIOA->BSRR = 1<<4;
	
	while(1)
	{
		GPIOA->BSRR = 1<<20;				//assert ~CS
		
		SPI_write(0x9D);
		//SPI_write(0xA2);
 
		GPIOA->BSRR = 1<<4;				//de-assert ~CS
	}
	
}
 
 
 
 
void SPI1_init(void)
{
	RCC->AHB1ENR |= 1;								//enable clock to PortA
	RCC->APB2ENR |= 1<<12;						//enable clock to SPI1
	
	GPIOA->MODER &= ~(3<<14 | 3<<10 | 3<<12 | 3<<8);		//clear SPI bits
	GPIOA->MODER |= (2<<10 | 2<<14 | 2<<12 | 1<<8 );	//set MOSI,MISO,SCK bits for AF and NSS as GPO
	
	GPIOA->AFR[0] &= ~(0xF<<20 | 0xF<<24 | 0xF<<28);			//clear AF
	GPIOA->AFR[0] |= (5<<20 | 5<<24 | 5<<28);			//setting AF05 for MOSI,MISO and SCK
	
	//SPI1->CR1 &= ~(1<<6);
	SPI1->CR1 = 0x31C;											//disable SPI, 8 bit, Master, Mode0 SPI
	//SPI1->CR1 &=~(1<<11);
	SPI1->CR2 |= 0;												//Motorola Frame format
	SPI1->CR1 |= 0x40;										//SPI enable
	
}
 
 
 
 
void SPI_write(uint8_t data)
{
	while(!(SPI1->SR & 0x2));		//till transmit buffer is NOT empty, do nothing.
	
	SPI1->DR = data;
	
	while(SPI1->SR & 0X80);		//while BSY flag is 1 do nothing. ie wait till transmission is complete
	
}

Sending 16 bit data, of-course, works perfectly (sending 0x9D and 0xA2 here):

0690X00000DC8YRQA1.png

My application requires me to send 24 bit data in a single ~CS cycle. So I can't use the 16-bit frame format. I need 8 bit frame format. Going through forum answers I found this answer trying to force the data register as:

*(__IO uint8_t *)&SPI->DR = data;

But even this doesn't work for me. I am still getting the 16 clock cycles on SCK. Any tips?

This topic has been closed for replies.
Best answer by berendi

Note that the BSY bit is not set immediately when DR is written. Wait for TXE=1 first, then for BSY=0, and only then disable CS.

Casting to *(volatile uint8_t *)&SPI->DR might not even be necessary on the F4 series.

4 replies

berendi
berendiBest answer
Principal
February 23, 2020

Note that the BSY bit is not set immediately when DR is written. Wait for TXE=1 first, then for BSY=0, and only then disable CS.

Casting to *(volatile uint8_t *)&SPI->DR might not even be necessary on the F4 series.

KSchr.11
KSchr.11Author
Associate III
February 23, 2020

Thanks a ton! That simple change in code actually worked like a charm. :)

Should have read the instructions in RM carefully,my bad.

S.Ma
Principal
February 23, 2020

Check in the reference manual if your SPI has FIFO built-in for 8 or 16 bit write queuing. If not, the SPI is Gen1 and the cast is only needed for futureproofing your code.

Well, take an example SPI code (STM32Cube for the F411 nucleo, spi example, LL if available), run the example in 8 bit mode, and use debugger to look at the SPI registers. Then compare with your own.

berendi
Principal
February 23, 2020

F4 SPI has no FIFO.