Skip to content

Commit f48d2df

Browse files
committed
atmel-samd: Improve TouchIn to allow for multiple simultaneous touch pads.
1 parent e8db23d commit f48d2df

File tree

4 files changed

+81
-39
lines changed

4 files changed

+81
-39
lines changed

atmel-samd/common-hal/nativeio/TouchIn.c

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ freq_hop_sel_t selfcap_freq_hops[3u] = {DEF_SELFCAP_HOP_FREQS};
8989
* the elements of this structure. DO NOT modify any of the input values
9090
* directly in this structure.
9191
*/
92-
static touch_selfcap_config_t selfcap_config = {
93-
DEF_SELFCAP_NUM_CHANNELS, /* Self Cap number of channels. */
94-
DEF_SELFCAP_NUM_SENSORS, /* Self Cap number of sensors. */
92+
touch_selfcap_config_t selfcap_config = {
93+
0, /* Self Cap number of channels. */
94+
0, /* Self Cap number of sensors. */
9595
DEF_SELFCAP_NUM_ROTORS_SLIDERS, /* Self Cap number of rotors and
9696
* sliders. */
9797

@@ -181,58 +181,87 @@ touch_config_t touch_config = {
181181
DEF_TOUCH_PTC_ISR_LVL, /* PTC interrupt level. */
182182
};
183183

184-
bool ptc_initialized = false;
184+
nativeio_touchin_obj_t *active_touchin_obj[DEF_SELFCAP_NUM_CHANNELS];
185+
185186
void common_hal_nativeio_touchin_construct(nativeio_touchin_obj_t* self,
186187
const mcu_pin_obj_t *pin) {
187188
if (!pin->has_touch) {
188189
// No ADC function on that pin
189190
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have touch capabilities", pin->name));
190191
}
191192

192-
touch_ret_t status;
193-
if (!ptc_initialized) {
194-
/* Setup and enable generic clock source for PTC module. */
195-
struct system_gclk_chan_config gclk_chan_conf;
196-
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
197-
gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
198-
system_gclk_chan_set_config(PTC_GCLK_ID, &gclk_chan_conf);
199-
system_gclk_chan_enable(PTC_GCLK_ID);
200-
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_PTC);
201-
202-
/* Initialize touch library for Self Cap operation. */
203-
status = touch_selfcap_sensors_init_with_rs_table(&touch_config,
204-
PRIV_SELFCAP_RS_TABLE_INIT, PRIV_NM_TABLE_INIT,
205-
PRIV_FREQ_AUTO_TUNE_CHK, PRIV_MOIS_TOLERANCE_CHK);
206-
if (status != TOUCH_SUCCESS) {
207-
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch init failed (%d)", status));
193+
if (selfcap_config.num_channels > 0) {
194+
// Deinit the touch sensor, we're going to reinitialize it.
195+
touch_selfcap_sensors_deinit();
196+
197+
// Remove holes in the active list from sensors that may have been
198+
// disabled.
199+
int first_hole = -1;
200+
for (int i = 0; i < selfcap_config.num_channels; i++) {
201+
if (active_touchin_obj[i] == NULL && first_hole == -1) {
202+
first_hole = i;
203+
} else if (active_touchin_obj[i] != NULL && first_hole != -1) {
204+
active_touchin_obj[first_hole] = active_touchin_obj[i];
205+
first_hole = i;
206+
}
208207
}
209-
ptc_initialized = true;
210-
}
211-
// Map Y line to channel. Boards can switch the order.
212-
int channel;
213-
for (channel = 0; channel < DEF_SELFCAP_NUM_CHANNELS; channel++) {
214-
if (selfcap_y_nodes[channel] == Y(pin->touch_y_line)) {
215-
break;
208+
if (first_hole > -1) {
209+
selfcap_config.num_channels = first_hole;
210+
selfcap_config.num_sensors = first_hole;
216211
}
217212
}
218-
if (channel == DEF_SELFCAP_NUM_CHANNELS) {
219-
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin %q on this board does not have touch capabilities", pin->name));
220-
}
221-
status = touch_selfcap_sensor_config(SENSOR_TYPE_KEY, channel, channel,
222-
NO_AKS_GROUP, 10u, HYST_25, RES_8_BIT, &self->sensor_id);
213+
214+
// Add our sensor to the end of the list.
215+
self->pin = pin;
216+
selfcap_y_nodes[selfcap_config.num_channels++] = Y(pin->touch_y_line);
217+
active_touchin_obj[selfcap_config.num_sensors++] = self;
218+
219+
/* Setup and enable generic clock source for PTC module. */
220+
struct system_gclk_chan_config gclk_chan_conf;
221+
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
222+
gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
223+
system_gclk_chan_set_config(PTC_GCLK_ID, &gclk_chan_conf);
224+
system_gclk_chan_enable(PTC_GCLK_ID);
225+
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_PTC);
226+
227+
touch_ret_t status;
228+
/* Initialize touch library for Self Cap operation. */
229+
status = touch_selfcap_sensors_init_with_rs_table(&touch_config,
230+
PRIV_SELFCAP_RS_TABLE_INIT, PRIV_NM_TABLE_INIT,
231+
PRIV_FREQ_AUTO_TUNE_CHK, PRIV_MOIS_TOLERANCE_CHK);
223232
if (status != TOUCH_SUCCESS) {
224-
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad config failed (%d)", status));
233+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch init failed (%d)", status));
234+
}
235+
for (int i = 0; i < selfcap_config.num_channels; i++) {
236+
status = touch_selfcap_sensor_config(SENSOR_TYPE_KEY, i, i,
237+
NO_AKS_GROUP, 10u, HYST_25, RES_8_BIT, &active_touchin_obj[i]->sensor_id);
238+
if (status != TOUCH_SUCCESS) {
239+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad config failed (%d)", status));
240+
}
225241
}
226242
status = touch_selfcap_sensors_calibrate(AUTO_TUNE_RSEL);
227243
if (status != TOUCH_SUCCESS) {
228244
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad calibration failed (%d)", status));
229245
}
230246

231-
self->pin = pin;
247+
// Run a measurement to get calibrated.
248+
common_hal_nativeio_touchin_get_value(self);
232249
}
233250

251+
// This may get called twice, once on exit or deinit and once from the finaliser
252+
// (__del__). We need the finaliser to reduce the chance of us writing to memory
253+
// we no longer own because we keep track of Python pointers in active_touchin_obj.
234254
void common_hal_nativeio_touchin_deinit(nativeio_touchin_obj_t* self) {
235255
touch_selfcap_sensor_disable(self->sensor_id);
256+
// Remove ourselves from the list of active objects. We don't change the
257+
// selfcap settings at all because we don't want to reinit now. Instead,
258+
// we'll collect blank spots later on reinit.
259+
for (int i = 0; i < DEF_SELFCAP_NUM_CHANNELS; i++) {
260+
if (active_touchin_obj[i] == self) {
261+
active_touchin_obj[i] = NULL;
262+
break;
263+
}
264+
}
236265
}
237266

238267
volatile bool touch_read_ready = false;
@@ -263,12 +292,15 @@ bool common_hal_nativeio_touchin_get_value(nativeio_touchin_obj_t *self) {
263292

264293
while(!touch_read_ready && ticks_ms - start_ticks < 1000) {
265294
// wait
295+
#ifdef MICROPY_VM_HOOK_LOOP
296+
MICROPY_VM_HOOK_LOOP
297+
#endif
266298
}
267299
}
268300

269301
if (touch_acq_status & TOUCH_BURST_AGAIN) {
270302
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch read failed"));
271303
}
272304

273-
return (p_selfcap_measure_data->p_sensor_states[self->sensor_id / 8] & (1 << (self->sensor_id % 8))) == 1;
305+
return (p_selfcap_measure_data->p_sensor_states[self->sensor_id / 8] & (1 << (self->sensor_id % 8))) != 0;
274306
}

atmel-samd/main.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
#include "asf/sam0/drivers/system/system.h"
2323
#include <board.h>
2424

25-
#ifdef SPI_FLASH_SECTOR_SIZE
25+
#ifdef EXPRESS_BOARD
26+
#include "common-hal/nativeio/types.h"
2627
#include "QTouch/touch_api_ptc.h"
2728
#endif
2829

@@ -128,7 +129,10 @@ void reset_mp(void) {
128129
MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
129130
}
130131

131-
extern bool ptc_initialized;
132+
#ifdef EXPRESS_BOARD
133+
extern nativeio_touchin_obj_t *active_touchin_obj[DEF_SELFCAP_NUM_CHANNELS];
134+
extern touch_selfcap_config_t selfcap_config;
135+
#endif
132136
void reset_samd21(void) {
133137
// Reset all SERCOMs except the one being used by the SPI flash.
134138
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
@@ -146,9 +150,13 @@ void reset_samd21(void) {
146150
sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1;
147151
}
148152

149-
#ifdef SPI_FLASH_SECTOR_SIZE
153+
#ifdef EXPRESS_BOARD
150154
touch_selfcap_sensors_deinit();
151-
ptc_initialized = false;
155+
for (int i = 0; i < selfcap_config.num_channels; i++) {
156+
active_touchin_obj[i] = NULL;
157+
}
158+
selfcap_config.num_channels = 0;
159+
selfcap_config.num_sensors = 0;
152160
#endif
153161

154162
struct system_pinmux_config config;

atmel-samd/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ extern const struct _mp_obj_module_t samd_module;
132132
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
133133
#define EXTRA_BUILTIN_MODULES \
134134
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }
135+
#define EXPRESS_BOARD
135136
#else
136137
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
137138
#define EXTRA_BUILTIN_MODULES

shared-bindings/nativeio/TouchIn.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ mp_obj_property_t nativeio_touchin_value_obj = {
126126
STATIC const mp_rom_map_elem_t nativeio_touchin_locals_dict_table[] = {
127127
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&nativeio_touchin___enter___obj) },
128128
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&nativeio_touchin___exit___obj) },
129+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&nativeio_touchin_deinit_obj) },
129130
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&nativeio_touchin_deinit_obj) },
130131

131132
{ MP_OBJ_NEW_QSTR(MP_QSTR_value), MP_ROM_PTR(&nativeio_touchin_value_obj)},

0 commit comments

Comments
 (0)