Working with STM32 and Acceleration Sensor: ADXL345 in SPI mode Part 2

In part 1 (here), we saw to configure the SPI and other parameters required for ADXL345 operation in SPI mode. We shall continue from here:

8. adx345 read/write functions:

In order for the adxl345 to distinguish between SPI and I2C, when sending the address, a bit shall be set called multibyte as shown here:

Hence, we shall create two symbolic names for read operation and multibyte as following:

#define   MULTI_BYTE_EN			0x40
#define	  READ_OPERATION		0x80

Hence, the adxl345 read function as following:

static void adxl345_read(uint8_t address, uint8_t * rxdata)
{
	
	/*Set read operation*/
	address |= READ_OPERATION;

	/*Enable multi-byte*/
	address |= MULTI_BYTE_EN;

	/*Pull cs line low to enable slave*/
	cs_enable();

	/*Send address*/
	spi1_transmit(&address,1);

	/*Read 6 bytes */
	spi1_receive(rxdata,6);

	/*Pull cs line high to disable slave*/
	cs_disable();

}

adxl345 write function:

static void adxl345_write(uint8_t address, uint8_t value)
{
	uint8_t data[2];

	/*Enable multi-byte, place address into buffer*/
	data[0] = address|MULTI_BYTE_EN;

	/*Place data into buffer*/
	data[1] = value;

	/*Pull cs line low to enable slave*/
	cs_enable();

	/*Transmit data and address*/
	spi1_transmit(data, 2);

	/*Pull cs line high to disable slave*/
	cs_disable();


}

The initialization is similar to the i2c guide:

void adxl345_init(adxl345Parameters param)
	{
		acc_range=param;
		adxl_spi_pins_init();
		adxl_spi_config();
		/*Set data format range to +-4g*/
		adxl345_write (DATA_FORMAT_R, param);

		/*Reset all bits*/
		adxl345_write (POWER_CTL_R, RESET);

		/*Configure power control measure bit*/
		adxl345_write (POWER_CTL_R, SET_MEASURE_B);

	}

For the update adxl345 function:

void adxl345_update()
	{



		adxl345_read(DATA_START_ADDR,data_rec);

		x = ((data_rec[1]<<8)|data_rec[0]);
		y = ((data_rec[3]<<8)|data_rec[2]);
		z = ((data_rec[5]<<8)|data_rec[4]);

	}

For getting the values:

void adxl345_get_values(accleration_values_t * values)
	{
	float divider;
	switch(acc_range)
	{
		case accl_2g: divider=0.003906; /*1/256*/	break;
		case accl_4g: divider=0.0078125;/*1/128*/	break;
		case accl_8g: divider=0.01563;	/*1/64*/	break;
		case accl_16g: divider=0.03125;	/*1/32*/	break;
	}

		values->ax=x*divider;
		values->ay=y*divider;
		values->az=z*divider;
	}

Hence, the entire adxl345.c source file:

#include "adxl345.h"
#include "spi.h"


#define DATA_FORMAT_R   		(0x31) /*data format register*/
#define POWER_CTL_R 			(0x2D) /*Power control register*/
#define DATA_START_ADDR			(0x32) /*Start address to read the values*/

#define	RESET					(0x00) /*Reset value*/
#define SET_MEASURE_B		    (0x08) /*Put adxl345 into measurement mode*/

/*Variables which hold some variable*/
uint8_t data_rec[6];
uint8_t acc_range;
int16_t x,y,z;


#define   MULTI_BYTE_EN			0x40
#define	  READ_OPERATION		0x80



static void adxl345_write(uint8_t address, uint8_t value)
{
	uint8_t data[2];

	/*Enable multi-byte, place address into buffer*/
	data[0] = address|MULTI_BYTE_EN;

	/*Place data into buffer*/
	data[1] = value;

	/*Pull cs line low to enable slave*/
	cs_enable();

	/*Transmit data and address*/
	spi1_transmit(data, 2);

	/*Pull cs line high to disable slave*/
	cs_disable();


}

static void adxl345_read(uint8_t address, uint8_t * rxdata)
{

	/*Set read operation*/
	address |= READ_OPERATION;

	/*Enable multi-byte*/
	address |= MULTI_BYTE_EN;

	/*Pull cs line low to enable slave*/
	cs_enable();

	/*Send address*/
	spi1_transmit(&address,1);

	/*Read 6 bytes */
	spi1_receive(rxdata,6);

	/*Pull cs line high to disable slave*/
	cs_disable();

}

void adxl345_init(adxl345Parameters param)
	{
		acc_range=param;
		adxl_spi_pins_init();
		adxl_spi_config();
		/*Set data format range to +-4g*/
		adxl345_write (DATA_FORMAT_R, param);

		/*Reset all bits*/
		adxl345_write (POWER_CTL_R, RESET);

		/*Configure power control measure bit*/
		adxl345_write (POWER_CTL_R, SET_MEASURE_B);

	}


void adxl345_update()
	{



		adxl345_read(DATA_START_ADDR,data_rec);

		x = ((data_rec[1]<<8)|data_rec[0]);
		y = ((data_rec[3]<<8)|data_rec[2]);
		z = ((data_rec[5]<<8)|data_rec[4]);

	}

void adxl345_get_values(accleration_values_t * values)
	{
	float divider;
	switch(acc_range)
	{
		case accl_2g: divider=0.003906; /*1/256*/	break;
		case accl_4g: divider=0.0078125;/*1/128*/	break;
		case accl_8g: divider=0.01563;	/*1/64*/	break;
		case accl_16g: divider=0.03125;	/*1/32*/	break;
	}

		values->ax=x*divider;
		values->ay=y*divider;
		values->az=z*divider;
	}

adxl345.h header file:

#ifndef ADXL345_H_
#define ADXL345_H_

#include "stdint.h"

typedef enum
{
	accl_2g=0,
	accl_4g=1,
	accl_8g=2,
	accl_16g=3
}adxl345Parameters;

typedef struct
{

	float ax;
	float ay;
	float az;

}accleration_values_t;

void adxl345_init(adxl345Parameters param);
void adxl345_update();
void adxl345_get_values(accleration_values_t * values);






#endif /* ADXL345_H_ */

Within main.c:

#include "delay.h"
#include "adxl345.h"
#include "stdio.h"
accleration_values_t accleration_values;
extern void uart2_rxtx_init(void);
int main(void)
{
	uart2_rxtx_init();
	adxl345_init(accl_4g);
	while(1)
		{
			adxl345_update();
			adxl345_get_values(&accleration_values);
			printf("ax=%0.5f\tay=%0.5f\taz=%0.5f\r\n",accleration_values.ax,accleration_values.ay,accleration_values.az);
			delay(20);

		}

}

9. Code:

You may download the entire code from here:

10. Results:

Open your serial terminal application and set the baudrate to 115200 and you should get the following:

2 Comments

  • H.S.Raghavendra Rao Posted December 17, 2023 4:46 am

    Dear Sir,
    Namaskar, Good Morning,
    Observed that the main.c in the Zipped version of code downloaded has i2c_init(),
    if wrongly placed please make this corrections, else kindly neglect this mail,
    sorry for the interruption.
    thanks withr egards,
    HSR-Rao.

    • Husamuldeen Posted December 17, 2023 8:34 am

      Hi,
      yes, I noticed it to.
      However, it won’t effect the operation of the code.

Add Comment

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