|
37 | 37 | #include "supervisor/shared/translate.h" |
38 | 38 |
|
39 | 39 | #include "nrf.h" |
40 | | -#include "nrfx/hal/nrf_saadc.h" |
41 | 40 |
|
42 | | -#include "tick.h" |
43 | | - |
44 | | -bool touch_enabled = false; |
45 | | - |
46 | | -#define CHANNEL_NO 0 |
47 | 41 | #define N_SAMPLES 10 |
48 | | -#define K_FACTOR 100000000L |
49 | | - |
50 | | -static uint16_t process_samples(nrf_saadc_value_t samples[], int n_samples) { |
51 | | - // XXX sort of like a least squares fit here, with the assumption |
52 | | - // that the timing ('x') is stable (thus we suspend interrupts while |
53 | | - // taking these measurements) |
54 | | - |
55 | | - int32_t sumy = 0; |
56 | | - int32_t sumxy = 0; |
57 | | - |
58 | | - for (int i = 0; i < N_SAMPLES; i++) { |
59 | | - sumy += samples[i]; |
60 | | - sumxy += i*samples[i]; |
61 | | - } |
62 | | - |
63 | | - // we don't really care about the units, and so we can cut out a |
64 | | - // whole bunch of stuff which is based only on N_SAMPLES, eg: |
65 | | - // n, sum(x), sum(x^2) and sum(x)^2 terms. This leaves only: |
66 | | - |
67 | | - int16_t m = (N_SAMPLES - 1) * sumy / 2 - sumxy; |
68 | | - |
69 | | - // m is proportional to the charge rate of the capacitor which is |
70 | | - // in reciprocal proportion to the actual capacitance. |
71 | | - return (uint16_t)(K_FACTOR / m); |
72 | | -} |
| 42 | +#define TIMEOUT_US 10000 |
73 | 43 |
|
74 | 44 | static uint16_t get_raw_reading(touchio_touchin_obj_t *self) { |
75 | 45 |
|
76 | | - nrf_saadc_value_t samples[N_SAMPLES]; |
77 | | - |
78 | | - // Configure analog input. |
79 | | - // XXX analogio.AnalogIn and this class both use SAADC channel 0 |
80 | | - // all the time and never any other channel. This seems a bit |
81 | | - // silly. |
82 | | - |
83 | | - const nrf_saadc_channel_config_t config = { |
84 | | - .resistor_p = NRF_SAADC_RESISTOR_DISABLED, |
85 | | - .resistor_n = NRF_SAADC_RESISTOR_DISABLED, |
86 | | - .gain = NRF_SAADC_GAIN1_6, |
87 | | - .reference = NRF_SAADC_REFERENCE_INTERNAL, |
88 | | - .acq_time = NRF_SAADC_ACQTIME_3US, |
89 | | - .mode = NRF_SAADC_MODE_SINGLE_ENDED, |
90 | | - .burst = NRF_SAADC_BURST_DISABLED, |
91 | | - .pin_p = NRF_SAADC_INPUT_VDD, |
92 | | - .pin_n = NRF_SAADC_INPUT_VDD, |
93 | | - }; |
94 | | - |
95 | | - nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT); |
96 | | - nrf_saadc_oversample_set(NRF_SAADC_OVERSAMPLE_DISABLED); |
97 | | - nrf_saadc_enable(); |
| 46 | + uint16_t ticks = 0; |
98 | 47 |
|
99 | | - for (uint32_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; i++) |
100 | | - nrf_saadc_channel_input_set(i, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); |
| 48 | + for (uint16_t i = 0; i < N_SAMPLES; i++) { |
| 49 | + // set pad to digital output high for 10us to charge it |
101 | 50 |
|
102 | | - nrf_saadc_channel_init(CHANNEL_NO, &config); |
103 | | - nrf_saadc_buffer_init(samples, N_SAMPLES); |
| 51 | + nrf_gpio_cfg_output(self->pin->number); |
| 52 | + nrf_gpio_pin_set(self->pin->number); |
| 53 | + mp_hal_delay_us(10); |
104 | 54 |
|
105 | | - // set pad to digital output high for 10us to charge it |
| 55 | + // set pad back to an input and take some samples |
106 | 56 |
|
107 | | - nrf_gpio_cfg_output(self->pin->number); |
108 | | - nrf_gpio_pin_set(self->pin->number); |
| 57 | + nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); |
109 | 58 |
|
110 | | - mp_hal_delay_us(10); |
111 | | - |
112 | | - // set pad back to an input and take some samples |
113 | | - // IRQs are suspended to make sure our samples are at fixed times. |
114 | | - |
115 | | - __disable_irq(); |
116 | | - |
117 | | - nrf_saadc_channel_input_set(CHANNEL_NO, self->pin->adc_channel, self->pin->adc_channel); |
118 | | - |
119 | | - nrf_saadc_task_trigger(NRF_SAADC_TASK_START); |
120 | | - while (nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED) == 0); |
121 | | - nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED); |
122 | | - |
123 | | - // XXX surely there's a better way? PPI? |
124 | | - for (uint32_t i = 0; i < N_SAMPLES; i++) { |
125 | | - nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); |
126 | | - while (nrf_saadc_event_check(NRF_SAADC_EVENT_DONE) == 0); |
127 | | - nrf_saadc_event_clear(NRF_SAADC_EVENT_DONE); |
| 59 | + while(nrf_gpio_pin_read(self->pin->number)) { |
| 60 | + if (ticks >= TIMEOUT_US) return TIMEOUT_US; |
| 61 | + ticks++; |
| 62 | + mp_hal_delay_us(1); |
| 63 | + } |
128 | 64 | } |
129 | | - |
130 | | - __enable_irq(); |
131 | | - |
132 | | - nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP); |
133 | | - while (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED) == 0); |
134 | | - nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED); |
135 | | - |
136 | | - // turn off SAADC & set output pin low (to minimize leakage currents) |
137 | | - |
138 | | - nrf_gpio_pin_clear(self->pin->number); |
139 | | - |
140 | | - nrf_saadc_channel_input_set(CHANNEL_NO, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); |
141 | | - nrf_saadc_disable(); |
142 | | - |
143 | | - nrf_gpio_cfg_output(self->pin->number); |
144 | | - |
145 | | - return process_samples(samples, N_SAMPLES); |
146 | | - |
| 65 | + return ticks; |
147 | 66 | } |
148 | 67 |
|
149 | 68 | void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, |
150 | 69 | const mcu_pin_obj_t *pin) { |
151 | | - if (!pin->adc_channel) { |
152 | | - mp_raise_ValueError(translate("Invalid pin")); |
153 | | - } |
154 | 70 | self->pin = pin; |
155 | 71 | claim_pin(pin); |
156 | 72 | } |
|
0 commit comments