Обсуждаем контроллеры компании Atmel.
Ответить

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

Чт июл 06, 2023 15:51:28

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

Добавлено after 46 seconds:
veso74, это я уже заметил и исправил, результат тот же.

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

Чт июл 06, 2023 15:58:53

Повторю вопрос: компилятор и IDE какой?
(Проверял на два прежде чем привел пример здесь).

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

Чт июл 06, 2023 16:02:53

veso74, CodeVisionAvr версии 2.05.0, а компилятор gcc по идее, не нашел в кодевижне, где это написано.

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

Чт июл 06, 2023 16:04:46

не знаю логики построения, но
Код:
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 бит "пустые" мне кажутся странными.

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

Чт июл 06, 2023 16:08:21

veso74, fg - 4-х байтная переменная, но подставляем в нее только 3 последних значения master_arr[]. 0 значение массива мы подставляем в переменную nG.

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

Чт июл 06, 2023 16:15:46

А что у младших 8 бита fg?
Если они нулевые, установите их явно.
А так сначала нет неустановленного значения fg, затем дополняете 3 по 8 бит ...

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

Чт июл 06, 2023 16:20:37

veso74, fG = 0|(master_arr[1] << 8)|(master_arr[2] << 16)|(master_arr[3] << 24); //generator freqency. Так?

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

Чт июл 06, 2023 16:22:58

грубо: да (а может быть, и еше "красивее" :) ). Ничего, так и быть.

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

Чт июл 06, 2023 18:13:49

Осталось теперь разобраться почему это не работает: 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 контроллера.

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

Чт июл 06, 2023 19:13:26

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

расскажите, лучше, это означает:
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-х байт от слейва, дальше пауза и снова. когда получится - поймете зачем пустышка, без нее можно, но щас пока так.
не будете пытаться понять, что пишите - вы безнадежны, так что включайте голову. удачи.

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

Чт июл 06, 2023 19:30:34

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 байта.

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

Чт июл 06, 2023 19:41:46

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

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)

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

Чт июл 06, 2023 19:54:28

a797945, 1. 00000000
2. У меня другое равенство fG = 0|(master_arr[1] << 8 )|(master_arr[2] << 16)|(master_arr[3] << 24)
00 01 02 03- значение fG

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

Чт июл 06, 2023 20:01:07

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

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

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

так я и говорю - не торопитесь, пытайтесь осмысливать.
Последний раз редактировалось a797945 Чт июл 06, 2023 20:10:15, всего редактировалось 2 раз(а).

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

Чт июл 06, 2023 20:06:58

a797945, да вы правы, глупая ошибка.

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

Пт июл 07, 2023 09:37:16

Подправил код, добавил в прерывание проверку 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 байт, остальные иногда проскакивают и совпадают с реальными значениями.

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

Пт июл 07, 2023 09:37:16

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

Это невозможно (и неправильно):
Код:
volatile unsigned char master_arr [4];
...
... (master_arr[2] >> 16)|(master_arr[3] >> 24);

привожу пример:
master_arr[3] = 123 (случайное значение) = 0x7B = 0b01111011. Переместите 24 раза вправо и посмотрите, что произойдет?

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

Пт июл 07, 2023 09:59:14

в помощь вам. давайте порасуждаем
сочиняем прошивку для слейва, подошли к разрешению прерываний, стоп, а какие нас тут ждут грабли
г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
..."

и в обработчике прерываний нужно как можно меньше действий.

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

Пт июл 07, 2023 15:13:06

Изменил код, теперь время получения посылки и отправки ее обратно мастеру - совпадают. Но почему-то нулевой байт посылки, отправляемой обратно мастеру всегда неверен. Например, мастер отправляет посылку: 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 KiB) Скачиваний: 30

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

Пт июл 07, 2023 16:06:44

"мастер ..., ждет ответ, ..."
мастер ждет не ответ, а когда закончится передача байта - она же прием байта.
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-й ?
Ответить