Ch ươ ng trình:
5.3.9 Giao tiếp SP
Giao diện ngoại vi nối tiếp SPI (Serial Peripheral Interface) là một giao tiếp nối tiếp song công. Nó có thể có nhiều master và slave cùng được kết nối trên một bus xác định. Chỉ một master và một slave có thể truyền dữ liệu tại mỗi thời điểm. Trong suốt quá trình truyền dữ liệu master luôn luôn gửi từ 8 đến 16 bít dữ liệu tới slave và slave luôn gửi một byte dữ liệu tới master.
Cả SPI và I2C đều hỗ trợ tốt cho các ngoại vi tốc độ chậm được truy cập không liên tục như EEPROM và Real-Time Clock nhưng SPI có tốc độ dữ liệu cao hơn I2C, thường lên tới hàng chục Mbps, phù hợp cho các ứng dụng truyền dữ liệu theo luồng. Nó còn hiệu quả hơn nhờ giao diện song công đầy đủ , sử dụng trong các ứng dụng giữa 1 bộ codec và 1 bộ xử lý tín hiệu số.
Cũng như trong I2C, master khởi tạo quá trình trao đổi dữ liệu. Khi master tạo ra clock và chọn thiết bị slave, dữ liệu có thểđược truyền theo 2 hướng đồng thời. Thực tế thì dữ liệu được truyền theo cả hai hướng, nên master và slave phải biết khi nào byte nhận có ý nghĩa hay không. Nên thiết bị phải vứt bỏ byte nhận được khi nó đang truyền và tạo ra 1 byte giảđể truyền khi nó đang nhận.
Hình 5-25. Cấu hình 1 master nhiều slave
Giao tiếp SPI gồm 4 đường tín hiệu : clock (SCLK), dữ liệu ra từ master vào slave MOSI (Master Out Slave In), dữ liệu vào master từ slave MISO (Master In Slave Out), và tín hiệu chọn slave SS (Slave Select).
Khi giao tiếp sử dụng SPI cần để ý cặp thông số cực clock CPOL (Clock Polarity) và phase clock CPHA (Clock Phase), cặp thông số này được dùng để xác định sườn của tín hiệu clock mà dữ liệu được lái và lấy mẫu. Mỗi thông số có 2 trạng thái mức cao – mức thấp nên tổng hợp lại có 4 tổ hợp có thể mà mỗi tổ hợp đều không tương thích với các tổ hợp còn lại. Nên cặp giao tiếp master/slave phải sử dụng đúng cặp thông sốđể giao tiếp.
Các tổ hợp CPOL và CPHA xác định:
- Khi nào bít dữ liệu đầu tiên được thiết lập - Khi nào các bít dữ liệu khác được thiết lập - Khi nào dữ liệu được lấy mẫu
Mối quan hệ này được biểu diễn ở bảng dưới Tổ hợp CPOL và
CPHA
Bit đầu tiên được thiết lập
Các bít khác được thiết lập
Dữ liệu được lấy mẫu
CPOL = 0, CPHA =0 Trước sườn dương SCK đầu tiên
Sườn âm SCK Sườn dương SCK CPOL = 0, CPHA =1 Sườn dương SCK
đầu tiên Sườn dương SCK Sườn âm SCK CPOL = 1, CPHA =0 Trước sườn âm SCK
đầu tiên
Sườn dương SCK Sườn âm SCK CPOL = 1, CPHA =1 Sườn âm SCK đầu
tiên
Sườn âm SCK Sườn dương SCK
Mô tả các thanh ghi SPI:
Register Mô tả Kiểu truy cập S0SPCR SPI Control Register : thanh ghi điều khiển
hoạt động SPI R/W
thông báo các trạng thái của SPI
S0SPDR SPI Data Register : đây là thanh ghi 2 chiều cung cấp dữ liệu truyền và nhận cho SPI. Dữ liệu truyền được cung cấp tới SPI0 được ghi vào thanh ghi này còn dữ liệu nhận được bởi SPI0 có thểđọc từ thanh ghi này
R/W
S0SPCCR SPI Clock Counter Register : thanh ghi điều
khiển tần số của master SCK0 R/W S0SPINT SPI Interrupt Flag : chứa cờ ngắt cho giao
diện SPI R/W
Ví dụ sau gồm các hàm cơ bản cho phép thực hiện truyền và nhận dữ liệu trên SPI. Các hàm này có thể sử dụng như là thư viện cho các ứng dụng lớn hơn.
#include "LPC23xx.h" void SPIInit( void ) { PCONP |= (1 << 8); S0SPCR = 0x00; /* enable ports */ PINSEL0 |= 0xC0000000; PINSEL1 |= 0x0000003C; IODIR0 = 1 << 16; IOSET0 = 1 << 16; /* Setting SPI0 clock*/ S0SPCCR = 0x8;
S0SPCR = 0x00000020; }
/* Send a block of data to the SPI port, the first */ void SPISend( unsigned char *buf, int Length )
{
int i;
unsigned char Dummy; if ( Length == 0 ) return;
for ( i = 0; i < Length; i++ ) {
S0SPDR = *buf;
while ( !(S0SPSR & SPIF) );
Dummy = S0SPDR; /* Flush the RxFIFO */ buf++;
}
return; }
/*the module will receive a block of data from SPI*/ void SPIReceive( BYTE *buf, int Length )
{
for ( i = 0; i < Length; i++ ) { *buf = SPIReceiveByte(); buf++; } return; }
/*Receive one byte of data from the SPI port*/ unsigned char SPIReceiveByte( void )
{
unsigned char data;
/* wrtie dummy unsigned char out to generate clock, then read data from MISO */
S0SPDR = 0xFF;
/* Wait for transfer complete, SPIF bit set */ while ( !(S0SPSR & SPIF) );
data = S0SPDR; return ( data ); }