基于CC2640 SPI口的SD卡驱动程序

该代码段展示了如何在TICC2650平台上初始化和操作SPI接口,特别是与SD卡的通信。它涵盖了SPI配置、速度设置、读写交易以及SD卡的选通、命令发送和数据传输。还包括了电源管理的相关头文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#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;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值