Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: delay in 10-100mks on SAM7
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
tokauchusya
Люди добрые помогите разобраться с TimerTC от SAM7.
Мне нежно реализовать на TimerTC задержку от 10-100 микросекунд, а я не пойму как там выставляются задержки. Объясните пожалуйста.

Код
void timer0_isr (void)
{
  ***
  // мигнуть диодом
}

char InitTimer()
{  
  AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;// Enable Clock for TIM0
  AT91C_BASE_TC0->TC_CCR    = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
  AT91C_BASE_TC0->TC_CMR    = 2 | AT91C_TC_CPCTRG;
  AT91C_BASE_TC0->TC_RC     = 0x0E; // ??

  // TIM0 Interrupt: Mode and Vector with Lowest Priority and Enable
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_HIGHEST;
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned long) timer0_isr;
  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0);
  AT91C_BASE_TC0->TC_IER    = AT91C_TC_CPCS;

  return 1;
}


Здесь я пытаюсь получить 10 микросекунд, но это на самом деле не так. Что именно не так объясните. Как высчитывается коэффициент?
aaarrr
Цитата(tokauchusya @ Jun 24 2009, 01:54) *
Здесь я пытаюсь получить 10 микросекунд, но это на самом деле не так. Что именно не так объясните. Как высчитывается коэффициент?

Да все не так почти sad.gif

Код
char InitTimer()
{  
  AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;// Enable Clock for TIM0
  AT91C_BASE_TC0->TC_CCR    = AT91C_TC_CLKEN | AT91C_TC_SWTRG;  // Зачем-то сразу запустили таймер. Это нужно делать в самом конце.
  AT91C_BASE_TC0->TC_CMR    = 2 | AT91C_TC_CPCTRG;  // С такими настройками будете получать прерывание каждые 10мкс.
  // Для однократной задержки логично использовать режим Wave и поставить бит CPCSTOP
  AT91C_BASE_TC0->TC_RC     = 0x0E; // ??

  // TIM0 Interrupt: Mode and Vector with Lowest Priority and Enable
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | AT91C_AIC_PRIOR_HIGHEST;  // Зачем прерывание по фронту?
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned long) timer0_isr;
  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0);
  AT91C_BASE_TC0->TC_IER    = AT91C_TC_CPCS;

  return 1;
}
tokauchusya
Вы так и не обьяснили, как имея рабочую частоту MCK 48 Мгц, получить определенную задержку ? По какой формуле это считаеться?
dimka76
Цитата(tokauchusya @ Jun 24 2009, 12:09) *
Вы так и не обьяснили, как имея рабочую частоту MCK 48 Мгц, получить определенную задержку ? По какой формуле это считаеться?


T1 = 1/(Fcpu/(коэффициент деления предделителя)) время изменения содержимого таймера на единицу
delay = T1*(0xFFFF - K) если прерывание по переполнению таймера, отсюда
K = 0xFFFF - (delay/T1)

delay - требуемая задержка
К - кол-во тиков таймера ( c этого значения таймер должен стартовать)

если прерывание по совпадению, то

K = delay/T1 значение регистра совпадения
начальное значение таймера = 0
tokauchusya
огромное спасибо
piz2383
Вот код:
Подскажите, а то что-то туплюююю Вот код:

Код
volatile unsigned char doo = 0;

__arm void tim0isr (void)
{
  
  doo = 1;  

  AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_TC0->TC_SR;
  AT91C_BASE_AIC->AIC_IVR        = 0;
  AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_TC0;    
  AT91C_BASE_AIC->AIC_EOICR   = 0;
  AT91C_BASE_TC0->TC_IDR = AT91C_TC_CPCS;
}

char InitTimer()
{
  AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0;// Enable Clock for TIM0
  
  // TIM0 Interrupt: Mode and Vector with Lowest Priority and Enable
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_PRIOR_HIGHEST;
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned long) tim0isrEntry;
  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0);

  AT91C_BASE_TC0->TC_CMR    = TC_CLKS_MCK32 | AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_CPCSTOP;  

  return 1;
}

void DELAY_MK(unsigned short coef)
{  
  unsigned int delay = ((coef*22)/15);  

  AT91C_BASE_TC0->TC_RC     = delay;
  
  AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
  
  doo = 0;

AT91C_BASE_TC0->TC_CCR    = AT91C_TC_CLKEN | AT91C_TC_SWTRG;  
  
  while(!doo)
   ;
}


Когда я выполняю:
Код
DELAY_MK(3000);
DELAY_MK(4000);
DELAY_MK(5000);
DELAY_MK(6000);
DELAY_MK(2000);
DELAY_MK(10000);
DELAY_MK(17000);

То это занимает 46 милисекунд, все правильно

А если выполняю:
Код
for(int i =0; i < 20000; i++)
      DELAY_MK(6);


То вместо 120 милисекнд, этот код выполняеться чуть более 300 милисекунд.

Вопрос, в чем и где я ошибился? Просто мне нужно гарантированно добиться задержки в 6 микросекунд.



И встречный вопрос. Никто не поделиться кодом, который делает задежку в микросекундах без таймеров, а так просто с помощью нупов или циклом для частоты 48 Мгц???

Заранее всем спасмбо.
aaarrr
Цитата(piz2383 @ Jul 29 2009, 19:16) *
Вопрос, в чем и где я ошибился? Просто мне нужно гарантированно добиться задержки в 6 микросекунд.

Во-первых, Вы добавляете накладные расходы на организацию цикла и вызов подпрограммы (если, конечно, она не заинлайнена). Это немного, но все же.
Второе и главное - сколько, по-вашему, будет выполняться такой код:
Код
  unsigned int delay = ((coef*22)/15);

Аппаратного делителя на борту нет, вот и вылезает дикое время.

Цитата(piz2383 @ Jul 29 2009, 19:16) *
И встречный вопрос. Никто не поделиться кодом, который делает задежку в микросекундах без таймеров, а так просто с помощью нупов или циклом для частоты 48 Мгц???

Получается что-то вроде:
Код
volatile unsigned int x = us * 12;

while(--x);

Умножение, естественно, лучше исключить, т.е. подсчитать значение x заранее.
И результат компиляции все равно надо проверять дизассемблированием.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.