USB программатор для AVR и интерфейс обмена данными с ПК в одном флаконе
Речь пойдет о том как получить USB программатор для AVR и интерфейс обмена данными с ПК в одном флаконе
Что понадобится из железа:
- Микросхема серии FT2232 - http://www.ftdichip.com/Products/FT2232C.htm
- Микроконтроллер AVR с SPI интерфейсом - http://atmel.ru/Production/tables/avr.htm
Схему можно собрать согласно автору AVReal (см. рисунок) - http://real.kiev.ua/old/avreal/ru/adapters.html
Что понадобится из ПО:
- Программу AVReal - http://real.kiev.ua/avreal
- Драйвер FTD2XX - http://ftdichip.com/Drivers/D2XX.htm
- И компилятор С++.
Проверить что устройство собрано и работает правильно можно выполнив следующую команду с использованием AVReal:
avreal32.exe +mega324p -pd="DLP2232M A",s="FTPOH771A" -aft2232:reset=adbus3:enable=adbus4 -r test.hex >test.txt
Пример приведен для FT2232D в связке с Atmega324p. Подробности по командам программирования здесь: http://real.kiev.ua/old/avreal/ru/description.html
Код под микроконтроллер может быть следующим (что бы далеко за примером не ходить - взял из 3DO DiagBlastera под Atmega324p):
#include <avr/io.h> #include <avr/interrupt.h> typedef unsigned char uint8; //входной и выходной кольцевые буферы volatile uint8 dbi_ring[256]; volatile uint8 dbo_ring[256]; volatile uint8 dbo_down, dbo_up, dbi_down, dbi_up; void SPI_SlaveInit(void) { /* Set MISO output, all others input */ DDRB = (1<<PB6); /* Разрешаем работу SPI и прерывание по окнчанию передачи байта */ SPCR = (1<<SPE)|(1<<DORD)|(1<<SPIE);//|(1<<SPR0); // режим 0, LSB - см. Atmega324p Datasheet С. 168 SPDR=0; //обнуляем регистр данных } ISR(SPI_STC_vect) //прерывание по получению байта { uint8 tmp=SPDR; //читаем данные //отправляем данние если есть, если нет - можно просто отправить любое значени //в данном примере подразумевается текстовый протокол, поэтому ноль используется как незначащий символ if( dbo_down==dbo_up ) //исходящий буфер пуст SPDR=0; else //есть что отправить SPDR=dbo_ring[dbo_down++]; if(!tmp)return; //ничего не получили - выход dbi_ring[dbi_up++]=tmp; //получили - запись в кольцевой буфер для обработки в главной процедуре } void Debug_Init() { dbo_down=dbo_up=0; //обнулим выходной кольцевой буфер dbi_down=dbi_up=0; //обнулим входной кольцевой буфер SPI_SlaveInit(); //инициализация ведомого SPI интерфейса } int main() // пример главной процедуры { Debug_Init(); //инициализация SPI интерфейса DDRA = 0xff; // на порт А можно повесить светодиоды для проверки PORTA = 0; sei(); //разрешаем прерывания while(1) //бесконечный цикл { //если пришли данные выведем их на порт А if(dbi_down!=dbi_up) PORTA = dbi_ring[dbi_down++]; } return 0; }
Для компиляции примера необходимо использовать AVR Studio и WinAVR.
Код со стороны ПК привожу в виде простейшего и потому надеюсь понятного примера:
#include <windows.h> #include "FTD2XX.h" #pragma comment(lib, "FTD2XX.lib") //Класс для работы с AVR через FT2232 в режиме 0, LSB - см. Atmega164p datasheet С. 168 class SPIDeb { private: FT_HANDLE ftHandle; //хендл устройства - надо отметить, что тип FTDI устройства в данном примере не проверяется, но это не сложно добавить ) FT_STATUS ftStatus; //переменная для статуса исполнения команд bool opened; //признак что устройство открыто public: SPIDeb(){opened=false;}; //конструктор ~SPIDeb(){Close();}; //деструктор bool Init(unsigned int divval); //подключение устройства, divval - делитель для получения частоты = 12М/((divval+1)*2) int Send(const unsigned char *buff, int size); //отправка буфера по SPI int Read(unsigned char *buff, int size); //чтение принятых от устройства данных void Close(); //отключение устройства }; bool SPIDeb::Init(unsigned int divval) { DWORD sended=0; //переменная в которую пишется число отправленных байт char sendbuff[]={0x86,0x2,0x00}; sendbuff[1]=divval&0xff; //запишем в команду установки делителя частоты переданное значение sendbuff[2]=divval>>8; //с помощью данной команды можно регулировать частоту SPI обмена if(opened)return true; ftStatus = FT_Open(0,&ftHandle); //открываем первое попавшееся устройство if (ftStatus != FT_OK) return false; //если ничего не открылось - информируем об ошибке UCHAR Mask = 0x13; // здесь указывается направление сигнала (1 - выход, 0 - вход) //соответствие сигналам FT2232: bit0(AD0)...bit7(AD7) - относительно контроллера будет: SCK,MOSI,MISO,RESET,CS..... UCHAR Mode = 2; // режим MPSSE см. док. FT_000109 ftStatus = FT_SetBitMode(ftHandle,Mask,Mode); //установка режима FT_Write (ftHandle, (void*)sendbuff, 3, &sended); //отправим устройству команду установки частоты opened=true; if (ftStatus == FT_OK) return opened; //если режим MPSSE открытым устройством не поддерживается - сворачиваем деятельность Close(); return false; } int SPIDeb::Send(const unsigned char *buff, int size) { DWORD sended=0; //переменная в которую пишется число отправленных байт unsigned char *sbf; //буфер для отправки данных if(!opened)return 0; sbf=new unsigned char[size*12]; //выделяем память под поток команд для устройства //поскольку контроллеру нужно время на обработку принятого байта и извлечение из исходящего буфера данных для отправки //использовались четыре команды на каждый обмен байтами с устройством for(int i=0;i<size;i++) //формирование массива команд для FT2232 см. док. FT_000109 с сайта производителя { sbf[i*12]=0x80; //выбор SPI устройства - установка CS в низкий уровень sbf[i*12+1]=0x02; sbf[i*12+2]=0x13; sbf[i*12+3]=0x3f; //посылка байта в контроллер с одновременным чтением, полученный байт затем можно считать функцией Read sbf[i*12+4]=0x07; sbf[i*12+5]=buff[i]; sbf[i*12+6]=0x80; //отключение SPI устройства - CS в высокий уровень sbf[i*12+7]=0x12; sbf[i*12+8]=0x13; sbf[i*12+9]=0x1b; //фиктивная запись в устройство - для задержки - что бы контроллер успел приготовиться к следующему обмену sbf[i*12+10]=0x07; sbf[i*12+11]=buff[i]; } FT_Write (ftHandle, (void*)sbf, 12*size, &sended); //запись блока команд в устройство delete []sbf; //чистим память - конечно лучше выделить фиксированный буфер, но на скорую руку и так сойдет return sended/12; //вернем число переданных байт } int SPIDeb::Read(unsigned char *buff, int size) { DWORD inquery=0,readed=0; if(!opened)return 0; FT_GetQueueStatus(ftHandle,&inquery); //проверка - есть ли данные в очереди? if(inquery>size)inquery=size; //если данных больше чем размер буфера - примем столько сколько сможем if(!inquery)return 0; //нет данных - на выход FT_Read(ftHandle,buff,inquery,&readed); //чтение return readed; //возврат количества полученных байт } void SPIDeb::Close() { if(!opened)return; FT_SetBitMode(ftHandle,0,0); //сбрасываем устройство FT_Close(&ftHandle); //отключаем драйвер }
вт, 15/07/2014 - 10:29