cancel
Showing results for 
Search instead for 
Did you mean: 

How to read data as master on SPI?

KSchr.11
Associate II

I am learning serial protocols using STM32 boards (F411RE and L432KC). So far I have successfully configured the boards as master and slave to send data from one board to another, and as I checked it works perfectly(I communicate the received data from board to PC via UART). That utilized the MOSI line. Now I am trying to get data from the slave, using the MISO line.

As I learned, to get data from slave you write a dummy byte to slave like 0x00 and get the data in the same chip select cycle. I did that and hooked up the MISO line to scope, decoded it and the line has my string in the appropriate order.

However, storing the string on the master side seems to be an issue. Both the MCUs have a single data register in SPI module for tx and rx.

I try to send "hello" from slave and this is what I am getting on master:

0693W000000VLiLQAW.jpg

It's not perfect, there are repeated as well as alternate characters.

I am sharing the codes for master and slave, which are quite long, but the main function might be the only thing to looked at.

Code for Master:

#include "stm32l4xx.h"                  // Device header
#include <string.h>
 
#define CS_LOW (GPIOA->BSRR = (1<<20))
#define CS_HI (GPIOA->BSRR = (1<<4))
 
 
void SPI_init(void);
void SPI_write(uint8_t data);
void delayms(int count);
void setclkfreq(void);
 
void UART_init(void);
void uart_txchar(char c);
void uart_txstr(char* string);
 
 
 
 
int main()
{
	char buff[16] = {0};
	setclkfreq();						//set clock to 16Mhz
	SPI_init();							
	UART_init();
	
	CS_HI;
	
	while(1)
	{
		
		CS_LOW;
		
		for(int i=0; i<5; i++)
		{
			
			SPI_write(0x00);					//write dummy byte
		
			buff[i] = SPI1->DR;				//store MISO data in buff
		
		}
		
		CS_HI;
		
		uart_txstr(buff);                             //write buff data to PC
		uart_txstr("\n\r");
		delayms(1000);
	}
	
}
 
 
 
 
void SPI_init(void)
{
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
	
	GPIOA->MODER &=~(3<<8 | 3<<10 | 3<<12 | 3<<14);
	GPIOA->MODER |= (1<<8 | 2<<10 | 2<<12 | 2<<14);			//CS is selected as GPO while others are AFs
	
	//GPIOA->PUPDR |= 1<<12;			//pull up MISO line
	
	
	GPIOA->AFR[0] &=~(0XF<<20 | 0xF<<24 | 0xF<<28);
	GPIOA->AFR[0] |= (5<<20 | 5<<24 | 5<<28);				//af for mosi,miso and sck
	
	SPI1->CR1 &=~ (SPI_CR1_SPE);
	SPI1->CR1 |= (3<<3) | SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM;
	
	SPI1->CR1 |= SPI_CR1_SPE;
}
 
 
 
 
 
void SPI_write(uint8_t data)
{
	*(__IO uint8_t *)&SPI1->DR = data;
	while(!(SPI1->SR & SPI_SR_TXE));
	while((SPI1->SR & SPI_SR_BSY));
 
}
 
 
 
 
void SPI_writestring(char* str)
{
	int len = strlen(str);
	
	for(int i=0; i<len; i++)
	{
		CS_LOW;
		SPI_write(str[i]);
		CS_HI;
	}
	
}
 
 
 
 
 
void delayms(int count)
{
	int i;
	SysTick->LOAD = 16000;		//16000 cycles in 1 ms
	SysTick->VAL = 0;					//reset current value to 0
	SysTick->CTRL = 5;				//clksource = internal. counter enabled. interrupt disabled
	
	for(i=0; i<count; i++)			//repeat 1ms cycles count number of times
	{
		while((SysTick->CTRL & 0x10000)==0){}			//do nothing till Countflag becomes 1
	}
	
	SysTick->CTRL=0;		//disable counter
	
}
 
 
 
void setclkfreq(void)
{
	FLASH->ACR &=~ FLASH_ACR_LATENCY;
	FLASH->ACR |= FLASH_ACR_LATENCY_0WS;			
	
	RCC->CR |= RCC_CR_MSION;		//turn on MSI (Multi Speed Internal)
	
	RCC->CFGR &=~ RCC_CFGR_SW;
	
	while(!(RCC->CR & RCC_CR_MSIRDY));
	
	RCC->CR &=~ RCC_CR_MSIRANGE;
	RCC->CR |= RCC_CR_MSIRANGE_8;				//16Mhz
	
	RCC->CR |= RCC_CR_MSIRGSEL;
	
	while(!(RCC->CR & RCC_CR_MSIRDY));
	
	
	
}
 
void UART_init(void)
{
	RCC->APB1ENR1 &=~ RCC_APB1ENR1_USART2EN;
	RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;		//ENABLE UART2
 
	RCC->AHB2ENR &=~ RCC_AHB2ENR_GPIOAEN;
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;			//PORT A enable
 
	
	GPIOA->AFR[0] &=~ 0XF00;
	GPIOA->AFR[0] |= 0X700;				//ENABLE transmit
	
	GPIOA->MODER &=~(3<<4);
	GPIOA->MODER |= 2<<4;			//PA2 output
	
	USART2->CR1 &=~ (USART_CR1_UE);
	
	USART2->BRR = 0x683;				// 9600 bps
	
	USART2->CR1 |= USART_CR1_TE;
	
	USART2->CR1 |= USART_CR1_UE;
	
}
 
void uart_txchar(char c)
{
	while(!(USART2->ISR & (USART_ISR_TXE)));
	USART2->TDR = c;
	while(!(USART2->ISR & USART_ISR_TC));
	
}
 
void uart_txstr(char* string)
{
	while(*string)
	{
		uart_txchar(*(string++));
	}
	
}
 

Code for Slave :

#include "stm32f4xx.h"                  // Device header
#include <string.h>
 
/*
PA5 - SCK
PA4 - NSS
PA7 -MOSI
PA6 - MISO
*/
 
 
void SPI1_init(void);
char SPI_read(void);
void delayms(int count);
void SPI_write(char data);
void SPI_writestring(char* str);
 
 
 
int main()
{
 
	char buff[16] = {0};
	char c;
	
	SPI1_init();
 
	while(1)
	{
		//c = SPI_read();
		SPI_writestring("hello");
		delayms(1000);
		
	}
	
}
 
 
 
 
void SPI1_init(void)
{
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;								//enable clock to PortA
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;						//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 | 2<<8 );	//set MOSI,MISO,NSS,SCK bits for AF 
	
	GPIOA->PUPDR |= 1<<14;
	
	GPIOA->AFR[0] &= ~(0xF<<16 | 0xF<<20 | 0xF<<24 | 0xF<<28);			//clear AF
	GPIOA->AFR[0] |= (5<<20 | 5<<24 | 5<<28 | 5<<16);			//setting AF05 for MOSI,MISO and SCK
	
	SPI1->CR1 &=~(SPI_CR1_SPE);
	SPI1->CR1 |= (3<<3);											//Mode0
	SPI1->CR1 &=~ (SPI_CR1_MSTR | SPI_CR1_SSI | SPI_CR1_SSM);         //slave and hw NSS
	
	SPI1->CR1 |= SPI_CR1_SPE;										//SPI enable
	
}
 
 
 
 
 
 
 
 
 
char SPI_read(void)
{
	char data;
	while(!(SPI1->SR & SPI_SR_RXNE));
	
	
	while(SPI1->SR & SPI_SR_BSY);
	
	data = SPI1->DR;
	
	return data;
	
}
 
void SPI_write(char data)
{
	SPI1->DR = data;
	
	while(!(SPI1->SR & SPI_SR_TXE));
	while(SPI1->SR & SPI_SR_BSY);
}
 
void SPI_writestring(char* str)
{
	int len= strlen(str);
	
	for(int i=0; i<len; i++)
	{
		SPI_write(str[i]);
	}
}
 
 

I have tried removing the given delays too, had no effect.

Since on the scope, I am getting the data on MISO line correctly, I suspect my method of storing data on master side is the flawed one.

How do I deal with this?

1 ACCEPTED SOLUTION

Accepted Solutions

buff[i] = *(__IO uint8_t *)&SPI1->DR; //store MISO data in buff

See Data packing section in SPI chapter in RM. You have used it for Tx...

JW

View solution in original post

2 REPLIES 2

buff[i] = *(__IO uint8_t *)&SPI1->DR; //store MISO data in buff

See Data packing section in SPI chapter in RM. You have used it for Tx...

JW

Thank you so much. You pointed reading Data packing last time too, but I didn't, sorry. And as you pointed, yeah I forgot the casting. My bad. 😅