diff options
Diffstat (limited to 'center_fw/src/main.c')
-rw-r--r-- | center_fw/src/main.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/center_fw/src/main.c b/center_fw/src/main.c new file mode 100644 index 0000000..a521acb --- /dev/null +++ b/center_fw/src/main.c @@ -0,0 +1,196 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "global.h" + +uint16_t adc_data[192]; +bool sync_running = false; + +static void quicksort(uint16_t *head, uint16_t *tail); + +int main(void) { + /* Configure clocks for 64 MHz system clock. + * + * HSI @ 16 MHz --[PLL x16 /4]--> PLL "R" clock @ 64 MHz + */ + /* Enable peripherals */ + RCC->APBENR1 |= RCC_APBENR1_PWREN; + /* Increase flash wait states to 2 required for operation above 48 MHz */ + FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_PRFTEN | (FLASH->ACR & ~FLASH_ACR_LATENCY_Msk) | (2<<FLASH_ACR_LATENCY_Pos); + while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2<<FLASH_ACR_LATENCY_Pos)) { + /* wait for flash controller to acknowledge change. */ + } + /* Configure PLL with multiplier 16, divisor 2 for "R" output, and enable "R" (sysclk) output */ + RCC->PLLCFGR = (16<<RCC_PLLCFGR_PLLN_Pos) | (2<<RCC_PLLCFGR_PLLSRC_Pos) | (3<<RCC_PLLCFGR_PLLR_Pos) | RCC_PLLCFGR_PLLREN; + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) { + /* wait for PLL to stabilize. */ + } + /* Switch SYSCLK to PLL source. */ + RCC->CFGR |= (2<<RCC_CFGR_SW_Pos); + while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != (2<<RCC_CFGR_SWS_Pos)) { + /* wait for RCC to switch over. */ + } + + RCC->AHBENR |= RCC_AHBENR_DMA1EN; + RCC->APBENR1 |= RCC_APBENR1_TIM3EN | RCC_APBENR1_DBGEN; + RCC->APBENR2 |= RCC_APBENR2_TIM1EN | RCC_APBENR2_ADCEN; + RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN | RCC_IOPENR_GPIOCEN; + + TIM1->PSC = 1; + TIM1->ARR = 32767; + TIM1->DIER = TIM_DIER_UIE | TIM_DIER_CC1IE; + TIM1->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN; + TIM1->CCR1 = 3000; + NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); + NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0); + NVIC_EnableIRQ(TIM1_CC_IRQn); + NVIC_SetPriority(TIM1_CC_IRQn, 0); + + TIM3->CR2 = (2<<TIM_CR2_MMS_Pos); /* Update event on TRGO */ + TIM3->PSC = 0; + /* We sample 32 times per 1 kHz AC cycle, and use 16 times oversampling. */ + TIM3->ARR = 124; /* Output 64 MHz / 125 = 512 kHz signal */ + TIM3->CR1 = TIM_CR1_CEN; + + DMAMUX1[0].CCR = 5; /* ADC */ + DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; + DMA1_Channel1->CMAR = (uint32_t)(void *)adc_data; + + NVIC_EnableIRQ(DMA1_Channel1_IRQn); + NVIC_SetPriority(DMA1_Channel1_IRQn, 64); + + ADC1->ISR = ADC_ISR_CCRDY | ADC_ISR_ADRDY; /* Clear CCRDY */ + ADC1->CR = ADC_CR_ADVREGEN; + delay_us(20); + ADC1->CR = ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL) { + /* wait. */ + } + ADC1->CFGR1 = (1<<ADC_CFGR1_EXTEN_Pos) | (3<<ADC_CFGR1_EXTSEL_Pos) | ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* TIM3 TRGO */ + ADC1->CFGR2 = (1<<ADC_CFGR2_CKMODE_Pos) | (4<<ADC_CFGR2_OVSR_Pos) | (1<<ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_TOVS | ADC_CFGR2_OVSE; /* Oversample by 16 */ + ADC1->CHSELR = (1<<4); /* Enable input 4 -> PA4 (Vdiff)*/ + while (!(ADC1->ISR & ADC_ISR_CCRDY)) { + /* wait. */ + } + ADC1->ISR = ADC_ISR_CCRDY; /* Clear CCRDY */ + ADC->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN; + ADC1->CR = ADC_CR_ADVREGEN | ADC_CR_ADEN; + while (!(ADC1->ISR & ADC_ISR_ADRDY)) { + /* wait. */ + } + ADC1->CR |= ADC_CR_ADSTART; + + GPIOA->MODER = OUT(0) | IN(1) | OUT(2) | OUT(3) | ANALOG(4) | OUT(5) | OUT(6) | IN(7) | ANALOG(9) | ANALOG(10) | OUT(11) | ANALOG(12)| AF(13) | AF(14); + GPIOB->MODER = ANALOG(0) | OUT(3) | ANALOG(1) | ANALOG(2) | ANALOG(4) | ANALOG(5) | ANALOG(6) | ANALOG(8) | OUT(7) | ANALOG(9); + GPIOC->MODER = OUT(15) | ANALOG(14) | ANALOG(9); + + DBG->APBFZ1 |= DBG_APB_FZ1_DBG_TIM3_STOP; + while (42) { + } +} + +void TIM1_BRK_UP_TRG_COM_IRQHandler(void) { + TIM1->SR &= ~TIM_SR_UIF; + GPIOB->BSRR = (1<<7); + if (!sync_running) { + while(DMA1_Channel1->CCR != 0) { + DMA1_Channel1->CCR = 0; + } + DMA1_Channel1->CCR = (1<<DMA_CCR_MSIZE_Pos) | (1<<DMA_CCR_PSIZE_Pos) | DMA_CCR_MINC | DMA_CCR_TCIE; + DMA1_Channel1->CNDTR = COUNT_OF(adc_data); + DMA1_Channel1->CCR |= DMA_CCR_EN; + sync_running = true; + } +} + +void TIM1_CC_IRQHandler(void) { + TIM1->SR &= ~TIM_SR_CC1IF; + GPIOB->BRR = (1<<7); +} + +void DMA1_Channel1_IRQHandler(void) { + DMA1->IFCR = DMA_IFCR_CTCIF1; + quicksort(adc_data, &adc_data[COUNT_OF(adc_data)-1]); + asm volatile ("bkpt"); + sync_running = false; +} + +void delay_us(int duration_us) { + while (duration_us--) { + for (int i=0; i<32; i++) { + asm volatile ("nop"); + } + } +} + +void NMI_Handler(void) { + asm volatile ("bkpt"); +} + +void HardFault_Handler(void) __attribute__((naked)); +void HardFault_Handler() { + asm volatile ("bkpt"); +} + +void SVC_Handler(void) { + asm volatile ("bkpt"); +} + + +void PendSV_Handler(void) { + asm volatile ("bkpt"); +} + +void __libc_init_array (void) __attribute__((weak)); +void __libc_init_array () { +} + +/* https://github.com/openmv/openmv/blob/2e8d5d505dbe695b8009d832e5ef7691009148e1/src/omv/common/array.c#L117 */ +static void quicksort(uint16_t *head, uint16_t *tail) { + while (head < tail) { + uint16_t *h = head - 1; + uint16_t *t = tail; + uint16_t v = tail[0]; + for (;;) { + do { + ++h; + } while (h < t && h[0] < v); + do { + --t; + } while (h < t && v < t[0]); + if (h >= t) { + break; + } + uint16_t x = h[0]; + h[0] = t[0]; + t[0] = x; + } + uint16_t x = h[0]; + h[0] = tail[0]; + tail[0] = x; + // do the smaller recursive call first, to keep stack within O(log(N)) + if (t - head < tail - h - 1) { + quicksort(head, t); + head = h + 1; + } else { + quicksort(h + 1, tail); + tail = t; + } + } +} + |