forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathAnalogIn.c
More file actions
130 lines (106 loc) · 4.49 KB
/
AnalogIn.c
File metadata and controls
130 lines (106 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "common-hal/analogio/AnalogIn.h"
#include <string.h>
#include "py/gc.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/binary.h"
#include "py/mphal.h"
#include "peripherals/adc.h"
#include "shared-bindings/analogio/AnalogIn.h"
#include "atmel_start_pins.h"
#include "hal/include/hal_adc_sync.h"
#include "hpl/gclk/hpl_gclk_base.h"
#ifdef SAMD21
#include "hpl/pm/hpl_pm_base.h"
#endif
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self,
const mcu_pin_obj_t *pin) {
uint8_t adc_index;
uint8_t adc_channel = 0xff;
for (adc_index = 0; adc_index < NUM_ADC_PER_PIN; adc_index++) {
// TODO(tannewt): Only use ADC0 on the SAMD51 when touch isn't being
// used.
if (pin->adc_input[adc_index] != 0xff) {
adc_channel = pin->adc_input[adc_index];
break;
}
}
if (adc_channel == 0xff) {
// No ADC function on that pin
mp_raise_ValueError("Pin does not have ADC capabilities");
}
claim_pin(pin);
gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_B);
static Adc* adc_insts[] = ADC_INSTS;
self->instance = adc_insts[adc_index];
self->channel = adc_channel;
self->pin = pin;
}
bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
return self->pin == mp_const_none;
}
void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) {
if (common_hal_analogio_analogin_deinited(self)) {
return;
}
reset_pin(self->pin->pin);
self->pin = mp_const_none;
}
void analogin_reset() {
}
uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
// Something else might have used the ADC in a different way,
// so we completely re-initialize it.
struct adc_sync_descriptor adc;
samd_peripherals_adc_setup(&adc, self->instance);
// Full scale is 3.3V (VDDANA) = 65535.
// On SAMD21, INTVCC1 is 0.5*VDDANA. On SAMD51, INTVCC1 is 1*VDDANA.
// So on SAMD21 only, divide the input by 2, so full scale will match 0.5*VDDANA.
adc_sync_set_reference(&adc, ADC_REFCTRL_REFSEL_INTVCC1_Val);
#ifdef SAMD21
adc_sync_set_channel_gain(&adc, self->channel, ADC_INPUTCTRL_GAIN_DIV2_Val);
#endif
adc_sync_set_resolution(&adc, ADC_CTRLB_RESSEL_12BIT_Val);
adc_sync_enable_channel(&adc, self->channel);
// We need to set the inputs because the above channel enable only enables the ADC.
adc_sync_set_inputs(&adc, self->channel, ADC_INPUTCTRL_MUXNEG_GND_Val, self->channel);
// Read twice and discard first result, as recommended in section 14 of
// http://www.atmel.com/images/Atmel-42645-ADC-Configurations-with-Examples_ApplicationNote_AT11481.pdf
// "Discard the first conversion result whenever there is a change in ADC configuration
// like voltage reference / ADC channel change"
// Empirical observation shows the first reading is quite different than subsequent ones.
uint16_t value;
adc_sync_read_channel(&adc, self->channel, ((uint8_t*) &value), 2);
adc_sync_read_channel(&adc, self->channel, ((uint8_t*) &value), 2);
adc_sync_deinit(&adc);
// Shift the value to be 16 bit.
return value << 4;
}
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
return 3.3f;
}