Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как вразумить avr-gcc ?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
impatt
Пробую avr-gcc-3.3.1 и avr-gcc-4.1.1.
C-шный текст прост:
в цикле проверяется значение переменной и если оно, скажем, не ноль, то цикл продолжает крутиться. Если бы переменная не была изменяемая извне (прерыванием), то тогда бы такой код совершенно надёжно был бы вечно зацикленным. Однако прерывание меняет переменную. Но компилятор почему-то даже объявленную переменную как volatile, засасывает в регистры и потом, в цикле, проверяет содержимое регистров, куда ты была засосана. А прерывание, как все нормальные функции, берёт переменную в ОЗУ по её адресу, меняет, и кладёт назад. таким образом, цикл не почувстует изменение переменной, что не есть гут.
Если я ставлю отпимизацию -O0, то всё ОК, ошибки нет. Если -O2, -Os, то всё, неправильно - заоптимизируется до регистров. Оставлять оптимизацию -O0 - не кошерно, не годится.
Что сделать, чтобы компилятор перестал игнорировать спецификатор(модификатор) volatile ?

Спасибо.
prottoss
Цитата(impatt @ Oct 23 2006, 16:55) *
Пробую avr-gcc-3.3.1 и avr-gcc-4.1.1...
...Что сделать, чтобы компилятор перестал игнорировать спецификатор(модификатор) volatile ?
Спасибо.
Честно говоря, не имел дело с gcc, но в ИАР данная проблема решается префиксом __root. Может быть в gcc есть аналог?
aesok
GCC не игнорирует volatile!!! Ошибка в чем то другом. Показывайте код.

Анатолий.
impatt
Цитата(prottoss @ Oct 23 2006, 12:02) *
Цитата(impatt @ Oct 23 2006, 16:55) *
Пробую avr-gcc-3.3.1 и avr-gcc-4.1.1...
...Что сделать, чтобы компилятор перестал игнорировать спецификатор(модификатор) volatile ?
Спасибо.
Честно говоря, не имел дело с gcc, но в ИАР данная проблема решается префиксом __root. Может быть в gcc есть аналог?


Может, и есть, но сомневаюсь. но даже если и есть, то я не знаю, что такое __root, и, потому не могу узнать, есть ли аналог.
Вообще, прежде всего непонятно, какого рожна он таки забил на моё указание, что переменная volatile. Такие вольности с обращением с кодом немного настораживают: сегодня я вот увидел, что за глюк (в С-тексте глюка нет, а в asm-е уже появился), а завтра не увижу, и начнётся потеря времени и прочие ухищрения. Коллега, например, сидит на IAR-е, так у него прога (операционная система с полумегабайтной страничной памятью на Atmega128) не работает, пока не поставит оптимизацию в "0". Я вот радовался, что gcc стабильнее и правильнее, но, вижу, gcc тоже не без греха.
Жаль.
zltigo
Цитата(prottoss @ Oct 23 2006, 12:02) *
данная проблема решается префиксом __root. Может быть в gcc есть аналог?

Вообще-то эта проблема решается именно volatile, __root это из другой оперы.
То, что volatile не сработал - это криминально :-(.
Цитата
Что сделать, чтобы компилятор перестал игнорировать спецификатор(модификатор) volatile

Попробуйте минимизировать потери от отключения оптимизации изменив оптимизацию не глобально, а
#pragma на конкретный кусочек текста.


Цитата(impatt @ Oct 23 2006, 12:10) *
Коллега, например, сидит на IAR-е, так у него прога (операционная система с полумегабайтной страничной памятью на Atmega128) не работает, пока не поставит оптимизацию в "0". Я вот радовался, что gcc стабильнее и правильнее, но, вижу, gcc тоже не без греха.

Не 'без греха' гораздо чаще писатель не явно выражающий свою мысль и зачастую подавляющий
warnings/notes. Грехи многих компиляторов чаще заключаются в излишней молчаливости по отношению
к местам в которых они 'сомневаются'.
impatt
Цитата(aesok @ Oct 23 2006, 12:07) *
GCC не игнорирует volatile!!! Ошибка в чем то другом. Показывайте код.

Анатолий.


Показываю (прошу прощения за кривое форматирование: не могу своим умом постигнуть, как в этом форуме делать вёрстку, может, оттого, что не знаю html ?) :

Фрагмент файл uart.c:
******
Код
#include "interface/uart.h"
uint8_t pushToDebugBuffer(uint8_t symbol){
DEBUG_TX_INT_LOCK();
while(debugPushCursor == debugPopCursor){
  DEBUG_TX_INT_UNLOCK();
  SLEEP();
  DEBUG_TX_INT_LOCK();
}
*debugPushCursor = symbol;
debugPushCursor = nextAddress(debugPushCursor);
DEBUG_TX_INT_UNLOCK();
if(!globIntFlags.isDebugPortBusy) popFromDebugBuffer(); //если передача когда-то закончилась, то возобновляем её
return symbol;
}

******

Фрагмент файла uart.h (макрос CLARBIT, SETBIT просто логическая операция над портом, определно где-то, ) :
*******
Код
//SPECPREFIX пустой, если заголовок подключается из uart.c, и равен extern, если другими
SPECPREFIX uint8_t debugBuffer[32];
SPECPREFIX volatile uint8_t *debugPushCursor;
SPECPREFIX volatile uint8_t *debugPopCursor;

#define DEBUG_TX_INT_LOCK(s)  CLEARBIT(UCSR1B, TXCIE1)
#define DEBUG_TX_INT_UNLOCK(s)  SETBIT(UCSR1B, TXCIE1)
*******

Фрагмент кода прерывания:

******
#include "interface/uart.h"
INTERRUPT(/*SIG_UART0_TRANS*/SIG_USART1_TRANS){
// например,  
debugPopCursor++;
}
******
aesok
SPECPREFIX volatile uint8_t *debugPushCursor;

Если не ошибаюсь:
в этом коде volatile помечен не указатель а то на что этот указатель указывает, попробуйте так:

SPECPREFIX uint8_t volatile *debugPushCursor;


Если есть книга по С/C++ под рукой попробуйте найти про модификатор const и указатили.

Анатолий.
zltigo
Цитата(impatt @ Oct 23 2006, 12:19) *
Показываю (прошу прощения за кривое форматирование: не могу своим умом постигнуть, как в этом форуме делать вёрстку, может, оттого, что не знаю html ?) :

Через code и /code, естественно в []
В баре есть и значек диез '#' для этого.
impatt
Цитата(aesok @ Oct 23 2006, 12:32) *
SPECPREFIX volatile uint8_t *debugPushCursor;

Если не ошибаюсь:
в этом коде volatile помечен не указатель а то на что этот указатель указывает, попробуйте так:

SPECPREFIX uint8_t volatile *debugPushCursor;

Если есть книга по С/C++ под рукой попробуйте найти про модификатор const и указатили.


Спасибо за совет, мне эта мысль показалось интересной. Но, к сожалению, не помогло.
Указатели засасываются в регистры и потом всё мелется в этих регистрах.
Это я про смену мест volatile и типа.
Про const сейчас тоже гляну. Хоть и непонятно, но интересно почитать будет, ибо мозги уже клинит от этой ситуации, хоть развеюсь.

Цитата(zltigo @ Oct 23 2006, 12:35) *
Цитата(impatt @ Oct 23 2006, 12:19) *

Показываю (прошу прощения за кривое форматирование: не могу своим умом постигнуть, как в этом форуме делать вёрстку, может, оттого, что не знаю html ?) :

Через code и /code, естественно в []
В баре есть и значек диез '#' для этого.


Эх, когда бы это всё постичь... :)
klen
Вот результат компиляции по мотивам приведеннго выше кода

сорцы
Код
#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t volatile debugPopCursor;
// достуап к debugPopCursor в режиме приложения
void AppMode (uint8_t* Tmp )
{
while(*Tmp == debugPopCursor)
  {
   debugPopCursor++;
  }

  Tmp = &debugPopCursor;
  debugPopCursor -= 10;
}

// достуап к debugPopCursor в режиме прерывания
ISR(USART_TX_vect)
{
    debugPopCursor++;
}

листинг
Код
uint8_t volatile debugPopCursor;
// достуап к debugPopCursor в режиме приложения
void AppMode (uint8_t* Tmp )
{
148:    fc 01           movw    r30, r24
14a:    05 c0           rjmp    .+10     ; 0x156 <AppMode+0xe>
while(*Tmp == debugPopCursor)
  {
   debugPopCursor++;
14c:    80 91 0d 01     lds    r24, 0x010D
150:    8f 5f           subi    r24, 0xFF; 255
152:    80 93 0d 01     sts    0x010D, r24
156:    90 91 0d 01     lds    r25, 0x010D
15a:    80 81           ld    r24, Z
15c:    89 17           cp    r24, r25
15e:    b1 f3           breq    .-20     ; 0x14c <AppMode+0x4>
  }

  Tmp = &debugPopCursor;
  debugPopCursor -= 10;
160:    80 91 0d 01     lds    r24, 0x010D
164:    8a 50           subi    r24, 0x0A; 10
166:    80 93 0d 01     sts    0x010D, r24
16a:    08 95           ret

0000016c <__vector_20>:
}

// достуап к debugPopCursor в режиме прерывания
ISR(USART_TX_vect)
{
16c:    1f 92           push    r1
16e:    0f 92           push    r0
170:    0f b6           in    r0, 0x3f; 63
172:    0f 92           push    r0
174:    11 24           eor    r1, r1
176:    8f 93           push    r24
    debugPopCursor++;
178:    80 91 0d 01     lds    r24, 0x010D
17c:    8f 5f           subi    r24, 0xFF; 255
17e:    80 93 0d 01     sts    0x010D, r24
182:    8f 91           pop    r24
184:    0f 90           pop    r0
186:    0f be           out    0x3f, r0; 63
188:    0f 90           pop    r0
18a:    1f 90           pop    r1
18c:    18 95           reti

Переменная заложена в 0x010D и никаких глюков. Давайте разбиратся.
impatt
Цитата(klen @ Oct 23 2006, 12:51) *
Вот результат компиляции по мотивам приведеннго выше кода
Давайте разбиратся.


Давайте. Я сейчас погляжу, поразмыслю, и напишу, что надумал.
Спасибо за участие, насколькоя понял - вы из команды разработчиков GCC ?
Тем более приятно smile.gif
impatt
Цитата(klen @ Oct 23 2006, 12:51) *
Вот результат компиляции по мотивам приведеннго выше кода
Давайте разбиратся.


Почитал Вашу компиляцию и понял, что это всё-же не совсем то, что было у меня (хотя и допускаю, что принципиальных отличий нет). Предлагаю вернуться к истокам, а именно попытаться скомпилить код, который я приведу ниже. Это будет, наверное, наибольшее приближение. Напоминаю условия:
Есть три файла: в первом обработчик прерывания, во втором заголовок, в котором определены участвующие переменные, и третий, где содержаться функции "пользовательского пространства" (а обработчик, соответственно, хочется назвать частью "ядра" smile.gif.
Пользовательский код добавляет в циклический буфер символ по указателю вставки, курсору push. Прерывание выгребает тот-же буфер по мере ухода символов. Выгребает по другому указателю-курсору (pop). Когда при вставке указатели равны, то это значит, что буфер заполнен и приложение попадает в блокировку на вывод (здесь - крутится в цикле).
Проблема проявилась в том, что при работе функции записи в буфер сравнивание указателей-курсоров производится без учёта того, что один из них может меняться прерыванием.

Пользовательский код:
Код
//----uart.c--------
uint8_t debugBuffer[32];   //кольцевой буфер
uint8_t volatile  *debugPushCursor;  //_указатель_ для функции записи
uint8_t volatile  *debugPopCursor;  //_указатель_ для функции чтения

//запись символа в кольцевой буфер
void pushToDebugBuffer(uint8_t symbol){
DEBUG_TX_INT_LOCK();  //макрос, запрещающий прерывание и изменение курсора чтения
while(debugPushCursor == debugPopCursor){//если буфер полон, то ожидаем прерывания
  DEBUG_TX_INT_UNLOCK();  //разрешаем прерывания и изменения курсора чтения
  SLEEP();      //ожидание прерывания
  DEBUG_TX_INT_LOCK();  //прерывание пришло, запрещаем изменение курсора чтения (может, можно убрать)
}
*debugPushCursor = symbol;  //буфер не полон, записываем символ
debugPushCursor = nextAddress(debugPushCursor); //приращиваем курсор записи (из-за того, что быфер кольцевой, простая операция ++ не канает
DEBUG_TX_INT_UNLOCK(); //разрешаем работу прерывания и изменение курсора чтения
return;
}

//функция чтения из кольцевого буфера
//вызывается только из прерывания
void popFromDebugBuffer(void){
uint8_t *nextPopCursorPosition;
if((nextPopCursorPosition = nextAddress(debugPopCursor)) != debugPushCursor){
  //если следующая позиция настроена на ожидание ввода от курсора pushCursor, то весь буфер передан (догнали курсор снизу), выходим.
  //здесь оказываемся, если ещё есть чего передавать
  globIntFlags.isDebugPortBusy=true;
  UDR1 = *debugPopCursor; //передаём в UART из текущего курсора чтения
  debugPopCursor = nextPopCursorPosition; //прибавлем курсор на будущее
} else {
  globIntFlags.isDebugPortBusy=false;
}
return;
}

//приращение курсора, в данном примере просто для иллюстрации
//вычислитель следующего адреса в кольцевом буфере на основе заданного указателя
uint8_t *nextAddress (uint8_t *pointer){
pointer++;
if(pointer == debugBuffer + sizeof(debugBuffer)){ //если указатель вылез за верх. границу буфера, ставим на начало
  pointer = debugBuffer; //здесь ставим на начало
}
return pointer;
}


Код прерывания:
Код
//-----interrupt.c-------
extern uint8_t debugBuffer[32];   //кольцевой буфер
extern uint8_t volatile  *debugPushCursor;  //_указатель_ для функции записи
extern uint8_t volatile  *debugPopCursor;  //_указатель_ для функции чтения

//прерывание по отправке байта в порт
INTERRUPT(SIG_USART1_TRANS){
popFromDebugBuffer(); //функция приращения курсора чтения и отправки байта в порт, здесь не важно, из чего она состоит. Кстати, код функции описан в первом файле. Наверное, это не принципиально ?
}


Так вот, я, конечно, понимаю, что повторился немного, но здесь старался прокомментировать подробнее.
Попробуйте, что получится. Если получится хорошо, то я тоже скомпилирую пример (сейчас смена кончается, не успеваю).
Ещё раз сенкс за участие. Надеюсь, не слишком сумбурно излагаю.
aesok
Что генерирует GCC смогу посмотреть вечером. (точнее ночью при свете костра blink.gif )

А пока проверте так:
volatile uint8_t volatile *debugPushCursor


Тоесть пометить volatile и указатель и то на что он указывает.

Анатолий.
Сергей Борщ
Цитата(impatt @ Oct 23 2006, 13:47) *
Пользовательский код:
Код
uint8_t volatile  *debugPushCursor;  //_указатель_ для функции записи

Ещё раз сенкс за участие. Надеюсь, не слишком сумбурно излагаю.
Увы, вы описали точно такой же указатель как и раньше. Вам нужно

Код
uint8_t * volatile  debugPushCursor;  //_указатель_ для функции записи
Чтобы проще было понимать куда вставлять volatile или const пробуйте читать запись справа налево. В нашем случае у Вас был "указатель на volatile uint8_t", у меня - "volatile-указатель на uint8_t".
impatt
Цитата(Сергей Борщ @ Oct 23 2006, 14:56) *
Цитата(impatt @ Oct 23 2006, 13:47) *


Пользовательский код:
Код
uint8_t volatile  *debugPushCursor;  //_указатель_ для функции записи

Ещё раз сенкс за участие. Надеюсь, не слишком сумбурно излагаю.
Увы, вы описали точно такой же указатель как и раньше. Вам нужно

Код
uint8_t * volatile  debugPushCursor;  //_указатель_ для функции записи
Чтобы проще было понимать куда вставлять volatile или const пробуйте читать запись справа налево. В нашем случае у Вас был "указатель на volatile uint8_t", у меня - "volatile-указатель на uint8_t".


Ура, получилось. Очень благодарен за помощь !
Признаться, я догадывался, что неправ именно я, но не был уверен точно, так как испробовал всё, что знал.
Теперь вопрос-завершение: откуда узнаются такие тонкости ? У меня книга Герберта Шилдта по "С", там таких тонкостей нет (или я таки проглядел ?). Может, есть специальные книги с подборкой таких тонкостей ?

Ещё раз большое спасибо всем высказавшим своё мнение: проблему решили очень оперативно и грамотно.
zltigo
Цитата(impatt @ Oct 24 2006, 05:06) *
Теперь вопрос-завершение: откуда узнаются такие тонкости ?

Вещь достаточно очевидная, что указатель и то, на что он указывает есть разные вещи.
Далее голый синтаксис для описания кто есть кто.
Цитата
У меня книга Герберта Шилдта по "С", там таких тонкостей нет (или я таки проглядел ?). Может, есть специальные книги с подборкой таких тонкостей ?

Мне в свое время году в ~90 для прочистки мозгов очень помог еще советский "стандарт" на язык "C".
Прекрасно четко изложено, четкие пояснения и никакой лирики.
impatt
Цитата(zltigo @ Oct 24 2006, 10:11) *
Вещь достаточно очевидная, что указатель и то, на что он указывает есть разные вещи.

Это-то да.

Цитата(zltigo @ Oct 24 2006, 10:11) *
Далее голый синтаксис для описания кто есть кто.

Мне почему-то не казалось это очевидным. Наверное, плохо глядел.
Andy Great
Цитата
Теперь вопрос-завершение: откуда узнаются такие тонкости ?

Из форм Бэкуса-Наура, описывающих стандарт. Или чем там сейчас описывают. Кстати, сравните описание Си, например, или Ява с Обероном - размер описания разителен. Соответственно, простота понимания и написания парсера.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.