📄 sd_card.c
字号:
/************************************************************************************/
/* sd_card.c: 27/10/2006 */
/* */
/* 外部程序会使用到的函数:sd_init, user_new_file, sd_write_file, spi_init */
/* bcd_to_ascii, ascii_to_bcd, chars_to_int, ints_to_long */
/* delay */
/* */
/************************************************************************************/
#include "sd_card.h"
#include "pcf8563.h"
//#include <msp430x16x.h>
#include "msp430x14x.h"
/* SD卡信息 */
//static unsigned long sd_address; //SD卡中的物理地址
static unsigned long sd_fat1_addr; //FAT1的开始地址
static unsigned long sd_fat2_addr; //FAT2的开始地址
static unsigned long sd_fdt_addr; //FDT的开始地址
static unsigned long sd_data_addr; //DATA(用户数据区)的开始地址
static unsigned int sd_rs; //relative sectors 相对扇区数
static unsigned int sd_rsc; //reserved sectors 保留扇区数
static unsigned int sd_sf; //sectors per FAT 每个FAT表扇区数
static unsigned char sd_fnum; //FAT numbers FAT表个数
static unsigned int sd_mcn; //the max cluster number 最大簇号
static unsigned char sd_sc; //sectors per cluster 每簇扇区数
static unsigned long sd_ts; //total sectors 总扇区数
/* 工作目录信息 */
static unsigned int dir_firstc; //工作目录的首簇簇号
static unsigned int dir_lastc; //工作目录的末簇簇号(最后一个登记项)
static unsigned char dir_sector; //工作目录的末扇区号(最后一个登记项)0~SC-1
static unsigned int dir_byte; //工作目录的扇区内字节偏移
//(最后一个登记项的首字节) 0~480(32的倍数)
/* 文件信息 */
static unsigned int c_file; //簇号(待写入文件的首字节位置)
static char s_file; //扇区号,0~SC-1(待写入文件的首字节位置)
static unsigned int b_file; //扇区内字节偏移,0~511(待写入文件的首字节位置)
static unsigned int c_attr; //文件属性(登记项)所在的簇号
static char s_attr; //文件属性(登记项)所在的扇区号 0~SC-1
static unsigned int b_attr; //文件属性(登记项)所在的扇区内字节偏移,0~480(32的倍数)
static unsigned int c_read; //上次读的簇号
static char s_read; //上次读的扇区号
static unsigned int c_first; //文件首簇的簇号
/* 其它信息 */
//FAT表目前扇区号,目的避免从第一扇区查找空簇花费大量的时间
static unsigned int fat_offset;
//工作目录名:USERDATA,扩展名为空格,说明其为文件夹
static char dir_name[11] = {'U','S','E','R','D','A','T','A',' ',' ',' '};
//文件名,由实时时钟的时间命名: DDhhmmss.LOG
static char file_name[11] = {0,0,0,0,0,0,0,0,'L','O','G'};
char sd_buffer[BUFFER_LENGTH] = {0}; //数据缓存区
unsigned int indicator; //待写入SD卡的字节数,指示待写入数据末字节的位置
//注意:
//sd_buffer[0]~sd_buffer[indicator-1]为待写入SD卡的数据
//若indicator不是512的整数倍,调用sd_write_file时会把sd_buffer[indicator-1]之后
//至512整数倍的字节写入SD卡,然后把该扇区的内容读出,储存在sd_buffer[0]~sd_buffer[511]
//中以供下次调用函数时重新写入.(这是因为读写SD卡时只能以扇区为单位进行)
//同时更新indicator=b_file,下次储存数据时从sd_buffer[indicator]开始!!!!
//注意sd_buffer[]的长度要满足实际使用要求!
/* 外部变量 */
extern char pcf_bday,pcf_bhour,pcf_bminute,pcf_bsecond;
extern char pcf_b10ms;
extern unsigned int pcf_wdate,pcf_wtime;
/****************************************************************************/
/* 延时函数 */
/* Function : delay */
/* Input : unsinged long t --延时时间(毫秒) */
/* Output : Nothing */
/* Description : */
/* 利用指令运行的时间延时,一次循环需要7个时钟周期,假定时钟频率使用 */
/* 8MHz,则延时t毫秒需要的循环次数为:t*8000/7 */
/****************************************************************************/
void delay(unsigned long t)
{
unsigned long i;
i = t*8000/7;
while(--i);
}
//在430中,当t*8000超过65535时,t和i都必须是长整型运算才正确.
/****************************************************************************/
/* 初始化SPI */
/* Function : spi_init */
/* Input : none */
/* Output : none */
/* Description : */
/* P5.4 as SD select,P5.1-5.3 SPI option select,P5.0 as SD dectecting */
/****************************************************************************/
void spi_init(void)
{
UCTL1 = CHAR + SYNC + MM + SWRST; // 8-bit, SPI, Master
UTCTL1 = CKPH + SSEL1 + SSEL0 + STC; // SMCLK, 3-pin mode, clock idle low, data valid on rising edge, UCLK delayed
UBR01 = 0x02; // 0x02: SMCLK/2 for baud rate (4M)
UBR11 = 0x00; //
UMCTL1 = 0x00; // no modulation
P5SEL |= 0x0E; // P5.1-3 SPI option select
P5DIR |= 0x1A; // P5.4,P5.3,P5.1 output direction
ME2 |= USPIE1; // Enable USART1 SPI mode
UCTL1 &= ~SWRST; // SPI enable
}
/****************************************************************************/
/* SPI通讯子函数 */
/* Function : spi_send_byte */
/* Input : const unsigned char data -- the byte to transfer */
/* Output : unsigned char -- the byte received */
/* Description : */
/* */
/****************************************************************************/
unsigned char spi_send_byte(const unsigned char data)
{
while ((IFG2&UTXIFG1) ==0); // wait while not ready for TX
TXBUF1 = data; // write
while ((IFG2 & URXIFG1)==0); // wait for RX buffer
return (RXBUF1);
}
/**************************************************************************/
/* Function : sd_send_cmd */
/* Input : const char cmd -- 命令编号 */
/* : unsigned long data -- 命令参数 */
/* : */
/* Output : none */
/* Description : 发送一个命令 */
/**************************************************************************/
void sd_send_cmd(const char cmd, unsigned long data)
{
char frame[6];
char temp;
int i;
frame[0]=(cmd|0x40);
//把data从高字节到低字节依次取出放入frame[1]~frame[4]中
for(i=3;i>=0;i--)
{
temp=(char)(data>>(8*i));
frame[4-i]=(temp);
}
//CMD0的CRC校验码为0x95,其它命令在SPI模式下的校验码被忽略,故都用0x95
frame[5]=0x95;
for(i=0;i<6;i++)
spi_send_byte(frame[i]);
}
/****************************************************************************/
/* 接收SD Card的响应 (包括R1响应和单块读时的开始字节0xfe) */
/* Function : sd_get_response */
/* Input : none */
/* Output : char response -- 接收到的响应 */
/* Description : */
/****************************************************************************/
char sd_get_response(void)
{
//Response comes 1-8bytes after command
int i=0;
char response;
while(i<=64)
{
response=spi_send_byte(0xff);
if(response!=0xff) break;
//if(response==0x00)break;
//if(response==0x01)break;
i++;
}
return response;
}
/*******************************************************************************/
/* Function : sd_check_busy */
/* Input : none */
/* Output : char */
/* Description : */
/* 接收数据响应 xxx0<status>1 : status 010: Data accected, status 101: Data */
/* rejected due to a crc error, status 110: Data rejected due to a Write error*/
/* 然后等待清除busy信号 */
/*******************************************************************************/
char sd_check_busy(void)
{
int i=0;
char response;
char rvalue;
while(i<=64)
{
response=spi_send_byte(0xff);
response &= 0x1f;
switch(response)
{
case 0x05: rvalue=SD_SUCCESS; break;
case 0x0b: return(SD_CRC_ERROR);
case 0x0d: return(SD_WRITE_ERROR);
default:
rvalue = SD_OTHER_ERROR;
break;
}
if(rvalue == SD_SUCCESS) break;
i++;
}
i=0;
do
{
response=spi_send_byte(0xff);
i++;
}while(response == 0);
return rvalue;
}
/*******************************************************************************/
/* Function : sd_set_blocklen */
/* Input : const unsigned long blocklen -- block length (2^n) */
/* Output : char response -- R1响应 */
/* Description : 设置块的长度,默认块的长度定义在CSD中,一般为512字节 */
/*******************************************************************************/
char sd_set_blocklen (const unsigned long blocklen)
{
char response;
CS_LOW();
sd_send_cmd(CMD16, blocklen);
// get response from SD - make sure that it's 0x00 (R1 ok response format)
//if(sd_get_response()!=0x00);
response = sd_get_response();
CS_HIGH();
// Send 8 Clock pulses of delay.
spi_send_byte(0xff);
return response;
}
/*******************************************************************************/
/* Function : sd_delay */
/* Input : char number -- 待发送的字节数 */
/* Output : none */
/* Description : 发送空字节(0xff) */
/*******************************************************************************/
void sd_delay(char number)
{
char i;
for(i=0;i<number;i++)
spi_send_byte(0xff); //clock out an idle byte(0xff)
}
/*******************************************************************************/
/* Function : sd_detection */
/* Input : none */
/* Output : none */
/* Description : 检查SD卡是否就位,卡没就位时红绿灯交替闪烁 */
/* SD_CD脚为0表示卡已就位,退出循环 */
/*******************************************************************************/
void sd_detection(void)
{
while(P5IN&SD_CD)
{
LED_RED_ON();
delay(500); // delay 500 milliseconds
LED_RED_OFF();
LED_GREEN_ON();
delay(500); // delay 500 milliseconds
LED_GREEN_OFF();
}
}
/*******************************************************************************/
/* Function : sd_read_block */
/* Input : const unsigned long address -- SD卡中的物理地址 */
/* char *index -- 接收数据的数组的首地址 */
/* Output : char -- 读取成功与否的状态码 */
/* Description : 写入成功后返回SD_SUCCESS (0x00) */
/*******************************************************************************/
char sd_read_block(const unsigned long address,char *index)
{
unsigned int i;
char rvalue = SD_RESPONSE_ERROR;
char *p;
p = index;
CS_LOW();
sd_send_cmd(CMD17,address);
if(sd_get_response() == 0)
{
if(sd_get_response() == 0xfe)
{
for(i = 0;i < 512;i++)
*(p+i) = spi_send_byte(0xff);
// get CRC bytes (not really needed by us, but required by SD card)
spi_send_byte(0xff);
spi_send_byte(0xff);
rvalue = SD_SUCCESS;
}
else
rvalue = SD_DATA_TOKEN_ERROR;
}
CS_HIGH();
spi_send_byte(0xff);
return rvalue;
}
/*******************************************************************************/
/* Function : sd_write_block */
/* Input : const unsigned long address -- SD卡的物理地址 */
/* char *index -- 待发送数组的首地址 */
/* Output : char -- 读取成功与否的状态码 */
/* Description : 写入成功后返回SD_SUCCESS (0x00) */
/*******************************************************************************/
char sd_write_block(const unsigned long address, char *index)
{
unsigned int i;
char rvalue = SD_RESPONSE_ERROR;
char *p;
p = index;
CS_LOW();
sd_send_cmd(CMD24,address);
if(sd_get_response() == 0)
{
//need 8 clock cycles before the data block is started
spi_send_byte(0xff);
//send the data token to signify the start of the data
spi_send_byte(0xfe);
//clock the actual data transfer and transmit the bytes
for(i=0;i<512;i++)
spi_send_byte(*(p+i));
//put CRC bytes (not really needed by us, but required by SD card)
spi_send_byte(0xff);
spi_send_byte(0xff);
rvalue = sd_check_busy();
}
CS_HIGH();
spi_send_byte(0xff);
return rvalue;
}
/*******************************************************************************/
/* Function : sd_init */
/* Input : none */
/* Output : none */
/* Description : 初始化SD卡并进入SPI模式,读取卡信息,打开或新建工作目录 */
/*******************************************************************************/
void sd_init(void)
{
//unsigned int i;
sd_detection(); //检查SD卡是否插好
spi_init(); //初始化SPI
fat_offset = 0; //FAT表目前扇区号为0
// Delay for at least 74 clock cycles. This means to actually
//clock out at least 74 clock cycles with no data present on
// the clock. In SPI mode, send at least 10 idle bytes (0xFF).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -