123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- Аппаратный вариант
- Для работы с аппаратным SPI его нужно сначала, естественно,
- инициализировать. Посмотрим, как это будет выглядеть для ATmega8535 (а
- также для многих других МК того же класса, например, ATmega8515, ATmega16 и
- пр., у которых выводы аппаратного SPI совпадают с интерфейсом
- SPI-программирования и занимают старшие 4 бита порта В). Заодно
- инициализируем и вывод для управления "выбором кристалла" — в большинстве
- случаев он в интерфейсе SPI играет важную роль (например, микросхемы
- памяти, которые мы рассмотрим далее, высокий уровень на этом выводе, кроме
- всего прочего, устанавливает в состояние с низким потреблением). Часто для
- этого выбирают вывод /SS, который в режиме "мастера" не задействован (не
- забудем, что его нужно сконфигурировать на выход!), но мы для разнообразия
- выберем вывод РВО — часто требуется управлять несколькими устройствами,
- одного вывода /SS тогда все равно недостаточно, и младшие биты порта В,
- идущие подряд, оказываются более удобными (листинг 11.1).
- [ Листинг 11.1 ]
- .equ CS = РВ0
- .equ MOSI = PB5
- .equ MISO = РВ6
- .equ SCK = PB7 ;разряды порта В, используемые интерфейсом SPL.
- Листинг 11.2 иллюстрирует инициализацию в режиме 0 ("мастер", DORD = 0 —
- старший бит первым, SPR1 и SPR0 = 0 — скорость fрез/4).
- [ Листинг 11.2 ]
- ldi temp,(1<<SPE)+(1<<MSTR)
- out SPCR,temp
- ldi temp,(l<<SCK)+(1<<MOSI)+(1<<CS)+(1<<PB4)
- out DDRB,temp ;SCK,MOSI,CS, SS - выходы
- sbi PORTB,CS ;сразу устанавливаем в 1
- Листинг 11.3 иллюстрирует инициализацию в режиме 3 ("мастер", DORD = 0 —
- старший бит первым, SPR1 и SPR0 = 0 — скорость fрез/4).
- [ Листинг 11.3 ]
- ldi temp, (1«SPE) + (1«MSTR) + (1«CP0L) + (1«CPHA)
- out SPCR,temp
- ldi temp, (1«SCK) + (1«M0SI) + (1«CS) + (1«PB4)
- >out DDRB,temp ;SCK,MOSI,CS, SS - выходы
- ser temp ;0xFF
- out PORTB,temp ;PB7..0 — высокий уровень, весь порт В
- Процедура записи-чтения тогда будет выглядеть очень просто (листинг 11.4).
- [ Листинг 11.4 ]
- WR_spi: ;запись-чтение SPI, в temp данные на входе и на выходе
- out SPDR,temp ; начать передачу
- wait_spi:
- sbis SPSR,SPIF ; ожидаем конца передачи
- rjmp wait_spi
- in temp,SPDR ; чтение данных
- ret
- При работе с большинством устройств через SPI, к сожалению, этой простой
- процедурой дело не ограничивается — чаще всего требуется, по крайней мере,
- вовремя правильно установить "выбор кристалла", причем иногда (если
- интерфейс у ведомого устройства недостаточно скоростной) с формированием
- искусственных задержек и прочими сложностями, сильно загромождающими
- программу.
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Программный вариант
- Программный вариант процедур чтения-записи более громоздок, но зато
- позволяет задействовать любые удобные выводы портов МК (в том числе и
- таких, которые вообще аппаратного SPI не имеют) и не требует особой
- инициализации, кроме формирования направления работы соответствующих
- выводов. Листинг 11.5 иллюстрирует, как будет выглядеть чтение-запись в
- варианте, соответствующем режиму 0.
- [ Листинг 11,5 ]
- .equ CS = 0 ; выводы PortB
- .equ MOSI = 1
- .equ MISO = 2
- .equ SCK = 3
- ...
- ; инициализация SPI
- ; установка MOSI, SCK, CS на выход
- ldi temp,(1<<CS)|(1<<MOSI)|(1<<SCK)
- out DDRB,temp
- cbi PORTB,SCK
- cbi PORTB,MOSI
- sbi PORTB,CS
- ...
- ;чтение-запись
- RW_spi: ;запись/чтение через SPI. посылаемый байт в data_out,
- ; принимаемый в data_in
- cli ; на случай, если в программе есть длинные
- ; прерывания, иначе можно удалить
- ldi temp,8 ; счетчик бит
- clr data_in
- spi_Loop:
- lsl data_out ;старший бит в перенос
- brcc put_0 ; если в переносе 0 — перейти
- sbi PORTB,mosi
- nop ; задержка на один такт
- rjmp r_bit
- put_0:
- cbi PORTB,mosi
- nop ; задержка на один такт
- r_bit:
- sbi PORTB,sck ; выдали строб и подождали
- nop ; задержка на один такт
- sbic PINB,miso ; читаем бит с miso
- rjmp r1_bit
- clc ; если 0 — сбросим перенос
- rjmp rend_bit
- r1_bit:
- sec ; если 1 — установим перенос
- rend_bit:
- rol data_in ; перенос во входной байт
- cbi PORTB,sck ; выдали строб и подождали
- nop
- dec temp
- brne spi_loop
- sei ; если команды cli нет, то тоже можно удалить
- ret
- При тактовой частоте МК 4 МГц такая процедура обеспечит скорость передачи
- порядка 0,5 МГц. Пустые операции (пор) нужны, чтобы сформировать задержку
- (-250 не при 4 МГц) между формированием данных на линиях MISO и MOSI и
- моментом их чтения (перепадом на SCK). Если быстродействие ведомого
- позволяет, то эти операции можно убрать.
|