microscope-ring-light-remot.../poti.c

125 lines
2.7 KiB
C

#include "stm32f030x6.h"
#include <poti.h>
#include <stdint.h>
const uint8_t adc_channels[POTI_COUNT] = {POTI_ADC_CHANNELS};
static volatile uint16_t adc_raw_values[POTI_COUNT];
static volatile uint16_t adc_moving_avg[POTI_COUNT];
static volatile uint8_t adc_moving_avg_out[POTI_COUNT];
/**
* @brief Perform calibration. ADC must be disabled
*/
static void perform_cal(void)
{
ADC1->CR = ADC_CR_ADCAL;
while (ADC1->CR & ADC_CR_ADCAL);
(void)ADC1->DR;
}
void poti_init_adc(void)
{
int i;
uint32_t reg;
RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
RCC->AHBENR |= RCC_AHBENR_DMAEN;
for (i = 0; i < POTI_COUNT; i++) {
adc_moving_avg[i] = 0u;
}
DMA1_Channel1->CCR = 0ul;
/* Clear ADC ready bit */
ADC1->ISR = ADC_ISR_ADRDY;
ADC1->CFGR1 = 0;
/* Start calibration */
perform_cal();
/* Activate channels to convert */
reg = 0ul;
for (i = 0; i < POTI_COUNT; i++) {
if (adc_channels[i] <= 17)
reg |= (1<<adc_channels[i]);
}
ADC1->CHSELR = reg;
/* Setup sample time (239.5 cycles) */
ADC1->SMPR = ADC_SMPR_SMP_2 | ADC_SMPR_SMP_1 | ADC_SMPR1_SMPR_0;
/* Setup ADC clock (PCLK / 4) */
ADC1->CFGR2 = ADC_CFGR2_CKMODE_1;
/* Setup continuous sample mode with DMA in circular mode */
ADC1->CFGR1 = ADC_CFGR1_CONT | ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG;
/* Enable ADC and wait for ready */
ADC1->CR = ADC_CR_ADEN;
while (!(ADC1->ISR & ADC_ISR_ADRDY));
/* Setup DMA channel 1 */
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
DMA1_Channel1->CMAR = (uint32_t)adc_raw_values;
DMA1_Channel1->CNDTR = POTI_COUNT;
DMA1_Channel1->CCR = DMA_CCR_PL_0 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC |
DMA_CCR_CIRC | DMA_CCR_TCIE | DMA_CCR_EN;
/* Enable Interrupt with lower priority. Prevents jitter on the DMX lines */
NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* Start the conversion */
ADC1->CR |= ADC_CR_ADSTART;
}
void poti_get_values(struct poti_values *out_val)
{
int i;
if (!out_val)
return;
for (i = 0; i < POTI_COUNT; i++) {
/* return iverted values, because of potentiometer polarities */
out_val->current_pot_vals[i] = ~adc_raw_values[i];
out_val->pot_vals_filtered[i] = ~adc_moving_avg_out[i];
}
}
static uint16_t calc_moving_avg(uint16_t adc_val, uint16_t prev_avg)
{
uint32_t val;
val = (uint32_t)prev_avg;
val /= 16u;
val *= 15u;
val += adc_val;
return val;
}
void DMA_CH1_IRQHandler(void)
{
uint32_t isr;
int i;
isr = DMA1->ISR;
DMA1->IFCR = isr & DMA_ISR_TCIF1;
if (isr & DMA_ISR_TCIF1) {
/* All ADC samples converted */
for (i = 0; i < POTI_COUNT; i++) {
adc_moving_avg[i] = calc_moving_avg(adc_raw_values[i], adc_moving_avg[i]);
adc_moving_avg_out[i] = (uint8_t)(adc_moving_avg[i] / 16u / 16u);
}
}
}