DCF77 & IF482 improvements
This commit is contained in:
1 parent
e1b6d9a04c
commit
bad5805810
7 files changed
+106
-122
No files matched your search
+10
-66
@@ -16,9 +16,6 @@ https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/Funkuhr.zip/
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
TaskHandle_t DCF77Task;
|
||||
hw_timer_t *dcfCycle = NULL;
|
||||
|
||||
#define DCF77_FRAME_SIZE (60)
|
||||
#define DCF77_PULSE_DURATION (100)
|
||||
|
||||
@@ -39,51 +36,19 @@ int dcf77_init(void) {
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
3, // priority of the task
|
||||
&DCF77Task, // task handle
|
||||
&ClockTask, // task handle
|
||||
0); // CPU core
|
||||
|
||||
assert(DCF77Task); // has dcf77 task started?
|
||||
assert(ClockTask); // has clock task started?
|
||||
|
||||
#ifdef RTC_INT // if we have hardware pps signal we use it as precise time base
|
||||
|
||||
#ifndef RTC_CLK // assure we know external clock freq
|
||||
#error "External clock cycle not defined in board hal file"
|
||||
#if defined RTC_INT && (RTC_CLK == DCF77_PULSE_DURATION)
|
||||
pps_init(); // use pps clock
|
||||
#else
|
||||
pps_init(DCF77_PULSE_DURATION); // use esp32 clock
|
||||
#endif
|
||||
|
||||
// setup external interupt for active low RTC INT pin
|
||||
pinMode(RTC_INT, INPUT_PULLUP);
|
||||
|
||||
// setup external rtc 1Hz clock for triggering DCF77 telegram
|
||||
ESP_LOGI(TAG, "Time base external clock");
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
||||
I2C_MUTEX_UNLOCK();
|
||||
} else {
|
||||
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
||||
return 0; // failure
|
||||
}
|
||||
|
||||
#else // if we don't have pps signal from RTC we use ESP32 hardware timer
|
||||
|
||||
#define RTC_CLK (DCF77_PULSE_DURATION) // setup clock cycle
|
||||
ESP_LOGI(TAG, "Time base ESP32 clock");
|
||||
dcfCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
|
||||
timerAttachInterrupt(dcfCycle, &DCF77IRQ, true);
|
||||
timerAlarmWrite(dcfCycle, 10 * RTC_CLK, true); // 100ms
|
||||
|
||||
#endif
|
||||
|
||||
// wait until beginning of next second, then kick off first DCF pulse and
|
||||
// start clock signal
|
||||
|
||||
DCF_Out(sync_clock(now()));
|
||||
|
||||
#ifdef RTC_INT // start external clock
|
||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), DCF77IRQ, FALLING);
|
||||
#else // start internal clock
|
||||
timerAlarmEnable(dcfCycle);
|
||||
#endif
|
||||
DCF_Out(sync_clock(now())); // sync DCF time on next second
|
||||
pps_start(); // start pulse
|
||||
|
||||
return 1; // success
|
||||
} // ifdcf77_init
|
||||
@@ -157,9 +122,8 @@ void dcf77_loop(void *pvParameters) {
|
||||
&wakeTime, // receives moment of call from isr
|
||||
portMAX_DELAY); // wait forever (missing error handling here...)
|
||||
|
||||
#if (RTC_CLK == DCF77_PULSE_DURATION)
|
||||
DCF_Out(0); // we don't need clock rescaling
|
||||
|
||||
#if !defined RTC_CLK || (RTC_CLK == DCF77_PULSE_DURATION) // we don't need clock rescaling
|
||||
DCF_Out(0);
|
||||
#else // we need clock rescaling by software timer
|
||||
for (uint8_t i = 1; i <= RTC_CLK / DCF77_PULSE_DURATION; i++) {
|
||||
DCF_Out(0);
|
||||
@@ -253,24 +217,4 @@ void set_DCF77_pin(dcf_pinstate state) {
|
||||
} // switch
|
||||
} // DCF77_pulse
|
||||
|
||||
// helper function to sync phase of DCF output signal to start of second t
|
||||
uint8_t sync_clock(time_t t) {
|
||||
time_t tt = t;
|
||||
|
||||
// delay until start of next second
|
||||
do {
|
||||
tt = now();
|
||||
} while (t == tt);
|
||||
|
||||
ESP_LOGI(TAG, "Sync on Sec %d", second(tt));
|
||||
|
||||
return second(tt);
|
||||
}
|
||||
|
||||
// interrupt service routine triggered by external interrupt or internal timer
|
||||
void IRAM_ATTR DCF77IRQ() {
|
||||
xTaskNotifyFromISR(DCF77Task, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
#endif // HAS_DCF77
|
||||
+21
-47
@@ -1,4 +1,4 @@
|
||||
#if defined HAS_IF482 && defined RTC_INT
|
||||
#if defined HAS_IF482
|
||||
|
||||
/* NOTE:
|
||||
The IF482 Generator needs an high precise 1 Hz clock signal which cannot be
|
||||
@@ -84,15 +84,16 @@ not evaluated by model BU-190
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
TaskHandle_t IF482Task;
|
||||
#define IF482_FRAME_SIZE (17)
|
||||
#define IF482_PULSE_DURATION (1000)
|
||||
|
||||
HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS)
|
||||
|
||||
// initialize and configure IF482 Generator
|
||||
int if482_init(void) {
|
||||
|
||||
// setup external interupt for active low RTC INT pin
|
||||
pinMode(RTC_INT, INPUT_PULLUP);
|
||||
// open serial interface
|
||||
IF482.begin(HAS_IF482);
|
||||
|
||||
// start if482 serial output feed task
|
||||
xTaskCreatePinnedToCore(if482_loop, // task function
|
||||
@@ -100,49 +101,26 @@ int if482_init(void) {
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
3, // priority of the task
|
||||
&IF482Task, // task handle
|
||||
&ClockTask, // task handle
|
||||
0); // CPU core
|
||||
|
||||
assert(IF482Task); // has if482loop task started?
|
||||
assert(ClockTask); // has clock task started?
|
||||
|
||||
// open serial interface
|
||||
IF482.begin(HAS_IF482);
|
||||
|
||||
// if we have hardware pps signal we use it as precise time base
|
||||
#ifdef RTC_INT
|
||||
// assure we know clock freq
|
||||
#ifndef RTC_CLK
|
||||
#error "No RTC clock cycle defined in board hal file"
|
||||
#endif
|
||||
// use external rtc 1Hz clock for triggering IF482 telegram
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
||||
I2C_MUTEX_UNLOCK();
|
||||
} else {
|
||||
ESP_LOGE(TAG, "I2c bus busy - IF482 initialization error");
|
||||
return 0; // failure
|
||||
}
|
||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), IF482IRQ, FALLING);
|
||||
|
||||
// no RTC, thus we use less precise ESP32 hardware timer
|
||||
#if defined RTC_INT && (RTC_CLK == IF482_PULSE_DURATION)
|
||||
pps_init(); // use pps clock
|
||||
#else
|
||||
// setup 1000ms clock signal for IF482 generator using esp32 hardware timer 1
|
||||
ESP_LOGD(TAG, "Starting IF482 pulse...");
|
||||
dcfCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
|
||||
timerAttachInterrupt(dcfCycle, &IF482IRQ, true);
|
||||
timerAlarmWrite(dcfCycle, 10000, true); // 1000ms cycle
|
||||
timerAlarmEnable(dcfCycle);
|
||||
pps_init(IF482_PULSE_DURATION); // use esp32 clock
|
||||
#endif
|
||||
|
||||
pps_start(); // start pulse
|
||||
|
||||
return 1; // success
|
||||
|
||||
} // if482_init
|
||||
|
||||
String IF482_Out(time_t tt) {
|
||||
|
||||
time_t t = myTZ.toLocal(tt);
|
||||
char mon, buf[14], out[17];
|
||||
char mon, buf[14], out[IF482_FRAME_SIZE];
|
||||
|
||||
switch (timeStatus()) { // indicates if time has been set and recently synced
|
||||
case timeSet: // time is set and is synced
|
||||
@@ -179,12 +157,7 @@ void if482_loop(void *pvParameters) {
|
||||
pdMS_TO_TICKS(IF482_OFFSET); // duration of telegram transmit
|
||||
const TickType_t startTime = xTaskGetTickCount(); // now
|
||||
|
||||
// wait until begin of a new second
|
||||
t = tt = now();
|
||||
do {
|
||||
tt = now();
|
||||
} while (t == tt);
|
||||
|
||||
sync_clock(now()); // wait until begin of a new second
|
||||
BitsPending = true; // start blink in display
|
||||
|
||||
// take timestamp at moment of start of new second
|
||||
@@ -198,17 +171,18 @@ void if482_loop(void *pvParameters) {
|
||||
&wakeTime, // receives moment of call from isr
|
||||
portMAX_DELAY); // wait forever (missing error handling here...)
|
||||
|
||||
#if !defined RTC_CLK || (RTC_CLK == IF482_PULSE_DURATION) // we don't need clock rescaling
|
||||
// now we're synced to start of second tt and wait
|
||||
// until it's time to start transmit telegram for tt+1
|
||||
vTaskDelayUntil(&wakeTime, shotTime); // sets waketime to moment of shot
|
||||
IF482.print(IF482_Out(now() + 1));
|
||||
|
||||
#else // we need clock rescaling by software timer
|
||||
/*
|
||||
not yet implemented for IF482
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
} // if482_loop()
|
||||
|
||||
// interrupt service routine triggered by RTC 1Hz precise clock
|
||||
void IRAM_ATTR IF482IRQ() {
|
||||
xTaskNotifyFromISR(IF482Task, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
#endif // HAS_IF482
|
||||
@@ -7,6 +7,9 @@ static const char TAG[] = "main";
|
||||
|
||||
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
|
||||
|
||||
TaskHandle_t ClockTask;
|
||||
hw_timer_t *clockCycle = NULL;
|
||||
|
||||
// initialize RTC
|
||||
int rtc_init(void) {
|
||||
|
||||
@@ -97,4 +100,65 @@ float get_rtctemp(void) {
|
||||
return 0;
|
||||
} // get_rtctemp()
|
||||
|
||||
int pps_init() {
|
||||
// we have hardware pps signal as time base
|
||||
#if defined RTC_INT && defined RTC_CLK
|
||||
|
||||
// setup external interupt for active low RTC INT pin
|
||||
pinMode(RTC_INT, INPUT_PULLUP);
|
||||
|
||||
// setup external rtc 1Hz clock as pulse per second clock
|
||||
ESP_LOGI(TAG, "Time base external clock");
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
||||
I2C_MUTEX_UNLOCK();
|
||||
} else {
|
||||
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
||||
return 0; // failure
|
||||
}
|
||||
return 1; // success
|
||||
#endif
|
||||
}
|
||||
|
||||
int pps_init(uint32_t pps_freq) {
|
||||
// if we don't have hardware pps we use ESP32 hardware timer
|
||||
if (pps_freq) {
|
||||
ESP_LOGI(TAG, "Time base ESP32 clock");
|
||||
clockCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler
|
||||
timerAttachInterrupt(clockCycle, &CLOCKIRQ, true);
|
||||
timerAlarmWrite(clockCycle, 10 * pps_freq, true);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid pps clock frequency");
|
||||
return 0; // failure
|
||||
}
|
||||
return 1; // success
|
||||
}
|
||||
|
||||
void pps_start() {
|
||||
#ifdef RTC_INT // start external clock
|
||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
||||
#else // start internal clock
|
||||
timerAlarmEnable(clockCycle);
|
||||
#endif
|
||||
}
|
||||
|
||||
// helper function to sync phase of DCF output signal to start of second t
|
||||
uint8_t sync_clock(time_t t) {
|
||||
time_t tt = t;
|
||||
// delay until start of next second
|
||||
do {
|
||||
tt = now();
|
||||
} while (t == tt);
|
||||
ESP_LOGI(TAG, "Sync on Sec %d", second(tt));
|
||||
return second(tt);
|
||||
}
|
||||
|
||||
// interrupt service routine triggered by either rtc pps or esp32 hardware
|
||||
// timer
|
||||
void IRAM_ATTR CLOCKIRQ() {
|
||||
xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
|
||||
#endif // HAS_RTC
|
||||
Reference in new issue
Block a user