You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tinySA/NANOVNA_STM32_F303/adc.c

269 lines
8.5 KiB

/*
* 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; i++){
adcConvert(&ADCD1, &adcgrpcfgVBAT, samplesVBAT, 1);
vbat+= samplesVBAT[0];
vrefint+= samplesVBAT[1];
}
vbat>>=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

Powered by TurnKey Linux.