У меня Linux головного мозга.
Поэтому когда я решил сделать свой космический модуль (https://anklab.ru/forum/index.php?topic=45.0) то стал использовать средства разработки по эти ОС, тем паче их в достатке.
Но при отладке возникла проблема, следующего характера: на макетке я могу увидеть только финальный этап работы программы, а если до него даже не дошло то как определить где затык?
Для форточек существует среда разработки, где это все реализованно, но ... Вобчем я приступил к поиску и нашел (https://www.nongnu.org/simulavr/).
Это эмулятор микроконтроллеров серии AVR.
Алгоритм работы следующий:
1. Запускаем сам эмулятор командой.
simulavr -g -p 1200 -d atmega328 -F 8000000
где:
-g запустить эмулятор как сервер куда будет подключаться отладчик,
-p порт сервера,
-d atmega328 выбор эмулируемого контроллера,
-F частота работы контроллера в герцах.
2. Комилируем прошивку с флагом
-ggdb чтобы в ней сохранилась отладочная информация.
3. Запускаем отладчик выбрав файл прошивки.
avr-gdb ./avrblink.o
Здесь листинг прошивки для понимания
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#define _data_1 PORTC |= (1<<3) // Выбираем пин для вывода данных в сдвиговые регистры и устанавливаем на нём 1 путём установки порта и назначения разряда соответствующего пину
#define _data_0 PORTC &= ~(1<<3) // -.- устанавливаем на нём 0 -.-
#define _clock_high PORTC |= (1<<4) // Выбираем пин clock и устанавливаем на нём высокий уровень
#define _clock_low PORTC &= ~(1<<4) // Выбираем пин clock и устанавливаем на нём низкий уровень
#define _latch_up PORTC |= (1<<5) // Выбираем пин защёлки и поднимаем её
#define _latch_down PORTC &= ~(1<<5) // Выбираем пин защёлки и опускаем её
#define SIZE_SCREEN 4 //размер буфера экрана
#define SIZE_ABC 8 //размер буфера экрана
unsigned char buffer [SIZE_SCREEN]; //создаем буфер буфер экрана
// присваиваем имя значению в буфере экрана оно означает цвет светодиода
#define _Blue buffer[3]
#define _Green buffer[2]
#define _Red buffer[1]
#define _RGB buffer[0]
#define _Null memset (buffer, 0, 4) //обнуление буфера экрана
//Алфавит
unsigned char ABC [SIZE_ABC] =
{
0b00000001,
0b00000010,
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
};
// конец алфавита
int record (); //прототип функции для записи в сдвиговые регистры
int blink (); //прототип функции включающей мигалку
int stop (); //прототип функции включающей сигнал стоп
int left (); //прототип функции включающей сигнал левого поворота
int right (); //прототип функции включающей сигнал правого поворота
int left_stop (); //прототип функции включающей сигнал левого поворота и сигнала стоп
int right_stop (); //прототип функции включающей сигнал правого поворота и сигнала стоп
int main (void)
{
DDRC = 0b00111000; //устанавливаем необходимые пины на вывод
_clock_high; // для предотвращения ложного срабатывания
_latch_up; // поднимаем защелку
while (1)
{
blink ();
_delay_ms(50);
stop ();
_delay_ms(50);
left ();
_delay_ms(50);
right ();
_delay_ms(50);
left_stop ();
_delay_ms(50);
right_stop ();
_delay_ms(50);
}
}
int record ()
{
_latch_down; // опускаем защелку
for (int x = 0; x<SIZE_SCREEN; x++) //цикл для переборки байтов в массиве (уточнить как храниться число)
{
for (int y = 7; y>=0; y--) // цикл для перебора битов в байте и подачи их на выход
{
_clock_low; // переводим регистры в режим ожидания данных
if ((buffer[x] & (1<<y)) == 0) // накладываем побитовую маску для считывания нужного бита
{
_data_0; // если ответ 0, выставляем на входе регистра 0
}
else
{
_data_1; //иначе, выставляем на входе регистра 1
}
_clock_high; // записываем данные в регистр
}
}
_latch_up; // поднимаем защелку, включаем светодиоды
}
int blink ()
{
_Null;
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(50);
_Null;
_Blue = ABC[7] | ABC[5] | ABC[2] | ABC[0];
_RGB = ABC[2];
record ();
}
int stop ()
{
_Null;
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
}
int left ()
{
_Null;
_Green = ABC[4];
_Red = ABC[4];
record ();
_delay_ms(100);
_Null;
_Green = ABC[5];
_Red = ABC[5];
record ();
_delay_ms(100);
_Null;
_Green = ABC[6];
_Red = ABC[6];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7];
_Red = ABC[7];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [4];
_Red = ABC[7] | ABC [4];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [5];
_Red = ABC[7] | ABC [5];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6];
_Red = ABC[7] | ABC [6];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6] | ABC [4];
_Red = ABC[7] | ABC [6] | ABC [4];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6] | ABC [5];
_Red = ABC[7] | ABC [6] | ABC [5];
record ();
}
int right ()
{
_Null;
_Green = ABC[3];
_Red = ABC[3];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2];
_Red = ABC[2];
record ();
_delay_ms(100);
_Null;
_Green = ABC[1];
_Red = ABC[1];
record ();
_delay_ms(100);
_Null;
_Green = ABC[0];
_Red = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[3] | ABC [0];
_Red = ABC[3] | ABC [0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2] | ABC [0];
_Red = ABC[2] | ABC [0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[1] | ABC [0];
_Red = ABC[1] | ABC [0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[3] | ABC [1] | ABC [0];
_Red = ABC[3] | ABC [1] | ABC [0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2] | ABC [1] | ABC [0];
_Red = ABC[2] | ABC [1] | ABC [0];
record ();
}
int left_stop ()
{
_Null;
_Green = ABC[4];
_Red = ABC[4] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[5];
_Red = ABC[5] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[6];
_Red = ABC[6] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7];
_Red = ABC[7] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [4];
_Red = ABC[7] | ABC [4] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [5];
_Red = ABC[7] | ABC [5] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6];
_Red = ABC[7] | ABC [6] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6] | ABC [4];
_Red = ABC[7] | ABC [6] | ABC [4] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[7] | ABC [6] | ABC [5];
_Red = ABC[7] | ABC [6] | ABC [5] | ABC[3] | ABC[2] | ABC[1] | ABC[0];
_RGB = ABC[0];
record ();
}
int right_stop ()
{
_Null;
_Green = ABC[3];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[3];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[2];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[1];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[1];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[3] | ABC [0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[3] | ABC [0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2] | ABC [0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[2] | ABC [0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[1] | ABC [0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[1] | ABC [0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[3] | ABC [1] | ABC [0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[3] | ABC [1] | ABC [0];
_RGB = ABC[0];
record ();
_delay_ms(100);
_Null;
_Green = ABC[2] | ABC [1] | ABC [0];
_Red = ABC[7] | ABC[6] | ABC[5] | ABC[4] | ABC[2] | ABC [1] | ABC [0];
_RGB = ABC[0];
record ();
}
4. Подключаемся к серверу.
(gdb) target remote localhost:1200
5. Загружаем прошивку.
(gdb) load
6. Создаём точку останова командой
breakbreak record
Breakpoint 4 at 0xa6: file avrblink.c, line 70.
Где в качестве аргумента можно указать как в моём случае имя функции, так и непосредственно строку программы.
Посмотреть какие есть точки останова можно командой
info breakpointУдалить
delete N/ где N порядковый номер точки останова.
7. В avr-gdb есть 3 основных команды для просмотра значений переменной или области памяти.
x - команда проверяет память, начиная с определенного адреса.
Пример
x/4t &buffer
где (4) кол-во байт памяти которые необходимо прочитать, (t) вид отображения двоичный, (&buffer) начальный адрес памяти откуда производиться чтение. Может быть указан как напрямую, так и ввиде указателя как в примере. Оператор & вычисляет адрес переменной
print – выводит значение какого-либо выражения (выражение передаётся в качестве параметра);
display – добавляет выражение в список выражений, значения которых отображаются каждый раз при остановке программы;
Здесь подробнее.
Поскольку мне нужно было смотреть как изменяестя буфер экрана после каждой точки отанова я использавал команду
displaydisplay/t buffer
8. Продолжаем выполнение программы командой
continue. Порограмма будет выполнятся до следующей точки останова и по достижени оной в консоль будет выводиться значение буфера экрана
/t buffer = {1, 1001111, 1000000, 0}
команды для пошагового выполнения программы
step – или s пошаговое выполнение программы;
next – или n пошаговое выполнение программы, но, в отличие от команды step, не выполняет пошагово вызываемые функции;
finish – выполняет программу до выхода из текущей функции; отображает возвращаемое значение,если такое имеется;
Вот
здесь описание других команд и естественно есть справка в самой программе.
Мне этого пока достаточно. Интернеты говорят о режиме
Emacs GUD, это режим для отладки с помощью
avr-gdb в
Emacs... по мимо регистров и локальных переменных используемых в программе, он позволяет просматривать участки памяти... и прочие вкусности, но я пока не разбирался.
P.S. Если кому то помог то замечательно, если кто-то подскажет как ещё можно использовать этот софт или даст ссылку на инструкцию по использованию
Emacs GUD, буду рад.
P.P.S Насколько я знаю через AVR-Studio можно пошагово исполнять программу в железе интересно это можно реализовать в Linux?
Как нибудь попробую, до emacs так и не дорос, но честно говоря он мне не по душе, сколько раз пытался, но безрезультатно.
Так что под линукс для себя понял, только хардкор - только vim.
Конечно плюшки в нём настраиваются непривычно, порой долго, но уже свыкся.
Из IDE понравилась Platformio, но забросил.
BluePill stm32 с ардуиновским бутлоадером запускал с помощью Platformio, в качестве редактора используя vim, где-то на своём сайте (сейчас лежит, сервер сдох) даже про это писал кажется.
+++
На данном этапе сижу под оффтопиком, потому как нужен совсем другой софт.
ы. В дуалбуте gentoo, последний раз обновлял бедную год назад... :)
Цитата: zenon от 07 Окт., 2020, 22:17в качестве редактора используя vim
Я так и не смог себя заставить в нём разобраться :) Отталкивает с самого начала, редактор должен редактировать после запуска, а не заставлять запоминать комбинации клавиш для сего действа. Возможно я слишком молод для понимания этой идеологии ;D
Я тоже не ас в vim, эволюция nano -> vim была долгой. Bash -> zsh было быстрее.
.vimrc в котором это видно, Ctrl+O, Ctrl+X сохранить, выйти.
syntax enable
set background=dark
" colorscheme grb256 "" colorscheme distinguished "" colorscheme jellybeans " colorscheme railscasts
" badwolf codeschool github jellybeans solarized vividchalk
" candy distinguished grb256 ir_black railscasts twilight vwilight
" BEST - vwlight/codeschool/jellybeans
" colorscheme jellybeans
colorscheme diokai
" au BufReadPost *.conf set syntax=etc
let g:lastplace_ignore = "gitcommit,gitrebase,svn,hgcommit"
let g:lastplace_ignore_buftype = "quickfix,nofile,help"
let g:lastplace_open_folds = 0
set autoread " Auto-reload buffers when file changed on disk
" Allow backgrounding buffers without writing them, and remember marks/undo
" for backgrounded buffers
set hidden " Disable swap files; systems don't crash that often these days
set updatecount=0
set nocompatible " Вообще, первая команда, которую надо поставить в vim — set nocompatible и отключить (нужную только олдовым хакерам BSD 4.4-Lite) совместимость с vi Билла Джоя. Он сразу станет удобней работать.
" nocompatible устанавливается автоматически, если есть .vimrc или .gvimrc.
" Для опции backspace я бы указал set backspace=indent,eol,start, так правильнее, нагляднее и понятнее, поддержка set backspace=2 оставлена из соображений совместимости.
" set backspace=2 "— что бы нажатие клавиши Backspace и через конец строки и отступы.
set wrapmargin=5 "— отступ от правой границы окна, где надо начинать перенос. Удобнее textwidth, если размеры окна изменяются.
set tildeop "~" " в vim используется для изменения регистра текущего символа. Строго говоря, эта операция нарушает идеологию vi о том, что для каждой операции можно добавлять movement. Эта опция включает такую возможность, теперь, например, "~W" изменит регистр до конца слова.
set scrolloff=3 "— сколько строк вверху и внизу экрана показывать при скроллинге. Очень удобно.
set sidescrolloff=2 "
" Whitespace
set tabstop=2 " количество пробелов в табуляции
set shiftwidth=2 " an autoindent (with <<) is two spaces
set expandtab " use spaces, not tabs
set smarttab "
set et " включим автозамену по умолчанию
set nowrap " попросим Vim не-переносить длинные строки
set ai " включим автоотступы для новых строк
set cin " включим отступы в стиле Си
set listchars=tab:▸\ ,trail:•,extends:❯,precedes:❮ " Indicator chars set listchars=tab:··¶ set listchars=tab:»\ ,trail:·,eol:¶¶
set list " показывать непечатаемые символы
set showbreak=↪\•
set backspace=indent,eol,start " backspace through everything in insert mode
" Joining lines
if v:version > 703 || v:version == 703 && has("patch541")
set formatoptions+=j " Delete comment char when joining commented lines
endif
set nojoinspaces " Use only 1 space after "." when joining lines, not 2
set synmaxcol=800 " don't try to highlight long lines
set nonumber " line numbers aren't needed
set ruler " show the cursor position all the time
set cursorline " highlight the line of the cursor
set showcmd " show partial commands below the status line
set shell=bash " avoids munging PATH under zsh
"let g:is_bash=1 " default shell syntax
set history=200 " remember more Ex commands
" Time out on key codes but not mappings.
" Basically this makes terminal Vim work sanely.
set notimeout
set ttimeout
set ttimeoutlen=100
" Далее настроим поиск и подсветку результатов поиска и совпадения скобок
set showmatch
set hlsearch
set incsearch
set ignorecase
set lz " ленивая перерисовка экрана при выполнении скриптов
" Порядок применения кодировок и формата файлов
set ffs=unix,dos,mac
set fencs=utf-8,cp1251,koi8-r,ucs-2,cp866
" Взаимодействие и элементы интерфейса
" Я часто выделяю мышкой содержимое экрана в Putty, но перехват мышки в Vim мне иногда мешает.
" Отключаем функционал вне графического режима:
if !has('gui_running')
set mouse=
endif
set wildmenu " — менюшки в консольке
" Использование иксового клипборда:
set clipboard+=unnamed
" set paste " При копипасте (например Ctrl+Shift+V) корректно проставляются все отступы
" set pastetoggle=
" set number
" Если всё поехало вкривь после вставки - нажать Ctrl+u
inoremap <silent> <C-u> <ESC>u:set paste<CR>.:set nopaste<CR>gi
" set statusline=%F%m%r%h%w\ [FORMAT=%{&ff}]\ [TYPE=%Y]\ [ASCII=\%03.3b]\ [HEX=\%02.2B]\ [POS=%04l,%04v][%p%%]\ [LEN=%L]
" set statusline=%t\ %y%m%r[%{&fileencoding}]%<[%{strftime(\"%d.%m.%y\",getftime(expand(\"%:p\")))}]%k%=%-14.(%l,%c%V%)\
if has("statusline") && !&cp
set laststatus=2 " always show the status bar
set statusline=%<%1*\ %f\ %* " filename
set statusline+=%2*%m%r%* " modified, readonly
set statusline+=\ %3*%y%* " filetype
set statusline+=\ %4*%{fugitive#head()}%0*
set statusline+=%= " left-right separation point
set statusline+=\ %5*%l%*/%L[%p%%] " current line/total lines
set statusline+=\ %5*%v%*[0x%B] " current column [hex char]
endif
hi StatusLine term=inverse,bold cterm=NONE ctermbg=24 ctermfg=189
hi StatusLineNC term=inverse,bold cterm=NONE ctermbg=24 ctermfg=153
hi User1 term=inverse,bold cterm=NONE ctermbg=29 ctermfg=159
hi User2 term=inverse,bold cterm=NONE ctermbg=29 ctermfg=16
hi User3 term=inverse,bold cterm=NONE ctermbg=24
hi User4 term=inverse,bold cterm=NONE ctermbg=24 ctermfg=221
hi User5 term=inverse,bold cterm=NONE ctermbg=24 ctermfg=209
" Mapping
" автодополнение фигурной скобки (так, как я люблю :)
imap {<CR> {<CR>}<Esc>O<Tab>
" автодополнение по Control+Space
imap <C-Space> <C-N>
" 'умный' Home
nmap <Home> ^
imap <Home> <Esc>I
" выход
imap <C-x> <Esc>:qa<CR>
nmap <C-x> :qa<CR>
" сохранение
imap <C-o> <Esc>:w<CR>
nmap <C-o> :w<CR>
"imap <C-s> <Esc>:w<CR>
"nmap <C-s> :w<CR>
" no search
nmap <silent> <F3> :silent nohlsearch<CR>
imap <silent> <F3> <C-o>:silent nohlsearch<CR>
" следующая ошибка
imap <C-F10> <Esc>:cn<CR>i
nmap <C-F10> :cn<CR>
" предыдущая ошибка
imap <S-F10> <Esc>:cp<CR>i
nmap <S-F10> :cp<CR>
" вкл/выкл отображения номеров строк
imap <C-F1> <Esc>:set<Space>nu!<CR>a
nmap <C-F1> :set<Space>nu!<CR>
" вкл/выкл отображения найденных соответствий
imap <S-F1> <Esc>:set<Space>hls!<CR>a
nmap <S-F1> :set<Space>hls!<CR>
" q: sucks
nmap q: :q
Но два режима работы vim надо всё-таки понять.
Сборку, компиляцию, прошивку, выхлоп ошибок прикручивается не очень сложно.
Вух. Благодарю. Оставлю на будущее. Пока связки nano и bach мне достаточно. Я в самом начале изучения программирования чего-либо и автомобиль пока не нужен достаточно велосипеда. :) И поскольку писать софт для серверов без Иксов пока не нужно, обхожусь связкой Visual Studio Code и AVR8_Burn-O-Mat для прошивки.
Ну так если с VS знаком, то platformio это надстройка над, те как расширение https://platformio.org/platformio-ide
В линуксе оно нативно кажется ставится, уже не помню точно. https://docs.platformio.org/en/latest/core/installation.html
Сейчас пытаюсь в Geany всё делать, отладка пока под вопросом...
Тыц (https://ph0en1x.net/76-howto-config-geany-linux-for-avr-programming-gcc-asm.html)
Там без Makefile, но с ним удобнее, сразу компиляция, сборка, заливка в мк, Shift+F9, F9, F5 например, примеры в соседней ветки выкладывал.