Page 1 of 1

[SOLVED] SECOND SPI QUESTION

Posted: Thu Nov 07, 2019 9:28 am
by zekageri
Hello guys!
I want to use two spi interface of the esp32.
I'am already using the TFT_eSPI.h lib with the VSPI of the esp32 on core0.
Now i want to implement the HSPI on core1 for an ADXL345 accelerometer.

I have this sketch that i'am trying to implement but this is not working for some reason.
I always get 0,0,-1 results on the serial.

Here is the datasheet:

https://pdf1.alldatasheet.com/datasheet ... XL345.html

Code: Select all

#define BW_RATE     0x2C //Data rate and power mode control
#define POWER_CTL   0x2D //Power Control Register
#define DATA_FORMAT 0x31 //Data format control
#define DATAX0      0x32 //X-Axis Data 0

#define SCK 17 		// SCL  /** labels on the adxl board **/
#define MISO 12	// SDA
#define MOSI 16	// SD0
#define SS 15 		// CS

#define SECOND_SPI_FREQUENCY  27000000

SPIClass Second_SPI(HSPI); // TFT LIB USES VSPI

char values[10];
int16_t x, y, z;
float xg, yg, zg;
long Second_SPI_MILLIS = millis();

void writeRegister(char registerAddress, char value) {
    digitalWrite(SS, LOW);
    Second_SPI.transfer(registerAddress);
    Second_SPI.transfer(value);
    digitalWrite(SS, HIGH);
}

void readRegister(char registerAddress, int16_t numBytes, char * values) {
    char address = 0x80 | registerAddress;
    if (numBytes > 1)address = address | 0x40;
    digitalWrite(SS, LOW);
    Second_SPI.transfer(address);
    for (int16_t i = 0; i < numBytes; i++) {
        values[i] = Second_SPI.transfer(0x00);
    }
    digitalWrite(SS, HIGH);
}
static const inline void Setup_Second_SPI(){
    Second_SPI.begin(SCK,MISO,MOSI,SS);  
    Second_SPI.setDataMode(SPI_MODE0);
    Second_SPI.setBitOrder(MSBFIRST);
    Second_SPI.setFrequency(SECOND_SPI_FREQUENCY);
    // SS Hight
    pinMode(SS, OUTPUT);
    digitalWrite(SS, HIGH);
    // ADXL345
    writeRegister(DATA_FORMAT, 0x03);   // ±16g 10bit
    writeRegister(POWER_CTL, 0x08);
    writeRegister(BW_RATE, 0x0F);
}

static const inline void Second_SPI_Loop(){
    if(millis() - Second_SPI_MILLIS >= 1500){
        Second_SPI_MILLIS = millis();
        readRegister(DATAX0, 6, values);
        x = ((int16_t)values[1] << 8) | (int16_t)values[0];
        y = ((int16_t)values[3] << 8) | (int16_t)values[2];
        z = ((int16_t)values[5] << 8) | (int16_t)values[4];
        xg = x * 0.03125;
        yg = y * 0.03125;
        zg = (z * 0.03125) - 1;

        Serial.print(xg);
        Serial.print("\t");
        Serial.print(yg);
        Serial.print("\t");
        Serial.println(zg);
    }
}
Ofc the Second_SPI_Setup() is in the setup() and the Second_SPI_Loop() is in the loop().
What can be the problem?
Thank you for your patience.

Re: SECOND SPI QUESTION

Posted: Thu Nov 07, 2019 4:17 pm
by idahowalker
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 )
//

Re: SECOND SPI QUESTION

Posted: Thu Nov 07, 2019 8:14 pm
by TomWS1
zekageri wrote:
Thu Nov 07, 2019 9:28 am
Now i want to implement the HSPI on core1 for an ADXL345 accelerometer.

I have this sketch that i'am trying to implement but this is not working for some reason.
I always get 0,0,-1 results on the serial.


If I recall correctly, the ADXL345 isn't a pure SPI interface as it can switch between SPI and I2C modes based on the levels of the signal lines. There is a discussion in the data sheet about sharing SPI with other peripherals, but I think this condition can also exist if the SCLK line is not held High when not accessing the device. Pullups on SCLK & CS might solve this.

Re: SECOND SPI QUESTION

Posted: Mon Nov 11, 2019 9:24 am
by zekageri
Thank you all for your patience and help.
The problem was with the adxl module.
In this module version was a 0 ohm resistor on the miso pin to the gnd, and it was pulled the line to low all the time.