Skip to content

Commit 8c10240

Browse files
committed
Add ADC support for internal TEMP/VBAT/VREF
* Add ADC support for reading internal temperature sensor. * Add ADC support for reading internal VREF/VBAT monitor.
1 parent 3591285 commit 8c10240

1 file changed

Lines changed: 143 additions & 2 deletions

File tree

stm/adc.c

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@
1313
#define ADCx_CLK (RCC_APB2Periph_ADC1)
1414
#define ADC_NUM_CHANNELS (16)
1515

16+
/* Internally connected ADC channels Temp/VBAT/VREF*/
17+
#if defined (STM32F40XX) || defined(STM32F41XX)
18+
#define ADC_TEMP_CHANNEL (16)
19+
#define ADC_VBAT_CHANNEL (18)
20+
#define ADC_VREF_CHANNEL (17)
21+
#elif defined (STM32F42XX) || defined(STM32F43XX)
22+
#define ADC_TEMP_CHANNEL (18)
23+
#define ADC_VBAT_CHANNEL (18) /* same channel as TEMP */
24+
#define ADC_VREF_CHANNEL (17)
25+
#endif
26+
27+
/* Core temperature sensor definitions */
28+
#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */
29+
#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */
30+
31+
/* VBAT divider */
32+
#if defined (STM32F40XX) || defined(STM32F41XX)
33+
#define VBAT_DIV (2)
34+
#elif defined (STM32F42XX) || defined(STM32F43XX)
35+
#define VBAT_DIV (4)
36+
#endif
37+
1638
/* GPIO struct */
1739
typedef struct {
1840
GPIO_TypeDef* port;
@@ -82,6 +104,12 @@ void adc_init(uint32_t resolution) {
82104

83105
/* Enable ADCx */
84106
ADC_Cmd(ADCx, ENABLE);
107+
108+
/* Enable VBAT/VREF monitor */
109+
ADC_VBATCmd(ENABLE);
110+
111+
/* Enable temperature sensor */
112+
ADC_TempSensorVrefintCmd(ENABLE);
85113
}
86114

87115
uint32_t adc_read_channel(int channel)
@@ -93,7 +121,7 @@ uint32_t adc_read_channel(int channel)
93121
}
94122

95123
/* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */
96-
ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_3Cycles);
124+
ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_15Cycles);
97125

98126
/* Start ADC single conversion */
99127
ADC_SoftwareStartConv(ADCx);
@@ -102,7 +130,7 @@ uint32_t adc_read_channel(int channel)
102130
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
103131
}
104132

105-
/* ADC conversion timed out */
133+
/* ADC conversion timed out */
106134
if (timeout == 0) {
107135
return 0;
108136
}
@@ -111,6 +139,80 @@ uint32_t adc_read_channel(int channel)
111139
return ADC_GetConversionValue(ADCx);
112140
}
113141

142+
int adc_read_core_temp()
143+
{
144+
int timeout = 10000;
145+
146+
/* ADC temperature sensor channel config ADC/Channel/SEQ Rank/Sample time */
147+
/* Note: sample time must be higher than minimum sample time */
148+
ADC_RegularChannelConfig(ADCx, ADC_TEMP_CHANNEL, 1, ADC_SampleTime_480Cycles);
149+
150+
/* Start ADC single conversion */
151+
ADC_SoftwareStartConv(ADCx);
152+
153+
/* Wait for conversion to be complete*/
154+
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
155+
}
156+
157+
/* ADC conversion timed out */
158+
if (timeout == 0) {
159+
return 0;
160+
}
161+
162+
/* Convert ADC reading to temperature */
163+
/* Temperature formula from datasheet P.411 */
164+
return ((ADC_GetConversionValue(ADCx) - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
165+
}
166+
167+
float adc_read_core_vbat()
168+
{
169+
int timeout = 10000;
170+
171+
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
172+
/* Note: sample time must be higher than minimum sample time */
173+
ADC_RegularChannelConfig(ADCx, ADC_VBAT_CHANNEL, 1, ADC_SampleTime_144Cycles);
174+
175+
/* Start ADC single conversion */
176+
ADC_SoftwareStartConv(ADCx);
177+
178+
/* Wait for conversion to be complete */
179+
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
180+
}
181+
182+
/* ADC conversion timed out */
183+
if (timeout == 0) {
184+
return 0;
185+
}
186+
187+
/* Convert ADC reading to voltage, VBAT pin is
188+
internally connected to a bridge divider by VBAT_DIV */
189+
return ADC_GetConversionValue(ADCx)*VBAT_DIV/4096.0f*3.3f;
190+
}
191+
192+
float adc_read_core_vref()
193+
{
194+
int timeout = 10000;
195+
196+
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
197+
/* Note: sample time must be higher than minimum sample time */
198+
ADC_RegularChannelConfig(ADCx, ADC_VREF_CHANNEL, 1, ADC_SampleTime_112Cycles);
199+
200+
/* Start ADC single conversion */
201+
ADC_SoftwareStartConv(ADCx);
202+
203+
/* Wait for conversion to be complete*/
204+
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
205+
}
206+
207+
/* ADC conversion timed out */
208+
if (timeout == 0) {
209+
return 0;
210+
}
211+
212+
/* Convert ADC reading to voltage */
213+
return ADC_GetConversionValue(ADCx)/4096.0f*3.3f;
214+
}
215+
114216
/******************************************************************************/
115217
/* Micro Python bindings */
116218

@@ -132,15 +234,54 @@ static mp_obj_t adc_obj_read_channel(mp_obj_t self_in, mp_obj_t channel) {
132234
return ret;
133235
}
134236

237+
static mp_obj_t adc_obj_read_core_temp(mp_obj_t self_in) {
238+
mp_obj_t ret = mp_const_none;
239+
pyb_adc_obj_t *self = self_in;
240+
241+
if (self->is_enabled) {
242+
int data = adc_read_core_temp();
243+
ret = mp_obj_new_int(data);
244+
}
245+
return ret;
246+
}
247+
248+
static mp_obj_t adc_obj_read_core_vbat(mp_obj_t self_in) {
249+
mp_obj_t ret = mp_const_none;
250+
pyb_adc_obj_t *self = self_in;
251+
252+
if (self->is_enabled) {
253+
float data = adc_read_core_vbat();
254+
ret = mp_obj_new_float(data);
255+
}
256+
return ret;
257+
}
258+
259+
static mp_obj_t adc_obj_read_core_vref(mp_obj_t self_in) {
260+
mp_obj_t ret = mp_const_none;
261+
pyb_adc_obj_t *self = self_in;
262+
263+
if (self->is_enabled) {
264+
float data = adc_read_core_vref();
265+
ret = mp_obj_new_float(data);
266+
}
267+
return ret;
268+
}
269+
135270
static void adc_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
136271
pyb_adc_obj_t *self = self_in;
137272
print(env, "<ADC %lu>", self->adc_id);
138273
}
139274

140275
static MP_DEFINE_CONST_FUN_OBJ_2(adc_obj_read_channel_obj, adc_obj_read_channel);
276+
static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_temp_obj, adc_obj_read_core_temp);
277+
static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_vbat_obj, adc_obj_read_core_vbat);
278+
static MP_DEFINE_CONST_FUN_OBJ_1(adc_obj_read_core_vref_obj, adc_obj_read_core_vref);
141279

142280
static const mp_method_t adc_methods[] = {
143281
{ "read_channel", &adc_obj_read_channel_obj},
282+
{ "read_core_temp", &adc_obj_read_core_temp_obj},
283+
{ "read_core_vbat", &adc_obj_read_core_vbat_obj},
284+
{ "read_core_vref", &adc_obj_read_core_vref_obj},
144285
{ NULL, NULL },
145286
};
146287

0 commit comments

Comments
 (0)