As the subtitle suggests, the higher purpose of this experience was simply for me to have fun messing around with scrapped electronics; however to make it a more coherent job I decided to find a practical use for my work. Once I confirmed the possibility of flashing a new firmware I listed the capabilities of the board.

In order to power the heating panel, the device provided:

Two digits led displays to show passing time

A TRIAC to power the load and a single yellow LED connected to it

An optical encoder to select the time with an included button to start it

A buzzer

Not much, but exactly what was needed for its intended purpose. There were no sensors, just user input and an output load. Barring recreating the timer function with my own code, the only idea that I came up with was to make a light dimmer by piloting the load as a PWM and setting the percentage instead of the time with the digital handle.

Note: If you have any additional idea for this device feel free to suggest it — I had loads of fun doing this!

For reference, a Triac is sort of a transistor for AC current. Think of it as a switch for your house’s power supply. My goal was to use it to drive a load — a lightbulb, a cooling fan — at an arbitrary percentage of its power through a technique known as PWM (Pulse Width Modulation). Basically, you turn off and on very fast the light to achieve a smaller dose of output.

First Mistakes

With my mind made up, I started working on the first lines of code to load on the thing. Here, I made my first grave mistake.

The device itself is powered directly with a 220V A/C source, which it then proceeds to lower to the MCU operating tension. This was a first reason of concern, because all of the connection are exposed and very easy to touch while handling the board. I had to be extra careful while powering it up.

After confirming it worked, I prepared to flash it with new firmware. I have the displeasure of working with Microchip products and tools, so I immediately recognized the programming pins as compatible with typical programmers. Unfortunately, my assumption was wrong.

The strip highlighted in the image provides, indeed, the 5 lines needed to flash the PIC16 — reset, clock, data, ground and 3.3V; they are NOT, however, disposed in the same order as typical Microchip programmers.

When I plugged in both my programmer and the power source, the lights went off abruptly. Terrible sign. I then proceeded to test again without the programmer, and it worked. This means that, without realizing it, I short-circuited something around the programming pins.

Upon further inspection of the PCB lines I realized the pins were all wrong; that, together with the fact that the MCU is not powered through a transformer but with a custom made circuit that does NOT isolate the ground line lead me to believe that I potentially plugged a few hundred volts into my laptop’s USB port, causing a temporary power shortage.

I am not quite sure about what went wrong but luckily, nothing was damaged in the process.

Shortly after followed my second mistake.

I mentioned the circuit powering the MCU is not standard. Lowering an high voltage involves a capacitor strong enough to withstand all those Volts. While I was wrapping my head around the previous problems I mishandled the board: the plug was pulled, but the capacitor was still loaded. I got a jolt of pain through my fingers, but nothing more. Lesson learned: I now only touch it with insulated gloves, whether it looks alive or not.

Edit: happened again while I was taking pictures of the device. Please don’t be dumb like me.

Hacking the Pinout

This is a simple but cumbersome part. I could see most of the traces on the PCB and the model of the device: PIC16F1508. By comparing it with the datasheet’s pinout I could get a pretty good idea of what function was connected to each pin. Plus, on such a simple system there are only 18 GPIOs, so trial and error was cheap.

Finding out the correct lines for the programmer to work with was a little tricky: I had to follow the traces and guess when they disappeared under other components. After ground and 3.3V were discovered by a quick multimeter test the other 3 connections (reset, data and clock) followed soon.

As for the peripherals I configured all GPIOs to output and tried to set them high and low, going step by step through the debugger. Finding the load enable and buzzer was easy (flashy and loud) enough: digit display control and encoder input were a little more challenging.

Digit Displays

The way common digit displays are assembled each segment works like an individual LED; they are all connected to a common anode or catode (the former in my case) and can be driven high or low to light up part of the number. Then, there is an additional line that turns on and off the entire number for each digit. To use less resources however the corresponding segments in each one of the digits are wired together: this means that one can only show the same number on both displays.

How does one shows any number other than 00, 11, 22,…? The answer is magic. Sort of.

Not unlike prestidigitation tricks the way to show different symbols is to be quicker than the eye. Say we want to display “25”: first, you set up the digit “2” by lighting the correct segments and turning on the first half of the display. If both digits were on we would see “22”, but only the first one is enabled. Then turn off the first one, set up the digits to show “5” and turn on the second one. Do it fast enough and the human eye cannot notice the trick: it will read a clean “25”.

An example from a digital clock captured in slow motion

In this case, “fast enough” means less than 10 milliseconds for the whole cycle, a piece of cake even for such a small MCU.

Everything I need is to set up a properly timed interrupt and the game is done.

Encoder Input

Now, this is something I never used before: from the user’s perspective it is like any rotatory gauge; it just never stops spinning.

Under the hood there are two light emitters that funnel into a detector each. The light is shadowed through a striped mask. When the shaft rotates the lights start flashing as holes into the mask move around. By reading the corresponding pulses coming from the sensors it is possible to detect such movement.

So, knowing that the two sensors are connected on GPIOs A4 and A5 I could check for state changes deduce the cylinder was moving. But how do I know which direction it is rotating in?

Every rotatory encoder can have a different approach, but most of them are based on the order in which the two sensors flash. When detector A changes before detector B it is rotating clockwise, otherwise counterclockwise.

With patience I set up a debugging test and made some attempts to see which sensor was changing first and when. Ideally I should have connected the board to an oscilloscope, but beggars can’t be choosers.

In the end, it was exactly like that: when rotating from right to left sensor B was changing before sensor A (by a few hundred microseconds). This is the final code that polls the input:

pulse1 = read_encoderA();

pulse2 = read_encoderB(); if (pulse1 != last_pulse_1) {

if (state.last_pulse_2 == pulse1) {

//The encoder is rotating clockwise

}

last_pulse_1 = pulse1;

} if (pulse2 != last_pulse_2) {

if (state.last_pulse_1 == pulse2) {

// The encoder is rotating counterclockwise

}

last_pulse_2 = pulse2;

}

Dimming the Lightbulb —First Attempt

As mentioned, the board has a TRIAC to control the AC current load. The component itself is driven by an optoisolator which in turn is driven by the GPIO of the MCU. To properly dim the load I tried to use a technique called Pulse Width Modulation (PWM). In short it consists in turning off and on a load fast enough to emulate outputting an arbitrary percentage of power.

In theory, this should be simple enough, not so different from controlling the digit display in fact. I set a variable to indicate the current duty cycle (from 0 to 100) and manage it in the same interrupt timer. Everything nice and ready, but not working.

The lightbulb I had connected to the load was not really lighting up. It worked with a simple on/off strategy, but when the frequency went up the output was flat 0. I inspected the signal driving the TRIAC and found out it was a mess.

After a few hours of hardware debugging I realized that the LED that was supposed to signal whether the output was ON or OFF was also weakening the signal (it was connected on the same pin, before the optoisolator). I had to remove it in order to gain a better signal.

Dimming the Lightbulb — Second Attempt

The result improved, but was far from perfect: the light was flickering seemingly at random. I tried to increase the update frequency and the timer’s precision but to no avail. At this point I sought help from my boss, an electrical engineer.

As it turns out, my idea of how a TRIAC works was fundamentally wrong. I thought it to act like a simple transistor — enable the load when on, disable it when off. Instead it is more complicated than that because it is specifically design to drive an alternating current.

Dimming the Lightbulb —Third Attempt

When I turn it on the TRIAC activates and stays active until it reaches the next zero level in the sinusoidal wave of the AC line. This means that turning it of and on effectively does nothing, depending on the PWM period. What I should be doing instead is turning it on before the next wave reaches zero; how soon I do it calibrates how much of the wave the TRIAC outputs to the load.

Because of this I cannot blindly toggle it, but I require to know when the wave has reached zero to start counting how much time I should keep it off for. This is a problem, because the board I’m hacking does not provide me with such a feature.

Maybe I don’t need it though. When I was blindly turning the load on and off I could see moments of “reduced” light flashing by in the midst of confused outputs. If I could knew even just for a moment where I stood in the sine wave I could take that point as reference and keep cycling periods of 10 milliseconds, which is the constant period at which European A/C oscillates. Then, increasing or lowering the output is just a matter of moving the delayed activation sooner or later, respectively.

I don’t really care that much about knowing where I stand in this regulation; I just want to regulate it. I can consider any moment the MCU wakes up as a starting point and let the user work out the dimming scale.

The question now becomes: “am I able to trigger the TRIAC at sufficiently accurate intervals?”

Firing a timer every 10 milliseconds is a piece of cake, but I’m not sure how much drift off there is. Even being 1 nanosecond late would eventually move the percentage setting from what I have configured if it was happening repeatedly, so I have to be as accurate as possible.

Tuning The Timer

I was already using a timer interrupt to drive the digit display, changing the displayed number every 10 milliseconds. Microchip MCUs have widely different configuration systems for the timer peripheral, with a few common points:

Basically, a 16-bit counter is incremented on each clock pulse. Upon rolling over from 0xFFFF to 0x0000 an interrupt is fired

You have to select the input frequency to feed to the timer (in my case, only the internal oscillator is available)

You can set one or more prescalers to fine tune the oscillator’s input (typically divide it by a power of two)

My first approach was simplistic: the only oscillator I can use is the internal one (powering the instruction cycle), which is 4 MHz at most. Then I set the prescaler to divide it by 256.

4000000/256 = 15625;

This means that the timer will count 15625 pulses each second. I want an interrupt every 10 milliseconds, so I have to set the target to 15626/100 = 156 pulses. I can do this by setting the current timer counter to 0xFFFF-156 to guarantee it will roll over 156 pulses from now.

TMR1 = 0xFFFF - 156;

Then, when the interrupt is fired I turn on the TRIAC pin, which will automatically go down once the AC wave reaches 0 again.

Ideally this should be enough to regulate the output, but the results were less than thrilling.

The lightbulb connected to the output is flickering randomly due to the inaccurate timer

You can see the light flickering more or less at random. This is because my timer is nowhere near accurate enough, and for a good reason. When dividing by 100 to get a 10 milliseconds interval I neglected the error and dropped 25 pulses in the process. Not enough accuracy, but I can increase it.

Instead of dividing by 256 the 4 MHz input I’ll just keep it as it is. Now the timer will increment 4000000 times per second; this amount can be divided cleanly by 100 to get 40000 increments per 10 milliseconds. It also barely fits the 16-bit period!