#include "general.h"
#include "platform.h"
#include "morse.h"
#include "usb.h"
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/adc.h>
bool running_status = false;
static volatile uint32_t time_ms = 0;
uint32_t target_clk_divider = 0;
static size_t morse_tick = 0;
#ifdef PLATFORM_HAS_POWER_SWITCH
static uint8_t monitor_ticks = 0;
#define ADC_VREFINT_MAX 1638U
#define ADC_VREFINT_MIN 1404U
#endif
static void usb_config_morse_msg_update(void)
{
if (usb_config_is_updated()) {
if (usb_config == 0)
morse("NO USB HOST.", true);
else
morse(NULL, false);
usb_config_clear_updated();
}
}
void platform_timing_init(void)
{
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(rcc_ahb_frequency / (8U * SYSTICKHZ));
nvic_set_priority(NVIC_SYSTICK_IRQ, 14U << 4U);
systick_interrupt_enable();
systick_counter_enable();
}
void platform_delay(uint32_t ms)
{
platform_timeout_s timeout;
platform_timeout_set(&timeout, ms);
while (!platform_timeout_is_expired(&timeout))
continue;
}
void sys_tick_handler(void)
{
time_ms += SYSTICKMS;
if (morse_tick >= MORSECNT) {
if (running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN);
usb_config_morse_msg_update();
SET_ERROR_STATE(morse_update());
morse_tick = 0;
} else
++morse_tick;
#ifdef PLATFORM_HAS_POWER_SWITCH
if (platform_target_get_power()) {
if (monitor_ticks == 8U) {
uint8_t channel = ADC_CHANNEL_VREF;
adc_set_regular_sequence(ADC1, 1, &channel);
adc_start_conversion_direct(ADC1);
}
if (monitor_ticks == 9U) {
const uint32_t ref = adc_read_regular(ADC1);
ADC_SR(ADC1) &= ~ADC_SR_EOC;
monitor_ticks = 0;
if (ref > ADC_VREFINT_MAX || ref < ADC_VREFINT_MIN) {
platform_target_set_power(false);
morse("TPWR ERROR", true);
}
} else
++monitor_ticks;
} else
monitor_ticks = 0;
#endif
}
uint32_t platform_time_ms(void)
{
return time_ms;
}
#define USED_SWD_CYCLES 22
#define CYCLES_PER_CNT 10
void platform_max_frequency_set(const uint32_t frequency)
{
#ifdef BITBANG_CALIBRATED_FREQS
if (frequency > BITBANG_0_DELAY_FREQ)
target_clk_divider = UINT32_MAX;
else if (!frequency)
target_clk_divider = UINT32_MAX - 1U;
else {
const uint32_t ratio = rcc_ahb_frequency / frequency;
target_clk_divider = (ratio - BITBANG_DIVIDER_OFFSET) / BITBANG_DIVIDER_FACTOR;
}
#else
uint32_t divisor = rcc_ahb_frequency - USED_SWD_CYCLES * frequency;
if (divisor >= 0x80000000U) {
target_clk_divider = UINT32_MAX;
return;
}
divisor /= 2U;
target_clk_divider = divisor / (CYCLES_PER_CNT * frequency);
if (target_clk_divider * (CYCLES_PER_CNT * frequency) < divisor)
++target_clk_divider;
#endif
}
uint32_t platform_max_frequency_get(void)
{
#ifdef BITBANG_CALIBRATED_FREQS
if (target_clk_divider == UINT32_MAX)
return BITBANG_NO_DELAY_FREQ;
const uint32_t ratio = (target_clk_divider * BITBANG_DIVIDER_FACTOR) + BITBANG_DIVIDER_OFFSET;
return rcc_ahb_frequency / ratio;
#else
uint32_t result = rcc_ahb_frequency;
result /= USED_SWD_CYCLES + CYCLES_PER_CNT * target_clk_divider;
return result;
#endif
}