分类 硬件技术 下的文章

USB-C与PD学习笔记——在新的USB应用中换用Type-C接口

USB 发展概览

USB,是英文Universal Serial Bus(通用串行总线)的缩写,是一个外部总线标准,目前由USB-IF维护。自1994年问世,大致经历了以下时期:USB1.0(1.5Mb/s ,Low-Speed, 1996.01)、USB1.1(12Mb/s ,Full-Speed, 1998.09)、USB2.0(480Mb/s ,High-Speed, 2000.04)、USB3.0(5.0Gb/s ,Super-Speed, 2008.11,又称USB3.1 Gen1、USB3.2 Gen1)、USB3.1 Gen2(10Gb/s ,Super-Speed+, 2013.12,又称USB3.2 Gen2)、USB3.2 Gen2x2(20Gb/s,Super-Speed++, 2017.09,仅支持Type-C接口)、USB4(包含 USB4® 20Gbps与USB4® 40Gbps并向下兼容前述规范,2019.09)。需要注意的是,雷电接口不属于USB规范,它是英特尔维护的一个接口规范,切莫混淆。

版本 速度 发布年份(参考)
USB1.0 1.5Mb/s ,Low-Speed,低速 1996.01
USB1.1 12Mb/s ,Full-Speed,全速 1998.09
USB2.0 480Mb/s ,High-Speed,高速 2000.04
USB3.0 5.0Gb/s ,Super-Speed 2008.11
USB3.1 Gen2 10Gb/s ,Super-Speed+ 2013.12
USB3.2 Gen2x2 20Gb/s,Super-Speed++ 2017.09
USB4® 20Gbps 20Gbps 2019.09
USB4® 40Gbps 40Gbps 2019.09

USB3时代命名混乱,最初的USB3.0速率为5.0Gb/s,后来USB3.1和3.2发布后,速度使用Gen1、Gen2、Gen2x2来表示。USB4时代USB-IF已经意识到了这个问题,简化USB版本命名。

USB-IF除维护上述的USB数据协议标准之外,他也定义了USB协议所使用的各种接口和电气规范。在USB3.1以及之前,接口与电器规范包含在USB规范中;从USB3.2开始,USB 3.2规范已经不再包含接口和电气规范,转为单独提供。

USB-IF定义了USB的电源规范。从最初的BC1.0(Battery Charging1.0)到提供5V1.5A电流支持的BC1.2。又从PD1.0开始,到广泛使用的PD2.0&3.0,支持最高20V5A的100W供电能力。最新的PD3.1快充标准由USB-IF 于2021年5月发布。由此,基于USB Type-C的电源支持添加了28V、36V、48V档,其分别能够提供140W、180W、240W三档功率;可调电压模式提供了15V到电源适配器最大电压的可调范围,分辨率100mV。在PD协议中,电源的供给方向与USB接口的功能角色通过单独的导线通信进行配置,实现了大量的功能。

笔者最初开始学习USB-PD的目的是为USB2.0设备更换Type-C接口。本学习笔记最初的目标是为电子工程师提供参考,以便快速将Type-C接口应用于电路设计中;后期若有机会深入,可以研究一下快充协议触发。当然笔者才疏学浅,这个目标目前还很遥远。目前我为探索通过Type-C充电时各IO的信号,画了一张板子做测试用,文件已上传GitHub

本文相关的参考文档,如往常一样,我会在文末附加链接。

USB Type-C 接口定义

USB Type-C 母座定义(前视图):

USB Type-C 公头定义(前视图):

如何从C口获得电力

这个标题可能看起来有些无聊,但很多初学者对此并不了解。从传统的几款USB接口中获取电力非常简单,你只需要连接VBUS和GND,即可轻松获得电力。但Type-C 接口并非如此。这时有人会说,我画了张板子,Type-C口只是用来供电,我只连接了VBUS和GND,手机充电器插上,板子就工作了。哪有你说的那么悬?

传统5V取电:

目前市面常见的Android手机已经普遍采用Type-C 接口,但充电线与电源适配器间的连接仍大量使用USB A型接口,而这类充电器并不能代表全部。有一类电源适配器的输出口也是C口,它们应当支持PD快充协议。按PD规范,C口应该支持双向充电,这是两者协商决定的,提供电力的设备被称为Source,而受电的设备被称为Sink。Source端应上拉CC,Sink端应下拉CC,以此完成识别。复杂的快充协商要求两边是IC来执行,而普通的5V设备想做到被其他设备识别,只需要几颗电阻就可以。

所以,如上图所示。如果我们要从C口获取电力,我们需要的便是在受电即Sink端Type-C母口的CC1和CC2分别连接一个下拉电阻即可,一般取值5.1K。为什么要分别连接一颗下拉电阻,而不能直接短接CC1和CC2共用一颗电阻?因为在双头Type-C连接线缆中,CC实际只有一条,另一条将作为VCON,给线缆中的EMark芯片供电。注意,这里的EMark芯片是选配的,USB-IF规定了载流能力超过3A的线缆必须带有EMark芯片。而EMark 芯片会将CC线短接的情况识别为耳机附件模式,最终导致在Source端不能正确识别Sink设备。

按照上面介绍的逻辑,如果我们设计的是Type-C公头取电,比如是一条5V电源转接线。这种情况下我们只需要在CC上设计一个5.1K下拉电阻,VCON悬空即可。毕竟在公头Type-C上,只有一个CC线。另外,如果我们设计的是一个连接到Sink端的Type-C公头,此时我们应该为CC添加上拉电阻,以保证Sink正确识别到插入的是电源。具体的电阻大小与电源供电能力有关,此处不在赘述。

如何实现快充:

目前市面上有大量的快充协议,最广泛的可能要属USB PD 和高通的 QC。前者是在CC线上使用PD协议进行通信,后者是在D+和D-上加载不同电压来协商。学习这些信号的时序、协议需要耗费大量的时间。业界有公司专门为此设计了专用的接口芯片,他们往往提供了多种与单片机通信的方式,使用时无需关注PD协议信号的处理,通过简单的配置即可使用。此类产品如:沁恒CH224。

参考

记维修搜狗录音笔C1

前言:

之前从老王那里入了两支坏的搜狗录音笔C1,很多大佬上车了。据说这批货是售后出来的,状态良莠不齐。花了一点时间,最终我这两支拼成了一个。本文简述过程,记录部分资料以备日后使用。也顺便试一下用IPFS(星际文件系统)作为图床效果如可。

以上图片大小为3386KB

维修过程:

首先,我对两支录音笔进行了测试。其结果如下:

一号:外观尚可,外壳完整,右侧有些许撬痕。拆机发现严重进液,主板严重腐蚀,通电发现大短路不开机,MIC FPC有腐蚀,后测试发现MIC坏,排线有腐蚀断线。

二号:外观不良,外壳有磕伤,撬痕极其明显,结构变形不佳。电池亏电,充电后可正常开机并连接手机APP,MIC排线有多处弯折与裂痕,LED不亮,MIC变形。

很明显,如此情况只能两支拼一支了。首先将一号机的底壳与二号机的主板电池装在一起,然后将二号MIC排线的接插件替换到一号排线上,再将一号MIC排线上的两个MIC换新、腐蚀断点飞线。这期间我顺便简单跑了一下MIC_FPC的线路。

MIC脚位定义:

MIC内部构造:

FPC连接器脚位:

脚位 功能 脚位 功能
5 LED_VCC 6 LED_R
4 GND 7 LED_G
3 CLOCK 8 LED_B
2 MIC_OUT 9 R/L & VDD
1 GND 10 GND

最终将一号排线与一号中壳、上盖等组装在一起。与底壳主板等简单装配后实际测试录音、转写等功能没有问题。但录音的音质一般,这有可能是我换的MIC质量不好(可能性不大)导致,也可能是产品性能仅限于此了。

使用感受:

正如上文所述,感觉录音的音质一般,这有可能是我换的MIC质量不好。个人拙见,搜狗录音笔C1适合用于会议记录与采访等场景,专业的视频录制收音确实不适合。虽然这笔有两个MIC,但只有降噪用途,其并不能录制双声道立体声。

获取转写功能:

此机器的主要卖点是录音转文字服务,简称转写服务。此功能不是本地完成的,而是将录音文件上传云端处理。搜狗有一个名为 搜狗录音助手 的APP有偿提供此服务,后来我们通过淘宝了解到,搜狗录音笔C1带有终生免费的转写服务权益。

经沟通客服了解到:免费转写服务权益会绑定在第一次绑定录音笔时使用的账号上,此权益可以迁移一次。咱们这种货,肯定不是第一次绑定啦,所以绑定后不会获得终生免费的转写服务权益。根据从客服处了解的信息,咱可以提供机器的SN(SN查看:绑定后在APP左上角点击录音笔图标,SN在出现的录音笔管理页面最下方)和新账号(一般是注册的手机号),然后客服登记后台转移权益。转移后便会获得有效期至2201年的转写服务。

这种事情,我们需要与搜狗客服沟通过程需要一些技巧。不要说自己的机器是售后报废机,可以说是朋友赠送的。至于咱们怎么修的,这个没有必要的情况也不必跟客服讲。客服告知我们的权益转移流程需要提供之前绑定的账号,我们可以告知其朋友说不记得了,一般客服也不会再要求必须提供之前的账号,只要有机器SN和咱的新账号他们就会帮咱处理。

那么,如何与客服取得联系呢?APP里面有啦!搜索添加微信公众号:搜狗AI黑科技。

注:本文图片托管于IPFS(星际文件系统),由CloudFlare IPFS网关提供图片解析,插图可能会随时间久远而丢失!

Proxmark3 Easy 复制4100卡到T5577卡

前言:

最近搬新住处,小区的门禁是用的ID卡,配一张卡30元。可以理解,但还是感觉很贵。想来手里有PM3 Easy,另外还有几张HACKNOWN的双频混合卡,记得它的低频是使用的T5577方案。把吃灰的东西用起来,也复习一下PM3的使用。

实践本文,您可能需要:

  1. Proxmark3 Easy
  2. 待复制的EM4100卡
  3. 空白的T5577卡
  4. 门禁刷卡机,用于验证复制的卡能否正常使用

EM4100卡简介:

EM4100卡工作频率为125KHz,是低频卡。发送数据时采用曼彻斯特编码,比特率为RF/64 。该卡存储64个只读数据位(bit),每个二进制位存储的不是0就是1。起始9个位为9个1,用作表示一次传输的开始。接下来传输10组数据,每组有4位数据+1位偶校验(每组5位中1的个数为偶数个),这个巧妙的设计在进行数据校验的同时确保了发送数据时不会出现连发9个1的情况,从而避免数据发送过程与起始信号冲突。这10组数据中前2组是用于标记版本或厂商,后8组是编号数据。10组数据位的后面跟随的是4位列校验位,最后以0为结束位。如下图所示:

01.jpg

什么是偶校验?所谓的偶校验即指定的一组二进制数据中限定1的个数为偶数,本例中,假如一组数据的数据位为0100(0x4),则目前1的个数为奇数,为了满足偶校验,会在校验位上写1以将1的个数补充到偶数个,这组数据最终就是01001。反之,如果数据位为0101,1的个数已经是偶数,为了满足偶校验,校验位上就写0。

EM4100卡片卡号:

上文中提到的10组数据,每组都编码了一个16进制值。这10个16进制值所构成的就是EM TAG ID这个ID是这张卡存储的所有信息。这也是卡片在读卡过程中发出的实际数据(当热,数据发送时还有发送校验位),因其发射数据时采用的时曼彻斯特编码调制方式,又称其为曼彻斯特内码(Manchester)

需要注意,曼彻斯特内码不在卡面标注ID卡表面通常会印有一串10位10进制数字,该数字为ABA码,它是由EM TAG ID去掉前2位后剩余的用户ID部分转换成10进制后得到的。较大的ID卡表面可能还会印有一个中间由 ,分隔的值,这个是韦根码(wiegand),它是使用ID代码倒数5、6位和后4位分别换算成10进制组成。

假设有一张EM4100卡片的EM TAG ID是:06008148DD 。那么它的ABA码就是:0008472797 [(HEX:008148DD)==>(DEC:0008472797) ];其韦根码为:129,18653 [ (HEX: 81 , HEX:48DD) ==> ( 129 ,18653) ] .

综上,EM TAG ID包含了卡片所有数据,且刷卡时发射的数据也是它,我们复制的新卡自然也应该是发送这些数据。

T5577空白卡简介:

T5577的Page0有8个区块,区块0存储的配置信息,用于配置卡片的工作模式。区块1~7可以存储用户数据,区块7也可以用于存储访问密码。每个区块有33个二进制位。通过把需要发送的数据存储在用户数据区,再通过修改区块0的数据,配置卡片工作方式,以此模拟EM4100卡片。

思路:

为实现目标,首先需要将T5577卡片配置在合适的模式下。曼彻斯特编码、RF/64、ST=0等。经过计算,T5577的Page0:Block0应该配置为:0X00148040。

接下来将EM TAG ID填入上文EM4100卡片简介的图中,计算行列校验位的数值并补齐,以此获得64bit的实际发送数据,将数据转换为16位16进制值,并将其依次写入Block1和Block2。

这样T5577卡片应该就会按照EM4100的方式工作了,在刷卡器上应该会被正常识别。

操作步骤:

实际PM3的命令中提供了更简单的操作方式,有一个命令可以将T5577写成EM4100的工作模式。

在开始之前,我们需要使用hw tune命令来测试天线是否正常。正常情况据说低频天线应该能测到10V以上的电压。但是我的不知是坏了还是怎么,表现如下,但是实际可以正常读写低频卡。

proxmark3> hw tune

Measuring antenna characteristics, please wait.........          
# LF antenna:  0.55 V @   125.00 kHz          
# LF antenna:  0.55 V @   134.00 kHz          
# LF optimal:  1.10 V @    46.88 kHz          
# HF antenna: 24.39 V @    13.56 MHz          
# Your LF antenna is unusable.

首先将原始的EM4100卡片防止在PM3的低频天线上,然后使用lf search命令搜索卡片。如果一切顺利,会有类似如下部分提示:

.....
Checking for known tags:

EM410x pattern found:           

EM TAG ID      : 06008148DD          
Unique TAG ID  : **********         

Possible de-scramble patterns 
.....

将EM4100卡片从低频天线上取下,将EM TAG ID记下来,稍后备用。至此,我们已经获取了EM4100卡片的所有数据。

将T5577空白卡放到低频天线上,运行lf em4x em410xwrite <EM TAG ID> 1 64命令,本例中EM TAG ID为:06008148DD,所以命令如下。

lf em4x em410xwrite 06008148DD 1 64

命令执行后,再次执行 lf search命令,若能够回显与之前的EM4100卡片相同之信息,即表示复制成功。考虑兼容性,具体能否使用还是需要到门禁处实际刷卡验证。

不同固件可能某些命令会不完全一样,比如,上文的命令在某个固件中需要使用以格式:

lf em 410xwrite 06008148DD 1

如果需要尝试识别某张卡是不是T5577卡,可以使用lf t55xx detect命令,回显信息类似如下即表明是。

proxmark3> lf t55xx detect
Chip Type  : T55x7          
Modulation : ASK          
Bit Rate   : 5 - RF/64          
Inverted   : No          
Offset     : 33          
Seq. Term. : No          

Block0     : 0x00148040          

Downlink Mode used : default/fixed bit length

使用了上面的lf t55xx detect命令后,可以使用lf t55xx dump命令获取T5577卡中每个块的原始数据。

假设我们需要单独写入某个块,我们可以使用lf t55xx wr <block> <data>的方式写入。以下是将0x00148040写入到块0中。

lf t55xx wr 0 00148040

网上也有人说要把块0写成0x001480E0,也有人说要把块0写成0x00148041,目前我写的是默认的0x00148040,如果不行,大家可以多试一试。如果命令使用过程遇到问题,可以使用help命令获取帮助。

PS:听说有些读卡器有针对T5577的检测,如果检测到是T5577就不响应,此种情况被称为防火墙,而瞒过此类检测的操作被称为穿过防火墙,T5577卡一般可通过添加写卡密码的方式做到穿防火墙,因为添加密码后必须使用正确的密码方可执行detect 和dump指令。

参考:

我用ArduinoProMicro_SSD1351_MLX90614整红外测温计

我用ArduinoProMicro_SSD1351_MLX90614整红外测温计

前言:

最初我想玩屏,于是从某网友手里买了个分辨率128*96的RGB OLED屏,然后尝试通过网友提供的C51示例代码适配到ArduinoProMicro,学习了一下SPI驱动彩屏。然后买了个MLX90614挂上,配合着前面的硬件学习了一下I2C,说起来MLX90614是SMBus协议,和I2C还有点区别。目前程序实现了读写MLX90614,主函数仅实现了隔三秒读取温度显示一次。整个项目的代码已经上传到GitHub,目前的状态只能算是个硬件测试程序,距离实用还差的远。初学者朋友有兴趣的可以Fork玩一下,也欢迎大佬指导改进。

项目地址:

Github:https://github.com/LexsionLee/Thermometer_MLX90614_SSD1351.git

效果图片:

A01.jpg

A02.jpg

硬件:

MCU:ATMEGA32U4
Board:ProMicro (Arduino Leonardo)

OLED Driver IC:SSD1351

OLED Power IC:ASM1117 3V3

温度传感器:MLX90614

引脚使用:

命名 IO口 功能
OLED_CLK D15 SCL
OLED_DIN D16 SDIN
OLED_RES D10 RST
OLED_DC D9 D/C
OLED_CS D8 /CS

CS为 低电平有效

功能 IO口
MLX90614_I2C_SDA D2
MLX90614_I2C_SCL D3

实现:

我选取了硬件SPI的IO口用于驱动屏幕,虽然网友提供的代码是软件模拟SPI。这种选择源于后期使用硬件SPI的可能性的考虑。事实证明,软件模拟的SPI速度太慢,对于这种彩色OLED屏来说,刷屏速度无法接受,能明显看到刷屏动作,体检极差。最终重写了部分不支持C++编译的代码。换用了硬件SPI的方式。这样果然快多了,画面瞬间刷完。

我用取模软件对数字显示字体进行了取模,推荐字体如下:

Lucida Console
MS Gothic
Rockwell
Rockwell Conden

I2C软件模拟部分,分别对通信协议中基础的片段进行了模拟,然后分层次拼接实现具体的读写功能。与某些I2C通信不同,这个SMBus协议中传输了一位PEC数据,用来校验传输的数据是否正确。我们读取时可以忽略,但是尝试写入时必然要发送PEC的。PEC的值是用本次读写操作中所有数据连在一起通过CRC-8校验得出的。比如写EEPROM时发送的PEC是由从机地址、欲写入的寄存器地址、数据低8位、数据高8位这些数据经过CRC-8校验得出。具体算法没弄懂,索性抄了网友的PEC生成函数,在PC上写了个临时程序验证OK,就这样用了。

手册(Datasheet)中给出的各种地址是需要拼上一个所谓的Opcode的,RAM部分的拼的是0,EEPROM拼的是001X XXXX。具体参考8.4.5. Commands。

EEPROM地址EMISS包含发射率参数(工厂默认1.0=0x FFFF),这是个16位数值。计算公式为:Emissivity = dec2hex[ round( 65535 x ε) ],其实就是65535乘以发射率(范围0.1~1.0),然后得出的结果转换为16进制值。修改EMISS需要先向该地址写0x0000,然后再将新的值写入。

实时的红外测温数据从TOBJ中读出,数据格式为4位16进制值,最高位为错误标记位。我使用的版本只有TOBJ1,所以我程序中读取的TOBJ1的数据。该数据乘以0.02得出的值即为当前红外传感器测得的绝对温度,即开氏温度。众所周知,此温度减去273.15即为摄氏温度。传感器量程能报告的最高温度为382.19℃(0x7FFF),如果报告数据最高位(MSB)为1(0x8XXX)则表示数据有错误,程序上需要做对应处理(目前程序中没有对此做处理)。另外我们可以从TA中读出传感器本身的当前温度数据(线性输出极限范围-38.2~+125℃),处理方式同上。

最后我们将得到的温度数据输出到屏幕上显示即可。

踩坑记录:

因为博主技术太菜,所以会遇到一些低级错误,记下来防止再犯错误!

In function XXX :XXX.cpp:XXXXX :"undefined reference to XXX"

Arduino(AVR) 使用的是C++语言,它使用的编译器是g++ 。在编译时,.ino文件会被改成.cpp,作为C++文件编译。我们认为C++是C的超集,如此看来,我们使用C的语法来写程序应当是可行的。但如果我们的项目由多个.c和.h文件构成且其他.c与.h文件中有函数在.ino文件中调用时,即c文件和cpp文件混编的情况,编译器便会报错。编译器会报告ino文件中调用的函数没有定义,即:In function XXX :XXX.cpp:XXXXX :"undefined reference to XXX" 。具体什么原因,这里不详细展开。这种情况,在合适位置加上extern "C"即可。具体如下:

#ifndef _XXX_H_
#define _XXX_H_

#ifdef __cplusplus
extern "C" {
#endif

void afunctionA(void);
void afunctionB(void);

#ifdef __cplusplus
}
#endif

error: old-style parameter declarations in prototyped function definition

编译项目的时候,提示“old-style parameter declarations in prototyped function definition”。看函数写的也没啥问题,这个项目之前是能够编译通过的,今天改了几段代码,增加了几个函数,然后编译才出现的错误。百度搜索了一下,居然是头文件中这个函数声明时少打了个分号!!!

unknown type name 'class'; did you mean 'labs'

Arduino编译时遇到unknown type name 'class'; did you mean 'labs'这个错误,一番查资料才明白,C++和C混编导致此问题。C文件中调用了C++的函数,而C文件编译时调用的C编译器不支持C++中的类。一般可以把.c文件重命名为.cpp解决。但需要处理C文件中不符合C++语言的代码。

#error: duplicate 'unsigned'

在将C文件更名为.cpp文件后编译出现此错误,是因为 #define u8 unsigned char 造成的。这是写C51时的宏定义习惯,大家都知道,这么写就不需要每次都写那么长的一串了。百度搜索了一下,据说在C++编译器中这种写法不规范,应当使用 typedef unsigned char u8; 来定义类型。我也不知道他说的是否准确、严谨,但是我尝试使用typedef的方式替代之前的写法,再次尝试编译果然可以了。题外话,Arduino的代码库中已经有定义了u16类型,我自己写的就把u16写成了uu16来规避这个问题。