NikolaKirov 0 19 октября, 2005 Опубликовано 19 октября, 2005 · Жалоба Необходимо переключат функции которъе въизъиваются на перервание. Сделал extern __near void (* pTX_InterruptFunction)(void); а сам interrupt #pragma vector = USART_TXC_vect __interrupt void TXCinterrupt(void) { pTX_InterruptFunction(); } все работает но вот такое генерируется \ 00000000 93BA ST -Y, R27 \ 00000002 93AA ST -Y, R26 \ 00000004 938A ST -Y, R24 \ 00000006 93FA ST -Y, R31 \ 00000008 93EA ST -Y, R30 \ 0000000A 923A ST -Y, R3 \ 0000000C 922A ST -Y, R2 \ 0000000E 921A ST -Y, R1 \ 00000010 920A ST -Y, R0 \ 00000012 937A ST -Y, R23 \ 00000014 936A ST -Y, R22 \ 00000016 935A ST -Y, R21 \ 00000018 934A ST -Y, R20 \ 0000001A 933A ST -Y, R19 \ 0000001C 932A ST -Y, R18 \ 0000001E 931A ST -Y, R17 \ 00000020 930A ST -Y, R16 \ 00000022 B78F IN R24, 0x3F 54 pTX_InterruptFunction(); \ 00000024 .... LDI R26, LOW(pTX_InterruptFunction) \ 00000026 .... LDI R27, (pTX_InterruptFunction) >> 8 \ 00000028 91ED LD R30, X+ \ 0000002A 91FC LD R31, X \ 0000002C 9509 ICALL 55 } \ 0000002E BF8F OUT 0x3F, R24 \ 00000030 9109 LD R16, Y+ \ 00000032 9119 LD R17, Y+ \ 00000034 9129 LD R18, Y+ \ 00000036 9139 LD R19, Y+ \ 00000038 9149 LD R20, Y+ \ 0000003A 9159 LD R21, Y+ \ 0000003C 9169 LD R22, Y+ \ 0000003E 9179 LD R23, Y+ \ 00000040 9009 LD R0, Y+ \ 00000042 9019 LD R1, Y+ \ 00000044 9029 LD R2, Y+ \ 00000046 9039 LD R3, Y+ \ 00000048 91E9 LD R30, Y+ \ 0000004A 91F9 LD R31, Y+ \ 0000004C 9189 LD R24, Y+ \ 0000004E 91A9 LD R26, Y+ \ 00000050 91B9 LD R27, Y+ \ 00000052 9518 RETI И как видно перервание становится медленое. А мои функции совсем простенкие,такое сохранение регистров не нужно. Явно что то не так делаю. Как правилно ето делат? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ig_z 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба И как видно перервание становится медленое. А мои функции совсем простенкие,такое сохранение регистров не нужно. Явно что то не так делаю. Как правилно ето делат? <{POST_SNAPBACK}> Если вызываемая функция и вызывающая находятся в разных модулях, то компилятор не может знать о простоте или сложности вашей функции и совершенно корректно сохранит все регистры. Выход - помещать эти функции в один модуль. ( хотя вроде есть среды с =умными= линкерами для подобных ситуаций, но у иара он точно этого не делает - жертва универсальности) А если эти функции в одном модуле и оптимизация включена - тогда дело дрянь. Только на асме Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alex11 6 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Все не совсем так - при выключенном оптимизаторе, как только в interrupt-функции появляется вызов другой функции, то сохраняются все регистры. При включенном - если функция в этом же модуле, то сохраняются только требуемые (это для IAR 4.11). Но следует быть аккуратным с оптимизатором, он очень любит выбрасывать куски программы не смотря на объявления переменных volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pat 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Необходимо переключат функции которъе въизъиваются на перервание. Сделал extern __near void (* pTX_InterruptFunction)(void); а сам interrupt #pragma vector = USART_TXC_vect __interrupt void TXCinterrupt(void) { pTX_InterruptFunction(); } А мои функции совсем простенкие,такое сохранение регистров не нужно. Явно что то не так делаю. Как правилно ето делат? [post=57923]<{POST_SNAPBACK}>[/post] Что бы компилятор не творил такие безобразия можно сделать следующее 1) Не вызывать функцию из обработчика прерываний а описать все в теле #pragma vector = USART_TXC_vect __interrupt void TXCinterrupt(void) { } 2) Обязательно использовать в качестве ваших переменных, которые используются в прерывании, залоченные регистры ну те которые объявляются в IAR как __regvar __no_init volatile unsigned char val @ 13; Так же их надо залочить в опциях Потеряете совместимость с другими компиляторами, но если у вас все переменные будут залочены компилятор будет сохранять в стеке только SREG. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба 2) Обязательно использовать в качестве ваших переменных, которые используются в прерывании, залоченные регистры ну те которые объявляются в IAR как __regvar __no_init volatile unsigned char val @ 13; Так же их надо залочить в опциях <{POST_SNAPBACK}> Не следует этим слишком увлекаться, т. к. некоторые библиотечные функции используют регистры R4 - R7. Залочивание этих регистров может привести к некорректной работе при вызове оных функций. Поэтому IAR не рекомендует залочивать более 9 регистров (хотя и позволяет это сделать). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Runner 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Что бы компилятор не творил такие безобразия можно сделать следующее 1) Не вызывать функцию из обработчика прерываний а описать все в теле #pragma vector = USART_TXC_vect __interrupt void TXCinterrupt(void) { } 2) Обязательно использовать в качестве ваших переменных, которые используются в прерывании, залоченные регистры ну те которые объявляются в IAR как __regvar __no_init volatile unsigned char val @ 13; Так же их надо залочить в опциях Потеряете совместимость с другими компиляторами, но если у вас все переменные будут залочены компилятор будет сохранять в стеке только SREG. <{POST_SNAPBACK}> 1)Очень даже правильно. Как раз тот случай, когда директивы и макросы вместо функций будут к месту. 2) Из опыта - есть ограничения на количество регистров, залоченных под глобальные переменные - не более 9 (или 8?). Если залочить больше будут проблеммы с линковкой. Полезная документашка лежит под http://atmel.com/dyn/resources/prod_documents/doc1234.pdf - совмещение asm и C. Там есть пример функции обработчика прерывания на asm-e в С программе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Runner 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба 2) Обязательно использовать в качестве ваших переменных, которые используются в прерывании, залоченные регистры ну те которые объявляются в IAR как __regvar __no_init volatile unsigned char val @ 13; Так же их надо залочить в опциях <{POST_SNAPBACK}> Не следует этим слишком увлекаться, т. к. некоторые библиотечные функции используют регистры R4 - R7. Залочивание этих регистров может привести к некорректной работе при вызове оных функций. Поэтому IAR не рекомендует залочивать более 9 регистров (хотя и позволяет это сделать). <{POST_SNAPBACK}> И так всегда! Пока чешу репу уже ответят... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NikolaKirov 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Проблем с переключение задач которъие въиполняется на перервание слишком сериознъи. Я просто удивлен что такая фирма как IAR так подходит к етому вопросу. У меня ест одна идея #pragma vector = 0x1000 __interrupt void Usart_Trnasmit() { ------------- ------------- } так обявляем функции которъие нада переключат проблем как организироват само переключение если захочу поставит __task void TrInterrupt(void) @ USART_TXC_vect и там в асме переходит к нужнои функции компилер ругается что на етот адрес могу толко __interrupt ставит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Pat 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба 2) Из опыта - есть ограничения на количество регистров, залоченных под глобальные переменные - не более 9 (или 8?). Если залочить больше будут проблеммы с линковкой. <{POST_SNAPBACK}> Всего залочить можно 12 регистров R4 - R15. Проблеммы могут возникнуть только в случае, если использовать функции из родных ИАРовских библиотек. Особенно это касается математических функций с float в качестве аргумента. Там вообще ничего не даст залочить. Если же все самописаное то проблем нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BVU 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Проблем с переключение задач которъие въиполняется на перервание слишком сериознъи. Я просто удивлен что такая фирма как IAR так подходит к етому вопросу. У меня ест одна идея #pragma vector = 0x1000 __interrupt void Usart_Trnasmit() { ------------- ------------- } так обявляем функции которъие нада переключат проблем как организироват само переключение если захочу поставит __task void TrInterrupt(void) @ USART_TXC_vect и там в асме переходит к нужнои функции компилер ругается что на етот адрес могу толко __interrupt ставит. <{POST_SNAPBACK}> Nikola, в классических системах это делается немного по другому. В теле Вашего прерывания должен находиться переход (call) на адрес расположенный в оперативной памяти (строго фиксировано), где размещается еще один вызов функции (переключение на функцию) адресс которой подставляется (настраивается в данный момент времени) в зависимости от логики работы программы. Так Вы получаете расширение ресурсов своего преравания. Что касается скорости выполнения, то здесь теряется время на дополнительный вызов. На asm это реализуется просто, как это сделать корректно на 'C' - надо подумать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NikolaKirov 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Кажется нашел решение __near void (* pTX_InterruptFunction)(void); #pragma vector = USART_RXC_vect __interrupt void RXCinterrupt(void) { asm(" call pRX_InterruptFunction"); } так все ОК но не знаю еще не будут ли глюки в работе Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба в классических системах это делается немного по другому. В теле Вашего прерывания должен находиться переход (call) на адрес расположенный в оперативной памяти (строго фиксировано), где размещается еще один вызов функции (переключение на функцию) адресс которой подставляется (настраивается в данный момент времени) в зависимости от логики работы программы. Так Вы получаете расширение ресурсов своего преравания. Что касается скорости выполнения, то здесь теряется время на дополнительный вызов. На asm это реализуется просто, как это сделать корректно на 'C' - надо подумать. С AVR это не пройдет, так как адресное пространство кода и данных раздельное и сегменты кода во flash лежать обычно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BVU 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба в классических системах это делается немного по другому. В теле Вашего прерывания должен находиться переход (call) на адрес расположенный в оперативной памяти (строго фиксировано), где размещается еще один вызов функции (переключение на функцию) адресс которой подставляется (настраивается в данный момент времени) в зависимости от логики работы программы. Так Вы получаете расширение ресурсов своего преравания. Что касается скорости выполнения, то здесь теряется время на дополнительный вызов. На asm это реализуется просто, как это сделать корректно на 'C' - надо подумать. С AVR это не пройдет, так как адресное пространство кода и данных раздельное и сегменты кода во flash лежать обычно. <{POST_SNAPBACK}> Да, конечно же... AVR имеет архитектуру гарвардского типа. :( Если бы не высокая производительность выполнения команд, AVR бы проигравал со своей системой прерывания во всех отношениях... Надо подумать как это обойти?! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NikolaKirov 0 20 октября, 2005 Опубликовано 20 октября, 2005 · Жалоба Етот метод которъи я описл деиствително работает и регистръи не сохраняются в само перервание вообще. Но не знаю какая разница ест между функция перервания и объчная функция в аспекте сохранения регистров. И почему у IAR толко функции перервании сохраняют все регистръи если обратится к другои фунцкции. Если кто то может обяснит разницу можно и наити каие подводнъие камни ест в метода которъй нашел я. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 69 21 октября, 2005 Опубликовано 21 октября, 2005 · Жалоба в классических системах это делается немного по другому. В теле Вашего прерывания должен находиться переход (call) на адрес расположенный в оперативной памяти (строго фиксировано), где размещается еще один вызов функции (переключение на функцию) адресс которой подставляется (настраивается в данный момент времени) в зависимости от логики работы программы. Так Вы получаете расширение ресурсов своего преравания. Что касается скорости выполнения, то здесь теряется время на дополнительный вызов. На asm это реализуется просто, как это сделать корректно на 'C' - надо подумать. С AVR это не пройдет, так как адресное пространство кода и данных раздельное и сегменты кода во flash лежать обычно. <{POST_SNAPBACK}> Да, конечно же... AVR имеет архитектуру гарвардского типа. :( Если бы не высокая производительность выполнения команд, AVR бы проигравал со своей системой прерывания во всех отношениях... Надо подумать как это обойти?! <{POST_SNAPBACK}> Прошу прощения, что вмешиваюсь. Тут все не так и все гораздо проще. IAR делит регистры на local и scratch. Первые - это регистры, которые в вызываемой функции компилятор может использовать только предварительно сохранив их с последующим восстановлением перед выходом. Т.е. это, так называемые, call preserved регистры. Вторые - это регистры, которые компилятор при вызове функции может юзать по своему усмотрению. Из этого следует: если имеет место вызов любой функции (тело которой компилятору в точке компиляции не видно) из прерывания, то компилятор не может делать никаких предположений об использовании регистров в этой функции и обязан сохранить все scratch регистры - local регистры ему тут сохранять не надо, т.к. они, если необходимо, будут сохранены в вызываемой функции. Что мы и наблюдаем в приведенном задавшим вопрос фрагменте - сохранены только scratch регистры. Это поведение компилятора корректное, гарантирующее от возникновения коллизий из-за асинхронного доспупа к регистрам. К архитектуре проца это отношения не имеет. Возьмите фон неймановский MSP430, там поведение в обработчике прерывания будет ровно таким же. Если не хочется иметь этот оверхед, то единственным корректным путем будет разместить тело функции прямо внутри обработчка прерывания - как уже посоветовали. Чтобы не загромождать ISR можно функцию оставить, но объявить как встраиваемую (inline) и поместить ее определение в заголовочный файл, включаемый в исходник, где определен ISR. Все остальные "финты ушами" вроде вызова функции через асмовую вставку - это быть самому себе злобным буратиной. В этом случае, когда возникнет прерывание и управление будет передано в функцию, которая не является ISR (т.к. компилятор не знает, что функция эта вызвана асинхронно по отношению к потоку управления), в этой функции будут без ограничений использоваться scratch регистры, значения которых, не будут сохранены (с последующим восстановлением). В результате огребете гору замечательных и труднопресказуемых глюков. Оно надо? Никогда ни в коем случае так делать нельзя. Если уж вызываете функцию без сохранения контекста компилятором, то делайте это сами руками. Такая необходимость может возникнуть при написании переключателя конткестов в вытесняющий RTOS. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться