How to write out 8 bits using "Register manipulation"?

Hello,

I want to drive a LCD and I want to get the maximum speed possible with an 16MHz Arduino board.

I already had everything working with “digitalWrite” but I’m not happy with the speed I can get with this.

This is the function, I used to set one byte to the parallel interface:

#define PIN_D0 2
#define PIN_D1 3
#define PIN_D2 4
#define PIN_D3 5
#define PIN_D4 6
#define PIN_D5 7
#define PIN_D6 8
#define PIN_D7 9

// Set one byte to the parallel interface
void ParportWriteDataDW(unsigned char aData) {
  digitalWrite(PIN_D0, aData & (1<<0));
  digitalWrite(PIN_D1, aData & (1<<1));
  digitalWrite(PIN_D2, aData & (1<<2));
  digitalWrite(PIN_D3, aData & (1<<3));
  digitalWrite(PIN_D4, aData & (1<<4));
  digitalWrite(PIN_D5, aData & (1<<5));
  digitalWrite(PIN_D6, aData & (1<<6));
  digitalWrite(PIN_D7, aData & (1<<7));
}

Works perfectly but is a bit too slow for my needs.

This is the second try. LCD connected to the exact same pins:

// Set one byte to the parallel interface
void ParportWriteData(unsigned char aData) {
  unsigned char maskD = B11111100;
  unsigned char bitsD = aData << 2;
  PORTD = (PORTD & ~maskD) | (bitsD & maskD);
  unsigned char maskB = B00000011;
  unsigned char bitsB = aData >> 6;
  PORTB = (PORTB & ~maskB) | (bitsB & maskB);
}

This one does not work. I only get garbage on the LCD. I tried over and over again to find the reason why this doesn’t work, but so far I had no success…

This one also doesn’t work:

// Set one byte to the parallel interface
void ParportWriteData(unsigned char aData) {
  unsigned char maskD = B11111100;
  unsigned char bitsD = aData << 2;
  PORTD = (PORTD & ~maskD) | (bitsD & maskD);
  unsigned char maskB = B00000011;
  unsigned char bitsB = aData >> 6;
  PORTB = (PORTB & ~maskB) | (bitsB & maskB);
  digitalWrite(PIN_D0, aData & (1<<0));
  digitalWrite(PIN_D1, aData & (1<<1));
  digitalWrite(PIN_D2, aData & (1<<2));
  digitalWrite(PIN_D3, aData & (1<<3));
  digitalWrite(PIN_D4, aData & (1<<4));
  digitalWrite(PIN_D5, aData & (1<<5));
  digitalWrite(PIN_D6, aData & (1<<6));
  digitalWrite(PIN_D7, aData & (1<<7));
}

So my register manipulation “kills” something that even an added “digitalWrite” can’t fix.

Can someone have a look at the above function and maybe tell my how I can send out one byte of data to GPIO pins as fast as possible without running into problems?

Thanks in advance.

To read a port, use PIND or PINB accordingly.

Where do you set the Data Direction Registers (DDRD, DDRB)?

I use "pinMode" to set the pins to "output".

But I also used "DDRD and DDRB" before which didn't change anything:

  unsigned char modeBits = (aPinMode == OUTPUT) ? 0xFF : 0x00;
  unsigned char maskD = B11111100;
  DDRD = (DDRD & ~maskD) | (modeBits & maskD);
  unsigned char maskB = B00000011;
  DDRB = (DDRB & ~maskB) | (modeBits & maskB);

Seems like either the Arduino libraries are doing some "magic", which I still miss in my code, or that I got the pins/bits wrong...

What Arduino are you using?

Once you start using direct port manipulation your code will not be transferrable between different models.

If you figure out which I/O pins relate to which bits in which port the direct port manipulation is very straightforward.

...R

You missed my main point. This line PORTD = (PORTD & ~maskD) | (bitsD & maskD); should be:

PORTD = (PIND & ~maskD) | (bitsD & maskD);

I can't make much sense of the following, and don't think it will work, either:

unsigned char modeBits = (aPinMode == OUTPUT) ? 0xFF : 0x00;
  unsigned char maskD = B11111100;
  DDRD = (DDRD & ~maskD) | (modeBits & maskD);
  unsigned char maskB = B00000011;
  DDRB = (DDRB & ~maskB) | (modeBits & maskB);

I don't have any problems with direct port manipulation, so I know it works if done properly.

Here is a routine performing a very similar function. I wrote it many years ago, and it still works fine. Perhaps it will help you see what is wrong with yours.

Of course, the DDRD and DDRB registers must be properly set.

/*
Send lower 4 bits of data byte to display
*/
void	LCDSendNibble(char data )
{
	data &= 0x0F;			//lower 4 bits of data
	data <<= 3;
	PORTB &= ~0x38;			//clear LCD bus bits 456
	PORTB |= (data & 0x38);	//or in data
	data <<= 1;
	PORTD &= ~0x80;			//same for top bit on PORTD.7
	PORTD |= (data & 0x80);
	_delay_us(1);
	PORTD |= (1<<4);		//E = 1
	_delay_us(2);			//requires minimum 1 us delay
	PORTD &= ~(1<<4);		//E = 0
	_delay_us(1);
}