Arduino ATMega8 freeze when using PWM

edit

I did some more testing, it only happens on ATMega8, ATMega328 works fine so text below can be ignored in case of it.

In short, when I use PWM output on arduino pin 9 with ATMega8 MCU freezes, digitalWrite works, analogWrite doesn’t. I don’t know what could be the issue, ATMega328 works fine with same circuit, configuration and code.

Hi, I’ve stumbled on a problem (as expected) :smiley: with using PWM on ATMega8/328 while using internal 8MHz oscillator. Simply put, I can’t get PWM to work. On ATMega8 it freezes MCU and on ATMega328 it doesn’t seem to do anything. Are there some limits on using PWM (analogWrite) while using internal oscillator?

That’s my problem in short, now the whole story :). I’m trying to make custom Lego train motor controller. I used Arduino Uno for development, it’s rather simple actually, IR 1838B reciever for remote controll, few leds to be used as front and back lights on the train, and L293D to drive DC motor of Lego Train Power Functions.

With remote I can turn on and off front and rear LEDs separately and I wanted for DC motor to have several speeds that I will control via PWM on pin 9 (0%, 50%, 75% and 100%). While everything is connected on breadboard it works fine.
It should go inside Lego train so I need it to be as small as possible. So I’ve made minimalistic PCB and I wanted to use Atmega8 (that’s why I chose pin 9, it’s OC1A on both Atmega8 and Atmega328) as code fits in it and I have quite few of them in TQFP package, to save some space I decided to use internal RC. I’ve made the PCB, soldered the components, recompiled it for ATMega8 and flashed it to MCU via USBAsp. It seemed to work fine until I tried to start the motor, nothing happened and when I tried to start front/read LED’s also nothing happened. Like MCU froze.
I changed the code to simple on/off (digitalWrite instead of analogWrite) and it works as expected. No more lockups, I can turn it on, reverse it, turn LEDs on and off…

After that I built similar test circuit on breadboard with simple leds so I can test it on another ATMega8 to see if the one I soldered was faulty. I again tested this simple code on Uno and it worked fine. Recompiled and flashed it to ATMega8 and it froze again. Simple led on/off works, but PWM one freezes MCU. I used to LEDs, one remote button toggles on/off of one of these LEDs, and the other one changes PWM value of analogWrite for the other LED. On/off works fine, but as soon as I press button to trigger analogWrite on the other LED it freezes, I can’t even control on/off LED until I reset MCU.
I tried the same thing with one ATMega328p I had around, the same as one used on Uno, except I configured it to use internal 8MHz oscillator instead of external 16MHz as it’s on Arduino and PWM similarly didn’t work. Only improvement was that MCU didn’t lock up, PWM LED didn’t react, but other LED still reacted. I also added test code to PWM part to see if it even triggers (simple ++ counter that counts how many times I pressed remote button and then it blinks the other LED that number of times) and that also works, so it’s not that it “skips” that part of the code.

Sorry for the long story :slight_smile:

I've tried some more things, turns out resistor for PWM LED wasn't plugged in all the way on one side and that's why it seemed not to work when I used ATMega328p.

Code works on ATMega328p with internal oscillator or external crystall oscillator (tried 8 and 16 MHz) and corresponding fuses. But on Atmega8 when I triger analogWrite MCU freezes regardless if I use internal or external clock. I'm out of ideas, arduino pin 9 should support PWM on both ATMega8 and ATMega328 but for some reason it freezes ATMega8.

PWM is related to a timer. Whenever you use that timer for other purposes, its PWM outputs stop working. Or, if you use a analogWrite() to a pin connected to that timer, it will reset whatever you programmed it before. Each controller can have a different number of timers, and different pins connected to those timers. Have a look at the data sheets to find out more.

And most probably the ATmega8 doesn't freeze due to analogWrite(), it must be something else in your code that stops it.

Thanks for the reply :).

I don't use any timers directly, only if IRremote library uses it. But then again ATMega328 works fine with same code (recompiled for it, of course).

I've made reduced version of this code and I'll try to tidy it up a bit and post it. Basically it waits for signal from IR remote and depending on button pressed does one of three functions. Increase PWM value on pin 9, decrease PWM value on pin 9 and toggle pin A2 (I use it to check if it's still "alive").

I just did quick test, I removed all this PWM increase/decrease code and replaced it with "analogWrite(9, 200);". So now I have two functions, one toggles led on A2, and the other sends analogWrite(9, 200) and same thing happened, if I press key for LED toggle on A2 it lights up, or turns off. If I press key that does analogWrite it stops responding on any key.

IRremote also uses a timer, again depending on the controller type. You can select the timer-to-use in that library, so that it doesn't conflict with the PWM timer. Most probably the analogWrite() affects that timer, turning off IRremote.

Thank you! That was a push in right direction :). I've found timer declaration in IRremoteInt.h, for Atmega8 it says #define IR_USE_TIMER1 which is associated with pin 9. I tried changing it to IR_USE_TIMER2 as it's on Uno/Atmega328 but it won't compile, I guess it needs more changes because or timer registers that are not defined for timer2 on Atmega8.

Thanks again, I learned something new to be careful with :)

If you look into the library, you'll find the available timers for each controller type, and only one of them should be uncommented. If no other timer is offered for the ATmega8, no other timer can be used, and you should use a better equipped controller.

Yes, I've seen that, ATmega8 has only timer1 set up, but there's still timer1. They say more setting can be added if needed and there's timer2 left. I suppose nobody needed it, Atmega8 is rather old.

For now I've cut trace from pin 9 and soldered jumper wire from pin 11, analogWrite works on this pin as it's related to timer2 instead of timer1. I'll try to add support for timer2 on ATmega8 in IRremote library when I find time. Maybe it'll work, maybe it won't, but at least I'll learn something along the way :).

Thanks again, Lego train now runs with variable speed :D.