摘 要:本文結合具體的FPGA與ARM接口電路介紹了SPI接口驅動程序設計,并給出了部分程序的核心代碼。本驅動編寫的思路嚴格按照Linux下字符設備驅動程序的要求,并重點介紹了中斷掛載及內存映射等關鍵技術,對其他SPI外設的驅動程序設計有較強的參考意義。
關鍵詞:linux;SPI;驅動
中圖分類號:TP336
在某項目的單板設計中,集成了Altera公司的STRATIX II EP2S180 FPGA和三星公司的S3C2440A ARM9處理器,F(xiàn)PGA用于處理原始數(shù)據(jù),ARM用于配置FPGA參數(shù)并接收FPGA處理后數(shù)據(jù),之間采用SPI串行接口通信。
SPI接口驅動基于Linux系統(tǒng)開發(fā),Linux內核中雖已集成了SPI驅動,但接口復雜且冗長,不適宜本項目采用,因此重新設計了SPI驅動。
1 接口電路設計
ARM工作在SPI主模式,F(xiàn)PGA工作在SPI從模式,F(xiàn)PGA與ARM間接口電路如圖1所示。
圖1 接口電路
ARM使用SPI0控制器,EINT13作為中斷輸入,GPG6用于復位FPGA中斷。
ARM通過SPIMOSI0接口對FPGA進行參數(shù)配置,而后啟動FPGA進行數(shù)據(jù)處理。FPGA處理完數(shù)據(jù)后通過EINT13對ARM發(fā)送上升沿中斷,觸發(fā)ARM讀取FPGA數(shù)據(jù)。ARM讀取完畢后,通過INT_ACK信號線發(fā)上升沿信號對FPGA進行中斷清除。
2 SPI驅動程序設計
SPI為串行接口,其驅動在Linux中沿用字符設備驅動格式,字符設備驅動接口函數(shù)數(shù)據(jù)結構如下:
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = s3c24xx_SPI_open,
.release = s3c24xx_SPI_close,
.read = s3c24xx_SPI_read,
};
驅動程序需要實現(xiàn)s3c24xx_SPI_open、s3c24xx_SPI_close、s3c24xx_SPI_read等幾個關鍵函數(shù)。
s3c24xx_SPI_open函數(shù)用于初始化SPI控制器并對FPGA發(fā)送初始化配置參數(shù)并掛載中斷處理函數(shù)。
s3c24xx_SPI_close函數(shù)用于關閉FPGA設備。
s3c24xx_SPI_read用于讀取FPGA數(shù)據(jù),該函數(shù)通過調用wait_event_interruptible工作在阻塞模式,由中斷處理函數(shù)負責喚醒 。
中斷描述結構如下:
struct spi_irq_desc {
int irq;
int pin;
int pin_setting;
int number;
char *name;
};
static struct spi_irq_desc spi_irqs [] = {
{IRQ_EINT13, S3C2410_GPG(5),S3C2410_GPG5_EINT13,2,“SPIINT”},
};
在s3c24xx_SPI_open函數(shù)中掛載中斷處理函數(shù)spi_interrupt,具體如下:
request_irq(spi_irqs[i].irq, spi_interrupt, IRQ_TYPE_EDGE_RISING,
spi_irqs[i].name,(void *)spi_irqs[i]);
request_irq將EINT13的處理函數(shù)設定為spi_interrupt,需要重點注意的是操作系統(tǒng)自動將EINT13引腳配置為中斷模式,并設置為上升沿觸發(fā),無需用戶再進行GPIO配置。
在中斷處理函數(shù)中,涉及到對SPI的發(fā)送寄存器和接收寄存器的讀寫操作。在Linux環(huán)境中,由于采用了MMU及虛擬內存設計,無法直接讀寫外部寄存器,需將其映射到內存空間,而后采用iowrite32完成讀寫。
以對SPICON0寄存器寫入0x18示例如下,該寄存器地址為0x59000000:
spicon0_phys = 0x59000000;
spi0_virt =(unsigned long)ioremap(spi0_phys, 0x20);
va_s3c2440_SPI_SPCON0 = (unsigned long *)(spi0_virt + 0x00);
iowrite32(0x18,va_s3c2440_SPI_SPCON0);
在spi_interrupt函數(shù)中實現(xiàn)SPI接口讀取,spi字長為8位,spi的接口配置為時鐘上升沿發(fā)送,下降沿讀取。
因此為讀取FPGA需要對發(fā)送寄存器SPTDAT0先寫一個字節(jié),而后判斷狀態(tài)寄存器SPSTA0是否完成發(fā)送,如果完成則讀取接收寄存器SPRDAT0,從FPGA讀取一個字節(jié),以后循環(huán)讀取定長字節(jié),即可完成對FPGA數(shù)據(jù)的讀取。
而后對GPG6依次寫0、1、0,之間加入1us延時,即可產生上升沿中斷以復位FPGA中斷。
對FPGA的讀定長數(shù)據(jù)操作示例如下:
int s3c2440SPIRead(char* buffer, int nbyte)
{
char* pChar = buffer;
int ix = nbyte;
for(; nbyte > 0; nbyte--)
{
*(volatile char*)va_s3c2440_SPI_SPTDAT0=0x55;
/*等待傳輸完成*/
while(!(*((volatile char*)va_s3c2440_SPI_SPSTA0) 0x1));
*pChar=*(volatile char*)(va_s3c2440_SPI_SPRDAT0);
pChar++;
}
return(ix);
}
為避免編譯器將va_s3c2440_SPI_SPTDAT0地址列入CACHE空間,必須對va_s3c2440_SPI_SPTDAT0進行volatile char*強制類型轉換,否則將讀到過期數(shù)據(jù)。
中斷處理函數(shù)完成讀數(shù)據(jù)后調用wake_up_interruptible(spi_waitq)喚醒阻塞的讀操作s3c24xx_SPI_read,該函數(shù)調用copy_to_user函數(shù)將數(shù)據(jù)復制到用戶空間。
3 結束語
該接口程序已成功應用于某工程項目,本文是基于調試經驗,重點介紹了SPI接口程序框架及內存映射和中斷掛載等關鍵技術,可以作為開發(fā)類似驅動的參考。
參考文獻:
[1]韋東山.嵌入式Linux應用開發(fā)[M].北京:人民郵電出版社,2010.
作者單位:中國船舶重工集團公司第七二二研究所,武漢 430079