Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AT91SAM9G45
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Sergey1212
Вобщем задача такая
хочу реализовать параллельную шину данных и 8 ног внешнего прерывания по которым будет опрашиваться шина.
данные с шины должны опрашиваться как можно быстрее т.е. прерываться выполнения IRQ и не допускать вложенности.
Для этих целей хочу использовать FIQ. Использовать EBI для общения как с статической памятью не получится, буду использовать ногодрыг, да и устройство на другой стороне имеет относительно низкую скорость шины.
IRQ будут висеть на таймерах и т.д. а FIQ на физических пинах.

Отсюда вопросы насколько хорошо выполненна реализация IRQ в стандартных примерах атмеля?
из архив at91sam9m10-ekes-softpack-1.9.zip
Если там все по кривому, было бы не плохо увидеть ссылку на правильный код.
Получится ли вообще повесить на 8 ног FIQ прерывания?
Не владею асемблером, где можно посмотреть пример кода с FIQ на этот проц?
сохранение стека, возврат и т.д.
И еще стоит ли вообще использовать FIQ или достаточно использовать на эти 8 ног IRQ с одинаковым самым высоким приоритетом?
будут ли выполняющиеся в этот момент IRQ с более низким приоритетом прерываться для выполнения IRQ с более высоким приоритером?
и как я понимаю вложенности тоже не будет т.к. IRQ будут с одинаковым высоким приоритетом?
aaarrr
Цитата(Sergey1212 @ Apr 26 2013, 11:54) *
Отсюда вопросы насколько хорошо выполненна реализация IRQ в стандартных примерах атмеля?

Не знаю, как сейчас, но раньше было криво - дурацкий код для обеспечения вложенности прерываний
с убитой векторизацией и дичайшим оверхедом для прерывания с высшим приоритетом.

Цитата(Sergey1212 @ Apr 26 2013, 11:54) *
Получится ли повесить на 8 ног FIQ прерывания?

FIQ прерывание одно. Поэтому получится, но только если все ноги находятся в пределах одного порта.

Цитата(Sergey1212 @ Apr 26 2013, 11:54) *
И еще стоит ли вообще использовать FIQ или достаточно использовать на эти 8 ног IRQ с одинаковым самым высоким приоритетом?

Лучше FIQ, чем вложенные прерывания.
Sergey1212
Не подскажите пример хорошей реализации IRQ и FIQ?
jcxz
Цитата(Sergey1212 @ Apr 26 2013, 13:54) *
Получится ли вообще повесить на 8 ног FIQ прерывания?
Получится. По ИЛИ.

Цитата(Sergey1212 @ Apr 26 2013, 13:54) *
Не владею асемблером, где можно посмотреть пример кода с FIQ на этот проц?
сохранение стека, возврат и т.д.
Вы сначала не ассемблер, а описание на ядро ARM7/9 почитайте. Нет там никакого сохранения стека. По соотв. прерыванию (IRQ или FIQ) переключается контекст CPU.

Цитата(Sergey1212 @ Apr 26 2013, 13:54) *
будут ли выполняющиеся в этот момент IRQ с более низким приоритетом прерываться для выполнения IRQ с более высоким приоритером?
и как я понимаю вложенности тоже не будет т.к. IRQ будут с одинаковым высоким приоритетом?
Не будут, но по-другой причине. В ядре нет никаких приоритетов. Если произошло IRQ, то CPU переключается в контекст IRQ и автоматом запрещает IRQ.
То же для FIQ (но запрещаются и IRQ и FIQ).
Приоритеты есть только в контроллере прерываний, который можно использовать, а можно - нет.
Поэтому для одного высокочастотного прерывания ядро ARM7/9 удобнее кортексов: если FIQ происходит, то вход в контекст FIQ очень быстрый и нет необходимости ничего сохранять и восстанавливать.

А вообще для быстрой работы с GPIO лучше использовать DMA (если есть возможность в вашем процессоре).
А дёргание в прерывании и программный ногодрыг - это пустая трата тактов процессора.
А ещё лучше - используйте канал SPI. Мегагерц на 60 думаю сможете его завести. И дорог на плате меньше.
aaarrr
ИМХО, хорошая реализация может выглядеть примерно так:
1. Векторизация через LDR PC, [PC,# -&F20] безо всяких оберток.
2. Если нужны вложенные прерывания (тут надо крепко подумать, нужны ли на самом деле), делаем
индивидуальные обертки для всех процедур прерывания, кроме прерывания с высшим приоритетом.
3. Обработчик FIQ пишем на ассемблере сразу по адресу вектора.

Но некоторое знание ассемблера и тщательное изучение AIC понадобятся в любом случае.
Sergey1212
а всетаки пример может кто скинет?
с вложенными IRQ, использованием AIC и FIQ
Sergey1212
Есть вот такой код фика
CODE

FIQ_Handler_Entry:

stmfd sp!, {r0, lr}
ldr lr, =AT91C_BASE_AIC
ldr r0, [lr, #AIC_FVR]
str lr, [lr, #AIC_FVR]
msr CPSR_c,#I_BIT | F_BIT | ARM_MODE_SVC
//;- Save scratch/used registers and LR in User Stack
stmfd sp!, {r1-r3, r4, r12, lr}
//;- Branch to the routine pointed by the AIC_FVR

ldr r0, =fiq
mov r14, pc
bx r0
//;- Restore scratch/used registers and LR from User Stack
ldmia sp!, {r1-r3, r4, r12, lr}
//;- Leave Interrupts disabled and switch back in FIQ mode
msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ
mov r0, #0xFFFFFF
ldr r8, =AT91C_BASE_AIC
str r0, [r8, #AIC_EOICR]

//;- Restore the R0 ARM_MODE_SVC register
ldmia sp!, {r0, lr}
//;- Restore the Program Counter using the LR_fiq directly in the PC
subs pc,lr,#4

но работает он только если я в AIC_SMR[source] = AT91C_AIC_PRIOR_HIGHEST | 0;
а если использую другие варианты (0x2 << 5) или (0x1 << 5) или (0x3 << 5) то прерывание остается активным т.к. все время заходит в процедуру fiq и там прочитанный статус равен 0
если тот же обраотчик вешаю на IRQ то все работает отлично прерывания сбрасываются как положено
т.е. дело не в обработчике
вот код fiq
Код
void fiq(void)
{
    volatile unsigned int dummy, reg;
    unsigned int status;
    status = AT91C_BASE_PIOA->PIO_ISR;
    status &= AT91C_BASE_PIOA->PIO_IMR;

    printf("HI %d \r\n", status);

    if(status!=0)
    {
        dummy = AT91C_BASE_PIOA->PIO_ISR;
        printf("HI fiq \r\n");
    }
}


Подскажите в чем проблема?
И как сделать чтобы переходил по вектору на процедуру сохраненную через AIC
комментирую строку ldr r0, =fiq в фик не попадаю
жытага нет поэтому в слепую очень уж непросто разбираться и учиться
подскажите пожалуйста
aaarrr
Прочитайте внимательно раздел "27.8.4.5 Fast Forcing":
1. Прерывания по фронту в этом режиме автоматически не сбрасываются, поэтому и зависает
2. AIC_FVR всегда возвращает значение из AIC_SVR0

Подумайте, нужны ли вам вообще прерывания по фронту - для внутренних источников (к которым относится и GPIO), в 99.9% случаев смысла работать по фронту нет.
jcxz
Цитата(Sergey1212 @ May 2 2013, 11:44) *
Есть вот такой код фика
...
//;- Restore the R0 ARM_MODE_SVC register
ldmia sp!, {r0, lr}
//;- Restore the Program Counter using the LR_fiq directly in the PC
subs pc,lr,#4

И где же восстановление прерванного режима CPU???
У вас после такого возврата, CPU останется в режиме FIQ, стек разрушится, не говоря уже о том что прерывания останутся запрещёнными.

Цитата(Sergey1212 @ May 2 2013, 11:44) *
если тот же обраотчик вешаю на IRQ то все работает отлично прерывания сбрасываются как положено
По-моему - Вы обманываете. Такой код работать не будет.

И это кроме того, что таким Вы убиваете весь смысл FIQ как быстрого прерывания. Зачем он Вам тогда нужен? Пользуйтесь IRQ. Такими манипуляциями Вы низводите плюсы FIQ (скорость входа/выхода) до обычной скорости IRQ с внешним AIC-контроллером, т.е. - самой тормозной.

Цитата(aaarrr @ May 2 2013, 12:41) *
Подумайте, нужны ли вам вообще прерывания по фронту - для внутренних источников (к которым относится и GPIO), в 99.9% случаев смысла работать по фронту нет.
Проблема автора в том, что он не хочет ничего читать из документации на CPU, а хочет надёргать каких-то левых чужих кусков не разбираясь как они работают, и чтобы это всё заработало, да ещё и быстро...

Цитата(Sergey1212 @ May 2 2013, 11:44) *
...
printf("HI %d \r\n", status);
...

Запускать такие тяжёлые функции из ISR, к тому же ещё на стеке SVC (printf до фига ест стека) неизвестно какого размера (скорей всего - небольшого)???
Ну-ну, успехов! wink.gif
aaarrr
Цитата(jcxz @ May 2 2013, 11:52) *
По-моему - Вы обманываете. Такой код работать не будет.

Нет, тут все правильно: subs pc, lr, #4 восстановит режим.

Цитата(jcxz @ May 2 2013, 11:52) *
Запускать такие тяжёлые функции из ISR, к тому же ещё на стеке SVC (printf до фига ест стека) неизвестно какого размера (скорей всего - небольшого)???
Ну-ну, успехов! wink.gif

Если это из атмеловских примеров, то у них как раз все наоборот - стек IRQ/FIQ имеет минимальный размер, а SVC/USR достаточно приличные.
Но правильно, конечно, будет убрать это дурацкое переключение и расширить при необходимости стек FIQ.
Sergey1212
Цитата
По-моему - Вы обманываете. Такой код работать не будет.

И это кроме того, что таким Вы убиваете весь смысл FIQ как быстрого прерывания. Зачем он Вам тогда нужен? Пользуйтесь IRQ. Такими манипуляциями Вы низводите плюсы FIQ (скорость входа/выхода) до обычной скорости IRQ с внешним AIC-контроллером, т.е. - самой тормозной.

Проблема автора в том, что он не хочет ничего читать из документации на CPU, а хочет надёргать каких-то левых чужих кусков не разбираясь как они работают, и чтобы это всё заработало, да ещё и быстро...

Запускать такие тяжёлые функции из ISR, к тому же ещё на стеке SVC (printf до фига ест стека) неизвестно какого размера (скорей всего - небольшого)???
Ну-ну, успехов! wink.gif

Я конечно понимаю что вы очень умный и начитанный документаций до того что даже не можете понять что код рабочий.

Посмотрел бы я на вас без жытаги, без понимания в асемблере и с такой богатой документацие где ведь все по полочкам разложено, в том числе и команды асма, какие регистры надо сохранять или не надо и что вообще надо делать при входе в прерывание на этом асемблере и т.д.
А писать код на асме без отладки думаю не простое дело даже для знающих ассемблер и изучивших проц.
По поводу принтф, как по вашему я должен отлаживать код?

То что смысл весь фика убиваю так это да, но я непонимаю и незнаю как сделать чтобы было правильно.
Если бы все знал и понимал думаю тут бы не оказался.




Цитата(aaarrr @ May 2 2013, 10:41) *
Прочитайте внимательно раздел "27.8.4.5 Fast Forcing":
1. Прерывания по фронту в этом режиме автоматически не сбрасываются, поэтому и зависает
2. AIC_FVR всегда возвращает значение из AIC_SVR0

Подумайте, нужны ли вам вообще прерывания по фронту - для внутренних источников (к которым относится и GPIO), в 99.9% случаев смысла работать по фронту нет.

Дело в том что если я не по фронту делаю то при подаче на ногу сигнала вызов прерывания повторяется пока этот сигнал не будет снят.
для сброса я так понимаю нужно AIC_ICCR использовать?
aaarrr
Цитата(Sergey1212 @ May 2 2013, 12:32) *
Дело в том что если я не по фронту делаю то при подаче на ногу сигнала вызов прерывания повторяется пока этот сигнал не будет снят.

Судя по коду обработчика, у вас задействовано прерывание GPIO Input Change. Оно переходит в активный уровень по любому фронту на одной из разрешенных линий. То есть выделение фронта сделано еще до AIC, поэтому последний должен работать по уровню и никаких "повторений" наблюдаться не должно.
jcxz
Цитата(Sergey1212 @ May 2 2013, 14:32) *
Я конечно понимаю что вы очень умный и начитанный документаций до того что даже не можете понять что код рабочий.
Вы-то как это поняли? Методом тыка? biggrin.gif

Цитата(Sergey1212 @ May 2 2013, 14:32) *
Посмотрел бы я на вас без жытаги, без понимания в асемблере и с такой богатой документацие где ведь все по полочкам разложено, в том числе и команды асма, какие регистры надо сохранять или не надо и что вообще надо делать при входе в прерывание на этом асемблере и т.д.
Не поверите, но изучал ассемблер ARM7/9 я как раз без JTAG ещё. А вот без понимания ассемблера дальше приложений пользовательского уровня соваться не стоит.
Не надо делать: впустую переключать контекст, использовать AIC если у вас одно прерывание (да и больше - не всегда он нужен), даже половину регистров в FIQ в ARM7/9-ядрах можно не сохранять, а использовать для static переменных...
Всего этого вы не узнаете пока не прочитаете доку на ядро.

Цитата(Sergey1212 @ May 2 2013, 14:32) *
По поводу принтф, как по вашему я должен отлаживать код?
Код в первую очередь отлаживается головой.
Sergey1212
Да спасибо, это видимо потому что прерывание не сбрасывал, вот только как то странно получалось как только уровень снимал оно сбрасывалось
щас добавил в обработчик AT91C_BASE_AIC->AIC_ICCR = status;
стало при появлении уровня срабатывать и при исчезновении еще раз
а при настройке по фронту все равно не сбрасывается
а если вы говорите что оно еще до AIC где-то настроено это где тогда?
хотелось бы всетаки по фронту сделать
чтобы появился уровень затем снялся и только тогда прерывание появилось
jcxz
Цитата(aaarrr @ May 2 2013, 14:00) *
Нет, тут все правильно: subs pc, lr, #4 восстановит режим.
Да, давненько не писал для ARM7/9. На cortex-ах отвык уже... Не заметил этого модификатора, ведь при применении к PC у него особый смысл wink.gif
Я всегда делал по-другому:
Код
SUB  LR, LR, #4
STMFD  SP!, {..., LR}
...
LDMFD  SP!, {..., PC}^
Sergey1212
Цитата(jcxz @ May 2 2013, 12:59) *
Вы-то как это поняли? Методом тыка? biggrin.gif

Не поверите, но изучал ассемблер ARM7/9 я как раз без JTAG ещё. А вот без понимания ассемблера дальше приложений пользовательского уровня соваться не стоит.
Не надо делать: впустую переключать контекст, использовать AIC если у вас одно прерывание (да и больше - не всегда он нужен), даже половину регистров в FIQ в ARM7/9-ядрах можно не сохранять, а использовать для static переменных...
Всего этого вы не узнаете пока не прочитаете доку на ядро.

Код в первую очередь отлаживается головой.

Практически методом тыка.
В первую очередь головой но на вашем же примере видно что с помощью головы не всегда все становится ясно рабочий ли код или нет
Это при том что вы знаете и ассемблер и ядро

Подскажите идиоту в какую доку смотреть чтобы включать фик без использования AIC и чтобы еще при этом IRQ через AIC работали?
И еще вопрос если я не делаю переключения контекста смогу ли я менять глобальные переменные находящиеся в другом контексте?
aaarrr
Цитата(Sergey1212 @ May 2 2013, 13:02) *
стало при появлении уровня срабатывать и при исчезновении еще раз

Оно именно так и работает - по изменению уровня, т.е. по обоим фронтам. Так устроена железка, настроить нельзя.
Можно только проверять реальный уровень линии внутри прерывания.

Цитата(Sergey1212 @ May 2 2013, 13:11) *
Подскажите идиоту в какую доку смотреть чтобы включать фик без использования AIC и чтобы еще при этом IRQ через AIC работали?

Что значит "без использования AIC"?

Цитата(Sergey1212 @ May 2 2013, 13:11) *
И еще вопрос если я не делаю переключения контекста смогу ли я менять глобальные переменные находящиеся в другом контексте?

Да, это просто переключение банка регистров. На работе с расположенными в памяти глобальными переменными никак не отразится.
jcxz
Цитата(Sergey1212 @ May 2 2013, 15:11) *
В первую очередь головой но на вашем же примере видно что с помощью головы не всегда все становится ясно рабочий ли код или нет
Я же не отлаживаю ваше ПО, а просто мельком просмотрел.

Цитата(Sergey1212 @ May 2 2013, 15:11) *
Подскажите идиоту в какую доку смотреть чтобы включать фик без использования AIC и чтобы еще при этом IRQ через AIC работали?
Контроллер прерывания не входит в состав ядра. Здесь надо вам читать доку на ваш процессор, а не ядро. Я вашего процессора не знаю.
В том ARM9, с которым я имел дело, в его AIC было 32 канала прерываний. Младшие 2 из которых всегда шли на FIQ-вход ядра, остальные - на IRQ-вход.
Соответственно при инициализации прерывания, надо соответствующий event отнести к одной из групп. Если у вас в группе FIQ будет только один
event, то работа с AIC в ISR может ограничиться только квитированием прерывания AIC-у (если это вообще нужно вашему AIC).
В ARM7-ядрах NXP выбор типа FIQ/IRQ выполняется в регистре VICIntSelect, который работает как битовая карта.
В вашем CPU может быть свой метод.
Далее - читаете описание периферии, которая генерит int-event-ы и смотрите как её надо инитить и как ей квитировать прерывания для этой периферии (если надо).

Цитата(Sergey1212 @ May 2 2013, 15:11) *
И еще вопрос если я не делаю переключения контекста смогу ли я менять глобальные переменные находящиеся в другом контексте?
Переменные не относятся к контексту CPU. Они находятся в ОЗУ. А контекст - этот состояние ядра с соответствующим ему набором регистров. Вот получить доступ к регистрам другого контекста вы не сможете. Надо переключать контекст чтобы получить к ним доступ.
Sergey1212
Цитата
Не надо делать: впустую переключать контекст, использовать AIC если у вас одно прерывание (да и больше - не всегда он нужен)

Я так и не понял, всетаки без AIC не обойтись?
Или его ненадо использовать?

Цитата
Подумайте, нужны ли вам вообще прерывания по фронту - для внутренних источников (к которым относится и GPIO), в 99.9% случаев смысла работать по фронту нет.

Цитата
Оно именно так и работает - по изменению уровня, т.е. по обоим фронтам. Так устроена железка, настроить нельзя.

А для чего тогда настройки по фронтам?
Их всетаки можно использовать для GPIO?
Если можно то как я понимаю будет только один раз вызываться прерывание
aaarrr
Цитата(Sergey1212 @ May 2 2013, 15:12) *
Их всетаки можно использовать для GPIO?
Если можно то как я понимаю будет только один раз вызываться прерывание

Нет, нельзя. Просто почитайте, как формируется сигнал прерывания от PIO.
Sergey1212
Всем спасибо, хоть что-то разъяснилось)
Код сократился до такого варианта:
Код
stmfd   sp!, {r0, lr}            
ldr     lr, =AT91C_BASE_AIC
ldr     r0, [lr, #AIC_FVR]
mov  lr, pc
bx     r0
ldmia       sp!, {r0, lr}
subs        pc,lr,#4

Чего тут еще не нужно делать?
вот r0 нужно сохранять-возвращать?
может и вместо bx что-то посоветуете чтобы lr не приходилось менять перед bx чтобы и его не сохранять?
а может чего-то нехватает?
jcxz
Я же уже писал... smile3046.gif
В моём ARM9-ядре (ARM926EJ-S из состава OMAP-L137) достаточно в контроллере прерываний посадить только одно прерывание на линию FIQ (остальные - на IRQ).
Тогда достаточно будет оставить:
Код
SUB  LR, LR, #4
STMFD  SP!, {..., LR}
...
LDMFD  SP!, {..., PC}^
Вместо многоточия можно писать свой код, учитывая, что регистры R8-R12 можно не сохранять.
Вместо многоточия можно также поставить вызов си-функции. Тогда в команды STMFD/LDMFD нужно добавить все регистры из диапазона R0-R7, которые нужно сохранять
(список таких регистров ищется в разделе "Calling Conventions" на ваш компилятор).

Для CodeComposer (и ARM926EJ-S из состава OMAP-L137) это будет:
Код
FIQ_handler:    
SUBS  LR, LR, #4
STMFD SP!, {R0-R3, R12, LR}    ;Store registers on FIQ stack
BL  c_func                                 ;Go to ISR (still in FIQ mode), will return to following line
LDMFD SP!, {R0-R3, R12, PC}^  ;Restore registers from FIQ stack. Return to program current status


Так что выгоднее FIQ-обработчик писать на асм - если уложитесь в регистры R8-R12 то вообще ничего на стек сохранять не нужно и можно избавиться от STMFD/LDMFD, и может даже от команд загрузки рабочих регистров статическими переменными и константами.
Я так на ARM7 с частотой 72МГц получал частоты прерываний порядка нескольких мегагерц при 50% загрузке CPU. И даже без JTAG... sm.gif
aaarrr
Цитата(Sergey1212 @ May 2 2013, 15:50) *
Чего тут еще не нужно делать?
вот r0 нужно сохранять-возвращать?
может и вместо bx что-то посоветуете чтобы lr не приходилось менять перед bx чтобы и его не сохранять?
а может чего-то нехватает?

Начнем с того, что нужно сделать, но не сделано: следует сохранить регистры r0-r3 и r12. См. пример FIQ_Handler из сообщения jcxz.

Весь приведенный фрагмент кода можно благополучно заменить одной командой ldr pc, [pc, #-0xf20],
расположенной по адресу вектора FIQ (0x1c). Только C-обработчик нужно будет снабдить модификатором,
который укажет компилятору на то, что это обработчик FIQ-прерывания (__fiq, __attribute__ ((interrupt( fiq ))) и т.п.,
в зависимости от используемого компилятора). Результат будет тот же, зато в стек не будет записано лишнего.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.