#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>

/* Nucleo-G474RE: LD2 is on PA5 */
#define BLINK_PORT GPIOA
#define BLINK_PIN GPIO5
#define BLINK_PERIOD_MS 1000

static volatile uint32_t s_ticks = 0;

void sys_tick_handler(void) { s_ticks++; }

static void delay_ms(uint32_t ms) {
  uint32_t until = s_ticks + ms;
  while (s_ticks < until)
    ;
}

static void clock_setup(void) {
  rcc_clock_setup_pll(&rcc_hsi_configs[RCC_CLOCK_3V3_170MHZ]);
}

static void systick_setup(void) {
  /* 1 ms tick at 170 MHz core clock */
  systick_set_reload(rcc_ahb_frequency / 1000 - 1);
  systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
  systick_counter_enable();
  systick_interrupt_enable();
}

static void gpio_setup(void) {
  rcc_periph_clock_enable(RCC_GPIOA);
  gpio_mode_setup(BLINK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, BLINK_PIN);
  gpio_set_output_options(BLINK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_LOW,
                          BLINK_PIN);
}

int main(void) {
  clock_setup();
  systick_setup();
  gpio_setup();

  while (1) {
    gpio_toggle(BLINK_PORT, BLINK_PIN);
    delay_ms(BLINK_PERIOD_MS);
  }

  return 0;
}
