Software PWM of all pins

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've made a simple LED display controller. AtMega32 is directly driving the LEDs and commands are sent using serial communication. The software is very simple. An interrupt is fired when something is received in serial and the ISR sets the PORTx registers according to the command received.

 

Now I've noticed that I need a way to control the brightness of the LEDs. Therefore I need PWM.

 

The question is if there is a way to do it without touching the PORTx registers? Could I just set the ports as inputs through DDRx registers when the LEDs should not illuminate? Should I also disable the pull-up resistors with PUD bit in SFIOR?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Soft PWM on any number of pins is easy. You pick a timer you set up both compare and overflow interrupts. At the overflow you set all the outputs high (probably?) and in the compare you set one or more output pins low. If all the outputs need the SAME duty cycle you just set them all at the same time. If different pins need different duty then you arrange for a "compare" at the time the first one needs to change, then you set the offset to the relative time of the next one that needs to change and so on.

 

You do all this in the completely "normal" way. You initialise the DDRs to "output" for the pins that will drive. At the time of the overflow and the compare you set the PORT bits high or low as required.

Kestis wrote:
The question is if there is a way to do it without touching the PORTx registers?

I have no idea what you mean by that? What would be the appeal of driving pins using anything but PORT ?

 

In the tutorial forum there is a "long" thread about timers and somewhere in that thread I posted a very simple example of a one-pin soft-PWM (I was using it to vary an LCD brighness but couldn't use the pins actually dedicated to the PWM output). Might be worth a look if you can find it.

 

EDIT: oh boy the search engine here is poor. But using Google I found this:

 

https://www.avrfreaks.net/commen...

Last Edited: Wed. Jul 11, 2018 - 08:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
What would be the appeal of driving pins using anything but PORT ?

The reason is in the way my software works. Currently the information about pin states is not stored anywhere else than the PORT registers. I would need to rewrite my software if I made the PWM using PORT registers. Therefore I'd like to have the PWM completely separated.

 

There is following table in the datasheet. It looks like I could set the PUD to 1 and then do the PWM by setting the DDR register.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kestis wrote:
Currently the information about pin states is not stored anywhere else than the PORT registers.
Well for one thing I'm not sure why it would need to be. PORT registers are read/write registers so it's a perfectly valid place to hold (and later read back) "state last set" - so you don't really need to hold that anywhere else do you? But if you did surely you could just add a bit array to keep track of settings?
Kestis wrote:
It looks like I could set the PUD to 1 and then do the PWM by setting the DDR register.
I seriously don't know what you are talking about. What is wrong with using DDR = (1 << n) and then later PORT |= (1 <<n) or PORT &= ~ (1 << n) to define the output state and, as I say, if you need to know current state then if (PORT & (1 << n)) or if it's simply that you want to "toggle" then PORT ^= (1 << n)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to give an example.

Step 1. Some of the LEDs illuminated. One of the PORT registers could be 0b01001110

Step 2. The timer interrupt turns them all off and the register now equals 0b00000000

Step 3. Another timer interrupt should turn the correct LEDs on again. The PORT register was cleared in the previus step so the information about LEDs that should be illuminated is not available anymore.

 

It would be way easier if the PWM could be done just by setting the DDR register 0x00 or 0xFF. Otherwise the contents of the PORT register would need to be copied somewhere else to save them until the LEDs are turned back on again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kestis wrote:
Step 3. Another timer interrupt should turn the correct LEDs on again. The PORT register was cleared in the previus step so the information about LEDs that should be illuminated is not available anymore.
So store it in a variable.
Kestis wrote:
Otherwise the contents of the PORT register would need to be copied somewhere else to save them until the LEDs are turned back on again.
Why is that a problem? The pattern of "used bits" is surely just one uint8_t for each PORT ? What's more , if fixed (const) it presumably does not even need to occupy RAM but could be in __flash?

Last Edited: Wed. Jul 11, 2018 - 10:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kestis wrote:

Could I just set the ports as inputs through DDRx registers when the LEDs should not illuminate?

 

Yes.

 

If I write this (my LEDs are active low) then the odd numbered LEDs flash on and off...

 

  LED_DDR = 0xFF;
  LED_PORT = 0x55;

  while (1) {

    delay_ms(50);
    LED_DDR = 0x00;
    delay_ms(50);
    LED_DDR = 0xFF;
  }

 

Kestis wrote:

Should I also disable the pull-up resistors with PUD bit in SFIOR?

 

The pull-up value is quite high so you may not notice anything, but it won't hurt to disable then just to be sure.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

can you tell why  step 2 in #5 write a zero ?

 

there are something wrong with your PWM if an ISR (not releated to PWM change the output). If the ISR is about some other pins on the same port then just AND with a mask so those become zero. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Should I also disable the pull-up resistors with PUD bit in SFIOR?

Remember, this will apply to your non-led inputs as well 

When in the dark remember-the future looks brighter than ever.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I got it working fine.

avrcandies wrote:
Remember, this will apply to your non-led inputs as well 
That's not a problem as the only input is the serial interface. None of the GPIO pins is used as input.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kestis wrote:
. I would need to rewrite my software if I made the PWM using PORT registers.
Re writing parts of the code during development is very common and called refactoring. A lot of refactoing can be avoided if you have a lot of experience and/or planned thoroughly what the code must do, but sometimes the crystal ball is too opaque to do that.

 

Slapping on new functionality while trying to avoid touching already written code is a recipy for disaster in the long run.

Your code will become increasingly more convoluted and more difficult to maintain.

Learn how to keep the flow of your sourcecode clean during development.

Writing code that is easy to understand for human beings is more important than forcing the uC to accept your latest idea.

You probably want to be able to understand your code 5 years from now.

If you write your code in an easy to understand way, you will have less bugs, and bugs are easier to find.

 

For the PWM stuff, it might be a good idea to write your led data to a RAM buffer and write some timer based interrupt routine for the PWM-ming.

Another idea is to add an external transistor or mosfet with a single hardware PWM output.

If you use some shift registers such as 74xx595 for the leds, you can use the output enable to PWM the leds.

74HC595 can deliver 35mA per output, but only 70mA total (DC) You can reverse the polarity of half the leds on each 74hc595 to double the output current capability. (I think).

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com