Wednesday, May 29, 2013

Installing a bootloader on a Sanguinololu (see part 2 for the completion)

While most of the story is described below, part 2 contains the final resolution.

I received my replacement ATMega1284P's from Mouser just before the holiday weekend.  At the same time, I ordered the replacement chips, I ordered a nifty chip puller from Amazon -- it was pretty cheap and with prime, arrived on the same day as the replacement chips.

With everything in hand, I figured this would be a pretty straightforward fix -- boy was I wrong.

I removed the old ATMega from the Sanguinololu board with the chip puller.  I then did something I don't normally do - I thought ahead - and added a sticker to the top of the chip that came out of the socket, that way I can tell it apart from the two new ones... smart eh?

I dropped one of the new ATMegas into the socket and made sure it was correctly seated.  Job done, right, just flash the latest Marlin and off to the races.  Nope - the Arduino IDE would not connect to the Sanguinololu board.  The USB device showed up, but it would never connect.  A little digging on the internet and I discovered that a factory new ATMega1284P does not have a 'boot loader' already installed.  With out the bootloader it's not possible for the Arduino IDE to communicate with the chip over USB.

In order to install a bootloader, I needed to program the chip with a ISP (In System Programming) programmer.  From what I could see, I could buy something that would do the job for me, or I could use another Arduino board to act as an ISP device.  I chose the latter option.

To make this work, connect your Arduino board to your computer and from the Arduino IDE, select File | Examples | ArduinoISP -- this will load a sketch that you can send to your arduino board and let it behave as an ISP device.

From within the loaded sketch, you can see which pins will be used for which purpose.  I was using a Mega2560 board, so the SPI pins where 50,51,52, & 53.


Using jumpers, I connected the Mega2560 directly to the small expansion header labeled SPI/ISP on the Sanguinololu board as indicated below:



The 3 SPI pins and the Reset pin all connect to sockets on the large double rowed digital socket on the ATMega.  I used the ground connection at the end of this connector, along with the 5V pin from the power socket.

I also wired 3 LEDs (as suggested by the Sketch) through a common resistor to ground, with the anode of each LED connected to a single pin on the PWM socket block (7,8, and 9).  The LED connected to pin 9 will pulse off and on when the ISP sketch is running on the ATMega.

Also, when the ATMega resets, each LED will blink quickly in series before settling to the heartbeat pulse.  With this you can see when the ATMega resets, as the 3 LEDs will quickly blink shortly after reset - this turned out to be important.



With everything wired up (and the Sanguinololu disconnected from everything but the Arduino ISP) I had my heart pulse LED, my power LEDs on the ATMega and the power LED on the Sanguinololu all lit up.

Now with the Arduino IDE, I selected the board type as Sanguino w/ATmega1284P 16Mhz and kept the serial port the same as previously.

This is an important note - at this time, you are selecting the type of chip you are installing the bootloader on to, but the serial port is the port the Arduino ISP is connected to.  Only the Arduino is connected to the computer.

<At this point, I suggest you read the section below on modifying your boards.txt file, and don't plough on like I did, only to discover it doesn't work exactly as you want it to>

Now from the Tools menu of the Arduino IDE select Tools | Programmer | Arduino as ISP.

With that done, select the Burn Bootloader from the Tools menu.  This will start burning the selected bootloader onto the ATmega1284p that's connected via SPI to the Arduino board.

It will take a few minutes and you'll see the LEDs you connected to the Arduino flash as the sketch and Arduino IDE do their work.

When complete, the Arduino IDE will indicate success and the heartbeat LED will be pulsing again.  At this point the ATmega1284p will now have the new bootloader installed and you'll be able to upload the printer firmware.

This is where I ran into problems, and hopefully if you're reading this then you can avoid the extra hours of headache I had trying to figure this out...

So it turns out that the default bootloader settings include default FUSE settings.  I've learnt that in micro-controller speak, FUSEs are not what you'd find protecting your toaster oven from setting fire to your kitchen, and that these FUSEs can be 'blown' and then un-blown.  In fact, FUSE is pretty much a crappy name for these things -- if anything they're just a few extra bytes of EEPROM or NVRAM, basically you use them to configure the chip with the ISP.

Furthermore, the ATMega1284P maps the JTAG port onto the GPIO C port when JTAG is enabled, and the C port standard GPIO functions are disabled.  The default FUSE settings leave the JTAG enabled, so your printer firmware will not work.  The axis endstops and x-axis direction pin all share space with the JTAG.  In order to make this work for a printer configuration, you'll need to update your FUSE settings.

The easiest way to do this is to reconnect everything as before so the Arduino is setup to act as a ISP device for the ATMega in the Sanguino board.  However, before programming the device, you should modify boards.txt and update the FUSE settings as follows:
  • low fuse = 0xD7
  • high fuse = 0xDC
  • extended fuse = 0xFD

You'll find boards.txt in the Sanguino folder under hardware.  Go to the bottom of the file and change:

atmega1284.bootloader.high_fuses=0x9A to atmega1284.bootloader.high_fuses=0xDC

This will set bit 6 of the high fuse, which will in turn disable the JTAG function and return port C to your control.

Initially, I investigated the FUSE settings using AVRdude, a command line program that lets you talk to the Arduino and see what's going on under the hood.  For some reason, I had a hard time getting this to work with my Mac, but it worked fine on Windows 7, though this required stopping the auto-reset.

On an Arduino, when you connect to the USB serial port, the device will normally reset.  This was causing the AVRdude problems connecting to the ATMega.  I solved this by connecting a 10uF capacitor between ground and reset (pin 3 on the power connector socket).  This basically acted as a low pass filter stopping the reset pin from going low.

Now when I connected with AVRdude, the ATMega didn't reset and things seemed to work.  One other magic ingredient was the inclusion of '-b 19200' as a parameter.  This allowed AVRdude to actually talk with the Arduino using the serial speed that was set in the ArduinoISP sketch.

I was able to set the FUSE with the following command:


avrdude -p m1284p -c arduino -P com6 -v -b 19200 -U hfuse:w:0xDC:m

-p for the part we're trying to program (a ATMega1284p in this case)
-c for the ISP programmer (an Arduino here)
-P for the com port
-v for verbose mode, so you can see what's going on
-b to set the baud rate (really important!!!)
-U is the actual write command to update the high-fuse.

If you want to test the connection from AVRdude to your target chip, you can leave off the -U and add a -n which will just give you info on the connection but not perform any writes.

Anyway, after sending that command I got the following output:



While this worked, and I was able to get the printer firmware up and running, I'd recommend editing the boards.txt file and setting the hfuse value before the initial flash.

Some photos of the wiring I ended up with:

LEDs, Sanguino & Mega2560
Sanguinololu ISP connection
  
Mega2560 ISP connection
Mega2560 Reset Circuit

Close up of Mega Power connection (white line is reset)

Update:  When I actually tried the board in my printer, it didn't work as expected - Repetier Host was getting a lot of comms errors - I tried messing with the baud rate, and no luck.  Did some more searching and discovered that the FUSE settings I had didn't take the crystal clock into account correctly.  I decided to re-plug in the old working ATMega1284P chip (the one with the dodgy X/Y endstops) and read the FUSE settings from that.  Here's what I got:


As you can see, this is different from what I'd set -- similar, but not the same.  Looking at these bits and the ATmega1284p data sheet, I see the following changes:

For the low fuse: I had a 0xFF and it should be a 0xD7.   This means bits 5 & 3 should be reset. Bit 5 along with bit 4 control the startup time (SUT1,SUT0), while bits 3..0 (CKSEL3...CKSEL0) control the clock source.  In this case a startup-time of 01B with a clock select of 0111B configures the ATMega for a full swing crystal oscillator (which is what is on the sanguinololu board).

For the high fuse: I had 0xDA and it was 0xDC.  In this case, bit 2 is set and bit 1 is reset.  This controls the Boot Size, and while I didn't notice anything different I set it to the previous setting just to be careful.

For the extended fuse: I had 0xFF and it was 0xFD, basically bit should be reset.  This controls the brown out detection level and I did notice a warning when connecting to the Sanguinolou that there had been a brown out reset, which I hadn't seen before.

So to set these new FUSE settings, I could have edited the boards.txt and done it through the Arudino IDE as before, or I could use the following command for AVRdude:


avrdude -p m1284p -c arduino -P com6 -v -b 19200 -U hfuse:w:0xDC:m -U lfuse:w:0xD7:m -U efuse:w:0xFD:m


With this done, I reconnected the sanguinololu up to Repetier host and... (see part 2)


No comments:

Post a Comment