|
|
|
@ -1,6 +1,6 @@
|
|
|
|
// Module to record roller and wheel speeds from MCPWM capture interrupts. Not yet sure if a task is required at all.
|
|
|
|
// Module to record roller and wheel speeds from MCPWM capture interrupts. Not yet sure if a task is required at all.
|
|
|
|
|
|
|
|
|
|
|
|
#include "wheel_speed.h"
|
|
|
|
#include "shaft_speed.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "io.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "driver/mcpwm.h"
|
|
|
|
#include "driver/mcpwm.h"
|
|
|
|
@ -10,11 +10,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t wheel_pulses = 0; // Total pulses of wheel so far
|
|
|
|
static uint32_t wheel_pulses = 0; // Total pulses of wheel so far
|
|
|
|
static uint32_t wheel_last_edge_time = 0; // Precision timer value of most recent edge
|
|
|
|
static uint32_t wheel_last_edge_time = 0; // Precision timer value of most recent edge
|
|
|
|
|
|
|
|
static uint32_t fan_last_edge_time = 0;
|
|
|
|
// Also store timestamp as microseconds since start to avoid overflow of the precision timer when checking for stop
|
|
|
|
// Also store timestamp as microseconds since start to avoid overflow of the precision timer when checking for stop
|
|
|
|
static int64_t wheel_last_timestamp = 0;
|
|
|
|
static int64_t wheel_last_timestamp = 0;
|
|
|
|
|
|
|
|
static int64_t fan_last_timestamp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Use a single item queue for each measurement we need to distribute.
|
|
|
|
// Use a single item queue for each measurement we need to distribute.
|
|
|
|
static xQueueHandle wheel_measurement_queue;
|
|
|
|
static xQueueHandle wheel_measurement_queue;
|
|
|
|
|
|
|
|
static xQueueHandle fan_measurement_queue;
|
|
|
|
|
|
|
|
|
|
|
|
// struct to hold move our pulse measurements from our ISR via the queue
|
|
|
|
// struct to hold move our pulse measurements from our ISR via the queue
|
|
|
|
typedef struct {
|
|
|
|
typedef struct {
|
|
|
|
@ -30,32 +33,43 @@ static bool speed_pulse_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id
|
|
|
|
// Not strictly necessary to do the wakeup check here, as we shouldn't be blokcing anything. Doesn't hurt though.
|
|
|
|
// 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;
|
|
|
|
BaseType_t high_task_wakeup = pdFALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cap_sig != MCPWM_SELECT_CAP0) {
|
|
|
|
|
|
|
|
// Not sure how we'd ever wind up here
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add one to our revs counter
|
|
|
|
|
|
|
|
wheel_pulses++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pulse_measurement_t new_measurement;
|
|
|
|
pulse_measurement_t new_measurement;
|
|
|
|
int64_t time_now;
|
|
|
|
int64_t time_now;
|
|
|
|
|
|
|
|
|
|
|
|
time_now = esp_timer_get_time();
|
|
|
|
if (cap_sig == MCPWM_SELECT_CAP0){
|
|
|
|
// Just make sure we have a previous edge to compare to, and that it was no more than ZERO_SPEED_TIMEOUT_US ago
|
|
|
|
// Add one to our revs counter
|
|
|
|
if ((wheel_last_timestamp != 0) and ((time_now - wheel_last_timestamp) < ZERO_SPEED_TIMEOUT_US)) {
|
|
|
|
wheel_pulses++;
|
|
|
|
new_measurement.timestamp = time_now;
|
|
|
|
|
|
|
|
new_measurement.period = edata->cap_value - wheel_last_edge_time;
|
|
|
|
time_now = esp_timer_get_time();
|
|
|
|
// Like with the rollers, technically passing the wheel pulses with the rest of the measurement here means that it won't be updated
|
|
|
|
// Just make sure we have a previous edge to compare to, and that it was no more than ZERO_SPEED_TIMEOUT_US ago
|
|
|
|
// for the first pulse detected after being stopped. The total count will still be correct, but will just not update for 1.
|
|
|
|
if ((wheel_last_timestamp != 0) and ((time_now - wheel_last_timestamp) < ZERO_SPEED_TIMEOUT_US)) {
|
|
|
|
new_measurement.pulses = wheel_pulses;
|
|
|
|
new_measurement.timestamp = time_now;
|
|
|
|
xQueueOverwriteFromISR(wheel_measurement_queue, &new_measurement, &high_task_wakeup);
|
|
|
|
new_measurement.period = edata->cap_value - wheel_last_edge_time;
|
|
|
|
|
|
|
|
// Like with the rollers, technically passing the wheel pulses with the rest of the measurement here means that it won't be updated
|
|
|
|
|
|
|
|
// for the first pulse detected after being stopped. The total count will still be correct, but will just not update for 1.
|
|
|
|
|
|
|
|
new_measurement.pulses = wheel_pulses;
|
|
|
|
|
|
|
|
xQueueOverwriteFromISR(wheel_measurement_queue, &new_measurement, &high_task_wakeup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wheel_last_edge_time = edata->cap_value;
|
|
|
|
|
|
|
|
wheel_last_timestamp = time_now;
|
|
|
|
|
|
|
|
} else if (cap_sig == MCPWM_SELECT_CAP1){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
time_now = esp_timer_get_time();
|
|
|
|
|
|
|
|
// Just make sure we have a previous edge to compare to, and that it was no more than ZERO_SPEED_TIMEOUT_US ago
|
|
|
|
|
|
|
|
if ((fan_last_timestamp != 0) and ((time_now - fan_last_timestamp) < ZERO_SPEED_TIMEOUT_US)) {
|
|
|
|
|
|
|
|
new_measurement.timestamp = time_now;
|
|
|
|
|
|
|
|
new_measurement.period = edata->cap_value - fan_last_edge_time;
|
|
|
|
|
|
|
|
xQueueOverwriteFromISR(fan_measurement_queue, &new_measurement, &high_task_wakeup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fan_last_edge_time = edata->cap_value;
|
|
|
|
|
|
|
|
fan_last_timestamp = time_now;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Not sure how we'd ever wind up here
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wheel_last_edge_time = edata->cap_value;
|
|
|
|
|
|
|
|
wheel_last_timestamp = time_now;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return high_task_wakeup == pdTRUE;
|
|
|
|
return high_task_wakeup == pdTRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -71,6 +85,18 @@ float get_wheel_speed(){
|
|
|
|
return ((float)rtc_clk_apb_freq_get() / (float)(pulse_measurement.period)) / (float)(WHEEL_PULSES_PER_REV);
|
|
|
|
return ((float)rtc_clk_apb_freq_get() / (float)(pulse_measurement.period)) / (float)(WHEEL_PULSES_PER_REV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float get_fan_speed(){
|
|
|
|
|
|
|
|
pulse_measurement_t pulse_measurement;
|
|
|
|
|
|
|
|
// Get the pulse period in APB clock ticks.
|
|
|
|
|
|
|
|
xQueuePeek(fan_measurement_queue, &pulse_measurement, 0);
|
|
|
|
|
|
|
|
if ((pulse_measurement.period == 0) or
|
|
|
|
|
|
|
|
((esp_timer_get_time() - pulse_measurement.timestamp) >= ZERO_SPEED_TIMEOUT_US)) {
|
|
|
|
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert that to revs/sec
|
|
|
|
|
|
|
|
return ((float)rtc_clk_apb_freq_get() / (float)(pulse_measurement.period)) / (float)(FAN_PULSES_PER_REV);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float get_wheel_revs() {
|
|
|
|
float get_wheel_revs() {
|
|
|
|
pulse_measurement_t pulse_measurement;
|
|
|
|
pulse_measurement_t pulse_measurement;
|
|
|
|
xQueuePeek(wheel_measurement_queue, &pulse_measurement, 0);
|
|
|
|
xQueuePeek(wheel_measurement_queue, &pulse_measurement, 0);
|
|
|
|
@ -80,18 +106,23 @@ float get_wheel_revs() {
|
|
|
|
void wheel_speed_setup(void) {
|
|
|
|
void wheel_speed_setup(void) {
|
|
|
|
// Create our measurement queue
|
|
|
|
// Create our measurement queue
|
|
|
|
wheel_measurement_queue = xQueueCreate(1, sizeof(pulse_measurement_t));
|
|
|
|
wheel_measurement_queue = xQueueCreate(1, sizeof(pulse_measurement_t));
|
|
|
|
|
|
|
|
fan_measurement_queue = xQueueCreate(1, sizeof(pulse_measurement_t));
|
|
|
|
|
|
|
|
|
|
|
|
// Prime queue
|
|
|
|
// Prime queue
|
|
|
|
pulse_measurement_t blank_measurement = {0, 0};
|
|
|
|
pulse_measurement_t blank_measurement = {0, 0};
|
|
|
|
xQueueOverwrite(wheel_measurement_queue, &blank_measurement);
|
|
|
|
xQueueOverwrite(wheel_measurement_queue, &blank_measurement);
|
|
|
|
|
|
|
|
xQueueOverwrite(fan_measurement_queue, &blank_measurement);
|
|
|
|
|
|
|
|
|
|
|
|
// Attach GPIO to capture unit 0 in MCPWM0
|
|
|
|
// Attach GPIO to capture unit 0 in MCPWM0
|
|
|
|
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, GPIO_WHEEL_SPEED);
|
|
|
|
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, GPIO_WHEEL_SPEED);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_1, GPIO_FAN_SPEED);
|
|
|
|
|
|
|
|
|
|
|
|
// Configure and enable MCPWM capture unit
|
|
|
|
// Configure and enable MCPWM capture unit
|
|
|
|
mcpwm_capture_config_t conf = {.cap_edge = MCPWM_POS_EDGE, // trigger on riding edge
|
|
|
|
mcpwm_capture_config_t conf = {.cap_edge = MCPWM_POS_EDGE, // trigger on riding edge
|
|
|
|
.cap_prescale = 1, // pulses per interrupt
|
|
|
|
.cap_prescale = 1, // pulses per interrupt
|
|
|
|
.capture_cb = speed_pulse_isr_handler,
|
|
|
|
.capture_cb = speed_pulse_isr_handler,
|
|
|
|
.user_data = NULL};
|
|
|
|
.user_data = NULL};
|
|
|
|
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf);
|
|
|
|
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf);
|
|
|
|
|
|
|
|
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, &conf);
|
|
|
|
}
|
|
|
|
}
|