|
|
View previous topic :: View next topic |
Author |
Message |
cskinner
Joined: 09 Sep 2011 Posts: 4
|
question about putting together a vfd drive |
Posted: Fri Sep 09, 2011 8:40 am |
|
|
I’m trying to write a driver for a vfd display using D0-D7 to transmit data. The part I’m getting caught up on is how to go about assembling the data going to port D. Is my only option to do it bitwise?
thanx
Link to the vfd: http://ssl.bulix.org/projects/lcd4linux/attachment/wiki/Noritake/noritake_gu128x32-311_spec.pdf
This what I have so far:
Code: |
#define set_tris_lcd(x) set_tris_d(x) //port D used for DATA D0 to D7
#define VFD_WR PIN_B1 //write
#define VFD_BL PIN_B2 //blank
#define VFD_CS PIN_B4 // cable select
#define VFD_RESET PIN_B5
#define VFD_BUSY PIN_B0
//************************************************************************//
// BRIGHTNESS LEVEL - According to datasheet to configure VFD brightness
//************************************************************************//
#DEFINE brightness_9 0x6C
#DEFINE brightness_27 0x67
#DEFINE brightness_52 0x64
#DEFINE brightness_65 'c'
#DEFINE brightness_81 0x62
#DEFINE brightness_100 0x61
//************************************************************************//
// character write
//************************************************************************//
void vfd_write_character(unsigned char c)
{
unsigned char busy;
set_tris_lcd(0xff); // set data port to input
output_high(VFD_CS);
output_high(VFD_WR);
output_high(VFD_REST);
output_high(VFD_BL);
input_low(BUSY);
do {
output_high(VFD_CS);
output_high(VFD_WR);
output_low(VFD_EN);
} while input_low(BUSY)== 0;
set_tris_lcd(0x00); // set data port to output
output_low(VFD_CS); // write
output_low(VFD_WR);
output_low(VFD_WR);
output_d(c);
output_high(VFD_EN);
output_low(VFD_EN);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 09, 2011 3:18 pm |
|
|
If your LCD data lines are connected to PortD, what's wrong with using
output_d() ? Why is that a problem ?
If you don't use fast i/o mode on PortD, the output_d() function
will automatically change the TRIS to all outputs on PortD. |
|
|
cskinner
Joined: 09 Sep 2011 Posts: 4
|
|
Posted: Fri Sep 09, 2011 4:46 pm |
|
|
I'm unsure how to go about string the data together. How would one make something like this: 01 'G' 0x00 'LEN' 'Q" output to port D as one line? It should be a 8bytes of data when I'm done. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 09, 2011 10:25 pm |
|
|
I think the easiest way to make a driver would be to translate this one to CCS:
http://ldd6410.googlecode.com/svn/trunk/tests/lcd4linux-0.10.1-RC2/drv_Noritake.c
This is one of the include files:
http://lcd4linux.sourcearchive.com/documentation/0.10.0plus-pcvs20051015/drv__generic__parport_8c-source.html
You can start by translating the low level routines.
Do this routine first:
Code: |
void drv_GU311_send_char(char c)
|
It calls these i/o routines:
Code: |
void drv_generic_parport_data(char c)
void drv_generic_parport_control(char mask, char value)
void ndelay(unsigned long delay)
|
drv_generic_parport_data(c) -
This should be converted to
drv_generic_parport_control(SIGNAL_WR, 0) and
drv_generic_parport_control(SIGNAL_WR, 0xff) -
These two should be converted to this (using your #defines):
Code: |
output_low(VFD_WR);
output_high(VFD_WR);
|
ndelay() -
On the internet, ndelay() is described as a nanosecond delay routine.
In the code that I linked, he does use it that way, but his comments
are misleading. He uses the abbreviation of "ms" for microseconds,
and he should be using "us". However, the shortest delay on a 16F
or 18F PIC running at 20 MHz is 200 ns, so most of his delays can't
be duplicated. Anything less than ndelay(1000) should be converted
to delay_us(1).
So the converted send_char routine would be like this:
Code: |
void drv_GU311_send_char(char c)
{
output_d(c); // Put data on PortD
delay_us(1);
output_low(VFD_WR); // Create negative WR pulse
delay_us(1);
output_high(VFD_WR);
delay_us(1);
}
|
According to his comments, polling the Busy line is not needed, because
he uses fixed delays. But, he seems to be confused about the time
required to execute the lcd commands. After sending the Clear command
he waits for 500 ns below. But in the Noritake data sheet that you linked,
they show a delay of 500 us. So he does have some mistakes.
Quote: |
static void drv_GU311_clear(void)
{
static char clear_cmd[] = { 0x01, 'O', 'P' };
drv_GU311_send_string(clear_cmd, sizeof(clear_cmd));
ndelay(500); /* Delay for execution - this command is the longuest */
}
|
|
|
|
cskinner
Joined: 09 Sep 2011 Posts: 4
|
|
Posted: Sat Sep 10, 2011 11:04 am |
|
|
Wow, this above and beyond what I was asking for, thanx! |
|
|
cskinner
Joined: 09 Sep 2011 Posts: 4
|
|
Posted: Tue Oct 11, 2011 8:16 pm |
|
|
Okay, I took some time to make sure I understand the code but I am getting stuck when try to compile the driver. I keep getting "Error 128".
Am I not suppose to compile a driver?
Code: |
//************************************************************************//
// Display pin defintions
//************************************************************************//
#define set_tris_vfd(x) set_tris_d(x) //port D used for DATA D0 to D7
#define VFD_WR PIN_B1 //write
#define VFD_BL PIN_B2 //blank
#define VFD_CS PIN_B4 // channel select
#define VFD_RESET PIN_B5
#define VFD_BUSY PIN_B0
//************************************************************************//
// BRIGHTNESS LEVEL(brt) - According to datasheet to configure VFD brightness
//************************************************************************//
#DEFINE brightness_03 'p'
#DEFINE brightness_04 'o'
#DEFINE brightness_05 'n'
#DEFINE brightness_07 'm'
#DEFINE brightness_09 0x6C
#DEFINE brightness_11 'k'
#DEFINE brightness_14 'j'
#DEFINE brightness_17 'i'
#DEFINE brightness_21 'h'
#DEFINE brightness_27 0x67
#DEFINE brightness_33 'f'
#DEFINE brightness_42 'e'
#DEFINE brightness_52 0x64
#DEFINE brightness_65 'c'
#DEFINE brightness_81 0x62
#DEFINE brightness_100 0x61
Name[] = "Noritake";
typedef struct {
int type;
char *name;
int rows;
int cols;
int xres;
int yrex;
int goto_cost;
int protocol;
} MODEL;
int Model, Protocol;
static MODEL Models[] = {
{0x01, "GU311", 4, 21, 6, 8, 5, 1},
{0x02, "GU311_Graphic", 4, 21, 6, 8, 6, 1},
{0xff, "Unknown", -1, -1, -1, -1, -1, -1}
};
//************************************************************************//
//Hardware functions
//************************************************************************//
void drv_GU311_wait_busy(void)
{
char c;
c = drv_generic_parport_status();
while ((c & VFD_BUSY)==0);
delay_us(1);
c = drv_generic_parport_status();//non functional
}
void vfd311_drv_send_char(char c)
{
drv_GU311_wait_busy();
unsigned char c;
output_d(c); // Put data on PortD
delay_us(1);
output_low(VFD_WR); // Create negative WR pulse
delay_us(1);
output_high(VFD_WR);
delay_us(1);
output_d(c)
delay_us(1)
output_d(VFD_WR)
}
void drv_GU311_send_string(char *str, int size)
{
int i;
for (i = 0; i < size; i++)
drv_GU311_send_char(str[i]);
}
/* Command-string elaboration functions */
void drv_GU311_make_text_string(const int row, const int col, const char *data, int len)
{
// Character write
// static char cmd[96]= {Header, Op Code, 0, 0, LEN, 0}
char cmd[96] = { 0x01, 'C', 0, 0, 'S', 0 };
unsigned char start_addr;
/* Cols are 0x00..0x15, on 4 lines. */
start_addr = (0x16 * row) + col;
if (start_addr > 0x57)
return;
if (len > 0x57)
return;
cmd[2] = start_addr;
cmd[3] = len;
memcpy(cmd + 5, data, len);
drv_GU311_send_string(cmd, len + 5);
}
/* API functions */
void drv_GU311_clear(void)
{
char clear_cmd[] = { 0x01, 'O', 'P' };
drv_GU311_send_string(clear_cmd, sizeof(clear_cmd));
delay_us(0.5); /* Delay for execution - this command is the longuest */
}
void drv_GU311_write(const int row, const int col, const char *data, int len)
{
drv_GU311_make_text_string(row, col, data, len);
}
void drv_GU311_reset(void)
{
output_low(VFD_REST); /* initiate reset */
delay_us(1); /* reset hold time 1ms */
output_high(VFD_REST);
delay_us(20); /* reset ready time 200ms */
}
int drv_GU311_start(void)
{
/* port association */
if input(VFD_CS) == 0
return -1;
if input(VFD_WR) == 0
return -1;
if input(VFD_RESET) == 0
return -1;
if input (VFD_BLANK) == 0
return -1;
/* SIGNAL_BUSY=PARPORT_STATUS_BUSY; *//* Not currently needed */
/* SIGNAL_FRP=PARPORT_STATUS_ACK; *//* Not currently needed */
/* Signals configuration */
void drv_generic_parport_data(char c); /* parallel port in output mode */
void drv_generic_parport_control(char mask, char value);
/* All lines to "deactivate", -> 1 level on the wire */
output_low(VFD_CS); /* CS to 0 all the time, write done by WR */
drv_GU311_reset();
void control_code (char cmd_code, char brt)
}
void control_code (char cmd_code, char brt)
{
char cmd[3] = { 0x01, 'O' }; // select charatcter command code
/* Ready for commands from now on. */
/* Display configuration */
cmd[2] = cmd_code(); /*command code settings */
drv_GU311_send_string(cmd_code, sizeof(cmd_code));
cmd[2] = brt(); /* brightness control */
drv_GU311_send_string(brt, sizeof(brt)); /* Select 'Quick Mode' */
drv_Noritake_clear();
return 0;
}
int drv_Noritake_start(const char *section)
{
char *model = 0;
int i;
model = cfg_get(section, "Model", NULL);
if (model != NULL && *model != '\0') {
for (i = 0; Models[i].type != 0xff; i++) {
if (strcasecmp(Models[i].name, model) == 0)
break;
}
if (Models[i].type == 0xff) {
error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
return -1;
}
Model = i;
info("%s: using model '%s'", Name, Models[Model].name);
} else {
error("%s: no '%s.Model' entry from %s", Name, section, cfg_source());
return -1;
}
DROWS = Models[Model].rows;
DCOLS = Models[Model].cols;
XRES = Models[Model].xres;
YRES = Models[Model].xres;
GOTO_COST = Models[Model].goto_cost;
Protocol = Models[Model].protocol;
/* display preferences */
CHARS = 0; /* number of user-defineable characters */
CHAR0 = 0; /* ASCII of first user-defineable char */
/* real worker functions */
drv_Noritake_clear = drv_GU311_clear;
if (Models[Model].type == 0x01) {
drv_generic_text_real_write = drv_GU311_write;
} else {
error("%s: Unsupported display. Currently supported are : GU311.", Name);
return -1;
}
return drv_GU311_start(section);
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 11, 2011 8:55 pm |
|
|
There are lots of errors that have to be fixed.
This array has no data type declared. You need to declare it as 'int8' or 'char':
Quote: |
Name[] = "Noritake";
|
Here you have a structure typedef and a variable with the same name.
This is a problem because the CCS compiler is case insensitive by default.
To fix this, you need to add the #case directive near the start of the program:
Quote: |
typedef struct {
int type;
char *name;
int rows;
int cols;
int xres;
int yrex;
int goto_cost;
int protocol;
} MODEL;
int Model, Protocol;
|
Here, CCS doesn't like having embedded string data, without having
storage explicitly allocated for it:
Quote: |
static MODEL Models[] = {
{0x01, "GU311", 4, 21, 6, 8, 5, 1},
{0x02, "GU311_Graphic", 4, 21, 6, 8, 6, 1},
{0xff, "Unknown", -1, -1, -1, -1, -1, -1}
};
|
You can fix it by editing the structure to declare an array instead of a
pointer, as shown below:
Quote: |
typedef struct {
int type;
char name[15];
int rows;
int cols;
int xres;
int yrex;
int goto_cost;
int protocol;
}MODEL; |
Here you're calling a function which doesn't exist anywhere in the program:
Quote: |
void drv_GU311_wait_busy(void)
{
char c;
c = drv_generic_parport_status();
while ((c & VFD_BUSY)==0);
delay_us(1);
c = drv_generic_parport_status(); //non functional
} |
Here you are testing a status byte against a CCS pin number, when it
the code expects a bitmask. But you don't have a Parallel Port status
byte (from a PC's parallel port) available on a PIC so this code is wrong
in its basic design:
Quote: |
#define VFD_BUSY PIN_B0
c = drv_generic_parport_status();
while ((c & VFD_BUSY)==0);
delay_us(1);
|
Basically, it just goes on and on like this, so I'm going to stop. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|