CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

question about putting together a vfd drive

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
cskinner



Joined: 09 Sep 2011
Posts: 4

View user's profile Send private message

question about putting together a vfd drive
PostPosted: Fri Sep 09, 2011 8:40 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Sep 09, 2011 3:18 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Sep 09, 2011 4:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Sep 09, 2011 10:25 pm     Reply with quote

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
Code:

output_d(c);


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

View user's profile Send private message

PostPosted: Sat Sep 10, 2011 11:04 am     Reply with quote

Wow, this above and beyond what I was asking for, thanx!
cskinner



Joined: 09 Sep 2011
Posts: 4

View user's profile Send private message

PostPosted: Tue Oct 11, 2011 8:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Oct 11, 2011 8:55 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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