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          
  
  
      
Проект эмуляции