/** * ENSICAEN * 6 Boulevard MarĂ©chal Juin * F-14050 Caen Cedex * * This file is owned by ENSICAEN students. No portion of this * document may be reproduced, copied or revised without written * permission of the authors. */ /** * @author Dimitri Boudier * @version 1.0.0 - 2023-10-14 * * @todo Nothing. * @bug None. * @note This driver can be used with only ONE Accel 2 click at once. */ /** * @file accel_2_click.c * @brief Driver for the MIKROE "Accel 2 click" board * * Ref. https://www.mikroe.com/accel-2-click */ #include "main.h" #include "accel_2_click.h" /***************************************************************************** * GLOBAL VARIABLE DECLARATIONS *****************************************************************************/ ACCEL_2_handle_t accel_2_handle; /***************************************************************************** * FUNCTION DEFINITIONS *****************************************************************************/ void ACCEL_2_init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *SS_Port, uint16_t SS_Pin) { uint8_t value_write, value_read; /** * Attach the SPI peripheral handle * Attach the GPIO pin used for the SS signal */ accel_2_handle.hspi = hspi; accel_2_handle.SS_Port = SS_Port; accel_2_handle.SS_Pin = SS_Pin; /** * Check if the device is present, * if not get stuck in an infinite loop. */ ACCEL_2_readReg(ACCEL_2_REG_WHO_AM_I, &value_read, 1); if( value_read != ACCEL_2_WHO_AM_I_VALUE ) { while(1); // It's a trap! } /** * Device configuration: * + 4-wire SPI mode * + Acquisition enabled on all three axes * + Continuous data update * + Output data rate > 0 Hz * + Full-scale at +/- 2g * * Anything else at default value. */ value_write = ACCEL_2_OUTPUTDATARATE_1600HZ | ACCEL_2_BDU_CONTINUOUS_UPDATE | ACCEL_2_XYZ_ENABLE; ACCEL_2_writeReg(ACCEL_2_REG_CTRL_REG4, value_write); ACCEL_2_readReg(ACCEL_2_REG_CTRL_REG4, &value_read, 1); if( value_read != value_write ) { while(1); // It's a trap! } /** * Set the full scale */ value_write = ACCEL_2_AAFILTER_BW_200HZ | ACCEL_2_FULL_SCALE_2G | ACCEL_2_SELF_TEST_DISABLE | ACCEL_2_SPI_4WIRE; ACCEL_2_writeReg(ACCEL_2_REG_CTRL_REG5, value_write); ACCEL_2_readReg(ACCEL_2_REG_CTRL_REG5, &value_read, 1); if( value_read != value_write ) { while(1); // It's a trap! } } void ACCEL_2_writeReg(uint8_t reg_addr, uint8_t reg_value) { uint8_t send_data[] = {reg_addr, reg_value}; HAL_GPIO_WritePin(accel_2_handle.SS_Port, accel_2_handle.SS_Pin, RESET); HAL_SPI_Transmit(accel_2_handle.hspi, send_data, sizeof(send_data), HAL_MAX_DELAY); HAL_GPIO_WritePin(accel_2_handle.SS_Port, accel_2_handle.SS_Pin, SET); } void ACCEL_2_readReg(uint8_t reg_addr, uint8_t* reg_value, uint8_t n_bytes) { reg_addr |= ACCEL_2_READ_REG; //!< See LIS3DSH datasheet, 5.2: the MSbit is a Read-/Write bit HAL_GPIO_WritePin(accel_2_handle.SS_Port, accel_2_handle.SS_Pin, RESET); HAL_SPI_Transmit(accel_2_handle.hspi, ®_addr, 1, HAL_MAX_DELAY); HAL_SPI_Receive(accel_2_handle.hspi, reg_value, n_bytes, HAL_MAX_DELAY); HAL_GPIO_WritePin(accel_2_handle.SS_Port, accel_2_handle.SS_Pin, SET); } void ACCEL_2_getSensitivity(float* sensitivity) { uint8_t ctrl_reg5_value; *sensitivity = ACCEL_2_SENSITIVITY_AT_2G; ACCEL_2_readReg(ACCEL_2_REG_CTRL_REG5, &ctrl_reg5_value, sizeof(ctrl_reg5_value)); switch( ctrl_reg5_value & ACCEL_2_FULL_SCALE_BITS ) { case ACCEL_2_FULL_SCALE_2G: *sensitivity = ACCEL_2_SENSITIVITY_AT_2G; break; case ACCEL_2_FULL_SCALE_4G: *sensitivity = ACCEL_2_SENSITIVITY_AT_4G; break; case ACCEL_2_FULL_SCALE_6G: *sensitivity = ACCEL_2_SENSITIVITY_AT_6G; break; case ACCEL_2_FULL_SCALE_8G: *sensitivity = ACCEL_2_SENSITIVITY_AT_8G; break; case ACCEL_2_FULL_SCALE_16G: *sensitivity = ACCEL_2_SENSITIVITY_AT_16G; break; } } void ACCEL_2_getAccelX(float* x_accel) { uint8_t out_x_registers[2]; int16_t out_x_value; float x_raw_value; float sensitivity; ACCEL_2_readReg(ACCEL_2_REG_OUT_X_L, out_x_registers, sizeof(out_x_registers)); out_x_value = (int16_t)( (out_x_registers[1] << 8) + out_x_registers[0] ); x_raw_value = (float)(out_x_value); ACCEL_2_getSensitivity(&sensitivity); *x_accel = sensitivity * x_raw_value; } void ACCEL_2_getAccelY(float* y_accel) { uint8_t out_y_registers[2]; int16_t out_y_value; float y_raw_value; float sensitivity; ACCEL_2_readReg(ACCEL_2_REG_OUT_Y_L, out_y_registers, sizeof(out_y_registers)); out_y_value = (int16_t)( (out_y_registers[1] << 8) + out_y_registers[0] ); y_raw_value = (float)(out_y_value); ACCEL_2_getSensitivity(&sensitivity); *y_accel = sensitivity * y_raw_value; } void ACCEL_2_getAccelZ(float* z_accel) { uint8_t out_z_registers[2]; int16_t out_z_value; float z_raw_value; float sensitivity; ACCEL_2_readReg(ACCEL_2_REG_OUT_Z_L, out_z_registers, sizeof(out_z_registers)); out_z_value = (int16_t)( (out_z_registers[1] << 8) + out_z_registers[0] ); z_raw_value = (float)(out_z_value); ACCEL_2_getSensitivity(&sensitivity); *z_accel = sensitivity * z_raw_value; } void ACCEL_2_getAccelXYZ(float* x_accel, float* y_accel, float* z_accel) { uint8_t out_xyz_registers[6]; int16_t out_x_value; int16_t out_y_value; int16_t out_z_value; float x_raw_value; float y_raw_value; float z_raw_value; float sensitivity; ACCEL_2_readReg(ACCEL_2_REG_OUT_X_L, out_xyz_registers, sizeof(out_xyz_registers)); out_x_value = (int16_t)( (out_xyz_registers[1] << 8) + out_xyz_registers[0] ); out_y_value = (int16_t)( (out_xyz_registers[3] << 8) + out_xyz_registers[2] ); out_z_value = (int16_t)( (out_xyz_registers[5] << 8) + out_xyz_registers[4] ); x_raw_value = (float)(out_x_value); y_raw_value = (float)(out_y_value); z_raw_value = (float)(out_z_value); ACCEL_2_getSensitivity(&sensitivity); *x_accel = sensitivity * x_raw_value; *y_accel = sensitivity * y_raw_value; *z_accel = sensitivity * z_raw_value; }