hgpt:
Further update using an ESP32 board.
You are using the loop function to run your code on an ESP32 is an issue regarding speed of execution. On an ESP32 the loop() has the lowest priority of all running tasks. By using freeRTOS and tasks, you can set the priority of the tasks to be above loop() and you can assign a task to a core. One core could be assigned the task of reading your ADC and putting the data into a stream buffer, which freeRTOS has. The other task can be assigned to reading the stream buffer and placing the data where you program the data to be placed. By keeping the loop() functions empty, on an ESP32, the loop(), automatically assigned to run on core 1, function will run, when it can, and do clean up tasks but only if the other tasks on core 1 are not using core time.
The freeRTOS library is built in on the ESP32.
Here is an example of two tasks running on different cores at the same time (some code left out to fit the 9K limit), still a work in progress:
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "ESP32_LSM9DS1.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
////
#include "ESP32_SPI_API.h"
////////////////////////////////////////////////////
/* create event group */
EventGroupHandle_t eg;
/* define event bits */
#define evtMLX90393 ( 1 << 0 ) // 1
#define evtfMLX90393_ReadSensorTriggered ( 1 << 1 ) // 10
#define evtfMLX90393_ReadSensor (1 << 2 ) // 100
#define evtfMLX90393Begin ( 1 >> 3 ) //1000
////////////////////////////////////////////////////
#define TaskCore1 1
#define TaskCore0 0
#define SerialDataBits 115200
#define TaskStack10K 10000
#define TaskStack30K 30000
#define Priority4 4
///////////////////////////////////////////////////
TickType_t xSemaphoreTicksToWait = 500;
#define csPinMLX90393 4
#define spiCLK 25 //
#define spiMOSI 26 //
#define spiMISO 27 //
spi_device_handle_t _hMLX90393;
TickType_t xTicksToWait0 = 0;
void IRAM_ATTR triggerMLX90393read()
{
BaseType_t xHigherPriorityTaskWoken;
xEventGroupSetBitsFromISR(eg, evtfMLX90393_ReadSensorTriggered, &xHigherPriorityTaskWoken);
}
//////////////////////////////////////////
void setup()
{
pinMode( 18, INPUT );
Serial.begin( SerialDataBits );
//attaching the interrupt to microcontroller pin
attachInterrupt( 18, triggerMLX90393read, FALLING );
////
eg = xEventGroupCreate();
////
if ( fInitializeSPI_Channel( spiCLK, spiMOSI, spiMISO, HSPI_HOST, true) != 0 )
{
Serial.println ( "fInitializeSPI_Channel error " );
}
if ( fInitializeSPI_Devices( _hMLX90393, csPinMLX90393 ) != 0 )
{
Serial.print ( "fInitializeSPI_Device MLX90393 error " );
}
if ( fInitializeAG() != true )
{
Serial.print ( "fInitializeSPI_Device LSM9DS1 error " );
}
if ( fInitializeM() != true )
{
Serial.print ( "fInitializeSPI_Device LSM9DS1_M error " );
}
/////////////////// CORE 0 ////////////////////////////////////////////////////////////////////////////////
xTaskCreatePinnedToCore ( fGetIMU, "v_getIMU", TaskStack30K, NULL, Priority4, NULL, TaskCore0 );
//////////////////// CORE 1 ////////////////////////////////////////////////////////////////////////////////
xTaskCreatePinnedToCore ( fMLX90393, "fMLX90393", TaskStack30K, NULL, Priority4, NULL, TaskCore1 );
xTaskCreatePinnedToCore ( fMLX90393_triggerReadSensor, "fMLX90393_triggerReadSensor", TaskStack10K, NULL, Priority4, NULL, TaskCore1 );
}
//////////////////////////////////////////////////////////
void loop() {} <<<<---- empty loop()
//////////////////////////////////////////////////////////
////
////
void fMLX90393_triggerReadSensor( void * pvParameters )
{
for ( ;; )
{
xEventGroupWaitBits (eg, evtfMLX90393_ReadSensorTriggered, pdTRUE, pdTRUE, portMAX_DELAY);
xEventGroupSetBits( eg, evtfMLX90393_ReadSensor );
}
vTaskDelete(NULL);
}// void fMLX90393_triggerReadSensor( void * pvParameters )
////
void fMLX90393( void * pvParameters )
{
int rx[10] = { 0 };
int _gain = MLX90393_GAIN_1X;
int xyResoultion = 0;
int zResoultion = 1;
int xRes;
int yRes;
int zRes;
esp_err_t intError;
vTaskDelay( 500 ); // the LSM9DS1 needs some time to complete its setup and calibration
intError = fWriteSPIdata8bits2( _hMLX90393, MLX90393_REG_RT ); // reset
vTaskDelay( 3 ); // allow reset time to complete
// set gain
intError = fWriteSPIdata32bits( _hMLX90393, MLX90393_REG_WR, 0x00, (((_gain & 0x7) << MLX90393_GAIN_SHIFT) | MLX90393_HALL_CONF), (MLX90393_CONF1 & 0x3F) << 2 );
intError = fWriteSPIdata32bits( _hMLX90393, MLX90393_REG_WR, 0x00, 0x42, (MLX90393_CONF2 & 0x3F) << 2 ); // using 0x00 for the lower 8 bits of the register
//
fMLX90393_ChangeResoultion( _hMLX90393, 3 );
// read MLX90393_CONF3 for resolution
intError = fReadSPIdataXbits( _hMLX90393, (MLX90393_CONF3 & 0x3f) << 2, rx, 3 );
// // combine response into 16bit
int temp = ( rx[2] << 8) | rx[1];
// find resoultion being used
temp = temp >> 5;
// extract 1st 2 bits, x resolution
xRes = temp & 3;
temp = temp >> 2;
yRes = temp & 3;
temp = temp >> 2;
zRes = temp & 3;
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS( 100 );
xLastWakeTime = xTaskGetTickCount();
while (1)
{
vTaskDelayUntil( &xLastWakeTime, xFrequency );
// request a single data read
intError = fWriteSPIdata8bits2( _hMLX90393, MLX90393_REG_SM | MLX90393_AXIS_ALL ); // single measurement all axis and temprature
//triggered from void IRAM_ATTR triggerMLX90393read(), when the unit has data available
xEventGroupWaitBits ( eg, evtfMLX90393_ReadSensor, pdTRUE, pdTRUE, portMAX_DELAY);
intError = fReadSPIdataXbits( _hMLX90393, MLX90393_REG_RM | MLX90393_AXIS_ALL, rx, 9 );
/* rx[0] = status bit
rx[1] & rx[2] = temprature
rx[3] & rx[4] x
rx[5] & rx[6] y
rx[7] & rx[8] z
*/
// Convert data to 16 bit
uint16_t xi, yi, zi;
xi = (rx[3] << 8) | rx[4]; // shift MSB over to the left by 8 & with LSB
yi = (rx[5] << 8) | rx[6];
zi = (rx[7] << 8) | rx[8];
// determine gain being used
float xT = 0.0f, yT = 0.0f, zT = 0.0f;
xT = (float)xi * mlx90393_lsb_lookup[_gain][xRes][xyResoultion];
yT = (float)yi * mlx90393_lsb_lookup[_gain][yRes][xyResoultion];
zT = (float)zi * mlx90393_lsb_lookup[_gain][zRes][zResoultion];
xLastWakeTime = xTaskGetTickCount();
}
vTaskDelete(NULL);
}
void fGetIMU( void *pvParameters )
{
if ( fDO_AG_ID() )
{
if ( fDO_M_ID() )
{
fReboot();
vTaskDelay( 50 );
fEnableGandA(); // enable gyros and accelerometers
fEnableM();
setupAccelScale( LSM9DS1_ACCELRANGE_16G );
setupGyroScale ( LSM9DS1_GYROSCALE_2000DPS );
setupMagScale( LSM9DS1_MAGGAIN_16GAUSS );
calibrate();
} // if ( fDO_M_ID )
// } // if ( fInitializeM() )
} // if ( fDO_AG_ID() )
// } // if ( fInitializeAG() )
// } // if ( fInitializeDevice( ) )
vTaskDelay( 1 ); // pasue to make sure that the MLX90393 begins its do things
////
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS( 100 );
xLastWakeTime = xTaskGetTickCount();
while (1)
{
vTaskDelayUntil( &xLastWakeTime, xFrequency );
if ( getLSM9DS1_ID_OK() && getMAG_ID_OK() ) // then do things
{
fReadAccelerometers();
fReadGyros();
fReadMagnetometer();
} // if ( LSM9DS1_ID_OK && M_ID_OK ) // then do things
else
{
}
xLastWakeTime = xTaskGetTickCount();
}
vTaskDelete(NULL);
} // void fGetIMU( void *pvParameters )
////
You can use the hardware timer to trigger tasks down to 1uS increments. There is another timer that can be used for nanoSec triggering. In your case, I'd just make the task to read the ADC, placed on core 1, do round robin instead of uS or nS triggering. Or, if the ADC has an interrupt to let you know that the reading is done, I'd trigger the task with the interrupt. Something like I do with the void fMLX90393( void * pvParameters ) task.