Making bootloader for Atmega162

Hi,

I have been trying to design a board for control of a telescope. The software is written in Arduino for the Mega1280. However, I want to be able to release the design as a DIY thing, and to be able to use it without having a seperate arduino board.

The issue is that the program requires two 16bit timers, which means that it would need an Arduino mega. But the mega is an horrible TQFP package, which is a pain in the neck to solder (I've done it a couple of times successfully, but its not really a DIY friendly thing).

I was looking through the Atmel product list, and the Atmega162 also has two 16 bit timers, but best of all is available as a DIP package. It is also supported by avrdude and gcc.

I have started making some of the files for it, including the code for boards.txt, and the pins_arduino file (included below). But I am not sure how to go about modifying and creating a bootloader hex file for it. Any help would be greatly appreciated.

I should mention that I dont have the chip yet as I wanted to check feasibility of adding a different part first before buying one.

Thanks for any help.

Tom.

boards.txt

##############################################################

atmega162.name=AstroEQ w/ ATmega162

atmega162.upload.protocol=arduino
atmega162.upload.maximum_size=14336
atmega162.upload.speed=19200

atmega162.bootloader.low_fuses=0xFF
atmega162.bootloader.high_fuses=0xDA
atmega162.bootloader.extended_fuses=0xFB
atmega162.bootloader.path=atmega
atmega162.bootloader.file=ATmegaBOOT_atmega168_atmega162.hex
atmega162.bootloader.unlock_bits=0x3F
atmega162.bootloader.lock_bits=0x0F

atmega162.build.mcu=atmega162
atmega162.build.f_cpu=16000000L
atmega162.build.core=arduino
atmega162.build.variant=AstroEQ

##############################################################

pins_arduino.h

/*
  pins_arduino.h - Pin definition functions for Arduino
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2007 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
*/

#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <avr/pgmspace.h>

#define NUM_DIGITAL_PINS            35
#define NUM_ANALOG_INPUTS           0
#define analogInputToDigitalPin(p)  (-1)

#define digitalPinHasPWM(p)         ((p) == 5 || (p) == 6 || (p) == 8 || (p) == 9 || (p) == 10 || (p) == 30)

const static uint8_t SS   = 10;
const static uint8_t MOSI = 11;
const static uint8_t MISO = 12;
const static uint8_t SCK  = 13;

const static uint8_t LED_BUILTIN = 13;

#define digitalPinToPCICR(p)    ( (((p) >= 14) && ((p) <= 17)) || \
                                  (((p) >= 20) && ((p) <= 27)) || \
                                  (((p) >= 31) && ((p) <= 34)) ? (&PCICR) : ((uint8_t *)0) )
								  
#define digitalPinToPCICRbit(p) ( (((p) >= 20) && ((p) <= 27)) ? 0 : 1 )

#define digitalPinToPCMSK(p)    ( (((p) >= 20) && ((p) <= 27)) ? (&PCMSK0) : \
								  (((p) >= 14) && ((p) <= 17)) || \
                                  (((p) >= 31) && ((p) <= 34)) ? (&PCMSK1) : ((uint8_t *)0) )

#define digitalPinToPCMSKbit(p) ( (((p) >= 20) && ((p) <= 27)) ? ((p) - 20) : \
								  (((p) >= 14) && ((p) <= 17)) ? ((p) - 14) : ((p) - 27) )

#ifdef ARDUINO_MAIN

// On the Arduino board, digital pins are also used
// for the analog output (software PWM).  Analog input
// pins are a separate set.

// ATMEL ATMEGA8 & 168 / ARDUINO
//
//                  +-\/-+
// PWM  (D 8) PB0  1|    |28  VCC
// PWM  (D 9) PB1  2|    |27  PA0 (D14)
//      (D19) PB2  3|    |26  PA1 (D15)
//      (D18) PB3  4|    |25  PA2 (D16)
// PWM  (D10) PB4  5|    |24  PA3 (D17)
//      (D11) PB5  6|    |23  PA4 (D31)
//      (D12) PB6  7|    |22  PA5 (D32)
//      (D13) PB7  8|    |21  PA6 (D33)
//            RST  9|    |20  PA7 (D34)
//      (D 0) PD0 10|    |19  PE0 (D28)
//      (D 1) PD1 11|    |18  PE1 (D29)
//      (D 2) PD2 12|    |17  PE2 (D30) PWM
//      (D 3) PD3 13|    |16  PC7 (D27)
// PWM  (D 5) PD4 14|    |15  PC6 (D26)
// PWM  (D 6) PD5 15|    |24  PC5 (D25)
//      (D 4) PD6 16|    |23  PC4 (D24)
//      (D 7) PD7 17|    |22  PC3 (D23)
//            XT2 18|    |21  PC2 (D22)
//            XT1 19|    |20  PC1 (D21)
//            GND 20|    |19  PC0 (D20)
//                  +----+
//
//
//
//0
//2
//3B
//            1B
//3A
//1A


// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint16_t PROGMEM port_to_mode_PGM[] = {
	NOT_A_PORT,
	(uint16_t) &DDRA,
	(uint16_t) &DDRB,
	(uint16_t) &DDRC,
	(uint16_t) &DDRD,
};

const uint16_t PROGMEM port_to_output_PGM[] = {
	NOT_A_PORT,
	(uint16_t) &PORTA,
	(uint16_t) &PORTB,
	(uint16_t) &PORTC,
	(uint16_t) &PORTD,
};

const uint16_t PROGMEM port_to_input_PGM[] = {
	NOT_A_PORT,
	(uint16_t) &PINA,
	(uint16_t) &PINB,
	(uint16_t) &PINC,
	(uint16_t) &PIND,
};

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
	PD, /* 0 */
	PD,
	PD,
	PD,
	PD,
	PD,
	PD,
	PD,
	PB, /* 8 */
	PB,
	PB,
	PB,
	PB,
	PB,
	PA, /* 14 */
	PA,
	PA,
	PA,
	PB, /* 18 */
	PB,
	PC, /* 20 */
	PC,
	PC,
	PC,
	PC,
	PC,
	PC,
	PC,
	PE, /* 28 */
	PE,
	PE,
	PA, /* 31 */
	PA,
	PA,
	PA,
};

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
	_BV(0), /* 0, port D */
	_BV(1),
	_BV(2),
	_BV(3),
	_BV(5),
	_BV(6),
	_BV(4),
	_BV(7),
	_BV(0), /* 8, port B */
	_BV(1),
	_BV(4),
	_BV(5),
	_BV(6),
	_BV(7),
	_BV(0), /* 14, port A */
	_BV(1),
	_BV(2),
	_BV(3),
	_BV(2), /* 18, port B */
	_BV(3),
	_BV(0), /* 20, port C */
	_BV(1),
	_BV(2),
	_BV(3),
	_BV(4),
	_BV(5),
	_BV(6),
	_BV(7),
	_BV(0), /* 28, port E */
	_BV(1),
	_BV(2),
	_BV(4), /* 31, port A */
	_BV(5),
	_BV(6),
	_BV(7),
};

const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
	NOT_ON_TIMER, /* 0 - port D */
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	TIMER3A,
	TIMER1A,
	NOT_ON_TIMER,
	TIMER0, /* 8 - port B */
	TIMER2,
	TIMER3B,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,/* 14, port A */
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER, /* 18, port B */
	NOT_ON_TIMER,
	NOT_ON_TIMER, /* 20, port C */
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER, /* 28, port E */
	NOT_ON_TIMER,
	TIMER1B,
	NOT_ON_TIMER, /* 31, port A */
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
};

#endif

#endif

Have you considered using a Teensy?

You probably need a new bootloader file to handle the differences internally in the processor. There are quite a few examples (eg. the Optiboot loader) which you could download and modify.

However you could explore other options...

First, do you really need 2 x 16-bit timers? Could one be pressed into service to do two things? Or could 8-bit resolution be enough? I did a sketch that output VGA signals using just a Uno, and timing had to be pretty precise.

Second, you don't need a bootloader. It just simplifies uploading things through the serial port, which the Uno has courtesy of the USB interface.

For example here:

This minimal board can be programmed using the ICSP header (labelled) using a device like the USBtinyISP, or indeed another Arduino Uno acting as a programmer.

The programming device is around $22, and can be shared between different projects.

You see, if you make up your own board, unless you muck around with a USB chip (itself likely to be surface mount) then you are going to need some sort of special cable anyway, like a FTDI cable, which also costs around $20. So you may as well go the ICSP programming route, and save worrying about the bootloader.

Well, I have managed to get an optiboot bootloader to compile for the Atmega162. Just waiting for a chip to arrive to test it on.

Tom.

I have a chip now and am trying to get it to work, but have so far been unsuccessful.

I have tried to adapt the Makefile, optiboot.c, and boot.h files to suit the 162, and can get it to compile to hex.
I can then upload the hex file using another arduino as an isp fine.

However each time I try to upload a sketch to the Atmega162, I just get that it is not in sync, and it would appear that the chip is not comunicating.
Furthermore, the LED I have connected to what I have called Pin 13 doesn't seem to behave correctly. Initially it just wouldn't turn on at all. Based on the datasheet, I couldn't find any reference to the ability to toggle an output by writing 1 to PINxn, whereas in the 328 datasheet it is mentioned. As such I have changed any reference of it to:

#if defined(__AVR_ATmega162__) || defined(__AVR_ATmega8__) 
  LED_PORT ^= _BV(LED);
#else
  LED_PIN |= _BV(LED);
#endif

which I believe will do the job. However this doesn't appear to work. Sometimes when I try to program the LED comes on very dimly and nothing after that. Other times it blinks once. Some times it doesn't do anything until Arduino closes the COM port, and then it blinks once.

The next change is that the Atmega162 doesn't have an MCUSR register, but the 4 bits in it are contained as the least significant 4 bits in the MCUCSR register, so I believe this change should be appropriate

#ifdef __AVR_ATmega162__
  ch = MCUCSR;
  ch &= 0x0F;
  MCUCSR &= 0xF0;
#else
  ch = MCUSR;
  MCUSR = 0;
#endif
  if (!(ch & _BV(EXTRF))) appStart();

The Watchdog timer register has a different name, so I have changed that. Similarly the timers have different registers, so I have updated those with #if define()'s.

I am not entirely sure what I have missed, so if anyone could help point me in the right direction that would be great. I am happy to provide more info if needed.

Tom

p.s. quick thought, could it be something to do with the wrong register numbers in the inline assembler bits?

optiboot.c:
http://www.railways-in-miniature.co.uk/electronics/FileDump/optiboot/optiboot.c

boot.h:
http://www.railways-in-miniature.co.uk/electronics/FileDump/optiboot/boot.h

lines added to Makefile

atmega162: TARGET = atmega162
atmega162: MCU_TARGET = atmega162
atmega162: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega162: AVR_FREQ = 16000000L 
atmega162: $(PROGRAM)_atmega162.hex
atmega162: $(PROGRAM)_atmega162.lst

atmega162_isp: atmega162
atmega162_isp: TARGET = atmega162
# 2.7V brownout
atmega162_isp: HFUSE = DA
# Low power xtal (16MHz) 16KCK/14CK+65ms
atmega162_isp: LFUSE = FF
# 512 byte boot
atmega162_isp: EFUSE = 1A
atmega162_isp: isp

I've made a bit of progress, it turns out that the NWRRSTART should be 0x3800, and not 0x1C00. Just for curiosities sake, does anyone know where this comes from (originally I used a value found in the datasheet).
Also, the Low Fuse byte should be 0xD8 rather than 0xDA otherwise there was only 256Bytes of bootloader space. Woops!

Now I get three quick blinks of the LED as expected when downloading begins, however at the moment it is still not responding (not in sync: resp=0x00).

WOOO! Got it :smiley:

The hardware serial port of the Atmega162 is slightly different, so the initialisation of it needs to be changed to:

#ifndef SOFT_UART
#ifdef __AVR_ATmega8__
  ...
#elif defined(__AVR_ATmega162__)
  UCSR0A = _BV(U2X0); //Double speed mode USART0
  UCSR0B = _BV(RXEN0) | _BV(TXEN0);
  UCSR0C = _BV(URSEL0) | _BV(UCSZ00) | _BV(UCSZ01);
  UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#else
  ...
#endif
#endif

Also, i'm guessing that the NRWWSTART value = 'program memory space' - 'bootloader size' = 16k - 1k = 0x3C00

Seems to be working nicely. Got the blink sketch to upload and run.
I did need to decrease to 57600 BAUD from 115200 to get a reliable connection (keeps timing out otherwise).

Tom

optiboot_atmega162.hex (1.41 KB)

pins_arduino.h (5.07 KB)

boards.txt (13.5 KB)

My pins_arduino.h file was wrong. I have attached a corrected version.

pins_arduino.h (5.06 KB)

TCWORLD:
My pins_arduino.h file was wrong. I have attached a corrected version.

Cool, I've got your files. I'll try to make it work, but this is my FIRST arduino project...
any help would be welcome

I also have a bootloader hex (x0xb0x_boot.HEX) file for the 162. Its from adafruit, for the x0xb0x.
I guess its more or less the same as yours.

But... I really dont know what to do with yout files :frowning:

YES! It worked.
I renamed my bootloader.hex file ant put it in the optiboot map.
COOOLLL

Now I can burn the firmware of the x0xb0x to it, and finaly play with my x0xb0x
XD
THANKS
:smiley:

To bad... The bootloader doesn't work. It won't load the firmware... Maybe because i first loaded a false programme to the 162 and after that the bootloader.
Or because i renamed the .HEX Bootloader file...
I dont get it...

Whats the problem with it?

Here's what I did:

In the directory:
..\arduino-1.0\hardware\arduino\variants

  1. Add a folder called Atmega162 (I called it AstroEQ for various reasons, but doesnt matter).
  2. Put the "pins_arduino.h" inside this directory.

In the directory:
..\arduino-1.0\hardware\arduino\

  1. Add the following to "boards.txt":
##############################################################
atmega162.name=ATmega162

atmega162.upload.protocol=arduino
atmega162.upload.maximum_size=15360
atmega162.upload.speed=57600

atmega162.bootloader.low_fuses=0xFF
atmega162.bootloader.high_fuses=0xD8
atmega162.bootloader.extended_fuses=0xFB
atmega162.bootloader.path=optiboot
atmega162.bootloader.file=optiboot_atmega162.hex
atmega162.bootloader.unlock_bits=0x3F
atmega162.bootloader.lock_bits=0x0F

atmega162.build.mcu=atmega162
atmega162.build.f_cpu=16000000L
atmega162.build.core=arduino
atmega162.build.variant=Atmega162

##############################################################

Note that the last line of that (before the #####) has the name of the folder you created in step 1. If you used the boards.txt file I uploaded, these lines are already at the bottom of the file. You just need to edit the last line to match the correct folder name as mentioned.
The first line of the above is the what you want it to appear as in the IDE.

In the directory:
..\arduino-1.0\hardware\arduino\bootloaders\optiboot\

4)Copy the file "optiboot_atmega162.hex" to this folder.

5)Restart the Arduino IDE (close all open windows, and reopen).

  1. Select "Tools->Board->'name from step 4' "

  2. Select "Tools->Programmer->'Arduino as ISP' "

  3. Click "Tools->'Burn Bootloader' "

If the bootloader burns sucessfully, it should now work. Just upload a sketch as normal.

I have just looked up 'x0xb0x'. Am I right in thinking you are trying to use this:

If so, they have given you a .hex file, so you don't actually need Arduino IDE, or the bootloader. Perhaps I had misunderstood what you are trying to do.

If you are just trying to load their hex file, you can do it following the steps above only in step 4 instead of using the bootloader file I made, download the x0xb0x hex file and rename it to "optiboot_atmega162.hex", then it should burn that hex file.

I did all the above, and the bootloader burned.
But i wonder if the name in step 4 :
4)Copy the file "optiboot_atmega162.hex" to this folder.

Could be changed to x0xb0x_boot.HEX
?

You beat me too it, I was just editing my post above.

If you rename the file, it will trick the arduino IDE into uploading that file.

TCWORLD:
You beat me too it, I was just editing my post above.
Jj
I did just that, but doesn't the name mess
If you rename the file, it will trick the arduino IDE into uploading that file.

Hehehe, nice :stuck_out_tongue:

I did just that.
But i still cant load the firmware on it... No correct device name...
I'll look into it again tomorrow. I need sleep now...
:sleeping:

Just to be shure,
how did you hookup the 162?

UNO -> Atmega162
Miso -> Miso
Mosi -> Mosi
SS -> Reset
+5v -> VCC
GND -> GND

What happens when you try and program it?

OK that's what I did.

I think the problem is in my x0xb0x.

I put a brand new CPU in today, with firmware, and still... no play time.
So I'll first have to fix the x0xb0x...

I think the bootloader worked just fine.

Hi TCWORLD
i just want to know, can you run bootloader on ATMega162 to work with Arduino IDE?