Merge branch 'adc-fault' into adc

adc
Ondřej Hruška 7 years ago
commit 3b341cd033
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      FreeRTOSConfig.h
  2. 2
      USB/STM32_USB_Device_Library/Class/MSC_CDC/usbd_msc_cdc.c
  3. 7
      framework/unit_registry.c
  4. 8
      freertos.c
  5. 3
      platform/hw_utils.c
  6. 6
      platform/plat_compat.h
  7. 17
      tasks/task_msg.c
  8. 2
      tasks/task_msg.h
  9. 18
      units/adc/_adc_api.c
  10. 211
      units/adc/_adc_core.c
  11. 57
      units/adc/_adc_init.c
  12. 8
      units/adc/_adc_internal.h
  13. 2
      units/adc/_adc_settings.c
  14. 45
      units/adc/unit_adc.c
  15. 2
      units/adc/unit_adc.h
  16. 2
      units/usart/unit_usart.c

@ -111,7 +111,7 @@
#define configUSE_TIMERS 1 #define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 4 // above normal #define configTIMER_TASK_PRIORITY 4 // above normal
#define configTIMER_TASK_STACK_DEPTH 128 #define configTIMER_TASK_STACK_DEPTH TSK_STACK_TIMERS //128
#define configTIMER_QUEUE_LENGTH 4 #define configTIMER_QUEUE_LENGTH 4
#define configTOTAL_HEAP_SIZE 4096 #define configTOTAL_HEAP_SIZE 4096

@ -112,7 +112,7 @@ __ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __AL
0x03, /* bmAttributes: Interrupt */ 0x03, /* bmAttributes: Interrupt */
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: TODO: 2?*/ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: TODO: 2?*/
HIBYTE(CDC_CMD_PACKET_SIZE), HIBYTE(CDC_CMD_PACKET_SIZE),
0xFF, /* bInterval: TODO was 0x10?*/ 0x10, //0xFF, /* bInterval: TODO was 0x10?*/
/********** CDC Data Class Interface Descriptor ***********/ /********** CDC Data Class Interface Descriptor ***********/
/*75*/ 0x09, /* bLength: Endpoint Descriptor size */ /*75*/ 0x09, /* bLength: Endpoint Descriptor size */

@ -612,14 +612,17 @@ void ureg_tick_units(void)
UlistEntry *li = ulist_head; UlistEntry *li = ulist_head;
while (li != NULL) { while (li != NULL) {
Unit *const pUnit = &li->unit; Unit *const pUnit = &li->unit;
if (pUnit && pUnit->data && pUnit->status == E_SUCCESS && pUnit->tick_interval > 0) { if (pUnit && pUnit->data && pUnit->status == E_SUCCESS && (pUnit->tick_interval > 0 || pUnit->_tick_cnt > 0)) {
if (pUnit->_tick_cnt > 0) {
pUnit->_tick_cnt--; // check for 0 allows one-off timers
}
if (pUnit->_tick_cnt == 0) { if (pUnit->_tick_cnt == 0) {
if (pUnit->driver->updateTick) { if (pUnit->driver->updateTick) {
pUnit->driver->updateTick(pUnit); pUnit->driver->updateTick(pUnit);
} }
pUnit->_tick_cnt = pUnit->tick_interval; pUnit->_tick_cnt = pUnit->tick_interval;
} }
pUnit->_tick_cnt--;
} }
li = li->next; li = li->next;
} }

@ -114,13 +114,13 @@ __weak void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTas
/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ /* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer; static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; static StackType_t xIdleStack[TSK_STACK_IDLE];
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{ {
*ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
*ppxIdleTaskStackBuffer = &xIdleStack[0]; *ppxIdleTaskStackBuffer = &xIdleStack[0];
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; *pulIdleTaskStackSize = TSK_STACK_IDLE;
/* place for user code */ /* place for user code */
} }
/* USER CODE END GET_IDLE_TASK_MEMORY */ /* USER CODE END GET_IDLE_TASK_MEMORY */
@ -128,13 +128,13 @@ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackTy
/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ /* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xTimersTaskTCBBuffer; static StaticTask_t xTimersTaskTCBBuffer;
static StackType_t xTimersStack[configTIMER_TASK_STACK_DEPTH]; static StackType_t xTimersStack[TSK_STACK_TIMERS];
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimersTaskTCBBuffer, StackType_t **ppxTimersTaskStackBuffer, uint32_t *pulTimersTaskStackSize ) void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimersTaskTCBBuffer, StackType_t **ppxTimersTaskStackBuffer, uint32_t *pulTimersTaskStackSize )
{ {
*ppxTimersTaskTCBBuffer = &xTimersTaskTCBBuffer; *ppxTimersTaskTCBBuffer = &xTimersTaskTCBBuffer;
*ppxTimersTaskStackBuffer = &xTimersStack[0]; *ppxTimersTaskStackBuffer = &xTimersStack[0];
*pulTimersTaskStackSize = configTIMER_TASK_STACK_DEPTH; *pulTimersTaskStackSize = TSK_STACK_TIMERS;
/* place for user code */ /* place for user code */
} }
/* USER CODE END GET_IDLE_TASK_MEMORY */ /* USER CODE END GET_IDLE_TASK_MEMORY */

@ -371,7 +371,10 @@ bool solve_timer(uint32_t base_freq, uint32_t required_freq, bool is16bit,
*presc = (uint16_t) wPresc; *presc = (uint16_t) wPresc;
if (wPresc * wCount == 0) return false; if (wPresc * wCount == 0) return false;
if (real_freq != NULL) {
*real_freq = (base_freq / (wPresc * wCount)); *real_freq = (base_freq / (wPresc * wCount));
}
return true; return true;
} }

@ -18,13 +18,17 @@
// 180 is normally enough if not doing extensive debug logging // 180 is normally enough if not doing extensive debug logging
#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread) #define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread)
#define TSK_STACK_IDLE 64 //configMINIMAL_STACK_SIZE
#define TSK_STACK_TIMERS 64 //configTIMER_TASK_STACK_DEPTH
#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads #define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads
#define UNIT_TMP_LEN 512 // Buffer for internal unit operations #define UNIT_TMP_LEN 512 // Buffer for internal unit operations
#define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash #define FLASH_SAVE_BUF_LEN 128 // Malloc'd buffer for saving to flash
#define MSG_QUE_SLOT_SIZE 64 // FIXME this should be possible to lower, but there's some bug with bulk transfer / INI parser #define MSG_QUE_SLOT_SIZE 64 // FIXME this should be possible to lower, but there's some bug with bulk transfer / INI parser
#define RX_QUE_CAPACITY 16 // TinyFrame rx queue size (64 bytes each) #define RX_QUE_CAPACITY 36 // TinyFrame rx queue size (64 bytes each)
#define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload #define TF_MAX_PAYLOAD_RX 512 // TF max Rx payload
#define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame) #define TF_SENDBUF_LEN 64 // TF transmit buffer (can be less than a full frame)

@ -8,7 +8,7 @@
volatile uint32_t msgQueHighWaterMark = 0; volatile uint32_t msgQueHighWaterMark = 0;
static void que_safe_post(struct rx_sched_combined_que_item *slot) static bool que_safe_post(struct rx_sched_combined_que_item *slot)
{ {
uint32_t count = 0; uint32_t count = 0;
assert_param(slot != NULL); assert_param(slot != NULL);
@ -18,7 +18,7 @@ static void que_safe_post(struct rx_sched_combined_que_item *slot)
BaseType_t status = xQueueSendFromISR(queMsgJobHandle, slot, &xHigherPriorityTaskWoken); BaseType_t status = xQueueSendFromISR(queMsgJobHandle, slot, &xHigherPriorityTaskWoken);
if (pdPASS != status) { if (pdPASS != status) {
dbg("! Que post from ISR failed"); dbg("! Que post from ISR failed");
return; return false;
} }
#if USE_STACK_MONITOR #if USE_STACK_MONITOR
@ -30,7 +30,7 @@ static void que_safe_post(struct rx_sched_combined_que_item *slot)
BaseType_t status = xQueueSend(queMsgJobHandle, slot, MSG_QUE_POST_TIMEOUT); BaseType_t status = xQueueSend(queMsgJobHandle, slot, MSG_QUE_POST_TIMEOUT);
if (pdPASS != status) { if (pdPASS != status) {
dbg("! Que post failed"); dbg("! Que post failed");
return; return false;
} }
#if USE_STACK_MONITOR #if USE_STACK_MONITOR
@ -41,6 +41,8 @@ static void que_safe_post(struct rx_sched_combined_que_item *slot)
#if USE_STACK_MONITOR #if USE_STACK_MONITOR
msgQueHighWaterMark = MAX(msgQueHighWaterMark, count); msgQueHighWaterMark = MAX(msgQueHighWaterMark, count);
#endif #endif
return true;
} }
/** /**
@ -48,7 +50,7 @@ static void que_safe_post(struct rx_sched_combined_que_item *slot)
* *
* @param callback - the callback function * @param callback - the callback function
*/ */
void scheduleJob(Job *job) bool scheduleJob(Job *job)
{ {
assert_param(job->cb != NULL); assert_param(job->cb != NULL);
@ -57,7 +59,7 @@ void scheduleJob(Job *job)
.job = *job, // copy content of the struct .job = *job, // copy content of the struct
}; };
que_safe_post(&slot); return que_safe_post(&slot);
} }
/** /**
@ -112,7 +114,10 @@ void rxQuePostMsg(uint8_t *buf, uint32_t len)
slot.msg.len = len > MSG_QUE_SLOT_SIZE ? MSG_QUE_SLOT_SIZE : len; slot.msg.len = len > MSG_QUE_SLOT_SIZE ? MSG_QUE_SLOT_SIZE : len;
memcpy(slot.msg.data, buf, slot.msg.len); memcpy(slot.msg.data, buf, slot.msg.len);
que_safe_post(&slot); if (!que_safe_post(&slot)) {
dbg("rxQuePostMsg fail!");
break;
}
len -= slot.msg.len; len -= slot.msg.len;
buf += slot.msg.len; buf += slot.msg.len;

@ -25,7 +25,7 @@ void TaskMsgJob(const void *argument);
* *
* @param job * @param job
*/ */
void scheduleJob(Job *job); bool scheduleJob(Job *job);
/** /**
* Add a message to the queue. This always takes the entire slot (64 bytes) or multiple * Add a message to the queue. This always takes the entire slot (64 bytes) or multiple

@ -9,3 +9,21 @@
#define ADC_INTERNAL #define ADC_INTERNAL
#include "_adc_internal.h" #include "_adc_internal.h"
error_t UU_ADC_AbortCapture(Unit *unit)
{
CHECK_TYPE(unit, &UNIT_ADC);
struct priv *priv = unit->data;
enum uadc_opmode old_opmode = priv->opmode;
priv->auto_rearm = false;
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
if (old_opmode == ADC_OPMODE_BLCAP ||
old_opmode == ADC_OPMODE_STREAM ||
old_opmode == ADC_OPMODE_TRIGD) {
UADC_ReportEndOfStream(unit);
}
return E_SUCCESS;
}

@ -4,12 +4,16 @@
#include "platform.h" #include "platform.h"
#include "unit_base.h" #include "unit_base.h"
#include "unit_adc.h"
#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) #define DMA_POS(priv) ((priv)->dma_buffer_itemcount - (priv)->DMA_CHx->CNDTR)
volatile bool emergency = false;
//#define CRUMB() if(emergency) trap("crumb")
static void UADC_JobSendBlockChunk(Job *job) static void UADC_JobSendBlockChunk(Job *job)
{ {
Unit *unit = job->unit; Unit *unit = job->unit;
@ -21,7 +25,7 @@ static void UADC_JobSendBlockChunk(Job *job)
uint32_t count = job->data2; uint32_t count = job->data2;
bool close = (bool) job->data3; bool close = (bool) job->data3;
dbg("Send indices [%d -> %d)", (int)start, (int)(start+count)); // dbg("Send indices [%d -> %d)", (int)start, (int)(start+count));
TF_TYPE type = close ? EVT_CAPT_DONE : EVT_CAPT_MORE; TF_TYPE type = close ? EVT_CAPT_DONE : EVT_CAPT_MORE;
@ -58,7 +62,7 @@ static void UADC_JobSendTriggerCaptureHeader(Job *job)
EventReport_Start(&er); EventReport_Start(&er);
priv->stream_frame_id = er.sent_msg_id; 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); // dbg("Sending TRIG HEADER with id %d (idx %d)", (int)er.sent_msg_id, (int)index_trigd);
{ {
// preamble // preamble
uint8_t buf[4]; uint8_t buf[4];
@ -81,10 +85,10 @@ static void UADC_JobSendTriggerCaptureHeader(Job *job)
uint16_t items_from_end = pretrig_remain - index_trigd; uint16_t items_from_end = pretrig_remain - index_trigd;
assert_param(priv->dma_buffer_itemcount - items_from_end >= index_trigd); assert_param(priv->dma_buffer_itemcount - items_from_end >= index_trigd);
dbg("Pretrig wraparound part: start %d, len %d", // dbg("Pretrig wraparound part: start %d, len %d",
(int) (priv->dma_buffer_itemcount - items_from_end), // (int) (priv->dma_buffer_itemcount - items_from_end),
(int) items_from_end // (int) items_from_end
); // );
EventReport_Data( EventReport_Data(
(uint8_t *) &priv->dma_buffer[priv->dma_buffer_itemcount - (uint8_t *) &priv->dma_buffer[priv->dma_buffer_itemcount -
@ -95,10 +99,10 @@ static void UADC_JobSendTriggerCaptureHeader(Job *job)
pretrig_remain -= items_from_end; pretrig_remain -= items_from_end;
} }
dbg("Pretrig front part: start %d, len %d", // dbg("Pretrig front part: start %d, len %d",
(int) (index_trigd - pretrig_remain), // (int) (index_trigd - pretrig_remain),
(int) pretrig_remain // (int) pretrig_remain
); // );
assert_param(pretrig_remain <= index_trigd); assert_param(pretrig_remain <= index_trigd);
EventReport_Data((uint8_t *) &priv->dma_buffer[index_trigd - pretrig_remain], EventReport_Data((uint8_t *) &priv->dma_buffer[index_trigd - pretrig_remain],
@ -136,31 +140,17 @@ void UADC_ReportEndOfStream(Unit *unit)
scheduleJob(&j); scheduleJob(&j);
} }
void UADC_DMA_Handler(void *arg) static void handle_httc(Unit *unit, bool tc)
{ {
Unit *unit = arg;
assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); uint16_t start = priv->stream_startpos;
uint16_t end;
const uint32_t isrsnapshot = priv->DMAx->ISR; const bool ht = !tc;
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
const bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_chnum);
const bool ht = LL_DMA_IsActiveFlag_HT(isrsnapshot, priv->dma_chnum);
const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum);
// check what mode we're in
const bool m_trigd = 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_BLCAP; const bool m_fixcpt = priv->opmode == ADC_OPMODE_BLCAP;
if (m_trigd || m_stream || m_fixcpt) {
if (ht || tc) {
const uint16_t start = priv->stream_startpos;
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);
@ -172,8 +162,12 @@ void UADC_DMA_Handler(void *arg)
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); if (ht == tc) {
assert_param(start <= end); // 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) { if (start != end) {
uint32_t sgcount = (end - start) / priv->nb_channels; uint32_t sgcount = (end - start) / priv->nb_channels;
@ -192,7 +186,13 @@ void UADC_DMA_Handler(void *arg)
.data3 = (uint32_t) close, .data3 = (uint32_t) close,
.cb = UADC_JobSendBlockChunk .cb = UADC_JobSendBlockChunk
}; };
scheduleJob(&j); 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) { if (close) {
// dbg("End of capture"); // dbg("End of capture");
@ -212,6 +212,49 @@ void UADC_DMA_Handler(void *arg)
else { else {
priv->stream_startpos = end; priv->stream_startpos = end;
} }
}
void UADC_DMA_Handler(void *arg)
{
Unit *unit = arg;
assert_param(unit);
struct priv *priv = unit->data;
assert_param(priv);
if (priv->opmode == ADC_OPMODE_UNINIT) {
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
LL_DMA_ClearFlag_TE(priv->DMAx, priv->dma_chnum);
return;
}
const uint32_t isrsnapshot = priv->DMAx->ISR;
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
const bool tc = LL_DMA_IsActiveFlag_TC(isrsnapshot, priv->dma_chnum);
const bool ht = LL_DMA_IsActiveFlag_HT(isrsnapshot, priv->dma_chnum);
const bool te = LL_DMA_IsActiveFlag_TE(isrsnapshot, priv->dma_chnum);
// check what mode we're in
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 (m_trigd || m_stream || m_fixcpt) {
if (ht || tc) {
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 {
handle_httc(unit, tc);
}
} }
} else { } else {
// This shouldn't happen, the interrupt should be disabled in this opmode // This shouldn't happen, the interrupt should be disabled in this opmode
@ -235,18 +278,21 @@ void UADC_DMA_Handler(void *arg)
void UADC_ADC_EOS_Handler(void *arg) void UADC_ADC_EOS_Handler(void *arg)
{ {
uint64_t timestamp = PTIM_GetMicrotime();
Unit *unit = arg; Unit *unit = arg;
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
// Normally
uint64_t timestamp = 0;
if (priv->opmode == ADC_OPMODE_ARMED) timestamp = PTIM_GetMicrotime();
LL_ADC_ClearFlag_EOS(priv->ADCx); LL_ADC_ClearFlag_EOS(priv->ADCx);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
// Wait for the DMA to complete copying the last sample // Wait for the DMA to complete copying the last sample
uint16_t dmapos; uint16_t dmapos;
while ((dmapos = (uint16_t) DMA_POS(priv)) % priv->nb_channels != 0); hw_wait_while((dmapos = (uint16_t) DMA_POS(priv)) % priv->nb_channels != 0, 100); // XXX this could be changed to reading it from the DR instead
uint32_t sample_pos; uint32_t sample_pos;
if (dmapos == 0) { if (dmapos == 0) {
@ -257,41 +303,44 @@ void UADC_ADC_EOS_Handler(void *arg)
sample_pos -= priv->nb_channels; sample_pos -= priv->nb_channels;
int cnt = 0; // index of the sample within the group int cnt = 0; // index of the sample within the group
for (uint32_t i = 0; i < 18; i++) {
if (priv->extended_channels_mask & (1 << i)) { const bool can_average = priv->real_frequency_int < UADC_MAX_FREQ_FOR_AVERAGING;
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 = priv->dma_buffer[sample_pos+cnt]; uint16_t val = priv->dma_buffer[sample_pos+cnt];
cnt++; cnt++;
if (can_average) {
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) +
((float) val) * priv->avg_factor_as_float; ((float) val) * priv->avg_factor_as_float;
}
priv->last_samples[i] = val; priv->last_samples[i] = val;
}
}
if (i == priv->trigger_source) {
if (priv->opmode == ADC_OPMODE_ARMED) { if (priv->opmode == ADC_OPMODE_ARMED) {
// dbg("Trig line level %d", (int)val); uint16_t val = priv->last_samples[priv->trigger_source];
bool trigd = false; // dbg("Trig line level %d", (int)val);
uint8_t edge_type = 0; if ((priv->trig_prev_level < priv->trig_level) && val >= priv->trig_level && (bool) (priv->trig_edge & 0b01)) {
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); UADC_HandleTrigger(unit, 1, timestamp);
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 && (bool) (priv->trig_edge & 0b10)) {
// dbg("******** Falling edge"); // dbg("******** Falling edge");
// Falling edge // Falling edge
trigd = (bool) (priv->trig_edge & 0b10); UADC_HandleTrigger(unit, 2, timestamp);
edge_type = 2;
}
if (trigd) {
UADC_HandleTrigger(unit, edge_type, timestamp);
} }
priv->trig_prev_level = val;
} }
else if (priv->opmode == ADC_OPMODE_REARM_PENDING) {
// auto-rearm was waiting for the next sample
if (priv->opmode == ADC_OPMODE_REARM_PENDING) {
if (!priv->auto_rearm) { if (!priv->auto_rearm) {
// It looks like the flag was cleared by DISARM before we got a new sample. // It looks like the flag was cleared by DISARM before we got a new sample.
// Let's just switch to IDLE // Let's just switch to IDLE
@ -301,11 +350,6 @@ void UADC_ADC_EOS_Handler(void *arg)
UADC_SwitchMode(unit, ADC_OPMODE_ARMED); UADC_SwitchMode(unit, ADC_OPMODE_ARMED);
} }
} }
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)
@ -313,6 +357,7 @@ void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
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.");
@ -323,7 +368,7 @@ void UADC_HandleTrigger(Unit *unit, uint8_t edge_type, uint64_t timestamp)
priv->trig_holdoff_remain = priv->trig_holdoff; priv->trig_holdoff_remain = priv->trig_holdoff;
// Start the tick // Start the tick
unit->tick_interval = 1; unit->tick_interval = 1;
unit->_tick_cnt = 0; unit->_tick_cnt = 1;
} }
priv->stream_startpos = (uint16_t) DMA_POS(priv); priv->stream_startpos = (uint16_t) DMA_POS(priv);
@ -349,6 +394,7 @@ void UADC_StartBlockCapture(Unit *unit, uint32_t len, TF_ID frame_id)
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
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);
@ -363,11 +409,11 @@ void UADC_StartStream(Unit *unit, TF_ID frame_id)
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
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.");
UADC_SwitchMode(unit, ADC_OPMODE_STREAM); UADC_SwitchMode(unit, ADC_OPMODE_STREAM);
} }
@ -377,8 +423,8 @@ void UADC_StopStream(Unit *unit)
assert_param(unit); assert_param(unit);
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
if (priv->opmode == ADC_OPMODE_UNINIT) return;
// dbg("Stop stream.");
UADC_ReportEndOfStream(unit); UADC_ReportEndOfStream(unit);
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
} }
@ -390,6 +436,16 @@ void UADC_updateTick(Unit *unit)
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
// Recover from shutdown after a delay
if (priv->opmode == ADC_OPMODE_EMERGENCY_SHUTDOWN) {
dbg("Recovering from emergency shutdown");
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
LL_TIM_EnableCounter(priv->TIMx);
UADC_ReportEndOfStream(unit);
unit->tick_interval = 0;
return;
}
if (priv->trig_holdoff_remain > 0) { if (priv->trig_holdoff_remain > 0) {
priv->trig_holdoff_remain--; priv->trig_holdoff_remain--;
@ -406,10 +462,14 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
struct priv *priv = unit->data; struct priv *priv = unit->data;
assert_param(priv); assert_param(priv);
if (new_mode == priv->opmode) return; // nothing to do const enum uadc_opmode old_mode = priv->opmode;
if (new_mode == old_mode) return; // nothing to do
// if un-itied, can go only to IDLE // if un-itied, can go only to IDLE
assert_param((priv->opmode != ADC_OPMODE_UNINIT) || (new_mode == ADC_OPMODE_IDLE)); assert_param((old_mode != ADC_OPMODE_UNINIT) || (new_mode == ADC_OPMODE_IDLE));
priv->opmode = ADC_OPMODE_UNINIT;
if (new_mode == ADC_OPMODE_UNINIT) { if (new_mode == ADC_OPMODE_UNINIT) {
// dbg("ADC switch -> UNINIT"); // dbg("ADC switch -> UNINIT");
@ -436,11 +496,12 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
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");
// 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.
// In IDLE, we don't need the DMA interrupts // In IDLE, we don't need the DMA interrupts
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_ClearFlag_TC(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);
@ -448,7 +509,7 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
LL_ADC_ClearFlag_EOS(priv->ADCx); LL_ADC_ClearFlag_EOS(priv->ADCx);
LL_ADC_EnableIT_EOS(priv->ADCx); LL_ADC_EnableIT_EOS(priv->ADCx);
if (priv->opmode == ADC_OPMODE_UNINIT) { if (old_mode == ADC_OPMODE_UNINIT) {
// Nothing is started yet - this is the only way to leave UNINIT // Nothing is started yet - this is the only way to leave UNINIT
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);
@ -457,9 +518,28 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
LL_ADC_REG_StartConversion(priv->ADCx); LL_ADC_REG_StartConversion(priv->ADCx);
} }
} }
else if (new_mode == ADC_OPMODE_EMERGENCY_SHUTDOWN) {
// Emergency shutdown is used when the job queue overflows and the stream is torn
// This however doesn't help in the case when user sets such a high frequency
// that the whole app becomes unresponsive due to the completion ISR, need to verify the value manually.
LL_DMA_ClearFlag_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_ClearFlag_TC(priv->DMAx, priv->dma_chnum);
LL_DMA_DisableIT_HT(priv->DMAx, priv->dma_chnum);
LL_DMA_DisableIT_TC(priv->DMAx, priv->dma_chnum);
LL_TIM_DisableCounter(priv->TIMx);
UADC_SetSampleRate(unit, 10000); // fallback to a known safe value
LL_ADC_ClearFlag_EOS(priv->ADCx);
LL_ADC_DisableIT_EOS(priv->ADCx);
unit->tick_interval = 0;
unit->_tick_cnt = 250; // 1-off
}
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(old_mode == ADC_OPMODE_IDLE || old_mode == ADC_OPMODE_REARM_PENDING);
// avoid firing immediately by the value jumping across the scale // avoid firing immediately by the value jumping across the scale
priv->trig_prev_level = priv->last_samples[priv->trigger_source]; priv->trig_prev_level = priv->last_samples[priv->trigger_source];
@ -469,7 +549,7 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
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(old_mode == ADC_OPMODE_ARMED || old_mode == 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
LL_ADC_DisableIT_EOS(priv->ADCx); LL_ADC_DisableIT_EOS(priv->ADCx);
@ -484,6 +564,5 @@ void UADC_SwitchMode(Unit *unit, enum uadc_opmode new_mode)
LL_DMA_EnableIT_TC(priv->DMAx, priv->dma_chnum); LL_DMA_EnableIT_TC(priv->DMAx, priv->dma_chnum);
} }
// the actual switch
priv->opmode = new_mode; priv->opmode = new_mode;
} }

@ -28,6 +28,32 @@ error_t UADC_preInit(Unit *unit)
return E_SUCCESS; return E_SUCCESS;
} }
/** Configure frequency */
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz)
{
struct priv *priv = unit->data;
uint16_t presc;
uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, hertz, true, &presc, &count,
&priv->real_frequency)) {
dbg("Failed to resolve timer params.");
return E_BAD_VALUE;
}
dbg("Frequency error %d ppm, presc %d, count %d",
(int) lrintf(1000000.0f *
((priv->real_frequency - hertz) / (float) hertz)),
(int) presc, (int) count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
LL_TIM_SetAutoReload(priv->TIMx, count - 1);
priv->real_frequency_int = hertz;
return E_SUCCESS;
}
/** Finalize unit set-up */ /** Finalize unit set-up */
error_t UADC_init(Unit *unit) error_t UADC_init(Unit *unit)
{ {
@ -103,19 +129,20 @@ error_t UADC_init(Unit *unit)
// ------------------- CONFIGURE THE TIMER -------------------------- // ------------------- CONFIGURE THE TIMER --------------------------
dbg("Setting up TIMER"); dbg("Setting up TIMER");
{ {
// Find suitable timer values TRY(UADC_SetSampleRate(unit, priv->frequency));
uint16_t presc; // // Find suitable timer values
uint32_t count; // uint16_t presc;
float real_freq; // uint32_t count;
if (!solve_timer(PLAT_APB1_HZ, priv->frequency, true, &presc, &count, &real_freq)) { // float real_freq;
dbg("Failed to resolve timer params."); // if (!solve_timer(PLAT_APB1_HZ, priv->frequency, true, &presc, &count, &real_freq)) {
return E_BAD_VALUE; // dbg("Failed to resolve timer params.");
} // return E_BAD_VALUE;
dbg("Frequency error %d ppm, presc %d, count %d", // }
(int) lrintf(1000000.0f * ((real_freq - priv->frequency) / (float)priv->frequency)), (int) presc, (int) count); // dbg("Frequency error %d ppm, presc %d, count %d",
// (int) lrintf(1000000.0f * ((real_freq - priv->frequency) / (float)priv->frequency)), (int) presc, (int) count);
LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1)); //
LL_TIM_SetAutoReload(priv->TIMx, count - 1); // LL_TIM_SetPrescaler(priv->TIMx, (uint32_t) (presc - 1));
// LL_TIM_SetAutoReload(priv->TIMx, count - 1);
LL_TIM_EnableARRPreload(priv->TIMx); LL_TIM_EnableARRPreload(priv->TIMx);
LL_TIM_EnableUpdateEvent(priv->TIMx); LL_TIM_EnableUpdateEvent(priv->TIMx);
LL_TIM_SetTriggerOutput(priv->TIMx, LL_TIM_TRGO_UPDATE); LL_TIM_SetTriggerOutput(priv->TIMx, LL_TIM_TRGO_UPDATE);
@ -169,7 +196,7 @@ error_t UADC_init(Unit *unit)
priv->dma_buffer_itemcount*sizeof(uint16_t), priv->dma_buffer_itemcount*sizeof(uint16_t),
priv->nb_channels); 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; if (NULL == priv->dma_buffer) return E_OUT_OF_MEM;
assert_param(((uint32_t) priv->dma_buffer & 3) == 0); // must be aligned assert_param(((uint32_t) priv->dma_buffer & 3) == 0); // must be aligned
@ -208,8 +235,10 @@ error_t UADC_init(Unit *unit)
irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit); irqd_attach(priv->DMA_CHx, UADC_DMA_Handler, unit);
irqd_attach(priv->ADCx, UADC_ADC_EOS_Handler, unit); irqd_attach(priv->ADCx, UADC_ADC_EOS_Handler, unit);
dbg("irqs attached");
UADC_SwitchMode(unit, ADC_OPMODE_IDLE); UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
dbg("ADC done");
return E_SUCCESS; return E_SUCCESS;
} }

@ -11,6 +11,8 @@
#include "unit_base.h" #include "unit_base.h"
#define UADC_MAX_FREQ_FOR_AVERAGING 20000
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. Allows immediate value readout and averaging. ADC_OPMODE_IDLE, //!< Idle. Allows immediate value readout and averaging.
@ -19,6 +21,7 @@ enum uadc_opmode {
ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data. ADC_OPMODE_TRIGD, //!< Triggered, sending pre-trigger and streaming captured data.
ADC_OPMODE_BLCAP, //!< Capture of fixed length without a trigger ADC_OPMODE_BLCAP, //!< Capture of fixed length without a trigger
ADC_OPMODE_STREAM, //!< Unlimited capture ADC_OPMODE_STREAM, //!< Unlimited capture
ADC_OPMODE_EMERGENCY_SHUTDOWN, //!< Used when the buffers overrun to safely transition to IDLE after a delay
}; };
enum uadc_event { enum uadc_event {
@ -40,6 +43,8 @@ struct priv {
uint16_t averaging_factor; //!< Exponential averaging factor 0-1000 uint16_t averaging_factor; //!< Exponential averaging factor 0-1000
// internal state // internal state
float real_frequency;
uint32_t real_frequency_int;
uint32_t extended_channels_mask; //!< channels bitfield including tsense and vref uint32_t extended_channels_mask; //!< channels bitfield including tsense and vref
float avg_factor_as_float; float avg_factor_as_float;
ADC_TypeDef *ADCx; //!< The ADC peripheral used ADC_TypeDef *ADCx; //!< The ADC peripheral used
@ -126,4 +131,7 @@ void UADC_StartStream(Unit *unit, TF_ID frame_id);
/** End stream */ /** End stream */
void UADC_StopStream(Unit *unit); void UADC_StopStream(Unit *unit);
/** Configure frequency */
error_t UADC_SetSampleRate(Unit *unit, uint32_t hertz);
#endif //GEX_F072_ADC_INTERNAL_H #endif //GEX_F072_ADC_INTERNAL_H

@ -98,7 +98,7 @@ void UADC_writeIni(Unit *unit, IniWriter *iw)
iw_entry(iw, "enable_tsense", str_yn(priv->enable_tsense)); iw_entry(iw, "enable_tsense", str_yn(priv->enable_tsense));
iw_comment(iw, "Enable Vref channel (#17)"); iw_comment(iw, "Enable Vref channel (#17)");
iw_entry(iw, "enable_vref", str_yn(priv->enable_tsense)); iw_entry(iw, "enable_vref", str_yn(priv->enable_vref));
iw_cmt_newline(iw); iw_cmt_newline(iw);
iw_comment(iw, "Sampling time (0-7)"); iw_comment(iw, "Sampling time (0-7)");

@ -15,6 +15,7 @@ enum TplCmd_ {
CMD_READ_SMOOTHED = 1, CMD_READ_SMOOTHED = 1,
CMD_GET_ENABLED_CHANNELS = 10, CMD_GET_ENABLED_CHANNELS = 10,
CMD_GET_SAMPLE_RATE = 11,
CMD_SETUP_TRIGGER = 20, CMD_SETUP_TRIGGER = 20,
CMD_ARM = 21, CMD_ARM = 21,
@ -25,6 +26,7 @@ enum TplCmd_ {
CMD_STREAM_START = 26, CMD_STREAM_START = 26,
CMD_STREAM_STOP = 27, CMD_STREAM_STOP = 27,
CMD_SET_SMOOTHING_FACTOR = 28, CMD_SET_SMOOTHING_FACTOR = 28,
CMD_SET_SAMPLE_RATE = 29,
}; };
/** Handle a request message */ /** Handle a request message */
@ -33,6 +35,8 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
struct priv *priv = unit->data; struct priv *priv = unit->data;
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
// TODO toggling individual channels - would require DMA re-init and various changes in the usage of the struct
switch (command) { switch (command) {
/** /**
* Get enabled channels. * Get enabled channels.
@ -47,6 +51,24 @@ 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;
case CMD_SET_SAMPLE_RATE:
{
uint32_t freq = pp_u32(pp);
if (freq == 0) return E_BAD_VALUE;
TRY(UADC_SetSampleRate(unit, freq));
}
// Pass through - send back the obtained sample rate
/**
* Read the real used frequency, expressed as float.
* May differ from the configured or requested value due to prescaller limitations.
*/
case CMD_GET_SAMPLE_RATE:
pb_u32(&pb, priv->real_frequency_int);
pb_float(&pb, priv->real_frequency);
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
return E_SUCCESS;
/** /**
* Set smoothing factor 0-1000. * Set smoothing factor 0-1000.
* pld: u16:factor * pld: u16:factor
@ -85,6 +107,11 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
return E_BUSY; return E_BUSY;
} }
if (priv->real_frequency_int > UADC_MAX_FREQ_FOR_AVERAGING) {
com_respond_str(MSG_ERROR, frame_id, "Too fast for smoothing");
return E_FAILURE;
}
for (uint8_t i = 0; i < 18; i++) { for (uint8_t i = 0; i < 18; i++) {
if (priv->extended_channels_mask & (1 << i)) { if (priv->extended_channels_mask & (1 << i)) {
pb_float(&pb, priv->averaging_bins[i]); pb_float(&pb, priv->averaging_bins[i]);
@ -117,7 +144,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
const uint8_t source = pp_u8(pp); const uint8_t source = pp_u8(pp);
const uint16_t level = pp_u16(pp); const uint16_t level = pp_u16(pp);
const uint8_t edge = pp_u8(pp); const uint8_t edge = pp_u8(pp);
const uint16_t pretrig = pp_u16(pp); // TODO test pre-trigger ... const uint16_t pretrig = pp_u16(pp);
const uint32_t count = pp_u32(pp); const uint32_t count = pp_u32(pp);
const uint16_t holdoff = pp_u16(pp); const uint16_t holdoff = pp_u16(pp);
const bool auto_rearm = pp_bool(pp); const bool auto_rearm = pp_bool(pp);
@ -219,18 +246,7 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
*/ */
case CMD_ABORT:; case CMD_ABORT:;
dbg("> Abort capture"); dbg("> Abort capture");
{ TRY(UU_ADC_AbortCapture(unit));
enum uadc_opmode old_opmode = priv->opmode;
priv->auto_rearm = false;
UADC_SwitchMode(unit, ADC_OPMODE_IDLE);
if (old_opmode == ADC_OPMODE_BLCAP ||
old_opmode == ADC_OPMODE_STREAM ||
old_opmode == ADC_OPMODE_TRIGD) {
UADC_ReportEndOfStream(unit);
}
}
return E_SUCCESS; return E_SUCCESS;
/** /**
@ -260,7 +276,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* u32 - sample count (for each channel) * u32 - sample count (for each channel)
*/ */
case CMD_BLOCK_CAPTURE: case CMD_BLOCK_CAPTURE:
// 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_REARM_PENDING &&
@ -276,7 +291,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* The stream can be terminated by the stop command. * The stream can be terminated by the stop command.
*/ */
case CMD_STREAM_START: case CMD_STREAM_START:
// 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_REARM_PENDING &&
@ -289,7 +303,6 @@ static error_t UADC_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
* Stop a stream. * Stop a stream.
*/ */
case CMD_STREAM_STOP: case CMD_STREAM_STOP:
// 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");

@ -11,6 +11,6 @@
extern const UnitDriver UNIT_ADC; extern const UnitDriver UNIT_ADC;
// UU_ prototypes error_t UU_ADC_AbortCapture(Unit *unit);
#endif //U_TPL_H #endif //U_TPL_H

@ -65,7 +65,7 @@ void UUSART_DMA_HandleRxFromIRQ(Unit *unit, uint16_t endpos)
.data2 = count, .data2 = count,
.cb = UUSART_SendReceivedDataToMaster .cb = UUSART_SendReceivedDataToMaster
}; };
scheduleJob(&j); scheduleJob(&j); // TODO disable unit on failure
// Move the read cursor, wrap around if needed // Move the read cursor, wrap around if needed
if (endpos == UUSART_RXBUF_LEN) endpos = 0; if (endpos == UUSART_RXBUF_LEN) endpos = 0;

Loading…
Cancel
Save