1. 完善SD驱动
1.1 完善SD控制和传输函数
根据上一章节封装的几个硬件设置接口,在控制和传输函数中相应位置进行调用:
static int sdIoctl (PLW_SD_ADAPTER psdadapter, int cmd, long arg) { switch (cmd) { case SDBUS_CTRL_POWEROFF: // TODO:关闭电源 break; case SDBUS_CTRL_POWERUP: case SDBUS_CTRL_POWERON: // TODO:使能电源 break; case SDBUS_CTRL_SETBUSWIDTH: // TODO:设置线宽 sunxi_mmc0_buswidth_set((int)arg); break; case SDBUS_CTRL_SETCLK: // TODO:设置时钟频率 sunxi_mmc0_clock_set((int)arg); break; case SDBUS_CTRL_DELAYCLK: break; case SDBUS_CTRL_GETOCR: // TODO:获取支持的电压情况 *(UINT32 *)arg = SD_VDD_32_33 | SD_VDD_33_34; break; default: return -1; } return 0; } static int sdTransfer (PLW_SD_ADAPTER psdadapter, PLW_SD_DEVICE psddevice, PLW_SD_MESSAGE psdmsg, int num) { int ret; while (num--) { ret = sunxi_mmc0_xfer(psdmsg); if (ret) { return -1; } psdmsg++; } return 0; }
在 sdTransfer 函数中根据SD消息的个数循环调用 sunxi_mmc0_xfer 传输命令和数据。同时在 sdDevCreate 中调用控制器硬件初始化设置接口:
int sdDevCreate (void) { // TODO:硬件初始化 sunxi_mmc0_init(); // 创建SD适配器 API_SdAdapterCreate("/bus/sd/0", &sdfuncs); // 注册SD存储设备类驱动 API_SdmLibInit(); API_SdMemDrvInstall(); // 注册host信息到sdm框架 sdmhost = API_SdmHostRegister(&sdhost); // 通知sdm框架立即初始化sd卡,创建块设备等 API_SdmEventNotify(sdmhost, SDM_EVENT_BOOT_DEV_INSERT); return 0; }
1.2 修改映射和内核启动参数
在bspMap.h中添加ccu和smhc模块寄存器地址映射:
接着修改内核启动参数,将原来的根文件系统从挂载在ram换成挂载在sd卡上:
/* * 这里使用 bsp 设置启动参数, 如果 bootloader 支持, 可使用 bootloader 设置. * 为了兼容以前的项目, 这里 kfpu=yes 允许内核中(包括中断)使用 FPU. * * TODO: 可以修改内核启动参数 */ API_KernelStartParam("ncpus=1 kdlog=no kderror=yes kfpu=no heapchk=yes hz=1000 hhz=1000 " /*"rfsmap=/:/dev/ram"*/ "rfsmap=/boot:/media/sdcard0,/:/media/sdcard1"); /* 操作系统启动参数设置 */
- /boot:/media/sdcard0:表示将根文件系统的/boot目录挂载在/media/sdcard0位置,这个位置一般都是sd卡fat分区挂载的位置,里面存放sylixos的bin镜像,从而让uboot能从fat分区加载SylixOS镜像并启动。
- /:/media/sdcard1:表示将根文件系统挂载在/media/sdcard1位置,这个位置一般都是sd卡tps分区挂载的位置,里面存放系统程序、库、用户程序等。
最后在 halDevInit 中调用 sdDevCreate 创建和初始化sd卡设备:
static VOID halDevInit (VOID) { /* * 创建根文件系统时, 将自动创建 dev, mnt, var 目录. */ rootFsDevCreate(); /* 创建根文件系统 */ #if LW_CFG_PROCFS_EN > 0 procFsDevCreate(); /* 创建 proc 文件系统 */ #endif /* LW_CFG_PROCFS_EN > 0 */ #if LW_CFG_SHM_DEVICE_EN > 0 shmDevCreate(); /* 创建共享内存设备 */ #endif /* LW_CFG_SHM_DEVICE_EN > 0 */ randDevCreate(); /* 创建随机数文件 */ /* * TODO: 加入你的处理代码, 参考代码如下: */ #if 1 /* 参考代码开始 */ SIO_CHAN *psio0 = uartSioChanCreate(); /* 创建串口 0 通道 */ ttyDevCreate("/dev/ttyS0", psio0, 512, 512); /* add tty device */ #endif /* 参考代码结束 */ sdDevCreate(); #if LW_CFG_YAFFS_EN > 0 yaffsDevCreate("/yaffs2"); /* create yaffs device(only fs)*/ #endif /* LW_CFG_YAFFS_EN > 0 */ }
2. 分区和格式化
重新编译BSP,重启开发板并分区和格式化SD卡,在SylixOS下如何分区和格式化参见http://www.databusworld.cn/9935.html。我们这里需要将SD卡分成三个区,第一个保留区域,因为里面有uboot,不能被新数据覆盖,第二个fat分区,第三个tps分区,如下所示:
这里我将保留分区和fat分区各分100MB,剩下空间全部给tps分区。再次重启开发板,启动系统后如果看到以下信息说明sd卡初始化和根文件系统挂载基本没问题了:
一般如果文件系统挂载有问题的话,在命令行前面的root会变成unknow,通过这个可以快速的判断文件系统是否正常挂载了。
3. SD验证
存储类驱动开发完成后,可以通过几个简单的测试来初步验证驱动是否正常,下面一一介绍。
3.1 查看挂载信息
通过showmount命令查看设备各个分区的挂载位置:
可以看出sd卡的第二个分区也就是fat分区挂载在/media/sdcard0位置,第三个分区也就是tps分区挂载在/media/sdcard1位置。
到根目录下通过ll命令也可以查看各个目录的挂载位置:
3.2 中断信息
如果驱动采用了DMA描述符方式来传输数据,一般都会配合中断来工作的,那么就可以通过ints命令查看驱动的中断次数来确定驱动是否在工作,但是由于本次驱动我们采用的cpu轮询读写fifo,并没有使用中断,所以这种方法失效。
3.3 读写文件
进入apps目录下,通过以下几个步骤快速验证读写文件是否正常:
- 通过touch命令创建一个新的空文件。
- 使用ll命令查看该文件信息。
- 通过echo命令将一段字符串写入新文件中。
- 再次使用ll命令查看该文件信息,主要是文件大小是否变化。
- 使用cat命令查看改文件内容,确认是否是刚才写入到文件中的字符串。
如果一切正常的话,cat出来的内容和echo写进去的内容应该是一样的。
3.4 速度测试
简单快速的读写速度测试可以使用base编译出的dd工具,这个工具和linux下的dd作用类似,但是由于我们还没有做好网络驱动,所以我们需要将sd卡插到电脑上并dd程序复制到fat分区中:
如上图所示,将libsylixos下编译出来的dd和libvpmpdm.so这两个文件复制到sd卡fat分区,然后将sd卡插回开发板重启启动。启动后进入/boot目录,通过如下命令测试fat分区写速度:
/boot/dd if=/dev/zero of=testw.dbf2 bs=1M count=10
通过如下命令测试fat分区读速度:
/boot/dd if=testw.dbf2 of=/dev/null bs=1M count=10
测试结果如下所示:
测试tps分区速度之前首先通过cp命令将libvpmpdm.so复制到/lib目录下,然后进入到apps目录下,同样的操作测试tps分区的读写速度:
到底为止,一个简单的sd驱动我们就完成了,在实际的测试中,一般还配合iozone来更详细的测试驱动在不同条件下的读写速度。带sd驱动的最小系统源码可以在这里下载:https://pan.baidu.com/s/1DqcgPGlN4byx2PERATukaA?pwd=kfh9。
2023年5月22日 21:45 1F
板子全志d1,sd卡挂载后unknow,代码是链接最后的提供的那个,问题出在哪呢