TA的每日心情  | 衰 2024-11-15 16:19 | 
|---|
 
  签到天数: 3 天 [LV.2]偶尔看看I 
管理员 
 
	- 积分
 - 2978
 
 
 
 
 | 
 
沁恒微电子最新推出基于青稞RISC-V 内核设计的工业级微控制器CH32X035,CH32X035内置 USB 和 PD PHY,支持 USB Host主机和 USB Device设备功能、USB PD及type C快充功能,内置可编程协议I/O控制器,提供了2 组OPA 运放、3组CMP电压比较器、4组USART串口、I2C、SPI、多组定时器、12位ADC、14 路Touchkey等丰富外设资源。 
 
小编选取了CH32x035G8U6进行了相关应用的开发,例程目前可实现: 
1、Sink端诱骗充电器输出不同的电压、 
 
2、Source端对外给用电设备充电、 
 
3、单C口DRP充放电、 
 
针对三种不同的运行模式,工程中使用了宏定义进行相关功能的配置,仅需设置宏定义 PD_START_MODE 对应的参数值即可启动相关模式。 
 
—————————————————————————————————— 
 
#ifndef  PD_START_MODE 
 
#define  START_SINK            0 
#define  START_SOURCE      1 
#define  START_DRP              2 
#define  PD_START_MODE     START_DRP 
 
#endif 
 
—————————————————————————————————— 
 
例: PD_START_MODE     START_SINK            工程运行Sink模式 
 
        PD_START_MODE     START_SOURCE      工程运行Source模式 
 
        PD_START_MODE     START_DRP              工程运行DRP模式 
 
 
1、CH32x035G8U6-DRP-1V0原理图: 
  
 
 
2、CH32x035G8U6-DRP-1V0 PCB: 
 
  
 
3、PCB工程简介 
       CH32x035的CC引脚内部无5.1K下拉,所以采用外挂的形式来兼容Sink和DRP应用(两者需要5.1K下拉的存在),原理图中使用 PC0 引脚来控制 CC控制端口的下拉电阻 1:开启  0:关闭,后期设计可按需选择控制引脚。使用PC18来VBUS控制端口 MOS的开断  1:开启  0:关闭,(注:这里是我的设计失误,因使用了PC18导致SWD调试无法使用,后期设计需注意规避) 
 
 
  
 
工程文件主要划分为: PD操作函数: 
[url=]复制[/url]  
/* Function extensibility */ 
void PD_Sink_Mode(void);                 /* 设置C口为Sink模式 */ 
void PD_Source_Mode(void);               /* 设置C口为Source模式 */ 
 
void Fill_SrcCap_List(void);             /* 自动填写SourceCap列表,只需设置总功率和档位  */ 
void Fill_Voltage_List(uint8_t VoltTemp);/* 自动填写请求电压让Source端输出电压 */ 
 
 
void Get_CC_Status(void);                /* C口连接检测函数 */ 
uint8_t Get_Sink_Status(void);           /* 获取Sink模式下CC的连接状态 */ 
uint8_t Get_Source_Status(void);         /* 获取Source模式下CC的连接状态 */ 
 
void Set_CMP_Voltage(uint8_t bCC,uint8_t CMP_Volt);/* 设置CC的比较电压 */ 
uint8_t Check_Request_Voltage(void);               /* 检测来源于Sink的请求电压是否符合规范 */ 
 
void PD_Recvd_Message( void );           /* PD物理层接收函数 */ 
void PD_Phy_SendPack(uint8_t SopType,uint8_t MsgLen);/* PD发送包函数 */ 
void PD_Send_Message(uint8_t Extend,uint8_t SopType,uint8_t MsgLen,uint8_t MsgType,uint8_t State,uint8_t LiatState);/*PD物理层发送函数*/ 
 
void PD_Main_Proc( );/* PD 处理函数 */ 
[url=]复制[/url]  
 
/********************************************************************* 
* @fn      USBPD_IRQHandler 
* 
* @brief   PD中断函数. 
* 
* @return  none 
*/ 
void USBPD_IRQHandler(void) 
{ 
    /* HRST复位中断 */ 
    if(USBPD->STATUS & IF_RX_RESET) 
    { 
        USBPD->STATUS |= IF_RX_RESET; 
        /* 需添加CH32X035复位操作,此处未添加*/ 
    } 
    /* 数据消息接收完成中断 */ 
    if(USBPD->STATUS & IF_RX_ACT) 
    { 
        USBPD->STATUS |= IF_RX_ACT;  /*清除中断 */ 
 
        if(( USBPD->STATUS & MASK_PD_STAT ) == PD_RX_SOP0) 
        { 
            if((( PD_Rx_Buf[ 0 ] & 0x1F) == GoodCRC ) && (( PD_Rx_Buf[1] & 0x70) == 0 )) 
            { 
               PD_Ctrl.Basic.Config.RecvGoodCRC = ENABLE; 
            }else{ 
                PD_Ctrl.Basic.Config.SpecRev = PD_Rx_Buf[0]>>6;  /* Get version number */ 
                Delay_Us(30);        /* Delay 30us, answer GoodCRC */ 
                PD_Tx_Buf[ 0 ] = (0x41 | (( PD_Ctrl.Basic.Config.DataRole)<<5)); 
                PD_Tx_Buf[ 1 ] = (( PD_Rx_Buf[ 1 ] & 0x0E ) | ( PD_Ctrl.Basic.Config.PowerRole)); 
                PD_Ctrl.Basic.Config.SendGoodCRC = ENABLE; 
                PD_Phy_SendPack(UPD_SOP0,2); 
            } 
        }else{ 
            PD_Recvd_Message(); 
        } 
    } 
    /*Transmission completion interrupt flag*/ 
    if(USBPD->STATUS & IF_TX_END) 
    { 
        USBPD->STATUS |= IF_TX_END; /* Clear the send interrupt flag */ 
         USBPD-> ORT_CC1 &= ~CC_LV0; 
         USBPD-> ORT_CC2 &= ~CC_LV0; 
         if( PD_Ctrl.Basic.Config.SendGoodCRC) 
         { 
             PD_Ctrl.Basic.Config.SendGoodCRC = DISABLE; 
             PD_Ctrl.Basic.Config.MsgRecvd = ENABLE; 
         } 
         PD_Recvd_Message(); 
    } 
} 
 
 
系统设置函数:[url=]复制[/url]  
 
 
#ifndef USER_SYSTEM_H_ 
#define USER_SYSTEM_H_ 
 
#include "ch32x035.h" 
 
 
 
#define  DebugPrintf   1 
 
 
 
#ifndef  PD_START_MODE 
 
#define  START_SINK        0 
#define  START_SOURCE      1 
#define  START_DRP         2 
 
/*Set the running mode:Source、Sink、DRP*/ 
#define  PD_START_MODE     START_DRP 
 
#endif 
 
 
 
void System_GPIO_Init(void); 
void System_Timer1_Init( u16 arr, u16 psc ); 
void System_PD_Init( void ); 
 
 
 
 
 
#endif /* USER_SYSTEM_H_ */ 
 
 
[url=]复制[/url]  
#include "user_system.h" 
 
/* PC0  CC控制端口         开漏输出       1:开启下拉   0:关闭下拉 
* PC18 VBUS控制端口   推挽输出        1:开启电源   0:关闭电源*/ 
void System_GPIO_Init(void) 
{ 
    GPIO_InitTypeDef GPIO_InitStructure = {0}; 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);               //On PD I/O clock, AFIO clock and PD clock 
 
 
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    GPIO_Init(GPIOC, &GPIO_InitStructure); 
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 
    GPIO_Init(GPIOC, &GPIO_InitStructure); 
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_18; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    GPIO_Init(GPIOC, &GPIO_InitStructure); 
 
} 
 
 
/********************************************************************* 
* @fn      TIM1_Init 
* 
* @brief   Initialize TIM1 
* 
* @return  none 
*/ 
void System_Timer1_Init( u16 arr, u16 psc ) 
{ 
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; 
    NVIC_InitTypeDef NVIC_InitStructure; 
 
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );//时钟使能 
 
    TIM_TimeBaseInitStructure.TIM_Period = arr-1;  //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc-1; //设置用来作为TIMx时钟频率除数的预分频值 
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim 
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;//重复计数设置 
    TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);//根据指定的参数初始化TIMx的时间基数单位 
 
    TIM_ClearITPendingBit( TIM1, TIM_IT_Update ); 
 
    NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;   //TIM3中断 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//从优先级3级 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道被使能 
    NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 
 
    TIM_ITConfig( TIM1, TIM_IT_Update , ENABLE ); //使能指定的TIM3中断,允许更新中断 
 
    TIM_Cmd( TIM1, ENABLE );//使能TIMx 
} 
 
 
/********************************************************************* 
* @fn      System_PD_Init 
* 
* @brief   This function uses to initialize PD Registers. 
* SelMode: 0 sink;1 Source;2 DRP 
* SnkReqVolt:0 、 5 、9 、12 、 15 、20 
* SrcGears:0-7 
* SrcPower :0-60W 
* SrcDetTimer:0-255 
* SnkDetTimer:0-255 
* MainPower:0/1 
* MainData: 0/1 
* PowerStatus: 0/1 
* @return  none 
*/ 
void System_PD_Init( void ) 
{ 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBPD, ENABLE); 
    memset(& D_Ctrl,0,sizeof(PD_Ctrl)); 
    memset( & D_Ctrl.Basic, 0x00, sizeof( BASIC_CONFIG ) ); 
 
#if(PD_START_MODE==START_SINK) 
#if DebugPrintf 
   printf( "System_PD_Init:System operation mode:Sink \n" ); 
#endif 
   PD_Ctrl.Basic.Config.SnkReqVolt = 5;/*Sink、DRP :Set request voltage*/ 
   PD_Sink_Mode();                     /*Set Sink mode*/ 
 
#elif(PD_START_MODE==START_SOURCE) 
#if DebugPrintf 
    printf( "System_PD_Init:System operation mode:Source \n" ); 
#endif 
    PD_Ctrl.Basic.Config.SrcGears = 5;  /*Source、DRP :Set PD Gears*/ 
    PD_Ctrl.Basic.Config.SrcPower = 35; /*Source、DRP :Set PD Power*/ 
    PD_Source_Mode(); 
 
#elif(PD_START_MODE==START_DRP) 
#if DebugPrintf 
    printf( "System_PD_Init:System operation mode RP \n" ); 
#endif 
    PD_Ctrl.Basic.Config.SnkReqVolt = 5;  /*Sink、DRP :Set request voltage*/ 
    PD_Ctrl.Basic.Config.SrcGears = 3;    /*Source、DRP :Set PD Gears*/ 
    PD_Ctrl.Basic.Config.SrcPower = 35;   /*Source、DRP :Set PD Power*/ 
    PD_Ctrl.Basic.Config.SrcDetTimer = 50;/*Source、DRP :Set Source Check Timer*/ 
    PD_Ctrl.Basic.Config.SnkDetTimer = 30;/*Sink、DRP :Set Sink Check Timer*/ 
    PD_Ctrl.Basic.Config.MainPower = 1;   /*DRP :Set Primary power role*/ 
    PD_Ctrl.Basic.Config.MainData = 1;    /*DRP :Set Primary Data role*/ 
    PD_Ctrl.Basic.Config.PowerStatus = 1; /*DRP :Set Current power role*/ 
    PD_Source_Mode(); 
#endif 
    /*Source、DRP :Set the PD version*/ 
    PD_Ctrl.Basic.Config.SpecRev = PD_SpecRev_3v0; 
    /*Source、DRP、SINK :Set the clock for sending and receiving PD:12M、24M、48M*/ 
    PD_Ctrl.Basic.Config.TransFreq = UPD_TMR_TX_48M; 
    PD_Ctrl.Basic.Config.RecvdFreq = UPD_TMR_RX_48M; 
    /*Source、DRP、SINK :Set the power supply voltage for VDD*/ 
    AFIO->CTLR |= USBPD_IN_HVT | USBPD_PHY_V33; 
    PD_Ctrl.State = Sta_DisConnect; 
    PD_Ctrl.Basic.Config.StartDete = ENABLE; 
} 
 
  PD_Ctrl.Basic.Config.SnkReqVolt = 5;即可让充电器输出5V电压(数值可选:5/9/12/15/20) 
    PD_Ctrl.Basic.Config.SrcGears = 3;   设置SourceCap的档位值,3表示一共有3档5/9/12 
    PD_Ctrl.Basic.Config.SrcPower = 35;  设置SourceCap的功率,配合SrcGears求电流 
    PD_Ctrl.Basic.Config.SrcDetTimer = 50;针对DRP检测时Source状态下的检测时间 
    PD_Ctrl.Basic.Config.SnkDetTimer = 30;针对DRP检测时Sink状态下的检测时间 
    PD_Ctrl.Basic.Config.MainPower = 1;  设置DRP运行的主要电源角色 
    PD_Ctrl.Basic.Config.MainData = 1;    设置DRP运行的主要数据角色 
    PD_Ctrl.Basic.Config.PowerStatus = 1; 设置DRP运行时起始的电源角色 
 |   
 
 
 
 |