In response to last month’s article about countdown counters, Jay Dowling states that he does not use countdown counters at all, but only uses countup counters. This allows him to design only countup counters, instead of also designing countdown counters and up/down counters. Plus, counters that count up only require less logic than counters that can count up and down. Supporting only one kind of counter, a countup counter, reduces risk in the design.
In firmware, using a countup counter when a countdown counter is needed requires special treatment. Instead of counting from 200 down to 0, firmware needs to handle it as counting from -200 up to 0. However, this creates problems when trying to use an 8-bit integer variable. An unsigned 8-bit integer (uint8_t) can store values from 0 to 255, and a signed 8-bit integer (int8_t) can store values from -128 to 127. But firmware needs to use it from -255 to 0 to have full access to the range of the counter. My compiler generated a warning when I tried to set such a variable to -200 (as it should):
int8_t cnt = -200; // Compiler warning uint8_t ucnt = -200; // Compiler warning
The following removes my warnings but I have to go through extra steps when reading a value back to make sure it ends up being a number in the right range. In this example, startCnt and currentCnt keep the count as a positive number. Then it is negated when written to or read from the counter register:
int16_t startCnt, currentCnt; startCnt = 200; writeReg (regCounter, (uint8_t) -startCnt); // Make it negative currentCnt = -(0xFF00 | (int16_t) readReg (regCounter));
This is prone to firmware errors when the counters have something other than 8 bits. Note the 0xFFC0 and 0xFFF8 below compared to 0xFF00 above:
currentCnt = -(0xFFC0 | (int16_t) readReg (reg6BitCounter)); currentCnt = -(0xFFF8 | (int16_t) readReg (reg3BitCounter));
If hardware changes the number of bits in a counter from one revision to the next, firmware has to be searched for all instances of reading that register to make sure the correct number of leading bits is added on, a tedious and error-prone process.
The countup counter could be designed to count up to some threshold value (e.g. count from 0 up to 200) but additional comparison logic is required to see if the threshold has been reached and the comparison must be done on every tick.
Jay suggested that a solution is to add a 2’s complement module in front, thereby allowing firmware to deal with positive numbers and allowing hardware to use countup counters. While adding a 2’s complement module does add logic, only one is needed for all the counters in the chip, thereby spreading out incremental cost across all counters. Plus, it is only used when firmware reads or writes to a counter, not on every counter tick by every counter.
Jay also commented that he often uses Gray-code counters because they provide better noise and power reduction over binary counters, since only one bit changes each clock tick instead of as many as all bits changing on a clock cycle.
Jay comes from a background where they look for ways to save microwatts of power. My project teams didn’t need to worry about saving microwatts of power in an ASIC that was going in our 1500-watt LaserJet printers. Jay also had a case where switching all counters in the FPGA to Gray-code counters solved some of their noise problems.
Again, to avoid forcing firmware to do the extra numerical manipulation, a Gray-code/binary translator, along with the 2’s complement module, can be used to access all Gray-code, up-only counters in the chip, thereby increasing firmware quality while taking advantage of a more efficient hardware design.
Until the next translation issue…
2 Comments
But why should that direction be up instead of down? Even for HW design, I think a down counter is simpler than an up counter.
Usually FPGAs have carry (look-ahead adder) enhancements built into them. Full / half adders are well understood / studied / documented. In fact, I was never even taught binary subtraction, it was always take 2’s complement and add. But it really depends on the chip implementation (gate type and organization).
So the short answer is… it depends.