From 322b306bf2d59fbfbcf93784362aac8a695b1ca3 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 10 Dec 2017 13:11:30 +0100 Subject: ADC properly triggering now --- fw/main.c | 83 +++++++++++++++++++++++++++++++++++++++++++--------------- fw/transpose.h | 1 + 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/fw/main.c b/fw/main.c index 4e4ef36..108d3a1 100644 --- a/fw/main.c +++ b/fw/main.c @@ -162,8 +162,11 @@ void cfg_spi1() { /* FIXME maybe try w/o BIDI */ } +/* This is a lookup table mapping segments to present a standard segment order on the UART interface. This is converted + * into an internal representation once on startup in main(). The data type must be at least uint16. */ uint32_t segment_map[8] = {5, 7, 6, 4, 1, 3, 0, 2}; +/* The value to be written into the aux register. This encompasses LED state as well as the current setting bits. */ static volatile uint32_t aux_reg = 0; static volatile int frame_duration_us; volatile int nbits = MAX_BITS; @@ -171,17 +174,34 @@ volatile int nbits = MAX_BITS; static unsigned int active_bit = 0; static int active_segment = 0; -/* Bit timing base value. This is the lowes bit interval used */ +/* Bit timing base value. This is the lowes bit interval used in TIM1/TIM3 timer counts. */ #define PERIOD_BASE 4 /* This value is a constant offset added to every bit period to allow for the timer IRQ handler to execute. This is set - * empirically using a debugger and a logic analyzer. */ + * empirically using a debugger and a logic analyzer. + * + * This value is in TIM1/TIM3 timer counts. */ #define TIMER_CYCLES_FOR_SPI_TRANSMISSIONS 9 +/* This value sets the point when the LED strobe is asserted after the begin of the current bit cycle and IRQ + * processing. This must be less than TIMER_CYCLES_FOR_SPI_TRANSMISSIONS but must be large enough to allow for the SPI + * transmission to reliably finish. + * + * This value is in TIM1/TIM3 timer counts. */ #define TIMER_CYCLES_BEFORE_LED_STROBE 8 -#define AUX_SPI_PRETRIGGER 64 -#define ADC_PRETRIGGER 64 +/* This value sets how long the TIM1 CC IRQ used for AUX register setting etc. is triggered before the end of the + * longest cycle. This value should not be larger than PERIOD_BASE<BDTR = TIM_BDTR_MOE; TIM1->CCMR1 = (6<CCER = TIM_CCER_CC1E | TIM_CCER_CC2E; + TIM1->CCMR2 = (6<CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC4E; TIM1->CCR2 = TIMER_CYCLES_BEFORE_LED_STROBE; /* Trigger at the end of the longest bit cycle. This means this does not trigger in shorter bit cycles. */ TIM1->CCR1 = timer_period_lookup[nbits-1] - AUX_SPI_PRETRIGGER; + TIM1->CCR4 = timer_period_lookup[nbits-1] - ADC_PRETRIGGER; TIM1->DIER = TIM_DIER_CC1IE; TIM1->ARR = 0xffff; /* This is as large as possible since TIM1 is reset by TIM3. */ @@ -284,6 +305,7 @@ void cfg_timers_led() { void TIM1_CC_IRQHandler() { /* This handler takes about 1.5us */ + GPIOA->BSRR = GPIO_BSRR_BS_0; // Debug /* Set SPI baudrate to 12.5MBd for slow-ish 74HC(T)595. This is reset again in TIM3's IRQ handler.*/ SPI1->CR1 |= (2<BSRR = GPIO_BSRR_BR_10; /* Send AUX register data */ SPI1->DR = aux_reg | segment_map[active_segment]; - /* Kick off ADC for (oversampled) temperature measurement */ - ADC1->CR |= ADC_CR_ADSTART; /* Clear interrupt flag */ TIM1->SR &= ~TIM_SR_CC1IF_Msk; + + GPIOA->BSRR = GPIO_BSRR_BR_0; // Debug } void TIM3_IRQHandler() { /* This handler takes about 2.1us */ + GPIOA->BSRR = GPIO_BSRR_BS_0; // Debug /* Reset SPI baudrate to 25MBd for fast MBI5026. Every couple of cycles, TIM1's ISR will set this to a slower value * for the slower AUX registers.*/ @@ -344,6 +367,8 @@ void TIM3_IRQHandler() { /* Clear interrupt flag */ TIM3->SR &= ~TIM_SR_UIF_Msk; + + GPIOA->BSRR = GPIO_BSRR_BR_0; // Debug } enum Command { @@ -476,8 +501,6 @@ void USART1_IRQHandler(void) { /* COBS skip counter. During payload processing this contains the remaining non-null payload bytes */ static int cobs_count = 0; - GPIOA->BSRR = GPIO_BSRR_BS_0; // Debug - if (USART1->ISR & USART_ISR_ORE) { /* Overrun handling */ overruns++; /* Reset and re-synchronize. Retry next frame. */ @@ -516,26 +539,30 @@ void USART1_IRQHandler(void) { } } } - - GPIOA->BSRR = GPIO_BSRR_BR_0; // Debug } #define ADC_OVERSAMPLING 4 uint32_t vsense; void DMA1_Channel1_IRQHandler(void) { + /* This interrupt takes either 1.2us or 13us. It can be pre-empted by the more timing-critical UART and LED timer + * interrupts. */ GPIOA->BSRR = GPIO_BSRR_BS_4; // Debug - static int count = 0; - static uint32_t adc_aggregate[2] = {0, 0}; + static int count = 0; /* oversampling accumulator sample count */ + static uint32_t adc_aggregate[2] = {0, 0}; /* oversampling accumulator */ + /* Clear the interrupt flag */ DMA1->IFCR |= DMA_IFCR_CGIF1; adc_aggregate[0] += adc_buf[0]; adc_aggregate[1] += adc_buf[1]; if (count++ == (1<>ADC_OVERSAMPLING); vsense = ((adc_aggregate[1]>>ADC_OVERSAMPLING) * adc_vcc_mv)/4095 ; adc_temp_tenth_celsius = 300 - (((TS_CAL1*adc_vcc_mv/4095) - vsense)*100)/43; + /* Reset oversampling state */ count = 0; adc_aggregate[0] = 0; adc_aggregate[1] = 0; @@ -544,29 +571,43 @@ void DMA1_Channel1_IRQHandler(void) { } void adc_config(void) { - ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; - ADC1->CFGR2 = (1<SMPR = (7<CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<CFGR2 = (2<SMPR = (7<CHSELR = ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; + /* Enable internal voltage reference and temperature sensor */ ADC->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN; + /* Perform ADC calibration */ ADC1->CR |= ADC_CR_ADCAL; while (ADC1->CR & ADC_CR_ADCAL) ; + /* Enable ADC */ ADC1->CR |= ADC_CR_ADEN; - /* FIXME handle adc overrun */ + ADC1->CR |= ADC_CR_ADSTART; + /* Configure DMA 1 Channel 1 to get rid of all the data */ DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR; DMA1_Channel1->CMAR = (unsigned int)&adc_buf; DMA1_Channel1->CNDTR = sizeof(adc_buf)/sizeof(adc_buf[0]); DMA1_Channel1->CCR = (0<CCR |= - DMA_CCR_CIRC + DMA_CCR_CIRC /* circular mode so we can leave it running indefinitely */ | (1<CCR |= DMA_CCR_EN; + | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */ + DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */ + /* triggered on transfer completion. We use this to process the ADC data */ NVIC_EnableIRQ(DMA1_Channel1_IRQn); NVIC_SetPriority(DMA1_Channel1_IRQn, 3); } diff --git a/fw/transpose.h b/fw/transpose.h index b1ca41b..389071c 100644 --- a/fw/transpose.h +++ b/fw/transpose.h @@ -8,6 +8,7 @@ enum { NROWS = 4, NCOLS = 8, MAX_BITS = 10, + MIN_BITS = 6, }; enum { -- cgit