S3C6410 SPI 裸机驱动

刚刚写的SPI驱动,想移植到LINUX上面用来读写SD卡

只测试了发送,没有测试接收.

 

spi.c

 

/************************************************************************************************************** 文件名:	spi.c* 功能:		S3C6410 SPI底层驱动函数* 作者:		* 创建时间:	2012年9月8日20:35* 最后修改时间:2012年9月8日* 详细:		SPI始化,发送,接收,配置等* 			使用的是手动控制片选,因为在实际使用过程中手动控制片选较为灵活,但是也有个问题,就是何时取消片选,应为数据写入到发送FIFO并* 			不代表数据已经发送完成了,如果在数据没有发送完成之前取消了片选会导致数据传输错误,因此简单的方法就是在发送数据后加入一定* 			的延时,让数据发送完成后取消片选
*************************************************************************************************************/
#include "system.h"
#include "spi.h"
#include "delay.h"//SPI通道数量
#define SPI_CH_N	2
//SPI外设结构
const SPI_TypeDef *SPI_CH[SPI_CH_N] = {SPI0,SPI1};//默认模式1
//主设备模式,空闲时钟低电平,第一个时钟边沿有效(上升沿有效),使能发送接收,数据宽度8bit,关闭DMA,使能手动控制片选
const SPI_Config_TypeDef SPI_DEFAULT_01 = {0,0,0,1,1,8,0,0,0,0};/*************************************************************************************************************************
*函数    :	void SPI_SetSpeed(u8 ch,u8 Speed)
*功能    :	设置SPI速度
*参数    :	CH:SPI通道选择;Speed:SPI速度设置
*返回    :	无
*依赖	: 	底层宏定义
*作者     :	cp1300@139.com
*时间     :	20121005
*最后修改时间:	20121005
*说明     :	修改的时候注意SPI应该处于空闲或者无效状态,使用的时钟是PCLK
* 			SPI 时钟输出 = 时钟源 / ( 2 ×(预分频值 +1))
*************************************************************************************************************************/
void SPI_SetSpeed(u8 ch,u8 Speed)
{SPI_TypeDef *SPI;if(ch >= SPI_CH_N)return;			//通道号超出范围SPI = (SPI_TypeDef *)SPI_CH[ch];	//获取对应通道寄存器结构指针SPI->CLKCFG = 0;	//清空设置并关闭时钟SPI->CLKCFG = Speed;//设置预分频值SPI->CLKCFG |= BIT8;//使能时钟
}/*************************************************************************************************************************
*函数    :	u8 SPI_Init(u8 ch,SPI_Config_TypeDef *config,u8 Speed)
*功能    :	SPI初始化
*参数    :	CH:SPI通道选择;config:配置结构指针;Speed:SPI速度设置
*返回    :	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];		//获取对应通道寄存器结构指针SPI->CHCFG |= BIT5;	//SPI软复位Delay_US(10);		//适当延时switch(ch){case 0:	//通道0{Set_GateClk(PCLK_SPI0,ENABLE);	//使能SPI0门控时钟rGPCCON &= ~0xfff;rGPCCON |= 0x222;				//初始化SPI0 MISO CLK MOSI 相关IO}break;case 1:	//通道1{Set_GateClk(PCLK_SPI1,ENABLE);	//使能SPI1门控时钟rGPCCON &= ~(0xfff << 16);rGPCCON |= (0x222 << 16);		//初始化SPI1 MISO CLK MOSI 相关IO}break;default:break;}SPI->CLKCFG &= ~BIT8;	//关闭SPI时钟SPI->CHCFG = 0;		//清除设置并关闭SPI发送接收通道if(config->EnSlave)	//使能从设备模式{chcfg |= BIT4;}if(config->EnCPOH)	//使能空闲时钟高电平{chcfg |= BIT3;}if(config->EnCPHB)	//使能第二个时钟边沿有效{chcfg |= BIT2;}if(config->EnRx)	//使能接收{chcfg |= BIT1;}if(config->EnTx)	//使能发送{chcfg |= BIT0;}switch(config->SetTranSize)//设置传输数据位宽{case 16: modcfg |= (1 << 29);modcfg |= (1 << 17);break;	//半字case 32: modcfg |= (2 << 29);modcfg |= (2 << 17);break;	//字default : break;	//字节}if(config->EnRxDMA)	//使能接收DMA{modcfg |= BIT2;}if(config->EnTxDMA)	//使能发送DMA	{modcfg |= BIT1;}if(config->EnDMA4Burst)	//设置DMA传输类型为4个脉冲{modcfg |= BIT0;}if(config->EnAutoCS)	//使能自动片选{slavecfg |= BIT1;switch(ch){case 0:	//通道0{rGPCCON &= ~0xf000;rGPCCON |= 0x2000;				//初始化CS 相关IO}break;case 1:	//通道1{rGPCCON &= ~(0xf0000000);rGPCCON |= (0x2000 << 16);				//初始化CS 相关IO}break;default:break;}}//写入配置数据SPI->CHCFG = chcfg;SPI->MODECFG = modcfg;SPI->SLAVE = slavecfg;SPI->CLKCFG |= BIT8;	//使能SPI时钟SPI_SetSpeed(ch,Speed);	//设置SPI速度SPIx_ReadWriteData(ch,0xaa);	//启动第一次传输return 0;
}/*************************************************************************************************************************
*函数    :	u32 SPIx_ReadWriteData(u8 ch,u32 TxData)
*功能    :	SPI发送接收数据
*参数    :	CH:SPI通道选择;TxData:要发送的数据
*返回    :	收到的数据
*依赖	: 	底层宏定义
*作者     :	cp1300@139.com
*时间     :	20121005
*最后修改时间:	20121005
*说明     :	发送和接收的数据宽度要看配置,可以是8bit,16bit,32bit
* 			发送完成后要加延时,因为数据写入到FIFO后并没有马上发送完,当发送完成之前片选可能就已经取消了,因此需要适当的添加延时
* 			因为我们无法判断数据是否已经从移位寄存器中发送完毕,只能检测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];		//获取对应通道寄存器结构指针	do{temp = (SPI->STATUS >> 6) & 0x7f;	//获取发送FIFO数据数量retry ++;if(retry > 8000) 					return 0;}while(temp > 63);						//发送FIFO满了,等待SPI->TXDATA = TxData;					//发送数据		retry = 0;do{temp = (SPI->STATUS >> 13) & 0x7f;	//获取接收FIFO数据数量retry ++;if(retry > 8000) 					return 0;}while(temp == 0);						//接收FIFO为空,等待return SPI->RXDATA;						//返回受到的数据  									    
}

 

 

 

 

 

spi.h

 

/************************************************************************************************************** 文件名:	spi.h* 功能:		S3C6410 SPI底层驱动函数* 作者:		陈鹏* 创建时间:	2012年9月8日20:35* 最后修改时间:2012年9月8日* 详细:		SPI始化,发送,接收,配置等
*************************************************************************************************************/
#ifndef SPI_H_
#define SPI_H_#include "system.h"//SPI配置结构定义
typedef struct
{u8	EnSlave;		//使能SPI从设备模式u8	EnCPOH;			//使能空闲时钟高电平u8	EnCPHB;			//使能时钟第二个边沿有效,否则为第一个边沿有效u8	EnRx;			//使能接收u8	EnTx;			//使能发送u8	SetTranSize;	//设置传输数据宽度,8bit,16bit,32bit;u8	EnRxDMA;		//使能接收DMAu8	EnTxDMA;		//使能发送DMAu8	EnDMA4Burst;	//设置DMA传输类型为4个脉冲u8	EnAutoCS;		//使能自动片选
}SPI_Config_TypeDef;//默认模式1
//主设备模式,空闲时钟低电平,第一个时钟边沿有效(上升沿有效),使能发送接收,数据宽度8bit,关闭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中断服务程序中闪烁,周期400MS
void LED1_flash(void)
{LED1_FLASH();
}int main(void)
{	u8 i = 0;LCD_Init();					//初始化LCDUART0_Init(DISABLE,115200);	//初始化串口,失能中断接收,波特率115200LED_Init();					//初始化LEDrGPCCON |= 1 << 12;rGPCDAT |= BIT3;Timer1_Init(400000-1,ENABLE,LED1_flash);	//初始化定时器0,周期400mslcd_printf("Get_FCLK : %d Hz\n",Get_FCLK());	lcd_printf("Get_PCLK : %d Hz\n",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);	//适当添加延时rGPCDAT |= BIT3;Delay_US(6);}
}

 

 

 

 

测试了一下硬件控制片选,发现片选信号非常完美

上图

 

补充SPI寄存器结构

 

//SPI
typedef struct
{vu32	CHCFG;			//配置寄存器vu32	CLKCFG;			//时钟配置寄存器vu32	MODECFG;		//FIFO控制寄存器vu32	SLAVE;			//从属器选择寄存器vu32	INTEN;			//中断启动寄存器vu32	STATUS;			//状态寄存器vu32	TXDATA;			//发送数据寄存器vu32	RXDATA;			//接收数据寄存器vu32	CNT;			//计数,主控器收到多少数据vu32	CLR;			//状态清除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)

 

 

 

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部