一个比较高效的SPI方式SD卡的驱动
2011-07-28 19:51
330 查看
原文出处:http://blog.ednchina.com/shishougang/206753/message.aspx
标签: SPI SD
/* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#ifndef __SPI_MMC_H__
#define __SPI_MMC_H__
#define SPI_SEL 16#define SET_MMC_CS FIO0SET = (1 << SPI_SEL);
#define CLR_MMC_CS FIO0CLR = (1 << SPI_SEL);
#define MMC_CMD_SIZE 6 // the SPI data is 8 bit long, the MMC use 48 bits, 6 bytes
#define MMC_DATA_SIZE 512 // data of one sector in byte
#define MAX_TIMEOUT 0xFF // retry times#define GO_IDLE_STATE 0x00
#define SEND_CSD 0x09
#define SEND_CID 0x0A
#define READ_SINGLE_BLOCK 0x11
#define WRITE_SINGLE_BLOCK 0x18
#define SEND_OP_COND 0x29
#define APP_CMD 0x37
#define CRC_ON_OFF 0x3B
void spiSend(BYTE *buffer, DWORD length);
void spiReceive(BYTE *buffer, DWORD length);
BYTE spiReceiveByte(void);
BYTE mmcInit(void);
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache);
BOOL mmcWriteSector(DWORD sector, BYTE *buffer);#endif
/******************************************************/
/* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#include <LPC214X.H>
#include "..\type.h"
#include "spi_mmc.h"
#define sspLowSpeed() SSPCPSR = 0x80;
#define sspHighSpeed() SSPCPSR = 0x08;
void sspSend(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = *buffer; // first byte to send
buffer ++;
length --;
while(length){
SSPDR = *buffer; // keep FIFO not empty nor not full
buffer ++;
length --;
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
void sspReceive(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = 0xFF;
length --;
while(length){
SSPDR = 0xFF; // keep FIFO not empty nor not full
while(!(SSPSR & 0x04));
*buffer = SSPDR;
buffer ++;
length --;
}
while(!(SSPSR & 0x04)); // last byte to receive
*buffer = SSPDR;
}
BYTE sspReceiveByte(void){
SSPDR = 0xFF;
while(SSPSR & 0x10);
return SSPDR;
}
void sspSendByte(BYTE data){
BYTE dummy;
SSPDR = data;
while(SSPSR & 0x10);
dummy = SSPDR;
}
BYTE mmcSendCommand(BYTE command, DWORD argument){
BYTE R1;
BYTE retry ;
BYTE MMCCmd[MMC_CMD_SIZE + 1];
MMCCmd[0]= command | 0x40;
MMCCmd[1]= argument >> 24;
MMCCmd[2]= argument >> 16;
MMCCmd[3]= argument >> 8;
MMCCmd[4]= argument;
if(!command)MMCCmd[5]= 0x95;
else MMCCmd[5]= 0xFF;
MMCCmd[6]= 0xFF;
sspSend(MMCCmd, MMC_CMD_SIZE + 1);
retry = MAX_TIMEOUT;
do{
R1 = sspReceiveByte();
if(!(retry --))break;
}while(R1 == 0xFF); sspReceiveByte(); return R1;
}
BYTE mmcInit(void){
BYTE i;
BYTE R1;
BYTE retry;
WORD dummy; PINSEL1 |= 0x000000A8; // enable SCK(P0.17), MISO(P0.18), MOSI(P0.19)
FIO0DIR |= 1 << SPI_SEL; // use P0.16 as SSEL of SSP port
FIO0SET = 1 << SPI_SEL;
SSPCR0 = 0x0007; // 8bit, SPI format, CPOL = 0, CPHA = 0, and SCR is 0
sspLowSpeed();
SSPCR1 = 0x02; // master mode, SSP enabled, normal operational mode while(SSPSR & 0x04)dummy = SSPDR; // clear the RxFIFO retry = MAX_TIMEOUT;
do{
SET_MMC_CS;
for(i = 0; i < 10; i ++)sspReceiveByte();
CLR_MMC_CS;
R1 = mmcSendCommand(GO_IDLE_STATE, 0); // CMD0
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1 != 0x01);
retry = MAX_TIMEOUT;
do{
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
R1 = mmcSendCommand(APP_CMD, 0); // CMD55
if(R1 != 0x01)continue;
R1 = mmcSendCommand(SEND_OP_COND, 0); // CMD41
}while(R1 != 0x00); retry = MAX_TIMEOUT;
do{
R1 = mmcSendCommand(1, 0); // send active command
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1);
sspHighSpeed();
mmcSendCommand(CRC_ON_OFF, 0); // disable CRC
mmcSendCommand(16, 512); // set sector size to 512
SET_MMC_CS;
return 0;
}
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache){
BYTE R1;
BYTE retry = MAX_TIMEOUT;
if(*SectorInCache == sector)return 0;
else *SectorInCache = sector;
CLR_MMC_CS; R1 = mmcSendCommand(READ_SINGLE_BLOCK, sector << 9); // read command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
} while(sspReceiveByte() != 0xFE){ // wait to start recieve data
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
} sspReceive(buffer, 512);
sspReceiveByte(); // dummy CRC
sspReceiveByte();
SET_MMC_CS;
sspReceiveByte(); // extra 8 CLK return 0;
}
BOOL mmcWriteSector(DWORD sector, BYTE *buffer){
BYTE R1;
WORD retry = 0xFFFF;
CLR_MMC_CS;
R1 = mmcSendCommand(WRITE_SINGLE_BLOCK, sector << 9); // write command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
sspReceiveByte();
sspReceiveByte();
sspSendByte(0xFE); // start transmit
sspSend(buffer, MMC_DATA_SIZE); // 512 bytes
sspReceiveByte(); // dummy CRC
sspReceiveByte();
R1 = sspReceiveByte();
if((R1 & 0x1F) != 0x05){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
while(!sspReceiveByte()){ // wait until write finish
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}
SET_MMC_CS;
sspReceiveByte();
return 0;
}
与通用的程序相比就是在连续发送和连续接收的地方作了一些简单处理。改动不大,但是提升的效率却很惊人,读取速度提高了能有50%左右。
标签: SPI SD
一个比较高效的SPI方式SD卡的驱动
流传的用SPI驱动SD卡的程序基本都是针对没有FIFO的SPI接口的,这样做程序比较通用;但是如果处理器的SPI接口有FIFO的话,那么FIFO的性能就浪费了。其实把程序稍加改动,就可以大幅度提高SD卡的读取速度,具体程序如下: /******************************************************//* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#ifndef __SPI_MMC_H__
#define __SPI_MMC_H__
#define SPI_SEL 16#define SET_MMC_CS FIO0SET = (1 << SPI_SEL);
#define CLR_MMC_CS FIO0CLR = (1 << SPI_SEL);
#define MMC_CMD_SIZE 6 // the SPI data is 8 bit long, the MMC use 48 bits, 6 bytes
#define MMC_DATA_SIZE 512 // data of one sector in byte
#define MAX_TIMEOUT 0xFF // retry times#define GO_IDLE_STATE 0x00
#define SEND_CSD 0x09
#define SEND_CID 0x0A
#define READ_SINGLE_BLOCK 0x11
#define WRITE_SINGLE_BLOCK 0x18
#define SEND_OP_COND 0x29
#define APP_CMD 0x37
#define CRC_ON_OFF 0x3B
void spiSend(BYTE *buffer, DWORD length);
void spiReceive(BYTE *buffer, DWORD length);
BYTE spiReceiveByte(void);
BYTE mmcInit(void);
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache);
BOOL mmcWriteSector(DWORD sector, BYTE *buffer);#endif
/******************************************************/
/* SD Card driver using SSP for LPC2148 */
/* by 314forever */
/* spi_mmc.c 2009.1 */
/******************************************************/
#include <LPC214X.H>
#include "..\type.h"
#include "spi_mmc.h"
#define sspLowSpeed() SSPCPSR = 0x80;
#define sspHighSpeed() SSPCPSR = 0x08;
void sspSend(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = *buffer; // first byte to send
buffer ++;
length --;
while(length){
SSPDR = *buffer; // keep FIFO not empty nor not full
buffer ++;
length --;
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
while(!(SSPSR & 0x04));
dummy = SSPDR;
}
void sspReceive(BYTE *buffer, DWORD length){
BYTE dummy;
while(SSPSR & 0x04)dummy = SSPDR; // clean FIFO
SSPDR = 0xFF;
length --;
while(length){
SSPDR = 0xFF; // keep FIFO not empty nor not full
while(!(SSPSR & 0x04));
*buffer = SSPDR;
buffer ++;
length --;
}
while(!(SSPSR & 0x04)); // last byte to receive
*buffer = SSPDR;
}
BYTE sspReceiveByte(void){
SSPDR = 0xFF;
while(SSPSR & 0x10);
return SSPDR;
}
void sspSendByte(BYTE data){
BYTE dummy;
SSPDR = data;
while(SSPSR & 0x10);
dummy = SSPDR;
}
BYTE mmcSendCommand(BYTE command, DWORD argument){
BYTE R1;
BYTE retry ;
BYTE MMCCmd[MMC_CMD_SIZE + 1];
MMCCmd[0]= command | 0x40;
MMCCmd[1]= argument >> 24;
MMCCmd[2]= argument >> 16;
MMCCmd[3]= argument >> 8;
MMCCmd[4]= argument;
if(!command)MMCCmd[5]= 0x95;
else MMCCmd[5]= 0xFF;
MMCCmd[6]= 0xFF;
sspSend(MMCCmd, MMC_CMD_SIZE + 1);
retry = MAX_TIMEOUT;
do{
R1 = sspReceiveByte();
if(!(retry --))break;
}while(R1 == 0xFF); sspReceiveByte(); return R1;
}
BYTE mmcInit(void){
BYTE i;
BYTE R1;
BYTE retry;
WORD dummy; PINSEL1 |= 0x000000A8; // enable SCK(P0.17), MISO(P0.18), MOSI(P0.19)
FIO0DIR |= 1 << SPI_SEL; // use P0.16 as SSEL of SSP port
FIO0SET = 1 << SPI_SEL;
SSPCR0 = 0x0007; // 8bit, SPI format, CPOL = 0, CPHA = 0, and SCR is 0
sspLowSpeed();
SSPCR1 = 0x02; // master mode, SSP enabled, normal operational mode while(SSPSR & 0x04)dummy = SSPDR; // clear the RxFIFO retry = MAX_TIMEOUT;
do{
SET_MMC_CS;
for(i = 0; i < 10; i ++)sspReceiveByte();
CLR_MMC_CS;
R1 = mmcSendCommand(GO_IDLE_STATE, 0); // CMD0
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1 != 0x01);
retry = MAX_TIMEOUT;
do{
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
R1 = mmcSendCommand(APP_CMD, 0); // CMD55
if(R1 != 0x01)continue;
R1 = mmcSendCommand(SEND_OP_COND, 0); // CMD41
}while(R1 != 0x00); retry = MAX_TIMEOUT;
do{
R1 = mmcSendCommand(1, 0); // send active command
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}while(R1);
sspHighSpeed();
mmcSendCommand(CRC_ON_OFF, 0); // disable CRC
mmcSendCommand(16, 512); // set sector size to 512
SET_MMC_CS;
return 0;
}
BOOL mmcReadSector(DWORD sector, BYTE *buffer, DWORD *SectorInCache){
BYTE R1;
BYTE retry = MAX_TIMEOUT;
if(*SectorInCache == sector)return 0;
else *SectorInCache = sector;
CLR_MMC_CS; R1 = mmcSendCommand(READ_SINGLE_BLOCK, sector << 9); // read command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
} while(sspReceiveByte() != 0xFE){ // wait to start recieve data
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
} sspReceive(buffer, 512);
sspReceiveByte(); // dummy CRC
sspReceiveByte();
SET_MMC_CS;
sspReceiveByte(); // extra 8 CLK return 0;
}
BOOL mmcWriteSector(DWORD sector, BYTE *buffer){
BYTE R1;
WORD retry = 0xFFFF;
CLR_MMC_CS;
R1 = mmcSendCommand(WRITE_SINGLE_BLOCK, sector << 9); // write command
if(R1 != 0x00){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
sspReceiveByte();
sspReceiveByte();
sspSendByte(0xFE); // start transmit
sspSend(buffer, MMC_DATA_SIZE); // 512 bytes
sspReceiveByte(); // dummy CRC
sspReceiveByte();
R1 = sspReceiveByte();
if((R1 & 0x1F) != 0x05){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
while(!sspReceiveByte()){ // wait until write finish
if(!(retry --)){
SET_MMC_CS;
sspReceiveByte();
return 1;
}
}
SET_MMC_CS;
sspReceiveByte();
return 0;
}
与通用的程序相比就是在连续发送和连续接收的地方作了一些简单处理。改动不大,但是提升的效率却很惊人,读取速度提高了能有50%左右。
相关文章推荐
- SPI方式驱动SD卡的方法
- 自己DIY一个智能家居模型框架--spi驱动
- S5PV210 Linux 模拟SPI方式控制ADS7846触摸屏驱动
- datalist 的用法。也是增删改查,但是比较智能。用数据绑定的方式,可以有不同的显示方法,下面是对一个表的增删改查的参考代码
- 一个多对多关系表的数据分页显示问题-sp_cursoropen 比较 临时表方式
- 单片机spi驱动SD卡
- 最近在搞SPI Flash的驱动,有一个问题迟迟不能解决
- W25Q128(W25Q系列SPI Flahs和W25X系列的SPI Flash)驱动,使用句柄方式,分离底层,便于移植
- 富文本(TTTAttributedLabel是一个替代,UILabel提供了一种简单的方式来高效地呈现属性字符串。作为奖励,它还支持链接嵌入,自动与NSTextCheckingTypes手动通过指定)
- stm32 SD卡 SPI驱动以及fatfs移植
- 在测试Adhesive的时候发现一个Mongodb官方驱动1.1.0.4184比较严重的BUG
- [Linux] 内核中 SPI 设备驱动模型(Platform设备驱动方式)
- STM32的简单的SD卡读写(不带文件系统,SPI方式)
- 转载_一个 SPI 转串口驱动的优化
- 刚写出来的一个扫雷 打开一片空白的递归函数 比较简洁布雷方式
- Serial Peripheral Interface Bus · Motorola SPI ARM PL022 控制器驱动移植 SPI接口的SD卡调试
- java中如何判断一个数是否为正整数(多种种方式比较有意思)对时间处理也可以
- 高并发网站更新数据库数据比较高效的方式
- 团队建设:一个团队从无到有再到高效的管理方式
- 一个 SPI 转串口驱动的优化