- 2025-01-15
-
发表了主题帖:
SD NAND、SPI NAND 和 Raw NAND 的定义与比较
SD nand,贴片式SD卡,使用起来和SD卡一致,不同的是采用,通常采用LGA-8封装,尺寸为8mm x 6mm x 0.75mm,重点是采用贴片封装,可以直接贴在板卡上,直接解决了SD卡固定问题,再也不用为SD卡的接触稳定性操心!
SD nand 和 SD 卡、SPI Nor flash、 nand flash、eeprom一样,都是嵌入式系统中常见的用来存储数据所使用的存储芯片。
SD NAND、SPI NAND和Raw NAND
SD的英文全称是Secure Digital Memory,就是我们所熟知的SD卡
固态硬盘(Solid State Disk,SSD)是以NAND闪存介质为主的一种存储产品,应用于笔记本电脑、台式电脑、移动终端、服务器和数据中心等场合.
NAND闪存类型
按照每个单元可以存储的位数,可以将NAND闪存类型分为SLC、MLC、TLC、QLC和PLC。
以SLC NAND为例,每个单元存储数据位数为1位,这意味着每个单元可以存储一个“0”或“1”;类似的,MLC NAND每个单元可以存储数据两位,即“00”“01”“10”“11”,其它如TLC、QLC、PLC也按照相应位数进行以此类推。
不同的闪存类似,其性能、耐久性和价格是不同的。
在性能和耐久性方面,SLC>MLC>TLC>QLC>PLC。
在成本价格上,SLC>MLC>TLC>QLC>PLC。
- 2024-12-17
-
发表了主题帖:
【半导体存储】关于NAND Flash的一些小知识
前言
作为一名电子专业的学生,半导体存储显然是绕不过去的一个坎,今天聊一聊关于Nand Flash的一些小知识。
这里十分感谢深圳雷龙发展有限公司为博主提供的两片CS创世SD NAND的存储芯片,同时也给大家推荐该品牌的相关产品。
一、定义
存储芯片根据断电后是否保留存储的信息可分为易失性存储芯片(RAM)和非易失性存储芯片(ROM)。
非易失性存储器芯片在断电后亦能持续保存代码及数据,分为闪型存储器 (Flash Memory)与只读存储器(Read-OnlyMemory),其中闪型存储器是主流,而闪型存储器又主要是NAND Flash 和NOR Flash。
NAND Flash 存储单元尺寸更小,存储密度更高,单位容量成本更低,块擦/写速度快, 具有更长的寿命,多应用于大容量数据存储,如智能手机、PC、平板电脑、U 盘、固态硬盘、服务器等领域。
NOR Flash 读取速度更快,具备可在芯片内执行程序(XIP)的特点,在传输效率、稳定性和可靠性方面更具优势,通常用于小容量数据存储,适宜中等容量代码存储(通常在 1Mb~1Gb),在计算机、消费电子(智能手机、TV、TWS 耳机、可 穿戴设备)、安防设备、汽车电子(ADAS、车窗控制、仪表盘)等领域均有应用。
二、NAND Flash
NAND Flash的存储单元是数据存储的最小单位,目前闪存已经由数千亿个存储单元组成,通过将电子移入和移出封闭在绝缘体中的电荷存储膜来存储数据。
NAND Flash存储器使用浮栅晶体管,它能在没有电源的情况下存储信息。所有的电路都依赖于某种能量来使整个电池的电荷产生差异,这种能量迫使电子穿过栅极,Nand闪存的浮动栅极系统通过使用第二个栅极在电子穿过电池时收集和捕获一些电子, 这使得粘在浮栅上的电子在没有电压的情况下保持原位,在这一过程中不管是否有电源连 接,芯片都能继续存储下一个值。
NAND Flash 为大容量数据存储的实现提供了廉价有效的解决方案,是目前全球市场大容量非易失存储的主流技术方案。
三、NAND Flash分类
NAND闪存卡的主要分类以NAND闪存颗粒的技术为主,NAND闪存颗粒根据存储原理分为SLC、MLC、TLC和QLC,从结构上又可分为2D、3D两大类。
Flash按技术主要分为SLC、MLC、TLC和QLC四大类,对应不同的空间结构,这四类技术可又分为2D结构和3D结构两大类;2D结构的存储单元仅布置在芯片的XY平面中,为了提高存储密度,制造商开发了3D NAND或V-NAND(垂直NAND)技术,该技术将Z平面中的存储单元堆叠在同一晶圆上。
3D NAND, 即立体堆叠技术,如果把2D NAND看成平房,那么3D NAND就是高楼大厦,建筑面积成倍扩增,理论上可以无限堆叠,可以摆脱对先进制程工艺的束缚,同时也不依赖于极紫外光刻(EUV)技术。
与2D NAND缩小Cell提高存储密度不同的是,3D NAND只需要提高堆栈层数,目前多种工艺架构并存。从2013年三星推出了第一款24层SLC/MLC 3D V-NAND,到现在层数已经迈进200+层,并即将进入300+层阶段。目前,三星/西部数据/海力士/美光/铠 侠等几乎垄断了所有市场份额,并且都具有自己的特殊工艺架构,韩系三星/海力士的CTF,美系镁光/英特尔的FG,国内长江存储的X-tacking。
随着堆栈层数的增加,工艺也面临越来越多的挑战,对制造设备和材料也提出了更多的要求。主要包括以下几个方面:
1)ONON薄膜应力:随着器件层数增加,薄膜应力问题越发凸显,会影响后续光刻对准精度;
2)高深宽比通孔刻蚀:随着深宽比增加,刻蚀难度会显著增加,容易出现刻蚀不完全、通孔结构扭曲等问题;
3)WL台阶的设计与刻蚀:垂直管状环栅结构的器件需要刻蚀出精确的台阶结构,保障CT能打到对应位置,而随着层数增加, 工艺难度加大,需要重新设计WL台阶结构。
四、品牌推荐——雷龙发展代理CS创世SD NAND
对于电子这一专业来说,仅仅从书面上了解一款电子元件是远远不够格的,上手实践才是第一要义。
这里十分感谢深圳雷龙发展有限公司为博主提供的两片SD NAND的存储芯片,同时也给大家推荐该品牌的相关产品。
博主拿到手上的芯片型号为:CSNP4GCR01-AMW,其性能如下
这款存储芯片作为博主正在完成的物联网项目中表现优异,性能良好,是作为存储工具的不二选择。
- 2024-12-06
-
发表了主题帖:
SD NAND 概述
SD NAND是一种小型、可表面贴装的存储解决方案,适用于各种嵌入式系统和便携式设备。SD NAND技术是近年来在存储领域内的一项创新,它结合了传统SD/TF卡的功能与NAND闪存的持久性,以适应现代电子设备对于尺寸、性能和可靠性的严格要求。
EEWORLDIMGTK0
1.SD NAND的技术特性、优势以及应用场景
下面将从多个角度详细探讨SD NAND的技术特性、优势以及应用场景:
1. 基本概念与设计特点
定义及别称:SD NAND也被称为贴片式T卡、贴片式TF卡或贴片式SD卡等,它是一种将传统的TF/SD卡功能集成进一个6*8mm LGA-8封装的存储芯片。
内部结构:SD NAND芯片内部包含一个控制器和一个Flash存储单元,支持SDIO模式和SPI模式,具备ECC、磨损平均、电源管理和时钟控制等功能。
封装优势:采用LGA-8封装,便于机器贴片,解决了传统TF卡不能机贴、容易脱落的问题,同时占用更少的PCB面积。
2. 使用寿命与稳定性
EEWORLDIMGTK1
使用SLC NAND Flash晶圆:SLC NAND Flash是NAND闪存中使用寿命最长、性能最稳定的类型,擦写次数可达5~10万次,保证了SD NAND的耐用性。
高低温测试:SD NAND已通过10k次随机掉电和高低温冲击测试,证明了其在极端环境下的可靠性。
3. 容量与成本效益
多种容量选择:目前量产的SD NAND容量有128MB、512MB,未来还将推出更高容量的产品,如4GB甚至32GB,满足不同需求。
-成本优势:与传统大容量eMMC/TF卡相比,SD NAND具有更优的成本效益,特别是在需要中小容量存储的应用场景中。
4. 易用性与兼容性
免驱动使用:由于SD NAND内置了必要的控制器和固件,大多数CPU只要支持SD接口就能直接使用,无需额外开发Flash驱动,降低了工程师的开发难度。
减少CPU负荷:将针对NAND Flash的操作交由SD NAND处理,减轻了CPU的负担,提高了整体效率。
5. 与其他存储技术的比较
相比TF/SD卡:SD NAND解决了卡类产品容易脱落、不能机贴、占用面积大等问题。
相比eMMC:SD NAND避免了eMMC产品因容量过大导致的高成本和复杂的焊接问题。
相比Raw NAND:SD NAND简化了Raw NAND需要编写驱动、容易掉电丢失数据等问题。
还需要补充的是:
1. 速度与性能:SD NAND的读写速度取决于其使用的NAND闪存类型(如SLC、MLC、TLC、QLC)和控制器的性能。在选择SD NAND时,应根据具体应用的需求考虑其速度等级和性能评估。
2. 应用场景:SD NAND特别适合于空间受限或要求高可靠性的嵌入式系统,如可穿戴设备、智能家居设备和工业控制系统。
3. 未来发展趋势:随着物联网和智能设备的兴起,对于小型化、高性能存储解决方案的需求日益增长,SD NAND有望在这些领域得到更广泛的应用。
SD NAND作为一种创新的存储解决方案,以其小巧的尺寸、优越的性能和便捷的使用方式,为现代电子设备提供了更多的设计灵活性和成本效益。无论是在工业自动化、消费电子还是个人便携式设备中,SD NAND都展现出了巨大的潜力和广阔的市场前景。
雷龙科技旗下的CS创世品牌自2016年成立以来,一直专注于采用国际先进的芯片设计和技术,结合本地化的生产和制造优势,为客户提供高品质的产品和服务。在众多产品中,CS创世的SD NAND存储解决方案以其卓越的性能、可靠性和小巧的尺寸,受到市场的广泛关注和应用。
2.CS创世SD NAND的特点
1. 小巧的尺寸:采用6x8mm LGA-8封装,便于机器贴片,解决了传统TF卡不能机贴、容易脱落的问题,同时占用更少的PCB面积。
2. 高性能:支持SDIO模式和SPI模式,具备ECC、磨损平均、电源管理和时钟控制等功能,确保了高效的数据读写性能。
3. 高耐用性:使用SLC NAND Flash晶圆,擦写次数可达5~10万次,远超其他类型的NAND闪存,并通过10k次随机掉电和高低温冲击测试,证明了其在极端环境下的可靠性。
4. 易用性:内置控制器和固件,无需额外开发Flash驱动,大大简化了工程师的开发难度,并提供了丰富的软件支持,如STM32参考例程和原厂技术支持。
#include <stdio.h>
#include "sd_nand.h"
int main() {
// 初始化SD NAND
if (sd_nand_init() != SD_NAND_OK) {
printf("SD NAND初始化失败!
");
return -1;
}
// 写入数据到SD NAND
char data[] = "Hello, CS创世!";
uint32_t address = 0x1000;
if (sd_nand_write(address, data, sizeof(data)) != SD_NAND_OK) {
printf("写入数据失败!
");
return -1;
}
// 从SD NAND读取数据
char read_data[sizeof(data)] = {0};
if (sd_nand_read(address, read_data, sizeof(data)) != SD_NAND_OK) {
printf("读取数据失败!
");
return -1;
}
// 打印读取到的数据
printf("从SD NAND读取到的数据:%s
", read_data);
return 0;
}
代码仅供参考。
3.总结
通过结合卓越的技术特性和强大的支持资源,雷龙发展CS创世的SD NAND不仅能满足各种嵌入式系统和便携式设备对存储的需求,还能帮助开发者和企业缩短产品开发周期,降低成本,提高市场竞争力。随着数字化转型和云计算的发展,数据存储需求将持续增加,雷龙科技CS创世的SD NAND有望在这些领域发挥更大的作用,为用户提供更多创新和价值。
- 2024-11-07
-
发表了主题帖:
北京君正X2000新品案例:流媒体音乐接收器
关于北京君正
北京君正集成电路股份有限公司成立于2005年,基于创始团队创新的CPU设计技术,迅速在消费电子市场实现SoC芯片产业化,2011年5月公司在深圳创业板上市(300223)。
君正在处理器技术、多媒体技术和AI技术等计算技术领域持续投入,其芯片在智能视频监控、AIoT、工业和消费、生物识别及教育电子领域获得了稳健和广阔的市场。
2020年,君正完成对美国ISSI及其下属子品牌Lumissil的收购。ISSI面向汽车、工业和医疗等领域提供高品质、高可靠性的存储器产品,包括SRAM、DRAM、NOR Flash、2D NAND Flash和eMMC,客户遍布全球。Lumissil面向汽车、家电和消费电子等领域提供LED驱动、微处理器、电源管理和互联等芯片产品。
君正将整合其积累十几年的计算技术,及ISSI三十余年的存储、模拟和互联技术,利用公司拥有的完整车规芯片质量和服务体系,为汽车、工业、AIoT等行业的发展持续做出贡献。
亲,如果你在网站上没找到想要的信息可以联系我们,我们提供原厂技术支持,并提供君正集成电路完整解决方案,大大降低你的开发难度及开发时间,让你比同行更快一步
- 2024-10-25
-
发表了主题帖:
开箱展示—CS创世SD NAND FLASH(贴片式SD卡/TF卡)
最近收到了来自深圳市雷龙发展有限公司寄来的存储卡,奈何最近也没有好的嵌入式项目需要用到,哪这里就简单给大家展示一下吧。
原始包装大概就是这样子了垃,有两个存储芯片和一个简单的转接器,测试的时候可以把芯片焊接到转接器上,等到自己真正开发的时候,可以设计好电路,直接把存储卡焊接到PCB板上,就可以正常读取了。
转接板的一头,其实就跟我们常见的TF卡一样,我们可以直接把它插到读卡器上读取
这里也就测试一下,实际使用时肯定不会这样用:
由于我是把tf卡插到读卡器里读取的,读卡器又是USB接口,所以这里被识别成了U盘一样的东西。
这篇文章也就一个简单的测试了,更多更详细的信息还是去这里:深圳市雷龙发展有限公司官网了解详细吧。
- 2024-10-16
-
发表了主题帖:
国产安路FPGA SD NAND FLASH 初步描述
说起SD NAND FLASH常被联想到SD卡,SD NAND FLASH具备当前SD卡的基本功能,并具有更高的存储密度,更小的体积,通过芯片形式焊接在电路中稳定可靠,在电路中高度集成可SMT机贴片等优点。这一节我们主要是介绍一下SD NAND FLASH,该应用实例的SD NAND FLASH采用深圳市雷龙发展有限公司的CSNP1GCR01-AOW型号的存储芯片,雷龙发展在SD NAND FLASH中已经有多年的深厚研发经验和严格的测试流程。
一、SD NAND FLASH芯片简介
CSNP1GCR01-AOW是基于NAND FLASH 和SD 控制器的1Gb容量空间的存储芯片。比传统的NAND FLASH具有还有坏块管理,数据ECC功能和异常掉电保证数据安全存储等功能。封装尺寸为8mm x 6mm x0.75mm。
产品特点:
接口:具备1线或者4线SD标准2.0版本
供电:Vcc = 2.7V - 3.6V
默认模式:可变的时钟范围0~25MHz,高达12.5MB/s的接口速度(使用4线)
高速模式:可变的时钟范围0~50MHz,高达25MB/s的接口速度(使用4线)
工作温度范围:-40°C to +85°C
存储温度范围:-55°C to +125°C
标准电流:< 250uA
开关功能命令支持高速,商务和未来的一些功能
矫正存储区域的错误
内容保护机制兼容最安全的SDMI标准
支持SD NAND密码保护功能
使用机械开关进行写保护功能
内置写保护功能(永久和临时)
通用场景
应用程序特定命令
舒适擦除机制
通过下图的功能框图可以理解,SD NAND FLASH是通过Memory core来进行存储数据的,通过SD控制进行通讯接口的控制和存储的管理。
外部引脚位置和定义如下图所示:
机械尺寸如下图所示:
二、总结
本节主要介绍了SD NAND FLASH的基本功能特性,引脚定义和外形的机械尺寸,通过这个基本的描述可以对SD NAND FLASH有个初步的了解。下一节主要介绍,SD NAND FLASH的初始化过程。
- 2024-09-25
-
发表了主题帖:
北京君正X2000新品案例:流媒体音乐接收器
关于北京君正
北京君正集成电路股份有限公司成立于2005年,基于创始团队创新的CPU设计技术,迅速在消费电子市场实现SoC芯片产业化,2011年5月公司在深圳创业板上市(300223)。
君正在处理器技术、多媒体技术和AI技术等计算技术领域持续投入,其芯片在智能视频监控、AIoT、工业和消费、生物识别及教育电子领域获得了稳健和广阔的市场。
2020年,君正完成对美国ISSI及其下属子品牌Lumissil的收购。ISSI面向汽车、工业和医疗等领域提供高品质、高可靠性的存储器产品,包括SRAM、DRAM、NOR Flash、2D NAND Flash和eMMC,客户遍布全球。Lumissil面向汽车、家电和消费电子等领域提供LED驱动、微处理器、电源管理和互联等芯片产品。
君正将整合其积累十几年的计算技术,及ISSI三十余年的存储、模拟和互联技术,利用公司拥有的完整车规芯片质量和服务体系,为汽车、工业、AIoT等行业的发展持续做出贡献。
亲,如果你在网站上没找到想要的信息可以联系深圳市雷龙发展有限公司,我们提供原厂技术支持,
- 2024-09-24
-
发表了主题帖:
CS创世8GB SD NAND的低功耗特性
在电子设备不断追求低功耗的今天,CS创世半导体的8GB SD NAND芯片以其低功耗特性脱颖而出。这款芯片的读写电流仅为15mA,相较于同类产品,其功耗显著降低,这不仅延长了设备的使用时间,还减少了对电池的依赖。这种低功耗特性特别适合用于那些需要长时间运行且对电池寿命有严格要求的设备,如运动耳机和各类相机产品。
CS创世8GB SD NAND芯片的封装尺寸仅为7*8.5毫米,仅有8个管脚,使得它在设计和布局上更加灵活,适合小尺寸的应用领域。这种设计不仅提升了产品的美观度,还降低了生产成本,使得这款芯片在市场上具有极高的竞争力。其内置的控制核心和高稳定性的存储单元,保证了数据传输的高效和稳定,使得这款芯片在性能和可靠性方面都达到了一个新的高度。
此外,这款芯片的小文件读取速度在HD TUNE实测中可达到1.4MB/S,这一速度在同类产品中处于领先地位。这种高速度的读取能力,使得它在处理大量数据时更加迅速和高效,特别适合需要快速数据传输的应用场景,如各类相机产品和儿童相机。这种创新和可靠性的结合,使得这款芯片在性能和可靠性方面都达到了一个新的高度,满足了客户对高性能存储解决方案的需求。
非常欢迎您来到雷龙官网,并感谢您的信任与支持!在存储技术日新月异的今天,选择合适的闪存解决方案对于提升数据存储效率、保障数据安全至关重要。雷龙作为在存储行业深耕13年的专业品牌,我们深知每一位用户的需求与期望,因此致力于提供高质量、高性能、高可靠性的小容量闪存解决方案。
如果您在浏览官网文章或了解我们的产品过程中遇到任何疑惑或不懂的地方,我们非常乐意为您提供帮助。请随时通过以下方式联系我们:
在线客服:访问深圳市雷龙发展有限公司官网时,您可以直接通过网页上的在线客服功能与我们的客服人员实时交流,解答您的疑问。
- 2024-09-20
-
发表了主题帖:
北京君正案例实现高速高质量打印技术-国产主控芯片
3D打印技术持续演变,高速打印机以前所未有的速度改变着3D打印的规则。K1 Max作为创想三维的旗舰高速新品,融合了高速和智能的革命性特性,自上市以来,深受用户喜爱。
本文将深度解析K1 Max高速打印机的核心技术,以及其如何实现高速度和高质量打印的原理。
1、超高速打印
K1 Max以其卓越性能而广受青睐,得益于精湛的工程设计,其打印速度高达600mm/s,加速度更达20000mm/s²。为了达成这种超高速打印效果,我们运用了一系列先进的技术:
1.1高流量挤出机构
K1 Max引入了一系列精心设计的功能,从而展现出色的打印性能:
1.1.1精准的步进电机,为打印提供了稳定的基础。
1.1.2强大的挤出力,近端双齿轮减速挤出机构使得K1 Max获得强大的挤出力,保障了打印的效率和质量。
1.1.3耐堵塞设计,陶瓷加热热端的快速升温与双金属喉管的有效热量控制,共同在耗材挤出中发挥关键作用。
1.1.4耐磨的喷嘴材质,铜合金镶嵌硬化钢喷嘴设计在确保良好传热的同时,显著延长了喷嘴的使用寿命,可以支持各种加纤材料打印,拓宽了应用场景。
1.2高速运动机构
k1 Max采用coreXY结构来支持高速运动,它具有以下特点:
1.2.1高精度运动控制,可以实现平稳、精确的运动,从而提高打印的精度。
1.2.2平行运动,这种设计有助于避免运动时的扭曲和偏移,确保打印机的精准度。
1.2.3高速运动,实现更高的打印速度,这使得打印任务可以更快地完成。
1.2.4较小的移动质量,避免在移动过程中引入不必要的惯性。
1.2.5适合大尺寸打印,有效地控制和稳定大尺寸平台上的运动。
1.2.6较小的机械振动,可以减少机械振动。
1.3运动学算法控制系统
K1 Max采用Creality OS基于klipper的运动控制系统来支持机器高速稳定运动,这种运动控制系统具有以下特点:
1.3.1加速度
1.3.2梯形运动生成器
1.3.3前瞻运动系统
1.3.4智能振动补偿
1.3.5挤出压力提前算法
2、自动调平
自动调平是指在3D打印机中使用传感器和控制系统来自动检测和调整打印平台的高度,以确保打印平台与打印头之间的距离在整个打印过程中保持一致。这有助于获得更准确的首层效果、更稳定的打印结果,提高打印质量和可靠性。
3、交流热床加热系统
K1 Max使用了交流热床加热系统,可以精确控制和维持打印平台的温度。这个系统使用交流电,比传统的直流加热系统更有效率,因为直流系统需要转换电流,这会降低能量利用效率。此外,交流加热系统还可以实现更均匀的温度分布,加快加热速度,适用于更宽的温度范围。K1 Max还引入了智能电压切换系统,可以在110V AC和220V AC环境下自动切换,使得用户无需担心电压兼容性问题。
4、AI故障检测系统
K1 Max在设备上部署了边缘AI技术,帮助用户进行实时故障监控。边缘AI将AI技术应用在物联网设备上,实现本地数据处理和决策,提升实时性、保护隐私并有效利用网络带宽。AI故障检测系统依赖于图像识别与处理、深度学习神经网络和端到端目标检测算法。这些技术能获取和识别图像信息,优化模型,学习图像模式,并直接提取图像中的目标物体。K1 Max的边缘AI技术和故障检测系统利用这些技术,能在打印过程中高效准确识别物体,保障打印安全。
文章来源:3D打印产业布道者
关于北京君正
北京君正集成电路股份有限公司成立于2005年,基于创始团队创新的CPU设计技术,迅速在消费电子市场实现SoC芯片产业化,2011年5月公司在深圳创业板上市(300223)。
君正在处理器技术、多媒体技术和AI技术等计算技术领域持续投入,其芯片在智能视频监控、AIoT、工业和消费、生物识别及教育电子领域获得了稳健和广阔的市场。
2020年,君正完成对美国ISSI及其下属子品牌Lumissil的收购。ISSI面向汽车、工业和医疗等领域提供高品质、高可靠性的存储器产品,包括SRAM、DRAM、NOR Flash、2D NAND Flash和eMMC,客户遍布全球。Lumissil面向汽车、家电和消费电子等领域提供LED驱动、微处理器、电源管理和互联等芯片产品。
君正将整合其积累十几年的计算技术,及ISSI三十余年的存储、模拟和互联技术,利用公司拥有的完整车规芯片质量和服务体系,为汽车、工业、AIoT等行业的发展持续做出贡献。
亲,如果你在网站上没找到想要的信息可以联系我们,我们提供原厂技术支持,并提供君正集成电路完整解决方案,大大降低你的开发难度及开发时间,让你比同行更快一步,更好的解决方案都在深圳市雷龙发展有限公司。
- 2024-08-07
-
发表了主题帖:
K210使用创世NAND flash完成火灾检测
前言
前几天收到了雷龙NAND的芯片,一共两个芯片和一个转接板,我之前也没有使用过这款芯片,比较好奇,体验了一下,个人认为,如果你画PCB制作一些板子的话,很推荐,比SD卡要方便很多。刚好最近在做K210的火灾检测,就用这个SD NAND来体验一下。
一、NAND是什么?
不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装,标准SDIO接口,兼容SPI/SD接口,兼容各大MCU平台,可替代普通TF卡/SD卡,尺寸6x8mm毫米,内置SLC晶圆擦写寿命10万次,通过1万次随机掉电测试耐高低温,支持工业级温度-40°~+85°,机贴手贴都非常方便,速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。支持TF卡启动的SOC都可以用SD NAND,比eMMC便宜。
简单来说就是贴片TF,但是稳定性更高。
二、来看一看NAND
这是NAND的转接板
这是NAND的芯片,可以看出尺寸非常小,非常适合用来画板子,这样可以省去贴SD卡卡座的步骤。
最后贴好就是这个样子
先用crystaldiskmark跑一下看看
这个是跑出来的数据,数据上来看,还不错。但是实际使用怎么样呢
三、部署火灾检测
将文件放入SD NAND中,然后把转接板插在K210上
然后打开MAXIPY运行
兄弟们,惊呆了,强烈推荐!!!!用过K210的都知道,这个玩意比较挑内存卡,普通的内存卡它根本读不到,结果这个芯片可以直接用,确实有点震惊到我。
我之前画过一个K210,因为贴SD卡卡座比较头大,现在有了新方案可以代替他,是时候着手在画一个了。
用来做DIY去代替内存卡,直接贴在板子上,非常省空间!!!!
最后简单贴一下代码,模型文件在QQ群里,感兴趣的可以主页加群
import sensor
import image
import lcd
import utime
import KPU as kpu
from machine import UART
from fpioa_manager import fm
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.set_hmirror(0)
sensor.run(1)
fm.register(6, fm.fpioa.UART1_TX, force=True)
fm.register(7, fm.fpioa.UART1_RX, force=True)
uart_A = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)
task = kpu.load("/sd/yolov2.kmodel")
f=open("anchors.txt","r")
anchor_txt=f.read()
L=[]
for i in anchor_txt.split(","):
L.append(float(i))
anchor=tuple(L)
f.close()
a = kpu.init_yolo2(task, 0.6, 0.3, 5, anchor)
f=open("lable.txt","r")
labels_txt=f.read()
labels = labels_txt.split(",")
f.close()
while(True):
img = sensor.snapshot()
code = kpu.run_yolo2(task, img)
if code:
for i in code:
a=img.draw_rectangle(i.rect(),(0,255,0),2)
a = lcd.display(img)
for i in code:
lcd.draw_string(i.x()+45, i.y()-5, labels[i.classid()]+" "+'%.2f'%i.value(), lcd.WHITE,lcd.GREEN)
else:
a = lcd.display(img)
a = kpu.deinit(task)
————————————————
亲爱的卡友们,欢迎光临雷龙官网,如果看完文章之后还是有疑惑或不懂的地方,请联系我们,深圳市雷龙发展专注存储行业13年,专业提供小容量存储解决方案。
- 2024-08-02
-
发表了主题帖:
君正X2600在3D打印机上的优势:多核异构,远程控制与实时控制
在当前的3D打印机领域,君正的X2600芯片以其独特的优势引起了业界的广泛关注。这款多核异构芯片,拥有两个大核和一个小的RISC-V处理器,不仅能够处理复杂的打印任务,还可以通过接USB摄像头实现远程控制,极大地提高了3D打印机的便捷性与稳定性。
一、多核异构,强大处理能力
君正X2600芯片采用多核异构架构,将两个大核处理器与一个RISC-V处理器完美融合。其中,两个大核可以运行Linux、Debian等操作系统,胜任复杂的打印任务处理,而小核RISC-V处理器则可专注于实时控制,以实现更高效的打印过程。
二、接USB摄像头,远程控制
雷龙发展代理的君正X2600在3D打印机上的一个显著优势是其可以通过接USB摄像头实现远程控制。这一特性使得用户可以随时随地监控打印进度,无需亲自到打印机现场,为使用者提供了极大的便利。
三、实时控制,提高稳定性
除了远程控制功能外,X2600的小核RISC-V处理器还能实现实时控制。这意味着,无论是打印过程中的速度、温度还是其他参数,都可以实现精准调控,从而确保了打印机的稳定性和打印质量的提高。
四、应用实例
为了更好地说明X2600在3D打印机上的优势,让我们通过一个具体的应用实例来进行阐述。比如,一位设计师正在远程办公,需要打印一份复杂的3D模型。通过使用X2600控制的3D打印机,设计师可以轻松地将模型文件传输到打印机,并通过接USB摄像头实时查看打印进度。同时,由于X2600的实时控制功能,打印机在打印过程中能够根据需求进行精准调控,确保了打印的稳定性和准确性。这样一来,设计师可以在家中轻松完成打印任务,节省了大量时间和精力。
五、总结
综上所述,君正X2600在3D打印机上展现出强大的优势。其多核异构架构、远程控制功能以及实时控制特点,为用户提供了更为便捷、高效的打印体验。通过实际应用案例,我们可以看到X2600在3D打印领域具有广泛的应用前景。相信未来随着技术的不断发展,雷龙发展代理的X2600还将为3D打印机行业带来更多的创新与突破。
- 2024-07-24
-
发表了主题帖:
【CS创世 SD NAND】SD NAND芯片的测评与使用(基于卷积神经网络的数字识别)
目录
前言:
简介:
对照:
测试:
使用:
照片存储:
基于卷积神经网络的数字识别:
————————————————
前言:
感谢深圳雷龙公司寄送的样品,其中包括两张2代的4gbit和32gbit的SD NAND FLASH芯片以及一份测试板卡。
添加描述
简介:
根据官方文档的描述,这款芯片采用LGA-8封装,具有标准SDIO接口,并同时兼容SPI和SD接口。因此,可以直接移植标准驱动代码,支持使用SD NAND FLASH的SOC也可以用于TF卡启动。
以下是该芯片的主要参数(以CSNP32GCR01-BOW手册为准):
接口:符合标准SD Specification Version 2.0规范,包括1-I/O和4-I/O两种模式。
默认模式:在默认模式下,时钟频率可变范围为0-25 MHz,接口速度高达12.5 MB/sec(使用4条并行数据线路)。
高速模式:在高速模式下,时钟频率可变范围为0-50 MHz,接口速度高达25 MB/sec(使用4条并行数据线路)。
对照:
下面是SD NAND芯片和传统TF卡的一些对比:
添加描述
目前,一些树莓派和一些国产的微处理器经常通过SD卡进行系统的移植,但一些设计不合理的卡槽经常不能保护SD卡,反而会损坏折断。相比之下,SD NAND可以通过贴片直接嵌入嵌入式设备中,更适合嵌入式环境的开发。同时,裸露的SD卡槽和松动的SD卡时常会影响系统的稳定性,因此一个可以反复擦拭的稳定存储芯片显得十分重要。
通过将测试板和芯片进行简单的焊接,我们可以像使用SD卡一样对SD NAND FLASH进行测试。
测试:
首先,我们使用CrystalDiskMark 8.0.4c对这款储存器进行了测试:
本次测试的是512MB的容量的产品,容量是真实的。我们可以看出,在包括顺序读取、顺序写入、随机读取和随机写入的四个测试方式下,SD NAND取得了不错的测试结果,接近官方数据,可以成功进行高速存储。
添加描述
使用:
此外,我们还利用k210与SD NAND进行了照片的存储和基于卷积神经网络的数字识别。
1.照片存储:
通过向SD NAND内烧录micropython代码,实现了k210对照片的拍摄和存储。存储速度非常快。
import sensor, lcd
from Maix import GPIO
from fpioa_manager import fm
from board import board_info
import os, sys
import time
import image
#### image size ####
set_windowing = (224, 224)
#### sensor config ####
sensor.reset(freq=22000000, dual_buff=False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA) # 320x240
try:
sensor.set_jb_quality(95) # for IDE display quality
except Exception:
pass # no IDE support
if set_windowing:
sensor.set_windowing(set_windowing)
# sensor.set_auto_gain(False)
# sensor.set_auto_whitebal(False, rgb_gain_db=(0x52,0x40,0x4d))
# sensor.set_saturation(0)
# sensor.set_brightness(4)
# sensor.set_contrast(0)
# sensor.set_hmirror(True) # image horizonal mirror
# sensor.set_vflip(True) # image vertical flip
# sensor.set_auto_whitebal(False)
sensor.skip_frames()
#### lcd config ####
lcd.init(type=1, freq=15000000)
lcd.rotation(2)
#### boot key ####
boot_pin = 16 # board_info.BOOT_KEY
fm.register(boot_pin, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.PULL_UP)
######################################################
#### main ####
def capture_main(key):
def draw_string(img, x, y, text, color, scale, bg=None , full_w = False):
if bg:
if full_w:
full_w = img.width()
else:
full_w = len(text)*8*scale+4
img.draw_rectangle(x-2,y-2, full_w, 16*scale, fill=True, color=bg)
img = img.draw_string(x, y, text, color=color,scale=scale)
return img
def del_all_images():
os.chdir("/sd")
images_dir = "cap_images"
if images_dir in os.listdir():
os.chdir(images_dir)
types = os.listdir()
for t in types:
os.chdir(t)
files = os.listdir()
for f in files:
os.remove(f)
os.chdir("..")
os.rmdir(t)
os.chdir("..")
os.rmdir(images_dir)
# del_all_images()
os.chdir("/sd")
dirs = os.listdir()
images_dir = "cap_images"
last_dir = 0
for d in dirs:
if d.startswith(images_dir):
if len(d) > 11:
n = int(d[11:])
if n > last_dir:
last_dir = n
images_dir = "{}_{}".format(images_dir, last_dir+1)
print("save to ", images_dir)
if images_dir in os.listdir():
img = image.Image()
img = draw_string(img, 2, 200, "please del cap_images dir", color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
sys.exit(1)
os.mkdir(images_dir)
last_cap_time = 0
last_btn_status = 1
save_dir = 0
save_count = 0
os.mkdir("{}/{}".format(images_dir, save_dir))
while(True):
img0 = sensor.snapshot()
if set_windowing:
img = image.Image()
img = img.draw_image(img0, (img.width() - set_windowing[0])//2, img.height() - set_windowing[1])
else:
img = img0.copy()
# img = img.resize(320, 240)
if key.value() == 0:
time.sleep_ms(30)
if key.value() == 0 and (last_btn_status == 1) and (time.ticks_ms() - last_cap_time > 500):
last_btn_status = 0
last_cap_time = time.ticks_ms()
else:
if time.ticks_ms() - last_cap_time > 5000:
img = draw_string(img, 2, 200, "release to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
else:
img = draw_string(img, 2, 200, "release to capture", color=lcd.WHITE,scale=1, bg=lcd.RED)
if time.ticks_ms() - last_cap_time > 2000:
img = draw_string(img, 2, 160, "keep push to change type", color=lcd.WHITE,scale=1, bg=lcd.RED)
else:
time.sleep_ms(30)
if key.value() == 1 and (last_btn_status == 0):
if time.ticks_ms() - last_cap_time > 5000:
img = draw_string(img, 2, 200, "change object type", color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
time.sleep_ms(1000)
save_dir += 1
save_count = 0
dir_name = "{}/{}".format(images_dir, save_dir)
os.mkdir(dir_name)
else:
draw_string(img, 2, 200, "capture image {}".format(save_count), color=lcd.WHITE,scale=1, bg=lcd.RED)
lcd.display(img)
f_name = "{}/{}/{}.jpg".format(images_dir, save_dir, save_count)
img0.save(f_name, quality=95)
save_count += 1
last_btn_status = 1
img = draw_string(img, 2, 0, "will save to {}/{}/{}.jpg".format(images_dir, save_dir, save_count), color=lcd.WHITE,scale=1, bg=lcd.RED, full_w=True)
lcd.display(img)
del img
del img0
def main():
try:
capture_main(key)
except Exception as e:
print("error:", e)
import uio
s = uio.StringIO()
sys.print_exception(e, s)
s = s.getvalue()
img = image.Image()
img.draw_string(0, 0, s)
lcd.display(img)
main()
EEWORLDIMGTK3
添加描述
2.基于卷积神经网络的数字识别:
我们向SD NAND内烧录了功能代码、模型参数和模型结构。SD NAND可以很好地存储以上内容,并通过k210正确加载模型。在使用过程中,SD NAND表现出了出色的稳定性,没有出现崩溃或弹出的情况。
EEWORLDIMGTK4
添加描述
# generated by maixhub, tested on maixpy3 v0.4.8
# copy files to TF card and plug into board and power on
import sensor, image, lcd, time
import KPU as kpu
import gc, sys
input_size = (224, 224)
labels = ['1', '2', '3', '4', '5', '6', '7', '8']
anchors = [0.45, 1.55, 1.46, 2.54, 1.22, 1.55, 1.58, 2.59, 1.47, 2.78]
def lcd_show_except(e):
import uio
err_str = uio.StringIO()
sys.print_exception(e, err_str)
err_str = err_str.getvalue()
img = image.Image(size=input_size)
img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
lcd.display(img)
def main(anchors, labels = None, model_addr="/sd/m.kmodel", sensor_window=input_size, lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing(sensor_window)
sensor.set_vflip(1)
sensor.run(1)
lcd.init(type=1)
lcd.rotation(lcd_rotation)
lcd.clear(lcd.WHITE)
if not labels:
with open('labels.txt','r') as f:
exec(f.read())
if not labels:
print("no labels.txt")
img = image.Image(size=(320, 240))
img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)
lcd.display(img)
return 1
try:
img = image.Image("startup.jpg")
lcd.display(img)
except Exception:
img = image.Image(size=(320, 240))
img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)
lcd.display(img)
try:
task = None
task = kpu.load(model_addr)
kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]
while(True):
img = sensor.snapshot()
t = time.ticks_ms()
objects = kpu.run_yolo2(task, img)
t = time.ticks_ms() - t
if objects:
for obj in objects:
pos = obj.rect()
img.draw_rectangle(pos)
img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))
img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))
lcd.display(img)
except Exception as e:
raise e
finally:
if not task is None:
kpu.deinit(task)
if __name__ == "__main__":
try:
# main(anchors = anchors, labels=labels, model_addr=0x300000, lcd_rotation=0)
main(anchors = anchors, labels=labels, model_addr="/sd/model-54796.kmodel")
except Exception as e:
sys.print_exception(e)
lcd_show_except(e)
finally:
gc.collect()
通过以上两个实验,SD NAND代替传统的SD/TF卡进行数据存储表现出了极大的优势和稳定性。
- 2024-07-08
-
发表了主题帖:
如何使用ESP32C3驱动SPI NAND flash
最近收到了一片国产工业级SD NAND,可以替代SD卡,容量大,贴片封装,非常适合做飞控"黑匣子"。
EEWORLDIMGTK0
不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装,标准SDIO接口,兼容SPI/SD接口,兼容各大MCU平台,可替代普通TF卡/SD卡,尺寸6x8mm毫米,内置SLC晶圆擦写寿命10万次,通过1万次随机掉电测试耐高低温,支持工业级温度-40°~+85°,机贴手贴都非常方便,速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。支持TF卡启动的SOC都可以用SD NAND,厂商提供了STM32参考例程及原厂技术支持,主流容量:128MB/512MB/2GB/4GB/8GB,比TF卡稳定,比eMMC便宜。
飞控板上ESP32C3的SDIO接口暂时用不了,只能先用SPI接口驱动。
EEWORLDIMGTK1
评估板做了个micro SD卡的接口,方便直接插到带卡槽的开发板上进行调试。
ESP32C3的SPI接口是硬件SPI,支持DMA,速度应该还可以,但是我用杜邦线连接的,肯定会影响信号质量,估计时钟很难跑到50MHz了。
EEWORLDIMGTK2
接线:
EEWORLDIMGTK3
编写测试程序:
/* SD card and FAT filesystem example.
This example uses SPI peripheral to communicate with SD card.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#define EXAMPLE_MAX_CHAR_SIZE 64
static const char *TAG = "example";
#define MOUNT_POINT "/sdcard"
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
// You can also change the pin assignments here by changing the following 4 lines.
#define PIN_NUM_MISO CONFIG_EXAMPLE_PIN_MISO
#define PIN_NUM_MOSI CONFIG_EXAMPLE_PIN_MOSI
#define PIN_NUM_CLK CONFIG_EXAMPLE_PIN_CLK
#define PIN_NUM_CS CONFIG_EXAMPLE_PIN_CS
static esp_err_t s_example_write_file(const char *path, char *data)
{
ESP_LOGI(TAG, "Opening file %s", path);
FILE *f = fopen(path, "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return ESP_FAIL;
}
fprintf(f, data);
fclose(f);
ESP_LOGI(TAG, "File written");
return ESP_OK;
}
static esp_err_t s_example_read_file(const char *path)
{
ESP_LOGI(TAG, "Reading file %s", path);
FILE *f = fopen(path, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return ESP_FAIL;
}
char line[EXAMPLE_MAX_CHAR_SIZE];
fgets(line, sizeof(line), f);
fclose(f);
// strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
return ESP_OK;
}
void app_main(void)
{
esp_err_t ret;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
// Please check its source code and implement error recovery when developing
// production applications.
ESP_LOGI(TAG, "Using SPI peripheral");
// By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = host.slot;
ESP_LOGI(TAG, "Mounting filesystem");
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
ESP_LOGI(TAG, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
// Use POSIX and C standard library functions to work with files.
// First create a file.
const char *file_hello = MOUNT_POINT"/hello.txt";
char data[EXAMPLE_MAX_CHAR_SIZE];
snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Hello", card->cid.name);
ret = s_example_write_file(file_hello, data);
if (ret != ESP_OK) {
return;
}
const char *file_foo = MOUNT_POINT"/foo.txt";
// Check if destination file exists before renaming
struct stat st;
if (stat(file_foo, &st) == 0) {
// Delete it if it exists
unlink(file_foo);
}
// Rename original file
ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo);
if (rename(file_hello, file_foo) != 0) {
ESP_LOGE(TAG, "Rename failed");
return;
}
ret = s_example_read_file(file_foo);
if (ret != ESP_OK) {
return;
}
// Format FATFS
ret = esp_vfs_fat_sdcard_format(mount_point, card);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to format FATFS (%s)", esp_err_to_name(ret));
return;
}
if (stat(file_foo, &st) == 0) {
ESP_LOGI(TAG, "file still exists");
return;
} else {
ESP_LOGI(TAG, "file doesnt exist, format done");
}
const char *file_nihao = MOUNT_POINT"/nihao.txt";
memset(data, 0, EXAMPLE_MAX_CHAR_SIZE);
snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Nihao", card->cid.name);
ret = s_example_write_file(file_nihao, data);
if (ret != ESP_OK) {
return;
}
//Open file for reading
ret = s_example_read_file(file_nihao);
if (ret != ESP_OK) {
return;
}
// All done, unmount partition and disable SPI peripheral
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
//deinitialize the bus after all devices are removed
spi_bus_free(host.slot);
}
这段代码是使用SPI(串行外设接口)与SD卡进行通信。它展示了如何挂载SD卡、写入文件、读取文件、重命名文件、格式化SD卡,最后卸载SD卡。
代码首先包含了必要的头文件,并定义了一些常量,如最大字符大小、SD卡的挂载点和SPI通信的引脚分配。
然后定义了两个辅助函数:s_example_write_file和s_example_read_file。s_example_write_file函数打开一个给定路径的文件,写入数据,然后关闭文件。如果无法打开文件,它会记录一个错误并返回失败状态。s_example_read_file函数打开一个给定路径的文件,从中读取一行,然后关闭文件。如果无法打开文件,它会记录一个错误并返回失败状态。
app_main函数是程序的主入口点。它首先定义了挂载SD卡的配置。然后初始化SPI总线和SD卡插槽。如果初始化失败,它会记录一个错误并返回。
接下来,它试图挂载SD卡。如果挂载失败,它会记录一个错误并返回。如果挂载成功,它会记录一个成功消息并打印SD卡的属性。
程序然后在SD卡上写入一个文件,检查另一个文件是否存在,如果存在则删除它,然后将第一个文件重命名为第二个文件。然后从第二个文件中读取。
程序接着格式化SD卡,并检查第二个文件是否仍然存在。如果存在,它会记录一个消息并返回。如果不存在,它会记录一个成功消息,写入第三个文件,并从第三个文件中读取。
最后,卸载SD卡并禁用SPI外设。
编译:
EEWORLDIMGTK4
烧写到ESP32C3后运行,控制台输出:
I (286) app_start: Starting scheduler on CPU0
I (291) main_task: Started on CPU0
I (291) main_task: Calling app_main()
I (291) example: Initializing SD card
I (301) example: Using SPI peripheral
I (301) example: Mounting filesystem
I (311) gpio: GPIO[1]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (321) sdspi_transaction: cmd=52, R1 response: command not supported
I (361) sdspi_transaction: cmd=5, R1 response: command not supported
I (391) example: Filesystem mounted
Name: CS064
Type: SDHC/SDXC
Speed: 20.00 MHz (limit: 20.00 MHz)
Size: 7382MB
CSD: ver=2, sector_size=512, capacity=15118336 read_bl_len=9
SSR: bus_width=1
I (401) example: Opening file /sdcard/hello.txt
I (411) example: File written
I (411) example: Renaming file /sdcard/hello.txt to /sdcard/foo.txt
I (411) example: Reading file /sdcard/foo.txt
I (421) example: Read from file: 'Hello CS064!'
I (421) vfs_fat_sdmmc: Formatting card, allocation unit size=16384
I (2911) example: file doesnt exist, format done
I (2911) example: Opening file /sdcard/nihao.txt
I (2921) example: File written
I (2921) example: Reading file /sdcard/nihao.txt
I (2921) example: Read from file: 'Nihao CS064!'
I (2921) gpio: GPIO[1]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (2931) example: Card unmounted
I (2931) gpio: GPIO[4]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2941) gpio: GPIO[6]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2951) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (2961) main_task: Returned from app_main()
可以看到输出了存储卡信息:
Name: CS064
Type: SDHC/SDXC
Speed: 20.00 MHz (limit: 20.00 MHz)
Size: 7382MB
CSD: ver=2, sector_size=512, capacity=15118336 read_bl_len=9
SSR: bus_width=1
后面还输出了读写文件相应的信息。
- 2024-07-04
-
发表了主题帖:
Verilog:【8】基于FPGA实现SD NAND FLASH的SPI协议读写
在此介绍的是使用FPGA实现SD NAND FLASH的读写操作,以雷龙发展提供的CS创世SD NAND FLASH样品为例,分别讲解电路连接、读写时序与仿真和实验结果。
目录
1 视频讲解
2 SD NAND FLASH背景介绍
3 样品申请
4 电路结构与接口协议
4.1 SD NAND
4.2 SD NAND测试板
4.3 FPGA开发板
5 SD卡协议与时序流程
5.1 SD卡协议
5.2 SD卡2.0版本初始化步骤
5.3 SD卡的读步骤
5.4 SD卡的写步骤
6 模块代码
6.1 sd_card_top
6.2 sd_card_cmd
6.3 sd_card_sec_read_write
6.4 spi_master
6.5 其余代码
6.5.1 sd_card_test
6.5.2 ax_debounce
6.5.3 seg_decoder
6.5.4 seg_scan
7 实验结果
8 参考资料
使用FPGA讲解SD NAND FLASH的文章网上也有很多比较详实的内容,本文的部分思路也是参考了其他博主的博客思路。
1 视频讲解
为了便于更加清晰地讲解内容,本文也将文章的对应部分以视频的形式进行了录制:
(后期正在紧锣密鼓制作ing)
2 SD NAND FLASH背景介绍
目前市面上主流的存储芯片,分为了EEPROM、NOR FLASH、NAND FLASH三种,其中后两种是市面上主要的非易失闪存技术,他们分别具有不同的特点:
1.EEPROM
EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用设备中。
相较于EEPROM计数,下文提到的FLASH技术,具有更快的速度,工艺上可以分为NOR FLASH和NAND FLASH两种
2.NOR FLASH
NOR FLASH是一种非易失闪存技术。其特点是芯片内执行 (XIP),应用程序可以直接在存储芯片内运行,不必再把代码读到系统 RAM 中。其传输效率较高高,在 1~4MB 的小容量时具有很高的成本效益。
3.NAND FLASH
NAND FLASH内部采用非线性宏单元模式,这种结构能提供极高的单元密度,并且写入和擦除的速度很快。作为当前最热门的存储芯片,目前生活中常见的电子产品都会使用到这种存储芯片,例如数码相机、U盘等等。
由于NAND FLASH在大容量应用中的便利性,因此作为今天介绍的主角~
什么是SD NAND呢(以下省略FLASH)?下面的内容是从雷龙发展官网的介绍中得到:
SD NAND俗称贴片式TF卡,尽管与TF卡名称类似,但是有较大的区别:
相比常见的TF卡,SD NAND是专门为内置存储进行设计,焊接在PCB板上以供工业级产品的应用。因此对品质稳定性、一致性、以及尺寸都有较高的要求。
下图中左侧即为SD NAND、右侧是常见的TF卡。
3 样品申请
本文所使用的CS创世SD NAND是从深圳雷龙发展申请获得,可以在官网中最上面找到申请样品的入口:
深圳市雷龙发展有限公司创立于2008年,专注NAND Flash设计研发13年。创始人均为步步高/华为技术背景出身。是一家专注于存储元器件代理分销商。 如果有一些技术问题也可以和其公司人员进行沟通,相关的工作人员非常专业和热心。
下图是我收到的测试样品:
4 电路结构与接口协议
4.1 SD NAND
本文所使用的产品是CSNP4GCR01-AMW,是雷龙的第二代产品,产品如下图所示:
数据手册可以在立创商城进行下载,其封装与连接的电路原理参考图如下图所示:
芯片共包含8个引脚,包括4根数据线(6、7、1、2);2根电源线(4、8);1根时钟线(3);1根命令控制线(5)
手册中提供了SD NAND的两种使用模式,分别为SD MODE 以及 SPI MODE。他们所对应的引脚定义,如下图所示:
对于两种模式的切换,官方给出了初始化的方式。下文在代码的时序部分也会涉及到相关内容。
在对SD卡数据读写速度要求不高的情况下,选用SPI通信模式可以说是一种最佳方案。因为在该模式下,同只需要通过四根线就是可以完成所有的数据交换,可以为我们节省出宝贵的FPGA I/O资源。下图给出了SPI一对一通信时,主设备与从设备之间的连接关系。
(注:SPI协议详解传送门)
因此本文主要介绍SPI MODE下各个引脚的功能:
确定了通讯模式后,也就便于我们后文中,利用这种通讯模式按照SD卡的读写时序进行读写操作。
4.2 SD NAND测试板
单独的SD NAND不便于我们使用FPGA进行读写测试,好在官方提供了测试板,如下图所示:
有了它就可以轻松实现SD NAND与我们常见的FPGA开发板上的Micro SD插槽进行连接与测试了。
适用产品:LGA8,6x8mm 封装的SD NAND产品。
测试板尺寸:长度6.22厘米,宽度2.49厘米,接口长度2.53厘米。
使用方法:将芯片焊接至测试板上,可在原有的Micro SD卡座上直接调试和测试。
准备工具:热风枪,锡膏,镊子。温度要求:将热风枪温度调至300摄氏度℃即可焊接。
4.3 FPGA开发板
本文所使用的是黑金的AX301开发板,上面装有一个 Micro SD 卡座, FPGA 通过 SPI 数据总线访问 Micro SD 卡,SD 卡座和 FPGA 的硬件电路连接如下:
借由硬件电路的连接,FPGA可以直接与我们的SD NAND进行通信了。
至此,我们已经实现了SD NANDSPI通信方式方案的确定以及基于此的硬件电路连接,下一步就是根据SD卡的读写时序讲通信方式初始化为SPI模式,并按照SD卡协议进行读写操作。
5 SD卡协议与时序流程
5.1 SD卡协议
以下内容来自黑金的实验手册:
SD 卡的协议是一种简单的命令/响应的协议。全部命令由主机发起, SD 卡接收到命令后并返
回响应数据。根据命令的不同,返回的数据内容和长度也不同。 SD 卡命令是一个 6 字节组成的命
令包,其中第一个字节为命令号, 命令号高位 bit7 和 bit6 为固定的“01“,其它 6 个 bit 为具体
的命令号。第 2 个字节到第 5 个字节为命令参数。第 6 个字节为 7 个 bit 的 CRC 校验加 1 个 bit 的结束位。 如果在 SPI 模式的时候, CRC 校验位为可选。 如下图所示, Command 表示命令,通常使用十进制表示名称,例如 CMD17,这个时候 Command 就是十进制的 17。
对于详细的SD卡协议内容,可以参考传送门中的相关内容,给出了比较具体的解释。
SD 卡对每个命令会返回一个响应,每个命令有一定的响应格式。响应的格式跟给它的命令号
有关。在 SPI 模式中,有三种响应格式: R1, R2, R3。
在进行SD NAND的SPI模式读写操作时,主要使用到了以下几种SD卡命令,下面的表格进行简单介绍,这里可以找到完整版:
5.2 SD卡2.0版本初始化步骤
上电后延时至少 74clock,等待 SD 卡内部操作完成
片选 CS 低电平选中 SD 卡
发送 CMD0,需要返回 0x01,进入 Idle 状态
为了区别 SD 卡是 2.0 还是 1.0,或是 MMC 卡,这里根据协议向上兼容的,首先发送只有SD2.0 才有的命令 CMD8,如果 CMD8 返回无错误,则初步判断为 2.0 卡,进一步循环发送命令 CMD55+ACMD41,直到返回 0x00,确定 SD2.0 卡
如果 CMD8 返回错误则判断为 1.0 卡还是 MMC 卡,循环发送 CMD55+ACMD41,返回无错误,则为 SD1.0 卡,到此 SD1.0 卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送 CMD1 进行初始化,如果返回无错误,则确定为 MMC 卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始化结束。 (通过 CMD16 可以改变 SD 卡一次性读写的长度)
CS 拉高
5.3 SD卡的读步骤
发送 CMD17(单块)或 CMD18(多块)读命令,返回 0X00
接收数据开始令牌 fe(或 fc) +正式数据 512Bytes + CRC 校验 2Bytes(默认正式传输的数据长度是 512Bytes)
5.4 SD卡的写步骤
发送 CMD24(单块)或 CMD25(多块)写命令,返回 0X00
发送数据开始令牌 fe(或 fc) +正式数据 512Bytes + CRC 校验 2Bytes
6 模块代码
本代码所实现的功能,是基于黑金AX301B,实现对SD NAND FLASH的数据写入与读取,并显示在开发板的数码管上。当按下开发板上的按键时,会自动将数据加一操作,并进行同步显示。
前文介绍的是SD NAND的协议以及初始化、读写操作的流程,下面介绍代码的组成部分,整个工程主要由以下部分模块构成:
sd_card_test(top模块)
ax_debounce:ax_debounce_m0(按键消抖模块)
sd_card_top:sd_card_top_m0(SD卡top模块)
sd_card_cmd:sd_card_cmd_m0(SD卡指令)
sd_card_sec_read_write:sd_card_sec_read_write_m0(SD卡读写)
spi_master:spi_master_m0(SPI一个字节读写)
seg_decoder:seg_decoder_m0(数码管控制)
seg_decoder:seg_decoder_m1(数码管控制)
seg_scan:seg_scan_m0(数码管控制)
下面主要介绍上述四个加粗的模块以及其功能
6.1 sd_card_top
本模块是SD card的top模块,用来实现不同子模块之间的连接。
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//==========================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------
// 2017/6/21 meisq 1.0 Original
//*************************************************************************/
module sd_card_top
#(
parameter SPI_LOW_SPEED_DIV = 248, // SD card low speed mode frequency division parameter,spi clk speed = clk speed /((SPI_LOW_SPEED_DIV + 2) * 2 )
parameter SPI_HIGH_SPEED_DIV = 0 // SD card high speed mode frequency division parameter,spi clk speed = clk speed /((SPI_HIGH_SPEED_DIV + 2) * 2 )
)
(
input clk,
input rst,
output SD_nCS, //SD card chip select (SPI mode)
output SD_DCLK, //SD card clock
output SD_MOSI, //SD card controller data output
input SD_MISO, //SD card controller data input
output sd_init_done, //SD card initialization is complete
input sd_sec_read, //SD card sector read
input[31:0] sd_sec_read_addr, //SD card sector read address
output[7:0] sd_sec_read_data, //SD card sector read data
output sd_sec_read_data_valid, //SD card sector read data valid
output sd_sec_read_end, //SD card sector read end
input sd_sec_write, //SD card sector write
input[31:0] sd_sec_write_addr, //SD card sector write address
input[7:0] sd_sec_write_data, //SD card sector write data
output sd_sec_write_data_req, //SD card sector write data next clock is valid
output sd_sec_write_end //SD card sector write end
);
wire[15:0] spi_clk_div; //SPI module clock division parameter
wire cmd_req; //SD card command request
wire cmd_req_ack; //SD card command request response
wire cmd_req_error; //SD card command request error
wire[47:0] cmd; //SD card command
wire[7:0] cmd_r1; //SD card expect response
wire[15:0] cmd_data_len; //SD card command read data length
wire block_read_req; //SD card sector data read request
wire block_read_valid; //SD card sector data read data valid
wire[7:0] block_read_data; //SD card sector data read data
wire block_read_req_ack; //SD card sector data read response
wire block_write_req; //SD card sector data write request
wire[7:0] block_write_data; //SD card sector data write data next clock is valid
wire block_write_data_rd; //SD card sector data write data
wire block_write_req_ack; //SD card sector data write response
wire nCS_ctrl; //SPI module chip select control
wire spi_wr_req; //SPI module data sending request
wire spi_wr_ack; //SPI module data request response
wire[7:0] spi_data_in; //SPI module send data
wire[7:0] spi_data_out; //SPI module data returned
wire[15:0] clk_div;
sd_card_sec_read_write
#(
.SPI_LOW_SPEED_DIV(SPI_LOW_SPEED_DIV),
.SPI_HIGH_SPEED_DIV(SPI_HIGH_SPEED_DIV)
)
sd_card_sec_read_write_m0(
.clk (clk ),
.rst (rst ),
.sd_init_done (sd_init_done ),
.sd_sec_read (sd_sec_read ),
.sd_sec_read_addr (sd_sec_read_addr ),
.sd_sec_read_data (sd_sec_read_data ),
.sd_sec_read_data_valid (sd_sec_read_data_valid ),
.sd_sec_read_end (sd_sec_read_end ),
.sd_sec_write (sd_sec_write ),
.sd_sec_write_addr (sd_sec_write_addr ),
.sd_sec_write_data (sd_sec_write_data ),
.sd_sec_write_data_req (sd_sec_write_data_req ),
.sd_sec_write_end (sd_sec_write_end ),
.spi_clk_div (spi_clk_div ),
.cmd_req (cmd_req ),
.cmd_req_ack (cmd_req_ack ),
.cmd_req_error (cmd_req_error ),
.cmd (cmd ),
.cmd_r1 (cmd_r1 ),
.cmd_data_len (cmd_data_len ),
.block_read_req (block_read_req ),
.block_read_valid (block_read_valid ),
.block_read_data (block_read_data ),
.block_read_req_ack (block_read_req_ack ),
.block_write_req (block_write_req ),
.block_write_data (block_write_data ),
.block_write_data_rd (block_write_data_rd ),
.block_write_req_ack (block_write_req_ack )
);
sd_card_cmd sd_card_cmd_m0(
.sys_clk (clk ),
.rst (rst ),
.spi_clk_div (spi_clk_div ),
.cmd_req (cmd_req ),
.cmd_req_ack (cmd_req_ack ),
.cmd_req_error (cmd_req_error ),
.cmd (cmd ),
.cmd_r1 (cmd_r1 ),
.cmd_data_len (cmd_data_len ),
.block_read_req (block_read_req ),
.block_read_req_ack (block_read_req_ack ),
.block_read_data (block_read_data ),
.block_read_valid (block_read_valid ),
.block_write_req (block_write_req ),
.block_write_data (block_write_data ),
.block_write_data_rd (block_write_data_rd ),
.block_write_req_ack (block_write_req_ack ),
.nCS_ctrl (nCS_ctrl ),
.clk_div (clk_div ),
.spi_wr_req (spi_wr_req ),
.spi_wr_ack (spi_wr_ack ),
.spi_data_in (spi_data_in ),
.spi_data_out (spi_data_out )
);
spi_master spi_master_m0(
.sys_clk (clk ),
.rst (rst ),
.nCS (SD_nCS ),
.DCLK (SD_DCLK ),
.MOSI (SD_MOSI ),
.MISO (SD_MISO ),
.clk_div (clk_div ),
.CPOL (1'b1 ),
.CPHA (1'b1 ),
.nCS_ctrl (nCS_ctrl ),
.wr_req (spi_wr_req ),
.wr_ack (spi_wr_ack ),
.data_in (spi_data_in ),
.data_out (spi_data_out )
);
endmodule
6.2 sd_card_cmd
sd_card_cmd 模块主要实验 sd 卡基本命令操作,还有上电初始化的 88 个周期的时钟,数据
块的读写,状态机如下:
EEWORLDIMGTK17
代码如下:
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//==========================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------
// 2017/6/21 meisq 1.0 Original
//*************************************************************************/
module sd_card_cmd(
input sys_clk,
input rst,
input[15:0] spi_clk_div, //SPI module clock division parameter
input cmd_req, //SD card command request
output cmd_req_ack, //SD card command request response
output reg cmd_req_error, //SD card command request error
input[47:0] cmd, //SD card command
input[7:0] cmd_r1, //SD card expect response
input[15:0] cmd_data_len, //SD card command read data length
input block_read_req, //SD card sector data read request
output reg block_read_valid, //SD card sector data read data valid
output reg[7:0] block_read_data, //SD card sector data read data
output block_read_req_ack, //SD card sector data read response
input block_write_req, //SD card sector data write request
input[7:0] block_write_data, //SD card sector data write data next clock is valid
output block_write_data_rd, //SD card sector data write data
output block_write_req_ack, //SD card sector data write response
output nCS_ctrl, //SPI module chip select control
output reg[15:0] clk_div,
output reg spi_wr_req, //SPI module data sending request
input spi_wr_ack, //SPI module data request response
output[7:0] spi_data_in, //SPI module send data
input[7:0] spi_data_out //SPI module data returned
);
parameter S_IDLE = 0;
parameter S_WAIT = 1;
parameter S_INIT = 2;
parameter S_CMD_PRE = 3;
parameter S_CMD = 4;
parameter S_CMD_DATA = 5;
parameter S_READ_WAIT = 6;
parameter S_READ = 7;
parameter S_READ_ACK = 8;
parameter S_WRITE_TOKEN = 9;
parameter S_WRITE_DATA_0 = 10;
parameter S_WRITE_DATA_1 = 11;
parameter S_WRITE_CRC = 12;
parameter S_WRITE_ACK = 13;
parameter S_ERR = 14;
parameter S_END = 15;
reg[3:0] state;
reg CS_reg;
reg[15:0] byte_cnt;
reg[7:0] send_data;
wire[7:0] data_recv;
reg[9:0] wr_data_cnt;
assign cmd_req_ack = (state == S_END);
assign block_read_req_ack = (state == S_READ_ACK);
assign block_write_req_ack= (state == S_WRITE_ACK);
assign block_write_data_rd = (state == S_WRITE_DATA_0);
assign spi_data_in = send_data;
assign data_recv = spi_data_out;
assign nCS_ctrl = CS_reg;
always@(posedge sys_clk or posedge rst)
begin
if(rst == 1'b1)
begin
CS_reg <= 1'b1;
spi_wr_req <= 1'b0;
byte_cnt <= 16'd0;
clk_div <= 16'd0;
send_data <= 8'hff;
state <= S_IDLE;
cmd_req_error <= 1'b0;
wr_data_cnt <= 10'd0;
end
else
case(state)
S_IDLE:
begin
state <= S_INIT;
clk_div <= spi_clk_div;
CS_reg <= 1'b1;
end
S_INIT:
begin
//send 11 bytes on power(at least 74 SPI clocks)
if(spi_wr_ack == 1'b1)
begin
if(byte_cnt >= 16'd10)
begin
byte_cnt <= 16'd0;
spi_wr_req <= 1'b0;
state <= S_WAIT;
end
begin
byte_cnt <= byte_cnt + 16'd1;
end
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hff;
end
end
S_WAIT:
begin
cmd_req_error <= 1'b0;
wr_data_cnt <= 10'd0;
//wait for instruction
if(cmd_req == 1'b1)
state <= S_CMD_PRE;
else if(block_read_req == 1'b1)
state <= S_READ_WAIT;
else if(block_write_req == 1'b1)
state <= S_WRITE_TOKEN;
clk_div <= spi_clk_div;
end
S_CMD_PRE:
begin
//before sending a command, send an byte 'ff',provide some clocks
if(spi_wr_ack == 1'b1)
begin
state <= S_CMD;
spi_wr_req <= 1'b0;
byte_cnt <= 16'd0;
end
else
begin
spi_wr_req <= 1'b1;
CS_reg <= 1'b1;
send_data <= 8'hff;
end
end
S_CMD:
begin
if(spi_wr_ack == 1'b1)
begin
if((byte_cnt == 16'hffff) || (data_recv != cmd_r1 && data_recv[7] == 1'b0))
begin
state <= S_ERR;
spi_wr_req <= 1'b0;
end
else if(data_recv == cmd_r1)
begin
spi_wr_req <= 1'b0;
if(cmd_data_len != 16'd0)
begin
state <= S_CMD_DATA;
byte_cnt <= 16'd0;
end
else
state <= S_END;
end
else
byte_cnt <= byte_cnt + 16'd1;
end
else
begin
spi_wr_req <= 1'b1;
CS_reg <= 1'b0;
if(byte_cnt == 16'd0)
send_data <= (cmd[47:40] | 8'h40);
else if(byte_cnt == 16'd1)
send_data <= cmd[39:32];
else if(byte_cnt == 16'd2)
send_data <= cmd[31:24];
else if(byte_cnt == 16'd3)
send_data <= cmd[23:16];
else if(byte_cnt == 16'd4)
send_data <= cmd[15:8];
else if(byte_cnt == 16'd5)
send_data <= cmd[7:0];
else
send_data <= 8'hff;
end
end
S_CMD_DATA:
begin
if(spi_wr_ack == 1'b1)
begin
if(byte_cnt == cmd_data_len - 16'd1)
begin
state <= S_END;
spi_wr_req <= 1'b0;
byte_cnt <= 16'd0;
end
else
begin
byte_cnt <= byte_cnt + 16'd1;
end
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hff;
end
end
S_READ_WAIT:
begin
if(spi_wr_ack == 1'b1 && data_recv == 8'hfe)
begin
spi_wr_req <= 1'b0;
state <= S_READ;
byte_cnt <= 16'd0;
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hff;
end
end
S_READ:
begin
if(spi_wr_ack == 1'b1)
begin
if(byte_cnt == 16'd513)
begin
state <= S_READ_ACK;
spi_wr_req <= 1'b0;
byte_cnt <= 16'd0;
end
else
begin
byte_cnt <= byte_cnt + 16'd1;
end
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hff;
end
end
S_WRITE_TOKEN:
if(spi_wr_ack == 1'b1)
begin
state <= S_WRITE_DATA_0;
spi_wr_req <= 1'b0;
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hfe;
end
S_WRITE_DATA_0:
begin
state <= S_WRITE_DATA_1;
wr_data_cnt <= wr_data_cnt + 10'd1;
end
S_WRITE_DATA_1:
begin
if(spi_wr_ack == 1'b1 && wr_data_cnt == 10'd512)
begin
state <= S_WRITE_CRC;
spi_wr_req <= 1'b0;
end
else if(spi_wr_ack == 1'b1)
begin
state <= S_WRITE_DATA_0;
spi_wr_req <= 1'b0;
end
else
begin
spi_wr_req <= 1'b1;
send_data <= block_write_data;
end
end
S_WRITE_CRC:
begin
if(spi_wr_ack == 1'b1)
begin
if(byte_cnt == 16'd2)
begin
state <= S_WRITE_ACK;
spi_wr_req <= 1'b0;
byte_cnt <= 16'd0;
end
else
begin
byte_cnt <= byte_cnt + 16'd1;
end
end
else
begin
spi_wr_req <= 1'b1;
send_data <= 8'hff;
end
end
S_ERR:
begin
state <= S_END;
cmd_req_error <= 1'b1;
end
S_READ_ACK,S_WRITE_ACK,S_END:
begin
state <= S_WAIT;
end
default:
state <= S_IDLE;
endcase
end
always@(posedge sys_clk or posedge rst)
begin
if(rst == 1'b1)
block_read_valid <= 1'b0;
else if(state == S_READ && byte_cnt < 16'd512)
block_read_valid <= spi_wr_ack;
else
block_read_valid <= 1'b0;
end
always@(posedge sys_clk or posedge rst)
begin
if(rst == 1'b1)
block_read_data <= 8'd0;
else if(state == S_READ && spi_wr_ack == 1'b1)
block_read_data <= data_recv;
end
endmodule
6.3 sd_card_sec_read_write
sd_card_sec_read_write 模块继续完成 SD 卡初始化,然后等待扇区读写指令,并完成扇区的
读写操作。 下图为模块的状态机转换图,首先发送 CMD0 命令,然后发送 CMD8 命令,再发送
CMD55,接着发送 ACMD41,如果应答正常, sd 卡初始化完成,等待扇区的读写。
EEWORLDIMGTK18
代码如下:
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//===============================================================================
// Revision History:
// Date By Revision Change Description
//-------------------------------------------------------------------------------
// 2017/6/21 meisq 1.0 Original
//*******************************************************************************/
module sd_card_sec_read_write
#(
parameter SPI_LOW_SPEED_DIV = 248, // spi clk speed = clk speed /((SPI_LOW_SPEED_DIV + 2) * 2 )
parameter SPI_HIGH_SPEED_DIV = 0 // spi clk speed = clk speed /((SPI_HIGH_SPEED_DIV + 2) * 2 )
)
(
input clk,
input rst,
output reg sd_init_done,
input sd_sec_read,
input[31:0] sd_sec_read_addr,
output[7:0] sd_sec_read_data,
output sd_sec_read_data_valid,
output sd_sec_read_end,
input sd_sec_write,
input[31:0] sd_sec_write_addr,
input[7:0] sd_sec_write_data,
output sd_sec_write_data_req,
output sd_sec_write_end,
output reg[15:0] spi_clk_div,
output reg cmd_req,
input cmd_req_ack,
input cmd_req_error,
output reg[47:0] cmd,
output reg[7:0] cmd_r1,
output reg[15:0] cmd_data_len,
output reg block_read_req,
input block_read_valid,
input[7:0] block_read_data,
input block_read_req_ack,
output reg block_write_req,
output[7:0] block_write_data,
input block_write_data_rd,
input block_write_req_ack
);
reg[7:0] read_data;
reg[31:0] timer;
localparam S_IDLE = 0;
localparam S_CMD0 = 1;
localparam S_CMD8 = 2;
localparam S_CMD55 = 3;
localparam S_CMD41 = 4;
localparam S_CMD17 = 5;
localparam S_READ = 6;
localparam S_CMD24 = 7;
localparam S_WRITE = 8;
localparam S_ERR = 14;
localparam S_WRITE_END = 15;
localparam S_READ_END = 16;
localparam S_WAIT_READ_WRITE = 17;
localparam S_CMD16 = 18;
reg[4:0] state;
reg[31:0] sec_addr;
assign sd_sec_read_data_valid = (state == S_READ) && block_read_valid;
assign sd_sec_read_data = block_read_data;
assign sd_sec_read_end = (state == S_READ_END);
assign sd_sec_write_data_req = (state == S_WRITE) && block_write_data_rd;
assign block_write_data = sd_sec_write_data;
assign sd_sec_write_end = (state == S_WRITE_END);
always@(posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
state <= S_IDLE;
cmd_req <= 1'b0;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'd0;
cmd <= 48'd0;
spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];
block_write_req <= 1'b0;
block_read_req <= 1'b0;
sec_addr <= 32'd0;
sd_init_done <= 1'b0;
end
else
case(state)
S_IDLE:
begin
state <= S_CMD0;
sd_init_done <= 1'b0;
spi_clk_div <= SPI_LOW_SPEED_DIV[15:0];
end
S_CMD0:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_CMD8;
cmd_req <= 1'b0;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h01;
cmd <= {8'd0,8'h00,8'h00,8'h00,8'h00,8'h95};
end
end
S_CMD8:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_CMD55;
cmd_req <= 1'b0;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd4;
cmd_r1 <= 8'h01;
cmd <= {8'd8,8'h00,8'h00,8'h01,8'haa,8'h87};
end
end
S_CMD55:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_CMD41;
cmd_req <= 1'b0;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h01;
cmd <= {8'd55,8'h00,8'h00,8'h00,8'h00,8'hff};
end
end
S_CMD41:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_CMD16;
cmd_req <= 1'b0;
sd_init_done <= 1'b1;
spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];
end
else if(cmd_req_ack)
begin
state <= S_CMD55;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h00;
cmd <= {8'd41,8'h40,8'h00,8'h00,8'h00,8'hff};
end
end
S_CMD16:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_WAIT_READ_WRITE;
cmd_req <= 1'b0;
sd_init_done <= 1'b1;
spi_clk_div <= SPI_HIGH_SPEED_DIV[15:0];
end
else if(cmd_req_ack)
begin
state <= S_CMD55;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h00;
cmd <= {8'd16,32'd512,8'hff};
end
end
S_WAIT_READ_WRITE:
begin
if(sd_sec_write == 1'b1)
begin
state <= S_CMD24;
sec_addr <= sd_sec_write_addr;
end
else if(sd_sec_read == 1'b1)
begin
state <= S_CMD17;
sec_addr <= sd_sec_read_addr;
end
spi_clk_div <= 16'd0;
end
S_CMD24:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_WRITE;
cmd_req <= 1'b0;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h00;
cmd <= {8'd24,sec_addr,8'hff};
end
end
S_WRITE:
begin
if(block_write_req_ack == 1'b1)
begin
block_write_req <= 1'b0;
state <= S_WRITE_END;
end
else
block_write_req <= 1'b1;
end
S_CMD17:
begin
if(cmd_req_ack & ~cmd_req_error)
begin
state <= S_READ;
cmd_req <= 1'b0;
end
else
begin
cmd_req <= 1'b1;
cmd_data_len <= 16'd0;
cmd_r1 <= 8'h00;
cmd <= {8'd17,sec_addr,8'hff};
end
end
S_READ:
begin
if(block_read_req_ack)
begin
state <= S_READ_END;
block_read_req <= 1'b0;
end
else
begin
block_read_req <= 1'b1;
end
end
S_WRITE_END:
begin
state <= S_WAIT_READ_WRITE;
end
S_READ_END:
begin
state <= S_WAIT_READ_WRITE;
end
default:
state <= S_IDLE;
endcase
end
endmodule
6.4 spi_master
这一模块用来完成SPI一个字节的读写。
spi master 状态机设计, 主要完成一个字节 spi 数据的读写,由于是全双工的,写一个字节的
同时也读一个字节。 首先空闲状态“IDLE”接收到写请求后进入“DCLK_IDLE”状态,这个状态为
spi 时钟沿变化保持一定的时间,用来控制 spi 时钟的周期,然后进入 spi 时钟沿的变化状态,一
个字节上升沿和下降沿一共 16 个数据沿。 在最后一个数据沿进入“LAST_HALF_CYCLE”状态,为
让最后一个沿也保持一定的时间,再进入应答状态,完成一次写请求。spi_master 模块中模拟了一个 spi 时钟,在状态机进入到‘DCLK_EDGE’时进行翻转。状态机图示如下:
EEWORLDIMGTK19
代码如下:
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//==========================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------
// 2017/6/19 meisq 1.0 Original
//*************************************************************************/
module spi_master
(
input sys_clk,
input rst,
output nCS, //chip select (SPI mode)
output DCLK, //spi clock
output MOSI, //spi data output
input MISO, //spi input
input CPOL,
input CPHA,
input nCS_ctrl,
input[15:0] clk_div,
input wr_req,
output wr_ack,
input[7:0] data_in,
output[7:0] data_out
);
localparam IDLE = 0;
localparam DCLK_EDGE = 1;
localparam DCLK_IDLE = 2;
localparam ACK = 3;
localparam LAST_HALF_CYCLE = 4;
localparam ACK_WAIT = 5;
reg DCLK_reg;
reg[7:0] MOSI_shift;
reg[7:0] MISO_shift;
reg[2:0] state;
reg[2:0] next_state;
reg [15:0] clk_cnt;
reg[4:0] clk_edge_cnt;
assign MOSI = MOSI_shift[7];
assign DCLK = DCLK_reg;
assign data_out = MISO_shift;
assign wr_ack = (state == ACK);
assign nCS = nCS_ctrl;
always@(posedge sys_clk or posedge rst)
begin
if(rst)
state <= IDLE;
else
state <= next_state;
end
always@(*)
begin
case(state)
IDLE:
if(wr_req == 1'b1)
next_state <= DCLK_IDLE;
else
next_state <= IDLE;
DCLK_IDLE:
//half a SPI clock cycle produces a clock edge
if(clk_cnt == clk_div)
next_state <= DCLK_EDGE;
else
next_state <= DCLK_IDLE;
DCLK_EDGE:
//a SPI byte with a total of 16 clock edges
if(clk_edge_cnt == 5'd15)
next_state <= LAST_HALF_CYCLE;
else
next_state <= DCLK_IDLE;
//this is the last data edge
LAST_HALF_CYCLE:
if(clk_cnt == clk_div)
next_state <= ACK;
else
next_state <= LAST_HALF_CYCLE;
//send one byte complete
ACK:
next_state <= ACK_WAIT;
//wait for one clock cycle, to ensure that the cancel request signal
ACK_WAIT:
next_state <= IDLE;
default:
next_state <= IDLE;
endcase
end
always@(posedge sys_clk or posedge rst)
begin
if(rst)
DCLK_reg <= 1'b0;
else if(state == IDLE)
DCLK_reg <= CPOL;
else if(state == DCLK_EDGE)
DCLK_reg <= ~DCLK_reg;//SPI clock edge
end
//SPI clock wait counter
always@(posedge sys_clk or posedge rst)
begin
if(rst)
clk_cnt <= 16'd0;
else if(state == DCLK_IDLE || state == LAST_HALF_CYCLE)
clk_cnt <= clk_cnt + 16'd1;
else
clk_cnt <= 16'd0;
end
//SPI clock edge counter
always@(posedge sys_clk or posedge rst)
begin
if(rst)
clk_edge_cnt <= 5'd0;
else if(state == DCLK_EDGE)
clk_edge_cnt <= clk_edge_cnt + 5'd1;
else if(state == IDLE)
clk_edge_cnt <= 5'd0;
end
//SPI data output
always@(posedge sys_clk or posedge rst)
begin
if(rst)
MOSI_shift <= 8'd0;
else if(state == IDLE && wr_req)
MOSI_shift <= data_in;
else if(state == DCLK_EDGE)
if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b1)
MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};
else if(CPHA == 1'b1 && (clk_edge_cnt != 5'd0 && clk_edge_cnt[0] == 1'b0))
MOSI_shift <= {MOSI_shift[6:0],MOSI_shift[7]};
end
//SPI data input
always@(posedge sys_clk or posedge rst)
begin
if(rst)
MISO_shift <= 8'd0;
else if(state == IDLE && wr_req)
MISO_shift <= 8'h00;
else if(state == DCLK_EDGE)
if(CPHA == 1'b0 && clk_edge_cnt[0] == 1'b0)
MISO_shift <= {MISO_shift[6:0],MISO};
else if(CPHA == 1'b1 && (clk_edge_cnt[0] == 1'b1))
MISO_shift <= {MISO_shift[6:0],MISO};
end
endmodule
6.5 其余代码
6.5.1 sd_card_test
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//================================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------------
// 2017/6/19 meisq 1.0 Original
//*******************************************************************************/
module sd_card_test(
input clk,
input rst_n,
input key1,
output SD_nCS,
output SD_DCLK,
output SD_MOSI,
input SD_MISO,
output [5:0] seg_sel,
output [7:0] seg_data
);
parameter S_IDLE = 0;
parameter S_READ = 1;
parameter S_WRITE = 2;
parameter S_END = 3;
reg[3:0] state;
wire sd_init_done;
reg sd_sec_read;
wire[31:0] sd_sec_read_addr;
wire[7:0] sd_sec_read_data;
wire sd_sec_read_data_valid;
wire sd_sec_read_end;
reg sd_sec_write;
wire[31:0] sd_sec_write_addr;
reg [7:0] sd_sec_write_data;
wire sd_sec_write_data_req;
wire sd_sec_write_end;
reg[9:0] wr_cnt;
reg[9:0] rd_cnt;
wire button_negedge;
reg[7:0] read_data;
ax_debounce ax_debounce_m0
(
.clk (clk),
.rst (~rst_n),
.button_in (key1),
.button_posedge (),
.button_negedge (button_negedge),
.button_out ()
);
wire[6:0] seg_data_0;
seg_decoder seg_decoder_m0(
.bin_data (read_data[3:0]),
.seg_data (seg_data_0)
);
wire[6:0] seg_data_1;
seg_decoder seg_decoder_m1(
.bin_data (read_data[7:4]),
.seg_data (seg_data_1)
);
seg_scan seg_scan_m0(
.clk (clk),
.rst_n (rst_n),
.seg_sel (seg_sel),
.seg_data (seg_data),
.seg_data_0 ({1'b1,7'b1111_111}),
.seg_data_1 ({1'b1,7'b1111_111}),
.seg_data_2 ({1'b1,7'b1111_111}),
.seg_data_3 ({1'b1,7'b1111_111}),
.seg_data_4 ({1'b1,seg_data_1}),
.seg_data_5 ({sd_init_done,seg_data_0})
);
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
wr_cnt <= 10'd0;
else if(state == S_WRITE)
begin
if(sd_sec_write_data_req == 1'b1)
wr_cnt <= wr_cnt + 10'd1;
end
else
wr_cnt <= 10'd0;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
rd_cnt <= 10'd0;
else if(state == S_READ)
begin
if(sd_sec_read_data_valid == 1'b1)
rd_cnt <= rd_cnt + 10'd1;
end
else
rd_cnt <= 10'd0;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
read_data <= 8'd0;
else if(state == S_READ)
begin
if(sd_sec_read_data_valid == 1'b1 && rd_cnt == 10'd0)
read_data <= sd_sec_read_data;
end
else if(state == S_END && button_negedge == 1'b1)
read_data <= read_data + 8'd1;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
sd_sec_write_data <= 8'd0;
else if(sd_sec_write_data_req)
sd_sec_write_data <= read_data + wr_cnt[7:0];
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
state <= S_IDLE;
sd_sec_read <= 1'b0;
sd_sec_write <= 1'b0;
end
else if(sd_init_done == 1'b0)
begin
state <= S_IDLE;
end
else
case(state)
S_IDLE:
begin
state <= S_READ;
end
S_WRITE:
begin
if(sd_sec_write_end == 1'b1)
begin
sd_sec_write <= 1'b0;
state <= S_READ;
end
else
sd_sec_write <= 1'b1;
end
S_READ:
begin
if(sd_sec_read_end == 1'b1)
begin
state <= S_END;
sd_sec_read <= 1'b0;
end
else
begin
sd_sec_read <= 1'b1;
end
end
S_END:
begin
if(button_negedge == 1'b1)
state <= S_WRITE;
end
default:
state <= S_IDLE;
endcase
end
sd_card_top sd_card_top_m0(
.clk (clk ),
.rst (~rst_n ),
.SD_nCS (SD_nCS ),
.SD_DCLK (SD_DCLK ),
.SD_MOSI (SD_MOSI ),
.SD_MISO (SD_MISO ),
.sd_init_done (sd_init_done ),
.sd_sec_read (sd_sec_read ),
.sd_sec_read_addr (sd_sec_read_addr ),
.sd_sec_read_data (sd_sec_read_data ),
.sd_sec_read_data_valid (sd_sec_read_data_valid ),
.sd_sec_read_end (sd_sec_read_end ),
.sd_sec_write (sd_sec_write ),
.sd_sec_write_addr (sd_sec_write_addr ),
.sd_sec_write_data (sd_sec_write_data ),
.sd_sec_write_data_req (sd_sec_write_data_req ),
.sd_sec_write_end (sd_sec_write_end )
);
endmodule
6.5.2 ax_debounce
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//================================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------------
// 2017/5/3 meisq 1.0 Original
//*******************************************************************************/
`timescale 1 ns / 100 ps
module ax_debounce
(
input clk,
input rst,
input button_in,
output reg button_posedge,
output reg button_negedge,
output reg button_out
);
---------------- internal constants --------------
parameter N = 32 ; // debounce timer bitwidth
parameter FREQ = 50; //model clock :Mhz
parameter MAX_TIME = 20; //ms
localparam TIMER_MAX_VAL = MAX_TIME * 1000 * FREQ;
---------------- internal variables ---------------
reg [N-1 : 0] q_reg; // timing regs
reg [N-1 : 0] q_next;
reg DFF1, DFF2; // input flip-flops
wire q_add; // control flags
wire q_reset;
reg button_out_d0;
------------------------------------------------------
contenious assignment for counter control
assign q_reset = (DFF1 ^ DFF2); // xor input flip flops to look for level chage to reset counter
assign q_add = ~(q_reg == TIMER_MAX_VAL); // add to counter when q_reg msb is equal to 0
combo counter to manage q_next
always @ ( q_reset, q_add, q_reg)
begin
case( {q_reset , q_add})
2'b00 :
q_next <= q_reg;
2'b01 :
q_next <= q_reg + 1;
default :
q_next <= { N {1'b0} };
endcase
end
Flip flop inputs and q_reg update
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
DFF1 <= 1'b0;
DFF2 <= 1'b0;
q_reg <= { N {1'b0} };
end
else
begin
DFF1 <= button_in;
DFF2 <= DFF1;
q_reg <= q_next;
end
end
counter control
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
button_out <= 1'b1;
else if(q_reg == TIMER_MAX_VAL)
button_out <= DFF2;
else
button_out <= button_out;
end
always @ ( posedge clk or posedge rst)
begin
if(rst == 1'b1)
begin
button_out_d0 <= 1'b1;
button_posedge <= 1'b0;
button_negedge <= 1'b0;
end
else
begin
button_out_d0 <= button_out;
button_posedge <= ~button_out_d0 & button_out;
button_negedge <= button_out_d0 & ~button_out;
end
end
endmodule
6.5.3 seg_decoder
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//==========================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------
// 2017/6/19 meisq 1.0 Original
//*************************************************************************/
module seg_decoder
(
input[3:0] bin_data, // bin data input
output reg[6:0] seg_data // seven segments LED output
);
always@(*)
begin
case(bin_data)
4'd0:seg_data <= 7'b100_0000;
4'd1:seg_data <= 7'b111_1001;
4'd2:seg_data <= 7'b010_0100;
4'd3:seg_data <= 7'b011_0000;
4'd4:seg_data <= 7'b001_1001;
4'd5:seg_data <= 7'b001_0010;
4'd6:seg_data <= 7'b000_0010;
4'd7:seg_data <= 7'b111_1000;
4'd8:seg_data <= 7'b000_0000;
4'd9:seg_data <= 7'b001_0000;
4'ha:seg_data <= 7'b000_1000;
4'hb:seg_data <= 7'b000_0011;
4'hc:seg_data <= 7'b100_0110;
4'hd:seg_data <= 7'b010_0001;
4'he:seg_data <= 7'b000_0110;
4'hf:seg_data <= 7'b000_1110;
default:seg_data <= 7'b111_1111;
endcase
end
endmodule
6.5.4 seg_scan
//
// //
// //
// Author: meisq //
// msq@qq.com //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//==========================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------
// 2017/6/19 meisq 1.0 Original
//*************************************************************************/
module seg_scan(
input clk,
input rst_n,
output reg[5:0] seg_sel, //digital led chip select
output reg[7:0] seg_data, //eight segment digital tube output,MSB is the decimal point
input[7:0] seg_data_0,
input[7:0] seg_data_1,
input[7:0] seg_data_2,
input[7:0] seg_data_3,
input[7:0] seg_data_4,
input[7:0] seg_data_5
);
parameter SCAN_FREQ = 200; //scan frequency
parameter CLK_FREQ = 50000000; //clock frequency
parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;
reg[31:0] scan_timer; //scan time counter
reg[3:0] scan_sel; //Scan select counter
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
scan_timer <= 32'd0;
scan_sel <= 4'd0;
end
else if(scan_timer >= SCAN_COUNT)
begin
scan_timer <= 32'd0;
if(scan_sel == 4'd5)
scan_sel <= 4'd0;
else
scan_sel <= scan_sel + 4'd1;
end
else
begin
scan_timer <= scan_timer + 32'd1;
end
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
seg_sel <= 6'b111111;
seg_data <= 8'hff;
end
else
begin
case(scan_sel)
//first digital led
4'd0:
begin
seg_sel <= 6'b11_1110;
seg_data <= seg_data_0;
end
//second digital led
4'd1:
begin
seg_sel <= 6'b11_1101;
seg_data <= seg_data_1;
end
//...
4'd2:
begin
seg_sel <= 6'b11_1011;
seg_data <= seg_data_2;
end
4'd3:
begin
seg_sel <= 6'b11_0111;
seg_data <= seg_data_3;
end
4'd4:
begin
seg_sel <= 6'b10_1111;
seg_data <= seg_data_4;
end
4'd5:
begin
seg_sel <= 6'b01_1111;
seg_data <= seg_data_5;
end
default:
begin
seg_sel <= 6'b11_1111;
seg_data <= 8'hff;
end
endcase
end
end
endmodule
7 实验结果
下载实验程序后,可以看到数码管显示一个数字,这个数字是存储在 sd 卡中第一扇区的第一
个数据,数据是随机的,这个时候按键 KEY1 按下,数字加一,并写入了 sd 卡,再次下载程序,
可以看到直接显示更新后的数据。
- 2024-06-14
-
发表了主题帖:
语音控制模块_雷龙发展
1,串口
uart串口控制模式,即异步传送收发器,通过其完成语音控制。
图中,GND表示单片机系统电源的参考地,TXD是串行发送引脚,RXD是串行接收引脚。发送uart将来自cpu等控制设备的并行数据转换为串行形式,并将其串行发送到接收uart,接收uart然后将串行数据转换为接收数据接收设备的并行数据。
2数据协议
起始位:通信线路上空闲时为“1”,当检测到“0”即下降沿时,认为数据传输开始
有效数据位:传输开始后传递的需要接收和发送的数据值,可以表示指令或数据
奇偶校验位:奇偶校验,通过来校验传输数据中“1”的个数为奇数个(奇校验)或偶数个(偶校验)来指示传输数据是否正确
停止位:数据传输结束,传输线恢复常“1”状态
3 雷龙语音模块原理图
通过麦克风输入口接收语音,再将语音信号转换为数字信号,数字信号通过uart通信传输给fpga,使fpga对信号进行应答并控制电路的高低电平产生相应的动作。同时通过spk喇叭接口播报应答语。
二 工作原理
工作原理包括信号采集、预处理、特征提取和匹配等步骤。下面我们逐一详细介绍这些步骤:
1.信号采集
离线语音识别系统的第一步是信号采集。声音信号通过麦克风(传感器)以电信号的形式被捕捉到,这是后续处理的基础。
2.预处理
预处理阶段包括去除噪声、回声消除、降噪等处理,以提高语音信号的质量。同时,进行采样和量化,将连续的模拟信号转换为离散的数字信号。主要通过DSP来处理,雷龙语音模块内置DSP芯片,可以做各种卷积和数字滤波处理。大幅提高语音质量。
3.特征提取
在特征提取阶段,将语音信号转化为具有代表性的特征向量。这些特征向量能够捕捉到语音信号中的关键信息,如音调、音色和音节等。特征信息也是需要通过算法来提取,也需要大量的计算能力。
4.匹配
在匹配阶段,将提取的特征向量与预定义的词典中的词进行匹配。最常用的匹配算法是动态时间规整(DTW),它能有效地解决语音信号的时间扭曲问题。
三 工程框图
工作过程与说明:
uart接收模块可以定义信号,rx.data与信号bps_start,有信号通过时,使得rx.data处于低电平,bps_start信号置为1,启动波特率设置模块。
uart发送模块可以定义信号,clk_bps与信号uart_rx,先发送一个波特率周期的低电平到clk_bps,再使uart_rx从低到高传输,从rx_data接收数据位。
四 实物图
我将语音模块与自己的开发板vcc gnd tx rx相连,实现通信,语音播报效果很好!
五 示例词条
————————————————
雷龙发展公司致力于为客户提供一站式的离线语音解决方案。我们的服务涵盖了多个领域,包括家电、医疗器械、安防报警、汽车电子、多媒体、通信、电话录音、工业自动化控制、玩具及互动消费类产品等。通过我们的专业知识和经验,我们能够满足各类产品的语音交互需求,让用户享受更加智能、便捷的使用体验。
-
发表了主题帖:
NAND flash测试-雷龙发展
文章目录
一、简介
二、速度测试
最近比较忙,也一直没空发什么文章,这算是新年第一篇吧,正好最近收到了一个雷龙的flash芯片,先拿来玩一下吧。
有兴趣的小伙伴可以去雷龙官网找小姐姐领取一个免费试用。
一、简介
大概样子就是上面这样,使用LGA-8封装,实际上驱动也是通用SD卡的驱动,相比与SD卡可以直接贴片到嵌入式设备中,并且体积更小,数据存储和SD卡存储一样。
我使用的型号是CSNP1GCR01-AOW,
不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),
尺寸小巧,简单易用,兼容性强,稳定可靠,
固件可定制,LGA-8封装,标准SDIO接口,
兼容SPI/SD接口,兼容各大MCU平台,
可替代普通TF卡/SD卡,
尺寸6x8mm毫米,
内置SLC晶圆擦写寿命10万次,
通过1万次随机掉电测试耐高低温,
支持工业级温度-40°~+85°,
机贴手贴都非常方便,
速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)
标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。
支持TF卡启动的SOC都可以用SD NAND
,提供STM32参考例程及原厂技术支持,
主流容量:128MB/512MB/4GB/8GB,
比TF卡稳定,比eMMC便宜,
样品免费试用。
实际应用场景
新一代SD NAND主要应用领域
•5G
•机器人
•智能音箱
•智能面板(HMI)
•移动支付
•智能眼镜(AR)
•智能家居
•医疗设备
•轨道交通
•人脸识别
•3D打印机
二、速度测试
手里正好还有一张内存卡,那么就做下对比测试:
先理解下下面这四种测试的含义:
SEQ1M|Q8T1表示顺序读写,位深1024K,1线程8队列的测试速度
SEQ1M|Q1T1表示顺序读写,位深1024K,1线程1队列测试速度
RND4K|Q32T16表示随机读写,位深10244K,16线程32队列的测试速度
RND4K|Q1T1表示随机读写,位深10244K,一线程一队列的测试速度
那么由于CSNP1GCR01-AOW是512M的,那么就统一使用256M的随机读写来测试
CSNP1GCR01-AOW读写速度:
------------------------------------------------------------------------------
CrystalDiskMark 8.0.4 x64 (C) 2007-2021 hiyohiyo
Crystal Dew World: https://crystalmark.info/
------------------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes
[Read]
SEQ 1MiB (Q= 8, T= 1): 18.242 MB/s [ 17.4 IOPS] <437121.30 us>
SEQ 1MiB (Q= 1, T= 1): 18.409 MB/s [ 17.6 IOPS] < 56695.70 us>
RND 4KiB (Q= 32, T= 1): 4.807 MB/s [ 1173.6 IOPS] < 27159.12 us>
RND 4KiB (Q= 1, T= 1): 4.215 MB/s [ 1029.1 IOPS] < 968.89 us>
[Write]
SEQ 1MiB (Q= 8, T= 1): 7.326 MB/s [ 7.0 IOPS] <1026141.24 us>
SEQ 1MiB (Q= 1, T= 1): 7.549 MB/s [ 7.2 IOPS] <138263.48 us>
RND 4KiB (Q= 32, T= 1): 2.453 MB/s [ 598.9 IOPS] < 52662.34 us>
RND 4KiB (Q= 1, T= 1): 2.029 MB/s [ 495.4 IOPS] < 1987.79 us>
Profile: Default
Test: 256 MiB (x5) [F: 0% (0/481MiB)]
Mode: [Admin]
Time: Measure 5 sec / Interval 5 sec
Date: 2024/01/15 11:35:30
OS: Windows 10 Professional [10.0 Build 19044] (x64)
内存卡读写速度:
EEWORLDIMGTK2
------------------------------------------------------------------------------
CrystalDiskMark 8.0.4 x64 (C) 2007-2021 hiyohiyo
Crystal Dew World: https://crystalmark.info/
------------------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes
[Read]
SEQ 1MiB (Q= 8, T= 1): 17.579 MB/s [ 16.8 IOPS] <454375.89 us>
SEQ 1MiB (Q= 1, T= 1): 18.236 MB/s [ 17.4 IOPS] < 57188.36 us>
RND 4KiB (Q= 32, T= 1): 5.105 MB/s [ 1246.3 IOPS] < 25574.24 us>
RND 4KiB (Q= 1, T= 1): 4.622 MB/s [ 1128.4 IOPS] < 884.01 us>
[Write]
SEQ 1MiB (Q= 8, T= 1): 1.676 MB/s [ 1.6 IOPS] <3669329.62 us>
SEQ 1MiB (Q= 1, T= 1): 7.962 MB/s [ 7.6 IOPS] <130440.09 us>
RND 4KiB (Q= 32, T= 1): 0.018 MB/s [ 4.4 IOPS] <2106948.05 us>
RND 4KiB (Q= 1, T= 1): 0.015 MB/s [ 3.7 IOPS] <251984.23 us>
Profile: Default
Test: 256 MiB (x5) [F: 0% (0/953MiB)]
Mode: [Admin]
Time: Measure 5 sec / Interval 5 sec
Date: 2024/01/15 11:53:09
OS: Windows 10 Professional [10.0 Build 19044] (x64)
- 2024-05-21
-
发表了主题帖:
NAND Flash(贴片式TF卡)存储新突破,基础示例
目录
引言
SD卡的发展
SD NAND卡的特性与优势
二代SD NAND五大优点
SD NAND六大主要优势
现有产品分类
实际应用场景
SD NAND芯片推荐线路连接:
CSNP4GCR01-AMW的介绍
基础使用例程
例程环境简介
硬件设备及电路
项目创建流程
代码
例程结果
对比市场现有产品
创世半导体(CS)是全球首家推出SD NAND FLASH产品的厂商,SD NAND的出现大大降低了使用 NAND FLASH 的技术难度。
————————————————
引言
随着科技的发展,数据的存储需求也在日益增长。在这个信息爆炸的时代,一款高效、稳定、便携的存储设备显得尤为重要。新品SD卡——SD NAND,应运而生,为我们的数据存储带来了新的革命。
SD卡的发展
SD卡自问世以来,其体积不断缩小,容量逐步增大,速度也在不断提升。
开始。
1997年11月,闪迪和英飞凌联合推出了MMC(MultiMediaCard)存储卡。
1999年8月,闪迪又联合松下、东芝推出了SD(Secure Digital)存储卡。SD卡拥有与MMC卡相同的长宽尺寸,略厚一些(2.1mm VS. 1.4mm)。早期SD卡设备/读卡器都能同时兼容MMC卡。
2000年1月,SD卡协会正式成立,当年推出了最大容量64MB、传输速度约12.5MB/s的产品。
2003年3月,闪迪展示了面向手机等移动设备的miniSD卡(目前已退出市场)。
2004年2月,闪迪又和摩托罗拉发布了更小巧的microSD卡(也称为TransFlash或TF卡)。
2005年7月,SD卡协会确认了microSD卡规范,传输速度也提升到了约25MB/s。
2006年1月,SD 2.0带来了采用FAT32文件系统、最大容量32GB的SDHC(包括miniSDHC、microSDHC)卡。而最初版本的SD卡采用FAT12/FAT16文件系统,最大容量为2GB。
2010年5月,SD 3.01带来了采用exFAT文件系统、最大容量提升到2TB的SDXC(包括microSDXC)卡;以及UHS-I高速总线,最大传输速度为104MB/s。
2011年6月,SD 4.0带来了UHS-II总线。这种SD卡(包括microSD卡)具有两排触点,可以实现全双工156MB/s、半双工312MB/s的传输速度。
2016年2月,SD 5.0带来了视频速度等级规范,包括V30、V60、V90。
2016年11月,SD 5.1增加了针对App运行性能的A1标准。在满足10MB/s持续读写的基础上,增加了随机读取1500IOPS、随机写入500IOPS的要求。
2017年2月,SD 6.0带来了全双工312MB/s、全双工624MB/s的UHS-III总线以及随机读取4000IOPS、随机写入2000IOPS的A2标准。UHS-III向下兼容UHS-II,但到目前为止都没有看到任何样品。
2016年11月,SD 5.1增加了针对App运行性能的A1标准。在满足10MB/s持续读写的基础上,增加了随机读取1500IOPS、随机写入500IOPS的要求。
2017年2月,SD 6.0带来了全双工312MB/s、全双工624MB/s的UHS-III总线以及随机读取4000IOPS、随机写入2000IOPS的A2标准。UHS-III向下兼容UHS-II,但到目前为止都没有看到任何样品。
2019年初,闪迪推出“UHS-I超频卡”,突破了104MB/s的速度瓶颈。之后,金士顿、雷克沙等厂商也追加了类似规格的产品。
2020年5月,SD 8.0引入了PCIe 3.0×2、PCIe 4.0×1和PCIe 4.0×2,将最高速度提升至接近4GB/s(3938MB/s)。
2022年5月,SD 9.0增加了快速启动和安全启动特性,为SD卡创造了半嵌入式应用场景。
内存卡在近年来的发展主要集中在提高容量和读写速度上。例如,现在市场上已经出现了容量达到1TB的MicroSD卡,读写速度也不断提高,以满足用户对存储容量和速度的需求。
同时,一些新型内存卡如CFexpress和SD Express也正在逐渐普及,它们支持更快的数据传输速度和更大的容量。随着手机互联网的发展,云存储也逐渐在吞食存储卡的市场。过去需要通过内存卡扩展手机存储空间,现在则可以通过云服务,把数据存储在云端。
SD NAND的特性与优势
以CSNP4GCR01-AMW为例。
不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),
尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装,
标准SDIO接口,兼容SPI/SD接口,兼容各大MCU平台,可替代普通TF卡/SD卡,
尺寸6x8mm毫米,机贴手贴都非常方便,
内置SLC晶圆擦写寿命10万次,通过1万次随机掉电测试耐高低温,
支持工业级温度-40°~+85°,
速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)
标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。
支持TF卡启动的SOC都可以用SD NAND,
提供STM32参考例程及原厂技术支持,
主流容量:128MB/512MB/2GB/4GB/8GB,
比TF卡稳定,比eMMC便宜。
二代SD NAND五大优点
•尺寸小巧
•简单易用
•兼容性强
•稳定可靠
•固件可定制
SD NAND六大主要优势
•LGA-8封装,机贴手贴都方便。
•尺寸小巧5(6*8mm),助力产品颜值提升。
•容量适宜(1Gb/4Gb/32Gb)帮助客户降低成本。
•擦写寿命长(内置SLC晶圆,擦写寿命可达5-10万次,专为嵌式而生)。
•免驱动(即贴即用)直连SD/SPI接口即可使用,已内置Flash管理程序。
•稳定可靠:已通过10k次随机掉电高低温冲击测试。内置FW包含平均读写,坏块管理,垃圾回收等处理机制。
SD NAND 与 TF卡的区别:(看图表)
现有产品分类
本篇示例代码采用工业级CSNP4GCR01-AMW。容量为512MB。
实际应用场景
新一代SD NAND主要应用领域
•5G
•机器人
•智能音箱
•智能面板(HMI)
•移动支付
•智能眼镜(AR)
•智能家居
•医疗设备
•轨道交通
•人脸识别
•3D打印机
SD NAND芯片推荐线路连接:
CSNP4GCR01-AMW的介绍
不用写驱动程序自带坏块管理的NAND Flash(贴片式TF卡),
尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装,
标准SDIO接口,兼容SPI/SD接口,兼容各大MCU平台,可替代普通TF卡/SD卡,
尺寸6x8mm毫米,机贴手贴都非常方便,
内置SLC晶圆擦写寿命10万次,通过1万次随机掉电测试耐高低温,
支持工业级温度-40°~+85°,
速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)
标准的SD 2.0协议使得用户可以直接移植标准驱动代码,省去了驱动代码编程环节。
支持TF卡启动的SOC都可以用SD NAND,
提供STM32参考例程及原厂技术支持,
主流容量:128MB/512MB/2GB/4GB/8GB,
比TF卡稳定,比eMMC便宜。
基础使用例程
例程环境简介
项目环境:
使用开发板为正点原子探索者STM32F407ZG;
STM32CubeMX;
Keil;
SD NAND:芯片型号 CSNP4GCR01-AMW;芯片转接板(将芯片引脚引出为TF 卡)
硬件设备及电路
SD NAND原理图:
探索者TF 卡槽:
STM32线路连接
使用SDIO模式,
D0接PC8; D1接PC9; D2接PC10; D3接PC11;
信号
SDIO信号“4线模式”
CLK:HOST给DEVICE的时钟信号。
VDD:电源信号。
VSS:Ground信号。
DAT0-DAT3:4条数据线
CMD:用于HOST发送命令和DEVICE回复响应。
项目创建流程
基础时钟配置:
SDIO模式配置:
FATFS配置:
更改缓存区大小:
完成项目其他基础配置。
代码
while(1)之前:
FATFS fs; /* FatFs 文件系统对象 */
FIL file; /* 文件对象 */
FRESULT f_res; /* 文件操作结果 */
UINT fnum; /* 文件成功读写数量 */
BYTE ReadBuffer[512] = {0}; /* 读缓冲区 */
BYTE WriteBuffer[] = /* 写缓冲区 */
"This is STM32 working with FatFs \r\n STM32的FATFS文件系统测试 \r\n ";
// 在外部 SD 卡挂载文件系统,文件系统挂载时会对 SD 卡初始化
// note:必须先要保证SD卡正常拥有FAT文件系统,如果没有会失败。
f_res = f_mount(&fs, "0:", 1);
/*----------------------- 文件系统测试:写测试 -----------------------------*/
/* 打开文件,如果文件不存在则创建它 */
f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(f_res == FR_OK)
{
/* 将指定存储区内容写入到文件内 */
f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &fnum);
/* 不再读写,关闭文件 */
f_close(&file);
}
/*------------------- 文件系统测试:读测试 ------------------------------------*/
f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_OPEN_EXISTING | FA_READ);
if(f_res == FR_OK)
{
f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);
}
/* 不再读写,关闭文件 */
f_close(&file);
/* 不再使用文件系统,取消挂载文件系统 */
f_mount(NULL, "0:", 1);
/* 操作完成,停机 */
MX_SDIO_SD_Init()函数中加入
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
hsd.Init.ClockDiv = 34;
/* USER CODE BEGIN SDIO_Init 2 */
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END SDIO_Init 2 */
}
例程结果
新建了一个 STM32cube.txt 文件
写入内容如下图所示。
Keil 调试 :成功读取文件内容,暂存至数组中。内容如下
代码解释
对比市场现有产品
目前再嵌入式中使用最多的存储情况:
EEPROM:
只能存放字节类型的数据:芯片为AT24CXX;采用IIC通信,存储内容类型,大小有限。
U盘 :
存放文件格式多样;采用USB接口;占用空间大;可以热拔插;
关于MCU的存储方面,以前基本上用内置的E2PROM,或者是外置的NOR Flash 就可以了。但随着物联网的兴起,MCU的应用越来越广泛了,逐渐的MCU会涉及到大容量的存储需求,用来存储音频,图片(GUI)、视频缓存、协议栈等等。
那传统的E2PROM和NOR Flash就不够用了。这个时候MCU可能就需要用到NAND Flash了。但MCU采用大容量存储芯片NAND Flash,面临着新的挑战。
每个产品都有自己的优缺点。再存储器件选取上,都是考虑项目本身的需求,个产品性能综合考虑最优存储产品。
- 2024-05-11
-
发表了主题帖:
北京君正主控芯片:为什么要用人工智能重新定义血压计?
2023年,汉王重磅推出了柯氏音法电子血压计,这是继有创血压测量、水银血压计、示波法电子血压计之后的新一代血压计,即第四代血压计,特点是同时拥有水银血压计的医用级准确性和电子血压计的便捷性。
柯氏音法测血压是医疗行业的金标准,汉王用人工智能技术将柯氏音法成功电子化,因此能达到医用级准确。这一成果做到了当下医疗企业乃至国内外电子血压计市场无人做到的颠覆性突破,迅速受到了多方关注。作为进军大健康领域打响的第一枪,柯氏音法电子血压计产品线,汉王已潜心准备了数年。
「柯氏音法电子化」困难重重
汉王历经多年研发 不断精进技术攻克关键难题
柯氏音法的电子化难度很大,存在硬件条件限制,例如传感器不够精准,血压信号不够清晰等,医疗企业自身很难攻克这些难关,只有汉王这样拥有30年深厚技术积累的人工智能企业才有能力通过技术手段,让柯氏音法电子化成为可能。
三年前,刘迎建先生组建了专门的研发部门,一批技术骨干神经紧绷,闷头扎进了柯氏音法电子血压计的研发工作中,前期进行了庞大的数据搜集工作,采集了30多万人的血压数据组成大规模数据库,通过神经网络进行深度学习,一遍遍训练、精进神经网络算法,测量结果精准度就像医生经验值增长一样,随着海量数据的训练越来越高。
硬件设计也经历了多次打磨迭代,想要识别精准,需要高性能芯片的支撑。为了精准捕捉柯氏音,研发团队最终敲定了采用两颗24位高精度ADC芯片,内置先进的“压力+声音”双传感器,进行血压信号与柯氏音的同步采集,不漏听每一个血压信号,让人工智能精准听诊柯氏音。
其他配置在数据上皆呈现出压倒性优势:搭载的GHz级主频CPU,是市面主流示波法血压计算力的50余倍;8MB的FLASH存储空间超出主流示波法血压计60余倍;32MB的DDR高出示波法血压计4000余倍,数据处理速度超快,为深度学习神经网络算法提供澎湃算力的硬件支持。
为了让用户随时随地查看测量结果,还内置了物联网NB芯片,完成血压测量后,无需连接蓝牙或WIFI,数据会自动同步上传APP,进行数据智能分析,形成个性化健康报告。与蓝牙或WIFI连接方式相比,物联网传输的操作更方便,稳定性更强。双人数据可以分开记录,方便对比,数据不混淆,为用户的血压健康保驾护航。
当临床实践显示:汉王柯氏音法电子血压计测量误差平均差达到了惊人的≤±1mmHg(IOS临床标准对血压计测量误差要求为平均差≤±5mmHg),不仅血压测得准,还测得全,适用范围广泛,在房颤、心律不齐、低血压等多种症状下,或者是孕妇等特殊人群,均可准确测量血压。
这一结果令所有研发人员内心激动不已,这不仅是测量精准度的重大突破,更是在行业内树立了全新标杆,开创了电子血压计的医用级准确测量全新时代,成功攻克了当前国内外无人解决的难题。业内人士对汉王柯氏音法电子血压计给予了高度评价:能将柯氏音法电子化,精准度能达到医用级别,汉王拿到了电子血压计这一赛道的“圣杯”。
人人都可精准测血压
守护血压健康提高预期寿命 利于现在惠及未来
高血压是世界上死亡和残疾的主要危险因素之一,根据《健康中国行动(2019-2030年)》数据显示,中国18岁及以上居民高血压患病率为25.2%,全国现有高血压患者2.7亿。这不是冰冷的数字,背后是数亿个活生生的家庭。
汉王柯氏音法电子血压计可用于家庭日常监测、医院诊疗、养老机构、健康管理中心等场所,提供精准可靠的血压测量服务,真正实现血压人人可测,随时可测,如有高血压症状可及时发现,尽早治疗,避免漏诊误诊,挽救一个个鲜活的生命。
科技向善,造福人类。水银血压计里的汞对环境的危害极大,根据联合国环境规划署主导的《水俣公约》,自2026年1月1日起,我国将全面禁止生产含汞体温计和含汞血压计产品。在水银血压计将慢慢退出历史舞台的关键时刻,新一代汉王柯氏音法电子血压计问世,可作为其完美的替代品,同样精准,却更加环保,为人类社会可持续发展贡献力量。
柯氏音法拥有医疗行业公认的精准度,不是说汉王电子血压计就准,而是汉王电子血压计采用的柯氏音法原理足够精准。汉王利用人工智能技术发力电子血压计赛道,就是希望用科技为提高人们的健康水平和生活质量做一些实事。我们有信心,新一代汉王柯氏音法电子血压计必将成为人们健康管理必备品,广泛应用至全国、全世界,提高全球人均预期寿命,利于现在,惠及未来。
文章来源:汉王官网
关于北京君正
北京君正集成电路股份有限公司成立于2005年,基于创始团队创新的CPU设计技术,迅速在消费电子市场实现SoC芯片产业化,2011年5月公司在深圳创业板上市(300223)。
君正在处理器技术、多媒体技术和AI技术等计算技术领域持续投入,其芯片在智能视频监控、AIoT、工业和消费、生物识别及教育电子领域获得了稳健和广阔的市场。
2020年,君正完成对美国ISSI及其下属子品牌Lumissil的收购。ISSI面向汽车、工业和医疗等领域提供高品质、高可靠性的存储器产品,包括SRAM、DRAM、Nor Flash、2D NAND Flash和eMMC,客户遍布全球。Lumissi面向汽车、家电和消费电子等领域提供LED驱动、微处理器、电源管理和互联等芯片产品。
君正将整合其积累十几年的计算技术,及ISSI三十余年的存储、模拟和互联技术,利用公司拥有的完整车规芯片质量和服务体系,为汽车、工业、AIOT等行业的发展持续做出贡献。
亲,如果你在网站上没找到想要的信息可以联系深圳雷龙发展,我们提供原厂技术支持,并提供君正集成电路完整解决方案。
- 2024-05-08
-
发表了主题帖:
【商业】SD NAND(贴片式TF卡)性能体验及应用
SD NAND【商业】
外观
NAND与TF卡的区别
雷龙CS SD NAND(贴片式TF卡)性能体验及应用
最后
SD NAND
外观正反示意图
NAND与TF卡的区别
什么是SD NAND?它俗称贴片式T卡,贴片式TF卡,贴片式SD卡,贴片式内存卡,贴片式闪存卡,贴片式卡…等等。虽然SD NAND 和TF卡称呼上有些类似,但是SD NAND和TF卡有着本质上的区别。
为什么SD NAND 和 TF卡 之间有这么大区别呢?
因为 SD NAND是为内置存储而生,是焊接在PCB板上的,是针对工业级应用的产品,要求品质稳定、一致性高、使用稳定性高、同时尺寸也小。
而TF卡主要是针对普通消费者,品质和一致性、使用稳定性等相对要求不高,再加上国内鱼龙混杂的市场环境,导致内置存储用TF卡的品质风险高。
NAND Flash产品的一个特质就是它的品质并不是0和1这么简单,有些品质隐患是使用一段时间之后才被发现,如果这个产品已经销往海外,处理起来会变得异常麻烦。
使用SD NAND可以为客户产品带来整体品质的提升,提供确定性,是客户产品良好品牌和口碑的稳定基石。
而使用TF卡时,产品整机不可控因素会增高,比如常见的卡座老化松动、TF触点氧化、TF卡遗失、抗震性能减退等等。
综上所述,虽然SD NAND与TF卡使用的协议相同,但从外观到内在都有区别。正在使用TF卡的客户需要提升产品稳定性及耐用性时,SD NAND 是绝佳选择。
PS. TF卡用户切换SD NAND时只需要更改原有PCB上卡座位置的线路,驱动程序无需改动。
雷龙CS SD NAND(贴片式TF卡)性能体验及应用
参照:雷龙CS SD NAND(贴片式TF卡)性能体验及应用 (longsto.com)
前段时间有幸得到了雷龙出品的贴片式的TF卡的芯片及转接板,从而对其产品进行了相应的了解和测评。
从获得的相关资料看,雷龙出品的贴片式芯片分为两类,即BOW型和AOW型,其中BOW型为第一代产品,属商业级;AOW型则是第二代产品,属工业级或接近工业级。
而就存储容量看,主流容量:128MB/512MB/2GB/4GB/8GB。
详细信息参见下表所示:
芯片及转接板的外观如下图所示。
对普通用户来讲,受贴面焊的限制,还是选取厂家的产品比较方便,其测试卡的成品形式见下图所示。
下面再来看一看具体的测试过程。
1.电脑上的测试
大容量存储介质:
首先将测试卡插入USB转换器上,以连接电脑的USB口,见下图所示。
在正常的情况下,会在电脑上呈现出一个虚拟的U盘设备,其容量会因芯片的容量而改变。
在向U盘写入文件后,其测试效果如下图所示,这说明其读写性能正常。
2.FPGA板测试
基于FPGA的SD卡的数据读写实现(SD NAND FLASH): http://www.longsto.com/news/69.html
- 2024-04-25
-
发表了主题帖:
君正主控应用案例:办公必备神器,长城黑白激光一体机
伴随着这些年素质教育水平的提高,学校老师们成功减负,家长身上的担子越来越重,同时移动互联网的发展,学校和家长的沟通方式也在发生着变化,现在很多老师喜欢给学生布置作业是电子版的形式,如果是试卷一类还需要自己打印。
因此越来越多的家庭都在考虑配备一台家用级打印机,因为现在的打印机和过去不同,现在的打印机在操作时更方便,不管是上墨,还是清晰度,都已经远远超过了过去的一些传统打印机。
在这样的需求之下,促进了家用级打印机市场的发展,很多品牌都推出了针对学生家庭作业、网课使用场景的打印机产品,那么哪种类型的家用级打印机最适合购买呢?下面由小编根据自己的使用感受来给大家介绍一番吧。
打印机类别
目前,常用的打印机分为三种,分别是:“激光打印机”、“喷墨打印机”、还有家庭不常用到的“针式打印机”。
激光打印机
小编建议大家首选激光打印机。激光打印机是将激光扫描技术和电子成像技术相结合的打印设备。激光打印机70%的技术都蕴含在硒鼓之中,打印与硒鼓密不可分。激光打印机是需要使用到硒鼓和碳粉的混合物作为墨粉,整个工作原理是将数据信号,变成激光束,由激光头发出激光,经棱镜手折射到感光硒鼓上,然后将墨粉加热,固化到纸张上。
激光打印机打印速度快,黑白文件效果好,稳定性高,长期放置也不容易出问题,基本上不需要维护,只需要更换硒鼓或者粉盒。操作简单,非常适合家庭或公司日常办公使用。
在市场上的各类激光打印机产品中,小编特别想给大家推荐的是长城黑白激光一体机GBM-B2020NW和GBP-B2020W型号。
长城黑白激光一体机【GBM-B2020NW和GBP-B2020W】
1、高速打印,适配大部分客户的打印负荷:打印速度高达22页/分钟,满足大部分客户的打印需求;首页输出时间小于8秒,反应灵敏。
2、长城云打印,轻松实现远程打印:通过长城云打印,可连接移动端设备,支持手机及平板申较云端远程打印。
3、移动设备直连,无需安装驱动:支持移动设备,无需安装打印机驱动,便可实现打印输出。
4、体积小巧,外观精致:外观设计小巧,便于狭小空间摆放,按键功能一目了然。
5、兼容多种系统:除Windows操作系统外,更可适配麒麟KVinOS,统信UOS等国产操作系统。
大家可以根据自己的使用习惯进行选择,比如像平时打印力度不是特别大,选择一些小型打印机即可满足家庭使用。
同时也要选择性能稳定,操作比较简单的打印机,这样的打印机才比较适合日常办公生活使用。而且最好选择配置优良的打印机,这样才能延长使用时间,功能多,打印出来的效果也比较好。
文章节选自:知乎@哆喵呜、百家号@樱花号
关于北京君正
北京君正集成电路股份有限公司成立于2005年,基于创始团队创新的CPU设计技术,迅速在消费电子市场实现SoC芯片产业化,2011年5月公司在深圳创业板上市(300223)。
君正在处理器技术、多媒体技术和AI技术等计算技术领域持续投入,其芯片在智能视频监控、AIoT、工业和消费、生物识别及教育电子领域获得了稳健和广阔的市场。
2020年,君正完成对美国ISSI及其下属子品牌Lumissil的收购。ISSI面向汽车、工业和医疗等领域提供高品质、高可靠性的存储器产品,包括SRAM、DRAM、Nor Flash、2D NAND Flash 和eMMC,客户遍布全球。Lumissi面向汽车、家电和消费电子等领域提供LED驱动、微处理器、电源管理和互联等芯片产品。
君正将整合其积累十几年的计算技术,及ISSI三十余年的存储、模拟和互联技术,利用公司拥有的完整车规芯片质量和服务体系,为汽车、工业、AIOT等行业的发展持续做出贡献。
亲,如果你在网站上没找到想要的信息可以联系我们,我们提供原厂技术支持,并提供君正集成电路完整解决方案,大大降低你的开发难度及开发时间,让你比同行更快一步,更好的解决方案都在深圳市雷龙发展有限公司。