#include #include #include "misc.h" #include "nlr.h" #include "mpconfig.h" #include "qstr.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) || defined(STM32F40_41xxx) #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) || defined(STM32F40_41xxx) #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 const 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_all(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-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 : adc_all object */ typedef struct _pyb_obj_adc_all_t { mp_obj_base_t base; bool is_enabled; } pyb_obj_adc_all_t; static void adc_all_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { print(env, ""); } static mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) { pyb_obj_adc_all_t *self = self_in; if (self->is_enabled) { uint32_t chan = mp_obj_get_int(channel); uint32_t data = adc_read_channel(chan); return mp_obj_new_int(data); } else { return mp_const_none; } } static mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) { pyb_obj_adc_all_t *self = self_in; if (self->is_enabled) { int data = adc_read_core_temp(); return mp_obj_new_int(data); } else { return mp_const_none; } } static mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) { pyb_obj_adc_all_t *self = self_in; if (self->is_enabled) { float data = adc_read_core_vbat(); return mp_obj_new_float(data); } else { return mp_const_none; } } static mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) { pyb_obj_adc_all_t *self = self_in; if (self->is_enabled) { float data = adc_read_core_vref(); return mp_obj_new_float(data); } else { return mp_const_none; } } static MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel); static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp); static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat); static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref); static const mp_method_t adc_all_methods[] = { { "read_channel", &adc_all_read_channel_obj}, { "read_core_temp", &adc_all_read_core_temp_obj}, { "read_core_vbat", &adc_all_read_core_vbat_obj}, { "read_core_vref", &adc_all_read_core_vref_obj}, { NULL, NULL }, }; static const mp_obj_type_t adc_all_type = { { &mp_const_type }, "ADC_all", .print = adc_all_print, .methods = adc_all_methods, }; mp_obj_t pyb_ADC_all(mp_obj_t resolution) { /* init ADC */ adc_init_all(mp_obj_get_int(resolution)); pyb_obj_adc_all_t *o = m_new_obj(pyb_obj_adc_all_t); o->base.type = &adc_all_type; o->is_enabled = true; return o; } MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_all_obj, pyb_ADC_all); /******************************************************************************/ /* Micro Python bindings : adc object (single channel) */ typedef struct _pyb_obj_adc_t { mp_obj_base_t base; mp_obj_t pin_name; int channel; bool is_enabled; } pyb_obj_adc_t; static void adc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_obj_adc_t *self = self_in; print(env, "pin_name, PRINT_STR); print(env, " channel=%lu>", self->channel); } static mp_obj_t adc_read(mp_obj_t self_in) { pyb_obj_adc_t *self = self_in; if (self->is_enabled) { uint32_t data = adc_read_channel(self->channel); return mp_obj_new_int(data); } else { return mp_const_none; } } static MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); static const mp_method_t adc_methods[] = { { "read", &adc_read_obj}, { NULL, NULL }, }; static const mp_obj_type_t adc_type = { { &mp_const_type }, "ADC", .print = adc_print, .methods = adc_methods, }; mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) { pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); o->base.type = &adc_type; o->pin_name = pin_name_obj; // work out the channel from the pin name const char *pin_name = mp_obj_str_get_str(pin_name_obj); GPIO_TypeDef *port; switch (pin_name[0]) { case 'A': case 'a': port = GPIOA; break; case 'B': case 'b': port = GPIOB; break; case 'C': case 'c': port = GPIOC; break; default: goto pin_error; } uint pin_num = 0; for (const char *s = pin_name + 1; *s; s++) { if (!('0' <= *s && *s <= '9')) { goto pin_error; } pin_num = 10 * pin_num + *s - '0'; } if (!(0 <= pin_num && pin_num <= 15)) { goto pin_error; } int i; for (i = 0; i < ADC_NUM_CHANNELS; i++) { if (adc_gpio[i].port == port && adc_gpio[i].pin == (1 << pin_num)) { o->channel = i; break; } } if (i == ADC_NUM_CHANNELS) { nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %s does not have ADC capabilities", pin_name)); } // init ADC just for this channel adc_init_single(o->channel); o->is_enabled = true; return o; pin_error: nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %s does not exist", pin_name)); } MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_obj, pyb_ADC);