this is a working code that is splitting the 8 bit data on two different ports and I am not understanding how it is working.
if we AND PORTB to ~0x3F which is 0xC0 , it will make bits DB0-DB5 all zeros so how is the PORTB and PORTC
assignments working ?
Just break each part of the operation down, and use binary values. The playground article will explain the operations. Then it is just a matter of working them out. Tough to get thinking this way, but practice will make it easier.
The mask is 0x3F which has the lower 6 bits set. c & DMSK gives a byte with the lower 6 bits from c and the upper 2 bits set to zero. PORTB & ~DMSK gives a byte with the upper 2 bits from PORTB and the lower 6 bits set to zero. Or-ing these two bytes gives a byte with the upper 2 bits from PORTB and the lower 6 bits from c. Similar analysis can be applied to the PORTC assignment.
See comments in the code. What AVR are you going to run this on as it won't work on the UNO as is.
/*-------------------------------------------------
DATA:
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
PB0 PB1 PB2 PB3 PB4 PB5 PC6 PC7
CONTROL:
RES RD WR RS
PC2 PC3 PB4 PB5
---------------------------------------------------*/
#define DMSK 0x3F // = Binary 00111111
void write_8(unsigned char c)
{
PORTB = (PORTB & ~DMSK)|(c & DMSK); // Read PORTB and mask to keep upper 2 bits, Mask c to keep lower 6 bits, OR both together and write back to PORTB
PORTC = (PORTC & DMSK)|(c & ~DMSK); // Read PORTC and mask to keep lower 6 bits, mask c to keep upper 2 bits, OR both and write back to PORTC
}
void TFT_setup(void)
{
DDRB |= DMSK; // Set lower 6 bits of PORTB as output (upper 2 bits remain the same as the value is OR'ed)
DDRC |= ~DMSK; // Set upper 6 bits of PORTC as output
DDRC |= 0x3C; // Set bits 2-5 of PORTC as output
}
void write_8(unsigned char c)
{
PORTB = (PORTB & ~DMSK)|(c & DMSK); // Read PORTB and mask to keep upper 2 bits, Mask c to keep lower 6 bits, OR both together and write back to PORTB
PORTC = (PORTC & DMSK)|(c & ~DMSK); // Read PORTC and mask to keep lower 6 bits, mask c to keep upper 2 bits, OR both and write back to PORTC
}
void TFT_setup(void)
{
DDRB |= DMSK; // Set lower 6 bits of PORTB as output (upper 2 bits remain the same as the value is OR'ed)
DDRC |= ~DMSK; // Set upper 6 bits of PORTC as output
DDRC |= 0x3C; // Set bits 2-5 of PORTC as output
}
oh I see it now ,, PORT B bits 0-5 are made zero but when OR'ed with data gives the pins correct values.
I am running this code on atmega1284 .
void write_8(unsigned char c)
{
PORTB = (PORTB & 0xF8)|(c & 07); // Read PORTB and mask to keep upper 5 bits, Mask c to keep lower 3 bits, OR both together and write back to PORTB
PORTC = (PORTC & 07)|(c & F8); // Read PORTC and mask to keep lower 3 bits, mask c to keep upper 5 bits, OR both and write back to PORTC
}
void TFT_setup(void)
{
DDRB |= ((1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2)|(1<<PORTB5))
DDRC |= ((1<<PORTC2)|(1<<PORTC3)|(1<<PORTC4)|(1<<PORTC5)|(1<<PORTC6)|(1<<PORTC7))
DDRD |= ((1<<PORTD2)|(1<<PORTD3))
}
please note I am using one DDRC command to set the data and control bits as output and not two DDRC commands as in original post.
I obviously have no idea of your hardware layout/limitations but if your designing it yourself then life would be so much easier if you could dedicate all 8 pins on a port to the 8 bit data bus. It should also speed up display refresh quite a bit as less instructions needed to just write a value to a single port instead or Reading, AND'ing, OR'ing & writing to two separate ports.