2025-05-01 8:05 AM - last edited on 2025-05-01 8:42 AM by Andrew Neil
Hi,
I want to generate a timeslot control signal consisting of one 10-microsecond pulse followed by fifteen 2-microsecond pulses.
I want the period to remain constant, aligned on the falling edge.
My problem is that before and after the long pulse, the period changes, and I don’t know how to fix it.
I have:
instead of:
I use two methods and i am not able to make both of them work.
Here is my code:
Method 1 : Timer1 16 in PWM mode
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if( htim->Instance == TIM16)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
else
{
if(htim->Instance->RCR>0)
{
htim->Instance->RCR=0;
htim->Instance->CCR1=g_TSC_Long_Low_Pulse_Duration-1;
}
else
{
htim->Instance->RCR=(g_TSC_Max_TimeSlotsToRun-1)-1;
htim->Instance->CCR1=g_TSC_Short_Low_Pulse_Duration-1;
}
}
}
}
Method 2: time base (Tim 6)
typedef enum {
PULSE_LOW,
PULSE_HIGH
} PulseState;
PulseState pulse_state = PULSE_LOW;
uint8_t ts_counter = 0;
bool is_long_pulse_done = false;
g_TSC_Full_Signal_Period = (uint32_t)((double) (1/((TS_ACQ_RATE_HERTZ) / HAL_RCC_GetSysClockFreq()) ));
g_TSC_Short_Low_Pulse_Duration = (uint32_t)((double) (TS_SHORT_PULSE_DURATION_S * HAL_RCC_GetSysClockFreq()) );
g_TSC_Short_High_Pulse_Duration = g_TSC_Full_Signal_Period - g_TSC_Short_Low_Pulse_Duration;
g_TSC_Long_Low_Pulse_Duration = (uint32_t)((double) (TS_LONG_PULSE_DURATION_S * HAL_RCC_GetSysClockFreq()) );
g_TSC_Long_High_Pulse_Duration = g_TSC_Full_Signal_Period - g_TSC_Long_Low_Pulse_Duration;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6)
{
switch (pulse_state)
{
case PULSE_LOW:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
if (!is_long_pulse_done)
__HAL_TIM_SET_AUTORELOAD(htim, g_TSC_Long_Low_Pulse_Duration-1); // long LOW
else
__HAL_TIM_SET_AUTORELOAD(htim, g_TSC_Short_Low_Pulse_Duration-1); // short LOW
pulse_state = PULSE_HIGH;
break;
case PULSE_HIGH:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
if (!is_long_pulse_done)
{
__HAL_TIM_SET_AUTORELOAD(htim, g_TSC_Long_High_Pulse_Duration-1); // long HIGH
is_long_pulse_done = true;
ts_counter = 0;
}
else
{
__HAL_TIM_SET_AUTORELOAD(htim, g_TSC_Short_High_Pulse_Duration-1); // short HIGH
ts_counter++;
if (ts_counter >= 15){
is_long_pulse_done = false;
}
}
}
for the second method i have an extra problem, i can not have a pulse with less then 3 micro second width
Can somebody help me please?
2025-05-01 8:27 AM
You want the Period to be the same, but don't state WHAT it is.
Perhaps you can use PMW Mode 2, and modulate the width of the LOW portion?
Other alternative for patterns are TIM+DMA+GPIO->BSRR
2025-05-01 8:41 AM
i want a period of 25 microsecond.
If i modulate the low portion, all my pulses would have the same width and i do not want that to happen.
Can you explain more what you mean by TIM+DMA+GPIO->BSRR
2025-05-01 9:05 AM
@okeycii wrote:If i modulate the low portion, all my pulses would have the same width and i do not want that to happen.
Would they?
If the period is fixed, and you modulate the low portion, then that means the high portion has to change - ie, your pulse widths do change!
QEF ?
2025-05-01 10:17 AM
Set up the channel to toggle on match, leave the pulse value at 0 and set up the ARR field to be the duration of the high time, low time, high time, low time, etc...
{10, 25, 2, 25, 2, 25, ...}
2025-05-01 10:43 AM
It shouldn't be hard to maintain the period, if you change the duty of the space, the mark is tied to it, no?
As TDK mentions Toggle Mode would also work, you'd need to ensure the polarity
You could use a TIM at a high rate to trigger a Memory-to-Memory DMA operation, moving patterns from a buffer to GPIO pins. The GPIO Banks are each 16-pins wide, the BSRR allows a single write pattern to make individual or groups of pins in pin SET or RESET. The BSRR is 32-bit wide, review in the Reference Manual. The DMA sequence length can be used in a circular mode to keep repeating the pattern.