#include "timer.h" #include #include #include #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); }