/* Megumin LED display firmware * Copyright (C) 2018 Sebastian Götte * * 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 . */ #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<ACR & FLASH_ACR_LATENCY_Msk) != (2<PLLCFGR = (16<CR |= RCC_CR_PLLON; while (!(RCC->CR & RCC_CR_PLLRDY)) { /* wait for PLL to stabilize. */ } /* Switch SYSCLK to PLL source. */ RCC->CFGR |= (2<CFGR & RCC_CFGR_SWS_Msk) != (2<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<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<CFGR2 = (1<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<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; } } }