#include "timer.h"
#include <stdint.h>
#include <stdbool.h>
#include <stm32f4xx.h>
#include "exti.h"
#include "pin.h"
#include "registers.h"
#include "display.h"
#include "delay.h"
#include "uart.h"
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
}
#define DIGITS 4
display_t display;
timer_t display_timer;
uart_t uart;
typedef struct {
char digits[4];
uint8_t digits_count;
uint8_t dot;
bool error;
} converted_number_t;
converted_number_t convert_number(char* data);
void main()
{
// Setup
SystemCoreClockSetHSI();
systick_configure();
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_USART2EN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// The timer clocks are at 12 MHz.
// For 100 Hz, the prescaler would be 120 000. That is too big,
// so 200 Hz is chosen. From there it will have to be divided by 2 by application.
// For 6800 Hz, 1765 prescaler will be used, leading to 6798... Hz
// Initialize timer for display at interrupt frequency
// digit update frequency * digits * 34
// aim for 100 Hz * 4 * 17 = 6 800 Hz
{
pin_t pin_data;
pin_t pin_sftclk;
pin_t pin_strobe;
pin_init(&pin_data, GPIOA, 9);
pin_init(&pin_sftclk, GPIOA, 8);
pin_init(&pin_strobe, GPIOB, 5);
pin_into_output(&pin_data);
pin_into_output(&pin_sftclk);
pin_into_output(&pin_strobe);
display_init(&display, DIGITS, pin_data, pin_sftclk, pin_strobe);
}
{
pin_t pin_rx;
pin_t pin_tx;
pin_init(&pin_tx, GPIOA, 2);
pin_init(&pin_rx, GPIOA, 3);
pin_into_alternate(&pin_rx, 7);
pin_into_alternate(&pin_tx, 7);
usart_init(&uart, USART2, 2);
usart_configure_speed(&uart, 12000000, 9600);
usart_configure_uart(&uart, true, USART_WORD_8_BITS, true,
USART_PARITY_EVEN, USART_STOP_BIT_ONE);
usart_configure_receiver(&uart, true);
}
timer_init(&display_timer, TIM3, 3);
timer_configure(&display_timer, 0, 500, 0);
timer_set_refresh(&display_timer, 4);
timer_enable_interrupt(&display_timer);
timer_enable(&display_timer);
__enable_irq();
char buffer[64];
// Application
while (1) {
if (usart_receive(&uart, buffer, sizeof(buffer) / sizeof(buffer[0]), '\n') == 0) {
continue;
}
converted_number_t converted = convert_number(buffer);
if (converted.error) {
display_digits_set(&display, "Err\0");
display_dots(&display, 0);
} else {
uint8_t empty_count = DIGITS - converted.digits_count;
display_dots(&display, converted.dot << empty_count);
for (uint8_t digit = 0; digit < DIGITS; digit++) {
char value = '\0';
if (digit >= empty_count) {
value = converted.digits[digit - empty_count];
}
display_digit_set(&display, digit, value);
}
}
/* DELAY_US(100); */
}
}
converted_number_t convert_number(char* data) {
converted_number_t number;
bool found_dot = false;
uint8_t curr_digit = 0;
number.dot = 0;
number.error = false;
while (*data != '\0' && curr_digit < DIGITS) {
char curr = *(data++);
// handle first dot
if (curr == '.' && !found_dot) {
found_dot = true;
// if dot first, assume zero.
if (curr_digit == 0) {
number.digits[curr_digit++] = '0';
}
number.dot = 1 << (curr_digit - 1);
continue;
// handle digit
} else if (curr >= '0' && curr <= '9') {
number.digits[curr_digit++] = curr;
// handle others
} else {
number.error = true;
break;
}
}
if (*data != '\0') {
number.error = true;
}
number.digits_count = curr_digit;
return number;
}
/* void TIM2_handler(void) { */
/* // The stopwatch timer */
/* } */
void TIM3_handler(void) {
timer_clear_interrupt(&display_timer);
display_update(&display);
}