Tuesday, April 16, 2013

AVR Microcontrollers Part 2

Introduction

This is part 2 of my playing around with AVR microcontrollers. Last time, I had a basic setup which could program an AVR using the Arduino ISP. I used it to drive a simple 7-segment, multiplexed 4-digit LED display. This is a follow up where I try out some of the other features the ATTiny24A has to offer. I also decided to invest some money in an AVR Dragon programmer/debugger so I'll go over some basic playing and setup with this device. I'll also discuss some of the problems and pitfalls I've encountered along the way.

AVR Dragon Setup

The AVR Dragon is a decently low-cost AVR programmer/debugger. It supports a wide variety of programming and debugging capabilities (as far as I know, every AVR protocol is supported). This includes the high-voltage programming capabilities used for fixing fuse problems with certain AVR devices. Even though the product is made by Atmel, it comes in a very hobby-like package. The device doesn't come with any cabling required to use it, nor does it come fully populated with all the headers. It doesn't even come with a case, you just get a bare PCB device.

Despite these faults, it isn't too difficult to setup the device to use. What other items you will need (including what it's used for):

  • USB A-B cable. This is used to power the AVR Dragon/communicate with it.
  • 6-pin 2x3, 0.1" pitch female-female cable. I had a hard time finding a cable which could be used for this so I decided to make my own. This is used for SPI programming, aWire debugging, PDI debugging, and debugWIRE debugging. Note that the 5V AVR Dragon power supply for target boards also has the same connector, but you don't necessarily need the full six pins since half the pins are ground and the other half are 5V. Since I am making my own cable, I decided to make it so the AVR Dragon end has a solid 6-pin 2x3 connector. On the other end, I put individual female connectors so I can have any cable configuration on the target board. This is not a requirement, but it will make programming/debugging chips on a breadboard possible/easier rather than a fixed 6-pin connector. As a note, it's not required that this be a female-female cable, only the AVR dragon side needs to have a female connector.
  • 10-pin 2x5, 0.1" pitch female-female cable. This is used for JTAG programming/debugging. Again, I chose to make my own cable with the same 10-pin solid connector on one end and individual connectors on the other end. Note that not all 10 positions need be loaded, only 8 are and arguably you might be able to get away with fewer.
  • 20-pin, 2x10, 0.1" pitch female-female cable. This is used for the high-voltage serial/parallel programming. What I believe the primary use of this interface is for is to reset fuses if you accidentally set them incorrectly and brick your device. Again, I have a fixed 20-pin connector on one end and individual pins on the other.
  • 20-pin, 2x10, 0.1" pitch male-pin rectangular connector. The AVR Dragon does not come populated with a header for the high-voltage serial/parallel programmer pins, so if you need this functionality you'll need the header (or solder directly onto the board).
  • 40-pin, 2x20, 0.1" pitch male-pin rectangular connector. This is for use with the on-board prototyping area. Each pin matches each of the various pinouts for any chip attached to the prototyping area.
  • DIP connectors for the prototyping area. There are available slots for a 28-pin, 2x14, 0.1" pitch 0.3" row separation DIP socket as well as a 40-pin, 2x20, 0.1" pitch 0.6" row separation DIP socket. Unfortunately the 28-pin socket pinout is nested inside of the 40-pin socket area so you can't easily get both DIP sockets in place. A potential solution is to solder one DIP socket on one side and the other DIP socket on the reverse side. Alternatively you can also use a 40-pin, 2x20 0.1" pitch "Zero-Insertion-Force socket with wide pin holders that will accept both 0.3" and 0.6" row spacing DIP packages. These aren't particularly cheap, though. The cheapest I found were ~$15 USD each.

BOM List

These are the parts I'm using along with a complete BOM list. Basically I went onto DigiKey and found parts which would meet my requirements, while trying to minimize cost. I had an old USB A-B cable around so I didn't need to purchase a new one. I wanted my cables and AVR Dragon headers to be gold-plated to help with long-term durability and corrosion/chemical resistance. However, you can probably just as easily get away with tin-plated connectors/headers at a slightly lower cost. Note that I chose not to populate the prototyping area yet as I'm still unsure which path I want to take with this area (ZIF or dual DIP sockets on both sides). For now I'm going to stick prototype programming packages into a breadboard I have. You'll also need some wiring, I'm using 22 AWG solid core because that's what I have, but a stranded core would probably work better for the cables because they're more flexible and are less prone to break as a result of bending/movement. Also, I've seen recommendations that these cables should be kept relatively short, preferably under the 6" range (~150mm).

Manufacturer Item No. Description Notes Unit Cost (USD) Qty Total Cost (USD)
Atmel ATAVRDRAGON AVR Dragon 53.75 1 53.75
Harwin Inc. M20-1160042 Female Crimp Rectangular Connector Price for qty. 100 0.0443 80 4.43
Harwin Inc. M20-1060100 Female 1x1 Rectangular Connector Housing Price for qty. 50. Strange that Digikey's description states these are 2x8 positions, but they are indeed 1x1. 0.04180 40 2.09
Harwin Inc. M20-1070300 Female 2x3 0.1" pitch Rectangular Connector Housing 0.51 2 1.02
Harwin Inc. M20-1070500 Female 2x5 0.1" pitch Rectangular Connector Housing 0.65 1 0.65
Harwin Inc. M20-1071000 Female 2x10 0.1" pitch Rectangular Connector Housing 0.95 1 0.95
Sullins Connector Solutions PRPC030DAAN-RC Male-pin 2x30 0.1" pitch Rectangular Connector Housing For both the HV programmer and prototyping area. Will need to manually cut. 1.15 1 1.15
Total 132 64.04

Software

The software I'm using to write my AVR programs is Atmel Studio 6. This is the latest official tool provided by Atmel and uses the Visual Studio 2010 core. As a result, it's only available on Windows. Despite the fact that it uses the Visual Studio 2010 core, Atmel provides the tool free of charge. Note that even though I'm using Atmel Studio to program/debug, this isn't the only choice. Luckily, the AVRDude tool I used last time is compatible with the AVR Dragon.

the Atmel website seems to be lacking documentation on how to setup the AVR dragon. They direct you to the AVR Dragon product page to download software front-end and USB drivers, but there isn't actually any download link. Turns out what you need to do is download Atmel Studio to get the USB drivers. Also, the first time I plugged the AVR Dragon in Windows did some driver setup/installation.

Updating AVR Dragon Firmware

Luckily, upgrading the AVR Dragon firmware is a fairly painless process to do with Atmel Studio. Upgrading the firmware allows you to take advantage of bug fixes, support for new chips, and occasionally new functionality. To do this, plug in the AVR Dragon, start up Atmel Studio and in the top menubar, go to Tools > AVR Tools Firmware Upgrade. The updater will work for a little while, and eventually it will ask you to power-cycle the device. Simply unplug/plug the AVR Dragon and you're good to go with the latest and greatest firmware.

Testing Out the Setup

To test out the setup I thought I'd play around with a few of the features of AVRtiny24A. These included the sleep functionality, interrupts, ADC, and internal temperature sensor. So I created a short firmware which would use the ADC to read the internal temperature sensor. Atmel recommends sampling the internal temperature sensor while in "reduced noise ADC mode", which disables the system core clock but leaves a few peripheral functionality on, including the ADC. On conversion complete an interrupt is triggered and the system core clock resumes.

Interrupts

AVR interrupts are "called" from the interrupt jump table. There are a variety of external and internal interrupt sources and each source can have a unique interrupt handler. To create an interrupt handler you use the ISR macro, which takes the interrupt vector entry you want to handle. You can refer to the datasheet to find the appropriate address for which interrupt you want (for the AVRtiny24A it's on Table 9-1), or you can use the AVR Libc documentation. Here's my interrupt handler:

volatile uint16_t temperature;

ISR(ADC_vect)
{
 // disable interrupts
 cli();
 // read temperature reading
 // must read ADCL first as this locks the ADC module write capabilities
 uint8_t Tlo = ADCL;
 uint8_t Thi = ADCH;
 temperature = (static_cast<uint16_t>(Thi) << 8) + Tlo;
}

There are a few important things to note:

  • For reading ADC samples you must read the ADCL value first. Reading the ADCL value will lock the ADC so it cannot update the sample value. On reading ADCH the lock is removed and the ADC can update sample information again. The reasoning for this is to prevent mixing data bytes from different samples.
  • Any variables which could be accessed/modified outside the normal code flow should be declared volatile. For example, temperature could be read by the normal code. It is also being modified by the interrupt handler which executes out of normal order, thus it must be declared volatile. On the other hand, Tlo and Thi can only ever be accessed by the ADC sample complete interrupt handler. Additionally, interrupts are explicitly disabled so there is no possibility of an interrupt interrupting the interrupt. Thus, these two variables can never be accessed in a non-linear fashion.

Main Code loop and setup

This is the rest of my code. It initializes the correct settings and then infinitely loops and samples temperature data.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define nop()  __asm__ __volatile__("nop")

int main(void)
{
 // Initialize the ADC
 
 // use internal 1.1V reference and internal Temp sensor ADC input
 ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADPS2);
 ADMUX |= (1 << REFS1) | (1 << 1) | (1 << 5);
 // enable sleeping, use ADC reduced noise mode when sleeping
 MCUCR = (MCUCR | (1 << SE) | (1 << SM0)) & ~(1 << SM1);
    while(1)
    {
        // ADC is automatically started when put into sleep mode. Interrupts need to be enabled.
  sei();
  sleep_cpu();
  // wait a cycle without doing anything, allows a debug breakpoint
  nop();
    }
}

Programming and Debugging a Target

Programming and debugging of the AVRTiny24A turns out to be remarkably troublesome. The main problem is that the debugWire and ISP interfaces are mutually exclusive. Namely, if a chip has the DWEN fuse enabled, you can only use debugWire. If SPIEN is enabled you can only use the SPI programming interface. Atmel Studio has the ability to toggle between the two, but there are some caveats with this. Luckily, if you're debugging your programs in general you don't need to switch back and forth between the two, the debugWire has basic programming capabilities which will allow you to compile a program and on starting debug will automatically upload the program. I don't know if the program is permanently stored on the target device or if it's uploaded only to the AVR Dragon, but it's quite usable for debugging.

The downside is that as far as I can tell, debugWire cannot modify the EEPROM or other fuse bits (other than toggling between debugWire and ISP if debugWire is enabled), so you will need to switch back to ISP mode to do these things.

To program a chip from Atmel Studio, compile/recompile your code. Plug the AVR Dragon into your computer, choose the tool, device, and interface. Click Apply.

In the memories tab you can read/write the flash or EEPROM. Find the Intel hex file (.hex) or an Executable and Linking Format (.elf) you want to program the chip with. In general you should erase the flash before programming because of the way flash memory works. There's also a tab for modifying the fuse bits.

If you run into problems programming the target device, most likely this is because of the AVR Dragon's weak drive strength. Try reducing the cable lengths, ISP programmer clock speed, or both. Alternatively, Kasper Pedersen has a nice Dragonhide piggyback solution which handles several problems with the AVR Dragon such as ESD protection, cable termination, and transmission strength.

Figure 1. Atmel Studio Device Programming

To setup device debugging, in the top menu open Project > {Project Name} Propertiess.... Go to the Tool tab and select the AVR Dragon as the programmer/debugger using the debugWire interface. You can now launch the project debugger. On launch, the debugger will ask you if you want to enable debugWire (if your device is currently in ISP mode). Choose yes and then you're good to go.

Switching back to ISP mode is a bit more of a challenge. There is a nice menu item in the top menu under Debug > Disable debugWire and Close. In theory choosing this option will reset the fuses so ISP mode will work again. However, there is one caveat: when the debugWire is being disabled, power is cut to the 5V source on the AVR Dragon. On externally powered targets you should be fine, but if you're using this 5V source to power your circuitry, you'll have some problems as the debugWire can't be disabled. Be careful with inrush current, though. I tried using the AVR Dragon on the LED circuit I built last time, but with a larger bulk decoupling capacitance and the chip either didn't power on or was very finicky.

One solution I found which works is to add a large enough capacitor which can temporarily power the device. I put a 10uF capacitor and it was enough to temporarily power my target. You can of course use the high-voltage programmer to program fuses, but I try to avoid the high-voltage programmer as much as I can.

Conclusion

So in conclusion, the AVR Dragon is a decent little tool for programming and debugging. There are several things I don't like about it, namely the weak drive problems, the device disabling the 5V power circuit when trying to program, and the power problem with what I assume is caused by inrush current. Sadly, it is the only official Atmel tool which supports high-voltage programming for when you ruin a chip's fuses. It's also decently cheap, at ~$65 to get everything you need to use the device. I suppose the argument can be made that high-voltage programming isn't necessarily the best way to go if you brick a chip as you can easily replace it for a dollar or two, but oh well. I don't particularly like the form factor, I really like the look of the PICKIT series of programmer/debuggers and the way they device can easily be used as a R&D tool as well as be used in field maintainance. I don't have a PICKIT and don't have any experience with the PICKIT/PIC microcontrollers so I can't say exactly how the two compare, but I do want to play around with Microchip's microcontrollers sometime in the future.

No comments :

Post a Comment