Force inactive output between pulse trains

This commit is contained in:
Raphael Coeffic
2022-03-20 16:30:59 +01:00
parent d2685aeadf
commit 3057652b40
8 changed files with 143 additions and 59 deletions
@@ -29,6 +29,8 @@
#include "pulses/crossfire.h"
#endif
#define STOP_TIMER_ON_LAST_UPDATE
static const stm32_pulse_timer_t extmoduleTimer = {
.GPIOx = EXTMODULE_TX_GPIO,
.GPIO_Pin = EXTMODULE_TX_GPIO_PIN,
@@ -36,22 +38,69 @@ static const stm32_pulse_timer_t extmoduleTimer = {
.TIMx = EXTMODULE_TIMER,
.TIM_Prescaler = __LL_TIM_CALC_PSC(EXTMODULE_TIMER_FREQ, 2000000),
.TIM_Channel = EXTMODULE_TIMER_Channel,
.TIM_IRQn = EXTMODULE_TIMER_IRQn,
.DMAx = EXTMODULE_TIMER_DMA,
.DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL,
.DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL,
.DMA_IRQn = EXTMODULE_TIMER_DMA_STREAM_IRQn,
};
#if defined(STOP_TIMER_ON_LAST_UPDATE)
static_assert(EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH1
|| EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH1N
|| EXTMODULE_TIMER_Channel == LL_TIM_CHANNEL_CH3,
"Unsupported timer channel");
static void set_compare_reg(uint32_t val)
{
switch(EXTMODULE_TIMER_Channel){
case LL_TIM_CHANNEL_CH1:
case LL_TIM_CHANNEL_CH1N:
LL_TIM_OC_SetCompareCH1(EXTMODULE_TIMER, val);
break;
case LL_TIM_CHANNEL_CH3:
LL_TIM_OC_SetCompareCH3(EXTMODULE_TIMER, val);
break;
}
}
extern "C" void EXTMODULE_TIMER_DMA_IRQHandler()
{
if (!LL_DMA_IsActiveFlag_TC5(EXTMODULE_TIMER_DMA))
return;
LL_DMA_ClearFlag_TC5(EXTMODULE_TIMER_DMA);
LL_TIM_ClearFlag_UPDATE(EXTMODULE_TIMER);
LL_TIM_EnableIT_UPDATE(EXTMODULE_TIMER);
set_compare_reg(0);
LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1);
}
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
if (!LL_TIM_IsActiveFlag_UPDATE(EXTMODULE_TIMER))
return;
LL_TIM_ClearFlag_UPDATE(EXTMODULE_TIMER);
LL_TIM_DisableIT_UPDATE(EXTMODULE_TIMER);
// Halt pulses and force to inactive level
LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel,
LL_TIM_OCMODE_FORCED_INACTIVE);
}
#endif
void extmoduleStop()
{
EXTERNAL_MODULE_OFF();
stm32_pulse_deinit(&extmoduleTimer);
}
void extmodulePpmStart(uint16_t ppm_delay, bool polarity)
static void config_ppm_output(uint16_t ppm_delay, bool polarity)
{
EXTERNAL_MODULE_ON();
stm32_pulse_init(&extmoduleTimer);
// PPM generation principle:
//
// Hardware timer in PWM mode is used for PPM generation
@@ -65,7 +114,6 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity)
ocInit.OCMode = LL_TIM_OCMODE_PWM1;
ocInit.OCState = LL_TIM_OCSTATE_ENABLE;
ocInit.OCNState = LL_TIM_OCSTATE_ENABLE;
if (polarity) {
ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW;
@@ -74,28 +122,70 @@ void extmodulePpmStart(uint16_t ppm_delay, bool polarity)
}
ocInit.CompareValue = ppm_delay * 2;
stm32_pulse_config_output(&extmoduleTimer, &ocInit);
stm32_pulse_config_output(&extmoduleTimer, &ocInit);
}
void extmodulePpmStart(uint16_t ppm_delay, bool polarity)
{
EXTERNAL_MODULE_ON();
stm32_pulse_init(&extmoduleTimer);
config_ppm_output(ppm_delay, polarity);
}
void extmoduleSendNextFramePpm(void* pulses, uint16_t length,
uint16_t ppm_delay, bool polarity)
{
if (!stm32_pulse_stop_if_running(&extmoduleTimer))
return;
// Config output
set_compare_reg(ppm_delay * 2);
uint32_t ll_polarity;
if (polarity) {
ll_polarity = LL_TIM_OCPOLARITY_LOW;
} else {
ll_polarity = LL_TIM_OCPOLARITY_HIGH;
}
LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity);
LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length);
}
#if defined(PXX1)
void extmodulePxx1PulsesStart()
{
EXTERNAL_MODULE_ON();
stm32_pulse_init(&extmoduleTimer);
LL_TIM_OC_InitTypeDef ocInit;
LL_TIM_OC_StructInit(&ocInit);
ocInit.OCMode = LL_TIM_OCMODE_PWM1;
ocInit.OCState = LL_TIM_OCSTATE_ENABLE;
ocInit.OCNState = LL_TIM_OCSTATE_ENABLE;
ocInit.OCPolarity = LL_TIM_OCPOLARITY_LOW;
ocInit.CompareValue = 9 * 2; // 9 uS
stm32_pulse_config_output(&extmoduleTimer, &ocInit);
stm32_pulse_init(&extmoduleTimer);
}
void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length)
{
if (!stm32_pulse_stop_if_running(&extmoduleTimer))
return;
set_compare_reg(9 * 2);
LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_PWM1);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length);
}
#endif
// TODO: polarity?
void extmoduleSerialStart()
{
EXTERNAL_MODULE_ON();
@@ -112,44 +202,6 @@ void extmoduleSerialStart()
stm32_pulse_config_output(&extmoduleTimer, &ocInit);
}
void extmoduleSendNextFramePpm(void* pulses, uint16_t length,
uint16_t ppm_delay, bool polarity)
{
if (!stm32_pulse_stop_if_running(&extmoduleTimer))
return;
switch(EXTMODULE_TIMER_Channel){
case LL_TIM_CHANNEL_CH1:
LL_TIM_OC_SetCompareCH1(EXTMODULE_TIMER, ppm_delay * 2);
break;
case LL_TIM_CHANNEL_CH3:
LL_TIM_OC_SetCompareCH3(EXTMODULE_TIMER, ppm_delay * 2);
break;
}
uint32_t ll_polarity;
if (polarity) {
ll_polarity = LL_TIM_OCPOLARITY_LOW;
} else {
ll_polarity = LL_TIM_OCPOLARITY_HIGH;
}
LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length);
}
#if defined(PXX1)
void extmoduleSendNextFramePxx1(const void* pulses, uint16_t length)
{
if (!stm32_pulse_stop_if_running(&extmoduleTimer))
return;
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length);
}
#endif
#if defined(AFHDS3) && !(defined(EXTMODULE_USART) && defined(EXTMODULE_TX_INVERT_GPIO))
void extmoduleSendNextFrameAFHDS3(const void* pulses, uint16_t length)
{
@@ -174,11 +226,13 @@ void extmoduleSendNextFrameSoftSerial100kbit(const void* pulses, uint16_t length
ll_polarity = LL_TIM_OCPOLARITY_LOW;
}
LL_TIM_OC_SetPolarity(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, ll_polarity);
LL_TIM_OC_SetMode(EXTMODULE_TIMER, EXTMODULE_TIMER_Channel, LL_TIM_OCMODE_TOGGLE);
// Start DMA request and re-enable timer
stm32_pulse_start_dma_req(&extmoduleTimer, pulses, length);
}
// Delay based byte sending @ 57600 bps
void extmoduleSendInvertedByte(uint8_t byte)
{
uint16_t time;
@@ -22,6 +22,8 @@
#include "stm32_pulse_driver.h"
#include "definitions.h"
#define STOP_TIMER_ON_LAST_UPDATE
void stm32_pulse_init(const stm32_pulse_timer_t* tim)
{
LL_GPIO_InitTypeDef pinInit;
@@ -38,6 +40,16 @@ void stm32_pulse_init(const stm32_pulse_timer_t* tim)
timInit.Prescaler = tim->TIM_Prescaler;
timInit.Autoreload = 65535;
LL_TIM_Init(tim->TIMx, &timInit);
#if defined(STOP_TIMER_ON_LAST_UPDATE)
// Enable DMA IRQ
NVIC_EnableIRQ(tim->DMA_IRQn);
NVIC_SetPriority(tim->DMA_IRQn, 7);
// Enable timer IRQ
NVIC_EnableIRQ(tim->TIM_IRQn);
NVIC_SetPriority(tim->TIM_IRQn, 7);
#endif
}
void stm32_pulse_deinit(const stm32_pulse_timer_t* tim)
@@ -57,7 +69,6 @@ void stm32_pulse_deinit(const stm32_pulse_timer_t* tim)
void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, LL_TIM_OC_InitTypeDef* ocInit)
{
LL_TIM_DisableCounter(tim->TIMx);
LL_TIM_OC_Init(tim->TIMx, tim->TIM_Channel, ocInit);
LL_TIM_OC_EnablePreload(tim->TIMx, tim->TIM_Channel);
@@ -66,7 +77,6 @@ void stm32_pulse_config_output(const stm32_pulse_timer_t* tim, LL_TIM_OC_InitTyp
}
LL_TIM_EnableDMAReq_UPDATE(tim->TIMx);
LL_TIM_EnableCounter(tim->TIMx);
}
// return true if stopped, false otherwise
@@ -77,12 +87,15 @@ bool stm32_pulse_stop_if_running(const stm32_pulse_timer_t* tim)
// disable timer
LL_TIM_DisableCounter(tim->TIMx);
LL_TIM_DisableIT_UPDATE(tim->TIMx);
return true;
}
void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim,
const void* pulses, uint16_t length)
{
// re-init DMA stream
LL_DMA_DeInit(tim->DMAx, tim->DMA_Stream);
LL_DMA_InitTypeDef dmaInit;
@@ -112,12 +125,25 @@ void stm32_pulse_start_dma_req(const stm32_pulse_timer_t* tim,
dmaInit.NbData = length;
dmaInit.Channel = tim->DMA_Channel;
dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH;
LL_DMA_Init(tim->DMAx, tim->DMA_Stream, &dmaInit);
#if defined(STOP_TIMER_ON_LAST_UPDATE)
// Enable TC IRQ
LL_DMA_EnableIT_TC(tim->DMAx, tim->DMA_Stream);
#endif
// Enable DMA
LL_TIM_ClearFlag_UPDATE(tim->TIMx);
LL_TIM_DisableDMAReq_UPDATE(tim->TIMx);
LL_TIM_SetCounter(tim->TIMx, 0);
LL_DMA_EnableStream(tim->DMAx, tim->DMA_Stream);
// re-init timer
// Trigger update to effect the first DMA transation
// and thus load ARR with the first duration
LL_TIM_EnableDMAReq_UPDATE(tim->TIMx);
LL_TIM_GenerateEvent_UPDATE(tim->TIMx);
// start timer
LL_TIM_EnableCounter(tim->TIMx);
}
@@ -33,10 +33,12 @@ struct stm32_pulse_timer_t {
TIM_TypeDef* TIMx;
uint16_t TIM_Prescaler;
uint32_t TIM_Channel;
IRQn_Type TIM_IRQn;
DMA_TypeDef* DMAx;
uint32_t DMA_Stream;
uint32_t DMA_Channel;
IRQn_Type DMA_IRQn;
};
void stm32_pulse_init(const stm32_pulse_timer_t* tim);