parent
6c3de019d4
commit
c3ce48f06b
@ -0,0 +1,116 @@
|
||||
// Module to record roller and wheel speeds from MCPWM capture interrupts. Not yet sure if a task is required at all.
|
||||
|
||||
#include "bin_level.h"
|
||||
#include "io.h"
|
||||
|
||||
#include "driver/mcpwm.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
// Precision timer value of the start of our pulse.
|
||||
static uint32_t bin_level_pulse_timer_start[3] = {0, 0, 0};
|
||||
|
||||
// Store state of each pulse channel
|
||||
static bool bin_level_pulse_started[3] = {false, false, false};
|
||||
|
||||
// Also store timestamp as microseconds since start to avoid overflow of the precision timer when checking for stop
|
||||
static int64_t bin_level_last_timestamp[3] = {0, 0, 0};
|
||||
|
||||
// Use a single item queue for each measurement we need to distribute.
|
||||
static xQueueHandle bin_level_measurement_queue[3];
|
||||
|
||||
// struct to hold move our pulse measurements from our ISR via the queue
|
||||
typedef struct {
|
||||
uint32_t length; // pulse length in APB clock ticks
|
||||
int64_t timestamp; // time measurement occurred in microseconds since boot
|
||||
} bin_level_measurement_t;
|
||||
|
||||
// Gets called by the MCPWM capture module. Tells us which capture unit it was, which edge, and when it happened
|
||||
// Our ultrasound depth sensor pulses are active low (so start on neg edge, finish on pos edge)
|
||||
static bool bin_level_pulse_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig,
|
||||
const cap_event_data_t *edata, void *arg) {
|
||||
|
||||
// Not strictly necessary to do the wakeup check here, as we shouldn't be blokcing anything. Doesn't hurt though.
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
|
||||
int b_id = 0;
|
||||
|
||||
if (cap_sig == MCPWM_SELECT_CAP0) {
|
||||
b_id = 0;
|
||||
} else if (cap_sig == MCPWM_SELECT_CAP1) {
|
||||
b_id = 1;
|
||||
} else if (cap_sig == MCPWM_SELECT_CAP2) {
|
||||
b_id = 2;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t time_now;
|
||||
time_now = esp_timer_get_time();
|
||||
|
||||
if (edata->cap_edge == MCPWM_NEG_EDGE) {
|
||||
// start our pulse measurement. Note that this will roll around every minute or so, so comparison logic needs to
|
||||
// handle that
|
||||
bin_level_pulse_timer_start[b_id] = edata->cap_value;
|
||||
bin_level_last_timestamp[b_id] = time_now;
|
||||
bin_level_pulse_started[b_id] = true;
|
||||
} else {
|
||||
// Only a valid end of pulse if we had detected a start, and it was less than MAX_PULSE_LENGTH_MS ago
|
||||
if (bin_level_pulse_started[b_id] and((bin_level_last_timestamp[b_id] - time_now) < pdMS_TO_TICKS(MAX_PULSE_LENGTH_MS))) {
|
||||
bin_level_measurement_t new_measurement;
|
||||
new_measurement.timestamp = time_now;
|
||||
new_measurement.length = edata->cap_value - bin_level_pulse_timer_start[b_id];
|
||||
xQueueOverwriteFromISR(bin_level_measurement_queue[b_id], &new_measurement, &high_task_wakeup);
|
||||
}
|
||||
// Reset pulse start detection
|
||||
bin_level_pulse_started[b_id] = false;
|
||||
}
|
||||
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
float get_bin_level(bin_id_t bin_id) {
|
||||
bin_level_measurement_t pulse_measurement;
|
||||
// Get the pulse period in APB clock ticks.
|
||||
xQueuePeek(bin_level_measurement_queue[bin_id], &pulse_measurement, 0);
|
||||
|
||||
// Return 0 if the pulse measurement is too old
|
||||
if ((pulse_measurement.length == 0) or
|
||||
((esp_timer_get_time() - pulse_measurement.timestamp) >= (RECENT_PULSE_TIMEOUT_MS*1000))) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//return 1000.0 * ((float)(pulse_measurement.length) / (float)rtc_clk_apb_freq_get());
|
||||
|
||||
// Convert pulse length to distance in meters
|
||||
return ((1000.0 * ((float)(pulse_measurement.length) / (float)rtc_clk_apb_freq_get())) - (float)(BIN_LEVEL_OFFSET_MS)) / (float)(BIN_LEVEL_MS_PER_METER);
|
||||
}
|
||||
|
||||
void bin_level_setup(void) {
|
||||
// Create our measurement queues
|
||||
bin_level_measurement_queue[0] = xQueueCreate(1, sizeof(bin_level_measurement_t));
|
||||
bin_level_measurement_queue[1] = xQueueCreate(1, sizeof(bin_level_measurement_t));
|
||||
bin_level_measurement_queue[2] = xQueueCreate(1, sizeof(bin_level_measurement_t));
|
||||
|
||||
// Prime queues
|
||||
bin_level_measurement_t blank_measurement = {0, 0};
|
||||
xQueueOverwrite(bin_level_measurement_queue[0], &blank_measurement);
|
||||
xQueueOverwrite(bin_level_measurement_queue[1], &blank_measurement);
|
||||
xQueueOverwrite(bin_level_measurement_queue[2], &blank_measurement);
|
||||
|
||||
// Attach GPIO to capture units in MCPWM.
|
||||
// Use MCPWM unit 1, as we're using unit 0 for the wheel speed
|
||||
mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_0, GPIO_BIN1_LEVEL);
|
||||
mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_1, GPIO_BIN2_LEVEL);
|
||||
mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_2, GPIO_BIN3_LEVEL);
|
||||
|
||||
// Configure and enable MCPWM capture units
|
||||
mcpwm_capture_config_t conf = {.cap_edge = MCPWM_BOTH_EDGE, // trigger on both edges
|
||||
.cap_prescale = 1, // pulses per interrupt
|
||||
.capture_cb = bin_level_pulse_isr_handler,
|
||||
.user_data = NULL};
|
||||
mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP0, &conf);
|
||||
mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP1, &conf);
|
||||
mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP2, &conf);
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
#ifndef bin_level_h
|
||||
#define bin_level_h
|
||||
|
||||
#include "../common/shared_structs.h"
|
||||
|
||||
// Ultrasound sensor pulse output will be BIN_LEVEL_OFFSET_MS + (depth * BIN_LEVEL_METERS_PER_MS)
|
||||
#define BIN_LEVEL_MS_PER_METER 15.5
|
||||
#define BIN_LEVEL_OFFSET_MS 4.24
|
||||
|
||||
// Time without a pulse after which the level will be considered to be 0 (to catch problems with the sensor)
|
||||
#define RECENT_PULSE_TIMEOUT_MS 5000
|
||||
|
||||
// Time after which a pulse will be considered invalid
|
||||
#define MAX_PULSE_LENGTH_MS 60
|
||||
|
||||
void bin_level_setup(void);
|
||||
|
||||
// Returns the last calculated speed for the wheel in revs/second.
|
||||
float get_bin_level(bin_id_t bin_id);
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue