|
C++, мучения в освоении и JTAG отладке |
|
|
|
Mar 14 2011, 18:42
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Расскажу один назидательный случай, который случился со мной в освоении и отладке программ на С++. После того, как разобрался с помощью гуру, как разместить константы во Flash, а нев SRAM, со мной случилась другая проблема, связанная с загрузкой и JTAJ отладкой. Когда программа на С++ блистала своей красотой и лаконичностью, когда все прекрасно показывал симулятор IAR, настала пора грузить ее в кристалл. И вот тут-то началось! Отладчик JTAG упорно не хотел добегать до метки main, программа ускакивала в ловушку на векторе UndefinedHandler. Опускаю процесс поисков, сразу к сути. Оказывается, нельзя ни в коем случае в глобальных объектах заниматься инициализацией периферии кристалла. Вообще касаться периферии нельзя! Резонов два: -1. порядок вызовов конструкторов не определен, и -2 при JTAG отладке ARM после загрузки FLASH успевает промолотить еще достаточное количество инструкций прежде, чем сработает break по RESET и сдернет программу обратно в address_reset. Последнее меня и погубило. Дело в том, что я записал в конструктор куски инициализации Flash, а отладчик сдергивал кристалл как раз в момент этой инициализации. Возвращался по Reset он уже в испорченное содержимое сегмента-векторов. Победить удалось следующим приемом- из конструкторов глобальных объектов убрал любое обращение к периферии кристалла. Вместо этого, ввел в классы с периферией методы инициализации периферии типа obj.Start() с вызовом этих методов после входа в main(). Мне кажется, пережитые мучения пойдут на пользу всем, кто хочет переползти с С на С++.
|
|
|
|
|
 |
Ответов
|
Mar 14 2011, 19:11
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(Aprox @ Mar 14 2011, 22:42)  Расскажу один назидательный случай Если вы внимательно почитаете материалы форума, то про найденные вами "грабли" давно и внятно все было изложено. Вам два совета: - хороший тон - инициализация железа до входа в main(); - если уж хочется железо инициализировать в классах, никто не мешает объявить глобальные указатели на объекты, а в какой-либо low_level_init написать, что-нибудь типа: Usart const *pUsart1; .... void low_level_init(void) { pUsart1 = new Usart(1, 19200, 8, 1, 0); // пример чисто условный. ... } Есть еще варианты с singleton'ами, гарантирующими однократный вызов конструктора объекта.
|
|
|
|
|
Mar 15 2011, 08:26
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(sergeeff @ Mar 14 2011, 22:11)  Вам два совета: - хороший тон - инициализация железа до входа в main(); Почему? Я вспоминаю примеры профессиональных устройств c UCOS и С++, где задачи и железо при них создаются уже после входа в main(). Например, Ethernet модули фирмы NetBurner. Цитата - если уж хочется железо инициализировать в классах, никто не мешает объявить глобальные указатели на объекты, а в какой-либо low_level_init написать, что-нибудь типа:
Usart const *pUsart1; ....
void low_level_init(void) { pUsart1 = new Usart(1, 19200, 8, 1, 0); // пример чисто условный. ... }
Есть еще варианты с singleton'ами, гарантирующими однократный вызов конструктора объекта. Я пробовал с low_level_init. Для JTAG отладки программ ARM-ов - не годится. Проблема в том, что для JTAG отладки периферии требуется создать глобальные переменные-указатели на SFR-регистры. Иначе отладчик просто не видит периферию. По крайней мере, у меня с отладкой на кристаллах STR91xx именно так. И если в low_level_init произвести инициализацию этих указателей, то следующая за этим инициализация сегментов просто их стирает. В результате, отладчик улетает неизвестно куда. Я по-прежнему считаю, что самый простой и надежный прием написания программ на C++ для ARMов- это вообще не касаться периферии до входа в main().
|
|
|
|
|
Mar 15 2011, 10:04
|

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

|
Вставьте в low_level_init задержку чтобы отладчик успел остановить проц во время исполнения этой задержки. QUOTE (Aprox @ Mar 15 2011, 10:26)  Я пробовал с low_level_init. Для JTAG отладки программ ARM-ов - не годится. Проблема в том, что для JTAG отладки периферии требуется создать глобальные переменные-указатели на SFR-регистры. Иначе отладчик просто не видит периферию. По крайней мере, у меня с отладкой на кристаллах STR91xx именно так. И если в low_level_init произвести инициализацию этих указателей, то следующая за этим инициализация сегментов просто их стирает. В результате, отладчик улетает неизвестно куда. Да ну, ерунда какая-то. Если речь идет об IAR. С STR91x не работал, а 71х прекрасно отлаживался без всяких указателей. И с чего бы отладчику куда-то улетать из-за неправильных указателей. Ну хотите указатели - инициализируйте их в main(). Периферия-то при чем? QUOTE Я по-прежнему считаю, что самый простой и надежный прием написания программ на C++ для ARMов- это вообще не касаться периферии до входа в main(). Ага, особенно если до входа в main инициализируются глобальные переменные, которые находятся во внешней S(D)RAM или создаются глобальные объекты, которые используют S(D)RAM, а она еще не включена.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 15 2011, 11:20
|

Местный
  
Группа: Участник
Сообщений: 374
Регистрация: 7-11-07
Из: Moscow
Пользователь №: 32 131

|
Цитата(Сергей Борщ @ Mar 15 2011, 13:04)  Вставьте в low_level_init задержку чтобы отладчик успел остановить проц во время исполнения этой задержки. А в боевом варианте задержку вручную потом убирать? Цитата Да ну, ерунда какая-то. Если речь идет об IAR. С STR91x не работал, а 71х прекрасно отлаживался без всяких указателей. И с чего бы отладчику куда-то улетать из-за неправильных указателей. Ну хотите указатели - инициализируйте их в main(). Периферия-то при чем? Кристаллы STR91xx имеют уже готовую фирменную библиотеку драйверов периферийных устройств. Библиотека написана на C и требует запуска инициализации собственных внутренних переменных. Как понимаете, вызывать инициализацию такой библиотеки в low_level_init нельзя, потому что следующая за этим инициализация сегментов данных основной программы затрет внутренние переменные слинкованной библиотеки. Поведение программы становится непредсказуемым. Единственный выход- заниматься периферией только после входа в main(). Цитата Ага, особенно если до входа в main инициализируются глобальные переменные, которые находятся во внешней S(D)RAM или создаются глобальные объекты, которые используют S(D)RAM, а она еще не включена. Зачем нарываться на приключения? Создавайте объекты, взаимодействующие с периферией, во внутренней SRAM кристалла. Этой SRAM вполне достаточно. Цитата(Andy Mozzhevilov @ Mar 15 2011, 13:10)  Создать именно в программе? Зачем там лишние сущности? Подключаете ddf файл для вашего контроллера, и смотрите всю периферию. По моему вы придумали для себя проблему, а потом ее решили, причем далеко не лучшим способом. Во всяком случае сейчас посмотрел установленный у себя IAR и тут: C:\Program Files\IAR Systems\Embedded Workbench 6.0\arm\config\debugger\ST\ находятся ddf файлы в том числе для STR91xx Причем это все автоматически подключается, если вы в качестве целевого контроллера выберите именно ваш тип контроллера, а не generiс типа ARM7 или ARM9 Я работаю с IAR v4.30A. Там нет ddf заготовок для STR91xx. Использую установку Taget =ARM9663-E. Предложения типа перейти на новые версии IAR пока не рассматриваю, поскольку создана инфраструктура разработки, привязанная типом отладчика именно к указанной версии. Иными словами придется менять и отладчик, поскольку старый не понимает отладочной информации новых версий. Цитата Это только один из способов, причем не факт, что самый надежный. Вы лишаете себя возможности создавать глобальные объекты классов с использованием периферии, при этом вручную вынуждены в определенной последовательности вызывать функции дополнительной инициализации объектов из main или откуда то еще, то есть совершаете дополнительное действие, которое можно забыть сделать. Я так не считаю. В моем варианте объекты могут использовать периферию. Надо только в этих объектах предусмотреть метод Старт_Периферии() и вызывать его сразу по входу в main(). Поскольку этот метод есть неотъемлемая часть класса, то забыть чего-либо в периферии вряд ли получиться. Кроме того, это пожалуй единственный прием работать с готовыми библиотеками драйверов периферии, написанными на C.
|
|
|
|
|
Mar 15 2011, 14:01
|

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

|
QUOTE (Aprox @ Mar 15 2011, 13:20)  А в боевом варианте задержку вручную потом убирать? обрамить в #ifdef NDEBUG. QUOTE (Aprox @ Mar 15 2011, 13:20)  Кристаллы STR91xx имеют уже готовую фирменную библиотеку драйверов периферийных устройств. Библиотека написана на C и требует запуска инициализации собственных внутренних переменных. Сочувствую. QUOTE (Aprox @ Mar 15 2011, 13:20)  Создавайте объекты, взаимодействующие с периферией, во внутренней SRAM кристалла. Этой SRAM вполне достаточно. "Отучаемся говорить за других". Вам достаточно. Если внешнюю память предусмотрели - она кому-то нужна. QUOTE (Aprox @ Mar 15 2011, 13:20)  Кроме того, это пожалуй единственный прием работать с готовыми библиотеками драйверов периферии, написанными на C. Нет, не единственный. Можно переписать cstartup.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
Сообщений в этой теме
Aprox C++ Mar 14 2011, 18:42    Andy Mozzhevilov Цитата(Aprox @ Mar 15 2011, 14:20) Я рабо... Mar 15 2011, 12:19     Aprox Цитата(Andy Mozzhevilov @ Mar 15 2011, 15... Mar 15 2011, 14:49      Andy Mozzhevilov Цитата(Aprox @ Mar 15 2011, 17:49) Да, я ... Mar 15 2011, 16:08       sergeeff Цитата(Andy Mozzhevilov @ Mar 15 2011, 20... Mar 15 2011, 22:01       Aprox Цитата(Andy Mozzhevilov @ Mar 15 2011, 19... Mar 16 2011, 07:23  Andy Mozzhevilov Цитата(Aprox @ Mar 15 2011, 11:26) Я проб... Mar 15 2011, 10:10 Andy Mozzhevilov Обращайтесь, если что. Можно в аську. Mar 16 2011, 08:36 Aprox Цитата(Andy Mozzhevilov @ Mar 16 2011, 11... Mar 17 2011, 17:28  Andy Mozzhevilov Цитата(Aprox @ Mar 17 2011, 20:28) Вы гов... Mar 18 2011, 04:37   Aprox Цитата(Andy Mozzhevilov @ Mar 18 2011, 07... Mar 18 2011, 08:16    Andy Mozzhevilov Цитата(Aprox @ Mar 18 2011, 11:16) Вспоми... Mar 18 2011, 08:24     Aprox Цитата(Andy Mozzhevilov @ Mar 18 2011, 11... Mar 18 2011, 11:10      sergeeff Цитата(Aprox @ Mar 18 2011, 15:10) Не сов... Mar 18 2011, 18:28       Aprox Цитата(sergeeff @ Mar 18 2011, 21:28) А к... Mar 19 2011, 09:30        sergeeff Цитата(Aprox @ Mar 19 2011, 13:30) Наверн... Mar 19 2011, 09:38 MALLOY2 Цитата2. Вызвать из нее функцию статической инициа... Mar 23 2011, 13:18 Andy Mozzhevilov Цитата(MALLOY2 @ Mar 23 2011, 16:18) Можн... Mar 23 2011, 17:30  Andy Mozzhevilov Код// __iar_data_init - функция из библиотеки, вы... Mar 24 2011, 08:12
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|