Panic - AVR crashes - cosmic rays - fire - evil electronic demonsDr Nathan Scott & Dr Hiroyuki Kagawa ยท Sep 2006 Bad things happen to good peopleOver the years I have had some very frustrating days, days when I wanted to put all my AVRs in a bag, put the bag on the road, and drive my car over it repeatedly. If you are now in that state of mind, I am full of sympathy and I hope something on this page will help. The Zen of troubleshootingIf you are crazy-angry and throwing things, you are probably not in a mental state that will help you find the problem(s). Do something else for a bit and come back later. Or else look at this picture of a beautiful, calm lake and take some soothing, deep breaths.
Figure 1 You are there, you are really there... Sometimes the answer will come to you while you eat dinner or in the bath. Don't just sit for hours banging your head on your breadboard, this will cause a rash. Having said that, don't ever quit. Persistence has to be the number one quality of all the good engineers I know. They don't give up until they know why something isn't working. Which means that on average everything they attempt seems to work. But they will tell you - they have told me - the secret is just a moderate amount of smartness and a great throbbing pile of stubborn persistence. The first rule of troubleshooting is to try to narrow down where the problem is. If you have two systems connected together, and the pair is not working, you won't immediately be sure which subsystem is at fault (or is it the wire between them?). Disconnect the parts and test each one, then reconnect them. Maybe 90% of the time this will show the way forward. The other 10% of the time the problem really is from the combination of the systems i.e. it is an emergent property of the connected pair. But eliminate the easy things first. The same goes for software. The number one rule for software writing is "change only one thing at a time". This is so that at least you know how to go back one step when everything goes pear-shaped. If you make 23 changes all at once, in a mania of software upgrading, and then the result is no good, which of the 23 changes is at fault? So take it slow. Be ready to go backwards. When things are not working for me, I start to simplify my project. I remove systems and simplify code gradually until the behaviour becomes understandable. So a well-designed project should be at least somewhat modular to make it easy to disable or enable the sub-systems. For example if you have a data acquisition system with a signal conditioning board, always design it to have a ribbon cable with IDC connectors between the two boards. Then you can completely remove the analog subsystem at any time if you suspect it is causing problems. Try to keep a supply of parts handy so you can swap components. When I buy AVRs or indeed any other electronic part, I try hard to buy at least two of them. If you suspect your AVR has been fried, you can pry it off the board, check all the voltages etc., then put a fresh one on. This approach has helped me more times than I can say. Very often it just proves that the problem is NOT with the AVR. They are actually pretty tough. "Divide and conquer" OK, enough wishy-washy philosophical dribble. Here are some classic evil situations and there is a slim chance one of these is a new kind of trouble you have not met. Help me make this better - send me your suggestions for additional topics, stuff you have learned. AVR does not seem to be running at all or can't be programmedThe AVR starts running when the power turns on provided various conditions are met:
If all the above seems OK and you still can't program it, here's something to try. Check that there is a reasonable amount of capacitance between your GND and VCC wires PHYSICALLY NEAR YOUR CRYSTAL. As a minimum I suggest a100uF electrolytic capacitor across the main GND and VCC wires of the AVR, right next to the XTAL1 and XTAL2 pins. Be sure to get it the right way around. If this solves your problem then I hope you can understand why. The AVR runs at many MHz, say 8 MHz, and this means it demands power in a fluctuating cycle at about the same rate. If the AVR demands power it means some current must flow from your power supply to satisfy the demand. But if the wire is long, say about one meter long, it has a small but important amount of inductance. Such a wire cannot instantly supply current to a load because it takes some time for the magnetic field to build up around the wire. Remember from physics at high school - a current in a wire causes a magnetic field around the wire. If you want the current you have to accept the magnetic field too, they go together and we don't have any choice. A small amount of energy is stored in the magnetic field. This is why inductors resist changes in current. Anyway if you have long wires and the AVR is demanding sudden changes in current, the wires will be bucking the change at every chance and this can mean that VCC does not stay nice and constant. It can actually be so bad that the AVR gets reset all the time. The answer - you guessed it - is to put a fat capacitor right near the AVR to smooth out possible pulses and spikes that could appear in the power supply. If that did not solve your problem, you may need to get access to an oscilloscope to check whether there is a good oscillator signal at XTAL2. If the oscillator is running, you should see a strong and roughly sinusoidal voltage at the correct frequency, and with minimum value about 1V and maximum value about VCC-1 V. So if you are using VCC = 5V you should see a wave with minimum 1V and maximum 4V. In my projects I always have an LED which is set up to flash about twice per second (see the TMR0 tutorial for one way to do this). Do also check the next section because "not running at all" can look a lot like "running but in a disabled or limited way". AVR is programmable and running but some features are not workingRecall that the AVR has effectively two "simultaneous" threads: the main program thread and the interrupts. It is possible for one of these threads to be stopped because of a software error, and for the other thread to carry on. The usual problem is an accidental endless software loop. If such a loop happens in any interrupt, the interrupt will never terminate and all other interrupts will thus be disabled. Remember - only one interrupt can run at a time. If there is an endless loop in the main program thread, the main program will stop. However interrupts can carry on so some functions (like my flashing light above) will happily continue. If you think you may have endless loop problems, carefully check all your for and while loops. Is there any way any of them might never finish - perhaps because of an unexpected combination of inputs? Are you using the INT0 or INT1 interrupts in your project? Recall that the default preference for these is "continuous interrupt while low". If you then also happen to have a low voltage on PD2 or PD3, this will mean that INT0 or INT1 is always firing and is using up close to 100% of the AVR's brain power. No other interrupt will get a look in because INT0 and INT1 are very high priority. An oscilloscope trace of the PD2 or PD3 signals might really help in this case. AVR runs but resets all the timeIn my programs I nearly always have two safety features:
I have traced my AVR reset problems to the following causes:
C languageWhen I first started writing C I made a whole lot of stupid errors. In some cases my compiler was wise enough to issue a warning, but in other cases there was none.if (a = b)...Classic, classic error. In C the "=" means "copy the value of b and put it into a". C also allows the operation a = b to have a "result" which is just the value of a after the copy operation. And C permits any integer to be a valid boolean, with 0 meaning FALSE and anything else, TRUE. So "if (a = b) ..." does two unexpected things. First it overwrites a with some value you might not want in there. Then it does a boolean check on that value alone rather than its relation to b! So go over your code and check all your if statements. They should all use "==", the double equals, the COMPARE operator. Some C programmers do actually use the "if (a = b)..." notation deliberately but I really strongly suggest you don't. if (a % 10) ...I used this once when I wanted to do something only every tenth time through a loop. But it happened nearly every time. Then my brain engaged and I realised that a % 10 means "remainder after dividing by 10". So it is nearly always non-zero and thus nearly always true. I should have written "if ((a % 10) == 0)..." case without breakICCAVR compiler bugsWhen I first started using ICCAVR I was also just starting with the AVR and with microprocessors generally. I had lots of problems of course and in the early days I was very quick to blame the compiler. However I have gradually come to understand that 99+% of those "compiler" bugs were actually MY ERRORS. However that doesn't mean the compiler is perfect. Here are some things that really do seem to be compiler bugs: Using pointers with global variabls unsigned long int g; // note this is a global variable void doSomething() { _StackCheck(); // we will almost certainly NOT detect stack damage at this point. char *c = (char*) &g; *c = 12; _StackCheck(); // we will almost certainly detect stack damage at this point. } I have no idea why this problem occurs - it's a bug. Here is my solution. void doSomething() { unsigned long int local; // note local variable, same size as the global we really want to change _StackCheck(); // we will almost certainly NOT detect stack damage at this point. char *c = (char*) &local; // note that we only set up the pointer to the LOCAL variable - seems to be a safe operation *c = 12; // set LSB of local variable _StackCheck(); // should be OK this time g = local; // copy local variable contents to global variable } |
|
|
|