реклама на сайте
подробности

 
 
> Управление мегой от ПК (через SPI)
zi4rox
сообщение Apr 6 2009, 16:38
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 50
Регистрация: 4-04-08
Пользователь №: 36 480



Как управлять ATMega с компьютера, средствами SPI ?

Необходимо твердо в этом вопросе разобраться и для себя уяснить что и как. Поэтому поставил себе следующие условия простой задачи:

Мега, получает с ПК управляющий код (байт), анализирует его и выполняет какое то определенное действие (пускай будет моргать светодиодами на порту). Используется SPI, мега получается в режиме salve.

Схема к данной задачи:


После моих проб, ошибок и советов добрых людей получилось 2 реализации:
* Программирую в CodeVisionAVR

1. С использованием примера из даташита atmega16 (стр. 132)

Код
#include <mega16.h>

#define DDR_SPI DDRB
#define DD_MISO PORTB.6


// Управляющие коды, которые могут быть переданы
#define CMD1 0x01
#define CMD2 0x02
#define CMD3 0x03
#define CMD4 0x04

void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDR_SPI = (1 << DD_MISO);
/* Enable SPI */
SPCR = (1 << SPE);
}

unsigned char SPI_SlaveReceive(void)
{
/* Wait for reception complete */
while(!(SPSR & (1 << SPIF)))
;
/* Return data register */
return SPDR;
}

void main (void){
SPI_SlaveInit();
DDRA = 0xFF; // сделали порт A выходом


while (1){

// анализируем полученный ответ
switch(SPI_SlaveReceive())
{
case CMD1:
PORTA = 0x01;
break;
case CMD2:
PORTA = 0x01;
break;
case CMD3:
PORTA = 0x03;
break;
case CMD4:
PORTA = 0x04;
break;
default:
PORTA = 0xFF;
break;
}

};
}


2. С использованием стандартных функций в spi.h (а также codewizard'а в cvavr):

Код
#include <mega16.h>
#include <spi.h>


// Управляющие коды, которые могут быть переданы
#define CMD1 0x01
#define CMD2 0x02
#define CMD3 0x03
#define CMD4 0x04

unsigned char read;

void main (void){

// инициализируем порты
PORTB=0x00;
DDRB=0x40; //тут SPI порт
PORTF=0x00;
DDRF=0xFF;

// инициализируем SPI
SPCR=0x40;
SPSR=0x00;

while (1){

read = spi(0x00);
/* [b]вот здесь мне непонятно что писать в качестве аргумента spi()? [без аргумента выдает ошибку]. [/b]*/

switch(read)
{
    case CMD1:
        PORTA = 0x01;
        break;
    case CMD2:
        PORTA = 0x02;
        break;
    case CMD3:
        PORTA = 0x03;
        break;
    case CMD4:
        PORTA = 0x04;
        break;
    default:
        PORTA = 0xFF;
        break;
}
         };
}


Проблема в том, что оба этих варианта не работают, и цели поставленной задачи достичь не удалось :cry:

Прошу помочь, натолкнуть в сторону где можно найти ошибку.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SasaVitebsk
сообщение Apr 19 2009, 16:54
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Дело в том, что mega работает в режиме slaveSPI. В этом режиме должна использоваться нога SS. Это надо не забывать. По ней осуществляется синхронизация. Опыт показывает, что достаточно синхронизировать пакет, а не каждый байт. Тем не менее...

У меня, как я и писал, связь осуществляется посредством ByteBlaster-а. Того же, который используется при программировании в AvReal. Я им пользуюсь, как и многие (спасибо Real-у). В данном адаптере не используется нога SS. В связи с этим ей надо управлять каким то другим макаром. У меня к этой ноге есть доступ непосредственно у самой меги. Чем я и пользуюсь. В противном случае надо реализовать хотя бы заземление её.

У меня SPI используется несколько не стандартно. Я его использую полудуплексно. То есть посылаю пакет меге, а потом получаю пакет ответа. В связи с некоторыми особенностями схемы, а также благодаря моей программной ошибке у меня иногда происходила рассинхронизация между пакетами. Я ввёл дополнительную синхронизацию, дабы обеспечить устойчивую работу. В последствии, когда ошибка была устранена, я не стал убирать синхронизацию, так как убедился в её эффективности. Сейчас стабильность 100% за счёт контроля и повторов.

Разрабатывалась в связи с тем, что требовалось задействовать в изделии ногу RESET. После соответственного прошивания фуза, ISP программирование перестаёт функционировать. Для того, чтобы можно было изделие перешивать, и был написан данный бутлоадер.

Это было краткое описание. Теперь сами процедуры.

На AVR.
Код
// Сбросить SPI
void ClrSPI(void)
{
  PORTB = 0xff;                                            // Передёрнуть SS
  PORTB = 0xfc;                                            // Обнулить
  SPSR;                                                    // сбросить флаги
  SPDR;        
}

Используется после каждого исполнения команды. То есть после цикла приём-передача. У вас может и не быть. Но должен быть SS на земле.
Код
// Ждать прихода символа по SPI
void WaitSPSR(void)
{
  while(!(SPSR & (1<<SPIF)))                             // ждать освобождения буфера
  {
     __watchdog_reset();                                // сбросить собаку
     if((_TIFR1 &(1<<TOV1))!=0)                            // Если пришло время моргнуть
     {
       _TIFR1 = 1<<TOV1;                                // перезарядить таймер
       BLINK;                                            // и моргнуть
     }
  }
}

То что вам не надо - типа моргания светодиодом - можете выкинуть. Просто беру "как есть", чтобы исключить ошибки.
Код
// Вывод символа на SPI
void TxByte(uint8_t    outbyte)                            // передача
{
  SPDR = outbyte;                                        // вывести
  WaitSPSR();                                              // ждать Завершения операции
  SPDR;
}


Ввод делаю прямо в тексте проги типа так...
Код
....
      SPDR=1;                                            // Для синхронизации
      WaitSPSR();                                          // ждать прихода символа
      c=SPDR;                                            // Читаем символ
....

Обратите внимание на "1".
Для самого приёма, естественно, без разницы что туда передаётся. А вот на IBM, я по этой "1" ловлю синхронизацию.


Теперь IBM.
Я использовал Delfi7 и SmallPort. Сам SmallPort я уже где-то выкладывал, но если надо, то прикреплю. Работает очень устойчиво и весит мало. Идёт под XP и 98/Me. Под другими просто не проверял. В вызовах вы легко разберётесь и просто переделаете под себя.
Проект был очень малобюджетный, поэтому я не изголялся. У заказчика тоже должен быть стимул. Чтобы получить качественный продукт - необходимо нормально его оплатить.

Код
Procedure WaitMks;
var
  i  : integer;
  a  : integer;
begin
  for i:=0 to FTime do
    a:=a+Form1.SmallPort.Port[$378];
end;

function TxRx(data:byte):byte;
var
  i     : integer;
  a,b   : byte;
begin
b:=0;
for i:=0 to 7 do begin
   b := b shl 1;                                // следующий бит
   a := (data shr 1) and $40;                   // текущий бит
   Form1.SmallPort.Port[$378]:= a;              // выдать в MOSI
   WaitMks;
   Form1.SmallPort.Port[$378]:= a or 1;         // стробировать (SCK=1)
   WaitMks;
   if((Form1.SmallPort.Port[$379] and $80)=0)
   then b := b or  1;                           // принять новый бит
   WaitMks;
   Form1.SmallPort.Port[$378]:= a;              // стробировать (SCK=0)
   data := data shl 1;                          // следующий бит
end;
result := b;
end;


Покажу ещё две процедуры - приём/передача пакета. Разобрав их поймёте как осуществлялась синхронизация.
Код
procedure WriteMes;
var
    i    : integer;
    a,
    data : byte;
begin
  for i:=0 to 31 do begin
    data := TxRx(SPACE);
    if data = 1 then break;
    a := SPACE and $40;                                 // текущий бит
    Form1.SmallPort.Port[$378]:= a;                     // выдать в MOSI
    WaitMks;
    Form1.SmallPort.Port[$378]:= a or 1;                // стробировать (SCK=1)
    WaitMks;
    Form1.SmallPort.Port[$378]:= a;                     // стробировать (SCK=0)
  end;
  Mes.crc8 := Mes.Address;                              // инициализировать CRC
  TxRx(FEND);                                           // Передаём символ FEND
  Mes.crc8 := calcCRC(Mes.crc8,FEND);                    // Подсчитать CRC8
  TxRx(Mes.Address or $80);                             // Передаём ADRWAKE
  Mes.crc8 := calcCRC(Mes.crc8,Mes.Address);            // Подсчитать CRC8
  TxRx(Mes.Command);                                    // Передаём команду
  Mes.crc8 := calcCRC(Mes.crc8,Mes.Command);            // Подсчитать CRC8
  OutByteWake(Mes.DataSize);                            // Передаём длину
  for i:=0 to Mes.DataSize-1 do
        OutByteWake(Mes.Data[i]);                       // Передаём данные
  OutByteWake(Mes.crc8);                                // Передаём CRC
end;

procedure ReadMes;
label mend;
var
    i   : integer;
    d,a : byte;
    err : boolean;
    nerr: integer;
begin
  Mes.Err := 0;                                         // Пока нет ошибок
  Mes.crc8 := Mes.Address;                              // инициализировать CRC
  nerr := 0;
  d:=0;
  repeat
    d := d shl 1;                                       // следующий бит
    a := SPACE and $40;                                 // текущий бит
    Form1.SmallPort.Port[$378]:= a;                     // выдать в MOSI
    WaitMks;
    Form1.SmallPort.Port[$378]:= a or 1;                // стробировать (SCK=1)
    WaitMks;
    if((Form1.SmallPort.Port[$379] and $80)=0)
    then d := d or  1;                                  // принять новый бит
    Form1.SmallPort.Port[$378]:= a;                     // стробировать (SCK=0)
    WaitMks;
    nerr := nerr+1;
    if(nerr>800)then begin
       Mes.Err := 11;                                    // Нет ответа
       goto mend;
    end;
  until(d=FEND);                                        // Ждём начала пакета
  Mes.crc8 := calcCRC(Mes.crc8,FEND);                    // Подсчитать CRC8
  d := TxRx(SPACE) and $7f;                             // Читаем адрес
  Mes.crc8 := calcCRC(Mes.crc8,d);                      // Подсчитать CRC8
  if(d<>Mes.Address)then begin
    Mes.Err := 6;                                       // Ошибка адреса
    goto mend;
  end;
  d := TxRx(SPACE);                                     // Читаем команду
  Mes.crc8 := calcCRC(Mes.crc8,d);                      // Подсчитать CRC8
  if((d and $80)<>0)then begin
    Mes.Err := 10;                                      // Ошибка команды
    goto mend;
  end;
  Mes.Command := d;
  d := GetByteWake;                                     // Читаем длину
  Mes.DataSize := d;
  for i:=0 to Mes.DataSize-1 do
        Mes.Data[i] := GetByteWake;                     // Читаем данные
  d := GetByteWake;                                     // Читаем CRC
  if(Mes.crc8<>0)then begin
    Mes.Err := 9;                                       // Ошибка CRC
  end;
  mend:
end;


В завершение прошу здесь опустить разбор моего стиля программирования. Я не выкладываю эти тексты, как образец стилистики. Цель - помочь. Пусть пользуется тот, кому это нужно. Писалось на скорую руку за 2 ночи (переделывалось), поэтому прошу извинение за стилистику написания.

PS: Совсем забыл. Прошу отметить что у меня откинута нога RESET. В противном случае надо соответствующий бит в процедурах установить в "1".
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- zi4rox   Управление мегой от ПК (через SPI)   Apr 6 2009, 16:38
- - SysRq   (стёр, ибо поиском наешл сообщения автора и посмот...   Apr 6 2009, 17:54
- - zi4rox   С компа, самописной программкой. В ней не сомневаю...   Apr 6 2009, 18:00
|- - SysRq   Цитата(zi4rox @ Apr 6 2009, 22:00) В ней ...   Apr 6 2009, 18:37
|- - Genadi Zawidowski   Цитата(SysRq @ Apr 6 2009, 22:37) Если AV...   Apr 7 2009, 18:09
|- - SysRq   Цитата(Genadi Zawidowski @ Apr 7 2009, 22...   Apr 7 2009, 18:38
- - andrikk   последовательно сигналам - резисторы Ом по 100, дл...   Apr 6 2009, 19:34
- - =GM=   Цитата(zi4rox @ Apr 6 2009, 15:38) Пробле...   Apr 7 2009, 16:12
|- - zi4rox   Цитата(=GM= @ Apr 7 2009, 20:12) попробуй...   Apr 19 2009, 08:08
- - SasaVitebsk   Только что сделал бут ч/з SPI на базе ByteBlaster....   Apr 19 2009, 14:25
- - zi4rox   Отписал Вам в личное сообщение, но не уверен, что ...   Apr 19 2009, 15:20
- - sigmaN   Я, конечно, мегу никогда не кодил, но как-то стран...   Apr 19 2009, 16:59
- - zi4rox   2SasaVitebsk Спасибо, за столь развернутый пост. ...   Apr 19 2009, 17:08
- - andrikk   инициализация Кодvoid spi_init(void) { v...   Apr 20 2009, 11:54
- - zi4rox   Всё вроде делаю правильно, а нужного результата не...   Apr 20 2009, 14:39
- - SasaVitebsk   Тем не менее у вас всё абсолютно правильно. Инициа...   Apr 20 2009, 16:30
- - zi4rox   Да, я SS посадил на землю - без этого даже кривая ...   Apr 20 2009, 17:12
- - SasaVitebsk   Блин просмотрел. У вас ошибка в голове. Надо так ...   Apr 20 2009, 17:55
|- - zi4rox   Цитата(SasaVitebsk @ Apr 20 2009, 21:55) ...   Apr 20 2009, 18:32
- - SysRq   Питается от чего оно у вас? Фильтры по питанию сто...   Apr 20 2009, 17:57
- - andrikk   попробуйте использовать 4094 (8–STAGE SHIFT-AND-ST...   Apr 20 2009, 19:03
- - SasaVitebsk   Да не может быть никаких затыков. Это не медицина....   Apr 20 2009, 19:31


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th July 2025 - 09:07
Рейтинг@Mail.ru


Страница сгенерированна за 0.01449 секунд с 7
ELECTRONIX ©2004-2016