First steps with Optiboot and ATmega32U4

I downloaded the master branch of optiboot and I successfully compiled with:

make atmega32u4 AVR_FREQ=8000000L BAUD_RATE=9600 LED=B7 BIGBOOT=1 RS485=D4

then I burned the bootloader into my MCU:

avrdude -v -p atmega32u4 -B 250kHz -C /home/mark/.platformio/packages/tool-avrdude/avrdude.conf -e -c atmelice_isp -D -P usb -U lfuse:w:0xff:m -U hfuse:w:0xd8:m -U efuse:w:0xcb:m
avrdude -v -p atmega32u4 -B 250kHz -C /home/mark/.platformio/packages/tool-avrdude/avrdude.conf -e -c atmelice_isp -D -P usb -U flash:w:optiboot/optiboot/bootloaders/optiboot/optiboot_atmega32u4_UART1_9600_8000000L_BB1.hex:i

with no errors.
I prepared my test firmware and compiled in Visual Studio Code to have the hex file.

Note: as first test I by-passed the RS485 transceiver, so I'm connected directly to the MCU using a TTL-USB serial converter (that works fine).

Hence I tried to download the firmware with:

avrdude -v -p atmega32u4 -b 9600 -C /home/mark/.platformio/packages/tool-avrdude avrdude.conf -e -c arduino -D -P /dev/ttyUSB0 -U flash:w:.pio/build/leonardo/firmware.hex:i

but nothing happens:

avrdude: Version 7.0-20220530 (feaa1c6)
         Copyright (c) Brian Dean, http://www.bdmicro.com/
         Copyright (c) Joerg Wunsch

         System wide configuration file is "/home/mark/.platformio/packages/tool-avrdude/avrdude.conf"
         User configuration file is "/home/mark/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/ttyUSB0
         Using Programmer              : arduino
         Overriding Baud Rate          : 9600
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x00
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00
avrdude: opening programmer "arduino" on port "/dev/ttyUSB0" failed

avrdude done.  Thank you.

I was expecting it should work out of the box, at least without the RS485 feature.
Is there anything I can do to understand what's happening?

Here the schematic:

As said, right now I'm connected to PD2 and PD3 directly.

Update: removing the RS485=D4 argument it works fine. At least just once after burning the bootloader. I cannot download the firmware anymore, after that.
What could rise such an issue if the enable pin is not used at all?

Not sure if this is going to help.

How do you reset the 32U4 before (or as first step of) doing an upload?

Leonardo code contains (outside your sight) a piece of code to handle a reset "command" on the serial port. This is done by opening and closing the serial port with a baudrate of 1200 baud.

You're right when I invoke avrdude from command line. But when I use Visual Studio Code with PlatformIO it tries to reset the port using the 1200 baud trick, but in any case it works only the first time after burning the bootloader. Even a power cycle (that should allow 1 s inside the bootloader) does not work.

Anyway, some progresses.
I connected the RS485 transceiver and I put this line just after the main loop in the Optiboot code:

putch('U')

and I checked I can receive the chars in a serial terminal. Hence both the hardware and the connections work fine as expected. I also checked the baudrate with an oscilloscope to be sure.
I had to add the polarization resistors because the cheap RS485 to USB converter don't have them.

Still when I try to download the firmware via RS485 I get:

         Programmer Type : Arduino
         Description     : Arduino
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_recv(): programmer is not responding
         Hardware Version: 9600
         Firmware Version: 8.32703

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_recv(): programmer is not responding
avrdude: initialization failed, rc=-1
avrdude: AVR device initialized and ready to accept instructions
avrdude: Device signature = 0x869a17
avrdude: Expected signature for ATmega32U4 is 1E 95 87

avrdude done.  Thank you.

I bet the wrong signature is due to some communication error.
But the hardware is ok, if I burn my firmware using ISP I can communicate with my board without any problem.

Going ahead...

I guess the problem is how they handle the enable pin of RS485:

#ifdef RS485
  uint8_t x;
  do {
    x = UART_SRA;
  } while (!(x & _BV(UDRE0)));
  // clear transmitted flag
  x |= _BV(TXC0);
  UART_SRA = x;
  // put transceiver to output mode
# ifdef RS485_INVERT
  RS485_PORT &= ~_BV(RS485_BIT);
# else
  RS485_PORT |= _BV(RS485_BIT);
# endif  
  // put char
  UART_UDR = ch;
  // wait for char transmitted
  while (!(UART_SRA & _BV(TXC0))) {  /* Spin */ }
  // put transceiver to input mode
# ifdef RS485_INVERT
  RS485_PORT |= _BV(RS485_BIT);
# else
  RS485_PORT &= ~_BV(RS485_BIT);
# endif

Between the rising of the enable pin and the actual transmission there is no delay! It takes just a clock cycle for an AVR to rise a pin. Usually, in my own board, I add a small delay between these actions. And not byte-per-byte, but after the whole packet is sent.

I tried to add a delay:

for (uint16_t delay = 10000; delay; delay--);

without luck, but using a software uart (SOFT_UART=1) it almost completes the downloads even if usually stops with a wrong data:

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: erasing chip
avrdude: reading input file ".pio/build/leonardo/firmware.hex"
avrdude: writing flash (11374 bytes):

Writing | ################################################## | 100% 15.65s

avrdude: 11374 bytes of flash written
avrdude: verifying flash memory against .pio/build/leonardo/firmware.hex:
avrdude: load data flash data from input file .pio/build/leonardo/firmware.hex:
avrdude: input file .pio/build/leonardo/firmware.hex contains 11374 bytes
avrdude: reading on-chip flash data:

Reading | #########################################          | 82% 11.67savrdude: stk500_loadaddr(): (a) protocol error, expect=0x14, resp=0x84

avrdude: stk500_paged_load(): (a) protocol error, expect=0x14, resp=0x10
Reading | ##########################################         | 83% 11.69savrdude: stk500_cmd(): programmer is out of sync
avr_read(): error reading address 0x0000
    read operation not supported for memory "flash"
avrdude: failed to read all of flash memory, rc=-2
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x19

But without the delay it barely reaches the 2-3% of writing.
In any case there must be something else to fix here.

Any idea is appreciated.

The 1200bps trick only works with the USB bootloader, not optiboot.

The rs485 support in optiboot is pretty primitive and questionable. Someone wrote the basic code, and I added the makefile hacks. But I expect it only works in rather limited cases (for which I don’t have examples.)

Gcc will optimize away empty loops, which is why your added delay code didn’t help.

Thanks. So what do you recommend? Is there any other available bootloader for m32u4 that supports RS485? If I had time to experiment a little further, how can I try to add a working delay?

It should result in a reset of the 32U4, shouldn't it? To my knowledge, that is part of the uploaded application. And as a result, optiboot should be running.

Hmm. The sketch will probably do the reset, but I’m not sure that optiboot will properly enter bootloader mode when it see the type of reset that the sketch causes…

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.