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