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

Странное предупреждение

При отладке одно из главнейших правил: ПРИ ПРОЯВЛЕНИИ БАГА НЕ СЛЕДУЕТ СТАРАТЬСЯ ДОБИТЬСЯ ТОГО, ЧТОБЫ ОН НЕ ПРОЯВЛЯЛСЯ. НАДО НАОБОРОТ - ЗАКРЕПИТЬ УСЛОВИЯ, ПРИ КОТОРЫХ ОН ПРОЯВЛЯЕТСЯ, ДОБИТЬСЯ ЕГО ПОВТОРЯЕМОСТИ И ИСКАТЬ ЕГО ПРИЧИНУ И УСТРАНИТЬ! И пока этого не сделано - двигаться дальше нельзя.
так я нашел причину и устранил. ))

 

inline void waitSpi() { while( (SPI1->SR & (uint8_t)SPI_FLAG_BSY));} - вот этот код не работает с оптимизацией в пустом хороводе. И не изредка - а всегда. 100 раз из 100. А без оптимизации работает как часы. ни каких сбоев в обмене по SPI замечено не было.

 

Ведь не тот баг страшен, который чётко проявляется, а тот - что проявляется иногда, внезапно и хаотично.
У меня црц считается с ошибкой всегда, когда вкл оптимизация, не изредка, а всегда. И всегда считается правильно с отключенной оптимизацией. Нету хаотичных и внезапных сбоев.

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


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

Любопытства ради и самообразования для, не могли бы вы привести код црц и чем копилируете?

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


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

inline void waitSpi() { while( (SPI1->SR & (uint8_t)SPI_FLAG_BSY));} - вот этот код не работает с оптимизацией в пустом хороводе. И не изредка - а всегда. 100 раз из 100. А без оптимизации работает как часы. ни каких сбоев в обмене по SPI замечено не было.

Я так понимаю, версия про "volatile" была проверена и не подтвердилась? Опять же, конкретно в этом случае чтение листинга дизассемблера не затруднило бы нисколько. Из оправданий - только лень.

Кстати, бывают баги, зависящие от задержек. Скажем, регистр SPI1->SR нужно начинать читать не сразу, а через пару тактов, без оптимизации задержка получалась сама собой - как вариант.

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


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

Любопытства ради и самообразования для, не могли бы вы привести код црц и чем копилируете?

читайте выше. там и код и чем компилирую.

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


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

ээээ.... а разве при переполнении стека программа аварийно не завершается?

При переполнении стека симптомы могут быть какие угодно: может fault вылететь, а могут просто данные испортиться.

 

А без оптимизации шагается но и работает без ошибок.

Я уже писал выше что можно сделать. Скомпилить данную функцию с оптимизацией. А потом вырезать её ассемблерный листинг и вставить в код компилируемый без оптимизации (как асм-функцию). И проверить работу кода теперь.

И по асму шагать не надо, надо выучить ассемблер и "глазами" аналитически сравнить си-исходник с асм-результатом. И только если в этом случае будут найдены несоответствия между ними - только в этом случае можно однозначно говорить о вине компилятора.

 

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

Если Вы считаете, что в недостаточном объёме выделенной под стек памяти виноват оптимизатор, а не "пейсатель" кода, то больше разговаривать не о чем..... :smile3046:

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


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

И по асму шагать не надо, надо выучить ассемблер и "глазами" аналитически сравнить си-исходник с асм-результатом. И только если в этом случае будут найдены несоответствия между ними - только в этом случае можно однозначно говорить о вине компилятора.

Советую взять современный GCC и дать ему ключики -Os -flto. При любом более-менее нетривиальном коде "аналитическое сравнение" легко способно перейти в бессонные ночи :biggrin:

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


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

компилятор генерит правильный s-файл. Иначе генерит таблицу, в которой смещения не помещаются.

Где тут моя ошибка? Где ошибка компилятора я разобрался и на всякий случай сменил компилятор (была сборка arm-kgp-eabi-procyon).

Из Вашего описания я понял, что асм-файл писали Вы сами....

Для таких малопопулярных ядер как ESP8266, вполне допускаю что компилятор гораздо более сырой, чем для main stream Cortex-M например.

 

Советую взять современный GCC и дать ему ключики -Os -flto. При любом более-менее нетривиальном коде "аналитическое сравнение" легко способно перейти в бессонные ночи :biggrin:

У juvf функция очень тривиальная и маленькая. В худшем случае будет бессонный час. :laughing:

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


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

Для таких малопопулярных ядер как ESP8266, вполне допускаю что компилятор гораздо более сырой, чем для main stream Cortex-M например.

Пожалуйста, похожая история с Cortex-M: тыц.

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


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

У меня црц считается с ошибкой всегда, когда вкл оптимизация, не изредка, а всегда. И всегда считается правильно с отключенной оптимизацией. Нету хаотичных и внезапных сбоев.

Это не устранение причины. Это как вместо лечения причины болезни, бороться с её симптомами.

Если Вы подозреваете, что виноват компилятор, то устранение бага в таком случае - замена компилятора. Ведь если он косячит в данной функции, то где гарантия что не косячит в других местах? Просто эти косяки сейчас не проявляются (например - по этим веткам ветвления не проходит управление, но при каком-то стечении обстоятельств в будущем оно пройдёт и баг получит уже пользователь).

Но вину компилятора сперва нужно однозначно доказать.

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


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

При переполнении стека симптомы могут быть какие угодно: может fault вылететь, а могут просто данные испортиться.
я же писал, данные не портятся, в фолаут не вылетаю, а црц считает с ошибкой.

 

Если Вы считаете, что в недостаточном объёме выделенной под стек памяти виноват оптимизатор, а не "пейсатель" кода, то больше разговаривать не о чем..... :smile3046:
Я достаточно выделил памяти на стек. Без оптимизации глубины стека хватает с запасом. Если оптимизатор удвоил запросы ОЗУ на стек, то мне такой оптимизатор не нужен. :laughing:

Во вторых, бывало вылазил за стек.... на разных проекта.... либо фолаут, либо данные портились. Это быстро обнаруживается. Тут идет подсчет црц, но неправильный. Ни чего не портиться и не падает.

 

 

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


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

Пожалуйста, похожая история с Cortex-M: тыц.

Да я не спорю, что и в компиляторах есть косяки. Я даже сам несколько лет назад выкладывал сюда на форум описание одного из них.

Но я чётко доказал, что это именно косяк компилятора (это был IAR вроде v6.20 или v6.40).

И выложил и фрагмент си-кода и результат компиляции (ассемблер) и ключи компиляции, при которых этот результат получен. Чтобы каждый смог лично проверить.

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


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

Ведь если он косячит в данной функции, то где гарантия что не косячит в других местах?
Нет гарантии. Все места проверяются глубоким тестированием. А если компилятор оптимизатор не косячит - то нет ни какой гарантии, что нет косяков пейсателя/компилятора в других местах. Все места проверяются глубоким тестированием, стрестестами и т.п. , Это касается любого компилятора/оптимизатора, любого кода.

 

 

Я так понимаю, версия про "volatile" была проверена и не подтвердилась? ....
конечно первым делом volatile.

SPI1->SR нужно начинать читать не сразу, а через пару тактов, без оптимизации задержка получалась сама собой - как вариант.
Чуть не написал "Слона не увидел", но слона нет. Во первых в даташите про это ни чего не говориться, во вторых.... сначала готовлю данные, потом их отправляю в спи, не дожидаясь завершения ..... на русском сложно писать, написшу на си

 

sleepMs(1000);
for()
{
//подготовка данных
waitSpi();
//запись данных в спи регистр.
}

в waitSpi() с оптимизацией не задерживаюсь ни когда, а должен не задерживаться только первый раз. После отправки данных до чтения регистра SPI1->SR проходит много времени, но меньше, чем выход 8 бит в спи.

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


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

inline void waitSpi() { while( (SPI1->SR & (uint8_t)SPI_FLAG_BSY));} - вот этот код не работает с оптимизацией в пустом хороводе. И не изредка - а всегда. 100 раз из 100. А без оптимизации работает как часы. ни каких сбоев в обмене по SPI замечено не было.

Описание типов данных, какое ядро/МК, описание SPI_FLAG_BSY и декларации SPI1 где? Асм-результат с оптимизацией где?

Или с декларациями что-то не так или у вас в этом коде например гонки или куча других причин. :laughing:

И опять - пример никак не свидетельствует о вине компилятора.

Вот приведу такой случай из своей практики:

Писал я как-то под CC5502 (TI DSP). Был простейший цикл типа Вашего выше: просто в цикле опрашивался флаг, типа: while (!flag);

Этот flag в состояние !=0 устанавливался в ISR завершения DMA-транзакции (цикл ждал завершения DMA).

И вот у меня возникла ситуация подобная Вашей: без оптимизации или с минимальной оптимизацией всё работает, а с полной оптимизацией - виснет в бесконечном ожидании в этом цикле и через некоторое время вылетает в bus-fault в DMA-контроллере. А дальше стало ещё хуже - выяснилось, что при добавлении/убирании строчек кода из совершенно других мест си-исходника, этот код иногда начинает работать. Причём работать 100%! Но при следующем редактировании исходника опять начинает падать в bus-fault (внимание adnega - очень знакомое поведение, не правда-ли? :rolleyes: )

 

Видимо Вы бы уже сложили ручки и обвинили во всём компилятор. Но я продолжил рыть. И в конце-концов нашёл причину!

Оказалось, что при полной оптимизации код цикла получался такой короткий и быстрый, что CPU всё время был занят подкачкой команд в буфер предвыборки, только загрузил в конвеер команду условного перехода, пока грузил следующий пакет предвыборки за ней, то команда успевала выполниться, шёл сброс конвеера и загрузки предвыборки из начала цикла. Вобщем - тело цикла было длиной всего 2-3 такта. И если получалось что тело цикла располагалось на границе сегментов предвыборки (смещение начала цикла в памяти & 3 было == определённым значениям), то процессор полностью загружал шину к памяти своими запросами. А у него приоритет доступа к шине был выше чем у DMA-контроллера. DMA-контроллер считав данные из периферии, делал 512 попыток запроса доступа к шине ОЗУ у арбитра, не получал доступа и в конце концов останавливал работу с выставлением fault-а.

При добавлении/удалении строк кода в разных местах исходника, весь код сдвигался, соответственно - чтение тела цикла иногда влезало в 1 сегмент prefetch (требовало на 1 такт меньше времени) и код чудесным образом начинал работать (DMA-контроллер в этот 1 освободившийся такт успевал пролезть на шину и записать данные в ОЗУ).

 

Вот такой пример из практики. И что же - тут виноват компилятор? Нет, виноват конечно был я - не надо было располагать DMA-буфер и код в одном сегменте ОЗУ (МК не позволял задать для DMA приоритет доступа к шине выше чем CPU) :laughing:

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


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

Из Вашего описания я понял, что асм-файл писали Вы сами....

Как телепат телепату, откройте секрет, где в моем сообщении можно хоть как-то прийти к такому выводу?

В строчке

make.EXE: *** [obj_sw/esp8266.o] Error 1

видим, что не собирается цель esp8266.o

А ошибку видим в s-файле с роботским именем C:\Users\user\AppData\Local\Temp\ccShzzAY.s в месте похуже корзины.

Т.е. вы решили, что мой проект лежит в Temp, я сам написал asm-файл и дал ему имя ccShzzAY.s, а затем как-то

заставил компилятор ругаться при сборке esp8266.o причем русским языком ниже сказано про Си-исходник? КАК?

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


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

в waitSpi() с оптимизацией не задерживаюсь ни когда, а должен не задерживаться только первый раз. После отправки данных до чтения регистра SPI1->SR проходит много времени, но меньше, чем выход 8 бит в спи.

Как одна из возможных причин:

Загружаете данные в буферный регистр SPI. Флаг DLY при этом не выставляется. А выставляется он только после того, как данные из буфера попадут в сдвиговый регистр. А попадут они туда после того как пройдёт некая задержка от завершения предыдущего SPI-фрейма (предыдущего поднятия CS=high), выдержки межфреймовой паузы (при CS=high), выдержки паузы после CS=fall и началом первого клока SCLK. Вот в этот момент возможно данные переместятся в сдвиговый регистр и выставится флаг DLY.

Т.е. - от момента записи данных в буферный регистр SPI до момента выставления флага DLY может пройти существенное время (в зависимости от частоты SCLK). А у Вас в программе возможно вы после записи очередной порции данных в буферный регистр SPI сразу переходите к waitSpi() и считаете что данные уже передались (так как флага нет), а они по-настоящему ещё и не начинали передаваться.

При запрете оптимизации же, код выполняется медленнее и DLY успевает выставиться, поэтому и работает.

 

Вот такой тип багов и называется "гонки". Как я выше и писал. И он конечно ваш, а не оптимизатора. :laughing:

 

PS: Это как возможный вариант причины бага. Причина может быть и другой. Так как всего кода я не вижу и как работает SPI в вашем МК - не знаю.

 

А ошибку видим в s-файле с роботским именем C:\Users\user\AppData\Local\Temp\ccShzzAY.s в месте похуже корзины.

Т.е. вы решили, что мой проект лежит в Temp, я сам написал asm-файл и дал ему имя ccShzzAY.s, а затем как-то

заставил компилятор ругаться при сборке esp8266.o причем русским языком ниже сказано про Си-исходник? КАК?

Я не смотрю на имена файлов тем более пути. Достаточно только расширения. И про си-исходник там сказано только что что-то в нём меняете. Как вариант: после смены там функция становится больше, перемещается в другое место в памяти и эта функция вызывается из асм между метками .L274, .L276 - и команда вызова становится длиннее и расстояние между .L274 и .L276 увеличивается.

 

PS: Если хотите чтобы Вас понимали однозначно, излагайте свои мысли ясно.

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


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

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

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

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

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

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

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

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

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

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