Skip to content

Commit a04a33f

Browse files
committed
Merge pull request adafruit#175 from iabdalkader/master
Add missing ADC driver
2 parents 11cc694 + 8c10240 commit a04a33f

6 files changed

Lines changed: 2711 additions & 0 deletions

File tree

stm/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ SRC_C = \
5757
pybwlan.c \
5858
i2c.c \
5959
usrsw.c \
60+
adc.c \
6061

6162
SRC_S = \
6263
startup_stm32f40xx.s \
@@ -100,6 +101,7 @@ SRC_STM = \
100101
usbd_storage_msd.c \
101102
stm324x7i_eval.c \
102103
stm324x7i_eval_sdio_sd.c \
104+
stm32f4xx_adc.c \
103105

104106
#SRC_STM_OTG = \
105107
# usb_hcd.c \

stm/adc.c

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#include <stdio.h>
2+
#include <stm32f4xx_rcc.h>
3+
#include <stm32f4xx_gpio.h>
4+
#include <stm32f4xx_adc.h>
5+
6+
#include "misc.h"
7+
#include "mpconfig.h"
8+
#include "obj.h"
9+
#include "adc.h"
10+
11+
/* ADC defintions */
12+
#define ADCx (ADC1)
13+
#define ADCx_CLK (RCC_APB2Periph_ADC1)
14+
#define ADC_NUM_CHANNELS (16)
15+
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+
38+
/* GPIO struct */
39+
typedef struct {
40+
GPIO_TypeDef* port;
41+
uint32_t pin;
42+
} gpio_t;
43+
44+
/* ADC GPIOs */
45+
static gpio_t adc_gpio[] = {
46+
{GPIOA, GPIO_Pin_0}, /* ADC123_IN0 */
47+
{GPIOA, GPIO_Pin_1}, /* ADC123_IN1 */
48+
{GPIOA, GPIO_Pin_2}, /* ADC123_IN2 */
49+
{GPIOA, GPIO_Pin_3}, /* ADC123_IN3 */
50+
{GPIOA, GPIO_Pin_4}, /* ADC12_IN4 */
51+
{GPIOA, GPIO_Pin_5}, /* ADC12_IN5 */
52+
{GPIOA, GPIO_Pin_6}, /* ADC12_IN6 */
53+
{GPIOA, GPIO_Pin_7}, /* ADC12_IN7 */
54+
{GPIOB, GPIO_Pin_0}, /* ADC12_IN8 */
55+
{GPIOB, GPIO_Pin_1}, /* ADC12_IN9 */
56+
{GPIOC, GPIO_Pin_0}, /* ADC123_IN10 */
57+
{GPIOC, GPIO_Pin_1}, /* ADC123_IN11 */
58+
{GPIOC, GPIO_Pin_2}, /* ADC123_IN12 */
59+
{GPIOC, GPIO_Pin_3}, /* ADC123_IN13 */
60+
{GPIOC, GPIO_Pin_4}, /* ADC12_IN14 */
61+
{GPIOC, GPIO_Pin_5}, /* ADC12_IN15 */
62+
63+
};
64+
65+
void adc_init(uint32_t resolution) {
66+
ADC_InitTypeDef ADC_InitStructure;
67+
GPIO_InitTypeDef GPIO_InitStructure;
68+
ADC_CommonInitTypeDef ADC_CommonInitStructure;
69+
70+
/* Enable ADCx, DMA and GPIO clocks */
71+
#if 0
72+
/* GPIO clocks enabled in main */
73+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
74+
RCC_AHB1Periph_GPIOB |
75+
RCC_AHB1Periph_GPIOC, ENABLE);
76+
#endif
77+
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
78+
79+
/* ADC Common Init */
80+
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
81+
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
82+
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
83+
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
84+
ADC_CommonInit(&ADC_CommonInitStructure);
85+
86+
/* Configure ADC GPIOs */
87+
for (int i=0; i<ADC_NUM_CHANNELS; i++) {
88+
GPIO_InitStructure.GPIO_Pin = adc_gpio[i].pin;
89+
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
90+
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
91+
GPIO_Init(adc_gpio[i].port, &GPIO_InitStructure);
92+
}
93+
94+
/* ADCx Init */
95+
// ADC_DeInit();
96+
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
97+
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
98+
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
99+
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
100+
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
101+
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
102+
ADC_InitStructure.ADC_NbrOfConversion = 1;
103+
ADC_Init(ADCx, &ADC_InitStructure);
104+
105+
/* Enable ADCx */
106+
ADC_Cmd(ADCx, ENABLE);
107+
108+
/* Enable VBAT/VREF monitor */
109+
ADC_VBATCmd(ENABLE);
110+
111+
/* Enable temperature sensor */
112+
ADC_TempSensorVrefintCmd(ENABLE);
113+
}
114+
115+
uint32_t adc_read_channel(int channel)
116+
{
117+
int timeout = 10000;
118+
119+
if (channel > (ADC_NUM_CHANNELS-1)) {
120+
return 0;
121+
}
122+
123+
/* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */
124+
ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_15Cycles);
125+
126+
/* Start ADC single conversion */
127+
ADC_SoftwareStartConv(ADCx);
128+
129+
/* Wait for conversion to be complete*/
130+
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
131+
}
132+
133+
/* ADC conversion timed out */
134+
if (timeout == 0) {
135+
return 0;
136+
}
137+
138+
/* Return converted data */
139+
return ADC_GetConversionValue(ADCx);
140+
}
141+
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+
216+
/******************************************************************************/
217+
/* Micro Python bindings */
218+
219+
typedef struct _pyb_adc_obj_t {
220+
mp_obj_base_t base;
221+
int adc_id;
222+
bool is_enabled;
223+
} pyb_adc_obj_t;
224+
225+
static mp_obj_t adc_obj_read_channel(mp_obj_t self_in, mp_obj_t channel) {
226+
mp_obj_t ret = mp_const_none;
227+
pyb_adc_obj_t *self = self_in;
228+
229+
if (self->is_enabled) {
230+
uint32_t chan = mp_obj_get_int(channel);
231+
uint32_t data = adc_read_channel(chan);
232+
ret = mp_obj_new_int(data);
233+
}
234+
return ret;
235+
}
236+
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+
270+
static void adc_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
271+
pyb_adc_obj_t *self = self_in;
272+
print(env, "<ADC %lu>", self->adc_id);
273+
}
274+
275+
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);
279+
280+
static const mp_method_t adc_methods[] = {
281+
{ "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},
285+
{ NULL, NULL },
286+
};
287+
288+
static const mp_obj_type_t adc_obj_type = {
289+
{ &mp_const_type },
290+
"ADC",
291+
.print = adc_obj_print,
292+
.methods = adc_methods,
293+
};
294+
295+
mp_obj_t pyb_ADC(mp_obj_t resolution) {
296+
/* init ADC */
297+
adc_init(mp_obj_get_int(resolution));
298+
299+
pyb_adc_obj_t *o = m_new_obj(pyb_adc_obj_t);
300+
o->base.type = &adc_obj_type;
301+
o->adc_id = 1;
302+
o->is_enabled = true;
303+
return o;
304+
}

stm/adc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mp_obj_t pyb_ADC(mp_obj_t resolution);

0 commit comments

Comments
 (0)