#include <stdint.h>
#include <stm32f4xx.h>
#include "exti.h"
#include "pin.h"
#include "timer.h"
#include "stm32f401xe.h"
#define LED_PIN 5
#define LED_GPIO GPIOA
#define BUTTON_PIN 13
#define BUTTON_GPIO GPIOC
#define BUTTON_GPIO_ID 2 // A 0 B 1 C 2
void hard_fault_handler() {
while(1) {}
}
void usage_fault_handler() {
while(1) {}
}
void nmi_handler() {
while(1) {}
}
void bus_fault_handler() {
while(1) {}
}
/*----------------------------------------------------------------------------
* SystemCoreClockConfigure: configure SystemCoreClock using HSI
(HSE is not populated on Nucleo board)
*----------------------------------------------------------------------------*/
void SystemCoreClockSetHSI(void) {
RCC->CR |= ((uint32_t)RCC_CR_HSION); // Enable HSI
while ((RCC->CR & RCC_CR_HSIRDY) == 0); // Wait for HSI Ready
RCC->CFGR = RCC_CFGR_SW_HSI; // HSI is system clock
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); // Wait for HSI used as system clock
FLASH->ACR = FLASH_ACR_PRFTEN; // Enable Prefetch Buffer
FLASH->ACR |= FLASH_ACR_ICEN; // Instruction cache enable
FLASH->ACR |= FLASH_ACR_DCEN; // Data cache enable
FLASH->ACR |= FLASH_ACR_LATENCY_5WS; // Flash 5 wait state
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // HCLK = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // APB1 = HCLK/4
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; // APB2 = HCLK/2
RCC->CR &= ~RCC_CR_PLLON; // Disable PLL
// HSI = 16 MHz
// PLL configuration: VCO = HSI/M * N, Sysclk = VCO/P
// => Sysclk = 48 MHz, APB1 = 12 MHz, APB2 = 24 MHz
// Since divider for APB1 is != 1, timer clock is 24 MHz
RCC->PLLCFGR = ( 16ul | // PLL_M = 16
(384ul << 6) | // PLL_N = 384
( 3ul << 16) | // PLL_P = 8
(RCC_PLLCFGR_PLLSRC_HSI) | // PLL_SRC = HSI
( 8ul << 24) ); // PLL_Q = 8
RCC->CR |= RCC_CR_PLLON; // Enable PLL
while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); // Wait till PLL is ready
RCC->CFGR &= ~RCC_CFGR_SW; // Select PLL as system clock source
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait till PLL is system clock src
}
pin_t led;
exti_t button_exti;
pin_t button;
timer_t toggle_timer;
timer_t debounce_timer;
// the timer runs at 200 Hz
/* uint16_t timer_values[3] = { 20, 100, 300 }; */
uint16_t timer_values[3] = { 40, 200, 600 };
uint8_t current_timer_value = 1;
void main()
{
// TODO: enable tim2, exti, syscfg
SystemCoreClockSetHSI();
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOCEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
volatile uint32_t dummy;
dummy = (RCC->AHB1ENR);
dummy = (RCC->AHB1ENR);
dummy = (RCC->APB1ENR);
dummy = (RCC->APB1ENR);
dummy = (RCC->APB2ENR);
dummy = (RCC->APB2ENR);
pin_init(&led, LED_GPIO, LED_PIN);
pin_into_output_pushpull(&led);
pin_speed(&led, LOW_SPEED);
pin_init(&button, BUTTON_GPIO, BUTTON_PIN);
pin_into_input(&button);
exti_init(&button_exti, BUTTON_PIN, EXTI, SYSCFG);
exti_external_interrupt(&button_exti, BUTTON_GPIO_ID);
exti_falling_interrupt(&button_exti);
exti_clear_interrupt(&button_exti);
exti_enable_interrupt(&button_exti);
// configure toggle timer
timer_init(&toggle_timer, TIM2, 2);
timer_set_refresh(&toggle_timer, timer_values[0]);
timer_configure(&toggle_timer, 1, 60000, 0);
timer_enable_interrupt(&toggle_timer);
timer_enable(&toggle_timer);
// configure debounce timer
timer_init(&debounce_timer, TIM3, 3);
timer_set_refresh(&debounce_timer, 10);
timer_configure(&debounce_timer, 1, 60000, 1);
timer_enable_interrupt(&debounce_timer);
__enable_irq();
while(1) { __WFI(); }
}
// Toggle led timer
void TIM2_handler(void)
{
timer_clear_interrupt(&toggle_timer);
pin_toggle(&led);
}
// Debounce button timer
void TIM3_handler(void)
{
timer_clear_interrupt(&debounce_timer);
if (!pin_read(&button)) {
timer_set_refresh(&toggle_timer,
timer_values[current_timer_value++]);
current_timer_value %= sizeof(timer_values) / sizeof(uint16_t);
}
}
void EXTI15_10_handler(void)
{
if (exti_is_interrupt(&button_exti)) {
exti_clear_interrupt(&button_exti);
timer_set_counter(&debounce_timer, 0);
timer_enable(&debounce_timer);
}
}