#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
#include <driverLib/timer.h>
#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/drivers/SPI.h>
#include <ti/drivers/spi/SPICC26XXDMA.h>
#include <ti/drivers/dma/UDMACC26XX.h>
#include <stdint.h>
#include "string.h"
#include "Board.h"
#include "SDCard.h"
/*******************************************************************************
* GLOBAL variables
*/
uint8_t SDWorked_Status = 0;
/*******************************************************************************
* LOCAL variables
*/
PIN_Config SPICSN_GpioInitTable[] = {
Board_SPI0_CSN | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH| PIN_PUSHPULL | PIN_DRVSTR_MIN,
PIN_TERMINATE
};
PIN_Handle SPICSN_Pin_Handle = NULL;
PIN_State SPICSN_Pin_State;
static SPI_Handle spiHandle = NULL;
static SPI_Params spiParams;
static uint8_t SPI_TransactionStatus_Success = false;
static uint8_t SD_Type=0;
///*******************************************************************************
//* @fn transferCallback
//*
//* @brief Callback function
//*
//* @param SPI_Handle, SPI_Transaction
//*
//* @return None
//*/
static void transferCallback(SPI_Handle handle, SPI_Transaction *transaction)
{
SPI_TransactionStatus_Success = true;
}
///*******************************************************************************
// * @fn bspSpiClose
// *
// * @brief Close the RTOS SPI driver
// *
// * @return none
// */
//void bspSpiClose(void)
//{
// if (spiHandle != NULL)
// {
// SPI_close(spiHandle);
// spiHandle = NULL;
// }
//}
//
//
//void bspSpiFlush(void)
//{
// /* make sure SPI hardware module is done */
// while(SSIBusy(((SPICC26XX_HWAttrs*)spiHandle->hwAttrs)->baseAddr))
// { };
//}
//
//
/*******************************************************************************
* @fn bspSpiWriteRead
*
* @brief Write to and read from an SPI device in the same transaction
*
* @param txBuf - pointer to data buffer
* @param rxBuf - pointer to data buffer
* @param wlen - number of bytes to write
*
* @return
*/
uint8_t bspSpiWriteRead(uint8_t *txBuf, uint8_t *rxBuf, uint16_t wlen)
{
SPI_Transaction masterTransaction;
bool success;
masterTransaction.count = wlen;
masterTransaction.txBuf = txBuf;
masterTransaction.rxBuf = rxBuf;
success = SPI_transfer(spiHandle, &masterTransaction);
return success;
}
// Write to an SPI device
int bspSpiWrite(const uint8_t *buf, size_t length)
{
SPI_Transaction masterTransaction;
bool success;
masterTransaction.count = length;
masterTransaction.txBuf = (void*)buf;
masterTransaction.arg = NULL;
masterTransaction.rxBuf = NULL;
success = SPI_transfer(spiHandle, &masterTransaction);
return success ? 0 : -1;
}
// Read from an SPI device
int bspSpiRead(uint8_t *buf, size_t length)
{
SPI_Transaction masterTransaction;
bool success;
masterTransaction.count = length;
masterTransaction.txBuf = NULL;
masterTransaction.arg = NULL;
masterTransaction.rxBuf = buf;
success = SPI_transfer(spiHandle, &masterTransaction);
return success ? 0 : -1;
}
/*
// Write and read from an SPI device
int bspSpiWriteRead(uint8_t *buf, uint8_t wlen, uint8_t rlen)
{
SPI_Transaction masterTransaction;
bool success;
masterTransaction.count = wlen + rlen;
masterTransaction.txBuf = buf;
masterTransaction.arg = NULL;
masterTransaction.rxBuf = buf;
success = SPI_transfer(spiHandle, &masterTransaction);
if (success)
{
memcpy(buf,buf+wlen,rlen);
}
return success ? 0 : -1;
}*/
/* See bsp_spi.h file for description */
void bspSpiFlush(void)
{
/* make sure SPI hardware module is done */
while(SSIBusy(((SPICC26XX_HWAttrs*)spiHandle->hwAttrs)->baseAddr))
{ };
}
/* See bsp_spi.h file for description */
void bspSpiClose(void)
{
if (spiHandle != NULL)
{
SPI_close(spiHandle);
spiHandle = NULL;
}
}
/*******************************************************************************
* @fn SD_Enable
*
* @brief Select/deselect the SD Card
*
* @param select - true to select, false to deselect
*
* @return none
*/
void selectCSN(bool status)
{
if (status)
{
PIN_setOutputValue(SPICSN_Pin_Handle,PIN_ID(Board_SPI0_CSN),Board_SPI0_CSN_ON);
}
else
{
PIN_setOutputValue(SPICSN_Pin_Handle,PIN_ID(Board_SPI0_CSN),Board_SPI0_CSN_OFF);
}
}
/*******************************************************************************
* Function Name : SPI_SetSpeed
* Description : SPI设置速度为高速
* Input : u8 SpeedSet
* 如果速度设置输入0,则低速模式,非0则高速模式
* SPI_SPEED_HIGH 1
* SPI_SPEED_LOW 0
* Output : None
* Return : None
*******************************************************************************/
void SPI_SetSpeed(uint8_t SpeedSet)
{
bspSpiClose();
SPI_Params_init(&spiParams);
//如果速度设置输入0,则低速模式,非0则高速模式
if(SpeedSet==0)
{
spiParams.bitRate = 100000;
}
else
{
spiParams.bitRate = 4000000;
}
spiParams.frameFormat = SPI_POL1_PHA1;
spiParams.mode = SPI_MASTER;
// spiParams.transferMode = SPI_MODE_BLOCKING;
// spiParams.transferMode = SPI_MODE_CALLBACK;
// spiParams.transferCallbackFxn = transferCallback;
spiHandle = SPI_open(Board_SPI0, &spiParams);
if (spiHandle == NULL)
{
Task_exit();
}
}
void SPI_Configuration(void)
{
if(SPICSN_Pin_Handle == NULL)
{
SPICSN_Pin_Handle = PIN_open(&SPICSN_Pin_State, SPICSN_GpioInitTable);
}
SPI_SetSpeed(0); //设置SPI速度为低速
}
/*******************************************************************************
* Function Name : SD_SPIWriteRead_OneByte
* Description : SPI读写一个字节(发送完成后返回本次通讯读取的数据)
* Input : unit8_t txData 待发送的数
* Output : None
* Return : uint8_t txData 收到的数
*******************************************************************************/
/*
uint8_t SD_SPI_ReadWriteByte(uint8_t Data)
{
uint8_t status = 0;
uint8_t txData[1] = {0xAA};
uint8_t rxData[1] = {0xAA};
txData[0] = Data;
status = bspSpiWriteRead(txData, rxData, 1);
if(status)
{
// bspSpiFlush();
// while(SPI_TransactionStatus_Success == false);
// SPI_TransactionStatus_Success = false;
return rxData[0];
}
else
{
return 0;
}
}
*/
uint8_t SD_SPI_ReadWriteByte(uint8_t *wBuf, uint16_t wLen)
{
uint8_t status = 0;
uint8_t rBuf[2];
if(wLen == 1)
{
status = bspSpiWriteRead(wBuf, rBuf, wLen);
}
else if(wLen > 1)
{
status = bspSpiWriteRead(wBuf, NULL, wLen);
}
if(status)
{
return rBuf[0];
}
else
{
return 0;
}
}
//SD卡初始化的时候,需要低速
void SD_SPI_SpeedLow(void)
{
SPI_SetSpeed(0);//设置到低速模式
}
//SD卡正常工作的时候,可以高速了
void SD_SPI_SpeedHigh(void)
{
SPI_SetSpeed(1);//设置到高速模式
}
//SPI硬件层初始化
void SD_SPI_Init(void)
{
SPI_init();
SPI_Configuration();
}
///////////////////////////////////////////////////////////////////////////////////
//取消选择,释放SPI总线
void SD_DisSelect(void)
{
uint8_t temp;
selectCSN(false);
temp = 0xFF;
SD_SPI_ReadWriteByte(&temp, 1);//提供额外的8个时钟
}
//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
uint8_t SD_Select(void)
{
selectCSN(true);
if(SD_WaitReady()==0)return 0;//等待成功
SD_DisSelect();
return 1;//等待失败
}
//等待卡准备好
//返回值:0,准备好了;其他,错误代码
uint8_t SD_WaitReady(void)
{
uint8_t temp;
temp = 0xFF;
if(SDWorked_Status == 0)
{
SD_SPI_ReadWriteByte(&temp, 1);
SD_SPI_ReadWriteByte(&temp, 1);
return 0;
}
else
{
uint32_t t=0;
do
{
if(SD_SPI_ReadWriteByte(&temp, 1)==0XFF)return 0;//此处有时得不到0xFF,而是0x00
t++;
}while(t<0XFFFFFF);//等待
return 1;
}
}
//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
// 其他,得到回应值失败
uint8_t SD_GetResponse(uint8_t Response)
{
uint16_t Count=0xFFFF;//等待次数
uint8_t temp;
temp = 0xFF;
while ((SD_SPI_ReadWriteByte(&temp, 1)!=Response)&&Count)Count--;//等待得到准确的回应
if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
else return MSD_RESPONSE_NO_ERROR;//正确回应
}
//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
uint8_t SD_RecvData(uint8_t*buf,uint16_t len)
{
uint8_t temp;
temp = 0xFF;
if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
while(len--)//开始接收数据
{
*buf=SD_SPI_ReadWriteByte(&temp, 1);
buf++;
}
//下面是2个伪CRC(dummy CRC)
SD_SPI_ReadWriteByte(&temp, 1);
SD_SPI_ReadWriteByte(&temp, 1);
return 0;//读取成功
}
//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
{
uint16_t t;
uint8_t temp;
if(SD_WaitReady())return 1;//等待准备失效
temp = cmd;
SD_SPI_ReadWriteByte(&temp, 1);
if(cmd!=0XFD)//不是结束指令
{
// for(t=0;t<512;t++)
// {
// temp = buf[t];
// SD_SPI_ReadWriteByte(&temp, 1);
// }
SD_SPI_ReadWriteByte(buf, 512);
temp = 0xFF;
SD_SPI_ReadWriteByte(&temp, 1);//忽略crc
SD_SPI_ReadWriteByte(&temp, 1);
t = SD_SPI_ReadWriteByte(&temp, 1);//接收响应
if((t&0x1F)!=0x05)return 2;//响应错误
}
return 0;//写入成功
}
//向SD卡发送一个命令
//输入: u8 cmd 命令
// u32 arg 命令参数
// u8 crc crc校验值
//返回值:SD卡返回的响应
uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
uint8_t r1;
uint8_t Retry=0;
uint8_t temp;
SD_DisSelect();//取消上次片选
if(SD_Select())return 0XFF;//片选失效
//发送
temp = cmd | 0x40;
SD_SPI_ReadWriteByte(&temp, 1);//分别写入命令
temp = arg >> 24;
SD_SPI_ReadWriteByte(&temp, 1);
temp = arg >> 16;
SD_SPI_ReadWriteByte(&temp, 1);
temp = arg >> 8;
SD_SPI_ReadWriteByte(&temp, 1);
temp = arg;
SD_SPI_ReadWriteByte(&temp, 1);
temp = crc;
SD_SPI_ReadWriteByte(&temp, 1);
if(cmd==CMD12)
{
temp = 0xFF;
SD_SPI_ReadWriteByte(&temp, 1);//Skip a stuff byte when stop reading
}
//等待响应,或超时退出
Retry=0X1F;
do
{
temp = 0xFF;
r1 = SD_SPI_ReadWriteByte(&temp, 1);
}while((r1 & 0X80) && Retry--);
//返回状态值
return r1;
}
//获取SD卡的CID信息,包括制造商信息
//输入: u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
// 1:错误
uint8_t SD_GetCID(uint8_t *cid_data)
{
uint8_t r1;
//发CMD10命令,读CID
r1=SD_SendCmd(CMD10,0,0x01);
if(r1==0x00)
{
r1=SD_RecvData(cid_data,16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
// 1:错误
uint8_t SD_GetCSD(uint8_t *csd_data)
{
uint8_t r1;
r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
if(r1==0)
{
r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
//获取SD卡的总扇区数(扇区数)
//返回值:0: 取容量出错
// 其他:SD卡的容量(扇区数/512字节)
//每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
uint32_t SD_GetSectorCount(void)
{
uint8_t csd[16];
uint32_t Capacity;
uint8_t n;
uint16_t csize;
//取CSD信息,如果期间出错,返回0
if(SD_GetCSD(csd)!=0) return 0;
//如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
Capacity = (uint32_t)csize << 10;//得到扇区数
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
Capacity= (uint32_t)csize << (n - 9);//得到扇区数
}
return Capacity;
}
//初始化SD卡
uint8_t SD_Initialize(void)
{
uint8_t r1; // 存放SD卡的返回值
uint16_t retry; // 用来进行超时计数
uint8_t buf[4];
uint16_t i;
uint8_t temp;
SD_SPI_Init();
SD_SPI_SpeedLow(); //设置到低速模式
for(i=0;i<10;i++)
{
temp = 0xFF;
SD_SPI_ReadWriteByte(&temp, 1);//发送最少74个脉冲
}
retry=20;
do
{
r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
}while((r1!=0X01) && retry--);
SD_Type=0;//默认无卡
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
temp = 0xFF;
for(i=0;i<4;i++)
{
buf[i]=SD_SPI_ReadWriteByte(&temp, 1); //Get trailing return value of R7 resp
}
if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
{
retry=0XFFFE;
do
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
}while(r1&&retry--);
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
{
for(i=0;i<4;i++)
{
buf[i]=SD_SPI_ReadWriteByte(&temp, 1);//得到OCR值
}
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //检查CCS
else SD_Type=SD_TYPE_V2;
}
}
}else//SD V1.x/ MMC V3
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41
if(r1<=1)
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //等待退出IDLE模式
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
}while(r1&&retry--);
}else
{
SD_Type=SD_TYPE_MMC;//MMC V3
retry=0XFFFE;
do //等待退出IDLE模式
{
r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
}
}
SD_DisSelect();//取消片选
SD_SPI_SpeedHigh();//高速
if(SD_Type)return 0;
else if(r1)return r1;
return 0xaa;//其他错误
}
//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
uint8_t r1;
if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD17,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_RecvData(buf,512);//接收512个字节
}
}else
{
r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
do
{
r1=SD_RecvData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SD_SendCmd(CMD12,0,0X01); //发送停止命令
}
SD_DisSelect();//取消片选
return r1;//
}
//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
uint8_t r1;
if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD24,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_SendBlock(buf,0xFE);//写512个字节
}
}else
{
if(SD_Type!=SD_TYPE_MMC)
{
SD_SendCmd(CMD55,0,0X01);
SD_SendCmd(CMD23,cnt,0X01);//发送指令
}
r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
if(r1==0)
{
do
{
r1=SD_SendBlock(buf,0xFC);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
r1=SD_SendBlock(0,0xFD);//接收512个字节
}
}
SD_DisSelect();//取消片选
return r1;//
}
//以下三个函数是用于在SD卡中创建文件时为所创建的文件加入时间戳(“SD_RTC_Init(void),SD_RTC_Set(UTCTimeStruct *pTimer),SD_RTC_Get(UTCTimeStruct *pTimer)”)。SD_RTC_Init(void)是RTC时钟初始化函数,SD_RTC_Set(UTCTimeStruct *pTimer)设置最初的起始时间,SD_RTC_Get(UTCTimeStruct *pTimer)得到当前的时间年月日时分秒。
void SD_RTC_Init(void)
{
UTC_init();
UTCTimeStruct SetTime;
SetTime.year = 2017;
SetTime.month = 3;
SetTime.day = 3;
SetTime.hour = 3;
SetTime.minutes = 3;
SetTime.seconds = 3;
SD_RTC_Set(&SetTime);
}
void SD_RTC_Set(UTCTimeStruct *pTimer)
{
UTCTimeStruct SetTime;
UTCTime SetTime_seconds;
SetTime.year = pTimer->year;
SetTime.month = pTimer->month - 1;
SetTime.day = pTimer->day - 1;
SetTime.hour = pTimer->hour - 1;
SetTime.minutes = pTimer->minutes;
SetTime.seconds = pTimer->seconds;
SetTime_seconds = UTC_convertUTCSecs(&SetTime);
UTC_setClock(SetTime_seconds);
}
void SD_RTC_Get(UTCTimeStruct *pTimer)
{
UTCTimeStruct GetTime;
UTC_convertUTCTime(&GetTime, UTC_getClock());
pTimer->year = GetTime.year;
pTimer->month = GetTime.month + 1;
pTimer->day = GetTime.day + 1;
pTimer->hour = GetTime.hour + 1;
pTimer->minutes = GetTime.minutes;
pTimer->seconds = GetTime.seconds;
}
基于CC2640 SPI口的SD卡驱动程序
最新推荐文章于 2025-05-10 11:13:28 发布