剛剛寫的SPI驅(qū)動,想移植到LINUX上面用來讀寫SD卡
只測試了發(fā)送,沒有測試接收.
spi.c
/*************************************************************************************************************
* 文件名: spi.c
* 功能: S3C6410 SPI底層驅(qū)動函數(shù)
* 作者: 陳鵬
* 創(chuàng)建時間: 2012年9月8日20:35
* 最后修改時間:2012年9月8日
* 詳細: SPI始化,發(fā)送,接收,配置等
* 使用的是手動控制片選,因為在實際使用過程中手動控制片選較為靈活,但是也有個問題,就是何時取消片選,應(yīng)為數(shù)據(jù)寫入到發(fā)送FIFO并
* 不代表數(shù)據(jù)已經(jīng)發(fā)送完成了,如果在數(shù)據(jù)沒有發(fā)送完成之前取消了片選會導(dǎo)致數(shù)據(jù)傳輸錯誤,因此簡單的方法就是在發(fā)送數(shù)據(jù)后加入一定
* 的延時,讓數(shù)據(jù)發(fā)送完成后取消片選
*************************************************************************************************************/
#include "system.h"
#include "spi.h"
#include "delay.h"
//SPI通道數(shù)量
#define SPI_CH_N 2
//SPI外設(shè)結(jié)構(gòu)
const SPI_TypeDef *SPI_CH[SPI_CH_N] = {SPI0,SPI1};
//默認(rèn)模式1
//主設(shè)備模式,空閑時鐘低電平,第一個時鐘邊沿有效(上升沿有效),使能發(fā)送接收,數(shù)據(jù)寬度8bit,關(guān)閉DMA,使能手動控制片選
const SPI_Config_TypeDef SPI_DEFAULT_01 = {0,0,0,1,1,8,0,0,0,0};
/*************************************************************************************************************************
*函數(shù) : void SPI_SetSpeed(u8 ch,u8 Speed)
*功能 : 設(shè)置SPI速度
*參數(shù) : CH:SPI通道選擇;Speed:SPI速度設(shè)置
*返回 : 無
*依賴 : 底層宏定義
*作者 : cp1300@139.com
*時間 : 20121005
*最后修改時間: 20121005
*說明 : 修改的時候注意SPI應(yīng)該處于空閑或者無效狀態(tài),使用的時鐘是PCLK
* SPI 時鐘輸出 = 時鐘源 / ( 2 ×(預(yù)分頻值 +1))
*************************************************************************************************************************/
void SPI_SetSpeed(u8 ch,u8 Speed)
{
SPI_TypeDef *SPI;
if(ch >= SPI_CH_N)
return; //通道號超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對應(yīng)通道寄存器結(jié)構(gòu)指針
SPI->CLKCFG = 0; //清空設(shè)置并關(guān)閉時鐘
SPI->CLKCFG = Speed;//設(shè)置預(yù)分頻值
SPI->CLKCFG |= BIT8;//使能時鐘
}
/*************************************************************************************************************************
*函數(shù) : u8 SPI_Init(u8 ch,SPI_Config_TypeDef *config,u8 Speed)
*功能 : SPI初始化
*參數(shù) : CH:SPI通道選擇;config:配置結(jié)構(gòu)指針;Speed:SPI速度設(shè)置
*返回 : 0:初始化成功;1:初始化失敗
*依賴 : 底層宏定義
*作者 : cp1300@139.com
*時間 : 20121005
*最后修改時間: 20121005
*說明 : 無
*************************************************************************************************************************/
u8 SPI_Init(u8 ch,const SPI_Config_TypeDef *config,u8 Speed)
{
u32 chcfg = 0;
u32 modcfg = 0;
u32 slavecfg = 0;
SPI_TypeDef *SPI;
if(ch >= SPI_CH_N)
return 1; //通道號超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對應(yīng)通道寄存器結(jié)構(gòu)指針
SPI->CHCFG |= BIT5; //SPI軟復(fù)位
Delay_US(10); //適當(dāng)延時
switch(ch)
{
case 0: //通道0
{
Set_GateClk(PCLK_SPI0,ENABLE); //使能SPI0門控時鐘
rGPCCON &= ~0xfff;
rGPCCON |= 0x222; //初始化SPI0 MISO CLK MOSI 相關(guān)IO
}break;
case 1: //通道1
{
Set_GateClk(PCLK_SPI1,ENABLE); //使能SPI1門控時鐘
rGPCCON &= ~(0xfff << 16);
rGPCCON |= (0x222 << 16); //初始化SPI1 MISO CLK MOSI 相關(guān)IO
}break;
default:break;
}
SPI->CLKCFG &= ~BIT8; //關(guān)閉SPI時鐘
SPI->CHCFG = 0; //清除設(shè)置并關(guān)閉SPI發(fā)送接收通道
if(config->EnSlave) //使能從設(shè)備模式
{
chcfg |= BIT4;
}
if(config->EnCPOH) //使能空閑時鐘高電平
{
chcfg |= BIT3;
}
if(config->EnCPHB) //使能第二個時鐘邊沿有效
{
chcfg |= BIT2;
}
if(config->EnRx) //使能接收
{
chcfg |= BIT1;
}
if(config->EnTx) //使能發(fā)送
{
chcfg |= BIT0;
}
switch(config->SetTranSize)//設(shè)置傳輸數(shù)據(jù)位寬
{
case 16: modcfg |= (1 << 29);modcfg |= (1 << 17);break; //半字
case 32: modcfg |= (2 << 29);modcfg |= (2 << 17);break; //字
default : break; //字節(jié)
}
if(config->EnRxDMA) //使能接收DMA
{
modcfg |= BIT2;
}
if(config->EnTxDMA) //使能發(fā)送DMA
{
modcfg |= BIT1;
}
if(config->EnDMA4Burst) //設(shè)置DMA傳輸類型為4個脈沖
{
modcfg |= BIT0;
}
if(config->EnAutoCS) //使能自動片選
{
slavecfg |= BIT1;
switch(ch)
{
case 0: //通道0
{
rGPCCON &= ~0xf000;
rGPCCON |= 0x2000; //初始化CS 相關(guān)IO
}break;
case 1: //通道1
{
rGPCCON &= ~(0xf0000000);
rGPCCON |= (0x2000 << 16); //初始化CS 相關(guān)IO
}break;
default:break;
}
}
//寫入配置數(shù)據(jù)
SPI->CHCFG = chcfg;
SPI->MODECFG = modcfg;
SPI->SLAVE = slavecfg;
SPI->CLKCFG |= BIT8; //使能SPI時鐘
SPI_SetSpeed(ch,Speed); //設(shè)置SPI速度
SPIx_ReadWriteData(ch,0xaa); //啟動第一次傳輸
return 0;
}
/*************************************************************************************************************************
*函數(shù) : u32 SPIx_ReadWriteData(u8 ch,u32 TxData)
*功能 : SPI發(fā)送接收數(shù)據(jù)
*參數(shù) : CH:SPI通道選擇;TxData:要發(fā)送的數(shù)據(jù)
*返回 : 收到的數(shù)據(jù)
*依賴 : 底層宏定義
*作者 : cp1300@139.com
*時間 : 20121005
*最后修改時間: 20121005
*說明 : 發(fā)送和接收的數(shù)據(jù)寬度要看配置,可以是8bit,16bit,32bit
* 發(fā)送完成后要加延時,因為數(shù)據(jù)寫入到FIFO后并沒有馬上發(fā)送完,當(dāng)發(fā)送完成之前片選可能就已經(jīng)取消了,因此需要適當(dāng)?shù)奶砑友訒r
* 因為我們無法判斷數(shù)據(jù)是否已經(jīng)從移位寄存器中發(fā)送完畢,只能檢測FIFO
*************************************************************************************************************************/
u32 SPIx_ReadWriteData(u8 ch,u32 TxData)
{
u16 retry = 0;
SPI_TypeDef *SPI;
u8 temp;
if(ch >= SPI_CH_N)
return 1; //通道號超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對應(yīng)通道寄存器結(jié)構(gòu)指針
do
{
temp = (SPI->STATUS >> 6) & 0x7f; //獲取發(fā)送FIFO數(shù)據(jù)數(shù)量
retry ++;
if(retry > 8000)
return 0;
}
while(temp > 63); //發(fā)送FIFO滿了,等待
SPI->TXDATA = TxData; //發(fā)送數(shù)據(jù)
retry = 0;
do
{
temp = (SPI->STATUS >> 13) & 0x7f; //獲取接收FIFO數(shù)據(jù)數(shù)量
retry ++;
if(retry > 8000)
return 0;
}
while(temp == 0); //接收FIFO為空,等待
return SPI->RXDATA; //返回受到的數(shù)據(jù)
}
spi.h
/*************************************************************************************************************
* 文件名: spi.h
* 功能: S3C6410 SPI底層驅(qū)動函數(shù)
* 作者: 陳鵬
* 創(chuàng)建時間: 2012年9月8日20:35
* 最后修改時間:2012年9月8日
* 詳細: SPI始化,發(fā)送,接收,配置等
*************************************************************************************************************/
#ifndef SPI_H_
#define SPI_H_
#include "system.h"
//SPI配置結(jié)構(gòu)定義
typedef struct
{
u8 EnSlave; //使能SPI從設(shè)備模式
u8 EnCPOH; //使能空閑時鐘高電平
u8 EnCPHB; //使能時鐘第二個邊沿有效,否則為第一個邊沿有效
u8 EnRx; //使能接收
u8 EnTx; //使能發(fā)送
u8 SetTranSize; //設(shè)置傳輸數(shù)據(jù)寬度,8bit,16bit,32bit;
u8 EnRxDMA; //使能接收DMA
u8 EnTxDMA; //使能發(fā)送DMA
u8 EnDMA4Burst; //設(shè)置DMA傳輸類型為4個脈沖
u8 EnAutoCS; //使能自動片選
}SPI_Config_TypeDef;
//默認(rèn)模式1
//主設(shè)備模式,空閑時鐘低電平,第一個時鐘邊沿有效(上升沿有效),使能發(fā)送接收,數(shù)據(jù)寬度8bit,關(guān)閉DMA,使能手動控制片選
extern const SPI_Config_TypeDef SPI_DEFAULT_01;
void SPI_SetSpeed(u8 ch,u8 Speed);
u8 SPI_Init(u8 ch,const SPI_Config_TypeDef *config,u8 Speed);
u32 SPIx_ReadWriteData(u8 ch,u32 TxData);
#endif /*SPI_H_*/
main.c
測試
#include "system.h"
#include "uart.h"
#include "tft_lcd.h"
#include "other.h"
#include "delay.h"
#include "timer.h"
#include "spi.h"
//LED1閃爍程序,在定時器0中斷服務(wù)程序中閃爍,周期400MS
void LED1_flash(void)
{
LED1_FLASH();
}
int main(void)
{
u8 i = 0;
LCD_Init(); //初始化LCD
UART0_Init(DISABLE,115200); //初始化串口,失能中斷接收,波特率115200
LED_Init(); //初始化LED
rGPCCON |= 1 << 12;
rGPCDAT |= BIT3;
Timer1_Init(400000-1,ENABLE,LED1_flash); //初始化定時器0,周期400ms
lcd_printf("Get_FCLK : %d Hzn",Get_FCLK());
lcd_printf("Get_PCLK : %d Hzn",Get_PCLK());
SPI_Init(0,&SPI_DEFAULT_01,100);
while(1)
{
LED2_FLASH(); //LED2閃爍
//Delay_US(600000);
rGPCDAT &= ~BIT3;
SPIx_ReadWriteData(0,i++);
Delay_US(1); //適當(dāng)添加延時
rGPCDAT |= BIT3;
Delay_US(6);
}
}
測試了一下硬件控制片選,發(fā)現(xiàn)片選信號非常完美
上圖
補充SPI寄存器結(jié)構(gòu)
//SPI
typedef struct
{
vu32 CHCFG; //配置寄存器
vu32 CLKCFG; //時鐘配置寄存器
vu32 MODECFG; //FIFO控制寄存器
vu32 SLAVE; //從屬器選擇寄存器
vu32 INTEN; //中斷啟動寄存器
vu32 STATUS; //狀態(tài)寄存器
vu32 TXDATA; //發(fā)送數(shù)據(jù)寄存器
vu32 RXDATA; //接收數(shù)據(jù)寄存器
vu32 CNT; //計數(shù),主控器收到多少數(shù)據(jù)
vu32 CLR; //狀態(tài)清除
vu32 SWAPCFG ; //交換配置寄存器
vu32 FBCLK; //反饋時鐘選擇寄存器
}SPI_TypeDef;
//SPI
#define SPI0_BASE 0x7f00b000
#define SPI1_BASE 0x7f00c000
//SPI0
#define SPI0 ((SPI_TypeDef*)SPI0_BASE)
//SPI1
#define SPI1 ((SPI_TypeDef*)SPI1_BASE)