Fixzed triggers and also missed TC/TH

adc^2
Ondřej Hruška 7 years ago
parent d6e73a5641
commit 85453afa44
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 183
      units/adc/_adc_core.c
  2. 2
      units/adc/_adc_init.c

@ -140,6 +140,80 @@ void UADC_ReportEndOfStream(Unit *unit)
scheduleJob(&j);
}
static void handle_httc(Unit *unit, bool tc)
{
struct priv *priv = unit->data;
uint16_t start = priv->stream_startpos;
uint16_t end;
const bool ht = !tc;
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_BLCAP;
if (ht) {
// dbg("HT");
end = (uint16_t) (priv->dma_buffer_itemcount / 2);
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
}
else {
// dbg("TC");
end = (uint16_t) priv->dma_buffer_itemcount;
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
}
if (ht == tc) {
// This shouldn't happen - looks like we missed the TC flag
dbg("!! %d -> %d", (int) start, (int) end);
// TODO we could try to catch up. for now, just take what is easy to grab and hope it doesnt matter
if (end == 64) start = 0;
}
if (start != end) {
uint32_t sgcount = (end - start) / priv->nb_channels;
if (m_trigd || m_fixcpt) {
sgcount = MIN(priv->trig_stream_remain, sgcount);
priv->trig_stream_remain -= sgcount;
}
bool close = !m_stream && priv->trig_stream_remain == 0;
Job j = {
.unit = unit,
.data1 = start,
.data2 = sgcount * priv->nb_channels,
.data3 = (uint32_t) close,
.cb = UADC_JobSendBlockChunk
};
if (!scheduleJob(&j)) {
// Abort if we can't queue - the stream would tear and we'd hog the system with error messages
dbg("(!) Buffers overflow, abort capture");
emergency = true;
UADC_SwitchMode(unit, ADC_OPMODE_EMERGENCY_SHUTDOWN);
return;
}
if (close) {
// dbg("End of capture");
// 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 {
// dbg("start==end, skip this irq");
}
if (tc) {
priv->stream_startpos = 0;
}
else {
priv->stream_startpos = end;
}
}
void UADC_DMA_Handler(void *arg)
{
Unit *unit = arg;
@ -169,67 +243,17 @@ void UADC_DMA_Handler(void *arg)
if (m_trigd || m_stream || m_fixcpt) {
if (ht || tc) {
const uint16_t start = priv->stream_startpos;
uint16_t end;
if (ht) {
// dbg("HT");
end = (uint16_t) (priv->dma_buffer_itemcount / 2);
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
}
else {
// dbg("TC");
end = (uint16_t) priv->dma_buffer_itemcount;
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
}
if (start > end) {
dbg("start %d, end %d", (int) start, (int) end);
}
assert_param(start <= end);
if (start != end) {
uint32_t sgcount = (end - start) / priv->nb_channels;
if (m_trigd || m_fixcpt) {
sgcount = MIN(priv->trig_stream_remain, sgcount);
priv->trig_stream_remain -= sgcount;
}
bool close = !m_stream && priv->trig_stream_remain == 0;
Job j = {
.unit = unit,
.data1 = start,
.data2 = sgcount * priv->nb_channels,
.data3 = (uint32_t) close,
.cb = UADC_JobSendBlockChunk
};
if (!scheduleJob(&j)) {
// Abort if we can't queue - the stream would tear and we'd hog the system with error messages
dbg("(!) Buffers overflow, abort capture");
emergency = true;
UADC_SwitchMode(unit, ADC_OPMODE_EMERGENCY_SHUTDOWN);
return;
}
if (close) {
// dbg("End of capture");
// 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);
if (ht && tc) {
uint16_t half = (uint16_t) (priv->dma_buffer_itemcount / 2);
if (priv->stream_startpos > half) {
handle_httc(unit, true);
handle_httc(unit, false);
} else {
handle_httc(unit, false);
handle_httc(unit, true);
}
} else {
// dbg("start==end, skip this irq");
}
if (tc) {
priv->stream_startpos = 0;
}
else {
priv->stream_startpos = end;
handle_httc(unit, tc);
}
}
} else {
@ -259,13 +283,9 @@ void UADC_ADC_EOS_Handler(void *arg)
struct priv *priv = unit->data;
assert_param(priv);
const bool trig_ready4_rising = (priv->trig_prev_level < priv->trig_level) && (bool) (priv->trig_edge & 0b01);
const bool trig_ready4_falling = (priv->trig_prev_level > priv->trig_level) && (bool) (priv->trig_edge & 0b10);
const bool armed = (trig_ready4_rising && trig_ready4_falling) && priv->opmode == ADC_OPMODE_ARMED;
// Normally
uint64_t timestamp = 0;
if (armed) timestamp = PTIM_GetMicrotime();
if (priv->opmode == ADC_OPMODE_ARMED) timestamp = PTIM_GetMicrotime();
LL_ADC_ClearFlag_EOS(priv->ADCx);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
@ -284,14 +304,12 @@ void UADC_ADC_EOS_Handler(void *arg)
int cnt = 0; // index of the sample within the group
const uint8_t trig_source = priv->trigger_source;
const bool can_average = priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING;
const uint16_t *dma_buffer = priv->dma_buffer;
const uint32_t channels_mask = priv->extended_channels_mask;
for (uint8_t i = 0; i < 18; i++) {
if (channels_mask & (1 << i)) {
uint16_t val = dma_buffer[sample_pos+cnt];
uint16_t val = priv->dma_buffer[sample_pos+cnt];
cnt++;
if (can_average) {
@ -301,24 +319,27 @@ void UADC_ADC_EOS_Handler(void *arg)
}
priv->last_samples[i] = val;
}
}
if (armed && i == trig_source) {
// dbg("Trig line level %d", (int)val);
if (trig_ready4_rising && val >= priv->trig_level) {
// dbg("******** Rising edge");
// Rising edge
UADC_HandleTrigger(unit, 1, timestamp);
}
else if (trig_ready4_falling && val <= priv->trig_level) {
// dbg("******** Falling edge");
// Falling edge
UADC_HandleTrigger(unit, 2, timestamp);
}
priv->trig_prev_level = val;
}
if (priv->opmode == ADC_OPMODE_ARMED) {
uint16_t val = priv->last_samples[priv->trigger_source];
// dbg("Trig line level %d", (int)val);
if ((priv->trig_prev_level < priv->trig_level) && val >= priv->trig_level && (bool) (priv->trig_edge & 0b01)) {
// dbg("******** Rising edge");
// Rising edge
UADC_HandleTrigger(unit, 1, timestamp);
}
else if ((priv->trig_prev_level > priv->trig_level) && val <= priv->trig_level && (bool) (priv->trig_edge & 0b10)) {
// dbg("******** Falling edge");
// Falling edge
UADC_HandleTrigger(unit, 2, timestamp);
}
priv->trig_prev_level = val;
}
// auto-rearm was waiting for the next sample
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.

@ -196,7 +196,7 @@ error_t UADC_init(Unit *unit)
priv->dma_buffer_itemcount*sizeof(uint16_t),
priv->nb_channels);
priv->dma_buffer = malloc_ck(priv->dma_buffer_itemcount * sizeof(uint16_t));
priv->dma_buffer = calloc_ck(priv->dma_buffer_itemcount, sizeof(uint16_t));
if (NULL == priv->dma_buffer) return E_OUT_OF_MEM;
assert_param(((uint32_t) priv->dma_buffer & 3) == 0); // must be aligned

Loading…
Cancel
Save