adc
Ondřej Hruška 7 years ago
parent 260fcc3e65
commit 21d9e97653
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 32
      units/adc/_adc_core.c
  2. 66
      units/adc/unit_adc.c

@ -8,6 +8,8 @@
#define ADC_INTERNAL #define ADC_INTERNAL
#include "_adc_internal.h" #include "_adc_internal.h"
#define DMA_POS(priv) ((priv)->dma_buffer_itemcount - (priv)->DMA_CHx->CNDTR)
void UADC_ReportEndOfStream(Unit *unit) void UADC_ReportEndOfStream(Unit *unit)
{ {
dbg("~~End Of Stream msg~~"); dbg("~~End Of Stream msg~~");
@ -101,27 +103,29 @@ void UADC_ADC_EOS_Handler(void *arg)
uint64_t timestamp = PTIM_GetMicrotime(); uint64_t timestamp = PTIM_GetMicrotime();
Unit *unit = arg; Unit *unit = arg;
dbg("ADC EOS ISR hit");
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
LL_ADC_ClearFlag_EOS(priv->ADCx);
// Wait for the DMA to complete copying the last sample // Wait for the DMA to complete copying the last sample
while (priv->DMA_CHx->CNDTR % priv->nb_channels != 0); uint16_t dmapos;
while ((dmapos = (uint16_t) DMA_POS(priv)) % priv->nb_channels != 0);
uint32_t sample_pos; uint32_t sample_pos;
if (priv->DMA_CHx->CNDTR == 0) { if (dmapos == 0) {
sample_pos = (uint32_t) (priv->dma_buffer_itemcount - 1); sample_pos = (uint32_t) (priv->dma_buffer_itemcount);
} else { } else {
sample_pos = priv->DMA_CHx->CNDTR; sample_pos = dmapos;
} }
sample_pos -= priv->nb_channels; sample_pos -= priv->nb_channels;
dbg("Sample pos %d", (int)sample_pos);
int cnt = 0; // index of the sample within the group
for (uint32_t i = 0; i < 18; i++) { for (uint32_t i = 0; i < 18; i++) {
if (priv->extended_channels_mask & (1 << i)) { if (priv->extended_channels_mask & (1 << i)) {
uint16_t val = priv->dma_buffer[sample_pos]; uint16_t val = priv->dma_buffer[sample_pos+cnt];
dbg("Trig line level %d", (int)val); cnt++;
priv->averaging_bins[i] = priv->averaging_bins[i] =
priv->averaging_bins[i] * (1.0f - priv->avg_factor_as_float) + priv->averaging_bins[i] * (1.0f - priv->avg_factor_as_float) +
@ -131,6 +135,8 @@ void UADC_ADC_EOS_Handler(void *arg)
if (priv->opmode == ADC_OPMODE_ARMED) { if (priv->opmode == ADC_OPMODE_ARMED) {
if (i == priv->trigger_source) { if (i == priv->trigger_source) {
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) {
@ -155,8 +161,6 @@ void UADC_ADC_EOS_Handler(void *arg)
} }
} }
} }
dbg(" EOS ISR end.");
} }
void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp) void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
@ -180,7 +184,7 @@ void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
dbg("Trigger condition hit, edge=%d", edge_type); dbg("Trigger condition hit, edge=%d", edge_type);
// TODO Send pre-trigger // TODO Send pre-trigger
priv->stream_startpos = (uint16_t) priv->DMA_CHx->CNDTR; priv->stream_startpos = (uint16_t) DMA_POS(priv);
priv->trig_stream_remain = priv->trig_len; priv->trig_stream_remain = priv->trig_len;
UADC_SwitchMode(unit, ADC_OPMODE_TRIGD); UADC_SwitchMode(unit, ADC_OPMODE_TRIGD);
} }
@ -192,7 +196,7 @@ void UADC_StartBlockCapture(Unit *unit, uint32_t len, TF_ID frame_id)
assert_param(priv); assert_param(priv);
priv->stream_frame_id = frame_id; priv->stream_frame_id = frame_id;
priv->stream_startpos = (uint16_t) priv->DMA_CHx->CNDTR; priv->stream_startpos = (uint16_t) DMA_POS(priv);
priv->trig_stream_remain = len; priv->trig_stream_remain = len;
UADC_SwitchMode(unit, ADC_OPMODE_FIXCAPT); UADC_SwitchMode(unit, ADC_OPMODE_FIXCAPT);
} }
@ -205,7 +209,7 @@ void UADC_StartStream(Unit *unit, TF_ID frame_id)
assert_param(priv); assert_param(priv);
priv->stream_frame_id = frame_id; priv->stream_frame_id = frame_id;
priv->stream_startpos = (uint16_t) priv->DMA_CHx->CNDTR; priv->stream_startpos = (uint16_t) DMA_POS(priv);
dbg("Start streaming."); dbg("Start streaming.");
UADC_SwitchMode(unit, ADC_OPMODE_STREAM); UADC_SwitchMode(unit, ADC_OPMODE_STREAM);
} }
@ -291,6 +295,8 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
LL_ADC_Enable(priv->ADCx); LL_ADC_Enable(priv->ADCx);
LL_DMA_EnableChannel(priv->DMAx, priv->dma_chnum); LL_DMA_EnableChannel(priv->DMAx, priv->dma_chnum);
LL_TIM_EnableCounter(priv->TIMx); LL_TIM_EnableCounter(priv->TIMx);
LL_ADC_REG_StartConversion(priv->ADCx);
} }
} }
else if (new_mode == ADC_OPMODE_ARMED) { else if (new_mode == ADC_OPMODE_ARMED) {

@ -24,6 +24,7 @@ enum TplCmd_ {
CMD_BLOCK_CAPTURE = 25, CMD_BLOCK_CAPTURE = 25,
CMD_STREAM_START = 26, CMD_STREAM_START = 26,
CMD_STREAM_STOP = 27, CMD_STREAM_STOP = 27,
CMD_SET_SMOOTHING_FACTOR = 28,
}; };
/** Handle a request message */ /** Handle a request message */
@ -33,6 +34,10 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
switch (command) { switch (command) {
/**
* Get enabled channels.
* Response: bytes with indices of enabled channels, ascending order.
*/
case CMD_GET_ENABLED_CHANNELS: case CMD_GET_ENABLED_CHANNELS:
dbg("> Query channels"); dbg("> Query channels");
for (uint8_t i = 0; i < 18; i++) { for (uint8_t i = 0; i < 18; i++) {
@ -43,6 +48,21 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
com_respond_pb(frame_id, MSG_SUCCESS, &pb); com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS; return E_SUCCESS;
/**
* Set smoothing factor 0-1000.
* pld: u16:factor
*/
case CMD_SET_SMOOTHING_FACTOR:
dbg("> Set smoothing");
uint16_t fac = pp_u16(pp);
if (fac > 1000) return E_BAD_VALUE;
priv->avg_factor_as_float = fac/1000.0f;
return E_SUCCESS;
/**
* Read raw values from the last measurement.
* Response: interleaved (u8:channel, u16:value) for all channels
*/
case CMD_READ_RAW: case CMD_READ_RAW:
dbg("> Read raw"); dbg("> Read raw");
if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) { if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) {
@ -59,6 +79,10 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
com_respond_pb(frame_id, MSG_SUCCESS, &pb); com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS; return E_SUCCESS;
/**
* Read smoothed values.
* Response: interleaved (u8:channel, f32:value) for all channels
*/
case CMD_READ_SMOOTHED: case CMD_READ_SMOOTHED:
dbg("> Read smoothed"); dbg("> Read smoothed");
if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) { if(priv->opmode != ADC_OPMODE_IDLE && priv->opmode != ADC_OPMODE_ARMED) {
@ -75,9 +99,22 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
com_respond_pb(frame_id, MSG_SUCCESS, &pb); com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS; return E_SUCCESS;
/**
* Configure a trigger. This is legal only if the current state is IDLE.
*
* Payload:
* u8 - source channel
* u16 - triggering level
* u8 - edge to trigger on: 1-rising, 2-falling, 3-both
* u16 - pre-trigger samples count
* u32 - post-trigger samples count
* u16 - trigger hold-off in ms (dead time after firing, before it cna fire again if armed)
* u8(bool) - auto re-arm after firing and completing the capture
*/
case CMD_SETUP_TRIGGER: case CMD_SETUP_TRIGGER:
dbg("> Setup trigger"); dbg("> Setup trigger");
if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
{ {
uint8_t source = pp_u8(pp); uint8_t source = pp_u8(pp);
uint16_t level = pp_u16(pp); uint16_t level = pp_u16(pp);
@ -126,6 +163,9 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
} }
return E_SUCCESS; return E_SUCCESS;
/**
* Arm (permissible only if idle and the trigger is configured)
*/
case CMD_ARM: case CMD_ARM:
dbg("> Arm"); dbg("> Arm");
if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY; if(priv->opmode != ADC_OPMODE_IDLE) return E_BUSY;
@ -138,6 +178,10 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
UADC_SwitchMode(unit, ADC_OPMODE_ARMED); UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
return E_SUCCESS; return E_SUCCESS;
/**
* Dis-arm. Permissible only when idle or armed.
* Switches to idle.
*/
case CMD_DISARM: case CMD_DISARM:
dbg("> Disarm"); dbg("> Disarm");
if(priv->opmode == ADC_OPMODE_IDLE) { if(priv->opmode == ADC_OPMODE_IDLE) {
@ -149,6 +193,9 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
return E_SUCCESS; return E_SUCCESS;
/**
* Abort any ongoing capture and dis-arm.
*/
case CMD_ABORT:; case CMD_ABORT:;
dbg("> Abort capture"); dbg("> Abort capture");
enum uadc_opmode old_opmode = priv->opmode; enum uadc_opmode old_opmode = priv->opmode;
@ -161,6 +208,10 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
} }
return E_SUCCESS; return E_SUCCESS;
/**
* Force a trigger (complete with pre-trigger capture and hold-off)
* The reported edge will be 0b11, here meaning "manual trigger"
*/
case CMD_FORCE_TRIGGER: case CMD_FORCE_TRIGGER:
dbg("> Force trigger"); dbg("> Force trigger");
if(priv->opmode == ADC_OPMODE_IDLE) { if(priv->opmode == ADC_OPMODE_IDLE) {
@ -172,6 +223,12 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime()); UADC_HandleTrigger(unit, 0b11, PTIM_GetMicrotime());
return E_SUCCESS; return E_SUCCESS;
/**
* Start a block capture (like manual trigger, but without pre-trigger and arming)
*
* Payload:
* u32 - sample count (for each channel)
*/
case CMD_BLOCK_CAPTURE: case CMD_BLOCK_CAPTURE:
dbg("> Block cpt"); dbg("> Block cpt");
if(priv->opmode != ADC_OPMODE_ARMED && if(priv->opmode != ADC_OPMODE_ARMED &&
@ -182,6 +239,10 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
UADC_StartBlockCapture(unit, count, frame_id); UADC_StartBlockCapture(unit, count, frame_id);
return E_SUCCESS; return E_SUCCESS;
/**
* Start streaming (like block capture, but unlimited)
* The stream can be terminated by the stop command.
*/
case CMD_STREAM_START: case CMD_STREAM_START:
dbg("> Stream ON"); dbg("> Stream ON");
if(priv->opmode != ADC_OPMODE_ARMED && if(priv->opmode != ADC_OPMODE_ARMED &&
@ -190,6 +251,9 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
UADC_StartStream(unit, frame_id); UADC_StartStream(unit, frame_id);
return E_SUCCESS; return E_SUCCESS;
/**
* Stop a stream.
*/
case CMD_STREAM_STOP: case CMD_STREAM_STOP:
dbg("> Stream OFF"); dbg("> Stream OFF");
if(priv->opmode != ADC_OPMODE_STREAM) { if(priv->opmode != ADC_OPMODE_STREAM) {
@ -210,7 +274,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
/** Unit template */ /** Unit template */
const UnitDriver UNIT_ADC = { const UnitDriver UNIT_ADC = {
.name = "ADC", .name = "ADC",
.description = "Analog/Digital converter", .description = "Analog/digital converter",
// Settings // Settings
.preInit = UADC_preInit, .preInit = UADC_preInit,
.cfgLoadBinary = UADC_loadBinary, .cfgLoadBinary = UADC_loadBinary,

Loading…
Cancel
Save