用于MAX7456隨屏顯示器SPI
MAX7456串行接口
MAX7456單通道單色隨屏顯示(OSD)發(fā)生器預(yù)裝了256個(gè)字符和圖形,并可通過SPI接口在線編程。通過SPI兼容串行接口可以設(shè)置工作模式、顯示存儲(chǔ)器以及字符存儲(chǔ)器。狀態(tài)(STAT)寄存器、顯示存儲(chǔ)器數(shù)據(jù)輸出(DMDO)寄存器和字符存儲(chǔ)器數(shù)據(jù)輸出(CMDO)寄存器都可讀,可以對(duì)其進(jìn)行寫操作和讀操作。關(guān)于MAX7456寄存器及存儲(chǔ)器結(jié)構(gòu)的詳細(xì)信息請(qǐng)參考數(shù)據(jù)資料和應(yīng)用筆記4117,"使用MAX7456存儲(chǔ)器和評(píng)估板文件生成定制字符和圖形"。
MAX7456支持高達(dá)10MHz接口時(shí)鐘(SCLK)。圖1為寫數(shù)據(jù)時(shí)序,圖2是從器件讀數(shù)據(jù)的時(shí)序。
寫寄存器時(shí),拉低/CS可使能串行接口。在SCLK的上升沿從SDIN讀取數(shù)據(jù)。當(dāng)/CS變?yōu)楦唠娖綍r(shí),數(shù)據(jù)鎖存到輸入寄存器。如果傳輸過程中/CS變高,程序終止(即數(shù)據(jù)不寫入寄存器)。/CS變低之后,器件等待從SDIN讀入第一個(gè)字節(jié),以確定正在執(zhí)行的數(shù)據(jù)傳輸類型。
讀寄存器時(shí),如上文所述,拉低/CS。地址在SCLK的上升沿鎖入SDIN。然后數(shù)據(jù)在SCLK的下降沿從SDOUT輸出。
SPI命令長度為16位:最高8位(MSB)代表寄存器地址,最低8位(LSB)代表數(shù)據(jù)(圖1和2)。這種格式有兩個(gè)例外:
- 自動(dòng)遞增寫模式,用于訪問顯示存儲(chǔ)器,是一個(gè)8位操作(圖3)。寫數(shù)據(jù)前必須寫入起始地址。對(duì)顯示存儲(chǔ)器執(zhí)行自動(dòng)遞增寫命令時(shí),8位地址由內(nèi)部產(chǎn)生,串口只需8位數(shù)據(jù),如圖3所示。
- 從顯示存儲(chǔ)器讀字符數(shù)據(jù)時(shí),若處于16位工作模式,應(yīng)該是24位(8位地址+16位數(shù)據(jù))。
執(zhí)行讀操作時(shí),只需要8位地址,如圖2所示。
圖1. 寫操作
圖2. 讀操作
圖3. 自動(dòng)遞增寫操作
C程序
下文給出的C程序已針對(duì)MAXQ2000微控制器進(jìn)行了編譯,用于MAX7456評(píng)估(EV)板。本文給出了完整的程序例程。程序是自述文檔,幾乎沒有附加說明。C程序可從以下文件獲得:spi.c和MAX7456.h。
以下程序使用了SPI協(xié)議的標(biāo)準(zhǔn)定義,MAXQ2000處理器為SPI主機(jī),MAX7456是SPI從器件。
CS與MAX7456數(shù)據(jù)資料中的定義相同。
SDIN對(duì)應(yīng)于MOSI (主機(jī)出從器件入)。
SDOUT對(duì)應(yīng)于MOSI (主機(jī)入從器件出)。
SCLK對(duì)應(yīng)于CK。
前綴SPI_用于全部程序。
數(shù)據(jù)結(jié)構(gòu)
下文所示數(shù)據(jù)結(jié)構(gòu)可直接或逐位讀寫數(shù)據(jù),用于獨(dú)立訪問SPI端口。
/* Port 5 Output Register */__no_init volatile __io union{unsigned char PO5;struct{unsigned char bit0 : 1;unsigned char bit1 : 1;unsigned char bit2 : 1;unsigned char bit3 : 1;unsigned char bit4 : 1;unsigned char bit5 : 1;unsigned char bit6 : 1;unsigned char bit7 : 1;} PO5_bit;}
上述代碼將一個(gè)單字節(jié)賦值給PO5,這是微控制器輸出端口的地址。然后將另一個(gè)字節(jié)賦值給相同的可以逐位訪問的存儲(chǔ)器地址。
因此,可用以下命令直接對(duì)該端口進(jìn)行尋址:
PO5 = 0x10;
或用以下命令逐位讀寫:
PO5_bit.bit4 = 1;
如果該程序用于其它處理器,該結(jié)構(gòu)需要重新編寫。
如果采用不支持位字段寬度的老式C編譯器,可用位布爾運(yùn)算設(shè)置及清除位:
/* Portable bit-set and bit-clear macros. */#define BIT_SET(sfr,bitmask) sfr |= (bitmask)#define BIT_CLR(sfr,bitmask) sfr =~ (bitmask)#define BIT0 0x01#define BIT1 0x02#define BIT2 0x04#define BIT3 0x08#define BIT4 0x10#define BIT5 0x20#define BIT6 0x40#define BIT7 0x80example: BIT_SET(PO5,BIT0); BIT_CLR(PO5,BIT6);
宏
以下是一個(gè)簡單的編程技巧,使程序更容易移植:用宏定義控制器引腳排列,如下所示。
#define SPI_CS PO5_bit.bit4 // PO5_bit.bit4 = active-low CS—chip select#define SPI_MOSI PO5_bit.bit5 // PO5_bit.bit5 = MOSI—master out slave in,// data to MAX7456#define SPI_MISO PI5_bit.bit7 // PO5_bit.bit7 = MISO—master in slave out,// data from MAX7456#define SPI_CK PO5_bit.bit6 // PO5_bit.bit6 = SCK - SPI clock
用以上宏和數(shù)據(jù)結(jié)構(gòu)可以單獨(dú)置位及復(fù)位每個(gè)IO口,命令如下:
SPI_CS = 1;
改變宏時(shí)相應(yīng)引腳也將改變,將上述代碼用于其它設(shè)計(jì)時(shí),如果SPI口引腳排列不同,或?yàn)榱藢?shí)現(xiàn)更理想的PCB布局而對(duì)引腳進(jìn)行重新排列,上述程序非常有用。
單字節(jié)寫操作程序
單字節(jié)寫操作(圖1)程序如下所示。如果可以保證在程序入口處的/CS和CK線狀態(tài)正確,可以去掉前兩條命令。
程序首先發(fā)送地址,然后發(fā)送數(shù)據(jù)。進(jìn)行兩次循環(huán)。采用單循環(huán)及16位數(shù)據(jù)存儲(chǔ)可以簡化程序。在MAXQ2000微控制器中執(zhí)行16位“int”所占用的時(shí)間比執(zhí)行8位“char”長,因此需進(jìn)行權(quán)衡考慮。
/*************************************************************************************** spiWriteReg** Writes to an 8-bit register with the SPI port**************************************************************************************/void spiWriteReg(const unsigned char regAddr, const unsigned char regData){unsigned char SPICount; // Counter used to clock out the dataunsigned char SPIData; // Define a data structure for the SPI dataSPI_CS = 1; // Make sure we start with active-low CS highSPI_CK = 0; // and CK lowSPIData = regAddr; // Preload the data to be sent with AddressSPI_CS = 0; // Set active-low CS low to start the SPI cycle // Although SPIData could be implemented as an "int", // resulting in one// loop, the routines run faster when two loops // are implemented with// SPIData implemented as two "char"s.for (SPICount = 0; SPICount 8; SPICount++) // Prepare to clock out the Address byte{if (SPIData 0x80) // Check for a 1SPI_MOSI = 1; // and set the MOSI line appropriatelyelseSPI_MOSI = 0;SPI_CK = 1; // Toggle the clock lineSPI_CK = 0;SPIData = 1; // Rotate to get the next bit} // and loop back to send the next bit// Repeat for the Data byteSPIData = regData; // Preload the data to be sent with Datafor (SPICount = 0; SPICount 8; SPICount++){if (SPIData 0x80)SPI_MOSI = 1;elseSPI_MOSI = 0;SPI_CK = 1;SPI_CK = 0;SPIData = 1;} SPI_CS = 1;SPI_MOSI = 0;}
評(píng)論