Working with STM32 and Acceleration Sensor: ADXL335 Analog Sensor

ADXL335

In this guide, we shall see how to interface ADXL335 Accelerometer sensor with STM32F4. Since this sensor is analog based sensor, we shall use DMA to handle the data from the adxl335. To setup multichannel ADC with DMA, please refer to this guide here.

In this guide, we shall cover the following:

  • ADXL335.
  • Connection.
  • Developing the code
  • Code.
  • Results.

1. ADXL335:

The ADXL335 is a small, thin, low power, complete 3-axis accel- erometer with signal conditioned voltage outputs. The product measures acceleration with a minimum full-scale range of ±3 g. It can measure the static acceleration of gravity in tilt-sensing applications, as well as dynamic acceleration resulting from motion, shock, or vibration.

The user selects the bandwidth of the accelerometer using the CX, CY, and CZ capacitors at the XOUT, YOUT, and ZOUT pins. Bandwidths can be selected to suit the application, with a range of 0.5 Hz to 1600 Hz for the X and Y axes, and a range of 0.5 Hz to 550 Hz for the Z axis.

FEATURES

3-axis sensing
Small, low profile package

4 mm × 4 mm × 1.45 mm LFCSP
Low power : 350 μA (typical) Single-supply operation: 1.8 V to 3.6 V 10,000 
shock survival

Excellent temperature stability
BW adjustment with a single capacitor per axis RoHS/WEEE lead-free compliant

APPLICATIONS

Cost sensitive, low power, motion- and tilt-sensing applications
Mobile devices
Gaming systems

Disk drive protection Image stabilization Sports and health devices

2. Connection:

The connection as following:

ADXL335 STM32F4 Nucleo-64
Vcc5V
GNDGND
XoutPA0
YoutPA1
ZoutPA2

3. Developing the code:

We start off by creating new c source file and header file with the name of adxl335.

With in header file, we shall declare a data structure to hold the acceleration values as following:

typedef struct acc_data_t{
float accx;
float accy;
float accz;
}acc_data_t;

Then the two following functions as following:

void adxl335_init();

void get_accel_data(acc_data_t *acc);

Hence, the header file as following:

#ifndef ADXL335_H_
#define ADXL335_H_

#include "stdint.h"

typedef struct acc_data_t{
float accx;
float accy;
float accz;
}acc_data_t;


void adxl335_init();

void get_accel_data(acc_data_t *acc);


#endif /* ADXL335_H_ */

Now, for the source code, we start with adxl335_init which will be initializing the ADC with DMA.

The ADC with DMA for multichannel configuration as following:

#define LEN_3_CH 0x02

#define CH0 0x00
#define CH1 0x01
#define CH4 0x04

uint16_t acc_data[3];


void adxl335_init()
{
	/*Enable clock access to GPIOA*/
	RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
	/*Configure PA0, PA1 and PA4 as analog*/
	GPIOA->MODER|=GPIO_MODER_MODE0|GPIO_MODER_MODE1|GPIO_MODER_MODE4;

	/*Enable clock access to ADC1*/
	RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;

	/*Enable scan mode */

	ADC1->CR1|=ADC_CR1_SCAN;


	/*Enable the following:
	 * DMA request.
	 * Continuous mode.
	 * */

	ADC1->CR2|=ADC_CR2_CONT|ADC_CR2_DDS|ADC_CR2_DMA;

	/*Set the length of conversion to be 3.*/
	ADC1->SQR1|=(LEN_3_CH<<ADC_SQR1_L_Pos);

	/*Set the sequence as following:
	 * PA0(CH0), PA1(CH1), PA4(CH4)
	 * */

	ADC1->SQR3|=(CH0<<ADC_SQR3_SQ1_Pos)|(CH1<<ADC_SQR3_SQ2_Pos)|(CH4<<ADC_SQR3_SQ3_Pos);

	/*DMA Setup*/

	/*DMA related setup*/
	RCC->AHB1ENR		|=RCC_AHB1ENR_DMA2EN;
	DMA2_Stream0->CR	&=~DMA_SxCR_EN;
	while(DMA2_Stream0->CR ==DMA_SxCR_EN){;}
	DMA2_Stream0->CR	|=DMA_SxCR_MSIZE_0|DMA_SxCR_PSIZE_0|DMA_SxCR_MINC|DMA_SxCR_CIRC;
	DMA2_Stream0->PAR	 =(uint32_t)(&(ADC1->DR));
	DMA2_Stream0->M0AR 	 =(uint32_t )(acc_data);
	DMA2_Stream0->NDTR	 =3;

	/*Launch the DMA*/
	DMA2_Stream0->CR 	|=DMA_SxCR_EN;

	/*Launch the ADC*/
	ADC1->CR2			|=ADC_CR2_ADON;

	ADC1->CR2|=ADC_CR2_SWSTART;


}

After that, we need a helper function that will convert the ADC value to acceleration as following:


static float adc_to_acc(uint16_t adc_value)
{
	return  ((( ( (float)(adc_value * 3.3)/RawMax) - 1.65 ) / 0.330)*9.81);

}

Now for the get_accel_data function. Since the function take a pointer to the data structure acc_data_t as pointer, it is possible to get the members of the structure using -> operator.

Hence, we can get the acceleration values as following:

void get_accel_data(acc_data_t *acc)
{

	float ax_scalled=adc_to_acc(acc_data[0]);
	float ay_scalled=adc_to_acc(acc_data[1]);
	float az_scalled=adc_to_acc(acc_data[2]);


	acc->accx=ax_scalled;
	acc->accy=ay_scalled;
	acc->accz=az_scalled;


}

Hence, the source as following:

#include "stm32f4xx.h"
#include "adxl335.h"

#define LEN_3_CH 0x02

#define CH0 0x00
#define CH1 0x01
#define CH4 0x04

#define RawMax  4095

uint16_t acc_data[3];


void adxl335_init()
{
	/*Enable clock access to GPIOA*/
	RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
	/*Configure PA0, PA1 and PA4 as analog*/
	GPIOA->MODER|=GPIO_MODER_MODE0|GPIO_MODER_MODE1|GPIO_MODER_MODE4;

	/*Enable clock access to ADC1*/
	RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;

	/*Enable scan mode */

	ADC1->CR1|=ADC_CR1_SCAN;


	/*Enable the following:
	 * DMA request.
	 * Continuous mode.
	 * */

	ADC1->CR2|=ADC_CR2_CONT|ADC_CR2_DDS|ADC_CR2_DMA;

	/*Set the length of conversion to be 3.*/
	ADC1->SQR1|=(LEN_3_CH<<ADC_SQR1_L_Pos);

	/*Set the sequence as following:
	 * PA0(CH0), PA1(CH1), PA4(CH4)
	 * */

	ADC1->SQR3|=(CH0<<ADC_SQR3_SQ1_Pos)|(CH1<<ADC_SQR3_SQ2_Pos)|(CH4<<ADC_SQR3_SQ3_Pos);

	/*DMA Setup*/

	/*DMA related setup*/
	RCC->AHB1ENR		|=RCC_AHB1ENR_DMA2EN;
	DMA2_Stream0->CR	&=~DMA_SxCR_EN;
	while(DMA2_Stream0->CR ==DMA_SxCR_EN){;}
	DMA2_Stream0->CR	|=DMA_SxCR_MSIZE_0|DMA_SxCR_PSIZE_0|DMA_SxCR_MINC|DMA_SxCR_CIRC;
	DMA2_Stream0->PAR	 =(uint32_t)(&(ADC1->DR));
	DMA2_Stream0->M0AR 	 =(uint32_t )(acc_data);
	DMA2_Stream0->NDTR	 =3;

	/*Launch the DMA*/
	DMA2_Stream0->CR 	|=DMA_SxCR_EN;

	/*Launch the ADC*/
	ADC1->CR2			|=ADC_CR2_ADON;

	ADC1->CR2|=ADC_CR2_SWSTART;


}



static float adc_to_acc(uint16_t adc_value)
{
	return  ((( ( (float)(adc_value * 3.3)/RawMax) - 1.65 ) / 0.330)*9.81);

}


void get_accel_data(acc_data_t *acc)
{

	float ax_scalled=adc_to_acc(acc_data[0]);
	float ay_scalled=adc_to_acc(acc_data[1]);
	float az_scalled=adc_to_acc(acc_data[2]);


	acc->accx=ax_scalled;
	acc->accy=ay_scalled;
	acc->accz=az_scalled;


}

For main.c, first add the adxl335 header file:

#include "adxl335.h"

Declare the structure that will hold the data:

acc_data_t adxl335_data;

Within main function:

Initialize the sensor:

adxl335_init();

Within while(1) loop:

get_accel_data(&adxl335_data);

print the results:

printf("Acc  x=%0.2f y=%0.2f z=%0.2f\r\n",adxl335_data.accx,adxl335_data.accy,adxl335_data.accz);

4. Code:

You may download the code from here:

5. Results:

After uploading the code, open serial terminal program and set the 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 *