Recently I wanted to expand the functionality of an automated test harness for an embedded device.  The device has a 16 character display made of 4 Avago HDLx-2416 Series parts (datasheet).  I gutted the device and tapped the display's pins to my AVR.  The AVR reads the LED display's signal pins and sends the displayed string to the test harness via serial connection.  Now the test harness can verify that the device under test's display is lighting as expected.

/*
* ScreenScan.cpp
*
* Created: 6/8/2012
*  Author: BK Turley
*/

/*
port wiring:

PB0 - ascii 0
PB1 - ascii 1
PB2 - ascii 2
PB3 - ascii 3
PB4 - displayaddr0
PB5 - displayaddr1
PB6 - crystal
PB7 - crystal

PC0 - /EN1
PC1 - /EN2
PC2 - /EN3
PC3 - /EN4
PC4 - /dispclear
PC5 - /dispblank(temporary)
PC6 - /reset

PD0 - RX
PD1 - TX
PD2 - external interrupt 0
PD3 - unused
PD4 - ascii 4
PD5 - ascii 5
PD6 - ascii 6
PD7 - unused

*/

#include <avr/io.h>
#include <avr/interrupt.h>

#define FOSC 20000000 // Clock Speed
#define BAUD 4800
#define MYUBRR (FOSC/16/BAUD -1)

#define TRUE 1
#define FALSE 0

char asciitable[128];
char dispdata[16];
volatile uint8_t freshdata = FALSE;
volatile uint8_t Bdata;
volatile uint8_t Cdata;
volatile uint8_t Ddata;

const uint8_t multiplierlookup[9] = {0,0,1,0,2,0,0,0,3};

void fillasciitable(void){
for (uint8_t i=0; i<128; i++)
asciitable[i] = (char)i;
}

void update_displaydata(void){

if (!(Cdata & 0b00110000)){ //if dispclear or dispblank is active(low)
for (uint8_t i=0; i<16; i++) //blank the data array
dispdata[i] = ' ';
}else{ // change the appropriate character

uint8_t bank = ~(Cdata & 0b00001111) & 0B00001111;              // bank describes which of the 4 displays was edited
uint8_t address = ~(0b00000011 & (Bdata >> 4)) & 0b00000011;    // address describes what portion of the display was edited

uint8_t multiplier = multiplierlookup[bank];
dispdata[(4*multiplier)+address] = asciitable[(Ddata & 0b01110000) | (Bdata & 0b00001111)];
}
freshdata = FALSE;
sei();             //enable global interrupts
}

void send_displaydata(void){ //TODO:  packetize and checksum instead of sending entire 16 char string every time

// send data
for (uint8_t i=0; i<16; i++){
while ( !(UCSR0A & (1 << UDRE0)) ); // Wait until buffer is empty
UDR0 = dispdata[i];                 // Send the data to the TX buffer
}
// send a newline
while ( !(UCSR0A & (1 << UDRE0)) ); // Wait until buffer is empty
UDR0 = 'n';                        // Send the data to the TX buffer
}

int main(void)
{

// setup ports
// pin7 --> pin0
DDRB = DDRB & 0b11000000;   // set B0-B5 to input, leave B6 & B7 alone (crystal).
DDRC = DDRC & 0b11000000;   // set C0-C5 to input, leave C6 & C7 alone.
DDRD = DDRD & 0b00000011;   // set D2-D7 to input, leave D0 & D1 alone.

PORTB = PORTB & 0b11000000; // tristate B0-B5
PORTC = PORTC & 0xff;
PORTD = 0b00000100; // set PD2 to high (turn on pull up resistor)

// setup interrupt
EIMSK |= _BV(INT0);   //Enable INT0 on PD2
EICRA |= _BV(ISC01);  //Trigger on falling edge of INT0

// Set baud rate
UBRR0H = (MYUBRR >> 8);
UBRR0L = MYUBRR;

// Enable receiver and transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
// Set frame: 8data, 1 stop
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);

fillasciitable();

//enable interrupts
sei();

// OPERATION LOOP
while(TRUE)
{
if(freshdata){
update_displaydata();
send_displaydata();
}
}
}

// External interrupt service routine
ISR(INT0_vect)
{    if(freshdata)
return;
Bdata = PINB;
Cdata = PINC;
Ddata = PIND;
freshdata = TRUE;
cli(); //disable interrupts
}

Leave a Reply

Your email address will not be published. Required fields are marked *