blob: 696e7650b381dc8f51cbccdb982a565491cf4dfc [file] [log] [blame]
danicampora868fa822015-02-19 21:03:21 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 * Copyright (c) 2015 Daniel Campora
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28#include <stdio.h>
29#include <string.h>
30
Damien George4a23a012015-02-21 18:58:43 +000031#include "py/mpconfig.h"
danicampora868fa822015-02-19 21:03:21 +010032#include "py/nlr.h"
33#include "py/runtime.h"
34#include "py/binary.h"
35#include "py/gc.h"
Damien George22a63442017-02-22 12:36:23 +110036#include "py/mperrno.h"
danicampora868fa822015-02-19 21:03:21 +010037#include "bufhelper.h"
38#include "inc/hw_types.h"
39#include "inc/hw_adc.h"
40#include "inc/hw_ints.h"
41#include "inc/hw_memmap.h"
42#include "rom_map.h"
43#include "interrupt.h"
44#include "pin.h"
danicamporad226dd22015-02-27 16:50:06 +010045#include "gpio.h"
danicampora868fa822015-02-19 21:03:21 +010046#include "prcm.h"
47#include "adc.h"
48#include "pybadc.h"
49#include "pybpin.h"
danicamporab761ed22015-03-11 21:49:50 +010050#include "pybsleep.h"
danicampora868fa822015-02-19 21:03:21 +010051#include "pins.h"
52#include "mpexception.h"
53
54
danicampora6de1b392015-03-17 11:05:59 +010055/******************************************************************************
56 DECLARE CONSTANTS
57 ******************************************************************************/
58#define PYB_ADC_NUM_CHANNELS 4
59
60/******************************************************************************
61 DEFINE TYPES
62 ******************************************************************************/
63typedef struct {
danicampora868fa822015-02-19 21:03:21 +010064 mp_obj_base_t base;
Daniel Campora22b4c282015-09-14 20:03:32 +020065 bool enabled;
66} pyb_adc_obj_t;
67
68typedef struct {
69 mp_obj_base_t base;
Daniel Campora7027fd52015-08-10 16:44:20 +020070 pin_obj_t *pin;
danicampora868fa822015-02-19 21:03:21 +010071 byte channel;
Daniel Campora7027fd52015-08-10 16:44:20 +020072 byte id;
Daniel Campora22b4c282015-09-14 20:03:32 +020073 bool enabled;
74} pyb_adc_channel_obj_t;
75
danicampora868fa822015-02-19 21:03:21 +010076
danicampora6de1b392015-03-17 11:05:59 +010077/******************************************************************************
Daniel Campora7027fd52015-08-10 16:44:20 +020078 DECLARE PRIVATE DATA
79 ******************************************************************************/
Daniel Campora22b4c282015-09-14 20:03:32 +020080STATIC pyb_adc_channel_obj_t pyb_adc_channel_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 0, .enabled = false},
81 {.pin = &pin_GP3, .channel = ADC_CH_1, .id = 1, .enabled = false},
82 {.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2, .enabled = false},
83 {.pin = &pin_GP5, .channel = ADC_CH_3, .id = 3, .enabled = false} };
84STATIC pyb_adc_obj_t pyb_adc_obj = {.enabled = false};
85
86STATIC const mp_obj_type_t pyb_adc_channel_type;
87
88/******************************************************************************
89 DECLARE PRIVATE FUNCTIONS
90 ******************************************************************************/
91STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in);
Daniel Campora7027fd52015-08-10 16:44:20 +020092
93/******************************************************************************
danicampora6de1b392015-03-17 11:05:59 +010094 DEFINE PUBLIC FUNCTIONS
95 ******************************************************************************/
Daniel Campora22b4c282015-09-14 20:03:32 +020096STATIC void pyb_adc_init (pyb_adc_obj_t *self) {
danicamporab761ed22015-03-11 21:49:50 +010097 // enable and configure the timer
98 MAP_ADCTimerConfig(ADC_BASE, (1 << 17) - 1);
99 MAP_ADCTimerEnable(ADC_BASE);
100 // enable the ADC peripheral
101 MAP_ADCEnable(ADC_BASE);
Daniel Campora22b4c282015-09-14 20:03:32 +0200102 self->enabled = true;
103}
104
105STATIC void pyb_adc_check_init(void) {
106 // not initialized
107 if (!pyb_adc_obj.enabled) {
Damien George22a63442017-02-22 12:36:23 +1100108 mp_raise_OSError(MP_EPERM);
Daniel Campora22b4c282015-09-14 20:03:32 +0200109 }
110}
111
112STATIC void pyb_adc_channel_init (pyb_adc_channel_obj_t *self) {
113 // the ADC block must be enabled first
114 pyb_adc_check_init();
115 // configure the pin in analog mode
116 pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA);
117 // enable the ADC channel
118 MAP_ADCChannelEnable(ADC_BASE, self->channel);
119 self->enabled = true;
120}
121
122STATIC void pyb_adc_deinit_all_channels (void) {
123 for (int i = 0; i < PYB_ADC_NUM_CHANNELS; i++) {
124 adc_channel_deinit(&pyb_adc_channel_obj[i]);
125 }
danicamporab761ed22015-03-11 21:49:50 +0100126}
127
danicampora868fa822015-02-19 21:03:21 +0100128/******************************************************************************/
129/* Micro Python bindings : adc object */
130
Damien George7f9d1d62015-04-09 23:56:15 +0100131STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
danicampora6de1b392015-03-17 11:05:59 +0100132 pyb_adc_obj_t *self = self_in;
Daniel Campora22b4c282015-09-14 20:03:32 +0200133 if (self->enabled) {
134 mp_printf(print, "ADC(0, bits=12)");
135 } else {
136 mp_printf(print, "ADC(0)");
danicampora868fa822015-02-19 21:03:21 +0100137 }
danicampora868fa822015-02-19 21:03:21 +0100138}
139
Daniel Campora22b4c282015-09-14 20:03:32 +0200140STATIC const mp_arg_t pyb_adc_init_args[] = {
141 { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
142 { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 12} },
143};
Paul Sokolovskyeac22e22017-01-04 16:10:42 +0300144STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
Daniel Campora22b4c282015-09-14 20:03:32 +0200145 // parse args
146 mp_map_t kw_args;
147 mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
148 mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args)];
149 mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_adc_init_args, args);
danicampora868fa822015-02-19 21:03:21 +0100150
Daniel Campora22b4c282015-09-14 20:03:32 +0200151 // check the peripheral id
152 if (args[0].u_int != 0) {
Damien George22a63442017-02-22 12:36:23 +1100153 mp_raise_OSError(MP_ENODEV);
Daniel Campora22b4c282015-09-14 20:03:32 +0200154 }
155
156 // check the number of bits
157 if (args[1].u_int != 12) {
Damien George50ddaaf2016-10-18 09:53:43 +1100158 mp_raise_ValueError(mpexception_value_invalid_arguments);
Daniel Campora22b4c282015-09-14 20:03:32 +0200159 }
160
161 // setup the object
162 pyb_adc_obj_t *self = &pyb_adc_obj;
163 self->base.type = &pyb_adc_type;
164
165 // initialize and register with the sleep module
166 pyb_adc_init(self);
Daniel Camporac92e6a42015-09-27 13:45:48 +0200167 pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
Daniel Campora22b4c282015-09-14 20:03:32 +0200168 return self;
danicampora868fa822015-02-19 21:03:21 +0100169}
danicampora868fa822015-02-19 21:03:21 +0100170
Daniel Campora22b4c282015-09-14 20:03:32 +0200171STATIC mp_obj_t adc_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
172 // parse args
173 mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args) - 1];
174 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args);
175 // check the number of bits
176 if (args[0].u_int != 12) {
Damien George50ddaaf2016-10-18 09:53:43 +1100177 mp_raise_ValueError(mpexception_value_invalid_arguments);
Daniel Campora22b4c282015-09-14 20:03:32 +0200178 }
179 pyb_adc_init(pos_args[0]);
danicampora868fa822015-02-19 21:03:21 +0100180 return mp_const_none;
181}
Daniel Campora22b4c282015-09-14 20:03:32 +0200182STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_init_obj, 1, adc_init);
danicampora868fa822015-02-19 21:03:21 +0100183
Daniel Campora7027fd52015-08-10 16:44:20 +0200184STATIC mp_obj_t adc_deinit(mp_obj_t self_in) {
danicampora6de1b392015-03-17 11:05:59 +0100185 pyb_adc_obj_t *self = self_in;
Daniel Campora22b4c282015-09-14 20:03:32 +0200186 // first deinit all channels
187 pyb_adc_deinit_all_channels();
188 MAP_ADCDisable(ADC_BASE);
189 self->enabled = false;
danicamporaea43fa12015-03-16 13:18:29 +0100190 // unregister it with the sleep module
Daniel Camporac92e6a42015-09-27 13:45:48 +0200191 pyb_sleep_remove ((const mp_obj_t)self);
danicampora868fa822015-02-19 21:03:21 +0100192 return mp_const_none;
193}
Daniel Campora7027fd52015-08-10 16:44:20 +0200194STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit);
danicampora868fa822015-02-19 21:03:21 +0100195
Daniel Campora22b4c282015-09-14 20:03:32 +0200196STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
197 STATIC const mp_arg_t pyb_adc_channel_args[] = {
danicampora2e0cd202015-10-19 11:41:29 +0200198 { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
Daniel Campora22b4c282015-09-14 20:03:32 +0200199 { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
200 };
201
202 // parse args
203 mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_channel_args)];
204 mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args);
205
206 uint ch_id;
danicampora2e0cd202015-10-19 11:41:29 +0200207 if (args[0].u_obj != MP_OBJ_NULL) {
Daniel Campora22b4c282015-09-14 20:03:32 +0200208 ch_id = mp_obj_get_int(args[0].u_obj);
209 if (ch_id >= PYB_ADC_NUM_CHANNELS) {
Damien George22a63442017-02-22 12:36:23 +1100210 mp_raise_ValueError(mpexception_value_invalid_arguments);
danicampora2e0cd202015-10-19 11:41:29 +0200211 } else if (args[1].u_obj != mp_const_none) {
Daniel Campora22b4c282015-09-14 20:03:32 +0200212 uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
213 if (ch_id != pin_ch_id) {
Damien George50ddaaf2016-10-18 09:53:43 +1100214 mp_raise_ValueError(mpexception_value_invalid_arguments);
Daniel Campora22b4c282015-09-14 20:03:32 +0200215 }
216 }
217 } else {
218 ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
219 }
220
221 // setup the object
222 pyb_adc_channel_obj_t *self = &pyb_adc_channel_obj[ch_id];
223 self->base.type = &pyb_adc_channel_type;
224 pyb_adc_channel_init (self);
225 // register it with the sleep module
Daniel Camporac92e6a42015-09-27 13:45:48 +0200226 pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
Daniel Campora22b4c282015-09-14 20:03:32 +0200227 return self;
228}
229STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel);
230
danicampora868fa822015-02-19 21:03:21 +0100231STATIC const mp_map_elem_t adc_locals_dict_table[] = {
Daniel Campora7027fd52015-08-10 16:44:20 +0200232 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_init_obj },
233 { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_deinit_obj },
Daniel Campora22b4c282015-09-14 20:03:32 +0200234 { MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&adc_channel_obj },
danicampora868fa822015-02-19 21:03:21 +0100235};
236
237STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
238
239const mp_obj_type_t pyb_adc_type = {
240 { &mp_type_type },
241 .name = MP_QSTR_ADC,
242 .print = adc_print,
243 .make_new = adc_make_new,
244 .locals_dict = (mp_obj_t)&adc_locals_dict,
245};
246
Daniel Campora22b4c282015-09-14 20:03:32 +0200247STATIC void adc_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
248 pyb_adc_channel_obj_t *self = self_in;
249 if (self->enabled) {
250 mp_printf(print, "ADCChannel(%u, pin=%q)", self->id, self->pin->name);
251 } else {
252 mp_printf(print, "ADCChannel(%u)", self->id);
253 }
254}
255
256STATIC mp_obj_t adc_channel_init(mp_obj_t self_in) {
257 pyb_adc_channel_obj_t *self = self_in;
258 // re-enable it
259 pyb_adc_channel_init(self);
260 return mp_const_none;
261}
262STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_init_obj, adc_channel_init);
263
264STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) {
265 pyb_adc_channel_obj_t *self = self_in;
266
267 MAP_ADCChannelDisable(ADC_BASE, self->channel);
268 // unregister it with the sleep module
Daniel Camporac92e6a42015-09-27 13:45:48 +0200269 pyb_sleep_remove ((const mp_obj_t)self);
Daniel Campora22b4c282015-09-14 20:03:32 +0200270 self->enabled = false;
271 return mp_const_none;
272}
273STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_deinit_obj, adc_channel_deinit);
274
275STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) {
276 pyb_adc_channel_obj_t *self = self_in;
277 uint32_t value;
278
279 // the channel must be enabled
280 if (!self->enabled) {
Damien George22a63442017-02-22 12:36:23 +1100281 mp_raise_OSError(MP_EPERM);
Daniel Campora22b4c282015-09-14 20:03:32 +0200282 }
283
284 // wait until a new value is available
285 while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel));
286 // read the sample
287 value = MAP_ADCFIFORead(ADC_BASE, self->channel);
288 // the 12 bit sampled value is stored in bits [13:2]
289 return MP_OBJ_NEW_SMALL_INT((value & 0x3FFF) >> 2);
290}
291STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_value_obj, adc_channel_value);
292
Paul Sokolovskyeac22e22017-01-04 16:10:42 +0300293STATIC mp_obj_t adc_channel_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
Daniel Campora22b4c282015-09-14 20:03:32 +0200294 mp_arg_check_num(n_args, n_kw, 0, 0, false);
295 return adc_channel_value (self_in);
296}
297
298STATIC const mp_map_elem_t adc_channel_locals_dict_table[] = {
299 { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_channel_init_obj },
300 { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_channel_deinit_obj },
301 { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&adc_channel_value_obj },
302};
303
304STATIC MP_DEFINE_CONST_DICT(adc_channel_locals_dict, adc_channel_locals_dict_table);
305
306STATIC const mp_obj_type_t pyb_adc_channel_type = {
307 { &mp_type_type },
308 .name = MP_QSTR_ADCChannel,
309 .print = adc_channel_print,
310 .call = adc_channel_call,
311 .locals_dict = (mp_obj_t)&adc_channel_locals_dict,
312};