65.9K
CodeProject 正在变化。 阅读更多。
Home

COFILOS SD 卡驱动程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2017 年 4 月 4 日

CDDL

2分钟阅读

viewsIcon

9458

COFILOS SD 卡驱动程序

在 COFILOS 上开发 SD 卡驱动程序

去年,我完成了 COFILOS 和 Perseus 板的一个重要里程碑。我完成了一个完全使用 TDD 编写的 SD 卡驱动程序。

您可以查看以下视频 COFILOS SD Card

即使我从互联网上获得了指导代码和足够的相关信息,编写起来仍然很困难。结果是一个非常易读和有组织的的代码。

初始化阶段非常复杂(占用了实现时间的大部分),如下所示

/*!
* \brief Device Start (Stub)
* @param pstDriver_ : Pointer to Device structure
* @return 0 (SUCCESS), 1: Fail (Could not open SPI driver)
*/
BOOL f_DriverSD_Start(void *pstDriver_ )
{
type_stDRIVERSD *pst_SD;
INT8U v_error;
INT8U v_PhysDevID;
BOOL v_retval;

pst_SD = (type_stDRIVERSD *) pstDriver_;

if (pst_SD->stDriver.eState != DRIVER_CLOSE) return 1;
if (pst_SD->f_HAL_HookCardPresent == NULL) return 1;
if (pst_SD->f_HAL_HookCardPresent() == 0) return 255;

v_retval = 1; /* default is failure */

f_DriverSDHelper_InitSPI(pst_SD);

f_DriverCoFILOS_Open((PINT8) "SPI.Driver", 
0xFF, (DRIVER_STRUCT *) &pst_SD->st_SPI);

Driver_Start((DRIVER_STRUCT *) &pst_SD->st_SPI);

/* Acquire Mutex, we need uninterrupted SPI access */
Driver_Control((DRIVER_STRUCT *) &pst_SD->st_SPI, CMD_SET_SPIMUTEX_ON, NULL);

f_DriverSDHelper_ResetSD(pst_SD);

/* set default value for Unknown Card Type */
/* Assuming initially that all is good */
v_PhysDevID = pst_SD->v_PhyVolumeID;
st_SDPhysical[v_PhysDevID].v_UnknownCard = eSDUn_None;
pst_SD->v_CardType = eSDCardUnknown;

/* set CS, clocked */
f_DriverSDHelper_SelectDevice(pst_SD);

v_error = f_DriverSDHelper_SendCMD0(pst_SD);
if (v_error == 0xFE)
{
  /* Unknown Card */
  /* TODO: Unknown Card */
  f_DriverSDHelper_UnknownDevice(pst_SD->v_PhyVolumeID, eSDUn_CMD0);
}
else
{
  v_error = f_DriverSDHelper_SendCMD8(pst_SD);

  if (v_error == 0) /* SDV2 Byte or Block */
  {
    v_error = f_DriverSDHelper_SendACMD41(pst_SD, 0x40000000);
    v_error = f_DriverSDHelper_SendCMD58(pst_SD);

    if (pst_SD->v_CardType == eSDCardSDv2Byte)
    {
      v_error = f_DriverSDHelper_SendCMD16(pst_SD);
      st_SDPhysical[v_PhysDevID].v_CardType = eSDCardSDv2Byte;
    }
    else
    {
      st_SDPhysical[v_PhysDevID].v_CardType = eSDCardSDv2Block;
    }
  }
  else if (v_error == 0xFE) /* SDv1 or MMCv3 or Unknown ? */
 {
   st_SDPhysical[v_PhysDevID].v_CardType = eSDCardSDv1;
   v_error = f_DriverSDHelper_SendACMD41(pst_SD, 0x00000000);
   if (v_error != 0)
   {
     /* MMCv3 ? */
     v_error = f_DriverSDHelper_SendCMD1(pst_SD);
     if (v_error == 0)
    {
      st_SDPhysical[v_PhysDevID].v_CardType = eSDCardMMCv3;
    }
    else
    {
      f_DriverSDHelper_UnknownDevice(pst_SD->v_PhyVolumeID, eSDUn_CMD1);
    }
   }

   if (v_error == 0)
   {
     v_error = f_DriverSDHelper_SendCMD16(pst_SD);
   }
  }
  else
  {
    /* Unknown card */
    f_DriverSDHelper_UnknownDevice(pst_SD->v_PhyVolumeID, eSDUn_CMD8);
  }
}

/* if Card is SDv1 or better then acquire CSD/CID */
switch(st_SDPhysical[v_PhysDevID].v_CardType)
{
   case eSDCardSDv1:
   case eSDCardSDv2Block:
   case eSDCardSDv2Byte:
     f_DriverSDHelper_SendCMD9(pst_SD);
     f_DriverSDHelper_SendCMD10(pst_SD);
     break;
  default:;
}

/* Deassert CS, clocked */
f_DriverSDHelper_DeSelectDevice(pst_SD);

/* Release Mutex, finished exclusive SPI access */
Driver_Control((DRIVER_STRUCT *) &pst_SD->st_SPI, CMD_SET_SPIMUTEX_OFF, NULL);

if (st_SDPhysical[v_PhysDevID].v_CardType == eSDCardUnknown)
{
  v_retval = 1;
}
else
{
  st_SDPhysical[v_PhysDevID].v_DriverState = eSD_Started;
  v_retval = 0;
  pst_SD->st_SPI.v_ConfigReg = 0xA002; /* increase clock to 24MHz */
}
st_SDPhysical[v_PhysDevID].v_OpenCnt = 0;

return v_retval;

}

在主机(PC)上完成 TDD 阶段后,我需要在实际目标(ColdFire)微控制器上运行我的测试。

在下图中,您可以看到硬件设置以及我的程序员。我使用 Kingston 的 8GB micro-SD 卡进行测试。

sd_board

我已经捕获了 SD 卡的扇区(和镜像)并将它们保存在我的硬盘上。我希望能够比较微控制器读取的内容与实际存储的数据。

在目标运行代码后,我打开了一个 PuTTY 终端来连接我的目标上的虚拟 COM 端口。然后通过 CLI(命令行解释器)我挂载了 SD 卡。我发出了 SDInfo 命令,提供的数据是 SD 卡的“几何结构”。

sd_cli_init

然后我读取了扇区零(或 FAT 文件系统的 MBR)。我将数据与捕获的镜像进行比较,以确认读取了相同的信息。

sd_cli_rdsec0000

第一个 FAT 扇区 (0x2000) 也被读取并验证。我必须检查它,因为我需要在稍后阶段运行一个 FAT 文件系统处理程序来读取 SD 卡(虽然不是很快)。

sd_cli_rdsec2000

然后,开始写入测试。我 CLI 中的 write 命令目前支持写入单个 32 位值。这足以验证扇区写入操作。所以我使用了未使用的扇区 1 来写入值 0x1234567

sd_cli_wrsec0001

接下来,对扇区 1 进行读取以检查扇区是否已写入。瞧!请注意大端写入(字节 0 处为 0x78,而不是 0x12)。

sd_cli_wrsec0001b

 

同时在调试过程中,我使用了 Tektronix TDS3012B 数字示波器和一个 Python 脚本来捕获和解码 SD SPI 数据。

spi_capture

该脚本还输出一个 VCD 格式的文件,适用于 GTKWave。因此,我可以看到并分析数据,包括模拟和数字数据。

spi_sd

由于使用了 TDD 方法,目标上的调试阶段非常快。通过几次迭代以及示波器和 Python 脚本工具的帮助,SD 卡驱动程序运行良好。

COFILOS SD 卡驱动程序 - CodeProject - 代码之家
© . All rights reserved.