Go Down

Topic: SoftwareSerial magic numbers (Read 14 times) previous topic - next topic

robtillaart

Good to hear it works, "outside the lab" ;)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

genom2

#31
Feb 07, 2013, 11:00 pm Last Edit: Feb 08, 2013, 10:56 pm by genom2 Reason: 1
Hi robtillaart,

I wondered why a long devision (int32) is needed. I tried to find a solution with int (int16) only. And came up with this precise solution (focus is on rxintra):
Code: [Select]

 // 8MHZ
 int baudrate = (int)speed;

 int j=-39 | baudrate;
 int m=2* (-baudrate & 2*j | baudrate);
 int a=((2*m) & m ) | baudrate;
 int rxintra=(-15240-3*a-j)/a-1;

It's precise in a sense that it resembles all table data with 0 difference. (But it's not "linear" in your sense. Instead I call it "weird".)
To make your proof simple I wrote this scetch:
Code: [Select]

#include "WProgram.h"

//
// Lookup table
//
typedef struct _DELAY_TABLE
{
 long baud;
 unsigned short rx_delay_centering;
 unsigned short rx_delay_intrabit;
 unsigned short rx_delay_stopbit;
 unsigned short tx_delay;
} DELAY_TABLE;

//  8 Mhz table
static const DELAY_TABLE table[] PROGMEM =
{
 //  baud    rxcenter    rxintra    rxstop  tx
 { 115200,   1,          5,         5,      3,      },
 { 57600,    1,          15,        15,     13,     },
 { 38400,    2,          25,        26,     23,     },
 { 31250,    7,          32,        33,     29,     },
 { 28800,    11,         35,        35,     32,     },
 { 19200,    20,         55,        55,     52,     },
 { 14400,    30,         75,        75,     72,     },
 { 9600,     50,         114,       114,    112,    },
 { 4800,     110,        233,       233,    230,    },
 { 2400,     229,        472,       472,    469,    },
 { 1200,     467,        948,       948,    945,    },
 { 300,      1895,       3805,      3805,   3802,   },
};

int SoftwareSerial_rxintraA(long speed)
{
 for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
 {
   long baud = pgm_read_dword(&table[i].baud);
   if (baud == speed)
   {
     return pgm_read_word(&table[i].rx_delay_intrabit);
   }
 }
 return -1;
}

int SoftwareSerial_rxintraB(long speed)
{
 long baudrate = speed;
 // 8MHZ
 int rxintra = 8000000L/(7 * baudrate) - 4;
 return rxintra;
}

int SoftwareSerial_rxintraC(long speed)
{
 // 8MHZ
 int baudrate = (int)speed;

 int j=-39 | baudrate;
 int m=2* (-baudrate & 2*j | baudrate);
 int a=((2*m) & m ) | baudrate;
 int rxintra=(-15240-3*a-j)/a-1;
 return rxintra;
}

void setup() {
 Serial.begin(9600);
 Serial.println("baud\tA\tB\tC");
 for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
 {
   long baud = pgm_read_dword(&table[i].baud);
   Serial.print(baud);  Serial.print("\t");
   Serial.print(SoftwareSerial_rxintraA(baud));  Serial.print("\t");
   Serial.print(SoftwareSerial_rxintraB(baud));  Serial.print("\t");
   Serial.print(SoftwareSerial_rxintraC(baud));  Serial.print("\t");
   Serial.println();
 }
}

void loop() {
}


robtillaart

Amazing!
Seen quite some code in my life but this is a very amazing code (+1)

I didn't ran the code but I am wondering how you can represent 115200 in a int16. (you can't) so it is wrapped or truncated .
That result is tweaked by bit manipulation and some magic numbers to the right values.
Can you explain on which principle the math is based? website?


Drawback is its maintainability as it is hard to understand.
Furthermore as the table is only calculated once when begin(speed) is called, I doubt if there is a serious performance gain.

Does your magic code also calculate the intermediate values e.g. a baud rate of 7800 as in the previous post?


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

genom2

No, it will not deliver reasonable results for 7800. (At the beginning of this thread you ask for linearity. "weird" functions are not "linear" in your sense.)

I did not invent this "weird" function. Instead a genetic program invented it for me. I fed in the table you gave, reduced to the columns 'baud' and 'rxintra':
Code: [Select]

49664   5
57600   15
38400   25
31250   32
28800   35
19200   55
14400   75
9600    114
4800    233
2400    472
1200    948
300     3805

Because it's an int16 genetic programmer I had to truncate 115200 down to 16 Bits which is 49664.

After a while it found a perfect solution (which is equivalent to 0 differences to the given table). I kept it running for a night whilst the genetic programmer delivered even shorter code solutions. At the next morning I picked the best code sequence (so far) which had a codelen of 24:
Code: [Select]

a = -39;
a |= x;
j = a;
a += a;
n = a;
a &= 0;
a -= x;
a &= n;
a |= x;
a += a;
m = a;
a += m;
a &= m;
a |= x;
n = a;
a += a;
y= a;
a = -15240;
a -= y;
a -= n;
a -= j;
a = a / n;
y= a;
y--;

Where x is baud and y is rxintra. I manually transformed to, what you already know as:
Code: [Select]

// 8MHZ
  int baudrate = (int)speed;

  int j=-39 | baudrate;
  int m=2* (-baudrate & 2*j | baudrate);
  int a=((2*m) & m ) | baudrate;
  int rxintra=(-15240-3*a-j)/a-1;

robtillaart

This is real fun!

Do you have a link to that genetic programmer you used?
Or did you write it yourself? post code ?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up