Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 22:54 28 Mar 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM2, MM+: SSD1306 OLED loadable drivers updated

     Page 1 of 2    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 07:06pm 20 Aug 2019
Copy link to clipboard 
Print this post

Prompted by an question on an old thread I've updated the ssd1306 OLED loadable driver.
The driver supports 0.96" 128x64 and 128x32 displays - not the 1.3" I2C versions which simply don't seem to work.

To use the driver load the attached code into the Micromite. Edit the code to reflect your usage if required (I2C-address, SCK-pin, SDA-pin, Vertical size (64 or 32), orientation (1 to 4)). Connect the display using the SCK and SDA pins specified in the SSD1306 subroutine call - these can be freely chosen as the I2C bus is bit-banged. Then type "LIBRARY SAVE". Reset the Micromite and you should see the banner
"SSD1306 I2C driver loaded". If this isn't pretty much instantaneous your wiring is incorrect and the I2C bus has timed out.

You can now use all the graphics commands specified in the Micromite manual. Note that any non-zero colour will be white and zero will be black (unlit)





sub mm.startup
 SSD1306(&H3C,2,15,64,1) 'I2C-address, SCK-pin, SDA-pin, Vertical size (64 or 32), orientation (1 to 4)
End Sub
CSUB SSD1306
   00000395
   'Delay
   40024800 00442021 40024800 0044102B 1440FFFD 00000000 03E00008 00000000
   'BBStart
   27BDFFE0 AFBF001C AFB10018 AFB00014 00808821 3C109D00 8E030090 8E02001C
   8064002E 0040F809 2405FFFE 8E030090 8E02001C 8064002C 0040F809 2405FFFE
   40034800 00711821 40024800 0043102B 1440FFFD 3C029D00 8C430090 8C42001C
   8064002E 0040F809 2405FFFD 40034800 00711821 40024800 0043102B 1440FFFD
   3C029D00 8C430090 8C42001C 8064002C 0040F809 2405FFFD 40024800 00518821
   40024800 0051102B 1440FFFD 8FBF001C 8FB10018 8FB00014 03E00008 27BD0020
   'BBStop
   27BDFFE0 AFBF001C AFB10018 AFB00014 00808821 3C109D00 8E030090 8E02001C
   8064002C 0040F809 2405FFFD 8E030090 8E02001C 8064002E 0040F809 2405FFFD
   40034800 00711821 40024800 0043102B 1440FFFD 3C029D00 8C430090 8C42001C
   8064002C 0040F809 2405FFFE 40034800 00711821 40024800 0043102B 1440FFFD
   3C029D00 8C430090 8C42001C 8064002E 0040F809 2405FFFE 40024800 00518821
   40024800 0051102B 1440FFFD 8FBF001C 8FB10018 8FB00014 03E00008 27BD0020
   'BBWriteBit
   27BDFFE0 AFBF001C AFB20018 AFB10014 AFB00010 00809021 10C00009 00A08821
   3C029D00 8C430090 8C42001C 8064002E 0040F809 2405FFFE 10000008 3C029D00
   3C029D00 8C430090 8C42001C 8064002E 0040F809 2405FFFD 3C029D00 8C430090
   8C42001C 8064002C 0040F809 2405FFFE 00001021 40824800 10000005 3C109D00
   40024800 0051102A 10400013 8FBF001C 8E030090 8E020020 0040F809 8064002C
   1040FFF7 00000000 40024800 00529021 40024800 0052102B 1440FFFD 3C029D00
   8C430090 8C42001C 8064002C 0040F809 2405FFFD 8FBF001C 8FB20018 8FB10014
   8FB00010 03E00008 27BD0020
   'BBReadBit
   27BDFFE0 AFBF001C AFB10018 AFB00014 00808021 00A08821 3C029D00 8C430090
   8C42001C 8064002E 0040F809 2405FFFE 40034800 00701821 40024800 0043102B
   1440FFFD 3C029D00 8C430090 8C42001C 8064002C 0040F809 2405FFFE 40024800
   00508021 40024800 0050102B 1440FFFD 00000000 40824800 10000005 3C109D00
   40024800 0051102A 50400014 00008021 8E030090 8E020020 0040F809 8064002C
   1040FFF7 00000000 3C119D00 8E230090 8E220020 0040F809 8064002E 00408021
   8E230090 8E22001C 8064002C 0040F809 2405FFFD 10000002 02001021 02001021
   8FBF001C 8FB10018 8FB00014 03E00008 27BD0020
   'BBWriteByte
   27BDFFD0 AFBF002C AFB60028 AFB50024 AFB40020 AFB3001C AFB20018 AFB10014
   AFB00010 0080B021 00A08821 00C09821 00009021 3C109D00 0000A021 24150008
   32620080 10400007 8E030090 8E02001C 8064002E 0040F809 2405FFFE 10000006
   8E030090 8E02001C 8064002E 0040F809 2405FFFD 8E030090 8E02001C 8064002C
   0040F809 2405FFFE 02801021 40824800 10000006 8E030090 40024800 0051102A
   50400013 26520001 8E030090 8E020020 0040F809 8064002C 1040FFF7 00000000
   40034800 00761821 40024800 0043102B 1440FFFD 00000000 8E030090 8E02001C
   8064002C 0040F809 2405FFFD 26520001 1655FFD3 00139840 3C029D00 8C430090
   8C42001C 8064002E 0040F809 2405FFFE 40034800 00761821 40024800 0043102B
   1440FFFD 3C029D00 8C430090 8C42001C 8064002C 0040F809 2405FFFE 40024800
   0056B021 40024800 0056102B 1440FFFD 00000000 40824800 10000005 3C109D00
   40024800 0051102A 50400014 00008021 8E030090 8E020020 0040F809 8064002C
   1040FFF7 00000000 3C119D00 8E230090 8E220020 0040F809 8064002E 00408021
   8E230090 8E22001C 8064002C 0040F809 2405FFFD 10000002 2E020001 2E020001
   8FBF002C 8FB60028 8FB50024 8FB40020 8FB3001C 8FB20018 8FB10014 8FB00010
   03E00008 27BD0030
   'writei2c
   27BDFFD0 AFBF002C AFB60028 AFB50024 AFB40020 AFB3001C AFB20018 AFB10014
   AFB00010 0080B021 00A0A821 00C08821 3C029D00 8C420000 8C500000 3C140018
   26946A00 0214001B 028001F4 0000A012 00009812 00002012 0411FE97 00000000
   240207D0 0202001B 004001F4 00008012 00101080 001029C0 00A22823 00B08021
   00102880 02058021 001028C0 00A09021 02802021 00153040 0411FF5F 00000000
   10400013 00001821 02C08021 10000007 2415FFFF 02402821 92260000 0411FF56
   00000000 10400009 26310001 2610FFFF 1615FFF8 02602021 02802021 0411FEA6
   00000000 10000002 24030001 00001821 00601021 8FBF002C 8FB60028 8FB50024
   8FB40020 8FB3001C 8FB20018 8FB10014 8FB00010 03E00008 27BD0030
   'oled_write_command
   27BDFFE0 AFBF001C A3A00010 A3A40011 3C029D00 8C420090 24040002 8045003D
   27A60010 0411FFAF 00000000 8FBF001C 03E00008 27BD0020
   'OLED_setxy
   27BDFFE8 AFBF0014 AFB00010 00808021 24A4FFB0 308400FF 0411FFEB 00000000
   7E041900 34840010 0411FFE7 00000000 3204000F 0411FFE4 00000000 8FBF0014
   8FB00010 03E00008 27BD0018
   'updatedisplay
   27BDFFD8 AFBF0024 AFB40020 AFB3001C AFB20018 AFB10014 AFB00010 3C029D00
   8C43008C 8C700000 8C420090 8042003C 000211C0 24430007 28440000 0064100B
   000210C3 24420001 02021021 80430000 10600022 8FBF0024 A0400000 3C029D00
   8C420090 8042003C 28420008 1440001A 00008821 24140040 3C129D00 00002021
   02202821 0411FFCB 00000000 82130000 A2140000 8E420090 24040081 8045003D
   02003021 0411FF6E 00000000 A2130000 26310001 8E420090 8042003C 24430007
   28440000 0064100B 000210C3 0222102A 1440FFEA 26100080 8FBF0024 8FB40020
   8FB3001C 8FB20018 8FB10014 8FB00010 03E00008 27BD0028
   'DrawRectangleMEM
   27BDFFD0 AFBF002C AFB50028 AFB40024 AFB30020 AFB2001C AFB10018 AFB00014
   00808821 00A09821 00C09021 00E0A021 3C029D00 8C42008C 8C420000 90440000
   240300F5 10830010 8FB00040 3C159D00 8EA20090 8042003C 000211C0 24430007
   28440000 0064100B 000220C3 8EA2003C 0040F809 24840400 8EA3008C AC620000
   2403FFF5 A0430000 3C039D00 8C630090 80640015 24050002 14850009 24050003
   2404007F 00942823 00932023 0220A021 02409821 00809021 10000015 00A08821
   14850009 24050004 2404007F 00918823 00929023 8064003C 2484FFFF 00939823
   1000000B 0094A023 1485000A 0232202A 8064003C 2484FFFF 00912823 00922023
   02809021 0080A021 02608821 00A09821 0232202A 14800005 0274202A 02202021
   02408821 00809021 0274202A 14800005 2A240000 02602021 02809821 0080A021
   2A240000 0004880B 2404007F 2A250080 0085880A 2A450000 0005900B 2A450080
   0085900A 2A640000 0004980B 8063003C 0263282A 2464FFFF 0085980A 2A840000
   0004A00B 0283202A 2463FFFF 0064A00A 0251182A 10600025 0293482A 10000029
   3C039D00 24640007 28650000 0065200A 000428C3 000529C0 00E52821 000327C3
   00042742 00643021 30C60007 00C42023 00882004 12000006 308400FF 00452821
   90A60000 00862025 10000006 A0A40000 00452821 00042027 90A60000 00C42024
   A0A40000 24630001 0283202A 1080FFE6 24640007 26310001 0251182A 50600005
   02601821 10000007 3C039D00 24080001 02601821 1120FFDB 26270001 1000FFF6
   26310001 8C630090 8063003C 000319C0 24640007 28650000 0085180B 000318C3
   00431021 24030001 A0430001 8FBF002C 8FB50028 8FB40024 8FB30020 8FB2001C
   8FB10018 8FB00014 03E00008 27BD0030
   'DrawBitmapMEM
   27BDFFB0 AFBF004C AFBE0048 AFB70044 AFB60040 AFB5003C AFB40038 AFB30034
   AFB20030 AFB1002C AFB00028 AFA40050 00A0A821 00C09021 AFA7005C 8FB00060
   8FB10068 3C029D00 8C42008C 8C420000 90440000 240300F5 10830010 8FB3006C
   3C149D00 8E820090 8042003C 000211C0 24430007 28440000 0064100B 000220C3
   8E82003C 0040F809 24840400 8E83008C AC620000 2403FFF5 A0430000 8FA3005C
   18600096 0200F021 AFB5001C 00122023 AFA40020 70721802 2463FFFF AFA30014
   AFB20024 0000B821 AFA00018 24140001 3C099D00 240A0002 240C0003 10000083
   240E0004 8D280090 81050015 14AA0007 00602021 8D240098 8C840000 2484FFFF
   00603821 10000013 008D2023 14AC000A 00000000 8D240094 8C840000 2484FFFF
   00832023 8D250098 8CA70000 24E7FFFF 10000008 00ED3823 14AE0006 01603821
   8D250094 8CA70000 24E7FFFF 00E33823 01602021 2C850080 50A00033 24C60001
   04E20031 24C60001 8105003C 00E5282A 50A0002D 24C60001 24840001 24E50007
   28E80000 00E8280A 000528C3 000529C0 00852021 000747C3 00084742 00E83821
   30E70007 00E82823 00B42804 30A500FF 00054027 92C70000 00F53824 10E0000C
   310800FF 8FA70064 10E00005 00442021 90870000 00A72825 10000012 A0850000
   90850000 01054024 1000000E A0880000 1A200006 00000000 00442021 90870000
   00A72825 10000007 A0850000 56200006 24C60001 00442021 90850000 01052824
   A0850000 24C60001 14D0FFAE 24630001 25EF0001 2718FFFF 11F20010 033EC821
   01F71821 24640007 28760000 0096180B 0003B0C3 0276B021 00181FC3 00031F42
   0303A821 32B50007 02A3A823 02B4A804 03201821 1000FF9B 00003021 8FA30010
   24630001 AFA30010 14700004 25AD0001 10000008 8FA40018 AFA00010 1A40FFF7
   01A05821 8FB90050 8FB80014 1000FFE4 00007821 24840001 AFA40018 8FA7001C
   00FE3821 AFA7001C 8FA30014 8FA40020 00641821 AFA30014 8FA70024 8FA30018
   8FA4005C 10640005 02E7B821 1E00FFEA 8FAD001C 1000FFEF 8FA40018 3C039D00
   8C630090 8063003C 000319C0 24640007 28650000 0085180B 000318C3 00431021
   24030001 A0430001 8FBF004C 8FBE0048 8FB70044 8FB60040 8FB5003C 8FB40038
   8FB30034 8FB20030 8FB1002C 8FB00028 03E00008 27BD0050
   'getFPC
   27BDFFF8 AFBF0004 00852023 03E42021 ACC40000 8FBF0004 03E00008 27BD0008
   'pstring
   27BDFFE0 AFBF001C AFB00018 00808021 00002021 3C059D00 24A50E30 27A60010
   0411FFEF 00000000 8FA40010 3C029D00 8C42002C 0040F809 02042021 8FBF001C
   8FB00018 03E00008 27BD0020
   'main
   27BDFFC8 AFBF0034 AFB40030 AFB3002C AFB20028 AFB10024 AFB00020 0080A021
   00A09821 00C09021 00E08821 00002021 3C059D00 24A50E98 27A60018 0411FFD5
   00000000 3C109D00 8E020090 8E230000 A043003C 8E020090 8051003C 8E430000
   A043002E 8E020090 8E630000 A043002C 8E020090 24030014 A0430014 8E020090
   8E830000 A043003D 8E020090 8FA30048 8C630000 A0430015 8E020090 8042003C
   000211C0 24430007 28440000 0064100B 000220C3 8E02003C 0040F809 24840400
   8E03008C AC620000 2403FFF5 A0430000 8E030090 8E02001C 8064002E 0040F809
   24050005 8E030090 8E020010 8064002E 24050008 0040F809 00003021 8E030090
   8E020010 8064002E 24050065 0040F809 00003021 8E030090 8E02001C 8064002C
   0040F809 24050005 8E030090 8E020010 8064002C 24050008 0040F809 00003021
   8E030090 8E020010 8064002C 24050065 0040F809 00003021 240400AE 0411FDB4
   00000000 240400D5 0411FDB1 00000000 24040080 0411FDAE 00000000 240400A8
   0411FDAB 00000000 8E020090 8043003C 24020040 54620006 2404001F 2404003F
   0411FDA3 00000000 10000004 240400D3 0411FD9F 00000000 240400D3 0411FD9C
   00000000 00002021 0411FD99 00000000 24040040 0411FD96 00000000 2404008D
   0411FD93 00000000 24040014 0411FD90 00000000 24040020 0411FD8D 00000000
   00002021 0411FD8A 00000000 240400A1 0411FD87 00000000 240400C8 0411FD84
   00000000 240400DA 0411FD81 00000000 3C029D00 8C420090 8043003C 24020040
   54620006 24040002 24040012 0411FD78 00000000 10000004 24040081 0411FD74
   00000000 24040081 0411FD71 00000000 240400CF 0411FD6E 00000000 240400D9
   0411FD6B 00000000 240400F1 0411FD68 00000000 240400DB 0411FD65 00000000
   24040040 0411FD62 00000000 240400A4 0411FD5F 00000000 240400A6 0411FD5C
   00000000 240400AF 0411FD59 00000000 3C029D00 8C420090 90420015 30420001
   10400007 3C029D00 8C430094 24040080 AC640000 8C420098 10000006 AC510000
   8C430098 24040080 AC640000 8C420094 AC510000 8FA50018 3C029D00 8C430048
   3C049D00 24840800 00852021 AC640000 8FA50018 8C43004C 3C049D00 24840A90
   00852021 AC640000 8FA50018 8C4300A4 3C049D00 24840708 00852021 AC640000
   8C430048 8C440094 8C860000 8C420098 8C470000 AFA00010 8C620000 00002021
   00002821 24C6FFFF 0040F809 24E7FFFF 3C049D00 24841214 0411FF06 00000000
   8FBF0034 8FB40030 8FB3002C 8FB20028 8FB10024 8FB00020 03E00008 27BD0038
   '.rodata
   'startup
   31445353 20363033 20433249 76697264 6C207265 6564616F 000A0D64
End CSub
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 09:09pm 21 Aug 2019
Copy link to clipboard 
Print this post

Many thanks! So, after a reset, if I see the message "SSD1306 I2C driver loaded", it means the display is connected in the right way and it already replied to your initialization sequence?
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 09:49pm 21 Aug 2019
Copy link to clipboard 
Print this post

  Quote  So, after a reset, if I see the message "SSD1306 I2C driver loaded", it means the display is connected in the right way and it already replied to your initialization sequence?

yes as long as you see it immediately
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 07:17am 22 Aug 2019
Copy link to clipboard 
Print this post

In my case, the message is immediate but then the display remains dark, no matter if I type some command like:

text 10,10,"hello"
line 0,0,100,30

nothing on the screen, shoud I type before some specific command to enable the display?
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 08:47am 22 Aug 2019
Copy link to clipboard 
Print this post

  Quote  nothing on the screen, shoud I type before some specific command to enable the display?


No, should just work. I tested on 128x64 and 128x32 as pictured using a 28 pin MM2. Note 1.3" I2C versions are wired incorrectly and don't work. I'm not aware of any faulty 128x32 displays.
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 04:28pm 22 Aug 2019
Copy link to clipboard 
Print this post

Ok, all working now!    The problem was the back of the display: there is a configuration resistor soldered on 0x78 and the alternative is 0x7A. So I configured your listing for &h78... but it was misleading because everithing started to work when I had the idea to simply dont touch your default setting (so the the real adress is &h3C ?) . I dont know why they wrote such numbers, if is not true...

 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 07:01pm 22 Aug 2019
Copy link to clipboard 
Print this post

  Quote  I dont know why they wrote such numbers, if is not true...


I2C devices have a 7-bit address and the 8th bit defines read or write. There are two conventions, one treats the addresses as 0-254 in steps of 2 and the other 0-127 in steps of one. MMBasic uses the second, your display is using the first.

hex 78 / 2 = hex 3C
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 11:12am 23 Aug 2019
Copy link to clipboard 
Print this post

Ok, it's clear now. Thank you.
There is a way to reduce the light by software in this display?


  Quote   1.3" I2C versions are wired incorrectly and don't work.

What do you mean? As I know the 1.3 version has a different controller with the need to adjust a little the graphic map.
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 07:51am 26 Aug 2019
Copy link to clipboard 
Print this post

Another question, Peter: I noticed the diplays are working even without the pull up resistors. May be you have configured the bit-banged ports with an internal pull-up?
(by the way, if you disconnect the entire display stuff, your library immediately pass the start-up test, so I wont state it as a sign of "hardware is ok")
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 10:32am 26 Aug 2019
Copy link to clipboard 
Print this post

  Quote  Another question, Peter: I noticed the diplays are working even without the pull up resistors. May be you have configured the bit-banged ports with an internal pull-up?


Yes, but may not always be adequate

  Quote  There is a way to reduce the light by software in this display?


not AFAIK

  Quote  What do you mean? As I know the 1.3 version has a different controller with the need to adjust a little the graphic map.


1.3" displays need 2-pixel offset on X. This works fine on SPI versions but I have never got one of the 1.3" I2C only displays to work - not something I'm going to spend any more time on.
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 04:36pm 26 Aug 2019
Copy link to clipboard 
Print this post

  Quote  I have never got one of the 1.3" I2C only displays to work

Arggh!! I just ordered one yesterday!
In the product page there is a statement:

  Quote  About control chip SSH1106:
SSG1106 compatible with SSD1306 basic, difference is that SSH1106 control chip RAM space is 132*64, while SSD1306 space is 128*64.
The 1.3-inch OLED 128*64 dot matrix, so in the middle of the screen production took 128 row. When using SSD1306 program point SSH1106 screen, only need to change address to 0x02 row to start.


Does this add some new information about the problem?


  Quote  There is a way to reduce the light by software in this display?
not AFAIK


I explain better: I mean if is possible to adjust globally the luminosity of the display, for example to fade-in a graphic image.
In the topic "Display drivers in Basic" (here the Link ) I seen the command:
OLED.SCmd(&H81)'SETCONTRAST
OLED.SCmd(&HCF)


so I was hoping a global luminosity was possible. Or can be decided only once at the startup sequence?
 
ceptimus
Senior Member

Joined: 05/07/2019
Location: United Kingdom
Posts: 130
Posted: 05:43pm 26 Aug 2019
Copy link to clipboard 
Print this post

I've got some Arduino (C++) code I wrote to drive I2C displays that initializes either the SSH1106 or the SSD1306 interface depending on a #define.  You have to send a slightly different bunch of initialization commands, and thereafter, as you say, there is a 2-pixel X offset, and also a slightly different set-up routine before sending the actual pixel bytes.  The 1106 is actually more sensible (apart from the 2-pixel offset) in that you only need to send 3 bytes of 'position' information rather than the 6 bytes to send the same information to the 1306.

There might be some #defines here that don't apply to either the 1106 or 1306 as this display driver could also handle two other types of display - but I've tried to edit out the unnecessary parts.


#define SH1106_ADDR 0x3C
#define SSD1306_ADDR 0x3C

#define DISPLAY_LCDWIDTH  128
#define DISPLAY_LCDHEIGHT  64

// display chars assuming 6x8 font
#define DISPLAY_CHARWIDTH (DISPLAY_LCDWIDTH / 6)
#define DISPLAY_CHARHEIGHT (DISPLAY_LCDHEIGHT / 8)
#define DISPLAY_NUMCHARS (DISPLAY_CHARWIDTH * DISPLAY_CHARHEIGHT)

// there may be unused pixels down each side of the display - for example with a 128 pixel-width display and a 6-bit-wide font there are 21 characters per row with 1 unused pixel down each edge
#define DISPLAY_LEFTMARGIN ((DISPLAY_LCDWIDTH - DISPLAY_CHARWIDTH * 6) / 2)  
// (unlikely to need a TOPMARGIN as displays are all likely to be a multiple of 8 pixels high - in any case we'll manage okay without)
#define DISPLAY_SETCONTRAST 0x81
#define DISPLAY_DISPLAYALLON_RESUME 0xA4
#define DISPLAY_DISPLAYALLON 0xA5
#define DISPLAY_NORMALDISPLAY 0xA6
#define DISPLAY_INVERTDISPLAY 0xA7
#define DISPLAY_DISPLAYOFF 0xAE
#define DISPLAY_DISPLAYON 0xAF

#define DISPLAY_SETDISPLAYOFFSET 0xD3
#define DISPLAY_SETCOMPINS 0xDA

#define DISPLAY_SETVCOMDETECT 0xDB

#define DISPLAY_SETDISPLAYCLOCKDIV 0xD5
#define DISPLAY_SETPRECHARGE 0xD9

#define DISPLAY_SETMULTIPLEX 0xA8

#define DISPLAY_SETLOWCOLUMN 0x00
#define DISPLAY_SETHIGHCOLUMN 0x10

#define DISPLAY_COLUMNADDR 0x21
#define DISPLAY_PAGEADDR   0x22

#define DISPLAY_SETSTARTLINE 0x40
#define DISPLAY_SETSTARTPAGE 0XB0
#define DISPLAY_MEMORYMODE 0x20

#define DISPLAY_COMSCANINC 0xC0
#define DISPLAY_COMSCANDEC 0xC8

#define DISPLAY_SEGREMAP 0xA0

#define DISPLAY_CHARGEPUMP 0x8D

#define DISPLAY_EXTERNALVCC 0x1
#define DISPLAY_SWITCHCAPVCC 0x2

 // queue up the initial setup commands for the display
#ifdef SH1106
 uint8_t commandQueue[23] = {
   DISPLAY_DISPLAYOFF,
   0x40, // display start line
   DISPLAY_SETCONTRAST, 0x80,
   DISPLAY_SEGREMAP | 0x01,
   DISPLAY_NORMALDISPLAY,
   DISPLAY_SETMULTIPLEX, 0x3F,
   0xAD, 0x8B, // charge pump enable, external VCC
   0x30, // VPP 9V
   DISPLAY_COMSCANDEC,
   DISPLAY_SETDISPLAYOFFSET, 0x00,
   DISPLAY_SETDISPLAYCLOCKDIV, 0x80,
   DISPLAY_SETPRECHARGE, 0x22,
   DISPLAY_SETCOMPINS, 0x12,
   DISPLAY_SETVCOMDETECT, 0x40,
   DISPLAY_DISPLAYON
 };
 uint8_t dataStart = queueCommands(dataBuffer, 23, commandQueue);
#endif

#ifdef SSD1306  
 uint8_t commandQueue[24] = {
   DISPLAY_SETMULTIPLEX, 0x3F,
   DISPLAY_SETDISPLAYOFFSET, 0x00,
   DISPLAY_SETSTARTLINE,
   DISPLAY_SEGREMAP | 0x01,
   DISPLAY_COMSCANDEC,
   DISPLAY_SETCOMPINS, 0x12,
   DISPLAY_SETCONTRAST, 0xFF,
   DISPLAY_DISPLAYALLON_RESUME,
   DISPLAY_NORMALDISPLAY,
   DISPLAY_SETDISPLAYCLOCKDIV, 0x80,
   DISPLAY_CHARGEPUMP, 0x14,
   DISPLAY_SETPRECHARGE, 0x22,
   DISPLAY_MEMORYMODE, 0x01,
   DISPLAY_SETVCOMDETECT, 0x20,
   DISPLAY_DISPLAYON
 };
 uint8_t dataStart = queueCommands(dataBuffer, 24, commandQueue);
#endif




void _display::transmitCharSmall(uint8_t row, uint8_t x, uint8_t c) {
#if defined(NEGATIVE_DISPLAY) && (defined(SH1106) || defined(SSD1306))
 uint8_t xorMask = c & 0x80 ? 0x00 : 0xFF;  // if MSB set display character reverse field
#else
 uint8_t xorMask = c & 0x80 ? 0xFF : 0x00;  // if MSB set display character reverse field
#endif
#ifdef SH1106
 x += 2;
 uint8_t commandQueue[3] = {(uint8_t)(0xB0 + row), (uint8_t)(x & 0x0F), (uint8_t)(((x >> 4) & 0x0F) | 0x10)};
 uint8_t dataStart = queueCommands(dataBuffer, 3, commandQueue);
 dataBuffer[dataStart++] = 7; // now append a 7-byte data packet
 dataBuffer[dataStart++] = 0x40; // tell display we're sending data not commands
#endif
#ifdef SSD1306
 uint8_t commandQueue[6] = {DISPLAY_PAGEADDR, row, row, DISPLAY_COLUMNADDR, x, x < DISPLAY_LCDWIDTH - 6 ? x + 5 : DISPLAY_LCDWIDTH - 1};
 uint8_t dataStart = queueCommands(dataBuffer, 6, commandQueue);
 dataBuffer[dataStart++] = 7; // now append a 7-byte data packet
 dataBuffer[dataStart++] = 0x40; // tell display we're sending data not commands
#endif

Edited 2019-08-27 04:22 by ceptimus
 
MipsyKing
Newbie

Joined: 12/02/2015
Location: Italy
Posts: 17
Posted: 07:17pm 27 Aug 2019
Copy link to clipboard 
Print this post

Very intersting ceptimus. Would be possible to translate this code into MM Basic (only the part about the 1,3" controller sh1106)in order to let Peter test his i2C display?
Mine is ordered, but it will take a month (at least) untill I will receive it!

And what about the idea to regulate the global light of the display (for example to simulate a fading between two screens), is possible or not?
 
ceptimus
Senior Member

Joined: 05/07/2019
Location: United Kingdom
Posts: 130
Posted: 07:56pm 27 Aug 2019
Copy link to clipboard 
Print this post

It would certainly be possible to drive the display wholly from MMBASIC - but it would need a whole lot of BASIC SUB-routines and would be much slower and less convenient than using Peter's C driver.

It's not really MMBASIC we need: it's a C function for MMBASIC - that's what all the magic hex codes in Peter's code are.

I've not written any of those for MicroMites yet, so I need to figure out how to set up the C compiler and such.  I might have a go at it after I've completed my current game project, assuming no one else has already done it by then!

Regarding fading between two screens - I don't think that will be possible.  You can do a sort of fade transition by changing the pixels from the previous to the new values in a seemingly random order - but that requires having the 'before' and 'after' screens stored in RAM buffers.

Playing with the SETCONTRAST and CHARGEPUMP constants might allow one to vary the brightness, but I don't remember trying it.  I vaguely remember something in the display data sheet that implied changing the chargepump thing might be a bad idea.

These little OLED displays don't really need their brightness changing, in my opinion: they're not bright enough to dazzle, even in the dark. It would be nice to be able to turn them up much brighter when outdoors - they're not really visible in direct sunlight - but unfortunately, they're not capable of that.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 01:11pm 28 Aug 2019
Copy link to clipboard 
Print this post

The initialisation in my code works fine with 1.3" SPI displays. The issue is almost certainly the I2C implementation on the 1.3" display. This has been a known issue on many of these boards. To get I2C to work you need to connect together the pins that in SPI mode are MOSI and MISO to make the composite I2C SDA connection. Many boards only connect MOSI and this means the boards don't send the ACK and NACK I2C handshake messages. Arduino types have got round this by implementing a bastardised version of I2C which doesn't need ACK and NACK. Us Micromite types don't do that sort of thing
 
ceptimus
Senior Member

Joined: 05/07/2019
Location: United Kingdom
Posts: 130
Posted: 02:15pm 28 Aug 2019
Copy link to clipboard 
Print this post

Are you talking about the dedicated I2C interface 1.3" displays?  I know there are some that support both SPI and I2C, but the ones I use are I2C only.

I'm not using the Arduino Wire library which is inefficient and time wasting - my code communicates directly with the Atmel Mega's TWI registers: it's interrupt driven and non-blocking.

It's a while since I wrote it.  The callback that happens at the end of either a successful or unsuccessful master transmit no longer sends anything back to the calling routine to indicate success or failure - you can see where I've commented out the status code return, and now the callback passes no parameters.  I seem to remember in testing that when the code did use different return values to indicate different varieties of 'fail' I could never make any of them happen, short of disconnecting the display - and then what is the calling code going to do anyhow?

The main application was where the processor was sending critical real-time data via a radio link - and if the display failed for some reason it was best for the device to continue operating without the display working.

There are lots of devices out in the field though, running this code, and no one has reported back any display problems. (yet)


/*  TWI (I2C) non-blocking interrupt driven.  Currently only supports master transmit mode
*  ceptimus.  September 2016
*/
#ifndef TWI_h
#define TWI_h
#include "config.h"

typedef void (*callbackPtr)(/* uint8_t */ void);

class TWI {
 public:    
   static void TWIstart(void); // configure TWI registers (sets communication speed)
   static void nonBlockingTWImasterTransmit(uint8_t slaveAddr, uint8_t data[], uint8_t length, callbackPtr callback);
 // following are only public so they can be accessed by the (non-member) ISR
   static uint8_t slaveAddr;
   static uint8_t *data; // data pointer for non-blocking interrupt routine
   static uint8_t remaining; // count of remaining data bytes to be sent by non-blocking interrupt routine
   static callbackPtr callback;
};
#endif

=========================================================

/*  TWI (I2C) non-blocking interrupt driven.  Currently only supports master transmit mode
*  ceptimus.  September 2016
*/
#include "TWI.h"

uint8_t TWI::slaveAddr;
uint8_t *TWI::data;
uint8_t TWI::remaining;
callbackPtr TWI::callback;

void TWI::TWIstart(void) { // configure for two wire interface operation
 // for 'standard' 400 kHz SCL frequency, set TWSR = 1 and TWBR = 3.  
 TWSR = 1; // set prescaler to 4
 TWBR = 3; // SCL = CPU clock / (16 + 2 * TWBR * prescaler) 16M / (16 + 2 * 3 * 4) = 400kHz
}

void TWI::nonBlockingTWImasterTransmit(uint8_t slave, uint8_t bytes[], uint8_t length, callbackPtr cback) {
 slaveAddr = slave;
 callback = cback;
 remaining = length;
 data = bytes;

 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE); // send START condition and enable TWI interrupts
}

ISR(TWI_vect) { // TWI interrupt has occurred meaning that TWINT flag has been set
 uint8_t statusCode = TWSR & 0xF8;
 switch(statusCode) {
   case 0x08: // normal response to a START
     TWDR = TWI::slaveAddr << 1; // send slave address (and enter master transmit mode)
     TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // transmit address
     break;
   case 0x10: // normal response to a repeated START
     break;
   case 0x18: // normal response to slave address
     TWI::remaining--;
     TWDR = *TWI::data++; // send first byte of data
     TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // send data byte
     break;
   case 0x28: // normal response to data byte
     if (TWI::remaining) { // still have more data to transmit
       TWI::remaining--;
       TWDR = *TWI::data++; // send next byte of data
       TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // send data byte
     } else { // all data sent
       TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE); // send STOP condition
       sei(); // allow interrupts during callback
       TWI::callback(/* 1 */); // this can't be a response code as the Status Register is anded with F8
     }
     break;
   case 0x38: // arbitration lost
     TWCR = (1 << TWINT) | (1 << TWEN); // disable further interrupts, release TW serial bus and enter slave mode
     sei(); // allow interrupts during callback
     TWI::callback(/* statusCode */);
     break;
   default: // unexpected response
     TWCR = TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN); // disable further interrupts, send STOP condition
     sei(); // allow interrupts during callback
     TWI::callback(/* statusCode */);
     break;
 }
}

.
Edited 2019-08-29 00:45 by ceptimus
 
ajkw
Senior Member

Joined: 29/06/2011
Location: Australia
Posts: 290
Posted: 02:44am 31 Oct 2021
Copy link to clipboard 
Print this post

Peter,

Is the source code for the SD1306 i2c driver for a Micromite available please?  

I would like to see if I can adapt it to make a SH1106 I have work correctly.

With the all-basic-driver the SH1106 will , with a mod, work but and I can change the contrast too, however it is just not fast enough to draw a screen, so there is some hope.  Perhaps I can make a change to the Csub version and then learn how to compile it.

Regards,
Anthony.
Edited 2021-10-31 12:45 by ajkw
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 08:19am 31 Oct 2021
Copy link to clipboard 
Print this post

  Quote  Is the source code for the SD1306 i2c driver for a Micromite available please?  


I've attached the complete MPLabX project
SSD1306loadable.X.zip
 
ajkw
Senior Member

Joined: 29/06/2011
Location: Australia
Posts: 290
Posted: 11:36am 31 Oct 2021
Copy link to clipboard 
Print this post

Thank you Peter.

I have identified the change I think I need to make and have gone on to install Mplab X.

The first tutorial on creating Csub's mentions MPlab 3.10 and the compiler 1.33 however opening the project with this version generates a error has the project was created in something later.

What versions should I be using please?

Anthony.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8516
Posted: 11:49am 31 Oct 2021
Copy link to clipboard 
Print this post

I'm currently running MPLabX V5.2 and compilers 1.33 and 1.44. This project was last built with V1.33
 
     Page 1 of 2    
Print this page
© JAQ Software 2024