Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
src/gps.c
src/int.c
src/menu.c
src/mcu_time.c
)


Expand Down
25 changes: 25 additions & 0 deletions src/gps.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "stm32f1xx_hal_uart.h"
#include "usart.h"
#include "eeprom.h"
#include "mcu_time.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -394,6 +395,30 @@ void gps_parse(char* line)
// Terminaute time string
gps_time[8] = '\0';

// Sync MCU time with compensated/timezone-adjusted GPS time
{
char mcu_sync_time[sizeof(gps_time)];
memcpy(mcu_sync_time, gps_time, sizeof(gps_time));
// Remove the +1s PPS compensation before syncing MCU time
// to avoid double-counting with TIM2 ISR increment
{
int hour = (mcu_sync_time[0]-'0') * 10 + (mcu_sync_time[1]-'0');
int min = (mcu_sync_time[3]-'0') * 10 + (mcu_sync_time[4]-'0');
int sec = (mcu_sync_time[6]-'0') * 10 + (mcu_sync_time[7]-'0');
sec--;
if(sec < 0) { sec = 59; min--; }
if(min < 0) { min = 59; hour--; }
if(hour < 0) { hour = 23; }
mcu_sync_time[0] = (char)((hour/10)+'0');
mcu_sync_time[1] = (char)((hour%10)+'0');
mcu_sync_time[3] = (char)((min/10)+'0');
mcu_sync_time[4] = (char)((min%10)+'0');
mcu_sync_time[6] = (char)((sec/10)+'0');
mcu_sync_time[7] = (char)((sec%10)+'0');
}
mcu_time_sync_from_string(mcu_sync_time, true);
}

pch = strtok(NULL, ","); // Latitude
gps_latitude_double = gps_parse_coordinate(pch,gps_latitude,sizeof(gps_latitude));
pch = strtok(NULL, ","); // N/S
Expand Down
3 changes: 3 additions & 0 deletions src/int.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "frequency.h"
#include "tim.h"
#include "menu.h"
#include "mcu_time.h"
#include <stdlib.h>
#include <string.h>

Expand Down Expand Up @@ -73,6 +74,8 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
pps_led_toogle = !pps_led_toogle;
// Update uptime
device_uptime++;
// Increment MCU time-of-day (drives display during flywheel)
mcu_time_increment();

if(HAL_GetTick() - last_pps > 1500)
{ // No GPS PPS output, blink 'x' icon
Expand Down
5 changes: 4 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "menu.h"
#include "int.h"
#include "tim.h"
#include "mcu_time.h"
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
Expand All @@ -18,7 +19,6 @@

void gpsdo(void)
{
HAL_TIM_Base_Start_IT(&htim2);

EE_Init(&ee_storage, sizeof(ee_storage_t));
EE_Read();
Expand Down Expand Up @@ -102,6 +102,9 @@ void gpsdo(void)
ee_storage.gps_time_offset = -MIN_TIME_OFFSET;
}
gps_time_offset = ee_storage.gps_time_offset+MIN_TIME_OFFSET;
// Initialize MCU timekeeping before enabling TIM2 ISR
mcu_time_init((int8_t)gps_time_offset);
HAL_TIM_Base_Start_IT(&htim2);
if (ee_storage.gps_date_format == 0xff) {
ee_storage.gps_date_format = DATE_FORMAT_UTC;
}
Expand Down
115 changes: 115 additions & 0 deletions src/mcu_time.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "mcu_time.h"
#include <string.h>

volatile mcu_time_t mcu_time;
volatile char mcu_time_string[9];
volatile bool mcu_time_dirty = false;

static void fmt_time(char* buf, uint8_t h, uint8_t m, uint8_t s) {
buf[0] = '0' + (h / 10); buf[1] = '0' + (h % 10);
buf[2] = ':';
buf[3] = '0' + (m / 10); buf[4] = '0' + (m % 10);
buf[5] = ':';
buf[6] = '0' + (s / 10); buf[7] = '0' + (s % 10);
buf[8] = '\0';
}

void mcu_time_init(int8_t initial_tz_offset) {
mcu_time.hours = 0;
mcu_time.minutes = 0;
mcu_time.seconds = 0;
mcu_time.timezone_offset = initial_tz_offset;
mcu_time.gps_disciplined = false;
mcu_time.seconds_since_gps = 0;

char tmp[9];
fmt_time(tmp, 0, 0, 0);
memcpy((void*)mcu_time_string, tmp, sizeof(tmp));
mcu_time_dirty = false;
}

void mcu_time_increment(void) {
uint8_t h = mcu_time.hours;
uint8_t m = mcu_time.minutes;
uint8_t s = mcu_time.seconds;

// increment one second
s++;
if (s >= 60) {
s = 0;
m++;
if (m >= 60) {
m = 0;
h = (h + 1) % 24;
}
}

mcu_time.hours = h;
mcu_time.minutes = m;
mcu_time.seconds = s;

// track discipline age
if (mcu_time.seconds_since_gps < 0xFFFFFFFFu) {
mcu_time.seconds_since_gps++;
}

// minimally update formatted string (ISR-friendly)
char tmp[9];
fmt_time(tmp, h, m, s);
memcpy((void*)mcu_time_string, tmp, sizeof(tmp));
}

void mcu_time_sync_from_string(const char* str, bool formatted_hh_colon_mm_colon_ss) {
uint8_t h, m, s;
if (formatted_hh_colon_mm_colon_ss) {
// "HH:MM:SS"
h = (uint8_t)((str[0] - '0') * 10 + (str[1] - '0'));
m = (uint8_t)((str[3] - '0') * 10 + (str[4] - '0'));
s = (uint8_t)((str[6] - '0') * 10 + (str[7] - '0'));
} else {
// "HHMMSS"
h = (uint8_t)((str[0] - '0') * 10 + (str[1] - '0'));
m = (uint8_t)((str[2] - '0') * 10 + (str[3] - '0'));
s = (uint8_t)((str[4] - '0') * 10 + (str[5] - '0'));
}

if (h > 23) h = 0;
if (m > 59) m = 0;
if (s > 59) s = 0;

mcu_time.hours = h;
mcu_time.minutes = m;
mcu_time.seconds = s;

mcu_time.gps_disciplined = true;
mcu_time.seconds_since_gps = 0;

char tmp[9];
fmt_time(tmp, h, m, s);
memcpy((void*)mcu_time_string, tmp, sizeof(tmp));
}

void mcu_time_set(uint8_t h, uint8_t m, uint8_t s) {
h %= 24; m %= 60; s %= 60;
mcu_time.hours = h;
mcu_time.minutes = m;
mcu_time.seconds = s;

char tmp[9];
fmt_time(tmp, h, m, s);
memcpy((void*)mcu_time_string, tmp, sizeof(tmp));
}

void mcu_time_set_timezone(int8_t offset) {
mcu_time.timezone_offset = offset;
}

const char* mcu_time_get_status(void) {
if (mcu_time.gps_disciplined) {
if (mcu_time.seconds_since_gps <= 10) {
return "GPS-Sync";
}
return "GPS-Disc";
}
return "Free-Run";
}
41 changes: 41 additions & 0 deletions src/mcu_time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

// Simple MCU-maintained time-of-day, disciplined by GPS PPS via TIM2 ISR.
typedef struct {
uint8_t hours; // 0-23
uint8_t minutes; // 0-59
uint8_t seconds; // 0-59
int8_t timezone_offset; // -14..+14 hours (optional; not actively used yet)
bool gps_disciplined; // true if recently synced to GPS time
uint32_t seconds_since_gps; // seconds since last GPS sync
} mcu_time_t;

extern volatile mcu_time_t mcu_time;

// "HH:MM:SS\0" - keep updates atomic via memcpy of 9 bytes
extern volatile char mcu_time_string[9];

// Optional dirty flag if you prefer formatting outside ISR (not used by default)
extern volatile bool mcu_time_dirty;

// Initialize module. Provide initial timezone offset if desired (can pass 0).
void mcu_time_init(int8_t initial_tz_offset);

// Increment by one second (call from TIM2 PeriodElapsed ISR).
void mcu_time_increment(void);

// Sync time from a string:
// - If formatted_hh_colon_mm_colon_ss is true, expects "HH:MM:SS"
// - Otherwise expects "HHMMSS"
void mcu_time_sync_from_string(const char* str, bool formatted_hh_colon_mm_colon_ss);

// Manual setters (optional)
void mcu_time_set(uint8_t h, uint8_t m, uint8_t s);
void mcu_time_set_timezone(int8_t offset);

// Returns a static string literal describing discipline state:
// "GPS-Sync" (if synced within last 10s), "GPS-Disc" (synced, but older), or "Free-Run"
const char* mcu_time_get_status(void);
9 changes: 5 additions & 4 deletions src/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "stm32f1xx_hal_gpio.h"
#include "int.h"
#include "menu.h"
#include "mcu_time.h"

/// All times in ms
#define DEBOUNCE_TIME 50
Expand Down Expand Up @@ -418,7 +419,7 @@ static void menu_draw()
LCD_Puts(1, 0, screen_buffer);
if(current_menu_screen == SCREEN_MAIN)
{
LCD_Puts(0, 1, gps_time);
LCD_Puts(0, 1, (const char*)mcu_time_string);
}
else if(current_menu_screen == SCREEN_DATE)
{
Expand All @@ -430,7 +431,7 @@ static void menu_draw()
uint32_t duration = now - last_hour_date_screen_update;
if(duration <= DATE_TIME_DURATION)
{
LCD_Puts(0, 1, gps_time);
LCD_Puts(0, 1, (const char*)mcu_time_string);
}
else
{
Expand Down Expand Up @@ -638,7 +639,7 @@ static void menu_draw()
{
snprintf(screen_buffer, SCREEN_BUFFER_SIZE, "GPS:%02d\5", num_sats);
LCD_Puts(1, 0, screen_buffer);
LCD_Puts(0, 1, gps_time);
LCD_Puts(0, 1, (const char*)mcu_time_string);
}
else
{
Expand All @@ -649,7 +650,7 @@ static void menu_draw()
default:
case SCREEN_GPS_TIME:
LCD_Puts(1, 0, "Time:");
LCD_Puts(0, 1, gps_time);
LCD_Puts(0, 1, (const char*)mcu_time_string);
break;
case SCREEN_GPS_LATITUDE:
snprintf(screen_buffer, SCREEN_BUFFER_SIZE, "Lat.: %s", gps_n_s);
Expand Down