Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как можно быстро обращаться к регистрам таймера из прерывания?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Bulat
По прерыванию от порта данные записываются в сдвиговый регистр. Прерывания возможны от 4 различных выводов во всевозможных комбинациях. Обработчик помимо записи в сдвиговый буфер и сдвига должен каждый раз запускать таймер, который контролирует паузу между битами поступаемыми на порт контроллера. Ниже приведен код:
Код
const AT91PS_TC    PauseTimerBase1 =AT91C_BASE_TC1;
const AT91S_PAUSE_TIMER1 PauseTimer1 = { AT91C_ID_TC1,0,240,480,960,1920,3840,TC_CLKS_MCK8};

const AT91PS_TC    PauseTimerBase2 =AT91C_BASE_TC2;
const AT91S_PAUSE_TIMER2 PauseTimer2 = { AT91C_ID_TC2,0,240,480,960,1920,3840,TC_CLKS_MCK8};

__ramfunc void irq_Receive()
{  
  unsigned int dummy;
  unsigned int source;                                                          //источник прерываний
  
  source = regs->PIOA_PDSR&0x780;                                               //определяем источник прерываний
  
    
    if(source==0x200) {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA|0x80000000;} //A1

    if(source==0x400) {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA&0x7FFFFFFF;}  //B1
  
    if(source==0x80)  {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB|0x80000000;} //A2

    if(source==0x100) {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB&0x7FFFFFFF;}  //B2
  
    if(source==0x280) {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB|0x80000000;} //A1,A2

    if(source==0x500) {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA&0x7FFFFFFF; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB&0x7FFFFFFF;}  //B1,B2
  
    if(source==0x300) {PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA|0x80000000; PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB&0x7FFFFFFF;} //A1,B2

    if(source==0x480) {PauseTimerBase2->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase2->TC_CCR = AT91C_TC_SWTRG; recB = recB>>1;  i_shB++; recB = recB|0x80000000; PauseTimerBase1->TC_CCR = AT91C_TC_CLKEN; PauseTimerBase1->TC_CCR = AT91C_TC_SWTRG; recA = recA>>1;  i_shA++; recA = recA&0x7FFFFFFF;}  //A2,B1
  
  
  dummy = AT91C_BASE_PIOA->PIO_ISR;
    
}

То есть, в обработчике учитываются 8 различных комбинаций, которые могут возникнуть на выводах порта с учетом маски. В каждом случае необходимо запускать и сбрасывать таймер паузы или же 2 таймера паузы для 1 и 2 каналов, в зависимости от комбинации на порту контроллера. Если данные на порт контроллера перестанут поступать, сработает таймер паузы и данные recA и recB перепишутся в буфер. Код работает, но недостаточно быстро. Контроллер не успевает принять все данные. Данные поступают в виде 32-битных слов со скоростью 100кГц, пауза между словами 40мкс.
Можно ли как то оптимизировать этот обработчик (оптимизатор IAR включен на максимум по скорости, inline threshold=16)? Есть ли возможность обращаться к регистрам таймера напрямую? Можно ли в качестве сдвигового регистра (recA,recB) назначить один из 15 основных регистров процессора, чтобы обращаться напрямую к регистру и операции сдвига осуществлять с помощью одной строки асм-вставки? Как еще можно ускорить работу обработчика?
Заранее благодарен!
baralgin
Эээ.. Тут вроде явно напрашивается switch вместо 8 if'ов. Не понятно что такое recA и recB. Если вы хотите чтобы компилятор их размещал в регистрах, то скопируйте их в локальные переменные, обработайте и потом отгружайте уже готовые значения обратно. Если они не volatile , то компилятор сам это будет делать.

Цитата
Как еще можно ускорить работу обработчика?
Писать правильный код на Си smile.gif .
Bulat
Цитата(baralgin @ Dec 3 2009, 21:46) *
Эээ.. Тут вроде явно напрашивается switch вместо 8 if'ов.

А switch быстрее if?
Bulat
Цитата(Bulat @ Dec 4 2009, 09:37) *
А switch быстрее if?

действительно, switch побыстрее оказался. спасибо)
evgen2
Цитата(Bulat @ Dec 4 2009, 08:55) *
действительно, switch побыстрее оказался. спасибо)

Ну так у вас явно выполнялись все if'ы, если бы стояло
if
else if
else if
...
else

то после оптимизации может быть и не было бы разницы. А switch - это типа "вычисляемый goto"
sergeeff Jr.
И вероятно так тоже будет чуть быстрее:

Код
recB = (recB >> 1) | 0x80000000;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.