Перейти к содержанию
    

Проект GCC: компиляция ошибок не дает, в микроконтроллере не работает. Этот же проект в XC8 и IAR for AVR работает. В чем может быть проблема?

Добрый день.

Мне понадобилось перегнать работающий проект из 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();
    }
  }
}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, bvn123 said:

компилируются без ошибок и предостережений (warnings)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/10/2022 at 3:24 PM, VladislavS said:
uart1_State,uart1_cntRx должны быть volatile.

Большое спасибо, с volatile проект GCC в микроконтроллере заработал.

Особенностей GCC не знаю,

в IAR же volatile требуется для размещении констант в RAM, переменные можно объявлять без нее, хотя теперь буду объявлять как volatile переменные и в IAR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

Что за сомнения ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

23 минуты назад, bvn123 сказал:

об обязательном использовании volatile при объявлении переменных

Все переменные volatile это перебор. Только глобальные, которые меняются в прерываниях, и регистры периферии. IAR  часто пропущеный volatile прощает. Уж не знаю, потому что недорабатывет или наоборот умнее.   GCC к пропущеным volatile беспощаден. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 9/10/2022 at 11:03 PM, VladislavS said:

Все переменные volatile это перебор. Только глобальные, которые меняются в прерываниях, и регистры периферии. IAR  часто пропущеный volatile прощает. Уж не знаю, потому что недорабатывет или наоборот умнее.   GCC к пропущеным volatile беспощаден. 

Спасибо, почитаю подробнее о volatile.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 10.09.2022 в 23:11, bvn123 сказал:

Спасибо, почитаю подробнее о volatile.

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

int  a;
...
if ( a == 0 )
{
    ...
}
...
if ( a != 0 )
{
    ...
}

Если переменная a объявлена, как написано, т.е. без volatile, компилятор может загрузить её значение в регистр, а затем использовать для обоих проверок. Если же указать volatile, для каждой из проверок значение будет в обязательном порядке загружаться из памяти. Соответственно, если после первого, но перед вторым if значение изменилось (обработчиком прерывания или другим потоком), то без volatile это изменение может быть замечено, а может остаться незамеченным (в зависимости от того, какой код будет сгенерирован -- а это зависит в т.ч. от уровня оптимизации), а с volatile будет гарантированно замечено.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...