Pages

Wednesday, July 28, 2010

how to transfer 2 byte data

Sometimes you want to send 2 byte data or more. But we all know that many transfer medium like serial, I2C, CAN bus, bluetooth, etc; only allows use 1 byte data transfer only. So how to send integer value into byte medium? One way is converting into a sequence of character. Another way is splitting the data per bytes. For example, sending integer16 into byteHi and byteLo. It may easy if using assembly languages.
This time I'll show you how to send integer data from microcontroller to PC. I'm using C language in the microcontroller, and C# in the PC.
The key of these processes are 16 bit to 8 bit converter.

On the PC, using C#
memory mapping
//using System.Runtime.InteropServices
struct unionStruct {
   [FieldOffset(0)]
   public short bigVal;
   [FieldOffset(0)]
   public byte smallLow;
   [FieldOffset(1)]
   public byte smallHi;
}

Basically, we create struct. But somehow, we make one field is overlapped in the memory. This is the splitting work. As shown on the picture, bigVal is overlapped with the memory of smallLow and smallHi. In the other words, when we put a value in the smallLow, we can access it from smallLow or from bigVal. When we put 0x12 in the smallLow, it's same like we put 0x0012 in the bigVal. When we put 0x34 in the smallHi, then, in the bigVal will be read 0x3400. So if we put 0x1234 in the bigVal, then we can read the low byte in the smallLow which has the value of 0x34. And also we can read the high byte in the smallHi which has the value of 0x12. It has the same principles on C language.

On the microcontroller, using C
typedef struct {
memory mapping
   unsigned char lo;
   unsigned char hi;
}hilo_t;

typedef union {
   unsigned int besar;
   hilo_t  kecil;
}hilo_ut;

In the C language, we can't control the field offset. So we can create a structure that has 2 byte field. And then we put the structure in the union to make it overlapped with 2 byte memory.

How it works?
To send data, make sure the sequence is same for the microcntroller and the PC.This to avoid misunderstanding between PC and microcontroller of how to put the high byte and the low byte.
  1. Splitting 16-bit data to send to PC.
    hilo_ut byteInterface; //declaration
    byteInterface.besar = data16;   //put 16-bit data
    send(byteInterface.kecil.lo);      //send low byte first
    send(byteInterface.kecil.hi);      //send high byte
  2. Assembly two 8-bit data into 16-bit data in the PC
    unionStruct byteInterface = new byteInterface();  //declaration
    byteInterface.smallLow = read();   //read low byte first because microcontroller sends low byte first
    byteInterface.smallHi = read();      //read high byte
    short needee = byteInterface.bigVal; //read the 16-bit data
  3. Splitting 16-bit data to send to microcontroller.
    unionStruct byteInterface = new byteInterface();  //declaration
    byteInterface.bigVal = dataBig;   //put the 16-bit value
    send(byteInterface.smallLow);      //send low byte
    send(byteInterface.smallHi);      //send high byte
  4. Assembly two 8-bit data into 16-bit data from the PC
    hilo_ut byteInterface; //declaration
    byteInterface.kecil.lo = read();   //read low byte first
    byteInterface.kecil.hi = read();      //read high byte
    unsigned int nedee = byteInterface.besar;
That is how the easy way.

Tuesday, July 20, 2010

how to trap errors in firmware

Programming a microcontroller sometimes makes you frustrated. Its because it has errors which we don't know where. So these is a little example:

-----------
for(;;)
{
   valueA = functionA();
   valueB = functionB();
   valueC = functionC();
}
------------ but my microcontroller seems not work??
Lets create a trap using leds attached on portA
--------------
//for(;;)
//{ //just make sure this piece of code run only one time
  portA = 1; 
  valueA = functionA();
  portA = 2;
  valueB = functionB();
  portA = 3;
  valueC = functionC();
  portA = 4;
//}
-------------
now look at leds, :
  • value = 4; it means all functions is working.
  • value = 2; it means functionA is never done, is must have some infinite loop like while (true value), or for(i=0;i>2;i--) but i value never goes below 2, etc. Now you know that the errors is inside functionA, you may delete the trap and create new trap just inside functionA
Another way is create some monitor to evaluate value. For example:
Suppose you have UART function working properly and called SendUsart(char data)
---------

for(;;)
{
   SendUsart('A'); SendUsart('0');
   valueA = functionA();
   SendUsart('B'); SendUsart(valueA);
   valueB = functionB();
   SendUsart('C'); SendUsart(valueB);
   valueC = functionC();
   SendUsart('D'); SendUsart(valueC);
   _delay_ms(500); //just to make your hyperterminal not flooded :D
}---------
now lets look at your hyperterminal:
....A0B2C3D5A0B2C3D5A0B2C3D5...
just look at the repeated value. Let suppose you have :
functionA(){
  return 50;
}
functionB(){
  return (valueA + 1);
}
functionC(){ 
  return (valueB + 1);
}
and the reading....
B2 : because on functionA you put 50, it will send 2 (ascii value of 2 is 50 decimal)
C3 : inside functionB, you add valueA with 1, the result is 51 (ascii : 3)
D5 : inside functionC, you add valueB with 1, the result must be 52 (ascii: 4), but in the reading is 53 (ascii value : 5). So the valueB must be changed somewhere. Usually from interrupt routine. You may check the routine.

so that is how using trap and monitor for finding bug inside firmware. Experienced programmer know where to put traps and monitor in error-prone routine.

Saturday, July 17, 2010

removing many items from list

Let's take a look a screenshoot first :

Lets suppose you have a list, and you want to delete selected list.
For the first time, I am using foreach, but it throws an exception. Yes of course, item count will change after removing. So the foreach constraint will changed while looping. So it can't use foreach. It must use loop.
for(int i = 0; i<mList.Count; i++)
  It's wrong because m.List.Count will change after deletion. You must create buffer to accomodate this.
int mCount = mList.Count;
for(int i = 0; i < mCount; i++)
mList.RemoveAt(table.Rows[i].index);

It's also remove unwanted items. Its because after deletion, index also change. For example, when you remove index 1 and then index 3, what actually happens is you delete index 1, and then index 2 become index 1, and soon. When you remove index 3, actually you remove the item who has index of 4 before deletion loop. Its now become index 3 and this who will be deleted. Because the index before deleted items never change, you can reverse the loop:
 int mCount = mList.Count - 1;
for(int i = mCount; i >=0; i--)
{
mList.RemoveAt( table.Rows[i].index);
}