Send serial message before programming

I’m working on a custom board, it’s compatible with the Arduino bootloader (in fact, I can program it within PlatformIO) but I have to reset the board sending a specific serial message.

Is it possible to configure this in PlatformIO / avrdude? The baudrate it the same of the bootloader, I just have to send this string, wait some ms and then the bootloader will be available.

Yes, with a pre action for the upload target you can execute whatever logic you want before upload. This is documented.

You can use env.subst("$UPLOAD_PORT") to get the serial port used by PlatformIO as the upload port, open it using the pyserial library, send data to it and close the port again.

2 Likes

Thanks! I’m almost there. I wrote this pre-script:

Import("env")
import serial

def before_upload(source, target, env):
    print("Reset board")    
    ser = serial.Serial(env.subst("$UPLOAD_PORT"))
    msg = "$LED,0,RST*28\r\n"
    ser.write(msg.encode())
    ser.close()

env.AddPreAction("upload", before_upload)

And this is my platformio.ini file:

[env:leonardo]
platform = atmelavr
board = leonardo
framework = arduino
board_build.f_cpu = 8000000L
build_flags = -Wl,-Map,output.map
lib_deps =
  septillion-git/FadeLed@^1.6.0
upload_protocol = arduino
upload_port = /dev/ttyUSB0
upload_speed = 9600
board_upload.wait_for_upload_port = false
board_upload.use_1200bps_touch = no
extra_scripts = pre:reset.py

It is executed before the upload, but it does something odd because avrdude cannot upload the firmware and the application does not work anymore. Even a power cycle does not restore the situation. I have to burn again the bootloader via ISP.

Instead, sending the same string above using a serial terminal and uploading the firmware from PlatformIO works fine, so there’s something wrong in my script here.

Do you see any evidence of errors?

This uses a default baud of 9600, which seems to be correct based on your upload_speed, but it may still be better to specify baudrate=9600.

Do you see the device returning to bootloader mode at all? Doesn’t that create a new COM port and thus invalidate the old COM port PlatformIO found before?

Do you have timing restrictions in the bootloader where after the starting the bootloader, you must talk to the bootloader with in the next x milliseconds?

After the .write(), you might want to call ser.flush().

I’m going to follow your advices and I’ll come back with a feedback, thanks.
In the meanwhile: I’m not sure 100% it comes back to the bootloader but surely the application does not run anymore.

Why it should create a new COM port? Oh wait, I’m not using the USB serial! It’s a plain UART with an external TTL-USB converter. Hence I disabled the waiting for the new port.

I changed the Optiboot defaults and it wait 4 seconds at boot before run the application, so there’s plenty of time.