Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions adc_esp/adc_esp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "adc_esp.h"
#include <string.h>

// Calibration characteristics
static esp_adc_cal_characteristics_t adc_chars;

adc_bits_width_t adc2_width = ADC_WIDTH_BIT_12; // Since ADC2 can't be configured directly, we set the width here

esp_err_t esp32_adc_init(ESP32_ADC_Config* config) {
esp_err_t ret = ESP_OK;

// Configure ADC unit
if (config->unit == ADC_UNIT_1) {
ret = adc1_config_width(config->width);
if (ret != ESP_OK) return ret;
}
else if (config->unit == ADC_UNIT_2) {
adc2_width = config->width;
} else {
return ESP_ERR_INVALID_ARG;
}

// Characterize ADC for calibration
esp_adc_cal_characterize(config->unit, config->attenuation,
config->width, config->vref, &adc_chars);

return ESP_OK;
}

esp_err_t esp32_adc_config_channel(adc_unit_t unit, adc_channel_t channel, adc_atten_t attenuation) {
if (unit == ADC_UNIT_1) {
return adc1_config_channel_atten((adc1_channel_t)channel, attenuation);
} else if (unit == ADC_UNIT_2) {
return adc2_config_channel_atten((adc2_channel_t)channel, attenuation);
}
return ESP_ERR_INVALID_ARG;
}

int esp32_adc_read_voltage(adc_unit_t unit, adc_channel_t channel, ESP32_ADC_Config* config) {
int raw_value = esp32_adc_read_raw(unit, channel);
if (raw_value < 0) return -1;

// Convert raw value to voltage
uint32_t voltage = esp_adc_cal_raw_to_voltage(raw_value, &adc_chars);
return voltage;
}

int esp32_adc_read_raw(adc_unit_t unit, adc_channel_t channel) {
int raw_value;

if (unit == ADC_UNIT_1) {
// Configure the channel attenuation if not already done
// This should ideally be done during initialization for each channel
adc1_channel_t adc1_channel = (adc1_channel_t)channel;
raw_value = adc1_get_raw(adc1_channel);
} else if (unit == ADC_UNIT_2) {
// ADC2 can't be used when Wi-Fi is active
esp_err_t ret = adc2_get_raw((adc2_channel_t)channel, adc2_width, &raw_value);
if (ret != ESP_OK) {
return -1;
}
} else {
return -1; // Invalid ADC unit
}

return raw_value;
}

float esp32_adc_normalize(int raw_value, ESP32_ADC_Config* config) {
if (raw_value < 0) return -1.0f;

int max_value;
switch (config->width) {
case ADC_WIDTH_BIT_9: max_value = 511; break;
case ADC_WIDTH_BIT_10: max_value = 1023; break;
case ADC_WIDTH_BIT_11: max_value = 2047; break;
case ADC_WIDTH_BIT_12: max_value = 4095; break;
default: return -1.0f;
}

return (float)raw_value / max_value;
}

esp_err_t esp32_adc_gpio_to_channel(int gpio_pin, adc_unit_t* unit, adc_channel_t* channel) {
// Map GPIO pin to ADC channel
// ADC1 channels
if (gpio_pin == 36) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_0; return ESP_OK; }
if (gpio_pin == 37) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_1; return ESP_OK; }
if (gpio_pin == 38) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_2; return ESP_OK; }
if (gpio_pin == 39) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_3; return ESP_OK; }
if (gpio_pin == 32) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_4; return ESP_OK; }
if (gpio_pin == 33) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_5; return ESP_OK; }
if (gpio_pin == 34) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_6; return ESP_OK; }
if (gpio_pin == 35) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_7; return ESP_OK; }

// ADC2 channels
if (gpio_pin == 4) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_0; return ESP_OK; }
if (gpio_pin == 0) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_1; return ESP_OK; }
if (gpio_pin == 2) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_2; return ESP_OK; }
if (gpio_pin == 15) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_3; return ESP_OK; }
if (gpio_pin == 13) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_4; return ESP_OK; }
if (gpio_pin == 12) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_5; return ESP_OK; }
if (gpio_pin == 14) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_6; return ESP_OK; }
if (gpio_pin == 27) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_7; return ESP_OK; }
if (gpio_pin == 25) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_8; return ESP_OK; }
if (gpio_pin == 26) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_9; return ESP_OK; }

return ESP_ERR_NOT_FOUND;
}
65 changes: 65 additions & 0 deletions adc_esp/adc_esp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#ifndef ESP32_ADC_H
#define ESP32_ADC_H

#include <driver/adc.h>
#include <esp_adc_cal.h>

// ADC configuration struct
typedef struct {
adc_unit_t unit; // ADC unit (ADC1 or ADC2)
adc_bits_width_t width; // ADC bit width (9-12 bits)
adc_atten_t attenuation; // ADC attenuation
uint32_t vref; // Reference voltage in mV (typically 1100mV)
} ESP32_ADC_Config;

/**
* Initialize ADC with the given configuration
* @param config ADC configuration
* @return ESP_OK on success, error code otherwise
*/
esp_err_t esp32_adc_init(ESP32_ADC_Config* config);

/**
* Configure a specific ADC channel with the given attenuation
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @param attenuation Attenuation level
* @return ESP_OK on success, error code otherwise
*/
esp_err_t esp32_adc_config_channel(adc_unit_t unit, adc_channel_t channel, adc_atten_t attenuation);

/**
* Read ADC value from the specified channel
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @param config ADC configuration used for calibration
* @return Voltage in millivolts, or -1 on error
*/
int esp32_adc_read_voltage(adc_unit_t unit, adc_channel_t channel, ESP32_ADC_Config* config);

/**
* Read raw ADC value from the specified channel
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @return Raw ADC value (0-4095 for 12-bit), or -1 on error
*/
int esp32_adc_read_raw(adc_unit_t unit, adc_channel_t channel);

/**
* Convert raw ADC value to normalized float (0.0-1.0)
* @param raw_value Raw ADC value
* @param config ADC configuration for bit width
* @return Normalized value between 0.0 and 1.0
*/
float esp32_adc_normalize(int raw_value, ESP32_ADC_Config* config);

/**
* Get ADC channel for a GPIO pin
* @param gpio_pin GPIO pin number
* @param unit Pointer to store the ADC unit
* @param channel Pointer to store the ADC channel
* @return ESP_OK if mapping successful, error code otherwise
*/
esp_err_t esp32_adc_gpio_to_channel(int gpio_pin, adc_unit_t* unit, adc_channel_t* channel);

#endif // ESP32_ADC_H
39 changes: 39 additions & 0 deletions esp32canmanager/esp32canmanager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "esp32canmanager.h"

ESP32CANManager::ESP32CANManager(int8_t tx, int8_t rx, uint16_t tx_queue, uint16_t rx_queue, uint16_t frequency) {
if (ESP32Can.begin(ESP32Can.convertSpeed(frequency), tx, rx, tx_queue, rx_queue)) {
printf("can bus started\n");
} else {
printf("can bus initialization FAIL\n");
}
}

bool ESP32CANManager::sendMessage(uint16_t id, void* data, uint8_t length, uint32_t timeout) {
// create the message
CanFrame obdFrame = { 0 };
obdFrame.identifier = id;
obdFrame.extd = 0; // use non extended 11 bit ID
obdFrame.data_length_code = length;
memcpy(obdFrame.data, data, length);
// printf("obdFrame: %x\n", obdFrame.data[0]);

uint32_t start = millis();
bool send_success = false;
while (!(send_success = ESP32Can.writeFrame(obdFrame)) && millis() - start < timeout){
this->runQueue(1);
}

return send_success;
}

void ESP32CANManager::runQueue(uint16_t duration) {
CanFrame rxFrame;

uint32_t start = millis();

while (millis() - start < duration) {
if(ESP32Can.readFrame(rxFrame, 1)) {
this->readHandler(rxFrame);
}
}
}
45 changes: 45 additions & 0 deletions esp32canmanager/esp32canmanager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef __ESP32_CAN_H__
#define __ESP32_CAN_H__

#include <Arduino.h>
#include <ESP32-TWAI-CAN.hpp>

#define DEFAULT_ESP32_CAN_FREQ 250

class ESP32CANManager {
public:
/* frequency: in kHz
* tx: pin number
* rx: pin number
* tx_queue: number of messages in TX queue
* rx_queue: number of messages in RX queue
*/
ESP32CANManager(int8_t tx, int8_t rx, uint16_t tx_queue, uint16_t rx_queue, uint16_t frequency = DEFAULT_ESP32_CAN_FREQ);

/* Handles data from received messages
* Intended to be implemented by class extension per board
* Called in runQueue()
*/
virtual void readHandler(CanFrame msg) = 0;

/* Send a message over CAN
*
* id: CAN ID to use to identify the signal
* data: Payload array
* length: Size of data in bytes
* timeout: in milliseconds
*
* @return true if message sent successfully, false otherwise
*/
bool sendMessage(uint16_t id, void* data, uint8_t length, uint32_t timeout = 1);


/* Processes CAN (read) messages stored in messageQueue for a set duration.
* THIS IS THE FUNCTION TO CALL FOR PROCESSING CAN READ MESSAGES
*
* duration: time in milliseconds
*/
void runQueue(uint16_t duration);
};

#endif