bvn123 0 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба Добрый день. Мне понадобилось перегнать работающий проект из IAR в Microchip Studio (MS). MS позволяет организовать проект как под компилятор XC8, так и под GCC. Организовал оба проекта - оба компилируются без ошибок и предостережений (warnings). Проект XC8 в микроконтроллере работает, GCC - частично: данные по USART передаёт, но не принимает, если организация приёма выполнена по прерыванию. Простой пример кода GCC с такой же инициализацией USART, но в котором прерывания не используются, работает на прием и передачу по USART. Т.е., инициализация USART корректна. Что-то не так в организации прерываний для GCC? Моя ошибка в синтаксисе при написании прерываний? Усеченный GCC в MS? Вот структура кода: ISR(TCA0_OVF_vect) {} //intr таймера, если в USART1 данные не поступали в течение 1024*40/8000000с или 5.12мс ISR(USART1_RXC_vect) {} int main{} Я поинтересовался в Microchip, служба поддержки ответила, что GCC не поддерживают - возможно, из-за того, что запрос попал к тем, кто занимается XC8. Более подробный код GCC ниже - он не работает в МК (такой же, откомпилированный в XC8, работает в МК (отличие - #include <avr/io.h> для GCC или <xc> для XC8)): Spoiler unsigned char uart1_Rx[10],uart1_State,uart1_cntRx; ISR(TCA0_OVF_vect){} //intr when USART1 doesn't receive char 1024*40/8000000s or 5.12ms new Rx ISR(USART1_RXC_vect){} void external_CLK_init(){} unsigned long uart1_SetBaudRate(unsigned long FBaud,unsigned long Fclk){} void uart1_Init(){} void uart1_Tx(unsigned char dt){} void uart1_TxEnd(){} void uart1_EchoRxTx(){} int main(){ external_CLK_init(); uart1_Init(); uart1_SetBaudRate(USB_BaudRate,F_CPU); sei(); //in <avr/interrupt.h> while (1){ if (uart1_State==uart1_stRxEnd){ switch (uart1_Rx[0]){ //the 1st received char by USART1 case cmRxTxTest: //cmd=0x10 uart1_EchoRxTx(); break; default: break; } uart1_Init(); } } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
makc 222 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба Уберите простыни кода под спойлеры. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба uart1_State,uart1_cntRx должны быть volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 44 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба 3 hours ago, bvn123 said: компилируются без ошибок и предостережений (warnings) А в IAR включена выдача всех ошибок и предупреждений? Раньше в нём по умолчанию очень много проверок было выключено, и компиляция проходила тихо, без ошибок и предупреждений, а код падал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bvn123 0 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба On 9/10/2022 at 3:24 PM, VladislavS said: uart1_State,uart1_cntRx должны быть volatile. Большое спасибо, с volatile проект GCC в микроконтроллере заработал. Особенностей GCC не знаю, в IAR же volatile требуется для размещении констант в RAM, переменные можно объявлять без нее, хотя теперь буду объявлять как volatile переменные и в IAR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 62 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба On 9/10/2022 at 9:23 PM, bvn123 said: Проверил в дизассемблере: uart1_State хранится в начальной ячейке SRAM (адрес 0x3С00 для ATmega808), uart1_cntRx и массив uart1_Rx[] тоже в SRAM, Дело не в том, где разместилась переменная, а в том как она используется. Какой уровень оптимизации у вас включен ? Вот простейшим пример использования volatile uint8_t flag; ISR(TIMER0_OVF0_vect) { flag = 1; } int main(void) { while(flag == 0); return 0; } Оптимизация Os Вот дизассемблер int main(void) { while(flag == 0); 30a: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__DATA_REGION_ORIGIN__> 30e: 81 11 cpse r24, r1 310: 01 c0 rjmp .+2 ; 0x314 <main+0xa> 312: ff cf rjmp .-2 ; 0x312 <main+0x8> return 0; } Компилятор видит, что функция ISR(TIMER0_OVF0_vect) нигде в программе не вызывается, следовательно переменная flag, по мнению компилятора. никогда не меняется. И поэтому компилятор просто зацикливает программу 312: ff cf rjmp .-2 ; 0x312 <main+0x8> Теперь для переменной flag добавляем квалификатор volatile. И возвращаемся к дизассемблеру. while(flag == 0); 30a: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__DATA_REGION_ORIGIN__> 30e: 88 23 and r24, r24 310: e1 f3 breq .-8 ; 0x30a <main> Квалификатор volatile запрещает компилятору оптимизировать работу с переменной flag. И теперь в цикле while происходит постоянное чтение значения переменной из памяти и проверка её значения. On 9/10/2022 at 9:23 PM, bvn123 said: В GCC в дизассемблере проверил, что строка 'sei();' преобразуется в ассемблерную команду SEI - появились сомнения в разрешении глобальных прерываний в GCC. Что за сомнения ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bvn123 0 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба On 9/10/2022 at 10:24 PM, dimka76 said: Дело не в том, где разместилась переменная, а в том как она используется. Спасибо, интересный пример, уже проверил рекомендацию VladislavS об обязательном использовании volatile при объявлении переменных - работает, в результате отредактировал свой предыдущий пост, затем увидел Ваш ответ. sei() - сначала делал ассемблерную вставку asm("SEI"), т.к. не мог найти в каком подключаемом файле находится и есть ли вообще, затем было впечатление, что почему-то не работают прерывания. Что вопрос только в volatile, не ожидал. Проект в GCC из трех проектов (IAR и XC8) самый актуальный: все завязано на bootloader, а под GCC есть пример, в котором расписано, какие директивы указывать Linker-у и для bootloader, чтобы не размещались вектора прерываний, и для приложения именно под серию AVR-0. При этом bootloader минимальный для AVR-0 - 256 байт. Для IAR разобрался с приложением - как сместить его для ATmega808 за bootloader, но как указать, что bootloader без прерываний - не разобрался, IAR автоматом размещает вектора, а они съедают бОльшую часть 256-ти байт. В старой ATmega8 и др. МК этой серии таких проблем со смещением программы за бутлодер не было - это поддерживалось аппаратно. Теперь же под ATmega808 одна программа для прямой загрузки, другая - для загрузки через bootloader. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба 23 минуты назад, bvn123 сказал: об обязательном использовании volatile при объявлении переменных Все переменные volatile это перебор. Только глобальные, которые меняются в прерываниях, и регистры периферии. IAR часто пропущеный volatile прощает. Уж не знаю, потому что недорабатывет или наоборот умнее. GCC к пропущеным volatile беспощаден. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bvn123 0 10 сентября, 2022 Опубликовано 10 сентября, 2022 · Жалоба On 9/10/2022 at 11:03 PM, VladislavS said: Все переменные volatile это перебор. Только глобальные, которые меняются в прерываниях, и регистры периферии. IAR часто пропущеный volatile прощает. Уж не знаю, потому что недорабатывет или наоборот умнее. GCC к пропущеным volatile беспощаден. Спасибо, почитаю подробнее о volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SII 0 23 сентября, 2022 Опубликовано 23 сентября, 2022 · Жалоба В 10.09.2022 в 23:11, bvn123 сказал: Спасибо, почитаю подробнее о volatile. Сие ключевое слово указывает компилятору, что значение переменной может измениться в любой момент неочевидным для компилятора образом. Например: int a; ... if ( a == 0 ) { ... } ... if ( a != 0 ) { ... } Если переменная a объявлена, как написано, т.е. без volatile, компилятор может загрузить её значение в регистр, а затем использовать для обоих проверок. Если же указать volatile, для каждой из проверок значение будет в обязательном порядке загружаться из памяти. Соответственно, если после первого, но перед вторым if значение изменилось (обработчиком прерывания или другим потоком), то без volatile это изменение может быть замечено, а может остаться незамеченным (в зависимости от того, какой код будет сгенерирован -- а это зависит в т.ч. от уровня оптимизации), а с volatile будет гарантированно замечено. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться