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
56 changes: 56 additions & 0 deletions dcf77.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1683,6 +1683,10 @@ namespace Internal {
const int16_t pp16m = adjust_pp16m;
return pp16m;
}
#if defined(ARDUINO_ARCH_RP2040)
//Workaround to [-Werror=return-type]
return 0;
#endif
}

#if defined(__AVR_ATmega168__) || \
Expand Down Expand Up @@ -1876,6 +1880,58 @@ namespace Internal {
Clock_Controller::process_1_kHz_tick_data(the_input_provider());
}
#endif

#if defined(ARDUINO_ARCH_RP2040)

//This implementation uses the low-level hardware timer of the RP2040 microcontroller.
//The hardware timer has a fixed tick rate of 1 MHz (one tick per microsecond).
//We are using an interrupt every 1 ms. More advanced features and higher resolution
//could be achieved by programming the PIO for signal sampling, streaming samples to DMA,
//and using DMA interrupts for computation. In the current state of the art,
//this might be an overkill, but we are open-minded about this approach.

const uint32_t timer_freq = 1000000; //not a frequency but ticks in 1s, fixed
const uint32_t ticks_per_ms = timer_freq/1000;
const uint32_t ticks_per_us = ticks_per_ms/1000;

#define ALARM_NUM 0
#define ALARM_IRQ timer_hardware_alarm_get_irq_num(timer_hw, ALARM_NUM)

static void alarm_in_us_arm(uint32_t delay_us) {
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
uint64_t target = timer_hw->timerawl + delay_us;
timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
}

void setup(const Clock::input_provider_t input_provider) {
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
irq_set_exclusive_handler(ALARM_IRQ, isr_handler);
irq_set_enabled(ALARM_IRQ, true);
alarm_in_us_arm(ticks_per_ms);
the_input_provider = input_provider;
}

// 1000 / 1 000 000 = 1 / 1 000
const uint16_t inverse_timer_resolution = 1000;

void __not_in_flash_func(isr_handler)() {
cumulated_phase_deviation += adjust_pp16m;
if (cumulated_phase_deviation >= inverse_timer_resolution) {
cumulated_phase_deviation -= inverse_timer_resolution;
// cumulated drift exceeds microsecond)
// drop microsecond step to realign
alarm_in_us_arm(ticks_per_ms - ticks_per_us);
} else if (cumulated_phase_deviation <= -inverse_timer_resolution) {
cumulated_phase_deviation += inverse_timer_resolution;
// cumulated drift exceeds 1 microsecond
alarm_in_us_arm(ticks_per_ms + ticks_per_us);
} else {
alarm_in_us_arm(ticks_per_ms);
}

Clock_Controller::process_1_kHz_tick_data(the_input_provider());
}
#endif
}
}

Expand Down
23 changes: 23 additions & 0 deletions dcf77.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,23 @@ namespace Internal {
#warning Compiling for Linux target only supported for unit test purposes. Only fake support for atomic sections. Please take care.

#define CRITICAL_SECTION for (int __n = 1; __n; __n = 0)
#elif defined(ARDUINO_ARCH_RP2040)
#warning Experimental RP2040 support using Earle F. Philhower, III Raspberry Pi Pico Arduino core

static inline critical_section_t* __disable_irq(void){
critical_section_t global_critical_section;
critical_section_enter_blocking(&global_critical_section);
return(&global_critical_section);
}

static inline void __restore_irq(const critical_section_t *global_critical_section) {
if (!(*global_critical_section)) {
force_load_store();
critical_section_exit(&global_critical_section);
}
}

#define CRITICAL_SECTION for (critical_section_t global_critical_section __attribute__((__cleanup__(__restore_irq))) = __disable_irq(), __n = 1; __n; __n = 0)
#else
#error Unsupported controller architecture
#endif
Expand Down Expand Up @@ -1135,8 +1152,14 @@ namespace Internal {
struct dummy_stage {
void reset() const {}
void reduce(const uint8_t sampled_data) const {}
#if defined(ARDUINO_ARCH_RP2040)
//Workaround to [-Werror=return-type]
bool data_ready() const {return 0;}
uint8_t avg() const {return 0;}
#else
bool data_ready() const {}
uint8_t avg() const {}
#endif
};

static const bool requires_averages = samples_per_bin > 1;
Expand Down