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

📄 spi.c

📁 u-boot1.3德国DENX小组开发的用于多种嵌入式CPU的bootloader
💻 C
字号:
/**************************************************************************** *  SPI flash driver for M25P64 ****************************************************************************/#include <common.h>#include <linux/ctype.h>#include <asm/io.h>#if defined(CONFIG_SPI) /*Application definitions */#define	NUM_SECTORS 	128	/* number of sectors */#define SECTOR_SIZE		0x10000#define NOP_NUM		1000#define COMMON_SPI_SETTINGS (SPE|MSTR|CPHA|CPOL)	/*Settings to the SPI_CTL */#define TIMOD01 (0x01)		/*stes the SPI to work with core instructions */ /*Flash commands */#define SPI_WREN	(0x06)	/*Set Write Enable Latch */#define SPI_WRDI	(0x04)	/*Reset Write Enable Latch */#define SPI_RDSR	(0x05)	/*Read Status Register */#define SPI_WRSR	(0x01)	/*Write Status Register */#define SPI_READ	(0x03)	/*Read data from memory */#define SPI_PP  	(0x02)	/*Program Data into memory */#define SPI_SE  	(0xD8)	/*Erase one sector in memory */#define SPI_BE		(0xC7)	/*Erase all memory */#define WIP		(0x1)	/*Check the write in progress bit of the SPI status register */#define WEL		(0x2)	/*Check the write enable bit of the SPI status register */#define TIMEOUT 350000000typedef enum {	NO_ERR,	POLL_TIMEOUT,	INVALID_SECTOR,	INVALID_BLOCK,} ERROR_CODE;void spi_init_f(void);void spi_init_r(void);ssize_t spi_read(uchar *, int, uchar *, int);ssize_t spi_write(uchar *, int, uchar *, int);char ReadStatusRegister(void);void Wait_For_SPIF(void);void SetupSPI(const int spi_setting);void SPI_OFF(void);void SendSingleCommand(const int iCommand);ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector);ERROR_CODE EraseBlock(int nBlock);ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData);ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData);ERROR_CODE Wait_For_Status(char Statusbit);ERROR_CODE Wait_For_WEL(void);/* ------------------- * Variables * ------------------- *//* ************************************************************************** * *  Function:    spi_init_f * *  Description: Init SPI-Controller (ROM part) * *  return:      --- * * *********************************************************************** */void spi_init_f(void){}/* ************************************************************************** * *  Function:    spi_init_r * *  Description: Init SPI-Controller (RAM part) - *		 The malloc engine is ready and we can move our buffers to *		 normal RAM * *  return:      --- * * *********************************************************************** */void spi_init_r(void){	return;}/**************************************************************************** *  Function:    spi_write **************************************************************************** */ssize_t spi_write(uchar * addr, int alen, uchar * buffer, int len){	unsigned long offset;	int start_block, end_block;	int start_byte, end_byte;	ERROR_CODE result = NO_ERR;	uchar temp[SECTOR_SIZE];	int i, num;	offset = addr[0] << 16 | addr[1] << 8 | addr[2];	/* Get the start block number */	result = GetSectorNumber(offset, &start_block);	if (result == INVALID_SECTOR) {		printf("Invalid sector! ");		return 0;	}	/* Get the end block number */	result = GetSectorNumber(offset + len - 1, &end_block);	if (result == INVALID_SECTOR) {		printf("Invalid sector! ");		return 0;	}	for (num = start_block; num <= end_block; num++) {		ReadData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);		start_byte = num * SECTOR_SIZE;		end_byte = (num + 1) * SECTOR_SIZE - 1;		if (start_byte < offset)			start_byte = offset;		if (end_byte > (offset + len))			end_byte = (offset + len - 1);		for (i = start_byte; i <= end_byte; i++)			temp[i - num * SECTOR_SIZE] = buffer[i - offset];		EraseBlock(num);		result = WriteData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp);		if (result != NO_ERR)			return 0;		printf(".");	}	return len;}/**************************************************************************** *  Function:    spi_read **************************************************************************** */ssize_t spi_read(uchar * addr, int alen, uchar * buffer, int len){	unsigned long offset;	offset = addr[0] << 16 | addr[1] << 8 | addr[2];	ReadData(offset, len, (int *)buffer);	return len;}void SendSingleCommand(const int iCommand){	unsigned short dummy;	/*turns on the SPI in single write mode */	SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));	/*sends the actual command to the SPI TX register */	*pSPI_TDBR = iCommand;	sync();	/*The SPI status register will be polled to check the SPIF bit */	Wait_For_SPIF();	dummy = *pSPI_RDBR;	/*The SPI will be turned off */	SPI_OFF();}void SetupSPI(const int spi_setting){	if (icache_status() || dcache_status())		udelay(CONFIG_CCLK_HZ / 50000000);	/*sets up the PF2 to be the slave select of the SPI */	*pSPI_FLG = 0xFB04;	*pSPI_BAUD = CONFIG_SPI_BAUD;	*pSPI_CTL = spi_setting;	sync();}void SPI_OFF(void){	*pSPI_CTL = 0x0400;	/* disable SPI */	*pSPI_FLG = 0;	*pSPI_BAUD = 0;	sync();	udelay(CONFIG_CCLK_HZ / 50000000);}void Wait_For_SPIF(void){	unsigned short dummyread;	while ((*pSPI_STAT & TXS)) ;	while (!(*pSPI_STAT & SPIF)) ;	while (!(*pSPI_STAT & RXS)) ;	dummyread = *pSPI_RDBR;	/* Read dummy to empty the receive register      */}ERROR_CODE Wait_For_WEL(void){	int i;	char status_register = 0;	ERROR_CODE ErrorCode = NO_ERR;	/* tells us if there was an error erasing flash */	for (i = 0; i < TIMEOUT; i++) {		status_register = ReadStatusRegister();		if ((status_register & WEL)) {			ErrorCode = NO_ERR;	/* tells us if there was an error erasing flash */			break;		}		ErrorCode = POLL_TIMEOUT;	/* Time out error */	};	return ErrorCode;}ERROR_CODE Wait_For_Status(char Statusbit){	int i;	char status_register = 0xFF;	ERROR_CODE ErrorCode = NO_ERR;	/* tells us if there was an error erasing flash */	for (i = 0; i < TIMEOUT; i++) {		status_register = ReadStatusRegister();		if (!(status_register & Statusbit)) {			ErrorCode = NO_ERR;	/* tells us if there was an error erasing flash */			break;		}		ErrorCode = POLL_TIMEOUT;	/* Time out error */	};	return ErrorCode;}char ReadStatusRegister(void){	char status_register = 0;	SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));	/* Turn on the SPI */	*pSPI_TDBR = SPI_RDSR;	/* send instruction to read status register */	sync();	Wait_For_SPIF();	/*wait until the instruction has been sent */	*pSPI_TDBR = 0;		/*send dummy to receive the status register */	sync();	Wait_For_SPIF();	/*wait until the data has been sent */	status_register = *pSPI_RDBR;	/*read the status register */	SPI_OFF();		/* Turn off the SPI */	return status_register;}ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector){	int nSector = 0;	ERROR_CODE ErrorCode = NO_ERR;	if (ulOffset > (NUM_SECTORS * 0x10000 - 1)) {		ErrorCode = INVALID_SECTOR;		return ErrorCode;	}	nSector = (int)ulOffset / 0x10000;	*pnSector = nSector;	/* ok */	return ErrorCode;}ERROR_CODE EraseBlock(int nBlock){	unsigned long ulSectorOff = 0x0, ShiftValue;	ERROR_CODE ErrorCode = NO_ERR;	/* if the block is invalid just return */	if ((nBlock < 0) || (nBlock > NUM_SECTORS)) {		ErrorCode = INVALID_BLOCK;	/* tells us if there was an error erasing flash */		return ErrorCode;	}	/* figure out the offset of the block in flash */	if ((nBlock >= 0) && (nBlock < NUM_SECTORS)) {		ulSectorOff = (nBlock * SECTOR_SIZE);	} else {		ErrorCode = INVALID_BLOCK;	/* tells us if there was an error erasing flash */		return ErrorCode;	}	/* A write enable instruction must previously have been executed */	SendSingleCommand(SPI_WREN);	/*The status register will be polled to check the write enable latch "WREN" */	ErrorCode = Wait_For_WEL();	if (POLL_TIMEOUT == ErrorCode) {		printf("SPI Erase block error\n");		return ErrorCode;	} else		/*Turn on the SPI to send single commands */		SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));	/* Send the erase block command to the flash followed by the 24 address  */	/* to point to the start of a sector. */	*pSPI_TDBR = SPI_SE;	sync();	Wait_For_SPIF();	ShiftValue = (ulSectorOff >> 16);	/* Send the highest byte of the 24 bit address at first */	*pSPI_TDBR = ShiftValue;	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	ShiftValue = (ulSectorOff >> 8);	/* Send the middle byte of the 24 bit address  at second */	*pSPI_TDBR = ShiftValue;	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	*pSPI_TDBR = ulSectorOff;	/* Send the lowest byte of the 24 bit address finally */	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	/*Turns off the SPI */	SPI_OFF();	/* Poll the status register to check the Write in Progress bit */	/* Sector erase takes time */	ErrorCode = Wait_For_Status(WIP);	/* block erase should be complete */	return ErrorCode;}/****************************************************************************** ERROR_CODE ReadData()** Read a value from flash for verify purpose** Inputs:	unsigned long ulStart - holds the SPI start address*			int pnData - pointer to store value read from flash*			long lCount - number of elements to read***************************************************************************** */ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData){	unsigned long ShiftValue;	char *cnData;	int i;	cnData = (char *)pnData;	/* Pointer cast to be able to increment byte wise */	/* Start SPI interface   */	SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));	*pSPI_TDBR = SPI_READ;	/* Send the read command to SPI device */	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	ShiftValue = (ulStart >> 16);	/* Send the highest byte of the 24 bit address at first */	*pSPI_TDBR = ShiftValue;	/* Send the byte to the SPI device */	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	ShiftValue = (ulStart >> 8);	/* Send the middle byte of the 24 bit address  at second */	*pSPI_TDBR = ShiftValue;	/* Send the byte to the SPI device */	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	*pSPI_TDBR = ulStart;	/* Send the lowest byte of the 24 bit address finally */	sync();	Wait_For_SPIF();	/* Wait until the instruction has been sent */	/* After the SPI device address has been placed on the MOSI pin the data can be */	/* received on the MISO pin. */	for (i = 0; i < lCount; i++) {		*pSPI_TDBR = 0;	/*send dummy */		sync();		while (!(*pSPI_STAT & RXS)) ;		*cnData++ = *pSPI_RDBR;	/*read  */		if ((i >= SECTOR_SIZE) && (i % SECTOR_SIZE == 0))			printf(".");	}	SPI_OFF();		/* Turn off the SPI */	return NO_ERR;}ERROR_CODE WriteFlash(unsigned long ulStartAddr, long lTransferCount,		      int *iDataSource, long *lWriteCount){	unsigned long ulWAddr;	long lWTransferCount = 0;	int i;	char iData;	char *temp = (char *)iDataSource;	ERROR_CODE ErrorCode = NO_ERR;	/* tells us if there was an error erasing flash */	/* First, a Write Enable Command must be sent to the SPI. */	SendSingleCommand(SPI_WREN);	/* Second, the SPI Status Register will be tested whether the  */	/*         Write Enable Bit has been set.  */	ErrorCode = Wait_For_WEL();	if (POLL_TIMEOUT == ErrorCode) {		printf("SPI Write Time Out\n");		return ErrorCode;	} else		/* Third, the 24 bit address will be shifted out the SPI MOSI bytewise. */		SetupSPI((COMMON_SPI_SETTINGS | TIMOD01));	/* Turns the SPI on */	*pSPI_TDBR = SPI_PP;	sync();	Wait_For_SPIF();	/*wait until the instruction has been sent */	ulWAddr = (ulStartAddr >> 16);	*pSPI_TDBR = ulWAddr;	sync();	Wait_For_SPIF();	/*wait until the instruction has been sent */	ulWAddr = (ulStartAddr >> 8);	*pSPI_TDBR = ulWAddr;	sync();	Wait_For_SPIF();	/*wait until the instruction has been sent */	ulWAddr = ulStartAddr;	*pSPI_TDBR = ulWAddr;	sync();	Wait_For_SPIF();	/*wait until the instruction has been sent */	/* Fourth, maximum number of 256 bytes will be taken from the Buffer */	/* and sent to the SPI device. */	for (i = 0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++) {		iData = *temp;		*pSPI_TDBR = iData;		sync();		Wait_For_SPIF();	/*wait until the instruction has been sent */		temp++;	}	SPI_OFF();		/* Turns the SPI off */	/* Sixth, the SPI Write in Progress Bit must be toggled to ensure the  */	/* programming is done before start of next transfer. */	ErrorCode = Wait_For_Status(WIP);	if (POLL_TIMEOUT == ErrorCode) {		printf("SPI Program Time out!\n");		return ErrorCode;	} else		*lWriteCount = lWTransferCount;	return ErrorCode;}ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData){	unsigned long ulWStart = ulStart;	long lWCount = lCount, lWriteCount;	long *pnWriteCount = &lWriteCount;	ERROR_CODE ErrorCode = NO_ERR;	while (lWCount != 0) {		ErrorCode = WriteFlash(ulWStart, lWCount, pnData, pnWriteCount);		/* After each function call of WriteFlash the counter must be adjusted */		lWCount -= *pnWriteCount;		/* Also, both address pointers must be recalculated. */		ulWStart += *pnWriteCount;		pnData += *pnWriteCount / 4;	}	/* return the appropriate error code */	return ErrorCode;}#endif				/* CONFIG_SPI */

⌨️ 快捷键说明

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