Monday, 4 January 2016

Updating our Christmas lights

Part #3

Firmware

The firmware (embedded software within a microprocessor/microcontroller) is done. Well, the first cut, anyway. As is the first cut of the board.

But I have a huge problem to figure out: how to test the firmware? I particularly wish to test the I2C interactions, as I've never written full-on I2C interaction code (though, in truth, I've pulled much from a Microchip PIC application note... but the issue is that the AN is written for a different chip and the memory layout is different, resulting in different code in many places!).

The cause of my dilemma is that the simulator within the MPLAB X development environment does not include simulation of signal-level communications devices, including I2C - meaning the first time my firmware code looks to verify a response from the target memory, an infinite loop occurs as the response is never received. I can prod the I2C module by injecting anticipated target memory responses, but that's not the same. And my preference is to test the firmware separate to the hardware if at all possible - so that any issues with the board can be pinned down to the board specifically, rather than a possible combination of hardware/firmware errors.

I've looked around to see if there were packages for my particular controller of choice for this circuit, but alas there aren't (though one company did have a nice special that ended early this morning our time on similar but not quite the same chips, so I didn't buy it... Part of me is regretting that already since some of the other devices I'd been looking at using the in past were in that deal, and the package included I2C simulation specifically with one of the EEPROM memories I'm looking at).

Another alternative is to write my own, possibly using the VLAB tools (written by a former workplace of mine, ASTC). The only problem there is that I'd still have to write a whole bunch of models for each of the PIC on-chip peripherals, and then I'd have to test the models individually in order to ensure the models were accurate before running my potentially dodgy code over an integrated set of them.

Alternately, I just do what I'd least like to do: finalise the board and build it (using something like ZIF sockets, particularly for the PIC chip to allow its extraction for re-programming). My PIC programmer, however, doesn't include the capacity to program the I2C EEPROMs... so I'll also need to buy a programmer board for them, too. Found a free board/PIC-based program at http://openprog.altervista.org/OP_eng.html, so have downloaded it and will proceed to get the components, make that board and see how I go.

My plan is to program one address in one chip, and write a small program that simply extracts that one value, and dump that 8-bit value out of port C on the PIC (via a bunch of LEDs). If that's successful, then I can proceed with the full version as the full firmware basically does the same job throughout.

Moreover, the 6 hardware PWM modules are pretty easy to configure, and the interrupts for the software PWM and the 0.56s and 2s periodic flashing lights I can simulate using the package (I will need to inject the I2C responses in order to get to that part of the code, though).

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...