fcap cleaning, added new features and reorganized the unit
This commit is contained in:
+148
-48
@@ -9,8 +9,8 @@
|
||||
#include "_fcap_internal.h"
|
||||
|
||||
static void UFCAP_StopMeasurement(Unit *unit);
|
||||
static void UFCAP_ConfigureForPWMCapture(Unit *unit);
|
||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit);
|
||||
static void UFCAP_ConfigureForIndirectCapture(Unit *unit);
|
||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec);
|
||||
static void UFCAP_ConfigureForFreeCapture(Unit *unit);
|
||||
|
||||
uint32_t UFCAP_GetFreeCounterValue(Unit *unit)
|
||||
@@ -20,7 +20,22 @@ uint32_t UFCAP_GetFreeCounterValue(Unit *unit)
|
||||
return TIMx->CNT;
|
||||
}
|
||||
|
||||
static void UFCAP_PWMBurstReportJob(Job *job)
|
||||
uint32_t UFCAP_FreeCounterClear(Unit *unit)
|
||||
{
|
||||
struct priv * const priv = unit->data;
|
||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
||||
|
||||
// this isn't perfect, we can miss one clock
|
||||
// but it's probably the best we can do here ...
|
||||
vPortEnterCritical();
|
||||
uint32_t val = TIMx->CNT;
|
||||
TIMx->CNT = 0;
|
||||
vPortExitCritical();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void UFCAP_IndirectBurstReportJob(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
struct priv * const priv = unit->data;
|
||||
@@ -29,9 +44,9 @@ static void UFCAP_PWMBurstReportJob(Job *job)
|
||||
PayloadBuilder pb = pb_start(buf, 20, NULL);
|
||||
|
||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
||||
pb_u16(&pb, priv->pwm_burst.n_count);
|
||||
pb_u64(&pb, priv->pwm_burst.period_acu);
|
||||
pb_u64(&pb, priv->pwm_burst.ontime_acu);
|
||||
pb_u16(&pb, priv->ind_burst.n_count);
|
||||
pb_u64(&pb, priv->ind_burst.period_acu);
|
||||
pb_u64(&pb, priv->ind_burst.ontime_acu);
|
||||
|
||||
assert_param(pb.ok);
|
||||
|
||||
@@ -41,15 +56,38 @@ static void UFCAP_PWMBurstReportJob(Job *job)
|
||||
priv->opmode = OPMODE_IDLE;
|
||||
}
|
||||
|
||||
static void UFCAP_CountBurstReportJob(Job *job)
|
||||
static void UFCAP_SinglePulseReportJob(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
struct priv * const priv = unit->data;
|
||||
|
||||
uint8_t buf[6];
|
||||
PayloadBuilder pb = pb_start(buf, 20, NULL);
|
||||
PayloadBuilder pb = pb_start(buf, 6, NULL);
|
||||
|
||||
pb_u16(&pb, priv->cnt_burst.msec);
|
||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
||||
pb_u32(&pb, job->data1);
|
||||
assert_param(pb.ok);
|
||||
|
||||
com_respond_pb(priv->request_id, MSG_SUCCESS, &pb);
|
||||
|
||||
// timer is already stopped, now in OPMODE_BUSY
|
||||
priv->opmode = OPMODE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count is passed in data1
|
||||
* @param job
|
||||
*/
|
||||
static void UFCAP_DirectBurstReportJob(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
struct priv * const priv = unit->data;
|
||||
|
||||
uint8_t buf[8];
|
||||
PayloadBuilder pb = pb_start(buf, 8, NULL);
|
||||
|
||||
pb_u8(&pb, priv->direct_presc);
|
||||
pb_u16(&pb, priv->dir_burst.msec);
|
||||
pb_u32(&pb, job->data1);
|
||||
|
||||
assert_param(pb.ok);
|
||||
@@ -69,40 +107,56 @@ void UFCAP_TIMxHandler(void *arg)
|
||||
|
||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
||||
|
||||
if (priv->opmode == OPMODE_PWM_CONT) {
|
||||
if (priv->opmode == OPMODE_INDIRECT_CONT) {
|
||||
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
|
||||
if (priv->n_skip > 0) {
|
||||
priv->n_skip--;
|
||||
} else {
|
||||
priv->pwm_cont.last_period = LL_TIM_IC_GetCaptureCH1(TIMx);
|
||||
priv->pwm_cont.last_ontime = priv->pwm_cont.ontime;
|
||||
priv->ind_cont.last_period = LL_TIM_IC_GetCaptureCH1(TIMx);
|
||||
priv->ind_cont.last_ontime = priv->ind_cont.ontime;
|
||||
}
|
||||
LL_TIM_ClearFlag_CC1(TIMx);
|
||||
LL_TIM_ClearFlag_CC1OVR(TIMx);
|
||||
}
|
||||
|
||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
||||
priv->pwm_cont.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
||||
priv->ind_cont.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
||||
LL_TIM_ClearFlag_CC2(TIMx);
|
||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
||||
}
|
||||
}
|
||||
else if (priv->opmode == OPMODE_PWM_BURST) {
|
||||
else if (priv->opmode == OPMODE_SINGLE_PULSE) {
|
||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
||||
// single pulse - does not wait for the second edge
|
||||
uint32_t len = LL_TIM_IC_GetCaptureCH2(TIMx);
|
||||
|
||||
priv->opmode = OPMODE_BUSY;
|
||||
UFCAP_StopMeasurement(unit);
|
||||
|
||||
Job j = {
|
||||
.cb = UFCAP_SinglePulseReportJob,
|
||||
.unit = unit,
|
||||
.data1 = len,
|
||||
};
|
||||
scheduleJob(&j);
|
||||
}
|
||||
}
|
||||
else if (priv->opmode == OPMODE_INDIRECT_BURST) {
|
||||
if (LL_TIM_IsActiveFlag_CC1(TIMx)) {
|
||||
const uint32_t period = LL_TIM_IC_GetCaptureCH1(TIMx);
|
||||
const uint32_t ontime = priv->pwm_burst.ontime;
|
||||
const uint32_t ontime = priv->ind_burst.ontime;
|
||||
|
||||
if (priv->n_skip > 0) {
|
||||
priv->n_skip--;
|
||||
} else {
|
||||
priv->pwm_burst.ontime_acu += ontime;
|
||||
priv->pwm_burst.period_acu += period;
|
||||
if (++priv->pwm_burst.n_count == priv->pwm_burst.n_target) {
|
||||
priv->ind_burst.ontime_acu += ontime;
|
||||
priv->ind_burst.period_acu += period;
|
||||
if (++priv->ind_burst.n_count == priv->ind_burst.n_target) {
|
||||
priv->opmode = OPMODE_BUSY;
|
||||
UFCAP_StopMeasurement(unit);
|
||||
|
||||
Job j = {
|
||||
.cb = UFCAP_PWMBurstReportJob,
|
||||
.cb = UFCAP_IndirectBurstReportJob,
|
||||
.unit = unit,
|
||||
};
|
||||
scheduleJob(&j);
|
||||
@@ -114,7 +168,7 @@ void UFCAP_TIMxHandler(void *arg)
|
||||
}
|
||||
|
||||
if (LL_TIM_IsActiveFlag_CC2(TIMx)) {
|
||||
priv->pwm_burst.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
||||
priv->ind_burst.ontime = LL_TIM_IC_GetCaptureCH2(TIMx);
|
||||
LL_TIM_ClearFlag_CC2(TIMx);
|
||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
||||
}
|
||||
@@ -139,18 +193,23 @@ void UFCAP_TIMyHandler(void *arg)
|
||||
TIM_TypeDef * const TIMy = priv->TIMy;
|
||||
uint32_t cnt = TIMx->CNT; // TIMx should be stopped now
|
||||
|
||||
dbg("> TIMy Handler, TIMx cntr is %d", cnt);
|
||||
priv->cnt_cont.last_count = cnt;
|
||||
// dbg("> TIMy Handler, TIMx cntr is %d", cnt);
|
||||
priv->dir_cont.last_count = cnt;
|
||||
|
||||
if (priv->opmode == OPMODE_COUNTER_CONT) {
|
||||
if (priv->opmode == OPMODE_DIRECT_CONT) {
|
||||
LL_TIM_DisableCounter(TIMx);
|
||||
LL_TIM_DisableCounter(TIMy);
|
||||
LL_TIM_SetCounter(TIMx, 0);
|
||||
LL_TIM_SetCounter(TIMy, 0);
|
||||
LL_TIM_EnableCounter(TIMy); // next loop
|
||||
} else if (priv->opmode == OPMODE_COUNTER_BURST) {
|
||||
LL_TIM_EnableCounter(TIMx);
|
||||
}
|
||||
else if (priv->opmode == OPMODE_DIRECT_BURST) {
|
||||
priv->opmode = OPMODE_BUSY;
|
||||
UFCAP_StopMeasurement(unit);
|
||||
|
||||
Job j = {
|
||||
.cb = UFCAP_CountBurstReportJob,
|
||||
.cb = UFCAP_DirectBurstReportJob,
|
||||
.unit = unit,
|
||||
.data1 = cnt,
|
||||
};
|
||||
@@ -215,35 +274,42 @@ void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode)
|
||||
UFCAP_StopMeasurement(unit);
|
||||
break;
|
||||
|
||||
case OPMODE_PWM_CONT:
|
||||
priv->pwm_cont.last_ontime = 0;
|
||||
priv->pwm_cont.last_period = 0;
|
||||
priv->pwm_cont.ontime = 0;
|
||||
case OPMODE_INDIRECT_CONT:
|
||||
priv->ind_cont.last_ontime = 0;
|
||||
priv->ind_cont.last_period = 0;
|
||||
priv->ind_cont.ontime = 0;
|
||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
||||
UFCAP_ConfigureForPWMCapture(unit); // is also stopped and restarted
|
||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
||||
break;
|
||||
|
||||
case OPMODE_PWM_BURST:
|
||||
priv->pwm_burst.ontime = 0;
|
||||
priv->pwm_burst.n_count = 0;
|
||||
priv->pwm_burst.period_acu = 0;
|
||||
priv->pwm_burst.ontime_acu = 0;
|
||||
case OPMODE_INDIRECT_BURST:
|
||||
priv->ind_burst.ontime = 0;
|
||||
priv->ind_burst.n_count = 0;
|
||||
priv->ind_burst.period_acu = 0;
|
||||
priv->ind_burst.ontime_acu = 0;
|
||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
||||
UFCAP_ConfigureForPWMCapture(unit); // is also stopped and restarted
|
||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
||||
break;
|
||||
|
||||
case OPMODE_COUNTER_CONT:
|
||||
priv->cnt_cont.last_count = 0;
|
||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
||||
UFCAP_ConfigureForDirectCapture(unit);
|
||||
case OPMODE_SINGLE_PULSE:
|
||||
priv->n_skip = 0;
|
||||
UFCAP_ConfigureForIndirectCapture(unit); // is also stopped and restarted
|
||||
break;
|
||||
|
||||
case OPMODE_COUNTER_BURST:
|
||||
case OPMODE_DIRECT_CONT:
|
||||
// msec is set by caller
|
||||
priv->dir_cont.last_count = 0;
|
||||
priv->n_skip = 1; // discard the first cycle (will be incomplete)
|
||||
UFCAP_ConfigureForDirectCapture(unit, priv->direct_msec);
|
||||
break;
|
||||
|
||||
case OPMODE_DIRECT_BURST:
|
||||
// msec is set by caller
|
||||
priv->n_skip = 0; // no skip here (if there was any)
|
||||
UFCAP_ConfigureForDirectCapture(unit);
|
||||
UFCAP_ConfigureForDirectCapture(unit, (uint16_t) priv->dir_burst.msec);
|
||||
break;
|
||||
|
||||
case OPMODE_COUNTER_FREERUNNING:
|
||||
case OPMODE_FREE_COUNTER:
|
||||
UFCAP_ConfigureForFreeCapture(unit);
|
||||
break;
|
||||
|
||||
@@ -256,7 +322,7 @@ void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode)
|
||||
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
|
||||
* @param unit
|
||||
*/
|
||||
static void UFCAP_ConfigureForPWMCapture(Unit *unit)
|
||||
static void UFCAP_ConfigureForIndirectCapture(Unit *unit)
|
||||
{
|
||||
struct priv * const priv = unit->data;
|
||||
TIM_TypeDef * const TIMx = priv->TIMx;
|
||||
@@ -282,14 +348,26 @@ static void UFCAP_ConfigureForPWMCapture(Unit *unit)
|
||||
// It's possible to select the other channel, which we use to connect both TIx to the shame CHx.
|
||||
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_a, priv->a_direct ? LL_TIM_ACTIVEINPUT_DIRECTTI : LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
||||
LL_TIM_IC_SetActiveInput(TIMx, ll_ch_b, priv->a_direct ? LL_TIM_ACTIVEINPUT_INDIRECTTI : LL_TIM_ACTIVEINPUT_DIRECTTI);
|
||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_a, priv->active_level ? LL_TIM_IC_POLARITY_RISING : LL_TIM_IC_POLARITY_FALLING);
|
||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_b, priv->active_level ? LL_TIM_IC_POLARITY_FALLING : LL_TIM_IC_POLARITY_RISING);
|
||||
|
||||
if (priv->dfilter > 15) priv->dfilter = 15;
|
||||
uint32_t filter = LL_TIM_IC_FILTERS[priv->dfilter];
|
||||
LL_TIM_IC_SetFilter(TIMx, ll_ch_a, filter);
|
||||
LL_TIM_IC_SetFilter(TIMx, ll_ch_b, filter);
|
||||
|
||||
LL_TIM_CC_EnableChannel(TIMx, ll_ch_a | ll_ch_b);
|
||||
|
||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_a, LL_TIM_IC_POLARITY_RISING);
|
||||
LL_TIM_IC_SetPolarity(TIMx, ll_ch_b, LL_TIM_IC_POLARITY_FALLING);
|
||||
LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_RESET);
|
||||
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_TI1FP1); // Use Filtered Input 1 (TI1)
|
||||
|
||||
LL_TIM_EnableMasterSlaveMode(TIMx);
|
||||
|
||||
LL_TIM_ClearFlag_CC1(TIMx);
|
||||
LL_TIM_ClearFlag_CC1OVR(TIMx);
|
||||
LL_TIM_ClearFlag_CC2(TIMx);
|
||||
LL_TIM_ClearFlag_CC2OVR(TIMx);
|
||||
|
||||
LL_TIM_EnableIT_CC1(TIMx);
|
||||
LL_TIM_EnableIT_CC2(TIMx);
|
||||
LL_TIM_EnableCounter(TIMx);
|
||||
@@ -300,18 +378,19 @@ static void UFCAP_ConfigureForPWMCapture(Unit *unit)
|
||||
* Configure peripherals for an indirect capture (PWM measurement) - continuous or burst
|
||||
* @param unit
|
||||
*/
|
||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit)
|
||||
static void UFCAP_ConfigureForDirectCapture(Unit *unit, uint16_t msec)
|
||||
{
|
||||
struct priv * const priv = unit->data;
|
||||
|
||||
// dbg("Configuring Direct capture...");
|
||||
|
||||
UFCAP_ClearTimerConfig(unit);
|
||||
|
||||
{
|
||||
TIM_TypeDef *const TIMy = priv->TIMy;
|
||||
assert_param(PLAT_AHB_MHZ<=65);
|
||||
uint16_t presc = PLAT_AHB_MHZ*1000;
|
||||
uint32_t count = priv->cnt_cont.msec+1; // it's one tick longer because we generate OCREF on the exact msec count - it must be at least 1 tick long
|
||||
uint32_t count = msec+1; // it's one tick longer because we generate OCREF on the exact msec count - it must be at least 1 tick long
|
||||
|
||||
LL_TIM_SetPrescaler(TIMy, (uint32_t) (presc - 1));
|
||||
LL_TIM_SetAutoReload(TIMy, count - 1);
|
||||
@@ -327,6 +406,7 @@ static void UFCAP_ConfigureForDirectCapture(Unit *unit)
|
||||
LL_TIM_OC_SetCompareCH1(TIMy, count-1);
|
||||
LL_TIM_CC_EnableChannel(TIMy, LL_TIM_CHANNEL_CH1); // enable the output channel that produces a trigger
|
||||
|
||||
LL_TIM_ClearFlag_UPDATE(TIMy);
|
||||
LL_TIM_EnableIT_UPDATE(TIMy);
|
||||
}
|
||||
|
||||
@@ -337,6 +417,24 @@ static void UFCAP_ConfigureForDirectCapture(Unit *unit)
|
||||
LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_ITR3); // ITR3 is TIM14 which we use as TIMy
|
||||
LL_TIM_EnableMasterSlaveMode(TIMx);
|
||||
|
||||
uint32_t presc = LL_TIM_ETR_PRESCALER_DIV1;
|
||||
switch (priv->direct_presc) {
|
||||
case 1: presc = LL_TIM_ETR_PRESCALER_DIV1; break;
|
||||
case 2: presc = LL_TIM_ETR_PRESCALER_DIV2; break;
|
||||
case 4: presc = LL_TIM_ETR_PRESCALER_DIV4; break;
|
||||
case 8: presc = LL_TIM_ETR_PRESCALER_DIV8; break;
|
||||
default:
|
||||
priv->direct_presc = 1; // will be sent with the response
|
||||
}
|
||||
|
||||
if (priv->dfilter > 15) priv->dfilter = 15;
|
||||
uint32_t filter = LL_TIM_ETR_FILTERS[priv->dfilter];
|
||||
|
||||
LL_TIM_ConfigETR(TIMx,
|
||||
priv->active_level ? LL_TIM_ETR_POLARITY_NONINVERTED : LL_TIM_ETR_POLARITY_INVERTED,
|
||||
presc,
|
||||
filter);
|
||||
|
||||
LL_TIM_EnableExternalClock(TIMx); // TODO must check and deny this mode if the pin is not on CH1 = external trigger input
|
||||
|
||||
LL_TIM_SetCounter(TIMx, 0);
|
||||
@@ -355,6 +453,8 @@ static void UFCAP_ConfigureForFreeCapture(Unit *unit)
|
||||
{
|
||||
struct priv * const priv = unit->data;
|
||||
|
||||
UFCAP_ClearTimerConfig(unit);
|
||||
|
||||
TIM_TypeDef *const TIMx = priv->TIMx;
|
||||
LL_TIM_EnableExternalClock(TIMx);
|
||||
LL_TIM_SetCounter(TIMx, 0);
|
||||
|
||||
+22
-12
@@ -14,10 +14,14 @@ error_t UFCAP_preInit(Unit *unit)
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv));
|
||||
if (priv == NULL) return E_OUT_OF_MEM;
|
||||
|
||||
priv->signal_pname = 'A';
|
||||
priv->signal_pnum = 0;
|
||||
priv->conf.signal_pname = 'A';
|
||||
priv->conf.signal_pnum = 0;
|
||||
|
||||
priv->opmode = OPMODE_PWM_CONT;
|
||||
priv->conf.active_level = 1;
|
||||
priv->conf.direct_presc = 1;
|
||||
priv->conf.dfilter = 0;
|
||||
priv->conf.direct_msec = 1000;
|
||||
priv->conf.startmode = OPMODE_IDLE;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
@@ -39,9 +43,9 @@ error_t UFCAP_init(Unit *unit)
|
||||
uint32_t ll_ch_a = 0;
|
||||
uint32_t ll_ch_b = 0;
|
||||
|
||||
switch (priv->signal_pname) {
|
||||
switch (priv->conf.signal_pname) {
|
||||
case 'A':
|
||||
switch (priv->signal_pnum) {
|
||||
switch (priv->conf.signal_pnum) {
|
||||
case 5:
|
||||
case 15:
|
||||
case 0: ll_ch_a = LL_TIM_CHANNEL_CH1; break;
|
||||
@@ -52,7 +56,7 @@ error_t UFCAP_init(Unit *unit)
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
switch (priv->signal_pnum) {
|
||||
switch (priv->conf.signal_pnum) {
|
||||
case 3: ll_ch_a = LL_TIM_CHANNEL_CH2; break;
|
||||
default:
|
||||
dbg("Bad signal pin!");
|
||||
@@ -80,7 +84,7 @@ error_t UFCAP_init(Unit *unit)
|
||||
|
||||
// ---- CLAIM ----
|
||||
|
||||
TRY(rsc_claim_pin(unit, priv->signal_pname, priv->signal_pnum));
|
||||
TRY(rsc_claim_pin(unit, priv->conf.signal_pname, priv->conf.signal_pnum));
|
||||
TRY(rsc_claim(unit, timRsc));
|
||||
TRY(rsc_claim(unit, tim2Rsc));
|
||||
|
||||
@@ -93,10 +97,17 @@ error_t UFCAP_init(Unit *unit)
|
||||
priv->ll_ch_b = ll_ch_b;
|
||||
priv->a_direct = a_direct;
|
||||
|
||||
TRY(hw_configure_gpio_af(priv->signal_pname, priv->signal_pnum, ll_timpin_af));
|
||||
// Load defaults
|
||||
priv->active_level = priv->conf.active_level;
|
||||
priv->direct_presc = priv->conf.direct_presc;
|
||||
priv->dfilter = priv->conf.dfilter;
|
||||
priv->direct_msec = priv->conf.direct_msec;
|
||||
priv->opmode = priv->conf.startmode;
|
||||
|
||||
GPIO_TypeDef *gpio = hw_port2periph(priv->signal_pname, &suc);
|
||||
uint32_t ll_pin = hw_pin2ll(priv->signal_pnum, &suc);
|
||||
TRY(hw_configure_gpio_af(priv->conf.signal_pname, priv->conf.signal_pnum, ll_timpin_af));
|
||||
|
||||
GPIO_TypeDef *gpio = hw_port2periph(priv->conf.signal_pname, &suc);
|
||||
uint32_t ll_pin = hw_pin2ll(priv->conf.signal_pnum, &suc);
|
||||
LL_GPIO_SetPinPull(gpio, ll_pin, LL_GPIO_PULL_DOWN); // XXX change to pull-up if the polarity is inverted
|
||||
|
||||
hw_periph_clock_enable(TIMx);
|
||||
@@ -104,8 +115,7 @@ error_t UFCAP_init(Unit *unit)
|
||||
irqd_attach(TIMx, UFCAP_TIMxHandler, unit);
|
||||
irqd_attach(TIMy, UFCAP_TIMyHandler, unit);
|
||||
|
||||
// UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
||||
UFCAP_SwitchMode(unit, OPMODE_COUNTER_CONT);
|
||||
UFCAP_SwitchMode(unit, priv->opmode); // switch to the default opmode
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
|
||||
+28
-13
@@ -14,18 +14,28 @@
|
||||
enum fcap_opmode {
|
||||
OPMODE_IDLE = 0,
|
||||
OPMODE_BUSY = 1, // used after capture is done, before it's reported
|
||||
OPMODE_PWM_CONT = 2,
|
||||
OPMODE_PWM_BURST = 3, // averaging
|
||||
OPMODE_COUNTER_CONT = 4,
|
||||
OPMODE_COUNTER_BURST = 5,
|
||||
OPMODE_COUNTER_FREERUNNING = 6,
|
||||
OPMODE_INDIRECT_CONT = 2,
|
||||
OPMODE_INDIRECT_BURST = 3, // averaging
|
||||
OPMODE_DIRECT_CONT = 4,
|
||||
OPMODE_DIRECT_BURST = 5,
|
||||
OPMODE_FREE_COUNTER = 6,
|
||||
OPMODE_SINGLE_PULSE = 7,
|
||||
};
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
// settings
|
||||
char signal_pname; // the input pin - one of TIM2 channels
|
||||
uint8_t signal_pnum;
|
||||
struct {
|
||||
char signal_pname; // the input pin - one of TIM2 channels
|
||||
uint8_t signal_pnum;
|
||||
|
||||
bool active_level;
|
||||
uint8_t direct_presc;
|
||||
uint8_t dfilter;
|
||||
uint16_t direct_msec;
|
||||
|
||||
enum fcap_opmode startmode;
|
||||
} conf;
|
||||
|
||||
// internal state
|
||||
TIM_TypeDef *TIMx;
|
||||
@@ -39,12 +49,17 @@ struct priv {
|
||||
TF_ID request_id;
|
||||
uint8_t n_skip; //!< Periods to skip before starting the real capture
|
||||
|
||||
bool active_level; // in PWM mode, the first part that is measured. (if 1, HHHLLL, else LLLHHH). In direct mode, clock polarity
|
||||
uint8_t direct_presc;
|
||||
uint16_t direct_msec;
|
||||
uint8_t dfilter;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t ontime; // length of the captured positive pulse in the current interval
|
||||
uint32_t last_period; //!< length of the captured interval between two rising edges
|
||||
uint32_t last_ontime; //!< length of the last captured ontime
|
||||
} pwm_cont;
|
||||
} ind_cont;
|
||||
|
||||
struct {
|
||||
uint32_t ontime; // length of the captured positive pulse in the current interval
|
||||
@@ -52,16 +67,15 @@ struct priv {
|
||||
uint64_t ontime_acu; //!< length of the last captured ontime, sum
|
||||
uint16_t n_count; //!< Periods captured
|
||||
uint16_t n_target; //!< Periods captured - requested count
|
||||
} pwm_burst;
|
||||
} ind_burst;
|
||||
|
||||
struct {
|
||||
uint32_t last_count; //!< Pulse count in the last capture window
|
||||
uint16_t msec; //!< Configured nbr of milliseconds to count
|
||||
} cnt_cont;
|
||||
} dir_cont;
|
||||
|
||||
struct {
|
||||
uint16_t msec; //!< Configured nbr of milliseconds to count
|
||||
} cnt_burst;
|
||||
uint16_t msec; // capture window length (used in the report callback) - different from the cont time, which is a semi-persistent config
|
||||
} dir_burst;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -98,5 +112,6 @@ void UFCAP_TIMxHandler(void *arg);
|
||||
void UFCAP_TIMyHandler(void *arg);
|
||||
|
||||
uint32_t UFCAP_GetFreeCounterValue(Unit *unit);
|
||||
uint32_t UFCAP_FreeCounterClear(Unit *unit);
|
||||
|
||||
#endif //GEX_F072_FCAP_INTERNAL_H
|
||||
|
||||
@@ -16,8 +16,16 @@ void UFCAP_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
uint8_t version = pp_u8(pp);
|
||||
(void)version;
|
||||
|
||||
priv->signal_pname = pp_char(pp);
|
||||
priv->signal_pnum = pp_u8(pp);
|
||||
priv->conf.signal_pname = pp_char(pp);
|
||||
priv->conf.signal_pnum = pp_u8(pp);
|
||||
|
||||
if (version >= 1) {
|
||||
priv->conf.active_level = pp_bool(pp);
|
||||
priv->conf.dfilter = pp_u8(pp);
|
||||
priv->conf.direct_presc = pp_u8(pp);
|
||||
priv->conf.direct_msec = pp_u16(pp);
|
||||
priv->conf.startmode = (enum fcap_opmode) pp_u8(pp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
@@ -25,10 +33,17 @@ void UFCAP_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 0); // version
|
||||
pb_u8(pb, 1); // version
|
||||
|
||||
pb_char(pb, priv->signal_pname);
|
||||
pb_u8(pb, priv->signal_pnum);
|
||||
pb_char(pb, priv->conf.signal_pname);
|
||||
pb_u8(pb, priv->conf.signal_pnum);
|
||||
|
||||
// V1
|
||||
pb_bool(pb, priv->conf.active_level);
|
||||
pb_u8(pb, priv->conf.dfilter);
|
||||
pb_u8(pb, priv->conf.direct_presc);
|
||||
pb_u16(pb, priv->conf.direct_msec);
|
||||
pb_u8(pb, priv->conf.startmode);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -39,10 +54,30 @@ error_t UFCAP_loadIni(Unit *unit, const char *key, const char *value)
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "signal-pin")) {
|
||||
suc = parse_pin(value, &priv->signal_pname, &priv->signal_pnum);
|
||||
if (streq(key, "pin")) {
|
||||
suc = parse_pin(value, &priv->conf.signal_pname, &priv->conf.signal_pnum);
|
||||
}
|
||||
else {
|
||||
else if (streq(key, "active-level")) {
|
||||
priv->conf.active_level = (bool) avr_atoi(value);
|
||||
}
|
||||
else if (streq(key, "input-filter")) {
|
||||
priv->conf.dfilter = (uint8_t) avr_atoi(value);
|
||||
}
|
||||
else if (streq(key, "direct-presc")) {
|
||||
priv->conf.direct_presc = (uint8_t) avr_atoi(value);
|
||||
}
|
||||
else if (streq(key, "direct-time")) {
|
||||
priv->conf.direct_msec = (uint16_t) avr_atoi(value);
|
||||
}
|
||||
else if (streq(key, "initial-mode")) {
|
||||
priv->conf.startmode = (enum fcap_opmode) str_parse_4(value,
|
||||
"N", OPMODE_IDLE,
|
||||
"I", OPMODE_INDIRECT_CONT,
|
||||
"D", OPMODE_DIRECT_CONT,
|
||||
"F", OPMODE_FREE_COUNTER,
|
||||
&suc);
|
||||
}
|
||||
else{
|
||||
return E_BAD_KEY;
|
||||
}
|
||||
|
||||
@@ -58,6 +93,27 @@ void UFCAP_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_comment(iw, "Signal input pin - one of:");
|
||||
iw_comment(iw, " Full support: A0, A5, A15");
|
||||
iw_comment(iw, " Indirect only: A1, B3");
|
||||
iw_entry(iw, "signal-pin", "%c%d", priv->signal_pname, priv->signal_pnum);
|
||||
iw_entry(iw, "pin", "%c%d", priv->conf.signal_pname, priv->conf.signal_pnum);
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
iw_comment(iw, "Active level or edge (0-low,falling; 1-high,rising)");
|
||||
iw_entry(iw, "active-level", "%d", (int)priv->conf.active_level);
|
||||
|
||||
iw_comment(iw, "Input filtering (0-15)");
|
||||
iw_entry(iw, "input-filter", "%d", (int)priv->conf.active_level);
|
||||
|
||||
iw_comment(iw, "Pulse counter pre-divider (1,2,4,8)");
|
||||
iw_entry(iw, "direct-presc", "%d", (int)priv->conf.direct_presc);
|
||||
|
||||
iw_comment(iw, "Pulse counting interval (ms)");
|
||||
iw_entry(iw, "direct-time", "%d", (int)priv->conf.direct_msec);
|
||||
iw_cmt_newline(iw);
|
||||
|
||||
iw_comment(iw, "Mode on startup: N-none, I-indirect, D-direct, F-free count");
|
||||
iw_entry(iw, "initial-mode", "%s", str_4(priv->conf.startmode,
|
||||
OPMODE_IDLE, "N",
|
||||
OPMODE_INDIRECT_CONT, "I",
|
||||
OPMODE_DIRECT_CONT, "D",
|
||||
OPMODE_FREE_COUNTER, "F"));
|
||||
}
|
||||
|
||||
|
||||
+231
-57
@@ -12,62 +12,134 @@
|
||||
|
||||
enum FcapCmd_ {
|
||||
CMD_STOP = 0,
|
||||
CMD_INDIRECT_CONT_START = 1,
|
||||
CMD_INDIRECT_BURST_START = 2,
|
||||
CMD_DIRECT_CONT_START = 3,
|
||||
CMD_DIRECT_BURST_START = 4,
|
||||
CMD_FREERUNNING_START = 5,
|
||||
|
||||
// Measuring a waveform
|
||||
CMD_INDIRECT_CONT_START = 1, // keep measuring, read on demand
|
||||
CMD_INDIRECT_BURST_START = 2, // wait and reply
|
||||
|
||||
// Counting pulses
|
||||
CMD_DIRECT_CONT_START = 3, // keep measuring, read on demand
|
||||
CMD_DIRECT_BURST_START = 4, // wait and reply
|
||||
CMD_FREECOUNT_START = 5, // keep counting pulses until stopped, read on reply
|
||||
|
||||
CMD_MEASURE_SINGLE_PULSE = 6,
|
||||
CMD_FREECOUNT_CLEAR = 7,
|
||||
|
||||
// Results readout for continuous modes
|
||||
CMD_INDIRECT_CONT_READ = 10,
|
||||
CMD_DIRECT_CONT_READ = 11,
|
||||
CMD_FREERUNNING_READ = 12,
|
||||
CMD_FREECOUNT_READ = 12,
|
||||
|
||||
CMD_SET_POLARITY = 20,
|
||||
CMD_SET_DIR_PRESC = 21,
|
||||
CMD_SET_INPUT_FILTER = 22,
|
||||
CMD_SET_DIR_MSEC = 23,
|
||||
|
||||
CMD_RESTORE_DEFAULTS = 30,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
uint8_t presc;
|
||||
uint16_t msec;
|
||||
|
||||
struct priv *priv = unit->data;
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
const char* msg_denied_on_pin = "Not available on the selected pin!";
|
||||
|
||||
switch (command) {
|
||||
/**
|
||||
* Stop any ongoing measurement and return to base state.
|
||||
*/
|
||||
case CMD_STOP:
|
||||
UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
||||
return E_SUCCESS;
|
||||
|
||||
// ----------------------- CONFIG --------------------------
|
||||
|
||||
/**
|
||||
* Set the active polarity, or triggering edge (for direct)
|
||||
*
|
||||
* pld: pol:u8 (0,1)
|
||||
*/
|
||||
case CMD_SET_POLARITY:
|
||||
{
|
||||
priv->active_level = pp_bool(pp);
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set the direct measurement prescaller 1,2,4,8
|
||||
*
|
||||
* pld: presc:u8
|
||||
*/
|
||||
case CMD_SET_DIR_PRESC:
|
||||
{
|
||||
presc = pp_u8(pp);
|
||||
if (presc != 1 && presc != 2 && presc != 4 && presc != 8) return E_BAD_VALUE;
|
||||
priv->direct_presc = presc;
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set the input filter for all modes
|
||||
*
|
||||
* pld: filter:u8 (0-15)
|
||||
*/
|
||||
case CMD_SET_INPUT_FILTER:
|
||||
{
|
||||
uint8_t input_filter = pp_u8(pp);
|
||||
if (input_filter >= 16) return E_BAD_VALUE;
|
||||
priv->dfilter = input_filter;
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Set the direct sampling time.
|
||||
*
|
||||
* pld: msec:u16
|
||||
*/
|
||||
case CMD_SET_DIR_MSEC:
|
||||
{
|
||||
msec = pp_u16(pp);
|
||||
priv->direct_msec = msec;
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Reset all SET* settings to their default values, stop any ongoing measure.
|
||||
*/
|
||||
case CMD_RESTORE_DEFAULTS:
|
||||
UFCAP_SwitchMode(unit, OPMODE_IDLE);
|
||||
|
||||
priv->active_level = priv->conf.active_level;
|
||||
priv->direct_presc = priv->conf.direct_presc;
|
||||
priv->direct_msec = priv->conf.direct_msec;
|
||||
priv->dfilter = priv->conf.dfilter;
|
||||
return E_SUCCESS;
|
||||
|
||||
// ------------------ COMMANDS ------------------------
|
||||
|
||||
/**
|
||||
* Start indirect continuous measurement.
|
||||
*/
|
||||
case CMD_INDIRECT_CONT_START:
|
||||
if (priv->opmode == OPMODE_PWM_CONT) return E_SUCCESS; // no-op
|
||||
if (priv->opmode == OPMODE_INDIRECT_CONT) return E_SUCCESS; // no-op
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
|
||||
|
||||
UFCAP_SwitchMode(unit, OPMODE_PWM_CONT);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_INDIRECT_BURST_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
|
||||
uint16_t count = pp_u16(pp);
|
||||
priv->pwm_burst.n_target = count;
|
||||
priv->request_id = frame_id;
|
||||
UFCAP_SwitchMode(unit, OPMODE_PWM_BURST);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_INDIRECT_CONT_READ:
|
||||
if (priv->opmode != OPMODE_PWM_CONT) {
|
||||
return E_BAD_MODE;
|
||||
}
|
||||
if (priv->pwm_cont.last_period == 0) {
|
||||
return E_BUSY;
|
||||
}
|
||||
|
||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
||||
pb_u32(&pb, priv->pwm_cont.last_period);
|
||||
pb_u32(&pb, priv->pwm_cont.last_ontime);
|
||||
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_CONT);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Start a continuous direct measurement (counting pulses in fixed time intervals)
|
||||
*
|
||||
* - meas_time_ms 0 = no change
|
||||
* - prescaller 0 = no change
|
||||
*
|
||||
* pld: meas_time_ms:u16, prescaller:u8
|
||||
* - prescaller is 1,2,4,8; 0 = no change
|
||||
*/
|
||||
case CMD_DIRECT_CONT_START:
|
||||
if (!priv->a_direct) {
|
||||
// This works only if we use the ETR pin. TIM2 shares CH1 with ETR.
|
||||
@@ -75,45 +147,147 @@ static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
|
||||
return E_FAILURE;
|
||||
}
|
||||
if (priv->opmode == OPMODE_COUNTER_CONT) return E_SUCCESS; // no-op
|
||||
if (priv->opmode == OPMODE_DIRECT_CONT) return E_SUCCESS; // no-op
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BUSY;
|
||||
|
||||
msec = pp_u16(pp);
|
||||
priv->cnt_cont.msec = msec;
|
||||
presc = pp_u8(pp);
|
||||
if (msec != 0) priv->direct_msec = msec;
|
||||
if (presc != 0) priv->direct_presc = presc;
|
||||
|
||||
UFCAP_SwitchMode(unit, OPMODE_COUNTER_CONT);
|
||||
UFCAP_SwitchMode(unit, OPMODE_DIRECT_CONT);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Start a burst of direct measurements with averaging.
|
||||
* The measurement is performed on N consecutive pulses.
|
||||
*
|
||||
* pld: count:u16
|
||||
*
|
||||
* resp: core_mhz:u16, count:u16, period_sum:u64, ontime_sum:u64
|
||||
*/
|
||||
case CMD_INDIRECT_BURST_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
|
||||
priv->ind_burst.n_target = pp_u16(pp);
|
||||
priv->request_id = frame_id;
|
||||
UFCAP_SwitchMode(unit, OPMODE_INDIRECT_BURST);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Start a single direct measurement of the given length (pulses in time period)
|
||||
* If 'prescaller' is not 0, it is changed via the param field.
|
||||
*
|
||||
* pld: meas_time_ms:u16, prescaller:u8
|
||||
* - prescaller is 1,2,4,8; 0 = no change
|
||||
*
|
||||
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
|
||||
*/
|
||||
case CMD_DIRECT_BURST_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
|
||||
priv->dir_burst.msec = pp_u16(pp);
|
||||
|
||||
presc = pp_u8(pp);
|
||||
if (presc != 0) priv->direct_presc = presc;
|
||||
|
||||
priv->request_id = frame_id;
|
||||
UFCAP_SwitchMode(unit, OPMODE_DIRECT_BURST);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Measure a single pulse length of the given polarity.
|
||||
* Measures time from a rising to a falling edge (or falling to rising, if polarity is 0)
|
||||
*
|
||||
* resp: core_mhz:u16, ontime:u32
|
||||
*/
|
||||
case CMD_MEASURE_SINGLE_PULSE:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
priv->request_id = frame_id;
|
||||
UFCAP_SwitchMode(unit, OPMODE_SINGLE_PULSE);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Start a free-running pulse counter.
|
||||
*
|
||||
* pld: prescaller:u8
|
||||
* - prescaller is 1,2,4,8; 0 = no change
|
||||
*/
|
||||
case CMD_FREECOUNT_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
|
||||
presc = pp_u8(pp);
|
||||
if (presc != 0) priv->direct_presc = presc;
|
||||
|
||||
UFCAP_SwitchMode(unit, OPMODE_FREE_COUNTER);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Reset the free-running pulse counter.
|
||||
*
|
||||
* resp: last_val:u32
|
||||
*/
|
||||
case CMD_FREECOUNT_CLEAR:
|
||||
if (priv->opmode != OPMODE_FREE_COUNTER) {
|
||||
return E_BAD_MODE;
|
||||
}
|
||||
|
||||
pb_u32(&pb, UFCAP_FreeCounterClear(unit));
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
// ------------------ READING ---------------------
|
||||
|
||||
/**
|
||||
* Read the most recent pulse measurement during continuous indirect measure.
|
||||
*
|
||||
* resp: core_mhz:u16, period:u32, ontime:u32
|
||||
*/
|
||||
case CMD_INDIRECT_CONT_READ:
|
||||
if (priv->opmode != OPMODE_INDIRECT_CONT) {
|
||||
return E_BAD_MODE;
|
||||
}
|
||||
if (priv->ind_cont.last_period == 0) {
|
||||
return E_BUSY;
|
||||
}
|
||||
|
||||
pb_u16(&pb, PLAT_AHB_MHZ);
|
||||
pb_u32(&pb, priv->ind_cont.last_period);
|
||||
pb_u32(&pb, priv->ind_cont.last_ontime);
|
||||
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
/**
|
||||
* Read the most recent result of a continuous direct measurement.
|
||||
*
|
||||
* resp: prescaller:u8, meas_time_ms:u16, pulse_count:u32
|
||||
*/
|
||||
case CMD_DIRECT_CONT_READ:
|
||||
if (!priv->a_direct) { // see above
|
||||
com_respond_str(MSG_ERROR, frame_id, msg_denied_on_pin);
|
||||
return E_FAILURE;
|
||||
}
|
||||
if (priv->opmode != OPMODE_COUNTER_CONT) return E_BAD_MODE;
|
||||
if (priv->cnt_cont.last_count == 0) return E_BUSY;
|
||||
if (priv->opmode != OPMODE_DIRECT_CONT) return E_BAD_MODE;
|
||||
if (priv->dir_cont.last_count == 0) return E_BUSY;
|
||||
|
||||
pb_u32(&pb, priv->cnt_cont.last_count);
|
||||
pb_u16(&pb, priv->cnt_cont.msec);
|
||||
pb_u8(&pb, priv->direct_presc);
|
||||
pb_u16(&pb, priv->direct_msec);
|
||||
pb_u32(&pb, priv->dir_cont.last_count);
|
||||
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_DIRECT_BURST_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
|
||||
msec = pp_u16(pp);
|
||||
priv->cnt_burst.msec = msec;
|
||||
priv->request_id = frame_id;
|
||||
UFCAP_SwitchMode(unit, OPMODE_COUNTER_BURST);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_FREERUNNING_START:
|
||||
if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE;
|
||||
UFCAP_SwitchMode(unit, OPMODE_COUNTER_FREERUNNING);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_FREERUNNING_READ:
|
||||
if (priv->opmode != OPMODE_COUNTER_FREERUNNING) {
|
||||
/**
|
||||
* Read the current value of the free-running pulse counter.
|
||||
*
|
||||
* The timing may have a significant jitter, this function is practically useful only for
|
||||
* slow pulse sources (like a geiger counter, item counting etc)
|
||||
*
|
||||
* resp: count:u32
|
||||
*/
|
||||
case CMD_FREECOUNT_READ:
|
||||
if (priv->opmode != OPMODE_FREE_COUNTER) {
|
||||
return E_BAD_MODE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user