Added some protections against creash due to high frequency, but its not ideal ...
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#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 32 // 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)
|
||||||
|
|||||||
+11
-6
@@ -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;
|
||||||
|
|||||||
+1
-1
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
+76
-22
@@ -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],
|
||||||
@@ -144,6 +148,13 @@ void UADC_DMA_Handler(void *arg)
|
|||||||
struct priv *priv = unit->data;
|
struct priv *priv = unit->data;
|
||||||
assert_param(priv);
|
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;
|
const uint32_t isrsnapshot = priv->DMAx->ISR;
|
||||||
|
|
||||||
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
|
if (LL_DMA_IsActiveFlag_G(isrsnapshot, priv->dma_chnum)) {
|
||||||
@@ -192,7 +203,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");
|
||||||
@@ -243,10 +260,11 @@ void UADC_ADC_EOS_Handler(void *arg)
|
|||||||
assert_param(priv);
|
assert_param(priv);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
uint32_t sample_pos;
|
uint32_t sample_pos;
|
||||||
if (dmapos == 0) {
|
if (dmapos == 0) {
|
||||||
@@ -313,6 +331,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 +342,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 +368,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 +383,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 +397,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 +410,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 +436,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 +470,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 +483,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 +492,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 +523,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 +538,6 @@ 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
|
dbg("Now setting the new opmode");
|
||||||
priv->opmode = new_mode;
|
priv->opmode = new_mode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,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 {
|
||||||
|
|||||||
+1
-12
@@ -240,18 +240,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user