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

Проблемы с исполнением кода

Нет ли еще идей?

Извините если глупость сморожу, но может просто технологический дефект во время изготовления? две штуки не статистика.

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


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

Извините если глупость сморожу, но может просто технологический дефект во время изготовления? две штуки не статистика.

Думали уже в эту сторону. Не совсем 2, было 3 - один сожгли( Но образцы, которые у нас, прошли отбраковку как на пластине, так и после корпусирования. Поэтому здесь было предположение, что какой-то сбой тестами не обнаруживается.

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

 

Кроме того, дефект кристалла не объясняет работоспособность программы при пошаговом исполнении в debug'е

Изменено пользователем AlexeyT

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


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

Нет ли еще идей?

1. Проблема именно при передаче управления в другой 32К сегмент?

2. Или при длинном переходе (исполнение инструкции, позволяющей больший диапазон расстояний перехода)?

Проверьте точно. Расположив источник вызова и целевой адрес близко к границе.

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

 

Если первое, то какова конфигурация шин и регионов памяти в данном МК? Во многих МК ОЗУ разбита на банки с отдельными шинами доступа к ним (часто они по соседним адресам).

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

При пошаговой отладке, отладчик может незаметно автоматом их включать.

Просто доступ по чтению/записи данных в эти сегменты есть? А если прочитать целевой адрес перехода как данные, а потом перейти на него?

DMA и прочие bus-master-ы активны? Может конфликт CPU с другим bus-master?

 

Если второе - какие именно инструкции перехода по адресу вызывают сбой? Пробовали разные (B/BL с разными длинами смещения, BX/BLX, MOV PC, ...)? есть ли разница по инструкциям?

Смотрели map-файл? Не создаётся-ли промежуточная функция подскока для данного вызова? Например IAR, при вызове функций, находящихся далеко (за пределами макс. дальности инструкции BL),

создаёт спец. функцию (обзывает её Venner) возле источника вызова, на которую и прыгает BL, а внутри находится одна инструкция LDR PC, [PC, #0] с целевым адресом.

Может компилятор генерит что-то подобное?

 

3. Так как в пошаговом режиме проблема не проявляется, может источник проблемы совсем не выполнение кода в текущем потоке?

Может возникает какое-то прерывание или исключение, а у Вас не проинициализирован NVIC и таблица прерываний? Проинициализируйте их, запрет прерываний может не помогать, так как есть

немаскируемое прерывание и исключения.

 

Также - как работает отладчик с этими сегментами: ставит бряки программные или аппаратные?

В каком состоянии находится MPU? Инициализировали его?

 

То что Вы привели в первом посте:

0800_01DC: 7047 BX LR

0800_BE46: 4E21 MOV R1, #78 //где-то здесь падаем

0800_BE48: 6D48 LDR R0, [PC, #+0x1B4] //где-то здесь падаем

0800_BE4A: F4F7B6F9 BL #-0xBC94

0800_01BA: 0246 MOV R2, R0

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

Может у Вас элементарный баг в программе и управление улетает по случайнвм адресам?

Приведите карту памяти МК.

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


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

У нас 2 экземпляра, результаты одинаковые. Разработчики микросхемы гоняли на модели - у них все ок. Если есть проблема в реализации кристалла, то наша задача - помочь её им определить.

 

Высказанные выше конструктивные идеи: 1) прерывания и 2) увеличенная задержка при обращении через границу блоков проверяем.

 

Нет ли еще идей?

 

 

Делайте фейковую константу по этому адресу где происходит сбой. Перекомпилируйте код, проверяйте далее. Теперь код точно не будет в этой ячейке.

 

И вот еще ссылка на анализ ситуации в HardFaulte.

http://community.arm.com/servlet/JiveServl...20for%20ARM.pdf

 

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


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

Приведите карту памяти МК.

Секция CODE (доступ по I, D шинам)

0x0000_0000-0x0000_0FFF Область для загрузчика, отражается на внешнюю шину

0x0800_0000-0x0805_FFFF Область внутреннего ОЗУ с пользовательской программой

0x1000_0000-0x1FFF_FFFF Область доступа к внешней системной шине

Секция DATA

0x2000_0000-0x2000_03FF Область ОЗУ на внешней системной шине

0x2000_0400-0x2001_FFFF Область внутреннего ОЗУ данных, доступ по D шине

0x3000_0000-0x3FFF_FFFF Область доступа к внешней системной шине

Peripheral

0x4000_0000-0x4002_F00C Периферия

EXT_BUS

0х6000_0000-0x9FFF_FFFF Внешняя системная шина

System

0xE000_0000-0xEFFF_FFFF Системная область ядра

 

Чтобы отмести подозрения на загрузчик - он не используется, идет напрямую загрузка bin-файла в ОЗУ через SWD. Потом выставляется MSP, VTOR, PC - и запуск на исполнение.

 

Если первое, то какова конфигурация шин и регионов памяти в данном МК? Во многих МК ОЗУ разбита на банки с отдельными шинами доступа к ним (часто они по соседним адресам).

ОЗУ инструкций не разбита на банки, с точки зрения системы - единый блок

 

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

Тактирование общее на весь блок памяти, всегда включено

 

Просто доступ по чтению/записи данных в эти сегменты есть?

Просто доступ на чтение/запись есть на всю ОЗУ инструкций, гоняли тестами.

 

DMA и прочие bus-master-ы активны? Может конфликт CPU с другим bus-master?

DMA есть, но неактивен, больше ведущих на шине нет.

 

Также - как работает отладчик с этими сегментами: ставит бряки программные или аппаратные?

Программные

 

В каком состоянии находится MPU? Инициализировали его?

Явно нет, стоят значения по умолчанию

MPU->TYPE = 0x0000_0800. Унифицированная карта памяти, 8 регионов

MPU->CTRL = 0x0000_0000. MPU запрещен

 

То что Вы привели в первом посте:

Цитата

0800_01DC: 7047 BX LR

0800_BE46: 4E21 MOV R1, #78 //где-то здесь падаем

0800_BE48: 6D48 LDR R0, [PC, #+0x1B4] //где-то здесь падаем

0800_BE4A: F4F7B6F9 BL #-0xBC94

0800_01BA: 0246 MOV R2, R0

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

Это не мусор, это фрагмент кода).

0x0800_01DC – возврат из вызываемой функции putc(вывод символа по UART) в main. Main занимает пространство 0х0800_B8CA-0x0800_BF6C

Затем идет подготовка к передаче нового байта. Вход в следующий putc – 0x8000_01BA, putc занимает адреса 0x0800_01BA – 0x0800_01DC

Память по этим адресам есть (см. карту памяти), программа занимает адреса 0х0800_0000-0x0800_CCC0

 

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


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

А там никаких конвейеров нигде не рушиться? если барьеров памяти и инструкций напихать что будет?

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


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

А там никаких конвейеров нигде не рушиться? если барьеров памяти и инструкций напихать что будет?

 

 

Эммммм... Какие барьеры и куда напихать? Прошу пояснить

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


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

Это не мусор, это фрагмент кода).

0x0800_01DC – возврат из вызываемой функции putc(вывод символа по UART) в main. Main занимает пространство 0х0800_B8CA-0x0800_BF6C

Затем идет подготовка к передаче нового байта. Вход в следующий putc – 0x8000_01BA, putc занимает адреса 0x0800_01BA – 0x0800_01DC

Память по этим адресам есть (см. карту памяти), программа занимает адреса 0х0800_0000-0x0800_CCC0

Вы как-то странно написали... сразу трудно въехать... У Вас идёт команда по адресу 080001DC - возврат из функции и за ней сразу идёт команда по другому адресу...

Это адрес, на который происходит возврат?

Далее идёт загрузка R1 и за ней - загрузка константы с адреса [0x8000BFFE]. 0x8000BFFE по Вашим словам находится сразу за функцией main() -

там похоже лежит таблица констант, используемых в main().

Так вот, я Вас спрашивал - по адресу 0x8000BFFE какие-то данные (согласно map-файлу) есть?

И кстати - адрес 0x8000BFFE (если я правильно посчитал) выровнен на границу 2, а доступ в команде LDR R0, [PC, #+0x1B4] осуществляется к двойному слову (32бит).

В ядре Кортекс можно включить запрет невыровненных доступов к памяти, тогда будет генериться исключение (не помню какое). У Вас это разрешено?

А если оно разрешено, но не разрешены всякие MMfault и UserFault, то будет происходить эскалация до HardFault насколько я помню.

Да и вообще странно, что компилятор генерит такой невыровненный код....

Попробуйте поставить бряк на точку входа в ISR HardFault и выполнить эту команду, а потом попробуйте подровнять адрес на 4 и сделать то же самое.

 

ЗЫ: Кстати - у Вас putc() похоже какая-то очень простая, раз выход из неё BX LR... :)

 

Секция CODE (доступ по I, D шинам)

0x0000_0000-0x0000_0FFF Область для загрузчика, отражается на внешнюю шину

0x0800_0000-0x0805_FFFF Область внутреннего ОЗУ с пользовательской программой

0x1000_0000-0x1FFF_FFFF Область доступа к внешней системной шине

 

Раз в МК есть разделение ОЗУ на ОЗУ для кода и данных, то может быть что первая часть не поддерживает невыровненный доступ.

Область для загрузчика, отражается на внешнюю шину - а сам загрузчик не встроенный в МК что-ль???

 

Чтобы отмести подозрения на загрузчик - он не используется, идет напрямую загрузка bin-файла в ОЗУ через SWD. Потом выставляется MSP, VTOR, PC - и запуск на исполнение.

Обычно это (стек и PC) выставляется первым вектором таблицы прерывания, с которого CPU их считывает при подаче reset-а эмулятором.

 

CFSR 0x00000100

Этим 8-мым битом CPU Вам говорит:

A bus fault on an instruction prefetch has occurred. The fault is signalled only if the

instruction is issued.

И у меня вызывает большие подозрения Ваша строка:

0800_BE4A: F4F7B6F9 BL #-0xBC94

Это вызов функции? Скорее всего именно она и вызывает fault. Точно узнать можно по содержимому стекинга.

 

Память тестировали - записывали данные, считывали - все ОК, память работоспособна, но при переходе границы 32-кБ блоков происходит HardFault:

PC = 0x0800016A, LR = 0xFFFFFFE9, XPSR = 0x21000003

Вы привели неправильные регистры. Это состояние регистров внутри ISR. Толку от него мало. Вам нужно привести регистры сохранённые при стекинге при входе в fault.

Прочитайте раздел описания ядра кортекс, посвящённый описанию стекинга и формата сохраняемых регистров.

Тогда узнаете значение PC перед срабатыванием fault.

 

Ещё - проверьте стек. Может он у вас элементарно переполняется.

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


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

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

Про тактирование уже писали - сбрасывали до 100 кГц, результат такой же.

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

 

А там никаких конвейеров нигде не рушится? Если барьеров памяти и инструкций напихать, что будет?

Будем пробовать, т.к. на этом проекте падаем при возврате в основную функцию из вызываемой.

 

Вы отладчиком в окне дизассемблера прошлись? Удалось найти инструкцию, на которой "всё падает"?

Да, и не раз. Повторюсь - при пошаговом исполнении из отладчика (s) программа работает до тех пор, пока пользователю не надоест запускать пошагово.

При запуске на исполнение из отладчика (g) - падаем вскоре после начала работы основной функции main.

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

При первом вызове она отработала нормально.

 

Ещё - проверьте стек. Может он у вас элементарно переполняется.

С переполнением стека сталкивались в самом начале. С тех пор стека МНОГО:)

MSP = 0x20014870 при запуске программы, MSP = 0x20013B00 при падении. Используется 0xD70 из выделенных 0x4000

 

Вам нужно привести регистры сохранённые при стекинге при входе в fault.

R0 = 0x40002000, R1 = 0x00000052, R2 = 0x40002000, R3 = 0x000003e8

R12 = 0x2000084C, LR = 0x0800BE47, PC = 0x07FF4FBE, xPSR = 0x21000000

!!! PC улетает ниже области, где лежит программа( Но почему при первом вызове той же процедуры все работает???

 

Обычно это (стек и PC) выставляется первым вектором таблицы прерывания, с которого CPU их считывает при подаче reset-а эмулятором.

По ресету управление передается на 0х0, где должен лежать загрузчик. Как в эмуляторе, так и на железе.

 

Сам загрузчик не встроенный в МК что-ль???

Таки да. Микросхема ОКРовская, есть нюансы. Есть вывод, в зависимости от которого обращения в область 0х0-0х1000 отправляются либо на внешнюю шину, либо на внутреннюю ПЗУ с кодом загрузчика.

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


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

R0 = 0x40002000, R1 = 0x00000052, R2 = 0x40002000, R3 = 0x000003e8

R12 = 0x2000084C, LR = 0x0800BE47, PC = 0x07FF4FBE, xPSR = 0x21000000

!!! PC улетает ниже области, где лежит программа( Но почему при первом вызове той же процедуры все работает???

Точка возврата в LR правильная, а команда 0800_BE46: 4E21 MOV R1, #78 уже не была выполнена.

Хмммм.... да уж.... :wacko:

Я бы ещё попробовал позаменять регистр возврата LR на какой другой или вернуться через стек POP {PC} или попробовать выровнять целевую точку возврата на 4...

Но походу явно тут торчат ослиные уши "отечественного предприятия".

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


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

или попробовать выровнять целевую точку возврата на 4...

Как это можно сделать средствами компилятора для проекта на С?

 

Разговоры про отладчик наводят на грустные мысли про прерывания, которые как-то включились, но вектора не прописаны. В пошаговом режиме они запрещены.

Проверили регистры при падении - действительно, кроме исключения HardFault, есть прерывания, ожидающие обслуживания. Обработчики для них прописаны.

Но они маскируемые, и по умолчанию (в программе) не разрешены. Если разрешить их обработку из отладчика, после какого-нибудь из breakpoint'ов, то попадем в исключение DebugMonitor (№=12).

Это правильная логика работы, или здесь

торчат ослиные уши
?

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


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

Как это можно сделать средствами компилятора для проекта на С?

на си - вряд-ли. Сделайте отдельную функцию на асме в пределах 32К исходной точки вызова.

А уже из неё - выровненный вызов за пределы 32К.

 

Но они маскируемые, и по умолчанию (в программе) не разрешены. Если разрешить их обработку из отладчика, после какого-нибудь из breakpoint'ов, то попадем в исключение DebugMonitor (№=12).

Это правильная логика работы, или здесь ?

Даташита нет под рукой, но насколько помню, в системной области есть регистр, в котором разрешаются различные fault-ы.

Там, среди прочих, вроде есть разрешение DebugFault. Видно Вы случайно разрешили его. Его вроде только отладчик может

использовать/разрешать. Проверьте.

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


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

Даташита нет под рукой, но насколько помню, в системной области есть регистр, в котором разрешаются различные fault-ы.

Регистр такой есть. SCB->SHCSR (0xE000ED24). Но в нем устанавливаются только UsageFault, BusFault, MemFault. По умолчанию все обработчики были запрещены.

При их разрешении и намеренных ошибках процессор стал падать не в Hard, а в Usage или Bus.

 

Но вот основной косяк объяснению не поддается :wacko: .

Имеем один и тот же простейший проект, с чуть разными картами памяти. 64 КБ разбиты на 2 части по 32 КБ.

В первом случае (Проект55) в верхнюю область памяти закинуты лишь 3 простых пользовательских функции.

Во втором (Проект56) - в верхнюю область линкер на свое усмотрение закинул и часть системных.

При этом Проект55 - работает, Проект56 - падает в UsageFault.

 

Активные регистры при падении:

LR=0xFFFFFFF9 (9 - использовался основной стек),

MSP=0x20005370 (использовано 0xF0 из 0x1000),

PC=0x08008080 (UsageFault_Handler),

xPSR=0x01000006 (UsageFault)

В стеке лежат:

LR=0x080080CB (следующая после команды _dadd),

PC=0x08008184 (SUBS - вроде ничего страшного. А вот команда перед ней, BMI.W 0x0800033C - условно-подозрительная)

xPSR=0x01000000.

 

______55.zip

______56.zip

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


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

Тестовая программа стала работать при вот таких изменениях:

 

1) НЕ РАБОТАЛО (сваливалось в Hard Fault):

 

main()
{
.....
qq = simple_proc_int(ww,ee);//Hard Fault
...  
}

2) ЗАРАБОТАЛО:

main()
{
...
*(volatile unsigned int*)(0x30010000) = 0xFFFF5500;    // пишем во внешнюю шину неважно какие значения 
*(volatile unsigned int*)(0x30010000) = 0xAAAAFF01;    // пишем во внешнюю шину неважно какие значения
*(volatile unsigned int*)(0x30010000) = 0xFFFF5500;    // пишем во внешнюю шину неважно какие значения

qq = simple_proc_int(ww,ee);//нормально проходим, в Hard Fault не сваливаемся!
...  
}

Здесь

int simple_proc_int(int a, int B)
{
int c = 0;
c += a<<2;
c += b<<3;
return c;
}

- элементарная тестовая функция, записанная в другом 32-кБ сегменте памяти.

 

 

Память данных условно разбита на 2 сегмента по 32 кБ. "Условно" - потому что с точки зрения процессора, вся память представляет собой единый массив до 128 кБ.

Проект57 - в верхнем сегменте памяти только тестовые функции, исполняется корректно. Между всеми вызовами тестовых функций стоят обращения на внешнюю шину.

Проект58 - линкер закинул в верхний сегмент памяти часть системных функций, но проект исполняется. Между всеми вызовами тестовых функций стоят обращения на внешнюю шину.

Проект59 - в верхней части находятся тестовые и часть системных функций. Но обращения стоят только в начале и конце процедуры main. Проект НЕ исполняется, падает в UsageFault при выполнении процедуры a = simple_proc_dbl(b,c).

 

Вроде бы времена обращений - но при пошаговом исполнении из-под отладчика проект59 также не работает.

 

Кто-то может предположить причины такого бреда?

_______.rar

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

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


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

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

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

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

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

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

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

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

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

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