PICking a Battle: Tales From a Cave Dive on IoT Development World
Cristiano Monteiro
Solutions Architect @ Dassault Systèmes | Global Solution Provider
Preamble
If you’re, for any reason, attracted by IoT, embedded applications, electronics, gadgetry, etc, this short text is made for you. If not, stick around and drink as much as possible from it. This stuff is here to stay, learning a bit more about them can’t hurt.
Please note I get verbose on some topics to make it enjoyable and informative for people with less familiarity with the topic.
A New Journey
After investing some time learning and developing Internet of Things (IoT) devices based on the popular Arduino framework, I’ve decided to go a step further and start a small project to exercise microcontroller (MCU) development without the training wheels of Arduino. Please allow me to share where I got, so you can do the same if you feel so inclined.
?
Arduino vs Native Development
Arduino is a great start in the world of embedded development. Its abstractions, making portability across microcontrollers easy, and the HUGE libraries portfolio are a big plus for rapid prototyping and to get your hands wet. However, when the need arises to squeeze the last bit of performance from a chip or maximize usage of the embedded peripherals for a given architecture or anything else, better get acquainted with the chip architecture and its native calls.
Take for example Arduino default encapsulation for setting a pin high (making it a logical 1):
digitalWrite(13, HIGH);
Where?digitalWrite?will execute the following:
void digitalWrite(uint8_t pin, uint8_t val
{
????????uint8_t timer = digitalPinToTimer(pin);
????????uint8_t bit = digitalPinToBitMask(pin);
????????uint8_t port = digitalPinToPort(pin);
????????volatile uint8_t *out;
????????if (port == NOT_A_PIN) return;
????????// If the pin that support PWM output, we need to turn it off
????????// before doing a digital write.
????????if (timer != NOT_ON_TIMER) turnOffPWM(timer);
????????out = portOutputRegister(port);
????????uint8_t oldSREG = SREG;
????????cli();
????????if (val == LOW) {
???????????????*out &= ~bit;
????????} else {
???????????????*out |= bit;
}
????????SREG = oldSREG;
})
Almost every line in the above example will waste at least one computing cycle. Translating: It will cost time! While a native call on the chip selected for this project would be:
?LATAbits.LATA1 = 1;
Don’t get me wrong, in my opinion Arduino is doing the right thing, hiding in a failproof envelope possible complexities in common functionalities, enabling it to handle the vast majority of usages. This is great, only failing when utmost performance is needed.
This is the main reason behind this exercise, explore a microcontroller's native environment and maximize usage of its internal peripherals. All of that utilizing C language (assembler… well… will reserve that for a future exercise).
Microcontrollers vs Microcontrollers
In the world of embedded development, the microcontroller unit (MCU) is the central piece. It’s a tiny, self-contained computer, which consumes very little energy and can be programmed to do almost anything we want, like their big brother, the desktop computer.
When it comes to options about which microcontrollers to experiment with, the field is enormous. So many options that the differentiation between them gets smaller every day. So, instead of focusing on the latest and greatest, I decided to dive into a relatively simple and old acquaintance of the industry and “pick” myself an 8-bit PIC controller, currently a product of Microchip company. Having roots dating back to 1976, when the first specimens were released in the wild, today PIC family is a never-ending, constantly evolving fauna of more than 2000 device models, according to the latest manufacturer compatibility chart.
It′s usual for a PIC controller to operate in the area of a few milliamperes and, when in sleep mode, go down to a few micro or even nano amperes when the proper low current variant is chosen.
PIC Core Independent Peripherals
?A PIC chip can be had by a few cents for some models and can feature a plethora of internal “Core Independent Peripherals”, hardware-based micro-machines which can run independently from the main processing core and perform several tasks, like timekeeping, signal conversion, external input detection, communication protocols handling, etc.
?See below the built-in peripherals offered with the MCU used in this project (PIC16F1827):
The project
One approach I recommend when learning new, real-life applicable, things is to go hands-on. In this instance, I needed a small project where I could exercise two or more capabilities of the target learning object. The idea that immediately occurred to me was an electronic dice! A small physical object that would replace a traditional dice. Instead of throwing a regular dice, a player would shake my electronic version, put it over a table, and after a second or two of anxiety-provoking suspense, the device would present a random value between 1 and 6, as a real dice.
?<nit-picking>Please note that since the current form only presents one random number, some English speakers would expect me to refer to it as “die” instead of “dice”. I will keep using "dice” as it doesn’t appear to be a consensus on the singular form, some countries utilize die for singular and dice as the plural while others utilize "dice" for both. Also, the project can be easily extended to present two or more distinct random numbers</nit-picking>
With this idea I could exercise some MCU features, like Random number generation (to select a value to be displayed), low power modes (to save battery when not in use), hardware timers (to determine when the user stops shaking, when to go to low power, etc), interrupt handling (to wake from sleep and feed entropy to the random number generator).
The selected number should be presented in a bright 7-segment led display, so it is visible by everybody playing and consumes minimum energy since, due to its nature, this device is better suited to operate under small batteries.
A 7-segment display will consume, well, 7 pins from an MCU, as you would expect. 8 pins if the decimal point were to be used. The “shaking sensor” switch will utilize one additional pin. If we consider the GND and VCC pins, this brings a possible total of 11 pins used. So, 12 pins or higher MCU is best suited.
I decided to go with PIC16F1827 since it possesses 18 pins (can leave the programming pins dedicated for that task), comes with 1 hardware breakpoint (you can stop your program execution at one line and observe the contents of the variables to solve bugs) and is one of the very few available in my country (chip shortage is real, several models have now 52 weeks or more lead time!)
So, eDice project was born!
Entropy and Randomness
A key part of the project is the random number generator. Nothing worse than a dice that keeps repeating the same number or in which the sequence of numbers is predictable.
Unfortunately, a characteristic of simple MCUs like PIC16F1827 is that it possesses a pseudo-random number generator only. The “random” numbers generated by it are not truly random. I ran some experiments and could determine that, upon reboot, the same sequence of numbers (mod’ed to a value between 1 and 6) would be offered every single time.
To counter this characteristic, some entropy needs to be seeded to the pseudo-random number to turn it into a truly random number. That’s is, collect external, real-world organic inputs and use that to tweak the random number.
To accomplish that I’ve set up one of the 5 available internal timers of this PIC to run constantly and each time the shaking sensor switch detects a movement the chip will sample the current time (down to milliseconds), mix that with the pseudo-random number and keep it, to be mixed with next sampling also. This means that the more you shake and vary your shaking pattern, the more random the next number will be.
As for the shaking sensor, a regular, incredibly simple, and effective mercury switch, which is no more than a small glass bulb where the two metal leads penetrate and a small mercury drop roams freely, making and breaking contact with the leads as the piece moves in space.
Low Power and Extreme Low Power
Due to the natural size constraints and the ubiquitous availability, I’ve selected the worldwide famous CR2032 3V battery as the powerhouse for the project. Fun fact: CR2032 gets this name because it's 20mm wide and 3.2mm tall.
Compact enough to be fitted in small spaces, the CR2032 stores on average 235 mAh, which I need to maximize usage to squeeze a decent life span out of it.
According to specs, a PIC16F1827 will consume about 19 uA in low power mode, having it's “L” sibling (PIC16LF1827) a mere 30 nA on sleep. Unfortunately, the L versions are VERY hard to find in this corner of the universe.
A lot of factors can influence the actual power consumption, but most of the waste from this project came from Floating I/Os (unassigned and unused pins will have current fluctuating on them), which got properly mapped and/or pulled down/up by a resistor; running timers, which got temporarily suspended when not in use; floating hardware switch, which was pulled down by default.
?Here are the measurements I did with all display segments lit, about 40 milliamperes:
Now in the maximum energy saving mode, around 23 microamperes. By my calculations a fully charged CR2032 should last more than 1 year while idling:
Switch bouncing
?One thing about switches is the “bouncing effect”, the mechanical oscillation from metal contacts coming together that causes microseconds intermittence on the electrical contacts. In a digital system, it can be disastrous, since the combo MCU + Software most of the time expects a solid electrical signal when a switch is pressed/triggered so it can run the associated routine. If a single press can translate to what essentially is multiple contacts, the associated function may be triggered several times in sequence leading to undesirable results. So, a debouncing method is required. It’s a largely studied and documented topic, for which many hardware and software solutions are available, hardware ones being preferred since they will save precious computing cycles from the core processor.
In the case of PIC16F1827, it possesses an internal Set/Reset (SR) Latch peripheral. S/R Latches (or Flip Flops) is a purpose-built circuit that can, once Set, retain a given state (a logical high), and only toggle it when the Reset line is activated. This can be used as a hardware debouncing mechanism by placing the output of the switch activation as the Set Latch input, the Latch output as the trigger for the intended function, and the Reset Latch being activated at the end of said function. This will effectively only consider the very first contact made by the switch and ignore any subsequent bouncing since multiple activations of the Set line will not change the state any further until it is Reset.
That would be a great demonstration of one of the MCU's capabilities. However, I’ll have to let you guys hang dry here since the very organic nature of the bouncing mechanics makes a great source of entropy and, in this application, triggering the function associated with the switch multiple times will sample the timer multiple times and contribute to the random number seed I use. Sorry guys, no demonstration or code for you here.
领英推荐
Tools of The Trade
?Unlike some competitors who shall remain anonymous, Microchip provides a very generous set of development tools and the user community behind their chips is huge, so, finding documentation, usage examples, bug workarounds, etc is pretty easy. Below are the tools we need to get started.
MPLAB X
It’s the current default development environment for Microchip’s line of MCUs. People online complain about it (bugs), but I found it pretty good, and the few bugs I faced could be solved by restarting. It’s mostly free (you pay for a “Pro” version of their compiler) and can be downloaded from the Microchip website.
MPLAB X come integrated with MPLAB Code Configurator (MCC), a visual tool to aid in getting the chip peripherals initialized and ready to be used. Again, this is a point of conflict on web forums, some love it, and some hate it. My experience was good enough to recommend it. Being able to see at a glance all available peripherals to a given chip model, their available configuration options (which can vary a lot from model to model), assign inputs and outputs from one to another with mouse clicks, and, in the end, have the C code that will perform the task generated and available to be studied, proved useful to me at least.
Main MPLAB X IDE interface below:
MPLAB Snap
A special-purpose device is needed to program an MCU. Microchip offers a line of hardware programmers/debuggers, with widely different prices and more capabilities as you progress further to the high end of the spectrum; however, their current entry-level tool, called MPLAB Snap, is cheapish (~ USD 34) and capable of programming their latest chips (especially the handsome line called PIC16F1), but please note that it will not be able to program some older chips and the ones that depend on high voltages for programming. If that’s all you have around in your region, then I’d recommend the more expensive model Pickit 4 (~ USD 77) which is supposed to be compatible with current and old models.
A plus side on both Snap and Pickit 4 is that they both can work with AVR chips, a line of MCUs from Atmel which got bought by Microchip back in 2016.
I can’t find either in my country and had to import the Snap paying huge fees (triple the price of the unit) that only lovely politically messed countries like mine can offer.
MPLAB Snap, enclosed in an ABS printed case, in action below:
Chips shortage and lead-time
As I mentioned before, chip shortage is a reality that will take at least one year more to clear. Even though Microchip produces around a million 8-bit chips a day, it doesn’t appear to be enough, since many models are constantly out of stock on traditional retailers (Digikey, Mouser, Arrow, etc) and the lead time is around a year. So, chances are that, depending on where you live, you may find only really old chips (fewer capabilities) or refurbished ones (used, got erased, and resold). One problem with used chips can be the remaining lifetime, since the number of rewrites is limited to 10.000 or 100.000, depending on the model. A bigger issue may be due to the method used to clear the chip. It has been reported that some sellers set the incorrect parameters while blanking a chip and come to erase even information that they should NOT be touching, like the internal oscillator calibration data (OSCCAL).
You see, some models possess as an internal peripheral an oscillator, a piece of hardware that will produce a pre-defined frequency once a voltage is applied; this is an essential piece of hardware that in some units needs to be supplied by an external physical component (an oscillator crystal) and in other come built-in and factory calibrated up to 1% accuracy. If the calibration data is erased, say goodbye to your accuracy and your program may drift unexpectedly during operation.
Recalibrating the internal oscillator is possible, should be fun, but I wouldn’t recommend it for someone just starting on this. It will require an external accurate source of time, some patience, etc.
BOM and Schematics
Now, to the guts:
Besides the PIC16F1827 and CR2032 battery pictured above, we need:
7-Digit display: It’s like 8 Light Emitting Diodes (LEDs) packed together in an eight-dot pattern so that selectively powering the segments will produce numbers from 0 to 9 plus a decimal point. Each segment you intend to use needs a current limiting resistor, otherwise, it will drain your battery quickly and eventually burn the LED. Examples can be found on the internet where people used a single resistor to work all the segments, this works to some extent but has limitations like, the brightness of the segments will get dimmer as more of them are lit. It’s like a house being water fed by a 1-inch pipe versus 8 houses being fed simultaneously by the same pipe. In the latter case, each of the 8 houses will get less water per time unit. In our case, for each LED fewer electrons will flow and all of them will get dimmer.
8 x 120 Ohms resistors, to go with the above display and 1 x 15 K Ohm resistor to pull the switch pin voltage down and keep it from floating while waiting to be activated.
10 uF ceramic capacitor: To smooth tiny power fluctuations which can affect the chip’s operation.
Mercury tilt switch: To sense shaking.
CR2032 cradle: To hold the battery.
Here are the schematics:
Assembly and Working
The acrylic plates and soldered unit:
Additional hardware to assemble:
Final result:
Video demonstration:
Full source code:
If you enjoyed that, please take a look at my other articles here in this medium.
Inventor, Author & Educator. Ham Radio licensee VU2NOX. Founder, TI Centre for Embedded Product Design at NSUT
2 年Excellent write up. Arduino is a microcontroller development system with training wheels is a very apt description ??. Long ago I had done this battery-less electronic dice:?https://www.instructables.com/An-Electronic-Battery-less-Dice/
ROV Supervisor at Oceaneering
2 年Great write-up, thanks ??
--
2 年Fantastic