some small adc fixes (impreoving trigger)

adc
Ondřej Hruška 7 years ago
parent f80761b327
commit d4e1d85bb4
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 42
      units/adc/_adc_core.c
  2. 3
      units/adc/_adc_internal.h
  3. 78
      units/adc/unit_adc.c

@ -31,11 +31,11 @@ void UADC_DMA_Handler(void *arg)
const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum); const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum);
// check what mode we're in // 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_stream = priv->opmode == ADC_OPMODE_STREAM;
const bool m_fixcpt = priv->opmode == ADC_OPMODE_FIXCAPT; 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) { if (ht || tc) {
const uint16_t start = priv->stream_startpos; const uint16_t start = priv->stream_startpos;
uint16_t end; uint16_t end;
@ -57,7 +57,7 @@ void UADC_DMA_Handler(void *arg)
if (start != end) { if (start != end) {
uint32_t sgcount = (end - start) / priv->nb_channels; 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); sgcount = MIN(priv->trig_stream_remain, sgcount);
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) // 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) { if (priv->trig_stream_remain == 0) {
dbg("End of capture"); dbg("End of capture");
UADC_ReportEndOfStream(unit); UADC_ReportEndOfStream(unit);
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
if (priv->auto_rearm && m_trig) { // If auto-arm enabled, we need to re-arm again.
UADC_SwitchMode(unit, ADC_OPMODE_ARMED); // 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 { } else {
@ -143,8 +145,8 @@ void UADC_ADC_EOS_Handler(void *arg)
priv->last_samples[i] = val; 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); dbg("Trig line level %d", (int)val);
bool trigd = false; bool trigd = false;
@ -165,12 +167,22 @@ void UADC_ADC_EOS_Handler(void *arg)
if (trigd) { if (trigd) {
UADC_HandleTrigger(unit, edge_type, timestamp); UADC_HandleTrigger(unit, edge_type, timestamp);
} }
}
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; priv->trig_prev_level = val;
} }
} }
} }
}
} }
void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp) void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
@ -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_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum); LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum);
} }
else if (new_mode == ADC_OPMODE_IDLE) { else if (new_mode == ADC_OPMODE_IDLE || new_mode == ADC_OPMODE_REARM_PENDING) {
dbg("ADC switch -> IDLE"); dbg("ADC switch -> IDLE or IDLE/REARM_PENDING");
// IDLE and ARMED are identical with the exception that the trigger condition is not checked // 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. // 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) { else if (new_mode == ADC_OPMODE_ARMED) {
dbg("ADC switch -> ARMED"); dbg("ADC switch -> ARMED");
assert_param(priv->opmode == ADC_OPMODE_IDLE); assert_param(priv->opmode == ADC_OPMODE_IDLE || priv->opmode == ADC_OPMODE_REARM_PENDING);
// there's nothing else to do here
// 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 || else if (new_mode == ADC_OPMODE_TRIGD ||
new_mode == ADC_OPMODE_STREAM || new_mode == ADC_OPMODE_STREAM ||

@ -13,7 +13,8 @@
enum uadc_opmode { enum uadc_opmode {
ADC_OPMODE_UNINIT, //!< Not yet switched to any mode 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_ARMED, //!< Armed for a trigger. Direct access and averaging are disabled.
ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data. ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data.
ADC_OPMODE_FIXCAPT,//!< Capture of fixed length without a trigger ADC_OPMODE_FIXCAPT,//!< Capture of fixed length without a trigger

@ -109,16 +109,20 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
*/ */
case CMD_SETUP_TRIGGER: case CMD_SETUP_TRIGGER:
dbg("> 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); const uint8_t source = pp_u8(pp);
uint16_t level = pp_u16(pp); const uint16_t level = pp_u16(pp);
uint8_t edge = pp_u8(pp); // TODO test falling edge and dual edge const uint8_t edge = pp_u8(pp);
uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ... const uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ...
uint32_t count = pp_u32(pp); const uint32_t count = pp_u32(pp);
uint16_t holdoff = pp_u16(pp); // TODO test hold-off ... const uint16_t holdoff = pp_u16(pp);
bool auto_rearm = pp_bool(pp); const bool auto_rearm = pp_bool(pp);
if (source > 17) { if (source > 17) {
com_respond_str(MSG_ERROR, frame_id, "Invalid trig source"); 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 // 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) { if (pretrig > max_pretrig) {
com_respond_snprintf(frame_id, MSG_ERROR, com_respond_snprintf(frame_id, MSG_ERROR,
"Pretrig too large (max %d)", (int) max_pretrig); "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: case CMD_ARM:
dbg("> 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) { if (priv->trig_len == 0) {
com_respond_str(MSG_ERROR, frame_id, "Trigger not configured."); com_respond_str(MSG_ERROR, frame_id, "Trigger not configured.");
return E_FAILURE; return E_FAILURE;
} }
// avoid firing immediately by the value jumping across the scale
priv->trig_prev_level = priv->last_samples[priv->trigger_source];
UADC_SwitchMode(unit, ADC_OPMODE_ARMED); UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
}
if (sticky != 255) {
priv->auto_rearm = (bool)sticky;
}
return E_SUCCESS; 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. * Switches to idle.
*/ */
case CMD_DISARM: case CMD_DISARM:
// TODO test
dbg("> Disarm"); dbg("> Disarm");
priv->auto_rearm = false;
if(priv->opmode == ADC_OPMODE_IDLE) { if(priv->opmode == ADC_OPMODE_IDLE) {
return E_SUCCESS; // already idle, success - no work to do return E_SUCCESS; // already idle, success - no work to do
} }
// capture in progress // 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); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
return E_SUCCESS; return E_SUCCESS;
@ -197,9 +220,11 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* Abort any ongoing capture and dis-arm. * Abort any ongoing capture and dis-arm.
*/ */
case CMD_ABORT:; case CMD_ABORT:;
// TODO test
dbg("> Abort capture"); dbg("> Abort capture");
{
enum uadc_opmode old_opmode = priv->opmode; enum uadc_opmode old_opmode = priv->opmode;
priv->auto_rearm = false;
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
if (old_opmode == ADC_OPMODE_FIXCAPT || if (old_opmode == ADC_OPMODE_FIXCAPT ||
@ -207,6 +232,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
old_opmode == ADC_OPMODE_TRIGD) { old_opmode == ADC_OPMODE_TRIGD) {
UADC_ReportEndOfStream(unit); UADC_ReportEndOfStream(unit);
} }
}
return E_SUCCESS; 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" * The reported edge will be 0b11, here meaning "manual trigger"
*/ */
case CMD_FORCE_TRIGGER: case CMD_FORCE_TRIGGER:
// TODO test
dbg("> Force trigger"); dbg("> Force trigger");
if(priv->opmode == ADC_OPMODE_IDLE) { // This is similar to block capture, but includes the pre-trig buffer and has fixed size based on trigger config
com_respond_str(MSG_ERROR, frame_id, "Not armed"); // 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; return E_FAILURE;
} }
if(priv->opmode != ADC_OPMODE_ARMED) return E_BUSY;
UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime()); UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime());
return E_SUCCESS; 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: case CMD_BLOCK_CAPTURE:
// TODO test // TODO test
dbg("> Block cpt"); 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; priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
uint32_t count = pp_u32(pp); uint32_t count = pp_u32(pp);
@ -249,7 +280,8 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
case CMD_STREAM_START: case CMD_STREAM_START:
// TODO test // TODO test
dbg("> Stream ON"); dbg("> Stream ON");
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; priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
UADC_StartStream(unit, frame_id); UADC_StartStream(unit, frame_id);
@ -261,7 +293,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
case CMD_STREAM_STOP: case CMD_STREAM_STOP:
// TODO test // TODO test
dbg("> Stream OFF"); dbg("> Stream OFF");
if(priv->opmode != ADC_OPMODE_STREAM) { if (priv->opmode != ADC_OPMODE_STREAM) {
com_respond_str(MSG_ERROR, frame_id, "Not streaming"); com_respond_str(MSG_ERROR, frame_id, "Not streaming");
return E_FAILURE; return E_FAILURE;
} }

Loading…
Cancel
Save