From 75efa123384f66e6c18b7f42878f5a8020d33633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 20 Feb 2018 22:58:24 +0100 Subject: [PATCH] wip direct, unfinished config --- platform/irq_dispatcher.c | 30 +++++++++++++---- platform/timebase.c | 16 +++++---- units/fcap/_fcap_core.c | 66 +++++++++++++++++++++++++++++++++---- units/fcap/_fcap_init.c | 13 +++++++- units/fcap/_fcap_internal.h | 15 +++++---- units/fcap/unit_fcap.c | 37 +++++++++++++++++---- 6 files changed, 144 insertions(+), 33 deletions(-) diff --git a/platform/irq_dispatcher.c b/platform/irq_dispatcher.c index 39a175a..9becbea 100644 --- a/platform/irq_dispatcher.c +++ b/platform/irq_dispatcher.c @@ -64,7 +64,9 @@ static struct callbacks_ { struct cbslot tim2; struct cbslot tim6; struct cbslot tim7; + struct cbslot tim14; struct cbslot tim15; + struct cbslot tim16; struct cbslot adc1; @@ -104,23 +106,31 @@ void irqd_init(void) // NVIC_EnableIRQ(TIM1_IRQn); /*!< TIM1 global Interrupt */ NVIC_EnableIRQ(TIM2_IRQn); /*!< TIM2 global Interrupt */ + HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0); // Used by FCAP + // NVIC_EnableIRQ(TIM3_IRQn); /*!< TIM3 global Interrupt */ NVIC_EnableIRQ(TIM6_DAC_IRQn); /*!< TIM6 global and DAC channel underrun error Interrupt */ HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); // Used for DAC timing NVIC_EnableIRQ(TIM7_IRQn); /*!< TIM7 global Interrupt */ - HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0); + HAL_NVIC_SetPriority(TIM7_IRQn, 2, 0);// this will be for dac (?) - /* Tim14 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */ - /* Tim14's priority is set to 0 in the init routine, which runs early in the startup sequence */ - // NVIC_EnableIRQ(TIM14_IRQn); /*!< TIM14 global Interrupt */ + NVIC_EnableIRQ(TIM14_IRQn); /*used by fcap as a time reference for direct capture */ /*!< TIM14 global Interrupt */ + HAL_NVIC_SetPriority(TIM14_IRQn, 2, 0); NVIC_EnableIRQ(TIM15_IRQn); /*!< TIM15 global Interrupt */ - HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0); + HAL_NVIC_SetPriority(TIM15_IRQn, 2, 0); // Used by ADC + + NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */ + HAL_NVIC_SetPriority(TIM16_IRQn, 2, 0); + -// NVIC_EnableIRQ(TIM16_IRQn); /*!< TIM16 global Interrupt */ + /* Tim17 is used for HAL timebase, because SysTick is used to time FreeRTOS and has the lowest priority. */ + /* Tim17's priority is set to 0 in the init routine, which runs early in the startup sequence */ // NVIC_EnableIRQ(TIM17_IRQn); /*!< TIM17 global Interrupt */ + + // NVIC_EnableIRQ(I2C1_IRQn); /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */ // NVIC_EnableIRQ(I2C2_IRQn); /*!< I2C2 Event Interrupt */ // NVIC_EnableIRQ(SPI1_IRQn); /*!< SPI1 global Interrupt */ @@ -163,7 +173,10 @@ static struct cbslot *get_slot_for_periph(void *periph) else if (periph == TIM2) slot = &callbacks.tim2; else if (periph == TIM6) slot = &callbacks.tim6; else if (periph == TIM7) slot = &callbacks.tim7; + else if (periph == TIM14) slot = &callbacks.tim14; else if (periph == TIM15) slot = &callbacks.tim15; + else if (periph == TIM16) slot = &callbacks.tim16; + // 17 - used by timebase else if (periph == ADC1) slot = &callbacks.adc1; @@ -326,6 +339,11 @@ void TIM15_IRQHandler(void) CALL_IRQ_HANDLER(callbacks.tim15); } +void TIM16_IRQHandler(void) +{ + CALL_IRQ_HANDLER(callbacks.tim16); +} + void ADC1_COMP_IRQHandler(void) { CALL_IRQ_HANDLER(callbacks.adc1); diff --git a/platform/timebase.c b/platform/timebase.c index 958f8cd..050e62b 100644 --- a/platform/timebase.c +++ b/platform/timebase.c @@ -7,10 +7,12 @@ // ---------------------------- HAL TIMEBASE ----------------------------- -#define TIMEBASE_TIMER TIM14 +#define TIMEBASE_TIMER TIM17 HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { + // EDIT - used 17 instead because 14 was needed for fcap + // TIM14 is a simple 16-bit timer timer with no special features. // This makes it a good choice for the timebase generation. We set it to generate // an interrupt every 1 ms @@ -19,9 +21,9 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) // - TIM14 is always up-counting // - using APB1 clock - __HAL_RCC_TIM14_CLK_ENABLE(); - NVIC_SetPriority(TIM14_IRQn, TickPriority); // highest possible priority - NVIC_EnableIRQ(TIM14_IRQn); + __HAL_RCC_TIM17_CLK_ENABLE(); + NVIC_SetPriority(TIM17_IRQn, TickPriority); // highest possible priority + NVIC_EnableIRQ(TIM17_IRQn); /* Compute TIM1 clock */ uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq(); @@ -45,7 +47,7 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) static volatile uint32_t uwUptimeMs = 0; /* TIMEBASE TIMER ISR */ -void TIM14_IRQHandler(void) +void TIM17_IRQHandler(void) { uwUptimeMs++; LL_TIM_ClearFlag_UPDATE(TIMEBASE_TIMER); @@ -89,10 +91,10 @@ uint64_t PTIM_GetMicrotime(void) uwMicros = TIMEBASE_TIMER->CNT; uwMillis = uwUptimeMs; - if (LL_TIM_IsActiveFlag_UPDATE(TIM14)) { + if (LL_TIM_IsActiveFlag_UPDATE(TIMEBASE_TIMER)) { // This means the timer has overflown after we disabled IRQ // Use the last CNT value before the overflow - uwMicros = TIM14->ARR; // this is 999us + uwMicros = TIMEBASE_TIMER->ARR; // this is 999us } } vPortExitCritical(); diff --git a/units/fcap/_fcap_core.c b/units/fcap/_fcap_core.c index d9a225b..b9e5809 100644 --- a/units/fcap/_fcap_core.c +++ b/units/fcap/_fcap_core.c @@ -7,6 +7,10 @@ #define FCAP_INTERNAL #include "_fcap_internal.h" +void UFCAP_StopMeasurement(Unit *unit); +void UFCAP_ConfigureForPWMCapture(Unit *unit); +void UFCAP_ConfigureForDirectCapture(Unit *unit); + static void UFCAP_PWMBurstReportJob(Job *job) { Unit *unit = job->unit; @@ -39,7 +43,6 @@ void UFCAP_TimerHandler(void *arg) if (priv->opmode == OPMODE_PWM_CONT) { if (LL_TIM_IsActiveFlag_CC1(TIMx)) { -// assert_param(!LL_TIM_IsActiveFlag_CC1OVR(TIMx)); if (priv->n_skip > 0) { priv->n_skip--; } else { @@ -51,7 +54,6 @@ void UFCAP_TimerHandler(void *arg) } if (LL_TIM_IsActiveFlag_CC2(TIMx)) { -// assert_param(!LL_TIM_IsActiveFlag_CC2OVR(TIMx)); priv->pwm_cont.ontime = LL_TIM_IC_GetCaptureCH2(TIMx); LL_TIM_ClearFlag_CC2(TIMx); LL_TIM_ClearFlag_CC2OVR(TIMx); @@ -59,7 +61,6 @@ void UFCAP_TimerHandler(void *arg) } else if (priv->opmode == OPMODE_PWM_BURST) { if (LL_TIM_IsActiveFlag_CC1(TIMx)) { -// assert_param(!LL_TIM_IsActiveFlag_CC1OVR(TIMx)); const uint32_t period = LL_TIM_IC_GetCaptureCH1(TIMx); const uint32_t ontime = priv->pwm_burst.ontime; @@ -85,7 +86,6 @@ void UFCAP_TimerHandler(void *arg) } if (LL_TIM_IsActiveFlag_CC2(TIMx)) { -// assert_param(!LL_TIM_IsActiveFlag_CC2OVR(TIMx)); priv->pwm_burst.ontime = LL_TIM_IC_GetCaptureCH2(TIMx); LL_TIM_ClearFlag_CC2(TIMx); LL_TIM_ClearFlag_CC2OVR(TIMx); @@ -95,6 +95,9 @@ void UFCAP_TimerHandler(void *arg) // clear everything - in idle it would cycle in the handler forever TIMx->SR = 0; } + else { + trap("Unhandled fcap TIMx irq"); + } } static void UFCAP_ClearTimerConfig(Unit *unit) @@ -120,9 +123,9 @@ static void UFCAP_ClearTimerConfig(Unit *unit) void UFCAP_StopMeasurement(Unit *unit) { struct priv * const priv = unit->data; - TIM_TypeDef * const TIMx = priv->TIMx; - LL_TIM_DeInit(TIMx); // clear all flags and settings + LL_TIM_DeInit(priv->TIMx); // clear all flags and settings + LL_TIM_DeInit(priv->TIMy); // clear all flags and settings } /** @@ -161,6 +164,11 @@ void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode) priv->n_skip = 1; // discard the first cycle (will be incomplete) UFCAP_ConfigureForPWMCapture(unit); // is also stopped and restarted break; + + case OPMODE_COUNTER_CONT: + UFCAP_ConfigureForDirectCapture(unit); + break; + default: trap("Unhandled opmode %d", (int)opmode); } @@ -208,3 +216,49 @@ void UFCAP_ConfigureForPWMCapture(Unit *unit) LL_TIM_EnableIT_CC2(TIMx); LL_TIM_EnableCounter(TIMx); } + + +/** + * Configure peripherals for an indirect capture (PWM measurement) - continuous or burst + * @param unit + */ +void UFCAP_ConfigureForDirectCapture(Unit *unit) +{ + struct priv * const priv = unit->data; + const uint32_t ll_ch_a = priv->ll_ch_a; // + + UFCAP_ClearTimerConfig(unit); + { + TIM_TypeDef *const TIMy = priv->TIMy; + uint16_t presc = PLAT_AHB_MHZ * 500; // this produces 2 kHz + uint32_t count = 2001; + + LL_TIM_SetPrescaler(TIMy, (uint32_t) (presc - 1)); + LL_TIM_SetAutoReload(TIMy, count - 1); + LL_TIM_EnableARRPreload(TIMy); + LL_TIM_GenerateEvent_UPDATE(TIMy); + LL_TIM_SetOnePulseMode(TIMy, LL_TIM_ONEPULSEMODE_SINGLE); // TODO check if this works + LL_TIM_OC_EnableFast(TIMy, LL_TIM_CHANNEL_CH1); + + dbg("TIMy presc %d, count %d", (int) presc, (int) count); + + LL_TIM_SetTriggerOutput(TIMy, LL_TIM_TRGO_OC1REF); + LL_TIM_OC_SetMode(TIMy, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1); // 1 until CC, then 0 + LL_TIM_OC_SetCompareCH1(TIMy, count - 1); // XXX maybe this must be lower + LL_TIM_CC_EnableChannel(TIMy, LL_TIM_CHANNEL_CH1); // enable the output channel that produces a trigger + } + + { + // TIMx - the slave + TIM_TypeDef *const TIMx = priv->TIMx; + LL_TIM_SetSlaveMode(TIMx, LL_TIM_SLAVEMODE_GATED); + LL_TIM_SetTriggerInput(TIMx, LL_TIM_TS_ITR3); // ITR3 is TIM14 which we use as TIMy + LL_TIM_EnableMasterSlaveMode(TIMx); + LL_TIM_EnableExternalClock(TIMx); // TODO must check and deny this mode if the pin is not on CH1 = external trigger input + + LL_TIM_EnableCounter(TIMx); + } + + LL_TIM_EnableCounter(priv->TIMy); // XXX this will start the pulse (maybe) +} + diff --git a/units/fcap/_fcap_init.c b/units/fcap/_fcap_init.c index 469e309..b9e05cc 100644 --- a/units/fcap/_fcap_init.c +++ b/units/fcap/_fcap_init.c @@ -33,6 +33,9 @@ error_t UFCAP_init(Unit *unit) TIM_TypeDef * const TIMx = TIM2; Resource timRsc = R_TIM2; + TIM_TypeDef * const TIMy = TIM14; + Resource tim2Rsc = R_TIM14; + uint32_t ll_ch_a = 0; uint32_t ll_ch_b = 0; @@ -79,6 +82,7 @@ error_t UFCAP_init(Unit *unit) TRY(rsc_claim_pin(unit, priv->signal_pname, priv->signal_pnum)); TRY(rsc_claim(unit, timRsc)); + TRY(rsc_claim(unit, tim2Rsc)); // ---- INIT ---- assert_param(ll_ch_a != ll_ch_b); @@ -91,7 +95,9 @@ error_t UFCAP_init(Unit *unit) TRY(hw_configure_gpio_af(priv->signal_pname, priv->signal_pnum, ll_timpin_af)); hw_periph_clock_enable(TIMx); + hw_periph_clock_enable(TIMy); irqd_attach(TIMx, UFCAP_TimerHandler, unit); + // TODO attach TIMy to a handler UFCAP_SwitchMode(unit, OPMODE_IDLE); @@ -108,8 +114,13 @@ void UFCAP_deInit(Unit *unit) UFCAP_SwitchMode(unit, OPMODE_IDLE); TIM_TypeDef *TIMx = priv->TIMx; + TIM_TypeDef *TIMy = priv->TIMy; LL_TIM_DeInit(TIMx); - irqd_attach(TIMx, UFCAP_TimerHandler, unit); + LL_TIM_DeInit(TIMy); + irqd_detach(TIMx, UFCAP_TimerHandler); + // TODO detach TIMy when any handler is added + hw_periph_clock_disable(TIMx); + hw_periph_clock_disable(TIMy); } // Release all resources, deinit pins diff --git a/units/fcap/_fcap_internal.h b/units/fcap/_fcap_internal.h index 18f4c5b..10ffc95 100644 --- a/units/fcap/_fcap_internal.h +++ b/units/fcap/_fcap_internal.h @@ -16,6 +16,8 @@ enum fcap_opmode { 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, // averaging }; /** Private data structure */ @@ -26,6 +28,7 @@ struct priv { // internal state TIM_TypeDef *TIMx; + TIM_TypeDef *TIMy; // used as a timebase source for TIMx in direct mode uint32_t ll_ch_b; uint32_t ll_ch_a; bool a_direct; @@ -49,6 +52,10 @@ struct priv { uint16_t n_count; //!< Periods captured uint16_t n_target; //!< Periods captured - requested count } pwm_burst; + + struct { + uint32_t last_count; //!< Pulse count in the last capture window + } cnt_cont; }; }; @@ -79,12 +86,8 @@ void UFCAP_deInit(Unit *unit); // ------------------------------------------------------------------------ -void UFCAP_TimerHandler(void *arg); - -void UFCAP_StopMeasurement(Unit *unit); - -void UFCAP_ConfigureForPWMCapture(Unit *unit); - void UFCAP_SwitchMode(Unit *unit, enum fcap_opmode opmode); +void UFCAP_TimerHandler(void *arg); + #endif //GEX_F072_FCAP_INTERNAL_H diff --git a/units/fcap/unit_fcap.c b/units/fcap/unit_fcap.c index 53c62cc..fcc460d 100644 --- a/units/fcap/unit_fcap.c +++ b/units/fcap/unit_fcap.c @@ -12,29 +12,32 @@ enum FcapCmd_ { CMD_STOP = 0, - CMD_PWM_CONT_START = 1, - CMD_PWM_BURST_START = 2, - CMD_PWM_CONT_READ = 10, + CMD_INDIRECT_CONT_START = 1, + CMD_INDIRECT_BURST_START = 2, + CMD_DIRECT_CONT_START = 3, + CMD_INDIRECT_CONT_READ = 10, + CMD_DIRECT_CONT_READ = 11, }; /** 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); switch (command) { case CMD_STOP: UFCAP_SwitchMode(unit, OPMODE_IDLE); return E_SUCCESS; - case CMD_PWM_CONT_START: + case CMD_INDIRECT_CONT_START: if (priv->opmode == OPMODE_PWM_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_PWM_BURST_START: + case CMD_INDIRECT_BURST_START: if (priv->opmode != OPMODE_IDLE) return E_BAD_MODE; uint16_t count = pp_u16(pp); @@ -43,7 +46,7 @@ static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, UFCAP_SwitchMode(unit, OPMODE_PWM_BURST); return E_SUCCESS; - case CMD_PWM_CONT_READ: + case CMD_INDIRECT_CONT_READ: if (priv->opmode != OPMODE_PWM_CONT) { return E_BAD_MODE; } @@ -51,7 +54,6 @@ static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, return E_BUSY; } - PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); pb_u16(&pb, PLAT_AHB_MHZ); pb_u32(&pb, priv->pwm_cont.last_period); pb_u32(&pb, priv->pwm_cont.last_ontime); @@ -59,6 +61,27 @@ static error_t UFCAP_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, com_respond_pb(frame_id, MSG_SUCCESS, &pb); return E_SUCCESS; + case CMD_DIRECT_CONT_START: + if (priv->opmode == OPMODE_COUNTER_CONT) return E_SUCCESS; // no-op + if (priv->opmode != OPMODE_IDLE) return E_BUSY; + + UFCAP_SwitchMode(unit, OPMODE_COUNTER_CONT); + return E_SUCCESS; + + case CMD_DIRECT_CONT_READ: + if (priv->opmode != OPMODE_COUNTER_CONT) { + return E_BAD_MODE; + } + if (priv->cnt_cont.last_count == 0) { + return E_BUSY; + } + + // TODO also add the window len - may need to shorten it for fast signals (or if fast capture is required) + pb_u32(&pb, priv->cnt_cont.last_count); + + com_respond_pb(frame_id, MSG_SUCCESS, &pb); + return E_SUCCESS; + default: return E_UNKNOWN_COMMAND; }