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

 
 
> Как вразумить 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
 
Start new topic
Ответов
aesok
сообщение Oct 23 2006, 09:07
Сообщение #2


Знающий
****

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



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

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


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

Группа: 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
klen
сообщение Oct 23 2006, 09:51
Сообщение #4


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

Группа: Свой
Сообщений: 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:47
Сообщение #5


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

Группа: 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
Сергей Борщ
сообщение Oct 23 2006, 11:56
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 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
Сообщение #7


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

Группа: 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
zltigo
сообщение Oct 24 2006, 07:11
Сообщение #8


Гуру
******

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



Цитата(impatt @ Oct 24 2006, 05:06) *
Теперь вопрос-завершение: откуда узнаются такие тонкости ?

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

Мне в свое время году в ~90 для прочистки мозгов очень помог еще советский "стандарт" на язык "C".
Прекрасно четко изложено, четкие пояснения и никакой лирики.


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


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

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



Цитата(zltigo @ Oct 24 2006, 10:11) *
Вещь достаточно очевидная, что указатель и то, на что он указывает есть разные вещи.

Это-то да.

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

Мне почему-то не казалось это очевидным. Наверное, плохо глядел.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- impatt   Как вразумить avr-gcc ?   Oct 23 2006, 08:55
- - prottoss   Цитата(impatt @ Oct 23 2006, 16:55) Пробу...   Oct 23 2006, 09:02
|- - impatt   Цитата(prottoss @ Oct 23 2006, 12:02) Цит...   Oct 23 2006, 09:10
|- - zltigo   Цитата(prottoss @ Oct 23 2006, 12:02) дан...   Oct 23 2006, 09:18
|- - aesok   SPECPREFIX volatile uint8_t *debugPushCursor; Есл...   Oct 23 2006, 09:32
||- - impatt   Цитата(aesok @ Oct 23 2006, 12:32) SPECPR...   Oct 23 2006, 09:48
|- - zltigo   Цитата(impatt @ Oct 23 2006, 12:19) Показ...   Oct 23 2006, 09:35
|- - impatt   Цитата(klen @ Oct 23 2006, 12:51) Вот рез...   Oct 23 2006, 10:07
|- - aesok   Что генерирует GCC смогу посмотреть вечером. (точ...   Oct 23 2006, 11:45
- - Andy Great   ЦитатаТеперь вопрос-завершение: откуда узнаются та...   Oct 24 2006, 08:06


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

 


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


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