Saturday, 2 January 2016

Updating our Christmas lights

Part #2

PWM configuration

In my previous post, I'd selected the PIC16F18344 as the baseline controller, but mentioned it had an issue with the internal EEPROM memory (that's memory that isn't erased when the controller loses power... an important consideration since we run our lights off a timer switch, so when they go off at night the controller will lose power!): it had nowhere near enough.

Running the controller flat out at 32MHz internal clock (instructions are executed every 4 clock cycles) means that the PWM modules can have a base frequency of not quite 500Hz (488.28125Hz, actually). This is the TMR2 (timer 2) module with the 1:64 prescaler and rolling over once every 256 cycles (since TMR2 is an 8-bit timer) at that /64 clock. TMR2 can be used as a period timer for the PWM modules, and 488Hz gives a period far shorter than the human eye's sample rate (PWM period is approx 2ms, human eye's sample rate is approx 32ms).

Given that I'm after 8 PWM outputs, 2 of which need software interrupt control, I need to run the chip as fast as possible, otherwise there'll be out-of-synch issues with the software PWM timing. Given that the PWM values need to be extracted from somewhere, I can of course compensate for that to some extent by factoring in a small buffer for values between full off and full on.

Here's what the 8 PWM outputs will do:
  • CCP1 (put into PWM mode) will run the blue section for blue/green/red/orange sets
  • CCP2 (put into PWM mode) will run the green section for blue/green/red/orange sets
  • CCP3 (put into PWM mode) will run the red section for blue/green/red/orange sets
  • CCP4 (put into PWM mode) will run the orange section for blue/green/red/orange sets
  • PWM5 (dedicated PWM module) will run section 1 of the icicle lights
  • PWM6 (dedicated PWM module) will run section 2 of the icicle lights
  • software PWM using TMR1 will run one set of monochrome lights
  • software PWM using TMR3 will run a second set of monochrome lights
The CCP and dedicated PWM modules have dedicated outputs, so there's no need to handle any interrupts for them. The software controlled ones, though, operate off 3 interrupts:
  • TMR1's and TMR3's interrupts fire when they overflow. Thus, with each timer pre-loaded with a duty-cycle value, the overflow interrupt handler toggles a separate GPIO pin low.
  • TMR2's interrupt also fires on overflow; this overflow co-incides with the CCP and PWM modules also beginning a new period and their dedicated hardware PWM outputs going high. So the TMR2 interrupt also fires a handler to set the TMR1 and TMR3 GPIO pins high.
Note that because the TMR1/3 and TMR2 interrupts are likely to be at different times, the TMR1 and TMR3 interrupts will fire between TMR2 interrupts (since the actual full count periods of the 3 timers is the same)... meaning those outputs will toggle like a PWM output should. There is a caveat, though: if the duty cycle values are 0 or 255, then the outputs are set and left alone.

Port C on the PIC16F18344 is an 8-bit port, and can easily be configured to have the 6 hardware PWMs route directly out, so will simply manually trigger RC6 and RC7 off the software PWMs. So there we go: 8 dedicated PWM output pins!

Periodic half-duty-cycle flashing




I've also had a thought about periodic flashing lights of a different sort: every half second and every 2 seconds. These'll run off TMR5, which will roll over every 0.5s, and an external counter in a variable will count every time it rolls over; once this count hits 4, the 2s output is toggled. No interrupts will handle this, as the main program is otherwise just clearing the watch-dog timer and getting set up for the next duty cycle values for the PWMs, so having it poll the TMR5 overflow flag status bit will be OK as well (none of the other tasks - including the interrupts - actually takes more than a few milliseconds, so you won't see any deviation in the period. I hope).

Will have to sort out which pins to use, once I solve the memory issues...

Memories, all alone with my memories...

(sorry, couldn't resist that).

I've discovered that Microchip/Atmel make a nice set of EEPROM chips with an I2C interface. The chips - regardless of the amount of memory on board - have only 8 pins. More importantly, any up to the 512kbit memories have 3 of their pins able to set a hardware address, so that you can have 8 different chips on the one I2C bus which can be selectable by the I2C control word sent as the first part of the I2C transaction. 8 EEPROM chips: one for each PWM channel! Sweet.

And, with 512kbits and 16-bit duty cycle values per PWM channel, I've got 32768 separate values I can use.

I'm not sure I want to have a re-load of the duty cycle every time the PWM rolls over. That gives me a complete pattern cycle of only just over a minute!

A better option is to have it trigger over 10th of a second, or as close to possible. This allows for significantly fast flashing if I need, but also allows for less chunky steps in the gradual bright/dim pattern as well (some early controllers with only 4 bit PWM resolution clearly show the steps and they look horrible).

I can configure TMR0 of the PIC16F13844 to fire every 0.098s, which is close enough. 512kbit EEPROMs thus give me a full pattern cycle of around 57 minutes. Nice :-) .

The PIC16F18344 defaults to the SCL I/O pin on RB4 and SDA on RB6 (clock and data lines of the two-wire I2C bus). That leaves me RB5 and RB7 to use for the 0.5s and 2s period outputs, and leave port A completely free for other stuff if I need (though RA3 I'll use as a manual reset input - probably not used on the final product but at least I can use it during hardware debugging!).

Off to design the circuit, board layout and firmware for the PIC16F18344. Stay tuned...

No comments:

Post a Comment