|
|
@ -39,6 +39,75 @@ static void UADC_JobSendBlockChunk(Job *job) |
|
|
|
priv->stream_serial++; |
|
|
|
priv->stream_serial++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void UADC_JobSendTriggerCaptureHeader(Job *job) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Unit *unit = job->unit; |
|
|
|
|
|
|
|
assert_param(unit); |
|
|
|
|
|
|
|
struct priv *priv = unit->data; |
|
|
|
|
|
|
|
assert_param(priv); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EventReport er = { |
|
|
|
|
|
|
|
.unit = unit, |
|
|
|
|
|
|
|
.type = EVT_CAPT_START, |
|
|
|
|
|
|
|
.timestamp = job->timestamp, |
|
|
|
|
|
|
|
.length = (priv->pretrig_len+1)*priv->nb_channels*sizeof(uint16_t) + 2 /*pretrig len*/ + 1 /*edge*/ + 1 /* seq */ |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t index_trigd = (uint16_t) job->data1; |
|
|
|
|
|
|
|
uint8_t edge = (uint8_t) job->data2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EventReport_Start(&er); |
|
|
|
|
|
|
|
priv->stream_frame_id = er.sent_msg_id; |
|
|
|
|
|
|
|
dbg("Sending TRIG HEADER with id %d (idx %d)", (int)er.sent_msg_id, (int)index_trigd); |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// preamble
|
|
|
|
|
|
|
|
uint8_t buf[4]; |
|
|
|
|
|
|
|
PayloadBuilder pb = pb_start(buf, 4, NULL); |
|
|
|
|
|
|
|
pb_u16(&pb, priv->pretrig_len); |
|
|
|
|
|
|
|
pb_u8(&pb, edge); |
|
|
|
|
|
|
|
pb_u8(&pb, priv->stream_serial++); // This is the serial counter for the first chunk
|
|
|
|
|
|
|
|
// (containing the pre-trigger, or empty if no pretrig configured)
|
|
|
|
|
|
|
|
EventReport_PB(&pb); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (priv->pretrig_len > 0) { |
|
|
|
|
|
|
|
// pretrig
|
|
|
|
|
|
|
|
uint16_t pretrig_remain = (uint16_t) ((priv->pretrig_len + 1) * priv->nb_channels); // +1 because we want pretrig 0 to exactly start with the triggering sample
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_param(index_trigd <= priv->dma_buffer_itemcount); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this is one past the last entry of the triggering capture group
|
|
|
|
|
|
|
|
if (pretrig_remain > index_trigd) { |
|
|
|
|
|
|
|
// used items in the wrap-around part of the buffer
|
|
|
|
|
|
|
|
uint16_t items_from_end = pretrig_remain - index_trigd; |
|
|
|
|
|
|
|
assert_param(priv->dma_buffer_itemcount - items_from_end >= index_trigd); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dbg("Pretrig wraparound part: start %d, len %d", |
|
|
|
|
|
|
|
(int) (priv->dma_buffer_itemcount - items_from_end), |
|
|
|
|
|
|
|
(int) items_from_end |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EventReport_Data( |
|
|
|
|
|
|
|
(uint8_t *) &priv->dma_buffer[priv->dma_buffer_itemcount - |
|
|
|
|
|
|
|
items_from_end], |
|
|
|
|
|
|
|
items_from_end * sizeof(uint16_t)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_param(items_from_end <= pretrig_remain); |
|
|
|
|
|
|
|
pretrig_remain -= items_from_end; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dbg("Pretrig front part: start %d, len %d", |
|
|
|
|
|
|
|
(int) (index_trigd - pretrig_remain), |
|
|
|
|
|
|
|
(int) pretrig_remain |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_param(pretrig_remain <= index_trigd); |
|
|
|
|
|
|
|
EventReport_Data((uint8_t *) &priv->dma_buffer[index_trigd - pretrig_remain], |
|
|
|
|
|
|
|
pretrig_remain * sizeof(uint16_t)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
EventReport_End(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void UADC_JobSendEndOfStreamMsg(Job *job) |
|
|
|
static void UADC_JobSendEndOfStreamMsg(Job *job) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Unit *unit = job->unit; |
|
|
|
Unit *unit = job->unit; |
|
|
@ -93,17 +162,17 @@ void UADC_DMA_Handler(void *arg) |
|
|
|
uint16_t end; |
|
|
|
uint16_t end; |
|
|
|
|
|
|
|
|
|
|
|
if (ht) { |
|
|
|
if (ht) { |
|
|
|
dbg("HT"); |
|
|
|
// dbg("HT");
|
|
|
|
end = (uint16_t) (priv->dma_buffer_itemcount / 2); |
|
|
|
end = (uint16_t) (priv->dma_buffer_itemcount / 2); |
|
|
|
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum); |
|
|
|
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
dbg("TC"); |
|
|
|
// dbg("TC");
|
|
|
|
end = (uint16_t) priv->dma_buffer_itemcount; |
|
|
|
end = (uint16_t) priv->dma_buffer_itemcount; |
|
|
|
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum); |
|
|
|
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
dbg("start %d, end %d", (int)start, (int)end); |
|
|
|
// dbg("start %d, end %d", (int)start, (int)end);
|
|
|
|
assert_param(start <= end); |
|
|
|
assert_param(start <= end); |
|
|
|
|
|
|
|
|
|
|
|
if (start != end) { |
|
|
|
if (start != end) { |
|
|
@ -126,7 +195,7 @@ void UADC_DMA_Handler(void *arg) |
|
|
|
scheduleJob(&j); |
|
|
|
scheduleJob(&j); |
|
|
|
|
|
|
|
|
|
|
|
if (close) { |
|
|
|
if (close) { |
|
|
|
dbg("End of capture"); |
|
|
|
// dbg("End of capture");
|
|
|
|
// If auto-arm enabled, we need to re-arm again.
|
|
|
|
// If auto-arm enabled, we need to re-arm again.
|
|
|
|
// However, EOS irq is disabled during the capture.
|
|
|
|
// However, EOS irq is disabled during the capture.
|
|
|
|
// We have to wait for the next EOS interrupt to occur.
|
|
|
|
// We have to wait for the next EOS interrupt to occur.
|
|
|
@ -134,7 +203,7 @@ void UADC_DMA_Handler(void *arg) |
|
|
|
UADC_SwitchMode(unit, (priv->auto_rearm && m_trigd) ? ADC_OPMODE_REARM_PENDING : ADC_OPMODE_IDLE); |
|
|
|
UADC_SwitchMode(unit, (priv->auto_rearm && m_trigd) ? ADC_OPMODE_REARM_PENDING : ADC_OPMODE_IDLE); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
dbg("start==end, skip this irq"); |
|
|
|
// dbg("start==end, skip this irq");
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (tc) { |
|
|
|
if (tc) { |
|
|
@ -201,18 +270,18 @@ void UADC_ADC_EOS_Handler(void *arg) |
|
|
|
|
|
|
|
|
|
|
|
if (i == priv->trigger_source) { |
|
|
|
if (i == priv->trigger_source) { |
|
|
|
if (priv->opmode == ADC_OPMODE_ARMED) { |
|
|
|
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; |
|
|
|
uint8_t edge_type = 0; |
|
|
|
uint8_t edge_type = 0; |
|
|
|
if (priv->trig_prev_level < priv->trig_level && val >= priv->trig_level) { |
|
|
|
if (priv->trig_prev_level < priv->trig_level && val >= priv->trig_level) { |
|
|
|
dbg("******** Rising edge"); |
|
|
|
// dbg("******** Rising edge");
|
|
|
|
// Rising edge
|
|
|
|
// Rising edge
|
|
|
|
trigd = (bool) (priv->trig_edge & 0b01); |
|
|
|
trigd = (bool) (priv->trig_edge & 0b01); |
|
|
|
edge_type = 1; |
|
|
|
edge_type = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (priv->trig_prev_level > priv->trig_level && val <= priv->trig_level) { |
|
|
|
else if (priv->trig_prev_level > priv->trig_level && val <= priv->trig_level) { |
|
|
|
dbg("******** Falling edge"); |
|
|
|
// dbg("******** Falling edge");
|
|
|
|
// Falling edge
|
|
|
|
// Falling edge
|
|
|
|
trigd = (bool) (priv->trig_edge & 0b10); |
|
|
|
trigd = (bool) (priv->trig_edge & 0b10); |
|
|
|
edge_type = 2; |
|
|
|
edge_type = 2; |
|
|
@ -246,7 +315,7 @@ void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp) |
|
|
|
assert_param(priv); |
|
|
|
assert_param(priv); |
|
|
|
|
|
|
|
|
|
|
|
if (priv->trig_holdoff != 0 && priv->trig_holdoff_remain > 0) { |
|
|
|
if (priv->trig_holdoff != 0 && priv->trig_holdoff_remain > 0) { |
|
|
|
dbg("Trig discarded due to holdoff."); |
|
|
|
// dbg("Trig discarded due to holdoff.");
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -261,9 +330,16 @@ void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp) |
|
|
|
priv->trig_stream_remain = priv->trig_len; |
|
|
|
priv->trig_stream_remain = priv->trig_len; |
|
|
|
priv->stream_serial = 0; |
|
|
|
priv->stream_serial = 0; |
|
|
|
|
|
|
|
|
|
|
|
// TODO Send pre-trigger
|
|
|
|
// dbg("Trigger condition hit, edge=%d, startpos %d", edge_type, (int)priv->stream_startpos);
|
|
|
|
|
|
|
|
|
|
|
|
dbg("Trigger condition hit, edge=%d, startpos %d", edge_type, (int)priv->stream_startpos); |
|
|
|
Job j = { |
|
|
|
|
|
|
|
.unit = unit, |
|
|
|
|
|
|
|
.timestamp = timestamp, |
|
|
|
|
|
|
|
.data1 = priv->stream_startpos, |
|
|
|
|
|
|
|
.data2 = edge_type, |
|
|
|
|
|
|
|
.cb = UADC_JobSendTriggerCaptureHeader |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
scheduleJob(&j); |
|
|
|
|
|
|
|
|
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_TRIGD); |
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_TRIGD); |
|
|
|
} |
|
|
|
} |
|
|
@ -291,7 +367,7 @@ void UADC_StartStream(Unit *unit, TF_ID frame_id) |
|
|
|
priv->stream_frame_id = frame_id; |
|
|
|
priv->stream_frame_id = frame_id; |
|
|
|
priv->stream_startpos = (uint16_t) DMA_POS(priv); |
|
|
|
priv->stream_startpos = (uint16_t) DMA_POS(priv); |
|
|
|
priv->stream_serial = 0; |
|
|
|
priv->stream_serial = 0; |
|
|
|
dbg("Start streaming."); |
|
|
|
// dbg("Start streaming.");
|
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_STREAM); |
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_STREAM); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -302,7 +378,7 @@ void UADC_StopStream(Unit *unit) |
|
|
|
struct priv *priv = unit->data; |
|
|
|
struct priv *priv = unit->data; |
|
|
|
assert_param(priv); |
|
|
|
assert_param(priv); |
|
|
|
|
|
|
|
|
|
|
|
dbg("Stop stream."); |
|
|
|
// dbg("Stop stream.");
|
|
|
|
UADC_ReportEndOfStream(unit); |
|
|
|
UADC_ReportEndOfStream(unit); |
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); |
|
|
|
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); |
|
|
|
} |
|
|
|
} |
|
|
@ -336,7 +412,7 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode) |
|
|
|
assert_param((priv->opmode != ADC_OPMODE_UNINIT) || (new_mode == ADC_OPMODE_IDLE)); |
|
|
|
assert_param((priv->opmode != ADC_OPMODE_UNINIT) || (new_mode == ADC_OPMODE_IDLE)); |
|
|
|
|
|
|
|
|
|
|
|
if (new_mode == ADC_OPMODE_UNINIT) { |
|
|
|
if (new_mode == ADC_OPMODE_UNINIT) { |
|
|
|
dbg("ADC switch -> UNINIT"); |
|
|
|
// dbg("ADC switch -> UNINIT");
|
|
|
|
// Stop the DMA, timer and disable ADC - this is called before tearing down the unit
|
|
|
|
// Stop the DMA, timer and disable ADC - this is called before tearing down the unit
|
|
|
|
LL_TIM_DisableCounter(priv->TIMx); |
|
|
|
LL_TIM_DisableCounter(priv->TIMx); |
|
|
|
|
|
|
|
|
|
|
@ -344,23 +420,23 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode) |
|
|
|
if (LL_ADC_IsEnabled(priv->ADCx)) { |
|
|
|
if (LL_ADC_IsEnabled(priv->ADCx)) { |
|
|
|
// Cancel ongoing conversion
|
|
|
|
// Cancel ongoing conversion
|
|
|
|
if (LL_ADC_REG_IsConversionOngoing(priv->ADCx)) { |
|
|
|
if (LL_ADC_REG_IsConversionOngoing(priv->ADCx)) { |
|
|
|
dbg("Stopping ADC conv"); |
|
|
|
// dbg("Stopping ADC conv");
|
|
|
|
LL_ADC_REG_StopConversion(priv->ADCx); |
|
|
|
LL_ADC_REG_StopConversion(priv->ADCx); |
|
|
|
hw_wait_while(LL_ADC_REG_IsStopConversionOngoing(priv->ADCx), 100); |
|
|
|
hw_wait_while(LL_ADC_REG_IsStopConversionOngoing(priv->ADCx), 100); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LL_ADC_Disable(priv->ADCx); |
|
|
|
LL_ADC_Disable(priv->ADCx); |
|
|
|
dbg("Disabling ADC"); |
|
|
|
// dbg("Disabling ADC");
|
|
|
|
hw_wait_while(LL_ADC_IsDisableOngoing(priv->ADCx), 100); |
|
|
|
hw_wait_while(LL_ADC_IsDisableOngoing(priv->ADCx), 100); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
dbg("Disabling DMA"); |
|
|
|
// dbg("Disabling DMA");
|
|
|
|
LL_DMA_DisableChannel(priv->DMAx, priv->dma_chnum); |
|
|
|
LL_DMA_DisableChannel(priv->DMAx, priv->dma_chnum); |
|
|
|
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 || new_mode == ADC_OPMODE_REARM_PENDING) { |
|
|
|
else if (new_mode == ADC_OPMODE_IDLE || new_mode == ADC_OPMODE_REARM_PENDING) { |
|
|
|
dbg("ADC switch -> IDLE or IDLE/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
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
@ -382,7 +458,7 @@ 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 || priv->opmode == ADC_OPMODE_REARM_PENDING); |
|
|
|
assert_param(priv->opmode == ADC_OPMODE_IDLE || priv->opmode == ADC_OPMODE_REARM_PENDING); |
|
|
|
|
|
|
|
|
|
|
|
// avoid firing immediately by the value jumping across the scale
|
|
|
|
// avoid firing immediately by the value jumping across the scale
|
|
|
@ -392,7 +468,7 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode) |
|
|
|
new_mode == ADC_OPMODE_STREAM || |
|
|
|
new_mode == ADC_OPMODE_STREAM || |
|
|
|
new_mode == ADC_OPMODE_BLCAP) { |
|
|
|
new_mode == ADC_OPMODE_BLCAP) { |
|
|
|
|
|
|
|
|
|
|
|
dbg("ADC switch -> TRIG'D / STREAM / BLOCK"); |
|
|
|
// dbg("ADC switch -> TRIG'D / STREAM / BLOCK");
|
|
|
|
assert_param(priv->opmode == ADC_OPMODE_ARMED || priv->opmode == ADC_OPMODE_IDLE); |
|
|
|
assert_param(priv->opmode == ADC_OPMODE_ARMED || priv->opmode == ADC_OPMODE_IDLE); |
|
|
|
|
|
|
|
|
|
|
|
// during the capture, we disallow direct readout and averaging to reduce overhead
|
|
|
|
// during the capture, we disallow direct readout and averaging to reduce overhead
|
|
|
|