реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Как вразумить avr-gcc ?, Компилятор заоптимизировал volatile переменную
impatt
сообщение Oct 23 2006, 08:55
Сообщение #1


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



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

Спасибо.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Oct 23 2006, 09:02
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



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


--------------------
Go to the top of the page
 
+Quote Post
aesok
сообщение Oct 23 2006, 09:07
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



GCC не игнорирует volatile!!! Ошибка в чем то другом. Показывайте код.

Анатолий.
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 23 2006, 09:10
Сообщение #4


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



Цитата(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 тоже не без греха.
Жаль.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 23 2006, 09:18
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(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. Грехи многих компиляторов чаще заключаются в излишней молчаливости по отношению
к местам в которых они 'сомневаются'.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 23 2006, 09:19
Сообщение #6


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



Цитата(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++;
}
******
Go to the top of the page
 
+Quote Post
aesok
сообщение Oct 23 2006, 09:32
Сообщение #7


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



SPECPREFIX volatile uint8_t *debugPushCursor;

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

SPECPREFIX uint8_t volatile *debugPushCursor;


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

Анатолий.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 23 2006, 09:35
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



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

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 23 2006, 09:48
Сообщение #9


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



Цитата(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, естественно в []
В баре есть и значек диез '#' для этого.


Эх, когда бы это всё постичь... :)

Сообщение отредактировал impatt - Oct 23 2006, 09:48
Go to the top of the page
 
+Quote Post
klen
сообщение Oct 23 2006, 09:51
Сообщение #10


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



Вот результат компиляции по мотивам приведеннго выше кода

сорцы
Код
#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 и никаких глюков. Давайте разбиратся.
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 23 2006, 10:07
Сообщение #11


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



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


Давайте. Я сейчас погляжу, поразмыслю, и напишу, что надумал.
Спасибо за участие, насколькоя понял - вы из команды разработчиков GCC ?
Тем более приятно smile.gif
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 23 2006, 10:47
Сообщение #12


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



Цитата(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(); //функция приращения курсора чтения и отправки байта в порт, здесь не важно, из чего она состоит. Кстати, код функции описан в первом файле. Наверное, это не принципиально ?
}


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

Сообщение отредактировал impatt - Oct 23 2006, 11:00
Go to the top of the page
 
+Quote Post
aesok
сообщение Oct 23 2006, 11:45
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Что генерирует GCC смогу посмотреть вечером. (точнее ночью при свете костра blink.gif )

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


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

Анатолий.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 23 2006, 11:56
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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

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

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
impatt
сообщение Oct 24 2006, 02:06
Сообщение #15


Частый гость
**

Группа: Validating
Сообщений: 169
Регистрация: 10-11-04
Из: Челябинск
Пользователь №: 1 088



Цитата(Сергей Борщ @ 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".


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

Ещё раз большое спасибо всем высказавшим своё мнение: проблему решили очень оперативно и грамотно.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 09:57
Рейтинг@Mail.ru


Страница сгенерированна за 0.01836 секунд с 7
ELECTRONIX ©2004-2016