1

I need to generate a pulse burst train. In each burst, there are 120 pulse with pulse width of 1us. And in between the bursts, there is a interphase width in 130us.

I set TIM1 as 1MHz PWM with Duty cycle 50% for 120 pulses burst. Then set 1Mhz PWM with Duty cycle 0% for low voltage interphase width.

When I set the 1MHz PWM, the oscilloscope measures the wrong diagram. The pulse bursts are 360us with pulse width 1us and interphase width 390 us. enter image description here

When I set 1 kHz, the program works fine. I guess that in the TIMx callback function, the operators need more time than 1us. If like that, I couldn't improve it. Could anyone help to support this debugging or give me another solution?

The following is my MCU setup of ST MCU BLUENRG-LP with system clock frequency of 64 MHz. The following is the setup of Prescaler 3 and Period 15.

/* - Set the pre-scaler value to have TIMx counter clock equal to 16 MHz  */
/* - Set the auto-reload value to have a counter frequency of 1M Hz        */
timxPrescaler = __LL_TIM_CALC_PSC(LL_TIM_GetPeriphClock(TIMx), 16000000);
timxPeriod = __LL_TIM_CALC_ARR(LL_TIM_GetPeriphClock(TIMx), timxPrescaler, 1000000); 

The following is my TIM1 OC PWM settup in STM LL driver.

static void MX_TIMx_Init(void)

{

    LL_TIM_InitTypeDef TIM_InitStruct = {0};
    LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
    LL_GPIO_InitTypeDef GPIO_InitStruct;

    /* Peripheral clock enable */
    LL_EnableClock_TIMx();
    LL_EnableClock_TIMx_CH1();

    GPIO_InitStruct.Pin = TIMx_CH1_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = TIMx_CH1_AF;
    LL_GPIO_Init(TIMx_CH1_PORT, &GPIO_InitStruct);

    /* TIMx interrupt Init */
    NVIC_SetPriority(TIMx_IRQn, IRQ_MED_PRIORITY);
    NVIC_EnableIRQ(TIMx_IRQn);

    TIM_InitStruct.Prescaler = timxPrescaler;
    TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
    TIM_InitStruct.Autoreload = timxPeriod;
    TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
    TIM_InitStruct.RepetitionCounter = 0;
    LL_TIM_Init(TIMx, &TIM_InitStruct);
    LL_TIM_EnableARRPreload(TIMx);
    LL_TIM_OC_EnablePreload(TIMx, LL_TIM_CHANNEL_CH1);
    TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
    TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
    TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
    TIM_OC_InitStruct.CompareValue = ((timxPeriod + 1 ) / 2);
    TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;  
    TIM_OC_InitStruct.OCNPolarity = LL_TIM_OCPOLARITY_HIGH;
    TIM_OC_InitStruct.OCIdleState = LL_TIM_OCIDLESTATE_HIGH;
    TIM_OC_InitStruct.OCNIdleState = LL_TIM_OCIDLESTATE_LOW;
    LL_TIM_OC_Init(TIMx, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
    LL_TIM_OC_DisableFast(TIMx, LL_TIM_CHANNEL_CH1);
}

The TIMx callback is as follows:

/**
  * @brief  Timer capture/compare interrupt processing
  * @param  None
  * @retval None
  */
void TimerCaptureCompare_Callback(void)
{
    uint32_t CNT, ARR;
    CNT = LL_TIM_GetCounter(TIMx);
    ARR = LL_TIM_GetAutoReload(TIMx);

    if (LL_TIM_OC_GetCompareCH1(TIMx) > ARR )
    {
        /* If capture/compare setting is greater than autoreload, there is a counter overflow and counter restarts from 0.
    Need to add full period to counter value (ARR+1)  */
        CNT = CNT + ARR + 1;
    }
    pulse_count = pulse_count - 1;
    if(pulse_count == 0)
    {
        if(isPulseOn)
        {
            // When pulse burst done, set dutycycle 0%
            LL_TIM_OC_SetCompareCH1(TIMx, 0);
            isPulseOn = FALSE;
            status = INTER;
            pulse_count = pulseInfo.interPhaseWidth;
        }
        else
        {
            // Set duty cycle 50% and start pulse burst again.
            LL_TIM_OC_SetCompareCH1(TIMx, 8);

            isPulseOn = TRUE;
            stm_stim_status = STIMULATION_PULSE;
            pulse_count = pulseInfo.pulseWidth;
            // Burst counts
            burst_count = burst_count-1;
            if( burst_count == 0)
            {
                burst_count = pulseInfo.burst_amount;
                status = IDLE;
                MX_TIMx_PWM_Disable();                      // disable PWM
                MX_GPIO_SetLow();                           // GPIO set low
            }
        }
    }
    uwMeasuredDutyCycle = (CNT * 100) / ( ARR + 1 );
}

In main loop, the state machine is like this.

void RunDriver(void)
{
    switch(status)
    {
        case INIT:
            pulse_count = pulseInfo.pulseWidth;
            burst_count = pulseInfo.burst_amount;
            // Enable PWM: 1MHz
            MX_TIMx_Init();
            MX_TIMx_PWM_Enable();
            status = PULSE;
            break;
        case PULSE:
            // PWM for 50% duty cycle
            break;
        case INTER: 
            // PWM for 0% duty cycle
            break;
        case IDLE:
        default:
            driver_count = driver_count+1;
            driver_count_time = driver_count * pulseInfo.burst_amount * (pulseInfo.pulseWidth+pulseInfo.interPhaseWidth)*2;
            if(driver_count_time >= driver_total)
            {
                
                main_status = STM_IDLE;
                driver_count = 0;
                driver_count_time = 0;
            }
            else
            {
                status = INIT;
                LL_uDelay(pulseInfo.pulsePeriod / 2, 64); 
            }
            break;
        }   
    }
}
toolic
  • 5,637
  • 5
  • 20
  • 33
Penergy
  • 21
  • 4

0 Answers0