I used a FT245RL to power a LCD i ripped from a dead UPS.
I was surprised on how easy it was to do, though this is all to do with the FT chip :)
Nicely 'hacked' into the back with rubber bands, hehe
And the circuit if anyone wants it...
And the C code to run it... (pity blogspot don't syntax color the code)
*EDIT: actually they do see http://lukabloga.blogspot.com/2008/10/to-test-new-highlighting.html
/*
To build use the following gcc statement
gcc -o LCD LCD.c -L. -lftd2xx -Wl,-rpath /usr/local/lib
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <ftd2xx.h>
//#include <ctype.h>
#include <unistd.h>
#include <string.h>
// Globals
#define BANNER1 "LCD VERISON:1.0 mohclips kiwi-hacker.net\n"
#define TOPLINE 1 // we have test to write on the top line
#define BOTTOMLINE 2 // we have text to write on the bottom line
FT_HANDLE ftHandle = NULL;
FT_STATUS ftStatus;
unsigned char ucMode = 0x00;
unsigned char backlight = 0; // turn on 1 /off 0 lcd backlight
//LCD Registers addresses
// ---data---- RS En BL NC
// 1 2 4 8 0x10 0x20 0x40 0x80
// d0 d1 d2 d3 d4 d5 d6 d7
#define LCD_RS 0x10 //20 = d5 on FT245RL pin 9 = LCD pin 4
#define LCD_EN 0x20 //80 = d7 on FT245RL pin 6 = LCD pin 6
#define BACKLIGHT 0x40
#define LCD_MASK 0x0F
/*
AN232R-01 Bit Bang Modes for the FT232R and FT245R
The clock for the (a)Synchronous Bit Bang mode is actually 16 times the Baud rate.
A value of 9600 Baud would transfer the data at (9600x16) = 153600 bytes per second,
or 1 every 6.5us.
For the data to change there, has to be new data written and the Baud rate clock has to tick.
If no new data is written to the device, the pins will hold the last value written.
19200 baud = 38400*16 = 614400 bytes/sec = 0.000001627604167 = 1 every 1.6 us
19200 baud = 19200*16 = 307200 bytes/sec = 0.000003255208333 = 1 every 3.3 us
9600 baud = 9600*16 = 153600 bytes/sec = 0.000006510416667 = 1 every 6.5 us
2400 baud = 16*2400 = 38400 bytes/sec = 0.000026041666667 = 1 every 26 us
1200 baud = 16*1200 = 19200 bytes/sec = 0.000052083333333 = 1 every 52 us
*/
#define BAUD_RATE 9600
#define ASYNC_BITBANG 0x01
#define SYNC_BITBANG 0x00 // you don't want this
#define delay_multiplier 1;
/*
http://www.microcontrollerboard.com/lcd.html
Register Selector
RS R/W
0 0 Sends a command to LCD
1 0 Sends information to LCD
R/W is always set low (0) by grounding it
E == 1 => process data on bus
*/
void bin_prnt_byte(int x)
{
int n;
for(n=0; n<8; n++)
{
if((x & 0x80) !=0)
{
printf("1");
}
else
{
printf("0");
}
if (n==3)
{
printf(" "); /* insert a space between nybbles */
}
x = x<<1;
}
printf("\t");
}
void delayus(int microsecs)
{
//http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/usleep.3.html
//suspend thread execution for an interval measured in microseconds
unsigned int us_sleep;
us_sleep = microsecs * delay_multiplier;
//printf("sleeping %d us\n",us_sleep);
usleep( us_sleep );
}
void delayms(int millisecs)
{
//http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/usleep.3.html
//suspend thread execution for an interval measured in microseconds
unsigned int us_sleep;
us_sleep = millisecs * 1000 * delay_multiplier;
//printf("sleeping %d us\n",us_sleep);
usleep( us_sleep );
}
void lcd_read() {
ftStatus = FT_GetBitMode(ftHandle, &ucMode); // get values on the D0-7 pins
if(ftStatus != FT_OK) {
printf("Failed to get bit mode\n");
} else {
printf("Ports Show: %x\n",ucMode);
};
};
void lcd_port(unsigned char out)
{
#define BUF_SIZE 1 // send 1 char out to driver
DWORD dwBytesWritten;
unsigned char rs;
unsigned char en;
rs = out & LCD_RS;
en = out & LCD_EN;
// send 1 char out to driver
if (backlight) {
out |= BACKLIGHT; //turn on the backlight
};
//bin_prnt_byte(out);
//printf("FT_Write: 0x%02x, RS 0x%02x, EN 0x%02x\n", out, rs, en);
if((ftStatus = FT_Write(ftHandle, &out, BUF_SIZE, &dwBytesWritten)) != FT_OK) {
printf("Error writing to FTDI driver %ld", ftStatus);
};
if (dwBytesWritten != 1) {
printf("Error data not written to ports : bytes written = %ld\n",dwBytesWritten);
};
//printf("Bytes Written: %ld\n",dwBytesWritten);
//ftStatus = FT_GetBitMode(ftHandle, &ucMode); // get values on the D0-7 pins
//printf("Wrote: %02x\n",ucMode);
}
void lcd_4bit_data (unsigned char dat)
{
unsigned char hi, lo;
hi = (dat >> 4) & LCD_MASK;
lo = dat & LCD_MASK;
//printf("4-bit data %x hi, lo %x, %x\n",dat, hi, lo);
lcd_port ( hi | LCD_RS | LCD_EN ); // data mode - pulse En Hi->Lo
// 450ns strobe
lcd_port ( hi | LCD_RS ); // data mode
delayms(1); // 200us for data writes
lcd_port ( lo | LCD_RS | LCD_EN ); // data mode - pulse En Hi->Lo
lcd_port ( lo | LCD_RS ); // data mode
delayms(1); // 200us for data writes
}
void lcd_8bit_cmd (char cmd)
{
//printf("8-bit cmd %x\n",cmd);
lcd_port ( cmd | LCD_EN ); // pulse En Hi->Lo
lcd_port ( cmd );
// we don't delay here, must be done elsewhere
}
//http://www.8051projects.net/lcd-interfacing/lcd-4-bit-programming.php
// timing from http://joshuagalloway.com/lcd.html - waits between nibbles
void lcd_4bit_cmd (char cmd)
{
unsigned char hi, lo;
hi = (cmd >> 4) & LCD_MASK;
lo = cmd & LCD_MASK;
//printf("4-bit cmd %x hi, lo %x, %x\n",cmd, hi, lo);
lcd_port ( hi | LCD_EN ); // pulse En Hi->Lo
lcd_port ( hi );
delayms(5); // Wait 5ms for command writes
lcd_port ( lo | LCD_EN ); // pulse En Hi->Lo
lcd_port ( lo );
delayms(5); // Wait 5ms for command writes
}
void lcd_reset()
{
/*
The reset process is extremely important
otherwise you just get garbage on the LCD
http://www.doc.ic.ac.uk/~ih/doc/lcd/initiali.html
http://www.repairfaq.org/filipg/LINK/F_Tech_LCD4.html
The module powers up in 8-bit mode. The initial startup instructions are sent in 8-bit mode,
with the lower four bits (which are not connected) of each instruction as don't cares.
After the fourth instruction, which switches the module to 4-bit operation,
the control bytes are sent on consecutive enable cycles (no delay is required between nybbles).
Most significant is sent first, followed immediately by least significant nybble.
** which is opposite to other sites say :(
*/
delayms(100); // Wait 20ms for LCD to power up
//lcd_8bit_cmd( Set_Function + Data_Length_8);
lcd_8bit_cmd( 0x3 );
delayms(5);
// delay should be 4.1ms
//lcd_8bit_cmd ( Set_Function + Data_Length_8);
lcd_8bit_cmd( 0x3 );
delayms(5);
// delay should be 100us
//lcd_8bit_cmd ( Set_Function + Data_Length_8);
lcd_8bit_cmd( 0x3 );
delayms(5);
// delay should be 4.1ms
//lcd_8bit_cmd ( Set_Function + Data_Length_4);
lcd_8bit_cmd( 0x2 );
delayms(5);
// delay should be 40us
}
void lcd_init ()
{
// http://www.8051projects.net/lcd-interfacing/commands.php
// nearly all LCDs always start in 8-bit mode
lcd_reset(); // Call LCD reset
// from here we are in 4-bit mode
lcd_4bit_cmd(0x28);
lcd_4bit_cmd(0x08);
lcd_4bit_cmd(0x01);
lcd_4bit_cmd(0x06);
lcd_4bit_cmd(0x0C);
}
void quit()
{
if(ftHandle != NULL) {
FT_Close(ftHandle);
ftHandle = NULL;
printf("Closed device\n");
}
exit(1);
}
void usage()
{
printf(BANNER1);
printf("\nUsage: LCD [-1 -2 -h -?]\n");
printf("\t-1 \"string\" = write up to 16 chars to the top line of the LCD\n");
printf("\t-2 \"string\" = write up to 16 chars to the bottom line of the LCD\n");
printf("\t-? -h = this help\n\n");
}
int main(int argc, char *argv[])
{
int iport;
int c; // getopt
int j;
unsigned char topline[16];
unsigned char bottomline[16];
int opts = 0;
iport = 0; // only one FT245 allowed at present
signal(SIGINT, quit); // trap ctrl-c call quit fn
while( (c = getopt(argc, argv, "h?1:2:")) != -1 )
{
/* Process the command line arguments */
switch( c )
{
case '1': if( optarg ) /* Configuration file */
{
strncpy( topline, optarg, sizeof( topline ) );
opts |= TOPLINE;
}
break;
case '2': if( optarg ) /* Configuration file */
{
strncpy( bottomline, optarg, sizeof( bottomline ) );
opts |= BOTTOMLINE;
}
break;
case 'h':
case '?': usage();
exit(-1);
break;
default: break;
} //switch
} // get opt
ftStatus = FT_Open(iport, &ftHandle);
if(ftStatus != FT_OK) {
/*
This can fail if the ftdi_sio driver is loaded
use lsmod to check this and rmmod ftdi_sio to remove
also rmmod usbserial
*/
printf("FT_Open(%d) failed = %ld\n", iport, ftStatus);
return 1;
}
ftStatus = FT_SetBitMode(ftHandle, 0xFF, 0x01); // ASYNC BIT BANG across all ports
if(ftStatus != FT_OK) {
printf("Failed to set bit mode\n");
}
ftStatus = FT_SetBaudRate(ftHandle, 9600);//BAUD_RATE
if(ftStatus != FT_OK) {
printf("Failed to set baud rate\n");
}
// turn on backlight
// backlight=1;
// lcd_port(0);
// init the LCD - very important
lcd_init();
if ( opts & TOPLINE ) {
// we always write to the top line as default
for(j = 0; j < strlen(topline); j++) {
lcd_4bit_data(topline[j]);
}
}
if ( opts & BOTTOMLINE ) {
lcd_4bit_cmd(0x80 + 0x40); // 0x40 = address of bottom line
for(j = 0; j < strlen(bottomline); j++) {
lcd_4bit_data(bottomline[j]);
}
}
// turn off backlight
// backlight=0;
// lcd_port(0);
ftStatus = FT_ResetDevice(ftHandle);
if(ftStatus != FT_OK) {
printf("Failed reset device\n");
};
if(ftHandle != NULL) {
ftStatus = FT_Close(ftHandle);
if(ftStatus != FT_OK) {
printf("Failed close device\n");
};
ftHandle = NULL;
}
//return 0;
}
No comments:
Post a Comment