atmel-samd: Improve TouchIn to allow for multiple simultaneous touch pads.

This commit is contained in:
Scott Shawcroft 2016-12-20 16:39:32 -08:00
parent e8db23d241
commit f48d2df634
4 changed files with 80 additions and 38 deletions

View File

@ -89,9 +89,9 @@ freq_hop_sel_t selfcap_freq_hops[3u] = {DEF_SELFCAP_HOP_FREQS};
* the elements of this structure. DO NOT modify any of the input values
* directly in this structure.
*/
static touch_selfcap_config_t selfcap_config = {
DEF_SELFCAP_NUM_CHANNELS, /* Self Cap number of channels. */
DEF_SELFCAP_NUM_SENSORS, /* Self Cap number of sensors. */
touch_selfcap_config_t selfcap_config = {
0, /* Self Cap number of channels. */
0, /* Self Cap number of sensors. */
DEF_SELFCAP_NUM_ROTORS_SLIDERS, /* Self Cap number of rotors and
* sliders. */
@ -181,7 +181,8 @@ touch_config_t touch_config = {
DEF_TOUCH_PTC_ISR_LVL, /* PTC interrupt level. */
};
bool ptc_initialized = false;
nativeio_touchin_obj_t *active_touchin_obj[DEF_SELFCAP_NUM_CHANNELS];
void common_hal_nativeio_touchin_construct(nativeio_touchin_obj_t* self,
const mcu_pin_obj_t *pin) {
if (!pin->has_touch) {
@ -189,50 +190,78 @@ void common_hal_nativeio_touchin_construct(nativeio_touchin_obj_t* self,
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have touch capabilities", pin->name));
}
touch_ret_t status;
if (!ptc_initialized) {
/* Setup and enable generic clock source for PTC module. */
struct system_gclk_chan_config gclk_chan_conf;
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
system_gclk_chan_set_config(PTC_GCLK_ID, &gclk_chan_conf);
system_gclk_chan_enable(PTC_GCLK_ID);
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_PTC);
if (selfcap_config.num_channels > 0) {
// Deinit the touch sensor, we're going to reinitialize it.
touch_selfcap_sensors_deinit();
/* Initialize touch library for Self Cap operation. */
status = touch_selfcap_sensors_init_with_rs_table(&touch_config,
PRIV_SELFCAP_RS_TABLE_INIT, PRIV_NM_TABLE_INIT,
PRIV_FREQ_AUTO_TUNE_CHK, PRIV_MOIS_TOLERANCE_CHK);
if (status != TOUCH_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch init failed (%d)", status));
// Remove holes in the active list from sensors that may have been
// disabled.
int first_hole = -1;
for (int i = 0; i < selfcap_config.num_channels; i++) {
if (active_touchin_obj[i] == NULL && first_hole == -1) {
first_hole = i;
} else if (active_touchin_obj[i] != NULL && first_hole != -1) {
active_touchin_obj[first_hole] = active_touchin_obj[i];
first_hole = i;
}
}
ptc_initialized = true;
}
// Map Y line to channel. Boards can switch the order.
int channel;
for (channel = 0; channel < DEF_SELFCAP_NUM_CHANNELS; channel++) {
if (selfcap_y_nodes[channel] == Y(pin->touch_y_line)) {
break;
if (first_hole > -1) {
selfcap_config.num_channels = first_hole;
selfcap_config.num_sensors = first_hole;
}
}
if (channel == DEF_SELFCAP_NUM_CHANNELS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin %q on this board does not have touch capabilities", pin->name));
}
status = touch_selfcap_sensor_config(SENSOR_TYPE_KEY, channel, channel,
NO_AKS_GROUP, 10u, HYST_25, RES_8_BIT, &self->sensor_id);
// Add our sensor to the end of the list.
self->pin = pin;
selfcap_y_nodes[selfcap_config.num_channels++] = Y(pin->touch_y_line);
active_touchin_obj[selfcap_config.num_sensors++] = self;
/* Setup and enable generic clock source for PTC module. */
struct system_gclk_chan_config gclk_chan_conf;
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
system_gclk_chan_set_config(PTC_GCLK_ID, &gclk_chan_conf);
system_gclk_chan_enable(PTC_GCLK_ID);
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_PTC);
touch_ret_t status;
/* Initialize touch library for Self Cap operation. */
status = touch_selfcap_sensors_init_with_rs_table(&touch_config,
PRIV_SELFCAP_RS_TABLE_INIT, PRIV_NM_TABLE_INIT,
PRIV_FREQ_AUTO_TUNE_CHK, PRIV_MOIS_TOLERANCE_CHK);
if (status != TOUCH_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad config failed (%d)", status));
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch init failed (%d)", status));
}
for (int i = 0; i < selfcap_config.num_channels; i++) {
status = touch_selfcap_sensor_config(SENSOR_TYPE_KEY, i, i,
NO_AKS_GROUP, 10u, HYST_25, RES_8_BIT, &active_touchin_obj[i]->sensor_id);
if (status != TOUCH_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad config failed (%d)", status));
}
}
status = touch_selfcap_sensors_calibrate(AUTO_TUNE_RSEL);
if (status != TOUCH_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Touch pad calibration failed (%d)", status));
}
self->pin = pin;
// Run a measurement to get calibrated.
common_hal_nativeio_touchin_get_value(self);
}
// This may get called twice, once on exit or deinit and once from the finaliser
// (__del__). We need the finaliser to reduce the chance of us writing to memory
// we no longer own because we keep track of Python pointers in active_touchin_obj.
void common_hal_nativeio_touchin_deinit(nativeio_touchin_obj_t* self) {
touch_selfcap_sensor_disable(self->sensor_id);
// Remove ourselves from the list of active objects. We don't change the
// selfcap settings at all because we don't want to reinit now. Instead,
// we'll collect blank spots later on reinit.
for (int i = 0; i < DEF_SELFCAP_NUM_CHANNELS; i++) {
if (active_touchin_obj[i] == self) {
active_touchin_obj[i] = NULL;
break;
}
}
}
volatile bool touch_read_ready = false;
@ -263,6 +292,9 @@ bool common_hal_nativeio_touchin_get_value(nativeio_touchin_obj_t *self) {
while(!touch_read_ready && ticks_ms - start_ticks < 1000) {
// wait
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
#endif
}
}
@ -270,5 +302,5 @@ bool common_hal_nativeio_touchin_get_value(nativeio_touchin_obj_t *self) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Touch read failed"));
}
return (p_selfcap_measure_data->p_sensor_states[self->sensor_id / 8] & (1 << (self->sensor_id % 8))) == 1;
return (p_selfcap_measure_data->p_sensor_states[self->sensor_id / 8] & (1 << (self->sensor_id % 8))) != 0;
}

View File

@ -22,7 +22,8 @@
#include "asf/sam0/drivers/system/system.h"
#include <board.h>
#ifdef SPI_FLASH_SECTOR_SIZE
#ifdef EXPRESS_BOARD
#include "common-hal/nativeio/types.h"
#include "QTouch/touch_api_ptc.h"
#endif
@ -128,7 +129,10 @@ void reset_mp(void) {
MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
}
extern bool ptc_initialized;
#ifdef EXPRESS_BOARD
extern nativeio_touchin_obj_t *active_touchin_obj[DEF_SELFCAP_NUM_CHANNELS];
extern touch_selfcap_config_t selfcap_config;
#endif
void reset_samd21(void) {
// Reset all SERCOMs except the one being used by the SPI flash.
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
@ -146,9 +150,13 @@ void reset_samd21(void) {
sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1;
}
#ifdef SPI_FLASH_SECTOR_SIZE
#ifdef EXPRESS_BOARD
touch_selfcap_sensors_deinit();
ptc_initialized = false;
for (int i = 0; i < selfcap_config.num_channels; i++) {
active_touchin_obj[i] = NULL;
}
selfcap_config.num_channels = 0;
selfcap_config.num_sensors = 0;
#endif
struct system_pinmux_config config;

View File

@ -132,6 +132,7 @@ extern const struct _mp_obj_module_t samd_module;
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define EXTRA_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }
#define EXPRESS_BOARD
#else
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#define EXTRA_BUILTIN_MODULES

View File

@ -126,6 +126,7 @@ mp_obj_property_t nativeio_touchin_value_obj = {
STATIC const mp_rom_map_elem_t nativeio_touchin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&nativeio_touchin___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&nativeio_touchin___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&nativeio_touchin_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&nativeio_touchin_deinit_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_value), MP_ROM_PTR(&nativeio_touchin_value_obj)},