|
Таймер и прерывания, Хочу понять принцип работы |
|
|
|
Aug 15 2011, 12:21
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Среда разработки: Keil. Микроконтроллер: lpc2367. Есть таймер, генерирующий прерывания. Таймер работает по принципу "Отсчитал до нужного MR, прервался и остановился". Процедура, на которую он прыгает при прерывании переопределяемая. Код void InitTimer() { /* Initialize Timer 2 */ PCONP |= PCTIM2;
PCLKSEL1 &= ~(3 << PCLK_TIMER2_OFFSET); PCLKSEL1 |= (1 << PCLK_TIMER2_OFFSET); T2PR = 63; // 1 mks T2MR0 = 99; // 100 mks T2MCR = 7; // interupt, reset, stop
VICIntEnClr = INTTIM2; VICVectAddr26 = (unsigned long)Timer2Handler; VICVectPriority26 = 10;
T2TCR = 0x01;
VICIntEnable += INTTIM2; } Код __irq void Timer2Handler() { if (OnTimerInterupt) OnTimerInterupt(); T2IR = 0x01; VICVectAddr = 0; } Код typedef void (*CallBackFunction)(void); CallBackFunction OnTimerInterupt = 0; Допустим, я назначаю на прерывание функцию, которая выполняется около 1мс (пусть будет Func1). При прерывании в этой функции запускаю этот же таймер, переопределяя OnTimerInterupt на функцию с небольшим временем выполнения (пусть будет Func2), и настраиваю таймер на срабатывание через 100 мкс. Вопрос: как поведет себя выполняющаяся функция Func1, при следующем прерывании таймера (в котором вызовется Func2)?
|
|
|
|
|
Aug 16 2011, 07:28
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Сегодня дошло, что в первом сообщении глупость. В таком порядке прерывания явно не должны вызываться.
Пните пожалуйста в направлении хорошего объяснения механизма работы прерываний (возможно, вложеных). На форуме перечитал много, но общее впечатление от тем осталось в стиле "Я попрыгал с бубном и у меня получилось". Из даташита на процессор мало что понятно, слишком скупая информация.
UPD: Ну или можно пнуть в направлении книжки по проектированию систем на микропроцессорах.
Сообщение отредактировал whiteTigr - Aug 16 2011, 07:40
|
|
|
|
|
Aug 16 2011, 07:52
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(sergeeff @ Aug 16 2011, 11:46)  А что конкретно непонятно? IRQ0 _______/------- IRQ1 __/-------------- Первым пришло низкоприоритетное прерывание, уже во время этого прерывания приходит высокоприоритетное. Что происходит в этом случае? а) Прерывается выполнение IRQ1 и начинает выполняться IRQ0? б) Или сначала завершается обработка IRQ1 и только потом начинает выполняться IRQ0? Ну и хотелось бы увидеть общие рекомендации по проектированию систем прерываний. Что можно делать, чего категорически нельзя, как желательно? Понимаю, что рано или поздно дойду до этого, но не хотелось бы топтать поле с граблями.
|
|
|
|
|
Aug 16 2011, 09:50
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(sergeeff @ Aug 16 2011, 12:50)  Вы же ARM'ами заняты? Ухук. Цитата(sergeeff @ Aug 16 2011, 12:50)  Там всего два прерывания IRQ и FIQ. Зато есть VIC (vectored interrupt controller). Он обеспечивает обработку до 16 irq и одного fiq. В даташите информация о 32 и возможности работы нескольких FIQ (правда с оговоркой, что так лучше не делать и ограничиться одним). Или я что-то путаю... Цитата(sergeeff @ Aug 16 2011, 12:50)  Цитата(whiteTigr @ Aug 16 2011, 11:52)  IRQ0 _______/------- IRQ1 __/--------------
Первым пришло низкоприоритетное прерывание, уже во время этого прерывания приходит высокоприоритетное. Что происходит в этом случае? а) Прерывается выполнение IRQ1 и начинает выполняться IRQ0? б) Или сначала завершается обработка IRQ1 и только потом начинает выполняться IRQ0?
Сам VIC обеспечинает возможность приоритетной обработки прерываний. Дело в том, как вы напишите собственно обработчик. Он может обеспечивать вложенные прерывания, а может нет. При любом варианте если приходит несколько прерываний, выполняется первым более высокоприоритетное. Это если одновременно приходят? Одновременный приход видится идеальным случаем. В моей платке получалось что главный таймер с приоритетом 12 умудрялся тормозить прерывания с приоритетами 7 и 10. Насколько я понял по временам - задержка как раз равна задержке на обработку в главном таймере. Т.е. все происходило по варианту (б). Цитата(sergeeff @ Aug 16 2011, 12:50)  Цитата Non-vectored interrupts have the lowest priority. Vectored IRQ have middle priority. Возможно что-то с этим связано. Vectored - это объявленные через VICVectAddr[N]. Non-vectored - через VICDefVectAddr. Так?
|
|
|
|
|
Aug 16 2011, 10:26
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(sergeeff @ Aug 16 2011, 14:00)  Как-то я с VIC'ом не работал, только с AIC'ом. При невложенных прерываниях, пока не отработает текущий обработчик, следующий не вызывается. Посему все обработчики пишем как можно короче и шустрее. И в главном цикле while(1) анализируем выставленные флаги в прерываниях... Мне вот сказано, что я должен ответить по RS485 через 200мкс после окончания посылки ко мне. Т.е. делается прерывание на прием байта, по последнему байту пакета запускается таймер на 200мкс, по прерыванию от него посылается ответ. Прерывание на прием набивает байты в пакет сразу же (нужно же определять конец пакета) - уже не сильно короткая получается, но и вынести из прерывания, по-моему, не получится. Прерывание по таймеру должно затолкать подготовленный для отправки пакет в выходной буфер. И получается что прерывание главного таймера (громко сказано "главного", приоритет у него наименьший) на обработку кнопок и дисплея мешает нормальной работе системы. Вот при сокращении главного таймера до Counter++ (и анализа Counter'a в while(1)) все заработало нормально. Хотя, мне кажется, что вложеные прерывания выглядят тут абсолютно нормальным решением, когда низкоприоритетное прерывание не будет мешать обработке высокоприоритетных событий. P.S.: чувствую, что задаю настолько глупые вопросы, что стыдно становится.
Сообщение отредактировал whiteTigr - Aug 16 2011, 10:37
|
|
|
|
|
Aug 16 2011, 11:40
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(whiteTigr @ Aug 16 2011, 13:26)  И в главном цикле while(1) анализируем выставленные флаги в прерываниях... Мне вот сказано, что я должен ответить по RS485 через 200мкс после окончания посылки ко мне. Т.е. делается прерывание на прием байта, по последнему байту пакета запускается таймер на 200мкс, по прерыванию от него посылается ответ. Ну и на кой выжидать 200 мкс после последнего байта, если у вас и так полно всякой работы? Кстати, у вас процессор на нормальной частоте работает? Какие-нибудь benchmark тесты не пробовали? А про вложенные прерывания. Возьмите и попробуйте, примеров достаточно, как правильно организовать. На сайте, правда, полно критиков вложенных прерываний, но у вас же есть своя голова на плечах.
|
|
|
|
|
Aug 16 2011, 11:49
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(sergeeff @ Aug 16 2011, 15:40)  Ну и на кой выжидать 200 мкс после последнего байта, если у вас и так полно всякой работы? Кстати, у вас процессор на нормальной частоте работает? Какие-нибудь benchmark тесты не пробовали? 200мкс по ТЗ указано. Идея была в том, что я запускаю таймер, по прерыванию которого отправлю подготовленную посылку. Ожидание, естественно не через "for (i = 0; i < ...; i++);" сделано. Резонатор стоит на 16МГц. Судя по настройкам uart'a эта частота умножается на 4 где-то внутри. Benchmark'и не пробовал (только сейчас узнал о них). Цитата(sergeeff @ Aug 16 2011, 15:40)  А про вложенные прерывания. Возьмите и попробуйте, примеров достаточно, как правильно организовать. На сайте, правда, полно критиков вложенных прерываний, но у вас же есть своя голова на плечах. Хорошо, попробую поискать. По этому форуму я уже предостаточно предостережений нашел. Чувствую, что не с пустого места такое возникает, и моё желание использовать вложеность - это мысли новичка, которые я должен искоренить.
|
|
|
|
|
Aug 17 2011, 05:04
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(toweroff @ Aug 16 2011, 20:22)  ойой может, флаг выставляете? по которому в основном теле что-то отправляется? Код void StartResponseTimer() { StopTimer(); T2TC = 0; T2MR0 = 199; // 200 mks OnTimerInterupt = &OnResponse; StartTimer(); }
void OnResponse() { int i; for (i = 0; i < OutBufP; i++) { RS485SendByte(OutBuf[i]); } }
...
void RS485SendByte(char byte) { TBuffer *buffer = &RS485.transmiteBuffer;
(*buffer).data[(*buffer).addrWrite] = byte; (*buffer).addrWrite = ((*buffer).addrWrite + 1) % BufferSize; (*buffer).count++;
// Если ничего не отправляется, то инициируем отправку // Иначе байт отправится после отправки предыдущего if (DE_PIN() == 0) { RS485SendByte_lowlevel(); } } Сильно криво? В SendByte никаких ожиданий, просто заталкивание посылки в выходной буфер. UPD: Код (*buffer).addrWrite = ((*buffer).addrWrite + 1) % BufferSize; После поста на форум эта строчка начала "резать глаз". Переписал в виде: Код buffer->addrWrite++; if (buffer->addrWrite >= BufferSize) buffer->addrWrite = 0;
Сообщение отредактировал whiteTigr - Aug 17 2011, 05:05
|
|
|
|
|
Aug 17 2011, 06:28
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Тогда уж напишите: Код if (++buffer->addrWrite == BufferSize) buffer->addrWrite = 0; Код buffer->addrWrite > BufferSize никогда не бывает
|
|
|
|
|
Aug 17 2011, 07:09
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407

|
Цитата(sergeeff @ Aug 17 2011, 10:28)  Тогда уж напишите: Код if (++buffer->addrWrite == BufferSize) buffer->addrWrite = 0; Код buffer->addrWrite > BufferSize никогда не бывает Недолюбливаю сравнивать через "==". Хотя тут можно и так. Несколько раз уже натыкался на то, что граница вначале константа, потом, в определенный момент, превращается в переменную и все сравнения через "==" приводят к зависанию программы. P.S.: посмотрел на генерируемый код, вернул первый вариант. При размере BufferSize равного степени двойки он генерирует add r0, r0, #1 and r0, r0, <mask>
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|