Теперь вы имеете общее представление о последовательном периферийном интерфейсе и можно перейти к рассмотрению SPI модуля.
SPI модуль микроконтроллера AVR atmega16 использует для своей работы 4 вывода - MOSI, MISO, SCK и SS. Когда модуль не задействован, эти выводы являются линиями портов ввода/вывода общего назначения. Когда модуль включен, режим работы этих выводов переопределяются согласно следующей таблице.
Если к микроконтроллеру подключено больше одного периферийного устройства, в качестве дополнительных выводов выбора (SS), можно использовать любые выводы общего назначения. При этом штатный вывод SS должен быть всегда правильно сконфигурирован, даже если он не используется.
Регистры SPI модуля
В микроконтроллере atmega16 для работы с модулем SPI используются три регистра:
- управляющий регистр SPCR,
- статусный регистр SPSR,
- регистр данных SPDR.
Все три регистра восьмиразрядные.
Кофигурация модуля SPI устанавливается с помощью регистра SPCR (SPI Control Register).
SPIE – разрешает /запрещает прерывания от модуля SPI. Если бит установлен в 1, прерывания от SPI разрешены.
SPE – включает/выключает модуль SPI. Если бит установлен в 1, модуль SPI включен.
DORD – определяет порядок передачи данных. Когда бит установлен в 1, содержимое регистра данных передается младшим битом вперед. Когда бит сброшен, то старшим битом вперед.
MSTR – определяет режим работы микроконтроллера. Если бит установлен в 1, микроконтроллер работает в режиме Master (ведущий). Если бит сброшен – в режиме Slave (ведомый). Обычно микроконтроллер работает в режиме master.
CPOL и CPHA – определяют в каком режиме работает SPI модуль. Требуемый режим работы зависит от используемого периферийного устройства.
SPR1 и SPR0 – определяют частоту тактового сигнала SPI модуля, то есть скорость обмена. Максимально возможная скорость обмена всегда указывается в спецификации периферийного устройства.
Статусный регистр SPSR (SPI Status Register) предназначен для контроля состояния SPI модуля, кроме того он содержит дополнительный бит управления скоростью обмена.
SPIF – флаг прерывания от SPI. Он устанавливается в 1 по окончании передачи байта данных. Если разрешены прерывания модуля, одновременно с установкой этого флага генерируется прерывание от SPI. Также этот флаг устанавливается в 1 при переводе микроконтроллера из режима master в режим slave с помощью вывода SS.
Сброс флага происходит аппаратно, при вызове подпрограммы обработки прерывания или после чтения регистра SPSR с последующим обращением к регистру данных SPDR.
WCOL- флаг конфликта записи. Флаг устанавливается в 1, если во время передачи данных выполняется попытка записи в регистр данных SPDR. Флаг сбрасывается аппаратно после чтения регистра SPSR с последующим обращением к регистру данных SPDR.
SPI2X — бит удвоения скорости обмена. Установка этого разряда в 1 удваивает частоту тактового сигнала SCK. Микроконтроллер при этом должен работать в режиме master.
Взаимосвязь между битами SPR0, SPR1, SPI2X и частотой тактового сигнала SCK показана в таблице.
Где Fosc — тактовая частота микроконтроллера AVR.
Для передачи и приема данных предназначен регистр SPDR (SPI Data Register). Запись данных в этот регистр инициирует передачу данных SPI модулем. При чтении этого регистра, считывается содержимое буфера сдвигового регистра SPI модуля.
Программный код
Минимальный программный код для работы с SPI модулем состоит из двух функций:
- функции инициализации.
- функции передачи/приема байта данных
Инициализация SPI модуля
Инициализация включает в себя конфигурирование выводов SPI модуля и управляющего регистра SPCR.
#define SPI_PORTX PORTB
#define SPI_DDRX DDRB
#define SPI_MISO 6
#define SPI_MOSI 5
#define SPI_SCK 7
#define SPI_SS 4
/*инициализация SPI модуля в режиме master*/
void SPI_Init(void)
{/*настройка портов ввода-вывода
все выводы, кроме MISO выходы*/
SPI_DDRX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
SPI_PORTX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
/*разрешение spi,старший бит вперед,мастер, режим 0*/
SPCR = (1<<SPE)|(0<<DORD)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|(1<<SPR1)|(0<<SPR0);
SPSR = (0<<SPI2X);
}
Передача/прием данных
Процесс передачи/приема данных с помощью SPI модуля, работающего в режиме Master, состоит из следующей последовательности действий:
1. установка низкого логического уровня на линии SS
2. загрузка данных в регистр SPDR
3. ожидание окончания передачи (проверка флага SPIF)
4. сохранение принятых данных (чтение SPDR), если требуется
5. возврат на 2-ой шаг, если переданы не все данные
6. установка высокого логического уровня на линии SS
Ниже приведено несколько вариантов функции передачи/приема данных.
Передача одного байта данных по SPI
void SPI_WriteByte(uint8_t data)
{
SPI_PORTX &= ~(1<<SPI_SS);
SPDR = data;
while(!(SPSR & (1<<SPIF)));
SPI_PORTX |= (1<<SPI_SS);
}
Передача и прием одного байта данных по SPI
uint8_t SPI_ReadByte(uint8_t data)
{
uint8_t report;
SPI_PORTX &= ~(1<<SPI_SS);
SPDR = data;
while(!(SPSR & (1<<SPIF)));
report = SPDR;
SPI_PORTX |= (1<<SPI_SS);
return report;
}
Передача нескольких байтов данных по SPI
*data – указатель на массив передаваемых данных, а num – размерность массива
void SPI_WriteArray(uint8_t num, uint8_t *data)
{
SPI_PORTX &= ~(1<<SPI_SS);
while(num--){
SPDR = *data++;
while(!(SPSR & (1<<SPIF)));
}
SPI_PORTX |= (1<<SPI_SS);
}
...
//Пример использования:
uint8_t buf[3] = {12, 43, 98};
…
SPI_WriteArray(3, buf);
Передачи и прием нескольких байтов данных по SPI
*data – указатель на массив передаваемых данных, а num – размерность массива.
Принятые данные будут сохраняться в том же массиве.
void SPI_ReadArray(uint8_t num, uint8_t *data)
{
SPI_PORTX &= ~(1<<SPI_SS);
while(num--){
SPDR = *data;
while(!(SPSR & (1<<SPIF)));
*data++ = SPDR;
}
SPI_PORTX |= (1<<SPI_SS);
}
Файлы
Простой SPI драйвер, в котором сведены все описанные выше функции - AVR_SPI_driver.rar
Остальные части
Учебный курс AVR. Работа с модулем SPI. Ч1
Учебный курс AVR. Работа с SPI. Управление сдвиговым регистром. Ч3
Comments
http://www.ermicro.com/blog/?p=1050
http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1
http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2
http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3
Пожалуйста, выложите пока на форум.
typedef struct{
unsigned char sec;
unsigned char min;
unsigned char hour;
} time_t;
time_t t;
void SPI_Send(time_t *time)
{
unsigned char num = 3;
RTC_SELECT();
while(num--){
SPDR = *time++;//error : incompatible types in assignment
// понятно что тип не тот
//а как быть не догоняю
while(!(SPSR & (1
Code:
void SPI_WriteStr(time_t *time)
{
SPI_PORTX &= ~(1<<SPI_SS);
SPDR = time->sec;
while(!(SPSR & (1<<SPIF)));
SPDR = time->min;
while(!(SPSR & (1<<SPIF)));
SPDR = time->hour;
while(!(SPSR & (1<<SPIF)));
SPI_PORTX |= (1<<SPI_SS);
}
А вообще.. у тебя же данные одного типа. Зачем тебе структура? В этом случае можно использовать и массив.
SPI_ReadArray((unsigned char *)&t, sizeof(t));
http://chipenable.ru/index.php/programming-avr/item/2-uchebnyy-kurs-iar-avr-pervaya-programma-na-si.html
#include
#include
#define MOSI 3
#define SCK 5
#define SS 2
void Port_init()
{
DDRB |= (1
SPI_DDRX |= (1
Code:
SPI_DDRX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
правильнее так
Code:
SPI_DDRX |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS);
SPI_DDRX &= ~(1<<SPI_MISO);
Подскажите пожалуйста, если использовать приведённый тут код в авр студио 6, какие библиотеки нужно подключать?
Code:
void USI_init_SPI_S (void)
{
DDR_SPI |= (1<<DO);
DDR_SPI &= ~(1<<UCSK);
DDR_SPI &= ~(1<<SS);
DDR_SPI &= ~(1<<DI);
USICR |= (1<<USIWM0) | (1<<USICS1);
}
unsigned char SPI_WR_S (unsigned char data_w)
{
USIDR = data_w;
USISR |= (1<<USIOIF);
while(!(USISR & (1<<USIOIF)));
return (USIDR);
}
int main (void)
{
unsigned char data_r[2];
unsigned char i=0;
USI_init_SPI_S ();
for(;;)
{
if(bit_is_clear(PIN_SPI, SS))
{
data_r = SPI_WR_S(data_r);
if(i>=2) i=0;
}
Запись данных ведется через MOSI. В коде его определили, как 5 выход на порту B.
Code:
#define SPI_MOSI 5
Вообще это стандартный MOSI вывод на atmega16. А если я хочу использовать другой вывод, как модуль узнает через какой выход слать данные? Явно это нигде не задается.
RSS feed for comments to this post