⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdi.c

📁 os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	ApOS (Another Project software for s3c2410) *	 *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License version 2 as *	published by the Free Software Foundation. *			 *						Copyright caiyuqing * */#include "../include/s3c2410/s3c2410.h"#include "../include/s3c2410/cpu.h"#include "../include/kernel/irq.h"#include "../include/s3c2410/sdi.h"#include "../include/s3c2410/dma.h"//#define SDI_DEBUG	1#define SD_CMD(n)	sd_cmd[(n)]//命令索引#define CRC_CHECK	1//需要进行CRC校验#define CRC_UNCHECK	0//不需要进行CRC校验#define NO_RESP		0//无Response#define SHORT_RESP	1//短Response#define LONG_RESP	2//长Response#define DEFAULT_RCA	0x0000//默认的RCA#define SDI_READ 	0//sdi读操作#define SDI_WRITE 	1//sdi写操作#define BLOCK(n)	(512*(n))#define CURRENT_STATE(n)	(((n)>>9)&0x0f)extern char sys_dma2_done;extern irq_ptr irq_rotunie[32];extern struct dma_ctrl_object 	dma_ctrl_object;struct sdi_control_obj sdi_control_obj;unsigned char sd_cmd[64];		//命令数组unsigned short sdi_RCA;			//sd卡的RCAunsigned int sdi_status;struct CID_struct sdi_CID;		//sd卡的CIDstruct CSD_register_struct sdi_CSD;	//sd卡的CSD/* *	写缓冲,该缓冲区保存着准备往sd卡的写入的数据 */#define PAGES 2unsigned char sd_Tx_buf[512*PAGES];/* *	读缓冲,该缓冲区保存着刚从sd卡读出的数据 */unsigned char sd_Rx_buf[512*PAGES];void dma2_irq(struct cpu_registers *regs);void sdi_irq(struct cpu_registers *regs);int sdi_send_status(unsigned short rca,unsigned int *status);void dump_sd_Rx_buf(int page){	int i;	for(i=0;i<512;i++)		printk("%0x ",sd_Rx_buf[page*512+i]);}/* *	初始化 sdi_control_obj */void sdi_ctrl_obj_init(struct sdi_control_obj *sco){	sco->sdicon	=&rSDICON;	sco->sdipre	=&rSDIPRE;	sco->sdicarg	=&rSDICARG;	sco->sdiccon	=&rSDICCON;	sco->sdicsta	=&rSDICSTA;	sco->sdirsp0	=&rSDIRSP0;	sco->sdirsp1	=&rSDIRSP1;	sco->sdirsp2	=&rSDIRSP2;	sco->sdirsp3	=&rSDIRSP3;	sco->sdidtimer	=&rSDIDTIMER;	sco->sdibsize	=&rSDIBSIZE;	sco->sdidcon	=&rSDIDCON;	sco->sdidcnt	=&rSDIDCNT;	sco->sdidsta	=&rSDIDSTA;	sco->sdifsta	=&rSDIFSTA;	sco->sdidat	=&rSDIDAT;	sco->sdiimsk	=&rSDIIMSK;		*sco->sdiimsk	=(1<<SDI_INT_CMDSENT);	irq_rotunie[INT_SDI]=sdi_irq;//初始化sdi的中断向量	irq_mask(INT_SDI,IRQ_MASK);//关闭sdi的中断,目前没有使用到中断}//初始化命令数组int init_sd_cmd(){	int i;	for(i=0;i<64;i++)	{		sd_cmd[i]=i|(1<<6);	}}/* *	本函数检测命令发送是否成功 * */#define RESP_FIN (finish&(1<<SDICSTA_RSP_FIN_OFFSET))#define TIME_OUT (finish&(1<<SDICSTA_CMD_TOUT_OFFSET))int sdi_cmd_check(int cmd,unsigned int be_resp,char check_crc){	int finish	=0;		/*	 *	status保存了命令检测后的状态.	 *	如果命令超时,则status的第30bit被置位;	 *	如果CRC校验出错,则status的第31bit被置位;	 *	如果命令发送成功且得到正确的Response,则status的低8位保存了该	 *	Response的索引(RspIndex)	 */	int status	=0;	/*	 *	No Response	 */	if(!be_resp)	{		finish=*sdi_control_obj.sdicsta;		/*		 *	if rSDICSTA[11]==1,command end		 */		while(!(finish&(1<<SDICSTA_CMD_SENT_OFFSET)))		{			finish=*sdi_control_obj.sdicsta;		}		#ifdef SDI_DEBUG			printk("sdi cmd%d with no response send :].\n",(cmd&0x3F));		#endif		/*		 *	Clear command end state		 */		*sdi_control_obj.sdicsta=finish;		return status;	}	else// With Response	{		finish=*sdi_control_obj.sdicsta;		/*		 *	if	rSDICSTA[9 ]==1,Response end		 *	if	rSDICSTA[10]==1,Time out		 */		while(!(RESP_FIN|TIME_OUT))		{	    	    finish=*sdi_control_obj.sdicsta;		}				#ifdef SDI_DEBUG			printk("sdi cmd%d with response send.\n",(cmd&0x3F));		#endif				/*		 *	若该Response有CRC校验,则进行检测		 */		if(check_crc&&(finish&(1<<SDICSTA_RSP_CRC_OFFSET)))		{			status|=1<<31;		}		/*		 *	检测是否超时		 */		if(finish&(1<<SDICSTA_CMD_TOUT_OFFSET))		{			status|=1<<30;		}		/*		 *	Clear the bit whicth has been set		 *	寄存器sdicsta清0		 */			*sdi_control_obj.sdicsta=(finish&0x1E00);				status|=(finish&0xff);		return status;	}}/* *	本函数实现sdi模块的命令发送 *	成功返回1,失败返回0 */int sdi_send_cmd(unsigned int cmd,int arg,	char rsp,char check_crc){	int status	=0;		/*	 *	with_data 标明该命令是否有带参数.有为1,无为0	 *		 */	char with_data	=0;		/*	 *	abort_cmd 标明该命令是否是abort command(CMD(12),CMD(52)).	 *	是为1,否为0	 */	char abort_cmd	=0;		//该命令是否有带参数	if(arg!=-1)	{		with_data=1;		*sdi_control_obj.sdicarg=arg;	}	//该命令是否为abort command	if(cmd==SD_CMD(12)||cmd==SD_CMD(52))	{		abort_cmd=1;	}		//该命令是否有有Response,若有,则该Response是什么类型的	switch(rsp)	{		//no Response		case NO_RESP:			*sdi_control_obj.sdiccon=(abort_cmd<<SDICCON_ABORD_CMD_OFFSET)|						(with_data<<SDICCON_WITH_DATA_OFFSET)|						(1<<SDICCON_CMD_START_OFFSET)|						cmd;			break;		//short Response		case SHORT_RESP:			*sdi_control_obj.sdiccon=(abort_cmd<<SDICCON_ABORD_CMD_OFFSET)|						(with_data<<SDICCON_WITH_DATA_OFFSET)|						(0<<SDICCON_LONG_RSP_OFFSET)|						(1<<SDICCON_WAIT_RSP_OFFSET)|						(1<<SDICCON_CMD_START_OFFSET)|						cmd;			break;		//long Response		case LONG_RESP:			*sdi_control_obj.sdiccon=(abort_cmd<<SDICCON_ABORD_CMD_OFFSET)|						(with_data<<SDICCON_WITH_DATA_OFFSET)|						(1<<SDICCON_LONG_RSP_OFFSET)|						(1<<SDICCON_WAIT_RSP_OFFSET)|						(1<<SDICCON_CMD_START_OFFSET)|						cmd;			break;		}	//检测命令发送和Response的接收是否成功	status=sdi_cmd_check(cmd,rsp,check_crc);		if(status&0xffffff00)//命令检测失败	{		return 0;		}	return 1; //命令检测成功}/* *	检测数据传送是否正确 */#define DAT_FIN (finish&(1<<SDIDSTA_DAT_FIN_OFFSET))	//rSDIDSTA[4]==1,data finish#define DAT_TOUT  (finish&(1<<SDIDSTA_DAT_TOUT_OFFSET))	//rSDIDSTA[5]==1,time outint sdi_data_check(){	int finish;	finish=*sdi_control_obj.sdidsta;	while( !(DAT_FIN|DAT_TOUT))		{		finish=*sdi_control_obj.sdidsta;	}	*sdi_control_obj.sdidsta=finish&0x7FC;  // Clear error state		if((finish&0xfc)!=(1<<SDIDSTA_DAT_FIN_OFFSET))	{		return 0;//数据传送出错	}	return 1;//数据传送成功}/* *	设置sdi的DMA通道 */void sdi_dma_setup(char operate,unsigned int *mem_addr,int blocks){	struct dma_ctrl_object *dma_obj	=&dma_ctrl_object;	/*	 *	使用2号DMA通道进行数据传送数据	 */	struct dma_chanel *dma_chanel	=((struct dma_chanel *)dma_obj)+DMA_CHANEL_2;	/*	 *	每个block占用512 byte	 *	关于tc的详细信息请查看dma.c中的说明(在dma.c中搜索tc即可)	 */	unsigned int tc=blocks*512;	irq_rotunie[INT_DMA2]	=&dma2_irq;	irq_mask(INT_DMA2,IRQ_UNMASK);	sys_dma2_done=0;//dma标志清0,若sys_dma2_done为1表示dma操作已经完成			switch(operate)	{		/*		 *	写SD卡.		 *	数据传送源是RAM.		 *		DMA的寄存器disrcc:		 *	 		LOC位被设置为AHB;(同步于AHB总线)		 *	 		INC位被设置为INCREMENT;(访问后递增)		 *	 	DMA的寄存器disrc:mem_addr(数据传送源地址)		 *	 			 *				 *	数据传送目标是SD卡.		 *		DMA的寄存器didstc:		 *			LOC位被设置为APB;(同步于APB总线)		 *			INC位被设置为FIXED;(访问后不递增)		 *		DMA的寄存器didst:sdi_control_obj.sdidat(数据传送目标)		 */		case SDI_WRITE:			*dma_chanel->disrcc=(AHB<<LOC_OFFSET)|(INCREMENT<<INC_OFFSET);			*dma_chanel->didstc=(APB<<LOC_OFFSET)|(FIXED<<INC_OFFSET);			*dma_chanel->disrc=mem_addr;			*dma_chanel->didst=sdi_control_obj.sdidat;			break;		/*		 *	读SD卡.与写操作的源地址和目标地址相反,各个寄存器的设置类似.		 *	...		 */		case SDI_READ:			*dma_chanel->disrcc=(APB<<LOC_OFFSET)|(FIXED<<INC_OFFSET);			*dma_chanel->didstc=(AHB<<LOC_OFFSET)|(INCREMENT<<INC_OFFSET);			*dma_chanel->disrc=sdi_control_obj.sdidat;			*dma_chanel->didst=mem_addr;			break;	}	/*	 *	sdi的DMA通道的属性设置	 *	具体信息可查看dma.c 398行~434行	 */	*dma_chanel->dcon=(1<<DMD_HS_OFFSET)|(0<<SYNC_OFFSET)|			(1<<INT_OFFSET)|(0<<TSZ_OFFSET)|(1<<SERVMODE_OFFSET)|(2<<HWSRCSEL_OFFSET)|			(1<<SWHW_SEL_OFFSET)|(1<<RELOAD_OFFSET)|(BYTE<<DSZ_OFFSET)|(tc);		while(((*dma_chanel->dstat)>>20)&0x3==1);//DMA is busy	/*	 *	打开sdi的DMA通道	 */	*dma_chanel->dmasktrig=(0<<STOP_OFFSET)|(1<<ON_OFF_OFFSET)|0;}/* *	dma chanel2 中断服务例程 */void dma2_irq(struct cpu_registers *regs){	clean_src_pnd(INT_DMA2);	clean_int_pnd(INT_DMA2);	irq_mask(INT_DMA2,IRQ_MASK);	dma_stop(DMA_CHANEL_2);	sys_dma2_done=1;//sys_dma2_done设为1,表示DMA操作完成}/* *	sdi中断服务例程 */void sdi_irq(struct cpu_registers *regs){	irq_mask(INT_SDI,IRQ_MASK);	printk("sdi interrupt\n");	clean_src_pnd(INT_SDI);	clean_int_pnd(INT_SDI);	irq_mask(INT_SDI,IRQ_UNMASK);} /* *	往SD卡写一个块的数据,每个块为512 byte *	写成功返回 1,否则返回0 * *	Tx_buf为写缓冲首地址,sd_addr为SD卡待写入块的首地址. *	事实上本函数将Tx_buf中的512个字节数据写入SD卡(写入 *	地址为sd_addr~sd_addr+512),每次写入的长度都是 *	512 byte(一个块) * *	我们可以这样调用:sdi_dma_write_block(sd_Tx_buf,BLOCK(10)); *	上面的调用是把 sd_Tx_buf中的512byte 写在SD卡的第10个块(扇区) */int sdi_dma_write_block(unsigned short rca,unsigned char *Tx_buf,		unsigned int sd_addr){	unsigned int card_state;	int cmd_status;	int check_conter;		/*	 *	循环检测SD卡,直到其处于tran状态	 */	for(check_conter=0;check_conter<100;check_conter++)	{		cmd_status=sdi_send_status(rca,&card_state);				if((CURRENT_STATE(card_state)==TRAN_STATE) && cmd_status)		{			break;		}	}	if(check_conter==100)	{		#ifdef SDI_DEBUG			printk("function \"sdi_dma_write_block\" card state fail 0x%0x,0x%0x.\n",				(card_state>>9)&0xf,cmd_status);		#endif		return 0;	}	//必须清除DCache,否则数据会出错	invalidate_DCache();		*sdi_control_obj.sdicon|=(1<<1);//FIFO Reset	sdi_dma_setup(SDI_WRITE,Tx_buf,1);//设置sdi的DMA通道	*sdi_control_obj.sdidcon=(1<<SDIDCON_TARSP_OFFSET)|			(1<<SDIDCON_BLK_MODE_OFFSET)|			(1<<SDIDCON_WIDE_BUS_OFFSET)|			(1<<SDIDCON_DMA_ENABLE_OFFSET)|			(3<<SDIDCON_DAT_MODE_OFFSET)|			(1<<SDIDCON_BLK_NUM_OFFSET);	/*	 *	向SD卡发送写单个块的命令(CMD24 WRITE_BLOCK)	 */	cmd_status=sdi_send_cmd(SD_CMD(24),sd_addr,SHORT_RESP,CRC_CHECK);	if(cmd_status!=1)	{		return 0;	}		while(!sys_dma2_done);//等待DMA的完成	*sdi_control_obj.sdidcon&=~(1<<15);//关闭sdi的DMA		if(!sdi_data_check())//数据检测	{				return 0;//写入出错	}	else	{		return 1;//写入成功	}		}/* *	读取SD卡一个块的数据,每个块为512 byte *	读成功返回 1,否则返回0 * *	Rx_buf为读缓冲首地址,sd_addr为SD卡待读出块的首地址. *	事实上本函数是将SD卡上地址为sd_addr~sd_addr+512的数据写入Rx_buf,  *	每次写入Rx_buf的数据长度都是512 byte(一个块) *	 *	我们可以这样调用:sdi_dma_read_block(sd_Rx_buf,BLOCK(10)); *	上面的调用是把SD卡的第10个块(扇区,512byte)的数据读到 sd_Rx_buf中 */int sdi_dma_read_block(unsigned short rca,unsigned char *Rx_buf,		unsigned int sd_addr){	unsigned int card_state;	int cmd_status;	int check_conter;		/*	 *	循环检测SD卡,直到其处于tran状态	 */	for(check_conter=0;check_conter<100;check_conter++)	{		cmd_status=sdi_send_status(rca,&card_state);				if((CURRENT_STATE(card_state)==TRAN_STATE) && cmd_status)		{			break;		}	}	if(check_conter==100)	{		#ifdef SDI_DEBUG			printk("function \"sdi_dma_read_block\" card state fail %0x,%0x.\n",				(card_state>>9)&0xf,cmd_status);					#endif				return 0;	}	//必须清除DCache,否则数据会出错	invalidate_DCache();		*sdi_control_obj.sdicon|=(1<<1);//FIFO Reset

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -