| Auto Baudrate Detection On The C16x |
The following example software was written as a customer demonstration of the IO and Timer capabilities of the SAB165 microcontroller. It is also a useful feature for a microcontroller to lock into a variable Baud rate in many embedded applications.
What it does
On reception of a @ character, the C165 is able to detect and change
its Baud rate to one of several predefined rates, if the detected Baud rates
error is within a redefined limit.
How it works
The serial RXD0 signal is also wired externally on the C165 to pin P3.7/T2IN.
This allows RXD0 to drive the T2IN control pin on the GPT1 timer module, which
controls the function of timer T2. This pin is then used to time a period of
the incoming character.
TTL Serial data
The ASCII code for the @ character is 0x40. Here is the serial TTL bit timing format.
![]()
Thus the RXDO in the case of @, consists of a negative edge followed by a low time of 7 Bits then a high time of a single bit followed by a low time of a single bit.
Bit Timing
The most straightforward method is to time a single BIT period of the incoming character. As there is single LOW BIT period at the end of the character this is the period which was chosen to be timed. It also has the added benefit that the timed answer is available at the end of the received character, ready to load into the relevant BAUD rate control register.

Timing Method
To time the last LOW BIT period, we need to detect the second negative edge, clear a timer and then capture the timer on the next positive edge. Timer block GPT1 has a core timer T3 and two auxiliary timer T2 and T4, for this purpose only T3 with T2 are used. The method chosen is for the core timer T3 to be continuously running at its maximum input frequency of 2.5Mhz @ 20Mhz CPU clock. The auxiliary timer, T2, is initially configured into Reload mode with T2 = 0 so that a negative transition of T2IN will reload T3 with 0 and cause a software interrupt. The interrupt counts the number of negative edges and when there have been two, it reconfigures T2 into Capture mode. The next positive edge will capture T3 into T2 and cause a software interrupt. The number of 2.5Mhz clocks in a single bit time is then held in T2. A table is then used to find the nearest BAUD rate control register value to be used by the serial channel.
*****************************************************************/
/* HITEX INTERFACE SOFTWARE DEVELOPMENT */
/* BY S.K JAN 1996 */
******************************************************************/
/* Contains the auto baudrate detection */
/*****************************************************************/
#include <reg167.h>
void set_baud_rate(short);
/* Reload T3 */
#define T2CON_NEG_EDGE ((0x4<<3) | 0x2)
/* Capture T3 */
#define T2CON_POS_EDGE ((0x5<<3) | 0x1)
#define EOT -1
#define BAUD_LOCK_ERROR 20
static short idata neg_edge_count;
struct BAUD_RATE
{ short capture;
unsigned short baud_reg; };
static const struct BAUD_RATE baud_table[]=
{ 100000L/(576*4),0x000A, /* 57600 baud */
100000L/(384*4),0x0010, /* 38400 baud */
100000L/(192*4),0x0020, /* 19200 baud */
100000L/(96*4),0x0040, /* 9600 baud */
100000L/(48*4),0x0080, /* 4800 baud */
100000L/(24*4),0x0100, /* 2400 baud */
100000L/(12*4),0x0200, /* 1200 baud */
100000L/(06*4),0x0400, /* 600 baud */
100000L/(03*4),0x0800, /* 300 baud */
EOT,0 };
*****************************************************************/
/* start_auto_detect() SK */
*****************************************************************/
/* Sets up GPT1 */
*****************************************************************/
void start_auto_detect() {
neg_edge_count = 0; /* negative edge */
/* counter = 0 */
T3CON = 0x0040; /* T3 timer running */
/* up @ 2.5MHz */
T2 = 0; /* T3 reload value */
T2CON = T2CON_NEG_EDGE; /* Reload T3 on */
/* negative */
/* transition of P3.7 */
T2IC = 0x4c; /* interrupt priority */
/* level 3 group 0 */
}
*****************************************************************/
/* t2_int() SK */
*****************************************************************/
/* T2 interupts on positive and negative */
/* transitions of p3.7 */
*****************************************************************/
void t2_int() interrupt 0x22 using t2_regs {
register short t2_capture;
/* starting T3 reloaded with T2 = 0 */
if (T2CON == T2CON_NEG_EDGE) {
/* @ has 2 negative edges */
if (++neg_edge_count == 2)
T2CON = T2CON_POS_EDGE;
}
else /* finished T2 = capture of T3 */
{
T2IC = 0; /* stop any more */
/* interrupts */
t2_capture = T2; /* number of 400nS */
/* clocks in 1 BIT time */
set_baud_rate(t2_capture);
}
}
*****************************************************************/
/* set_baud_rate(capture) SK */
*****************************************************************/
/* Set up S0BG with detected baudrate from */
/* <capture> value in */
/* lookup table <baud_table>. */
*****************************************************************/
void set_baud_rate(short capture) {
register short tester;
register struct BAUD_RATE *bptr = baud_table;
do {
tester = bptr->capture - capture;
if (tester < 0)
tester = -tester;
if (tester < BAUD_LOCK_ERROR) {
S0BG = bptr->baud_reg;
break;
}
bptr++;
}
while (bptr->capture != EOT);
}