123下一页
返回列表 发新帖我要提问本帖赏金: 5.00元(功能说明)

[国产单片机] PD快充也没那么神秘CH543D(PD诱骗受电Sink解析)

[复制链接]
 楼主| Liuhl1998 发表于 2022-3-16 15:01 | 显示全部楼层 |阅读模式
本帖最后由 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中断的特点来进行相应消息处理,软件如下:

  1. void PD_PHY_ISR(void) interrupt INT_NO_USBPD using 1
  2. {
  3.         if ( PIF_RX_RST ) {/*接收到复位信息中断*/
  4.                 printf("RST ");
  5.                 PD_PHY_HRST_ISR();                //收到HRST
  6.                 PD_PHY_RX_INIT();
  7.         }
  8.         if ( PIF_RX_ACT ){/*数据包接受完成中断*/
  9.             TR0 = 0;  ET0 = 0;
  10.                         PIF_RX_ACT = 0;
  11.                 if ( (UPD_INT_FG & MASK_PD_STAT) == PD_RX_SOP0 ) {        //收到HRST或SOP数据               
  12.                         Union_Header = (_Union_Header *)PD_RX_BUF;    //强制转化                        
  13.                                         if ( PD_PHY_STAT.WaitingGoodCRC ) {          //是否在等待GoodCRC
  14.                                           if(Union_Header->HeaderStruct.MsgType == GoodCRC){
  15.                                                         PD_PHY_STAT.WaitingGoodCRC = 0;                  
  16.                                                         if(PD_PHY_STAT.SendingRequest == 1){ PD_PHY_STAT.SendingRequest = 0;}        
  17.                                                         Send_Count = 0;
  18.                                                         PD_PROT_ISR();                                             
  19.                                 }
  20.                         }else {               
  21.                                         switch(Union_Header->HeaderStruct.MsgType)
  22.                                         {
  23.                                                 case SourceCap:
  24.                                                                  NDORcv=Union_Header->HeaderStruct.NDO;
  25.                                                            memcpy(PD_Source,PD_RX_BUF,30);
  26.                                                                  PD_PHY_STAT.SendingRequest = 1;
  27.                                                                  break;
  28.                                                 case Request:
  29.                                                                  break;
  30.                                                 case Accept:
  31.                                                            MsgID ++;
  32.                                                                  break;
  33.                                                 case Reject:
  34.                                                                  break;
  35.                                                 case PS_RDY:
  36.                                                                  break;
  37.                                                 case GetSrcCap:
  38.                                                             MsgID++;
  39.                                                            PD_PHY_STAT.SendingSourceCap = 1;
  40.                                                      break;
  41.                                                 case GetSinkCap:
  42.                                                                  MsgID++;
  43.                                                                  PD_PHY_STAT.SendingSinkCap = 1;         
  44.                                                                  break;
  45.                                           case SourceCap_VDM:
  46.                                                                  break;        
  47.                                                 default :
  48.                                                 break;        
  49.                                         }
  50.                                                 mDelayuS(25);
  51.                                           PD_PHY_STAT.SendingGoodCRC = 1;        //置发送GoodCRC标志位
  52.                                                 PD_PHY_TX_GoodCRC();                                //回复GoodCRC        
  53.                         }        
  54.         }else PD_PHY_RX_INIT();
  55. }
  56.         if ( PIF_TX_END ) {                /*数据包发送完成中断 */
  57.                   PIF_TX_END = 0;
  58.                         if(CCSel == 1){  //发送完成关闭低压
  59.                                 CC1_CTRL &= ~bCC_LVO;        
  60.                         }else if(CCSel == 2){
  61.                          CC2_CTRL &= ~bCC_LVO;        
  62.                         }            
  63.                 if ( PD_PHY_STAT.SendingGoodCRC ==1 ) {                       
  64.                         PD_PHY_STAT.SendingGoodCRC = 0;
  65.                         PD_PROT_ISR(); //GoodCRC发送完成,向Prot转交数据
  66.                 }else {                        /*开始接收GoodCRC*/
  67.                                         PD_PHY_STAT.WaitingGoodCRC = 1;        
  68.                                            mTimer_x_SetData(10000);    //5ms
  69.                                         PD_PHY_RX_INIT();
  70.                 }
  71.         }
  72. }
Sink端的程序编写从一个Request开始,Request请求结构如下:


下面是用CH543编写Request的代码:
  1. void PD_PHY_TX_Request(void)
  2. {
  3.         UINT16 Volt_Value;
  4.   UINT8 temp=0xff;  //pdo 档位
  5.         UINT8 i;
  6.         UINT16 Temp;
  7.         UINT16 Data_H8;
  8.         UINT16 Cur_Temp = 0;
  9.         
  10.         for (i=0;i!=NDORcv;i++)
  11.         {
  12.                         Union_SrcCap = (_Union_SrcCap *)&PD_Source[2+(4*i)];  
  13.                         Data_H8 = (Union_SrcCap->SrcCapStruct.DataH8);
  14.                         if((Data_H8 >> 6 ) == 3)
  15.                         {
  16.                                         PPS_Flag = 1;
  17.                                         printf("\r %d is PPS\n",(UINT16)(i+1));
  18.                         }else{
  19.                                                         Temp = (PD_Source[3+(i<<2)] >> 2)+((PD_Source[4+(i<<2)] & 0x0F)<<6);
  20.                                                         Temp*=50;
  21.                                                         if (Temp <= Volt_Value )
  22.                                                         {
  23.                                                                 if(Temp > Cur_Temp)
  24.                                                                 {
  25.                                                                         Cur_Temp = Temp;
  26.                                                                         temp = i+1;
  27.                                                                 }
  28.                                                         }
  29.                          }
  30.         }
  31.         if(Temp_PDO != temp )
  32.         {
  33.                 printf("No requested voltage! \r\n");
  34.                 printf("Request adjacent voltage! \r\n");
  35.         }
  36.         if(temp != 0xff)
  37.         {
  38.                         UPD_T_SOP = UPD_SOP0;
  39.                         UPD_T_LEN = 6;
  40.                         PD_TX_BUF[5] =( (temp<<4) | 0x02);
  41.                         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);
  42.                         PD_TX_BUF[3] =(PD_Source[3+((temp - 1)<<2)]&0x03) | (PD_Source[2+((temp - 1)<<2)]<<2);
  43.                         PD_TX_BUF[2] = PD_Source[2+((temp - 1)<<2)];
  44.                         PD_TX_BUF[1] = (0x10 | (MsgID << 1));
  45.                         PD_TX_BUF[0] =0x02 | (0xC0 & PD_Source[0]);
  46.                         PD_PHY_TX_INIT();
  47.         }else{        
  48.           printf("No Matched Volt.\r\n");
  49.         }
  50. }

按照PD的协商流程,可以完成PD通讯。另外在工程中增加了I/O中断来调节电压档位升降:
主程序内循环检测:
  1. if(Gears_Plus == 1)
  2.         {
  3.      if(P1_5 == 1)
  4.                  {
  5.                          PD_Request_Gears += 1;
  6.                          Gears_Plus = 0;
  7.                  }
  8.                 if(PD_Request_Gears>5)        
  9.                  {
  10.       PD_Request_Gears = 1;
  11.                  }                        
  12.         }
  13.         if(Gears_Sub == 1)
  14.         {
  15.                  if(P1_4 == 1)
  16.                  {
  17.                          PD_Request_Gears -= 1;
  18.                          Gears_Sub = 0;
  19.                  }
  20.      if(PD_Request_Gears<1)        
  21.                  {
  22.       PD_Request_Gears = 5;
  23.                  }                        
  24.         }
  25.         if(Temp_PDO !=PD_Request_Gears)
  26.         {
  27.                 Temp_PDO = PD_Request_Gears;

  28.                 printf("Temp_PDO == %d\r\n",(UINT16)Temp_PDO);
  29.                 PD_PHY_TX_Request();
  30.         }



通过逻辑分析仪观察,PD的SINK通讯成功!


当主机发来Source Cap后,设备端点按照PD协议流程进行响应并回复Request,直到主机发送PS_RDY 结束一次PD请求调压过程,然后设备端点可以多次发送Request来请求新的电压,从上图中可以看出,多次请求成功!

至此PD Sink端的应用升降电压就实现了,另外要实现PPS调压还需要完善程序代码(PPS和固定档位的PDO处理方法有一定区别),后面会找时间继续。附件是硬件、软件资料,小伙伴们可以按需下载。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

打赏榜单

lixiaojun1 打赏了 5.00 元 2023-12-25
理由:谢谢博主指导

评论

楼主您好,请问最新的资料,可以分享下吗  发表于 2022-10-17 08:59
[url=home.php?mod=space&uid=3379680]@wang159357[/url] :CS957914743  发表于 2022-10-9 13:08
[url=home.php?mod=space&uid=3335184]@Liuhl1998[/url] :您好,请问有最新的代码吗,怎么联系您呢  发表于 2022-10-9 11:12
[url=home.php?mod=space&uid=3379680]@wang159357[/url] :默认5V哈,需要触发  发表于 2022-10-9 10:54
我用数据线把你的CH543 PD文件的hex烧录进板子,再用万用表测电压,只有5v左右不动的电压,并没有诱骗成功啊  发表于 2022-8-22 15:42
楼主你好,能否给个联系方式,我有事想咨询一下,谢谢  发表于 2022-8-2 11:33
看完我就懂了,原来我差的是个脑子  发表于 2022-3-20 19:54
 楼主| Liuhl1998 发表于 2022-3-16 16:34 | 显示全部楼层
本帖最后由 Liuhl1998 于 2022-3-18 18:33 编辑

叙述的是大概流程,想要深入了解的可以参考www.usb.org 下载PD协议相关手册。

评论

楼主你好,能否给个联系方式,有事想咨询一下,谢谢  发表于 2022-8-2 11:34
cjseng 发表于 2022-3-18 15:36 | 显示全部楼层
楼主很厉害,不错
ahongW 发表于 2022-3-18 17:32 | 显示全部楼层
看完了感觉很神秘!
吃一颗草莓莓 发表于 2022-3-20 20:02 | 显示全部楼层
我不允许这篇贴还没有人看到!写得太好了吧!
ughbss 发表于 2022-3-22 13:42 | 显示全部楼层
有空我也研究下PD
 楼主| Liuhl1998 发表于 2022-3-23 10:04 | 显示全部楼层
 楼主| Liuhl1998 发表于 2022-3-23 10:05 | 显示全部楼层
ughbss 发表于 2022-3-22 13:42
有空我也研究下PD

我这有好多资料,需要时候扣我

评论

[url=home.php?mod=space&uid=3355042]@zengzh[/url] :附件里有源码哈  发表于 2023-4-12 18:38
邮箱:1686374074[url=home.php?mod=space&uid=752448]@qq.com[/url]  发表于 2023-2-2 10:53
[url=home.php?mod=space&uid=3355042]@zengzh[/url] :邮箱:1686374074[url=home.php?mod=space&uid=752448]@qq.com[/url]  发表于 2023-2-2 10:48
楼主,您这边的PD快充的资料可以发我一份吗,我最近在学习PD快充协议,非常感谢!  发表于 2023-2-2 10:48
[url=home.php?mod=space&uid=3379680]@wang159357[/url] :需要资料?  发表于 2022-10-9 13:09
发表于 2022-10-9 11:13
 楼主| Liuhl1998 发表于 2022-3-23 10:06 | 显示全部楼层
ahongW 发表于 2022-3-18 17:32
看完了感觉很神秘!

为了篇幅 精简,牺牲了内容。
pq113_6 发表于 2022-3-25 16:15 | 显示全部楼层
CH549应该也支持吧?官方资料有点少,讲的不清楚,是不是要用到库?

评论

回头研究下  发表于 2022-4-6 16:33
 楼主| Liuhl1998 发表于 2022-4-11 10:01 | 显示全部楼层
playxzy 发表于 2022-4-13 15:17 | 显示全部楼层
学习了
mainch 发表于 2022-5-23 14:25 | 显示全部楼层
谢谢楼主,有用的东西
 楼主| Liuhl1998 发表于 2022-7-21 14:51 | 显示全部楼层
有最新代码   需要的说一声

评论

[url=home.php?mod=space&uid=3379680]@wang159357[/url] :联系方式 ??  发表于 2022-10-9 13:09
我想要,楼主怎么联系  发表于 2022-10-9 10:17
dryy 发表于 2022-7-29 20:31 | 显示全部楼层
Liuhl1998 发表于 2022-7-21 14:51
有最新代码   需要的说一声

楼主请问有协议层代码可以分享一下吗
zwsam 发表于 2022-8-8 09:13 | 显示全部楼层
 楼主| Liuhl1998 发表于 2022-8-8 17:59 | 显示全部楼层
dryy 发表于 2022-7-29 20:31
楼主请问有协议层代码可以分享一下吗

都在例程里了哈,需要最新的可以私我
 楼主| Liuhl1998 发表于 2022-8-8 17:59 | 显示全部楼层
stb988 发表于 2022-8-23 08:43 | 显示全部楼层
gentlman2006 发表于 2022-8-27 16:50 | 显示全部楼层
请问楼主PPS的实现了吗

评论

[url=home.php?mod=space&uid=1096484]@zou870848836[/url] :联系方式?  发表于 2022-10-17 09:44
[url=home.php?mod=space&uid=3335184]@Liuhl1998[/url] :请问能学习下吗?  发表于 2022-10-11 15:41
实现了  发表于 2022-10-9 10:52
早就实现了  发表于 2022-10-9 10:51
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

109

帖子

33

粉丝
快速回复 在线客服 返回列表 返回顶部