diff --git a/comm/messages.c b/comm/messages.c index 2b4105b..620a17e 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -2,6 +2,7 @@ // Created by MightyPork on 2017/11/21. // +#include #include "platform.h" #include "framework/settings.h" #include "utils/ini_parser.h" @@ -91,6 +92,7 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg) bulk->userdata = NULL; bulkread_start(tf, bulk); + Indicator_Effect(STATUS_DISK_BUSY_SHORT); return TF_STAY; } @@ -152,6 +154,8 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg) bulkwrite_start(tf, bulk); + Indicator_Effect(STATUS_DISK_BUSY); + done: return TF_STAY; } @@ -161,6 +165,7 @@ done: /** Listener: Save settings to Flash */ static TF_Result lst_persist_cfg(TinyFrame *tf, TF_Msg *msg) { + Indicator_Effect(STATUS_DISK_REMOVED); settings_save(); return TF_STAY; } diff --git a/platform/status_led.c b/platform/status_led.c index cc66f2f..e031965 100644 --- a/platform/status_led.c +++ b/platform/status_led.c @@ -61,6 +61,12 @@ void Indicator_Effect(enum GEX_StatusIndicator indicator) led_on(); } + // prevent the two disk ops interfering (happens in write-reload) + if (indicator == STATUS_DISK_BUSY && active_effect == STATUS_DISK_BUSY_SHORT) return; + if (indicator == STATUS_DISK_BUSY_SHORT && active_effect == STATUS_DISK_BUSY) return; + + // TODO add some better protection against effect overlap? + active_effect = indicator; effect_time = 0; } @@ -119,7 +125,15 @@ void Indicator_Tick(void) active_effect = STATUS_NONE; } else if (effect_time % 100 == 0) led_on(); - else if (effect_time % 100 == 50) led_off(); + else if (effect_time % 100 == 20) led_off(); + } + else if (active_effect == STATUS_DISK_BUSY_SHORT) { + if (effect_time >= 200) { + led_off(); + active_effect = STATUS_NONE; + } + else if (effect_time % 100 == 0) led_on(); + else if (effect_time % 100 == 20) led_off(); } else if (active_effect == STATUS_WELCOME) { if (effect_time == 0) led_on(); diff --git a/platform/status_led.h b/platform/status_led.h index f61e3a9..5dbeb2d 100644 --- a/platform/status_led.h +++ b/platform/status_led.h @@ -16,6 +16,7 @@ enum GEX_StatusIndicator { STATUS_NONE = 0, STATUS_FAULT, STATUS_DISK_BUSY, + STATUS_DISK_BUSY_SHORT, STATUS_DISK_ATTACHED, STATUS_DISK_REMOVED, STATUS_WELCOME, diff --git a/units/touch/_touch_core.c b/units/touch/_touch_core.c index 8c1cf7b..76f8ebb 100644 --- a/units/touch/_touch_core.c +++ b/units/touch/_touch_core.c @@ -30,7 +30,7 @@ void UTOUCH_HandleIrq(void *arg) // assert_param((TSC->IOGCSR>>16) == priv->groups_phase[priv->next_phase]); // Store captured data - const uint32_t chmask = priv->channels_phase[priv->next_phase]; + const uint32_t chmask = TSC->IOCCR; for (int i = 0; i < 32; i++) { if (chmask & (1<readouts[i] = (uint16_t) (TSC->IOGXCR[i >> 2] & 0x3FFF); @@ -38,11 +38,14 @@ void UTOUCH_HandleIrq(void *arg) } priv->next_phase++; - // check if we've run out of existing or populated groups - if (priv->next_phase == 3 || priv->groups_phase[priv->next_phase] == 0) { - priv->next_phase = 0; - priv->status = UTSC_STATUS_READY; - // we'll stay in READY after the first loop until an error occurs or it's re-inited + + if (!priv->cfg.interlaced) { + // check if we've run out of existing or populated groups + if (priv->next_phase == 3 || priv->groups_phase[priv->next_phase] == 0) { + priv->next_phase = 0; + priv->status = UTSC_STATUS_READY; + // we'll stay in READY after the first loop until an error occurs or it's re-inited + } } TSC->CR &= ~TSC_CR_IODEF; // pull low - discharge @@ -90,21 +93,31 @@ void UTOUCH_updateTick(Unit *unit) static void startNextPhase(struct priv *priv) { - if (priv->next_phase == 0 && priv->groups_phase[0] == 0) { - // no groups are configured - return; - } - - TSC->IOGCSR = priv->groups_phase[priv->next_phase]; - TSC->IOCCR = priv->channels_phase[priv->next_phase]; - TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC; + if (priv->all_channels_mask == 0) return; if (priv->cfg.interlaced) { + // Find the next non-zero bit, wrap around if needed + while ((priv->all_channels_mask & (1<next_phase))==0) { + priv->next_phase++; + if (priv->next_phase == 32) { + priv->next_phase = 0; + priv->status = UTSC_STATUS_READY; + } + } + TSC->IOGCSR = (uint32_t) (1 << (priv->next_phase >> 2)); // phase divided by 4 + TSC->IOCCR = (uint32_t) (1 << priv->next_phase); + + // interlaced - float neighbouring electrodes TSC->CR |= TSC_CR_IODEF; - // floaty (must be used for interlaced pads) - // note: interlaced pads also need to be sampled individually + } else { + TSC->IOGCSR = priv->groups_phase[priv->next_phase]; + TSC->IOCCR = priv->channels_phase[priv->next_phase]; + + // separate - keep neighbouring electrodes at GND } + TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC; + // Go! priv->ongoing = true; TSC->CR |= TSC_CR_START; diff --git a/units/touch/_touch_init.c b/units/touch/_touch_init.c index 965d227..4321b4f 100644 --- a/units/touch/_touch_init.c +++ b/units/touch/_touch_init.c @@ -75,6 +75,8 @@ error_t UTOUCH_init(Unit *unit) __HAL_RCC_TSC_FORCE_RESET(); __HAL_RCC_TSC_RELEASE_RESET(); + priv->all_channels_mask = 0; + for (int gi = 0; gi < 8; gi++) { const uint8_t cap = priv->cfg.group_scaps[gi]; const uint8_t ch = priv->cfg.group_channels[gi]; @@ -132,11 +134,16 @@ error_t UTOUCH_init(Unit *unit) else { dbg_touch("TSC ch @ %s", rsc_get_name(r)); - // channels are configured individually when read. - // we prepare bitmaps to use for the read groups (all can be read in at most 3 steps) - priv->channels_phase[phasenum] |= bit; // this is used for the channel selection register - priv->groups_phase[phasenum] |= 1 << gi; // this will be used for the group enable register, if all 0, this and any following phases are unused. - phasenum++; + if (priv->cfg.interlaced) { + // interlaced - only update the mask beforehand + priv->all_channels_mask |= bit; + } else { + // channels are configured individually when read. + // we prepare bitmaps to use for the read groups (all can be read in at most 3 steps) + priv->channels_phase[phasenum] |= bit; // this is used for the channel selection register + priv->groups_phase[phasenum] |= 1 << gi; // this will be used for the group enable register, if all 0, this and any following phases are unused. + phasenum++; + } } } } @@ -154,7 +161,9 @@ error_t UTOUCH_init(Unit *unit) TSC->CR |= ((priv->cfg.spread_deviation - 1) << TSC_CR_SSD_Pos) | TSC_CR_SSE; } - dbg_touch("CR = %08x, ht is %d, lt is %d", TSC->CR, priv->cfg.charge_time, priv->cfg.drain_time); + dbg_touch("CR = %08x, ht is %d, lt is %d", (int)TSC->CR, + (int)priv->cfg.charge_time, + (int)priv->cfg.drain_time); // iofloat is used for discharging @@ -162,16 +171,22 @@ error_t UTOUCH_init(Unit *unit) TSC->IER = TSC_IER_EOAIE | TSC_IER_MCEIE; irqd_attach(TSC, UTOUCH_HandleIrq, unit); - dbg_touch("TSC phases:"); - priv->all_channels_mask = 0; - for (int i = 0; i < 3; i++) { - priv->all_channels_mask |= priv->channels_phase[i]; - dbg_touch(" %d: ch %08"PRIx32", g %02"PRIx32, i + 1, priv->channels_phase[i], (uint32_t) priv->groups_phase[i]); + if (!priv->cfg.interlaced) { + dbg_touch("TSC phases:"); + for (int i = 0; i < 3; i++) { + priv->all_channels_mask |= priv->channels_phase[i]; + + dbg_touch(" %d: ch %08"PRIx32", g %02"PRIx32, + i + 1, + priv->channels_phase[i], + (uint32_t) priv->groups_phase[i]); + } } priv->status = UTSC_STATUS_BUSY; // first loop ... priv->next_phase = 0; - UTOUCH_updateTick(unit); + + // starts in the tick callback return E_SUCCESS; } diff --git a/units/touch/_touch_internal.h b/units/touch/_touch_internal.h index 056fe11..ffc6d39 100644 --- a/units/touch/_touch_internal.h +++ b/units/touch/_touch_internal.h @@ -11,7 +11,7 @@ #include "unit_base.h" -#define TSC_DEBUG 1 +#define TSC_DEBUG 0 #if TSC_DEBUG #define dbg_touch(f,...) dbg(f,##__VA_ARGS__) diff --git a/units/touch/_touch_settings.c b/units/touch/_touch_settings.c index 3340c06..9c2b244 100644 --- a/units/touch/_touch_settings.c +++ b/units/touch/_touch_settings.c @@ -149,7 +149,7 @@ void UTOUCH_writeIni(Unit *unit, IniWriter *iw) iw_entry(iw, "ss-clock-prediv", "%d", (int)priv->cfg.ss_presc); iw_cmt_newline(iw); - iw_comment(iw, "Optimize for interlaced pads"); + iw_comment(iw, "Optimize for interlaced pads (individual sampling with others floating)"); iw_entry(iw, "interlaced-pads", str_yn(priv->cfg.interlaced)); iw_cmt_newline(iw);