#include "stm32f401xe.h"
#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"
#include "spi.h"
#include "buffered_peripheral.h"
#include "spi_matrix.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 COMMAND_SEPARATOR '\n'
// Button
pin_t user_button;
timer_t button_timer;
exti_t button_exti;
// Display
matrix_t matrix;
timer_t matrix_timer;
// SPI
pin_t spi_csn;
spi_t matrix_spi;
buffered_transceiver_t matrix_tx;
timer_t spi_csn_timer;
// Uart
uart_t uart;
buffered_transceiver_t uart_rx;
#define MAX_CMD_LENGTH 65
#define AUTO_TOGGLE_CYCLES 1000000
#define MAX_IMAGES 10
uint8_t images_count = 4;
uint8_t current_image = 0;
uint8_t images[MAX_IMAGES][8] = {
{0b11111111, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b11111111},
{ 0b00000100, 0b00001110, 0b11110001, 0b10000101, 0b10000001, 0b10110001, 0b10110001, 0b11111111 },
{ 0b11111000, 0b11100100, 0b11100010, 0b10000001, 0b10000001, 0b01000010, 0b00100100, 0b00011000 },
{ 0b11000000, 0b10011000, 0b11010000, 0b10011010, 0b10010010, 0b00011010, 0b00000010, 0b00000011 },
};
uint32_t cycle = 0;
bool auto_toggle = false;
bool toggle_next = false;
bool animation = false;
void handle_command(char* cmd, uint16_t len) {
if (len == 0) {
return;
}
bool handled = false;
switch (cmd[0]) {
case 'n':
// next
if (len == 1) {
handled = true;
toggle_next = true;
buffered_transceiver_transmit(&uart_rx, "Switching to next image.\r\n", 0);
}
break;
case 'N':
// auto toggle
if (len == 1) {
auto_toggle = !auto_toggle;
if (auto_toggle) {
buffered_transceiver_transmit(&uart_rx, "Going to toggle automatically.\r\n", 0);
} else {
buffered_transceiver_transmit(&uart_rx, "Manual switch mode.\r\n", 0);
}
}
break;
case 'a':
// animate
if (len == 1) {
handled = true;
animation = !animation;
if (animation) {
buffered_transceiver_transmit(&uart_rx, "Animation enabled.\r\n", 0);
} else {
buffered_transceiver_transmit(&uart_rx, "Animation disabled.\r\n", 0);
}
}
break;
case 'u':
// upload
// TODO
break;
case 's':
// number of slots is...
// TODO
break;
default:
break;
}
if (!handled) {
buffered_transceiver_transmit(&uart_rx, "Unknown command!\r\n", 0);
}
}
char* receive_command(uint16_t* length)
{
static char cmd[MAX_CMD_LENGTH];
static uint16_t index;
char* current_char = (cmd + index);
while (buffered_transceiver_receive(&uart_rx, current_char, 1) == 1) {
// echo
buffered_transceiver_transmit(&uart_rx, current_char, 1);
if (*current_char == COMMAND_SEPARATOR) {
buffered_transceiver_transmit(&uart_rx, "\r", 1);
*current_char = '\0';
*length = index;
index = 0;
return cmd;
}
index++;
}
// Commands are separated either through max length, or by new line
if (index == MAX_CMD_LENGTH + 1) {
*length = MAX_CMD_LENGTH;
index = 0;
return cmd;
}
return NULL;
}
void next_image()
{
current_image++;
current_image %= images_count;
matrix_set_buffer(&matrix, MATRIX_SLOT_OTHER, &images[current_image][0]);
if (animation) {
matrix_animate_swap(&matrix);
} else {
matrix_swap(&matrix);
}
}
void app_loop()
{
while (1) {
if (auto_toggle && cycle >= AUTO_TOGGLE_CYCLES) {
next_image();
cycle = 0;
} else if (toggle_next) {
next_image();
toggle_next = false;
}
uint16_t command_len;
char* cmd = receive_command(&command_len);
if (cmd != NULL) {
handle_command(cmd, command_len);
}
cycle++;
}
}
void main()
{
// Setup
SystemCoreClockSetHSI();
systick_configure();
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2LPENR_SPI1LPEN;
{ // UART init
pin_t pin_rx;
pin_t pin_tx;
#define UART_RX_BUFFER_SIZE 32
#define UART_TX_BUFFER_SIZE 32
static queue_t uart_rx_queue, uart_tx_queue;
static uint16_t uart_rx_buffer[UART_RX_BUFFER_SIZE], uart_tx_buffer[UART_TX_BUFFER_SIZE];
queue_init(&uart_rx_queue, sizeof(char), UART_RX_BUFFER_SIZE, uart_rx_buffer);
queue_init(&uart_tx_queue, sizeof(char), UART_TX_BUFFER_SIZE, uart_tx_buffer);
bool usart_generic_can_receive(void* peripheral);
bool usart_generic_can_transmit(void* peripheral);
uint16_t usart_generic_receive(void* peripheral, void* buffer, uint16_t max_size);
uint16_t usart_generic_transmit(void* peripheral, void* data, uint16_t size);
buffered_transceiver_vtable_t vtable = {
.can_receive = usart_generic_can_receive,
.can_transmit = usart_generic_can_transmit,
.transmit = usart_generic_transmit,
.receive = usart_generic_receive,
};
buffered_transceiver_init(&uart_rx, &uart_rx_queue, &uart_tx_queue, &uart, vtable);
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_9_BITS, true,
USART_PARITY_EVEN, USART_STOP_BIT_ONE);
usart_enable_interrupt(&uart, false, true);
usart_configure_transmitter(&uart, true);
usart_configure_receiver(&uart, true);
}
{ // SPI init
pin_t pin_mosi;
pin_t pin_csn;
pin_t pin_clk;
#define SPI_RX_BUFFER_SIZE 1
#define SPI_TX_BUFFER_SIZE 10
static queue_t spi_rx_queue, spi_tx_queue;
static uint16_t spi_rx_buffer[SPI_RX_BUFFER_SIZE], spi_tx_buffer[SPI_TX_BUFFER_SIZE];
queue_init(&spi_rx_queue, sizeof(uint16_t), SPI_RX_BUFFER_SIZE, spi_rx_buffer);
queue_init(&spi_tx_queue, sizeof(uint16_t), SPI_TX_BUFFER_SIZE, spi_tx_buffer);
bool spi_generic_can_receive(void* peripheral);
bool spi_generic_can_transmit(void* peripheral);
uint16_t spi_generic_receive(void* peripheral, void* buffer, uint16_t max_size);
uint16_t spi_generic_transmit(void* peripheral, void* data, uint16_t size);
buffered_transceiver_vtable_t vtable = {
.can_receive = spi_generic_can_receive,
.can_transmit = spi_generic_can_transmit,
.transmit = spi_generic_transmit,
.receive = spi_generic_receive,
};
buffered_transceiver_init(&matrix_tx, &spi_rx_queue, &spi_tx_queue, &matrix_spi, vtable);
pin_init(&pin_mosi, GPIOA, 7);
pin_init(&pin_csn, GPIOA, 4);
pin_init(&pin_clk, GPIOB, 3);
pin_into_alternate(&pin_mosi, 5);
/* pin_into_alternate(&pin_csn, 5); */
pin_into_alternate(&pin_clk, 5);
pin_set(&pin_csn);
pin_into_output_pushpull(&pin_csn);
timer_init(&spi_csn_timer, TIM4, 4);
timer_set_refresh(&spi_csn_timer, 1);
timer_configure(&spi_csn_timer, 0, 10000, 0);
timer_enable_interrupt(&spi_csn_timer, true, false);
spi_init(&matrix_spi, pin_csn, SPI1, 1);
spi_master_configure_speed(&matrix_spi, 7);
spi_master_configure(&matrix_spi, false, false, false,
SPI_MSB_FIRST, SPI_FRAME_16_BIT);
spi_enable_interrupt(&matrix_spi, true, false);
spi_master_enable(&matrix_spi, true);
}
{ // Matrix, timer init
matrix_init(&matrix, &matrix_tx, 5);
matrix_setup(&matrix);
matrix_enable(&matrix, true);
matrix_set_buffer(&matrix, MATRIX_SLOT0, images[current_image]);
timer_init(&matrix_timer, TIM3, 3);
timer_set_refresh(&matrix_timer, 20);
timer_configure(&matrix_timer, 0, 60000, 0);
timer_enable_interrupt(&matrix_timer, true, false);
timer_enable(&matrix_timer);
}
{ // Button, exti, timer
pin_init(&user_button, GPIOC, 13);
pin_into_input(&user_button);
exti_init(&button_exti, 13, EXTI, SYSCFG);
exti_external_interrupt(&button_exti, 2);
exti_falling_interrupt(&button_exti);
exti_clear_interrupt(&button_exti);
exti_enable_interrupt(&button_exti);
timer_init(&button_timer, TIM2, 2);
timer_set_refresh(&button_timer, 9999);
timer_configure(&button_timer, 0, 60000, 1);
pin_t pin_capture;
pin_init(&pin_capture, GPIOA, 15);
pin_into_alternate(&pin_capture, 1);
reg_write_bits(&button_timer.periph->CCMR1,
// TI1 on CCR1 no prescaler - capture every event sampling freq = fdts / 32, N = 8
// fdts = 24 MHz, fsample = 750kHz
(1 << TIM_CCMR1_CC1S_Pos) | (0 << TIM_CCMR1_IC1PSC_Pos) | (0xF << TIM_CCMR1_IC1F_Pos),
TIM_CCMR1_CC1S | TIM_CCMR1_IC1PSC | TIM_CCMR1_IC1F);
reg_write_bits(
&button_timer.periph->CCER,
// enable CC1 falling edge captures
(1 << TIM_CCER_CC1E_Pos) | (1 << TIM_CCER_CC1NP_Pos) | (0 << TIM_CCER_CC1P_Pos),
TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NP);
timer_enable_interrupt(&button_timer, true, true);
}
__enable_irq();
// Application
app_loop();
}
void EXTI15_10_handler(void) {
if (exti_is_interrupt(&button_exti)) {
exti_clear_interrupt(&button_exti);
timer_set_counter(&button_timer, 0);
timer_enable(&button_timer);
}
}
void TIM2_handler(void) {
if (timer_is_update_interrupt(&button_timer)) {
timer_clear_update_interrupt(&button_timer);
} else if (timer_is_capture1_interrupt(&button_timer)) {
uint32_t count = button_timer.periph->CCR1;
timer_clear_capture1_interrupt(&button_timer);
// 200 Hz => 5 ms
// 50 ms is 10. That means button was really pressed by user, no bouncing
// 2 s is 400
if (count > 10) { // at least 50 ms
if (count > 400) { // at least 2 s
auto_toggle = !auto_toggle;
} else { // less than 2 s
if (auto_toggle) {
auto_toggle = false;
}
else {
toggle_next = true;
}
}
// stop the timer
timer_disable(&button_timer);
}
}
}
void TIM3_handler(void) {
timer_clear_update_interrupt(&matrix_timer);
matrix_update(&matrix, &matrix_tx);
}
// A flag to prevent spi communication,
// to toggle csn high
bool spi_can_transmit_flag = true;
void SPI1_handler(void) {
if (spi_can_receive(&matrix_spi)) {
buffered_transceiver_trigger_receive(&matrix_tx, 1);
}
if (spi_can_transmit(&matrix_spi)) {
//
spi_can_transmit_flag = false;
timer_set_counter(&spi_csn_timer, 0);
timer_enable(&spi_csn_timer);
// Disable interrupt so cpu is not locked
spi_enable_interrupt(&matrix_spi, false, false);
}
}
void TIM4_handler(void) {
timer_clear_update_interrupt(&spi_csn_timer);
if (!(matrix_spi.periph->SR & SPI_SR_BSY)) {
// disable and enable spi so that CSN is pulsed.
spi_pulse_csn(&matrix_spi);
// Allow sending...
spi_can_transmit_flag = true;
// Disable this timer until transmission is done again
timer_disable(&spi_csn_timer);
// Transmit only after the pulse. SPI is enabled again.
buffered_transceiver_trigger_transmit(&matrix_tx, 1);
}
}
void USART2_handler(void) {
if (usart_can_receive(&uart)) {
buffered_transceiver_trigger_receive(&uart_rx, 1);
}
if (usart_can_transmit(&uart)) {
if (!buffered_transceiver_trigger_transmit(&uart_rx, 1)) {
usart_enable_interrupt(&uart, false, true);
}
}
}
bool spi_generic_can_receive(void *peripheral) {
return spi_can_receive((spi_t*)peripheral);
}
bool spi_generic_can_transmit(void *peripheral) {
return spi_can_transmit_flag && (((spi_t*)peripheral)->periph->SR & SPI_SR_BSY) == 0;
}
uint16_t spi_generic_receive(void *peripheral, void *buffer,
uint16_t max_size) {
return spi_receive((spi_t*)peripheral, buffer, max_size);
}
uint16_t spi_generic_transmit(void *peripheral, void *data, uint16_t size) {
// enable the interrupt so that we can send the rest
uint16_t ret = spi_transmit((spi_t*)peripheral, data, size);
spi_enable_interrupt((spi_t*)peripheral, true, false);
return ret;
}
bool usart_generic_can_receive(void *peripheral) {
return usart_can_receive((uart_t*)peripheral);
}
bool usart_generic_can_transmit(void *peripheral) {
return usart_can_transmit((uart_t*)peripheral);
}
uint16_t usart_generic_receive(void *peripheral, void *buffer,
uint16_t max_size) {
return usart_receive((uart_t*)peripheral, buffer, max_size);
}
uint16_t usart_generic_transmit(void *peripheral, void *data, uint16_t size) {
uint16_t ret = usart_transmit((uart_t*)peripheral, data, size);
// enable the interrupt so that we can send the rest
usart_enable_interrupt((uart_t*)peripheral, true, true);
return ret;
}