This commit is contained in:
Klaus K Wilting 2019-02-15 14:08:27 +01:00
parent 1ac176075a
commit 91889a2af8
10 changed files with 43 additions and 94 deletions

View File

@ -43,6 +43,9 @@
#define I2C_MUTEX_LOCK() xSemaphoreTake(I2Caccess, (3 * DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == pdTRUE #define I2C_MUTEX_LOCK() xSemaphoreTake(I2Caccess, (3 * DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) == pdTRUE
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(I2Caccess) #define I2C_MUTEX_UNLOCK() xSemaphoreGive(I2Caccess)
// time pulse frequency 1Hz
#define PPS (1000)
// Struct holding devices's runtime configuration // Struct holding devices's runtime configuration
typedef struct { typedef struct {
uint8_t lorasf; // 7-12, lora spreadfactor uint8_t lorasf; // 7-12, lora spreadfactor

View File

@ -22,7 +22,7 @@ void sync_rtctime(void);
time_t get_rtctime(void); time_t get_rtctime(void);
float get_rtctemp(void); float get_rtctemp(void);
void IRAM_ATTR CLOCKIRQ(); void IRAM_ATTR CLOCKIRQ();
int timepulse_init(uint32_t pps_freq); int timepulse_init(void);
void timepulse_start(); void timepulse_start();
void sync_clock(void); void sync_clock(void);

View File

@ -30,7 +30,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
[common] [common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c" ; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
release_version = 1.7.2 release_version = 1.7.24
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 0 debug_level = 0
@ -40,17 +40,17 @@ upload_protocol = esptool
extra_scripts = pre:build.py extra_scripts = pre:build.py
keyfile = ota.conf keyfile = ota.conf
platform_espressif32 = espressif32@1.6.0 platform_espressif32 = espressif32@1.6.0
;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage
board_build.partitions = min_spiffs.csv board_build.partitions = min_spiffs.csv
monitor_speed = 115200 monitor_speed = 115200
lib_deps_lora = lib_deps_lora =
MCCI LoRaWAN LMIC library@^2.3.1 MCCI LoRaWAN LMIC library@>=2.3.2
lib_deps_display = lib_deps_display =
U8g2@>=2.25.7 U8g2@>=2.25.7
lib_deps_rgbled = lib_deps_rgbled =
SmartLeds@>=1.1.5 SmartLeds@>=1.1.5
lib_deps_gps = lib_deps_gps =
TinyGPSPlus@>=1.0.2 TinyGPSPlus@>=1.0.2
; NeoGPS^4.2.9
lib_deps_rtc = lib_deps_rtc =
RTC@^2.3.0 RTC@^2.3.0
lib_deps_basic = lib_deps_basic =

View File

@ -22,15 +22,6 @@ bool volatile BitsPending = false;
#define DCF77_FRAME_SIZE (60) #define DCF77_FRAME_SIZE (60)
#define DCF77_PULSE_DURATION (100) #define DCF77_PULSE_DURATION (100)
// select internal / external clock
#if defined RTC_INT && defined RTC_CLK
#define PPS RTC_CLK
#elif defined GPS_INT && defined GPS_CLK
#define PPS GPS_CLK
#else
#define PPS DCF77_PULSE_DURATION
#endif
// array of dcf pulses for three minutes // array of dcf pulses for three minutes
uint8_t DCFtimeframe[DCF77_FRAME_SIZE]; uint8_t DCFtimeframe[DCF77_FRAME_SIZE];
@ -39,7 +30,7 @@ int dcf77_init(void) {
pinMode(HAS_DCF77, OUTPUT); pinMode(HAS_DCF77, OUTPUT);
set_DCF77_pin(dcf_low); set_DCF77_pin(dcf_low);
timepulse_init(PPS); // setup timepulse timepulse_init(); // setup timepulse
xTaskCreatePinnedToCore(dcf77_loop, // task function xTaskCreatePinnedToCore(dcf77_loop, // task function
"dcf77loop", // name of task "dcf77loop", // name of task
@ -129,19 +120,18 @@ void dcf77_loop(void *pvParameters) {
&wakeTime, // receives moment of call from isr &wakeTime, // receives moment of call from isr
portMAX_DELAY); // wait forever (missing error handling here...) portMAX_DELAY); // wait forever (missing error handling here...)
// select clock scale // select clock scale
#if (PPS == DCF77_PULSE_DURATION) // we don't need clock rescaling #if (PPS == DCF77_PULSE_DURATION) // we don't need clock rescaling
DCF_Out(0); DCF_Out(0);
#elif (PPS > DCF77_PULSE_DURATION) // we need upclocking #elif (PPS > DCF77_PULSE_DURATION) // we need upclocking
for (uint8_t i = 1; i <= PPS / DCF77_PULSE_DURATION; i++) { for (uint8_t i = 1; i <= PPS / DCF77_PULSE_DURATION; i++) {
DCF_Out(0); DCF_Out(0);
vTaskDelayUntil(&wakeTime, pdMS_TO_TICKS(DCF77_PULSE_DURATION)); vTaskDelayUntil(&wakeTime, pdMS_TO_TICKS(DCF77_PULSE_DURATION));
} }
#else // we need downclocking, not yet implemented
#elif (PPS < DCF77_PULSE_DURATION) // we need downclocking, not yet implemented #error Timepulse too fast for DCF77 emulator
#error Timepulse is too low for DCF77!
#endif #endif
} // for } // for
} // dcf77_loop() } // dcf77_loop()

View File

@ -44,7 +44,6 @@
#define HAS_GPS 1 // use on board GPS #define HAS_GPS 1 // use on board GPS
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M #define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M
#define GPS_INT GPIO_NUM_34 // 30ns accurary timepulse, to be external wired on pcb: NEO 6M Pin#3 -> GPIO34 #define GPS_INT GPIO_NUM_34 // 30ns accurary timepulse, to be external wired on pcb: NEO 6M Pin#3 -> GPIO34
#define GPS_CLK (1000) // pulse length 100ms, accuracy +/- 3 *e-8 [nanoseconds] = 0,95sec / year
// Pins for I2C interface of OLED Display // Pins for I2C interface of OLED Display
#define MY_OLED_SDA (4) #define MY_OLED_SDA (4)
@ -54,7 +53,6 @@
// Settings for on board DS3231 RTC chip // Settings for on board DS3231 RTC chip
#define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL #define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL
#define RTC_INT GPIO_NUM_34 // timepulse with accuracy +/- 2*e-6 [microseconds] = 0,1728sec / day #define RTC_INT GPIO_NUM_34 // timepulse with accuracy +/- 2*e-6 [microseconds] = 0,1728sec / day
#define RTC_CLK (1000) // pulse length 1000ms
// Settings for IF482 interface // Settings for IF482 interface
//#define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters //#define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters

View File

@ -21,10 +21,9 @@
#define BATT_FACTOR 2 // voltage divider 100k/100k on board #define BATT_FACTOR 2 // voltage divider 100k/100k on board
// GPS settings // GPS settings
#define HAS_GPS 1 // use on board GPS //#define HAS_GPS 1 // use on board GPS
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M //#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M
//#define GPS_INT GPIO_NUM_34 // 30ns accurary timepulse, to be external wired on pcb: NEO 6M Pin#3 -> GPIO34 //#define GPS_INT GPIO_NUM_34 // 30ns accurary timepulse, to be external wired on pcb: NEO 6M Pin#3 -> GPIO34
//#define GPS_CLK (1000) // pulse length 100ms, accuracy +/- 3 *e-8 [nanoseconds] = 0,95sec / year
// enable only if device has these sensors, otherwise comment these lines // enable only if device has these sensors, otherwise comment these lines
// BME680 sensor on I2C bus // BME680 sensor on I2C bus

View File

@ -22,8 +22,7 @@
// Settings for on board DS3231 RTC chip // Settings for on board DS3231 RTC chip
#define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL #define HAS_RTC MY_OLED_SDA, MY_OLED_SCL // SDA, SCL
//#define RTC_INT GPIO_NUM_34 // timepulse with accuracy +/- 2*e-6 [microseconds] = 0,1728sec / day #define RTC_INT GPIO_NUM_34 // timepulse with accuracy +/- 2*e-6 [microseconds] = 0,1728sec / day
//#define RTC_CLK (1000) // pulse length 1000ms
// Settings for IF482 interface // Settings for IF482 interface
//#define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters //#define HAS_IF482 9600, SERIAL_7E1, GPIO_NUM_12, GPIO_NUM_14 // IF482 serial port parameters

View File

@ -91,15 +91,6 @@ static const char TAG[] = "main";
#define IF482_FRAME_SIZE (17) #define IF482_FRAME_SIZE (17)
#define IF482_PULSE_DURATION (1000) #define IF482_PULSE_DURATION (1000)
// select internal / external clock
#if defined RTC_INT && defined RTC_CLK
#define PPS RTC_CLK
#elif defined GPS_INT && defined GPS_CLK
#define PPS GPS_CLK
#else
#define PPS IF482_PULSE_DURATION
#endif
HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS) HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS)
// initialize and configure IF482 Generator // initialize and configure IF482 Generator
@ -108,7 +99,7 @@ int if482_init(void) {
// open serial interface // open serial interface
IF482.begin(HAS_IF482); IF482.begin(HAS_IF482);
// setup timepulse // setup timepulse
timepulse_init(PPS); timepulse_init();
// start if482 serial output feed task // start if482 serial output feed task
xTaskCreatePinnedToCore(if482_loop, // task function xTaskCreatePinnedToCore(if482_loop, // task function
@ -165,8 +156,8 @@ void if482_loop(void *pvParameters) {
// phase 1: sync task on top of second // phase 1: sync task on top of second
const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
sync_clock(); // delay until top of second sync_clock(); // delay until top of second
timepulse_start(); // start timepulse timepulse_start(); // start timepulse
xTaskNotifyWait( xTaskNotifyWait(
0x00, // don't clear any bits on entry 0x00, // don't clear any bits on entry
@ -200,9 +191,10 @@ void if482_loop(void *pvParameters) {
IF482.print(IF482_Out(now() + 1)); IF482.print(IF482_Out(now() + 1));
} }
#elif (PPS < IF482_PULSE_DURATION) // we need downclocking, not yet implemented #else // we need downclocking, not yet implemented
#error Timepulse is too low for IF482! #error Timepulse too fast for IF482 generator
#endif #endif
} // forever } // forever
} // if482_loop() } // if482_loop()

View File

@ -338,7 +338,7 @@ void setup() {
#ifdef HAS_RTC #ifdef HAS_RTC
strcat_P(features, " RTC"); strcat_P(features, " RTC");
assert(rtc_init()); assert(rtc_init());
setSyncProvider(&get_rtctime); // sync time now and then setSyncProvider(get_rtctime); // sync time now and then
if (timeStatus() != timeSet) if (timeStatus() != timeSet)
ESP_LOGI(TAG, "Unable to sync system time with RTC"); ESP_LOGI(TAG, "Unable to sync system time with RTC");
else else
@ -350,7 +350,7 @@ void setup() {
strcat_P(features, " DCF77"); strcat_P(features, " DCF77");
#endif #endif
#if (defined HAS_IF482) && (defined RTC_INT) #if defined HAS_IF482 && defined RTC_INT
strcat_P(features, " IF482"); strcat_P(features, " IF482");
#endif #endif
@ -416,7 +416,7 @@ void setup() {
#endif // HAS_BUTTON #endif // HAS_BUTTON
#ifdef HAS_GPS #ifdef HAS_GPS
setSyncProvider(&get_gpstime); // sync time now and then setSyncProvider(get_gpstime); // sync time now and then
if (timeStatus() != timeSet) if (timeStatus() != timeSet)
ESP_LOGI(TAG, "Unable to sync system time with GPS"); ESP_LOGI(TAG, "Unable to sync system time with GPS");
else { else {

View File

@ -1,7 +1,5 @@
#include "rtctime.h" #include "rtctime.h"
#define I2C_DELAY (12) // 12ms is i2c delay when saving time to RTC chip
// Local logging tag // Local logging tag
static const char TAG[] = "main"; static const char TAG[] = "main";
@ -9,45 +7,31 @@ TaskHandle_t ClockTask;
hw_timer_t *clockCycle = NULL; hw_timer_t *clockCycle = NULL;
bool volatile TimePulseTick = false; bool volatile TimePulseTick = false;
// helper function to setup a pulse for time synchronisation // helper function to setup a pulse per second for time synchronisation
int timepulse_init(uint32_t pulse_period_ms) { int timepulse_init() {
// use time pulse from GPS as time base with fixed 1Hz frequency // use time pulse from GPS as time base with fixed 1Hz frequency
#if defined GPS_INT && defined GPS_CLK #ifdef GPS_INT
// setup external interupt for active low RTC INT pin // setup external interupt for active low RTC INT pin
pinMode(GPS_INT, INPUT_PULLDOWN); pinMode(GPS_INT, INPUT_PULLDOWN);
// setup external rtc 1Hz clock as pulse per second clock // setup external rtc 1Hz clock as pulse per second clock
ESP_LOGI(TAG, "Time base: GPS timepulse"); ESP_LOGI(TAG, "Time base: GPS timepulse");
switch (GPS_CLK) {
case 1000:
break; // default GPS timepulse 1000ms
default:
goto pulse_period_error;
}
return 1; // success return 1; // success
// use pulse from on board RTC chip as time base with fixed frequency // use pulse from on board RTC chip as time base with fixed frequency
#elif defined RTC_INT && defined RTC_CLK #elif defined RTC_INT
// setup external interupt for active low RTC INT pin // setup external interupt for active low RTC INT pin
pinMode(RTC_INT, INPUT_PULLUP); pinMode(RTC_INT, INPUT_PULLUP);
// setup external rtc 1Hz clock as pulse per second clock // setup external rtc 1Hz clock as pulse per second clock
ESP_LOGI(TAG, "Time base: external RTC timepulse");
if (I2C_MUTEX_LOCK()) { if (I2C_MUTEX_LOCK()) {
switch (RTC_CLK) { Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
case 1000: // 1000ms
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
break;
case 1: // 1ms
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1kHz);
break;
default:
I2C_MUTEX_UNLOCK();
goto pulse_period_error;
}
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock); Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
I2C_MUTEX_UNLOCK(); I2C_MUTEX_UNLOCK();
ESP_LOGI(TAG, "Time base: external RTC timepulse");
return 1; // success
} else { } else {
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error"); ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
return 0; // failure return 0; // failure
@ -56,22 +40,14 @@ int timepulse_init(uint32_t pulse_period_ms) {
#else #else
// use ESP32 hardware timer as time base with adjustable frequency // use ESP32 hardware timer as time base with adjustable frequency
if (pulse_period_ms) { clockCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
ESP_LOGI(TAG, "Time base: ESP32 hardware timer"); timerAttachInterrupt(clockCycle, &CLOCKIRQ, true);
clockCycle = timerAlarmWrite(clockCycle, 10000, true); // 1000ms
timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec ESP_LOGI(TAG, "Time base: ESP32 hardware timer");
timerAttachInterrupt(clockCycle, &CLOCKIRQ, true);
timerAlarmWrite(clockCycle, 10 * pulse_period_ms, true); // ms
} else
goto pulse_period_error;
return 1; // success return 1; // success
#endif #endif
} // timepulse_init
pulse_period_error:
ESP_LOGE(TAG, "Unknown timepulse period value");
return 0; // failure
}
void timepulse_start(void) { void timepulse_start(void) {
#ifdef GPS_INT // start external clock gps pps line #ifdef GPS_INT // start external clock gps pps line
@ -83,21 +59,13 @@ void timepulse_start(void) {
#endif #endif
} }
// helper function to sync time_t of top of next second // helper function to sync time_t of top of a second
void sync_clock(void) { void sync_clock(void) {
// do we have a second time pulse? Then wait for next pulse
#if defined(RTC_INT) || defined(GPS_INT)
// sync on top of next second by timepulse // sync on top of next second by timepulse
if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE) { if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(PPS)) == pdTRUE)
ESP_LOGI(TAG, "clock synced by timepulse"); ESP_LOGI(TAG, "clock synced by timepulse");
return; else
} else ESP_LOGW(TAG, "Missing timepulse, clock not synced");
ESP_LOGW(TAG, "Missing timepulse, thus clock can't be synced by second");
#endif
// no external timepulse, thus we must use less precise internal system clock
while (millis() % 1000)
; // wait for milli seconds to be zero before setting new time
ESP_LOGI(TAG, "clock synced by systime");
return; return;
} }
@ -105,8 +73,8 @@ void sync_clock(void) {
// timer // timer
void IRAM_ATTR CLOCKIRQ() { void IRAM_ATTR CLOCKIRQ() {
xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL); xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
#if defined(GPS_INT) || defined(RTC_INT) #if defined GPS_INT || defined RTC_INT
xSemaphoreGiveFromISR(TimePulse, pdFALSE); xSemaphoreGiveFromISR(TimePulse, NULL);
TimePulseTick = !TimePulseTick; // flip ticker TimePulseTick = !TimePulseTick; // flip ticker
#endif #endif
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();