CH567 自动烧写工具

最近我在使用 CH567 制作双 USB 设备,在这个过程中,我发现每次烧写程序都比较麻烦。例如,首先要拔掉设备,然后按下 DOWNLOAD 按键,接下来再插入USB端口中,最后才能烧写(值得庆幸的是我预留了RESET 按钮,否则还要重新插拔一次)。经过研究和实验,我设计了一个能够自动完成烧写的设备。基本原理是:使用芯片模拟USB设备下电过程(断开 D+、D-,再下电);然后通过MOSFET模拟按下DOWNLOAD键(Pin 下拉到GND);再使用芯片模拟USB设备上电过程(先上电,再连接 D+、D-);接下来用户就可以在PC上进行烧写;最后再通过MOSFET模拟RESET 键。烧写好的程序就可以正常运行了。

下面介绍这次用到的两颗主要芯片。首先是用于切换USB 信号(D+、D-)的CH442。它是 DPDT 模拟开关芯片,包含 2 路单刀双掷二选一开关。CH442 是CH44X 系列芯片的一款。这一系列是模拟开关芯片,具有高带宽,支持视频信号,支持低速、全速和高速 USB 信号的特点。

另外一个是 SY6280AAC芯片,用于控制 USB母头(连接CH567)的 USB 供电。

这次使用的主控为 DFRbot 出品的 FireBeetle,他的核心是 ESP32。实际上主要功能是通过GPIO来实现的,要求不高,有需要的朋友可以修改为任意的单片机。

最终电路图设计如下:

主控部分需要注意的是预留了一个跳线位置,必要时将此短接起来FireBeetle可以直接从USB1取电(例如,FireBeetle支持蓝牙,可以修改代码为蓝牙控制触发 CH567进去下载模式)。

下面是2个GPIO 通过MOSFET控制的RST和 PowerDown 引脚。没有触发时,RST和PWDPIN会出现3.3V,当有需要时可以拉低到GND。

接下来是USB接口和用于切换的CH442E 芯片,USB1 是USB公头,接入电脑中;USB3 是USB母头,用于连接CH567。CH442E控制USB1 的 USB信号(IN_D-、IN+D+)在USB3(DB、DC)和断开(S2B、S2C)之间切换。

最后是SY6280AA芯片,UPW_CTRL 控制IN_VCC 是否输出到 OUT_VCC 上。

这个设计是给FireBeetle 的Shield,最终的PCB 如下:

焊接之后照片如下,右侧是 DFRobot的FireBeetle,二者可以通过堆叠的方式进行连接。

完整代码如下:

#define PWD_CTRL 22
#define EN_CTRL  27
#define RST_CTRL 21
#define UPW_CTRL 14
#define IN_CTRL 26

void setup() {
  Serial.begin(115200);
  pinMode(PWD_CTRL, OUTPUT);
  pinMode(EN_CTRL, OUTPUT);
  pinMode(RST_CTRL, OUTPUT);
  pinMode(UPW_CTRL, OUTPUT);
  pinMode(IN_CTRL, OUTPUT);

  digitalWrite(PWD_CTRL, LOW);
  digitalWrite(EN_CTRL, LOW);
  digitalWrite(RST_CTRL, LOW);
  digitalWrite(UPW_CTRL, LOW);
  digitalWrite(IN_CTRL, LOW);

}

void unplug() {
  // USB1和USB3断开
  digitalWrite(IN_CTRL, LOW);
  Serial.print(IN_CTRL);
  Serial.println("IN_CTRL  LOW");

  // CH567 断开5V
  digitalWrite(UPW_CTRL, LOW);
  Serial.print(UPW_CTRL);
  Serial.println("UPW_CTRL  LOW");
  delay(20);
}

void plug() {
  // CH567 上电
  digitalWrite(UPW_CTRL, HIGH);
  Serial.print(UPW_CTRL);
  Serial.println("UPW_CTRL  HIGH");
  delay(20);

  // USB1和USB3连通
  digitalWrite(IN_CTRL, LOW);
  Serial.print(IN_CTRL);
  Serial.println("IN_CTRL  HIGH");
}

void loop() {
  if (Serial.available()) {
    byte c = Serial.read();
    // 按下 PowerDown
    if (c == 'd') {
      Serial.println("Press Power Down");
      // 按下 PowerDown 键
      digitalWrite(PWD_CTRL, HIGH);
      Serial.println("PWD_CTRL  HIGH");
    }
    // 抬起 PowerDown
    if (c == 'u') {
      Serial.println("Release Power Down");
      //抬起 PowerDown 键
      digitalWrite(PWD_CTRL, LOW);
      Serial.println("PWD_CTRL  HIGH");
    }

    // 按下抬起一次 RESET键
    if (c == 'r') {
      Serial.println("Press and Release RESET");
      //按下 RESET 键
      digitalWrite(RST_CTRL, HIGH);
      Serial.println("RST_CTRL  HIGH");
      delay(20);
      //抬起 PowerDown 键
      digitalWrite(RST_CTRL, LOW);
      Serial.println("RST_CTRL  LOW");
    }    
    // 模拟断开CH567 
    if (c == 'u') {
      Serial.println("unplug");
      unplug();
    }
    // 模拟插入CH567 
    if (c == 'p') {
      Serial.println("plug");
      plug();
    }    
  }
}

使用方法是通过串口接收指令,代码定义了如下五个动作:

1."d" 按下 PowerDown键

2."f" 抬起 PowerDown键

3."r" 按下然后抬起 RESET键

4."u" 模拟断开 USB 母头设备

5."p" 模拟插入 USB 母头设备

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注