Upcycling a controller board to be "an Arduino"

I've got a controller+LCD board here, originally from a washing machine, which I'm hoping to eventually put into a produce drier to control heater and fan. It's based on an ATMEGA649V, which AvrDude wants to call "atmega649".

I've successfully built Optiboot, although I had to disable EEPROM support since the AVR compiler shipped by Debian lacks the relevant library. I've added 4MHz support and tweaked the load address to be 0xfe00. I can load the resulting .hex onto the processor using a USBASP programmer.

The sense of the reset signal is inverted, so I've modified AvrDude such that the arduino/serial protocol drives DTR in the opposite sense. At that point I can talk to the bootloader using either USBASP or Arduino protocol and can verify that memory below 0xfe00 is unprogrammed.

With the help of Juraj, I've installed the various target-specific files into ~/Arduino, and can build and load sketches into the board. I've fitted an LED onto B5 and it flashes as expected: three times when the bootloader starts up, and twice every second if the test script is running.

When only the bootloader's in Flash I get a triple-flash roughly every second: my understanding is that that's what's expected since when it tries to transfer control to a sketch it rolls all the way up memory until it's back in the bootloader and repeats.

If the test sketch is in Flash I get a double-flash every second which is the expected behaviour.

My problem is that once the test sketch is in Flash I can't reset back to the bootloader: either using the serial connection of by grounding the pin. As soon as I release the reset there's roughly a second's pause and then I get a double-flash: never the expected triple-flash.

As part of sorting out the reset polarity and clock speed I wrote a simple program that tried multiple port speeds and DTR polarities, issuing a synchronise command for each and looking for a response. This works fine with an Uno in all cases, or with this board provided that a sketch isn't loaded; however if a sketch is loaded it sees no response which appears to confirm that the bootloader is never being run.

Hfuse is 0xd6, I suspect it should be 0xd4 but in practice I've tried all values of the bottom three bits with no obvious change. This is, obviously, a bit of a pain to fiddle with since I have to connect the USBASP programmer to change the setting followed by a serial converter to test it.

Does anybody have any thoughts as to what my silly mistake is?

MarkMLl

the fuses BOOTSZ1, BOOTSZ0 for bootloader address are right?
did you build a 512 bytes Optiboot or the 1kB BIGBOOT?

I was using Optiboot tailored for that chip from GitHub - MCUdude/ButterflyCore: An Arduino core for the ATmega169, ATmega329 and ATmega649 Initially I got the clockspeed wrong- the resonator is hidden under the LCD and I'd not put a scope on the pins- hence the test program that works through various speeds and both DTR polarities. Once I realised it was 4MHz I added build rules appropriately, I also made sure it was doing a triple-flash at start.

I wasn't able to compile the full BIGBOOT since Debian's AVR compiler doesn't bundle the EEPROM library and I couldn't work out the paths etc. to use one of the Arduino-supplied ones standalone (I spent quite a lot of time trying :slight_smile: I also made sure that the start of the bootloader was at 0xfe00... initially it had been 0xfc00 but had apparently worked which was what drew my attention to the "cycles through all addresses then runs the bootloader" issue.

hflag is 0xd6 from the build process which I interpret as 11 for the BOOTSZ bits, I think those should be 10 but changing them has no apparent effect.

I could obviously just use the USBASP programmer, but I like the convenience of having a serial console and not having to mess around changing hardware connections... besides which, I'm interested to know just what's going wrong.

MarkMLl

serial console doesn’t depend on bootloader.
for 512kB bootloader the BOOTSZ bits should be 11

serial console doesn't depend on bootloader.

True, but I meant that is using a USBASP programmer you don't immediately have access to it... needs an FTDI board, plus a USB hub to make sure that both are powered etc.

I think I might see what's going on. Let's assume to start with that the processor is tolerant of wrong hfuse values since if the sketch is small control will just run up memory until it finds the bootloader (could do with a dummy script to overwrite all the 0xffs).

I'm using ButterflyCore/optiboot_flash.c at master · MCUdude/ButterflyCore · GitHub which is at v6.2, while optiboot/optiboot.c at master · Optiboot/optiboot · GitHub is at 8.1 and (at v7) explicitly sorts out various boot condition issues.

The version I'm using has an early test that looks at the MCUSR register and is inclined to jump to the app without a pause in the bootloader... before flashing the LED, and with nothing output on the serial port which could be used for debugging.

I'm going to stick with 6.2 for the moment in case there's anything in that that explicitly sorts out 649 issues, but investigate rerieving the saved startup reason in r2 and possibly comment out that shortcircuit code.

I'll report back when I know more.

MarkMLl

I'm pretty sure that the combination of that version/variant of Optiboot and that particular board design aren't very happy with each other.

Looking at the saved reset reason, it always interprets a power-up as a brownout reset, and it always interprets a DTR toggle as a watchdog reset, both of which are probably caught by this fragment in Optiboot 6.2:

#if defined (__AVR_ATmega128__) || defined (__AVR_ATmega64__)
  ch = MCUCSR;
  MCUCSR = 0;
#else
  ch = MCUSR;
  MCUSR = 0;
#endif
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
      appStart(ch);

Now at that point I expected that if I commented those last couple of lines out control would stay- at least for a while- inside the bootloader. However what actually happens is that the loader locks up... and it also does that if I move those lines after the point where the UART and watchdog are initialised and the LED told to flash (specifically, the LED does not flash at all... which does not make complete sense).

I suspect that there are multiple problems, possibly including bad watchdog initialisation. It might be that if I move to the newer Optiboot that things will work properly, but I'd need to review the sources to work out whether it makes any attempt at all to support this target.

I'm probably going to drop this particular combination for the moment. It's been a very useful learning exercise, and has moved me quite a long way up the learning curve (how Optiboot is put together, building it, retrieving the reset reason, some of the lesser known GCC facilities that enable that, how to use AvrDude in various ways and so on) but I really have quite a lot of other things that I should be getting on with and I should be able to program this board using a USBASP... and if that doesn't work I'm in a much better position to work out why.

MarkMLl

The sense of the reset signal is inverted,

huh? the datasheet says the RESET is the same active-low as other AVRs...

it always interprets a power-up as a brownout reset

The fact that it's a V (low-voltage) variant implies that it may be running at a lower-than-5V supply. Did you adjust the brown-out level fuse from the normal "4.3V"?

Hfuse is 0xd6, I suspect it should be 0xd4

D6 looks right. AVR® Fuse Calculator – The Engbedded Blog

If you don't need the reset-cause propagation, you can certainly change the startup code in Optiboot.
The only "requirement" is that a WDT reset should start the App.
See the older code in the Arduino branch: ArduinoCore-avr/optiboot.c at master · arduino/ArduinoCore-avr · GitHub

I'd be inclined to increase the timeout to help enable the "manual reset" upload. (hmm. Looks like 2s is the max on a 649, though.)

westfw:
huh? the datasheet says the RESET is the same active-low as other AVRs...

At the chip, yes, but there's external components and I think it's edge- ratehr than level-triggered.

The fact that it's a V (low-voltage) variant implies that it may be running at a lower-than-5V supply. Did you adjust the brown-out level fuse from the normal "4.3V"?

Yes, the various build files result in 2.7v as the default. Part of the problem appears to be that the chip tries to self-pwer on some of the logic signals if Vcc is slow rising.

D6 looks right. AVR® Fuse Calculator – The Engbedded Blog

If you don't need the reset-cause propagation, you can certainly change the startup code in Optiboot.
The only "requirement" is that a WDT reset should start the App.
See the older code in the Arduino branch: ArduinoCore-avr/optiboot.c at master · arduino/ArduinoCore-avr · GitHub

I'd be inclined to increase the timeout to help enable the "manual reset" upload. (hmm. Looks like 2s is the max on a 649, though.)

Thanks for that. It's certainly been an interesting (and useful, and frustrating) exercise, and at least I've arrived at a rational understanding of what's happening even if some details are unclear.

I don't think it's a simple timeout issue, since there's no LED activity. I might try moving watchdog initialisation to after the LED flashes though, at least during development.

I'm just about to modify some of my standard hardware detection code, and will consider adding reset-cause handling at the application level if the OptiBoot version is all-FFs (i.e. no bootloader). I'm not sure that checking hfuse lsb would be adequate by itself.

MarkMLl