Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Конфликт RAM и SPI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
zheka
Господа, я понимаю, что причину моей проблемы вы не найдете, но может быть подскажете, как искать ошибку.
А может быть и констатируете, что это не ошибка, а глюк отладчика...

Суть такова. Контроллер STM32F103, в нем включен USART. В обработчике прерывания по приему заполняется буфер, объявленный как uint8_t rx_buffer[50]; Буфер кольцевой.
Работаю с KEIL. Отлаживаю по SWD, в окно watch я добавил rx_buffer. Проблема в чем - в эту переменную, согласно уведомлениям отладчика, периодически в случайные позиции на мгновение вместо 0x00 записывается 0xFF или 0xAA. При этом единственное место в программе, где в эту переменную что-то пишется - это обработка прерывания по приему, я ставил брейкпоинт на эту единственную строку - не срабатывает. Потому как я для чистоты эксперимента вообще отключил источник данных.

Я закомментировал практически всю программу
Код
main()
{
while(1)
  {
    LCD_DrawFill(0,0,30,30,BLACK);
  }

}

Выяснилось, что глюк появляется когда присутствует именно эта строка. ну и анализ и комментирование строк в этой функции привели к тому, что глюк вызывается при записи в регистр данных SPI3.

Я бы обозначил эту проблему, как конфликт SPI и RAM если бы не два "но".

1. В SPI ведется запись еще несколькими функциями, но проблема возникает только в одной из них.
2. Я написал кусок кода, который в цикле проверяет каждый элемент rx_buffer на предмет отличия его от изначального 0x00 и поставил на нем брейкпоинт. Понимая, что проверка и кратковременное изменение буфера могут не совпасть по времени, я запустил программу на ночь, по моим прикидкам буфер должен был быть проверен около 3 миллионов раз. Ни разу програма не засекла вмешательство в буфер.


Похожие глюки, с записыванием данных не в те переменные у меня была как-то, когда я объявил безразмерный массив ( uint8_t XXX[]; ) Но в данном случае ничего такого у меня нет.

Скажите, возможно ли что отладчик брешет?
Как используя средства отдладки KEIL подловить момент записи в переменную и определить кто на нее посягает?
scifi
Цитата(zheka @ Jan 19 2017, 09:43) *
Скажите, возможно ли что отладчик брешет?

Наверное. Тут нужно в деталях разбираться, как работает отладчик.

Цитата(zheka @ Jan 19 2017, 09:43) *
Как используя средства отдладки KEIL подловить момент записи в переменную и определить кто на нее посягает?

Обычно это называют watchpoint, вроде бы. У Кейла это называется data breakpoint. Если настроить всё как надо, отладчик остановится в тот момент, когда процессор попробует записать что-то в указанный диапазон адресов. Он не остановится, если туда полезет DMA, но это не ваш случай, насколько я понял.

Кстати, с тактированием всё нормально? Может быть, вы дико разогнали МК, не заметив этого, и он странно глючит? Или шум в цепи Vdda?
Ещё можно поварьировать частоту SWCLK. Если наблюдается неустойчивое соединение, можно повесить на цепь SWCLK маленькую ёмкость (десятки пФ) на землю.
zheka
Цитата
Кстати, с тактированием всё нормально? Может быть, вы дико разогнали МК, не заметив этого, и он странно глючит? Или шум в цепи Vdda?

Работаю с макеткой, которая хоть и китайская, но за 5 лет меня подобным образом ни разу не подводила.
У меня ничего не разогнано.
Вы понимаете, в чем парадокс?
За то, что это глюк отладчика говорит тот факт, что сам контроллер, его код, науськанный на непрерывное отслеживание изменений в буфере, не обнаруживает таковых.
За то, что проблема в контроллере и программе говорит тот факт, что отключение записи в SPI сохраняет данные в буфере в целостности.

Еще одна особенность, которую я не могу трактовать в пользу чего либо - если в буфере 0x00, то пишется FF или AA. А если какие-то данные есть, то там оказывается другое число. Понимаете, если бы туда шла запись, то писалось бы конкретное число, а тут идет порча битов.


Самое интересное, что, как я уже писал, в работе программа не ощутила изменений в буфере за 3 миллиона его проверок. То есть либо изменение кратковременное, либо это брехня. Ну а если бы и ощутила, протокол, который я собираюсь использовать, предполагает проверку контрольной суммы и данные были бы запрошены повторно. То есть можно смело выпускать устройство. Но все равно меня этот глюк гложет...

Скажите, а можно ли как то при объявлении переменной приказать ей разместиться в строго определенном адресе?
Ну или... если я чисто по тексту программы размещу ее в самом начале, она окажется по другому адресу?
Если это глюк и что-то в программе лезет по определенному адресу, где у меня случайным образом оказался rx_buffer, то проблема именно с этой переменной должна исчезнуть. Это будет свидетельствовать в пользу глюка отладчика.
KnightIgor
Цитата(zheka @ Jan 19 2017, 08:43) *
Господа, я понимаю, что причину моей проблемы вы не найдете, но может быть подскажете, как искать ошибку.
А может быть и констатируете, что это не ошибка, а глюк отладчика...

Я бы посмотрел (по карте памяти), какие переменные размещены до и после исследуемого буфера ("обрамляют" его) . Причина: не исключено, что в процедурах, работающих c "обрамляющими" переменными, нарушается некий указатель. Вторая тема: размер и размещение стэка. Третья тема: наличие, размер и размещение кучи (HEAP). Явно кто-то влазит на исследуемый буфер.

Я также работаю с KEIL. Он может показывать чушь содержимого переменной, если смотреть переменную через watch (особенно при включенной оптимизации кода), но до сих пор KEIL мне всегда показывал правду, если смотреть память по адресу.
zheka
Цитата
Я бы посмотрел (по карте памяти),

Это где примерно?
jcxz
Цитата(zheka @ Jan 19 2017, 09:43) *
Как используя средства отдладки KEIL подловить момент записи в переменную и определить кто на нее посягает?

Насчёт Кейла не скажу, но у Вас же Cortex-M3? В нём есть MPU. Выносите rx_buffer в отдельную секцию памяти, выравниваете ещё положение и размер на 64 байта (например), закрываете к ней доступ по записи через MPU, приоткрывая его временно только в точке записи (в ISR) (на всякий случай запретив прерывания на это время (или назначив прерыванию rx_buffer наивысший приоритет из всех)).
Если в каком-то другом месте будет попытка записи в эту область - сразу получите исключение, проанализируете его источник - найдёте виновника.
Я таким образом не раз решал проблемы со случайными записями в переменные.

Цитата(scifi @ Jan 19 2017, 09:51) *
Обычно это называют watchpoint, вроде бы. У Кейла это называется data breakpoint. Если настроить всё как надо, отладчик остановится в тот момент, когда процессор попробует записать что-то в указанный диапазон адресов. Он не остановится, если туда полезет DMA, но это не ваш случай, насколько я понял.

Плохой метод. Наличие watchpoint-ов вызывает изменение временной диаграммы работы программы (вызывает резкое её замедление).
Видимо потому, что анализ условия watchpoint выполняется программно в ПО эмулятора (или отладчика?).
Изменение времянки может привести к исчезновению проблемы.
Применение MPU - менее инвазивный метод.

Ещё другой способ:
Запускаете высокочастотное прерывание от любого таймера. Частотой 500-1000кГц (зависит от производительности процессора). Так чтобы оно грузило процессор процентов на 50% или больше.
В ISR сравниваете какие-то части rx_buffer с копией (Ваш ISR, который пишет в rx_buffer, должен дублировать запись и в его копию).
Назначаете приоритет прерывания записи rx_buffer самым высоким, прерывания от таймера - выше других, но ниже прерывания пишущего rx_buffer.
Если при очередной проверке данные не совпали - читаете из стека в какой точке идёт выполнение фоновой программы.
Если обработчик таймера будет коротким (лучше на асм), то сможете обнаружить точку модификации с точностью до примерно десятка команд или меньше.
Но конечно этот метод сильнее влияет на выполнение самой исследуемой программы чем метод с MPU. Да и весь rx_buffer сразу в одном прерывании не проконтролируешь, только 1-2 32-битных слова.
scifi
Цитата(jcxz @ Jan 19 2017, 12:44) *
Насчёт Кейла не скажу, но у Вас же Cortex-M3? В нём есть MPU.

Указано же, что это STM32F103. Нету там никакого MPU.

Цитата(jcxz @ Jan 19 2017, 12:44) *
Плохой метод. Наличие watchpoint-ов вызывает изменение временной диаграммы работы программы (вызывает резкое её замедление).
Видимо потому, что анализ условия watchpoint выполняется программно в ПО эмулятора (или отладчика?).

Когда я пользовался этой штукой, у меня ничто не замедлялось. Там же есть аппаратный watchpoint - вот он и был задействован, очевидно.
jcxz
Цитата(scifi @ Jan 19 2017, 12:56) *
Когда я пользовался этой штукой, у меня ничто не замедлялось. Там же есть аппаратный watchpoint - вот он и был задействован, очевидно.

Как раз я (под IAR) когда его пробовал - было резкое замедление, во много раз.
Поэтому тогда и реализовал метод с высокочастотным таймером.
Obam
Опередили про MPU…

PM0056 STM32F10xxx Cortex-M3 programming manual:
About the STM32 core peripherals
0xE000ED90-0xE000ED93 MPU type register Reads as zero, indicating no MPU is implemented(1)
jcxz
Цитата(Obam @ Jan 19 2017, 13:07) *
0xE000ED90-0xE000ED93 MPU type register Reads as zero, indicating no MPU is implemented(1)

Не надо использовать такие МК. wink.gif
Obam
"Кутузов был без глаза. Нет! У Кутузова не было глаза!"
Цитата(jcxz @ Jan 19 2017, 14:36) *
Не надо использовать такие МК. wink.gif


STM чумовая контора: с rev3 (PM0056) руководства по программированию в CM3 - есть MPU!
Что меня и смутило: как так в L152 - есть, а в F103 вдруг нет?!
scifi
Цитата(Obam @ Jan 19 2017, 14:05) *
STM чумовая контора: с rev3 (PM0056) руководства по программированию в CM3 - есть MPU!

Не надо наговаривать:
Цитата
This section describes the Memory protection unit (MPU) which is implemented in some STM32 microcontrollers. Refer to the corresponding device datasheet to see if the MPU is present in the STM32 type you are using.
zheka
/////

Господа, в общем вывод такой - это глюк даже не отладчика, а самого кейла.

Никто мне в переменную ничего не пишет. Об этом свидетельсвтует следующее
1.Несмотря на то, что по сообщениям окна watсh, переменную rx_buffer кто-то упорно насилует, брейкпоинты на запись не срабатывают. При этом они срабатывают когда туда на самом деле осуществляется запись.
2. Как я заметил, байт, который оказывается в буфере, зависит от того, что там было раньше. Если бы шла запись в переменную, то ее содержимое просто затиралось бы конкретным числом, а тут мусор есть производное от первоначального значения. Мне сложно представить себе такой глюк или конфликт с памятью, при котором из буфера что-то будет читаться, затем с полученным результатом что-то делается и результат записывается в ячейку.... А вот на порчу отдельных бит это похоже.
Более того, как я писал, появление левых данных всегда кратковременное, через долю секунды данные возвращаются к исходному виду. Опять таки, мне сложно представить глюк, который считывает данные, гадит, а потом восстанавливает.

Зато это очень похоже на периодическое искажение выведения результата кейлом - то есть данные в буфере постоянны, иногда KEIL считав их, теряет их правильность и выводит на экран бред, но при следующем чтении тех же самых правильных данных все нормально.
jcxz
Цитата(zheka @ Jan 19 2017, 21:22) *
Зато это очень похоже на периодическое искажение выведения результата кейлом - то есть данные в буфере постоянны, иногда KEIL считав их, теряет их правильность и выводит на экран бред, но при следующем чтении тех же самых правильных данных все нормально.

В чём проблема проверить это?
Когда появились странные данные, нажать кнопочку "Refresh" чтобы обновить данные в окне "watch".
Или в кейле нет такой кнопочки?

Цитата(zheka @ Jan 19 2017, 21:22) *
Мне сложно представить себе такой глюк или конфликт с памятью, при котором из буфера что-то будет читаться, затем с полученным результатом что-то делается и результат записывается в ячейку.... А вот на порчу отдельных бит это похоже.

Например - при доступах через bitband. Хотя в Вашем МК и его похоже тоже нету...
scifi
Цитата(zheka @ Jan 19 2017, 21:22) *
Господа, в общем вывод такой - это глюк даже не отладчика, а самого кейла.

Зато это очень похоже на периодическое искажение выведения результата кейлом - то есть данные в буфере постоянны, иногда KEIL считав их, теряет их правильность и выводит на экран бред, но при следующем чтении тех же самых правильных данных все нормально.

Я бы не спешил ругать Кейл. Всё-таки он полагается на дрова для отладочного адаптера, которые написаны другими товарищами, и в них возможны глюки. Кроме того, весьма вероятно, что в протоколе SWD нет средств контроля целостности данных, поэтому в случае порчи сигналов SWD получите то, что получили. А тут уже вы виноваты - не надо портить сигналы laughing.gif
rudy_b
Тут есть еще и проблема с дебильной периферией STM32 - некоторые биты в регистрах периферии сбрасываются при чтении этих или других регистров и отключить это нельзя.

Кроме того есть и есть и естественные проблемы с дебагом - в точке останова он считывает все, что открыто в его окнах - и если это фифо приема данных - соответствующая информация пропадет.

Использовать дебаг при работе с периферией нужно крайне аккуратно, не допуская подобных ситуаций. Ежели требуется периодический контроль буфера - это можно сделать по прерываниям с высшим приоритетом из другого куска программы. Но только в памяти - трогать ключевые регистры периферии (типа статусных и данных) не следует.
SasaVitebsk
Цитата(scifi @ Jan 20 2017, 13:33) *
Я бы не спешил ругать Кейл. Всё-таки он полагается на дрова для отладочного адаптера, которые написаны другими товарищами...

Я неоднократно наблюдал глюки отладчика Keil с фирменным родным ULINK в оплаченном пакете. (Проц lpc1765). В том числе и при выводе данных в окне периферии.
Особенно криво он себя ведёт, ну например, если 2 одинаковых задачи запускаются (RTX). Откуда он при этом выводит данные в окно отладки вообще не понятно.
В аналогичной ситуации IAR ведёт себя абсолютно корректно. Даже на сторонней ОСи. По моему это показатель.



Цитата(rudy_b @ Jan 20 2017, 19:34) *
проблема с дебильной периферией STM32

Объективно, я бы так сказал - периферия как периферия.
Есть удачные решения - есть не очень. Но в целом мне она понравилась.
С чем можно было бы согласится, что нет общего подхода к разным периферийным модулям. Но это просматривается почти во всех камнях. Единый подход более менее виден у LPC. Но и там есть к чему придраться.
Наличие флагов, которые сбрасываются при чтении - это много где. Ситуация с MSP значительно хуже. Там часть прерываний сбрасывается путём чтения регистра источника, часть путём принудительного сброса флага, часть чтением спец регистра... Короче вообще бардак. biggrin.gif
zltigo
Цитата(SasaVitebsk @ Jan 22 2017, 10:58) *
Ситуация с MSP значительно хуже. Там часть прерываний сбрасывается путём чтения регистра источника, часть путём принудительного сброса флага, часть чтением спец регистра... Короче вообще бардак. biggrin.gif

У него периферия реально заточена под общее микропотребление. Все остальное вторично.
jcxz
Цитата(SasaVitebsk @ Jan 22 2017, 11:58) *
С чем можно было бы согласится, что нет общего подхода к разным периферийным модулям. Но это просматривается почти во всех камнях.

Во многих МК, как я понимаю, часть периферийных блоков - свои, собственной разработки, поддерживаемые неизменными на протяжении разных линеек, для совместимости; другие блоки - купленные у кого-то (может даже у того-го же ARM), соответствующие некоему стандарту. Отсюда и разнобой.
SasaVitebsk
Цитата(jcxz @ Jan 23 2017, 09:45) *
Во многих МК, как я понимаю, часть периферийных блоков - свои, собственной разработки, поддерживаемые неизменными на протяжении разных линеек, для совместимости; другие блоки - купленные у кого-то (может даже у того-го же ARM), соответствующие некоему стандарту. Отсюда и разнобой.

Тут ещё накладываются и своя невнимательность, и то, что они свои периферийные модули изменяют-дорабатывают от камня к камню.
Так, к примеру RTC у F1 и F4 - небо и земля. А кое где видел такие отличия незаметные.. Переносишь библиотеку - не работает. Читаешь внимательно - диву даёшься.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.