I seem to remember seeing this somewhere....
Touche... I wrote the code in a rush from what I had in memory. It pretty much implements what we've spoken about.
I should assume I do not need to comment the enum or the struct as what they define should be evident.
#include <inttypes.h> //needed for uint8_t datatype
#include "WProgram.h" //needed for wiring extensions to C.
//some other include that aren't relevant to our issue.
// some interfacing code that has nothing to do with this: lcd_sendRaw()
uint8_t lcd_getRaw(LCD *l, uint8_t rs_mode){
digitalWrite(l->rs_pin, rs_mode); // registry select
digitalWrite(l->rw_pin, HIGH); //set read mode
uint8_t retVal = 0; // initializes return variable
for (int i = 0; i < l->bitmode; i++){ //if bitmode is 4, it will loop until i < 4, if bitmode is 8, it will loop until i<8
// set pin to input mode
pinMode(l->datapin[i], INPUT);
// reads pin, shift value to proper place and add it to retVal
retVal |= (digitalRead(l->datapin[i]) << i);
set pin to output mode
pinMode(l->datapin[i], OUTPUT);
}
if (l->bitmode == BIT_MODE_4){
// LCD is in 4 bit mode, only one nibble was obtained
// shift nibble to upper end of byte and loop to obtain low
// end of byte
retVal <<= 4; //obtained high nibble, must obtain low.
// trigger the strobe to signal for the next nibble
digitalWrite(l->enable_pin, HIGH);
digitalWrite(l->enable_pin, LOW);
// same loop as above, only this time we know the upper limit
for (int i = 0; i < 4; i++){
pinMode(l->datapin[i], INPUT);
retVal |= (digitalRead(l->datapin[i]) << i);
pinMode(l->datapin[i], OUTPUT);
}
}
// end of operation, trigger the strobe
digitalWrite(l->enable_pin, HIGH);
digitalWrite(l->enable_pin, LOW);
// return the complete value
return retVal;
}
Evaluating bitwise OR:
As per Boolean Algebra:
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1
C/C++ Operator for this operation is |
Bitshifts:
Bitshifting is an operation done to, of course, bits. As the name implies, all that is done is shift to the right or left. A left bitshift by n is equivalent to multiplying by 2^n. A right bitshift by n is equivalent to dividing by 2^n.
Examples:
(bitshift two one to the left) dec2 << dec1 = bin10 << dec1 = bin100 = 4
(bitshift two one to the right) dec2 >> dec1 = bin10 >> dec1 = bin1 = 1 (the zero gets dropped)
Algorithm to obtain raw data
We can store all data that is read from the LCD in one byte (8 bits). This will be stored in an 8 bit integer (same as a char type). For ease of access, we use an 8bit unsigned integer as defined in <inttypes.h>. Unsigned 8 bit integers range from dec0 to dec255, or b00000000 to b11111111.
We loop to get data out of the LCD. The first loop is generic and gets executed no matter whether the LCD is in 8 bit mode or 4 bit mode. The process is simple:
-
Initialize the return value to 0.
-
Read the first pin (i = 0), this is the least significant digit. In 4 bit mode, this would be data pin 4 on the LCD board, in 8 bit mode, this would be data pin 0. The output is either a HIGH (1) or LOW (0). Let the reading be the bit [D0]. It gets bitshifted by zero places to the left. The operation performed will be:
0 | [D0] = [D0]
which is stored back in the return value.
-
Read the second pin (i = 1). Let the output of this be the bit [D1]. It gets bitshifted one to the left and OR'ed to our return value:
[D1] << 1 = [D1]0
[D0] | [D1]0 = [D1][D0]
-
This process gets repeated until the upper limit is reached. If the display was operating on 8 bit mode, we end up with the full byte by the end of the loop, and it is returned. If the display is in 4 bit mode, we only have one nibble [D3][D2][D1][D0], the if clause executes.
In case of 4 bit mode
5) Bitshift retVal 4 places to the left. This puts the nibble as the upper end of the byte.
[D3][D2][D1][D0] << 4 = [D3][D2][D1][D0]0000
6) Trigger the strobe (This is what this entire argument has been about, and what I am not sure that should be the proper procedure).
7) Repeat process above to get the second nibble. By the end of the loop, the lower end of the byte will be completed and retVal can be returned.
Using returned data
The data returned will have the form [B7][B6][B5][B4][B3][B2][B1][B0]. What the data represents depends on value fed to register select (rs_pin). If rs_pin is given a LOW, then [B7] is the busy flag status and [B6]-[B0] will contain the Address Counter. If rs_pin is given a HIGH, then the return value will be data from DDRAM or CGRAM.
To filter out the busy flag, all that needs to be done is bitshift the return value 7 places to the right, which leaves [B7] by itself. To filter out the Address Counter a bitwise AND can be performed with 127dec (01111111), leaving [B6]-[B0].
Observations
This is obviously a backend to be used by other functions which will filter the data for the end user. At some point in time in the execution, the LCD's output gets corrupted, some things disappear.
A question if I may, and please take no offence on it, was my code that obfuscated that it needed documentation? It is not my intention to write unreadable code. I consider obfuscated code to be bad code.