Compare commits

...

2 Commits

Author SHA1 Message Date
5853bf849f fixes 2025-04-22 20:35:29 +02:00
9104869ecf save some implementation 2025-04-22 14:27:07 +02:00
31 changed files with 1191 additions and 373 deletions

17
.vscode/settings.json vendored
View File

@@ -1,6 +1,6 @@
{
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPath": "/home/bruno/esp/v5.4.1/esp-idf",
"idf.espIdfPath": "/home/bruno/esp/master/esp-idf",
"idf.pythonInstallPath": "/usr/bin/python",
"idf.openOcdConfigs": [
"board/esp32s3-builtin.cfg"
@@ -29,6 +29,19 @@
"esp_mac.h": "c",
"gpio.h": "c",
"chrono": "c",
"cstdint": "c"
"cstdint": "c",
"task.h": "c",
"compare": "c",
"uart_struct.h": "c",
"uart.h": "c",
"gpio_num.h": "c",
"mcp3550.h": "c",
"esp_timer.h": "c",
"math.h": "c",
"esp_check.h": "c",
"radio.h": "c",
"sx1262.h": "c",
"gps.h": "c",
"servocontroller.h": "c"
}
}

View File

@@ -1,5 +0,0 @@
set(component_srcs "ra01s.c")
idf_component_register(SRCS "${component_srcs}"
PRIV_REQUIRES driver
INCLUDE_DIRS ".")

View File

@@ -1,163 +0,0 @@
menu "SX126X Configuration"
config GPIO_RANGE_MAX
int
default 33 if IDF_TARGET_ESP32
default 46 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
choice FREQUENCY
prompt "Frequency to use"
default 433MHZ
help
Select Frequency to use.
config 433MHZ
bool "433MHz"
help
Frequency is 433MHz.
config 866MHZ
bool "866MHz"
help
Frequency is 866MHz.
config 915MHZ
bool "915MHz"
help
Frequency is 915MHz.
config OTHER
bool "Other"
help
Other Frequency.
endchoice
config OTHER_FREQUENCY
depends on OTHER
int "Frequency to use[MHz]"
range 1 999
default 433
help
Frequency to use[MHz].
config ADVANCED
bool "Enable Advanced settings"
default false
help
Enable Advanced settings.
config CODING_RATE
depends on ADVANCED
int "Error coding rate"
range 1 4
default 1
help
Error coding rate.
config BANDWIDTH
depends on ADVANCED
int "Signal Bandwidth"
range 0 6
default 4
help
Signal Bandwidth.
config SF_RATE
depends on ADVANCED
int "Spreading Factor"
range 5 12
default 7
help
Spreading Factor.
config USE_TCXO
bool "Enable TCXO"
default false
help
Enable Temperature-Compensated Crystal Oscillator.
config MISO_GPIO
int "SX126X MISO GPIO"
range 0 GPIO_RANGE_MAX
default 19 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 4 # C3 and others
help
Pin Number to be used as the MISO SPI signal.
config SCLK_GPIO
int "SX126X SCLK GPIO"
range 0 GPIO_RANGE_MAX
default 18 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 5 # C3 and others
help
Pin Number to be used as the SCLK SPI signal.
config MOSI_GPIO
int "SX126X MOSI GPIO"
range 0 GPIO_RANGE_MAX
default 23 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 6 # C3 and others
help
Pin Number to be used as the MOSI SPI signal.
config NSS_GPIO
int "SX126X NSS GPIO"
range 0 GPIO_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 7 # C3 and others
help
Pin Number to be used as the NSS SPI signal.
config RST_GPIO
int "SX126X RST GPIO"
range 0 GPIO_RANGE_MAX
default 16 if IDF_TARGET_ESP32
default 38 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 # C3 and others
help
Pin Number to be used as the RST signal.
config BUSY_GPIO
int "SX126X BUSY GPIO"
range 0 GPIO_RANGE_MAX
default 17 if IDF_TARGET_ESP32
default 39 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 3 # C3 and others
help
Pin Number to be used as the BUSY signal.
config TXEN_GPIO
int "SX126X TXEN GPIO"
range -1 GPIO_RANGE_MAX
default -1
help
Pin Number to be used as the TXEN signal.
config RXEN_GPIO
int "SX126X RXEN GPIO"
range -1 GPIO_RANGE_MAX
default -1
help
Pin Number to be used as the RXEN signal.
choice SPI_HOST
prompt "SPI peripheral that controls this bus"
default SPI2_HOST
help
Select SPI peripheral that controls this bus.
config SPI2_HOST
bool "SPI2_HOST"
help
Use SPI2_HOST. This is also called HSPI_HOST.
config SPI3_HOST
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
bool "SPI3_HOST"
help
USE SPI3_HOST. This is also called VSPI_HOST
endchoice
endmenu

View File

@@ -2,7 +2,7 @@ dependencies:
idf:
source:
type: idf
version: 5.4.1
version: 5.5.0
k0i05/esp_bme680:
component_hash: 2df0cb14d4425565a8745d4a96bfaa8ff7e90bbec3e208a073821406dded23c8
dependencies:

View File

@@ -13,8 +13,18 @@ idf_component_register(SRCS
"hw/mcp23018.h"
"hw/mpu9250.c"
"hw/mpu9250.h"
"hw/gps.c"
"hw/gps.h"
"hw/mcp3550.c"
"hw/mcp3550.h"
"hw/sx1262.c"
"hw/sx1262.h"
"components/sensors.c"
"components/sensors.h"
"components/servocontroller.c"
"components/servocontroller.h"
"components/radio.c"
"components/radio.h"
"main.c"
INCLUDE_DIRS ".")

88
main/components/packets.h Normal file
View File

@@ -0,0 +1,88 @@
#ifndef PACKETS_STRUCTS
#define PACKETS_STRUCTS
#include "stdint.h"
typedef struct __attribute__((packed))
{
uint32_t packetIndex;
uint8_t packetType;
uint32_t missionTimer;
} DownBoundPacket;
typedef struct __attribute__((packed))
{
// MPU data
int16_t accelerationX;
int16_t accelerationY;
int16_t accelerationZ;
int16_t gyroX;
int16_t gyroY;
int16_t gyroZ;
int16_t magnetX;
int16_t magnetY;
int16_t magnetZ;
int16_t accelerometer_temperature;
// CCS data
uint16_t eCO2;
uint16_t tvoc;
uint8_t currentCCS;
uint16_t rawCCSData;
// INA data
uint16_t volts;
uint16_t current;
uint16_t power;
// BME DATA
uint32_t temperature;
uint16_t humidity;
uint32_t pressure;
uint16_t gas;
bool gas_valid;
bool heater_stable;
uint8_t gas_range;
uint8_t gas_index;
// GPS DATA
uint32_t time_seconds; // Seconds since start of day
int32_t latitude_centi_degrees; // Latitude * 10,000
int32_t longitude_centi_degrees; // Longitude * 10,000
int16_t altitude_centi_meters; // Altitude * 100
uint8_t fix_quality;
uint8_t num_satellites;
uint16_t date_yyddmm; // YYDDMM (from GPRMC)
uint16_t speed_centi_knots; // Speed * 100 (from GPRMC)
int32_t predicted_latitude_centi_degrees; // Latitude * 10,000
int32_t predicted_longitude_centi_degrees; // Longitude * 10,000
int16_t predicted_altitude_centi_meters; // Altitude * 100
// ADC DATA
int32_t NH3;
int32_t CO;
int32_t NO2;
int32_t UVC;
int16_t currentServoA;
int16_t targetServoA;
int16_t currentServoB;
int16_t targetServoB;
} TelemetryPacket;
typedef struct __attribute__((packed))
{
uint32_t packetIndex;
uint8_t packetType;
} UplinkPacket;
typedef struct __attribute__((packed))
{
uint8_t powerMode;
uint8_t controlMode;
uint16_t servoA;
uint16_t servoB;
} SystemControlPacket;
#endif

108
main/components/radio.c Normal file
View File

@@ -0,0 +1,108 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "../hw/sx1262.h"
#include "radio.h"
#include "esp_log.h"
#include "string.h"
#include "esp_timer.h"
const char *msg = "Testing 123 test why is this not on air";
#define TAG "LoRa"
uint32_t packetIndex = 0;
TelemetryPacket telemetryPacket;
uint8_t packetReadiness = 0;
void lora_comms_task(void *pvParameters)
{
const int64_t interval_us = 100000; // 100 ms
int64_t start_time, end_time, elapsed;
LoRaInit();
int8_t txPowerInDbm = 20;
uint32_t frequencyInHz = 0;
frequencyInHz = 869525000;
ESP_LOGW(TAG, "Enable TCXO");
float tcxoVoltage = 2.2; // use TCXO
bool useRegulatorLDO = true; // use DCDC + LDO
// LoRaDebugPrint(true);
if (LoRaBegin(frequencyInHz, txPowerInDbm, tcxoVoltage, useRegulatorLDO) != 0)
{
ESP_LOGE(TAG, "Does not recognize the module");
while (1)
{
vTaskDelay(1);
}
}
uint8_t spreadingFactor = 7;
uint8_t bandwidth = SX126X_LORA_BW_250_0;
uint8_t codingRate = SX126X_LORA_CR_4_8;
uint16_t preambleLength = 8;
uint8_t payloadLen = 0;
bool crcOn = true;
bool invertIrq = false;
LoRaConfig(spreadingFactor, bandwidth, codingRate, preambleLength, payloadLen, crcOn, invertIrq);
uint8_t bufIn[256]; // Maximum Payload size of SX1261/62/68 is 255
uint8_t bufOut[256]; // Maximum Payload size of SX1261/62/68 is 255
DownBoundPacket downboundPacket;
UplinkPacket uplinkPacket;
SystemControlPacket systemControlPacket;
while (1)
{
start_time = esp_timer_get_time(); // µs since boot
if (packetReadiness == 1)
{
uint8_t downPacketSize = 0;
memset(bufOut, 0, sizeof(bufOut));
downboundPacket.missionTimer = start_time;
downboundPacket.packetIndex = packetIndex++;
downboundPacket.packetType = 1;
memcpy(bufOut, &downboundPacket, sizeof(downboundPacket));
downPacketSize += sizeof(downboundPacket);
memcpy(((uint8_t *)bufOut) + downPacketSize, &telemetryPacket, sizeof(telemetryPacket));
downPacketSize += sizeof(telemetryPacket);
ESP_LOGI(pcTaskGetName(NULL), "%d byte packet sent...", downPacketSize);
// Wait for transmission to complete
if (LoRaSend(bufOut, downPacketSize, SX126x_TXMODE_SYNC) == false)
{
ESP_LOGE(pcTaskGetName(NULL), "LoRaSend fail");
} else {
packetReadiness = 0;
}
}
uint8_t rxLen = LoRaReceive(bufIn, sizeof(bufIn));
if (rxLen > 0)
{
ESP_LOGI(pcTaskGetName(NULL), "%d byte packet received:[%.*s]", rxLen, rxLen, bufIn);
int8_t rssi, snr;
GetPacketStatus(&rssi, &snr);
ESP_LOGI(pcTaskGetName(NULL), "rssi=%d[dBm] snr=%d[dB]", rssi, snr);
}
int lost = GetPacketLost();
if (lost != 0)
{
ESP_LOGW(pcTaskGetName(NULL), "%d packets lost", lost);
}
end_time = esp_timer_get_time();
elapsed = end_time - start_time;
if (elapsed < interval_us)
{
vTaskDelay(pdMS_TO_TICKS((interval_us - elapsed) / 1000));
}
}
}

19
main/components/radio.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef RADIO_COMPONENT
#define RADIO_COMPONENT
#define LORA_POWER_LOW 2
#define LORA_POWER_HIGH 20
#define LORA_POWER_MAX_MAYBE_UNSAFE 22
#define LORA_TX_POWER LORA_POWER_LOW
#define TAG_RADIO "RADIO"
#include "packets.h"
void lora_comms_task(void *pvParameters);
extern TelemetryPacket telemetryPacket;
extern uint8_t packetReadiness;
#endif

View File

@@ -1,4 +1,8 @@
#include "sensors.h"
#include "esp_timer.h"
#include "radio.h"
#include "../hw/gps.h"
#include "servocontroller.h"
#define BLINK_GPIO 2
@@ -13,64 +17,76 @@ static void configure_led(void)
void i2c_sensors_task(void *pvParameters)
{
// initialize the xLastWakeTime variable with the current time.
TickType_t last_wake_time = xTaskGetTickCount();
const TickType_t I2C0_TASK_SAMPLING_RATE = 5;
const int64_t interval_us = 100000; // 100 ms
int64_t start_time, end_time, elapsed;
//
// initialize i2c device configuration
bme680b_init();
mpu9250_init();
mcp23018_init();
ina260_init();
ccs811_init();
mcp3550_spi_init();
configure_led();
int16_t accel[3], gyro[3], temp;
float accel_f[3], gyro_f[3], temp_f;
int16_t accel[3], gyro[3], temp, magnet[3];
float accel_f[3], gyro_f[3], temp_f, magnet_f[3];
uint16_t eCO2;
uint16_t tvoc;
uint8_t currentCCS;
uint16_t rawData;
uint16_t volts;
uint16_t current;
uint16_t power;
bme680_data_t bmeData;
// task loop entry point
for (;;)
{
packetReadiness = 2;
start_time = esp_timer_get_time(); // µs since boot
//
// handle sensor
if (BME680_DEV_HANDLE)
{
bme680_data_t data;
esp_err_t result = bme680_get_data(BME680_DEV_HANDLE, &data);
esp_err_t result = bme680_get_data(BME680_DEV_HANDLE, &bmeData);
if (result != ESP_OK)
{
ESP_LOGE(TAG_BME, "bme680 device read failed (%s)", esp_err_to_name(result));
}
else
{
data.barometric_pressure = data.barometric_pressure / 100;
// ESP_LOGI(TAG, "dewpoint temperature:%.2f °C", data.dewpoint_temperature);
ESP_LOGI(TAG_BME, "air temperature: %.2f °C", data.air_temperature);
ESP_LOGI(TAG_BME, "relative humidity: %.2f %%", data.relative_humidity);
ESP_LOGI(TAG_BME, "barometric pressure: %.2f hPa", data.barometric_pressure);
// ESP_LOGI(TAG, "gas resistance: %.2f kOhms", data.gas_resistance / 1000);
// ESP_LOGI(TAG, "iaq score: %u (%s)", data.iaq_score, bme680_air_quality_to_string(data.iaq_score));
bmeData.barometric_pressure = bmeData.barometric_pressure / 100;
ESP_LOGI(TAG_BME, "dewpoint temperature:%.2f °C", bmeData.dewpoint_temperature);
ESP_LOGI(TAG_BME, "air temperature: %.2f °C", bmeData.air_temperature);
ESP_LOGI(TAG_BME, "relative humidity: %.2f %%", bmeData.relative_humidity);
ESP_LOGI(TAG_BME, "barometric pressure: %.2f hPa", bmeData.barometric_pressure);
ccs811_set_env_data(bmeData.air_temperature, bmeData.relative_humidity);
ESP_LOGI(TAG_BME, "gas resistance: %.2f kOhms", bmeData.gas_resistance / 1000);
ESP_LOGI(TAG_BME, "iaq score: %u (%s)", bmeData.iaq_score, bme680_air_quality_to_string(bmeData.iaq_score));
}
} else {
}
else
{
bme680b_init();
}
ccs811_get_data(&eCO2, &tvoc);
ccs811_get_data(&eCO2, &tvoc, &currentCCS, &rawData);
ESP_LOGI(TAG_CCS, "eCO₂: %d ppm, TVOC: %d ppb", eCO2, tvoc);
ESP_LOGI(TAG_CCS, "Current: %d μA, Raw voltage: %d V", currentCCS, rawData);
if (mpu9250_read_sensor_data(MPU9250_DEV_HANDLE, accel, gyro, &temp) == ESP_OK)
if (mpu9250_read_sensor_data(MPU9250_DEV_HANDLE, accel, gyro, &temp, magnet) == ESP_OK)
{
mpu9250_convert_data(accel, gyro, temp, accel_f, gyro_f, &temp_f);
mpu9250_convert_data(accel, gyro, temp, magnet, accel_f, gyro_f, &temp_f, magnet_f);
ESP_LOGI(TAG_MPU, "Accel: X=%.2f g, Y=%.2f g, Z=%.2f g", accel_f[0], accel_f[1], accel_f[2]);
ESP_LOGI(TAG_MPU, "Gyro: X=%.2f°/s, Y=%.2f°/s, Z=%.2f°/s", gyro_f[0], gyro_f[1], gyro_f[2]);
ESP_LOGI(TAG_MPU, "Magnet: X=%.2fμT, Y=%.2fμT, Z=%.2fμT", magnet_f[0], magnet_f[1], magnet_f[2]);
ESP_LOGI(TAG_MPU, "Temperature: %.2f °C", temp_f);
}
else
@@ -81,10 +97,86 @@ void i2c_sensors_task(void *pvParameters)
ina260_readParams(&volts, &current, &power);
ina260_printParams(volts, current, power);
float VREFVoltage = volts * 1.25 / 1000; // Mame vobec nieco na VREFE? Na scheme su len medzi sebou prepojene
mics_adc_data_t ADCData = mcp3550_read_all(5.0); // vref = 5.0V
log_mics_adc_values(&ADCData);
ADCData = mcp3550_read_all(VREFVoltage);
log_mics_adc_values(&ADCData);
gpio_set_level(BLINK_GPIO, s_led_state);
/* Toggle the LED state */
s_led_state = !s_led_state;
vTaskDelaySecUntil(&last_wake_time, I2C0_TASK_SAMPLING_RATE);
end_time = esp_timer_get_time();
elapsed = end_time - start_time;
if (elapsed < interval_us)
{
vTaskDelay(pdMS_TO_TICKS((interval_us - elapsed) / 1000));
}
if (packetReadiness == 0) {
memset(&telemetryPacket, 0, sizeof(telemetryPacket));
telemetryPacket.accelerationX = accel[0];
telemetryPacket.accelerationY = accel[1];
telemetryPacket.accelerationZ = accel[2];
telemetryPacket.gyroX = gyro[0];
telemetryPacket.gyroX = gyro[1];
telemetryPacket.gyroX = gyro[2];
telemetryPacket.magnetX = gyro[0];
telemetryPacket.magnetX = gyro[1];
telemetryPacket.magnetX = gyro[2];
telemetryPacket.accelerometer_temperature = temp;
telemetryPacket.eCO2 = eCO2;
telemetryPacket.tvoc = tvoc;
telemetryPacket.currentCCS = currentCCS;
telemetryPacket.rawCCSData = rawData;
telemetryPacket.volts = volts;
telemetryPacket.current = current;
telemetryPacket.power = power;
telemetryPacket.temperature = bmeData.raw_data.temperature;
telemetryPacket.humidity = bmeData.raw_data.humidity;
telemetryPacket.pressure = bmeData.raw_data.pressure;
telemetryPacket.gas = bmeData.raw_data.gas;
telemetryPacket.gas_range = bmeData.raw_data.gas_range;
telemetryPacket.heater_stable = bmeData.raw_data.heater_stable;
telemetryPacket.gas_valid = bmeData.raw_data.gas_valid;
telemetryPacket.NH3 = ADCData.raw_nh3;
telemetryPacket.CO = ADCData.raw_co;
telemetryPacket.NO2 = ADCData.raw_no2;
telemetryPacket.UVC = ADCData.raw_uvc;
//TODO MOVE THIS TO A BETTER PLACE FOR SYNC
telemetryPacket.time_seconds = gpsDataOut.time_seconds;
telemetryPacket.latitude_centi_degrees = gpsDataOut.latitude_centi_degrees;
telemetryPacket.longitude_centi_degrees = gpsDataOut.longitude_centi_degrees;
telemetryPacket.fix_quality = gpsDataOut.fix_quality;
telemetryPacket.num_satellites = gpsDataOut.num_satellites;
telemetryPacket.altitude_centi_meters = gpsDataOut.altitude_centi_meters;
telemetryPacket.date_yyddmm = gpsDataOut.date_yyddmm;
telemetryPacket.speed_centi_knots = gpsDataOut.speed_centi_knots;
telemetryPacket.predicted_altitude_centi_meters = predictedPosition.altitude_centi_meters;
telemetryPacket.predicted_latitude_centi_degrees = predictedPosition.latitude_centi_degrees;
telemetryPacket.predicted_longitude_centi_degrees = predictedPosition.longitude_centi_degrees;
telemetryPacket.targetServoA = servoState.targetServoA;
telemetryPacket.targetServoB = servoState.targetServoB;
telemetryPacket.currentServoA = servoState.currentServoA;
telemetryPacket.currentServoB = servoState.currentServoB;
}
packetReadiness = 1;
}
//
// free resources

View File

@@ -7,6 +7,8 @@
#include <bme680.h>
#include "esp_mac.h"
#include "../hw/mcp3550.h"
#include "../hw/bme680b.h"
#include "../hw/ccs811.h"
#include "../hw/i2cbrn.h"

View File

@@ -0,0 +1,10 @@
#include "servocontroller.h"
#include "string.h"
ServoState servoState;
//TODO add a task and implement
void servoControllerInit() {
memset(&servoState, 0, sizeof(servoState));
}

View File

@@ -0,0 +1,19 @@
#ifndef SERVO_CONTROLLER_COMPONENT
#define SERVO_CONTROLLER_COMPONENT
#include "stdint.h"
typedef struct
{
int16_t currentServoA;
int16_t targetServoA;
int16_t currentServoB;
int16_t targetServoB;
} ServoState;
extern ServoState servoState;
void servoControllerInit();
#endif

70
main/hw/buscfg.h Normal file
View File

@@ -0,0 +1,70 @@
#ifndef BUSCFG_FILE
#define BUSCFG_FILE
#include "soc/gpio_num.h"
#define ESP_USB_DP GPIO_NUM_20
#define ESP_USB_DM GPIO_NUM_19
#define ESP_RXD0 GPIO_NUM_44
#define ESP_TXD0 GPIO_NUM_43
#define ESP_CONNECTOR_P1 MCP3550_MISO_GPIO
#define ESP_CONNECTOR_P2 MCP3550_MOSI_GPIO
#define ESP_CONNECTOR_P3 MCP3550_SCK_GPIO
#define ESP_CONNECTOR_P4 GPIO_NUM_39
#define ESP_CONNECTOR_P5 GPIO_NUM_38
#define ESP_CONNECTOR_P6 HSPI_UNKNOWN_CS
#define ESP_CONNECTOR_P9 HSPI_MISO_GPIO
#define ESP_CONNECTOR_P10 MCP3550_MOSI_GPIO
#define ESP_CONNECTOR_P11 MCP3550_SCK_GPIO
#define ESP_CONNECTOR_P12 HSPI_SD_CS
#define ESP_CONNECTOR_P13 HSPI_LORA_CS
#define ESP_CONNECTOR_P17 HWI2C_SDA
#define ESP_CONNECTOR_P18 HWI2C_SCL
#define ESP_CONNECTOR_P19 I2C2_SDA
#define ESP_CONNECTOR_P20 I2C2_SCL
#define ESP_CONNECTOR_P25 LORA_DIO1
#define ESP_CONNECTOR_P26 LORA_BUSY
#define ESP_CONNECTOR_P27 LORA_RXEN_MANUAL
#define ESP_CONNECTOR_P28 GPIO_NUM_6
#define ESP_CONNECTOR_P29 GPIO_NUM_5
#define ESP_CONNECTOR_P30 GPIO_NUM_4
#define ESP_CONNECTOR_P47 GPS_RXD
#define ESP_CONNECTOR_P48 GPS_TXD
#define ESP_CONNECTOR_P51 ESP_RXD0
#define ESP_CONNECTOR_P52 ESP_TXD0
#define ESP_CONNECTOR_P57 ESP_USB_DP
#define ESP_CONNECTOR_P58 ESP_USB_DM
#define HSPI_UNKNOWN_CS GPIO_NUM_42
#define LORA_RXEN_MANUAL GPIO_NUM_7
#define HSPI_MISO_GPIO GPIO_NUM_13
#define HSPI_MOSI_GPIO GPIO_NUM_11
//#define HSPI_MISO_GPIO GPIO_NUM_11
//#define HSPI_MOSI_GPIO GPIO_NUM_13
#define HSPI_SCK_GPIO GPIO_NUM_12
#define HSPI_LORA_CS GPIO_NUM_48
#define LORA_DIO1 GPIO_NUM_16
#define LORA_BUSY GPIO_NUM_15
#define HSPI_SD_CS GPIO_NUM_10
#define MCP3550_MOSI_GPIO GPIO_NUM_35
#define MCP3550_SCK_GPIO GPIO_NUM_36
#define MCP3550_MISO_GPIO GPIO_NUM_37
#define GPS_TXD GPIO_NUM_17
#define GPS_RXD GPIO_NUM_18
#define GPS_RTS UART_PIN_NO_CHANGE
#define GPS_CTS UART_PIN_NO_CHANGE
#define GPS_UART_NUM UART_NUM_2
#define HWI2C_SDA GPIO_NUM_8
#define HWI2C_SCL GPIO_NUM_9
#define I2C2_SDA GPIO_NUM_40
#define I2C2_SCL GPIO_NUM_41
#endif

View File

@@ -10,6 +10,22 @@ i2c_device_config_t CCS811_DEV_CFG = {
i2c_master_dev_handle_t CCS811_DEV_HANDLE;
void ccs811_getStatus()
{
uint8_t errorID;
uint8_t status;
uint8_t hardwareVersion;
uint16_t version;
uint16_t bootVersion;
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_STATUS, &status);
i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_APP_VERSION, &version);
i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_BOOT_VERSION, &bootVersion);
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_HW_VERSION, &hardwareVersion);
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_ERROR_ID, &errorID);
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d, boot version: %d, hardware version: %d, error ID: %d", status, version, bootVersion, hardwareVersion, errorID);
}
void ccs811_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &CCS811_DEV_CFG, &CCS811_DEV_HANDLE));
@@ -17,30 +33,47 @@ void ccs811_init()
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_POWER, 1);
vTaskDelay(10 / portTICK_PERIOD_MS);
uint8_t reset_seq[4] = {0x11, 0xE5, 0x72, 0x8A};
i2c_write_register(CCS811_DEV_HANDLE, 0xFF, reset_seq, sizeof(reset_seq)); //Reset
i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_SW_RESET, reset_seq, sizeof(reset_seq)); // Reset
vTaskDelay(10 / portTICK_PERIOD_MS);
uint8_t status;
uint16_t version;
i2c_read_register_8(CCS811_DEV_HANDLE, 0x00, &status);
i2c_read_register_16(CCS811_DEV_HANDLE, 0x24, &version);
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d", status, version);
i2c_write_register(CCS811_DEV_HANDLE, 0xF4, NULL, 0); //start
vTaskDelay(10 / portTICK_PERIOD_MS);
i2c_write_register_8(CCS811_DEV_HANDLE, 0x10, 0x0001); // MODE 1 interrupts vypnuté
i2c_read_register_8(CCS811_DEV_HANDLE, 0x00, &status);
i2c_read_register_16(CCS811_DEV_HANDLE, 0x24, &version);
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d", status, version);
}
esp_err_t ccs811_get_data(uint16_t * eCO2, uint16_t * tvoc)
ccs811_getStatus();
i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_APP_START, NULL, 0); // start
vTaskDelay(10 / portTICK_PERIOD_MS);
i2c_write_register_8(CCS811_DEV_HANDLE, CCS811_REG_MEAS_MODE, 0x40); // MODE 1 interrupts vypnuté
ccs811_getStatus();
}
esp_err_t ccs811_get_data(uint16_t *eCO2, uint16_t *tvoc, uint8_t *current, uint16_t *rawData)
{
uint8_t ccsResult[8];
esp_err_t ret = i2c_read_register(CCS811_DEV_HANDLE, 0x05, ccsResult, 8);
uint8_t algResultData[8];
esp_err_t ret = i2c_read_register(CCS811_DEV_HANDLE, CCS811_REG_ALG_RESULT_DATA, algResultData, 8);
if (ret == ESP_OK)
{
*eCO2 = (((uint16_t)(ccsResult[0] & 0xFF)) << 8) | (ccsResult[1] & 0xFF);
*tvoc = (((uint16_t)(ccsResult[2] & 0xFF)) << 8) | (ccsResult[3] & 0xFF);
ESP_LOGI(TAG_CCS, "CCS Status: %d, Error %d", ccsResult[4], ccsResult[5]);
*eCO2 = ((uint16_t)algResultData[0] << 8) | algResultData[1];
*tvoc = ((uint16_t)algResultData[2] << 8) | algResultData[3];
*current = algResultData[6] >> 2;
*rawData = ((uint16_t)(algResultData[6] & 0x03) << 8) | algResultData[7];
ESP_LOGI(TAG_CCS, "CCS Status: %d, Error: %d", algResultData[4], algResultData[5]);
return ESP_OK;
}
return ret;
}
}
esp_err_t ccs811_set_env_data(float temperature, float humidity)
{
uint8_t envData[4];
// Convert humidity: %RH × 512 (rounding)
uint16_t hum_conv = (uint16_t)(humidity * 512.0f + 0.5f);
envData[0] = (hum_conv >> 8) & 0xFF;
envData[1] = hum_conv & 0xFF;
// Convert temperature: (°C + 25) × 512
uint16_t temp_conv = (uint16_t)((temperature + 25.0f) * 512.0f + 0.5f);
envData[2] = (temp_conv >> 8) & 0xFF;
envData[3] = temp_conv & 0xFF;
return i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_ENV_DATA, envData, 4);
}

View File

@@ -5,11 +5,39 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define TAG_CCS "CCS811"
// CCS811 Registers
#define CCS811_REG_STATUS 0x00
#define CCS811_REG_MEAS_MODE 0x01
#define CCS811_REG_ALG_RESULT_DATA 0x02
#define CCS811_REG_RAW_DATA 0x03
#define CCS811_REG_ENV_DATA 0x05
#define CCS811_REG_THRESHOLDS 0x10
#define CCS811_REG_BASELINE 0x11
#define CCS811_REG_HW_ID 0x20
#define CCS811_REG_HW_VERSION 0x21
#define CCS811_REG_FW_BOOT_VERSION 0x23
#define CCS811_REG_FW_APP_VERSION 0x24
#define CCS811_REG_INTERNAL_STATE 0xA0
#define CCS811_REG_ERROR_ID 0xE0
#define CCS811_REG_APP_ERASE 0xF1
#define CCS811_REG_APP_DATA 0xF2
#define CCS811_REG_APP_VERIFY 0xF3
#define CCS811_REG_APP_START 0xF4
#define CCS811_REG_SW_RESET 0xFF
// Measurement Modes
#define CCS811_MODE_IDLE 0x00
#define CCS811_MODE_CONSTANT_1S 0x10
#define CCS811_MODE_CONSTANT_10S 0x20
#define CCS811_MODE_CONSTANT_60S 0x30
#define CCS811_MODE_WAKEUP 0x40
extern i2c_device_config_t CCS811_DEV_CFG;
extern i2c_master_dev_handle_t CCS811_DEV_HANDLE;
void ccs811_init();
esp_err_t ccs811_get_data(uint16_t * eCO2, uint16_t * tvoc);
esp_err_t ccs811_get_data(uint16_t *eCO2, uint16_t *tvoc, uint8_t *current, uint16_t *rawData);
esp_err_t ccs811_set_env_data(float temperature, float humidity);
#endif

244
main/hw/gps.c Normal file
View File

@@ -0,0 +1,244 @@
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "string.h"
#include "gps.h"
#define TAG "GPS"
#define BUF_SIZE 1024
#define GPS_LINE_MAX_LEN 128
gps_binary_struct_t gpsDataOut;
static QueueHandle_t uart_queue;
predicted_binary_position_struct_t predictedPosition;
// Initializes UART for GPS
void gps_init()
{
memset(&gpsDataOut, 0, sizeof(gpsDataOut));
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 122,
};
ESP_ERROR_CHECK(uart_param_config(GPS_UART_NUM, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(GPS_UART_NUM, GPS_TXD, GPS_RXD, GPS_RTS, GPS_CTS));
const int uart_buffer_size = (1024 * 2);
ESP_ERROR_CHECK(uart_driver_install(GPS_UART_NUM, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
}
void gps_task(void *arg)
{
uint8_t byte;
char line[GPS_LINE_MAX_LEN];
size_t line_pos = 0;
gps_init();
while (1) {
int len = uart_read_bytes(GPS_UART_NUM, &byte, 1, pdMS_TO_TICKS(1000));
if (len > 0) {
if (byte == '\n') {
line[line_pos] = '\0';
if (line[0] == '$') {
ESP_LOGV(TAG, "Received NMEA: %s", line);
if (strstr(line, "$GPGGA") == line) {
parse_gpgga(line);
parse_gpgga_to_struct(line, &gpsDataOut);
} else if (strstr(line, "$GPRMC") == line) {
parse_gprmc(line);
parse_gprmc_to_struct(line, &gpsDataOut);
}
}
line_pos = 0;
} else if (byte != '\r' && line_pos < (GPS_LINE_MAX_LEN - 1)) {
line[line_pos++] = byte;
} else if (line_pos >= GPS_LINE_MAX_LEN - 1) {
ESP_LOGW(TAG, "Line too long, discarded");
line_pos = 0;
}
}
}
}
void parse_gpgga(const char *nmea)
{
char *fields[15];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
temp[GPS_LINE_MAX_LEN - 1] = '\0';
int i = 0;
char *token = strtok(temp, ",");
while (token != NULL && i < 15) {
fields[i++] = token;
token = strtok(NULL, ",");
}
if (i < 10) return; // Not enough fields
// Time (hhmmss.sss)
const char *utc_time = fields[1];
// Latitude (ddmm.mmmm)
const char *lat = fields[2];
const char *lat_dir = fields[3];
// Longitude (dddmm.mmmm)
const char *lon = fields[4];
const char *lon_dir = fields[5];
// Fix quality (0 = invalid, 1 = GPS fix, 2 = DGPS fix)
const char *fix_quality = fields[6];
// Number of satellites
const char *num_satellites = fields[7];
// Altitude
const char *altitude = fields[9];
ESP_LOGI(TAG, "[GPGGA] Time: %s, Lat: %s %s, Lon: %s %s, Fix: %s, Sats: %s, Alt: %sm",
utc_time, lat, lat_dir, lon, lon_dir, fix_quality, num_satellites, altitude);
}
void parse_gprmc(const char *nmea)
{
char *fields[13];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
temp[GPS_LINE_MAX_LEN - 1] = '\0';
int i = 0;
char *token = strtok(temp, ",");
while (token != NULL && i < 13) {
fields[i++] = token;
token = strtok(NULL, ",");
}
if (i < 12) return;
const char *utc_time = fields[1];
const char *status = fields[2]; // A = active, V = void
const char *lat = fields[3];
const char *lat_dir = fields[4];
const char *lon = fields[5];
const char *lon_dir = fields[6];
const char *speed_knots = fields[7];
const char *date = fields[9];
ESP_LOGI(TAG, "[GPRMC] Date: %s, Time: %s, Lat: %s %s, Lon: %s %s, Speed: %s knots, Status: %s",
date, utc_time, lat, lat_dir, lon, lon_dir, speed_knots, status);
}
// Function to convert time string (hhmmss.sss) to seconds since start of day
static uint32_t time_to_seconds_struct(const char *time_str) {
if (time_str == NULL || strlen(time_str) < 6) return 0;
uint32_t hours = (time_str[0] - '0') * 10 + (time_str[1] - '0');
uint32_t minutes = (time_str[2] - '0') * 10 + (time_str[3] - '0');
uint32_t seconds = (time_str[4] - '0') * 10 + (time_str[5] - '0');
return hours * 3600 + minutes * 60 + seconds;
}
// Function to convert DMS (degrees minutes.decimalminutes) to centi-degrees
static int32_t dms_to_centi_degrees_struct(const char *dms_str, const char *direction) {
if (dms_str == NULL || direction == NULL || strlen(dms_str) < 7) return 0;
char degrees_str[4] = {0};
char minutes_decimal_str[10] = {0};
strncpy(degrees_str, dms_str, 2);
strncpy(minutes_decimal_str, dms_str + 2, strlen(dms_str) - 2);
double degrees = atof(degrees_str);
double minutes = atof(minutes_decimal_str);
double decimal_degrees = degrees + (minutes / 60.0);
if (direction[0] == 'S' || direction[0] == 'W') {
decimal_degrees *= -1.0;
}
return (int32_t)(decimal_degrees * 10000);
}
// Function to convert altitude string to centi-meters
static int16_t altitude_to_centi_meters_struct(const char *alt_str) {
if (alt_str == NULL) return 0;
return (int16_t)(atof(alt_str) * 100);
}
// Function to convert speed from knots to centi-knots
static uint16_t speed_to_centi_knots_struct(const char *speed_str) {
if (speed_str == NULL) return 0;
return (uint16_t)(atof(speed_str) * 100);
}
// Function to convert date string (ddmmyy) to yymmdd integer
static uint16_t date_to_yyddmm_struct(const char *date_str) {
if (date_str == NULL || strlen(date_str) != 6) return 0;
uint16_t day = (date_str[0] - '0') * 10 + (date_str[1] - '0');
uint16_t month = (date_str[2] - '0') * 10 + (date_str[3] - '0');
uint16_t year_short = (date_str[4] - '0') * 10 + (date_str[5] - '0');
// Assuming year is in the 21st century for simplicity
return (2000 + year_short) * 10000 + month * 100 + day;
}
// Function to parse GPGGA NMEA string and return the struct
void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data)
{
char *fields[15];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
temp[GPS_LINE_MAX_LEN - 1] = '\0';
int i = 0;
char *token = strtok(temp, ",");
while (token != NULL && i < 15) {
fields[i++] = token;
token = strtok(NULL, ",");
}
if (i >= 10) {
data->time_seconds = time_to_seconds_struct(fields[1]);
data->latitude_centi_degrees = dms_to_centi_degrees_struct(fields[2], fields[3]);
data->longitude_centi_degrees = dms_to_centi_degrees_struct(fields[4], fields[5]);
data->fix_quality = atoi(fields[6]);
data->num_satellites = atoi(fields[7]);
data->altitude_centi_meters = altitude_to_centi_meters_struct(fields[9]);
} else {
ESP_LOGW(TAG, "GPGGA: Not enough fields to parse struct");
}
}
// Function to parse GPRMC NMEA string and return the struct
void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data)
{
char *fields[13];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
temp[GPS_LINE_MAX_LEN - 1] = '\0';
int i = 0;
char *token = strtok(temp, ",");
while (token != NULL && i < 13) {
fields[i++] = token;
token = strtok(NULL, ",");
}
if (i >= 12) {
data->time_seconds = time_to_seconds_struct(fields[1]);
data->latitude_centi_degrees = dms_to_centi_degrees_struct(fields[3], fields[4]);
data->longitude_centi_degrees = dms_to_centi_degrees_struct(fields[5], fields[6]);
data->date_yyddmm = date_to_yyddmm_struct(fields[9]);
data->speed_centi_knots = speed_to_centi_knots_struct(fields[7]);
// Fix quality and num_satellites are typically in GPGGA, so they might be 0 here.
} else {
ESP_LOGW(TAG, "GPRMC: Not enough fields to parse struct");
}
}

39
main/hw/gps.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef GPS_COMPONENT
#define GPS_COMPONENT
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include "buscfg.h"
// Structure to hold parsed GPS data in a compact binary format
typedef struct {
uint32_t time_seconds; // Seconds since start of day
int32_t latitude_centi_degrees; // Latitude * 10,000
int32_t longitude_centi_degrees; // Longitude * 10,000
uint8_t fix_quality;
uint8_t num_satellites;
int16_t altitude_centi_meters; // Altitude * 100
uint16_t date_yyddmm; // YYDDMM (from GPRMC)
uint16_t speed_centi_knots; // Speed * 100 (from GPRMC)
} gps_binary_struct_t;
typedef struct {
int32_t latitude_centi_degrees; // Latitude * 10,000
int32_t longitude_centi_degrees; // Longitude * 10,000
int16_t altitude_centi_meters; // Altitude * 100
} predicted_binary_position_struct_t;
extern gps_binary_struct_t gpsDataOut;
extern predicted_binary_position_struct_t predictedPosition;
void gps_task(void *arg);
void parse_gpgga(const char *nmea);
void parse_gprmc(const char *nmea);
void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data);
void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data);
#endif

View File

@@ -3,50 +3,84 @@
i2c_master_bus_config_t i2c0_bus_cfg = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_NUM_0,
.scl_io_num = GPIO_NUM_9,
.sda_io_num = GPIO_NUM_8,
.scl_io_num = HWI2C_SCL,
.sda_io_num = HWI2C_SDA,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t i2c0_bus_hdl;
esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
{
const uint16_t probe_timeout_ms = 50; // timeout in milliseconds
uint8_t address;
// esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
// {
// const uint16_t probe_timeout_ms = 20; // timeout in milliseconds
// uint8_t address;
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
// printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
for (int i = 0; i < 128; i += 16)
{
printf("%02x: ", i);
// for (int i = 0; i < 128; i += 16)
// {
// printf("%02x: ", i);
for (int j = 0; j < 16; j++)
{
fflush(stdout);
// for (int j = 0; j < 16; j++)
// {
// fflush(stdout);
address = i + j;
// address = i + j;
esp_err_t ret = i2c_master_probe(handle, address, probe_timeout_ms);
// esp_err_t ret = i2c_master_probe(handle, address, probe_timeout_ms);
if (ret == ESP_OK)
{
printf("%02x ", address);
}
else if (ret == ESP_ERR_TIMEOUT)
{
printf("UU ");
}
else
{
printf("-- ");
}
}
printf("\r\n");
}
// if (ret == ESP_OK)
// {
// printf("%02x ", address);
// }
// else if (ret == ESP_ERR_TIMEOUT)
// {
// printf("UU ");
// }
// else
// {
// printf("-- ");
// }
// }
// printf("\r\n");
// }
return ESP_OK;
}
// return ESP_OK;
// }
/**
* i2c master initialization
*/
esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
{
uint8_t address;
bool found_any = false;
printf("Scanning I2C bus...\n");
for (int i = 0; i < 128; i++)
{
fflush(stdout);
address = i;
esp_err_t ret = i2c_master_probe(handle, address, 20);
if (ret == ESP_OK)
{
printf("Found device at 0x%02X\n", address);
found_any = true;
}
}
if (!found_any)
{
printf("No I2C devices found.\n");
}
return ESP_OK;
}
/**
* @brief Writes data to a specific register of an I2C device.

View File

@@ -3,6 +3,7 @@
#define I2C_TIMEOUT_MS_VALUE 20
#include <string.h>
#include "esp_log.h"
#include "buscfg.h"
#define TAG_I2C "cani2c"

View File

@@ -16,7 +16,8 @@ void ina260_reset() {
void ina260_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &INA260_DEV_CFG, &INA260_DEV_HANDLE));
i2c_write_register_16(INA260_DEV_HANDLE, INA260_CONFIG_REGISTER, 0x0FFF); // set ina max averaging and max time
i2c_write_register_16(INA260_DEV_HANDLE, INA260_CONFIG_REGISTER,
CONFIG_AVG_1024 | CONFIG_VBUSCT_8_244MS | CONFIG_ISHCT_8_244MS | CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS); // set ina max averaging and max time
}

View File

@@ -16,60 +16,57 @@ extern i2c_master_dev_handle_t INA260_DEV_HANDLE;
#define INA260_DIE_ID_REGISTER (0xFF)
// Bit masks
#define CONFIG_RST_BIT (1 << 15)
#define CONFIG_AVG_MASK (0x7 << 9)
#define CONFIG_VBUSCT_MASK (0x7 << 6)
#define CONFIG_ISHCT_MASK (0x7 << 3)
#define CONFIG_MODE_MASK (0x7 << 0)
#define CONFIG_RST_BIT (1 << 15)
#define CONFIG_AVG_MASK (0x7 << 9)
#define CONFIG_VBUSCT_MASK (0x7 << 6)
#define CONFIG_ISHCT_MASK (0x7 << 3)
#define CONFIG_MODE_MASK (0x7 << 0)
// Read-only bits
#define CONFIG_RESERVED_BITS (0x7 << 12) // Bits 1412 = 110b
#define CONFIG_RESERVED_BITS (0x7 << 12) // Bits 1412 = 110b
// Averaging modes (AVG)
#define CONFIG_AVG_1 (0x0 << 9)
#define CONFIG_AVG_4 (0x1 << 9)
#define CONFIG_AVG_16 (0x2 << 9)
#define CONFIG_AVG_64 (0x3 << 9)
#define CONFIG_AVG_128 (0x4 << 9)
#define CONFIG_AVG_256 (0x5 << 9)
#define CONFIG_AVG_512 (0x6 << 9)
#define CONFIG_AVG_1024 (0x7 << 9)
#define CONFIG_AVG_1 (0x0 << 9)
#define CONFIG_AVG_4 (0x1 << 9)
#define CONFIG_AVG_16 (0x2 << 9)
#define CONFIG_AVG_64 (0x3 << 9)
#define CONFIG_AVG_128 (0x4 << 9)
#define CONFIG_AVG_256 (0x5 << 9)
#define CONFIG_AVG_512 (0x6 << 9)
#define CONFIG_AVG_1024 (0x7 << 9)
// Bus voltage conversion time (VBUSCT)
#define CONFIG_VBUSCT_140US (0x0 << 6)
#define CONFIG_VBUSCT_204US (0x1 << 6)
#define CONFIG_VBUSCT_332US (0x2 << 6)
#define CONFIG_VBUSCT_588US (0x3 << 6)
#define CONFIG_VBUSCT_1_1MS (0x4 << 6)
#define CONFIG_VBUSCT_2_116MS (0x5 << 6)
#define CONFIG_VBUSCT_4_156MS (0x6 << 6)
#define CONFIG_VBUSCT_8_244MS (0x7 << 6)
#define CONFIG_VBUSCT_140US (0x0 << 6)
#define CONFIG_VBUSCT_204US (0x1 << 6)
#define CONFIG_VBUSCT_332US (0x2 << 6)
#define CONFIG_VBUSCT_588US (0x3 << 6)
#define CONFIG_VBUSCT_1_1MS (0x4 << 6)
#define CONFIG_VBUSCT_2_116MS (0x5 << 6)
#define CONFIG_VBUSCT_4_156MS (0x6 << 6)
#define CONFIG_VBUSCT_8_244MS (0x7 << 6)
// Shunt current conversion time (ISHCT)
#define CONFIG_ISHCT_140US (0x0 << 3)
#define CONFIG_ISHCT_204US (0x1 << 3)
#define CONFIG_ISHCT_332US (0x2 << 3)
#define CONFIG_ISHCT_588US (0x3 << 3)
#define CONFIG_ISHCT_1_1MS (0x4 << 3)
#define CONFIG_ISHCT_2_116MS (0x5 << 3)
#define CONFIG_ISHCT_4_156MS (0x6 << 3)
#define CONFIG_ISHCT_8_244MS (0x7 << 3)
#define CONFIG_ISHCT_140US (0x0 << 3)
#define CONFIG_ISHCT_204US (0x1 << 3)
#define CONFIG_ISHCT_332US (0x2 << 3)
#define CONFIG_ISHCT_588US (0x3 << 3)
#define CONFIG_ISHCT_1_1MS (0x4 << 3)
#define CONFIG_ISHCT_2_116MS (0x5 << 3)
#define CONFIG_ISHCT_4_156MS (0x6 << 3)
#define CONFIG_ISHCT_8_244MS (0x7 << 3)
// Operating mode (MODE)
#define CONFIG_MODE_POWERDOWN (0x0 << 0)
#define CONFIG_MODE_CURRENT_TRIGGER (0x1 << 0)
#define CONFIG_MODE_VOLTAGE_TRIGGER (0x2 << 0)
#define CONFIG_MODE_CURRENT_VOLTAGE_TRIGGER (0x3 << 0)
#define CONFIG_MODE_POWERDOWN2 (0x4 << 0)
#define CONFIG_MODE_POWERDOWN (0x5 << 0)
#define CONFIG_MODE_POWERDOWN (0x6 << 0)
#define CONFIG_MODE_POWERDOWN (0x7 << 0)
#define CONFIG_MODE_POWERDOWN 0x00
#define CONFIG_MODE_CURRENT_TRIGGER 0x01
#define CONFIG_MODE_VOLTAGE_TRIGGER 0x02
#define CONFIG_MODE_CURRENT_VOLTAGE_TRIGGER 0x03
#define CONFIG_MODE_POWERDOWN2 0x04
#define CONFIG_MODE_CURRENT_CONTINOUS 0x05
#define CONFIG_MODE_VOLTAGE_CONTINOUS 0x06
#define CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS 0x07
void ina260_init();
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow);
void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow);
#endif

View File

@@ -1,4 +1,6 @@
#include "mcp23018.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// Local buffer for tracking GPIO state
i2c_device_config_t MCP23018_DEV_CFG = {
@@ -36,6 +38,7 @@ void mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t v
// Write updated buffer to MCP23018
i2c_write_register_8(dev_handle, MCP23018_GPIOB, gpiob_state);
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
void mcp23018_init()

118
main/hw/mcp3550.c Normal file
View File

@@ -0,0 +1,118 @@
#include "mcp3550.h"
#include "mcp23018.h"
#include "driver/gpio.h"
#include <esp_timer.h>
#define TAG_MICS "MICS_ADC"
#define MCP3550_SPS 3.75f
#define MCP3550_CONVERSION_MS ((int)(1000.0f / MCP3550_SPS)) // ~267ms
#define MCP3550_TIMEOUT_MS 400
#define ADC_COUNT 4
const uint8_t adc_cs_pins[ADC_COUNT] = {
MCP_CS_ADC_NH3, MCP_CS_ADC_CO, MCP_CS_ADC_NO2, MCP_CS_ADC_UVC
};
spi_device_handle_t mcp3550_handle;
void mcp3550_spi_init()
{
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 100000,
.mode = 0,
.spics_io_num = -1, // We handle CS manually
.queue_size = 1,
};
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &devcfg, &mcp3550_handle));
// Set MISO pin for input (needed for polling)
gpio_set_direction(MCP3550_MISO_GPIO, GPIO_MODE_INPUT);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_MICS_POWER, 1); // CS HIGH
}
int32_t mcp3550_read(uint8_t cs_pin)
{
uint8_t rx_buf[4] = {0}; // 25 bits fits in 4 bytes
int64_t start = esp_timer_get_time(); // in microseconds
while (true) {
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0); // CS LOW
spi_transaction_t trans = {
.length = 25,
.rx_buffer = rx_buf,
};
esp_err_t err = spi_device_transmit(mcp3550_handle, &trans);
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
if (err != ESP_OK) {
ESP_LOGE(TAG_MICS, "SPI transmit failed on CS pin %u", cs_pin);
return INT32_MIN;
}
bool dr = (rx_buf[0] & 0x80) != 0;
if (!dr) break;
if ((esp_timer_get_time() - start) > (MCP3550_TIMEOUT_MS * 1000)) {
ESP_LOGW(TAG_MICS, "Timeout waiting for DR=0 on CS pin %u", cs_pin);
return INT32_MIN;
}
vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
}
// Combine 22-bit result (drop DR + status bits)
uint32_t raw = ((rx_buf[0] & 0x3F) << 16) | (rx_buf[1] << 8) | rx_buf[2];
// Sign-extend 22-bit value
int32_t value = raw;
if (value & (1 << 21)) value |= 0xFFC00000;
return value;
}
float mcp3550_to_voltage(int32_t value, float vref)
{
return ((float)value / (1 << 21)) * vref;
}
mics_adc_data_t mcp3550_read_all(float vref)
{
mics_adc_data_t data;
int32_t raw[ADC_COUNT];
float volts[ADC_COUNT];
for (int i = 0; i < ADC_COUNT; i++) {
raw[i] = mcp3550_read(adc_cs_pins[i]);
vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
volts[i] = mcp3550_to_voltage(raw[i], vref);
}
data.raw_nh3 = raw[0]; data.volts_nh3 = volts[0];
data.raw_co = raw[1]; data.volts_co = volts[1];
data.raw_no2 = raw[2]; data.volts_no2 = volts[2];
data.raw_uvc = raw[3]; data.volts_uvc = volts[3];
return data;
}
void log_mics_adc_values(mics_adc_data_t *data)
{
ESP_LOGI(TAG_MICS,
"ADC Readings:\n"
" NH3 -> Raw: %8d, Voltage: %7.6f V\n"
" CO -> Raw: %8d, Voltage: %7.6f V\n"
" NO2 -> Raw: %8d, Voltage: %7.6f V\n"
" UVC -> Raw: %8d, Voltage: %7.6f V",
data->raw_nh3, data->volts_nh3,
data->raw_co, data->volts_co,
data->raw_no2, data->volts_no2,
data->raw_uvc, data->volts_uvc);
}

38
main/hw/mcp3550.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef MPC3550_COMPONENT
#define MPC3550_COMPONENT
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "buscfg.h"
#define CONFIG_FREERTOS_HZ 100
#define MCP3550_SPS 3.75f
#define MCP3550_CONVERSION_MS ((int)(1000.0f / MCP3550_SPS)) // ~267ms
extern spi_device_handle_t mcp3550_handle;
void mcp3550_spi_init();
int32_t mcp3550_read(uint8_t cs_pin);
float mcp3550_to_voltage(int32_t value, float vref);
typedef struct {
int32_t raw_nh3;
int32_t raw_co;
int32_t raw_no2;
int32_t raw_uvc;
float volts_nh3;
float volts_co;
float volts_no2;
float volts_uvc;
} mics_adc_data_t;
extern spi_device_handle_t mcp3550_handle;
void log_mics_adc_values(mics_adc_data_t *data);
mics_adc_data_t mcp3550_read_all(float vref);
#endif

View File

@@ -1,4 +1,5 @@
#include "mpu9250.h"
#include "esp_timer.h"
i2c_device_config_t MPU9250_DEV_CFG = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
@@ -6,9 +7,11 @@ i2c_device_config_t MPU9250_DEV_CFG = {
.scl_speed_hz = 100000,
};
#define MAG_SCALE (4912.0f / 32760.0f)
i2c_master_dev_handle_t MPU9250_DEV_HANDLE;
esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *accel, int16_t *gyro, int16_t *temp)
esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *accel, int16_t *gyro, int16_t *temp, int16_t *magnet)
{
uint8_t buffer[14]; // 6 (Accel) + 2 (Temp) + 6 (Gyro)
esp_err_t ret = i2c_read_register(dev_handle, 0x3B, buffer, 14);
@@ -16,18 +19,28 @@ esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *
return ret;
// Convert raw data (Big-Endian)
accel[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Accel X
accel[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Accel Y
accel[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Accel Z
*temp = (((uint16_t)(buffer[6] & 0xFF)) << 8) | (buffer[7] & 0xFF); // Temperature
gyro[0] = (((uint16_t)(buffer[8] & 0xFF)) << 8) | (buffer[9] & 0xFF);; // Gyro X
gyro[1] = (((uint16_t)(buffer[10] & 0xFF)) << 8) | (buffer[11] & 0xFF);; // Gyro Y
gyro[2] = (((uint16_t)(buffer[12] & 0xFF)) << 8) | (buffer[13] & 0xFF);; // Gyro Z
accel[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Accel X
accel[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Accel Y
accel[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Accel Z
*temp = (((uint16_t)(buffer[6] & 0xFF)) << 8) | (buffer[7] & 0xFF); // Temperature
gyro[0] = (((uint16_t)(buffer[8] & 0xFF)) << 8) | (buffer[9] & 0xFF);
; // Gyro X
gyro[1] = (((uint16_t)(buffer[10] & 0xFF)) << 8) | (buffer[11] & 0xFF);
; // Gyro Y
gyro[2] = (((uint16_t)(buffer[12] & 0xFF)) << 8) | (buffer[13] & 0xFF);
; // Gyro Z
ret = i2c_read_register(dev_handle, 0x03, buffer, 6);
if (ret != ESP_OK)
return ret;
magnet[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Magnet X
magnet[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Magnet Y
magnet[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Magnet Z
return ESP_OK;
}
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, float *accel_out, float *gyro_out, float *temp_out)
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, int16_t *magnet, float *accel_out, float *gyro_out, float *temp_out, float *magnet_out)
{
accel_out[0] = accel[0] / 16384.0; // Accel X in g
accel_out[1] = accel[1] / 16384.0; // Accel Y in g
@@ -37,10 +50,16 @@ void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, float *ac
gyro_out[1] = gyro[1] / 131.0; // Gyro Y in deg/s
gyro_out[2] = gyro[2] / 131.0; // Gyro Z in deg/s
magnet_out[0] = magnet[0] * MAG_SCALE; // Gyro X in deg/s
magnet_out[1] = magnet[1] * MAG_SCALE; // Gyro Y in deg/s
magnet_out[2] = magnet[2] * MAG_SCALE; // Gyro Z in deg/s
*temp_out = (temp / 333.87) + 21.0; // Temperature in °C
}
void mpu9250_init() {
void mpu9250_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &MPU9250_DEV_CFG, &MPU9250_DEV_HANDLE));
i2c_write_register_16(MPU9250_DEV_HANDLE, 0x6B, 0x0001); // zapni uz tu hovadinu
i2c_write_register_16(MPU9250_DEV_HANDLE, 0x0A, 0x0012); // zapni uz tu hovadinu
}

View File

@@ -8,8 +8,8 @@ extern i2c_device_config_t MPU9250_DEV_CFG;
extern i2c_master_dev_handle_t MPU9250_DEV_HANDLE;
esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *accel, int16_t *gyro, int16_t *temp);
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, float *accel_out, float *gyro_out, float *temp_out);
esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *accel, int16_t *gyro, int16_t *temp, int16_t *magnet);
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, int16_t *magnet, float *accel_out, float *gyro_out, float *temp_out, float *magnet_out);
void mpu9250_init();
#endif

65
components/ra01s/ra01s.c → main/hw/sx1262.c Executable file → Normal file
View File

@@ -11,16 +11,18 @@
#include <driver/gpio.h>
#include "esp_log.h"
#include "ra01s.h"
#include "sx1262.h"
#define TAG "RA01S"
#define TAG "SX1262"
// SPI Stuff
#if CONFIG_SPI2_HOST
#define HOST_ID SPI2_HOST
#elif CONFIG_SPI3_HOST
#define HOST_ID SPI3_HOST
#endif
#define CONFIG_MISO_GPIO GPIO_NUM_11
#define CONFIG_MOSI_GPIO GPIO_NUM_10
#define CONFIG_SCLK_GPIO GPIO_NUM_9
#define CONFIG_NSS_GPIO GPIO_NUM_8
#define CONFIG_RST_GPIO GPIO_NUM_12
#define CONFIG_BUSY_GPIO GPIO_NUM_13
static spi_device_handle_t SpiHandle;
@@ -32,8 +34,6 @@ static bool debugPrint;
static int SX126x_SPI_SELECT;
static int SX126x_RESET;
static int SX126x_BUSY;
static int SX126x_TXEN;
static int SX126x_RXEN;
// Arduino compatible macros
#define delayMicroseconds(us) esp_rom_delay_us(us)
@@ -61,14 +61,10 @@ void LoRaInit(void)
ESP_LOGI(TAG, "CONFIG_NSS_GPIO=%d", CONFIG_NSS_GPIO);
ESP_LOGI(TAG, "CONFIG_RST_GPIO=%d", CONFIG_RST_GPIO);
ESP_LOGI(TAG, "CONFIG_BUSY_GPIO=%d", CONFIG_BUSY_GPIO);
ESP_LOGI(TAG, "CONFIG_TXEN_GPIO=%d", CONFIG_TXEN_GPIO);
ESP_LOGI(TAG, "CONFIG_RXEN_GPIO=%d", CONFIG_RXEN_GPIO);
SX126x_SPI_SELECT = CONFIG_NSS_GPIO;
SX126x_RESET = CONFIG_RST_GPIO;
SX126x_BUSY = CONFIG_BUSY_GPIO;
SX126x_TXEN = CONFIG_TXEN_GPIO;
SX126x_RXEN = CONFIG_RXEN_GPIO;
txActive = false;
debugPrint = false;
@@ -83,16 +79,6 @@ void LoRaInit(void)
gpio_reset_pin(SX126x_BUSY);
gpio_set_direction(SX126x_BUSY, GPIO_MODE_INPUT);
if (SX126x_TXEN != -1) {
gpio_reset_pin(SX126x_TXEN);
gpio_set_direction(SX126x_TXEN, GPIO_MODE_OUTPUT);
}
if (SX126x_RXEN != -1) {
gpio_reset_pin(SX126x_RXEN);
gpio_set_direction(SX126x_RXEN, GPIO_MODE_OUTPUT);
}
spi_bus_config_t spi_bus_config = {
.sclk_io_num = CONFIG_SCLK_GPIO,
.mosi_io_num = CONFIG_MOSI_GPIO,
@@ -102,10 +88,6 @@ void LoRaInit(void)
};
esp_err_t ret;
ret = spi_bus_initialize( HOST_ID, &spi_bus_config, SPI_DMA_CH_AUTO );
ESP_LOGI(TAG, "spi_bus_initialize=%d",ret);
assert(ret==ESP_OK);
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 9000000,
.mode = 0,
@@ -705,7 +687,6 @@ void SetRx(uint32_t timeout)
ESP_LOGI(TAG, "----- SetRx timeout=%"PRIu32, timeout);
}
SetStandby(SX126X_STANDBY_RC);
SetRxEnable();
uint8_t buf[3];
buf[0] = (uint8_t)((timeout >> 16) & 0xFF);
buf[1] = (uint8_t)((timeout >> 8) & 0xFF);
@@ -723,25 +704,12 @@ void SetRx(uint32_t timeout)
}
void SetRxEnable(void)
{
if (debugPrint) {
ESP_LOGI(TAG, "SetRxEnable:SX126x_TXEN=%d SX126x_RXEN=%d", SX126x_TXEN, SX126x_RXEN);
}
if ((SX126x_TXEN != -1) && (SX126x_RXEN != -1)) {
gpio_set_level(SX126x_RXEN, HIGH);
gpio_set_level(SX126x_TXEN, LOW);
}
}
void SetTx(uint32_t timeoutInMs)
{
if (debugPrint) {
ESP_LOGI(TAG, "----- SetTx timeoutInMs=%"PRIu32, timeoutInMs);
}
SetStandby(SX126X_STANDBY_RC);
SetTxEnable();
uint8_t buf[3];
uint32_t tout = timeoutInMs;
if (timeoutInMs != 0) {
@@ -766,19 +734,6 @@ void SetTx(uint32_t timeoutInMs)
}
}
void SetTxEnable(void)
{
if (debugPrint) {
ESP_LOGI(TAG, "SetTxEnable:SX126x_TXEN=%d SX126x_RXEN=%d", SX126x_TXEN, SX126x_RXEN);
}
if ((SX126x_TXEN != -1) && (SX126x_RXEN != -1)){
gpio_set_level(SX126x_RXEN, LOW);
gpio_set_level(SX126x_TXEN, HIGH);
}
}
int GetPacketLost()
{
return txLost;
@@ -1018,4 +973,4 @@ void ReadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes) {
// wait for BUSY to go low
vTaskDelay(1);
WaitForIdle(BUSY_WAIT, "end ReadCommand", false);
}
}

2
components/ra01s/ra01s.h → main/hw/sx1262.h Executable file → Normal file
View File

@@ -412,8 +412,6 @@ void SetCad();
uint8_t GetStatus(void);
uint16_t GetIrqStatus(void);
void ClearIrqStatus(uint16_t irq);
void SetTxEnable(void);
void SetRxEnable(void);
void SetRx(uint32_t timeout);
void SetTx(uint32_t timeoutInMs);
int GetPacketLost();

View File

@@ -15,6 +15,7 @@
#include "esp_mac.h"
#include <string.h>
#include "components/radio.h"
#include "components/sensors.h"
#include "components/util.h"
#include "hw/bme680b.h"
@@ -23,31 +24,72 @@
#include "hw/ina260.h"
#include "hw/mcp23018.h"
#include "hw/mpu9250.h"
#include "hw/buscfg.h"
#include "hw/gps.h"
#define TAG "cantest"
#define CONFIG_FREERTOS_HZ 100
void app_main(void)
{
/* instantiate i2c master bus 0 */
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c0_bus_cfg, &i2c0_bus_hdl));
spi_bus_config_t MCPBusCfg = {
.mosi_io_num = -1,
.miso_io_num = MCP3550_MISO_GPIO,
.sclk_io_num = MCP3550_SCK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4,
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &MCPBusCfg, SPI_DMA_DISABLED));
spi_bus_config_t HighSpeedBusCfg = {
// CONNECTED to LoRa and SD card
.mosi_io_num = HSPI_MOSI_GPIO,
.miso_io_num = HSPI_MISO_GPIO,
.sclk_io_num = HSPI_SCK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 64, // probably change
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &HighSpeedBusCfg, SPI_DMA_CH_AUTO));
/* scan i2c devices on i2c master bus 0 and print results */
ESP_ERROR_CHECK(i2c_master_bus_detect_devices(i2c0_bus_hdl));
mcp23018_init();
void servoControllerInit();
/* create task pinned to the app core */
xTaskCreatePinnedToCore(
xTaskCreate(
i2c_sensors_task,
"I2CTaskBME",
8192,
NULL,
(tskIDLE_PRIORITY + 2),
NULL);
xTaskCreate(
lora_comms_task,
"LoraCommsTask",
8192,
NULL,
APP_CPU_NUM);
(tskIDLE_PRIORITY + 2),
NULL);
xTaskCreate(
gps_task,
"gps_task",
8192,
NULL,
(tskIDLE_PRIORITY + 2),
NULL);
while (1)
{

View File

@@ -1091,6 +1091,8 @@ esp_err_t bme680_get_data(bme680_handle_t handle, bme680_data_t *const data) {
data->heater_stable = adc_data.heater_stable;
data->gas_valid = adc_data.gas_valid;
data->raw_data = adc_data;
/* compute scores */
bme680_compute_iaq(data);

View File

@@ -308,6 +308,22 @@ typedef struct bme680_cal_factors_s {
int8_t range_switching_error;
} bme680_cal_factors_t;
/**
* @brief BME680 ADC data structure definition.
*/
typedef struct bme680_adc_data_s {
uint32_t temperature;
uint16_t humidity;
uint32_t pressure;
uint16_t gas;
bool gas_valid;
uint8_t gas_range;
uint8_t gas_index;
bool heater_stable;
} bme680_adc_data_t;
/**
* @brief BME680 data structure definition.
*/
@@ -325,22 +341,9 @@ typedef struct bme680_data_s {
float temperature_score;
float humidity_score;
float gas_score;
bme680_adc_data_t raw_data;
} bme680_data_t;
/**
* @brief BME680 ADC data structure definition.
*/
typedef struct bme680_adc_data_s {
uint32_t temperature;
uint16_t humidity;
uint32_t pressure;
uint16_t gas;
bool gas_valid;
uint8_t gas_range;
uint8_t gas_index;
bool heater_stable;
} bme680_adc_data_t;
/**
* @brief BME680 configuration structure definition.
*/