some small adc fixes (impreoving trigger)

adc
Ondřej Hruška 6 years ago
parent f80761b327
commit d4e1d85bb4
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 46
      units/adc/_adc_core.c
  2. 3
      units/adc/_adc_internal.h
  3. 98
      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);
// 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 ||

@ -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

@ -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;
}

Loading…
Cancel
Save