|
|
  |
real time timer - прерывание по переполнению |
|
|
|
May 25 2010, 15:42
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
Не нашёл как установить обработчик прерывания по переполнению для таймера реального времени. Нужно ведь как-то так: Код AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, ???, m_interrupt_priority, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (void(*)())interrupt_handler); А я не знаю какой у него ID..
|
|
|
|
|
May 26 2010, 13:45
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
Столкнулся с такой проблемой. Я поставил делитель 3. Это примерно 10 тактов за мс. Если запрашивать показания таймера на больших временах (>10 ms), то всё правильно (разница тиков соответствует прошедшему времени). Но если запрашивать показания через ~1ms, то значения получаются одинаковыми. Почему так происходит, ведь таймер за 1мс должен протикать 10 раз? Причём, интересная особенность. Если сделать так: Код uint32_t x = AT91F_RTTReadValue(AT91C_BASE_RTTC); for (volatile uint32_t i = 0; i < 1000; i ++); x = AT91F_RTTReadValue(AT91C_BASE_RTTC) - x; то всё правильно. Если же вызывать AT91F_RTTReadValue(AT91C_BASE_RTTC) по таймеру, то разность получается 0.
Сообщение отредактировал srm - May 26 2010, 13:03
|
|
|
|
|
May 26 2010, 14:17
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
Локализовал проблему. Вот обработчик прерывания: Код static void interrupt_handler() { uint32_t mask = m_timer->TC_SR; m_instance->on_interrupt(mask); AT91C_BASE_AIC->AIC_EOICR = 0; }
inline bool on_interrupt(uint32_t mask) { if (mask & AT91C_TC_CPAS) on_event_a(); if (mask & AT91C_TC_CPBS) on_event_b(); if (mask & AT91C_TC_CPCS) on_overflow();
return (mask & (AT91C_TC_CPAS | AT91C_TC_CPCS | AT91C_TC_CPBS)) != 0; } Почему-то mask при каждом срабатывании содержит биты AT91C_TC_CPAS | AT91C_TC_CPBS (хотя значения регистров А = 0x2EED, B = 0x8CC9, C = 0xBBB6). Поэтому при каждом срабатывании вызываются оба метода: Код virtual void on_event_a() { m_time = CWatch::get_instance()->get_time_us(); }
virtual void on_event_b() { m_time = CWatch::get_instance()->get_time_us() - m_time; m_time ++; } почему регистр статуса не чистится? -------------------------------------------------- Что-то с форматом вызова.. если __irq static void interrupt_handler() - вроде, правильно, работает. Только почему-то через некоторое время после старта выполнение уходит в UndefinedHandler. Мой обработчик перестаёт вызываться. IRQ стек не переполнен...
Сообщение отредактировал srm - May 26 2010, 14:29
|
|
|
|
|
May 26 2010, 14:39
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(srm @ May 26 2010, 18:17)  Почему-то mask при каждом срабатывании содержит биты AT91C_TC_CPAS | AT91C_TC_CPBS (хотя значения регистров А = 0x2EED, B = 0x8CC9, C = 0xBBB6). Может, просто прерывание по CPA забыли разрешить? Цитата(srm @ May 26 2010, 18:17)  Что-то с форматом вызова.. если __irq static void interrupt_handler() - вроде, правильно, работает. Только почему-то через некоторое время после старта выполнение уходит в UndefinedHandler. Мой обработчик перестаёт вызываться. IRQ стек не переполнен... Как обрабатывается вектор прерывания в стартапе?
|
|
|
|
|
May 26 2010, 14:46
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
Цитата Может, просто прерывание по CPA забыли разрешить? нет, там всё норм. Цитата Как обрабатывается вектор прерывания в стартапе? там стандартный IAR'овский обработчик: Код irqHandler: /* Save interrupt context on the stack to allow nesting */ SUB lr, lr, #4 STMFD sp!, {lr} MRS lr, SPSR STMFD sp!, {r0, lr}
/* Write in the IVR to support Protect Mode */ LDR lr, =AT91C_BASE_AIC LDR r0, [r14, #AIC_IVR] STR lr, [r14, #AIC_IVR]
/* Branch to interrupt handler in Supervisor mode */ MSR CPSR_c, #ARM_MODE_SYS STMFD sp!, {r1-r3, r4, r12, lr} MOV lr, pc BX r0 LDMIA sp!, {r1-r3, r4, r12, lr} MSR CPSR_c, #ARM_MODE_IRQ | I_BIT
/* Acknowledge interrupt */ LDR lr, =AT91C_BASE_AIC STR lr, [r14, #AIC_EOICR]
/* Restore interrupt context and branch back to calling code */ LDMIA sp!, {r0, lr} MSR SPSR_cxsf, lr LDMIA sp!, {pc}^
Сообщение отредактировал srm - May 26 2010, 14:46
|
|
|
|
|
May 26 2010, 15:01
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
Цитата Раз так, то никаких __irq не нужно. Как и записи EOICR в вашем обработчике. запускаю на выполнение. ставлю бряк на обработчик прерывания: mask == 0x1001C, т.е. содержит все три флага: AT91C_TC_CPCS | AT91C_TC_CPAS | AT91C_TC_CPBS. если же сначала поставлю бряк и поймаю самое первое прерывание, то всё нормально: mask == 0x10008, т.е. содержит только флаг AT91C_TC_CPBS. magic
|
|
|
|
|
May 26 2010, 15:42
|
Частый гость
 
Группа: Участник
Сообщений: 144
Регистрация: 27-12-09
Из: Пермь
Пользователь №: 54 501

|
aaarrr, да, вроде, всё правильно.. может что-нибудь с режимом.. Код m_timer->TC_CMR = calculate_optimal_divider(max_time_ms) | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_WAVE | AT91C_TC_EEVT_XC0;
Сообщение отредактировал srm - May 26 2010, 15:42
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|