Skip to main content
Visitor II
May 1, 2025
Solved

generate one 10-microsecond pulse followed by fifteen 2-microsecond pulses

  • May 1, 2025
  • 4 replies
  • 761 views

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:

okeycii_0-1746110947051.jpeg

instead of:

okeycii_1-1746110991550.jpeg

 

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?

    This topic has been closed for replies.
    Best answer by okeycii

    it does work thank very much, i was loosing my mind trying to do this.

    4 replies

    Graduate II
    May 1, 2025

    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

    okeyciiAuthor
    Visitor II
    May 1, 2025

    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

    Super User
    May 1, 2025

    @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 ?

    Super User
    May 1, 2025

    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, ...}

    Graduate II
    May 2, 2025

     

    I just use the HAL_TIM_PWM_ConfigChannel to change the pulse

     

    15 pulses at 2us and 1 pulse at 10us 

    KarlYamashita_0-1746147941838.png

    period is 25us

    KarlYamashita_2-1746148152492.png

    KarlYamashita_3-1746148177888.png

    10us long pulse

    KarlYamashita_4-1746148218462.png

    2us short pulses

    KarlYamashita_5-1746148249075.png

     

    TIM_OC_InitTypeDef sConfigOC = {0};
    void InitTim15(void)
    {
    	sConfigOC.OCMode = TIM_OCMODE_PWM1;
    	sConfigOC.Pulse = 33;
    	sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    	sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    	sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    	sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    	sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    }
    
    volatile uint32_t pulseCount = 0;
    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
    {
    	if(pulseCount == 15)
    	{
    		sConfigOC.Pulse = 160;
    		if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    		{
    			Error_Handler();
    		}
    	}
    	else if(pulseCount == 16)
    	{
    		pulseCount = 0; // reset
    		sConfigOC.Pulse = 33;
    		if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
    		{
    			Error_Handler();
    		}
    	}
    	++pulseCount;
    }

     

     

     

     

     

    Super User
    May 2, 2025

    Oh, after a second read, you do want the period to be constant. Just invert the polarity of the channel from what you're already doing. You'll need to specify the negative duration instead of the positive duration, but then the period will line up with the falling edge instead of the rising.

    Another option would be to use downcounting instead of upcounting.

    okeyciiAuthorAnswer
    Visitor II
    May 2, 2025

    it does work thank very much, i was loosing my mind trying to do this.