|
Простой и прозрачный способ отладки программ, (особенно для начинающих) |
|
|
|
Dec 11 2007, 15:32
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Время от времени слышатся просьбы о помощи в отладке программы. Ниже предлагается простой способ отладки через уарт путём внесения отладочной информации в отлаживаемую программу, т.е. по мере необходимости в исследуемые ветви отлаживаемого кода вставляются две строчки с определённым текстом, например, таким Код rcall debug .db "some datum to be sent",0 или таким Код rcall debug .db "первая точка пройдена",0 Программа вывода отладочной информации имеет следующий вид Код debug: pop zh pop zl lsl zl rol zh deb1: lpm temp,z+ tst temp brne deb2 lsr zh ror zl ijmp deb2: sbis ucsr0a,udre0 rjmp deb2 out udr0,temp rjmp deb1 и занимает всего 14 слов кода. Интересно бы пообсуждать данный метод и узнать заодно, кто-нибудь пользуется подобным способом отладки?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Dec 11 2007, 15:53
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(=GM= @ Dec 11 2007, 18:32)  Интересно бы пообсуждать данный метод и узнать заодно, кто-нибудь пользуется подобным способом отладки? Я, например, только таким способом и пользуюсь  Приведенный фрагмент компактен и симпатичен, но не обеспечивает сохранение регистров, да и UART UARTу рознь, так что предпочитаю все сохранить, пусть даже код существенно более раздутый получается, и воспользоваться "полноценной" программой передачи (которая используется и другими компонентами). Плюс к отладочной пропечатке по точкам практически всегда использую hex-пропечатку того, чего надо, на уровне байтов, регистров, а то и блока данных в формате hex/ascii. Приведенный пример с вызовом и параметрами в виде констант вслед за ним еще очень удобен при систематической загрузке регистров какой-нибудь периферии или собственных аккумуляторов или еще чего, не надо кучи ldi и lpm, результат компактнее и нагляднее (и пусть в меня не бросают камнями апологеты ЯВУ). А еще для отладки оказалось весьма удобным использовать бутер, который принимает через UART непосредственно .hex, и перепрограммирует программную память прямо в терминале, по простому копированию. Но тут надо использовать либо xon/xoff, либо (что особенно удобно в случае USB/COM) аппаратное управление потоком. 921600 и "со свистом"... Заодно упрощается жизнь на ноутбуках, где кроме USB и нет ничего. Один раз бутер хоть чем зашить и все... Но, понятное дело, это для более-менее "объемистых" камешков, хоть восьмая мега нужна...
|
|
|
|
|
Dec 11 2007, 16:36
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(rx3apf @ Dec 11 2007, 15:53)  Приведенный фрагмент компактен и симпатичен, но не обеспечивает сохранение регистров, да и UART UARTу рознь, так что предпочитаю все сохранить, пусть даже код существенно более раздутый получается, и воспользоваться "полноценной" программой передачи (которая используется и другими компонентами) Код можете показать? Интересует как вы сохраняете регистры, и где. Что касается "полноценной" программы передачи, то тут вопрос, к примеру, вот вы начинающий и как раз хотите освоить приём-передачу "полноценной" программы с кольцевыми буферами и т.п. Что-то не срастается, глаз замылился, вы не видите очевидных вещей...значит, самое время воспользоваться более-менее автономным механизмом отладки. Цитата(rx3apf @ Dec 11 2007, 15:53)  Плюс к отладочной пропечатке по точкам практически всегда использую hex-пропечатку того, чего надо, на уровне байтов, регистров, а то и блока данных в формате hex/ascii Тут как-то не врубился, что это - hex-пропечатка? Цитата(rx3apf @ Dec 11 2007, 15:53)  Приведенный пример с вызовом и параметрами в виде констант вслед за ним еще очень удобен при систематической загрузке регистров какой-нибудь периферии или собственных аккумуляторов или еще чего, не надо кучи ldi и lpm, результат компактнее и нагляднее (и пусть в меня не бросают камнями апологеты ЯВУ) Это должен был бы быть мой следующий пост(:-(. Похоже, не один я такой прыткий...Покажите кусочек кода, если можно. Цитата(rx3apf @ Dec 11 2007, 15:53)  А еще для отладки оказалось весьма удобным использовать бутер, который принимает через UART непосредственно .hex, и перепрограммирует программную память прямо в терминале, по простому копированию. Но тут надо использовать либо xon/xoff, либо (что особенно удобно в случае USB/COM) аппаратное управление потоком. 921600 и "со свистом"... А смысл 921600, если пишется 5 мс? Насчёт загрузчика я пока думаю, не решил до конца вопрос. Заманчиво использовать тот-же усап, в принципе, можно всю рам задействовать, но вот что делать, если программа больше объёма рамы?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Dec 11 2007, 16:54
|
Гуру
     
Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047

|
Цитата(=GM= @ Dec 11 2007, 19:36)  Код можете показать? Интересует как вы сохраняете регистры, и где. Не претендуя на оптимальность и компактность: ;---------------------------------------------------------------------- ; Программа выдачи сообщений ; Текст сообщения описывается директивами .db непосредственно после ; команды rcall Msg, признаком конца текста является байт 00. ; После выполнения программы управление возвращается на следующую за ; байтом 00 команду. Программа не портит регистры. Для выдачи текста ; используется команда rcall Print. ; Эта версия программы может использоваться только для микроконтроллеров ; с 16-разрядным счетчиком PC !!! ;---------------------------------------------------------------------- Msg: push temp push YH ; сохраним push YL ; рабочие push ZH ; регистры push ZL in YH,SPH ; адрес текущей in YL,SPL ; позиции стека ldd ZH,Y+6 ldd ZL,Y+7 ; адрес операнда в памяти lsl ZL ; адрес для команды lpm rol ZH Msg1: lpm temp,Z+ ; очередной байт tst temp ; контроль на терминатор breq Msg2 ; текст закончился rcall Print ; вывод байта rjmp Msg1 Msg2: sbrc ZL,0 adiw ZL,1 ; коррекция для нечетного адреса lsr ZH ; новый адрес возврата ror ZL std Y+6,ZH std Y+7,ZL ; меняем адрес в стеке pop ZL pop ZH pop YL pop YH pop temp ret Цитата(=GM= @ Dec 11 2007, 19:36)  Что касается "полноценной" программы передачи, то тут вопрос, к примеру, вот вы начинающий и как раз хотите освоить приём-передачу "полноценной" программы с кольцевыми буферами и т.п. Что-то не срастается, глаз замылился, вы не видите очевидных вещей...значит, самое время воспользоваться более-менее автономным механизмом отладки. Но передачу-то в первую очередь надо отладить, потому как мало пихать байты в UDR, надо ведь и делители настроить, да и готовность приемника (в случае управления потоком) проверить. Для передачи часто можно и без кольцевых буферов обойтись. Цитата(=GM= @ Dec 11 2007, 19:36)  Тут как-то не врубился, что это - hex-пропечатка? В смысле, вывести на экран hex-значение байта. Цитата(=GM= @ Dec 11 2007, 19:36)  А смысл 921600, если пишется 5 мс? Меньше накладные расходы на пересылку. И 5 mS это ведь страница пишется. 64 байта даже в бинарном виде на 115200 передаются столько же, в .hex вдвое дольше. А страницы-то бывают и 128 (лениво смотреть, в старших камнях ведь и того больше, наверное ?) 12 кило кода в mega168 сейчас загружаются две секунды... Цитата(=GM= @ Dec 11 2007, 19:36)  Насчёт загрузчика я пока думаю, не решил до конца вопрос. Заманчиво использовать тот-же усап, в принципе, можно всю рам задействовать, но вот что делать, если программа больше объёма рамы? А при чем тут объем RAM ? Ну да, если не управлять потоком, то да, надо проглотить все сразу. Но ведь можно и тормознуть (я останавливаюсь после каждой строчки, т.е. нужен буфер на строку).
|
|
|
|
|
Dec 11 2007, 20:12
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Странные вы какие-то...
Отладка отладке -- рознь. Одно дело отлаживать код в мелкиих АВРках (tiny13, 15, 26), у которых нет uart, другое дело отлаживать код в крупных АВРках, где полно всяких "вводов/выводов".
Я лично так делаю. Когда код небольшой по размерам или код дожен работать в реальном времени, -- выделяю под отладку 2-3-4 вывода какого-нибудь порта. "Прохождение" проги контролирую изменением состояния соответствующей ноги. Можно ЛЭДом, можно осциллографом. Это так называемый, первый уровень отладки. Он годится лишь для маленьких АВРок и маленьких программ.
Если прога болшая и процессорное время позволяет, то организую отладочный канал на основе uart'а. С частотой особо не заморачиваюсь, делаю 115200. Такую частоту все компы поддерживают, поэтому проблем нет. На вывод организую буфер, не кольцевой, объемом от 10 до 64 байт (когда как). Этого вполне достаточно для того, чтобы вывести изнутри АВРки несколько байт перемненных. По этим байтам можно судить о том, что делает прога. Это -- второй уровень отладки. Обычно я использую этот подход для программ 500-4000 байт для средних АВРок (от tiny2313 до mega8).
Третий уровень. Это отладка с помощью JTAG-отладчитков. Сюда можно также отнести и 1d-отладку, но я с ней не "игрался", поэтому ничего не могу сказать. Итак, этот уровень позволяет не только посмотреть некоторые переменные, но и пройтись по шагам. Понятно, что не всякая АВРка имеет JTAG-интерфейс. Поэтому этот метод подходит только для больших АВРок и больших программ.
Все, что я сказал выше, это не есть какое-то незыблемое правило. Способ отладки зависит от типа АВРки и объема программного кода, от наличия под руками отладочных средств (JTAG-отладчика, конвертора uart -> RS232, -> USB) и желания что-то делать.
Два, маленьких примера. Я сейчас рожаю один проект на mega2561: два uart'а, графический LCD, тетя клава на 20 кнопулек (мышки только вот нет!). Система управления основанная на событиях, реальное время, ... ладно, не буду все рассказывать. Короче, достаточно солидный проект. Так вот, отлаживать его с помощью LED'ов -- невозможно, по моему тут даже и говорить не о чем. Если отладку производить с помощью uart'ов, то они оба заняты самой прогой. Поэтому, быстро и безупречно -- не получится. На других интерфейсах (I2C, SPI) тоже сидя не по одному устройству. Значит, оставется только JTAG. Что я и делаю.
Второй пример, для отладки модуля, упомянутого в первом примере, мне понадобилось сделать маленькую плату на tiny2313. Плата должна была принимать определенные пакеты и отсылать на них ответные. Типа эмулятор периферийного устройства (объекта). Я не умею писать проги без ошибок, поэтому отладка здесь тоже была нужна. Эту плату я отлаживал с помощью "лапко-дерганий" и вывода инфы в uart.
Сообщение отредактировал zhevak - Dec 11 2007, 20:24
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Dec 11 2007, 20:49
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Цитата(=GM= @ Dec 11 2007, 19:32)  ijmp deb2: sbis ucsr0a,udre0 rjmp deb2 out udr0,temp rjmp deb1[/code][/font] и занимает всего 10 слов кода.
Интересно бы пообсуждать данный метод и узнать заодно, кто-нибудь пользуется подобным способом отладки? Могу поделиться кодом терминалки примерно на столько же строк    ,для полного комплекта. Я допустим не только вывожу и и через кнопки ,но и решаю ,проезжать или останавливаться ,если остановились куда дальше движемся ,ну между делом заливаю прогу через боотлоадер  ,рестартую ,питание отключаю ,короче все в одном флаконе не перетыкая разьем  Вообще это давний способ отладки ,и на мой взгляд наиболее оптимальный для отлова динамических ошибок.
|
|
|
|
|
Dec 12 2007, 06:46
|
Местный
  
Группа: Свой
Сообщений: 313
Регистрация: 7-01-07
Из: Севастополь
Пользователь №: 24 170

|
Я тоже УАРТом отлаживаюсь. Вывод в фоновой программе, обычный 115200. Пользуюсь кольцевым буфером, а уж туда подпрограммы скидывают то, что надо. Все это вывожу на самопальный терминал в виде осциллографа, с прокручиваемым буфером. Скажем, на 1-й канал вывожу флаги, на второй метки или адреса - и сразу видно, куда свалился. Даже не всегда требуется пошаговая прокрутка. Так же сигналы через фильтры гоняю - принимаю отладочные данные от компа, укладываю их в ячейки ОЗУ фильтра, флагом разрешаю шаг фильтра. Фильтр выкладывает данные в буфер - и на осциллограф. Не знаю, кому как, а мне удобно - сразу отклик видно, шум и помехи можно добавлять всяческие. Главное - сигнал свой и реакция предсказуема. Ну и в конце - проверка реальным сигналом. Для пользователя УАРТ отключаю, хотя далеко в меню есть флажок для включения. Тут главное - не запутаться в версиях терминалов-осциллографов...
|
|
|
|
|
Dec 12 2007, 06:52
|

Местный
  
Группа: Свой
Сообщений: 409
Регистрация: 29-10-07
Пользователь №: 31 836

|
Подскажите пожалуйста что я делаю не так? в свою программу вставляю в "нужном" месте код: Код rcall debug .db 1,2,3,4,5,0 далее в пп обработки седующее: Код debug: pop zh pop zl deb1: lpm temp,z+ tst temp brne deb1 ijmp Проверяю в АВРстудии. Как я понимаю в регистр "temp" должны последовательно по команде "lpm" загружатся "1,2,3,4..". На деле же совершенно другие цифры. В чем "неправильность"?!  зы: Mega8515
Сообщение отредактировал adc - Dec 12 2007, 06:57
--------------------
Умный программист пишет тупым кодом гениальные вещи, а не наоборот...
|
|
|
|
|
Dec 12 2007, 08:03
|
Участник
  
Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695

|
Цитата(adc @ Dec 12 2007, 15:52)  Подскажите пожалуйста что я делаю не так? в свою программу вставляю в "нужном" месте код: Код rcall debug .db 1,2,3,4,5,0 далее в пп обработки седующее: Код debug: pop zh pop zl deb1: lpm temp,z+ tst temp brne deb1 ijmp Проверяю в АВРстудии. Как я понимаю в регистр "temp" должны последовательно по команде "lpm" загружатся "1,2,3,4..". На деле же совершенно другие цифры. В чем "неправильность"?! :05: зы: Mega8515 .include "m8515def.inc" ldi r16, low(RAMEND) out SPL,r16 ldi r16, high(RAMEND) out SPH,r16 rcall debug .db 1,2,3,4,5,0 nop nop debug: pop zh pop zl lsl zl rol zh deb1: lpm r16,z+ tst r16 brne deb1 ijmp
|
|
|
|
|
Dec 12 2007, 08:45
|

Местный
  
Группа: Свой
Сообщений: 409
Регистрация: 29-10-07
Пользователь №: 31 836

|
ae_ пасиба! Я писал что "..в свою программу вставляю в "нужном" месте код..." т.е. Инициализация стека уже сделана. а вот со сдвигом правильно, в точку!  только правильней так: Код debug: pop zh pop zl lsl zl rol zh deb1: lpm temp,z+ tst temp brne deb1 lsr zh //!!! ror zl //!!! ijmp Странно, почему ув. =GM= не написал такой код сразу?! (с добавлением lsr,ror и т.д.) или это подразумеевалось само сабой?!
Сообщение отредактировал adc - Dec 12 2007, 08:46
--------------------
Умный программист пишет тупым кодом гениальные вещи, а не наоборот...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|