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

программный SPI + радиомодуль SI4432

Пн окт 09, 2017 17:55:34

Здравствуйте, собрал схему с tiny2313 и радиомодулем SI4432 (точнее две схемы, передатчик и приемник). Оказалось что у этого МК нет SPI. Нашел программный SPI. Тут.
Попытался переделать функции записи и чтения SPI как в статье о работе с модулями SI4432 на Хабре. Все скомпилировалось в WinAVR и прогрузилось. Вроде этот код не зависает (вставлял для теста строчки мигание светодиодом).
Но радиосвязь не заработала.
Спецы, как еще можно проверить что мой программный SPI работает?
ПС. Код функций
Спойлер
Код:
#define PORT_SPI PORTB
#define PORT_D    PORTD

#define DDR_SPI  DDRB
#define DDR_D    DDRD

#define PIN_SPI  PINB

#define UCSK     PB7   //CLK
#define DO       PB6   //MISO
#define DI       PB5   //MOSI
#define SS       PD0
#define NIRQ     PD1
#define LED        PD5

unsigned char tmp;


void USI_init_SPI (void)
{
    DDR_SPI |=  (1<<DO);           //линия выхода данных - выход
   DDR_SPI |=  (1<<UCSK);         //линия тактирующего сигнала - выход
   DDR_SPI &= ~(1<<DI);           //линия входа данных - вход
   DDR_D   |=  (1<<SS);           //линия выбора кристалла - выход
}

//**************функция ЗАПИСИ байта по USI*******************//
void SPI_W (unsigned char reg, unsigned char data_w)
{
   PORT_D &= ~(1<<SS);         //выбираем кристалл, т.е. SI4432
   //------Запись адреса регистра в буфер SPI МК
   //------Установка старшего бита в адресе регистра необходима для проведения операции записи (всего 127 регистров)
    USIDR = reg | 0x80;            //передаваемые данные в сдвиговый регистр
   USISR |= (1<<USIOIF);         //сбрасываем флаг
   while(!(USISR & (1<<USIOIF)))   //пока нет флага окончания передачи
   {
      USICR |= (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC);//формируем тактирующие импульсы
   }
    USIDR = data_w;               //передаваемые данные в сдвиговый регистр
   USISR |= (1<<USIOIF);         //сбрасываем флаг
   while(!(USISR & (1<<USIOIF)))   //пока нет флага окончания передачи
   {
      USICR |= (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC);//формируем тактирующие импульсы
   }   
   PORT_D |= (1<<SS);            //отпускаем модуль SI4432
   //return (USIDR);               
}

//*************функция ЧТЕНИЯ байта по USI*******************//
unsigned char SPI_R (unsigned char reg)
{
   PORT_D &= ~(1<<SS);         //выбираем кристалл, т.е. SI4432
   //Запись адреса регистра в буфер SPI МК
   //Установка старшего бита в адресе регистра необходима для проведения операции записи (всего 127 регистров)
    USIDR = reg;               //передаваемые данные в сдвиговый регистр
   USISR |= (1<<USIOIF);         //сбрасываем флаг
   while(!(USISR & (1<<USIOIF)))   //пока нет флага окончания передачи
   {
      USICR |= (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC);//формируем тактирующие импульсы
   }
    USIDR = 0xFF;               //порожняк
   USISR |= (1<<USIOIF);         //сбрасываем флаг
   while(!(USISR & (1<<USIOIF)))   //пока нет флага окончания передачи
   {
      USICR |= (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC);//формируем тактирующие импульсы
   }      
   PORT_D |= (1<<SS);            //отпускаем модуль SI4432
   return (USIDR);               //возвращаем полученные данные
}


Исходник приемника
Спойлерmain.c


ППС. На ардуине связь на этих модулях работала хорошо. На библиотеке RadioHead
Вложения
main.c
(7.79 KiB) Скачиваний: 535

Re: программный SPI + радиомодуль SI4432

Вт окт 10, 2017 05:54:11

в тини2313 есть USI а его можно в режим И2С или в SPI настроить...

Re: программный SPI + радиомодуль SI4432

Ср окт 11, 2017 08:02:55

короче нашел способ проверить работоспособность программного SPI. Сначала буду добиваться связи по SPI между моими платами, а потом уже пытаться конфигурировать модули SI4432

Re: программный SPI + радиомодуль SI4432

Ср окт 11, 2017 08:16:58

в тини2313 есть USI а его можно в режим И2С или в SPI настроить...

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

Re: программный SPI + радиомодуль SI4432

Ср окт 11, 2017 14:02:31

да, точно, с телефона неудобно под спойлеры заглядывать (он всю страницу заново грузит, а с моим инетом это около минуты), потому и поверил на слово, что СПИ программный.
чето тне очень понял, какойто микс похоже - и аппаратные регистры задействованы и ноги переназначены, вечером с компа вчитаюсь, а может и у себя чего найду готового.

Re: программный SPI + радиомодуль SI4432

Чт окт 12, 2017 09:05:55

да, аппаратный...
непонятно, почему строчка:
.....//формируем тактирующие импульсы
внутри цикла?

Re: программный SPI + радиомодуль SI4432

Пт окт 13, 2017 08:11:01

Ivanoff-iv писал(а):непонятно, почему строчка:
.....//формируем тактирующие импульсы
внутри цикла?
потому что дебильный USI сам этого не делает! можете себе представить, в каком то ли пьяном, то ли наркотическом угаре разработчики создавали АППАРАТНЫЙ модуль последовательного интерфейса, которому для работы сдвигового регистра НЕОБХОДИМО ПРОГРАММНО подавать тактовые импульсы путем записи в регистр управления?! у меня даже матерных слов не хватает на это... :kill:

Re: программный SPI + радиомодуль SI4432

Пн янв 08, 2018 09:17:42

Ура. Похоже я отмучался. Вспомнил я про великий протеус и в нем домучал код. Этот код что в первом посте работает тока если два контроллера связывать (проверил работоспособность в протеусе).
Нашел другой код функции работы с SPI, подшаманил под свои нужды, и в пихнул его в код для теста SPI и драйвера 7сегментного индикатора, проверил в протеусе... и заработало!!!

Спойлер
Код:
/* Использование семисегментного индикатора с общим катодом и сдвиговым регистром по протоколу SPI */

#include <avr/io.h>         //подключаем библиотеки
#include <util/delay.h>

#define SPI_DDR     DDRB    //назначаем имя для изменеия направления на порту B
#define SPI_PORT    PORTB   //назначаем имя для используемого порта
#define SPI_SS      PB4     //назначаем имя выхода SS
#define SPI_MOSI    PB5     //назначаем имя выхода MOSI
#define SPI_MISO    PB6     //назначаем имя выхода MISO
#define SPI_SCK     PB7     //назначаем имя выхода SCK

char d[18] ={               //кодирование знаков для семисегментного индикатора
    0x7E,  //0
    0x30,  //1
    0x6D,  //2
    0x79,  //3
    0x33,  //4
    0x5B,  //5
    0x5F,  //6
    0x70,  //7
    0x7F,  //8
    0x7B,  //9
    0x77,  //a
    0x1F,  //b
    0x4E,  //c
    0x3D,  //d
    0x4F,  //e
    0x47,  //f
    0x80,   //.
    0x00   //пусто
};

void spi(unsigned char cmd, unsigned char data)                //Функция передачи двух пакетов по 8 бит по протоколу SPI
{
   unsigned char i=0;
   SPI_PORT &= ~(1<<SPI_SS);                      //сбрасываем SS в 0
   
   _delay_us(10);
   for (i=0; i<8; i++)
       {
      if( (cmd>>(7-i))&0x01 ) SPI_PORT |= (1<<SPI_MOSI); else SPI_PORT &= ~(1<<SPI_MOSI);      //SPI_MOSI = (cmd>>(7-i))&0x01
        _delay_us(10);       
      SPI_PORT |= (1<<SPI_SCK);               //SPI_SCK=1;
        _delay_us(30);
        SPI_PORT &= ~(1<<SPI_SCK);               //SPI_SCK=0;
        _delay_us(20);
       }
   for (i=0; i<8; i++)
       {
        if( (data>>(7-i))&0x01 ) SPI_PORT |= (1<<SPI_MOSI); else SPI_PORT &= ~(1<<SPI_MOSI);      //SPI_MOSI = (cmd>>(7-i))&0x01
        _delay_us(10);
        SPI_PORT |= (1<<SPI_SCK);               //SPI_SCK=1;
        _delay_us(30);
        SPI_PORT &= ~(1<<SPI_SCK);               //SPI_SCK=0;
        _delay_us(20);
       }
   SPI_PORT |= (1<<SPI_SS);                        //устанавливаем SS в 1
   _delay_us(20);      
}

void clrdig (void)          //Функция очистки индикаторов
{
    spi(0x01,d[17]);
    spi(0x02,d[17]);
    spi(0x03,d[17]);
    spi(0x04,d[17]);
    spi(0x05,d[17]);
}

int main(void)
{
   SPI_DDR = (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS);    //настраиваем MOSI, SCK, SS как выходы
   SPI_PORT |= (1<<SPI_SS);                              //устанавливаем SS в 1
 
   //Инициализация MAX7221
    spi(0x0C,0x00);     //Отключение индикаторов
    spi(0x09,0x00);     //Отключение декодирования
    spi(0x0A,0x0A);     //Интенсивность свечения индикаторов
    spi(0x0B,0x04);     //Количество индикаторов начиная с 0
    spi(0x0F,0x00);     //Отключение теста индикаторов
    spi(0x0C,0x01);     //Включение индикаторов

    clrdig();           //Очистка всех индикаторов

    int i=0;                //Переменная перебора выводимых символов
    int j=1;                //Переменная осчета номера индикатора

    while(1){           //Бесконечный цикл
        spi(j,d[i]);    //Вывод на индикатор j символа i
        _delay_ms(1000);    //Задержка выполнения 1000мс
        i++;
        if(i>17)i=0;
        j++;
        if(j>5)j=1;
    }
    return 0;
}


Сейчес буду отлаживать непосредственно SI4432 и 2313
Вложения
main.c
(3.67 KiB) Скачиваний: 505
Proteus_7led_2313.zip
(14.97 KiB) Скачиваний: 132
Ответить