summaryrefslogtreecommitdiffstatshomepage
path: root/stm/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm/adc.c')
-rw-r--r--stm/adc.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/stm/adc.c b/stm/adc.c
new file mode 100644
index 0000000000..1f666c2718
--- /dev/null
+++ b/stm/adc.c
@@ -0,0 +1,304 @@
+#include <stdio.h>
+#include <stm32f4xx_rcc.h>
+#include <stm32f4xx_gpio.h>
+#include <stm32f4xx_adc.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "obj.h"
+#include "adc.h"
+
+/* ADC defintions */
+#define ADCx (ADC1)
+#define ADCx_CLK (RCC_APB2Periph_ADC1)
+#define ADC_NUM_CHANNELS (16)
+
+/* Internally connected ADC channels Temp/VBAT/VREF*/
+#if defined (STM32F40XX) || defined(STM32F41XX)
+#define ADC_TEMP_CHANNEL (16)
+#define ADC_VBAT_CHANNEL (18)
+#define ADC_VREF_CHANNEL (17)
+#elif defined (STM32F42XX) || defined(STM32F43XX)
+#define ADC_TEMP_CHANNEL (18)
+#define ADC_VBAT_CHANNEL (18) /* same channel as TEMP */
+#define ADC_VREF_CHANNEL (17)
+#endif
+
+/* Core temperature sensor definitions */
+#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */
+#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */
+
+/* VBAT divider */
+#if defined (STM32F40XX) || defined(STM32F41XX)
+#define VBAT_DIV (2)
+#elif defined (STM32F42XX) || defined(STM32F43XX)
+#define VBAT_DIV (4)
+#endif
+
+/* GPIO struct */
+typedef struct {
+ GPIO_TypeDef* port;
+ uint32_t pin;
+} gpio_t;
+
+/* ADC GPIOs */
+static gpio_t adc_gpio[] = {
+ {GPIOA, GPIO_Pin_0}, /* ADC123_IN0 */
+ {GPIOA, GPIO_Pin_1}, /* ADC123_IN1 */
+ {GPIOA, GPIO_Pin_2}, /* ADC123_IN2 */
+ {GPIOA, GPIO_Pin_3}, /* ADC123_IN3 */
+ {GPIOA, GPIO_Pin_4}, /* ADC12_IN4 */
+ {GPIOA, GPIO_Pin_5}, /* ADC12_IN5 */
+ {GPIOA, GPIO_Pin_6}, /* ADC12_IN6 */
+ {GPIOA, GPIO_Pin_7}, /* ADC12_IN7 */
+ {GPIOB, GPIO_Pin_0}, /* ADC12_IN8 */
+ {GPIOB, GPIO_Pin_1}, /* ADC12_IN9 */
+ {GPIOC, GPIO_Pin_0}, /* ADC123_IN10 */
+ {GPIOC, GPIO_Pin_1}, /* ADC123_IN11 */
+ {GPIOC, GPIO_Pin_2}, /* ADC123_IN12 */
+ {GPIOC, GPIO_Pin_3}, /* ADC123_IN13 */
+ {GPIOC, GPIO_Pin_4}, /* ADC12_IN14 */
+ {GPIOC, GPIO_Pin_5}, /* ADC12_IN15 */
+
+};
+
+void adc_init(uint32_t resolution) {
+ ADC_InitTypeDef ADC_InitStructure;
+ GPIO_InitTypeDef GPIO_InitStructure;
+ ADC_CommonInitTypeDef ADC_CommonInitStructure;
+
+ /* Enable ADCx, DMA and GPIO clocks */
+#if 0
+ /* GPIO clocks enabled in main */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
+ RCC_AHB1Periph_GPIOB |
+ RCC_AHB1Periph_GPIOC, ENABLE);
+#endif
+ RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
+
+ /* ADC Common Init */
+ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
+ ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
+ ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
+ ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
+ ADC_CommonInit(&ADC_CommonInitStructure);
+
+ /* Configure ADC GPIOs */
+ for (int i=0; i<ADC_NUM_CHANNELS; i++) {
+ GPIO_InitStructure.GPIO_Pin = adc_gpio[i].pin;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(adc_gpio[i].port, &GPIO_InitStructure);
+ }
+
+ /* ADCx Init */
+// ADC_DeInit();
+ ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
+ ADC_InitStructure.ADC_ScanConvMode = DISABLE;
+ ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
+ ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
+ ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
+ ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
+ ADC_InitStructure.ADC_NbrOfConversion = 1;
+ ADC_Init(ADCx, &ADC_InitStructure);
+
+ /* Enable ADCx */
+ ADC_Cmd(ADCx, ENABLE);
+
+ /* Enable VBAT/VREF monitor */
+ ADC_VBATCmd(ENABLE);
+
+ /* Enable temperature sensor */
+ ADC_TempSensorVrefintCmd(ENABLE);
+}
+
+uint32_t adc_read_channel(int channel)
+{
+ int timeout = 10000;
+
+ if (channel > (ADC_NUM_CHANNELS-1)) {
+ return 0;
+ }
+
+ /* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */
+ ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_15Cycles);
+
+ /* Start ADC single conversion */
+ ADC_SoftwareStartConv(ADCx);
+
+ /* Wait for conversion to be complete*/
+ while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
+ }
+
+ /* ADC conversion timed out */
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* Return converted data */
+ return ADC_GetConversionValue(ADCx);
+}
+
+int adc_read_core_temp()
+{
+ int timeout = 10000;
+
+ /* ADC temperature sensor channel config ADC/Channel/SEQ Rank/Sample time */
+ /* Note: sample time must be higher than minimum sample time */
+ ADC_RegularChannelConfig(ADCx, ADC_TEMP_CHANNEL, 1, ADC_SampleTime_480Cycles);
+
+ /* Start ADC single conversion */
+ ADC_SoftwareStartConv(ADCx);
+
+ /* Wait for conversion to be complete*/
+ while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
+ }
+
+ /* ADC conversion timed out */
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* Convert ADC reading to temperature */
+ /* Temperature formula from datasheet P.411 */
+ return ((ADC_GetConversionValue(ADCx) - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
+}
+
+float adc_read_core_vbat()
+{
+ int timeout = 10000;
+
+ /* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
+ /* Note: sample time must be higher than minimum sample time */
+ ADC_RegularChannelConfig(ADCx, ADC_VBAT_CHANNEL, 1, ADC_SampleTime_144Cycles);
+
+ /* Start ADC single conversion */
+ ADC_SoftwareStartConv(ADCx);
+
+ /* Wait for conversion to be complete */
+ while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
+ }
+
+ /* ADC conversion timed out */
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* Convert ADC reading to voltage, VBAT pin is
+ internally connected to a bridge divider by VBAT_DIV */
+ return ADC_GetConversionValue(ADCx)*VBAT_DIV/4096.0f*3.3f;
+}
+
+float adc_read_core_vref()
+{
+ int timeout = 10000;
+
+ /* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
+ /* Note: sample time must be higher than minimum sample time */
+ ADC_RegularChannelConfig(ADCx, ADC_VREF_CHANNEL, 1, ADC_SampleTime_112Cycles);
+
+ /* Start ADC single conversion */
+ ADC_SoftwareStartConv(ADCx);
+
+ /* Wait for conversion to be complete*/
+ while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
+ }
+
+ /* ADC conversion timed out */
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* Convert ADC reading to voltage */
+ return ADC_GetConversionValue(ADCx)/4096.0f*3.3f;
+}
+
+/******************************************************************************/
+/* Micro Python bindings */
+
+typedef struct _pyb_adc_obj_t {
+ mp_obj_base_t base;
+ int adc_id;
+ bool is_enabled;
+} pyb_adc_obj_t;
+
+static mp_obj_t adc_obj_read_channel(mp_obj_t self_in, mp_obj_t channel) {
+ mp_obj_t ret = mp_const_none;
+ pyb_adc_obj_t *self = self_in;
+
+ if (self->is_enabled) {
+ uint32_t chan = mp_obj_get_int(channel);
+ uint32_t data = adc_read_channel(chan);
+ ret = mp_obj_new_int(data);
+ }
+ return ret;
+}
+
+static mp_obj_t adc_obj_read_core_temp(mp_obj_t self_in) {
+ mp_obj_t ret = mp_const_none;
+ pyb_adc_obj_t *self = self_in;
+
+ if (self->is_enabled) {
+ int data = adc_read_core_temp();
+ ret = mp_obj_new_int(data);
+ }
+ return ret;
+}
+
+static mp_obj_t adc_obj_read_core_vbat(mp_obj_t self_in) {
+ mp_obj_t ret = mp_const_none;
+ pyb_adc_obj_t *self = self_in;
+
+ if (self->is_enabled) {
+ float data = adc_read_core_vbat();
+ ret = mp_obj_new_float(data);
+ }
+ return ret;
+}
+
+static mp_obj_t adc_obj_read_core_vref(mp_obj_t self_in) {
+ mp_obj_t ret = mp_const_none;
+ pyb_adc_obj_t *self = self_in;
+
+ if (self->is_enabled) {
+ float data = adc_read_core_vref();
+ ret = mp_obj_new_float(data);
+ }
+ return ret;
+}
+
+static void adc_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
+ pyb_adc_obj_t *self = self_in;
+ print(env, "<ADC %lu>", self->adc_id);
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_2(adc_obj_read_channel_obj, adc_obj_read_channel);
+static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_temp_obj, adc_obj_read_core_temp);
+static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_vbat_obj, adc_obj_read_core_vbat);
+static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_vref_obj, adc_obj_read_core_vref);
+
+static const mp_method_t adc_methods[] = {
+ { "read_channel", &adc_obj_read_channel_obj},
+ { "read_core_temp", &adc_obj_read_core_temp_obj},
+ { "read_core_vbat", &adc_obj_read_core_vbat_obj},
+ { "read_core_vref", &adc_obj_read_core_vref_obj},
+ { NULL, NULL },
+};
+
+static const mp_obj_type_t adc_obj_type = {
+ { &mp_const_type },
+ "ADC",
+ .print = adc_obj_print,
+ .methods = adc_methods,
+};
+
+mp_obj_t pyb_ADC(mp_obj_t resolution) {
+ /* init ADC */
+ adc_init(mp_obj_get_int(resolution));
+
+ pyb_adc_obj_t *o = m_new_obj(pyb_adc_obj_t);
+ o->base.type = &adc_obj_type;
+ o->adc_id = 1;
+ o->is_enabled = true;
+ return o;
+}