NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » lcd driver for different pins

August 17, 2012
by eminthepooh
eminthepooh's Avatar

I'm trying to redo the lcd driver for another micro but have been stuck for a while. My wiring is as follows on port C: 7=x, 6=4th bit, 5=3rd bit, 4=2nd bit, 3=1st bit, 2=Enable, 1=R/W, 0=RS

having looked at the nerdkits library file I've made these changes which have resulted in it not working.

// lcd_set_type_data()
void lcd_set_type_data() {
  PORTC |= (1<<PC0);
}

// lcd_set_type_command()
void lcd_set_type_command() {
  PORTC &= ~(1<<PC0);
}

// lcd_write_nibble(...)
void lcd_write_nibble(char c) {

  // NOTE: only 2 or 3 work in the delays here.

  // set data
  PORTC &= ~(0x78 << 0);
  PORTC |= (c&0x0F) << 3;

  // E high
  PORTC |= (1<<PC2);
  _delay_us(1);
  // E low
  PORTC &= ~(1<<PC2);
  _delay_us(1);

}

void lcd_write_byte(char c) {
  lcd_write_nibble( (c >> 4) & 0x0F );
  lcd_write_nibble( c & 0x0F );
  _delay_us(80);
}

// lcd_init()
void lcd_init() {
  // set pin driver directions
  // (output on PD7,PD6, and PD3-6)
  DDRC |= 0xff;
    PORTC &= ~(1<PC1);  // always write, no read

  // wait 100msec
  _delay_ms(100);
  lcd_set_type_command();

  // do reset
  lcd_write_nibble(0x03);
  _delay_ms(6);
  lcd_write_nibble(0x03);
  _delay_us(250);
  lcd_write_nibble(0x03);
  _delay_us(250);

  // write 0010 (data length 4 bits)
  lcd_write_nibble(0x02);
  // set to 2 lines, font 5x8
  lcd_write_byte(0x28);
  // disable LCD
  //lcd_write_byte(0x08);
  // enable LCD
  lcd_write_byte(0x0c);
  // clear display
  lcd_write_byte(0x01);
  _delay_ms(5);
  // enable LCD
  lcd_write_byte(0x0c);
  // set entry mode
  lcd_write_byte(0x06);

  // set cursor/display shift
  lcd_write_byte(0x14);

  // clear and home
  lcd_clear_and_home();
}

any suggestions? thank you,

August 17, 2012
by eminthepooh
eminthepooh's Avatar

EDIT: line 40 should read

 PORTC &= ~(1<<PC1);  // always write, no read
August 17, 2012
by Ralphxyz
Ralphxyz's Avatar

Wow, eminthepooh, you must have torn all of your hair out over that one :-)

PORTC &= ~(1<PC1);
PORTC &= ~(1<<PC1);

Ralph

August 17, 2012
by eminthepooh
eminthepooh's Avatar

Thanks ralph, but that doesn't solve the problem. (I've even tried tying straight to ground, still no cigar)

August 17, 2012
by pcbolt
pcbolt's Avatar

eminthepooh -

Maybe I'm wrong here, but the lines inside "lcd_write_nibble()" seem to be throwing things off...

// set data
PORTC &= ~(0x78 << 0);
PORTC |= (c&0x0F) << 3;

Before you set enable high, you want PORTC to be x-b4-b3-b2-b1-0-0-r ('x' is whatever was there before and 'r' is the register select bit, 'bn' are bit values). Before you "OR" the nibble value in, PORTC should be x-0-0-0-0-0-0-r. So if you have x-x-x-x-x-x-x-r before this function gets called, you'd need to "AND" PORTC with 0x81 (0b10000001) to get x-0-0-0-0-0-0-r. Then you can "OR" with the nibble shifted over 3 places. Try,

// set data
PORTC &= 0x81;
PORTC |= (c&0x0F) << 3;

This is a good example of how to use the LCD code for different pins, just in case you may need some of the functionality of the PORTD pins. Let me know how it goes.

August 18, 2012
by eminthepooh
eminthepooh's Avatar

Thanks Pcbolt for your suggestion, but it didn't seem to work. my write nibble function is now this:

// lcd_write_nibble(...)
void lcd_write_nibble(char c) {

  // NOTE: only 2 or 3 work in the delays here.

  // set data
//  PORTC &= ~(0x78 << 0);
//  PORTC |= (c&0x0F) << 3;

    // set data
    PORTC &= 0x81;
    PORTC |= (c&0x0F) << 3;

  // E high
  PORTC |= (1<<PC2);
  _delay_us(1);
  // E low
  PORTC &= ~(1<<PC2);
  _delay_us(1);

}

But the problem has persisted sadly =[

August 19, 2012
by Rick_S
Rick_S's Avatar

1st, what frequency are you running your new micro at?

2nd, change the line back to what you had where you had (PCBOLT probably didn't realize that the RS bit is being set in a function you didn't list prior to entering the nibble function). The purpose of that first line in nibble is to clear the data to all zero before setting it with the new nibble.

// set data
PORTC &= ~(0x78 << 0);
PORTC |= (c&0x0F) << 3;

or if you want it to look more like the NK library,

// set data
PORTC &= ~(0x0F << 3);
PORTC |= (c&0x0F) << 3;

3rd, try tying your R/W line directly to ground instead of the MCU.

If your micro is not running at the same clock as the nerdkit (using a 14.7546 crystal which requires a change of the fuses on a new micro) the lcd library will not work. It uses hard coded NOP's (an assembly do nothing for a clock cycle command) to set the timings. If the mcu doesn't run at the same frequency, the timings are all out of whack and the LCD will not work.

Rick

August 19, 2012
by eminthepooh
eminthepooh's Avatar

Thanks Rick, My new mcu is running at 1mhz, and I've used the c utilities library to set delays, as you can see, delays are replaced with _delay_ms(). This micro works with the slower 1mhz clock if I tie the pins to the original LCD ports from the nerdkit lib (portC) and use the nerdkit LCD.c functions. I just can't seem to remap the pins is all :(

August 19, 2012
by Rick_S
Rick_S's Avatar

Ah, didn't catch the change for the libc delays. Did you try tying the R/W line low as in the NK setup?

August 19, 2012
by Rick_S
Rick_S's Avatar

If that doesn't work, maybe post your entire lcd.c and lcd.h files maybe there's something there we can see causing the issue.

Rick

Post a Reply

Please log in to post a reply.

Did you know that the Timer/Counter modules on the microcontroller can be configured to output a PWM (Pulse Width Modulation) signal? Learn more...