STM32F4 один главный таймер запускает два ведомых времени - PullRequest
1 голос
/ 23 апреля 2019

Я немного застрял в синхронизации таймера с STM32F446RE.

Я хочу использовать 1 таймер в качестве главного и два таймера в качестве ведомых.Главный таймер (то есть TIM2) имеет период 5 секунд и запускает два других таймера одновременно.

У подчиненных таймеров есть свои периоды (у 1-го ведомого есть период 4 секунды, а у 2-го ведомогопериод максимум 3 секунды).Второй подчиненный таймер (т. Е. TIM1) будет генерировать одноимпульсный выход.Оба раба должны бежать 1 раз и останавливаться.Они должны активироваться снова, только если главный таймер посылает триггерЯ хочу использовать 1. ведомое устройство, чтобы адаптировать период второго подчиненного устройства, вызывая обработчик прерываний, в котором я записываю регистры ARR и PSC и CCR1 (для одного импульса).

Я пытался сделать это с HALно это становится все более запутанным.У кого-нибудь есть хорошая идея, как кодировать это (маленький фрагмент кода был бы очень хорош) с записью регистров вместо HAL?

Я также взглянул на поваренную книгу по таймеру STM в главе 6, но не сделал 'пока не получилось.https://www.st.com/content/ccc/resource/technical/document/application_note/group0/91/01/84/3f/7c/67/41/3f/DM00236305/files/DM00236305.pdf/jcr:content/translations/en.DM00236305.pdf

Большое спасибо за любые отзывы!

С уважением, Тоби

1 Ответ

0 голосов
/ 25 апреля 2019

ОК, первая часть выполнена.

Конфигурация TIM2: - настроить как мастер с периодом 10 секунд.- использовать TIM_TRGO_UPDATE в качестве выходного триггера для подчиненного таймера (ов).

Сначала я создал таймер с помощью STM32CubeMX, а затем исследовал вызываемые HAL-функции.

static void Timer2_Init(){
    /* activate clock for TIM2 peripheral */
    __HAL_RCC_TIM2_CLK_ENABLE();
    /* Prescaler */
    TIM2->PSC = 44999; // bus is running with 90MHz
    /* set counter mode */
    TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
    TIM2->CR1 |= TIM_COUNTERMODE_UP;
    /* Auto-Reload Register */
    TIM2->ARR = 20000;
    /* Set Clock Division */
    TIM2->CR1 &= ~ TIM_CR1_CKD;
    TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;

    /* set Auto-Reload-Preload */
    //TIM2->CR1 |= (0 << 7);
    /* Update Event - if this timer is configured as Master with output TRGO_UPDATE
     * the slave timer TIM 1 will get a trigger and run one time
     *
     * This bit can be set by software, it is automatically cleared by hardware.
     * 0: No action
     * 1: Reinitialize the counter and generates an update of the registers. Note that the prescaler
     * counter is cleared too (anyway the prescaler ratio is not affected). For more see manual. */
    //TIM2->EGR = TIM_EGR_UG;

    /* Set Clock Source */
    TIM2->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);

    /* Master Configuration */
    TIM2->CR2 &= ~TIM_CR2_MMS;
    TIM2->CR2 |= TIM_TRGO_UPDATE;
    TIM2->SMCR &= ~TIM_SMCR_MSM;
    TIM2->SMCR |= TIM_SMCR_MSM;

    TIM2->CR1 = TIM_CR1_CEN;
}

Затем инициализацияTIM1: - настроить как мастер.- установите ARR на 5 секунд.- установить CCR1 для длительности импульса 1 секунда.

Снова я сначала использовал STM32CubeMX для создания кода, а затем проверил содержимое всех функций HAL.

static void Timer1_Init(){
    /* activate clock for TIM1 peripheral */
    __HAL_RCC_TIM1_CLK_ENABLE();
    /* Edited Registers of HAL_TIM_Base_Init(&htim1) */
    /* Prescaler */
    TIM1->PSC = 17999; // bus is running with 180MHz
    /* set counter mode */
    TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS); 
    TIM1->CR1 |= TIM_COUNTERMODE_UP; 
    /* Auto-Reload-Register */
    TIM1->ARR = 49999; 
    TIM1->CR1 &= ~ TIM_CR1_CKD; 
    TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1; 
    /* repetition counter if pulse should be displayed more than 1 time */
    TIM1->RCR = 0; 
    /* Auto-Reload Preload Enable */
    //TIM1->CR1 |=TIM_CR1_ARPE;
    /* update event */
    TIM1->EGR = TIM_EGR_UG; 


    /* Edited registers of HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) */
    TIM1->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);


    /* One Pulse Mode: Edited registers of HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) */
    //TIM1->CR1 &= ~TIM_CR1_OPM;
    TIM1->CR1 |= TIM_CR1_OPM; 


    /* Slave Mode configuration: edited registers of HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) */
    TIM1->SMCR &= ~TIM_SMCR_TS; 
    TIM1->SMCR |= TIM_TS_ITR1; 
    TIM1->SMCR &= ~TIM_SMCR_SMS; 
    TIM1->SMCR |= (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1); // = TIM_SLAVEMODE_TRIGGER -

//  TIM1->DIER &= ~TIM_DIER_TIE;
//  TIM1->DIER &= ~TIM_DIER_TDE;


    /* HAL_TIM_PWM_ConfigChannel: HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) */
    /* Disable the Channel 1: Reset the CC1E Bit */
//  TIM1->CCER &= ~TIM_CCER_CC1E;
    /* Reset the Output Compare Mode Bits */
    TIM1->CCMR1 &= ~TIM_CCMR1_OC1M; 
    TIM1->CCMR1 &= ~TIM_CCMR1_CC1S; 
    /* Select the Output Compare (OC) Mode 1 */
    TIM1->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1); // = TIM_OCMODE_PWM1 
    /* Reset and set the Output N Polarity level to LOW */
    TIM1->CCER &= ~TIM_CCER_CC1P; 
    TIM1->CCER |= TIM_CCER_CC1P; // = TIM_OCPOLARITY_LOW 
    /* Reset the Output N State */
//  TIM1->CCER &= ~TIM_CCER_CC1NP;
    //TIM1->CCER |= 0x00000000U;
    /* Reset the Output N State */
//  TIM1->CCER &= ~TIM_CCER_CC1NE;
    /* IS_TIM_BREAK_INSTANCE */
    /* Reset the Output Compare and Output Compare N IDLE State */
//  TIM1->CR2 &= ~TIM_CR2_OIS1;
//  TIM1->CR2 &= ~TIM_CR2_OIS1N;
    /* Set the Output Idle state */
    //TIM1->CR2 |= 0x00000000U;
    /* Set the Capture Compare Register: Pulse */
    TIM1->CCR1 = 40000; 
    /* Set the Preload enable bit for channel 1 */
    TIM1->CCMR1 |= TIM_CCMR1_OC1PE; 
    /*  Configure the Output Fast mode */
//  TIM1->CCMR1 &= ~TIM_CCMR1_OC1FE;
    //TIM1->CCMR1 |= 0x00000000U;

    /* Edited registers by HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) */
    /* Enable the Capture compare channel */
    TIM1->CCER |= (1 << 0); // = TIM_CCER_CC1E 
    /* Enable the main output */
    TIM1->BDTR |= TIM_BDTR_MOE; 

    /* Initialize the GPIO Pin for output: HAL_TIM_MspPostInit(&htim1) */
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* Enable Counter: will be automatically enabled with trigger event */
    //TIM1->CR1 = TIM_CR1_CEN; 
}

Следующим шагом является настройкавторой подчиненный таймер (TIM3), который будет редактировать регистры TIM1.

static void Timer3_Init(){
    /* activate clock for TIM1 peripheral */
    __HAL_RCC_TIM3_CLK_ENABLE();
    /* Edited Registers of HAL_TIM_Base_Init(&htim1) */
    /* Prescaler */
    TIM3->PSC = 50000; //44999;
    /* set counter mode */
    TIM3->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
    TIM3->CR1 |= TIM_COUNTERMODE_UP;
    /* Auto-Reload-Register */
    TIM3->ARR = 11000;
    TIM3->CR1 &= ~ TIM_CR1_CKD;
    TIM3->CR1 |= TIM_CLOCKDIVISION_DIV1;
    /* update event */
    TIM3->EGR = TIM_EGR_UG;

    /* Edited registers of HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) */
    TIM3->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);

    /* One Pulse Mode: Edited registers of HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) */
    //TIM1->CR1 &= ~TIM_CR1_OPM;
    TIM3->CR1 |= TIM_CR1_OPM;

    /* Slave Mode configuration: edited registers of HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) */
    TIM3->SMCR &= ~TIM_SMCR_TS;
    TIM3->SMCR |= TIM_TS_ITR1;
    TIM3->SMCR &= ~TIM_SMCR_SMS;
    TIM3->SMCR |= (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1); // = TIM_SLAVEMODE_TRIGGER

    /* HAL_TIM_PWM_ConfigChannel: HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) */
    /* Disable the Channel 1: Reset the CC1E Bit */
    /* Reset the Output Compare Mode Bits */
    TIM3->CCMR1 &= ~TIM_CCMR1_OC1M;
    TIM3->CCMR1 &= ~TIM_CCMR1_CC1S;
    /* Select the Output Compare (OC) Mode 1 */
    TIM3->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1); // = TIM_OCMODE_PWM1
    /* Reset and set the Output N Polarity level to HIGH */
    TIM3->CCER &= ~TIM_CCER_CC1P; // = TIM_OCPOLARITY_HIGH
    /* Set the Capture Compare Register: Pulse */
    TIM3->CCR1 = 0;
    /* Set the Preload enable bit for channel 1 */
    //TIM3->CCMR1 |= TIM_CCMR1_OC1PE;

    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
    TIM3->DIER = TIM_DIER_CC1IE; //DMA Interrupt Enable Register (DIER): Interrupt "Capture/Compare 1 interrupt enable"

    /* warning: setting this bit will cause the timer running continuously, but timer should only start with trigger,
     * so don't set the CEN bit - let the trigger do the job automatically */
    //TIM3->CR1 = TIM_CR1_CEN;
}

И, наконец, обработчик IRQ для TIM3:

void TIM3_IRQHandler(void)
{
    if (((TIM3->SR & TIM_FLAG_CC1) == TIM_FLAG_CC1) != RESET)
    {
        if (((TIM3->DIER & TIM_DIER_CC1IE) == TIM_DIER_CC1IE) != RESET)
        {
            TIM3->SR = ~ TIM_FLAG_CC1;
            /* do something *
        }
    }
}

Я рад любым отзывам об этом коде.

Я только что заметил, что внутренний RC-генератор не очень точен в моей тестовой среде.В руководстве DM00135183.pdf в разделе «6.2.2 HSI Clock» вы можете прочитать о точности и способах подстройки HSI.Но я думаю, что может быть лучше использовать внешний кварцевый генератор или керамический резонатор, если вы хотите более точную синхронизацию.

Если есть что-то, что я сделал неправильно или то, что я хочу сделать, не будет работать ожидаемым образом,Пожалуйста, также оставьте комментарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...