本帖最后由 Liuhl1998 于 2022-8-8 18:00 编辑
随着USB PD3.1的发布,PD快充将支持最高48V电压输出,充电功率同步提升至240W,在生活中PD充电器随处可见,为人们日常提供不可或缺的便捷。如果有一款合适的“诱”电端,PD充电器就可以连续输出可调节的电压,这对于工程师来说不就相当于一个可调的电压源吗?基于CH543的评估板做了这样一个受电端,效果差不多这样:
PD快充是基于CC线通讯完成,需要遵循USB Power Delivery规范,从PD协议规范中可以了解到具体的协商过程:
由上图可以看出USB PD通讯就是Host(Source)和Power Brick(Sink)之间的数据交互。当Sink接入后(主机检测到5.1K下拉电阻的接入),主机(Source)将在100ms~200ms内会发送Source Cap(包含可提供电压档位的PDO)。
设备接收到主机发来的消息时会回复Good CRC进行响应,并在24ms内回复Request(请求需要的电压电流)。
主机收到设备发来的Request会回复Good CRC进行响应,并检测自身PDO是否支持设备Request,支持:会在24ms内回复Accept,不支持:回复Reject。
设备接收到主机发来的Accept/Reject,都会回复Good CRC进行响应。
主机若是支持设备请求,将会在450ms进行调压,调压完成后发送PS_RDY,然后等待设备回复Good CRC进行响应。
理论明白了,现在就动手来实践吧,硬件采用的是:“沁恒微电子”的CH543评估板,CH543 内置了 USB Power Delivery 控制器和 PD BMC PHY 收发器,支持 USB type C、BC、PD2.0、PD3.0、PPS,还支持 12V 高压电源,PD通讯时需要的BMC编解码、4B5B编解码、CRC校验也都有集成,这样的话用CH543实现一个PD通讯就比较简单了。
单片机原理图CC可以直接连接Type-C端口,不需要额外添加器件(CH543内置5.1K下拉),电路还是比较简单的:
我这次编写的是PD Sink受电端,那么我只需要在合适的场景下及时回复Good CRC和Request,就能完成USB PD通讯。在消息处理上,我是根据CH543 USB PD中断的特点来进行相应消息处理,软件如下:
void PD_PHY_ISR(void) interrupt INT_NO_USBPD using 1
{
if ( PIF_RX_RST ) {/*接收到复位信息中断*/
printf("RST ");
PD_PHY_HRST_ISR(); //收到HRST
PD_PHY_RX_INIT();
}
if ( PIF_RX_ACT ){/*数据包接受完成中断*/
TR0 = 0; ET0 = 0;
PIF_RX_ACT = 0;
if ( (UPD_INT_FG & MASK_PD_STAT) == PD_RX_SOP0 ) { //收到HRST或SOP数据
Union_Header = (_Union_Header *)PD_RX_BUF; //强制转化
if ( PD_PHY_STAT.WaitingGoodCRC ) { //是否在等待GoodCRC
if(Union_Header->HeaderStruct.MsgType == GoodCRC){
PD_PHY_STAT.WaitingGoodCRC = 0;
if(PD_PHY_STAT.SendingRequest == 1){ PD_PHY_STAT.SendingRequest = 0;}
Send_Count = 0;
PD_PROT_ISR();
}
}else {
switch(Union_Header->HeaderStruct.MsgType)
{
case SourceCap:
NDORcv=Union_Header->HeaderStruct.NDO;
memcpy(PD_Source,PD_RX_BUF,30);
PD_PHY_STAT.SendingRequest = 1;
break;
case Request:
break;
case Accept:
MsgID ++;
break;
case Reject:
break;
case PS_RDY:
break;
case GetSrcCap:
MsgID++;
PD_PHY_STAT.SendingSourceCap = 1;
break;
case GetSinkCap:
MsgID++;
PD_PHY_STAT.SendingSinkCap = 1;
break;
case SourceCap_VDM:
break;
default :
break;
}
mDelayuS(25);
PD_PHY_STAT.SendingGoodCRC = 1; //置发送GoodCRC标志位
PD_PHY_TX_GoodCRC(); //回复GoodCRC
}
}else PD_PHY_RX_INIT();
}
if ( PIF_TX_END ) { /*数据包发送完成中断 */
PIF_TX_END = 0;
if(CCSel == 1){ //发送完成关闭低压
CC1_CTRL &= ~bCC_LVO;
}else if(CCSel == 2){
CC2_CTRL &= ~bCC_LVO;
}
if ( PD_PHY_STAT.SendingGoodCRC ==1 ) {
PD_PHY_STAT.SendingGoodCRC = 0;
PD_PROT_ISR(); //GoodCRC发送完成,向Prot转交数据
}else { /*开始接收GoodCRC*/
PD_PHY_STAT.WaitingGoodCRC = 1;
mTimer_x_SetData(10000); //5ms
PD_PHY_RX_INIT();
}
}
}
Sink端的程序编写从一个Request开始,Request请求结构如下:
下面是用CH543编写Request的代码:
void PD_PHY_TX_Request(void)
{
UINT16 Volt_Value;
UINT8 temp=0xff; //pdo 档位
UINT8 i;
UINT16 Temp;
UINT16 Data_H8;
UINT16 Cur_Temp = 0;
for (i=0;i!=NDORcv;i++)
{
Union_SrcCap = (_Union_SrcCap *)&PD_Source[2+(4*i)];
Data_H8 = (Union_SrcCap->SrcCapStruct.DataH8);
if((Data_H8 >> 6 ) == 3)
{
PPS_Flag = 1;
printf("\r %d is PPS\n",(UINT16)(i+1));
}else{
Temp = (PD_Source[3+(i<<2)] >> 2)+((PD_Source[4+(i<<2)] & 0x0F)<<6);
Temp*=50;
if (Temp <= Volt_Value )
{
if(Temp > Cur_Temp)
{
Cur_Temp = Temp;
temp = i+1;
}
}
}
}
if(Temp_PDO != temp )
{
printf("No requested voltage! \r\n");
printf("Request adjacent voltage! \r\n");
}
if(temp != 0xff)
{
UPD_T_SOP = UPD_SOP0;
UPD_T_LEN = 6;
PD_TX_BUF[5] =( (temp<<4) | 0x02);
PD_TX_BUF[4] = ((PD_Source[3+((temp - 1)<<2)]&0x03)<<2) |(PD_Source[2+((temp - 1)<<2)]>>6) | (PD_Source[4+((temp - 1)<<2)] &0xF0);
PD_TX_BUF[3] =(PD_Source[3+((temp - 1)<<2)]&0x03) | (PD_Source[2+((temp - 1)<<2)]<<2);
PD_TX_BUF[2] = PD_Source[2+((temp - 1)<<2)];
PD_TX_BUF[1] = (0x10 | (MsgID << 1));
PD_TX_BUF[0] =0x02 | (0xC0 & PD_Source[0]);
PD_PHY_TX_INIT();
}else{
printf("No Matched Volt.\r\n");
}
}
按照PD的协商流程,可以完成PD通讯。另外在工程中增加了I/O中断来调节电压档位升降:
主程序内循环检测:
if(Gears_Plus == 1)
{
if(P1_5 == 1)
{
PD_Request_Gears += 1;
Gears_Plus = 0;
}
if(PD_Request_Gears>5)
{
PD_Request_Gears = 1;
}
}
if(Gears_Sub == 1)
{
if(P1_4 == 1)
{
PD_Request_Gears -= 1;
Gears_Sub = 0;
}
if(PD_Request_Gears<1)
{
PD_Request_Gears = 5;
}
}
if(Temp_PDO !=PD_Request_Gears)
{
Temp_PDO = PD_Request_Gears;
printf("Temp_PDO == %d\r\n",(UINT16)Temp_PDO);
PD_PHY_TX_Request();
}
通过逻辑分析仪观察,PD的SINK通讯成功!
当主机发来Source Cap后,设备端点按照PD协议流程进行响应并回复Request,直到主机发送PS_RDY 结束一次PD请求调压过程,然后设备端点可以多次发送Request来请求新的电压,从上图中可以看出,多次请求成功!
至此PD Sink端的应用升降电压就实现了,另外要实现PPS调压还需要完善程序代码(PPS和固定档位的PDO处理方法有一定区别),后面会找时间继续。附件是硬件、软件资料,小伙伴们可以按需下载。
|
楼主您好,请问最新的资料,可以分享下吗
@wang159357 :CS957914743
@Liuhl1998 :您好,请问有最新的代码吗,怎么联系您呢
@wang159357 :默认5V哈,需要触发
我用数据线把你的CH543 PD文件的hex烧录进板子,再用万用表测电压,只有5v左右不动的电压,并没有诱骗成功啊
楼主你好,能否给个联系方式,我有事想咨询一下,谢谢
看完我就懂了,原来我差的是个脑子