Getting started with STM32L053: SPI Full Duplex

In the previous guide (here), we saw how to transfer data over SPI using DMA. In this guide, we shall see how to receive data from SPI bus.

In this guide, we shall cover the following:

  • SPI Receive function.
  • MPU9250 connection.
  • Code.
  • Results.

1. SPI Receive function:

In order to receive from SPI, the following steps are required:

  • Send dummy data (0x00 or 0xFF).
  • Wait until RX buffer is filled.
  • Read the DR register to store the received value.

Declare the following function:

void spi1_receive(uint8_t *data,uint32_t size)

The function takes two arguments:

  • Pointer to the data to be received.
  • Size of data to be received.

Within the function:

declare a while loop with condition of size:

while(size)

within while loop:

send dummy data:

SPI1->DR = 0;  // send dummy data

Wait until the RX buffer is filled by reading RXNE bit in SR (Status Register) of the SPI:

while (!((SPI1->SR) &(SPi_SR_RXNE))){};

Store the data of DR register in the pointer and increment the pointer as following:

*data++ = (SPI1->DR);

decrement the size:

size--;

That all for the receive function:

The entire function as following:

void spi1_receive(uint8_t *data,uint32_t size)
{
	while(size){

		SPI1->DR = 0;  // send dummy data
		while (!((SPI1->SR) &(1<<0))){};
		 /*Read data from Data Register*/
		 *data++ = (SPI1->DR);
		size--;

	}
}

2. MPU9250 connection:

To initialize the MOU9250 acceleration part:

void MPU9250_beginAccel(uint8_t mode) {
  switch(mode) {
  case ACC_FULL_SCALE_2_G:
    accelRange = 2.0;
    break;
  case ACC_FULL_SCALE_4_G:
    accelRange = 4.0;
    break;
  case ACC_FULL_SCALE_8_G:
    accelRange = 8.0;
    break;
  case ACC_FULL_SCALE_16_G:
    accelRange = 16.0;
    break;
  default:
    return; // Return without writing invalid mode
  }

  uint8_t data[2]={MPU9250_ADDR_ACCELCONFIG,mode};
  cs_low();
  spi_transmit(data, 2);
  cs_high();
	
}

To initialize the Gyroscope part:

oid MPU9250_beginGyro(uint8_t mode) {
  
  switch (mode) {
  case GYRO_FULL_SCALE_250_DPS:
    gyroRange = 250.0;
    break;
  case GYRO_FULL_SCALE_500_DPS:
    gyroRange = 500.0;
    break;
  case GYRO_FULL_SCALE_1000_DPS:
    gyroRange = 1000.0;
    break;
  case GYRO_FULL_SCALE_2000_DPS:
    gyroRange = 2000.0;
    break;
  default:
    return; // Return without writing invalid mode
  }
  uint8_t data[2]={27,mode};
  cs_low();
  spi_transmit(data, 2);
  cs_high();
}

To read the acceleration:

uint8_t MPU9250_accelUpdate(void)
{
	uint8_t data=0x3B|READ_FLAG;
	cs_low();
	spi_transmit(&data, 1);
	spi_receive(accelBuf,6);
	cs_high();
	return 0;
 
}

To read the gyroscope:

uint8_t MPU9250_gyroUpdate(void)
{
	uint8_t data=0x43|READ_FLAG;
	cs_low();
	spi_transmit(&data, 1);
	spi_receive(gyroBuf, 6);
	cs_high();
	return 0;
}

For full details about MPU9250, refer to this guide here.

In main.c:

#include "spi.h"
#include "stdio.h"
#include "uart.h"
#include "mpu9250.h"
#include "delay.h"
int main(void)
{
	systick_init_ms(2097000);
	uart_init();
	spi_init();
	MPU9250_beginAccel(ACC_FULL_SCALE_16_G);
	MPU9250_beginGyro(GYRO_FULL_SCALE_2000_DPS);

	while(1)
	{
		MPU9250_accelUpdate();
		MPU9250_gyroUpdate();

		printf("Acceleration data %0.3f %0.3f %0.3f \r\n",MPU9250_accelX(),MPU9250_accelY(),MPU9250_accelZ());
		printf("Gyroscope data %0.3f %0.3f %0.3f \r\n",MPU9250_gyroX(),MPU9250_gyroY(),MPU9250_gyroZ());
		delay(500);


	}

}

3. Code.

You may download the source code from here:

4. Results:

Upload the code to STM32L053 Nucleo-64 and open serial terminal and set baudrate to 115200 and you should get the following results:

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *