Silicon ChipMax’s Cool Beans - November 2021 SILICON CHIP
  1. Outer Front Cover
  2. Contents
  3. Subscriptions: PE Subscription
  4. Subscriptions: PicoLog Cloud
  5. Back Issues: PICOLOG
  6. Publisher's Letter
  7. Feature: The Fox Report by Barry Fox
  8. Feature: Techno Talk by Mark Nelson
  9. Feature: Net Work by Alan Winstanley
  10. Project: Dual Battery Lifesaver by Nicholas Vinen
  11. Project: USB Supercodec by Phil Prosser
  12. Project: Thermometer Calibrator by Allan Linton-Smith
  13. Feature: I/O Expander Modules by Tim Blythman
  14. Feature: Radio Controlled House Lights by Peter Brunning
  15. Project: Colour Maximite 2 (Generation 2) by Phil Boyce, Geoff Graham, Peter Mather
  16. Feature: AUDIO OUT by Jake Rothman
  17. Feature: Circuit Surgery by Ian Bell
  18. Feature: Max’s Cool Beans by Max the Magnificent
  19. Feature: PICn’Mix by Mike Hibbett
  20. PCB Order Form
  21. Advertising Index

This is only a preview of the November 2021 issue of Practical Electronics.

You can view 0 of the 72 pages in the full issue.

Articles in this series:
  • (November 2020)
  • Techno Talk (December 2020)
  • Techno Talk (January 2021)
  • Techno Talk (February 2021)
  • Techno Talk (March 2021)
  • Techno Talk (April 2021)
  • Techno Talk (May 2021)
  • Techno Talk (June 2021)
  • Techno Talk (July 2021)
  • Techno Talk (August 2021)
  • Techno Talk (September 2021)
  • Techno Talk (October 2021)
  • Techno Talk (November 2021)
  • Techno Talk (December 2021)
  • Communing with nature (January 2022)
  • Should we be worried? (February 2022)
  • How resilient is your lifeline? (March 2022)
  • Go eco, get ethical! (April 2022)
  • From nano to bio (May 2022)
  • Positivity follows the gloom (June 2022)
  • Mixed menu (July 2022)
  • Time for a total rethink? (August 2022)
  • What’s in a name? (September 2022)
  • Forget leaves on the line! (October 2022)
  • Giant Boost for Batteries (December 2022)
  • Raudive Voices Revisited (January 2023)
  • A thousand words (February 2023)
  • It’s handover time (March 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • Prophecy can be perplexing (May 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • How long until we’re all out of work? (August 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • Holy Spheres, Batman! (October 2023)
  • Where’s my pneumatic car? (November 2023)
  • Good grief! (December 2023)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (February 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk (July 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk (November 2024)
  • Techno Talk (December 2024)
  • Techno Talk (January 2025)
  • Techno Talk (February 2025)
  • Techno Talk (March 2025)
  • Techno Talk (April 2025)
  • Techno Talk (May 2025)
  • Techno Talk (June 2025)
Max’s Cool Beans By Max the Magnificent Flashing LEDs and drooling engineers – Part 21 I live in a maelstrom of weird and wonderful happenings. For example, I often get questions pertaining to my projects like, ‘What on earth possessed you to come up with that?’ (I can hear my mother’s voice ringing in my ears as clearly as if she was in the room with me, and now my wife – Gina the Gorgeous – has taken over for her). Well, if you are at all interested in discovering the answer to this question, you’ll be delighted to discover that I was recently interviewed in a Fish Fry Special Edition: Makers Today! podcast hosted by the inimitable Amelia Dalton (https://bit.ly/3C6bIiS). Have you ever paid any attention to the indexes in technical books? I don’t know about you, but I find it to be incredibly frustrating when I return to a book looking to find something to use as a reference but fail to find what I’m searching for in the index. The reason I mention this here is that, at the time of this writing, three of my chums – Adam Taylor, Dan Binnun and Saket Srivistava — recently finished writing a book called A Hands-On Guide to Designing Embedded Systems (https:// bit.ly/3hnu9If). They kindly sent an early PDF copy for me to peruse and ponder. I immediately had a quick skim before taking a deep dive, and my eye was caught by the index, whose sole contents were a note saying, ‘Index Goes Here.’ Since I spend a humongous amount of time hand-crafting the indexes for my own books, I was moved to pen a column on this topic: Just Call Me an Indexing Fool (https://bit.ly/3C0prba). I was just chatting to Matt Pulzer who is the illustrious publisher-editor of Practical Electronics. Matt is a font of esoteric erudition, so I was delighted to add to his treasure trove of trivia by informing him of a nugget of knowledge pertaining to the phrase ‘It was a dark and stormy night...’ As you may recall, this was used to comic effect in the Peanuts cartoons by Charles Schulz (https://bit. ly/2XfgOdS). In fact, Snoopy wrote so many stories starting this way that these openings ended up forming a book in their own right (https://amzn.to/3C5XVJ9). This archetypal example of a florid, melodramatic style of fiction writing comes from the opening sentence in the 1830 novel Paul Clifford, which was penned by English novelist Edward Bulwer-Lytton. In fact, this opening sentence is so bad that it led to the annual Bulwer-Lytton Fiction Contest, which challenges participants to write an atrocious opening sentence to the worst novel never written. Personally, I class this competition (https://bit. ly/2Xh8bQ3) alongside the Darwin Awards, which salute the improvement of the human genome by honoring those who accidentally remove themselves from it in a spectacular manner (https:// bit.ly/2YNUb0N), and the Ig Nobel awards, whose stated aim is to honor achievements that first make people laugh, and then make them think (https:// bit.ly/3C4Qj9Q). Are you nuts? As I’ve mentioned on occasion, I’m a big fan of steampunk, which is a subgenre of science fiction that incorporates retrofuturistic technology and aesthetics inspired by 19th-century industrial steam- Round Dome Pan Flat Oval Hexaganol Flat (Slotted) Phillips Torx (6-lobe) Square (Robertson) Hexagonal (Allen) Hexagonal (External) Fig.1. Machine-screw heads (top) and drives (bottom). 56 powered machinery. Many of my projects include brass control panels or facias, in which case I will also use brass fasteners. For some of my projects, like my Victorian Spectrum Analyser and my Countdown Timer (https://bit.ly/3yYmypv), whose job is to display the years, months, days, hours, minutes and seconds to my 100th birthday celebrations, which will kick off at 11:45am British Summer Time on 29 May 2057 (mark your calendar), I’ve used brass acorn nuts to good effect. With other projects, I’ve used machine screws with a variety of head shapes and drive styles as appropriate. There is, of course, an incredible variety of head shapes available, where each of these head shapes may be available with a diversity of drive styles, only a small selection of which are presented here (Fig.1). Just to increase the fun and frivolity, combinations of drives are also available, like Phillips + slotted and hexagonal + slotted. If you are aiming for historical authenticity and attempting to avoid the appearance of anachronisms, then you can’t go wrong with slotted or hexagonal heads (also, acorn nuts, which are not shown here). Just about everything else is an artifact of the 20th century, including Square (Robertson) drives, which were invented by Peter Robertson in 1907, Hexagonal (Allen) drives, which were invented by William Allen circa 1910, Phillips drives, which were invented by Henry Phillips in 1936, and Torx screws, which were invented by the Camcar Textron company in 1967. For my own projects, I predominantly use slotted screws, although I’m not averse to Allen or Robertson drives, and Fig.2. Two pseudo robot heads showing different types of ‘eye’ effects. Practical Electronics | November | 2021 ( a) 0 1 2 3 4 5 6 7 1 2 3 All f our SMAD s ( 8 patterns 0 - 7 clock wise) ( b) 0 1 2 3 0 All f our SMAD s ( 4 patterns 0 - 3 clock wise) ( c) (Above) Fig.3. SMAD segment map. (Right) Fig.4. Variations on a simple windmill effect. 0 1 sometimes even hexagonal heads should the occasion demand. On the other hand, although I love them for household tasks, you will never, ever find me using a Phillips screw on one of my steampunk extravaganzas. Of course, how you create your own projects is totally up to you; it’s not for me to cast aspersions (not the least that my throwing arm isn’t what it used to be). Having said this, I think a little attention to detail goes a long way. In the case of my two pseudo robot heads, each featuring two of our SMADs (Steve and Max’s Awesome Displays), for example, I’m using eight slotted drive, pan-headed machine screws to attach each of the SMADs to the front panels (Fig.2). Furthermore, although the side panels are actually attached to the main bodies of the heads (if you see what I mean) using hot glue, as seen in the image on the front cover of this issue, I’ve still augmented each panel with seven screws, just to convey the impression that they are more robust and sophisticated than is, in fact, the case. One last point on this subject: the silver head has black SMAD shells and facias while the black head has silver (well, nickel-coloured) SMAD shells and facias. As we just saw, the side panel screws on the silver head are a regular steel colour, while their equivalents on the black head are black. Similarly, the screws holding the silver SMADs on the black head are steel, while the screws holding the black SMADs on the silver head are black. In the not-so-distant past, I used to spend an exorbitant amount of time trying to track down black versions of various fasteners. More recently, unless I’m using brass, I simply purchase steel versions of everything and then use Gun Blue if I need any to be black (https://amzn.to/391DKj6). Feast your eyes In previous columns, I’ve mentioned the idea of using different SMAD segments and colours to represent eyes. In Fig.2. we see two versions I just threw together. On the left, I’m using blue to represent the eyeball and red to denote the pupil; on the right, I’m using white to signify the eyeball and black to act as the pupil. I’m going to continue experimenting with different representations, including making the eyes look left (west), right (east), up (north), and south (down). I’ll probably experiment with looking northwest, southwest, northeast, and southeast, also. Furthermore, when the eyes are looking directly forward, as shown in Fig.2, it might be interesting to see if we can achieve some sort of blinking effect. All of this is something I’m noodling over in the back of my mind, but I’d love to hear your suggestions. Lest we forget As a reminder, our SMAD segment map is shown in Fig.3. The numbers, which are applicable to both types of SMAD Practical Electronics | November | 2021 2 3 L ef t 2 SMAD s ( 4 patterns 0 - 3 clock wise) 0 1 2 3 R ight 2 SMAD s ( 4 patterns 0 - 3 anticlock wise) shell (29-segments and 45-segments), refer to the positions of the LEDs in the string, while the letter combinations are the names we use to identify the segments in just the 29-segment versions. In my previous column (PE, October 2021), we ended up with all four SMADs displaying a simple windmill effect comprising eight patterns (Fig.4a). The key part is where we create an array containing the LEDs we wish to light up in each pattern. For this first effect, we defined NUM_PATTERNS_ IN_EFFECT as being 8 (this corresponds to the fact that we have 8 ‘spokes,’ as illustrated in Fig.3), and MAX_LEDS_IN_ EFFECT as being 4 (there are two LEDs in each spoke). We then created a two-dimensional array of 8-bit integers called EffectMap[][], that is comprised of NUM_PATTERNS_IN_ EFFECT (ie, 8) rows, each containing MAX_LEDS_IN_EFFECT + 1 (ie, 5) items, and we initialised this array as follows: { {2, 1, 17, 0, 0}, // BA {4, 0, 2, 18, 41}, // AA BB EA {2, 3, 19, 0, 0}, // BC {4, 0, 4, 20, 42}, // AA BD EB {2, 5, 21, 0, 0}, // BE {4, 0, 6, 22, 43}, // AA BF EC {2, 7, 23, 0, 0}, // BG {4, 0, 8, 24, 44} // AA BH ED }; Remember that the fi rst value in each row tells us how many LEDs we wish to light for this pattern. The remaining values in the row are the numbers of the LEDs (any 0s on the right are just placeholders). You can remind yourself as to how all this worked by downloading the code (file CBOct21-05.txt) from the October 2021 page of the PE website at: https://bit.ly/3oouhbl Take your turn At the end of my column last month, I invited you to perform some thought experiments of your own. The first was to consider how we might go about modifying our latest program so that it has four patterns, each with two arms at 180° to each other. You can find my solution in file CBNov21-01.txt on the November 2021 page of the PE website at: https://bit.ly/3oouhbl Although not part of our main mission, I added a third ‘Deep Background’ colour of purple just to make life a little more interesting (Fig.4b). As you will see, implementing the new effect is easy peasy lemon squeezy. First, we change NUM_ PATTERNS_IN_EFFECT to be 4 and MAX_LEDS_IN_EFFECT to be 6. Next, we redefine the contents of our EffectMap[] [] array as follows: 57 { {5,0, 1,17, 5,21, 0}, // AA+BA+BE {6,2,18, 6,22,41,43}, // BB+BF+EA+EC {5,0, 3,19, 7,23, 0}, // AA+BC+BG {6,4,20, 8,24,42,44} // BD+BH+EB+ED }; Our next thought experiment was to ponder how we might modify this latest incarnation such that the windmill patterns on the left-hand robot head’s eyes rotate clockwise while the patterns on the right-hand robot head’s eyes rotate anticlockwise (Fig.4c). You can find my solution in file CB-Nov21-02.txt. To be honest, although my code functions as planned, it feels a little ‘clunky’ to me and I have a sneaking suspicion that this could be implemented in a more elegant fashion. Perhaps you might take a look and offer some suggestions. The final countdown The last problem I posed was to implement a sort of counter that I think of as an ‘Alien Countdown’ (I had a disturbed childhood). The idea here is to return to a version of our original 8-pattern windmill effect (Fig.4a) but with our new colour scheme (Fig.4b and Fig.4c). What we want to do is to create a program involving two or more SMADs that commences with them each displaying a single windmill arm pointing upwards. We start with the least-significant SMAD (the one on the right) spinning its arm clockwise, completing four full rotations each second (I originally specified one full rotation a second, but the effect looks more exciting and interesting when we speed it up). Every time this arm returns to its vertical position, the arm on the adjacent SMAD advances by one position (pattern). Similarly, every time the arm on the second SMAD returns to its vertical position, the arm on the third SMAD advances by one position, and so on for all of the SMADs in the chain. You can find my solution in file CB-Nov21-03.txt. In this case, I have to admit that I’m rather ‘chuffed’ with the way things turned out. Stripped of the nitty-gritty code, the main loop is as follows: int iSmad = 0; bool done = false; do { int smadOffset = iSmad * NUM_NEOS_PER_SMAD; // For current SMAD // Set Neos in old pattern to background color // <code goes here> // For current SMAD // Increment SMAD pointer to next pattern // <code goes here> // For current SMAD // Set Neos in new pattern to foreground color // <code goes here> // For current SMAD // Test to see if we’ve wrapped around if (SmadPtrs[iSmad] != NORTH) done = true; else iSmad = iSmad + 1; } while ( (done == false) && (iSmad < NUM_SMADS) ); This means that all we have to do is change our definition of NUM_SMADS (the number of SMADs in the chain) to accommodate any number of ‘digits’ in our counter. As usual, for your delectation and delight, I’ve captured a quick video showing all of the effects discussed in this column (https://bit.ly/3lJk1uN). What next? There are so many things we can do with SMADs in general, and with my robot heads in particular, that I’m undecided as to which direction to take things next. Do we continue playing with variations on the simple effects we’ve seen thus far, building our (my) confidence that we (I) have a clue what we are (I am) doing? Alternatively, do we take the plunge and start experimenting with some eyeCool bean Max Maxfield (Hawaiian shirt, on the right) is emperor wateringly cunning colour effects? Do you of all he surveys at CliveMaxfield.com – the go-to site for the have any thoughts you’d care to share at latest and greatest in technological geekdom. this point in the proceedings? As always, I welcome your sage comments, insightful Comments or questions? Email Max at: max<at>CliveMaxfield.com questions, and helpful suggestions. Max’s Cool Beans cunning coding tips and tricks I fear this column is going to be reminiscent of one of my mother’s tortuous tales, which typically kick off along the lines of: ‘I bumped into Mrs. Greebles at the fishmongers the other day. You remember, she was the oldest of three sisters; the youngest, Beryl, was a strumpet, while the middle girl eloped with an Australian taxidermist and they had two sons who were terrified of bananas and...’ 58 The amazing thing is that, after wandering so far out into the weeds that her audience starts to consider sending out a search party, she somehow manages to bring the story home to a triumphant conclusion: ‘And that’s why you should never name a walrus Wally!’ (And people wonder why I drink.) In an earlier Tips and Tricks (PE, July 2021), we noted that microcontrollers like the Teensy (which we are using to drive our 10-character, 21-segment Victorian Display) and the Arduino (which I use for all sorts of things) contain three types of memory: Flash, SRAM, and EEPROM. The Flash, which is non-volatile (it remembers its contents when power is removed from the system), is used to store the program. By comparison, the SRAM, which is volatile (it forgets its contents when power is removed from the system), is where the program creates, stores, Practical Electronics | November | 2021 Let’s also remind ourselves that we plan on having three copies of these settings bytes. First, we’ll have a default set called DefSettings that’s stored in the Flash memory as part of the main program. Next, we’ll have a customised set that’s been tweaked by the user and is stored in the EEPROM. Finally, we’ll have a working set called WrkSettings that’s stored in the SRAM; it is this latter set that will ultimately be used by the program once it’s up and running. Let’s start by considering the default set of values stored in DefSettings using a generic visualisation (Fig.5). First, we have a magic number, whose purpose will be explained shortly, #include <EEPROM.h> and whose value I’ve set to be 0x42 in hexadecimal (01000010 in binary), Just to remind ourselves how this works, which is, as we all should know by now, suppose we declare an integer variable The Answer to the Ultimate Question called Address to which we assign a of Life, the Universe, and Everything value of 0, along with an 8-bit (byte(https://bit.ly/pe-nov21-42). sized) variable called Data to which we This is followed by a version number, assign a value of 128. In this case, we can which I’m considering to be presented in write the data into our EEPROM using: the form of two 4-bit nybbles (remember, ‘two nybbles make a byte’), where the EEPROM.write(Address, Data); most-significant nybble holds the primary version number and the least-significant Contrariwise, we can read the data back nybble holds the secondary version out of our EEPROM using: number. Since our nybbles contain 0001 and 0000, this means we are at version Data = EEPROM.read(Address); 1.0 in our example. Next, we have the time format (0 = 12In the aforementioned Tips and Tricks hour, 1 = 24-hour) followed by the date column, we also made mention of the fact format 0 = YYYY/MM/DD, 1 = MM/DD/ that we are going to use the EEPROM to YYYY, 2 = DD/MM/YYYY). These are store a set of byte-sized unsigned integer followed by the number of modes and values (we’ll use the data type uint8_t the number of effects. For the purposes that we introduced in the September of these discussions, let’s assume that 2020 Tips and Tricks) to keep track of we have three modes numbered 0, 1, a variety of user settings, such as the and 2 that display the time, date, and preferred formats in which to display some scrolling text message, respectively. the date and time. Observe that, for the purpose of this example, only two of these (the time and Setting the scene date) have associated format settings. In the real world, we are going to have a When it comes to effects, let’s assume bunch of ‘settings bytes.’ For the purposes we have sixteen (numbered from 0 to 15). of these discussions, however, let’s assume For example, effect 0 could be static white we are working with a very limited subset text on a black background, effect 1 could comprising just ten bytes, which we can be static black text on a white background, think of as being numbered from 0 to 9. effect 2 could be an animated rainbow As part of this, we have defined NUM_ of coloured text on a black background, SET_BYTES as being equal to 10. and so forth. Next, we have three bytes N ames f or struct v ariables containing the effects associated with I ndex f or array each of our modes. As we see, we’re V alues in settings by tes assuming that the default will be to associate effect 0 (white text on a black 0 01000010 Magic N umber v d M a g i c N u m background) with each mode. 1 00010000 V ersion N umber v d V e r s i o N u m Finally, we have a special value called 00000000 T ime F ormat 2 v d T i m e a checksum, which will primarily be 00000000 D ate F ormat 3 v d D a t e of use when we wish to determine if 4 00000011 N umber of Modes v d N u m M o d e s the contents of the EEPROM are valid 00001111 N umber of E f f ects 5 v d N u m F x or not. We will return to this point in 00000000 F x Mode 0 ( D ate) 6 v d F x M o d e 00 a little while, but first... 7 00000000 F x Mode 1 ( T ime) v d F x M o d e 01 and manipulates variables when it runs. Also, we have a small amount of nonvolatile EEPROM (electrically erasable programmable read-only memory) in which we can store modest quantities of long-term information. In the case of the Teensy 3.6, we have 4KB of EEPROM (that’s 4,096 bytes numbered from 0 to 4,095 in decimal or 0x000 to 0xFFF in hexadecimal). If we want to use this EEPROM in our programs, we first need to include a special library that’s provided as part of the Arduino’s integrated development environment (IDE) using the following statement: v d F x M o d e 02 8 00000000 F x Mode 2 ( T ex t) v d C h e c k s u m 9 ? ? ? ? ? ? ? ? C heck sum Fig.5. Example contents of DefSettings. Practical Electronics | November | 2021 Let’s form a union! As we previously discussed (yes, I’m afraid you really, really should re-read the July 2021 Tips and Tricks), we are going to define a new data type in the form of a union that we will call Settings. A union offers multiple ways to visualise and manipulate the same area of memory. In our simple case, sometimes we wish to think of things as a structure of byte-sized variables we’ve called vds, while other times we wish to think of the same memory locations as an array of byte-sized variables we’ve called vda. (The ‘vd’ part of these identifiers stands for ‘Victorian Display,’ while the ‘s’ and ‘a’ parts stand for ‘structure’ and ‘array’, respectively.) typedef union { struct { uint8_t vdMagicNum; uint8_t vdVersionNum; uint8_t vdTime; uint8_t vdDate; uint8_t vdNumModes; uint8_t vdNumFx; uint8_t vdFxMode00; uint8_t vdFxMode01; uint8_t vdFxMode02; uint8_t vdChecksum; } vds; uint8_t vda[NUM_SET_BYTES]; } Settings; Next, we declare our DefSettings and WrkSettings variables as being of this union type, as shown below. The clever thing here is the way in which we initialise the values in our DefSettings variable as follows: Settings DefSettings = { .vds = { .vdMagicNum = 0x42, .vdVersionNum = 0x10, .vdTime = 0x00, .vdDate = 0x00, .vdNumModes = 0x03, .vdNumFx = 0x0F, .vdFxMode00 = 0x00, .vdFxMode01 = 0x00, .vdFxMode02 = 0x00, .vdChecksum = 0x00 } }; Settings WrkSettings; The 0x00 that we’ve assigned to the checksum value is for completeness only because we will be calculating a new value almost immediately (although this 0x00 value will never be used, neglecting to assign a default value here would bug me incessantly – also bugging me, why isn’t there a word ‘cessantly’?). 59 Check my checksum Address in E E P R O M 0x 000 X X X X X X X X 01000010 01000010 Magic N umber 0x 001 X X X X X X X X 00010000 00010000 V ersion N umber 0x 002 X X X X X X X X 00000000 00000001 T ime F ormat 0x 003 X X X X X X X X 00000000 00000010 D ate F ormat 0x 004 X X X X X X X X 00000011 00000011 N umber of Modes 0x 005 X X X X X X X X 00001111 00001111 N umber of E f f ects 0x 006 X X X X X X X X 00000000 00000111 F x Mode 0 0x 007 X X X X X X X X 00000000 00001001 F x Mode 1 0x 008 X X X X X X X X 00000000 00000101 F x Mode 2 0x 009 X X X X X X X X ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C heck sum ( a) U ninitialised ( b) D ef ault ( c) C ustom Fig.6. Contents of EEPROM at different stages. Stay constant Actually, this provides another teachable moment. If we never intended to change any of the values in our DefSettings variable, we should (would) have declared it as being a constant value as follows: const Settings DefSettings = {etc.} This would confer several advantages, the first being that the compiler would ‘throw a wobbly’ if our code attempted to change any of the values. Also, any initialised variables that are not declared as being of type const are stored in the Flash program memory and then copied by the start-up code into SRAM (all this takes place before the user program is executed). By comparison, in the case of any initialised variables that are declared as being of type const, the system knows these values aren’t going to change, which means they don’t need to be copied into SRAM, thereby saving valuable SRAM resources. Having said all this, we are planning on changing the checksum value in DefSettings, which explains why we didn’t use the const keyword in this case. The proof of the pudding Remember that the structure and the array are intended to provide two different ways to manipulate and display the same ten bytes of memory in our union. But how do we know that this actually works? Well, as I’ve mentioned before, I’m a hardware design engineer by trade, and writing code is not my strong suit, so I performed a little test as follows: for (int i = 0; i < NUM_SET_BYTES; i++) { WrkSettings.vda[i] = DefSettings.vda[i]; } for (int i = 0; i < NUM_SET_BYTES; i++) { Serial.print(i); Serial.print(“ “); Serial.println(WrkSettings.vda[i]); } Let’s remind ourselves that our last settings byte is used to contain a value called a ‘checksum.’ All we need to know at this point in our discussions is that a checksum is a small block of digital data that is derived from a larger block of digital data for the purpose of detecting errors that may have been introduced during the storage or transmission of the larger block of data. In our case, we are going to derive a byte-sized checksum value based on the contents of all of our other settings bytes. The procedure by which we generate our checksum value is referred to as a ‘checksum function’ or a ‘checksum algorithm.’ A good checksum algorithm will generate a significantly different output value for even a small change made to the input data. I hate to do this to you again (I might remind you as to how we introduced this column), but I think you know what I’m going to say, which is that we will return to this point shortly, but first... Meet my shell game Have you ever seen someone perform a shell game? This involves sleight of hand in which three inverted cups, or nutshells, are moved about and the contestant must identify which one ends up with a pea or other object underneath. If you are the contestant in question, you are convinced you know where the pea is hiding… right up to the point where the shell you selected is shown to be empty and your hardearned dosh bids you a fond farewell. Well, we are poised to do something similar with our settings bytes in general and our checksum byte in particular. Before we proceed, let’s make a decision that one of the very first things we will do when we initially run our program is to use our checksum function to generate a checksum byte based on all of the settings bytes (except the checksum byte itself) that are stored in our DefSettings variable. We will store the result in the checksum byte associated with DefSettings. Now, let’s assume that we’ve just taken a new microcontroller out of the box, plugged it into our system, and loaded our program into it. Since this is a new microcontroller, the EEPROM is going to be uninitialised, which means it will contain unknown values (Fig.6a). We’ve indicated these values as ‘X’ in this figure, but they would typically be all 1s (or, more rarely, all 0s). When we run our program, one of the first things we’ll do (after generating and storing the checksum byte in the DefSettings variable as discussed above) will be to check to see if the EEPROM contains valid settings data. How do we do this? Well, do you recall the magic number byte in Fig.5? We decided to load this byte with a value of 0x42, but any value other than 0x00 and 0xFF would suffice. E E P R O M D ef Settings W rk Settings ( a) P ower- up with empty E E P R O M E E P R O M D ef Settings W rk Settings When we initialised the values in our DefSettings variable, we used its structure aspect. Now, in the first ( c) P ower- up with loaded E E P R O M loop above, we use its array aspect to copy these values U ser from the DefSettings variable into the WrkSettings D ef Settings E E P R O M W rk Settings variable, after which we use the second loop to print the values from the WrkSettings variable. It works! (Phew!). If you wish, you can peruse and ponder this sketch in all its glory (file CB-Nov21-04.txt, which is ( e) U ser decides to change settings available on the November 2021 page of the PE website at: https://bit.ly/3oouhbl). Fig.7. Alternative action sequences. 60 E E P R O M D ef Settings W rk Settings ( b) L oad E E P R O M and W rk Settings E E P R O M D ef Settings W rk Settings ( d) L oad W rk Settings f rom E E P R O M U ser E E P R O M D ef Settings W rk Settings ( f ) U ser changes settings Practical Electronics | November | 2021 01000010 01000010 Magic N umber 00010000 00010000 V ersion N umber 00000001 00000001 T ime F ormat 00000010 00000010 D ate F ormat 00000011 00000011 N umber of Modes 00001111 00001111 N umber of E f f ects 00000111 00000111 F x Mode 0 00001001 00001001 F x Mode 1 00000101 00000101 F x Mode 2 01010110 10000100 C heck sum ( a) P arity by te ( b) Sum complement Fig.8. Simple checksum algorithms. What we are going to do is read the byte from address 0x000 in the EEPROM to see if it matches the magic number byte in DefSettings. However, as we’ve already discussed, since this is the first time we’ve run the program, we are powering up with an empty EEPROM (Fig.7a), so our test to read the magic number will fail. In this case, we will load the default settings values, including our recently calculated checksum byte, from DefSettings into both the EEPROM and WrkSettings (Fig.6b and Fig.7b). OK, suppose we play with our Victorian Display and then power it off again without changing any of the settings. In this case, when we next power the system up again, the EEPROM will contain a copy of the default settings (Fig.6b and Fig.7c). As before, one of the first things we do is to read the byte from address 0x000 in the EEPROM to see if it matches the magic number byte in DefSettings. In this case, the test passes, so we copy the values stored in the EEPROM into WrkSettings (Fig.7d). At this point, we would use our checksum function to verify that the data we’ve copied into our WrkSettings variable is good (we’ll discuss how we do this in a moment). If this test fails, we know that the data in the EEPROM has become corrupted in some way, in which case we will have to mediate the situation (perhaps by regressing to Fig.7b). Alternatively, if the test passes, then we know we are ready to rock and roll. Now, suppose that while our program is running, we decide to change some of the settings (Fig.7e). For example, we might decide to modify the time format from 12-hour to 24-hour. Similarly, we might decide to modify the date format from YYYY/MM/DD to DD/MM/YYYY. Also, we might decide to change the effects associated with the various modes. Obviously, we are going to have to equip our program with the ability to allow the user to select new values for everything. Each time the user does change one of the values then: a) the new selection will be copied into the appropriate byte in both the EEPROM and WrkSettings and b) a new checksum Practical Electronics | November | 2021 value will be generated, and this too will be stored in both the EEPROM and WrkSettings (Fig.6c and Fig.7f). Checksum Redux The reason the checksum bytes in Fig.6 and Fig.7 are shown as ‘????????’ is that we haven’t yet decided what algorithm we are going to use. The simplest checksum algorithm is called the ‘longitudinal parity check’ (Fig.8a). This involves breaking the data into ‘words’ with a fixed number (n) of bits and then computing the exclusive or (XOR) of all those words, excluding the as-yet-unknown checksum value itself. In our case, of course, our words are 8-bits wide. The easiest way to think about this is that we want to end up with an even number of 1s in each column. In the leastsignificant (bit 0) column we have six 1s (even), so the corresponding checksum bit will be 0. In the bit 1 column we have five 1s (odd), so the corresponding checksum bit will be 1. In the bit 2 column we have three 1s (odd), so – once again – the corresponding checksum bit will be 1. And so on for the rest of the bits, resulting in a checksum value of 01010110. In order to check the integrity of the data once we’ve read it out of the EEPROM and loaded it into WrkSettings, we will use our checksum function to compute the exclusive or (XOR) of all the settings bytes in WrkSettings, including the checksum byte. If the result is not 0x00 (all zeros), then we know an error must have occurred. Another simple technique is the ‘sum complement’ algorithm (Fig.8b). In this case, we treat the settings bytes as unsigned binary numbers and add them all together, excluding the asyet-unknown checksum value itself. In this case, 01000010 + 00010000 + 00000001 + 00000010 + 00000011 + 00001111 + 00000111 + 00001001 + 00000101 = 01111100. If the result had been bigger than our word size of eight bits, we would have simply discarded any overflow bits. Next, we generate the twos complement of this value (swap all the 0s for 1s, swap all of the 1s for 0s, and add 1 to the result), which gives us a checksum value of 10000100. When we wish to check the integrity of the data once we’ve read it out of the EEPROM and loaded it into WrkSettings, we add all the bytes, including the checksum byte, and discard any overflow bits. Once again, if the result is anything other than 0x00 (all zeros), then we know an error has occurred. Earlier we noted that, ‘A good checksum algorithm will generate a significantly different output value for even a small change made to the input data.’ Is this true of the two algorithms we just discussed? I fear not. Try flipping a single bit in one of our settings bytes and see what effect it has on the output. In my next Tips and Tricks column, we will consider a much more cunning algorithm, but first... Mission critical While fighting your way through this column, you may have wondered why we need to use checksum values to verify the integrity of our EEPROM contents. ‘Is this form of memory really that unreliable?’ you may be asking yourself. Well, the answer is ‘Yes’ and ‘No’ (I bet you saw that coming). It’s certainly true that the typical Arduino EEPROM has a specified life of only 100,000 write/erase cycles, but that would become an issue only if we did something silly like write to it every millisecond (how many times do we really expect a user to modify the settings for something like our Victorian Display?). One problem is that writing data to the EEPROM takes a relatively long time in the scheme of things, not that you would notice anything yourself, of course, especially since we are writing only a handful of bytes in the case of our Victorian Display. Still and all, we have to worry what might happen if a brownout (low-power) condition was to occur while writing to the EEPROM. Similarly, for a poorly timed user-initiated powerdown or reset occurring while we were writing to the EEPROM. In such a case, the checksum will not match on readback and we’ll know to treat the data as junk. Contrariwise, if we simply assume the data is fine, we could end up trying to work with junk, which will almost invariably end in tears. As an aside, one way to overcome data corruption caused by cell wearing or power failure or whatever is to sequentially write two (or more) identical sets of data. If one checksum is bad, we still have one good copy; if both checksums are bad, then – speaking in the engineer’s vernacular – we’re up a certain creek without motive power. Of course, we could also employ error-correcting strategies like using Hamming codes, which can detect up to two-bit errors or detect-and-correct one-bit errors, but this is outside the scope of these columns. Finally, something else you might be thinking is, ‘Do we really need to go to all this effort for the Victorian Display, which – after all – is only really a glorified clock, for goodness’ sake?’ Ah, well, that’s a very good question. My reasoning is that what we learn here will prove useful later in life should we ever find ourselves in the position of having to design real-world mission-critical or safety-critical systems. OK, that’s all for this Tips and Tricks. As always, I welcome your comments, questions and suggestions. 61