среда, 10 июля 2013 г.

Урок 4. Простая программа на C

<< Назад к оглавлению

ВНИМАНИЕ! ЭТО УСТАРЕВШАЯ СТАТЬЯ! НОВАЯ ЗДЕСЬ

Для нашей следующей программы понадобится компилятор Си. Его можно скачать в оглавлении. Так же понадобится файл линковщика для нашего контроллера. На всякий случай выкладываю его сюда.
pic18f2550
без бутлоадера Ссылка
с HID бутлоадером Ссылка
pic18f4550 
без бутлоадера Ссылка
с HID бутлоадером Ссылка
Файл линковщика .lkr говорит компилятору, какие библиотеки подключать и как использовать память контроллера. Например, если мы используем описанный в прошлом уроке бутлоадер, то мы должны подключить файл lkr с HID бутлоадером, и он сообщит компилятору, что программа должна располагаться после бутлоадера - с адреса 0x1000.

Итак, создаем проект в MPLAB
Это делается примерно так же как во втором уроке, только выбираем проект C и добавляем файл линковщика
Файл линковщика говорит о том, как мы собираемся использовать память контроллера. Поэтому и отличаются эти файлы, если мы используем бутлоадер или нет.
Далее привожу код программы. Это аналог программе, написанной в уроке 2.
#include <p18f2550.h>

#pragma config WDT = OFF //
#pragma config FOSC=INTOSCIO_EC // Выбран внутренний генератор
#pragma config MCLRE = OFF // отключаем сигнал сброса



#define REMAPPED_RESET_VECTOR_ADDRESS         0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS         0x1018
void main (void);

#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
   main();
}
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR (void)
{
    _asm NOP _endasm
}
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR (void)
{
    _asm NOP _endasm
}

#pragma code page
void delay(void)
{
long i;
for (i=0;i<100000;i++);
}

void main (void)
{
  
  TRISA = 0;

  PORTA = 0;

  while (1)
  {
  PORTAbits.RA2 = 1;
  delay();
  PORTAbits.RA2 = 0;
  delay();
}
    ;
}

Все обозначения вроде портов и встроенных устройств можно найти в файле p18f2550.h или p18f4550.h.
директива #include <p18f2550.h> подключает заголовки для контроллера
#pragma config - Это опять же выбор конфигурационных битов для контроллера. См урок №2.

#define REMAPPED_RESET_VECTOR_ADDRESS         0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS         0x1018

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

#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
void _reset (void)
{
    main();
}

Вот эти строки говорят, что следующий код будет начинаться именно с указанного адреса. В данном случая директива #pragma работает как команда ассемблера .ORG - то есть просит компилятор записать следующий код с определенной ячейки памяти. Вообще программа начнется с функции _reset. Потому что она идет первая по порядку. адрес 0x1000. Но после нее следуют еще прерывания. Поэтому когда происходит сброс контроллера, эта функция просто "перепрыгивает" код прерываний и запускает код за ними.
Но можно задать расположение программы в памяти еще с помощью скрипта линковшика. Посмотрите на эту строку.
#pragma code page
Это обозначает, что дальше будет программа записана в ту область, которая размечена в файле *lkr, как page

void delay(void)
{
long i;
for (i=0;i<100000;i++);
}
Вот это задается функция задержки. Она просто мотает переменную i до 100000 и ничего при этом не делает.
Вызывается функция следующей командой
delay();

void Remapped_High_ISR (void)
{
     _asm NOP _endasm
}

Эта функция - прерывание. В нашем случае она ничего не делает. Но вы можете добавить код обработки прерываний сюда.
 _asm

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

Файлы проекта:
 кода на С ссылка
https://yadi.sk/d/OeZ6mXRHVMZcF

суббота, 6 июля 2013 г.

Урок 3. Использование Bootloader'a

<< Назад к оглавлению

Окей, это будет первый шаг к освоению USB интерфейса.
Есть такая интересная штука. Называется бутлоадер. Что это такое?
Это программа, которая вшивается в начало памяти контроллера и позволяет его программировать.
То есть, для того, чтобы прошить контроллер теперь не нужно будет подключать программатор. Но мы с вами при этом расплатимся памятью программ, так как 0x1000 ячеек будет занято бутлоадером. Итак, к делу.
Интерфейс USB довольно капризный, так что все, что связано со стабильностью USB должно быть собрано очень аккуратно. Кварц должен быть добротно соединен с ножками контроллера.
Я вообще советую вам купить USB розетку, примонтировать ее на плату, чтобы всегда быть уверенным, что контроллер качественно соединен с портом USB.
на всякий случай даю вам распиновку порта
Взято из википедии.
Схема подключения контроллера pic18f2550

Сразу поясню, что когда мы выключатель sw2 замыкаем на землю, наш контроллер будет входить в режим бутлоадера, то есть прошивать. А если sw2 переключен на +5 то, контроллер будет пытаться запустить нашу программу
Схема подключения контроллера pic18f4550

Прошиваем контроллер следующим файлом
для pic18f2550 ссылка
для pic18f4550 ссылка
это прошивки, скомпилированные из исходников из официального пакета microchip solutions. Правда я поменял некоторые настройки.
Теперь качаем программу для работы с бутлоадером
linux ссылка
Для линукса я пока что не проверил.
Так вот, запускаем эту программу и в идеале мы должны увидеть это:
Кроме того, контроллер должен замигать светодиодом. Если программа не определяет ваш контроллер, то проверьте полярности и ищите ошибку в схеме.

Теперь о том, как это работает. Мы попробуем запустить нашу программу из урока №2. Только ее нужно немного изменить. 
Если бутлоадер получает команду запустить нашу с вами программу (sw2 замкнут на +), то он делает переход на адрес 0x1000 откуда, и будет начинаться теперь наша программа. А векторы прерывание соответственно будут перемещены из 0x8 в 0x1008 и из 0x18 в 0x1018
для того, чтобы изменить нашу программу нужно поменять 
org 0 на org 0x1000
и org 0x28 на org 0x1028
И программа теперь будет начинаться в аккурат после бутлоадера
Вот исходный код новой программы
Причем мы можем использовать для прошивки этих двух контроллеров через бутлоадер один и тот же HEX файл, так как он не будет проверять соответствие контроллера и не будет менять конфигурационные биты.
Если у вас все получилось, то у вас при запуске контроллера должен мигать светодиод на порту RA2 как в уроке 2. 
Для того, чтобы снова прошить контроллер через бутлоадер, замкните переключатель sw2 на землю.
Чтобы прошить выбираем
File->import firmware image 
выбираем hex файл
После этого нажимаем program->Erase/Program/Verify device
перезагружаем контроллер
Поздравляю - у вас работает первая USB программа, хоть пока что и написанная не вами

Собрать бутлоадер самому

На всякий случай выложу готовый проект, по которому можно собрать бутлоадер самому. Вдруг вам нужно изменить USBDIV конфигурационное слово, если у вас кварц не 20МГц, или кнопку, на которую надо нажать для пуска бутлоадера.
Пару слов о проекте. Это бутлоадер из MLA 2015_08_10. Microchip добавили такую опцию - при удачной прошивке по адресу 0x1006 записывается подпись. Это слово GOOD (0x600D). Расчет идет на то, что компилятор обычно ничего не хранит в этом адресе, а делает GOTO на основную часть программы. Тем не менее, это проблема, если вы пишете на ассемблере. Поэтому, если вы хотите нетронутую версию бутлоадера - установите MLA и соберите из него.
Еще одно. Бутлоадер собирается только с XC8 компилятором версии PRO. А воровать его с какого-нибудь всем известного сайта - это ай-яй-яй.
Ссылка на проект бутлоадера
https://yadi.sk/d/xYAFgZaDjFr4V

среда, 3 июля 2013 г.

Урок 2 глава 4 Работа со внутренними устройствами контроллера

<< Назад к оглавлению

Наш контроллер просто напичкан всякими трясучками и прибамбасинками.
Я вкратце расскажу как их использовать.
Смотрим на схему подключения нашего контроллера

то, что подписано рядом с ножками контроллера - это то, как их можно использовать.
так же, начиная со страницы ТО:14 дано описание возможностей ножек контроллера
Если вдруг у вас что-то работает не так, как надо, может быть, что один из этих модулей не включен или не выключен. Ну, например, у вас на ножке RA0 включен модуль АЦП, и вы не можете вывести на эту ножку сигнал плюс. Что делать?
Смотрим. На ножке, которая нас интересует есть только АЦП и цифровой ввод вывод. Отключим АЦП.
Смотрим по ТО. Ищем АЦП то есть по-буржуйски это будет ADC. Analog to Digital Converter
это у нас глава 21. Читаем. Там нам пишут регистры ADRESH и ADRESL - это для того, чтобы считывать результат с устройства.
а вот ADCON0 ADCON1 ADCON2 - есть регистры для управления этим модулем.
Читаем про них
так-с. ADCON0 bit0 = 0 -A/D converter disabled - то, что надо
А вот и включение и выключение АЦП на конкретных ножках - ADCON1 биты 3-0
мы запишем туда единички и АЦП на всех ножках будет выключен. читай ТО:262
MOVLW 0x0F 
MOVWF ADCON1 
С остальными модулями - аналогично. Читайте ТО, там все понятно.
Ну другое дело, конечно модули типа USB. Там все хуже. Но об этом в следующих уроках.

Урок 2 глава 3 Команды ассемблера

<< Назад к оглавлению

Я думаю, что не имеет смысла сильно расписывать то, что и так очень хорошо опубликовано.
Возьмите самоучитель за авторством Корабельникова, указанный в списке литературы в оглавлении. Там все крайне доступно объяснено.  Зеркало
Я сделаю здесь только краткий очерк. Список всех команд, поддерживаемых контроллером приведен в ТО:309 главе 26 instruction set.
Там даны краткие примеры по использованию команд.
Практические все логические операции производятся через специальный регистр - аккумулятор. Для того, чтобы записать туда число можно использовать такую команду:
MOVLW число
и потом, вы можете сложить это число с еще одним. И уже только после этого - записать его из аккумулятора в другой регистр.
Так же наш контроллер поддерживает умножение. Для умножения, надо множители записать в специальные регистры.
Управляют портом ввода-вывода те же регистры.
TRISA говорит о том, на ввод или на вывод будет работать порт А.
PORTA - выводит информацию на ножки порта А если оный работает на вывод. И с него можно считать состояние порта, если оный работает на ввод.
Кроме того могут быть дополнительные флаги, которые говорят о том, куда записывается результат выполнения команды, какую область памяти мы используем (BSR или access bank). Конкретнее смотрите в главе instructions set в ТО.