parent
b2e9d772b0
commit
5645cb032d
@ -0,0 +1,97 @@
|
|||||||
|
// 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 "io.h"
|
||||||
|
|
||||||
|
#include "driver/mcpwm.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "soc/rtc.h"
|
||||||
|
|
||||||
|
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
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// Use a single item queue for each measurement we need to distribute.
|
||||||
|
static xQueueHandle wheel_measurement_queue;
|
||||||
|
|
||||||
|
// struct to hold move our pulse measurements from our ISR via the queue
|
||||||
|
typedef struct {
|
||||||
|
uint32_t period; // period since last pulse in APB clock ticks
|
||||||
|
int64_t timestamp; // time measurement occurred in microseconds since boot
|
||||||
|
uint32_t pulses; // Total pulses of wheel so far
|
||||||
|
} pulse_measurement_t;
|
||||||
|
|
||||||
|
// Gets called by the MCPWM capture module. Tells us which capture unit it was, which edge, and when it happened
|
||||||
|
static bool speed_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;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
int64_t time_now;
|
||||||
|
|
||||||
|
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 ((wheel_last_timestamp != 0) and ((time_now - wheel_last_timestamp) < ZERO_SPEED_TIMEOUT_US)) {
|
||||||
|
new_measurement.timestamp = time_now;
|
||||||
|
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;
|
||||||
|
|
||||||
|
return high_task_wakeup == pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_wheel_speed(){
|
||||||
|
pulse_measurement_t pulse_measurement;
|
||||||
|
// Get the pulse period in APB clock ticks.
|
||||||
|
xQueuePeek(wheel_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)(WHEEL_PULSES_PER_REV);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_wheel_revs() {
|
||||||
|
pulse_measurement_t pulse_measurement;
|
||||||
|
xQueuePeek(wheel_measurement_queue, &pulse_measurement, 0);
|
||||||
|
return (float)pulse_measurement.pulses / (float)WHEEL_PULSES_PER_REV;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wheel_speed_setup(void) {
|
||||||
|
// Create our measurement queue
|
||||||
|
wheel_measurement_queue = xQueueCreate(1, sizeof(pulse_measurement_t));
|
||||||
|
|
||||||
|
// Prime queue
|
||||||
|
pulse_measurement_t blank_measurement = {0, 0};
|
||||||
|
xQueueOverwrite(wheel_measurement_queue, &blank_measurement);
|
||||||
|
|
||||||
|
// Attach GPIO to capture unit 0 in MCPWM0
|
||||||
|
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, GPIO_WHEEL_SPEED);
|
||||||
|
|
||||||
|
// Configure and enable MCPWM capture unit
|
||||||
|
mcpwm_capture_config_t conf = {.cap_edge = MCPWM_POS_EDGE, // trigger on riding edge
|
||||||
|
.cap_prescale = 1, // pulses per interrupt
|
||||||
|
.capture_cb = speed_pulse_isr_handler,
|
||||||
|
.user_data = NULL};
|
||||||
|
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf);
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef wheel_speed_h
|
||||||
|
#define wheel_speed_h
|
||||||
|
|
||||||
|
#include "../common/shared_structs.h"
|
||||||
|
|
||||||
|
// Number of sensor pulses per wheel rev. Note that this will overflow at about 4 billion pulses
|
||||||
|
#define WHEEL_PULSES_PER_REV 40
|
||||||
|
|
||||||
|
// Time without a pulse after which the speed will be considered to be 0.
|
||||||
|
// Note that with a clock at 80MHz, the pulse period counter overflows every 53 seconds
|
||||||
|
#define ZERO_SPEED_TIMEOUT_US 1000000
|
||||||
|
|
||||||
|
void wheel_speed_setup(void);
|
||||||
|
|
||||||
|
// Returns the last calculated speed for the wheel in revs/second.
|
||||||
|
float get_wheel_speed();
|
||||||
|
|
||||||
|
// Returns the total rev count for the wheel.
|
||||||
|
float get_wheel_revs();
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in new issue