• Recent Tutorials

  • Tripping The Class Fantastic: Programs Within Programs

    A Better Way

    I work with a guy (who shall remain nameless) who has done some incredible things with what we would consider to be very low spec machines. These are industrial type computers and they've been used to mobilize fire crews at various fire services here in the UK for many years. I figured if anyone could help me solve my problem it would be him as he has lots of experience of writing compact and efficient code that does some really cool things.

    So I asked, and his response went something along the lines of "Write a program within the program".

    "You can't fit a scripting engine on a PIC" was my reply.

    A discussion ensued and actually the solution he proposed made perfect sense and it went something like this....

    You want to display 4 colours - Off, Red, Green and Yellow. This requires two bits (00 = Off, 01 = Red, 10 = Green and 11 = Yellow)
    You want to display lots of different states - 1 byte = 8 bits = 4 steps. Each step can be one of the four colours.

    So, the 'program' 01 00 00 00 could be interpreted as show red for one cycle, then off for three. Likewise the program '10 01 10 01' would show green for a cycle, red for a cycle, green for a cycle and finally red before repeating.

    With a single byte we have a four step 'program memory' with each step containing one of the four 'program instructions' (off, red, green, yellow). Using this scheme we can achieve 256 different programs, far more than I had achieved with my state-machine driven effort (it should be noted though, that due to timing etc. not all of these are unique. 01000100 is identical to 00010001 in terms of the visual effect and therefore using programs that look alike should be avoided, this reduces the total number of unique programs quite substantially but still allows a good range to be generated).

    Code:
    01:  ledPrescaler++;
    02:  if (ledPrescaler>=ledPrescalerPeriod) {
    03:    ledCounter=ledCounter+1;
    04:    ledPrescaler=0;
    05:  }
    06:      
    07:  if ( ledCounter >= ledStepPeriod ) {
    08:    ledRot = (ledProgram & 0b00000011) << 6;
    09:    rotate_right(&ledProgram,1);
    10:    rotate_right(&ledProgram,1);
    11:    ledProgram = ((ledProgram & 0b00111111) + ledRot);
    12:    ledCounter=0;
    13:  }
    14:     
    15:  ledRed=0;
    16:  ledGreen=0;
    17:  if ((ledProgram & 0x03)==0x03) {
    18:    ledRed=((ledPrescaler & 0b01)==0b01);
    19:    ledGreen=!ledRed;
    20:  } else {
    21:    ledRed=((ledProgram & 0x01)==0x01);
    22:    ledGreen=((ledProgram & 0x02)==0x02);
    23:  }
    24: 
    25:  if (ledRed) {
    26:    portaval|=DRVVALUE_LEDRED;
    27:  } else {
    28:    portaval&=(DRVVALUE_LEDRED^0b11111111);
    29:  }
    30:  if (ledGreen) {
    31:    portaval|=DRVVALUE_LEDGRN;
    32:  } else {
    33:    portaval&=(DRVVALUE_LEDGRN^0b11111111);
    34:  }
    35:  output_a(portaval);
    Code Breakdown

    Obviously the first thing you'll note is that this is C not Pascal. This is the actual source for this element of the firmware. This code runs inside the main loop. This is a permanent loop that contains the firmware state-machine (more on state-machines coming in an article soon). The chip itself is clocked at 16MHz so each cycle through the loop is tiny in terms of time, so it's necessary to scale things down a little (lines 01 to 05 perform this scaling, incrementing 'ledCounter' only when we have been through the main loop 'ledPrescalerPeriod' times).

    The next two sections (lines 07 to 13 and lines 15 to 23) are actually our program interpreter.

    The first of these two sections performs more scaling (this time by ledStepPeriod). When it's time to move on, we take a copy of the right most bits of our program and shift them 6 bits to the left (line 8 ), we then rotate the program right by 2 bits (lines 9 and 10). This effectively moves us to the next step of our program. We then stuff the two bits we copied and shifted in line 8 back into the program buffer (line 11). In this way, our program forms a permanent loop. We then reset the scaling counter so that we don't advance too quickly.

    You could think of this first section as the fetch element of a CPU in that we've fetched the next element we want to execute by shifting it along in the variable that contains the program. The next logical step is to decode the program. This is done in lines 15 to 23. The simplest instructions are off (00), red (01) and green (02). These are all dealt with by the 'else' section (lines 21 and 22). The 'Yellow' program instruction (11) is slightly more tricky in that we need to alternate between red and green. This is done by setting the status of the red LED based on the value of the 1 bit from our pre-scaling counter 'ledPrescaler' (line 18 ). Since this gets incremented each time we come through the loop, the first time through the red LED might be on, the next time off. We then simply set the green LED state to be the opposite of the red (line 19).

    The final section of this code (lines 25-35) deals with actually sending the decoded program to the hardware. The variable portaval holds the current value of the IO port A (this is the physical digital IO port I used on the PIC to drive the LED, amongst other things). If the red LED should be on, we do a bit-wise OR to add the bit that turns the red LED on (line 26), if it should be off, we do a bit-wise AND on the value with the inverted bit pattern that it used to turn it on (line 28 ). If the bit pattern to turn it on is 0b00010000, the inverted pattern to turn it off is 0b11101111. We then do the same with the green (lines 30 to 34) and finally stuff the new data out to the IO port (line 35).
    Comments 10 Comments
    1. pstudio's Avatar
      pstudio -
      Interesting article. Of course there's a difference between writing programs on computers with almost unlimited memory compared to micro controllers but the point about keeping it simple and clean is absolutely still valid.
      I think many developers (myself included) sometimes have a tendency to make solutions more complicated than the really are. The reasons can be many. Maybe you're thinking of possible future usages of your code or maybe you just want to try a new more complex solution or maybe you just don't know better. Often the truth is that you could have settled with a simple and easy solution since that's all you really need and will need in the future.

      I've enjoyed reading this just like I've enjoyed reading your other articles through time. Looking forward to your next piece of writing.
    1. ricardo_sdl's Avatar
      ricardo_sdl -
      Very good article. Some good ideas.
    1. AthenaOfDelphi's Avatar
      AthenaOfDelphi -
      Thanks for the feedback guys, glad you enjoyed it
    1. chronozphere's Avatar
      chronozphere -
      Pretty interesting. Didn't know you did microcontroller programming. I'm currently exploring that stuff. I've got some ATmega and ATTiny chips here. I'd like to build some cool things with RGB LED's and perhaps do some audio projects.

      The raspberry pi is also interesting. It's GPIO pins allow you to drive all kinds of circuitry and since it can run a lightweight linux distribution, it will run pascal programs as well. You'd have to set up an ARMv6 cross compiler though.
    1. AthenaOfDelphi's Avatar
      AthenaOfDelphi -
      I've been tinkering with PICs on and off for about 6 years. Very cool little devices. My latest project is a digital controller for electrifying old mechanical clocks so they need very little attention (picture).

      Specs of this little adventure are:-

      • PIC18F97J94 (64,000 words of program memory)
      • 4x4 keypad
      • 20x4 LCD
      • 24 lines of 5v compatible digital IO (3 blocks of 8 bits which can be set to in or out)
      • Serial memory for configuration
      • Real time clock
      • Lead acid battery backup
      • High power DC switches for driving solenoids to strike chimes
      • USB interface for configuration/final setup


      In one of my old jobs, I was designing a commercial version of the First East Disco Dance Floor. My final prototype hooked up to a PC via RS232 and provided an 8x8 grid. The production model was going to use an Ethernet interface so we could lay bunches of these 8x8 1m square tiles next to each other and hook them up to a drive PC using 100Mbit Ethernet (pics of this are at the bottom of this page).

      Programming such small devices reminded me that sometimes you should keep things simple and compact... and that's what prompted this article
    1. SilverWarior's Avatar
      SilverWarior -
      Quote Originally Posted by AthenaOfDelphi View Post
      In one of my old jobs, I was designing a commercial version of the First East Disco Dance Floor. My final prototype hooked up to a PC via RS232 and provided an 8x8 grid. The production model was going to use an Ethernet interface so we could lay bunches of these 8x8 1m square tiles next to each other and hook them up to a drive PC using 100Mbit Ethernet (pics of this are at the bottom of this page).
      So thic could actually be done. I have similar idea in my head for quite some time. But for my idea I would probably need a bit bigger circuit as I would use bunch of Unltra Bright LED's (about 1200) on each panel. (basic RGB capability)
      So for this ethernet version would it be posible to automaticaly specify IP adress using router so that each board has its own IP.


      BTW Do you sell your circuits across EU. I might have saw an electronic circuit designed by you once. I cant remember for what it was for. But that Christina Loise Warne thext on electronic circuit seems verry familiar to me.
    1. AthenaOfDelphi's Avatar
      AthenaOfDelphi -
      Quote Originally Posted by SilverWarior View Post
      So thic could actually be done. I have similar idea in my head for quite some time. But for my idea I would probably need a bit bigger circuit as I would use bunch of Unltra Bright LED's (about 1200) on each panel. (basic RGB capability)
      So for this ethernet version would it be posible to automaticaly specify IP adress using router so that each board has its own IP.


      BTW Do you sell your circuits across EU. I might have saw an electronic circuit designed by you once. I cant remember for what it was for. But that Christina Loise Warne thext on electronic circuit seems verry familiar to me.
      The PIC I was looking at using for the dance floor had a built in Ethernet driver, all I had to do was add a socket with the various inductors etc. in that match the line to the circuit. Based on this, I have to assume it has a unique MAC address and thus, you could implement DHCP to provide a specific MAC address with a specific IP address. A lot of PICs have flash memory on board that you can store basic config in, but adding a dedicated config memory chip would cost you less than say £1 per PIC. Depending on volume of config you could probably get away with a single FRAM chip. Use one of your SPI/I2C channels for that, then all you need is a chip enable line (I prefer SPI for memory chips).

      Driving the LEDs, I used the MAX7313. This is an I2C chip, that can drive 16 intensity controlled channels. You can pop 64 of them on a single I2C bus using their addressing mechanism, so that works out at 21 per color (don't mix colours on one chip). That yields 336 pixel capability if you were to fully load a single I2C bus.

      As for selling my stuff... nope, I don't sell anything like that yet... I've not ruled it out, but to date I haven't sold anything. The difficulty with that sort of thing is cost of manufacture. You have to be sure you can sell in volume otherwise it's a big loss.

      I'm beginning to think maybe we should have a dedicated electronics forum
    1. SilverWarior's Avatar
      SilverWarior -
      Quote Originally Posted by AthenaOfDelphi View Post
      I'm beginning to think maybe we should have a dedicated electronics forum
      To be honest I not into electronics myself (I do know some basics) but I still got this idea.
    1. masonwheeler's Avatar
      masonwheeler -
      I have to wonder, though, in an age of Raspberry Pis and Arduinos, is any of this "low hardware, high-cost electronics" stuff at all relevant anymore?
    1. AthenaOfDelphi's Avatar
      AthenaOfDelphi -
      Absolutely it is. Whilst Pi's and Arduinos etc. are cheap, if you're going for volume it's very hard to beat one time programmable microcontrollers and electronics dedicated to the one task they have to perform. Pi's et al. are fine for prototyping, but they carry a lot of baggage that they require to make them general purpose, this adds unnecessary cost which every manufacturer will be wanting to keep to an absolute minimum. Every single component on custom boards like this should have a purpose... if not, it's added cost and should be removed.

      Plus, unless you start designing your own PCBs (which kind of negates one the benefits of development boards - the fact you don't have to spend a lot of time laying the board out), you can't do funky stuff like fit the PCB to the physical constraints of whatever it is you're working on. The vendor control board had to fit within the confines of the vending unit, accommodate the primary drive gear that effectively encapsulated the motor and one or two sensor mechanisms (optical beam switches). The attachments show the prototype PCB completely with hard wired programming cable so I could program it in situ in the vendor.

      Attachment 1272 Attachment 1271

      Pi's and Arduinos etc. definitely have a place in the engineers toolbox. I've got a number of projects I'm looking at that would be ideal for the Pi. I'm also looking at another project I designed and prototyped that has a few design flaws in it to see if I would be better off building a board that hosts a Pi as it's brain as opposed to a big fat PIC with lots of IO. Should have gone the Pi route in the beginning, but we live and learn... as a benefit of that particular project I now understand the thermal characteristics of my toaster oven that prevent it from being a good one to use for reflow soldering