Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50a893f536 | ||
|
|
d0fd39cffa | ||
|
|
c2c261a1c8 | ||
|
|
6586bcfa69 | ||
|
|
2073575f54 |
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.27)
|
cmake_minimum_required(VERSION 3.27)
|
||||||
set(PICO_SDK_PATH /home/sl/pico-sdk)
|
set(PICO_SDK_PATH /home/sl/pico-sdk)
|
||||||
set(PICO_PLATFORM rp2350)
|
set(PICO_PLATFORM rp2350)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
include(pico_sdk_import.cmake)
|
include(pico_sdk_import.cmake)
|
||||||
|
|
||||||
project(GPIOTest)
|
project(GPIOTest)
|
||||||
@@ -9,8 +10,8 @@ set(PICO_PSRAM_CS_PIN 47 CACHE STRING "GPIO used as Chip Select for PSRAM")
|
|||||||
set(PICO_PSRAM_SIZE_BYTES 8388608 CACHE STRING "PSRAM size in bytes")
|
set(PICO_PSRAM_SIZE_BYTES 8388608 CACHE STRING "PSRAM size in bytes")
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
add_executable(program main.c st7789.c graphics.c utf8.c ds1302.c beep.c)
|
add_executable(program main.c st7789.c graphics.c graphics_fb.c utf8.c ds1302.c beep.c ss49e.c)
|
||||||
target_link_libraries(program pico_stdlib pico_bootrom pico_rand hardware_gpio hardware_pwm hardware_spi hardware_regs hardware_psram pico_stdio_usb pico_time pico_sync)
|
target_link_libraries(program pico_stdlib pico_bootrom pico_rand hardware_adc hardware_dma hardware_gpio hardware_pwm hardware_spi hardware_regs hardware_psram pico_stdio_usb pico_time pico_sync)
|
||||||
#target_compile_definitions(program PRIVATE PICO_PSRAM_CS_PIN=${PICO_PSRAM_CS_PIN} PICO_PSRAM_SIZE_BYTES=${PICO_PSRAM_CS_PIN})
|
#target_compile_definitions(program PRIVATE PICO_PSRAM_CS_PIN=${PICO_PSRAM_CS_PIN} PICO_PSRAM_SIZE_BYTES=${PICO_PSRAM_CS_PIN})
|
||||||
target_compile_definitions(program PRIVATE PICO_PSRAM_CS_PIN=0 PICO_PSRAM_SIZE_BYTES=8388608)
|
target_compile_definitions(program PRIVATE PICO_PSRAM_CS_PIN=0 PICO_PSRAM_SIZE_BYTES=8388608)
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -326,9 +326,9 @@ const char GLYPH_CYRILLIC_SMALL_LETTER_CHE[] = {224, 224, 0, 0, 0, 0, 0, 0,
|
|||||||
const char GLYPH_CYRILLIC_SMALL_LETTER_SHA[] = {224, 224, 0, 0, 0, 0, 0, 0, 224, 224, 0, 0, 0, 0, 0, 224,
|
const char GLYPH_CYRILLIC_SMALL_LETTER_SHA[] = {224, 224, 0, 0, 0, 0, 0, 0, 224, 224, 0, 0, 0, 0, 0, 224,
|
||||||
255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 255,
|
255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 255,
|
||||||
7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 7};
|
7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 7};
|
||||||
const char GLYPH_CYRILLIC_SMALL_LETTER_SHCHA[] = {224, 224, 0, 0, 0, 0, 0, 0, 224, 224, 0, 0, 0, 0, 0, 224,
|
const char GLYPH_CYRILLIC_SMALL_LETTER_SHCHA[] = {
|
||||||
255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 255,
|
224, 224, 0, 0, 0, 0, 0, 0, 224, 224, 0, 0, 0, 0, 0, 224, 224, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255,
|
||||||
7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 7};
|
0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 7, 7, 6, 6, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6, 7, 7, 126, 126, 0};
|
||||||
const char GLYPH_CYRILLIC_SMALL_LETTER_HARD_SIGN[] = {96, 96, 96, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
const char GLYPH_CYRILLIC_SMALL_LETTER_HARD_SIGN[] = {96, 96, 96, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 255, 255, 12, 12, 12, 12, 12, 12, 28, 24, 248, 240,
|
0, 0, 0, 255, 255, 12, 12, 12, 12, 12, 12, 28, 24, 248, 240,
|
||||||
0, 0, 0, 7, 7, 6, 6, 6, 6, 6, 6, 6, 3, 3, 1};
|
0, 0, 0, 7, 7, 6, 6, 6, 6, 6, 6, 6, 3, 3, 1};
|
||||||
@@ -351,7 +351,7 @@ const char GLYPH_WIDTH[143] = {
|
|||||||
13, 9, 16, 17, 14, 13, 15, 12, 11, 13, 14, 2, 11, 14, 12, 16, 15, 16, 13, 16, 14, 12, 14, 14, 16, 17, 14, 14, 13,
|
13, 9, 16, 17, 14, 13, 15, 12, 11, 13, 14, 2, 11, 14, 12, 16, 15, 16, 13, 16, 14, 12, 14, 14, 16, 17, 14, 14, 13,
|
||||||
6, 11, 6, 13, 13, 5, 11, 12, 10, 12, 13, 8, 12, 11, 2, 4, 12, 4, 16, 11, 13, 12, 12, 8, 10, 8, 11, 12, 18,
|
6, 11, 6, 13, 13, 5, 11, 12, 10, 12, 13, 8, 12, 11, 2, 4, 12, 4, 16, 11, 13, 12, 12, 8, 10, 8, 11, 12, 18,
|
||||||
13, 12, 10, 7, 2, 7, 14, 12, 11, 18, 12, 17, 13, 15, 15, 14, 16, 14, 14, 17, 16, 12, 16, 16, 17, 16, 12, 13, 16,
|
13, 12, 10, 7, 2, 7, 14, 12, 11, 18, 12, 17, 13, 15, 15, 14, 16, 14, 14, 17, 16, 12, 16, 16, 17, 16, 12, 13, 16,
|
||||||
14, 13, 10, 9, 15, 13, 18, 11, 12, 12, 12, 14, 15, 11, 11, 10, 16, 12, 10, 16, 16, 15, 16, 10, 10, 16, 11};
|
14, 13, 10, 9, 15, 13, 18, 11, 12, 12, 12, 14, 15, 11, 11, 10, 16, 12, 10, 16, 20, 15, 16, 10, 10, 16, 11};
|
||||||
|
|
||||||
const char *GLYPH_ADDR[143] = {
|
const char *GLYPH_ADDR[143] = {
|
||||||
GLYPH_EXCLAMATION_MARK,
|
GLYPH_EXCLAMATION_MARK,
|
||||||
|
|||||||
+3
-3
@@ -111,7 +111,7 @@ void lcd_draw_vertical_xsmall_digit_segment(uint16_t x, uint16_t y, uint16_t col
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t DIGIT_MASKS[10] = {0b1110111, 0b0100100, 0b1011101, 0b1101101, 0b0101110,
|
static const uint8_t DIGIT_MASKS[10] = {0b1110111, 0b0100100, 0b1011101, 0b1101101, 0b0101110,
|
||||||
0b1101011, 0b1111011, 0b0100101, 0b1111111, 0b1101111};
|
0b1101011, 0b1111011, 0b0100101, 0b1111111, 0b1101111};
|
||||||
|
|
||||||
void lcd_draw_digit(uint8_t digit, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
|
void lcd_draw_digit(uint8_t digit, uint16_t x, uint16_t y, uint16_t color, uint16_t bgColor) {
|
||||||
@@ -199,7 +199,7 @@ void lcd_write_string(const char *string, uint16_t x, uint16_t y, uint16_t color
|
|||||||
st7789_write(glyphPixels, 24 * (glyphWidth + LETTER_SPACING) * sizeof(uint16_t));
|
st7789_write(glyphPixels, 24 * (glyphWidth + LETTER_SPACING) * sizeof(uint16_t));
|
||||||
x += glyphWidth + LETTER_SPACING;
|
x += glyphWidth + LETTER_SPACING;
|
||||||
} else {
|
} else {
|
||||||
lcd_fill_rectangle(x, y, 12, 24, bgColor);
|
_fill_rectangle(x, y, 12, 24, bgColor);
|
||||||
x += 12;
|
x += 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,7 @@ int lcd_string_width(const char *string) {
|
|||||||
} else {
|
} else {
|
||||||
int glyphIndex = glyph_index_for_code_point(character);
|
int glyphIndex = glyph_index_for_code_point(character);
|
||||||
if (glyphIndex != -1) {
|
if (glyphIndex != -1) {
|
||||||
width += GLYPH_WIDTH[glyphIndex] + 1;
|
width += GLYPH_WIDTH[glyphIndex] + LETTER_SPACING;
|
||||||
} else {
|
} else {
|
||||||
width += 12;
|
width += 12;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -29,6 +29,14 @@ static inline void _draw_v_strip(uint16_t x, uint16_t y, uint16_t len, uint16_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void _fill_rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
|
||||||
|
st7789_caset(x, x + w - 1);
|
||||||
|
st7789_raset(y, y + h - 1);
|
||||||
|
for (uint16_t i = 0; i < w * h; ++i) {
|
||||||
|
st7789_put(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void lcd_set_pixel(uint16_t x, uint16_t y, uint16_t color) {
|
inline void lcd_set_pixel(uint16_t x, uint16_t y, uint16_t color) {
|
||||||
x += LCD_OFFSET_X;
|
x += LCD_OFFSET_X;
|
||||||
y += LCD_OFFSET_Y;
|
y += LCD_OFFSET_Y;
|
||||||
@@ -39,11 +47,7 @@ inline void lcd_set_pixel(uint16_t x, uint16_t y, uint16_t color) {
|
|||||||
inline void lcd_fill_rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
|
inline void lcd_fill_rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
|
||||||
x += LCD_OFFSET_X;
|
x += LCD_OFFSET_X;
|
||||||
y += LCD_OFFSET_Y;
|
y += LCD_OFFSET_Y;
|
||||||
st7789_caset(x, x + w - 1);
|
_fill_rectangle(x, y, w, h, color);
|
||||||
st7789_raset(y, y + h - 1);
|
|
||||||
for (uint16_t i = 0; i < w * h; ++i) {
|
|
||||||
st7789_put(color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_draw_horizontal_digit_segment(uint16_t x, uint16_t y, uint16_t color);
|
void lcd_draw_horizontal_digit_segment(uint16_t x, uint16_t y, uint16_t color);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <boot/picobin.h>
|
#include <boot/picobin.h>
|
||||||
|
#include <hardware/adc.h>
|
||||||
|
#include <hardware/dma.h>
|
||||||
#include <hardware/flash.h>
|
#include <hardware/flash.h>
|
||||||
#include <hardware/gpio.h>
|
#include <hardware/gpio.h>
|
||||||
#include <hardware/irq.h>
|
#include <hardware/irq.h>
|
||||||
@@ -13,15 +15,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "beep.h"
|
|
||||||
#include "ds1302.h"
|
#include "ds1302.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "pins.h"
|
#include "pins.h"
|
||||||
|
#include "ss49e.h"
|
||||||
#include "st7789.h"
|
#include "st7789.h"
|
||||||
|
|
||||||
#define LOGGING
|
#define LOGGING
|
||||||
|
|
||||||
#define HALL_SENSOR_DEBOUNCE_DELAY_us 10000
|
|
||||||
#define BUTTON_DEBOUNCE_DELAY_us 3000
|
#define BUTTON_DEBOUNCE_DELAY_us 3000
|
||||||
#define BUTTON_HOLD_TIME_ms 1000
|
#define BUTTON_HOLD_TIME_ms 1000
|
||||||
#define TICKS_PER_REVOLUTION 6
|
#define TICKS_PER_REVOLUTION 6
|
||||||
@@ -37,7 +38,8 @@ enum GUIScreen {
|
|||||||
|
|
||||||
enum DisplayMode {
|
enum DisplayMode {
|
||||||
DISPLAY_MODE_SPEED,
|
DISPLAY_MODE_SPEED,
|
||||||
DISPLAY_MODE_DISTANCE,
|
DISPLAY_MODE_DISTANCE_FROM_POWER_ON,
|
||||||
|
DISPLAY_MODE_TOTAL_DISTANCE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GUIState {
|
struct GUIState {
|
||||||
@@ -51,15 +53,18 @@ struct GUIState {
|
|||||||
//...
|
//...
|
||||||
} settingsScreen;
|
} settingsScreen;
|
||||||
} screenState;
|
} screenState;
|
||||||
|
uint8_t drawnTimeHours;
|
||||||
|
uint8_t drawnTimeMinutes;
|
||||||
|
uint16_t drawnTimeTextWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
void on_gpio_interrupt(uint pin, uint32_t eventMask);
|
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_debounce_callback(alarm_id_t alarmId, void *userData);
|
||||||
int64_t button_hold_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_short_press(uint button);
|
||||||
void on_button_long_press(uint button);
|
void on_button_long_press(uint button);
|
||||||
|
void on_wheel_hall_sensor_tick();
|
||||||
|
|
||||||
void update_lcd();
|
void update_lcd();
|
||||||
void gui_init(struct GUIState *state);
|
void gui_init(struct GUIState *state);
|
||||||
@@ -92,27 +97,30 @@ int16_t convert_brightness(int16_t input) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for debouncing
|
struct PushButtonState {
|
||||||
alarm_id_t hallSensorDebounceAlarm = 0;
|
|
||||||
bool hallSensorLastState = 0;
|
|
||||||
bool hallSensorPrevState = 0;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
alarm_id_t debounceAlarm, holdAlarm;
|
alarm_id_t debounceAlarm, holdAlarm;
|
||||||
bool currentState, prevState, isHeld;
|
bool currentState, prevState, isHeld;
|
||||||
} buttonStates[4];
|
};
|
||||||
|
|
||||||
|
struct PushButtonState buttonStates[4];
|
||||||
|
|
||||||
// for debug (and for the future)
|
// for debug (and for the future)
|
||||||
absolute_time_t lastWheelTickTime = 0;
|
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
|
// for speed measurement
|
||||||
uint8_t intervalWheelTicks[SPEED_MEASUREMENT_WINDOW_SIZE];
|
uint8_t intervalWheelTicks[SPEED_MEASUREMENT_WINDOW_SIZE];
|
||||||
uint8_t currentInterval = 0;
|
uint8_t currentInterval = 0;
|
||||||
uint16_t ticksPerWindow = 0;
|
uint16_t ticksPerWindow = 0;
|
||||||
// critical_section_t intervalWheelTicksCritSec;
|
|
||||||
repeating_timer_t speedMeasureTimer;
|
|
||||||
|
|
||||||
uint totalTicks = 0;
|
// odometer counters
|
||||||
|
uint totalWheelTicks = 0;
|
||||||
|
uint wheelTicksFromPowerOn = 0;
|
||||||
|
|
||||||
DateTime currentDatetime;
|
DateTime currentDatetime;
|
||||||
|
|
||||||
@@ -167,18 +175,46 @@ int main() {
|
|||||||
}
|
}
|
||||||
#endif
|
#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_set_irq_callback(on_gpio_interrupt);
|
||||||
|
|
||||||
gpio_init(PIN_BEEPER);
|
// hall sensor (wheel only for now)
|
||||||
gpio_set_dir(PIN_BEEPER, GPIO_OUT);
|
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
|
// wheel sensor (with N-S alternating magnet arrangement)
|
||||||
gpio_init(PIN_MAIN_HALL_SENSOR);
|
ss49e_init(&wheelSensorState, MAGNET_POLTYPE_BIPOLAR, on_wheel_hall_sensor_tick);
|
||||||
gpio_pull_up(PIN_MAIN_HALL_SENSOR);
|
|
||||||
gpio_set_irq_enabled(PIN_MAIN_HALL_SENSOR, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
// 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
|
// on-board LED
|
||||||
gpio_init(25);
|
gpio_init(25);
|
||||||
@@ -196,7 +232,7 @@ int main() {
|
|||||||
|
|
||||||
ds1302_init();
|
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);
|
// ds1302_set_datetime(&tmp);
|
||||||
|
|
||||||
load_from_rtc();
|
load_from_rtc();
|
||||||
@@ -243,17 +279,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
||||||
if (pin == PIN_MAIN_HALL_SENSOR) {
|
if (pin == PIN_BUTTON_0 || pin == PIN_BUTTON_1 || pin == PIN_BUTTON_2 || pin == PIN_BUTTON_3) {
|
||||||
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) {
|
|
||||||
uint buttonIndex;
|
uint buttonIndex;
|
||||||
switch (pin) {
|
switch (pin) {
|
||||||
case PIN_BUTTON_0:
|
case PIN_BUTTON_0:
|
||||||
@@ -268,12 +294,7 @@ void on_gpio_interrupt(uint pin, uint32_t eventMask) {
|
|||||||
case PIN_BUTTON_3:
|
case PIN_BUTTON_3:
|
||||||
buttonIndex = 3;
|
buttonIndex = 3;
|
||||||
}
|
}
|
||||||
auto buttonState = &buttonStates[buttonIndex];
|
struct PushButtonState *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);
|
|
||||||
if (buttonState->debounceAlarm != -1)
|
if (buttonState->debounceAlarm != -1)
|
||||||
cancel_alarm(buttonState->debounceAlarm);
|
cancel_alarm(buttonState->debounceAlarm);
|
||||||
buttonState->debounceAlarm =
|
buttonState->debounceAlarm =
|
||||||
@@ -282,25 +303,63 @@ 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)() {
|
||||||
(void)alarmId;
|
if (dma_hw->ints0 & (1u << adcDmaChannelA)) {
|
||||||
(void)userData;
|
dma_hw->ints0 = 1u << adcDmaChannelA;
|
||||||
if (hallSensorLastState != hallSensorPrevState) {
|
for (uint i = 0; i < 1600; ++i)
|
||||||
absolute_time_t now = get_absolute_time();
|
ss49e_process_sample(&wheelSensorState, adcBufferA[i]);
|
||||||
lastWheelTickTime = now;
|
float sum = 0.0f, max = 0.0f, min = 9999.0f;
|
||||||
++intervalWheelTicks[currentInterval];
|
for (uint i = 0; i < 1600; ++i) {
|
||||||
++totalTicks;
|
sum += adcBufferA[i];
|
||||||
|
if (adcBufferA[i] > max)
|
||||||
gpio_put(25, !gpio_get(25));
|
max = adcBufferA[i];
|
||||||
hallSensorPrevState = hallSensorLastState;
|
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) {
|
int64_t button_debounce_callback(alarm_id_t alarmId, void *userData) {
|
||||||
(void)alarmId;
|
(void)alarmId;
|
||||||
uint buttonIndex = (uint)userData;
|
uint buttonIndex = (uint)userData;
|
||||||
auto buttonState = &buttonStates[buttonIndex];
|
struct PushButtonState *buttonState = &buttonStates[buttonIndex];
|
||||||
bool currentState = !gpio_get(FRONT_BUTTON_PINS[buttonIndex]);
|
bool currentState = !gpio_get(FRONT_BUTTON_PINS[buttonIndex]);
|
||||||
if (currentState != buttonState->prevState) {
|
if (currentState != buttonState->prevState) {
|
||||||
buttonState->prevState = currentState;
|
buttonState->prevState = currentState;
|
||||||
@@ -323,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) {
|
int64_t button_hold_callback(alarm_id_t alarmId, void *userData) {
|
||||||
(void)alarmId;
|
(void)alarmId;
|
||||||
uint buttonIndex = (uint)userData;
|
uint buttonIndex = (uint)userData;
|
||||||
auto buttonState = &buttonStates[buttonIndex];
|
struct PushButtonState *buttonState = &buttonStates[buttonIndex];
|
||||||
buttonState->holdAlarm = -1;
|
buttonState->holdAlarm = -1;
|
||||||
buttonState->isHeld = true;
|
buttonState->isHeld = true;
|
||||||
on_button_long_press(buttonIndex);
|
on_button_long_press(buttonIndex);
|
||||||
@@ -331,14 +390,15 @@ int64_t button_hold_callback(alarm_id_t alarmId, void *userData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_button_short_press(uint button) {
|
void on_button_short_press(uint button) {
|
||||||
// beep(60, 900);
|
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
printf("button %i short press\n", button);
|
printf("button %i short press\n", button);
|
||||||
#endif
|
#endif
|
||||||
if (button == 3 && guiState.screen == MAIN_SCREEN) {
|
if (button == 3 && guiState.screen == MAIN_SCREEN) {
|
||||||
uint oldDispMode = guiState.screenState.mainScreen.displayMode;
|
uint oldDispMode = guiState.screenState.mainScreen.displayMode;
|
||||||
if (oldDispMode == DISPLAY_MODE_SPEED)
|
if (oldDispMode == DISPLAY_MODE_SPEED)
|
||||||
guiState.screenState.mainScreen.displayMode = DISPLAY_MODE_DISTANCE;
|
guiState.screenState.mainScreen.displayMode = DISPLAY_MODE_DISTANCE_FROM_POWER_ON;
|
||||||
|
else if (oldDispMode == DISPLAY_MODE_DISTANCE_FROM_POWER_ON)
|
||||||
|
guiState.screenState.mainScreen.displayMode = DISPLAY_MODE_TOTAL_DISTANCE;
|
||||||
else
|
else
|
||||||
guiState.screenState.mainScreen.displayMode = DISPLAY_MODE_SPEED;
|
guiState.screenState.mainScreen.displayMode = DISPLAY_MODE_SPEED;
|
||||||
guiState.screenState.mainScreen.displayModeChanged = true;
|
guiState.screenState.mainScreen.displayModeChanged = true;
|
||||||
@@ -346,7 +406,6 @@ void on_button_short_press(uint button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_button_long_press(uint button) {
|
void on_button_long_press(uint button) {
|
||||||
// beep(60, 1273);
|
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
printf("button %i long press\n");
|
printf("button %i long press\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -356,29 +415,19 @@ void on_button_long_press(uint button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool speed_measure_timer_callback(repeating_timer_t *rt) {
|
void on_wheel_hall_sensor_tick() {
|
||||||
(void)rt;
|
++intervalWheelTicks[currentInterval];
|
||||||
|
++totalWheelTicks;
|
||||||
|
++wheelTicksFromPowerOn;
|
||||||
|
printf("\t\t\tTICK\7\n");
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t sum = 0;
|
uint16_t color565_lerp(uint16_t a, uint16_t b, uint alphaPercent) {
|
||||||
/*
|
uint alphaComplement = 100 - alphaPercent;
|
||||||
printf("window: ");
|
uint16_t red = ((b >> 11) * alphaPercent + (a >> 11) * alphaComplement) / 100;
|
||||||
for (int i = 0; i < 16; ++i) {
|
uint16_t green = (((b >> 5) & 0x3F) * alphaPercent + ((a >> 5) & 0x3F) * alphaComplement) / 100;
|
||||||
sum += intervalWheelTicks[i];
|
uint16_t blue = ((b & 0x1F) * alphaPercent + (a & 0x1F) * alphaComplement) / 100;
|
||||||
if (currentInterval == i)
|
return blue | (green << 5) | (red << 11);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// speed is in "2.1" decimal fixed-point, in km/h
|
// speed is in "2.1" decimal fixed-point, in km/h
|
||||||
@@ -391,24 +440,23 @@ void draw_speed(uint value) {
|
|||||||
if (value > 999)
|
if (value > 999)
|
||||||
value = 999;
|
value = 999;
|
||||||
|
|
||||||
uint16_t color;
|
const uint16_t speedToColorX[] = {0, 50, 100, 150, 200, 300};
|
||||||
if (value >= 300)
|
const uint16_t speedToColorY[] = {0x04ff, 0x27fb, 0x6fe4, 0xdfe4, 0xfe84, 0xfd04};
|
||||||
color = 0xfd04;
|
const size_t speedToColorPointCount = 6;
|
||||||
else if (value >= 200)
|
|
||||||
color = 0xfe84;
|
|
||||||
else if (value >= 150)
|
|
||||||
color = 0xdfe4;
|
|
||||||
else if (value >= 100)
|
|
||||||
color = 0x6fe4;
|
|
||||||
else if (value >= 50)
|
|
||||||
color = 0x27fb;
|
|
||||||
else
|
|
||||||
color = 0x04ff;
|
|
||||||
|
|
||||||
lcd_draw_digit(value / 100, DIGITS_START_X, DIGITS_START_Y, color, 0x0000);
|
uint16_t color = speedToColorY[speedToColorPointCount - 1];
|
||||||
lcd_draw_digit((value / 10) % 10, DIGITS_START_X + DIGIT_WIDTH + DIGIT_SPACING, DIGITS_START_Y, color, 0x0000);
|
for (int i = 1; i < speedToColorPointCount; ++i) {
|
||||||
|
if (value <= speedToColorX[i]) {
|
||||||
|
color = color565_lerp(speedToColorY[i - 1], speedToColorY[i],
|
||||||
|
(value - speedToColorX[i - 1]) * 100 / (speedToColorX[i] - speedToColorX[i - 1]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lcd_draw_digit(value / 100, DIGITS_START_X, DIGITS_START_Y, color, 0x528a);
|
||||||
|
lcd_draw_digit((value / 10) % 10, DIGITS_START_X + DIGIT_WIDTH + DIGIT_SPACING, DIGITS_START_Y, color, 0x528a);
|
||||||
lcd_draw_decimal_point(DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING, DIGITS_START_Y + 101, color);
|
lcd_draw_decimal_point(DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING, DIGITS_START_Y + 101, color);
|
||||||
lcd_draw_digit(value % 10, DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + 5, DIGITS_START_Y, color, 0x0000);
|
lcd_draw_digit(value % 10, DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + 5, DIGITS_START_Y, color, 0x528a);
|
||||||
|
|
||||||
#undef DIGITS_START_X
|
#undef DIGITS_START_X
|
||||||
#undef DIGITS_START_Y
|
#undef DIGITS_START_Y
|
||||||
@@ -417,11 +465,11 @@ void draw_speed(uint value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// distance is in "2.3" decimal fixed-point, in kilometers
|
// distance is in "2.3" decimal fixed-point, in kilometers
|
||||||
void draw_distance(uint value) {
|
void draw_short_term_distance(uint value) {
|
||||||
#define DIGITS_START_X 20
|
#define DIGITS_START_X 20
|
||||||
#define DIGITS_START_Y 37
|
#define DIGITS_START_Y 37
|
||||||
#define SMALL_DIGITS_Y_OFFSET 28
|
#define SMALL_DIGITS_Y_OFFSET 28
|
||||||
#define XSMALL_DIGITS_Y_OFFSET 28
|
#define XSMALL_DIGITS_Y_OFFSET 60
|
||||||
#define DIGIT_WIDTH 64
|
#define DIGIT_WIDTH 64
|
||||||
#define SMALL_DIGIT_WIDTH 48
|
#define SMALL_DIGIT_WIDTH 48
|
||||||
#define XSMALL_DIGIT_WIDTH 30
|
#define XSMALL_DIGIT_WIDTH 30
|
||||||
@@ -432,28 +480,64 @@ void draw_distance(uint value) {
|
|||||||
if (value > 99999)
|
if (value > 99999)
|
||||||
value = 99999;
|
value = 99999;
|
||||||
|
|
||||||
lcd_draw_digit(value / 10000, DIGITS_START_X, DIGITS_START_Y, 0xffff, 0x0000);
|
lcd_draw_digit(value / 10000, DIGITS_START_X, DIGITS_START_Y, 0xffff, 0x528a);
|
||||||
lcd_draw_digit((value / 1000) % 10, DIGITS_START_X + DIGIT_WIDTH + DIGIT_SPACING, DIGITS_START_Y, 0xffff, 0x0000);
|
lcd_draw_digit((value / 1000) % 10, DIGITS_START_X + DIGIT_WIDTH + DIGIT_SPACING, DIGITS_START_Y, 0xffff, 0x528a);
|
||||||
lcd_draw_decimal_point(DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING, DIGITS_START_Y + 101, 0xffff);
|
lcd_draw_decimal_point(DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING, DIGITS_START_Y + 101, 0xffff);
|
||||||
lcd_draw_small_digit((value / 100) % 10, DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + 10,
|
lcd_draw_small_digit((value / 100) % 10, DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + 10,
|
||||||
DIGITS_START_Y + SMALL_DIGITS_Y_OFFSET, 0xffff, 0x0000);
|
DIGITS_START_Y + SMALL_DIGITS_Y_OFFSET, 0xffff, 0x528a);
|
||||||
lcd_draw_small_digit((value / 10) % 10,
|
lcd_draw_small_digit((value / 10) % 10,
|
||||||
DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + SMALL_DIGIT_WIDTH + SMALL_DIGIT_SPACING +
|
DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + SMALL_DIGIT_WIDTH + SMALL_DIGIT_SPACING +
|
||||||
10,
|
10,
|
||||||
DIGITS_START_Y + SMALL_DIGITS_Y_OFFSET, 0xffff, 0x0000);
|
DIGITS_START_Y + SMALL_DIGITS_Y_OFFSET, 0xffff, 0x528a);
|
||||||
lcd_draw_xsmall_digit(value % 10,
|
lcd_draw_xsmall_digit(value % 10,
|
||||||
DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + SMALL_DIGIT_WIDTH * 2 +
|
DIGITS_START_X + DIGIT_WIDTH * 2 + DIGIT_SPACING * 2 + SMALL_DIGIT_WIDTH * 2 +
|
||||||
SMALL_DIGIT_SPACING + XSMALL_DIGIT_SPACING + 10,
|
SMALL_DIGIT_SPACING * 2 + 10,
|
||||||
DIGITS_START_Y + XSMALL_DIGITS_Y_OFFSET, 0xffff, 0x0000);
|
DIGITS_START_Y + XSMALL_DIGITS_Y_OFFSET, 0xffff, 0x528a);
|
||||||
|
|
||||||
#undef DIGITS_START_X
|
#undef DIGITS_START_X
|
||||||
#undef DIGITS_START_Y
|
#undef DIGITS_START_Y
|
||||||
#undef DIGIT_WIDTH
|
#undef DIGIT_WIDTH
|
||||||
#undef DIGIT_SPACING
|
#undef DIGIT_SPACING
|
||||||
|
#undef XSMALL_DIGITS_Y_OFFSET
|
||||||
|
}
|
||||||
|
|
||||||
|
// long term distance is in "4.2" decimal fixed-point, in kilometers
|
||||||
|
void draw_long_term_distance(uint value) {
|
||||||
|
#define DIGITS_START_X 15
|
||||||
|
#define DIGITS_START_Y 50
|
||||||
|
#define XSMALL_DIGITS_Y_OFFSET 32
|
||||||
|
#define XSMALL_DIGIT_WIDTH 30
|
||||||
|
#define XSMALL_DIGIT_SPACING 4
|
||||||
|
|
||||||
|
if (value > 999999)
|
||||||
|
value = 999999;
|
||||||
|
|
||||||
|
lcd_draw_small_digit(value / 100000, DIGITS_START_X, DIGITS_START_Y, 0xffff, 0x528a);
|
||||||
|
lcd_draw_small_digit((value / 10000) % 10, DIGITS_START_X + SMALL_DIGIT_WIDTH + SMALL_DIGIT_SPACING, DIGITS_START_Y,
|
||||||
|
0xffff, 0x528a);
|
||||||
|
lcd_draw_small_digit((value / 1000) % 10, DIGITS_START_X + SMALL_DIGIT_WIDTH * 2 + SMALL_DIGIT_SPACING * 2,
|
||||||
|
DIGITS_START_Y, 0xffff, 0x528a);
|
||||||
|
lcd_draw_small_digit((value / 100) % 10, DIGITS_START_X + SMALL_DIGIT_WIDTH * 3 + SMALL_DIGIT_SPACING * 3,
|
||||||
|
DIGITS_START_Y, 0xffff, 0x528a);
|
||||||
|
lcd_draw_decimal_point(DIGITS_START_X + SMALL_DIGIT_WIDTH * 4 + SMALL_DIGIT_SPACING * 4 - 6, DIGITS_START_Y + 76,
|
||||||
|
0xffff);
|
||||||
|
lcd_draw_xsmall_digit((value / 10) % 10, DIGITS_START_X + SMALL_DIGIT_WIDTH * 4 + SMALL_DIGIT_SPACING * 4 + 10,
|
||||||
|
DIGITS_START_Y + XSMALL_DIGITS_Y_OFFSET, 0xffff, 0x528a);
|
||||||
|
lcd_draw_xsmall_digit(value % 10,
|
||||||
|
DIGITS_START_X + SMALL_DIGIT_WIDTH * 4 + SMALL_DIGIT_SPACING * 4 + XSMALL_DIGIT_WIDTH +
|
||||||
|
XSMALL_DIGIT_SPACING + 10,
|
||||||
|
DIGITS_START_Y + XSMALL_DIGITS_Y_OFFSET, 0xffff, 0x528a);
|
||||||
|
|
||||||
|
#undef DIGITS_START_X
|
||||||
|
#undef DIGITS_START_Y
|
||||||
|
#undef XSMALL_DIGITS_Y_OFFSET
|
||||||
|
#undef XSMALL_DIGIT_WIDTH
|
||||||
|
#undef XSMALL_DIGIT_SPACING
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_lcd() {
|
void update_lcd() {
|
||||||
if (guiState.screen == MAIN_SCREEN) {
|
if (guiState.screen == MAIN_SCREEN) {
|
||||||
|
bool forceRedrawClock = guiState.screenState.mainScreen.displayModeChanged;
|
||||||
if (guiState.screenState.mainScreen.displayModeChanged) {
|
if (guiState.screenState.mainScreen.displayModeChanged) {
|
||||||
// lcd_fill_rectangle(49, 27, 213, 113, 0x0000);
|
// lcd_fill_rectangle(49, 27, 213, 113, 0x0000);
|
||||||
st7789_fill(0x0000);
|
st7789_fill(0x0000);
|
||||||
@@ -463,29 +547,43 @@ void update_lcd() {
|
|||||||
if (guiState.screenState.mainScreen.displayMode == DISPLAY_MODE_SPEED) {
|
if (guiState.screenState.mainScreen.displayMode == DISPLAY_MODE_SPEED) {
|
||||||
uint convertedSpeed = ticksPerWindow * cmphPerTpw / 10000;
|
uint convertedSpeed = ticksPerWindow * cmphPerTpw / 10000;
|
||||||
draw_speed(convertedSpeed);
|
draw_speed(convertedSpeed);
|
||||||
lcd_write_string("Скорость", 20, 0, 0xffff, 0x0000);
|
lcd_write_string("Скорость", 10, 0, 0xffff, 0x0000);
|
||||||
lcd_write_string("км/ч", 241, 126, 0xffff, 0x0000);
|
lcd_write_string("км/ч", 241, 126, 0xffff, 0x0000);
|
||||||
} else if (guiState.screenState.mainScreen.displayMode == DISPLAY_MODE_DISTANCE) {
|
} else if (guiState.screenState.mainScreen.displayMode == DISPLAY_MODE_DISTANCE_FROM_POWER_ON) {
|
||||||
uint convertedDistance = totalTicks * cmPerTick / 100;
|
uint convertedDistance = wheelTicksFromPowerOn * cmPerTick / 100;
|
||||||
draw_distance(convertedDistance);
|
draw_short_term_distance(convertedDistance);
|
||||||
lcd_write_string("Расстояние", 20, 0, 0xffff, 0x0000);
|
lcd_write_string("Текущий путь", 10, 0, 0xffff, 0x0000);
|
||||||
lcd_write_string("км", 280, 126, 0xffff, 0x0000);
|
lcd_write_string("км", 280, 37, 0xffff, 0x0000);
|
||||||
|
} else if (guiState.screenState.mainScreen.displayMode == DISPLAY_MODE_TOTAL_DISTANCE) {
|
||||||
|
uint convertedDistance = totalWheelTicks * cmPerTick / 1000;
|
||||||
|
draw_long_term_distance(convertedDistance);
|
||||||
|
lcd_write_string("Общий путь", 10, 0, 0xffff, 0x0000);
|
||||||
|
lcd_write_string("км", 280, 37, 0xffff, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (forceRedrawClock || guiState.drawnTimeHours != currentDatetime.hour ||
|
||||||
|
guiState.drawnTimeMinutes != currentDatetime.minute) {
|
||||||
|
lcd_fill_rectangle(305 - guiState.drawnTimeTextWidth, 0, guiState.drawnTimeTextWidth, 24, 0x0000);
|
||||||
|
guiState.drawnTimeHours = currentDatetime.hour;
|
||||||
|
guiState.drawnTimeMinutes = currentDatetime.minute;
|
||||||
char timeDisplay[6];
|
char timeDisplay[6];
|
||||||
memset(timeDisplay, ' ', sizeof(timeDisplay));
|
memset(timeDisplay, ' ', sizeof(timeDisplay));
|
||||||
timeDisplay[5] = 0;
|
timeDisplay[5] = 0;
|
||||||
sprintf(timeDisplay, "%i:%02i", currentDatetime.hour, currentDatetime.minute);
|
sprintf(timeDisplay, "%i:%02i", currentDatetime.hour, currentDatetime.minute);
|
||||||
lcd_write_string(timeDisplay, 320 - 20 - lcd_string_width(timeDisplay), 0, 0xffff, 0x0000);
|
lcd_write_string(timeDisplay, 305 - lcd_string_width(timeDisplay), 0, 0xffff, 0x0000);
|
||||||
lcd_fill_rectangle(320 - 160, 0, 140 - lcd_string_width(timeDisplay), 24, 0x0000);
|
guiState.drawnTimeTextWidth = lcd_string_width(timeDisplay);
|
||||||
|
}
|
||||||
} else if (guiState.screen == SETTINGS_SCREEN) {
|
} else if (guiState.screen == SETTINGS_SCREEN) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gui_init(struct GUIState *state) {
|
void gui_init(struct GUIState *state) {
|
||||||
state->screen = 0;
|
state->screen = 0;
|
||||||
state->screenState.mainScreen.displayMode = DISPLAY_MODE_DISTANCE;
|
state->screenState.mainScreen.displayMode = DISPLAY_MODE_DISTANCE_FROM_POWER_ON;
|
||||||
state->screenState.mainScreen.displayModeChanged = true;
|
state->screenState.mainScreen.displayModeChanged = true;
|
||||||
|
state->drawnTimeTextWidth = 0;
|
||||||
|
state->drawnTimeHours = 24;
|
||||||
|
state->drawnTimeMinutes = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_button_states() {
|
void init_button_states() {
|
||||||
@@ -509,7 +607,7 @@ void save_to_rtc() {
|
|||||||
static uint savedDistance;
|
static uint savedDistance;
|
||||||
uint8_t buffer[31];
|
uint8_t buffer[31];
|
||||||
memset(buffer, 0, 31);
|
memset(buffer, 0, 31);
|
||||||
uint newDistance = totalTicks * cmPerTick / 10;
|
uint newDistance = totalWheelTicks * cmPerTick / 10;
|
||||||
if (savedBefore && newDistance == savedDistance) {
|
if (savedBefore && newDistance == savedDistance) {
|
||||||
printf("skipped saving\n");
|
printf("skipped saving\n");
|
||||||
return;
|
return;
|
||||||
@@ -528,10 +626,6 @@ void save_to_rtc() {
|
|||||||
do {
|
do {
|
||||||
printf("\nattempting to write...\n");
|
printf("\nattempting to write...\n");
|
||||||
ds1302_set_write_protection(0);
|
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);
|
ds1302_write_ram_bulk(buffer, 31);
|
||||||
for (int i = 0; i < 30; ++i)
|
for (int i = 0; i < 30; ++i)
|
||||||
printf("%02x ", buffer[i]);
|
printf("%02x ", buffer[i]);
|
||||||
@@ -581,7 +675,7 @@ bool load_from_rtc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint savedDistance = *(uint *)(buffer + 0);
|
uint savedDistance = *(uint *)(buffer + 0);
|
||||||
totalTicks = savedDistance * 10 / cmPerTick;
|
totalWheelTicks = savedDistance * 10 / cmPerTick;
|
||||||
#ifdef LOGGING
|
#ifdef LOGGING
|
||||||
printf("successfully loaded data from RTC memory\n");
|
printf("successfully loaded data from RTC memory\n");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include "ss49e.h"
|
||||||
|
|
||||||
|
void ss49e_init(SS49E_State *self, enum MagnetPolarityType magnetPolarityType, ss49e_tick_callback_t tickCallback) {
|
||||||
|
self->workingPhase = SS49E_WORKING_PHASE_NORMAL;
|
||||||
|
self->tickCallback = tickCallback;
|
||||||
|
|
||||||
|
self->magnetPolType = magnetPolarityType;
|
||||||
|
const float level0 = 2445.0f / 4095.0f;
|
||||||
|
const float deviation = 380.0f / 4095.0f;
|
||||||
|
if (magnetPolarityType == MAGNET_POLTYPE_BIPOLAR) {
|
||||||
|
// self->threshold01 = level0 + deviation * 0.75;
|
||||||
|
// self->threshold10 = level0 - deviation * 0.75;
|
||||||
|
self->threshold01 = (2447.0 + 520.0 * 2.0 / 3.0) / 4095.0;
|
||||||
|
self->threshold10 = (2447.0 - 800.0 * 2.0 / 3.0) / 4095.0;
|
||||||
|
} else {
|
||||||
|
float activeLevel = level0 + (magnetPolarityType == MAGNET_POLTYPE_UNIPOLAR_POSITIVE ? deviation : -deviation);
|
||||||
|
self->threshold01 = level0 * 1 / 3 + activeLevel * 2 / 3;
|
||||||
|
self->threshold10 = activeLevel * 1 / 3 + level0 * 2 / 3;
|
||||||
|
}
|
||||||
|
self->currentLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ss49e_process_sample(SS49E_State *self, uint16_t sample) {
|
||||||
|
float normalized = (float)sample / 4095.0f;
|
||||||
|
if (self->currentLevel == 0) {
|
||||||
|
if (normalized >= self->threshold01) {
|
||||||
|
self->currentLevel = 1;
|
||||||
|
if (self->magnetPolType == MAGNET_POLTYPE_BIPOLAR || self->magnetPolType == MAGNET_POLTYPE_UNIPOLAR_POSITIVE)
|
||||||
|
self->tickCallback();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (normalized <= self->threshold10) {
|
||||||
|
self->currentLevel = 0;
|
||||||
|
if (self->magnetPolType == MAGNET_POLTYPE_BIPOLAR || self->magnetPolType == MAGNET_POLTYPE_UNIPOLAR_NEGATIVE)
|
||||||
|
self->tickCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef VELOMETER_SS49E_H
|
||||||
|
#define VELOMETER_SS49E_H
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum SS49E_WorkingPhase {
|
||||||
|
SS49E_WORKING_PHASE_NORMAL,
|
||||||
|
SS49E_WORKING_PHASE_CALIBRATING,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MagnetPolarityType {
|
||||||
|
MAGNET_POLTYPE_BIPOLAR,
|
||||||
|
MAGNET_POLTYPE_UNIPOLAR_POSITIVE,
|
||||||
|
MAGNET_POLTYPE_UNIPOLAR_NEGATIVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ss49e_tick_callback_t)();
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum SS49E_WorkingPhase workingPhase;
|
||||||
|
enum MagnetPolarityType magnetPolType;
|
||||||
|
ss49e_tick_callback_t tickCallback;
|
||||||
|
float threshold01, threshold10;
|
||||||
|
bool currentLevel;
|
||||||
|
} SS49E_State;
|
||||||
|
|
||||||
|
void ss49e_init(SS49E_State *self, enum MagnetPolarityType magnetPolarityType, ss49e_tick_callback_t tickCallback);
|
||||||
|
void ss49e_process_sample(SS49E_State *self, uint16_t sample);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user