Using LIS302DL Three-Axis Accelerometer and External Interrupt on Stm32f407g
Tags: c, stm32
Published: 2022-12-07 14:25:24

Environment: windows 10, STM32CubeIDE 1.8.0

In this tutorial we will use uart4 through `PA0` and `PA1` pins.

## Project Initialization

First, Create a new stm32f407g project in CubeIDE, and name the project lis302dl_test.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucz9grlag70opbtq4eh4.png)

Set up uart4 according to [Using Uart on Stm32f407g](https://dev.to/blueskyson/using-uart-on-stm32f407g-57hk).

Next, set `PE3` as GPIO_Output and `PE0` as GPIO_EXT0 according to the figure below.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/im01zicuihd737nugsrl.png)

Set `PA5`, `PA6`, `PA7` as the following figure and enable SPI1.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnixiu0rxj5ikisk2ann.png)

Enable EXTI line0 interrupt and set its priority:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwfbcrtvm7rcmvdkugew.png)

Press Ctrl+S to automatically generate the code.

## Check WHO_AM_I_ADDR

LIS302DL has many registers for reading and writing. For specific numbers and functions, please refer to the [official datasheet](https://www.st.com/en/mems-and-sensors/lis302dl.html) or refer to [lis302dl.h](https://github.com/STMicroelectronics/stm32-lis302dl/blob/main/lis302dl.h). If you want to directly include lis302dl.h, please manually complete or delete the missing dependent libraries.

Here are the registers used in this tutorial, which can be defined as private macros under /* USER CODE BEGIN PM */:

```c
/* USER CODE BEGIN PM */
#define LIS302DL_WHO_AM_I_ADDR               0x0F
#define LIS302DL_CTRL_REG1_ADDR              0x20
#define LIS302DL_CTRL_REG2_ADDR              0x21
#define LIS302DL_CTRL_REG3_ADDR              0x22
#define LIS302DL_STATUS_REG_ADDR             0x27
#define LIS302DL_OUT_X_ADDR                  0x29
#define LIS302DL_OUT_Y_ADDR                  0x2B
#define LIS302DL_OUT_Z_ADDR                  0x2D
#define LIS302DL_FF_WU_CFG1_REG_ADDR         0x30
#define LIS302DL_FF_WU_SRC1_REG_ADDR         0x31
#define LIS302DL_FF_WU_THS1_REG_ADDR         0x32
#define LIS302DL_FF_WU_DURATION1_REG_ADDR    0x33
/* USER CODE END PM */
```

Next, implement the functions for reading and writing SPI1 in /* USER CODE BEGIN 0 */:

```c
/* USER CODE BEGIN 0 */
void MEMS_Write(uint8_t address, uint8_t data){
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1,&address,1,10);
	HAL_SPI_Transmit(&hspi1,&data,1,10);
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
}

void MEMS_Read(uint8_t address, uint8_t *data){
    address |= 0x80;
	HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1,&address,1,10);
	HAL_SPI_Receive(&hspi1,data,1,10);
	HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3, GPIO_PIN_SET);
}
/* USER CODE END 0 */
```

Then rewrite the while loop of the main function of the project as follows:

```c
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
  uint8_t data;
  MEMS_Read(LIS302DL_WHO_AM_I_ADDR, &data);
  if(data == 0x3B)
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
  HAL_Delay(500);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
```

If the three-axis accelerometer model is LIS302DL, the green LED on the board will blink continuously.

## Test Printing X, Y, Z Values

Reference datasheet:

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7t2skre6wtkk3ydbvgaw.png)

Use the following code to set `CTRL_REG1`. The code means setting output rate to 400 Hz and enabling X, Y, Z:

```c
/* USER CODE BEGIN 2 */
MEMS_Write(LIS302DL_CTRL_REG1_ADDR, 0x47);
/* USER CODE END 2 */
```

`CTRL_REG2` needs no change.

`CTRL_REG3` and subsequent registers are only needed when using external interrupt in this tutorial later.

Next, rewrite the while loop to continuously print out the acceleration of the X, Y, and Z axes every 0.1 seconds through uart4:

```c
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
  uint8_t x, y, z;
  MEMS_Read(LIS302DL_OUT_X_ADDR, &x);
  MEMS_Read(LIS302DL_OUT_Y_ADDR, &y);
  MEMS_Read(LIS302DL_OUT_Z_ADDR, &z);
  
  char Monitor_data[100];
  memset(Monitor_data,'\0',sizeof(Monitor_data));
  sprintf(Monitor_data, "%3d %3d %3d\n\r", x, y, z);
  HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);
  
  HAL_Delay(100);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
```

After executing, the uart4 will be like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onl2pbqny0aijom1ijsc.png)

## Test Using External Interrupt

Also refer to the datasheet and set the following registers, the effects of the code are shown comments:

```c
/* USER CODE BEGIN 2 */
MEMS_Write(LIS302DL_CTRL_REG1_ADDR, 0x47);
MEMS_Write(LIS302DL_CTRL_REG2_ADDR, 0x00);

// use FF_WU_1 to trigger interrupt on INT1
MEMS_Write(LIS302DL_CTRL_REG3_ADDR, 0x01);

// enable interrupt on X high, Y high
MEMS_Write(LIS302DL_FF_WU_CFG1_REG_ADDR, 0x0A);

// free-fall/wake-up threshold (7 bit)
MEMS_Write(LIS302DL_FF_WU_THS1_REG_ADDR, 0x55);

// free-fall/wake-up duration (8 bit)
// Step 2.5 msec, from 0 to 637.5 msec if ODR=400Hz,
// else step 10 msec, from 0 to 2.55 sec when ODR=100Hz.
MEMS_Write(LIS302DL_FF_WU_DURATION1_REG_ADDR, 0x04);
/* USER CODE END 2 */
```

Implement `HAL_GPIO_EXTI_Callback` in main.c:

```c
/* USER CODE BEGIN 0 */

// ...

int is_handling = 0, count = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
	if (is_handling) {
		return;
	}
	is_handling = 1;

	char Monitor_data[100];
	memset(Monitor_data,'\0', sizeof(Monitor_data));
	sprintf(Monitor_data, "interrupt! %d\n\r", count++);
	HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);

	is_handling = 0;
}
/* USER CODE END 0 */
```

After execution, uart4 will print "interrupt!" and the current number of interrupts every time it is expected to shake left and right:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6hvzwp6ijlgyzrjd9k1.png)