目录

  • 前言
  • 一:操作CS创世 SD NAND的常用命令
    • 1.查看SD设备
    • 2.挂载分区
    • 3.卸载分区
    • 4.分区管理
    • 5.格式化分区
    • 6.简单读写
  • 二:SD底层协议简要介绍
  • 三:对CS创世 SD NAND进行读写操作的三大方式
    • 1. 使用dd命令
    • 2. 使用块设备的标准接口
    • 3. 使用ioctl产生系统调用
  • 四:CS创世 SD NAND的驱动框架介绍
    • 1. MMC/SD驱动在linux中的结构层次
    • 2. SD驱动中核心的数据结构举例
    • 3. host层函数调用关系解析
    • 4. 卡的检测
    • 5. 扫描流程
    • 6. 数据的读写
  • 五:CS创世 SD NAND启动
    • 君正平台
      • 1. 制作SD启动卡
      • 2. 选择启动方式
      • 3. 验证SD启动
    • 瑞芯微平台
      • 1. 制作SD启动卡
      • 2. 选择启动方式
      • 3. 验证SD启动
  • 六、结语

前言

今天就瑞芯微平台和北京君正平台下的linux系统中关于CS创世 SD NAND的使用做一些经验的分享,如有不正,请批评指正;

采用的开发板是RK3568和x2600e,ubuntu版本是20.04,交叉编译工具链是aarch64-linux-gnu-mips-linux-gnu-

下面将从五个板块来进行介绍,分别是操作CS创世 SD NAND的常用命令、SD底层协议简要介绍、对CS创世 SD NAND进行读写操作的三大方式、SD的驱动框架介绍以及CS创世 SD NAND启动,前三个板块没有瑞芯微和君正平台之分,只要是跑linux系统,差别不大,第四块以RK平台为例,第五块同时以君正平台和RK平台为例。

一:操作CS创世 SD NAND的常用命令

1.查看SD设备

使用lsblkfdisk -l命令可以查看到sd设备节点,一般为/dev/mmcblkX/dev/sdX,eg:/dev/mmcblk0;

2.挂载分区

mount 设备分区 挂载点 eg:mount /dev/mmcblk0p1 /mnt/sdcard

3.卸载分区

umount 设备分区/挂载点 eg:umount /dev/mmcblk0p1 或 umount /mnt/sdcard

4.分区管理

fdisk 设备节点eg:fdisk /dev/mmcblk0。进入交互页面后常用命令:

p 打印分区表
n 创建新分区
d 删除分区
t 更改分区类型
w 将更改写入磁盘并退出
q 不保存更改退出
m 显示帮助菜单
l 列出已知的分区类型
v 验证分区表
g 创建新的空GPT分区表
o 创建新的空DOS分区表

在进行分区管理前请务必备份重要数据,因为在更改生效后会丢失原来数据;

5.格式化分区

格式化为FAT32:mkfs.vfat 设备分区;eg: mkfs.vfat /dev/mmcblk0p1

格式化为ext4:mkfs.ext4 设备分区;eg:mkfs.ext4 /dev/mmcblk0p2

6.简单读写

cp,cat,echo等命令。eg:

复制文件:cp /usr/data/1.txt /mnt/sdcard/2.txt

查看文件内容:cat /mnt/sdcard/test.c

写文件:echo "测试内容" > /mnt/sdcard/test.txt

二:SD底层协议简要介绍

由于CS创世 SD NAND和SD卡遵守相同协议,并且标准协议中使用SD卡来描述,因此以下用词使用SD卡代替CS创世 SD NAND。文本以雷龙发展提供的工业级CS创世 SD NAND FLASH为例,介绍读写方式准备协议的理论知识,仅做简要介绍以及提醒一些需要注意的点,完整的协议内容较多,详细请参考SD2.0协议标准完整版;

SD驱动中最重要的部分就是初始化,这里描述一下初始化流程,(需要区别四类卡,SDHC卡,SDSC卡,SD1.X卡,mmc卡)先是给SD卡上电,通常这一步在将卡插入卡槽就会自动完成,然后是发送CMD0进行软复位,进入空闲模式,再发送CMD8,主机询问SD卡是否支持电压范围,(SD1.X和mmc卡不会对CMD8产生响应,只有SDHC和SDSC卡会对CMD8回复R1响应);如果不响应再区分SD1.X和mmc卡,发送ACMD41(先发送CMD55告诉SD卡接下来发送的是应用命令),如果不响应就说明是mmc卡(此时发送CMD1激活mmc卡,mmc卡响应后即完成mmc卡的初始化),如果回复R1相应就说明是V1.X卡;

收到R1响应再区分SDHC和SDSC,然后发送ACMD41,主机告诉SD卡支持高容量,根据返回的R3响应中的OCR寄存器来判断是标准还是高容量,只有当busy位置1时CCS位才有效,CCS位为1是高容量V2.0卡(即SDHC卡),CCS位为0是标准V2.0卡(即SDSC卡),至此区分出了V1.X,标准V2.0,高容量V2.0卡,这三种卡接下来的步骤一致:

发送CMD2获取CID寄存器的值,SD卡会回复R2响应,再发送CMD3,SD卡获得相对地址,流程图如下图所示:

然后是数据传输模式,初始化完成后进行数据传输就相对简单了,只需要发送对应的命令即可,流程图如下:

下面附上常用命令以及响应的图:

最后提醒几个需要注意的点:

  • 第一是上电之后有一个时间段叫“供电上升时间”,这个是电压上升到操作的总线电平以及等到能发送第一条命令的时间,这个时间需要在1ms,74个时钟周期以及供电上升时间这三者中取最大值,其实这点在驱动源码中也有体现,在mmc_power_up函数(drivers/mmc/core/core.c)如下图所示,同时在协议的6.4.1章节也有说明,这个时间如果没有等待而直接开始发送命令进行初始化,可能也能通过初始化,但是在后面的数据传输阶段就有概率会出现问题了,如果没有注意到这个供电上升时间,那么其实出现了异常是很难定位问题的;

  • 第二是SD卡的两种数据包格式,分别是常规数据和宽位数据,常规数据是指普通的8bit字节数据,发送规则是先发低字节再发高字节,每个字节是先发高位后发低位;而宽位数据一般指SD卡存储寄存器,规则是先发高位,后发低位, 这点在解析SD卡寄存器时需要格外注意,否则就会发现解析的数据明显不符规范;

三:对CS创世 SD NAND进行读写操作的三大方式

CS创世 SD NAND作为一种存储设备,不外乎就是读和写,同时这也是最重要的,熟悉读写方式对于使用CS创世 SD NAND开发非常有帮助,因此在这一块会详细介绍;

1. 使用dd命令

  1. 使用前先挂载分区的文件系统(常用于写入普通文件)
sudo dd if=输入文件 of=输出文件 bs=块大小 status=状态信息 其他选项参数··· 

eg:

sudo dd if=/mnt/sdcard/test.doc of=backup.doc bs=1M count=1
//将/mnt/sdcard/test.doc的前1M字节写入backup.doc;
  1. 使用前不挂载分区的文件系统(常用于写入镜像文件,备份或擦除整个CS创世 SD NAND等)
sudo dd if=输入设备 of=输出设备 bs=块大小 status=状态信息 其他选项参数

eg:

sudo dd if=sd_back_up.img of=/dev/mmcblk0 bs=4M status=progress
//将sd_back_up.img以4MB的块大小写入/dev/mmcblk0,同时显示进度和速度
sudo dd if=/dev/mmcblk1p1 of=/root/zboot.img bs=4M status=progress
//将mmcblk1p1设备中的所有数据读取到/root/zboot.img文件下

如果要对读取的数据进行限制,只读取部分数据,那么使用参数skip或者count

sudo dd if=/dev/sdX of=/path/to/output.img bs=4M skip=10 status=progress      
//skip:跳过前10个块再开始读取数据
sudo dd if=/dev/sdX of=/path/to/output.img bs=4M count=20 status=progress
//count:只读取20个块的数据

也可以结合skip和count,实现从特定位置读取指定数量的数据;

注意:若使用前不挂载分区,那么在写入之前请备份CS创世 SD NAND内重要数据,因为不挂载是绕过文件系统对原始存储设备直接操作,会完全忽略文件系统结构,很可能会覆盖已有数据,甚至可能会损坏文件系统,严重的话只能重新格式化;

如果是先挂载了分区,那么dd命令会通过文件系统进行操作,相对安全;

2. 使用块设备的标准接口

通过文件io或标准io进行读写,无论是挂载文件系统还是不挂载文件系统,都能使用文件io或标准io对CS创世 SD NAND进行操作,区别是前者通过文件系统较为安全且效率稍低而后者直接操作硬件存储设备效率更高同时对于数据的写入需要更加注意防止覆盖重要数据,下面分别提供两个示例;

第一个示例:使用标准io(fopen,fwrite,fread,fseek,fclose等)在已挂载文件系统的CS创世 SD NAND上进行读写,总所周知,在linux里流传着一句话,那就是“一切皆文件”,在这种情况下操作挂载点的文件其实与操作一般文件基本无异;示例实现的功能是在SD卡挂载目录/mnt/sdcard/目录下创建test_data.txt文件,然后再往里面写入4次0~255,然后再将数据读取出来验证是否写入成功并打印测试结果;

编译命令是aarch64-linux-gnu-gcc test2.c -o test2,编译成功后使用sftp root@ip将test2发送至开发板运行测试,运行结果以及程序见下面两张图;

第二个示例:使用文件io(open,write,read,lseek,close)对未挂载文件系统的CS创世 SD NAND直接操作;实现的功能是从CS创世 SD NAND的第1000块开始写入512字节数据,数据内容为0255,0255,写入后再把数据读取出来比较是否成功并打印结果;

编译命令是:aarch64-linux-gnu-gcc test.c -o test,编译成功后使用sftp root@ip将test2发送至开发板运行测试,运行结果和程序也如下面两张图所示

3. 使用ioctl产生系统调用

陷入内核进行处理,前两种方式都容易实现,而且不需要关注底层发送的命令,而ioctl可以对CS创世 SD NAND进行精细的命令控制来约束NAND的行为,并且在ioctl使用过程中还有一些需要注意的点,如果想要对CS创世 SD NAND进行最为底层的命令操作,那么ioctl必定是是首选,因此着重介绍这种方式;

使用ioctl来对CS创世 SD NAND发送命令,其中最为重要的就是填充struct mmc_ioc_cmd结构体,结构体的详细定义位于kernel/include/uapi/linux/mmc/ioctl.h,其中关于flags即命令标志位掩码的定义位于/include/linux/mmc/core.h文件中的struct mmc_command结构体中,下面对struct mmc_ioc_cmd结构体的各成员作详细介绍,如下图所示:

介绍完struct mmc_ioc_cmd结构体后细心的小伙伴会发现了这里面几乎所有的参数都好填充,唯独flags,命令标志位掩码的定义在core.h中,如下图所示:

那么在编写ioctl的程序时,填充flags需要用到core.h里面的内容,总所周知,linux里面的隔离是很严重的,在应用层调用内核层的定义,这是不允许的,编译会报错,之前刚开发的时候因为这个编译报错还折腾了不少时间,最终的解决办法就是把这些标志位的宏定义复制到自己写的应用程序中,这样就没有报错了,下面提供一份程序

程序较长,文件名是init.c(见附件),编译命令是:aarch64-linux-gnu-gcc init.c -o init,编译成功后使用sftp root@ip(若有adb功能也可使用adb push)将可执行程序init发送至开发板进行运行测试,文件中包含ioctl使用的详细解释,下面三张图是运行结果截图(前两张)以及使用逻辑分析仪抓取的命令(第三张图),波形文件名是:init.TLW,见附件,两者都与程序一致,运行过程中没有报错,这就是使用ioctl向CS创世 SD NAND发送底层命令的详细过程;

关于ioctl的使用,有下面几点需要格外注意,这些都是小编亲身走过的坑,所谓前人栽树,后人乘凉, 也算方便大家“乘凉”了哈哈;

第一是如果进行的是写操作,例如发送CMD24,CMD25等命令,那么struct mmc_ioc_cmd结构体的write_flag必须要赋值为非零值,如果是0值,那么很容易导致发送命令失败,得到“errno=110 (Connection timed out)”的错误信息,这个错误信息相对常见,意为连接超时,分析函数调用链可知:在__mmc_blk_ioctl_cmd(drivers/mmc/core/block.c)函数中有

根据write_flag的值会进一步增加MMC_DATA_WRITE或MMC_DATA_READ的标志再传到驱动中,因此发送写命令时请务必给write_flag赋非零值;

第二是在SD卡初始化完成后,开始数据传输前,需要发送ACMD6定义数据总线的宽度,分析源码可知:在mmc_sd_init_card(drivers/mmc/core/sd.c)函数中有如下图所示部分

SD和主机通常都是同时支持4位数据总线宽度的,在不修改SD驱动的情况下,主机控制器是4位总线宽度,所以如果不发送ACMD6,那么卡会保持默认的1位总线宽度,此时主机和NAND的总线宽度不一致,就会出现“errno=84 (Invalid or incomplete multibyte or wide character)”的错误信息,含义是无效或不完整的多字节或宽字符,解决办法有两种,一种是修改驱动源码,将主机控制器的总线宽度固定为1位,此时可以不发送ACMD6,主机和 CS创世 SD NAND都使用1位数据总线通信,第二种是发送ACMD6通知卡改变总线宽度为4位,两者都用4位总线传输数据,ACMD6的参数说明如下图,很明显要第二种方式更简单,因此如果遇到errno=84的错误码,检查一下主机和CS创世 SD NAND的总线宽度是否一致;

第三是频率问题,如果使用ioctl发送cmd时,检查了命令和各项参数都没有错,也没犯上面两种错误,但是运行程序发现就是会报各种错,例如下图(运行的是示例程序init)

那么很大概率就是频率太高,CS创世 SD NAND接受不了,此时需要降频,如下图

降低频率后再次运行,运行结果见下图

只要多加注意以上三点,相信使用ioctl就没有什么大问题;

四:CS创世 SD NAND的驱动框架介绍

以瑞芯微平台的RK3568驱动源码为例

1. MMC/SD驱动在linux中的结构层次

通常在linux系统中,MMC/SD设备都是被抽象成块设备来处理,在kernel的顶层目录下的drivers/mmc目录下通常有三个文件夹分别是core、card和host,有些驱动会将core和card合并成一个core,例如RK3568就是只有core和host,这个驱动框架就是以RK平台的SD驱动来介绍的,下面解释三个文件夹的作用;

1.card层: 要把操作的数据以块设备的处理方式写到存储设备上或从存储设备上读取;因为CS创世 SD NAND属于块设备,那么必然要提供块设备的驱动程序,这部分就是解决了一个问题,即如何将你的CS创世 SD NAND实现为块设备的。

2.core 层:则是将数据以何种格式,何种方式在 MMC/SD主机控制器与MMC/SD卡的记 忆体(即块设备)之间进行传递,这种格式、方式被称之为规范或协议.

这部分完成了不同协议和规范的实现,抽离出不同SD主机控制器的共性,并为HOST 层的驱动提供了接口函数

3.host 层: 是这个文件夹属于 Linux 内核中 MMC/SD 子系统 的 硬件驱动层,直接负责与 MMC/SD 主机控制器(Host Controller) 的硬件交互。它的核心作用是向上提供统一的接口供 Core 层 调用(如发送命令、读写数据),向下为不同厂商的 Host 控制器提供驱动实现,将上层(Core 层)的协议请求转换为具体的寄存器操作、时钟控制、DMA 传输等硬件行为。

core层根据协议规范来构造各种命令,那么命令是怎么发送给CS创世 SD NAND呢?通过主机控制器。

主机控制器通过设置SD需要的gpio资源,注册中断资源,使能控制器等等,然后再向上面的核心层增加一个host,这样核心层就能调用具体的硬件操作函数来和SD卡通信了;

card和core是封装好的共性以及规范,通常是不需要修改的,而host层是直接与硬件打交道,需要控制底层寄存器的,不同的host控制器硬件资源也不一样,因此驱动CS创世 SD NAND,host层才是应该需要修改开发的,MMC/SD驱动在linux中的结构层次见下图:

2. SD驱动中核心的数据结构举例

(CS创世 SD NAND和SD卡在驱动中使用的数据结构和调用的函数是一致的,并且有不少数据结构命名或函数功能注释翻译过来用SD卡描述更贴切,因此下面描述用词使用SD卡代替CS创世 SD NAND,不再赘述)

1.struct mmc_host

功能:表示一个MMC/SD卡主机控制器,它是驱动程序和内核MMC子系统之间的主要接口;

重要成员:

const struct mmc_host_ops *ops:包含操作该主机的各种函数指针,包括发送命令,设置时钟和电源,请求操作等,用于和硬件交互
struct device class_dev:代表该主机控制器的设备对象,可用于设备模型的注册和管理
unsigned int f_min:主机控制器支持的最小时钟频率
unsigned int f_max:主机控制器支持的最大时钟频率,对于SD卡的操作频率非常重要
struct mmc_card *card:指向插入该主机的SD卡设备
struct mmc_ios ios:包含了当前IO的状态信息,例如时钟频率,电压范围,电源模式等
const struct mmc_bus_ops *bus_ops:指向struct mmc_bus_ops结构体,定义了和MMC卡通信的操作集,例如读写,卡检测等;
u32 ocr_avail:存储MMC主机可用的操作条件寄存器OCR的值,
u32 caps:表示MMC主机的能力和特性,通过不同的位来标记主机的各种模式;
  1. struct mmc_card

功能:表示一个插入到MMC主机控制器的SD卡设备

重要成员:

struct mmc_host *host:指向SD卡所连接的主机控制器
unsigned int rca:相对卡地址,是SD卡的重要标识符,用于在总线上唯一标识该卡
unsigned int type:卡类型,例如MMC,SD,SDIO等,用于区分不同的设备类型
u32 ocr:操作条件寄存器,包含了SD卡的操作条件信息,例如支持的电压范围,电源模式等;
struct mmc_cid cid:包含卡的CID信息,例如制造商id,产品名称等;
  1. struct mmc_ios

功能:包含SD主机控制器的IO状态信息

重要成员:

unsigned int clock:当前的时钟频率,驱动可以根据需要调整此时钟频率,来满足不同操作的需求;
unsigned char power_mode:电源模式,例如MMC_POWER_OFF,MMC_POWER_UP,用于控制SD卡的电源状态
unsigned char bus_width:总线宽度,可以选择1线,4线,8线,根据SD卡的能力和操作需求进行调整
  1. struct mmc_host_ops

功能:包含了操作MMC主机控制器的一系列函数指针,是驱动程序与硬件交互的接口;

重要成员举例:

void (*request)(struct mmc_host *host, struct mmc_request *req):函数指针,用于将一个操作请求添加到主机控制器的请求队列中
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios):用于设置主机控制器的IO状态,例如调整时钟频率,电源模式和总线宽度等等;
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios):在需要切换SD卡的操作电压时调用此函数;
int (*get_ro)(struct mmc_host *host):检查MMC/SD卡是否被写保护了;
int (*get_cd)(struct mmc_host *host):检查SD卡的插入和拔出;
  1. struct mmc_request

功能:表示一个对SD卡的操作请求,通常包括命令,数据传输等信息;

重要成员:

struct mmc_command *cmd:指向要执行的命令;
struct mmc_data *data:指向要传输的数据对象,用于数据块的读写操作;

3. host层函数调用关系解析

这里主要做了两件事,其一是mmc_alloc_host分配一个mmc_host,其二是mmc_add_host添加一个mmc_host;

4. 卡的检测

我们用的SD卡只是一张卡,要操作卡还得通过主机控制器才行,因此会有struct mmc_card,struct mmc_host之分,截至这里再回忆一下 dw_mci_init_slot做的事情,大概就是准备一个 mmc_host 结构,然后添加一个主控制器设备到内核,最后又调用了一下 mmc_rescan 来检测是不是有卡插入了,有人会问如果此时卡没有插入呢,那么不就是白白调用一次mmc_rescan,那下次卡插入又是怎么检测到的呢,很明显,这种不能确定触发时间的完全未知的动作,肯定是需要通过中断机制来处理,检测到卡插入,触发中断,扫描卡,开始初始化等流程,检测到卡拔出触发中断,清理各类资源,释放空间;

5. 扫描流程

struct mmc_card 结构里面包含了一个 struct device 结构, mmc_alloc_card 不但申请了内存,而且还填充了 struct device 中的几个成员,尤其 card->dev.bus = &mmc_bus_type; 这一句要重点对待,mmc_bus_type的定义如下图

申请一个 mmc_card 结构,并简单初始化后, mmc_init_card 的使命就完成了,然后再调用 mmc_add_card 将这个 card 设备添加到内核。 mmc_add_card 其实很简单,就是调用 device_add 将 card->dev 添加到内核当中去;

device_add 里面,设备对应的总线会拿着你这个设备和挂在这个总线上的所有驱动程序去匹配( match ),此时会调用 match 函数(如下图),如果匹配到了就会调用总线的 probe 函数或驱动的 probe 函数;

所以match永远不会失败,匹配成功就会执行mmc_bus_probe(定义见下图)

追踪到这里,probe由调用了 drv->probe() ,这就需要知道drv的定义了,struct mmc_driver*drv=to_mmc_driver(dev->driver);match 函数总是返回 1 ,说明挂在这条总线上的 driver 都有可能跑到这里来了,事实的确也是这样的,不过好在挂在这条总线上的 driver 只有一个,定义见下图:

因此跳转到mmc_bllk_probe函数执行,函数定义如下:

mmc_blk_probe 是 MMC 块设备驱动的核心探测函数,负责将 MMC/SD 卡注册为块设备,使其能够被系统访问,看到这里已经把core,host目录下的文件都牵扯进来了,慢慢再捋一下就能看出从host到core的联系了;

6. 数据的读写

在驱动中,向SD卡发送cmd都是通过请求队列来完成的,所有的cmd都会被封装成请求,然后由内核的I/O调度器统一排序,合并或拆分,再下发给硬件驱动,这样避免了驱动直接操作硬件,而是通过标准接口解耦,增强了安全性和可维护性,所以分析cmd的发送首先要定位到request请求队列,关键函数调用流程如下图:

顺便附上上图中提到的两个ops操作集合的赋值:

分析到这里,整个SD驱动框架做的事情说简单一些其实就干了两件事,一是卡的扫描检测,而是数据的读写,不过这个过程中涉及到的数据结构和函数调用确实相对复杂,捋清楚驱动框架还是需要静下心来花费时间的;

五:CS创世 SD NAND启动

相同的板卡厂商一般CS创世 SD NAND启动的流程固定,大致讲一下流程,首先是要制作SD启动卡,即将启动镜像烧录进CS创世 SD NAND,一般板卡厂商都会有专门的制作工具,只需按照使用方法来制作启动卡即可,如果没有制作工具,那么一般使用dd命令将系统镜像写入卡内(写入时可能有地址参数要求,需要咨询板卡厂商的技术支持),然后是选择启动方式,一般是有几个boot引脚,启动时系统会根据boot引脚的电平组合来选择启动方式,有些开发板可能在选择CS创世 SD NAND启动时还需要配置其他内核参数,只需咨询对应的技术即可,最后就是验证系统是否能正常从SD启动,数据读写是否正常;

君正平台

开发板是x2600e,CS创世 SD NAND是采用CS256G-AOW;

1. 制作SD启动卡

君正的烧录工具支持将启动镜像烧录到CS创世 SD NAND,先编译准备好启动镜像,然后按照下图顺序进行制作启动卡;

2. 选择启动方式

查询芯片手册得知启动方式的选择依据如下图

再查看原理图如下:

可知目前的电平组合是001,即选择的是SFC@PD06_3.3V(默认从SPI NAND FLASH启动),现在需要改为从SD启动,那么就要将BOOT_SET0即PD14接低电平,使得电平组合为000,然后就是查看PCB,找到PD14的gpio,再修改硬件将其接地即可;

3. 验证SD启动

通过上图可知,系统成功从CS创世 SD NAND启动,然后使用一些简单的读写命令验证是否正常即可,一般而言只要能正常启动系统读写就没问题,因为启动过程中本身就已经包含了对SD进行读写。

瑞芯微平台

开发板是RK3568,CS创世 SD NAND采用CS256G-AOW,也采取相同步骤;

1. 制作SD启动卡

首先编译准备好镜像文件,并将其拷贝到windows端(可以将镜像放置共享目录下),然后打开瑞芯微的制作工具SDDiskTool,按照下图所示进行配置:

正常来说制作过程是2~3分钟,但是也遇到过十分钟左右的,这个可能因CS创世 SD NAND而异,但是只要没报错,就耐心等待制作完成;

2. 选择启动方式

由于咨询技术支持得到的答复是RK对于启动引导不开源,原理也是靠硬件选boot脚,然后在芯片手册上也没找到有关boot引脚配置的部分,所以说明在RK上我们不需要修改硬件,额外配置boot引脚来选择启动方式,后面在rockchip-common.h文件中找到了关于启动方式的优先顺序,如下图:

因此只要启动时在卡槽检测到CS创世 SD NAND,那么就会优先从SD启动;

3. 验证SD启动

从上面两张图中可以相互印证,系统成功从SD启动;

启动卡的分区情况如下图:

从mmcblk1p1至mmcblk1p6共6个分区,依次是uboot,misc,boot,recovery,backup和rootfs,前面5个分区一般存储特定数据,不建议用户将数据写入,而mmcblk1p6是根文件系统分区,存储所有系统文件、应用程序、用户数据等,进行用户操作时就是基于这个分区,因此进行读写测试或者存储用户数据建议在此分区进行。

六、结语

最后分享一些使用的软件:

串口工具:Windows下:MobaXterm;Ubuntu下:Minicom

分析内核源码:source insight 4

逻辑分析仪:ATK-Logic 或Acute TravelLogic Analyzer

除了软件,硬件上的逻辑分析仪,示波器,万用表也可辅助调试验证。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94756.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94756.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94756.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析Java并发编程与单例模式

目录 一、调度(四) 1.随机调度大环境 二、锁(二) 1.位置 2.无锁阻塞 3.重入锁 4.连续锁 4.1措施 三、线程方法(二) 1.wait 2.notify 3.wait-notify指位后移 3.1可能时再检查 3.1.1join(二) 3.1.1.1可能时再检查死亡 四、单例模式 1.实现 1.1private构造器 1…

java通过redis简单实现分布式锁

目录 一、简介 二、代码实现 1、maven添加依赖 2、核心逻辑代码 3、使用方式 三、总结 一、简介 我们知道在Java中可以通过关键字synchronized来防止并发引起的问题,而分布式中就需要考虑分布式锁了,今天来讲一个比较简单的实现,通过re…

网络编程--TCP/UDP Socket套接字

网络编程 程序员主要操作应用层和传输层来实现网络编程,也就是自己写一个程序,让这个程序可以使用网络来通信,这个程序属于应用层,实现通讯就需要获取到传输层提供的服务 这就需要使用传输层提供的api UDP: 无连接,不可…

claude-code订阅方案

Claude Code 订阅方案对比 编写日期:2025 年 08 月 20 日 🏷️ 专业版 Pro ($20/月,$200/年) 主要特性 可用模型:Claude Sonnet 4(Claude Opus 4成本太高,谨慎选择)适用场景:适合轻度…

146. LRU缓存

题目: 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值&#x…

第二十节:3D文本渲染 - 字体几何体生成与特效

第二十节:3D文本渲染 - 字体几何体生成与特效 TextGeometry深度解析与高级文字效果实现1. 核心概念解析 1.1 3D文字渲染技术对比技术原理优点缺点TextGeometry将字体轮廓转换为3D网格真实3D效果,支持材质性能开销大,内存占用高Canvas纹理将文…

zzz‘sJava知识点概括总结

类型转化 字符串&#xff1a;c语言&#xff1a;char Java&#xff1a;string 表达式值的类型由最高类型决定&#xff1a; 取值范围&#xff1a;byte<short<int<long<float<double&#xff08;且运算时byte和short都是转化为int类型进行计算防止数据溢出&…

SONiC 之 Testbed(2)Ansible

Ansible 是一款由 Red Hat 主导开发的 开源自动化工具&#xff0c;专注于 配置管理、应用部署、任务编排和IT自动化。它基于 无代理&#xff08;Agentless&#xff09;架构&#xff0c;通过 SSH&#xff08;默认&#xff09;或 WinRM 协议与目标设备通信&#xff0c;无需在被控…

瑞芯微RK3568与君正X2600e平台Linux系统CS创世SD NAND应用全解析与驱动架构详解

前言 今天就瑞芯微平台和北京君正平台下的linux系统中关于CS创世 SD NAND的使用做一些经验的分享&#xff0c;如有不正&#xff0c;请批评指正&#xff1b; 采用的开发板是RK3568和x2600e&#xff0c;ubuntu版本是20.04&#xff0c;交叉编译工具链是aarch64-linux-gnu-和mips…

深入解析 Flink Function

RichFunctionFunction只是个标记接口public interface Function extends java.io.Serializable {}RichFunction 的核心语义是为用户定义的函数&#xff08;UDF&#xff09;提供生命周期管理和运行时上下文访问的能力。任何一个普通的 Flink Function 接口&#xff08;例如 MapF…

JMeter —— 压力测试

目录 常用的性能指标 一、吞吐量类指标 二、响应时间类指标 三、资源利用率指标 JMeter 一、JMeter 简介 二.下载安装JMeter&#xff1a; 三.如何使用JMeter&#xff1a; 压力测试考察当前软硬件环境下系统所能承受的最大负荷并帮助找出系统瓶颈所在。压测都是为了系统…

Transformer在哪⾥做了权重共享?

1、什么是权值共享权重共享是指在模型的不同层之间复⽤相同的参数。这可以减少模型的总体参数数量&#xff0c;并使得模型在训练时更容易学习。2、在Transformer中的应用常见的做法是共享词嵌入层&#xff08;embedding layer&#xff09;和输出层&#xff08;output layer&…

将 agents 连接到 Elasticsearch 使用模型上下文协议 - docker

我们在之前的文章 “将 agents 连接到 Elasticsearch 使用模型上下文协议” 及 “使用 MCP 将代理连接到 Elasticsearch 并对索引进行查询” 详述了如何使用 Elasticsearch MCP server 来和我们的 Elasticsearch 进行对话。细心的开发者可能已经注意到我们的 Elasticsearch MCP…

Shell 编程基础与实践要点梳理

目录 前言 一、认识 Shell 1.1 Shell 的定义与作用 1.2 Shell 解释器 二、Shell 脚本入门 2.1 编写 Shell 脚本 2.2 赋予执行权限与执行脚本 三、Shell 变量 3.1 变量定义与规则 3.2 变量使用与操作 3.3 变量类型 四、Shell 字符串 4.1 字符串定义方式 4.2 字符串…

Python自动化测试完整教程:pytest + selenium实战

目录 前言环境搭建pytest基础教程selenium基础教程pytest selenium实战项目页面对象模式(POM)测试报告生成持续集成配置最佳实践和进阶技巧总结 前言 自动化测试是现代软件开发中不可或缺的一环。Python作为一门简洁优雅的编程语言&#xff0c;配合pytest测试框架和seleniu…

APM 系列(一):Skywalking 与 Easyearch 集成

概述 SkyWalking 是一个开源的可观测性平台&#xff0c;用于收集、分析、聚合和可视化服务和云原生基础设施的数据。SkyWalking 提供了一种简单的方法&#xff0c;即使在云之间也能保持对分布式系统的清晰视图。它是一个现代的 APM&#xff0c;专门为云原生、基于容器的分布式…

使用 AD 帐户从 ASP.NET 8 容器登录 SQL Server 的 Kerberos Sidecar

我最近在做一个项目,需要将一个 ASP.NET 8 Web API 应用程序容器化,该应用程序需要与本地运行的 SQL Server 数据库进行通信。我们决定将 ASP.NET 8 容器定位到 Linux 系统,因此必须与运行在 Windows AD 域中的数据库进行通信。 问题 我们之前的设置是使用 IIS 在 Windows …

More Effective C++ 条款11:禁止异常流出析构函数之外

More Effective C 条款11&#xff1a;禁止异常流出析构函数之外核心思想 在C中&#xff0c;析构函数绝对不允许抛出异常。如果异常从析构函数中传播出去&#xff0c;可能会导致程序立即终止或未定义行为&#xff0c;特别是在栈展开过程中处理已有异常时。通过捕获并处理所有析构…

商超高峰客流统计误差↓75%!陌讯多模态融合算法在智慧零售的实战解析

原创声明&#xff1a;本文为原创技术解析&#xff0c;核心技术参数、架构设计及实战数据引用自 “陌讯技术白皮书”&#xff0c;技术方案与落地案例结合aishop.mosisson.com智慧零售数据联动场景展开&#xff0c;禁止未经授权的转载与商用。 一、行业痛点&#xff1a;智慧零售…

PyTorch实战(2)——使用PyTorch构建神经网络

PyTorch实战&#xff08;2&#xff09;——使用PyTorch构建神经网络0. 前言1. PyTorch 构建神经网络初体验1.1 使用 PyTorch 构建神经网络1.2 神经网络数据加载1.3 模型测试1.4 获取中间层的值2. 使用 Sequential 类构建神经网络3. PyTorch 模型的保存和加载3.1 模型保存所需组…