S3C6410 SPI 裸機(jī)驅(qū)動(dòng)
剛剛寫(xiě)的SPI驅(qū)動(dòng),想移植到LINUX上面用來(lái)讀寫(xiě)SD卡
只測(cè)試了發(fā)送,沒(méi)有測(cè)試接收.
spi.c
/*************************************************************************************************************
* 文件名: spi.c
* 功能: S3C6410 SPI底層驅(qū)動(dòng)函數(shù)
* 作者: 陳鵬
* 創(chuàng)建時(shí)間: 2012年9月8日20:35
* 最后修改時(shí)間:2012年9月8日
* 詳細(xì): SPI始化,發(fā)送,接收,配置等
* 使用的是手動(dòng)控制片選,因?yàn)樵趯?shí)際使用過(guò)程中手動(dòng)控制片選較為靈活,但是也有個(gè)問(wèn)題,就是何時(shí)取消片選,應(yīng)為數(shù)據(jù)寫(xiě)入到發(fā)送FIFO并
* 不代表數(shù)據(jù)已經(jīng)發(fā)送完成了,如果在數(shù)據(jù)沒(méi)有發(fā)送完成之前取消了片選會(huì)導(dǎo)致數(shù)據(jù)傳輸錯(cuò)誤,因此簡(jiǎn)單的方法就是在發(fā)送數(shù)據(jù)后加入一定
* 的延時(shí),讓數(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è)備模式,空閑時(shí)鐘低電平,第一個(gè)時(shí)鐘邊沿有效(上升沿有效),使能發(fā)送接收,數(shù)據(jù)寬度8bit,關(guān)閉DMA,使能手動(dòng)控制片選
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è)置
*返回 : 無(wú)
*依賴 : 底層宏定義
*作者 : cp1300@139.com
*時(shí)間 : 20121005
*最后修改時(shí)間: 20121005
*說(shuō)明 : 修改的時(shí)候注意SPI應(yīng)該處于空閑或者無(wú)效狀態(tài),使用的時(shí)鐘是PCLK
* SPI 時(shí)鐘輸出 = 時(shí)鐘源 / ( 2 ×(預(yù)分頻值 +1))
*************************************************************************************************************************/
void SPI_SetSpeed(u8 ch,u8 Speed)
{
SPI_TypeDef *SPI;
if(ch >= SPI_CH_N)
return; //通道號(hào)超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對(duì)應(yīng)通道寄存器結(jié)構(gòu)指針
SPI->CLKCFG = 0; //清空設(shè)置并關(guān)閉時(shí)鐘
SPI->CLKCFG = Speed;//設(shè)置預(yù)分頻值
SPI->CLKCFG |= BIT8;//使能時(shí)鐘
}
/*************************************************************************************************************************
*函數(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
*時(shí)間 : 20121005
*最后修改時(shí)間: 20121005
*說(shuō)明 : 無(wú)
*************************************************************************************************************************/
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; //通道號(hào)超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對(duì)應(yīng)通道寄存器結(jié)構(gòu)指針
SPI->CHCFG |= BIT5; //SPI軟復(fù)位
Delay_US(10); //適當(dāng)延時(shí)
switch(ch)
{
case 0: //通道0
{
Set_GateClk(PCLK_SPI0,ENABLE); //使能SPI0門(mén)控時(shí)鐘
rGPCCON &= ~0xfff;
rGPCCON |= 0x222; //初始化SPI0 MISO CLK MOSI 相關(guān)IO
}break;
case 1: //通道1
{
Set_GateClk(PCLK_SPI1,ENABLE); //使能SPI1門(mén)控時(shí)鐘
rGPCCON &= ~(0xfff << 16);
rGPCCON |= (0x222 << 16); //初始化SPI1 MISO CLK MOSI 相關(guān)IO
}break;
default:break;
}
SPI->CLKCFG &= ~BIT8; //關(guān)閉SPI時(shí)鐘
SPI->CHCFG = 0; //清除設(shè)置并關(guān)閉SPI發(fā)送接收通道
if(config->EnSlave) //使能從設(shè)備模式
{
chcfg |= BIT4;
}
if(config->EnCPOH) //使能空閑時(shí)鐘高電平
{
chcfg |= BIT3;
}
if(config->EnCPHB) //使能第二個(gè)時(shí)鐘邊沿有效
{
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個(gè)脈沖
{
modcfg |= BIT0;
}
if(config->EnAutoCS) //使能自動(dòng)片選
{
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;
}
}
//寫(xiě)入配置數(shù)據(jù)
SPI->CHCFG = chcfg;
SPI->MODECFG = modcfg;
SPI->SLAVE = slavecfg;
SPI->CLKCFG |= BIT8; //使能SPI時(shí)鐘
SPI_SetSpeed(ch,Speed); //設(shè)置SPI速度
SPIx_ReadWriteData(ch,0xaa); //啟動(dòng)第一次傳輸
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
*時(shí)間 : 20121005
*最后修改時(shí)間: 20121005
*說(shuō)明 : 發(fā)送和接收的數(shù)據(jù)寬度要看配置,可以是8bit,16bit,32bit
* 發(fā)送完成后要加延時(shí),因?yàn)閿?shù)據(jù)寫(xiě)入到FIFO后并沒(méi)有馬上發(fā)送完,當(dāng)發(fā)送完成之前片選可能就已經(jīng)取消了,因此需要適當(dāng)?shù)奶砑友訒r(shí)
* 因?yàn)槲覀儫o(wú)法判斷數(shù)據(jù)是否已經(jīng)從移位寄存器中發(fā)送完畢,只能檢測(cè)FIFO
*************************************************************************************************************************/
u32 SPIx_ReadWriteData(u8 ch,u32 TxData)
{
u16 retry = 0;
SPI_TypeDef *SPI;
u8 temp;
if(ch >= SPI_CH_N)
return 1; //通道號(hào)超出范圍
SPI = (SPI_TypeDef *)SPI_CH[ch]; //獲取對(duì)應(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ū)動(dòng)函數(shù)
* 作者: 陳鵬
* 創(chuàng)建時(shí)間: 2012年9月8日20:35
* 最后修改時(shí)間:2012年9月8日
* 詳細(xì): SPI始化,發(fā)送,接收,配置等
*************************************************************************************************************/
#ifndef SPI_H_
#define SPI_H_
#include "system.h"
//SPI配置結(jié)構(gòu)定義
typedef struct
{
u8 EnSlave; //使能SPI從設(shè)備模式
u8 EnCPOH; //使能空閑時(shí)鐘高電平
u8 EnCPHB; //使能時(shí)鐘第二個(gè)邊沿有效,否則為第一個(gè)邊沿有效
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個(gè)脈沖
u8 EnAutoCS; //使能自動(dòng)片選
}SPI_Config_TypeDef;
//默認(rèn)模式1
//主設(shè)備模式,空閑時(shí)鐘低電平,第一個(gè)時(shí)鐘邊沿有效(上升沿有效),使能發(fā)送接收,數(shù)據(jù)寬度8bit,關(guān)閉DMA,使能手動(dòng)控制片選
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
測(cè)試
#include "system.h"
#include "uart.h"
#include "tft_lcd.h"
#include "other.h"
#include "delay.h"
#include "timer.h"
#include "spi.h"
//LED1閃爍程序,在定時(shí)器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); //初始化定時(shí)器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)添加延時(shí)
rGPCDAT |= BIT3;
Delay_US(6);
}
}
測(cè)試了一下硬件控制片選,發(fā)現(xiàn)片選信號(hào)非常完美
上圖
補(bǔ)充SPI寄存器結(jié)構(gòu)
//SPI
typedef struct
{
vu32 CHCFG; //配置寄存器
vu32 CLKCFG; //時(shí)鐘配置寄存器
vu32 MODECFG; //FIFO控制寄存器
vu32 SLAVE; //從屬器選擇寄存器
vu32 INTEN; //中斷啟動(dòng)寄存器
vu32 STATUS; //狀態(tài)寄存器
vu32 TXDATA; //發(fā)送數(shù)據(jù)寄存器
vu32 RXDATA; //接收數(shù)據(jù)寄存器
vu32 CNT; //計(jì)數(shù),主控器收到多少數(shù)據(jù)
vu32 CLR; //狀態(tài)清除
vu32 SWAPCFG ; //交換配置寄存器
vu32 FBCLK; //反饋時(shí)鐘選擇寄存器
}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)