Jump to content
Sign in to follow this  
  • entries
    8
  • comments
    7
  • views
    537

USI as SPI

parovoZZ

467 views

USI as SPI
Для работы с трансивером нам необходим интерфейс SPI. Извлекать его будем всё из того же модуля USI. Здесь кратенько. Линии данных у SPI однонаправленные, а это значит, что пин DO всегда подключен к концу сдвигового регистра, а DI - к началу. Таким образом организован режим передачи full duplex. Здесь нам не нужны никакие подтягивающие резисторы, т.к. линия ВСЕГДА либо в нуле, либо в единице. А когда мы не работаем по интерфейсу SPI, то нам и пофигу, что творится на линиях. Здесь только про режим master. Здесь нет пина SS - соответственно нет и проблем, которые он создает в аппаратном SPI (пин SS всегда должен быть сконфигурирован как выход, если мы работаем ТОЛЬКО как мастер. Как только на SS приходит низкий уровень, аппаратный SPI бросает всё и переключает себя в режим SLAVE). Трансивер по интерфейсу SPI способен работать со скоростями вплоть до 10 МГц. Поэтому наша задача организовать тактирование максимально энергоэффективно ни теряя понапрасну ни единого такта.
Начнем с функции инициализации.

//... Инициализация SPI
void SPI_Init(void)
{
    SPI_DDR |= (1<<MOSI) | (1<<SCK) | (0<<MISO);        // Все выводы, кроме MISO, выходы
   // SPI_PORT |= (0<<MOSI) | (0<<SCK) | (0<<MISO);

    USICR = (1<<USIWM0) | (1<<USICLK);
}

Здесь не нужны ни счетчик, ни его убогие флаги, ни флаги старта, стопа - всё это идет лесом.
Далее идет функция отправки элементарного байта.

//... Передать байт данных
void SPI_WriteByte(uint8_t data)
{
    uint8_t clk0 = (1<<USIWM0) | (1<<USITC);
    uint8_t clk1 = (1<<USIWM0) | (1<<USITC) | (1<<USICLK);

    //... Копируем байт в регистр USIDR
    USIDR = data;

    USICR = clk0;            // Режим SPI, тактируем шину сами
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
    USICR = clk0;
    USICR = clk1;
}

Здесь в регистр USIDR пишем наш байт и начинаем дергать за веревочку. Как писал выше, при тактировании от USICLK нам необходимо самим писать в этот бит то "0", то "1". Нам надо 8 тактов, поэтому за веревочку дергаем аж 16 раз!
Так сложилось исторически, но функция отправки и получения байта отдельно

//... Передать и получить байт данных
uint8_t SPI_ReadByte(uint8_t data)
{
    //... Отправляем байт
    SPI_WriteByte(data);

    //... Принятый байт возвращаем
    return USIDR;
}

Функция отправки массива байт

//... Отправить несколько байт по SPI. cmd - команда, data - данные для отправки
void SPI_WriteArray(uint8_t cmd, uint8_t num, uint8_t *data)
{
    nRF_SELECT();
   
    //... Отправим команду
    SPI_WriteByte(cmd);

    //... Затем данные
    while(num--)
    {
        SPI_WriteByte(*data++);
    }

    nRF_DESELECT();
}

И напоследок макросы 

#define nRF_SELECT()            ClearBit(nRF_CSN_PORT, nRF_CSN)
#define nRF_DESELECT()            SetBit(nRF_CSN_PORT, nRF_CSN)
#define    nRF_CE_PORT        PORTB                //
#define    nRF_CE_DDR        DDRB                //
#define    nRF_CSN_PORT        PORTB
#define    nRF_CSN_DDR        DDRB
#define Bit(bit)  (1<<(bit))

#define ClearBit(reg, bit)       reg &= (~(1<<(bit)))
//пример: ClearBit(PORTB, 1); //сбросить 1-й бит PORTB

#define SetBit(reg, bit)          reg |= (1<<(bit))   
//пример: SetBit(PORTB, 3); //установить 3-й бит PORTB

 



7 Comments


Recommended Comments

О чем думали в Atmel, когда изобретали такой идиотский модуль без аппаратного тактирования?! Я просто не могу найти никакого объяснения этому изврату...

Share this comment


Link to comment

Есть возможность затактироваться от таймера, но у меня нахрапом не получилось. И вроде как понял, где затык, но уже задор пропал)) Да и смысла особого нет, если работаем на максимальных скоростях. 8 тактов потеряем на обслуживание прерывания, а за оставшиеся 8 тактов особо полезного ничего не сделаешь.

Share this comment


Link to comment
01.04.2019 в 23:25, parovoZZ сказал:

Есть возможность затактироваться от таймера, но у меня нахрапом не получилось. И вроде как понял, где затык, но уже задор пропал)) Да и смысла особого нет, если работаем на максимальных скоростях. 8 тактов потеряем на обслуживание прерывания, а за оставшиеся 8 тактов особо полезного ничего не сделаешь.

все отлично, в протеусе пошло спасиба, а то всю голову сломал.

Share this comment


Link to comment
3 часа назад, Александр5786336 сказал:

все отлично, в протеусе пошло спасиба, а то всю голову сломал.

На таймере?

Share this comment


Link to comment

на таймере не пробовал, сейчас на двухпроводный режим перехожу, адресация приемника(хочу попробовать с tiny2313 на tiny2313 числа передать) через define задается последние три числа как я понял?

если есть куски трехпроводной буду премного благодарен (для общего развития) 

Edited by Александр5786336

Share this comment


Link to comment
10.08.2019 в 13:18, Александр5786336 сказал:

сейчас на двухпроводный режим перехожу,

Это про I2C?

10.08.2019 в 13:18, Александр5786336 сказал:

если есть куски трехпроводной буду премного благодарен

Что имеется ввиду?

10.08.2019 в 13:18, Александр5786336 сказал:

адресация приемника(хочу попробовать с tiny2313 на tiny2313 числа передать) через define задается последние три числа как я понял?

Я I2C slave не реализовывал. В любом случае, там придется всё делать ручками.

Share this comment


Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Add a comment...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...