如何使用 PSoC 5LP 芯片的 SPI 写入 SD 卡?
How do I write to an SD Card using SPI for the PSoC 5LP chip?
如何使用 SPI 和 PSoC 5LP (32-bit Cortex-M3) 芯片可用的 DMA 写入 SD 卡?
我目前有一个 DMA 和 SPI tx/rx 对工作,但用于不同的目的,所以如果实际传输不是问题,我只是不知道如何与 SD 卡交互。
datasheet for the PSoC 5LP is here.
基本信息:
我在简单模式下使用 DMA,DMA TD 链设置为:
8 位宽度,4 字节突发
自动完成完整的 TD(只需要初始硬件请求)
完成后循环回到初始 TD 的开头并等待 HW 请求
SPI 主机在 gui 中初始化,我使用 16Mhz 时钟、8 位 tx/rx 传输和 4 字节 tx/rx 缓冲区进行设置。中断在 rx FIFO 满时设置,连接到它们的是 rx DMA。
SDcard SPIrx/tx的指针分别是SPIM_RX_PTR和SPIM_TX_PTR。 DMA 与它们之间进行传输。我正在传输的阵列是 SDcardout 和 SDcardin。
使用 SPI 通信只会让您获得对卡的最低 command/block 级别访问权限;您将需要一个文件系统。 SD 卡 pre-formatted 作为 FAT32,因此 FAT file-system 将提供最大的可比性,但不是最可靠的(例如,如果写入因断电或重置而中断,则可能会损坏)。它还具有实施起来相对简单并且需要很少资源的优点。
有几个商业和 open-source FAT 文件系统库可用。我建议您查看 ELM FatFs or ELM Petit FatFs 两者都有宽松的许可证并且有据可查。在每种情况下,您只需要实现磁盘 I/O 存根以将它们映射到您的 SPI 驱动程序。网站上有大量示例、文档和应用说明可以为您提供帮助。您可以从另一个目标的 SPI SD 实现示例开始,然后将其调整为您的驱动程序(或者可能调整您的驱动程序)。其他 FAT 文件系统库与此大致相似,需要 I/O 层实现。
ELM FatFs 的 diskio 层不是特定于媒体的,因此您实际上需要在它和 SPI 驱动程序之间增加一个 MMC/SD 层。您不太可能找到针对特定目标的示例,但可以从其他目标的示例开始工作,因为 MMC/SD over SPI 本身不是特定于目标的,硬件依赖性仅出现在 SPI 级别,并且card-detect 和 write-protect(可选)信号的 GPIO 实现。有几个针对各种 ARM 目标的示例 here, a project for PSoC support here(在撰写本文时显然是 work-in-progress)。
我已经解决了这个问题。
我发现 PSoC 5 组件库随附的现有 SPI 模块不太适合与 SD 卡进行批量传输。据我所知,有必要在每次字节传输时清除软件中的 SPI 模块标志,从而降低 DMA 的用处。我认为一个解决方案是使用两个 TD(传输描述符)——一个执行数据传输,第二个在第一个 TD 完成后清除 RX 标志——无论如何,这是题外话。
我还发现组件库中提供的 emFile 组件的功能有限。我看不到任何附加 DMA 的方法,即使我可以,它的时钟速度似乎也很差。最重要的是,emFile 需要编译时选择 FAT16 或 FAT32,将您的设计限制在一个或另一个文件系统上。
因为我不喜欢更复杂的 DMA 设置,所以我决定在 UDB 编辑器中设计我自己的 SPI 组件硬件。可以在以下位置找到包含该组件的项目:https://github.com/PolyVinalDistillate/NSDSPI
它结合了上面提到的优秀 FatFS 库(感谢 ChaN),它处理 FAT12、FAT16 和 FAT32 格式的卡。如前所述,如果没有文件系统层,您将只能访问每个 512 字节的原始数据块。使用 FatFS,您可以获得 fopen()、fclose() 等的类似物
如果您在 PSoC Creator 中查看我的组件,您会发现它实际上由 2 个组件组成:一个是实现主要 SPI 逻辑的专用 UDB 组件,另一个是将我的 UDB 组件连接到 DMA 的原理图和一些控制逻辑。第二个组件也有包含我的硬件特定代码的 API 文件,并且是要放入您的 TopDesign 原理图中的组件。
FatFS 作为预编译库包含在内,API 文件夹中的 LowLevelFilesys.h 提供对所有文件功能的访问。
此组件在设计时考虑了批量读取,API 执行以下读取操作:
- 设置所需数据长度的 DMA TD 并告诉我的 SPI 组件将传输多少字节。
- 触发传输,使我的 SPI 组件自动发送 0xFF(无需为接收到的每个字节向 SPI 写入 0xFF),同时通过 DMA 将每个接收到的字节复制到接收缓冲区。
写卡以更典型的方式执行,在为它准备好 SD 卡后,DMA 只需将数据发送到 SPI 模块。
如果您 运行 我的项目在您的 PSoC 系统上,它将在 SD 卡上执行读/写测试,并存放报告规格的文件:
Testing Speed
Writing 16000 bytes to file, non-DMA
Took 94 ms
Rate 1361 kbps
Reading 16000 bytes to file, non-DMA
Took 50 ms
Verifying... All Good! :D
Rate 2560 kbps
Writing 16000 bytes to file, DMA
Took 17 ms
Rate 7529 kbps
Reading 16000 bytes to file, DMA
Took 12 ms
Verifying... All Good! :D
Rate 10666 kbps
有些 SD 卡的效果更好,有些则更差。我认为这取决于 SD 卡本身(例如 class、使用情况、技术年龄等)。
如何使用 SPI 和 PSoC 5LP (32-bit Cortex-M3) 芯片可用的 DMA 写入 SD 卡?
我目前有一个 DMA 和 SPI tx/rx 对工作,但用于不同的目的,所以如果实际传输不是问题,我只是不知道如何与 SD 卡交互。
datasheet for the PSoC 5LP is here.
基本信息:
我在简单模式下使用 DMA,DMA TD 链设置为: 8 位宽度,4 字节突发 自动完成完整的 TD(只需要初始硬件请求) 完成后循环回到初始 TD 的开头并等待 HW 请求
SPI 主机在 gui 中初始化,我使用 16Mhz 时钟、8 位 tx/rx 传输和 4 字节 tx/rx 缓冲区进行设置。中断在 rx FIFO 满时设置,连接到它们的是 rx DMA。
SDcard SPIrx/tx的指针分别是SPIM_RX_PTR和SPIM_TX_PTR。 DMA 与它们之间进行传输。我正在传输的阵列是 SDcardout 和 SDcardin。
使用 SPI 通信只会让您获得对卡的最低 command/block 级别访问权限;您将需要一个文件系统。 SD 卡 pre-formatted 作为 FAT32,因此 FAT file-system 将提供最大的可比性,但不是最可靠的(例如,如果写入因断电或重置而中断,则可能会损坏)。它还具有实施起来相对简单并且需要很少资源的优点。
有几个商业和 open-source FAT 文件系统库可用。我建议您查看 ELM FatFs or ELM Petit FatFs 两者都有宽松的许可证并且有据可查。在每种情况下,您只需要实现磁盘 I/O 存根以将它们映射到您的 SPI 驱动程序。网站上有大量示例、文档和应用说明可以为您提供帮助。您可以从另一个目标的 SPI SD 实现示例开始,然后将其调整为您的驱动程序(或者可能调整您的驱动程序)。其他 FAT 文件系统库与此大致相似,需要 I/O 层实现。
ELM FatFs 的 diskio 层不是特定于媒体的,因此您实际上需要在它和 SPI 驱动程序之间增加一个 MMC/SD 层。您不太可能找到针对特定目标的示例,但可以从其他目标的示例开始工作,因为 MMC/SD over SPI 本身不是特定于目标的,硬件依赖性仅出现在 SPI 级别,并且card-detect 和 write-protect(可选)信号的 GPIO 实现。有几个针对各种 ARM 目标的示例 here, a project for PSoC support here(在撰写本文时显然是 work-in-progress)。
我已经解决了这个问题。
我发现 PSoC 5 组件库随附的现有 SPI 模块不太适合与 SD 卡进行批量传输。据我所知,有必要在每次字节传输时清除软件中的 SPI 模块标志,从而降低 DMA 的用处。我认为一个解决方案是使用两个 TD(传输描述符)——一个执行数据传输,第二个在第一个 TD 完成后清除 RX 标志——无论如何,这是题外话。
我还发现组件库中提供的 emFile 组件的功能有限。我看不到任何附加 DMA 的方法,即使我可以,它的时钟速度似乎也很差。最重要的是,emFile 需要编译时选择 FAT16 或 FAT32,将您的设计限制在一个或另一个文件系统上。
因为我不喜欢更复杂的 DMA 设置,所以我决定在 UDB 编辑器中设计我自己的 SPI 组件硬件。可以在以下位置找到包含该组件的项目:https://github.com/PolyVinalDistillate/NSDSPI
它结合了上面提到的优秀 FatFS 库(感谢 ChaN),它处理 FAT12、FAT16 和 FAT32 格式的卡。如前所述,如果没有文件系统层,您将只能访问每个 512 字节的原始数据块。使用 FatFS,您可以获得 fopen()、fclose() 等的类似物
如果您在 PSoC Creator 中查看我的组件,您会发现它实际上由 2 个组件组成:一个是实现主要 SPI 逻辑的专用 UDB 组件,另一个是将我的 UDB 组件连接到 DMA 的原理图和一些控制逻辑。第二个组件也有包含我的硬件特定代码的 API 文件,并且是要放入您的 TopDesign 原理图中的组件。
FatFS 作为预编译库包含在内,API 文件夹中的 LowLevelFilesys.h 提供对所有文件功能的访问。
此组件在设计时考虑了批量读取,API 执行以下读取操作:
- 设置所需数据长度的 DMA TD 并告诉我的 SPI 组件将传输多少字节。
- 触发传输,使我的 SPI 组件自动发送 0xFF(无需为接收到的每个字节向 SPI 写入 0xFF),同时通过 DMA 将每个接收到的字节复制到接收缓冲区。
写卡以更典型的方式执行,在为它准备好 SD 卡后,DMA 只需将数据发送到 SPI 模块。
如果您 运行 我的项目在您的 PSoC 系统上,它将在 SD 卡上执行读/写测试,并存放报告规格的文件:
Testing Speed
Writing 16000 bytes to file, non-DMA
Took 94 ms
Rate 1361 kbps
Reading 16000 bytes to file, non-DMA
Took 50 ms
Verifying... All Good! :D
Rate 2560 kbps
Writing 16000 bytes to file, DMA
Took 17 ms
Rate 7529 kbps
Reading 16000 bytes to file, DMA
Took 12 ms
Verifying... All Good! :D
Rate 10666 kbps
有些 SD 卡的效果更好,有些则更差。我认为这取决于 SD 卡本身(例如 class、使用情况、技术年龄等)。