ArduinoISP not erasing pages (was Can't upload sketches to 328p on a breadboard)

EDIT:

Don’t bother reading the whole mess, it’s mostly me figuring out what the true problem is. For whatever reason, ArduinoISP isn’t erasing the pages before writing data to them, and the avrdude that is launched doesn’t perform a chip erase either. This results in the uploads being logically ANDed with the existing flash contents. This causes failures with the verification process of course. If I manually run avrdude and erase the chip, all is well again for one flash cycle. Then the very next upload is ANDed with the first and so on.

Anybody know why???

It’s my understanding that the bootloader is responsible for clearing the pages that are flashed. Since ArduinoISP is acting as a bootloader, shouldn’t it be doing this?

Hello, I hope this is the right place to ask this. I’ve been trying to get a bare 328p running at 20MHz on a breadboard. I built a new optiboot configured to run at 20MHz and a baud rate of 115200. I then configured a board setup in the Arduino hardware directory. This all went ok and I was able to burn a bootloader onto my blank chip from Mouser. When I reset the chip, it flashes the LED 3 times just like it should so I’m sure the bootloader is on there. I also know that the fuses are set to use the 20Mhz crystal as it won’t run without the crystal now, as I expected.

The problem now is that even though I prevent the reset with a 10uF cap, the ArduinoISP software will not load a sketch into the chip. It just turns on the “error” LED right away and that’s pretty much it. When burning the bootloader, it all went like it was supposed to with the LEDs flashing away during the upload.

I understand that what I’m doing should wipe out the bootloader when my sketch uploads. This is fine as I just want to ICSP the bare chip if I can. I burned the bootloader to set the fuses and they seem to be ok.

I followed this to setup the board for programming:

I used info from this page to setup the board description:
http://www.grozeaion.com/electronics/arduino/155-overclocking-atmega328p.html

Here is the board description I set up:

MWB20MHz.name=ATmega328 on a breadboard (20 MHz external clock)

MWB20MHz.upload.protocol=arduino
MWB20MHz.upload.maximum_size=32256
MWB20MHz.upload.speed=115200
### MWB20MHz.upload.using=arduino:arduinoisp

MWB20MHz.bootloader.low_fuses=0xF7
MWB20MHz.bootloader.high_fuses=0xD6
MWB20MHz.bootloader.extended_fuses=0x05
MWB20MHz.bootloader.path=arduino:optiboot
MWB20MHz.bootloader.file=optiboot_atmega328__20MHz.hex
MWB20MHz.bootloader.unlock_bits=0x3F
MWB20MHz.bootloader.lock_bits=0x0F

MWB20MHz.build.mcu=atmega328p
MWB20MHz.build.f_cpu=20000000L
MWB20MHz.build.core=arduino:arduino
MWB20MHz.build.variant=arduino:standard

Here is the Makefile I used to build the optiboot with other board models removed for posting:

# Makefile for ATmegaBOOT
# E.Lins, 18.7.2005
# $Id$
#
# Instructions
#
# To make bootloader .hex file:
# make diecimila
# make lilypad
# make ng
# etc...
#
# To burn bootloader .hex file:
# make diecimila_isp
# make lilypad_isp
# make ng_isp
# etc...

# program name should not be changed...
PROGRAM    = optiboot

# The default behavior is to build using tools that are in the users
# current path variables, but we can also build using an installed
# Arduino user IDE setup, or the Arduino source tree.
# Uncomment this next lines to build within the arduino environment,
# using the arduino-included avrgcc toolset (mac and pc)
# ENV ?= arduino
# ENV ?= arduinodev
# OS ?= macosx
# OS ?= windows


# enter the parameters for the avrdude isp tool
ISPTOOL	   = stk500v2
ISPPORT	   = usb
ISPSPEED   = -b 115200

MCU_TARGET = atmega168
LDSECTIONS  = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe

# Build environments
# Start of some ugly makefile-isms to allow optiboot to be built
# in several different environments.  See the README.TXT file for
# details.

# default
fixpath = $(1)

ifeq ($(ENV), arduino)
# For Arduino, we assume that we're connected to the optiboot directory
# included with the arduino distribution, which means that the full set
# of avr-tools are "right up there" in standard places.
TOOLROOT = ../../../tools
GCCROOT = $(TOOLROOT)/avr/bin/
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf

ifeq ($(OS), windows)
# On windows, SOME of the tool paths will need to have backslashes instead
# of forward slashes (because they use windows cmd.exe for execution instead
# of a unix/mingw shell?)  We also have to ensure that a consistent shell
# is used even if a unix shell is installed (ie as part of WINAVR)
fixpath = $(subst /,\,$1)
SHELL = cmd.exe
endif

else ifeq ($(ENV), arduinodev)
# Arduino IDE source code environment.  Use the unpacked compilers created
# by the build (you'll need to do "ant build" first.)
ifeq ($(OS), macosx)
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
endif
ifeq ($(OS), windows)
TOOLROOT = ../../../../build/windows/work/hardware/tools
endif

GCCROOT = $(TOOLROOT)/avr/bin/
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf

else
GCCROOT =
AVRDUDE_CONF =
endif
#
# End of build environment code.


# the efuse should really be 0xf8; since, however, only the lower
# three bits of that byte are used on the atmega168, avrdude gets
# confused if you specify 1's for the higher bits, see:
# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/
#
# similarly, the lock bits should be 0xff instead of 0x3f (to
# unlock the bootloader section) and 0xcf instead of 0x2f (to
# lock it), but since the high two bits of the lock byte are
# unused, avrdude would get confused.

ISPFUSES    = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
              -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
              -e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
              -U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
ISPFLASH    = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
              -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
              -U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m

STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe"
STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \
-lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt
STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt

OBJ        = $(PROGRAM).o
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls

DEFS       = 
LIBS       =

CC         = $(GCCROOT)avr-gcc

# Override is only needed by avr-lib build system.

override CFLAGS        = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
override LDFLAGS       = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib

OBJCOPY        = $(GCCROOT)avr-objcopy
OBJDUMP        = $(call fixpath,$(GCCROOT)avr-objdump)

SIZE           = $(GCCROOT)avr-size

# Test platforms
# lines added by MWB for testing ATMega328P @ 20MHZ
#
atmega328_20MHz:	TARGET = atmega328__20MHz
atmega328_20MHz:	MCU_TARGET = atmega328p
atmega328_20MHz:	CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega328_20MHz:	AVR_FREQ = 20000000L
atmega328_20MHz:	LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_20MHz:	$(PROGRAM)_atmega328__20MHz.hex
atmega328_20MHz:	$(PROGRAM)_atmega328__20MHz.lst
atmega328_20MHz_isp:	atmega328_20MHz
atmega328_20MHz_isp:	TARGET = atmega328__20MHz
atmega328_20MHz_isp:	MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328_20MHz_isp:	HFUSE = D6
# Low power xtal (16MHz) 16KCK/14CK+65ms
atmega328_20MHz_isp:	LFUSE = F7
# 2.7V brownout
atmega328_20MHz_isp:	EFUSE = 05
atmega328_20MHz_isp:	isp
#
# Generic build instructions
#
#

isp: $(TARGET)
	$(ISPFUSES)
	$(ISPFLASH)

isp-stk500: $(PROGRAM)_$(TARGET).hex
	$(STK500-1)
	$(STK500-2)

%.elf: $(OBJ)
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
	$(SIZE) $@

clean:
	rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex

%.lst: %.elf
	$(OBJDUMP) -h -S $< > $@

%.hex: %.elf
	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@

%.srec: %.elf
	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@

%.bin: %.elf
	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@

Whenever I try to upload a sketch, the ERROR LED comes on from ArduinoISP and avrdude times out with either the 0E or 00 error. It is my understanding the optiboot that I have successfully loaded will be wiped when my sketch uploads, but it never works. What am I missing?

Why do you mess with optiboot when you are using arduinoisp?? Optiboot works with usart upload.

pito: Why do you mess with optiboot when you are using arduinoisp?? Optiboot works with usart upload.

Like I said, I installed opti-boot to make sure the fuses were set to what I wanted. Plus I'm trying to figure this stuff out. Plus I will switch to using an FTDI adapter to program the chip thru the bootloader.

I seem to have found the issue. It was a baud rate problem. Aparently ArduinoISP wants to see a baud rate of 19200. I tried upping the baud rate in ArduinoISP, but that led to the out of sync errors. I then modified my board description to lower the baud rate to 19200 instead of 115200. This seems to have fixed it all. I can now upload to the chip on the board. Interestingly, my bootloader is still intact on the breadboard chip. I guess that's because of the fuse setting in my boards.txt file are protecting the bootloader area.

My fuses are as follows in the boards.txt file entry I created: low_fuses = 0xF7 high_fuses = 0xD6 ext_fuses = 0x05

Well, it's a new problem now. I flashed the chip several times with the blink program, changing the delay each time. Everything went fine for several flashes, then suddenly it starts telling me:

avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0002
         0x61 != 0x60
avrdude: verification error; content mismatch
avrdude: Send: Q [51]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [10] 

avrdude done.  Thank you.

I swear I didn't change anything. The bootloader is still present in the chip along with a mashed up version of my blink sketch. It's weird, the flash process went fine as far as avrdude was concerned, but the verify didn't. It's flashing some stuff into the chip, but not all. It's almost like the chip isn't being erased before the flash goes at it.

Here is a look at the beginning of the avrdude verbose output when I try to flash. The Uno running ArduinoISP seems to be doing the right thing as far as I can tell. It's not illuminating the ERROR LED and sticking like it was.

avrdude: Version 5.11, compiled on Sep  2 2011 at 19:38:36
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "C:\Users\mike\arduino-1.0.3\hardware/tools/avr/etc/avrdude.conf"

         Using Port                    : \\.\COM8
         Using Programmer              : stk500v1
         Overriding Baud Rate          : 19200
avrdude: Send: 0 [30]   [20] 
avrdude: Send: 0 [30]   [20] 
avrdude: Send: 0 [30]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [10] 
         AVR Part                      : ATMEGA328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : STK500
         Description     : Atmel STK500 Version 1.x firmware
avrdude: Send: A [41] . [80]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [02] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [81]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [01] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [82]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [12] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [98]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
avrdude: Send: A [41] . [84]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [85]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [86]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [87]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [89]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: Send: A [41] . [81]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [01] 
avrdude: Recv: . [10] 
avrdude: Send: A [41] . [82]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [12] 
avrdude: Recv: . [10] 
avrdude: Send: B [42] . [86] . [00] . [00] . [01] . [01] . [01] . [01] . [03] . [ff] . [ff] . [ff] . [ff] . [00] . [80] . [04] . [00] . [00] . [00] . [80] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [10] 
avrdude: Send: E [45] . [05] . [04] . [d7] . [c2] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [10] 
avrdude: Send: P [50]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [10] 
avrdude: AVR device initialized and ready to accept instructions

The plot thickens. I burned the bootloader again and I could again upload the blink sketch and get a successful verify. Oddly, the sketch fails verify when I change the delay() calls for the blink and upload again, but the LED blinks faster anyway. The location that fails the verify appears to be the location that stores the delay value that I am changing between uploads.

Here's what I think is happening. The chip isn't being erased when the sketch uploads thru ArduinoISP. The upload is being OR'd into memory. The first upload after burning the bootloader works fine because the bootloader upload erases the chip correctly. After that, I get a combo of the previous sketch with the new upload ORd into memory.

I've done some more testing and I'm fairly sure that the chip is being written to during the flash, but not correctly. Kind of like when the chip isn't erased to all 1s, but left in it's previous state and then reflashed. Like a double exposure.

This is definitely an issue of the chip not being erased. From what I've read, the bootloader erases pages as it needs them so the avrdude command runs with a -D argument. Trouble is I can't find where to tell it not to do that when I'm using arduinoISP. Seems like the correct thing would be for the arduinoISP program to act like the bootloader and clear the pages as it stores code to them.

My uploads are being combined by the way they turn off bits due to the nature of how the flash works. It is initialized to all 1's when it is erased. Then when programs upload they just turn off the bits they need off. Without erasing between uploads, well you should get the picture.

I don't see a bunch of people complaining about it, so I wonder what is special about my case. Why isn't the chip getting erased by avrdude? How can I fix the arguments to avrdude? Anybody?

ttt Edited subject line to reflect true problem and modified first post. Please look at the first post of the thread to cut to the chase. Thank you.

Are you trying to install then use a bootloader or are you trying to upload sketches?

I can install the bootloader (that I compiled) with ease. The main reason for doing it was to set the fuses for the crystal oscillator at 20MHz. That all went fine. The trouble comes when I start uploading sketches. The chip wasn’t being erased as a whole (since the bootloader remained), and the pages were being logically ANDed with the incoming program.

After manually erasing the whole chip, which wipes my bootloader but keeps the fuses the way I want, I can upload a sketch without issue, once. The very next sketch upload gets ANDed with the contents of the flash and causes the verify to fail. A manual chip erase (with or without reinstalling the bootloader) clears the flash and allows one sketch to upload successfully.

The ArduinoISP sketch does not check any return values from the target. It sends the four byte command and hopes for the best. I guess it’s possible for enough commands to make it to complete a partial session. Were I in your shoes I would very carefully check for loose connections and broken wires paying particular attention to SCK and MOSI. You should avoid particularly long wires; I’ve always had success using wires <= 6 inches. Next I would try a different breadboard or a different section of the breadboard.

I appreciate the input CodingBadly, but I've checked all that way early on. I can reproduce the problem easily and then run a command line avrdude and have a successful upload of the same hex file. It's most definitely due to the avrdude command that the IDE runs containing the -D argument which prevents a full chip erase. That is definitely the root of it all. I can make avrdude exhibit the same exact mismatches by using the -D command line argument. With the argument avrdude will only upload once successfully after manually erasing the chip, then it will fail verification on subsequent uploads. As soon as an upload is done that doesn't include the -D argument, it erases the whole chip, flashes and verifies perfectly every time.

It's because a bootloader like optiboot will perform a page erase before writing to it. ArduinoISP doesn't do that and since the avrdude command has the -D argument on it, the chip doesn't get erased at all and the new data is logically ANDed with the existing contents. I am positive on this.

How do I get the IDE to not include that argument when it uploads? Or, how do I get ArduinoISP to erase pages before writing to them? I figure it's some silly setting somewhere that is causing this.

Are you using the ArduinoISP sketch that comes with ... which version of the IDE are you using?

Are you using [u]Upload[/u] or [u]Upload Using Programmer[/u]?

I'm using 1.0.3 and am just using the regular upload, but I have the ArduinoISP set as the programmer type. And sure enough when I select upload using programmer, it suddenly works because it suddenly starts erasing the chip as part of the process. That seems to have done it. That runs avrdude without the -D switch so it does a chip erase.

THANKS

EDIT: Turns out that if I comment out the xxx.upload.protocol for my new boards.txt entry, then it pays attention to the xxx.upload.using command to invoke avrdude with the chip erase. IOW, it does an Upload Using Programmer automatically when I click the upload arrow. Now I don't have to do anything strange to make it work.

This is a snippet from the Tiny Core boards.txt file...

# The following do NOT work...
# attiny84at16.upload.using=avrispv2
# attiny84at16.upload.using=Pololu USB AVR Programmer

# The following DO work (pick one)...
attiny84at16.upload.using=arduino:arduinoisp
# attiny84at16.upload.protocol=avrispv2
# attiny84at16.upload.using=pololu

Are you saying you had both a [u]using[/u] and a [u]protocol[/u] entry?

And removing the [u]protocol[/u] entry solved the problem?

Upload Using Programmer solved the problem by running avrdude without the switch so that the chip would be erased. Yes I had both entries and removing the protocol line made it so that I didn't have to Upload Using Programmer any more, it did that by default when I just click the Upload arrow. All is good now, excepting the fact that millis() and micros() are a disaster at 20MHz. Micros is off by 6.6% causing delay() to be off by the same amount. So sad. I'm going to overclock to 24MHz and see how that works out. :) All of the delay(), millis() and micros() stuff is off unless you use a crystal that is a multiple of 8MHz, otherwise stuff is lost in the integer truncation of diving by 8 and the like.

afremont: All is good now, excepting the fact that millis() and micros() are a disaster at 20MHz.

This will help with millis... http://arduino.cc/forum/index.php?topic=70475.0

Micros is off by 6.6% causing delay() to be off by the same amount.

Sounds about right. If you need help getting micros working let me know. I may be able to help. (But you will have to be patient.)

I'm going to overclock to 24MHz and see how that works out. :) All of the delay(), millis() and micros() stuff is off unless you use a crystal that is a multiple of 8MHz, otherwise stuff is lost in the integer truncation of diving by 8 and the like.

If you're interested, I believe I have an Excel workbook for determining the error.

ISP programming does not have a "page erase" feature. You either erase the. Whole chip, or you get the merged bits problem that you describe. Only bootloader based self programming has page erase... (though that does seem strange...)

I put the stuff in to fix millis() and spent some time tinkering with it today. I think it’s working right, but I was concerned about the accuracy I was getting. I set up a square wave generating dallas clock chip to reference my timing to and I got consistent readings of 999975uS, which is exactly what I was expecting. This is measured using my Uno board that has the really accurate (<30 ppm error) resonator in it.

With the chip running at 20MHz, I wasn’t getting the accuracy I expected from a real crystal, but it was fairly stable. Because the Timer0 overflow occurs in less than 1mS, millis() doesn’t increment every time there is an overflow. It increments the count with a ratio of 512/625 (.8192). I set up a millis() type delay like I use in my clock project and was a little concerned about the measurements I was getting. I was getting an error of approximately 500ppm which is way more than I’d expect, but far less than a 1 off type error would be making in the code.

In order to confirm things, I set up a CTC function on Timer2 of the 20MHz board. I set the prescaler to 1024 and set the top count to 99 (100 counts). This toggles the output pin every 10240uS 5120uS for a period length of 10240uS. I consistently measure 10234uS on the period for an error of just about 500ppm. This backs up what I was getting using the “fixed” Arduino library, but the Timers don’t depend upon the library, only the crystal.

I assume that what I have is a series resonant crystal that I’m using in a parallel resonant circuit like most microcontrollers have. I have never used this crystal before, and it doesn’t have enough markings to find a spec for it. But 500ppm error seems just about right for a crystal being operated in the wrong resonance mode.

I’ve been thinking about how to fix the micros() stuff, but I haven’t come up with anything I like yet. Currently, micros() uses the Timer0 overflow count left shifted 8 bits which isn’t going to cut it any more.

EDIT: I take back the part about not being able to use the timer overflow count. The icky part is that the overflow count left shifted 8 bits and then ORd with the contents of Timer0 represent 3.4uS 3.2uS timer ticks vs 4uS ticks. Suggestions for converting this to uS cleanly (which means tiny) are welcome, but floating point is not allowed.

EDIT2: I’m thinking that left shifting 5 bits and then dividing by 10, but the left shift runs the risk of losing info. Can I do 64 bit integers temporarily? I think doing this micros() would overflow about every 429 seconds. Is that a tragedy compared to approx. 71 minutes as it currently is?

Here is the stuff I put in the Makefile to build optiboot for 20MHz:

# lines added by MWB for testing ATMega328P @ 20MHZ
#
atmega328_20MHz:    TARGET = atmega328__20MHz
atmega328_20MHz:    MCU_TARGET = atmega328p
atmega328_20MHz:    CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega328_20MHz:    AVR_FREQ = 20000000L
atmega328_20MHz:    LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_20MHz:    $(PROGRAM)_atmega328__20MHz.hex
atmega328_20MHz:    $(PROGRAM)_atmega328__20MHz.lst
atmega328_20MHz_isp:    atmega328_20MHz
atmega328_20MHz_isp:    TARGET = atmega328__20MHz
atmega328_20MHz_isp:    MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328_20MHz_isp:    HFUSE = D6
# Low power xtal (16MHz) 16KCK/14CK+65ms
atmega328_20MHz_isp:    LFUSE = F7
# 2.7V brownout
atmega328_20MHz_isp:    EFUSE = 05
atmega328_20MHz_isp:    isp

You just run "omake atmega328_20MHz" and it will create the bootloader hex file.

To actually upload it, you have to point to it with your boards.txt file entry, like this:

MWB20MHz.name=ATmega328 on a breadboard (20 MHz external clock)

### MWB20MHz.upload.protocol=stk500v1
MWB20MHz.upload.maximum_size=32256
MWB20MHz.upload.speed=19200
MWB20MHz.upload.using=arduino:arduinoisp

MWB20MHz.bootloader.low_fuses=0xF7
MWB20MHz.bootloader.high_fuses=0xDE
MWB20MHz.bootloader.extended_fuses=0x05
MWB20MHz.bootloader.path=arduino:optiboot
MWB20MHz.bootloader.file=optiboot_atmega328__20MHz.hex
MWB20MHz.bootloader.unlock_bits=0x3F
MWB20MHz.bootloader.lock_bits=0x0F

MWB20MHz.build.mcu=atmega328p
MWB20MHz.build.f_cpu=20000000L
MWB20MHz.build.core=arduino:arduino
MWB20MHz.build.variant=arduino:standard

You select the board and do the "burn bootloader" command.

afremont: Suggestions for converting this to uS cleanly (which means tiny) are welcome, but floating point is not allowed.

I'll look through my notes and get back to you (may take a few days).

Can I do 64 bit integers temporarily?

You probably won't like the result. 64 bit integers work but are very expensive in code size and speed.