|
|
|
@@ -1,4 +1,6 @@
|
|
|
|
|
#include <boot/picobin.h>
|
|
|
|
|
#include <hardware/adc.h>
|
|
|
|
|
#include <hardware/dma.h>
|
|
|
|
|
#include <hardware/flash.h>
|
|
|
|
|
#include <hardware/gpio.h>
|
|
|
|
|
#include <hardware/irq.h>
|
|
|
|
@@ -13,15 +15,14 @@
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "beep.h"
|
|
|
|
|
#include "ds1302.h"
|
|
|
|
|
#include "graphics.h"
|
|
|
|
|
#include "pins.h"
|
|
|
|
|
#include "ss49e.h"
|
|
|
|
|
#include "st7789.h"
|
|
|
|
|
|
|
|
|
|
#define LOGGING
|
|
|
|
|
|
|
|
|
|
#define HALL_SENSOR_DEBOUNCE_DELAY_us 10000
|
|
|
|
|
#define BUTTON_DEBOUNCE_DELAY_us 3000
|
|
|
|
|
#define BUTTON_HOLD_TIME_ms 1000
|
|
|
|
|
#define TICKS_PER_REVOLUTION 6
|
|
|
|
@@ -58,12 +59,12 @@ struct GUIState {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void on_gpio_interrupt(uint pin, uint32_t eventMask);
|
|
|
|
|
int64_t hall_sensor_debounce_callback(alarm_id_t alarmId, void *userData);
|
|
|
|
|
static void __not_in_flash_func(dma_irq_handler)();
|
|
|
|
|
int64_t button_debounce_callback(alarm_id_t alarmId, void *userData);
|
|
|
|
|
int64_t button_hold_callback(alarm_id_t alarmId, void *userData);
|
|
|
|
|
bool speed_measure_timer_callback(repeating_timer_t *rt);
|
|
|
|
|
void on_button_short_press(uint button);
|
|
|
|
|
void on_button_long_press(uint button);
|
|
|
|
|
void on_wheel_hall_sensor_tick();
|
|
|
|
|
|
|
|
|
|
void update_lcd();
|
|
|
|
|
void gui_init(struct GUIState *state);
|
|
|
|
@@ -96,25 +97,26 @@ int16_t convert_brightness(int16_t input) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for debouncing
|
|
|
|
|
alarm_id_t hallSensorDebounceAlarm = 0;
|
|
|
|
|
bool hallSensorLastState = 0;
|
|
|
|
|
bool hallSensorPrevState = 0;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
struct PushButtonState {
|
|
|
|
|
alarm_id_t debounceAlarm, holdAlarm;
|
|
|
|
|
bool currentState, prevState, isHeld;
|
|
|
|
|
} buttonStates[4];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct PushButtonState buttonStates[4];
|
|
|
|
|
|
|
|
|
|
// for debug (and for the future)
|
|
|
|
|
absolute_time_t lastWheelTickTime = 0;
|
|
|
|
|
|
|
|
|
|
// for hall sensors
|
|
|
|
|
int adcDmaChannelA, adcDmaChannelB;
|
|
|
|
|
uint16_t adcBufferA[1600];
|
|
|
|
|
uint16_t adcBufferB[1600];
|
|
|
|
|
SS49E_State wheelSensorState;
|
|
|
|
|
|
|
|
|
|
// for speed measurement
|
|
|
|
|
uint8_t intervalWheelTicks[SPEED_MEASUREMENT_WINDOW_SIZE];
|
|
|
|
|
uint8_t currentInterval = 0;
|
|
|
|
|
uint16_t ticksPerWindow = 0;
|
|
|
|
|
// critical_section_t intervalWheelTicksCritSec;
|
|
|
|
|
repeating_timer_t speedMeasureTimer;
|
|
|
|
|
|
|
|
|
|
// odometer counters
|
|
|
|
|
uint totalWheelTicks = 0;
|
|
|
|
@@ -173,18 +175,46 @@ int main() {
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// critical_section_init(&intervalWheelTicksCritSec);
|
|
|
|
|
add_repeating_timer_ms(SPEED_MEASUREMENT_INTERVAL_ms, speed_measure_timer_callback, NULL, &speedMeasureTimer);
|
|
|
|
|
|
|
|
|
|
gpio_set_irq_callback(on_gpio_interrupt);
|
|
|
|
|
|
|
|
|
|
gpio_init(PIN_BEEPER);
|
|
|
|
|
gpio_set_dir(PIN_BEEPER, GPIO_OUT);
|
|
|
|
|
// hall sensor (wheel only for now)
|
|
|
|
|
adc_init();
|
|
|
|
|
adc_gpio_init(42);
|
|
|
|
|
adc_select_input(2);
|
|
|
|
|
adc_set_round_robin(1 << 2);
|
|
|
|
|
adc_set_clkdiv(3000 / 1); // 16kHz for 1 sensor
|
|
|
|
|
adc_fifo_setup(true, true, 1, false, false);
|
|
|
|
|
|
|
|
|
|
// hall sensor
|
|
|
|
|
gpio_init(PIN_MAIN_HALL_SENSOR);
|
|
|
|
|
gpio_pull_up(PIN_MAIN_HALL_SENSOR);
|
|
|
|
|
gpio_set_irq_enabled(PIN_MAIN_HALL_SENSOR, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
|
|
|
|
// wheel sensor (with N-S alternating magnet arrangement)
|
|
|
|
|
ss49e_init(&wheelSensorState, MAGNET_POLTYPE_BIPOLAR, on_wheel_hall_sensor_tick);
|
|
|
|
|
|
|
|
|
|
// DMA for hall sensor
|
|
|
|
|
adcDmaChannelA = dma_claim_unused_channel(true);
|
|
|
|
|
adcDmaChannelB = dma_claim_unused_channel(true);
|
|
|
|
|
|
|
|
|
|
dma_channel_config dmaCfg = dma_channel_get_default_config(adcDmaChannelA);
|
|
|
|
|
channel_config_set_transfer_data_size(&dmaCfg, DMA_SIZE_16);
|
|
|
|
|
channel_config_set_read_increment(&dmaCfg, false);
|
|
|
|
|
channel_config_set_write_increment(&dmaCfg, true);
|
|
|
|
|
channel_config_set_dreq(&dmaCfg, DREQ_ADC);
|
|
|
|
|
channel_config_set_chain_to(&dmaCfg, adcDmaChannelB);
|
|
|
|
|
dma_channel_configure(adcDmaChannelA, &dmaCfg, adcBufferA, &adc_hw->fifo, 1600, false);
|
|
|
|
|
|
|
|
|
|
dmaCfg = dma_channel_get_default_config(adcDmaChannelB);
|
|
|
|
|
channel_config_set_transfer_data_size(&dmaCfg, DMA_SIZE_16);
|
|
|
|
|
channel_config_set_read_increment(&dmaCfg, false);
|
|
|
|
|
channel_config_set_write_increment(&dmaCfg, true);
|
|
|
|
|
channel_config_set_dreq(&dmaCfg, DREQ_ADC);
|
|
|
|
|
channel_config_set_chain_to(&dmaCfg, adcDmaChannelA);
|
|
|
|
|
dma_channel_configure(adcDmaChannelB, &dmaCfg, adcBufferB, &adc_hw->fifo, 1600, false);
|
|
|
|
|
|
|
|
|
|
dma_channel_set_irq0_enabled(adcDmaChannelA, true);
|
|
|
|
|
dma_channel_set_irq0_enabled(adcDmaChannelB, true);
|
|
|
|
|
irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler);
|
|
|
|
|
irq_set_enabled(DMA_IRQ_0, true);
|
|
|
|
|
|
|
|
|
|
adc_run(true);
|
|
|
|
|
dma_channel_start(adcDmaChannelA);
|
|
|
|
|
|
|
|
|
|
// on-board LED
|
|
|
|
|
gpio_init(25);
|
|
|
|
@@ -202,7 +232,7 @@ int main() {
|
|
|
|
|
|
|
|
|
|
ds1302_init();
|
|
|
|
|
|
|
|
|
|
DateTime tmp = {26, 9, 9, 15, 10, 0, DOW_WED};
|
|
|
|
|
// DateTime tmp = {26, 9, 9, 15, 10, 0, DOW_WED};
|
|
|
|
|
// ds1302_set_datetime(&tmp);
|
|
|
|
|
|
|
|
|
|
load_from_rtc();
|
|
|
|
@@ -249,17 +279,7 @@ int main() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
|
|
|
|
if (pin == PIN_MAIN_HALL_SENSOR) {
|
|
|
|
|
if (eventMask & GPIO_IRQ_EDGE_RISE)
|
|
|
|
|
hallSensorLastState = 0;
|
|
|
|
|
if (eventMask & GPIO_IRQ_EDGE_FALL)
|
|
|
|
|
hallSensorLastState = 1;
|
|
|
|
|
if (hallSensorDebounceAlarm)
|
|
|
|
|
cancel_alarm(hallSensorDebounceAlarm);
|
|
|
|
|
hallSensorDebounceAlarm =
|
|
|
|
|
add_alarm_in_us(HALL_SENSOR_DEBOUNCE_DELAY_us, hall_sensor_debounce_callback, NULL, false);
|
|
|
|
|
gpio_acknowledge_irq(pin, eventMask);
|
|
|
|
|
} else if (pin == PIN_BUTTON_0 || pin == PIN_BUTTON_1 || pin == PIN_BUTTON_2 || pin == PIN_BUTTON_3) {
|
|
|
|
|
if (pin == PIN_BUTTON_0 || pin == PIN_BUTTON_1 || pin == PIN_BUTTON_2 || pin == PIN_BUTTON_3) {
|
|
|
|
|
uint buttonIndex;
|
|
|
|
|
switch (pin) {
|
|
|
|
|
case PIN_BUTTON_0:
|
|
|
|
@@ -274,12 +294,7 @@ void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
|
|
|
|
case PIN_BUTTON_3:
|
|
|
|
|
buttonIndex = 3;
|
|
|
|
|
}
|
|
|
|
|
auto buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
// if (eventMask & GPIO_IRQ_EDGE_RISE)
|
|
|
|
|
// buttonState->currentState = 0;
|
|
|
|
|
// if (eventMask & GPIO_IRQ_EDGE_FALL)
|
|
|
|
|
// buttonState->currentState = 1;
|
|
|
|
|
// buttonState->currentState = !gpio_get(pin);
|
|
|
|
|
struct PushButtonState *buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
if (buttonState->debounceAlarm != -1)
|
|
|
|
|
cancel_alarm(buttonState->debounceAlarm);
|
|
|
|
|
buttonState->debounceAlarm =
|
|
|
|
@@ -288,26 +303,63 @@ void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t hall_sensor_debounce_callback(alarm_id_t alarmId, void *userData) {
|
|
|
|
|
(void)alarmId;
|
|
|
|
|
(void)userData;
|
|
|
|
|
if (hallSensorLastState != hallSensorPrevState) {
|
|
|
|
|
absolute_time_t now = get_absolute_time();
|
|
|
|
|
lastWheelTickTime = now;
|
|
|
|
|
++intervalWheelTicks[currentInterval];
|
|
|
|
|
++totalWheelTicks;
|
|
|
|
|
++wheelTicksFromPowerOn;
|
|
|
|
|
|
|
|
|
|
gpio_put(25, !gpio_get(25));
|
|
|
|
|
hallSensorPrevState = hallSensorLastState;
|
|
|
|
|
static void __not_in_flash_func(dma_irq_handler)() {
|
|
|
|
|
if (dma_hw->ints0 & (1u << adcDmaChannelA)) {
|
|
|
|
|
dma_hw->ints0 = 1u << adcDmaChannelA;
|
|
|
|
|
for (uint i = 0; i < 1600; ++i)
|
|
|
|
|
ss49e_process_sample(&wheelSensorState, adcBufferA[i]);
|
|
|
|
|
float sum = 0.0f, max = 0.0f, min = 9999.0f;
|
|
|
|
|
for (uint i = 0; i < 1600; ++i) {
|
|
|
|
|
sum += adcBufferA[i];
|
|
|
|
|
if (adcBufferA[i] > max)
|
|
|
|
|
max = adcBufferA[i];
|
|
|
|
|
if (adcBufferA[i] < min)
|
|
|
|
|
min = adcBufferA[i];
|
|
|
|
|
}
|
|
|
|
|
sum /= 1600;
|
|
|
|
|
printf("%f ~ %f ~ %f\n", min, sum, max);
|
|
|
|
|
dma_channel_set_write_addr(adcDmaChannelA, adcBufferA, false);
|
|
|
|
|
dma_channel_set_trans_count(adcDmaChannelA, 1600, false);
|
|
|
|
|
|
|
|
|
|
sum = 0;
|
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
|
sum += intervalWheelTicks[i];
|
|
|
|
|
}
|
|
|
|
|
currentInterval = (currentInterval + 1) % 16;
|
|
|
|
|
intervalWheelTicks[currentInterval] = 0;
|
|
|
|
|
ticksPerWindow = sum;
|
|
|
|
|
}
|
|
|
|
|
if (dma_hw->ints0 & (1u << adcDmaChannelB)) {
|
|
|
|
|
dma_hw->ints0 = 1u << adcDmaChannelB;
|
|
|
|
|
for (uint i = 0; i < 1600; ++i)
|
|
|
|
|
ss49e_process_sample(&wheelSensorState, adcBufferB[i]);
|
|
|
|
|
float sum = 0.0f, max = 0.0f, min = 9999.0f;
|
|
|
|
|
for (uint i = 0; i < 1600; ++i) {
|
|
|
|
|
sum += adcBufferB[i];
|
|
|
|
|
if (adcBufferB[i] > max)
|
|
|
|
|
max = adcBufferB[i];
|
|
|
|
|
if (adcBufferB[i] < min)
|
|
|
|
|
min = adcBufferB[i];
|
|
|
|
|
}
|
|
|
|
|
sum /= 1600;
|
|
|
|
|
printf("%f ~ %f ~ %f\n", min, sum, max);
|
|
|
|
|
dma_channel_set_write_addr(adcDmaChannelB, adcBufferB, false);
|
|
|
|
|
dma_channel_set_trans_count(adcDmaChannelB, 1600, false);
|
|
|
|
|
|
|
|
|
|
sum = 0;
|
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
|
sum += intervalWheelTicks[i];
|
|
|
|
|
}
|
|
|
|
|
currentInterval = (currentInterval + 1) % 16;
|
|
|
|
|
intervalWheelTicks[currentInterval] = 0;
|
|
|
|
|
ticksPerWindow = sum;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t button_debounce_callback(alarm_id_t alarmId, void *userData) {
|
|
|
|
|
(void)alarmId;
|
|
|
|
|
uint buttonIndex = (uint)userData;
|
|
|
|
|
auto buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
struct PushButtonState *buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
bool currentState = !gpio_get(FRONT_BUTTON_PINS[buttonIndex]);
|
|
|
|
|
if (currentState != buttonState->prevState) {
|
|
|
|
|
buttonState->prevState = currentState;
|
|
|
|
@@ -330,7 +382,7 @@ int64_t button_debounce_callback(alarm_id_t alarmId, void *userData) {
|
|
|
|
|
int64_t button_hold_callback(alarm_id_t alarmId, void *userData) {
|
|
|
|
|
(void)alarmId;
|
|
|
|
|
uint buttonIndex = (uint)userData;
|
|
|
|
|
auto buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
struct PushButtonState *buttonState = &buttonStates[buttonIndex];
|
|
|
|
|
buttonState->holdAlarm = -1;
|
|
|
|
|
buttonState->isHeld = true;
|
|
|
|
|
on_button_long_press(buttonIndex);
|
|
|
|
@@ -338,7 +390,6 @@ int64_t button_hold_callback(alarm_id_t alarmId, void *userData) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void on_button_short_press(uint button) {
|
|
|
|
|
// beep(60, 900);
|
|
|
|
|
#ifdef LOGGING
|
|
|
|
|
printf("button %i short press\n", button);
|
|
|
|
|
#endif
|
|
|
|
@@ -355,7 +406,6 @@ void on_button_short_press(uint button) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void on_button_long_press(uint button) {
|
|
|
|
|
// beep(60, 1273);
|
|
|
|
|
#ifdef LOGGING
|
|
|
|
|
printf("button %i long press\n");
|
|
|
|
|
#endif
|
|
|
|
@@ -365,29 +415,11 @@ void on_button_long_press(uint button) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool speed_measure_timer_callback(repeating_timer_t *rt) {
|
|
|
|
|
(void)rt;
|
|
|
|
|
|
|
|
|
|
uint16_t sum = 0;
|
|
|
|
|
/*
|
|
|
|
|
printf("window: ");
|
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
|
sum += intervalWheelTicks[i];
|
|
|
|
|
if (currentInterval == i)
|
|
|
|
|
printf("[%i] ", intervalWheelTicks[i]);
|
|
|
|
|
else
|
|
|
|
|
printf("%i ", intervalWheelTicks[i]);
|
|
|
|
|
}
|
|
|
|
|
printf("\n");
|
|
|
|
|
*/
|
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
|
sum += intervalWheelTicks[i];
|
|
|
|
|
}
|
|
|
|
|
currentInterval = (currentInterval + 1) % 16;
|
|
|
|
|
intervalWheelTicks[currentInterval] = 0;
|
|
|
|
|
ticksPerWindow = sum;
|
|
|
|
|
// printf("Total %i \r", sum);
|
|
|
|
|
return true;
|
|
|
|
|
void on_wheel_hall_sensor_tick() {
|
|
|
|
|
++intervalWheelTicks[currentInterval];
|
|
|
|
|
++totalWheelTicks;
|
|
|
|
|
++wheelTicksFromPowerOn;
|
|
|
|
|
printf("\t\t\tTICK\7\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t color565_lerp(uint16_t a, uint16_t b, uint alphaPercent) {
|
|
|
|
@@ -594,10 +626,6 @@ void save_to_rtc() {
|
|
|
|
|
do {
|
|
|
|
|
printf("\nattempting to write...\n");
|
|
|
|
|
ds1302_set_write_protection(0);
|
|
|
|
|
// for (int i = 0; i < 31; ++i) {
|
|
|
|
|
// ds1302_set_ram_byte(0xC0 + i * 2, buffer + i);
|
|
|
|
|
// sleep_us(2);
|
|
|
|
|
// }
|
|
|
|
|
ds1302_write_ram_bulk(buffer, 31);
|
|
|
|
|
for (int i = 0; i < 30; ++i)
|
|
|
|
|
printf("%02x ", buffer[i]);
|
|
|
|
|