home
NSLU2 driving a PIC microprocessor as an i2c slave - more notes
- developing a general purpose control box containing a PIC16F877A
that, at the end of a long i2c line, reads temperatures and controls various systems


Notes on my first pair of test programs - not yet complete!!

NB there MUST BE errors here - but it seems to work.......
my "cut, paste and pray" C coding is right at its limit......

PIC_i2c.c
This is the program used in the Slug to send i2c data and commands to the PIC and to request data from the PIC.

16F877_AD_rs232_LCD_i2c_5.C
This is the CCS C program running in the PIC.
Most of the time the PIC runs the "main" code routine where it reads probe temperatures etc and displays data
on a local 4x20 LCD (eBay QY-2004A). It can also drive data out along it's rs232 line.
When it chooses the Slug can send i2c commands to the PIC which then pauses its "main" program loop.
The Slug first sends a string of bytes that the PIC stores at a location defined by the Slug. The Slug then reads
data from an array in the PIC where the PIC has saved data during its "free running" state.
The Slug then lets the PIC resume its "main" routines.
Thus the PIC can be a stand alone measuring device and controller most of the time - the Slug now and
then requesting a report or sending command bytes that make the PIC run different sections of it's "main" program loop.
(The i2c master need not be the Slug - the Sweex/Edimax router could also do the job.)

i2cdetect 0
shows -
00: .........XX XX XX XX XX XX XX XX XX XX XX XX XX
10: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
20: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
30: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
40: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
50: 50 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX UU
70: XX XX XX XX XX XX XX XX
The PIC i2c address is Hex 50 or Decimal 80 - (or Hex A0 in non Linux format)

The Slug program "PIC_i2c" sends out a string of 8 data bytes to the PIC on the i2c bus
- these are:-
(this is the Slug array slugbuf[8])
1 - 80 (decimal address of the PIC - Linux version)
2 - StartPoint (saved by PIC in BYTE StartPoint) - PIC will save the data string received from Slug starting at buf[StartPoint]

- - it next sends the 6 data bytes to be stored in the PIC "picbuf" array
3 - The first value of byte x that is used as a memory offset in the PIC and counts up (0 to 6) later to
pull in the three 2-byte AtoD values (in pairs of high and low bytes)
4 - command byte - this makes the PIC change the display it's LCD - 0 = main temperature display - 1 = admin display
5 - for future use
6 - for future use
7 - for future use
8 - for future use

The PIC contains an array of memory locations picbuf[8] where it stores these bytes received from the Slug
The Slug bytes 3/4/5/6/7/8 above are placed in a segment of picbuf[8] starting at location picbuf[StartPoint]
This PIC "picbuf" array could be extended later and other StartPoint values chosen further along the array for other uses of the same PIC.

The Slug first sends all the above and with slugbuf[3] first containing x=0
It then starts to read data from the PIC.
To do this it sends slugbuf[2] and slugbuf[3] 8 times with x (in slugbuf[3]) incrementing to 1,2,3,4,5,6,7,8 (the PIC stores x in picbuf[StartPoint])
After each of the 8 writes the Slug reads back a data byte, the first 6 are the lo then hi values of the three A to D line readings,
the last 2 are spare at present.

Examples of Slug data string sent to PIC

./PIC_i2c 80 0 0 0 0 0 0 0 - see admin page
./PIC_i2c 80 0 0 1 0 0 0 0 - see temperatures as -2.5,12.5 etc
(address 80, StartPoint=0, Command byte 0 or 1, four unused empty values)

Slug to PIC
The i2c interrupt routine in the PIC program responds to the value of "state"
- if the Slug is sending data "state" goes from 0 to 1 to 2 etc as the data string comes in (up to 127 maximum)
For the first byte received "state" becomes 1 and the byte received is stored in the PIC BYTE "StartPoint"
Each byte received increments "state". The rest of the string from the Slug is placed in picbuf[StartPoint] and locations above that in sequence.

PIC to Slug
If "state" is hex 80 this means the master is requesting data from the PIC.
The PIC Val10Bit[ ] array contains three double byte temperature values at locations 0,1,2 that the PIC has placed
there during the "main" loop (while the Slug was not asking for data).
Each of these 0to1024 values is split into two 8 bit bytes, high and low, and sent in sequence back to the Slug
(as i goes 0 2 4 we read the 3 double byte values in Val10Bit [0,1and 2])
The high and low bytes of the three temperature are sent to the Slug as x (stored by the PIC in picbuf[StartPoint]) goes 0,1,2,3,4,5
Each of the three double byte readings represents the values (0to1024) from the lowest 3 PIC AtoD lines (0,1 and 2) which are connected to LM335 temperature probes

The PIC code "main" routines
The values of the first 3 PIC AtoD lines are read into the bottom of the (long) array value[8]
the AtoD values come in a numbers 0-65472. The resolution is in fact only 1024 so we divide the values by 64 and store the results in (long) array Val10Bit[8]

The LM335 thermometer give a voltage of 2.73 at 0 degrees C
We choose to send data over the range -10degC to +40degC - that is 100 half degree steps.
After some simple calculations the float array Temperature[8] holds 3 values like 20.5 or -3.5 degrees - these are displayed locally by the PIC LCD screen
(NB the slug is sent the raw A to D values from the thermometers and must do a similar calculation.)

run PIC_i2c
Slug52local:/home/graham/i2c# ./PIC_i2c 80 0 0 0 0 0 0 0
PicData 1 = 229 (decimal value of low byte, thermometer 1)
PicData 2 = 3 (decimal value of high byte, thermometer 1)

PicData 3 = 103 (decimal value of low byte, thermometer 2)
PicData 4 = 0 (decimal value of high byte, thermometer 2 )

PicData 5 = 7 (decimal value of low byte, thermometer 3)
PicData 6 = 1 (decimal value of high byte, thermometer 3 )

PicData 7 = 8 (not used)

3 is 256 + 512 = 768
768 + 229 = 997

103 = 103

256 + 7 = 263

- so, on a scale of 1 to 1024, these received A to D values are 997 103 and 263

Control from a Web page
The Blassic basic language can be used as an ultra-simple cgi scripting language.
PIC_control_bas.cgi reads the thermometers in the i2c slave PIC box (warning! it is about as crude as you can get!)
The file resides in the folder cgi-bin and is addressed in Firefox like http://192.168.0.52/cgi-bin/i2cPIC/PIC_control_bas.cgi

I have a startup script in /etc/init.d containing mount -o size=2M -t tmpfs tmpfs /var/www/ramdisk
It creates a folder in RAM for the use of Blassic and Blassic to Bash data transfers. This saves thrashing the external disk.

The web page shows -
Testing the PIC i2c slave box

Temperature 1 is -10 degrees C
Temperature 2 is 40.5 degrees C
Temperature 3 is -10 degrees C

My backup of PIC_i2c_one_value.c


Simplified general purpose PIC as i2c slave - Slug can switch PIC GPIO port pins and read GPIO port pin voltages and measure AtoD volts
I found the addressing methods above confusing - this simplified test also uses Slug as i2c master and 16F877A as i2c slave.

The PIC sends data to a 4x20 LCD display and an rs232 line. Port pins D0,1,2,3 are connected as outputs
and D4,5,6,7 are connected as inputs with 0 or 5V applied. All AtoD pins on port A can be read.

The Slug C program PIC_i2c_one_value_a.c is used as
./PIC_i2c_one_value_a 80 2 0 0 0 0 0 The arguments are -
1) the PIC i2c address
2) the value x that reads stored data in the PIC array Val10Bit[] - 2 values of x per doublebyte number in the array
So x must count to 32 to read all the Val10Bit[] values
3) command byte - 0 for temperature display, 1 for admin data page.
4) four 0 or 1 values to set pins D0-3

The PIC CCS C program is 16F877_AD_rs232_LCD_i2c_5b.C

For my backup 16F877_AD_rs232_LCD_i2c_5b.hex - - - - PIC_i2c_one_value_a