4 bit comms with an Oled display

Steve2381

Senior Member
Hi all. Tired eyes and a brain that just can't get going... probably should abandon this project for tonight!

I have a Parallel Oled display, and interfacing with it will be a little more of a pain than usual, as I will have to try and use some odd spare pins on a 40x2. The board it is being retro-fitted to is a pre-etched PCB and I don't really want to have to alter it all.
Ideally, I would go 8 bit... but I don't have enough spare. Then to add to the mix, they are not sequential either (not all C.0-C.3 or similar).

DB4, DB5 and DB6 are pin 28 (C.3), pin 24 (C.4) and pin 23 (C.5) respectively. DB7 is pin 34 (B.1). 'RS' is pin 38 (B.5) and 'E' is on pin 40 (B.7). R/W is available on a pin if I need it (But I think that gets tied to Ov?)

My question is that of addressing those pins. Normally, I would set them using dirs %00001111 or similar.... but I cannot do that, as I believe I will affect the status of the other pins on that bank (all pins on the 40x2 are used for various inputs and outputs).
Any shortcuts I could use? Otherwise its going to be a whole load of high/low commands.

I have searched and yet to find an example of 4 bit comms to an oled display... as far as I understand, I basically send the commands each time in two batches on the DB4-DB7 pins (in accordance to the datasheet)

Any pointers to some base code I could adapt would be great. All I have found is 8 bit comms. I started writing some code, and between my stabbing in the dark, the odd pins and my general ignorance... it just isn't going to work.

Datasheet for the display:

http://www.mouser.com/ds/2/291/NHD-0420DZW-AB5-247046.pdf

I know the pin arrangement is far from ideal, but sometimes you just have to go with it! (unless there is actually an incompatibility issue here I am missing)

Failing this.... I suppose I could get an AXE132 serial converter from the store.

Thanks
 

eclectic

Moderator
Failing this.... I suppose I could get an AXE132 serial converter from the store.

Thanks
Just my personal opinion ........................

How much time and aggro are you prepared to spend?....

£5.99? Less than the minimum wage for one hour. ...............................

e
 

Steve2381

Senior Member
Yea... I know eclectic.... I just like the challenge (plus I have never sussed out 4 bit comms).

I go to the Picaxe store.... ooh, I may as well get a few extra chips while I am here, ooh... that looks shiney... ooh.

All of a sudden my £5.99 is £35
 

AllyCat

Senior Member
Hi,

One of the advantages of 4-bit mode is that all the data and control lines can fit on a single port, rather like the I2C backpacks sold with (or for) many Chinese LCDs. If splitting the data lines across two ports (with non-sequential pin mapping), then simple High / Low commands probably is best. The Enable and RS pins are likely to be driven by High / Low or Pulsout anyway.

It just might be worth trying to handle the 3 consecutive data bits as a group, starting with a shift command (to the Low or High nybble). Then, AFAIK you would need to mask the "inactive" bits (of the port) to zero and OR the value to the port, then mask the inactives to 1 and AND the value to the port. Or the less familiar AND NOT might save a line of code.

As for the 4-bit mode itself, it can be quite difficult to debug because even a minor error can give a display that doesn't do anything (i.e. no "clues" as to what is wrong). A particular (necessary) initialisation trick is to send the 8-bit mode command 3 times (to ensure that the controller really is in 8-bit mode) and then send the 4-bit command, which can be decoded even if the low 4 bits are undefined (not connected).

Personally, I'm getting quite close to emulating an AXE132 with an 08M2 driving one of the Chinese I2C backpacks (on a 20 x 4 backlit LCD). But it's an absolute "can of worms" and probably only worth attempting for "the challenge".

Cheers, Alan.
 

hippy

Technical Support
Staff member
If you use pinX.Y and dirX.Y variables you can control a single pin without affecting how the rest are set or used.
 

Steve2381

Senior Member
Hey thanks guys for all that info... I will have a look through. I have ordered an Axe132 ... just in case.
I will have a go tonight
 

AllyCat

Senior Member
Hi,

.... DB4, DB5 and DB6 are (C.3),(C.4) and (C.5) respectively. DB7 is (B.1). ....

... Normally, I would set them using dirs %00001111 or similar.... but I cannot do that, as I believe I will affect the status of the other pins on that bank (all pins on the 40x2 are used for various inputs and outputs).
Any shortcuts I could use? Otherwise its going to be a whole load of high/low commands.
I believe that one of the main OP issues is of handling not "don't care" pins on a port but "don't touch" pins. That could be the case if the pins are controlled by other parts of the program which the programmer doesn't want to change, for very good reasons, such that it's already fully debugged, or very complex, or perhaps not even understood.

However, that doesn't appear to be addressed in the AXE132 "reference code" or even IWP's excellent finished project (because the "extra" pins on the port appear to be only "don't care", i.e. under the control of the dedicated hardware functions - I2C, hserin, etc.).

A totally general method that the OP might have in mind is somethimng like:
Code:
symbol  bit3mask = 8
   testbyte = char AND bit3mask
   if testbyte = 0 then
       low portb.3
   else
       high portb.3
   endif
However, since this requires the use of an extra variable (testbyte), it makes more sense to make that a bit-addressable variable (such as b0), which avoids the "mask" so the test can be simply if bit 3 = 0 then ... .

But hippy has offered a better solution which I believe is, for example, pinb.3 = bit3 .

That's very probably the best solution for 3 bits because it avoids not only affecting the other pins but also any shifting or "unscrambling" of the mapping of the data value to the data lines.

But what it we want to use say 5, 6 or 7 data lines on a port? In Assembler, I would probably read the present state of the pins, compare (XOR) them with the required states, mask out (AND) the "don't touch" pins and then XOR the pins with the masked value. An advantage of this method is that all the pins are updated at the same time (i.e. 1s to 0s and 0s to 1s) and the others unchanged. However, I believe that reading the actual state of an output port/pins is rather more problematic with a PICaxe.

So, if one can easily create a variable to "map" onto say port.pins 1 - 6, but port.0 and port.7 are "don't touch" (inputs, outputs, or even both), then can any better be done than six "port.pin = ... " statements?

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Hmm, it's not too easy to offer an answer to that.

Do you have a/any 14+ pin PICaxe chip on a development or prototype board (that can run on 5 volts) to use for some initial code testing? Ideally, start with 8-bit bus code (unless you're really familiar with it already), then add the subroutines to work with 4 bits and ultimately modify for a "split" data bus. What test gear do you have, a scope or logic analyser? The most difficult part is likely to be getting the display driver chip initialised reliably in 4-bit bus mode.

Cheers, Alan.
 

westaust55

Moderator
DB4, DB5 and DB6 are pin 28 (C.3), pin 24 (C.4) and pin 23 (C.5) respectively. DB7 is pin 34 (B.1). 'RS' is pin 38 (B.5) and 'E' is on pin 40 (B.7). R/W is available on a pin if I need it (But I think that gets tied to Ov?)

My question is that of addressing those pins. Normally, I would set them using dirs %00001111 or similar.... but I cannot do that, as I believe I will affect the status of the other pins on that bank (all pins on the 40x2 are used for various inputs and outputs).
Why not?
Unless I am missing something, normally you will use the DIRS<x> command for each port once to set the direction of the pins.
Done at the start of the program should not disrupt other devices/signals

Then for each byte of command or data sent to the OLED display, use byte variable b0 as a transfer buffer.
In pseudo code:

b0 = data/16 ; the upper nybble of data to send
pinC.3 = bit 0
pinC.4 = bit 1
pinC.5 = bit2
pinB.1 = bit3

then pulse the "E" pin

next
b0 = data AND $F ; the lower nybble of data to send
and repeat the four bit to pin transfer lines
 

Steve2381

Senior Member
I can get 8 bit LCD control going ... no issues there.
I am sure I am mis-sunderstanding something somewhere then, as I have some Picaxe code here I found somewhere that uses the DIRS% command all over the place... not just at the beginning to set the pins (as I usually do).
Westaust55... I don't understand that code you have illustrated (sorry!) This is where my knowledge falls down.

I will do what I normally do... get some suggestions and sit for a few evenings playing around with it. I usually get there in the end

Oh... and no posh test gear, just my dev board.
 

hippy

Technical Support
Staff member
Here's some simple 4-bit driving code which works on the AXE133 for LCD and OLED which should be portable to any M2 or X2 PICAXE for any connection configuration.

Connections can be on any output pin, any port, and in any order, though it is advisable to avoid putting E on the Download Serial Out.

The 'bPtr' variable is only used as a temporary 'index' variable and is not used in any other clever or non-obvious way. The character or command byte to output is placed in 'b0' to allow the output bits to be more easily set. Timing shouldn't need adjusting for use on X2 at default 8MHz but it may need adjusting for M2 or X2 at higher speeds.

If the display isn't as expected immediately after a download, try turning the power off then back on. The program as is should display "Hello World!" using two lines.
 

Attachments

Last edited:

Steve2381

Senior Member
Thanks Hippy. Tried your code and I get random results each time... occasionally I see Hello World but certainly not where they should be.
I will have a play around
 

hippy

Technical Support
Staff member
That you sometimes see "Hello World!" is encouraging and probably means you are 75% there; it's wired correctly and is responding. If it's not a dodgy wiring issue it could potentially be timing.

Add "PAUSE 100" commands liberally throughout the code and see if that makes it work reliably if slowly, then take them out one by one and see which one breaks thing.
 

Steve2381

Senior Member
I Splattered pause commands all over the place... no luck yet. I sometimes get Hello World in various formats, or just 4 lines of garbage.
I will have another go now.

edit..

Mmm, odd! Turned it one from last night... perfect, Hello World on 2 lines. But that was it... never again.

Checked all connections and they seem fine. Get garbage every reboot, but occasionally part of the message at a random location. Sometimes just 'HE' or 'ELLO'
Pause statements seem to make it worse - you loose the words all together and just get a single letter randomly on the screen.

Ideas? Its a 4x20 display, so I think it has to be in 2 line mode. I will just have to tinker and see what I can find

Edit again..... PSU? Do Oled displays take a lot of juice? The 7805 on my AXE091 is pretty warm
 
Last edited:

Hemi345

Senior Member
One gotcha you need to be aware of is when debugging a program that drives a display, you may need cycle the power to the display after you program it. If program isn't quite right, the display might get into an unknown state and on subsequent downloads and program restarts, it'll appear not to work at all. So cycle the power every time you download a new program.
 

Steve2381

Senior Member
PSU is fine... just checked. And I do cycle the supply... I learnt that a while back!

What MPU are we using here? There are soldered jumpers on the rear of the display for 6800 MPU or 8080 MPU. Would that make a difference?

Edit... Cracked it, loose connection on the jumper on the PCB. Working fine now.
Thanks all!
 
Top