2020-04-06 12:30 AM
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:
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?
Solved! Go to Solution.
2020-04-06 01:11 AM
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
2020-04-06 01:11 AM
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
2020-04-06 01:26 AM
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. :grinning_face_with_sweat: