воскресенье, 28 декабря 2014 г.

Простой код на С. Компилятор XC8

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

Я плавно переделываю уроки на использование пакета MPLABX и компилятора XC8. Так как старые уже не поддерживается. Тем не менее, вы можете найти старую статью здесь. Так же точно можете скачать компилятор C18 и использовать его. XC8 несколько отличается

Итак, нам понадобится компилятор XC8. Его можно скачать с официального сайта. ссылка, либо же с зеркала зеркало

Итак, создаем проект в MPLABX
Это делается примерно так же как во втором уроке, только выбираем компилятор XC8

 Это аналог программе, написанной в уроке 2.
#include <p18f2550.h>
#include <stdio.h>
#include <stdlib.h>
#include <p18f2550.h>
#include "config.h"


void delay(void)
{
long i;
for (i=0;i<100000;i++);
}

int main(int argc, char** argv) {
  TRISA = 0;
  PORTA = 0;
  while (1)
  {
  PORTAbits.RA2 = 1;
  delay();
  PORTAbits.RA2 = 0;
  delay();
};
    return (EXIT_SUCCESS);
}
Сначала запускается функция main(). Идет настройка вывода сигнала через порт А (TRISA=0;) а потом обнуляется этот выход с порта А (PORTA=0); Далее идет бесконечный цикл, в котором мы мигаем лампочкой на порту RA2 и вызываем функцию задержки.
Пока что у вас не скомпилируется этот проект. Потому что в include стоит файл config.h, а мы пока его еще не создали. Там будут конфигурационные биты.
Необходимо их настроить. Для этого идем в Window->PIC memory views->configuration bits

откроется окно, и выставляем там FOSC=INTOSCIO, WDT=OFF, MCLRE=OFF
Щелкаем правой клавишей и Generate Source Code to Output. Эта опция создаст код, необходимый для задачи конфигурационных битов. 
Копируем код, создаем файл заголовков config.h и вставляем сгенерированный код в конец файла.

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

Если вы будете использовать этот код с бутлоадером. А это намного удобнее, нам необходимо сдвинуть его в памяти программы на 0x1000. Если в C18 компиляторе для этого была специальная директива, то теперь для этого служит настройка компилятора. Грубо говоря, теперь когда мы пишем код в XС8, компилятор сам знает где должны быть прерывания, как размечена память, и.т.д. Все, что мы можем сделать - это сделать сдвиг. 
Итак, чтобы программа корректно работала с бутлоадером, нужно сделать следующее:
File->Project properties
Потом XC8 global options (не XC8 compiler options, специально на это обращаю внимание), и пишем в поле additional options

--CODEOFFSET=1000

Это означает, что весь код компилируется со сдвигом в 0x1000



Если вы захотите вставить код ассемблера в файл Си, то вам нужно будет его заключить между директивами

#asm

#endasm

Файлы проекта: ссылка

вторник, 23 декабря 2014 г.

Второй урок. Простой код на ассемблере и устройство вкратце.


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

В данном тексте приведены ссылки на книги. "название книги":страница обозначает указатель на определенную страницу книги. "название книги":Гглава - главу. При этом ТО - сокращение для тех. описания контроллера (Datasheet). Например ТО:15 - 15 страница технического описания. ТО:Г3 - третья глава технического описания
 
Эта статья переработана. Существует так же старая версия с оболочкой MPLAB 8.91. Прочесть ее можно здесь.

Вот и ладушки, если вы читаете второй урок, то наверное, в первом вы смогли подготовить инструменты. Или и так без меня все умеете. Теперь небольшое отступление для начинающих. За более подробной
информацией, обращайтесь к серьезным книгам, особенно к техническому описанию контроллера.

Итак, что такое контроллер, и как он работает?
Конечно же, это просто черный жучек с ножками. За неимением никаких других членов, он общается с окружающим миром исключительно напряжением на ножках. Что в общем и демонстрировалось в программе в первом уроке. Просто с определенной переодичностью контроллер зажигал
светодиодик.
В расcматриваемых нами контроллерах память разделена. Программа записывается в отдельное пространство, именуемое памятью программы (PROGRAM MEMORY). Переменные и настройки хранятся в памяти данных (DATA MEMORY). Причем, ячейки памяти, выделенные для использования как переменные называются регистрами общего назначения (GENERAL PURPOSE REGISTERS или GPR) и настройки находятся в регистрах специального назначения (SPECIAL FUNCTIONS REGISTERS или SFR). Память данных поделена на 15 блоков и блоки меняются регистром BSR (BLOCK SELECT REGISTER).
Так же существует EEPROM memory - это флеш память, используемая для длительного хранения информации.
Подробнее о памяти контроллера смотри главу 1 ссылка.

Код программы


Для начала мы будем писать на ассемблере.
Если вы написали команду на ассемблере, то это будет ровно одна команда, записанная в контроллер.
Таким образом вы будете отлично знать, что ваш контроллер делает и как. А вот если вы пишете на C, то на каждую строчку, написанную вами могут приходиться сотни команд, выполненных контроллером. Знать-то нужно и то и другое, но ассемблер даст нам понимание того, что и как работает в контроллере.

Ладно, начнем.

Открываем MPLABX IDE жмем File->New Project. В открывшемся окне выбираем Microchip Embedded Standalone Project


 выбираем семейство контроллеров advanced 8 bit MRUs и наш контроллер, например pic18f2550
Next, Next.Теперь компилятор предлагает нам выбрать соответствующий набор для разработки. К этому моменту должно быть установлено все необходимое.
Первый урок на ассемблере, поэтому выбираем MPASM. Далее. Задаем имя и прочие свойства. Укажите кодировку с русским. Например. UTF-8. Иначе ваши комментарии на кириллице не сохранятся.

И вот проект открыт. По началу в нем есть только makefile. Это файл для сборки проекта. Поэтому щелкаем на Source files->new->empty file

Ну назовем его например main.asm
Переписываем туда программу. Вот код:

Листинг source.asm


  #include <p18f2550.inc> ;подключение заголовков
list p=18f2550 ; выбор контроллера
CONFIG FOSC=INTOSCIO_EC ; Выбран внутренний генератор
  CONFIG MCLRE = OFF ; отключаем сигнал сброса
  CONFIG WDT   = OFF ; отключаем сторожевой таймер

DELAYCOUNTER EQU 0x00  ; задаем две переменные для создания задержки (паузы)
DELAYCOUNTER1 EQU 0x01; в программе. Они по адресу 0x00 и 0x01
A EQU 0; под буквой A будем подразумевать, что используется access bank

ORG 0 ; начинаем с 0 адреса памяти программы
  GOTO main ; перейти на метку main
  ORG 28h ; теперь пишем с 28 адреса. (сделано это для работы с прерываниями)
main ;(начинается программа main- просто метка для нашего удобства)


  CLRF BSR,A;       ; - выбираем нулевой блок памяти данных
  CLRF PORTA,A       ; - обнуляем выход на порту а    ;

  CLRF WDTCON,A; выключаем сторожевой таймер
  MOVLW 0x0F       ; записываем 0x0F в аккумулятор
  MOVWF ADCON1,A    ; перебрасываем значение в ADCON1 - настраиваем порт A на цифровой вход/выход
  CLRF TRISA,A ;- настраиваем порт а - только на выход
  
endloop ; это цикл, в который будет без конца гонять наша программа
  BTG LATA,2,A; мигнуть светодиодом 
  CALL delay255; вызвать паузу
  GOTO endloop; вернуться к началу цикла

delay255 ; функция вызова паузы
  SETF DELAYCOUNTER,A; записать 0xFF в счетчик времени
  GOTO delay; перейти к delay
delay 
  SETF DELAYCOUNTER1,A; записать 0xFF во 2й счетчик времени
delaysub1 ;
  DECFSZ DELAYCOUNTER1,F,A; уменьшить 2й счетчик на 1. если >0
  GOTO delaysub1; то вернуться на шаг назад
  DECFSZ DELAYCOUNTER,F,A; иначе - уменьшить 1й счетчик, если >0
  GOTO delay; вернуться на метку delay
  RETLW 0; иначе - выйти из функции

END ;конец программы

Для контроллера pic18f2550
https://yadi.sk/d/1YkpyyJTVLg2V
Для контроллера pic18f4550
https://yadi.sk/d/FxMGleO_VLgp7 - к сожалению не могу сейчас проверить
для копиляции щелкаем Run->build main project

после компиляции у нас должен в папке проекта появиться HEX файл. Он находится в папке dist\default\production. Его можно и нужно прошить в контроллер. Это та же программа, что и в уроке 1.
На самом деле среда MPLABX умеет работать с программаторами, но у меня PICkit 2 и с ней она работает посредственно, поэтому я прошиваю HEX файл напрямую через PICKIT

Пояснения к коду программы



Начнем потихоньку разбирать что там написано

В самом верху указываем то, какой у нас будет контроллер
#include <pic18f2550.inc>
Мы их рлдключаем для того. чтобы вместо того, чтобы всегда и везде мы записывали цифрами. мы могли использовать некоторые уже привычные нам обозначения.
напирмер, без подключения заголовков. команда записи в регистр выбора блока (BSR) -строка 16 нашей программы выглядела бы так
MOVWF 0FE0;

так... Еще директива. 
list p=18f2550
Она просто говорит
компилятору, какой контроллер будем прошивать. 

Дальше уже интереснее. Нам нужно задать управляющее слово. это - настройки контроллера. 
Задает их директива CONFIG 
По поводу всех настроек контроллера обращаемся так же к техническому описанию. ТО:288


Конфигурационные биты


CONFIG FOSC=INTOSCIO_EC
Эта настройка говорит о том, что мы будем использовать внутренний генератор импульсов. Он - внутри контроллера. Читаем в ТО:25

CONFIG MCLRE = OFF
Здесь мы отключаем сигнал сброса. То есть контроллер будет включаться сразу с подачей на него питания.

CONFIG WDT = OFF
Отключаем сторожевой таймер. Просто. чтобы не "запариваться". Он служит защитой от зависания контроллера. Читаем в ТО:299

Более подробно конфигурационные биты рассмотрены во 2-й главе к этому уроку. ссылка

Тело программы


DELAYCOUNTER EQU 0x00
Эта директива (EQU) ставит в соответствие к DELAYCOUNTER 0x00
То есть мы пишем DELAYCOUNTER, а программа думает "0x00"
Вообще мы будем использовать DELAYCOUNTER как переменную. а 0x00 - просто адрес, где она хранится в общих регистрах.
Кстати. Забыл сказать. 0x00 - это просто число. Так мы записываем числа в 16ричной системе счисления.
то есть 0x6B = 107

Мы используем для нашей программы память, входящую в access RAM, поэтому мы вольны использовать ячейки памяти от 0x00 до 0x5F. А ячейки от 0x60 до 0xFF - это регистры общего назначения.

ORG 0
Этим мы указываем компилятору, чтобы он писал все последующие команды последовательно с адреса 0.
GOTO main
ORG 28h
main
Переходим на метку main. И начиная с 0x28 адреса пишем программу дальше. Метка main - адрес 0x28
Обратите внимание, мы оставили свободное место между адресом программы 0x1 и 0x28. Зачем? Если мы будем в последствии использовать прерывания, то в случае. если прерывание будет требовать на время приостановить программу. оно начнет выполнять команды по адресу 0x8 или 0x18. и это место нужно будет заполнить программой обработки прерывания.

Все последующие команды смотри в главе 3. Команды ассемблера. ссылка

MOVWF ADCON1
Когда мы записываем значение в регистр ADCON1. мы меняем настройки АЦП. По поводу 
использования встроенных устройств контроллера смотри главу 4. ссылка


Пожалуйста, помогите сделать статью лучше. Увидели непонятность, неточность или  ошибку, сообщите в комментарии, или напишите мне. Спасибо. Jasuramme@mail.ru

воскресенье, 29 июня 2014 г.

CAN интерфейс и контроллер pic18f2550

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

ЭТО УСТАРЕВШАЯ ВЕРСИЯ. НОВУЮ МОЖНО НАЙТИ Здесь
Мы будем говорить о контроллере pic18f2550, поскольку только он сейчас есть у меня перед глазами. Но все нижесказанное должно быть справедливо и для pic18f4550.
В этом контроллере есть специальные встроенные возможности общаться с периферией, но нету возможности создать сеть штатными средствами.
Предположим, что необходимо создать связь между несколькими отдаленными контроллерами. Можно конечно продумать то, как они будут общаться, написать для этого программу и установить усилители сигналов, чтобы их можно было передать на дальние расстояния. Но не много ли работы?
Есть множество готовых решений, с помощью которых можно это сделать.
Мы будем рассматривать CAN интерфейс. Он изначально был предложен фирмой Bosch и в сети есть множество информации, описывающей can интерфейс.
В двух словах о нем.
- передача идет по двум проводам
- настраивается скорость передачи информации
- существует механизм проверки сообщений
- гарантированная доставка сообщений.
На самом деле мне кажется абсолютно неважным описывать что-то столько раз документированное.
http://ru.wikipedia.org/wiki/Controller_Area_Network
Так же официальная спецификация на стандарт CAN 2.0
http://www.bosch-semiconductors.de/media/pdf_1/canliteratur/can2spec.pdf

Есть специальный интерфейсный контроллер CAN от фирмы microchip MCP2515
http://ww1.microchip.com/downloads/en/DeviceDoc/21801G.pdf
Это специальное "добавление" к контроллеру, осуществляющее реализацию сети CAN. И для этого контроллера еще нужен будет передатчик MCP2551
http://ww1.microchip.com/downloads/en/DeviceDoc/21667f.pdf
Ниже показано подключение pic18f2550 к MCP2515
Файлы проекта:
https://yadi.sk/d/7MknbTTtVNWJD
Проект рассчитан на то, чтобы быть прошитым через bootloader.

Общение между pic18f2550 и MCP 2515 происходит с помощью протокола SPI, созданного для общения с периферийными устройствами.
Для SPI используются соответствующие ноги SDI SDO SCK и CS
причем SDI (input) mcp2515 нужно подключить к SDO (output) pic18f2550. А в качестве CS используется любой цифровой вывод контроллера.

В проекте следующие файлы
2550can.c - основной файл команды
io.h - файл, в котором настроены вводы выводы pic18f2550
mcp2515address.h - адреса регистров внутри модуля MCP2515
spi.h - файл для работы со SPI интерфейсом

В программе используются следующие специфические комманды

OpenSPI(SPI_FOSC_16, MODE_00, SMPMID)  - Настройка регистров, связанных со SPI модулем

WriteSPI(msg)  - записать через SPI интерфейс сообщение msg

ReadSPI(msg)  - Возвращает прочитанный байт через SPI
в коде программы определены следующие функции, выполняющие действия с контроллером MCP2515

SPIByteRead(адрес) - прочитать регистр по адресу
SPIReset() - перезагрузить
SPImsg() - передать через SPI одно сообщение
SPIByteWrite(адрес,сообщение) - записать в адрес сообщение
transmitmsg() - передать сообщение

Настройка контроллера производится в функции userinit(); и в последствии в CANinit();
нужно выставить соответствующие пины контроллера на вывод (SDO,SCK) и ввод (SDI) - читай подробнее в комментариях к контроллеру.

потом идет перезагрузка контроллера и модуль CAN переводится в конфигурационный режим. Все основные настройки можно делать только в этом режиме. Настраиваются соответствующие конфигурационные регистры. Во-первых bit-timing (CNF1,CNF2,CNF3). Все узлы сети CAN должны работать на одной тактовой частоте.

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

У контроллера MCP2515 есть возможность отправлять сообщение при высоком сигнале на входах RTS. Мы отключаем их. Будем отправлять с помощью команд, передаваемых через SPI.
настраиваем прерывания. Например, когда контроллер увидит сеть CAN вывод INT будет нулем. По умолчанию на нем будет 1.
Так же настраиваются RX0BF и RX1BF. Когда буфер 0 будет заполнен, на RX0BFпропадет напряжение.
Потом мы включаем нормальный режим, в котором контроллер работает.

А потом передаем сообщение (по факту передастся при первой возможности - подключении к CAN сети). И просто мигаем светодиодом на RA2

Проверить работу вы сможете, когда у вас 2 таким образом сконфигурированных контроллера, или другой узел CAN. И проверять пропадание напряжения на RX0BF и INT.
Если ни один из этих пинов не имеет напряжения даже без сети, значит проблема с реализацией SPI интерфейса.

У модуля CAN есть множество возможностей. Советую почитать спецификацию CAN и техническое описание MCP2515.

Подключение узлов осуществляется следующим образом.

То, что указано на схеме подключения имеет выводы CANH и CANL это и должно быть подключено к сетевым линиям.

Прошу спрашивать, если что-либо непонятно или требует дополнительного рассмотрения.




пятница, 27 сентября 2013 г.

Урок 6. USB. Сторона компьютера

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

В прошлом уроке мы собирали прошивку для контроллера, чтобы он работал через USB. Но для взаимодействия с компьютером нам нужна еще и специальная программа, которая будет запускаться на компьютере.
Вот сейчас мы и будем ее создавать.
Опять же в пакете Microchip solutions есть пример, для нашего контроллера, но я переписал его по своему. Во-первых я сделал без использования графического интерфейса, и размер кода уменьшился раза в 3-4. Что намного лучше для изучения. Тем не менее, принцип работы один. код в стандартном примере от microchip работает так же как этот.
Программа написана в C++. Проект собран в бесплатной студенческой версии Visual C++ express 2010. Я буду давать общие идеи и комментарии по коду, но подразумеваю, что вы уже имеете хоть какой-то опыт программирования в C++.
Итак, начинаем

Здесь находится весь проект, включая исходный текст ссылка

Для того, чтобы читать и записывать данные через USB порт нам нужно получить указатель на наше устройство. Поскольку в отличие от старых портов, подключено может быть устройств свыше сотни, то получить этот указатель не так-то просто. Для того, чтобы это сделать мы будем обращаться к драйверам windows, а именно SetupAPI. Кстати, как только мы получим указатель, то будем общаться с USB портом, будто бы это файл.
Передача данных будет занимать лишь пару команд. Но вот подготовка!
Поскольку мы программируем в С++ то нам нужно быть очень аккуратными с типами данных.
Создаем консольный проект win32. И добавляем туда единственный файл main.cpp

Итак, нам необходимо подключить некоторые библиотеки.
#include <iostream>
#include <Windows.h>
#include <setupapi.h>

Так же подключаем внешнюю библиотеку:
#pragma comment (lib, "Setupapi.lib")

Первая описанная функция в программе - это getUSBHandle(). Ее описание - в комментариях кода. Да и вообще основные комментарии приведены в коде. Она служит для того, чтобы найти наше устройство и подготовить указатели, чтобы мы могли записывать в устройство и читать из него.
Если в двух словах, то она использует стандартные windows функции для доступа к драйверам USB и через них получает указатель на само устройство.
Если интересно, что все эти функции делают и как, то обращайтесь к MSDN или к книге Агурова, что лежит в оглавлении. Что важно знать: у каждого устройства есть путь, и нам важно получить его. Мы сначала проверяем, совпадает ли ID с устройством, что мы ищем. А потом находим путь устройства.Мы ищем только среди устройств HID класса. это определяется в переменной Guid. Остальное см в комментариях программы
Следующая функция - writeReadUSB. Это просто вспомогательная функция, которая записывает в наше устройство. Обращаю внимание, что запись и чтение устройства после того, как мы создали указатель на него реализуется с помощью стандартных комманд WriteFile и ReadFile
И после этого уже мы видим функцию main с которой и начинается выполнение программы. Она вызывает getUSBHandle, пока мы не получим указатель на устройство, потом читает с клавиатуры комманду и в зависимости от нее, передает и читает данные с USB устройства.
В проекте по ссылке выше лежит исходный код с комментариями и сама скомпилированная программа. Удачи.

В процессе поиска ошибки я наткнулся на библиотеку hidapi. Она является кроссплатформенной. И Только для работы с hid устройствами. Очень проста в использовании. Привожу проект под нее. ссылка.
Hidapi скачан с официального сайта. Для того чтобы начать проект нужно добавить setupapi.lib в линковщик. project->properties->linker->input и подписать туда setupapi.lib;
Удачи.
Нашел пристойное описание библиотеки здесь: http://microsin.net/programming/PC/multi-platform-hid-api.html.
Спасибо!

вторник, 20 августа 2013 г.

Урок 5. USB. Сторона контроллера

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

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

Все, теперь добрались мы до чего-то интересного. Протокол USB.
Наша схема будет аналогична приведенной в уроке 3 про бутлоадер. Только еще пару ножек контроллера мы будем использовать, как датчики, чтобы проверить, правда ли все у нас работает.
Нам понадобится пакет Microchip Libraries for applications ссылка Зеркало
(на данный момент актуальная версия v2013-06-15)
Качаем этот файл и устанавливаем. Для компиляции проекта нам понадобятся эти библиотеки.
Мы будем собирать пример HID - custom demos
лежит он в папке с установленной программой:
\microchip_solutions_v2013-06-15\USB\Device - HID - Custom Demos\
Внутри в папке firmware - прошивка для контроллера. В остальных - программы для компьютера.
Дело в том, что в Microchip libraries каждый проект создан для десятка разных контроллеров, и учиться на этом коде довольно проблематично. Он очень громоздкий и не последовательный.
Страница кода одна и та же, но в зависимости от того, какой проект вы откроете, для такого контроллера и будет создаваться прошивка. Изначально из наших контроллеров там присутствует только pic18f4550 и для этого нужно открыть файл проекта USB Device - HID - Simple Custom Demo - C18 - PICDEM FSUSB.mcp
Это по идее для такой учебной платы picdem fsusb. Она как раз работает на контроллере pic18f4550.
Я для удобства восприятия удалил "лишний" код, необходимый для настройки других контроллеров и чуть изменил программу, чтобы она корректно работала под pic18f2550 ссылка. Для того, чтобы программа работала, архив нужно распаковать в
\microchip_solutions_v2013-06-15\USB\Device - HID - Custom Demos\любойкаталог
, поскольку пути к библиотекам прописаны относительно к текущему каталогу.
Не дурно бы было почитать документацию к USB библиотеке. Но почему-то microchip уже давно не выпускает новый нормальный user guide. Придется воспользоваться старым. Тем не менее он даст нам идею, как работает библиотека.
лежит он по адресу ссылка  зеркало
Этот файл за 2007 год! Так что уже многие функции библиотеки даже называются по-другому.
Примерно философия работы следующая:
Контроллер наш, поскольку имеет аппаратную поддержку протокола USB имеет в своей памяти определенные места, в которые нужно записать настройки usb. это первый главный момент. В основном все это находится в файле usb_descriptors.c. Вы можете открыть этот файл и посмотреть комментарии или даже отредактировать.
Потом, важно грамотно настроить биты конфигурации. И в теле программы мы будем вызывать функцию USBDeviceTasks(), которая выполняет в общем-то всю работу по обмену информации через USB.
Плюс, нужно определить некоторые стандартные функции, которые вызываются при получении нашим устройством различных команд, в момент подключения к хосту например. без них, устройство так и не сможет обнаружиться. Эти команды находятся в самом низу файла main.c и особенно здесь не рассматриваются, так как они осуществляют рутинную стандартную работу и вы будете вряд ли их менять.
На данный момент библиотека работает следующим образом:

Функция USBDeviceTasks()

Для того, чтобы поддерживать работу USB, когда хост обращается к устройству с сообщением, в течение определенного времени устройство должно дать ответ. В случае, если это не происходит, хост может просто отключить наше устройство, посчитав его сломанным.
Чтобы обработать usb сообщение и выслать ответ, нужно вызвать функцию этой библиотеки:
USBDeviceTasks(); ну и чтобы отправилось правильное сообщение надо подготовить буферы вывода и прочее.
В нашем примере мы просто циклически будем вызывать эту функцию. Есть и другой выбор: для того, чтобы вовремя давать ответ хосту, можно использовать прерывания, но я опишу это потом, если будет время.
Если мы просто периодически вызываем функцию USBDeviceTasks(), то обычно ее надо вызывать не реже, чем 1.8мс. Иногда бывают исключения из этого правила. Смотри комментарии usb_device.c для тог, чтобы узнать, что это за исключения.
Обычно вызвать USBDeviceTask() не требует много времени. Около 100 тактов процессора.

USB дескрипторы

Для корректной работы нашего устройства нужно будет задать USB дескрипторы. В общем-то это описание нашего устройства. Они содерждат класс устройства, в нашем случае это - HID (Human Interface Device, которым могут быть мышки, клавиатуры, или вообще любое устройство) и имя устройства. Все эти параметры заданы в файле usb_descriptors.c, который уже добавлен в проект. Перед началом работы хост с устройством обмениваются дескрипторами, это дает понять, каким образом будет осуществляться взаимодействие устройств.

Hardware profile

Файл hardware profile содержит информацию о том, какой контроллер или плату мы используем. Плюсо к нему microchip обычно добавляет файл конкретного контроллера. Например HardwareProfile - PICDEM FSUSB.h. В этом файле хранятся различные функции и адреса, связанные с аппаратной частью контроллера. Например, функция инициализации АЦП. В ней непосредственно указано, какое значение должно быть присвоено регистрам АЦП и на какую ножку будет подаваться напряжение.

Комментарии к программе

Все основные комментарии приведены мной в коде в файле main.c. Здесь лишь пара слов.
Когда мы открываем проект, перед нами будет следующий набор файлов:
lkr файл - файл линковщика. Он говорит о том, как и которую память можно использовать.
Плюс некоторые настройки usb протокола задаются в файле usb_config.h
На мой взгляд это дерево файлов и логика - далеко не идеальные, но это то, что предлагает microchip.
Далее логика работы программы сохранена, чтобы разобравшись с этой программой вам было легче понять другой похожий пример от microchip.
Основные функции программы:
void YourHighPriorityISRCode() - прерывание высокого уровня
void YourLowPriorityISRCode() - прерывание низкого уровня
void main(void) - главная функция
static void InitializeSystem(void) - инициализация контроллера (задание настроек)
void UserInit(void) - то же самое
void ProcessIO(void) - тело программы, где происходит вся обработка и расчеты
WORD_VAL ReadPOT(void) - функция вызова Аналого Цифрового Преобразователя
Далее будем рассматривать файл main.c, в котором находится наш исполняемый код. это сделано в самом файле в комментариях. 

проект для контроллеров pic18f4550 и pic18f2550 ссылка
Здесь для поддержки USB интерфейса используются прерывания.
Так же выкладываю проект, где еще больше кода удалено, чтобы дать идею, как программа работает. Здесь прерывания не используются, а просто периодически вызывается функция поддержки usb интерфейса.
Уменьшенный вариант: ссылка
Проект обязательно нужно распаковать в папку 
\microchip_solutions_v2013-06-15\USB\Device - HID - Custom Demos\любойкаталог
потому что там довольно жестко задаются пути к библиотекам
Этот проект работает с обоими контроллерами (только что проверил) с бутлоадером и без него.
Для того, чтобы проверить, работает ли наш пример, запускаем утилитку 
\microchip_solutions_v2013-06-15\USB\Device - HID - Custom Demos\HID PnP Demo.exe
она должна найти ваш контроллер.
В следующем уроке мы будем рассматривать как раз эту программу для компьютера, которая пересылает информацию контроллеру. То есть USB интерфейс на стороне компьютера.

среда, 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