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

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

Пт июн 09, 2023 14:54:10

Дайте ориг. код откуда взяли пример для:
Код:
dFi.w = F*167.77216; //частота передаваемая через SPI, какое-то фиксированное число 167.77216
PORTB &= ~_BV(PB0);
SPI_MasterTransmit(Cnt & 0x03);//0x03-маска
SPI_MasterTransmit(dFi.b[0]);//флаги передачи
SPI_MasterTransmit(dFi.b[1]);//флаги передачи
SPI_MasterTransmit(dFi.b[2]);//флаги передачи

Боюсь, что dFi.w не dFi.w, a &Fi.w (указатель, а [0], [1] ... - индекс для ячейки для double переменных.
Иначе я без побитового сдвига понятия не имею, как можно получить частоту в 3 байта, тем более со десет. знаком (F*167.77216).
А и какой double, в Вашем компиляторе для этого МК вероятно double -> float (32 bit).
Портировать код с другого МК на этот?
Последний раз редактировалось veso74 Пт июн 09, 2023 15:03:36, всего редактировалось 4 раз(а).

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

Пт июн 09, 2023 15:01:25

Начал менять настройки мастера, изменил прескейлер в регистре SPI SPCR с 16 до 128, при частоте CK - 7813 Гц и заработал 3 кейс.MOHCTEP был прав, осталось разобраться с как настроить частоту, чтобы работали все 4 кейса USI_OVERFLOW. Но пока что ка как бы я не настраивал частоту мастера, 4 кейс оживить не удается.

Добавлено after 2 minutes 33 seconds:
veso74, это прошивка с рабочего прибора, прошивка с слейва не сохранилась и сгорела в результате КЗ.
Скинул архив, иницилизация SPI в USART.c. Слейв в данной ситуации выступает как регулируемый генератор меандра.
Вложения
KD8105.rar
(511.15 KiB) Скачиваний: 23

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

Пт июн 09, 2023 15:41:54

warptred12, Попробуйте такой вариант сброса reqID.
Код:
switch(reqID) {
   ...
   ...
   case 3:
      dFi.b[2] = USIDR;
      USISR = 1<<USIOIF;  // Clear Overflow bit
      reqID++;   // !!
      flag_RT = 1;
   break;
    }
    reqID %=4;
    ...

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

Пт июн 09, 2023 15:58:21

После некоторых изменений, таких как перенос из for функции инициилизации USI и изменения прескейлера частоты тактирующего сигнала мастера, МК в протеусе начал реагировать на измения номера ножки и частоты со стороны мастера. Теперь 1 байт(номер ножки, отправляемый со стороны мастера) определяется корректно и на заданной ножке генерируется частота, но частота не соответствует заданной и форма генерируемой частоты далека от меандра.
Я думаю, что это связано с тем что кейс 3 по прежнему не работает, также пробовал подавать 2-х байтные и 1-байтные числа по SPI со стороны мастера и все равно частота на выходе МК ATtiny2313 не корректна.
На данный момент присутствует 3 основные проблемы:
1) Неверная частота на выходе МК.
2) Неверная форма сигнала, должен быть меандр.
3) Хоть и частота генерируется на верной ножке, почему-то МК подает +5В на другие ножки, которые задействованы как выводы частоты nG, а этого быть не должно.
Вот актуальный код слейва:
Спойлер
Код:
//https://weathergadget.wordpress.com/2016/05/19/usi-spi-slave-communication/
#include <tiny2313.h>
#include <math.h>
#include <io.h>
#include <delay.h>

#define  F_CPU (8000000)
#define  VFG_TIMER_MAX (65535)
#define  VFG_DDR DDRB
#define  VFG_PORT PORTB

#define CS    PORTD3     // Chip select
#define DO    PORTB5     // MISO or Data Out
#define USCK  PORTB7     // Clock

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;

unsigned int fG;
unsigned char nG;
unsigned int N[]={1,8,64,256,1024};
unsigned char flag_RT = 0;
unsigned char ch_num = 0;

volatile char reqID = 0;  // This is for the first byte we receive, which is intended to be the request identifier
//volatile unsigned char index = 0;  // this is to send back the right element in the array

//***********************************************USI************************************************

void SpiSlaveInit() {
    #asm("cli")
    USICR = ((1<<USIWM0)|(1<<USICS1));  // Activate 3- Wire Mode and use of external clock but NOT the interrupt at the Counter overflow (USIOIE)
    PORTD |= (1<<6);
    PORTD |= 1<<CS;                     // Activate Pull-Up resistor on PD3
    GIMSK |= 1<<INT1;                   
    MCUCR |= 1<<ISC10;
    #asm("sei")
}

// External Interrupt 0 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{     
    if((PIND & (1<<CS))== 0){
    PORTD |= (1<<5);
// If edge is falling, the command and index variables shall be initialized
// and the 4-bit overflow counter of the USI communication shall be activated:
    reqID = 0;
    //index = 0;
   flag_RT = 0;
    USICR |= (1<<USIOIE);
    USISR = 1<<USIOIF;      // Clear Overflow bit
    } 
    else{
// If edge is rising, turn the 4-bit overflow interrupt off:     
    USICR &= ~(1<<USIOIE);
    PORTD |= (1<<6);
    }
}

interrupt [USI_OVERFLOW] void usi_ovf_isr(void) {
switch(reqID) {
   case 0:
      PORTD |= (1<<0);
        ch_num = USIDR;
      USISR = 1<<USIOIF;  // Clear Overflow bit
        reqID++;
   break;
   case 1:
        PORTD |= (1<<1);
      dFi.b[1] = USIDR;
      USISR = 1<<USIOIF;  // Clear Overflow bit
      reqID++;
   break;
   case 2:
        PORTD |= (1<<2);
      dFi.b[2] = USIDR;
      USISR = 1<<USIOIF;  // Clear Overflow bit
        reqID++;
   break;
   case 3:
        PORTD |= (1<<4);
      dFi.b[3] = USIDR;
      USISR = 1<<USIOIF;  // Clear Overflow bit
      reqID = 0;
       flag_RT = 1;
    break;
    }     
}

//***********************************************timer1************************************************

void Tim1Init(void)
{
    #asm("cli")
    TCCR1A = (1<<COM1A0);                       //toggle on compare
    TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);    // set timer CTC mode, prescaler 1024
    TIMSK = (1<<OCIE1A);
    #asm("sei")
}

void SetUpTim1A(unsigned int Foc)    //calculate value OCR1A register
{
    unsigned int TimDiv;
    unsigned char ClockSelect=0;
    unsigned char i=0;
    for(i=0;i<=4;i++) {
        TimDiv = (F_CPU/(2*(Foc/167.77216)*N[i])-1)+0.5;
        if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){
        ClockSelect=i+1;
        break;
        }
    }
    OCR1A=TimDiv;
    TCCR1B = (1<<WGM12) | (ClockSelect<<CS10);   
}


void UpdateTim1A(unsigned int freq)             //old value storage
{
   static unsigned int fG_old = 0;
    //PORTA |= (1<<0);
   if (fG_old != freq)
   {
      SetUpTim1A(freq);
      fG_old = freq;
   }
}

void set_out_pin (unsigned char num){           //output pin selection
    nG=1<<num;
    VFG_DDR = nG;
    //PORTB |= (1<<6);
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    VFG_PORT = (VFG_PORT^nG)&(nG);
   
}

void main(void)
{
 static unsigned int fG_old = 0;
 unsigned long int tmp;
 Tim1Init();
 UpdateTim1A(fG);
 SpiSlaveInit();
 //DDRA=0b11111111;
 //DDRB=0b11111111;
 DDRD=0b11110111;
#asm("sei")
for(;;) {
//delay_ms(1);


PORTD &= (~((1<<0)|(1<<1)|(1<<2)|(1<<4)|(1<<5)|(1<<6)));
//PORTB &= (~(1<<3)|(1<<4)|(1<<6));
//PORTA &= (~(1<<0)|(1<<1));

    if (fG_old != fG) {             //old value detction
        SetUpTim1A(fG);
        fG_old = fG;
    }
 
    nG = ch_num;  //generator number                                         
    fG = dFi.b[1] << 8;
    tmp = dFi.b[2] << 16;
    fG |= tmp;
    tmp = dFi.b[2] << 24;
    fG |= tmp;   //generator frequency                   
    set_out_pin (nG);
    SetUpTim1A(fG);
}
}


Добавлено after 4 minutes 15 seconds:
MOHCTEP, этот вариант сброса не помогает, просто появляется +5В на ножках PB0 и PB1.

Добавлено after 5 minutes 5 seconds:
Вот форма генерируемого сигнала.
Вложения
Безымянный4.pdf
(601.27 KiB) Скачиваний: 29

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

Пт июн 09, 2023 16:11:48

VFG_DDR тоже настройте один раз, при инициализации. Тогда set_out_pin (nG); будет не нужна. Вместо ее вызова, в бесконечном цикле достаточно будет строки nG=1<<ch_num;

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

Пт июн 09, 2023 16:27:12

MOHCTEP, тогда при nG = 0 на мастере(0x00000000), частота генерируется на ножках PB0 и PB1.

Добавлено after 3 minutes 50 seconds:
При nG = 1(0x00000001), частота генерируется на ножке PB1, при nG = 2(0x00000002), частота генерируется на ножке PB2.
Вложения
Безымянный5.pdf
(620.77 KiB) Скачиваний: 23

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

Пт июн 09, 2023 16:38:04

nG никогда не должно быть == 0. При ch_num ==0, nG ==1.
Код:
void main(void)
{
 static unsigned int fG_old = 0;
 unsigned long int tmp;
 Tim1Init();
 UpdateTim1A(fG);
 SpiSlaveInit();
 //DDRA=0b11111111;
 DDRB=0b11111111;
 DDRD=0b11110111;
#asm("sei")
for(;;) {
//delay_ms(1);


PORTD &= (~((1<<0)|(1<<1)|(1<<2)|(1<<4)|(1<<5)|(1<<6)));
//PORTB &= (~(1<<3)|(1<<4)|(1<<6));
//PORTA &= (~(1<<0)|(1<<1));

    if (fG_old != fG) {             //old value detction
        SetUpTim1A(fG);
        fG_old = fG;
    }
 
    nG=1<<ch_num;  //generator number                                         
    fG = dFi.b[1] << 8;
    tmp = dFi.b[2] << 16;
    fG |= tmp;
    tmp = dFi.b[2] << 24;
    fG |= tmp;   //generator frequency                   
    //set_out_pin (nG);
    SetUpTim1A(fG);
}
}
Как-то так...

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

Пт июн 09, 2023 17:11:00

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;

объединение - каждый элемент (w,h,b) начинается с одной и тойже ячейки памяти,
т.е. dFi.b[0] - это младший байт из dFi.w


dFi.w = F*167.77216; - здесь неявное преобразование float->long int
(как компилятор это делает я не знаю, допустимо ли выбрасывать старший байт)

в передаче:
SPI_MasterTransmit(Cnt & 0x03); //1-й байт
SPI_MasterTransmit(dFi.b[0]); //2-байт - младший из dFi.w
SPI_MasterTransmit(dFi.b[1]); //3-байт - второй из dFi.w
SPI_MasterTransmit(dFi.b[2]); //4-байт - третий из dFi.w,
четвертый из dFi.w - проигнорирован, не передается,
т.е. целостность unsigned long int w нарушается

при приеме:
ch_num = USIDR;
dFi.b[1] = USIDR; - младший из dFi.w
dFi.b[2] = USIDR; - второй из dFi.w
dFi.b[3] = USIDR; - третий из dFi.w

fG = dFi.b[1] << 8;
tmp = dFi.b[2] << 16;
fG |= tmp;
tmp = dFi.b[2] << 24;
fG |= tmp;

т.е. в fG <b[1]><b[1]><b[0]>< 00 > (здесь b[] - из dFi.w передатчика)
а в dFi.w <b[3]><b[2]><b[1]><b[0]>

Добавлено after 11 minutes 45 seconds:
а между тем, если б передавать 5 байт (номер, float)
результат вычисления переправлялся бы целёхоньким
dFi.f = F*167.77216; - без преобразования типа

typedef union
{
float f;
unsigned long int w ; // w as WORD
unsigned int h[2]; // h as HALF-WORD
unsigned char b[4]; // b as BYTE
} Union32;

SPI_MasterTransmit(Cnt & 0x03); //1-й байт
SPI_MasterTransmit(dFi.b[0]); //2-байт - младший из dFi.f
SPI_MasterTransmit(dFi.b[1]); //3-байт - второй из dFi.f
SPI_MasterTransmit(dFi.b[2]); //4-байт - третий из dFi.f
SPI_MasterTransmit(dFi.b[3]); //5-байт - четвертый из dFi.f

и ничего не надо ручками склеивать в приемнике dFi.f = dFi.f передатчика, он же fG

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

Пт июн 09, 2023 17:14:39

...
dFi.w = F*167.77216; - здесь неявное преобразование float->long int
...

Код:
dFi.w = (unsigned long int)((float)F * 167.77216);

На одном компиляторе так должно быть, с другой - получилось и в оригинале.

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

Пт июн 09, 2023 17:31:21

a797945, а вот как этот 3 байт ловить не понятно, в прерывании программа не доходит до case 3. Вероятно отправляются 4 байта вместо 5 - для экономии памяти attiny.
Частота SCK задана минимальной на мастере(прескейлер 128/7813Гц). Не понимаю как мне подогнать Attiny под частоту тактирования мастера.

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

Пт июн 09, 2023 19:17:45

я не специалист, и тем паче не специалист по avr,
мне сложно Вам что-то советовать связанное со структурой МК или его перефирией.
если Вы предполагаете нехватку ресурсов на слейве, попробуйте
(для эксперимента) отправлять на слейв фиксированные "частоты", идея в том чтоб наладить передачу и генерацию, а математику со слейва пока убрать
эту:
for(i=0;i<=4;i++) {
TimDiv = (F_CPU/(2*(Foc/167.77216)*N[i])-1)+0.5;
if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){
ClockSelect=i+1;
break;
}
}
т.е. посчитать несколько значений для таймера(ов) слейва, мастером эти значения (через паузу или по кнопке) отсылать на слейв, там принимать и без математики просто записывать в таймер(а).

Вы все еще в протеусе или пробовали на "железе"?

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

Пт июн 09, 2023 19:20:45

a797945, ну ток с понедельника смогу в железе посмотреть, а пока в протеусе смотрю. Попробую этот вариант, отпишусь как будут результаты.

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

Пт июн 09, 2023 19:25:51

если задача не решается - всегда приходится разбивать ее на части, местами на небольшие - и отлаживать по частям

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

Вт июл 04, 2023 16:20:49

Проблема довольно сильно затянулась и до сих пор не удалось отладить в железе прошивку на attiny2313, так что я решил параллельно заниматься написанием прошивки на контроллер с полноценной поддержкой SPI ATMEGA8.
Код слейва:
Спойлер
Код:
#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;
unsigned char nG;
unsigned int N[]={1,8,64,256,1024};
unsigned char flag_RT = 0;
unsigned char ch_num = 0;

// Массив корторый приходит от мастера
volatile unsigned char master_arr [3];
// Массив который отдаем от мастеру
volatile unsigned char slave_arr  [3];
// счетчик входящих байт
volatile int countSPIb = -1;

void setup (void)
{
  // Настройка SPI как SLAVE
  DDRB |= (1 << PORTB4);                     // Настроить вывод MISO1 на выход
  SPCR |= (1 << SPIE) | (1 << SPE) | (0 << MSTR);    // Прерывание включено и сам SPI как SLAVE
}

interrupt [SPI_STC] void spi_isr(void)                      // Прерывание SPI1 - пришел байт
{
  if (countSPIb < 0) {                   // пришла "пустышка"
    countSPIb++;                         // увеличивам счетчик
    SPDR = slave_arr [countSPIb];       // подгружаем нулевой байт массива ведомого
    PORTC |= (1<<0);
    return;                              // выходим из процедуры
  }

  master_arr [countSPIb] = SPDR1;        // получаем байт от мастера
  countSPIb++;                           // увеличиваем счетчик
  SPDR = slave_arr [countSPIb];         // отдаем байт ведомого (+1 индекс)
  PORTC |= (1<<1);

  if (countSPIb >= sizeof(master_arr)) { // если кончился массив
    PORTC |= (1<<2);
    countSPIb = -1;                      // обнуляем счетчик и ждем следующий обмен
  }
}                                        // Конец SPI - пришел байт

//***********************************************timer1************************************************

void Tim1Init(void)
{
    #asm("cli")
    TCCR1A = (1<<COM1A0);                       //toggle on compare
    TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);    // set timer CTC mode, prescaler 1024
    TIMSK = (1<<OCIE1A);
    #asm("sei")
}

void SetUpTim1A(unsigned long int Foc)    //calculate value OCR1A register
{
    unsigned long int TimDiv;
    unsigned char ClockSelect=0;
    unsigned char i=0;
    for(i=0;i<=4;i++) {
        TimDiv = 1*((F_CPU/(2*Foc*N[i])-1));
        if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){
        ClockSelect=i+1;
        break;
        }
    }
    #asm("cli")
    OCR1A=TimDiv;
    TCCR1B = (1<<WGM12) | (ClockSelect<<CS10);
    #asm("sei")   
}


void UpdateTim1A(unsigned long int freq)             //old value storage
{
    static unsigned long int fG_old = 0;
    if (fG_old != freq)
    {
        SetUpTim1A(freq);
        fG_old = freq;
    }
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    VFG_PORT = (VFG_PORT^nG)&(nG);   
}

void main(void)
{
 static unsigned long int fG_old = 0;
 unsigned long int tmp;
 int i;
 VFG_DDR = 0b00000111;
 DDRC = 0b11111111;
 setup();
 Tim1Init();
#asm("sei")
for(;;) {
    if(PINB.2==0) {countSPIb = -1;}  //сброс в случае глюка связи

    if (fG_old != fG) {             //old value detction
        SetUpTim1A(fG);
        fG_old = fG;
    }

for (i = 0; i < sizeof(master_arr); i++) {
    nG = master_arr[i]; //generator number
    fG = master_arr[i] << 8;
    tmp = master_arr[i] << 16;
    fG |= tmp;
    tmp = master_arr[i] << 24;
    fG |= tmp;     
    //generator frequency                   
    UpdateTim1A(fG);
    SetUpTim1A(fG);
    }         
}
}

Мне кажется этот код интуитивно более понятен и будет проще его отладить, хотябы в протеусе, чтобы были дополнительные варианты в случае неудачи с аттини.
Ну проблема в том, что программа записывает только первый байт информации(nG - выбор выходной ножки котроллера), а в остальные записывает нули, так что вопрос к экспертам, где я облажался?

Добавлено after 38 minutes 21 second:
Теперь работает только PC0 и на нем частота 32 Гц, хотя ничего не менял в коде.

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

Вт июл 04, 2023 17:39:02

Непонятна суть цикла
Код:
for (i = 0; i < sizeof(master_arr); i++) {
    nG = master_arr[i]; //generator number
    fG = master_arr[i] << 8;
    tmp = master_arr[i] << 16;
    fG |= tmp;
    tmp = master_arr[i] << 24;
    fG |= tmp;     
    //generator frequency                   
    UpdateTim1A(fG);
    SetUpTim1A(fG);
    }         
Здесь вы всегда манипулируете последним байтом массива master_arr, назначая его обеим переменным nG и fG.

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

Вт июл 04, 2023 17:51:48

MOHCTEP, первый полученный байт по SPI, я присваиваю значению массива master_arr[0], а это значение присваиваю переменной nG(номер выхода генератора), master_arr[1],master_arr[2],master_arr[3] я пытаюсь присвоить переменной fG(частота генератора, подставляемая в формулу расчета регистра OCR1A).
Идея такова, что каждое прерывание я записываю по байту информации в массив master_arr[i], а в основном цикле я пытаюсь присвоить эти значения переменным nG и fG. Ну такова была идея по крайней мере.

Добавлено after 3 minutes 21 second:
Функция for (i = 0; i < sizeof(master_arr); i++) нужна для того чтобы подставить эти значения в правильном порядке, но опят таки я не уверен что это работает правильно.

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

Вт июл 04, 2023 18:05:06

Нет. Вы циклом всегда присваиваете каждый байт массива, по очереди, обеим переменным сразу. В итоге, после отработки этого странного цикла, обеим переменным будет присвоен последний байт массива.
Уберите этот цикл и модифицируйте переменные обращаясь к массиву по числовым индексам master_arr[0],master_arr[1]... и master_arr[3](четвертый байт) вам недоступен, так как длина массивов у вас = 3 байтам.

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

Вт июл 04, 2023 18:44:17

MOHCTEP, я увеличил массив до 4, потому что по SPI передается 4 байта, так будет верно ?
Спойлер
Код:
#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;
unsigned char nG;
unsigned int N[]={1,8,64,256,1024};
unsigned char flag_RT = 0;
unsigned char ch_num = 0;

// Массив корторый приходит от мастера
volatile unsigned char master_arr [4];
// Массив который отдаем от мастеру
volatile unsigned char slave_arr  [4];
// счетчик входящих байт
volatile int countSPIb = -1;

void setup (void)
{
  // Настройка SPI как SLAVE
  DDRB |= (1 << PORTB4);                            // Настроить вывод MISO1 на выход
  SPCR |= (1 << SPIE) | (1 << SPE) | (0 << MSTR);   // Прерывание включено и сам SPI как SLAVE
}

interrupt [SPI_STC] void spi_isr(void)              // Прерывание SPI1 - пришел байт
{
  if (countSPIb < 0) {                              // пришла "пустышка"
    countSPIb++;                                    // увеличивам счетчик
    SPDR = slave_arr [countSPIb];                   // подгружаем нулевой байт массива ведомого
    PORTC |= (1<<0);
    return;                                         // выходим из процедуры
  }

  master_arr [countSPIb] = SPDR1;                   // получаем байт от мастера
  countSPIb++;                                      // увеличиваем счетчик
  SPDR = slave_arr [countSPIb];                     // отдаем байт ведомого (+1 индекс)
  PORTC |= (1<<1);

  if (countSPIb >= sizeof(master_arr)) {            // если кончился массив
    PORTC |= (1<<2);
    countSPIb = -1;                                 // обнуляем счетчик и ждем следующий обмен
  }
}                                                   // Конец SPI - пришел байт

//***********************************************timer1************************************************

void Tim1Init(void)
{
    #asm("cli")
    TCCR1A = (1<<COM1A0);                           //toggle on compare
    TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);        // set timer CTC mode, prescaler 1024
    TIMSK = (1<<OCIE1A);
    #asm("sei")
}

void SetUpTim1A(unsigned long int Foc)              //calculate value OCR1A register
{
    unsigned long int TimDiv;
    unsigned char ClockSelect=0;
    unsigned char i=0;
    for(i=0;i<=4;i++) {
        TimDiv = 1*((F_CPU/(2*Foc*N[i])-1));
        if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){
        ClockSelect=i+1;
        break;
        }
    }
    #asm("cli")
    OCR1A=TimDiv;
    TCCR1B = (1<<WGM12) | (ClockSelect<<CS10);
    #asm("sei")   
}


void UpdateTim1A(unsigned long int freq)             //old value storage
{
    static unsigned long int fG_old = 0;
    if (fG_old != freq)
    {
        SetUpTim1A(freq);
        fG_old = freq;
    }
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    VFG_PORT = (VFG_PORT^nG)&(nG);   
}

void main(void)
{
 static unsigned long int fG_old = 0;
 unsigned long int tmp;
 int i;
 VFG_DDR = 0b00000111;
 DDRC = 0b11111111;
 setup();
 Tim1Init();
#asm("sei")
for(;;) {
    if(PINB.2==0) {countSPIb = -1;}             //сброс в случае глюка связи

    if (fG_old != fG) {                         //old value detction
        SetUpTim1A(fG);
        fG_old = fG;
    }

    nG = master_arr[0];                         //generator number
    fG = master_arr[1] << 8;
    tmp = master_arr[2] << 16;
    fG |= tmp;
    tmp = master_arr[3] << 24;
    fG |= tmp;                                  //generator frequency                       
    UpdateTim1A(fG);
    SetUpTim1A(fG);
    }         
}


Добавлено after 20 minutes 58 seconds:
Ну результат все тот же, в принципе.

Добавлено after 8 minutes 53 seconds:
Вопрос в том как это починить, чтобы оно работало или лучше писать заново.

Добавлено after 4 minutes 54 seconds:
Если что пример кода для реализации SPI slave'a брал тут: https://dzen.ru/media/esp32/spi-arduino ... adboard.ru

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

Вт июл 04, 2023 19:54:15

Ну... сложно что то умное подсказать на расстоянии, да еще и для протеуса. В качестве версии: проблема возможна в том, что вы постоянно перестраиваете переменные nG и fG в главном цикле и вместе с ними таймер. Независимо от того - пришло там что-то по SPI или нет. Возможно ваш таймер, от постоянных перенастроек, просто не успевает нормально отрабатывать цикл. Вот у вас есть счетчик заполнения массива countSPIb. Можно, к примеру, в майн цикле проверять его на равенство длине массива (это значит, что пришли все 5 байт от мастера и данные подготовлены) и только в этом случае пересчитать переменные + таймер и сбросить счетчик countSPIb, подготовившись к следующему приему.
Как-то так примерно...
Код:
interrupt [SPI_STC] void spi_isr(void)              // Прерывание SPI1 - пришел байт
{
  if (countSPIb < 0) {                              // пришла "пустышка"
    countSPIb++;                                    // увеличивам счетчик
    SPDR = slave_arr [countSPIb];                   // подгружаем нулевой байт массива ведомого
    PORTC |= (1<<0);
    return;                                         // выходим из процедуры
  }

  master_arr [countSPIb] = SPDR1;                   // получаем байт от мастера
  countSPIb++;                                      // увеличиваем счетчик
  SPDR = slave_arr [countSPIb];                     // отдаем байт ведомого (+1 индекс)
  PORTC |= (1<<1);

  if (countSPIb >= sizeof(master_arr)) {            // если кончился массив
    PORTC |= (1<<2);
    //countSPIb = -1;                                 // обнуляем счетчик и ждем следующий обмен
  }
}
...

void main(void){
   ...
   for(;;){
      ...
      if (countSPIb >= sizeof(master_arr)){
         nG = master_arr[0];                         //generator number
         fG = (master_arr[1] << 8)|(master_arr[2] << 16)|(master_arr[3] << 24);
         UpdateTim1A(fG);
         SetUpTim1A(fG);
         countSPIb = -1;
      }
   }
}   

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

Ср июл 05, 2023 12:28:06

MOHCTEP, в протеусе мастер отправляет верные данные, в хексадермальном формате 02 5C 8F 02(первый байт номер генератора, остальные 3 значения частоты), а вот в ответ мастеру - слейв шлет 00 01 01 01 в ответ, это значит, что по какой-то причине, байты, полученные от мастера записываются в единицы. Если я правильно понимаю, как работает SPI, то при получении байта, слейв отправляет полученный байт мастеру, в неизмененном виде, а у меня не так получается. Это значит что скорее всего код в прерывании криво написан, но пока конкретно не ясно, что там не так.

Добавлено after 7 minutes 56 seconds:
А для хранения значения переменной fg, у меня есть такая функция, которая сравнивает старое и новое значение и не изменилось ли значение fG
Спойлер
Код:
void UpdateTim1A(unsigned long int freq)             //old value storage
{
    static unsigned long int fG_old = 0;
    if (fG_old != freq)
    {
        SetUpTim1A(freq);
        fG_old = freq;
    }
}
 if (fG_old != fG) {                         //old value detction
        SetUpTim1A(fG);
        fG_old = fG;
    }



Добавлено after 4 minutes 34 seconds:
Еще может быть проблема в том, чт переменная fG - 32-х битная(unsigned long int), а мы записываем в нее 24 бита. Но я даже не знаю как это проверить, просто предположение.
Ответить