bouffalolab / bouffalo_sdk

BouffaloSDK is the IOT and MCU software development kit provided by the Bouffalo Lab Team, supports all the series of Bouffalo chips. Also it is the combination of bl_mcu_sdk and bl_iot_sdk
Apache License 2.0
372 stars 128 forks source link

How to control bl616 boot/en from dtr and rts #200

Open harbaum opened 9 months ago

harbaum commented 9 months ago

It seems the cube software drives the dtr and rts signals of the uart while flashing in order to enable the bootloader. How are rts and dtr to be used to drive boot and en to allow flashing the bl616 without the need to press these buttons manually?

It seems the bl616 development board supports this. Are the schematics of that board available somewhere?

gamelaster commented 9 months ago

image

This is from BL602, so modify Boot IO pin accordingly. Although. this mechanism have flaws (note that Linux and Windows changes states of DTR / RTS when opened).

harbaum commented 9 months ago

Have you actually tried that?

The cube software drives rts and dtr both low during the flash programming itself. The variant you showed would keep the cpu in reset during that which obviously won't work.

I have actually tried all kinds of variants incl. this and none worked.

gamelaster commented 9 months ago

I use this on BL602 devices, and it works.

harbaum commented 9 months ago

Under Windows or Linux?

harbaum commented 9 months ago

One interesting fact is that the Ai-M62-12F-Kit includes something like that. But it's not populated on the boards I own. I was expecting some logic similar to the one found on ESP32 boards.

gamelaster commented 9 months ago

Should work both on Windows and Linux.

Ai M62-12F-Kit contains the ordinary ESP32 circuit, but as you mentioned, it is not populated. But from what I remember, I had mounted Reset resistors, but not BOOT_PIN.

Sorry for vague answers, don't have boards and stuff at hand right now, but if you couldn't figure out, I can check for you.

harbaum commented 9 months ago

I should perhaps give some more context. I am using this with the M0S Dock. This has a BOOT button but no Reset button and thus needs to be power-cycled to go into boot mode. So far I have connected these to a CP2102 UART with DTR connected via a capacitor to EN. That way the falling edge of DTR gives a short negative pulse and resets the device. So a download now only involves to press the BOOT button and start the download software. This will open the port, raise DTR, the first attempt so sync will fail, the connection is closed, the DTR deasserted. This triggers a reset and since BOOT is pressed the device goes into bootloader. The software will retry, find the device in bootloader, and the download works. So far so good. The only downside is that I still need to manually press the BOOT button to pull the BOOT pin high. I was unable to achieve this with DTR and/or RTS.

Then it occurred to me that I can use another M0S instead of a CP2102. This gives me full control over BOOT and EN. And since I can debug the M0S itself, I can make it log the RTS/DTR states the software tries to use.

      idle     terminal runs      idle
            ______          ___
DTR   _____/                   \______
               ______          ___
RTS   ________/                   \___

Both, DTR and RTS are low when the port is closed and high when the terminal runs.

The cube software does this:

      idle                               sync attempt   idle 
            ____
DTR   _____/    \___________________________________________
               ___     ___        ___    
RTS   ________/   \___/   \_...__/   \______________________

So both, DTR and RTS return to 0 and then RTS pulses for five times before the software sends 300 0x55 bytes at 500kbit/s to initiate the communication. This is retried max four times.

If that's successful, it closes the connection and reopens it regularly at the requested baud rate.

And now I am trying to make the m0s detect this and do the whole reset/boot magic for the second m0s it's meant to download.

I can of course do some more magic. I e.g. know that only the cube programmer will set the baud rate for 500kBit/s and that afterward, the port is opened a second time for programming. I could use these baud rate changes to control en/boot and completely ignore DTR and RTS.

I could then also add a second "magic" baud rate that simply resets the target without entering bootloader. Actually the Arduino Leonardo does this. When the link is opened at 1200 bit/s then it enters boot loader. This is the magic you can do when you have full control over the USB uart port.

harbaum commented 9 months ago

I use this on BL602 devices, and it works.

I think I understand how this works for you. It works for download only, correct?

If you open a regular terminal program to e.g. see console or debug output then your solution will imho by default (without explicitly caring for dtr and rts) put the device into reset while the terminal is open. Is this the case?

I'd like to add some more logic that will allow to use regular terminal software without special care.

gamelaster commented 9 months ago

I think I understand how this works for you. It works for download only, correct?

Exactly correct. The Linux terminal behavior will put the chip into reset. Bouffalo Lab DevCube will pull RTS down, when you open terminal because of this. This is why I said in my first comment that it is flawed :sweat: (Espressif find out clever way how re-use RTS and DTR in manner, that serial convertor still can toggle flash mode, but also the chip works just fine with or without the terminal on, sadly, the circuit can be bit more complex as level signals on Bouffalo chips are different)

I used Ai-Thinker module for some of my stuff, and I solved it by this simple python UART viewer:

import time

import serial
import sys
import os
import threading

def read_serial(serial_port):
    while True:
        try:
            data = serial_port.read(2048).decode('utf-8', errors='ignore')
            if data:
                sys.stdout.write(data)
                sys.stdout.flush()
        except Exception as e:
            print(f"Error reading from serial port: {e}")
            break

def write_serial(serial_port):
    while True:
        try:
            data = sys.stdin.read(1)
            serial_port.write(data.encode('utf-8'))
        except Exception as e:
            print(f"Error writing to serial port: {e}")
            break

if len(sys.argv) != 2:
    print("Usage: python serial_pipe.py <serial_port_path>")
    sys.exit(1)

serial_port_path = sys.argv[1]

try:
    serial_port = serial.Serial(serial_port_path, baudrate=2000000, timeout=0.01)
    serial_port.setRTS(False)  # Set RTS to low

    # Create two threads for reading from and writing to the serial port
    read_thread = threading.Thread(target=read_serial, args=(serial_port,))
    write_thread = threading.Thread(target=write_serial, args=(serial_port,))

    read_thread.start()
    write_thread.start()

    read_thread.join()
    write_thread.join()

except serial.SerialException as e:
    print(f"Error opening the serial port: {e}")
except KeyboardInterrupt:
    pass
finally:
    if serial_port:
        serial_port.close()
harbaum commented 9 months ago

I am now using a Sipeed M0S Dock as a bl616 debugger (actually for a second M0S dock). So I am basically flashing the BL616 using another BL616. There's a little logic included to the control over EN and BOOT, so that the upload is fully automatic and any regular terminal software is still usable:

https://github.com/harbaum/MiSTeryNano/tree/main/bl616/m0s_debugger

This basically detects the pattern the flash cube software uses to switch into bootloader mode. It then monitors for UART activity and once there's at least one second of silence it assumes the flash has succeeded and returns the device into normal operation.

gamelaster commented 9 months ago

Well done @harbaum , I like it, thanks for sharing :)

harbaum commented 9 months ago

I am now convincing Sipeed to expose the BOOT and EN signals on the M0S like they already do with the serial RX and TX. This will reduce the level of soldering skills required to do this.