|
|
  |
Вложенные прерывания, GCC и ARM7 |
|
|
|
Mar 5 2010, 12:23
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(aaarrr @ Mar 5 2010, 13:04)  Вложенные прерывания предполагают, что выполнение процедуры обработки прерывания с приоритетом 5 может быть прервано прерыванием с приоритетом 6 или выше. Прерывание с меньшим приоритетом (4) может отработать только после записи VicVectAddr. А не наоборот? Из мануала по LPC24xx Цитата There are 16 priority levels, corresponding to the values 0 through 15 decimal, of which 15 is the lowest priority. То есть четвертый приоритет выше пятого. Цитата Кроме того, следует обратить внимание на некорректное выравнивание стека - должно быть четное число слов Все-таки кажется странным, что некорректный код публиковали бы под столь серьезным названием.
Сообщение отредактировал Novichok1 - Mar 5 2010, 12:25
|
|
|
|
|
Mar 5 2010, 12:35
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата Все-таки кажется странным, что некорректный код публиковали бы под столь серьезным названием. Не парьтесь, выравнивание на ARM7 не влияет ни на что. На LPC2xxx даже можно SP по модулю 4 не выравнивать  (Хотя не проверял, но по всем признакам это так) Цитата(Novichok1) А что на счет r3, это нормально, что она не сохраняется в стек? Вероятнее всего функция объявлена не как прерывание, а как просто функция. Там в атрибутах ещё должно указываться тип IRQ или FIQ, но точно не проверял как это влияет на прологи/эпилоги. Просто ставил всегда, когда не ставил свои обёртки. Со своими обёртками использовал атрибут naked.
Сообщение отредактировал GetSmart - Mar 5 2010, 12:38
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Mar 5 2010, 12:41
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Novichok1 @ Mar 5 2010, 15:23)  А не наоборот? Из мануала по LPC24xx
То есть четвертый приоритет выше пятого. Наоборот, не важно, уберите цифры и читайте больший-меньший. Цитата(Novichok1 @ Mar 5 2010, 15:23)  Все-таки кажется странным, что некорректный код публиковали бы под столь серьезным названием. Легко. Вы думаете, этот код великие корифеи пишут? Да и на старуху бывает проруха. Цитата(GetSmart @ Mar 5 2010, 15:35)  Не парьтесь, выравнивание на ARM7 не влияет ни на что. На LPC2xxx даже можно SP по модулю 4 не выравнивать  (Хотя не проверял, но по всем признакам это так) Ну, когда наткнетесь на некорректную работу плавучки, вспомните про выравнивание стека
|
|
|
|
|
Mar 5 2010, 12:43
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(GetSmart @ Mar 5 2010, 15:14)  Это точно пролог/эпилог функции с атрибутом interrupt ? Ох, виновен, виновен. Вот пролог: Код @ Interrupt Service Routine. @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 sub lr, lr, #4 stmfd sp!, {r0, r1, r2, r3, ip, lr} и эпилог: Код ldmfd sp!, {r0, r1, r2, r3, ip, lr} subs pc, lr, #4 То есть вроде все нормально. Но глюк то есть. Но опять таки, если применять свои ассемблерные вставки входа и выхода из обработчиков, то все в порядке. Но чтобы в одном обработчике прерывания можно было перейти в другое с более высоким приоритетом, нужно совершить запись в VicVectAddr, что не есть правильно. Посмотрел ассемблерные вставки, предложенные Вами, GetSmart, но они вроде ничем принципиальным не отличаются от тех, которыми пользуюсь я, то есть, тоже сохранение контекста, переход в другой режим работы процессора с разрешенными прерываниями, и вызов функции. Так чего же не хватает?
Сообщение отредактировал Novichok1 - Mar 5 2010, 12:48
|
|
|
|
|
Mar 5 2010, 12:54
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Novichok1 @ Mar 5 2010, 17:43)  То есть вроде все нормально. Но глюк то есть. Нихрена не нормально. Это бага GCC. Оно два раза вычетает из LR (адрес возврата в основную прогу) число 4. Кстати, я сразу не заметил, но и в первом прерывании та же самая беда. Цитата Но чтобы в одном обработчике прерывания можно было перейти в другое с более высоким приоритетом, нужно совершить запись в VicVectAddr, что не есть правильно. Такого не должно быть. Эта вещь реализована аппаратно в контроллере прерываний. Единственная причина по которой проц не может улететь на более высокоприоритетное прерывание - запрещённые глобально прерывания (все). То бишь установленный в "1" флаг I в регистре флагов.
Сообщение отредактировал GetSmart - Mar 5 2010, 12:57
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Mar 5 2010, 12:55
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(GetSmart @ Mar 5 2010, 15:35)  Со своими обёртками использовал атрибут naked. О! А этот вопрос был у меня в начале этой темы, не подскажете, как в GCC создавать свои атрибуты? Очень интересно и думаю будет полезно.
|
|
|
|
|
Mar 5 2010, 13:12
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(GetSmart @ Mar 5 2010, 15:54)  То бишь установленный в "1" флаг I в регистре флагов. Странно, я же сбрасываю его в ноль: /* (4) Change to SYS mode and enable IRQ */ msr cpsr_c, #0x1F Цитата Это не свой атрибут, а стандартный. Используется так: void AdcIntr_Wrapper() __attribute__((naked)); Спасибо, а не в курсе, в GCC все-таки можно создавать свои атрибуты?
|
|
|
|
|
Mar 5 2010, 14:03
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Novichok1) Спасибо, а не в курсе, Не, не в курсе. Я с GCC недавно пересёкся и не знаю что там к чему. Есть здесь такой чел klen он должен быть в курсах. Кстати, пустышку-обработчик не стоит обзывать static иначе она оптимизируется и выкинется. Если глобальные прерывания разрешены, значит что-то другое делаете не так. Может приоритеты неправильно задаёте. Вы тут периодически ошибаетесь, а мне гадать не интересно.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Mar 11 2010, 15:07
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
А разве к статическим членам нет доступа? Ведь обработчик-это просто функция (в моем случае-статический метод класса), у которой есть определенная отличная последовательность загрузки выгрузки. По сути, это низкоуровневый эквивалент событий(точнее, события-высокоуровневый эквивалент прерываний), по крайней мере по моим представлениям. Ну а к экземпляру класса, да, прямого доступа не будет. А сделал так, чтобы не нарушать стройность классовой модели, не хочу смешивать чисто сишные функции с классами. Это дает дополнительные преимущества по областям видимости данных и методов, а минусов я пока не нашел, если Вы их видите, то прошу ими поделиться.
|
|
|
|
|
Mar 11 2010, 18:22
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(GetSmart @ Mar 11 2010, 20:35)  Знаю только что обычным функциям класса передаётся "невидимый" параметр с указателем на текущий экземпляр класса. Это верно, но только для нестатических методов, то есть которые привязаны к конкретному экземпляру класса, на статические методы, которые принадлежат типу, а не конкретному экземпляру данного типа, это не распространяется, никаких невидимых параметров, типа параметра "this" туда не передается. Цитата(GetSmart @ Mar 11 2010, 20:35)  А уже из прерывания можно вызывать функцию(и) любого статического экземпляра, либо из статического указателя. О, а это очень даже полезная идея! Насколько я Вас понял, Вы предлагаете примерно следующее: этот главный обработчик обернуть в нечто подобное делегату из C#. В итоге это даст возможность легко подписываться на это прерывание из разных мест разным классам. Правда неизбежны некоторые накладные расходы на вызовы функций и дополнительные проверки.
|
|
|
|
|
Mar 11 2010, 19:02
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Вообще, излишняя универсальность, которая не понадобится в проге мне не нравится. Но как вариант, имеется класс низкого уровня с виртуальной функцией обработчика прерывания. Обработчик прерывания использует статическую переменную с указателем на этот класс. При входе в обработчик он вызывает эту функцию. Указатель можно инициализировать и менять в процессе любым совместимым экземпляром класса. А минимально, по простому: Код void MyIrq() { MyClassPtr->IrqHandler(); // функция класса, не статическая, статический указатель на экземпляр класса }
void MyIrq_Wrapper() // адрес этой функции будет записан в обработчик прерывания, должен быть атрибут (naked) { asm("пролог"); MyIrq(); asm("эпилог"); } Накладных расходов здесь почти нет. Главный накладной расход - компилятор GCC, так как у него не самый оптимальный код. В принципе, можно даже MyIrq() сократить, только предворительно проверить что за код создаёт компилер во всех режимах оптимизации. Лишь бы фрейм стека не выделялся. ----------- А чем вообще отличается статическая функция класса от обычной функции вне классовой дискриминации?  Область видимости чего-то и всё?
Сообщение отредактировал GetSmart - Mar 11 2010, 19:08
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Mar 12 2010, 04:49
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 8-07-09
Пользователь №: 51 032

|
Цитата(GetSmart @ Mar 11 2010, 22:02)  А чем вообще отличается статическая функция класса от обычной функции вне классовой дискриминации?  Область видимости чего-то и всё? На сколько я знаю, да. Но согласитесь, это удобно, если функция логически связана с классом, и ей нужен доступ к приватным и защищенным методам и полям, тогда проще ее объявить статическим методом, чем делать дополнительные телодвижения с установкой дружественной функцией. Да и более логичен вызов этой функции извне через название класса, как мне кажется. То есть не будет путаницы, если у вас несколько функций с одинаковыми именами, но относящихся к разным классам. А код я бы по другому сделал, например что-то типа: Код void OnIRQ // адрес этой функции будет записан в обработчик прерывания, должен быть атрибут (naked) { asm("пролог");
for(int i = 0; i < MAX_ISR_COUNT; i++) { if(interrupt_handlers[i] != NULL) { interrupt_handlers[i](); } }
asm("эпилог"); } Ну правда возникает вопрос в надобности использования нескольких обработчиков на одно прерывание) Ну в принципе можно и без массива обработчиков, тогда будет вызываться просто указатель на один обработчик. Но в любом случае, мне не совсем понятна нужность вот этого кода: Код void MyIrq() { MyClassPtr->IrqHandler(); // функция класса, не статическая, статический указатель на экземпляр класса } То есть, зачем нужен указатель на класс, ведь можно сразу в целевом классе назначить обработчик через указатель на функцию, без использования указателя на класс в главном обработчике прерывания.
Сообщение отредактировал Novichok1 - Mar 12 2010, 05:05
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|