// Mote Prime - Article

Mote Prime

A personal website

Articles

Atheism

Competitions

Humour

Paranonsense

Politics

Science

Technology

Links

Atheism

Humour

Paranonsense

Reviews

Science

Technology

About

Mote Prime

Author

Other Sites

OfQuack Podcasts

H:MC18

Little Book of Clam

Ads

Stop the Saatchi Bill

free debate

10:23

Mote Prime > Technology

Errata for AVR - An Introductory Course

John Morton's book "AVR - An Introductory Course" is a well laid out introduction to AVR programming and design, which takes a new user through from basic I/O and program layout to relatively complex projects in 150 pages.

However, it has numerous errors which will confuse or discourage new programmers. Unfortunately, these are exactly the people who are the book's intended audience.

In order to help out, I have compiled a list of errata. I would like to say at this point that there are many positive points about Mr. Morton's book that commend it. It is difficult for a list of errata to come across as anything other than negative, but I assure you that this is not my intention (with the unfortunate exception of the final robot design).

The list is presented in page number order, with chapter headings marked. Program listings are collected into an appendix, but I will link to them if they are related directly to the main text, since that matches the way that the book is likely to be used.

Classes of Error

Some errors are more severe than others. Common error classes, in approximate order of increasing severity, are:

Style Indicates that a style decision has been made which will have no effect on the final result, but is against common practice, or may be difficult to maintain.
Clarify Indicates that further clarification would be useful. Non-serious, but may leave certain principles or decisions unclear.
Typo Typographical error. Not usually serious, but can be serious if in the wrong place, especially in component values.
Factual Factual error. Can be serious, since they tend to affect designs. These are simple statements in contradiction to the datasheets.
Design Design error. This indicates that the design of the code or hardware is in error, or is at variance with common practice. These can have very serious consequences for the novice experimenter, up to and including damage to the chip itself.

Section 1: Introduction

p5 Typo
Paragraph 1 refers to the digits in a hexadecimal number as "bits" rather than digits.
p5 Typo
The description of the binary addition table refers to "pairs of bits" when it contains triplets as well. The reason for including the triplets is to cope with the carry bit passed out from a previous addition, but this is not made clear.
p5 Style/Clarify
The binary sum has an unlabelled "1" at the top - this is a carry digit from the column immediately to its right. These carry digits are consistently placed over the top of the sums (rather than beneath the total, which is more traditional) and their purpose may not be obvious to readers not familiar with this convention.
p7 Typo
Example 1.9 is referenced as "Example 1.10".
p10 Design
In paragraph 2, the description of how the push button array is read is simplified, but misleading since the inactive strobe outputs are described as logic 0. Although we have not yet been introduced to the concept of a high-impedance pin, this is necessary to avoid potential short circuits when more than one button is pushed. If, as in the text, PB0 is at +5V, and PB1 and PB2 are at 0V, then pressing SW1 and SW2 at the same time connects PB0 directly to PB1 and there is a conflict which will at least lead to unpredictable results, and at worst can damage the outputs on the chip itself.
p11 Design
Figure 1.2, the first real design that we have seen, has some fairly serious flaws. If this is just a rough sketch of a design, then these would be acceptable - an experienced designer will often leave out components which are "obvious" - but a design sketch should be labelled as such. If it is a real design, then the flaws could lead to a damaged 1200.

First, the keypad problems mentioned above. Current limiting resistors in series with either the row or the column lines would avoid damage.

Second, the 7 segment displays have no current limiting resistors, which is bad practice - a LED without a series resistor will try to take a large amount of current, to the detriment of both itself and the output from which it is driven.

Third, the common connections on each 7 segment display are directly driven from single AVR outputs, which means that they will be trying to source or sink up to 7 times the forward current for a single LED. Without resistors, one of these currents may be enough to damage the output pin; commoning seven of them together will cause 7 times as much trouble.

p13 Clarify
Although many assemblers produce .hex files as output, not all do. In particular, when you first install AVR Studio 3.5x, the default file format for output is not .hex. It would have been better to call these "output files" and then mention that the most common type is .hex, although other types exist.
p13 Style
The discussion on registers discusses I/O locations first (which are not registers in the same sense that the general-purpose registers are). This distinction is made in the text, but the metaphor seems odd to me, especially since I am used to using machines where the registers are solely for internal value manipulation.

The whole question of how to deal with the AVRs mixed addressing schemes is a difficult one, however. For example, an I/O register has two addresses associated with it, one for use with load/store instructions, and one for use with in/out instructions. This is difficult to explain to a new user.

p16 Factual
Paragraph 2 states that an I/O pin "can sink or source 20mA". This is incorrect, and I might speculate that this misunderstanding is due to Mr Morton's familiarity with the PIC line of microcontrollers - he has a similar book in print for these controllers also. (Appendix A in >this book is actually entitled "Specifications of some PICs", which is a bit of a giveaway!)

The I/O pins on PICs do behave in exactly the described manner, but according to the 1200 datasheet, its I/O pins can typically sink up to 20mA, but can only source 4mA at 5V. This misunderstanding leads to some serious design consequences later, especially when driving LED displays.

Ironically, Atmel have caught up late with this trend for "symmetrical drive" in the more recent Mega series of AVR chips, but for the humble AT90 series, including the 1200, the disparity in source and sink current remains.

p16 Design
Example 1.16 mentions driving LEDs through current limiting resistors (which is good) to ground. Driving to ground is not recommended since the maximum source current is only 4mA, as discussed previously. For this reason, connecting LEDs between outputs and +5V is the standard idiom for AVRs.
p16 Design
Exercise 1.12 mentions connecting input buttons between the pin and the +5V rail. Again, this is not common idiom on the AVR since there is no pulldown resistor. If the button is not pressed, the input floats, unconnected to anything, and this is very bad practice indeed. It would be possible to add a pull-down resistor to this arrangement, but connecting between the pin and GND allows us to use the AVRs internal pullup resistors on inputs. This is again the common design idiom, and is used extensively elsewhere in the book.
p19 Style
The file header with the author information is what is known as a "sloane square" - a comment completely surrounded by asterisks. This either takes a lot of fiddling about when the embedded data is changed, in order to make the right asterisks line up again, or it rapidly degenerates into a "leicester square" - a sloane square with a ragged right edge. It is common to spend more time adjusting the asterisk alignment in a sloane square than you would spend editing the actual comments! For this reason, it is usual practice to omit any aligned features to the right of a comment block like this; the lines of asterisks above and below are sufficient to delimit this section.
p21 Design
Example 1.19 suggests that you make unused pins outputs. If these are truly unused, then this is OK. However, it is safer (and thus the common idiom) to set them as inputs with pullups enabled. This prevents the AVR from attempting to drive current into anything which may inadvertantly be connected to the pins, and the pullups prevent any really unconnected pins from floating.

Section 2: Basic Operations with AT90S1200 and TINY12

p30 Typo
Figure 2.7 shows a resistor of value 320R. This is not a standard value (the nearest is 330R, which is probably what was meant). A novice may reject a 330R resistor, since he would have no reason to suspect that this was what was meant, and may not feel confident enough to substitute one value for another. Finding 320 ohm resistors is very difficult.
p30 Design
Also in Figure 2.7, it shows the 1200 driving a LED by sourcing current through one of the pins. This is not the way that the vast majority of LEDs are hooked up to AVRs due to the limits on source drive current. A back-of-the-envelope calculation suggests that this arrangement will draw about 6mA, which although not unsafe, is higher than the recommended figure of 4mA for an output. Most LEDs can deal with up to 20mA forward current, so the LED will not be as bright as it could be.
p31 Design
What is worse is that in the third paragraph here, the one example of programming hardware mentioned, the STK500, actually has the LEDs wired up in the common way, which means that the first program would fail as written, and would need to be modified to run on the recommended hardware!
p32 Typo
Figure 2.8 again shows a resistor of value 320R.
p32 Typo
Figure 2.8 shows the 1200 driving a LED by sinking current. This is good, but is not explained in the text why this differs from Figure 2.7. It also does not tally with the way that the subsequent code is written, in Program B, although the answers to exercise 2.1 and 2.2 are correct.
p32 Typo
Simulating the button press involves unchecking the box for PinD, bit 0, since it pulls the input low.
p36 Clarify
Although using ZH as a convenient 0 value is correct, it suggests a relationship between the data and the pointer register which does not actually exist. It would probably have been clearer to use temp as usual.
p37 Clarify/Style
The brbs and brbc instructions are very rarely used in AVR programs - the aliases breq, brne etc. are almost universal. It may have been clearer to omit the general instructions at this stage.
p40 Typo
Figure 2.11 again shows a resistor of value 320R.
p41 Typo
Figure 2.12 shows comparison against 15 as the termination condition for the loop. It should instead be 9.
p41 Style
In almost all cases, it is clearer and more informative to use a label than to use a branch relative to PC, since the name of the label is a big clue to the purpose of the jump.
p43 Typo
Figure 2.13 again shows comparison against 15 instead of 9.
p45 Typo
The code snippet at the bottom of the page uses the instruction out TCNT0,temp to read the value of the timer register. This should be in temp,TCNT0
p46 Typo
The code snippet also uses the instruction out TCNT0,temp to read the value of the timer register. As before, this should be in temp,TCNT0
p48 Typo
Figure 2.15 again shows a resistor of value 320R.
p56 Clarify
Figure 2.18 took me a while to decipher. A set of arrows indicating flow through the program would be very helpful here.
p58 Typo
Figure 2.19 again shows comparison against 15 instead of 9.
p69 Typo
The second paragraph refers to PB2 as the output. It is in fact PB0.
p69 Style
"...using a split form of the truth table for each gate gives us the most straightforward solution." I would differ with this opinion. By viewing the whole set of inputs PB1..PB5 as a single row in a truth table, it is possible to write the whole of the program in 14 lines, by indexing into a 32-entry table:

 Init:   ldi temp,0b000001
         out DDRB,temp
         ldi temp,0b111110
         out PORTB,temp
 Start:  in temp,PINB
         lsr temp
         ldi ZL,low(TruthTable*2)
         ldi ZH,high(TruthTable*2)
         add ZL,temp
         clr temp
         adc ZH,temp
         lpm
         out PORTB,ZL
         rjmp Start

The lookup table is at TruthTable and contains 32 values, with 0b111111 for "true" and 0b111110 for "false". These are PORTB's initial value, with PB0 set or reset accordingly.

p77 Design
This is the first time that the calculation of resistor values is mentioned. Although the values are correct for the stated currents, the currents required (30mA) are in excess of the recommended currents for sinking on a 1200 (20mA), and well in excess of those for sourcing current (4mA).
p78 Design
Figure 2.25 once again has the ubiquitous problem of trying to drive LEDs by sourcing current from the AVR outputs. The Hz/kHz indicator cannot operate properly as shown, since one or other of the states will require some drive current from the output. This can be solved by moving these to PD5 and PD6 and driving one or other low.

This project drives multiplexed LED displays. If all 7 segments of a display are on, the total current through the common pin would be up to 200mA. This needs some kind of buffer, and transistors are employed for this purpose. (This is odd, since they were not used for the same task in Figure 1.2.) There is no explanation at all as to why they are required. Since the LED drive logic all needs to be inverted, this carries through to here and means that the drive transistors have to be PNP rather than the NPN shown.

Finally, since this an application where timing is everything, it would be nice to label the crystal as 4MHz, even though this is a value we have used before.

p83 Style
The style of implementation for the Divide64 routine, where the loop jumps back using rjmp Divide64+1 makes my skin crawl, I am afraid to say. Encoding constant offsets from labels is the code maintenance equivalent of leaving primed rat-traps in a filing cabinet.

If you have a jump to a line, always, always, always use a label.

To see why, imagine what would happen if we needed to modify the routine to add another line of initialization. It would fail, and we would be left wondering why - there is nothing about the line lsr upperbyte that distinguishes it from any other line.

If we instead used Divide64_next: lsr upperbyte and rjmp Divide64_next this does two things. First, it signals that this is a loop, and where the loop starts. Second, it makes it much easier to see why we are branching - it is to go round the next loop.

p84 Style
Once again, we have the dreaded jump to label with offset, this time to three lines before the HalfSecond label. This crops up once more further down the page as rjmp FindTens+1.
p86 Style
Although the code for exercise 2.47 will work almost all of the time, by reading from PIND rather than from PORTD we run the risk that an external glitch will affect the value we are rotating around. By reading from PORTD, we avoid this problem.

Section 3: Introducing the rest of the family

p92 Factual
The first paragraph states that the X and Y registers can be used in any instruction that takes the Z register as an argument. This is broadly true, but not universally. The error is compounded by the fact that lpm, the most obviously Z-only instruction, is listed as one of the examples.
p92 Typo
Figure 3.2 is headed "PAM" - "RAM" is correct. It also shows RAM starting at address 000, which contradicts the previous figure.
p93 Clarify
The code to clear all registers suffers from the same clarity problems as the previous example on p36.
p93 Factual
The description of the ldd instruction is incorrect. Z is unchanged by the instruction (as is explicitly stated in the datasheet), and the value is retrieved from the address (Z+displacement).
p94 Design
The illustration of ijmp suffers from two major problems. First, it does not work in the manner indicated (the address is not in fact PC relative at all). Second, it will only work if the code is placed such that the jump table is in the first 250 locations in flash. Otherwise, the initialization of Z is incorrect (ZH would not be 0), and/or the addition of Function to ZL might need a carry into ZH.
p95 Clarify
It would be worth an explanation of how the two instructions in temp,SREG and bst temp,0 work to copy the carry flag to the T flag.
p96 Design/Clarify
The palindrome detection code has a subtle flaw which will trip the unwary. If it accepts the input as palindromic, the stack is back where it started; if it does not, then the stack still contains the mismatched items. This will cause problems if this is implemented as a subroutine.

Section 4: Intermediate operations

p100 Design
Figure 4.1 rehashes all the same old problems with LEDs as previous designs.
p102 Style
The sudden dive into random number theory is interesting but in this case superfluous since the randomness can be obtained by just counting very fast while the button is pressed.
p103 Style
In the paragraph after Excercise 4.7, there is mention of testing the state of the LED by testing bit 0 of PIND. Although this will work, it is better to test PORTD. PIND reflects the actual state of the pin, and especially given that a heavy load is attached, may not reflect what was put in it earlier. Testing PORTD avoids this problem, since it always returns the last set state regardless of the state of the physical outputs.
p104 Design
The code example on this page implements a timer interrupt routine, with one major omission. The status register, SREG, is not preserved. In this example, this is extremely unlikely to cause a problem, because of the nature of the main loop, but saving and restoring SREG in interrupt routines is one of the most important things to instil in new users of the AVR. Without it, you get inexplicable intermittent failures that are virtually impossible to track down. (This example is also part of Program K.) This is especially bad since it is even highlighted as a requirement in the AT90S1200 data sheet, on page 2.19: "Note that the Status Register - SREG - is not handled by the AVR hardware, neither for interrupts nor for subroutines. For the routines requiring a storage of the SREG, this must be performed by user software."
p108 Design
Figure 4.4 does not specify a part number for the op amp (and neither does the text). The resistor values are manageable in this case, but a better bet would probably have been to use a R-2R ladder network and terminate it directly at AIN0. The input impedance of the comparator is quite high and would not appreciably load either this or the resistor network shown - the op-amp is therefore redundant in any case.
p111 Typo
Example 4.1, line 5 reads out MCUCR. It should read out MCUCR,temp. It also assumes that interrupts have already been enabled globally using a sei instruction.
p114 Design
The design shown in Figure 4.9 suffers from the triplication of function on pin PB5. Unless, during programming, the RSTDISBL fuse is asserted, this is the reset pin and cannot be used as general digital I/O or analog input. A new Tiny15 from the factory does not have this fuse asserted and thus the program as presented will fail. As soon as the input voltage gets low enough to be read as a logic '0', the reset circuit will trigger and the program will immediately restart. Programming RSTDISBL would solve this problem, but since it is desirable to have a means to reset the device where possible, a simple re-routing of the input to pin PB3/ADC2 would avoid this complication. The program would then have to be changed to select ADC2 instead of ADC0 when measuring the input voltage.
p114 Typo
The flowchart in Figure 4.10 does not match the description in the text - the test criteria should be swapped over.
p114 Typo
The answer given for Exercise 4.13 (0b11100011 -> ADCSR) is incorrect given the rest of the program design. This value also sets up the ADC for free-running conversion, which is incompatible with the rest of the program. In free-running mode, the "ready" bit is never cleared. This means that the code snippets which wait for the conversion to complete will all lock up indefinitely. This value also contradicts the init section in Program M, which uses the value 0b11101011. This additionally sets the interrupt enable bit. Since there is no interrupt vector set up, it is as well that the global interrupt enable flag is not set! The true value required is 0b11000011.
p115 Clarify
To perform the function (5-input voltage) does indeed require a com instruction but the reason why is not obvious. Some additional explanation would be useful.
p116 Typo
EEPROM stands for Electrically Erasable Programmable Read Only Memory.
p117 Clarify
There is a well-known erratum with all AVRs concerning EEPROM address 0, which tends to get corrupted distressingly frequently. It would be useful to make people aware of this fact.
p118 Typo
The values in TimeL and TimeH after the read would be 0xFF and 0x28, and would have been 0xFF and 0x29 had the internal temporary register not been used.
p118 Typo
Example 4.6 has the values in TimeL and TimeH the wrong way round, and there is a missing comma in the line that initialises TimeH.
p120 Typo
Example 4.7, in the interrupt service routine, uses mov instructions to get values from I/O registers ICRL and ICRH. It should read in PrevL, ICRL and in PrevH, ICRH.
p120 Style
Example 4.7 uses code placement rather than a jump to divert control to the interrupt service routine. While this is valid, it is fragile - if you rearrange the code later, the program will mysteriously stop working. Even when the jump would be a jump to the next instruction, it is good practice always to treat the interrupt vector space as a jump table. The only exception to this is if memory is extremely tight, and this is clearly not the case in this example. Irony catches up with us here because the description of the program mentions defensive programming. Also, as usual, the SREG register is not preserved by the interrupt routine.
p122 Factual
This is a really, really pedantic nitpick. Table 4.5 lists the frequencies of some musical notes. According to the NIST website, the note "A" has frequency 220Hz, not 215Hz. The international standard for musical pitch is in fact set on the "A" above this, which is defined to be 440Hz. There is more information this "A440" standard here. Unless you have perfect pitch, the chances are you would never notice the difference, since it is the relationships between successive notes that are most dominant - this is why you can play the same piece of music in different keys and it will sound the same to most people. The corrected values for this table are therefore 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247 to the nearest whole Hz.
p124 Style/Design
The practice of placing a table at a fixed address in flash using .org directives is again a brittle strategy. Move the code, everything breaks. It is much better to allow the assembler to place the data for you and use a label to refer to the table. The lpm instruction on the 2313 is also sensitive to the contents of ZH, which should be set up as well as the esiting initialization of ZL.
p124 Design
Program N does not work in the manner described. Rather than taking large delay values (for low notes) and dividing them by 2 to go up octaves, it starts with low values and multiplies them by 2 to go down octaves. The invitation "you may wish to check them", referring to the values, is therefore well worth it. A corrected list of values and routines that work as described are presented in the errata for Program N.

Section 5: Advanced operations

p133 Factual
Figure 5.6, the description of the OR bit in USR has the data direction incorrect. It should read something like this: "0: Shift register contents have successfully been transferred to UDR. 1: Previous, unread contents of UDR have been overwritten by transfer of data from shift register."
p134 Clarify
Figure 5.7 shows a direct connection between a RS232 socket and the Rx/Tx pins of an AVR. The wording of the previous paragraph, although it mentions the voltage differences, is a little ambiguous, and could be clarified. Alternatively, the diagram could contain a buffer symbol on each line marked "voltage converter" or similar.
p135 Design
The keyboard converter project is a fairly large piece of software, and is likely to be the basis of future experimentation. The techniques described for dealing with the lookup table are brittle, in that they again rely on .org directives for placement of data in the code segment. They also assume that ZH will stay cleared; it would be safer to load both ZH and ZL prior to a lpm instruction, and use labels for the lookup table addresses.
p136 Design
Figure 5.9 rehashes the usual LED driving problem, and also contradicts the wiring for a serial port connector given in Figure 5.7. It also drives a speaker directly from an AVR pin, which may or may not work, depending on the type of speaker. The speaker is also not isolated with a capacitor, which will mean that it is DC biased when driven. This is again usually frowned upon.
p138 Clarify
The SPI section follows straight on from the UART section wihout noting that the 2313 does not have a user-accessible SPI interface. SPI interfaces are available on the larger chips such as the 8515 and 8535.
p138 Factual
The first sentence in the SPI section describes the UART, incorrectly, as a half-duplex UART. The 2313 datasheet correctly describes it as "a full duplex (separate receive and transmit registers) Universal Asynchronous Receiver and Transmitter (UART)". The UART is described thus for a good reason - it can receive and transmit at the same time.
p139 Typo
The master SPI device (the AVR) must select a slave by pulling its /SS line low, not high.
p142 Typo
Figure 5.14, the table for prescaler values includes the value "12 x CK". This should read "2 x CK".
p145 Style
Exercise 5.6 is seductive, and prone to error. The skeq macro will only skip single word instructions. These are almost all of them, but this just makes it more likely to confuse people when it fails. This kind of thing is why I advocate "always jump to a label" so strongly.
p147 Design
The circuit diagram provided in Figure 5.17 is, I am afraid to say, inexcusable. The LED display multiplexing scheme inherits the same problems as those in Figure 4.1, which is closely resembles, but the real killer (literally) is the motor drive. Motors, when switched on and off, act as inductors and generate large pulses of voltage which can kill an AVR stone dead in seconds. In order to counter this, a "freewheel" or "flyback" diode must be placed "in reverse" across each motor. Motors also draw heavy current, especially immediately after switch-on, before they have a chance to move. This means that adequate power supply isolation is essential, otherwise changes to the power supply voltage caused by the heavy load can themselves cause spontaneous resets. The transistors used to drive the motors would be better as PNP transistors in common-emitter configuration, since they will dissipate less power themselves. Finally, the very idea of driving a motor directly from an AVR port pin, as the LEFT motor is shown, is ludicrous. The current limits of 20mA will easily be exceeded, and the lack of any isolation between the motor and the AVR will mean that any voltage spikes generated will almost certainly fry the AVR in no time flat. Zap. Dead. Buy a new one.
pp148-151 Design
The program for running the robot is not very modular, and relies in many places on "tricks" which are brittle and hard to understand. For example, on p150, the final paragraph describes dealing with an out-of-bounds condition by placing specific instructions (not data) in the interrupt vector space, so that when the overflow occurrs they will be interpreted as the correct value. It really needs a complete rewrite with clarity as its main priority.

Appendix A: Specifications of some PICs

p152Typo
Did you spot it? The heading for this section should be "Specifications of some AVRs."

Appendix B: Pin layouts of various AVRs

None

Appendix C: Instruction overview

None

Appendix D: Instruction glossary

p160 Factual
The description of the ldd instruction is incorrect. The base register (Y or Z) is unchanged by the instruction (as is explicitly stated in the datasheet), and the value is retrieved from the address (base register value + displacement).
p163 Factual
The description of the std instruction is incorrect. The base register (Y or Z) is unchanged by the instruction (as is explicitly stated in the datasheet), and the value is stored into the address (base register value + displacement).
p164 Clarify
It would be clearer to extend the description of the WDR instruction to read "(must be done at regular intervals to avoid reset if watchdog timer is active)".

Appendix E: Interupt [sic] vector tables

p165Typo
"Interrupt" is spelled incorrectly in the title.

Appendix F: Hex conversion

None

Appendix G: ASCII conversion

None

Appendix H: When all else fails, read this

None

Appendix I: Contacts and further reading

None

Appendix J: Program Listings

pm BTypo
Program B, which runs on the hardware shown in Figure 2.8, has its LED drive statements the wrong way round. It should use cbi PortB,0 to turn the led on and sbi PortB,0 to turn it off, unless the wiring of the LED in Figure 2.8 is incorrect.
pm DClarify
Program D has a couple of slightly odd comments. First, the line ld ZL,20 is commented as "Zeroes ZL to R20", which may be confusing since the value zero never appears here. I do not have a better suggestion, however. Also, the line that drives the display, out PORTB,temp is commented as "outputs temp to Port B". Compare and contrast to example 1.18 (p18)! All programmers tend to fall into this trap sooner or later. A better comment may be "outputs temp to the display".
pm KDesign
None of the interrupt routines in Program K, preserve the status register, SREG.
pm MTypo
The initialisation of ADCSR should use the value 0b11000011.
pm NDesign
This does not calculate octave offsets as described, and the values in the lookup table are therefore also up the spout. The correct values for the note lookup table are (based on the corrected 220Hz lower A, and in decimal): 30578, 28862, 27242, 25713, 24270, 22908, 21622, 20408, 19263, 18182, 17161 and 16198. The shift instructions in the GetOctave loop are correct in the answer to problem 4.25, on page 233. Other minor differences include invalid notes being changed to B (0x0B) rather than C (0x00), sound output on PortD not PortB, comments for features not included (play button, keyboard, etc.), and finally no sei instruction to enable the interrupts that actually do all the work.
pm OTypo
Near the top of page 207, the line out TCNT0 should read out TCNT0,temp. The last line on this page and the first line on page 208 refer to registers NoteH and NoteH which have not been named in this program listing.
pm PDesign
I am afraid to say that this whole program really needs rewriting with a modular design and less reliance on "tricks".

Answers to exercises

p228Typo
Answer 2.51, line 5, the comment should read "Loops back if new > old."
p229Style
Answer 4.4 would be better using the standard idiom for multiplying by a power of two: adding the register to itself multiple times. In this case, it saves 1 instruction - in a multiply by 17 it would save 12.
p230Typo
Answer 4.6, the out instuctions do not specify a register. It should be temp. This may be a hangover from the PIC world, since PICs effectively have only one working register, and it is often omitted from instructions like this.
p230Design
Answer 4.11 (and 4.12 on the following page) show no regard for the physical character of the devices involved. There will be some settling time required for the op amp to track the step change in the input voltage - more so for the initial steps since they are larger. A LM358 op amp will require 1us or more to settle (typical bandwidth = 1MHz). The analog comparator will then require a further 400ns to produce a result. At 2.4576MHz, that is at least 4 instructions between setting the output bit and checking the result of the comparison. In the code, it is checked immediately. Liberal use of nops is encouraged!
p231Typo
Answer 4.14 should read 0b11000011 -> ADCSR since the free-running mode should not be enabled.
p232Typo
Answer 4.18 has the output logic for the TooHigh and TooLow sections the wrong way round.
p234Typo
Answer 5.1 includes the odd instruction dec Counter,8, which is a cut-and-paste typo from a few lines above. It should of course read dec Counter. This exercise can be answered without a counter register, but it is probably clearer to do it this way.
p234Typo
Answer 5.4, the line out TCNT0 should read out TCNT0,temp.

See Also

First, of course, the book. This is "AVR: An Introductory Course", by John Morton. Published by Newnes Press, ISBN 0 7506 5635 2. I obtained my copy from Amazon UK (the first review should seem familiar).

For more information on AVR Microcontrollers, including current datasheets and errata, see [[http://www.atmel.com Atmel's Website]] which contains the latest data sheets and product information. The AVR Studio development software is also available for free from this site.

Finally, there is a good online support and discussion forum at AVRFreaks.net which is a friendly and generally on-topic place, and is frequented by several of the guys from Atmel. You can also get the Atmel datasheets and both AVR Studio and AVR-GCC development systems from there.