Почему я не могу использовать Systick и Timer1 одновременно

Я использую таймер Systick для создания задержки, обработчик systick происходит один раз в микросекунду (1 мкс).

Кроме того, я использую TIM1, его обработчик происходит раз в секунду (1 с). Внутри обработчика timer1 я переключаю светодиод.

В основной функции внутри цикла while я переключаю другой светодиод (другой, чем в обработчике timer1), функция задержки здесь использует Systick.

Обработчик timer1 выполняется, как и ожидалось, но проблема в том, что цикл while в основной функции никогда не выполняется.

Любая помощь?

volatile uint32_t i=0;

void TIM1_UP_TIM10_IRQHandler(void)
{
    NVIC_ClearPendingIRQ(TIM1_UP_TIM10_IRQn);   
    i ^= 1;
    if(i == 1)
        LED_On(0);
    else
        LED_Off(0);
    TIM1->SR &= ~(1 << 0); 
}

int main(void)
{
    NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 32);
    NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

    LED_Initialize();
    RCC->APB2ENR |= (1 << 0); // Enable Timer1 clock

    TIM1->CR1 &= ~(1 << 4);  // Set the direction of timer to be upcounter
    TIM1->DIER |= (1 << 0);  // Enable tim1 interrupt request

    TIM1->PSC = 15999;  // each count takes 1 msec 
    TIM1->ARR = 1000;   //each 1 sec an overflow update event occurs
    TIM1->CR1 |= (1 << 0);

    SysTick_Init(16000000/1000000);

    while(1)
    {       
        LED_On(1);
        Delay_MS(5000);
        LED_Off(1);
        Delay_MS(5000);
    }

    return 0;
}

person محمد المغربى    schedule 26.05.2020    source источник
comment
вы правильно возвращаетесь из прерывания? вы, безусловно, можете использовать systick и tim1 (если в вашей системе есть systick (и tim1) вместе.   -  person old_timer    schedule 27.05.2020
comment
Какая частота у вашего УК? Вы должны попробовать SysTick_Init(16000000/1000); для 16000 МГц. Кроме того, с вашим таймером PSC = 16000 и ARR = 1000 у меня есть счет каждые 1 секунду.   -  person YvonBlais    schedule 27.05.2020
comment
Вы не предоставляете свой обработчик SYSTICK или функцию Delay_MS(). Это как-то критично.   -  person Clifford    schedule 27.05.2020


Ответы (3)


  1. если ваши часы 16 МГц, и вы хотите, чтобы прерывания происходили каждые 16 часов, теперь это будет работать. В лучшем сценарии остановки (выполнение кода из ОЗУ и т. д.) вам нужно как минимум 11 тактов для входа в обработчик прерываний и 6 тактов для выхода из него, что больше, чем время между прерываниями.

  2. Иметь прерывания каждый раз — плохая идея, даже если вы бежите быстрее. Устройство с частотой 168 МГц будет иметь только 168 тактов между прерываниями. Допустим, ваш обработчик будет работать 20 тактов + 11 + 6 = ~40 тактов. Это означает, что 25% процессорного времени будет использовано для увеличения переменной!!! Не делай этого. На многих других (max clock 72 или 80MHz) будет еще хуже.

  3. Если вам нужна задержка в США, сделайте что-то вроде этого (если вы перезагружаете счетчик, вам нужно принять это во внимание). Код предназначен только для демонстрации идеи

#define TICKSPER_uS 80

void delay_us(uint32_t uS)
{
    uint32_t endCnt = SysTick -> VAL + uS * TICKSPER_uS;
    while(SysTick -> VAL < endCNT);
}   
person 0___________    schedule 27.05.2020

Одна микросекунда — это неоправданно быстро для прерывания SYSTICK, особенно если оно работает на частоте всего 16 МГц. Вполне вероятно, что ваша система тратит почти 100% своего времени на подсчет тактов обработчика прерываний.

Даже если он может поддерживать частоту прерывания 1 МГц, если Delay_MS(5000) - это задержка в 5000 периодов SYSTICK, тогда вы будете переключать светодиод и 100 Гц и не будете воспринимать мигание, просто приглушите освещение.

Скорее всего, вы имели в виду одну миллисекунду, что является более разумным интервалом тактов:

SysTick_Init( 16000000 / 1000 ) ;

Хотя я бы предложил на самом деле:

SysTick_Init( SystemCoreClock / 1000 ) ;

чтобы ваш код адаптировался к изменениям тактовой частоты, поскольку 16 МГц — это довольно скромная частота для запуска STM32.

В любом случае также возможно, что ваш обработчик SYSTICK и Delay_MS() реализации неисправны, но невозможно догадаться, не видя этого кода. Если обеим предоставлен библиотечный код, то это менее вероятно.

person Clifford    schedule 27.05.2020

Это моя функция задержки для использования

//==============================================================================
static  uint32_t    timeMicroSecDivider = 0;
extern  uint32_t    uwTick;

//==============================================================================
//  The SysTick->LOAD match the uC Speed / 1000.
//  If the uC clock is 80MHz, the the LOAD is 80000
//  The SysTick->VAL is the decrement counter from (LOAD-1) to 0
//==============================================================================
uint64_t getTimeMicroSec()
{
  if ( timeMicroSecDivider == 0)
  {
    //  Number of clock by micro second
    timeMicroSecDivider = SysTick->LOAD  / 1000;
  }
  return( (uwTick * 1000) + ((SysTick->LOAD - SysTick->VAL) / timeMicroSecDivider));
}

//==============================================================================
void delayTimeMicroSec(uint32_t delay)
{
  uint64_t tickstart = getTimeMicroSec();

  while ((getTimeMicroSec() - tickstart) < delay)
    ;
}
person YvonBlais    schedule 27.05.2020