OLED module (v0.05; 2017/02/04) Licence ======= The OLED module is Copyright © 2014-2017 Richard Murray. It is released under the EUPL v1.1 (only). Text plotting ============= The display module "text area" is 16x8. That is, 16 characters across the display, and 8 rows down it, which is 128 characters in total. The home position (1,1) is the upper left. Text is plotted in the RISC OS system VDU font, obeying roughly the same rules as the standard VDU system (see VDU codes, below, for more details). Scrolling is automatic. Paged mode is not available. To change how characters appear, change the system VDU font. *FX 25,0 will restore normality afterwards. Graphics plotting ================= The display module offers 128 pixels horizontally and 64 pixels vertically. The home position (0,0) [note, not 1,1] is the BOTTOM left. Commands are provided to draw lines, (filled) rectangles, and (filled) circles. If this is insufficient, you can create your own custom sprites and have these copied to the display. Plot refresh scheduling ======================= Text or graphics plotting will schedule a callback for 5cs from the first plot command, so a display can be built up using multiple calls without incurring flashing or other such effects on the OLED. Once this delay has expired and the display refreshed, subsequent plotting will schedule another callback, and so on. Advanced direct plotting ======================== Two SWIs are provided (DumpSprite and DumpRaw) which bypass many of the driver's drawing functions and output directly to the display. The first - DumpSprite - will take a monochrome sprite and convert it to data to send to the display. The second - DumpRaw - accepts converted data and sends it directly to the display's GDRAM. Note that in both cases, output is immediate (a refresh callback is not scheduled) and the screen buffer maintained by the driver is NOT updated. Colours ======= Colour 0 is black (pixel off). Colour 1 is 'white' (pixel on). VDU codes ========= In the text plotting, most control codes are suppressed, with the exception of: 0 - data terminator 8 - backspace (moves cursor back a character, does not delete) 9 - forwardspace (moves cursor forward a character, does not erase) 10 - linefeed (moves cursor down a line) 11 - reverse linefeed (moves cursor up a line) 12 - clears the display (similar to OLED_CLS) 13 - carriage return (moves cursor to leftmost position on the line) 19 - set inverse text colour (black on white) 20 - restore normal text colour (white on black) 30 - home cursor (to 1,1 upper left) 31 - position text cursor, followed by two bytes giving X,Y position 127 - delete (moves cursor back a character, deletes) This is fairly similar to standard VDU operation, though note the following specific differences to the VDU behaviour: a. the home position is 1,1 (not 0,0 as in RISC OS), thus character positions are 1-16 across and 1-8 down; oversize values are clipped b. control codes 19 and 20 are slightly different c. other control codes are suppressed, so VDU 23,... won't work Note that the inverse/normal text colours are relative to normal. If you set inverted colours using OLED_CLS, then 'normal' will still produce white on black. Note that OLED_CLS has an option to set the text/background 'colour' while sending <12> just clears the display. TaskWindow ========== Because VDU redirection is used, it is not advised to call OLED SWIs when you are in a TaskWindow.The results are...undefined. Configuration ============= There are two things that may be configured by the use of system variables. The first is the display orientation. I run my display UPSIDE DOWN as this makes for a tidier mounting on a Pi case. As such, the module default is to set an upside-down orientation (ribbon at the bottom of the display). You can choose to specify a right-way-up orientation (ribbon at the top) instead if your mounting method is different. Please refer to: http://www.heyrick.co.uk/blog/index.php?diary=20140421 NOTE: ANY CONFIGURED ORIENTATION WILL OVERRIDE THAT PASSED IN THE OLED_Initialise SWI. To specify the default upside-down orientation: *Set OLED$Orientation 1 To specify the right-way-up orientation: *Set OLED$Orientation 2 To default to upside down but allow it to be changed by the user, don't specify anything... If the value is neither 1 nor 2, the option will be ignored. The second thing that may be specified is the default "contrast" (which really means brightness). The default, and recommended, is &7F which is nominally half brightness (but there's not so much between that and full). Specify: *Set OLED$Contrast &7F The configuration is read at initialisation time - when the module starts and also when you call OLED_Initialise. SWIs ==== OLED_Initialise [&59540] Entry: R0 = 0 to use previous setting (or default otherwise) 1 for default 2 to flip horizontally R1 = 0 to use previous setting (or default otherwise) 1 for default 2 to flip vertically Exit: R0 = Non-zero if OLED module is NOT connected R1 = Corrupted R2 = Orientation (1 = upside down default; 2 = right way up) This should be called once prior to using the display. "Normal" mode is with the ribbon connector at the bottom of the display. If your display is mounted the other way up, specify R0=R1=2 to flip it around. The correct right-way-up display is R0=R1=2. The module default is to select an upside-down display because this is how it mounts nicely on a Pi case. It is strongly recommended that your initialisation, if used in any RELEASE software, uses R0=R1=0 to initialise the module using the current settings. Note that , if defined, will OVERRIDE anything that may be specified here and FORCE a specific orientation. You can check R2 to see what orientation was set. OLED_Print [&59541] Entry: R0 = Pointer to null terminated text string to print. NOTE: The string is read byte by byte, and as such, there is no specific length limitation of the string that is provided. This will print a text string at the current cursor position. Refer to the "VDU codes" section for specifics of additional codes that can be inserted into the text string. Bad control codes are silently discarded. OLED_CLS [&59542] Entry: R0 = 0 (white text on black) or 1 (black text on white) This clears the screen and, optionally, sets the foreground/background to be inverted. OLED_Op [&59543] Entry: R0 = Operation code R1 = Option value (if R0 = 4,5) Perform various miscellaneous operations, which take place IMMEDIATELY: 0 - Set 'normal' display 1 - Set 'inverse' display (white is black, black is white) You should set 'normal' to restore. You can use these two to 'flash' the contents of a STATIC display without requiring a refresh; or in combination with a refreshed display to draw attention to something. 2 - Enable display (from sleep mode) 3 - Disable display (switch to sleep mode) 4 - Set "Contrast" (brightness): Contrast is in R1, which ranges from 0 (dimmest) to 255 (brightest). Some Contrast levels: &00 13.7mA The dimmest setting. &3F 29.0mA A not-so-bright setting that might be adequate for a room with a fairly low light level (such as a desk lamp or the like). &7F 33.3mA The default mid-way contrast. This is good. &BF 35.2mA Honestly, toggling between this and &7F, I couldn't tell any difference. &FF 36.2mA Maximum contrast; however because of the potential lifespan issues of OLED technology, it might be better to not drive it harder than it needs to be (oh, and don't place it in direct sunlight - UV absorbtion is bad). Current readings performed with the OLED hooked to a Pi providing 3.28V (a little low but not crashy-crashy; it's running from a USB port on my netbook) with ALL pixels on. The configuration sets the default contrast level when the module starts, and when OLED_Initialise is called. Unlike the orientation setting, the contrast may then be freely set with this call. 5 - Set top line Line number is in R1. Normally, the top line is 0. You can 'roll' the display by stepping through the lines (0-63) without the need to calculate and send new bitmaps for each step. FOR l% = 0 TO 64 SYS "OLED_Op", 5, (l% AND 63) WAIT NEXT 6 - Flip on vertical axis R1 = 0 to flip, non-zero to unflip. This will flip the display on its vertical axis, swapping left and right. Because of how the display implements this, it is necessary to resent the display bitmap. The module does this automatically. 7 - Flip on horizontal axis R1 = 0 to flip, non-zero to unflip. This will flip the display on its horizontal axis, swapping top and bottom. It takes effect immediately. Note: Vertical/Horizontal flip can be performed even if the display orientation is fixed. This is because it is intended to aid in special effects, not to replace the features of OLED_Initialise that are inhibited if an orientation is specified... OLED_SetColours [&59544] Entry: R0 = 0 ("white on black" (normal)) or 1 ("black on white" (inverted)) This sets both the text and the graphics colours. OLED_DrawLine [&59545] Entry: R0 = Start X R1 = Start Y R2 = End X R3 = End Y R4 = 0 (solid line) or 1 (dotted line) Draws a (dotted) line from Start X,Y to End X,Y. OLED_DrawBox [&59546] Entry: R0 = Lower left X R1 = Lower left Y R2 = Upper right X R3 = Upper right Y R4 = 0 (rectangle) or 1 (filled rectangle) Draws a (filled) rectangle from Lower left X,Y to Upper right X,Y. OLED_DrawCircle [&59547] Entry: R0 = Centre X R1 = Centre Y R2 = Radius R3 = 0 (circle) or 1 (filled circle) Draws a (filled) circle at X,Y with given radius. OLED_DrawTriangle [&59548] Entry: R0 = First vertex X R1 = First vertex Y R2 = Second vertex X R3 = Second vertex Y R4 = Third vertex X R5 = Third vertex Y This draws a FILLED triangle from 1st X,Y and 2nd X,Y to 3rd X,Y. There is no option to draw a triangle outline, as that is easily performed by three line draws. OLED_DrawFont [&59549] - not currently implemented - OLED_DrawSprite [&5954A] Entry: R0 = Pointer to sprite area containing a suitable sprite. R1 = Pointer to sprite (address, not sprite name). R2 = Reserved, set to 0. R3 = Reserved, set to 0. Given a suitable sprite (128x64, MODE 25), the sprite will be plotted into the driver's image buffer and that will be sent to the display. At the same time, the text cursor will be homed to position 1,1. OLED_ForceRefresh [&5954B] Entry: - This will cancel any pending refresh and instead refresh the display immediately. This may be useful for obtaining the quickest redraw time. OLED_DumpSprite [&5954C] Entry: R0 = Pointer to sprite area containing a suitable sprite. R1 = Pointer to sprite (address, not sprite name). Given a suitable sprite (128x64, MODE 25), the contents will be written directly to the display. Note - this does NOT update the driver's image buffer. If you want a quick sequence that does update the driver's image buffer, call DumpSprite as many times as necessary, and make the final call of the set be to DrawSprite. Note - results will not be what you expect if you call OLED_DumpSprite while a refresh is pending. If this is likely to be the case, call OLED_ForceRefresh first. Note - as the sprite dumped will overwrite everything on the display, you do not need to CLS it first (which will set a pending refresh). Just send the sprite... OLED_DumpRaw [&5954D] Entry: R0 = Pointer to 1024 bytes of data to be written to the display. Takes pixel data and writes it DIRECTLY to the display, with minimal driver intervention. The data will be broken into 128 byte chunks, with the first being sent to page 0 (top rows) and the last being sent to page 7 (bottom). Each byte represents eight pixels DOWN (from the top of the specified page) and the 128 represent one per column across the display. [ Hacker playtime: Try R0 = &8000 ;-) ] OLED_CanPrint [&5954D] Entry: - Exit: R0 = Zero if it is currently safe to output text via OLED_Print; else non-zero. This checks if it is 'safe' to print. We must: * Not be running in a TaskWindow (R0 = 1) * Not be in the Desktop with a task handle of zero (R0 = 2) * Not be printing anything (R0 = 3) Speeding up your IIC ==================== Sending data to the display, about 1100 bytes per screen, is rather slow. The default option in RISC OS is to set the IIC bus to work at 100kHz. This runs at approximately 12.5K/sec, which means it will take a little under a tenth of a second to send one frame. Not only is this likely to be noticed by the user, it is also slower than the display's refresh rate. It is possible to tweak the RISC OS ROM image to kick the IIC to work in "Fast" mode, which is 400kHz. Here, the data rate is about 50K/sec (which means a full frame ought to go out in under 1/25th second). Much better. Using Fast mode does introduce some potential compatibility problems; however I have been using it fine with a Pi and CJE's RTC/temp/powercontrol widget. Make a copy of your current RISC OS image file. Now load it into Zap and switch to Code mode [Sh-Ctrl-F5]. Go to address [F5] &3688. The code should look like this: LDR R0,[R3,#0] ORR R0,R0,#&8000 STR R0,[R3,#0] MOV R0,#&09C0 <-- this is what we want STR R0,[R3,#20] MOV R0,#0 MCR CP15,0,R0,C7,C10,5 I have given the other lines in case the address &3688 is not correct in your build, so you can look nearby for the right piece of code. Between July 2013 and January 2014, it moved two instructions (was at &3680). So it'll be close. Highlight the "MOV R0,#&09C0" line and press Enter. You'll see a mini editor appear at the bottom of the window where the bottom scroll bar should be. Delete the "9C0" and replace it with "270", then press Enter. Your code should now look like this: LDR R0,[R3,#0] ORR R0,R0,#&8000 STR R0,[R3,#0] MOV R0,#&0270 <-- now says #&0270 STR R0,[R3,#20] MOV R0,#0 MCR CP15,0,R0,C7,C10,5 Save this modified ROM image, then boot it. Side effects? If it is 'too fast', various IIC devices will stop working. If you have a CJE RTC, these appear to work just fine. Other things? Let me know. For what it is worth, Fast Mode was introduced in 1992, many modern devices ought to support it. The problem case, on the Pi, is a device performing clock stretching before the ACK bit (hardware bug). [see https://dl.dropboxusercontent.com/u/3669512/2835_I2C%20interface.pdf] If IIC devices fail at the faster speed, just revert back to your backed up ROM image (or change the 270 back to 9C0). If it doesn't fail - then you'll be able to write to the OLED much more quickly. The videos on my website are done using a Fast bus on a standard issue 2, 256MB Raspberry Pi. Here's a video of it in action: http://www.youtube.com/embed/1pWXNa8mdiw ===================== End of documentation.