diff options
Diffstat (limited to 'fw/main.c')
-rw-r--r-- | fw/main.c | 213 |
1 files changed, 152 insertions, 61 deletions
@@ -1,18 +1,26 @@ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" #include <stm32f0xx.h> -#include <stdint.h> -#include <system_stm32f0xx.h> #include <stm32f0xx_ll_utils.h> #include <stm32f0xx_ll_spi.h> +#pragma GCC diagnostic pop + +#include <system_stm32f0xx.h> + +#include <stdint.h> #include <string.h> #include <unistd.h> /* * Part number: STM32F030F4C6 */ -void tick(void) { - for(int i=0; i<50; i++) - __asm__("nop"); +/* Wait for about 0.2us */ +static void tick(void) { + /* 1 */ /* 2 */ /* 3 */ /* 4 */ /* 5 */ + /* 5 */ __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); + /* 10 */ __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); } void spi_send(int data) { @@ -32,18 +40,117 @@ void strobe_leds(void) { GPIOA->BSRR = GPIO_BSRR_BR_9; } -#define SR_COMM 0x0002 -#define SR_ERROR 0x0004 -#define SR_ID 0x0008 +static volatile unsigned int sys_time = 0; + +enum Segment { SegA, SegB, SegC, SegD, SegE, SegF, SegG, SegDP, nsegments }; +enum { + nrows = 4, + ncols = 8, + nbits = 10, +}; +enum { + frame_size_words = nrows*ncols*nsegments/32, +}; +struct framebuf { + /* Multiplexing order: first Digits, then Time/bits, last Segments */ + uint32_t data[nbits*frame_size_words]; + int brightness; /* 0 or 1; controls global brighntess control */ +}; + +struct framebuf fb[2] = {0}; +struct framebuf *read_fb=fb+0, *write_fb=fb+1; +volatile int led_state = 0; +volatile enum { FB_WRITE, FB_UPDATE } fb_op; + +#define LED_COMM 0x0001 +#define LED_ERROR 0x0002 +#define LED_ID 0x0004 #define SR_ILED_HIGH 0x0080 #define SR_ILED_LOW 0x0040 + +void shift_aux(int global_current, int leds, int active_segment) { + spi_send( + (global_current ? SR_ILED_HIGH : SR_ILED_LOW) + | (leds<<1) + | (0xff00 ^ (0x100<<active_segment))); + strobe_aux(); +} + +static volatile int frame_duration; +/* returns new bit time in cycles */ +int shift_data() { + static int active_segment = 0; + static unsigned int active_bit = 0; + static int last_frame_sys_time; + + /* Note: On boot, multiplexing will start with bit 1 due to the next few lines. This is perfectly ok. */ + active_bit++; + if (active_bit == nbits) { + active_bit = 0; + + active_segment++; + if (active_segment == nsegments) { + active_segment = 0; + + int time = sys_time; + frame_duration = time - last_frame_sys_time; + last_frame_sys_time = sys_time; + if (fb_op == FB_UPDATE) { + struct framebuf *tmp = read_fb; + read_fb = write_fb; + write_fb = tmp; + fb_op = FB_WRITE; + } + } + + shift_aux(read_fb->brightness, led_state, active_segment); + } + + uint32_t current_word = read_fb->data[active_bit*frame_size_words + active_segment]; + spi_send(current_word&0xffff); + spi_send(current_word>>16); + strobe_leds(); + + return 1<<active_bit; +} + +void cfg_timer3() { + TIM3->CCMR1 = 6<<TIM_CCMR1_OC1M_Pos; /* PWM Mode 1 */ + TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P; /* Inverting output */ + TIM3->DIER = TIM_DIER_CC1IE; + TIM3->CCR1 = 1000; /* Schedule first interrupt */ + TIM3->PSC = SystemCoreClock/5000000 * 2; /* 0.40us/tick */ + TIM3->ARR = 0xffff; + TIM3->EGR |= TIM_EGR_UG; + TIM3->CR1 = TIM_CR1_ARPE; + TIM3->CR1 |= TIM_CR1_CEN; +} + +TIM_TypeDef *tim3 = TIM3; + +void TIM3_IRQHandler() { + //TIM3->CR1 &= ~TIM_CR1_CEN_Msk; + + static int last_ivl; + last_ivl = TIM3->CNT; + /* This takes about 10us */ + int period = shift_data(); + static int ivl; + ivl = TIM3->CNT - last_ivl; + TIM3->CCR1 = period; + TIM3->CNT = 0xffff; /* To not enable OC1 right away */ + + TIM3->SR &= ~TIM_SR_CC1IF_Msk; + //TIM3->CR1 |= TIM_CR1_CEN; +} + int main(void) { RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR&RCC_CR_HSERDY)); - RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk; - RCC->CFGR |= (2<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x4 */ + RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; + RCC->CFGR |= (1<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x4 -> 50.0MHz */ RCC->CFGR2 &= ~RCC_CFGR2_PREDIV_Msk; - RCC->CFGR2 |= RCC_CFGR2_PREDIV_DIV2; + RCC->CFGR2 |= RCC_CFGR2_PREDIV_DIV2; /* prediv :2 -> 12.5MHz */ RCC->CR |= RCC_CR_PLLON; while (!(RCC->CR&RCC_CR_PLLRDY)); RCC->CFGR |= (2<<RCC_CFGR_SW_Pos); @@ -53,10 +160,11 @@ int main(void) { RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; GPIOA->MODER |= (2<<GPIO_MODER_MODER5_Pos) /* PA5 - SCLK */ - | (1<<GPIO_MODER_MODER6_Pos) /* PA6 - LED !OE */ + | (2<<GPIO_MODER_MODER6_Pos) /* PA6 - LED !OE */ | (2<<GPIO_MODER_MODER7_Pos) /* PA7 - MOSI */ | (1<<GPIO_MODER_MODER9_Pos) /* PA9 - LED strobe */ | (1<<GPIO_MODER_MODER10_Pos);/* PA10 - Auxiliary strobe */ @@ -71,6 +179,7 @@ int main(void) { GPIOA->AFR[0] |= (0<<GPIO_AFRL_AFRL5_Pos) /* SPI1_SCK */ + | (1<<GPIO_AFRL_AFRL6_Pos) /* TIM3_CH1 */ | (0<<GPIO_AFRL_AFRL7_Pos); /* SPI1_MOSI */ /* Configure SPI controller */ @@ -79,60 +188,41 @@ int main(void) { SPI1->CR2 &= ~SPI_CR2_DS_Msk; SPI1->CR2 |= LL_SPI_DATAWIDTH_16BIT; /* FIXME maybe try w/o BIDI */ + /* Baud rate PCLK/2 -> 25MHz */ SPI1->CR1 = SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | (0<<SPI_CR1_BR_Pos) | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA; - int val = 0xffff; - int aval = 0x0000; - GPIOA->BSRR = GPIO_BSRR_BR_6; /* OE */ - int j = 0; - int ctr = 0; - int q = 0; - int bval = 0x400; + read_fb->brightness = 1; + for (int i=0; i<sizeof(read_fb->data)/sizeof(uint32_t); i++) { + read_fb->data[i] = 0xffffffff; + } + cfg_timer3(); + + NVIC_EnableIRQ(TIM3_IRQn); + NVIC_SetPriority(TIM3_IRQn, 2); + + SysTick_Config(SystemCoreClock/1000); /* 1ms interval */ + while (42) { - for (int i=0; i<8; i++) { - spi_send(1<<(ctr&3)); - spi_send(1<<((ctr>>1)&3)); - strobe_leds(); - //spi_send(0x0200 | bval | (0xff^(1<<i))); - //spi_send((0xff^(1<<i))<<8); - //spi_send(SR_COMM | SR_ILED_HIGH | 0xff); - //spi_send(0x00ff ^ (1<<ctr) | (0x100<<ctr)); - spi_send(bval | (0xff00 ^ (0x100<<i))); - strobe_aux(); - for(int i=0; i<10; i++) - tick(); - j++; - if (j == 1000) { - j = 0; - ctr++; - if (ctr == 8) { - ctr = 0; - q++; - if (q == 6) - q = 0; - } - switch (q) { - case 0: - bval = SR_COMM | SR_ILED_LOW; - break; - case 1: - bval = SR_ID | SR_ILED_LOW; - break; - case 2: - bval = SR_ERROR | SR_ILED_LOW; - break; - case 3: - bval = SR_COMM | SR_ILED_HIGH; - break; - case 4: - bval = SR_ID | SR_ILED_HIGH; - break; - case 5: - bval = SR_ERROR | SR_ILED_HIGH; - break; - } + led_state = (sys_time>>8)&7; + + int ctr = sys_time>>2; + for (int bit=0, bmask=1; bit<nbits; bit++, bmask<<=1) { + + int data = 0; + for (uint32_t ibit = 1, j=0; ibit; ibit<<=1, j++) { + int _100 = (1<<nbits); + int _1ff = (2*_100-1); + int val = (ctr + (j<<(nbits-5))) & _1ff; + val = val&_100 ? _1ff-val : val; + data |= val&bmask ? ibit : 0; } + + for (int seg=0; seg<frame_size_words; seg++) + write_fb->data[bit*frame_size_words + seg] = data; } + fb_op = FB_UPDATE; + while (fb_op == FB_UPDATE) + ; } } @@ -151,5 +241,6 @@ void PendSV_Handler(void) { } void SysTick_Handler(void) { + sys_time++; } |