Skip to content

Another Pit Stop – Software PWM

September 22, 2014

I’ll be travelling for a couple of weeks and no hardware work.  I’ll be bringing a copy of the arduino version of the code though and some of my notes on software PWM.

I got some good ideas on PWM from the cosmac elf mailing list.  Maybe the one closest to my heart is from mike mclaren who suggests a toggle table and the working routine like

void stepinterval()
{ portb ^= toggle[step];     // update pwm outputs (RB0 & RB1)
  toggle[step++] = 0;        // clear element for next period
  if(step == 10)             // if end-of-period
  { step = 0;                // reset 'step' index and
    toggle[dc0] |= 1;        // insert b0 output toggle bit
    toggle[dc1] |= 2;        // insert b1 output toggle bit
    toggle[0] ^= ~portb;     // setup 1st element
    toggle[0] &= 0x03;       // only the RB1 & RB0 bits please
  }                          //
}  

Josh Bensadon explained the basics in a way that I could understand

The simplest solution is to use a byte value, compare it against a timer and use the DF flag as your PWM output. How much do you want to do in hardware? Doing more in Hardware frees your code to do more complex tasks. There’s 2 ways to doing it in software. 1. Interrupt method. 2. Polling method.
#1 speaks for itself, #2 can be done with a dedicated subroutine and a simple change of the P register to call/return, then insert the DX commands evenly throughout your mainline code.

The PWM routine…
increment your Timer variable (could be register for speed)
subtract Timer value from Motor0, then don’t panic, just shift the DF flag into your virtual output variable.
repeat for Motor1
Then send the virtual output variable to the port.

You could use the upper register of the register you’re using for a timer. Just shift the DF flag (twice) into the MSB (forcing the two LSB’s to be discarded). Then after sending the byte out, readjust this register by shifting two 0’s into the LSB, thus negating any roll over of the timer counter.

Also, you can choose to either ADD to the timer or Subtract, either way will cause a PWM on DF.

I’ve done similar code on the PIC to run my toy Tank.

Lee Hart had some excellent suggestions:

It’s best not to have your program completely tied up with the PWM loop.
To get around this, use a timer and/or interrupts to create your PWM output.

To create a timer, connect DMA-OUT to SC1. When the 1802 fetches or
executes, SC1=0; this requests a DMA cycle. When the current cycle
finishes, the next cycle will be DMA-OUT. R0 appears on the address bus,
and a byte from RAM on the data bus. The DMA cycle sets SC1=1; this
makes the following cycle the next Fetch.

This alters the normal Fetch-Execute-Fetch-Execute sequence into
Fetch-DMA-Execute-DMA-Fetch-DMA-Execute-DMA. Remember this when writing
your initial program where R0 is the program counter!

Now you can put a table in memory that provides the PWM pattern. An
output port latches each DMA byte. Each bit can control a different PWM
device, or provide a different rate.

Reset R0 periodically, either in your main program or with an interrupt.
The interrupt can be generated by one of the DMA output bits, so you can
control how many DMA cycles are executed before it loops. Example: If
bit 0 is interrupt, and bit 1 is your PWM, then

100%: bit 0: 10 reset R0 every 2 DMA cycles
bit 1: 11 100% on-time
66%: bit 0: 110 reset R0 every 3 DMA cycles
bit 1: 110
50% bit 0: 1110 reset every 4 cycles
bit 1: 1100
40% bit 0: 11110 reset every 5 cycles
bit 1: 11000
33% bit 0: 111110 reset every 6 cycles
bit 1: 110000

You get the idea. Crude step size, but negligible hardware and memory
requirements.

Or, use up a counter to generate an interrupt every X clock cycles. The
interrupt handler counts interrupts, and compares the number to the
desired PWM value. If the count is over the PWM value, turn on Q. When
the count rolls over (say, from 255 to 0), reset Q. Q then becomes your
PWM output.

Or, you can use a parallel-in serial-out shift register as your PWM
generator. Its serial output is looped back to its serial input. When
not loading, it simple recirculates whatever is in it forever. If you
load it with all 0’s, the output is always low (0% PWM). If loaded with
all 1’s, the output is always high (100% PWM). If you load it with 1
thru 7 1’s, you get 8 intermediate PWMs (1/8=12.5%, 2/8=25%), etc.

There are more ways; but this will get you thinking. 🙂

Advertisements

From → Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: