7SDevice part4

= PART 4 =

Device C Coding
Now we have to implement the real code that will run inside the PIC16F84A. The first thing to do is to set the processor configuration bits. We will disable code protection, watch dog timer, and power startup timer and declare the use of a XT oscillator. This is accomplished by in the file configuration_bits.c

Then in the user.h header we will put all port pins definition, we will declare the receiver machine states in an enum type, and we'll create some variables and functions prototypes.

note that most variables are volatile. We declare an object as "volatile" when its value could be changed or modified in a way that is not apparent to the compiler, so we want a consistent and explicit storage model without hidden optimization. DigitA and DigitB will store the digit to display. Dgt variable will be used to alternatively select the digit that the receiver state machine has to update. Buffer variable is the incoming byte form the host. App_WDT and WDT_TIMEOUT will be explained later on.

In the function InitApp in user.c we will initialize Ports and data direction as follow

Here we will also set timer0 clock source to be internal and prescaler to 1/32 and assign to timer0. From the datasheet we know that clock for internal counter is Fclock/4 so in our case is 1 Mhz. We set prescaler to 1/32 so the counter will increment at a rate of (Fclock/4)/32 that is 31250 hz. So our 8 bit counter will be incremented every 1/31250 sec  and the counter will overflow every 256/31250 = 0.008192  that is 8.192 msec as we've seen  in part 1. We enable interrupts and set the beginning receiver machine state to Init. From now on the interrupt routine will run forever displaying each digit in turn. In user.c there are also the compiler directive for store the ledcode table we seen in part 2 in the internal eeprom with these instructions

let see now the interrupt C routine

here we check for interrupt overflow flag T0IF and if the mutex variable “out” is 0 we select digit B, if 1 we select digit A with DSELECT signal (RA0). We switch off the leds first and then we retrieve the ledcode according the data digit displacement passed. The compiler function eeprom_read(displacement) will return the eeprom content at the address “Eeprom base + displacement” so for example when the host want to display the digit 5 he pass the uint8 number 5 to device and device will retrieve the corresponding ledcode accessing the location Eeprom base + 5 that in our case is 0x5D We put that value on port B and invert the mutex variable “out” then we reset the overflow flag.

I want to spend now some words about blocking code. Even if we aren't writing a multitasking application is a good idea to write the firmware code in a form of multiple state machine running at the same time.

With this approach the main code is composed of a unique super-loop. At every iteration each state machine task is called. Each state machine maintains its unique inner state variables and according to the environmental change events she update variables and change state if necessary. With this approach you can guarantee that many task can run at the same time and that the superloop execution time can be identified with a certain accuracy. If a state machine has the need to have a loop this is accomplished checking some state variable at each superloop iteration and changing state only when a certain condition is met.

In the part 3 we've seen that each machine state will be waiting for the other part to became ready or to complete its work. So we have to think about what happen if for some reason this information never came up. The state machine will hang in a loop we said. As a result the device would probably be unable to work again. For this reason we have to implement a mechanism to abort current operation and revert to a known state if something go wrong.

In every processor there is at least a system WatchDog Timer. This is a counter that increment on its own. When a specific value is reached the WatchDog timer reset the processor program counter and the code start again as if the part was just powered on. So the programmer has the responsibility to clear the watchdog timer in each part of the code he want assuring that in a normal working condition the trigger value is never reached. With this concept should a firmware hang in a loop for some reason after a max amount of time the processor will be surely reset.

We'll introduce the same concept for each state machine. So if the machine that handle the communication protocol hangs in a loop at every iteration of the superloop an application Watch Dog Timer will be incremented. This App_WDT will be reset during normal algorithm proceeding.

Note that is possible to have many different Application WatchDog timers running at the same time (App_WDT_1, App_WDT_2 ecc) So we can model a specific application behavior according the expiration of a specific Application Watch Dog timer. In This way instead to reset the whole processor we can reset a single task or even a specific part of a task within the superloop if needed.

Before we see the actual state machine device C Code implementation we have to say that it will be useful to have a mechanism to test if the hardware board just assembled is working properly  or not before connecting any host. To do so, i implemented a self test in the code. When device is powered and find both clock and MOSI line down she will enter in a blocking forever test state and will display a two digit counter running. This way you can check that every pcb track are ok and that the hardware is good. Let see now the application code.

The state machine start in the init state and wait for power to stabilize. Then check if a test condition is matched. If this is the case the next state is set at TEST. On the next superloop iteration she will enter in the TEST state and will stay there for ever until power off. The waiting power stabilizing time and the test state time are the unique part of the code that are blocking since in this context the application isn't started yet.

he state machine implementation is quite similar to what we saw in the java simulator. Here the blocking code we seen has been substituted. Let analyze this code

We can be in this state for two reason .. or we are at the beginning of a incoming byte or we are waiting for the n-th bit of the byte, Since we have to wait until clock is down we, at every iteration, increment the application watch dog timer and check if the clock is down.

If this condition is held for too much time something has probably go wrong with the host. So when the watchdog timer pass a boundary value WDT_TIMEOUT, the application state machine is reset in the Idle state, clearing the receive bit number and the incoming byte buffer. We set WDT_TIMEOUT to 30000. if we count the longest path within the superloop we'll see that the number of instructions really executed in a superloop is limited (take a look to the assembly listing of the code) compared with 30000. We set this istruction number around 15.

So 30000 App_WDT increments can be approximated as if there are 30000 *15 RISC instruction to be executed. Since each instruction is executed at Fclock/4 this timer will be expiring not less than 4/Fclock * 30000  * 15 =  450 msec @4 Mhz So after at least 450 msec without any host activity the machine state will be reset in the idle state.


 * (Some experiments after the writing of this article shown that is safe to reduce WDT_TIMEOUT to 1000 to respond faster to interruption events. In this case the device application reset is about 15 msec)

On receiving the right criteria (clock down in this case) the App_WDT is reset to 0. So in normal operation wdt is never triggered. When the application state machine is waiting for a byte coming from the host the state will be constantly ping-ponging from idle state to the WaitForClockDown.

Now it's time to see the implementation of host state machine. We will start with the simple Pinguino IDE implementation. First we should see how to connect the device board to PIC32_DIY board. Look at this drawing.



In the Pinguino IDE example given the pin assignment are as follow


 * Green		Serial Clock from Host
 * Red		+3.3 Power connection
 * Yellow 	MOSI data line from Host to Device
 * Orange	       MISO data line from Device to Host
 * White 		GND

In Pinguino32 DIY layout would be nice to have each connector with a spare +vcc and gnd pin available. This way would be much easier to connect together two board. But for now we have to use what we have. However you can choose any pin you like on the host side. On the Device side the connector is, numbering from top to bottom, as in picture


 * 1 – GND
 * 2 – MISO
 * 3 – MOSI
 * 4 – VCC
 * 5 – SCK

= Pinguino IDE Host Routine =

In most applications its enough to include in your project these two routine that are implemented as blocking code.

As you can see there aren't delay or other special attention to talk with device.
 * SPI_Send implement the host protocol to transfer a digit to device
 * Display_Send simply call SPI_Send for both digit passed.

A more complex Demo Host example
Should you want to use this device as a debug unit for displaying error codes probably the host protocol implementation has to be non blocking, because most other tasks running inside the main application code could be time sensitive and more important, so the display process should be a non intrusive low priority task. So i written this tiny example as a guide to show you how to implement the non blocking host routine.

The code is written for PIC32_DIY PIC32MX250F128B

The conceptual idea is :

When overflow occurs the Display Interrupt Handler is called. This implement step by step the Host-Device Protocol State Machine that is scattered among multiple interrupt callback execution. At each interrupt call the state machine proceed and change state if specific protocol conditions are met.
 * The timer1 driven by Peripheral Clock divided by 64 generate an overflow every 100 usec

I made also the USERLED (RA0) gently flashing during operation.
 * After what we've seen in the last section you might be able to read and understand the code on your own. Look to the processor datasheet for explanation of register used. Here you will find the Application WatchDog timer i introduced before and a start-up timer to have a clean sync start.

This code is written in MPLAB-X. I included in the project tree the .ld file to allow .hex loading through bootloader. You will find it in the .zip provided archive. To load the code with bootloader use


 * ubw32 -w  -n -r

As a final part let now do some testing and measures. 7SDevice_part5

= All parts of this article =
 * Part 1 - Goals and constraints
 * Part 2 - Hardware design
 * Part 3 - Protocol Handshaking simulation
 * Part 4 - Software
 * Part 5 - Measure and testing