I use the ESP32 SPI API to do the SPI thing.
https://docs.espressif.com/projects/esp ... aster.html
here is the 'main' code
Code: Select all
#include "sdkconfig.h" // for log_x
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "ESP32_LSM9DS1.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
////////////////////////////////////////////////////
#define TaskCore1 1
#define TaskCore0 0
#define SerialDataBits 115200
#define TaskStack30K 30000
#define Priority4 4
///////////////////////////////////////////
////////*************************************************
int int_Pin = 36;
volatile int IntCount = 0;
////////////////////////////////////////////////
float q[4] = {1.0f, 0.0f, 0.0f, 0.0f}; // vector to hold quaternion
float eInt[3] = {0.0f, 0.0f, 0.0f}; // vector to hold integral error for Mahony method
float deltat = 0.0f; // integration interval for both filter schemes
const float Kp = 7.50f;
// #define Kp 2.0f * 5.0f // these are the free parameters in the Mahony filter and fusion scheme, Kp for proportional feedback, Ki for integral
const float Ki = 1.7f;
float roll = 0.0f;
float pitch = 0.0f;
float yaw = 0.0f;
///////////////////////////////////////////////////////
void ULP_BLINK_RUN(uint32_t us);
////////*************************************************
///////////////////////////////
void trigger()
{
IntCount++;
}
///////////////////////////////
void setup()
{
Serial.begin( SerialDataBits );
// pinMode( int_Pin, INPUT );
// attachInterrupt( int_Pin, trigger, RISING );
// microseconds to delay between halt and wake states
ULP_BLINK_RUN(100000);
/////////////////// CORE 0 ////////////////////////////////////////////////////////////////////////////////
xTaskCreatePinnedToCore ( fGetIMU, "v_getIMU", TaskStack30K, NULL, Priority4, NULL, TaskCore0 );
//////////////////// CORE 1 ////////////////////////////////////////////////////////////////////////////////
}
//////////////////////////////////////////////////////////
void loop() {}
//////////////////////////////////////////////////////////
/*
A transaction on the SPI bus consists of five phases, any of which may be skipped:
The command phase. In this phase, a command (0-16 bit) is clocked out.
The address phase. In this phase, an address (0-64 bit) is clocked out.
The read phase. The slave sends data to the master.
The write phase. The master sends data to the slave.
In full duplex, the read and write phases are combined, causing the SPI host to read and write data simultaneously.
The command and address phase are optional in that not every SPI device will need to be sent a command and/or address.
Tis is reflected in the device configuration: when the command_bits or data_bits fields are set to zero, no command or address phase is done.
Something similar is true for the read and write phase: not every transaction needs both data to be written as well as data to be read.
When rx_buffer is NULL (and SPI_USE_RXDATA) is not set) the read phase is skipped.
When tx_buffer is NULL (and SPI_USE_TXDATA) is not set) the write phase is skipped.
*/
void fGetIMU( void *pvParameters )
{
if ( fInitializeDevice( ) )
{
Serial.println ( " device init " );
if ( fInitializeAG() )
{
Serial.println( "AG init" );
if ( fDO_AG_ID() )
{
Serial.println ( " AG self ID'd " );
if ( fInitializeM() )
{
Serial.println( "Init Magnetometer" );
if ( fDO_M_ID() )
{
Serial.print ( " M self ID'd: " );
Serial.println( getMAG_ID_OK() );
fReboot();
vTaskDelay( 50 );
if ( fEnableGandA() == false ) // enable gyros and accelerometers
{
Serial.print( " Fail: Enable Gyro and Accelerometer " );
}
if ( fEnableM() == false ) // enable gyros and accelerometers
{
Serial.println( " Fail: Enable Magnetometer" );
}
if ( setupAccelScale( LSM9DS1_ACCELRANGE_8G ) )
{
Serial.println( " Fail: SetupAccelScale" );
}
if ( setupGyroScale ( LSM9DS1_GYROSCALE_500DPS ) )
{
Serial.println( " Fail: setupGyroScale" );
}
if (setupMagScale( LSM9DS1_MAGGAIN_12GAUSS ) )
{
Serial.println( "FailL setupMagScale" );
}
// calibrate();
// Serial.print( " aXbias = " );
// Serial.print( get_aXbias(), 6 );
// Serial.print( " aYbias = " );
// Serial.print( get_aYbias(), 6 );
// Serial.print( " aZias = " );
// Serial.print( get_aZbias(), 6 );
// Serial.print( " gXbias ");
// Serial.print( get_gXbias(), 6 );
// Serial.print( " gYbias = " );
// Serial.print( get_gYbias(), 6 );
// Serial.print( " gZbias = " );
// Serial.println( get_gZbias(), 6 );
} // if ( fDO_M_ID )
else
{
Serial.print( "fDO_M_ID, fail: ");
Serial.print( returnHighBits(), BIN ); //each LSMDS1 may have its own ID
Serial.println( );
}
} // if ( fInitializeM() )
} // if ( fDO_AG_ID() )
else
{
Serial.print( "fDO_AG_ID, fail: ");
Serial.print( returnHighBits(), BIN ); //each LSMDS1 may have its own ID
Serial.println( );
}
} // if ( fInitializeAG() )
} // if ( fInitializeDevice( ) )
////
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS( 35 );
// Initialise the xLastWakeTime variable with the current time.
xLastWakeTime = xTaskGetTickCount();
float TimePast = esp_timer_get_time();
float TimeNow = esp_timer_get_time();
////
float Max = 0.0f;
while (1)
{
vTaskDelayUntil( &xLastWakeTime, xFrequency );
// Serial.println ( " doing a loop " );
if ( getLSM9DS1_ID_OK() && getMAG_ID_OK() ) // then do things
{
//TimeNow = xTaskGetTickCount();
TimeNow = esp_timer_get_time() / 1000000.0f;
// TimeNow = micros() / 1000000.0f;
deltat = ( TimeNow - TimePast);
// Serial.println( deltat,6 );
////
fReadAccelerometers();
fReadGyros();
fReadMagnetometer();
// Serial.print ( "aX= ");
Serial.print( get_aX(), 6 );
Serial.print ( ", ");
// Serial.print ( " aY= ");
Serial.print( get_aY(), 6 );
Serial.print ( ", ");
// Serial.print ( " aZ= ");
Serial.print( get_aZ(), 6 );
Serial.print ( ", ");
// Serial.print ( " gX= ");
Serial.print( get_gX(), 6 );
Serial.print ( ", ");
// Serial.print ( " gY= ");
Serial.print( get_gY(), 6 );
Serial.print ( ", ");
// Serial.print ( " gZ= ");
Serial.print( get_gZ(), 6 );
Serial.print ( ", ");
// Serial.print ( " mX= ");
Serial.print( get_mX(), 6 );
Serial.print ( ", ");
// Serial.print ( " mY= ");
Serial.print( get_mY(), 6 );
Serial.print ( ", ");
// Serial.print ( " mZ= ");
Serial.print( get_mZ(), 6 );
Serial.println();
// roll = atan2f( get_aX(), sqrtf( (get_aY() * get_aY()) + (get_aZ() * get_aZ())) );
// pitch = atan2f( get_aY(), sqrtf( (get_aX() * get_aX()) + (get_aZ() * get_aZ())) );
MahonyQuaternionUpdate ( get_aX(), get_aY(), get_aZ(), get_gX() * PI / 180.0f, get_gY() * PI / 180.0f, get_gZ() * PI / 180.0f, get_mX(), get_mY(), get_mZ() );
// Define output variables from updated quaternion---these are Tait-Bryan angles, commonly used in aircraft orientation.
// In this coordinate system, the positive z-axis is down toward Earth.
// Yaw is the angle between Sensor x-axis and Earth magnetic North (or true North if corrected for local declination, looking down on the sensor positive yaw is counterclockwise.
// Pitch is angle between sensor x-axis and Earth ground plane, toward the Earth is positive, up toward the sky is negative.
// Roll is angle between sensor y-axis and Earth ground plane, y-axis up is positive roll.
// These arise from the definition of the homogeneous rotation matrix constructed from quaternions.
// Tait-Bryan angles as well as Euler angles are non-commutative; that is, the get the correct orientation the rotations must be
// applied in the correct order which for this configuration is yaw, pitch, and then roll.
// For more see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles which has additional links.
// yaw = atan2f(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
pitch = -asinf(2.0f * (q[1] * q[3] - q[0] * q[2]));
roll = atan2f(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
Serial.print( roll, 6 );
Serial.print( ", " );
Serial.print( pitch, 6 );
Serial.println( );
// log_i( " interrupt Count %d", IntCount );
TimePast = TimeNow;
} // if ( LSM9DS1_ID_OK && M_ID_OK ) // then do things
else
{
Serial.print ( " LSM9DS1_ID_NOT_OK ");
Serial.print ( getLSM9DS1_ID_OK() );
Serial.print ( " or MAG_ID_OK not OK " );
Serial.println( getMAG_ID_OK() );
}
xLastWakeTime = xTaskGetTickCount();
}
vTaskDelete(NULL);
} // void fGetIMU( void *pvParameters )
////
//// Similar to Madgwick scheme but uses proportional and integral filtering on the error between estimated reference vectors and
//// measured ones.
void MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
{
float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability
float norm;
float hx, hy, bx, bz;
float vx, vy, vz, wx, wy, wz;
float ex, ey, ez;
float pa, pb, pc;
// Auxiliary variables to avoid repeated arithmetic
float q1q1 = q1 * q1;
float q1q2 = q1 * q2;
float q1q3 = q1 * q3;
float q1q4 = q1 * q4;
float q2q2 = q2 * q2;
float q2q3 = q2 * q3;
float q2q4 = q2 * q4;
float q3q3 = q3 * q3;
float q3q4 = q3 * q4;
float q4q4 = q4 * q4;
// Normalise accelerometer measurement
norm = sqrt(ax * ax + ay * ay + az * az);
if (norm == 0.0f) return; // handle NaN
norm = 1.0f / norm; // use reciprocal for division
ax *= norm;
ay *= norm;
az *= norm;
// Normalise magnetometer measurement
norm = sqrt(mx * mx + my * my + mz * mz);
if (norm == 0.0f) return; // handle NaN
norm = 1.0f / norm; // use reciprocal for division
mx *= norm;
my *= norm;
mz *= norm;
// Reference direction of Earth's magnetic field
hx = 2.0f * mx * (0.5f - q3q3 - q4q4) + 2.0f * my * (q2q3 - q1q4) + 2.0f * mz * (q2q4 + q1q3);
hy = 2.0f * mx * (q2q3 + q1q4) + 2.0f * my * (0.5f - q2q2 - q4q4) + 2.0f * mz * (q3q4 - q1q2);
bx = sqrt((hx * hx) + (hy * hy));
bz = 2.0f * mx * (q2q4 - q1q3) + 2.0f * my * (q3q4 + q1q2) + 2.0f * mz * (0.5f - q2q2 - q3q3);
// Estimated direction of gravity and magnetic field
vx = 2.0f * (q2q4 - q1q3);
vy = 2.0f * (q1q2 + q3q4);
vz = q1q1 - q2q2 - q3q3 + q4q4;
wx = 2.0f * bx * (0.5f - q3q3 - q4q4) + 2.0f * bz * (q2q4 - q1q3);
wy = 2.0f * bx * (q2q3 - q1q4) + 2.0f * bz * (q1q2 + q3q4);
wz = 2.0f * bx * (q1q3 + q2q4) + 2.0f * bz * (0.5f - q2q2 - q3q3);
// Error is cross product between estimated direction and measured direction of gravity
ex = (ay * vz - az * vy) + (my * wz - mz * wy);
ey = (az * vx - ax * vz) + (mz * wx - mx * wz);
ez = (ax * vy - ay * vx) + (mx * wy - my * wx);
if (Ki > 0.0f)
{
eInt[0] += ex; // accumulate integral error
eInt[1] += ey;
eInt[2] += ez;
}
else
{
eInt[0] = 0.0f; // prevent integral wind up
eInt[1] = 0.0f;
eInt[2] = 0.0f;
}
// Apply feedback terms
gx = gx + Kp * ex + Ki * eInt[0];
gy = gy + Kp * ey + Ki * eInt[1];
gz = gz + Kp * ez + Ki * eInt[2];
// Integrate rate of change of quaternion
pa = q2;
pb = q3;
pc = q4;
q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltat);
q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * deltat);
q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * deltat);
q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * deltat);
// Normalise quaternion
norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
norm = 1.0f / norm;
q[0] = q1 * norm;
q[1] = q2 * norm;
q[2] = q3 * norm;
q[3] = q4 * norm;
} // void MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
//////////////////////////////////////////////
void ULP_BLINK_RUN(uint32_t us)
{
size_t load_addr = 0;
RTC_SLOW_MEM[12] = 0;
ulp_set_wakeup_period(0, us);
const ulp_insn_t ulp_blink[] =
{
I_MOVI(R3, 12), // #12 -> R3
I_LD(R0, R3, 0), // R0 = RTC_SLOW_MEM[R3(#12)]
M_BL(1, 1), // GOTO M_LABEL(1) IF R0 < 1
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1), // RTC_GPIO2 = 1
I_SUBI(R0, R0, 1), // R0 = R0 - 1, R0 = 1, R0 = 0
I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(#12)] = R0
M_BX(2), // GOTO M_LABEL(2)
M_LABEL(1), // M_LABEL(1)
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
I_ADDI(R0, R0, 1), // R0 = R0 + 1, R0 = 0, R0 = 1
I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(#12)] = R0
M_LABEL(2), // M_LABEL(2)
I_HALT() // HALT COPROCESSOR
};
const gpio_num_t led_gpios[] =
{
GPIO_NUM_2,
// GPIO_NUM_0,
// GPIO_NUM_4
};
for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
rtc_gpio_init(led_gpios[i]);
rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_level(led_gpios[i], 0);
}
size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
ulp_process_macros_and_load( load_addr, ulp_blink, &size);
ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)
//////////////////////////////////////////////
Here is the ESP32_LSM9DS1.h code
Code: Select all
#include "ESP32_SPI_API.h"
#include <driver/spi_master.h>
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
// Temperature: LSB per degree celsius
#define LSM9DS1_TEMP_LSB_DEGREE_CELSIUS (8) // 1°C = 8, 25° = 200, etc.
#define FIFO_OFF 0
#define FIFO_THS 1
#define FIFO_CONT_TRIGGER 3
#define FIFO_OFF_TRIGGER 4
#define FIFO_CONT 5
#define AccelerometerDataReady 0x01
#define GyroDataReady 0x02
////////////////////////////
const uint8_t LSM9DS1_REGISTER_WHO_AM_I_XG = 0xF;
const uint8_t LSM9DS1_ID = 0B01101000;
////LSM9DS1_REGISTER_CTRL_REG4 = 0x1E,
const uint8_t LSM9DS1_FIFO_CTRL_REG = 0x2E;
const uint8_t LSM9DS1_REGISTER_CTRL_REG5_XL = 0x1F;
const uint8_t LSM9DS1_REGISTER_CTRL_REG6_XL = 0x20;
const uint8_t LSM9DS1_REGISTER_CTRL_REG7_XL = 0x21;
const uint8_t LSM9DS1_REGISTER_CTRL_REG8 = 0x22;
const uint8_t LSM9DS1_REGISTER_CTRL_REG9 = 0x23;
const uint8_t LSM9DS1_REGISTER_FIFO_SRC = 0x2F;
//// LSM9DS1_REGISTER_CTRL_REG10 = 0x24,
const uint8_t LSM9DS1_REGISTER_CTRL_REG1_G = 0x10;
//// LSM9DS1_REGISTER_CTRL_REG2_G = 0x11,
const uint8_t LSM9DS1_REGISTER_CTRL_REG3_G = 0x12;
//////// Linear Acceleration: mg per LSB
const int8_t LSM9DS1_ACCELRANGE_16G = (0b01 << 3);
const int8_t LSM9DS1_ACCELRANGE_8G = (0b11 << 3);
const int8_t LSM9DS1_ACCELRANGE_4G = (0b10 << 3);
const uint8_t LSM9DS1_ACCELRANGE_2G = (0b00 << 3);
//////// Magnetic Field Strength: gauss range
const uint8_t LSM9DS1_MAGGAIN_4GAUSS = (0b00 << 5); // +/- 4 gauss
const uint8_t LSM9DS1_MAGGAIN_8GAUSS = (0b01 << 5); // +/- 8 gauss
const uint8_t LSM9DS1_MAGGAIN_12GAUSS = (0b10 << 5); // +/- 12 gauss
const uint8_t LSM9DS1_MAGGAIN_16GAUSS = (0b11 << 5); // +/- 16 gauss
////// Linear Acceleration: mg per LSB
const float LSM9DS1_ACCEL_MG_LSB_2G = ( 2.0f / 32767.0f );
const float LSM9DS1_ACCEL_MG_LSB_4G = ( 4.0f / 32767.0f );
const float LSM9DS1_ACCEL_MG_LSB_8G = ( 8.0f / 32767.0f );
const float LSM9DS1_ACCEL_MG_LSB_16G = ( 16.0f / 32767.0f );
//////// Angular Rate: dps per LSB
const float LSM9DS1_GYRO_DPS_DIGIT_245DPS = ( 245.0f / 32767.0f );
const float LSM9DS1_GYRO_DPS_DIGIT_500DPS = ( 500.0f / 32767.0f );
const float LSM9DS1_GYRO_DPS_DIGIT_2000DPS = ( 2000.0f / 32767.0f );
////// GyroScale
const uint8_t LSM9DS1_GYROSCALE_245DPS = (0b00 << 3); // +/- 245 degrees per second rotation
const uint8_t LSM9DS1_GYROSCALE_500DPS = (0b01 << 3); // +/- 500 degrees per second rotation
const uint8_t LSM9DS1_GYROSCALE_2000DPS = (0b11 << 3); // +/- 2000 degrees per second rotation
// Magnetic Field Strength: gauss range
const float LSM9DS1_MAG_MGAUSS_4GAUSS = ( 4.0f / 32767.0f );
const float LSM9DS1_MAG_MGAUSS_8GAUSS = ( 8.0f / 32767.0f );
const float LSM9DS1_MAG_MGAUSS_12GAUSS = ( 12.0f / 32767.0f );
const float LSM9DS1_MAG_MGAUSS_16GAUSS = ( 16.0f / 32767.0f );
////// accel out
const uint8_t LSM9DS1_REGISTER_OUT_X_L_XL = 0x28;
const uint8_t LSM9DS1_REGISTER_OUT_X_H_XL = 0x29;
const uint8_t LSM9DS1_REGISTER_OUT_Y_L_XL = 0x2A;
const uint8_t LSM9DS1_REGISTER_OUT_Y_H_XL = 0x2B;
const uint8_t LSM9DS1_REGISTER_OUT_Z_L_XL = 0x2C;
const uint8_t LSM9DS1_REGISTER_OUT_Z_H_XL = 0x2D;
////// gyro out
const uint8_t LSM9DS1_REGISTER_OUT_X_L_G = 0x18;
const uint8_t LSM9DS1_REGISTER_OUT_X_H_G = 0x19;
const uint8_t LSM9DS1_REGISTER_OUT_Y_L_G = 0x1A;
const uint8_t LSM9DS1_REGISTER_OUT_Y_H_G = 0x1B;
const uint8_t LSM9DS1_REGISTER_OUT_Z_L_G = 0x1C;
const uint8_t LSM9DS1_REGISTER_OUT_Z_H_G = 0x1D;
//////
const uint8_t LSM9DS1_REGISTER_OUT_X_L_M = 0x28;
const uint8_t LSM9DS1_REGISTER_OUT_X_H_M = 0x29;
const uint8_t LSM9DS1_REGISTER_OUT_Y_L_M = 0x2A;
const uint8_t LSM9DS1_REGISTER_OUT_Y_H_M = 0x2B;
const uint8_t LSM9DS1_REGISTER_OUT_Z_L_M = 0x2C;
const uint8_t LSM9DS1_REGISTER_OUT_Z_H_M = 0x2D;
//////
const uint8_t LSM9DS1_MAG_ID = 0B00111101;
const uint8_t LSM9DS1_REGISTER_WHO_AM_I_M = 0x0F;
const uint8_t STATUS_REG = 0x27;
const uint8_t M_ZYX_AXIS_READY = 0x08;
const uint8_t LSM9DS1_REGISTER_CTRL_REG1_M = 0x20;
const uint8_t LSM9DS1_REGISTER_CTRL_REG2_M = 0x21;
const uint8_t LSM9DS1_REGISTER_CTRL_REG3_M = 0x22;
const uint8_t LSM9DS1_REGISTER_CTRL_REG4_M = 0x23;
const uint8_t LSM9DS1_REGISTER_CTRL_REG5_M = 0x24;
const uint8_t LSM9DS1_REGISTER_CFG_M = 0x30;
const uint8_t LSM9DS1_REGISTER_INT_SRC_M = 0x31;
//////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
bool fInitializeDevice( );
bool fInitializeAG();
bool fInitializeM();
bool fDO_AG_ID();
bool getLSM9DS1_ID_OK();
bool fDO_M_ID();
bool getMAG_ID_OK();
bool setupAccelScale ( int range );
int16_t returnHighBits();
int8_t returnLowBits();
int getDh();
int getMh();
bool fEnableGandA();
bool fEnableM();
bool setupMagScale ( int gain );
bool setupGyroScale ( int _gscale );
void calibrate();
float get_aXbias();
float get_aYbias();
float get_aZbias();
float get_gXbias();
float get_gYbias();
float get_gZbias();
void fReadAccelerometers();
float get_aX();
float get_aY();
float get_aZ();
void fReadGyros();
float get_gX();
float get_gY();
float get_gZ();
void fReadMagnetometer();
float get_mX();
float get_mY();
float get_mZ();
void fReboot();
Here is the ESP32_LSM9DS1.cpp code
Code: Select all
#include "ESP32_LSM9DS1.h"
///////////////////////////////////////////
spi_device_handle_t hAG;
spi_device_handle_t hM;
////
#define csPinAG 5
#define csPinM 32
#define spiCLK 25 // CLK module pin SCL
#define spiMOSI 26 // MOSI module pin SDA
#define spiMISO 27 // MISO module pin SDOAG tied to SDOM
//
float _accel_mg_lsb;
float _mag_mgauss_lsb;
float _gyro_dps_digit;
float aXbias = 0.0f;
float aYbias = 0.0f;
float aZbias = 0.0f;
float gXbias = 0.0f, gYbias = 0.0f, gZbias = 0.0f;
bool LSM9DS1_ID_OK = false;
bool M_ID_OK = false;
float aX, aY, aZ, gX, gY, gZ, mX, mY, mZ;
int8_t lowB;
int16_t highB;
float ACCELrange = 0.0f;
//////////////////////////////
int getMh()
{
return (int)hM;
}
int getDh()
{
return (int)hAG;
}
//////////////////////////////////////////
bool fInitializeDevice( )
{
esp_err_t intError;
intError = fInitializeSPI_Channel( spiCLK, spiMOSI, spiMISO, HSPI_HOST, true);
if ( intError == 0 )
{
return true;
}
}
bool fInitializeAG()
{
esp_err_t intError;
intError = fInitializeSPI_Devices( hAG, csPinAG );
if ( intError == 0 )
{
if ( (int)hAG != 0 )
{
return true;
}
}
} // bool fInitializeAG()
bool fInitializeM()
{
esp_err_t intError;
intError = fInitializeSPI_Devices( hM, csPinM );
if ( intError == 0 )
{
if ( (int)hM != 0 )
{
return true;
}
}
} // bool fInitializeM()
////
int16_t returnHighBits()
{
return highB;
}
////
int8_t returnLowBits()
{
return lowB;
}
////
void fReboot()
{
// soft reset & reboot accel/gyro
fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG8, 0x05 );
// soft reset & reboot magnetometer
fWriteSPIdata8bits( hM, LSM9DS1_REGISTER_CTRL_REG2_M, 0x0C );
}
////
bool fDO_AG_ID()
{
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_WHO_AM_I_XG );
highB = GetHighBits();
lowB = GetLowBits();
if ( highB == LSM9DS1_ID )
{
LSM9DS1_ID_OK = true;
return true;
} else
{
return false;
}
}
//////
////
bool getLSM9DS1_ID_OK()
{
return LSM9DS1_ID_OK;
}
//////
bool fDO_M_ID()
{
// uint8_t temp;
fReadSPIdata16bits( hM, LSM9DS1_REGISTER_WHO_AM_I_M );
highB = GetHighBits();
lowB = GetLowBits();
if ( highB == LSM9DS1_MAG_ID )
{
M_ID_OK = true;
return true;
} else
{
return false;
}
}
////
bool getMAG_ID_OK()
{
return M_ID_OK;
}
//////
bool setupAccelScale ( int _range )
{
esp_err_t intError = 0;
uint8_t range = _range;
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_CTRL_REG6_XL );
uint8_t reg = GetHighBits();
reg &= ~(0b00011000);
reg |= range;
fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG6_XL, reg );
switch (range)
{
case LSM9DS1_ACCELRANGE_2G:
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_2G;
ACCELrange = 2.0f;
break;
case LSM9DS1_ACCELRANGE_4G:
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_4G;
ACCELrange = 4.0f;
break;
case LSM9DS1_ACCELRANGE_8G:
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_8G;
ACCELrange = 8.0f;
break;
case LSM9DS1_ACCELRANGE_16G:
_accel_mg_lsb = LSM9DS1_ACCEL_MG_LSB_16G;
ACCELrange = 16.0f;
break;
}
if ( intError )
{
return true;
}
else
{
return false;
}
} // void setupAccel ( uint8_t range )
//////
bool fEnableGandA()
{
esp_err_t intError = 0;
// high pass filter cutoff gyro
intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG3_G, 0x48 );
if ( intError > 0 )
{
return false;
}
// intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG5_XL, 0x38 ); // enable X Y and Z axis
// if ( intError > 0 )
// {
// return false;
// }
intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG7_XL, 0xE0 ); // High resolution on,
if ( intError > 0 )
{
return false;
}
// enable accelerometer continous
intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG6_XL, 0x27 ); //
if ( intError > 0 )
{
return false;
}
// enable gyro continuous
intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG1_G, 0xC0 );
//// intError = fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG1_G, 0xC1 );
if ( intError > 0 )
{
return false;
}
////
return true;
} // bool fEnableGandA()
////
bool fEnableM()
{
esp_err_t intError = 0;
fWriteSPIdata8bits( hM, LSM9DS1_REGISTER_CTRL_REG1_M, 0xFC ); // high perf XY, 80 Hz ODR
if ( intError > 0 )
{
return false;
}
fWriteSPIdata8bits( hM, LSM9DS1_REGISTER_CTRL_REG3_M, 0x00 ); // continuous mode
if ( intError > 0 )
{
return false;
}
fWriteSPIdata8bits( hM, LSM9DS1_REGISTER_CTRL_REG4_M, 0x0C ); // high perf Z mode
if ( intError > 0 )
{
return false;
}
return true;
}
////
bool setupMagScale ( int _gain )
{
uint8_t gain = _gain;
float AtoDscaleFactor = 32767.5f;
if ( fReadSPIdata16bits( hM, LSM9DS1_REGISTER_CTRL_REG2_M ) > 0 )
{
return true;
}
uint8_t reg = GetHighBits();
reg &= ~(0b01100000); // ~ ones compliment
reg |= gain;
if ( fWriteSPIdata8bits( hM, LSM9DS1_REGISTER_CTRL_REG2_M, reg ) > 0 )
{
return true;
}
switch (gain)
{
case LSM9DS1_MAGGAIN_4GAUSS:
// _mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_4GAUSS;
_mag_mgauss_lsb = 4.0f / AtoDscaleFactor;
break;
case LSM9DS1_MAGGAIN_8GAUSS:
// _mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_8GAUSS;
_mag_mgauss_lsb = 8.0f / AtoDscaleFactor;
break;
case LSM9DS1_MAGGAIN_12GAUSS:
// _mag_mgauss_lsb = LSM9DS1_MAG_MGAUSS_12GAUSS;
_mag_mgauss_lsb = 12.0f / AtoDscaleFactor;
break;
case LSM9DS1_MAGGAIN_16GAUSS:
_mag_mgauss_lsb = 16.0f / AtoDscaleFactor;
break;
}
return false;
} // void setupMag ( lsm9ds1MagGain_t gain )
////
bool setupGyroScale ( int _gscale )
{
// esp_err_t intError = 0;
uint8_t gscale = _gscale;
float AtoDscaleFactor = 32767.5f;
if ( fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_CTRL_REG1_G) > 0 )
{
return true;
}
uint8_t reg = GetHighBits();
reg &= ~(0b00011000); // ~ ones compliment
reg |= gscale;
if ( fWriteSPIdata8bits( hAG, LSM9DS1_REGISTER_CTRL_REG1_G, reg ) > 0 )
{
return true;
}
//
switch ( gscale )
{
case LSM9DS1_GYROSCALE_245DPS:
//_gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_245DPS;
_gyro_dps_digit = 245.0f / AtoDscaleFactor;;
break;
case LSM9DS1_GYROSCALE_500DPS:
// _gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_500DPS;
_gyro_dps_digit = 500.0f / AtoDscaleFactor;
break;
case LSM9DS1_GYROSCALE_2000DPS:
// _gyro_dps_digit = LSM9DS1_GYRO_DPS_DIGIT_2000DPS;
_gyro_dps_digit = 2000.0f / AtoDscaleFactor;
break;
}
return false;
} // void setupGyro ( lsm9ds1GyroScale_t scale )
////
void calibrate()
{
float _Xbias = 0.0f; // temp storage location
float _Ybias = 0.0f; // temp storage location
float _Zbias = 0.0f; // temp storage location
int numberOfSamples = 33;
// read 32 samples from each device and average those samples
// do accelerometer bias
for ( int i = 0; i < numberOfSamples; i++ )
{
fReadAccelerometers();
_Xbias = _Xbias + (aX * _accel_mg_lsb); // scale factor * _accel_mg_lsb
_Ybias = _Ybias + (aY * _accel_mg_lsb);
_Zbias = _Zbias + (aZ * _accel_mg_lsb);
vTaskDelay( 40 );
} //for ( int i = 0; i < numberOfSamples; i++ )
aXbias = _Xbias / (float)numberOfSamples;
aYbias = _Ybias / (float)numberOfSamples;
aZbias = _Zbias / (float)numberOfSamples;
_Xbias = 0.0f;
_Ybias = 0.0f;
_Zbias = 0.0f;
// do gyro bias
for ( int i = 0; i < numberOfSamples; i++ )
{
fReadGyros();
_Xbias = _Xbias + (gX * _gyro_dps_digit); // scale factor * _gyro_dps_digit
_Ybias = _Ybias + (gY * _gyro_dps_digit);
_Zbias = _Zbias + (gZ * _gyro_dps_digit);
vTaskDelay( 40 );
} // for ( int i = 0; i < numberOfSamples; i++ )
gXbias = _Xbias / (float)numberOfSamples;
gYbias = _Ybias / (float)numberOfSamples;
gZbias = _Zbias / (float)numberOfSamples;
} // void calibrate()
////
float get_aXbias( )
{
return -(aXbias);
}
////
float get_aYbias()
{
return -(aYbias);
}
////
float get_aZbias()
{
return -(aZbias);
}
////
float get_gXbias()
{
return -(gXbias);
}
////
float get_gYbias()
{
return -(gYbias);
}
////
float get_gZbias()
{
return -(gZbias);
}
////
void fReadAccelerometers()
{
int16_t temp = 0;
// read status register
fReadSPIdata16bits( hAG, STATUS_REG );
// is new accel data available
if ( GetHighBits() & AccelerometerDataReady )
{
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_X_L_XL ); // read x accel
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
aX = (float)temp;
aX = (aX * _accel_mg_lsb) - aXbias;
temp = 0;
//
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_Y_L_XL ); // read Y accel
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
aY = (float)temp;
aY = (aY * _accel_mg_lsb) - aYbias;
temp = 0;
//
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_Z_L_XL ); // read z accel
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
aZ = (float)temp;
aZ = (aZ * _accel_mg_lsb) - aZbias;
}
}
////
float get_aX()
{
return aX;
}
float get_aY()
{
return aY;
}
float get_aZ()
{
return aZ;
}
////
void fReadGyros()
{
int16_t temp;
fReadSPIdata16bits( hAG, STATUS_REG );
// is new gyro data available
if ( GetHighBits() & GyroDataReady )
{
gX = 0.0f; gY = 0.0f; gZ = 0.0f;
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_X_L_G ); // read x gyro
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
temp /= 1000.0f;
gX = (float)temp * _gyro_dps_digit; // scale
gX -= gXbias;
temp = 0;
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_Y_L_G ); // read Y gyro
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
temp /= 1000.0f;
gY = (float)temp * _gyro_dps_digit; // scale
gY -= gYbias;
temp = 0;
fReadSPIdata16bits( hAG, LSM9DS1_REGISTER_OUT_Z_L_G ); // read Z gyro
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
temp /= 1000.0f;
gZ = (float)temp * _gyro_dps_digit; // scale
gZ -= gZbias;
}
}
////
float get_gX()
{
return gX;
}
////
float get_gY()
{
return gY;
}
////
float get_gZ()
{
return gZ;
}
////
void fReadMagnetometer()
{
int16_t temp;
fReadSPIdata16bits( hM, STATUS_REG );
if ( GetHighBits() & LSM9DS1_REGISTER_OUT_X_L_M )
{
fReadSPIdata16bits( hM, LSM9DS1_REGISTER_OUT_X_L_M ); // read X magnetometer
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
mX = (float)temp * _mag_mgauss_lsb; // scale
////
fReadSPIdata16bits( hM, LSM9DS1_REGISTER_OUT_Y_L_M ); // read Y magnetometer
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
mY = (float)temp * _mag_mgauss_lsb; // scale
// ////
fReadSPIdata16bits( hM, LSM9DS1_REGISTER_OUT_Z_L_M ); // read Z magnetometer
temp = GetHighBits(); temp <<= 8; temp |= GetLowBits();
mZ = (float)temp * _mag_mgauss_lsb; // scale
}
}
////
float get_mX()
{
return mX;
}
////
float get_mY()
{
return mY;
}
////
float get_mZ()
{
return mZ;
}
////
And, finally, the code to use the ESP32 SPI API the ESP32_SPI_API.h
Code: Select all
#include <driver/spi_master.h>
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
////////////////////////////////////
//
//#define MAGTYPE true
//#define XGTYPE false
//////////////////////////
///////////////////////////
//
////////////////////////////
uint8_t GetLowBits();
int8_t GetHighBits();
int fReadSPIdata16bits( spi_device_handle_t &h, int address );
int fWriteSPIdata8bits( spi_device_handle_t &h, int address, int sendData );
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin);
// spi_device_handle_t fInitializeSPI_Devices( int csPin);
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA);
the code to use the ESP32 SPI API the ESP32_SPI_API.cpp
Code: Select all
#include "ESP32_SPI_API.h"
/////////////////////////////
///////////////////////////
uint8_t txData[2] = { };
uint8_t rxData[25] = { };
uint8_t low;
int8_t high;
//////
//////////////////////////////////
uint8_t GetLowBits()
{
return low;
}
int8_t GetHighBits()
{
return high;
}
////////////////////////////////////////
int fInitializeSPI_Channel( int spiCLK, int spiMOSI, int spiMISO, spi_host_device_t SPI_Host, bool EnableDMA)
{
esp_err_t intError;
spi_bus_config_t bus_config = { };
bus_config.sclk_io_num = spiCLK; // CLK
bus_config.mosi_io_num = spiMOSI; // MOSI
bus_config.miso_io_num = spiMISO; // MISO
bus_config.quadwp_io_num = -1; // Not used
bus_config.quadhd_io_num = -1; // Not used
intError = spi_bus_initialize( HSPI_HOST, &bus_config, EnableDMA) ;
return intError;
}
//////
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin)
{
esp_err_t intError;
spi_device_interface_config_t dev_config = { }; // initializes all field to 0
dev_config.address_bits = 0;
dev_config.command_bits = 0;
dev_config.dummy_bits = 0;
dev_config.mode = 3 ;
dev_config.duty_cycle_pos = 0;
dev_config.cs_ena_posttrans = 0;
dev_config.cs_ena_pretrans = 0;
dev_config.clock_speed_hz = 7000000;
dev_config.spics_io_num = csPin;
dev_config.flags = 0;
dev_config.queue_size = 1;
dev_config.pre_cb = NULL;
dev_config.post_cb = NULL;
spi_bus_add_device(HSPI_HOST, &dev_config, &h);
return intError;
} // void fInitializeSPI_Devices()
///////////////////////////////////////////////////////////////
int fReadSPIdata16bits( spi_device_handle_t &h, int _address )
{
uint8_t address = _address;
esp_err_t intError = 0;
low=0; high=0;
spi_transaction_t trans_desc;
trans_desc = { };
trans_desc.addr = 0;
trans_desc.cmd = 0;
trans_desc.flags = 0;
trans_desc.length = (8 * 3); // total data bits
trans_desc.tx_buffer = txData;
trans_desc.rxlength = 8 * 2 ; // Number of bits NOT number of bytes
trans_desc.rx_buffer = rxData;
txData[0] = address | 0x80;
intError = spi_device_transmit( h, &trans_desc);
low = rxData[0]; high = rxData[1];
return intError;
} // void fSendSPI( uint8_t count, uint8_t address, uint8_t DataToSend)
////
int fWriteSPIdata8bits( spi_device_handle_t &h, int _address, int _sendData )
{
uint8_t address = _address;
uint8_t sendData = _sendData;
esp_err_t intError;
spi_transaction_t trans_desc;
trans_desc = { };
trans_desc.addr = 0;
trans_desc.cmd = 0;
trans_desc.flags = 0;
trans_desc.length = (8 * 2); // total data bits
trans_desc.tx_buffer = txData;
trans_desc.rxlength = 0 ; // Number of bits NOT number of bytes
trans_desc.rx_buffer = NULL;
txData[0] = address & 0x7F;
txData[1] = sendData;
intError = spi_device_transmit( h, &trans_desc);
return intError;
} // void fWriteSPIdata8bits( spi_device_handle_t &h, uint8_t address, uint8_t sendData )
//