From d4e1d85bb499cff049ed1688ea96933751165854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 7 Feb 2018 15:52:55 +0100 Subject: [PATCH] =?UTF-8?q?some=20small=20adc=20fixes=20(impreoving=1B[D?= =?UTF-8?q?=1B[D=1B=20trigger)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- units/adc/_adc_core.c | 46 +++++++++++------- units/adc/_adc_internal.h | 3 +- units/adc/unit_adc.c | 98 ++++++++++++++++++++++++++------------- 3 files changed, 97 insertions(+), 50 deletions(-) diff --git a/units/adc/_adc_core.c b/units/adc/_adc_core.c index 53c0905..a854e2f 100644 --- a/units/adc/_adc_core.c +++ b/units/adc/_adc_core.c @@ -31,11 +31,11 @@ void UADC_DMA_Handler(void *arg) const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum); // check what mode we're in - const bool m_trig = priv->opmode == ADC_OPMODE_TRIGD; + const bool m_trigd = priv->opmode == ADC_OPMODE_TRIGD; const bool m_stream = priv->opmode == ADC_OPMODE_STREAM; const bool m_fixcpt = priv->opmode == ADC_OPMODE_FIXCAPT; - if (m_trig || m_stream || m_fixcpt) { + if (m_trigd || m_stream || m_fixcpt) { if (ht || tc) { const uint16_t start = priv->stream_startpos; uint16_t end; @@ -57,7 +57,7 @@ void UADC_DMA_Handler(void *arg) if (start != end) { uint32_t sgcount = (end - start) / priv->nb_channels; - if (m_trig || m_fixcpt) { + if (m_trigd || m_fixcpt) { sgcount = MIN(priv->trig_stream_remain, sgcount); priv->trig_stream_remain -= sgcount; } @@ -67,14 +67,16 @@ void UADC_DMA_Handler(void *arg) // TODO send the data together with remaining count (used to detect end of transmission) - if (m_trig || m_fixcpt) { + if (m_trigd || m_fixcpt) { // Trig'd or Block capture - check for the max count condition if (priv->trig_stream_remain == 0) { dbg("End of capture"); UADC_ReportEndOfStream(unit); - UADC_SwitchMode(unit, ADC_OPMODE_IDLE); - if (priv->auto_rearm && m_trig) { - UADC_SwitchMode(unit, ADC_OPMODE_ARMED); - } + + // If auto-arm enabled, we need to re-arm again. + // However, EOS irq is disabled during the capture. + // We have to wait for the next EOS interrupt to occur. + // TODO verify if keeping the EOS irq enabled during capture has significant performance penalty. If not, we can leave it enabled. + UADC_SwitchMode(unit, (priv->auto_rearm && m_trigd) ? ADC_OPMODE_REARM_PENDING : ADC_OPMODE_IDLE); } } } else { @@ -143,8 +145,8 @@ void UADC_ADC_EOS_Handler(void *arg) priv->last_samples[i] = val; - if (priv->opmode == ADC_OPMODE_ARMED) { - if (i == priv->trigger_source) { + if (i == priv->trigger_source) { + if (priv->opmode == ADC_OPMODE_ARMED) { dbg("Trig line level %d", (int)val); bool trigd = false; @@ -165,9 +167,19 @@ void UADC_ADC_EOS_Handler(void *arg) if (trigd) { UADC_HandleTrigger(unit, edge_type, timestamp); } - - priv->trig_prev_level = val; } + else if (priv->opmode == ADC_OPMODE_REARM_PENDING) { + if (!priv->auto_rearm) { + // It looks like the flag was cleared by DISARM before we got a new sample. + // Let's just switch to IDLE + UADC_SwitchMode(unit, ADC_OPMODE_IDLE); + } else { + // Re-arming for a new trigger + UADC_SwitchMode(unit, ADC_OPMODE_ARMED); + } + } + + priv->trig_prev_level = val; } } } @@ -290,8 +302,8 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode) LL_DMA_DisableIT_HT(priv->DMAx, priv->dma_chnum); LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum); } - else if (new_mode == ADC_OPMODE_IDLE) { - dbg("ADC switch -> IDLE"); + else if (new_mode == ADC_OPMODE_IDLE || new_mode == ADC_OPMODE_REARM_PENDING) { + dbg("ADC switch -> IDLE or IDLE/REARM_PENDING"); // IDLE and ARMED are identical with the exception that the trigger condition is not checked // ARMED can be only entered from IDLE, thus we do the init only here. @@ -314,8 +326,10 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode) } else if (new_mode == ADC_OPMODE_ARMED) { dbg("ADC switch -> ARMED"); - assert_param(priv->opmode == ADC_OPMODE_IDLE); - // there's nothing else to do here + assert_param(priv->opmode == ADC_OPMODE_IDLE || priv->opmode == ADC_OPMODE_REARM_PENDING); + + // avoid firing immediately by the value jumping across the scale + priv->trig_prev_level = priv->last_samples[priv->trigger_source]; } else if (new_mode == ADC_OPMODE_TRIGD || new_mode == ADC_OPMODE_STREAM || diff --git a/units/adc/_adc_internal.h b/units/adc/_adc_internal.h index bda6c61..a00edc3 100644 --- a/units/adc/_adc_internal.h +++ b/units/adc/_adc_internal.h @@ -13,7 +13,8 @@ enum uadc_opmode { ADC_OPMODE_UNINIT, //!< Not yet switched to any mode - ADC_OPMODE_IDLE, //!< Idle, each sample overwrites the previous. Allows immediate value readout and averaging. + ADC_OPMODE_IDLE, //!< Idle. Allows immediate value readout and averaging. + ADC_OPMODE_REARM_PENDING, //!< Idle, waiting for the next sample to re-arm (auto trigger). ADC_OPMODE_ARMED, //!< Armed for a trigger. Direct access and averaging are disabled. ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data. ADC_OPMODE_FIXCAPT,//!< Capture of fixed length without a trigger diff --git a/units/adc/unit_adc.c b/units/adc/unit_adc.c index c2d6744..d44d933 100644 --- a/units/adc/unit_adc.c +++ b/units/adc/unit_adc.c @@ -109,16 +109,20 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P */ case CMD_SETUP_TRIGGER: dbg("> Setup trigger"); - if (priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) return E_BUSY; + if (priv->opmode != ADC_OPMODE_IDLE && + priv->opmode != ADC_OPMODE_ARMED && + priv->opmode != ADC_OPMODE_REARM_PENDING) { + return E_BUSY; + } { - uint8_t source = pp_u8(pp); - uint16_t level = pp_u16(pp); - uint8_t edge = pp_u8(pp); // TODO test falling edge and dual edge - uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ... - uint32_t count = pp_u32(pp); - uint16_t holdoff = pp_u16(pp); // TODO test hold-off ... - bool auto_rearm = pp_bool(pp); + const uint8_t source = pp_u8(pp); + const uint16_t level = pp_u16(pp); + const uint8_t edge = pp_u8(pp); + const uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ... + const uint32_t count = pp_u32(pp); + const uint16_t holdoff = pp_u16(pp); + const bool auto_rearm = pp_bool(pp); if (source > 17) { com_respond_str(MSG_ERROR, frame_id, "Invalid trig source"); @@ -141,7 +145,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P } // XXX the max size may be too much - uint16_t max_pretrig = (priv->dma_buffer_itemcount / priv->nb_channels); + const uint16_t max_pretrig = (priv->dma_buffer_itemcount / priv->nb_channels); if (pretrig > max_pretrig) { com_respond_snprintf(frame_id, MSG_ERROR, "Pretrig too large (max %d)", (int) max_pretrig); @@ -164,17 +168,28 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P */ case CMD_ARM: dbg("> Arm"); - if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; + uint8_t sticky = pp_u8(pp); + + if(priv->opmode == ADC_OPMODE_ARMED || priv->opmode == ADC_OPMODE_REARM_PENDING) { + // We are armed or will re-arm promptly, act like the call succeeded + // The auto flag is set regardless + } else { + if (priv->opmode != ADC_OPMODE_IDLE) { + return E_BUSY; // capture in progress + } - if (priv->trig_len == 0) { - com_respond_str(MSG_ERROR, frame_id, "Trigger not configured."); - return E_FAILURE; + if (priv->trig_len == 0) { + com_respond_str(MSG_ERROR, frame_id, "Trigger not configured."); + return E_FAILURE; + } + + UADC_SwitchMode(unit, ADC_OPMODE_ARMED); } - // avoid firing immediately by the value jumping across the scale - priv->trig_prev_level = priv->last_samples[priv->trigger_source]; + if (sticky != 255) { + priv->auto_rearm = (bool)sticky; + } - UADC_SwitchMode(unit, ADC_OPMODE_ARMED); return E_SUCCESS; /** @@ -182,13 +197,21 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P * Switches to idle. */ case CMD_DISARM: - // TODO test dbg("> Disarm"); + + priv->auto_rearm = false; + if(priv->opmode == ADC_OPMODE_IDLE) { return E_SUCCESS; // already idle, success - no work to do } + // capture in progress - if(priv->opmode != ADC_OPMODE_ARMED) return E_BUSY; + if (priv->opmode != ADC_OPMODE_ARMED && + priv->opmode != ADC_OPMODE_REARM_PENDING) { + // Capture in progress, we already cleared auto rearm, so we're done for now + // auto_rearm is checked in the EOS isr and if cleared, does not re-arm. + return E_SUCCESS; + } UADC_SwitchMode(unit, ADC_OPMODE_IDLE); return E_SUCCESS; @@ -197,15 +220,18 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P * Abort any ongoing capture and dis-arm. */ case CMD_ABORT:; - // TODO test dbg("> Abort capture"); - enum uadc_opmode old_opmode = priv->opmode; - UADC_SwitchMode(unit, ADC_OPMODE_IDLE); + { + enum uadc_opmode old_opmode = priv->opmode; + + priv->auto_rearm = false; + UADC_SwitchMode(unit, ADC_OPMODE_IDLE); - if (old_opmode == ADC_OPMODE_FIXCAPT || - old_opmode == ADC_OPMODE_STREAM || - old_opmode == ADC_OPMODE_TRIGD) { - UADC_ReportEndOfStream(unit); + if (old_opmode == ADC_OPMODE_FIXCAPT || + old_opmode == ADC_OPMODE_STREAM || + old_opmode == ADC_OPMODE_TRIGD) { + UADC_ReportEndOfStream(unit); + } } return E_SUCCESS; @@ -214,13 +240,17 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P * The reported edge will be 0b11, here meaning "manual trigger" */ case CMD_FORCE_TRIGGER: - // TODO test dbg("> Force trigger"); - if(priv->opmode == ADC_OPMODE_IDLE) { - com_respond_str(MSG_ERROR, frame_id, "Not armed"); + // This is similar to block capture, but includes the pre-trig buffer and has fixed size based on trigger config + // FORCE is useful for checking if the trigger is set up correctly + if (priv->opmode != ADC_OPMODE_ARMED && + priv->opmode != ADC_OPMODE_IDLE && + priv->opmode != ADC_OPMODE_REARM_PENDING) return E_BUSY; + + if (priv->trig_len == 0) { + com_respond_str(MSG_ERROR, frame_id, "Trigger not configured."); return E_FAILURE; } - if(priv->opmode != ADC_OPMODE_ARMED) return E_BUSY; UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime()); return E_SUCCESS; @@ -234,7 +264,8 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P case CMD_BLOCK_CAPTURE: // TODO test dbg("> Block cpt"); - if(priv->opmode != ADC_OPMODE_ARMED && + if (priv->opmode != ADC_OPMODE_ARMED && + priv->opmode != ADC_OPMODE_REARM_PENDING && priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; uint32_t count = pp_u32(pp); @@ -249,8 +280,9 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P case CMD_STREAM_START: // TODO test dbg("> Stream ON"); - if(priv->opmode != ADC_OPMODE_ARMED && - priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; + if (priv->opmode != ADC_OPMODE_ARMED && + priv->opmode != ADC_OPMODE_REARM_PENDING && + priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; UADC_StartStream(unit, frame_id); return E_SUCCESS; @@ -261,7 +293,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P case CMD_STREAM_STOP: // TODO test dbg("> Stream OFF"); - if(priv->opmode != ADC_OPMODE_STREAM) { + if (priv->opmode != ADC_OPMODE_STREAM) { com_respond_str(MSG_ERROR, frame_id, "Not streaming"); return E_FAILURE; }