Interfacing with a TLC2543 11-channel, 12-bit A/D


/* Program 2543_1.C (Flashlite V25)
**
** Illustrates an interface with a Texas Inst TLC2543 11 channel 12-bit
** A/D.  Performs a unipolar measurement on Channel 0 and bipolar
** measurement on Channel 1.
**
** Note that TLC2543 is configured for 16-bit transfer (bits 3 and 2 of
** command byte).
**
** In function spi_io, o_byte is shifted out, most sig bit first, with
** each bit being set on the rising clock and data is read into i_byte
** when the clock is high.  This routine might be modified for other SPI
** devices to specify CLK and phase.
**
** P2.3 (SDI) <--------------------------- D_OUT
**
** P2.2 (SDO) ---------------------------> D_IN
** P2.1 (CLK) ---------------------------> CLK
** P2.0 (/CS) ---------------------------> /CS
**
** copyright, Peter H. Anderson, Baltimore, MD, Sept, 00
*/

#include <stdio.h>
#include <dos.h>

#define SEG 0xf000
#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12

typedef unsigned char byte;

#define SDI 3
#define SDO 2
#define CLK 1
#define NOT_CS 0

/* #define D */   /* used for debugging */

unsigned int ad_meas(byte far *p, byte channel, byte bipolar);
byte spi_io(byte far *p, byte o_byte);
void put_bit(byte far *p, byte bit_num, byte state);
byte get_bit(byte far *p, byte bit_num);
void delay_short(byte d);

void main(void)
{
  byte far *p2, *pm2, *pmc2;
  byte dirs, channel;
  int ad_val;

  p2 = MK_FP(SEG, P2_OFFSET);
  pm2 = MK_FP(SEG, PM2_OFFSET);
  pmc2 = MK_FP(SEG, PMC2_OFFSET);
  *pmc2 = 0x00;  /* not special purpose */
  dirs = 0xf8;    /* lower three bits are outputs */
  *pm2 = dirs;

  put_bit(p2, NOT_CS, 1);  /* disable to device */
  put_bit(p2, CLK, 0);     /* clock at zero */

  while(1)
  {
     channel = 0;
     ad_val = ad_meas(p2, channel, 0);  /* unipolar measurement on Ch 0 */
     printf("0  %4x\n\n", ad_val);

     delay(500);

     channel = 1;
     ad_val = ad_meas(p2, channel, 1);  /* bipolar measurement on Ch 1 */
     printf("1  %4x\n\n\n", ad_val);

     delay(500);
   }
}

unsigned int ad_meas(byte far *p, byte channel, byte bipolar)
/* perform measurement on specified channel */
{
   byte high_byte, low_byte;
   unsigned int ad_val;

   put_bit(p, NOT_CS, 0);
   delay_short(20);
   high_byte = spi_io(p, (channel << 4) | 0x0c + bipolar);
   low_byte = spi_io(p, 0x00);
   put_bit(p, NOT_CS, 1);

   put_bit(p, NOT_CS, 0);
   delay_short(20);
   high_byte = spi_io(p, (channel << 4) | 0x0c + bipolar);
   low_byte = spi_io(p, 0x00);
   put_bit(p, NOT_CS, 1);
#ifdef D
   printf(".. %2x  %2x\n", high_byte, low_byte);
#endif
   ad_val = high_byte;
   ad_val = (ad_val << 8) | low_byte;  /* result is in high 12 bits */
   ad_val = ad_val >> 4;               /* now in low 12 bits */
   return(ad_val);
}

byte spi_io(byte far *p, byte o_byte)
{
    byte i_byte, n;

    for(n=0; n<8; n++)
    {
       if (o_byte & 0x80)  /* most sign bit first */
       {
           put_bit(p, SDO, 1);
       }
       else
       {
           put_bit(p, SDO, 0);
       }
       put_bit(p, CLK, 1); /* data sent on rising edge */
       i_byte = (i_byte << 1) | get_bit(p, SDI) ;
       /* read in the middle of the clock pulse */
       put_bit(p, CLK, 0);
       o_byte = o_byte << 1;
   }
   return(i_byte);
}

void put_bit(byte far *p, byte bit_num, byte state)
{
    byte mask_0, mask_1;
    mask_1 = 0x01 << bit_num;
    mask_0 = ~mask_1;

    if (state == 0)
    {
        *p = *p & mask_0;
    }
    else
    {
        *p = *p | mask_1;
    }
}

byte get_bit(byte far *p, byte bit_num)
{
    byte mask_1;
    mask_1 = 0x01 << bit_num;
    if (*p & mask_1)
    {
        return(1);
    }
    else
    {
        return(0);
    }
}

void delay_short(byte d)
{
   while(--d)     ;
}