cancel
Showing results for 
Search instead for 
Did you mean: 

Failing to receive data on MCU set up as SPI slave

KSchr.11
Associate II

Trying to receive data on MCU (L432KC) configured as SPI slave. I have tried using interrupt and DMA, but no luck.

I have set up the circuit like this : 1 MCU acts as master sending 1,2,3 every 500ms interval (I hooked up master lines to scope and the signals are generated correctly). On the other MCU configured as slave, I've connected a RGB led, which is supposed to react to 1,2,3.

Here's my code (interrupt handler commented)

#include "stm32l4xx.h"                  // Device header
 
//RGB led is common anode 
 
#define RED_ON (GPIOB->ODR &=~(1<<1))
#define RED_OFF (GPIOB->ODR |=1<<1)
 
#define BLUE_ON (GPIOB->ODR &=~(1<<6))
#define BLUE_OFF (GPIOB->ODR |= 1<<6)
 
#define GREEN_ON (GPIOB->ODR &=~(1<<7))
#define GREEN_OFF (GPIOB->ODR |= 1<<7);
 
void SPI1_Slave_init(void);
void delayms(int count);
int SPI1_read(void);
void SPI1rx_DMA_init(int c);
 
 
int main()
{
	int c=1;
	SPI1_Slave_init();
	SPI1rx_DMA_init(c);
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
	
	GPIOB->MODER &=~(3<<2 | 3<<12 | 3<<14);
	GPIOB->MODER |= 1<<2 | 1<<12 | 1<<14;
	
	GPIOB->ODR |= (1<<1 | 1<<6 | 1<<7);
	
	//NVIC_EnableIRQ(SPI1_IRQn);
	
	while(1)
	{
		DMA1_Channel2->CCR |= DMA_CCR_EN;			//enable channel 
		
		while(!(DMA1->ISR & DMA_ISR_TCIF2));			//wait till channel 2 transfer is complete
		
		
		
		
		switch(c)
		{
			case 1: GREEN_OFF;
			BLUE_OFF;
			RED_ON;
			break;
			
			case 2: RED_OFF;
			BLUE_OFF;
			GREEN_ON;
			break;
			
			case 3: RED_OFF;
			GREEN_OFF;
			BLUE_ON;
			break;
			
		}
		
		DMA1->IFCR |= DMA_IFCR_CTCIF2;
		
		DMA1_Channel2->CCR &=~ (DMA_CCR_EN);		//disable channel
		
	}
}
 
void SPI1_Slave_init(void)
{
	RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
	
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
	
	GPIOA->MODER &=~(3<<8 | 3<<10 | 3<<12 | 3<<14);
	GPIOA->MODER |= (2<<8 | 2<<10 | 2<<12 | 2<<14);			//set as AF
	
	
	GPIOA->AFR[0] &=~(0xF<<16 | 0XF<<20 | 0xF<<24 | 0xF<<28);
	GPIOA->AFR[0] |= (5<<16 | 5<<20 | 5<<24 | 5<<28);				//AF5 
	
	SPI1->CR1 &=~ (SPI_CR1_SPE);			//disable SPI
	
	SPI1->CR1 &=~ (SPI_CR1_SSI | SPI_CR1_SSM | SPI_CR1_MSTR);			//slave
	
	SPI1->CR1 |= (1<<3);			// 1MHz baud rate
	
	SPI1->CR2 &= ~(0xF<<8);
	SPI1->CR2 |= 7<<8;				//8 bit data
	
	//SPI1->CR2 |= SPI_CR2_RXNEIE;			//enable RXNE interrupt
	
	SPI1->CR1 |= SPI_CR1_SPE;
}
 
void SPI1rx_DMA_init(int c)
{
	
	RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
	
	//DMA channel config
	DMA1_Channel2->CCR &=~(DMA_CCR_EN);
	DMA1_Channel2->CCR &=~(DMA_CCR_DIR);
	DMA1_Channel2->CNDTR = 1;
	DMA1_Channel2->CPAR = (uint32_t)&SPI1->DR;			
	DMA1_Channel2->CMAR = (uint32_t)c;
	DMA1_CSELR->CSELR |= 1<<4;				//DMA1 Channel 2 mapped to request no 2 (SPI1_RX)
	
	SPI1->CR2 |= SPI_CR2_RXDMAEN;
	
}
 
 
 
/*
void SPI1_IRQHandler(void)
{
	uint8_t c;
	
	if(SPI1->SR & SPI_SR_RXNE)
	{
		c = *(__IO uint8_t *)&SPI1->DR;
		
		switch(c)
		{
			case 1: GREEN_OFF;
			BLUE_OFF;
			RED_ON;
			break;
			
			case 2: RED_OFF;
			BLUE_OFF;
			GREEN_ON;
			break;
			
			case 3: RED_OFF;
			GREEN_OFF;
			BLUE_ON;
			break;
			
		}
	}
	
}
 
*/

I've tested the LED part of code separately, blinking R,G and B and it also works fine.

Again, tested interrupt and DMA separately, so ignore one while considering the other in the code. I've tested it with a normal receive subroutine too, but I had not much hope with it anyway.

Just failing to receive data on slave. What am I doing wrong?

EDIT : Here are the waveforms on scope. When disconnected from slave, the waveforms are perfect. However when I connect the master to slave, there is some noise and the SCL line has a amplitude of 900mV.

0693W000001rE5UQAU.png0693W000001rE5PQAU.png

1 ACCEPTED SOLUTION

Accepted Solutions

> I've added the waveforms from scope please check that out. When connected this slave device, the SCL line goes a crazy.

That's SCK fighting against a pin being set high. Check your connections, maybe SCK from master goes to something different than SCK of slave.

Is the slave something like a Disco or Nucleo? If yes, are all relevant onboard connections (jumpers, solder bridges) disconnected?

JW

View solution in original post

12 REPLIES 12

Read out and check/post the SPI and relevant GPIO registers content.

JW

berendi
Principal

And DMA registers too if you are using it.

I would try it without DMA or interrupts first, waiting for RXNE to be set before reading the data register. If that doesn't work, neither interrupt nor DMA would.

Verify that all 3 inputs (NSS, CLK, MOSI) work by reading GPIOA->IDR. Slow down the master or increase the main clock frequency of the slave as much as you can for this experiment.

Try removing this line

SPI1->CR2 |= 7<<8;

as the slave is rather clocked by the master.

I tried with a normal subroutine too by checking RXNE. I removed that line too. Hasn't worked.

I've uploaded some waveforms please check that out. When connected to slave, the SCL line goes crazy.

How do I check the registers? I tried to add a UART subroutine to check my variable which receives the data from SPI->DR. But I've got nothing on terminal since pretty sure the while loop I have that waits for TC flag to be set doesn't exit.

I've added the waveforms from scope please check that out. When connected this slave device, the SCL line goes a crazy.

> I've added the waveforms from scope please check that out. When connected this slave device, the SCL line goes a crazy.

That's SCK fighting against a pin being set high. Check your connections, maybe SCK from master goes to something different than SCK of slave.

Is the slave something like a Disco or Nucleo? If yes, are all relevant onboard connections (jumpers, solder bridges) disconnected?

JW

> How do I check the registers?

The easiest is to reading them out using debugger.

If you don't have/use debugger, read out their content and transmit through the UART you use for debugging.

JW

My master device is a Disco board (STM32F303). I've tried a very similar program with same transmit subroutine on a port expander (MCP23S17) as slave and there it works perfectly fine. So I believe the master side has no issues.

My slave in this program is a Nucleo L432KC. While I have removed the jumper it came with, I'll look into the user manual to see if that particular pin is connected to something else, or I might try different pin or different SPI module (SPI3). I had set this same device (and with same pins) as a master to experiment on port expander I mentioned above couple of weeks back and had no issues.

It's a Nucleo board so I believe the debugger is built onto the board itself. I haven't used it for anything other than flashing my code through Keil. Is STM32 ST-Link Utility the program you use to debug and check the registers?

Hey I just used PA1 instead of PA5 for SCK and it works fine now. I checked user manual to see if PA5 was connected to something and don't really see anything.

Anyway, the pin going high for whatever reason was the cause of the problem. Thanks.