 |
www.angelfire.com/dragon/letstry
cwave04 at yahoo dot com | 
|
|
|
Reading/writing entire bytes
We are programming the microcontroller serieally. This means
sending sending and receiving signals bit by bit. For example
when the datasheet asks you to send 10100000 to the
microcontroller this is what the timing diagram should look like:
Remember the analogy of SCK with a window. The window is closing
and opening intermittently. It is open when SCK is 1, closed
when 0. The microcontroller gets a glimpse of the MOSI line only
when the window is open. Each glimpse counts as a bit.
Clearly, we shall often need to emit a positive pulse down the SCK
line. We shall write a little function

void pulseSCK() {
setBit(SCK,1,"SCK");
setBit(SCK,0,"SCK");
}
|
We shall make a convention here: never to touch SCK (after
initialising it to 0) outside this
function. This will guarantee that SCK is 0 always outside this
function.
Next we shall write a function to send a byte down the MOSI
line. The function will accept the byte as a string (instead of
as an unsigned char). Thus if we want to send the bit pattern
01010000 then we can directly write
sendByte("01010000");
rather than have to convert 01010000 to 0x50 first. This will reduce
the chance of mistakes. The function is easy to write:

void sendByte(char what[]) {
int i, check;
inpByte = 0;
for(i=0;i<8;i++) {
setBit(MOSI,what[i],"MOSI");
pulseSCK();
}
}
|
Now we are going to add a little trick that will save lot of
debugging effort later. It is an interesting fact (though not
clearly documented in the datasheet) that the microcontroller has
the habit of echoing back the last byte sent to it. Thus if the PC
sends the byte 10101000 to it down the MOSI line, then in the
next 8 SCK pulses the microcontroller will send the same bit
pattern back via the MISO line. This is a great way to know that
the microcontroller is alive and kicking. There are two
situations when the microcontroller will not echo via the MISO
line. The echoing will not be there during the first 4
bytes. Also the echoing is absent when the microcontroller wants
to send some real data to the microcontroller.
To achieve this we shall keep a global variable
unsigned char lastVal;
|
Whenever we send a byte down the MOSI line we shall keep a backup copy of
the value in this variable. This is done in the next function.
void bin2num(char binByte[]) {
int val;
int i;
val = 0;
for(i=0;i<8;i++) {
val <<= 1;
if(binByte[i]=='1') val |= 1;
}
lastVal = val;
}
|
We call this function from inside sendByte as follows.

void sendByte(char what[]) {
int i, check;
inpByte = 0;
for(i=0;i<8;i++) {
setBit(MOSI,what[i],"MOSI");
pulseSCK();
}
check = (lastVal == inpByte);
bin2num(what);
if(verbose)
fprintf(stderr,(check? "In synch\n" : "Out of synch\n");
}
|
Notice the word "synch" in the diagnostic message. Most communication
failures between the microcontroller and the PC occur because of lack
of synchronisation (e.g., missing a bit somewhere, and then
getting confused with the rest). We shall talk more about
synchronisation later in this tutorial.
We shall also need another version of the same function that
accepts the input as an unsigned char. We shall do this in two
steps. First we shall convert the byte into a string of bits, and then
feed the string into the sendByte function.
Here is the function to convert a byte into a string:
void num2bin(int num, char binByte[]) {
int i;
int mask;
for(i=0,mask=1<<7;i<8;i++,mask>>=1)
binByte[i] = ((num & mask) ? '1' : '0');
binByte[8] = 0;
}
|
The following function first calls the above function and then sends the
resulting string down the MOSI line via sendByte.
void sendByte1(int b) {
char binByte[20];
num2bin(b,binByte);
sendByte(binByte);
}
|
You may very well be irritated by the ineffcient coding: first converting
the number to a string and then (inside sendByte) converting
it back to a number. There are two minor reasons behind this:
- We need to check the feedback of the microcontroller. So we need the
lastVal variable. We have declared it
as an unsigned char. So if the data byte is
specified as a string, we need to convert it to an unsigned char before
saving it into lastVal.
- Now, if we ever need to tweak the MOSI line communication later (for
debugging/experimenting) it will help if the tweaking is done in a
single function. In our implementation
sendByte is the
workhorse function, since sendByte1 also calls it. So
tweaking sendByte would be enough, without touching
sendByte1.
Reading a byte from the microcontroller does not need any extra
work. We simply send 8 dummy bits (say all 0's) and pick up the
inpByte which is produced from the bits coming down
the MISO line.

unsigned char receive() {
sendByte("00000000");
return inpByte;
}
|
|