GoodLink(TM) code

Below is the code I needed to get the PDIUSBD12's GoodLink(TM) indicator to come on. Naturally this code runs on the PIC16F877 of my project, which is wired up as described on in the #defines as well as the USB page.

Below is a screenshot of HyperTerminal interacting with the system running this code. For more information on the PIC ←→ PC setup, see Tools.

This code assumes you are using either a dumb-terminal or equivalent (I was using HyperTerminal) to view the results of printf and to satisfy getch() statements.

This code was made for MPLAB v7.0, with the CCS add-in.

#include <16f877.h>
#include <ctype.h>
 
//--------------------------------------------------------
// Setup PIC and CCS compiler
#fuses XT, PUT, NOWDT, NOPROTECT
#use delay(clock = 4000000)
 
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
// By using C6 and C7, we will make use of the 877's hardware USART abilities
 
#use standard_io(b)
#byte port_d = 8
 
//--------------------------------------------------------
// Definitions
#define ON				1
#define OFF				0
 
#define D12_A0			PIN_B6
#define D12_WR_N		PIN_B2
#define D12_RD_N		PIN_B1
#define D12_RESET_N		PIN_B5
#define D12_SUSPEND		PIN_B4
#define D12_INT_N		PIN_B0
 
#define D12_DATA		0
#define D12_COMMAND		1
 
#define LED_N PIN_B7
 
//--------------------------------------------------------
// Global Variable Declarations
 
 
//--------------------------------------------------------
// Function prototypes
void D12Write(short, int);
void D12Read(unsigned char, int);
void D12InterruptHandler();
 
//--------------------------------------------------------
// Entry point
void main(void){
	short debug = OFF;
 
	output_low(LED_N);	// Turn on the yellow LED
 
	while(debug)
	{
		printf("Hello World!\r\n");
		delay_ms(1000);
		output_toggle(LED_N);	// Yellow LED
	}
 
	//---------------------------------
 
	printf("");		// Clear screen (ANSI escape sequence)
	printf("Putting pins into known state and resetting D12\r\n");
	set_tris_b(0x01);	//PIN_B1 (D12's INT) is input, the rest are output.
	set_tris_d(0x00);	//All output
	port_d = 0xFF;		//Set bus high, useful for checking the ribbon has not come loose
 
	output_high(D12_RD_N);
	output_high(D12_WR_N);
 
	output_low(D12_RESET_N);	// Reset PDIUSBD12
	output_low(D12_A0);			// Indicates bus is for data
	output_low(D12_SUSPEND);	// (? Not sure how this is meant to work in practice)
 
	disable_interrupts(GLOBAL);	// Stop interrupts from interrupting us while we setup ;)
 
	ext_int_edge(H_TO_L);		// Set up when to trigger
	enable_interrupts(INT_EXT);	// Enable external interrupts (connected to the D12's INT_N)
	clear_interrupt(INT_EXT);	// Remove pending interrupts
	enable_interrupts(GLOBAL);	// Globally enable interrupts
 
	printf("=================================================\r\n");
	printf("Ready. Press any key to proceed.\r\n");
 
 
	//---------------------------------
 
	getch();					// Wait for keypress
	output_high(D12_RESET_N);	// Bring D12 out of reset (start it up!)
	delay_ms(1);
 
	//if(input(D12_INT_N)==0)
	//	D12InterruptHandler();
 
	printf("CMD:  Set Address/Enable\r\n");
	D12Write(D12_COMMAND, 0xD0);
 
	printf("\tDATA: 0x80 (Enable, no address)\r\n");
	D12Write(D12_DATA, 0x80);
 
	printf("CMD:  Set endpoint enable\r\n");
	D12Write(D12_COMMAND, 0xD8);
	printf("\tDATA: 0x01 (Enabled)\r\n");
	D12Write(D12_DATA, 0x01);
 
	printf("CMD:  Set Mode\r\n");
	D12Write(D12_COMMAND, 0xF3);
	printf("\tDATA: No Lazy Clock, Clock Running, ");
	printf("Interrupts=1, SoftConnect=1\r\n");
	D12Write(D12_DATA, 0x1E);
	printf("\tDATA: Start of Frame interrupt disabled, ");
	printf("Set-to-one not set, ");
	printf("\r\n\t\tClock Division Factor = 1011b\r\n");
	D12Write(D12_DATA, 0x0B);
 
	printf("End of Program\r\n");
}
 
//--------------------------------------------------------
// Used for passing commands or data to the PDIUSBD12
void D12Write(short type, int data)
{
	switch(type)
	{
		case D12_DATA:
		case D12_COMMAND:
			set_tris_d(0x00);		// Set bus to output mode
			output_high(D12_RD_N);	// Ensure we don't conflict with RD_N
 
			if(type == D12_COMMAND)
				output_high(D12_A0);
			else
				output_low(D12_A0);
 
			port_d = data;			// Setup bus
			delay_ms(1);			// Settling time
			output_low(D12_WR_N);
			output_high(D12_WR_N);
 
			if(type == D12_COMMAND)
				output_low(D12_A0);
			break;
		default:
			printf("Error in D12Write(), unknown type: 0x%x!\r\n", type);
			printf("Expecting one of:\r\n\t 0x%x\r\n\t0x%x\r\n", D12_COMMAND, D12_DATA);
	}
}
 
//--------------------------------------------------------
// Used for reading data from the PDIUSBD12
void D12Read(unsigned char* buffer, int reads)
{
	int i;
 
	set_tris_d(0xFF);		// Set bus to intput mode
	for(i = 0; i<reads; i++)
	{
		output_low(D12_RD_N);
		buffer[i] = port_d;		// Latch in the bus
		output_high(D12_RD_N);
	}
}
 
//--------------------------------------------------------
// FIXME: Probably want to save some registers when handling
//        this interrupt, as it takes quite a long time.
#INT_EXT
void D12InterruptHandler()
{
	unsigned char buffer[2];
	int i;
 
	// The first "" is an bell control-character, the second an escape
	//  makes text red and bold,  makes it normal and white
	printf("\r\n\r\nInterrupt!\r\n");
	printf("CMD:  Read Interrupt Register\r\n");
	D12Write(D12_COMMAND, 0xF4);
	D12Read(buffer, 2);
	printf("Interrupt register bytes were 0x%x and 0x%x.\r\n\r\n", buffer[0], buffer[1]);
	getch();
 
	for(i=0; i<6; i++)
	{
		printf("CMD:  Read Last Transaction Status Register (0x%x)\r\n", 0x40 + i);
 
		D12Write(D12_COMMAND, 0x40 + i);
		D12Read(buffer, 1);
 
		printf("\tStatus: 0x%x.\r\n", buffer[0]);
	}
	printf("Press a key to resume\r\n\r\n");
	getch();
}