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

📄 sdc.c

📁 本程序为ST公司开发的源代码
💻 C
字号:
/************************************************** * * sdc.c * * CVS ID:   $Id: sdc.c,v 1.17 2007/03/19 17:59:41 belardi Exp $ * Author:   Sangwon Bae [swbae] - Optomech * Date:     $Date: 2007/03/19 17:59:41 $ * Revision: $Revision: 1.17 $ *  * Description: *  * *************************************************** *  * COPYRIGHT (C) Optomech  2006 *            All Rights Reserved * *************************************************** * * STM CVS Log: * * $Log: sdc.c,v $ * Revision 1.17  2007/03/19 17:59:41  belardi * Integration of Optomech SDC driver P150307 * * Revision 1.16  2007/02/27 09:29:35  belardi * Optomech patch 070226 * - MMC is supported by SDC driver * * Revision 1.15  2007/02/08 12:39:48  belardi * Optomech driver stability patch P070131 * * Revision 1.14  2006/12/13 09:24:52  belardi * Optomech stability fix for SDC driver (P061212) * * Revision 1.13  2006/11/28 09:28:45  belardi * bug fix from Optomech * * Revision 1.12  2006/09/18 09:55:24  belardi * Corrected CVS keyword usage * * Revision 1.11  2006/09/18 09:25:23  belardi * Added Log CVS keyword into file header * * ***************************************************/#include "gendef.h"#include "hwreg.h"#include "osal.h"#if (1 == HAVE_SDC)#include "hostif_high.h"#include "xfile.h"#include "sdc.h"#include "sdci.h"tU8  sdc_data[SDP_BUFFERLEN];tU32 sdc_nac;SDC_FLAG_STATUS sdc_status;t_fsm sdc_fsm_xfer;tU8   sdc_kick;t_child_cmd_event local_sdc_cmd_event;t_child_cmd_event sdc_cmd_event_data[EVENT_MAX_STAGES];/****************************************************************** * *  SD Card * *****************************************************************//* Init SDC task */void InitSDCTask(void){	sd_init();	sdc_kick = 0;	start_timer(SDC_TIMER, SD_ELAPSE_INSERTION);}/* SDC task */void SDCTask(void *unused){	while (TRUE)	{		OSAL_wait_thread(OSAL_THREAD_SDCTask);				event_disable_scheduling();		event_in_shedule(SDC_CMD_EVENT);		event_enable_scheduling();				sdc_process_preevents();				sdc_transition_handler();				event_disable_scheduling();		event_in_clear(SDC_CMD_EVENT);		event_out_shedule(SDC_STOP_EVENT);		event_out_shedule(SDC_DATA_EVENT);		event_out_shedule(SDC_MOUNT_EVENT);		event_enable_scheduling();      	}}void sd_init(void){	PDB |= 0x1000;      // CS	SD_CLK = SDP_CLOCK_INIT;    // 67.74MHz / 170 = 398.5 kHz < 400 kHz	SD_CSR1.field.bspe = 0;     // BSPI Disable	SD_CSR1.field.mstr = 1;     // BSPI is a master	SD_CSR1.field.rie = 0;	SD_CSR1.field.reie = 0;	SD_CSR1.field.beie = 0;	SD_CSR1.field.cpol = 0;	SD_CSR1.field.cpha = 0;  	SD_CSR1.field.wl = 0;	SD_CSR1.field.rfs = 0;      // 8 Word Rx	SD_CSR2.field.dfifo = 1;     // Clear FIFO	SD_CSR2.field.tfs = 0;      // 8 Word Tx	SD_CSR2.field.tie = 0;	SD_CSR3.field.mask_ss = 1;   // Mask SS	SD_CSR3.field.dma_en = 0;	SD_CSR3.field.tburst_len = 0;	SD_CSR3.field.rburst_len = 10;    // Set as 8	SD_CSR3.field.treq_len = 0;	SD_CSR3.field.rreq_len = 0;	SD_CSR1.field.bspe = 1;      // BSPI Enable	sdc_nac = SDP_NACDEFAULT;	sdc_status.value = SDS_NONE;}void *get_sdc_cmd_event_data(t_event_stage i){	return (void *)&sdc_cmd_event_data[i];}void sdc_process_preevents(void){	if (IS_SDC_CMD_EVENT)	{		local_sdc_cmd_event = SDC_CMD;		switch(local_sdc_cmd_event.command)		{		case CHILD_CMD_XFER_DATA:			FSM_activate(&sdc_fsm_xfer, SDC_DATA_FSM_IDLE, 1);			break;		case CHILD_CMD_BACKGROUND:			sdc_kick = 1;			break;		}	}}void sdc_transition_handler(void){	uint16 sdc_awaited_transitions;	do 	{		sdc_awaited_transitions = 0;		if (FSM_RUN == sdc_fsm_xfer.state)		{			sdc_awaited_transitions |= sdc_xfer_transition();		}	} while(sdc_awaited_transitions);	if(sdc_kick)	{		sdc_test_back();		sdc_kick = 0;	}}uint16 sdc_xfer_transition(void){	static tU32 sdc_begin;	static tU32 sdc_count;	static tU16 sdc_offset;	static tU8* sdc_target;	tU16 sdc_size;		switch (sdc_fsm_xfer.transition)	{	case SDC_DATA_FSM_IDLE:		if(0 == sdc_status.f.Ready)		{			sdc_fsm_xfer.transition = SDC_DATA_FSM_ERROR;			break;		}		sdc_begin = local_sdc_cmd_event.command_params.xfer_params.sector_start << 9;		sdc_count = local_sdc_cmd_event.command_params.xfer_params.count;		sdc_offset = local_sdc_cmd_event.command_params.xfer_params.offset;		sdc_target = local_sdc_cmd_event.command_params.xfer_params.dest;		if((0 == sdc_count) || (SDP_BLOCKLEN <= sdc_offset))		{			sdc_fsm_xfer.transition = SDC_DATA_FSM_DONE;			break;		}		sdc_fsm_xfer.transition = SDC_DATA_FSM_READ;	case SDC_DATA_FSM_READ:		sdc_size = SDP_BLOCKLEN - sdc_offset;		if(sdc_size > sdc_count)		{			sdc_size = sdc_count;		}		if(SDE_TIME_OUT == sd_open(sdc_begin, sdc_offset, sdc_target, sdc_size))		{			sdc_fsm_xfer.transition = SDC_DATA_FSM_ERROR;			break;		}		sdc_count -= sdc_size;		if(sdc_count)		{			sdc_begin += (sdc_size + sdc_offset);			sdc_target += sdc_size;			sdc_offset = 0;			break;		}	case SDC_DATA_FSM_DONE:				sdc_fsm_xfer.state = FSM_DONE;		event_data_set_sdc(READY);		return 0;	default:		sdc_set_error(&sdc_fsm_xfer, E_SDC_READ);		if(sdc_status.f.Ready)		{			sdc_kick = 1;		}		else		{			event_mount_set_sdc(SDC_UMOUNT);		}		return 0;	}			return CTR_TRANSITION_SDC_DATA_FOR_SDC;}void sdc_set_error(t_fsm *sdc_fsm, GRESULT error_reason){	sdc_fsm->state = FSM_ERROR;	sdc_fsm->error_reason = error_reason;	    	event_data_set_sdc(error_reason);	}void sdc_test(void){	sdc_kick = 1;	OSAL_wake_thread(OSAL_THREAD_SDCTask);}void sdc_test_back(void)	{		uint16 delay;		if (sdc_status.f.Ready)		{			if(OK != sd_check())			{				sdc_status.value = SDS_NONE;			event_mount_set_sdc(SDC_UMOUNT);				delay = SD_ELAPSE_INSERTION;			}			else			{				delay = SD_ELAPSE_REMOVAL;			}		}		else		{			switch(sd_detect())			{			case READY :				sdc_status.f.Ready = 1;			event_mount_set_sdc(SDC_MOUNT);			delay = SD_ELAPSE_MONITOR;			break;			case IN_PROGRESS :				delay = SD_ELAPSE_DETECTION;				break;			default :				delay = SD_ELAPSE_INSERTION;			}		}		start_timer(SDC_TIMER, delay);	}RETVAL sd_detect(void){	GRESULT res;	switch(sdc_status.f.Step)	{	case SDC_STEP_SUPPLY :		sd_delay(SD_CLOCK_SUPPLY);		sdc_status.f.Step ++;		return MEDIA_NOT_FOUND;	case SDC_STEP_RESET :		res = sd_reset();		break;	case SDC_STEP_WAKEUP :		if(E_FAIL == (res = sd_wakeup()))		{			return IN_PROGRESS;		}		break;	case SDC_STEP_READOCR :		res = sd_readocr();		break;#if 0	case SDC_STEP_SENDCSD :		res = sd_sendcsd();		break;#endif // 0	case SDC_STEP_SETBL :		res = sd_setbl();		break;	case SDC_STEP_DONE :		sdc_status.f.Step = 0;		return READY;	case SDC_STEP_FAIL :	default :		res = E_FAIL;	}	if(S_OK == res)	{		sdc_status.f.Step ++;		return IN_PROGRESS;	}	sdc_status.f.Step = 0;	return MEDIA_NOT_FOUND;}RETVAL sd_check(void){	if(SDE_OK == sd_command(SDC_READ_OCR, 0, SDR_3))	{		return OK;	}//	sdc_status.value = SDS_NONE;	// reset clock	sd_reset_clock();	return MEDIA_NOT_FOUND;}RETVAL sdc_cmd(t_child_cmd_event* cmd_event){	t_child_cmd_event* pout_event = (t_child_cmd_event *)pevent_get_out(SDC_CMD_EVENT);	*pout_event = *cmd_event;	event_set_out(SDC_CMD_EVENT);	event_out_shedule(SDC_CMD_EVENT);	return BUSY;}GRESULT sd_reset(void){	switch(sd_command(SDC_GO_IDLE_STATE, 0, SDR_1))	{	case SDE_OK :	case SDE_IN_IDLE_STATE :		sdc_status.f.Count = SDW_TRY_IDLE;		return S_OK;	default ://		sdc_status.value = SDS_NONE;		return E_DEVICE_NOT_AVAILABLE;	}}GRESULT sd_wakeup(void){	e_SDErr res = sd_command(SDC_APP_CMD, 0, SDR_1);	if(SDE_IN_IDLE_STATE == res)	{		res = sd_command(SDAC_SEND_OP_COND, 0, SDR_1);	}//  res = sd_command(SDC_READ_OCR, 0, SDR_3);  if(SDE_ILLEGAL_COMMAND & res)  {    res = sd_command(SDC_SEND_OP_COND, 0, SDR_1);  }	if(SDE_OK == res)	{		return S_OK;	}	if(sdc_status.f.Count)	{		sdc_status.f.Count --;		return E_FAIL;	}	return E_READ_TIMEOUT;}GRESULT sd_readocr(void){	if(SDE_OK != sd_command(SDC_READ_OCR, 0, SDR_3))	{//		sdc_status.value = SDS_NONE;		return E_READ_FAILURE;	}	// check voltage	if(SDP_OCR_33_MSK != (SDP_OCR_33_MSK & sdc_data[SDP_OCR_33_IDX]))	{//		sdc_status.value = SDS_ERROR;		return E_INVALID_DEVICE_TYPE;	}	return S_OK;}#if 0GRESULT sd_sendcsd(void){	const tU32 a_Unit[] = {0, 0, 0, 1, 10, 100, 1000, 10000};	const tU32 a_Value[] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80};	// send csd	if(SDE_OK != sd_command(SDC_SEND_CSD, 0, SDR_R))	{//		sdc_status.value = SDS_NONE;		return E_READ_FAILURE;	}	// get nac (we should assume clock cycle for taac. choose 10MHz safely.)	sdc_nac = a_Unit[SDP_CSD_TAAC_UMSK & sdc_data[SDP_CSD_TAAC_IDX]];	if(sdc_nac)	{		sdc_nac *= a_Value[SDP_CSD_TAAC_VMSK & (sdc_data[SDP_CSD_TAAC_IDX] >> SDP_CSD_TAAC_VOFFSET)];	}	else	{		sdc_nac = SDP_NACMIN;	}	sdc_nac += (SDP_CSD_NSAC_UNIT * sdc_data[SDP_CSD_NSAC_IDX]);	// optional check to avoid error	if(SDP_NACDEFAULT > sdc_nac)	{		sdc_nac = SDP_NACDEFAULT;	}	// check 8s multiple//	sdc_nac >>= 3;           // divide by 8                             // Some SDC doesn't follow their spec.                             // Wait more safely	return S_OK;}#endif //0GRESULT sd_setbl(void){	// set BLOCKLEN	if(SDE_OK != sd_command(SDC_SET_BLOCKLEN, SDP_BLOCKLEN, SDR_1))	{//		sdc_status.value = SDS_NONE;		return E_READ_FAILURE;	}  	// ready//	sdc_status.value = SDS_READY;  	// update clock	sd_burst_clock();	return S_OK;}e_SDErr sd_command(e_SDCmd cmd, tU32 param, e_SDRes type){	tU8 res;	tU32 cnt;	tU32 req;	tU8* p_out = sdc_data;	res = sd_query(cmd, param);	// check response type	switch(type)	{	case SDR_R :		if(SDE_OK != res)		{			sd_close();			return res;		}		cnt = 8;		req = 16;		break;	case SDR_2 :	case SDR_3 :		// set count		cnt = (SDR_2 == type) ? 1 : 4;		// set response		*p_out ++ = res;		// read response block		while(cnt --)		{			*p_out ++ = sd_read(0xFF);		}	case SDR_1 :	default :		sd_close();		return res;	}	// wait data	do	{		res = sd_read(0xFF);	} while((0xFF == res) && (cnt --));	// check result	if((0xFF == res) || (!(SDP_DATAERR_MSK & res)))	{		sd_close();		return res;	}	// read response	p_out = sdc_data;	cnt = req;	while(cnt --)	{		*p_out ++ = sd_read(0xFF);	}	sd_close();	return SDE_OK;}e_SDErr sd_open(tU32 addr, tU32 offset, tU8* dest, tU32 size){	tU8  res;	tU32 cnt;	if(SDE_OK != (res = sd_query(SDC_READ_SINGLE_BLOCK, addr)))	{		sd_close();		return res;	}	// wait data	cnt = sdc_nac;	do	{		res = sd_read(0xFF);	} while((0xFF == res) && (cnt --));	// check result	if((0xFF == res) || (!(SDP_DATAERR_MSK & res)))	{		sd_close();		return res;	}	cnt = (SDP_BLOCKLEN > (offset + size)) ? (SDP_BLOCKLEN - size - offset) : 0;	while(offset --)	{		sd_read(0xFF);	}	while(size --)	{		*dest ++ = sd_read(0xFF);	}	while(cnt --)	{		sd_read(0xFF);	}	sd_close();	return SDE_OK;}#if 0 // [RB] commented out to reduce ROM spacee_SDErr sd_wait(void){	return SDE_OK;}#endife_SDErr sd_query(e_SDCmd cmd, tU32 param){	tU8 res = SDE_TIME_OUT;	tU32 cnt = 17;	PDB |= 0x1000;              // confirm - optional	SD_CSR2.field.dfifo = 1;    // clear fifo	PDB &= ~0x1000;             // CS	// dummy high	sd_read(0xFF);	// start bit, transmission bit & command	sd_read(0x40 | (0x3F & cmd));	// parameter	sd_read(0xFF & (param >> 24));	sd_read(0xFF & (param >> 16));	sd_read(0xFF & (param >> 8));	sd_read(0xFF & param);	// CRC7 & end bit	sd_read(0x95);              // dummy for CMD0	// dummy high	sd_read(0xFF);	// wait response	do	{		res = sd_read(0xFF);	} while((0xFF == res) && (cnt --));	return res;}e_SDErr sd_close(void){	// trash crc	sd_delay(4);	PDB |= 0x1000;	sd_delay(2);	return SDE_OK;}void sd_delay(tU32 cnt){	while(cnt --)	{		sd_read(0xFF);	}}void sd_send(tU8 dat){	while(1)	{		if(SD_CSR2.field.tfe)		{			SD_TXR = (dat << 8);			break;		}	}}tU8 sd_read(tU8 dat){	sd_send(dat);	while(1)	{		if(SD_CSR2.field.rfne)		{			return (SD_RXR & 0xFF);		}	}}void sd_reset_clock(void){	SD_CLK = SDP_CLOCK_INIT;       // 67.74MHz / 170 = 398.5 kHz < 400 kHz}void sd_burst_clock(void){	SD_CLK = SDP_CLOCK_BURST;      // test value}#endif /* HAVE_SDC *//* End of sdc.c */

⌨️ 快捷键说明

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