#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" #include #include #include #pragma GCC diagnostic pop #include #include #include #include #include "transpose.h" /* * Part number: STM32F030F4C6 */ /* 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) { SPI1->DR = data; while (SPI1->SR & SPI_SR_BSY); } void strobe_aux(void) { GPIOA->BSRR = GPIO_BSRR_BS_10; tick(); GPIOA->BSRR = GPIO_BSRR_BR_10; } void strobe_leds(void) { GPIOA->BSRR = GPIO_BSRR_BS_9; tick(); GPIOA->BSRR = GPIO_BSRR_BR_9; } static volatile unsigned int sys_time = 0; volatile struct framebuf fb[2] = {0}; volatile struct framebuf *read_fb=fb+0, *write_fb=fb+1; volatile int led_state = 0; volatile enum { FB_WRITE, FB_FORMAT, FB_UPDATE } fb_op; volatile uint8_t rx_buf[sizeof(struct framebuf)]; volatile uint8_t this_addr = 0x05; /* FIXME */ #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<VAL; } inline unsigned int stk_end(unsigned int start) { return (start - SysTick->VAL) & 0xffffff; } 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) { volatile 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<CCMR1 = 6<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; NVIC_EnableIRQ(TIM3_IRQn); NVIC_SetPriority(TIM3_IRQn, 2); } void TIM3_IRQHandler() { //TIM3->CR1 &= ~TIM_CR1_CEN_Msk; FIXME /* This takes about 10us */ int period = shift_data(); TIM3->CCR1 = period; TIM3->CNT = 0xffff; /* To not enable OC1 right away */ TIM3->SR &= ~TIM_SR_CC1IF_Msk; //TIM3->CR1 |= TIM_CR1_CEN; } enum Command { CMD_PING, CMD_SET_ADDR, CMD_SET_FB, CMD_GET_DESC, }; int gaddr; void USART1_IRQHandler() { gaddr = USART1->RDR; USART1->RQR |= USART_RQR_RXFRQ; int addr = gaddr; /* FIXME DEBUG */ int cmd = addr>>5; addr &= 0x1F; /* Are we addressed? */ if (addr != this_addr) { /* We are not. Mute USART until next idle condition */ USART1->RQR |= USART_RQR_MMRQ; } else { /* We are. Switch by command. */ switch (cmd) { case CMD_SET_FB: /* Are we ready to process new frame data? */ if (fb_op != FB_WRITE) { //asm("bkpt"); /* FIXME DEBUG */ goto errout; /* Error: Not yet ready to receive new packet */ } /* Disable this RX interrupt for duration of DMA transfer */ USART1->CR1 &= ~USART_CR1_RXNEIE_Msk; /* Enable DMA transfer to write buffer */ DMA1->IFCR |= DMA_IFCR_CGIF3; DMA1_Channel3->CCR |= DMA_CCR_EN; USART1->CR3 |= USART_CR3_DMAR; break; } } errout: /* FIXME */ return; } void DMA1_Channel2_3_IRQHandler() { /* DMA Transfer complete, re-enable receive interrupt */ USART1->CR1 |= USART_CR1_RXNEIE; /* ...and disable this DMA channel */ USART1->CR3 &= ~USART_CR3_DMAR_Msk; DMA1_Channel3->CCR &= ~DMA_CCR_EN_Msk; /* Kick off formatting code in main loop outside interrupt context */ fb_op = FB_FORMAT; DMA1->IFCR |= DMA_IFCR_CGIF3; } void uart_config(void) { USART1->CR1 = /* 8-bit -> M1, M0 clear */ /* RTOIE clear */ (8 << USART_CR1_DEAT_Pos) /* 8 sample cycles/1 bit DE assertion time */ | (8 << USART_CR1_DEDT_Pos) /* 8 sample cycles/1 bit DE assertion time */ //| USART_CR1_OVER8 FIXME debug? /* CMIF clear */ | USART_CR1_MME /* WAKE clear */ /* PCE, PS clear */ | USART_CR1_RXNEIE /* other interrupts clear */ | USART_CR1_TE | USART_CR1_RE; //USART1->CR2 = USART_CR2_RTOEN; /* Timeout enable */ USART1->CR3 = USART_CR3_DEM; /* RS485 DE enable (output on RTS) */ int usartdiv = 25; USART1->BRR = usartdiv; USART1->CR1 |= USART_CR1_UE; /* Configure DMA for USART frame data reception */ DMA1_Channel3->CPAR = (unsigned int)&USART1->RDR; DMA1_Channel3->CMAR = (unsigned int)rx_buf; DMA1_Channel3->CNDTR = sizeof(rx_buf); DMA1_Channel3->CCR = (0<CCR |= (0<CR |= RCC_CR_HSEON; while (!(RCC->CR&RCC_CR_HSERDY)); RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; RCC->CFGR |= (2< 50.0MHz */ RCC->CFGR2 &= ~RCC_CFGR2_PREDIV_Msk; RCC->CFGR2 |= RCC_CFGR2_PREDIV_DIV2; /* prediv :2 -> 12.5MHz */ RCC->CR |= RCC_CR_PLLON; while (!(RCC->CR&RCC_CR_PLLRDY)); RCC->CFGR |= (2<AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN; RCC->APB2ENR |= RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; GPIOA->MODER |= (2<OSPEEDR |= (2<AFR[0] |= (1<PUPDR |= (2<I2SCFGR = 0; SPI1->CR2 &= ~SPI_CR2_DS_Msk; SPI1->CR2 &= ~SPI_CR2_DS_Msk; SPI1->CR2 |= LL_SPI_DATAWIDTH_16BIT; /* Baud rate PCLK/2 -> 25MHz */ SPI1->CR1 = SPI_CR1_BIDIMODE | SPI_CR1_BIDIOE | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | (0<brightness = 1; for (int i=0; idata)/sizeof(uint32_t); i++) { read_fb->data[i] = 0xffffffff; /*FIXME debug replace with 0x00000000 */ } cfg_timer3(); SysTick_Config(SystemCoreClock/1000); /* 1ms interval */ uart_config(); uint8_t i=0; int last_sys_time=0; while (42) { led_state = (sys_time>>8)&7; if ((sys_time ^ last_sys_time) & (1<<4)) { USART1->TDR = i++; } last_sys_time = sys_time; if (fb_op == FB_FORMAT) { //transpose_data(rx_buf, read_fb); fb_op = FB_UPDATE; while (fb_op == FB_UPDATE) ; } } } void NMI_Handler(void) { } void HardFault_Handler(void) __attribute__((naked)); void HardFault_Handler() { asm volatile ("bkpt"); } void SVC_Handler(void) { } void PendSV_Handler(void) { } void SysTick_Handler(void) { sys_time++; }