cancel
Showing results for 
Search instead for 
Did you mean: 

Problem while writing to SPI data register on Nucleo-64 , STM32F411-re

Npiet.1
Associate II

I am new to this nucleo board ( Nucleo-64 , STM32F411-re). I've configured SPI1 port as master and SPI4 port as slave. I am trying to establish communication between these two ports and verifying the data weather its reflecting on SPI1-> DR data registers.

I am having some doubts

  1. Is it possible to establish communication between two SPI ports on same board( SPI1 and SPI4 )
  2. Do this board has any loopback register so that I can verify the data I am sending
  3. Am I configured SPI registers correctly?? for above mentioned task
  4. Am I configured SPI NSS pin correctly??, provide I am configuring in Software mode as mentioned in the usermanual.

While debugging and watching the value of SPI-> DR register I am not able to see any values in the SPI Data register

// ----------------------------------------------------------------------------
 
#include <stdio.h>
#include <stdlib.h>
#include "diag/Trace.h"
#include "stm32f4xx.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_hal.h"
// ----------------------------------------------------------------------------
//
// Standalone STM32F4 empty sample (trace via DEBUG).
//
// Trace support is enabled by adding the TRACE macro definition.
// By default the trace messages are forwarded to the DEBUG output,
// but can be rerouted to any device or completely suppressed, by
// changing the definitions required in system/src/diag/trace_impl.c
// (currently OS_USE_TRACE_ITM, OS_USE_TRACE_SEMIHOSTING_DEBUG/_STDOUT).
//
 
// ----- main() ---------------------------------------------------------------
 
// Sample pragmas to cope with warnings. Please note the related line at
// the end of this function, used to pop the compiler diagnostics status.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#pragma GCC diagnostic ignored "-Wreturn-type"
#define size 8
 
char TxBuffer[size];
char RxBuffer[size];
char length = 8;
 
void init_periperalclock()   //init_peripheralClock();
{
	  /* Enable GPIO clock */
	  RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN);   //Port A clock enable
 
	  /* Enable SPI clock */
	  RCC->APB2ENR |= (RCC_APB2ENR_SPI1EN|RCC_APB2ENR_SPI4EN);  //SPI 1 Clock enable
	  //RCC->APB1ENR |= 16384;   //SPI 2 Clock enable
}
void init_gpio()
{
 
	/* Connections are as follows
	 * PA4 --> PB12  Slave select
	 * PA5 --> PB13  SCLK
	 * PA6 --> PA11  MISO
	 * PA7 --> PA1   MOSI
	 */
 
	// SPI1 --> PA4 - SS, PA5 - SCLK, PA6 - MISO, PA7 - MOSI
	GPIOA ->MODER |= (GPIO_MODER_MODER4_0|GPIO_MODER_MODER5_1|GPIO_MODER_MODER6_1|GPIO_MODER_MODER7_1); // PA5 PA6 PA7 - AF & PA4 - SS  // 256 + 2048 + 8192 + 32678 == 43264
	GPIOA ->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR4|GPIO_OSPEEDER_OSPEEDR5|GPIO_OSPEEDER_OSPEEDR6|GPIO_OSPEEDER_OSPEEDR7); // High speed
	GPIOA ->OTYPER |= (GPIO_ODR_ODR_4|GPIO_ODR_ODR_5|GPIO_ODR_ODR_6|GPIO_ODR_ODR_7); //Open drain
	GPIOA ->PUPDR |= (GPIO_PUPDR_PUPDR4_0|GPIO_PUPDR_PUPDR5_0|GPIO_PUPDR_PUPDR6_0|GPIO_PUPDR_PUPDR7_0);  // Push pull
    //GPIOA ->AFR[0] = 0x0050;
 
    // SPI4 --> PB12 - SS, PB13 - SCLK, PA1 - MOSI, PA11 - MISO
	GPIOA ->MODER |= (GPIO_MODER_MODER1_1|GPIO_MODER_MODER11_1);
	GPIOB ->MODER |= ((GPIO_MODER_MODER12_0|~GPIO_MODER_MODER12_0)|GPIO_MODER_MODER13_1);
 
	GPIOA ->OSPEEDR |=(GPIO_OSPEEDER_OSPEEDR1|GPIO_OSPEEDER_OSPEEDR11);
	GPIOB ->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR12|GPIO_OSPEEDER_OSPEEDR13); // High speed
 
	GPIOA ->OTYPER |= (GPIO_ODR_ODR_1|GPIO_ODR_ODR_11);
	GPIOB->OTYPER |= (GPIO_ODR_ODR_12|GPIO_ODR_ODR_13); // Open drain
 
	GPIOA ->PUPDR |= (GPIO_PUPDR_PUPDR1_0|GPIO_PUPDR_PUPDR11_0);
	GPIOB ->PUPDR|= (GPIO_PUPDR_PUPDR12_0|GPIO_PUPDR_PUPDR13_0);  // Push pull
 
	// PA5 - SCLK for SPI1, PA6 - MISO for SPI1, PA7 - MOSI for SPI1
	GPIOA ->AFR[0] = ((5<<20)|(5<<24)|(5<<28));
	GPIOA ->AFR[0] = 5<<4;  // PA1 - MOSI for SPI4
	GPIOA ->AFR[1] = 6<<12; // PA11- MISO for SPI4
	GPIOB ->AFR[1] = 6<<20; // PB13- SCLK for SPI4
}
 
void init_spiParameters()
{
	/* Setting up parameters for SPI1 (Master)
	  This configuration corresponds to MOSI
	  as Output Data and MISO as Input data*/
	SPI1 ->SR |= 0;
	SPI1 ->CR1 |= (SPI_CR1_BR_1 & ~SPI_CR1_BR_1); // Baud rate is set to fper/2
	SPI1 ->CR1 |= (SPI_CR1_CPOL|SPI_CR1_CPHA); // Setting up clock polarity and phase
 	SPI1 ->CR1 |= (SPI_CR1_DFF & ~SPI_CR1_DFF); // Selecting 8 bit data format // After this line BSY flag is setting
	SPI1 ->CR1 |= SPI_CR1_LSBFIRST; // Selecting LSB value first for transmission
	SPI1 ->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); // Slave select Output Enable
	SPI1 ->CR1 |= (SPI_CR1_MSTR | SPI_CR1_SPE);  // Declaring SPI1 as Master
 
 
	/* Setting up parameters for SPI4 (Slave)
	  This configuration corresponds to MISO
	  as Output Data and MOSI as Input data*/
	SPI4 ->CR1 |= (SPI_CR1_DFF & ~SPI_CR1_DFF);  // setting up DFF bit
	SPI4 ->CR1 |= (SPI_CR1_CPOL|SPI_CR1_CPHA); // Setting up clock polarity and phase
	SPI4 ->CR1 |= SPI_CR1_LSBFIRST; // Selecting LSB value first for transmission
	SPI4 ->CR1 |= SPI_CR1_SSM;  // Enabling SSM bit
	SPI4 ->CR1 |= (SPI_CR1_SSI & ~SPI_CR1_SSI); //Resetting SSI bit
	SPI4 ->CR1 |= SPI_CR1_SPE;  // Enabling SPI
	SPI4 ->CR1 |= (SPI_CR1_MSTR & ~SPI_CR1_MSTR); // Declaring SPI4 as Slave
}
 
void spiWrite()
{
	for(int i=0; i<length;)
	{
		if ((((SPI1 ->SR) & SPI_SR_TXE) == SPI_SR_TXE))
		{
			TxBuffer[i] = i;
			SPI1 ->DR = TxBuffer[i];  // MOSI A7 Line SPI1 carries this data
			i++;
		}
	}
 
}
 
void spiRead()
{
	for(int i =0; i<length;)
	{
		if ((((SPI4 ->SR) & SPI_SR_RXNE) == SPI_SR_RXNE))
		{
			RxBuffer[i] = SPI4 ->DR;  // MISO Line of SPI4 receives data
			i++;
	    }
	}
 
}
 
int
main(int argc, char* argv[])
{
 
  init_periperalclock();
  init_gpio();
  init_spiParameters();
  spiWrite();
  spiRead();
 
}
 
#pragma GCC diagnostic pop
 
// ----------------------------------------------------------------------------

3 REPLIES 3
KnarfB
Principal III

Didn't look at all register setup details, just one remark: you have to poll in an endless loop for SPI_SR_TXE and SPI_SR_RXNE

conditions. Therefore, you need another while loop within the for.

> Is it possible to establish communication between two SPI ports on same board( SPI1 and SPI4 )

Yes, thats possible. But I doubt that it will work with a sequential spiWrite() and spiRead() because write and read occur on the same SPI clock cycles. For short messages the FIFOs might help, but in general people use interrupt or DMA features for simultaneous write+read.

Npiet.1
Associate II

0690X00000D8Pv5QAF.png0690X00000D8PoiQAF.pngHi KnarfB,

I've edited code as you've mentioned above, Still I couldn't find an changes also the data isn't reflected/ written to SPI Data register. I have attached screenshots for your reference. If subsequent read and write is a problem, I had change the code such that It performs only spiWrite(), still the data is not written into the register.

while ((((SPI1 ->SR) & SPI_SR_TXE) == SPI_SR_TXE))
		{
			for(int i=0; i<length;)
			{
				TxBuffer[i] = i;
				SPI1 ->DR = TxBuffer[i];  // MOSI A7 Line SPI1 carries this data
				i++;
			}
                 }

KnarfB
Principal III

> Therefore, you need another while loop within the for.

You have to wait (poll) for each and every individual byte/char.

Here is a small example using SPI2 and SPI3 on a Nucleo-F446RE. It assumes that the GPIOs are already configured and copies the string from tx to rx buffer via SPI:

static char tx[16] = "Hello\r\n";
  static char rx[16];
 
  SPI2->CR1 = 0;
  SPI2->CR1 |= SPI_CR1_SSM;			// NSS in software
  SPI2->CR1 |= SPI_CR1_SSI;			// Internal slave select
  SPI2->CR1 |= SPI_CR1_MSTR;			// master mode
  SPI2->CR1 |= 5 << SPI_CR1_BR_Pos;		// 64:1 bitrate
  SPI2->CR1 |= SPI_CR1_SPE;			// SPI enable
 
  SPI3->CR1 = 0;
  SPI3->CR1 |= SPI_CR1_SSM;			// NSS in software
  SPI3->CR1 |= SPI_CR1_SPE;			// SPI enable
 
  for( int i=0; i<strlen(tx); ++i )
  {
	  while( !(SPI2->SR & SPI_SR_TXE) ); // poll for TX empty
	  SPI2->DR = tx[i];
 
	  while( !(SPI3->SR & SPI_SR_RXNE) ); // poll for RX non-empty
	  rx[i] = SPI3->DR;
  }
 
HAL_UART_Transmit( &huart2, rx, strlen(rx), HAL_MAX_DELAY );

Note that this is a toy example because the slave SPI needs to poll all the time to listen for (and not to miss) incoming chars. So, finally you might want to add interrupt handling or DMA. Note also that slave select is not handled here.