/* * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com * All rights reserved. * * This 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, or (at your option) * any later version. * * The software 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include "ch.h" #include "hal.h" #include "nanovna.h" #define ADC_FULL_SCALE 3300 #define F303_ADC_VREF_ALWAYS_ON #define ADC_CHSELR_VREFINT ADC_CHANNEL_IN18 #define ADC_CHSELR_VBAT ADC_CHANNEL_IN17 #define ADC_TOUCH_SMP_TIME ADC_SMPR_SMP_1P5 #define ADC_TOUCH_XY_SMP_TIME ADC_SMPR_SMP_601P5 #define ADC_VBAT_SMP_TIME ADC_SMPR_SMP_601P5 #define ADC_GRP_NUM_CHANNELS_VBAT 2 static adcsample_t samplesVBAT[ADC_GRP_NUM_CHANNELS_VBAT]; static adcsample_t samples[1]; static const ADCConversionGroup adcgrpcfgVBAT = { FALSE, ADC_GRP_NUM_CHANNELS_VBAT, NULL, NULL, ADC_CFGR_CONT | ADC_CFGR1_RES_12BIT, // CFGR1 ADC_TR(0, 0), // ADC watchdog threshold TR1 {0, ADC_SMPR2_SMP_AN16(ADC_VBAT_SMP_TIME) | ADC_SMPR2_SMP_AN17(ADC_VBAT_SMP_TIME)/*| ADC_SMPR2_SMP_AN18(ADC_VBAT_SMP_TIME)*/}, // SMPR {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN17) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN18)/*| ADC_SQR1_SQ3_N(ADC_CHANNEL_IN16)*/, 0, 0, 0} // CHSELR }; static const ADCConversionGroup adcgrpcfgVersion = { FALSE, 1, NULL, NULL, ADC_CFGR1_RES_12BIT, // CFGR1 ADC_TR(0, 0), // ADC watchdog threshold TR1 {ADC_SMPR1_SMP_AN1(ADC_TOUCH_XY_SMP_TIME), 0}, /* SMPR[2] */ {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1), 0, 0, 0} /* SQR[4] */ }; static const ADCConversionGroup adcgrpcfgTouch = { TRUE, // Enables the circular buffer mode for the group. 1, // Number of the analog channels belonging to the conversion group. NULL, // adccallback_touch NULL, // adcerrorcallback_touch // CFGR ADC_CFGR_EXTEN_0 // rising edge of external trigger | ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0 // EXT4 0x1001 event (TIM1_TRGO) // | ADC_CFGR_EXTSEL_2 // EXT4 0x100 event (TIM3_TRGO) | ADC_CFGR_AWD1EN, // Enable Analog watchdog check interrupt ADC_TR(0, TOUCH_THRESHOLD), // Analog watchdog threshold TR1, interrupt on touch press {ADC_SMPR1_SMP_AN4(ADC_TOUCH_SMP_TIME), 0}, // SMPR[2] {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN4), 0, 0, 0} // SQR[4] }; static ADCConversionGroup adcgrpcfgXY = { FALSE, 1, NULL, /* adccallback_touch */ NULL, /* adcerrorcallback_touch */ ADC_CFGR1_RES_12BIT, /* CFGR */ ADC_TR(0, 0), /* TR1 */ {ADC_SMPR1_SMP_AN3(ADC_TOUCH_XY_SMP_TIME) | ADC_SMPR1_SMP_AN4(ADC_TOUCH_XY_SMP_TIME), 0}, /* SMPR[2] */ {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN3), 0, 0, 0} /* SQR[4] */ }; void adc_init(void) { adcStart(&ADCD2, NULL); adcStart(&ADCD1, NULL); #ifdef F303_ADC_VREF_ALWAYS_ON adcSTM32EnableVBAT(&ADCD1); adcSTM32EnableVREF(&ADCD1); // adcSTM32EnableTS(&ADCD1); #endif } uint16_t adc_single_read(uint32_t chsel) { /* ADC setup */ // adcStart(&ADCD2, NULL); adcgrpcfgXY.sqr[0] = ADC_SQR1_SQ1_N(chsel); adcConvert(&ADCD2, &adcgrpcfgXY, samples, 1); return(samples[0]); } uint16_t adc1_single_read(uint32_t chsel) { (void)chsel; /* ADC setup */ adcConvert(&ADCD1, &adcgrpcfgVersion, samples, 1); return(samples[0]); } int16_t adc_vbat_read(void) { // Vbat measure averange count = 2^VBAT_AVERAGE #define VBAT_AVERAGE 4 // Measure vbat every 5 second #define VBAT_MEASURE_INTERVAL S2ST(5) static int16_t vbat_raw = 0; static systime_t vbat_time = -VBAT_MEASURE_INTERVAL-1; systime_t _time = chVTGetSystemTimeX(); if (_time - vbat_time < VBAT_MEASURE_INTERVAL) goto return_cached; vbat_time = _time; uint16_t VREFINT_CAL = (*((uint16_t*)0x1FFFF7BA)); uint32_t vrefint = 0; uint32_t vbat = 0; // const uint16_t V25 = 1750;// when V25=1.41V at ref 3.3V // const uint16_t Avg_Slope = 5; //when avg_slope=4.3mV/C at ref 3.3V // uint16_t temperature_cal1 = *((uint16_t*) ((uint32_t)0x1FFFF7B8U)); // /* Internal temperature sensor, address of parameter TS_CAL1: On STM32F3, // temperature sensor ADC raw data acquired at temperature 25 DegC (tolerance: +-5 DegC), // Vref+ = 3.3 V (tolerance: +-10 mV). */ // uint16_t temperature_cal2 = *((uint16_t*) ((uint32_t)0x1FFFF7C2U)); // /* Internal temperature sensor, address of parameter TS_CAL2: On STM32F3, // temperature sensor ADC raw data acquired at temperature 110 DegC (tolerance: +-5 DegC), // Vref+ = 3.3 V (tolerance: +-10 mV). */ // float avg_slope = ((float)(temperature_cal1 - temperature_cal2))/(110-25); // float ts; #ifndef F303_ADC_VREF_ALWAYS_ON adcSTM32EnableVBAT(&ADCD1); adcSTM32EnableVREF(&ADCD1); // adcSTM32EnableTS(&ADCD1); #endif for (uint16_t i = 0; i < 1<>=VBAT_AVERAGE; vrefint>>=VBAT_AVERAGE; #ifndef F303_ADC_VREF_ALWAYS_ON adcSTM32DisableVBAT(&ADCD1); adcSTM32DisableVREF(&ADCD1); // adcSTM32DisableTS(&ADCD1); #endif // ts = samplesVBAT[2]; // uint16_t vts = (ADC_FULL_SCALE * VREFINT_CAL * ts / (vrefint * ((1<<12)-1))); // uint16_t TemperatureC2 = (uint16_t)((V25-ts)/Avg_Slope+25); // uint16_t TemperatureC = (uint16_t)((V25-ts)/avg_slope+25); // vbat_raw = (3000 * 2 * vbat / 4095) * (VREFINT_CAL / vrefint) // uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * (float)vbat * 2 / (vrefint * ((1<<12)-1))); // For speed divide not on 4095, divide on 4096, get little error, but no matter vbat_raw = ((ADC_FULL_SCALE * 2 * vbat)>>12) * VREFINT_CAL / vrefint; return_cached: if (vbat_raw < 100) { // maybe D2 is not installed return -1; } return vbat_raw + config.vbat_offset; } void adc_start_analog_watchdog(void) { adcStartConversion(&ADCD2, &adcgrpcfgTouch, samples, 1); } void adc_stop_analog_watchdog(void) { adcStopConversion(&ADCD2); } static inline void adc_interrupt(void) { uint32_t isr = ADC2->ISR; ADC2->ISR = isr; if (isr & ADC_ISR_OVR) { // ADC overflow condition, this could happen only if the DMA is unable to read data fast enough. } if (isr & ADC_ISR_AWD1) { /* Analog watchdog error.*/ handle_touch_interrupt(); } } OSAL_IRQ_HANDLER(STM32_ADC2_HANDLER) { OSAL_IRQ_PROLOGUE(); adc_interrupt(); OSAL_IRQ_EPILOGUE(); } #if 0 uint16_t adc_multi_read(uint32_t chsel, uint16_t *result, uint32_t count) { /* ADC setup */ VNA_ADC->ISR = VNA_ADC->ISR; VNA_ADC->IER = 0; VNA_ADC->TR = ADC_TR(0, 0); VNA_ADC->SMPR = ADC_SMPR_SMP_1P5; VNA_ADC->CFGR1 = ADC_CFGR1_RES_12BIT; VNA_ADC->CHSELR = chsel; // palSetPadMode(GPIOA, 10, PAL_MODE_OUTPUT_PUSHPULL); do{ #if 0 if (count < 145) palSetPad(GPIOA, 10); else palClearPad(GPIOA, 10); #endif VNA_ADC->CR |= ADC_CR_ADSTART; // ADC conversion start. // while (VNA_ADC->CR & ADC_CR_ADSTART) while(!(VNA_ADC->ISR & ADC_ISR_EOC)); ; *(result++) =VNA_ADC->DR; }while(--count); return count; } int16_t adc_buf_read(uint32_t chsel, uint16_t *result, uint32_t count) { adc_stop(); #if 0 // drive high to low on Y line (coordinates from left to right) palSetPad(GPIOB, GPIOB_YN); palClearPad(GPIOA, GPIOA_YP); // Set Y line as output palSetPadMode(GPIOB, GPIOB_YN, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOA, GPIOA_YP, PAL_MODE_OUTPUT_PUSHPULL); // Set X line as input palSetPadMode(GPIOB, GPIOB_XN, PAL_MODE_INPUT); // Hi-z mode palSetPadMode(GPIOA, GPIOA_XP, PAL_MODE_INPUT_ANALOG); // <- ADC_TOUCH_X channel uint16_t res = adc_multi_read(ADC_TOUCH_X, result, count); #else // palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_ANALOG); uint16_t res = adc_multi_read(chsel, result, count); // ADC_CHSELR_CHSEL9 #endif touch_start_watchdog(); return res; } #endif