Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Обсуждаем контроллеры компании Atmel.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

Так стоп, я соврал, я ошибся и мне показалось что светодиодик с ножки PCINT4 - горит, но это не так.
Получается функция if (reqID >= (sizeof(master_arr) / sizeof(master_arr[0]))) по прежнему не работает.

Добавлено after 46 seconds:
veso74, это я уже заметил и исправил, результат тот же.
Реклама
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение veso74 »

Повторю вопрос: компилятор и IDE какой?
(Проверял на два прежде чем привел пример здесь).
Реклама
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

veso74, CodeVisionAvr версии 2.05.0, а компилятор gcc по идее, не нашел в кодевижне, где это написано.
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение veso74 »

не знаю логики построения, но

Код: Выделить всё

fG = (master_arr[1] << 8)|(master_arr[2] << 16)|(master_arr[3] << 24); //generator freqency
случайно не

Код: Выделить всё

fG = (master_arr[1])|(master_arr[2] << 8)|(master_arr[3] << 16); //generator freqency
? Что первые 8 бит "пустые" мне кажутся странными.
Реклама
Эиком - электронные компоненты и радиодетали
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

veso74, fg - 4-х байтная переменная, но подставляем в нее только 3 последних значения master_arr[]. 0 значение массива мы подставляем в переменную nG.
Реклама
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение veso74 »

А что у младших 8 бита fg?
Если они нулевые, установите их явно.
А так сначала нет неустановленного значения fg, затем дополняете 3 по 8 бит ...
Реклама
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

veso74, fG = 0|(master_arr[1] << 8)|(master_arr[2] << 16)|(master_arr[3] << 24); //generator freqency. Так?
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение veso74 »

грубо: да (а может быть, и еше "красивее" :) ). Ничего, так и быть.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

Осталось теперь разобраться почему это не работает: if (reqID >= (sizeof(master_arr) / sizeof(master_arr[0]))).

Добавлено after 1 hour 6 minutes 58 seconds:
Поковырявшись в протеусе увидел, что все это время он ругался: Data is overrun - received data is lost. Это значит, что слейв не успевает записывать данные за мастером. Снизил частоту SCK, проблема осталась, но в SPI анализаторе - увидел, что стал записываться 2 байт массива master_arr, хоть и неверно. Значит нужно как-то синхронизировать 2 контроллера.
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение a797945 »

"Это значит, что слейв не успевает записывать данные за мастером..."
НЕТ. это означает, что у вас нет намерения забирать данные вовремя.
но с этим вам пока рано.

расскажите, лучше, это означает:
volatile unsigned long int master_arr [4];

а теперь, что означает вот это:
master_arr[0] = SPDR;
а какой разрядности SPDR? напишите что будет в master_arr[0], если SPDR=01, только напишите все разряды.

пишете:
UpdateTim1A(fG);
SetUpTim1A(fG);
а ничего, что второе уже есть в первом? и такой вызов лишает смысла UpdateTim1A(fG)

а ничего, что вы умножаете частоту в 2^8 раз :
fG = (master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24);
т.е. делая из нее просто мусор.

предлагал ведь решать задачу по-этапно, но не - все в кучу, ошибка наслаивается на ошибку, а воз и ныне там.
я понимаю "лень - двигатель процесса", но иногда лень - это тот рог которым, упрутся в пень и ни с места.

пишите слейв с нуля, не копипастом, ручками; пытайтесь понимать зачем оно так, а не иначе.
в слейве сделайте прием 4-х байт, потом отсылку этих байт назад. и все никаких таймеров.
в мастере сделайте отсылку 4-х байт, следом байта "пустышку", и прием 4-х байт от слейва, дальше пауза и снова. когда получится - поймете зачем пустышка, без нее можно, но щас пока так.
не будете пытаться понять, что пишите - вы безнадежны, так что включайте голову. удачи.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

a797945, volatile unsigned long int master_arr [4] - это массив для хранения принятых байт.
master_arr[0] = SPDR - я присваиваю 0 элементу массива значение, хранящееся в 8-битном регистре данных.
а ничего, что второе уже есть в первом? и такой вызов лишает смысла UpdateTim1A(fG) - что значит второе уже есть в первом ? Функция UpdateTim1A(fG) нужна для хранения значения fG, для того чтобы высчитывать ее только при изменении входных значений.
fG = (master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24) - в этой строке побитовым сдвигом подставляются элементы массива, это сделано так, потому что полученные данные по SPI - 3 байтовые, а в стандарте си нет 3-х байтовых типов данных. Поэтому я подставляю в 4-х байтовый unsigned long int побитовым сдвигом эти 3 байта.
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение a797945 »

увы, вы не поняли ни одного моего слова. пробую последнюю попытку:

1.напишите ПОБИТНО содержание ячейки master_arr[0] (с любым значением, но все разряды)

2.напишите значение fg, если master_arr[1]=01 master_arr[2]=02 master_arr[3]=03, при такой сборке:
fG = (master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24)
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

a797945, 1. 00000000
2. У меня другое равенство fG = 0|(master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24)
00 01 02 03- значение fG
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение a797945 »

1. нет, например 3 будет:
00000000000000000000000000000011
long int - однако.

2. нет, будет
0x03020100
младший байт = 0

(master_arr[1] << 8 ) - взять из ячейки [1] 4 байта (там ведь у вас long int), сдвинуть их содержимое влево (на увеличение), ....
понимаете?
первый байт вы уже проскачили - ничего туда не положили, там остались 00

так я и говорю - не торопитесь, пытайтесь осмысливать.
Последний раз редактировалось a797945 Чт июл 06, 2023 20:10:15, всего редактировалось 2 раза.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

a797945, да вы правы, глупая ошибка.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

Подправил код, добавил в прерывание проверку 1-го входящего байта, добавил еще 1 счётчик flagRT, чтобы попытаться соблюсти в точности последовательность входящих байт, изменил формулу расчёта fG, но все равно слейв считывает мусор. Вот измененный код:
Спойлер

Код: Выделить всё

#include <mega8.h>
#include <math.h>
#include <io.h>
#include <delay.h>

#define  F_CPU (8000000)
#define  VFG_TIMER_MAX (65535)
#define  VFG_DDR DDRD
#define  VFG_PORT PORTD

volatile unsigned long int fG;
volatile unsigned char nG;
unsigned int N[]={1,8,64,256,1024};
//BYTE STORAGE
volatile unsigned char master_arr [4];
//BYTE COUNTER
volatile int reqID = 0;
volatile int flagRT = 0;

void setup (void)
{
#asm("cli")
DDRB |= (1 << PORTB4);                            //configure MISO as output
SPCR |= (1 << SPIE) | (1 << SPE) | (0 << MSTR);   //configure slave mod and interrupt
#asm("sei")
}

interrupt [SPI_STC] void spi_isr(void)      
{
switch(reqID) {
   case 0:
        if (SPDR == 0b00000001 || SPDR == 0b00000010 || SPDR == 0b00000011) {
        master_arr[0] = SPDR;
        SPDR = master_arr [0];
        PORTC |= (1<<0);
        reqID++;
        flagRT++;
        break;
        }
   case 1: 
        if (flagRT = 1) {
        master_arr[1] = SPDR;
        SPDR = master_arr [1];
        PORTC |= (1<<1);
        reqID++;
        flagRT++;
        break;
        }
   case 2:
        if (flagRT = 2) {
        master_arr[2] = SPDR;
        SPDR = master_arr [2];
        PORTC |= (1<<2);
        reqID++;
        break;
        }
   case 3:
        if (flagRT = 3) {
        master_arr[3] = SPDR;
        SPDR = master_arr [3];
        PORTC |= (1<<3);
        reqID++;
        flagRT = 0;
        break;
        }
    }
}
//***********************************************timer1************************************************

void main(void)
{
VFG_DDR = 0b00000111;
DDRC = 0b11111111;
setup();
#asm("sei")
for(;;) {
    
        PORTC &= ~(1<<0);
        PORTC &= ~(1<<1);
        PORTC &= ~(1<<2);
        PORTC &= ~(1<<3);
   if (reqID >= (sizeof(master_arr) / sizeof(master_arr[0])))
   {
        if (flagRT == 1) {nG = master_arr[0];} //generator number
        fG = 0|(master_arr[1] >> 8)|(master_arr[2] >> 16)|(master_arr[3] >> 24); //generator freqency 
        delay_ms(1);
        PORTC &= ~(1<<4);
        reqID= 0;            
    }         
}
}
Добавлено after 21 minute 4 seconds:
Причем мусор пишет всегда в 0 байт, остальные иногда проскакивают и совпадают с реальными значениями.
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение veso74 »

Мне кажется, что с побитовыми операциями у вас пробел :). (Надеюсь, я ошибаюсь).
Бумага и карандаш в помощь!

Это невозможно (и неправильно):

Код: Выделить всё

volatile unsigned char master_arr [4];
...
... (master_arr[2] >> 16)|(master_arr[3] >> 24);
привожу пример:
master_arr[3] = 123 (случайное значение) = 0x7B = 0b01111011. Переместите 24 раза вправо и посмотрите, что произойдет?
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение a797945 »

в помощь вам. давайте порасуждаем
сочиняем прошивку для слейва, подошли к разрешению прерываний, стоп, а какие нас тут ждут грабли
г1 флаг уже взведен,
г2 а мы не знаем, что сейчас делает мастер.
мусор же мы принимать не хотим, вместо 1-го байта принять 3-й - то же не хотим.
нужна подсказка от мастера. да, смотрим на линию SS. соответственно требования к мастеру:
1 чтоб случалась 1 на линии SS
2 чтоб была относительно продолжительной, 1 пикосек. 1 наносек - не годятся.
т.е. мастер должен опускать линию на все время передачи пачки, а подняв SS идти поделать какие делишки или потупить на задержке, перед тем как начинать следующий пакет.
да, SPI достаточно быстрый интерфейс, потому, пока, замедлим тактирование. кстати, не плохо бы знать время между байтами.

на слейве перед тем как принимать пакет (разрешить прерывание) ставим в ожидание 0 на SS, дождались обнуляем SR идем ждать счетчик байт перед отключением прерываний.

я бы не использовал прерывания на каждый байт, и массив master_arr, ну да ладно, пока так.

П.С. вам нравится писать случайные символы? зачем сдвиг вправо? (master_arr[2] >> 16)
писал же вам veso74 :
"...
Код:
fG = (master_arr[1])|(master_arr[2] << 8)|(master_arr[3] << 16); //generator freqency
..."

и в обработчике прерываний нужно как можно меньше действий.
warptred12
Открыл глаза
Сообщения: 76
Зарегистрирован: Чт июн 01, 2023 11:30:34

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение warptred12 »

Изменил код, теперь время получения посылки и отправки ее обратно мастеру - совпадают. Но почему-то нулевой байт посылки, отправляемой обратно мастеру всегда неверен. Например, мастер отправляет посылку: 02 89 41 00, а вот слейв отправляет обратно мастеру: 00 02 89 41 - это значит, что прочитанное значение сдвинуто вправо на 8 бит. Так же первая посылка, отправляемая мастером 00 00 00 00, а вот слейв читает ее как 80 00 00 00. Скриншот прикреплю ниже.

Код мастера:
Спойлер

Код: Выделить всё

#include <mega128.h>
#include <io.h>
#include <delay.h>

volatile unsigned char	reqTr,reqTm;

struct Tmr_t {
    unsigned char n;           
    double  F;
};

struct Tmr_t	T;       

unsigned char chrT;

typedef union //объединение
{
  unsigned long int w   ;     // w as WORD
  unsigned int h[2];     // h as HALF-WORD
  unsigned char  b[4];     // b as BYTE
} Union32;

Union32 dFi;

void SPI_MasterTransmit(unsigned char cData);

void IOInit(void) {

  PORTA = 0b00000000;
  DDRA  = 0b11111111;

  PORTB = 0b00001001;
  DDRB  = 0b11110111;

  PORTC = 0b00010000;
  DDRC  = 0b11111111;
 
  PORTD = 0b01101100;
  DDRD  = 0b10111011;
 
  PORTE = 0b00000011;
  DDRE  = 0b11111110;

  PORTF = 0b00000000;
  DDRF  = 0b11111110;

  PORTG = 0b00000000;
  DDRG  = 0b11111111;
  
  reqTr=0;
  reqTm=0;
}


void SPI_MasterInit(void) {
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);    /* Enable SPI, Master, set clock rate fck/16 */
}

void SPI_MasterTransmit(unsigned char cData) {
    SPDR = cData;                        /* Start transmission */
    while(!(SPSR & (1<<SPIF)));        /* Wait for transmission complete */
}

void SPITransmitFreq(unsigned char Cnt, double F) { //F- значение частоты
    dFi.w = F*167.77216; //частота передаваемая через SPI, какое-то фиксированное число 167.77216
    PORTB &= ~(1<<PORTB0);
    SPI_MasterTransmit(Cnt & 0x03);
    SPI_MasterTransmit(dFi.b[0]);
    SPI_MasterTransmit(dFi.b[1]);
    SPI_MasterTransmit(dFi.b[2]);
	PORTB |= (1<<PORTB0);
}

void main(void)
{
chrT=0x01;
T.n=0;
T.F=0;
SPI_MasterInit();
IOInit();
while (1)
      {
      unsigned char nG=2;
	  double fG=100;
      SPITransmitFreq(T.n, T.F);//T.F-значение частоты, T.n-номер генератора

					switch(nG) {
						case 0:	{T.n=0; T.F=fG; reqTm=1;}; break;	
						case 1:	{T.n=1; T.F=fG; reqTm=1;}; break;
						case 2:	{T.n=2; T.F=fG; reqTm=1;}; break;
                    }

      }
}
Изменил функцию прерывания по SPI, убрал switch, добавил for. Так же в основном цикле добавил проверку логического уровня на входе SS, там же включаю и выключаю прерывания.
Код слейва:
Спойлер

Код: Выделить всё

#include <mega8.h>
#include <math.h>
#include <io.h>
#include <delay.h>

#define  F_CPU (8000000)
#define  VFG_TIMER_MAX (65535)
#define  VFG_DDR DDRD
#define  VFG_PORT PORTD

volatile unsigned long int fG;
volatile unsigned char nG;
unsigned int N[]={1,8,64,256,1024};
//BYTE STORAGE
volatile unsigned char master_arr [4];
//BYTE COUNTER
volatile int reqID;
volatile int flagRT=0;

void setup (void)
{
#asm("cli")
DDRB |= (1 << PORTB4);              //configure MISO as output
SPCR |= (1 << SPE) | (0 << MSTR);   //configure slave mod and interrupt
#asm("sei")
}

interrupt [SPI_STC] void spi_isr(void)      
{
unsigned char i=0;
        for(i=0;i<5;i++) {
        master_arr[i] = SPDR;
        SPDR = master_arr [i];
        }
}
//***********************************************timer1************************************************

void main(void)
{
VFG_DDR = 0b00000111;
DDRC = 0b11111111;
setup();
#asm("sei")
for(;;) {
   if(PINB.2==0) {SPCR |= (1 << SPIE);} //ожидание 0 на SS для включения прерываний SPI
   if(PINB.2==1) {SPCR |= (0 << SPIE);} //ожидание 1 на SS для отключения прерываний SPI
        PORTC &= ~(1<<0);
        PORTC &= ~(1<<1);
        PORTC &= ~(1<<2);
        PORTC &= ~(1<<3);
   if (reqID >= (sizeof(master_arr) / sizeof(master_arr[0])))
   {
        nG = master_arr[0] & 0x03; //generator number
        fG = 0|(master_arr[1] << 8)|(master_arr[2] << 16)|(master_arr[3] << 24); //generator freqency 
        PORTC &= ~(1<<4);          
   }         
}
}
Добавлено after 6 minutes 9 seconds:
Не могу понять, почему 0 байт посылки искажается. Ведь код работает так: мастер отправляет данные из регистра SPDR, ждет ответ, когда получает ответ - шлет следующий байт и так по кругу. А слейв просто записывает полученные данные и отправляет их обратно. Без каких либо сдвигов, может быть я неправильно присваиваю значение нулевому элементу массива master_array[0] регистра данных SPDR.
Вложения
Безымянный 11.pdf
(588.23 КБ) 67 скачиваний
a797945
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313

Сообщение a797945 »

"мастер ..., ждет ответ, ..."
мастер ждет не ответ, а когда закончится передача байта - она же прием байта.
SPI соединение это кольцо из двух сдвиговых регистров, и сдвиг в обоих тактируется мастером.
так что, первый принятый мастером байт это случайные данные из слейва, если потактируете 5-й байт увидите возвращение 4-го.
в информации никакого сдвига нет - не переживайте, здесь все в порядке. помните про байт-пустышку говорил.

по прежнему сдвигаем 1-й байт на место 2-го ?
fG = 0|(master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24);
вы не понимаете, что при сдвиге " fG = 0|(master_arr[1] << 8 )|... " изначально 1-й байт накладывается на место где должен быть 2-й ?
Ответить

Вернуться в «AVR»