Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 03:34 10 May 2025 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 : SSD1331 96x64 colour OLED driver

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10066
Posted: 01:04pm 18 Jan 2019
Copy link to clipboard 
Print this post

As requested by WW for MM2. Can compile for MM+ if anyone needs it.




NB: transparent text isn't possible as no MISO pin on display. I've included the 8x6 font as this is definitely needed for this display

Sub mm.startup
SSD1331 2,9,16, 1' DCpin, RESETpin, CSpin, orientation (1-4)
End Sub

'
' File test.bas written 18-Jan-2019 11:22:59
'
CSub SSD1331
0000021E
'spi_write_data
27BDFFE0 AFBF001C AFB10018 AFB00014 309100FF 3C109D00 8E030090 8E02001C
8064002C 0040F809 24050006 8E030090 8E02001C 8064002D 0040F809 24050005
3C02BF80 AC515820 3C03BF80 8C625810 30420080 1040FFFD 3C02BF80 8C425820
3C029D00 8C430090 8C42001C 8064002D 0040F809 24050006 8FBF001C 8FB10018
8FB00014 03E00008 27BD0020
'spi_write_command
27BDFFE0 AFBF001C AFB10018 AFB00014 309100FF 3C109D00 8E030090 8E02001C
8064002C 0040F809 24050005 8E030090 8E02001C 8064002D 0040F809 24050005
3C02BF80 AC515820 3C03BF80 8C625810 30420080 1040FFFD 3C02BF80 8C425820
3C029D00 8C430090 8C42001C 8064002D 0040F809 24050006 8FBF001C 8FB10018
8FB00014 03E00008 27BD0020
'DefineRegion
27BDFFD8 AFBF0024 AFB30020 AFB2001C AFB10018 AFB00014 00808021 00A09021
00C08821 3C029D00 8C420090 90420015 30420001 10400015 00E09821 24040015
0411FFCC 00000000 320400FF 0411FFC9 00000000 322400FF 0411FFC6 00000000
24040075 0411FFC3 00000000 324400FF 0411FFC0 00000000 326400FF 0411FFBD
00000000 10000014 8FBF0024 24040075 0411FFB8 00000000 320400FF 0411FFB5
00000000 322400FF 0411FFB2 00000000 24040015 0411FFAF 00000000 324400FF
0411FFAC 00000000 326400FF 0411FFA9 00000000 8FBF0024 8FB30020 8FB2001C
8FB10018 8FB00014 03E00008 27BD0028
'DrawBitmapSPI
27BDFFB8 AFBF0044 AFBE0040 AFB7003C AFB60038 AFB50034 AFB40030 AFB3002C
AFB20028 AFB10024 AFB00020 0080B021 00A0F021 00C0A021 AFA70054 8FA4005C
8FA30060 3C029D00 8C420094 8C420000 02C2102B 104000C3 8FB50064 3C029D00
8C420098 8C420000 00A2102B 104000BD 8FA20058 70462802 00B63021 04C000B9
70471002 005E2821 04A000B6 00003821 2BC50000 03C5380A 00E02821 3C07BF80
8CE85830 AFA80010 8CE85800 AFA80014 8CE85840 AFA80018 ACE05800 3C080001
35088260 ACE85800 ACE05830 24080C00 ACE85840 7C901340 00043C03 2408FFF8
00E83824 02078025 321000FF 7C9120C0 00042143 2407FFE0 00872024 02248825
323100FF 7C721340 00032403 00884024 02489025 325200FF 7C7320C0 00031943
00673824 02679825 327300FF 24A7FFFF 02C02021 24C6FFFF 00E23821 0411FF74
00000000 3C179D00 8EE30090 8EE2001C 8064002C 0040F809 24050006 8EE30090
8EE2001C 8064002D 0040F809 24050005 0014C823 8FA20054 70547802 25EFFFFF
0280B821 00005821 0000C021 8FAD0058 3C069D00 240C0001 1000004D 3C02BF80
27DE0001 27C3FFFF 04600044 00000000 8CC30098 8C630000 007E182B 1460006A
8FBF0044 1E80002D 01E04821 1000003B 00000000 24630001 2464FFFF 04800020
00000000 8CC40094 8C840000 0083202B 1480001B 00000000 91040000 00872024
1080000D 00000000 8C445810 30840002 1480FFFD 00000000 AC505820 8C445810
30840002 1480FFFD 00000000 AC515820 1000000B 00000000 8C445810 30840002
1480FFFD 00000000 AC525820 8C445810 30840002 1480FFFD 00000000 AC535820
5465FFDD 24630001 254A0001 15540005 2529FFFF 10000011 00000000 02C01821
00005021 014B2021 24850007 28880000 00A8200B 000440C3 02A84021 000927C3
00042742 01243821 30E70007 00E43823 00EC3804 1000FFC7 006D2821 57CEFFB9
27DE0001 27180001 01F97821 01775821 8FA40054 0304182A 10600005 8FA50058
1CA0FFAF 03C57021 1000FFF7 27180001 3C02BF80 8C435810 30630080 1060FFFD
00000000 10000002 3C02BF80 8C435820 8C435810 30630020 1060FFFC 00000000
3C02BF80 AC405800 24040040 3C03BF80 AC645814 8FA70010 AC475830 8FA80014
AC485800 8FA30018 AC435840 3C029D00 8C430090 8C42001C 8064002D 0040F809
24050006 8FBF0044 8FBE0040 8FB7003C 8FB60038 8FB50034 8FB40030 8FB3002C
8FB20028 8FB10024 8FB00020 03E00008 27BD0048
'DrawRectangleSPI
27BDFFC0 AFBF003C AFBE0038 AFB70034 AFB60030 AFB5002C AFB40028 AFB30024
AFB20020 AFB1001C AFB00018 8FA30050 3C02BF80 8C575830 8C5E5800 8C485840
AFA80010 AC405800 3C080001 35088260 AC485800 AC405830 24080C00 AC485840
0086102A 14400005 00A7102A 00801021 00C02021 00403021 00A7102A 14400004
28930000 00A01021 00E02821 00403821 0013200B 00809821 3C029D00 8C420094
8C420000 0082402B 2444FFFF 0088980A 28D40000 0014300B 00C0A021 00C2202B
2442FFFF 0044A00A 28B50000 0015280B 00A0A821 3C029D00 8C420098 8C420000
00A2282B 2444FFFF 0085A80A 28F60000 0016380B 00E0B021 00E2202B 2442FFFF
0044B00A 7C711340 00032403 2402FFF8 00821024 02228825 323100FF 7C7020C0
00031943 2402FFE0 00621824 02038025 321000FF 02602021 02A02821 02803021
02C03821 0411FE8D 00000000 3C129D00 8E430090 8E42001C 8064002C 0040F809
24050006 8E430090 8E42001C 8064002D 0040F809 24050005 24020001 00539823
0274A021 00552023 00962021 70942002 1080000E 2484FFFF 3C02BF80 8C435810
30630002 1460FFFD 00000000 AC515820 8C435810 30630002 1460FFFD 00000000
AC505820 1480FFF5 2484FFFF 3C03BF80 8C625810 30420080 1040FFFD 3C02BF80
8C425810 30420020 14400006 3C02BF80 8C435820 8C435810 30630020 1060FFFC
00000000 3C02BF80 AC405800 24040040 3C03BF80 AC645814 AC575830 AC5E5800
8FA30010 AC435840 3C029D00 8C430090 8C42001C 8064002D 0040F809 24050006
8FBF003C 8FBE0038 8FB70034 8FB60030 8FB5002C 8FB40028 8FB30024 8FB20020
8FB1001C 8FB00018 03E00008 27BD0040
'getFPC
27BDFFF8 AFBF0004 00852023 03E42021 ACC40000 8FBF0004 03E00008 27BD0008
'pstring
27BDFFE0 AFBF001C AFB00018 00808021 00002021 3C059D00 24A50854 27A60010
0411FFEF 00000000 8FA40010 3C029D00 8C42002C 0040F809 02042021 8FBF001C
8FB00018 03E00008 27BD0020
'main
27BDFFC0 AFBF003C AFB50038 AFB40034 AFB30030 AFB2002C AFB10028 AFB00024
00809021 00A08821 00C09821 00E0A021 00002021 3C059D00 24A508C0 27A60018
0411FFD4 00000000 3C109D00 8E020090 8E230000 A043002E 8E020090 8E430000
A043002C 8E020090 8E630000 A043002D 8E020090 8E830000 A0430015 8E020090
24030014 A0430014 8E030090 8E020010 8064002E 24050008 0040F809 00003021
8E030090 8E020010 8064002E 24050065 0040F809 00003021 8E030090 8E02001C
8064002E 0040F809 24050006 8E030090 8E020010 8064002C 24050008 0040F809
00003021 8E030090 8E020010 8064002C 24050065 0040F809 00003021 8E030090
8E02001C 8064002C 0040F809 24050006 8E030090 8E020010 8064002D 24050008
0040F809 00003021 8E030090 8E020010 8064002D 24050065 0040F809 00003021
8E030090 8E02001C 8064002D 0040F809 24050006 3C02BF81 8C44F220 7C84D800
3C020661 3442A053 1082000B 24030050 3C02BF81 8C43F220 7C63D800 3C020660
3442A053 00621826 24020050 2404000C 0083100B 00401821 3C029D00 8C420088
00621821 8C640000 24030064 54830007 00008821 3C03BF80 8C715830 8C725800
8C755840 10000003 3C03BF81 00009021 3C03BF81 8C65F220 7CA5D800 3C040661
3484A053 10A4000B 24030050 3C03BF81 8C64F220 7C84D800 3C030660 3463A053
00831826 24040050 2405000C 00A3200B 00801821 00621021 8C430000 24020065
1062008E 3C029D00 8C420010 3C03BF81 8C65F220 7CA5D800 3C030661 3463A053
10A3000B 24040014 3C03BF81 8C64F220 7C84D800 3C030660 3463A053 00832026
24030014 24050003 00A4180B 00602021 24050008 0040F809 00003021 3C029D00
8C420010 3C03BF81 8C65F220 7CA5D800 3C030661 3463A053 10A3000B 24040014
3C03BF81 8C64F220 7C84D800 3C030660 3463A053 00832026 24030014 24050003
00A4180B 00602021 24050065 0040F809 00003021 3C029D00 8C420010 3C03BF81
8C65F220 7CA5D800 3C030661 3463A053 10A3000B 24040029 3C03BF81 8C64F220
7C84D800 3C030660 3463A053 00832026 24030029 2405000E 00A4180B 00602021
24050002 0040F809 00003021 3C029D00 8C420010 3C03BF81 8C65F220 7CA5D800
3C030661 3463A053 10A3000B 24040029 3C03BF81 8C64F220 7C84D800 3C030660
3463A053 00832026 24030029 2405000E 00A4180B 00602021 24050065 0040F809
00003021 3C029D00 8C420010 3C03BF81 8C65F220 7CA5D800 3C030661 3463A053
10A3000B 2404000E 3C03BF81 8C64F220 7C84D800 3C030660 3463A053 00832026
2403000E 24050019 00A4180B 00602021 24050008 0040F809 00003021 3C029D00
8C420010 3C03BF81 8C65F220 7CA5D800 3C030661 3463A053 10A3000B 2404000E
3C03BF81 8C64F220 7C84D800 3C030660 3463A053 00832026 2403000E 24050019
00A4180B 00602021 24050065 0040F809 00003021 3C02BF81 8C43FA84 24040001
7C831804 AC43FA84 3C02BF81 8C43FB04 24040003 7C831804 AC43FB04 3C02BF80
34038060 AC435800 24030003 AC435830 24030C00 AC435840 16200005 3C109D00
8C515830 8C525800 8C555840 3C109D00 8E030090 8E02001C 8064002E 0040F809
24050006 8E020004 0040F809 24042710 8E030090 8E02001C 8064002E 0040F809
24050005 8E020004 0040F809 24042710 8E030090 8E02001C 8064002E 0040F809
24050006 240400AE 0411FCCA 00000000 240400A0 0411FCC7 00000000 8E020090
80420015 24030001 14430006 24030002 24040072 0411FCBF 00000000 10000012
240400A1 14430006 24030003 24040063 0411FCB8 00000000 1000000B 240400A1
54430006 24040071 24040060 0411FCB1 00000000 10000004 240400A1 0411FCAD
00000000 240400A1 0411FCAA 00000000 00002021 0411FCA7 00000000 240400A2
0411FCA4 00000000 00002021 0411FCA1 00000000 240400A4 0411FC9E 00000000
240400A8 0411FC9B 00000000 2404003F 0411FC98 00000000 240400AD 0411FC95
00000000 2404008E 0411FC92 00000000 240400B0 0411FC8F 00000000 2404000B
0411FC8C 00000000 240400B1 0411FC89 00000000 24040031 0411FC86 00000000
240400B3 0411FC83 00000000 240400F0 0411FC80 00000000 2404008A 0411FC7D
00000000 24040064 0411FC7A 00000000 2404008B 0411FC77 00000000 24040078
0411FC74 00000000 2404008A 0411FC71 00000000 24040064 0411FC6E 00000000
240400BB 0411FC6B 00000000 2404003A 0411FC68 00000000 240400BE 0411FC65
00000000 2404003E 0411FC62 00000000 24040087 0411FC5F 00000000 24040006
0411FC5C 00000000 24040081 0411FC59 00000000 24040091 0411FC56 00000000
24040082 0411FC53 00000000 24040050 0411FC50 00000000 24040083 0411FC4D
00000000 2404007D 0411FC4A 00000000 240400AF 0411FC47 00000000 3C029D00
8C420090 90420015 30420001 10400008 3C029D00 8C430094 24040060 AC640000
8C420098 24030040 10000007 AC430000 8C430098 24040060 AC640000 8C420094
24030040 AC430000 8FA50018 3C029D00 8C430048 3C049D00 2484059C 00852021
AC640000 8FA50018 8C43004C 3C049D00 24840208 00852021 AC640000 8C430048
8C440094 8C860000 8C420098 8C470000 AFA00010 8C620000 00002021 00002821
24C6FFFF 0040F809 24E7FFFF 3C02BF80 AC515830 AC525800 AC555840 3C049D00
24841068 0411FDFB 00000000 8FBF003C 8FB50038 8FB40034 8FB30030 8FB2002C
8FB10028 8FB00024 03E00008 27BD0040
'.rodata
'startup
31445353 20313333 76697264 6C207265 6564616F 000A0D64
End CSub


DefineFont #8
5C200806
00000000 82200000 00800008 00004551 4F510000 0045F994 2B1CEA21 690000C2
B04C2090 AA104A62 84608046 00000000 40108410 81400081 00841004 A89C8A00
82000080 0080203E 30000000 00000042 0000003E 01000000 21000086 00004208
CAAA2972 82210027 00872008 21842072 42F8800F 00270A04 F824C510 0FFA0041
00270A02 8A3C0831 21F80027 00044108 8A9C2872 28720027 0027089E 61008601
86010080 00846000 40208410 0F000081 0000F880 10028140 20720084 00022084
BA9A2072 28720027 8028FAA2 8ABC28F2 2872002F 00278220 8AA248E2 08FA004E
800F823C 823C08FA 28720008 80278A2E 8ABE288A 82708028 00872008 12044138
4A8A0046 8048A230 82200882 6A8B800F 80288AAA 9AAA2C8A 28728028 00278AA2
82BC28F2 28720008 8046AAA2 A2BC28F2 087A8048 002F081C 200882F8 288A0082
00278AA2 89A2288A 288A0042 00A5AAAA 5208258A 288A8028 00822094 420821F8
0471800F 00074110 A9944AA9 4170804A 00471004 00804821 00000000 800F0000
00008140 07000000 80277A02 8A320B82 0700002F 00278220 8AA62608 07008027
0007FA22 41382431 E8010004 002778A2 8A320B82 06208028 00872008 12040310
09820046 0089C228 20088260 0D000087 8028AA2A 8A320B00 07008028 00278A22
F2220F00 06000008 802078A6 82320B00 07000008 002F7020 41100E41 08000023
80668AA2 89A20800 08000042 00A5AAA2 21940800 08008048 002778A2 21840F00
0400800F 0EE24028
End DefineFont


/*******************************************************************************
*
* Driver for SSD1331 Display written as CSUB
*
* (c) Peter Mather 2019 with acknowledgements to Peter Carnegie & Geoff Graham
* Also thanks to ADAfruit for the initialisation sequence
*
*
* This CSUB MUST be compiled with Optimization Level 1, -O1
* -O2,-O3,-Os will compile successfully, but generate exceptions at runtime.
*
* When Generating the CSUB, use MERGE CSUB mode, and name the CSUB
* SSD1331
*
* Entry point is function long long main(long long *DC,
* long long *RST,
* long long *CS
* long long *orientation)
*
* V1.0 2019-01-18 Peter Mather
*
******************************************************************************/
#include <stdarg.h>

#define Version 100 //Version 1.00
#define _SUPPRESS_PLIB_WARNING // required for XC1.33 Later compiler versions will need PLIB to be installed
#include <plib.h> // the pre Harmony peripheral libraries


#include "../cfunctions.h"
// Select one of these defines to set the pixel color order
#define SSD1331_COLORORDER_RGB
// #define SSD1331_COLORORDER_BGR

#if defined SSD1331_COLORORDER_RGB && defined SSD1331_COLORORDER_BGR
#error "RGB and BGR can not both be defined for SSD1331_COLORODER."
#endif

// Timing Delays
#define SSD1331_DELAYS_HWFILL (3)
#define SSD1331_DELAYS_HWLINE (1)

// SSD1331 Commands
#define SSD1331_CMD_DRAWLINE 0x21
#define SSD1331_CMD_DRAWRECT 0x22
#define SSD1331_CMD_FILL 0x26
#define SSD1331_CMD_SETCOLUMN 0x15
#define SSD1331_CMD_SETROW 0x75
#define SSD1331_CMD_CONTRASTA 0x81
#define SSD1331_CMD_CONTRASTB 0x82
#define SSD1331_CMD_CONTRASTC 0x83
#define SSD1331_CMD_MASTERCURRENT 0x87
#define SSD1331_CMD_SETREMAP 0xA0
#define SSD1331_CMD_STARTLINE 0xA1
#define SSD1331_CMD_DISPLAYOFFSET 0xA2
#define SSD1331_CMD_NORMALDISPLAY 0xA4
#define SSD1331_CMD_DISPLAYALLON 0xA5
#define SSD1331_CMD_DISPLAYALLOFF 0xA6
#define SSD1331_CMD_INVERTDISPLAY 0xA7
#define SSD1331_CMD_SETMULTIPLEX 0xA8
#define SSD1331_CMD_SETMASTER 0xAD
#define SSD1331_CMD_DISPLAYOFF 0xAE
#define SSD1331_CMD_DISPLAYON 0xAF
#define SSD1331_CMD_POWERMODE 0xB0
#define SSD1331_CMD_PRECHARGE 0xB1
#define SSD1331_CMD_CLOCKDIV 0xB3
#define SSD1331_CMD_PRECHARGEA 0x8A
#define SSD1331_CMD_PRECHARGEB 0x8B
#define SSD1331_CMD_PRECHARGEC 0x8C
#define SSD1331_CMD_PRECHARGELEVEL 0xBB
#define SSD1331_CMD_VCOMH 0xBE
#define LANDSCAPE 1
#define PORTRAIT 2
#define RLANDSCAPE 3
#define RPORTRAIT 4
#define MX170
#if defined(MX170)
// SPI pin numbers and registers
#define SPI_INP_PIN (HAS_44PINS ? 41 : 14)
#define SPI_OUT_PIN (HAS_44PINS ? 20 : 3)
#define SPI_CLK_PIN (HAS_44PINS ? 14 : 25)
#define SPI_PPS_OPEN PPSInput(2, SDI1, RPB5); PPSOutput(2, RPA1, SDO1)
#define SPI_PPS_CLOSE PPSOutput(2, RPA1, NULL)
#define SPICON *(volatile unsigned int *)(0xbf805800) //SPI status register
#define SPISTAT *(volatile unsigned int *)(0xbf805810) //SPI status register
#define SPIBUF *(volatile unsigned int *)(0xbf805820) //SPI output buffer
#define SPIBRG *(volatile unsigned int *)(0xbf805830) //SPI output buffer
#define SPICON2 *(volatile unsigned int *)(0xbf805840) //SPI status register
#define SPISTATCLR *(volatile unsigned int *)(0xbf805814) //SPI status clear register
#define ILImode 0x18520
#define ILIbrg 0
#elif defined(MX470)
// SPI pin numbers and registers
#define SPI_INP_PIN (HAS_100PINS ? 11 : 47)
#define SPI_OUT_PIN (HAS_100PINS ? 12 : 5)
#define SPI_CLK_PIN (HAS_100PINS ? 10 : 4)
#define SPI_PPS_OPEN { if(HAS_100PINS) {PPSInput(2, SDI2, RPG7); PPSOutput(1, RPG8, SDO2); } else {PPSInput(2, SDI2, RPC13); PPSOutput(2, RPG7, SDO2);}}
#define SPI_PPS_CLOSE { if(HAS_100PINS) PPSOutput(1, RPG8, NULL); else PPSOutput(2, RPG7, NULL); }
#define SPICON *(volatile unsigned int *)(0xbf805A00) //SPI status register
#define SPISTAT *(volatile unsigned int *)(0xbf805A10) //SPI status register
#define SPIBUF *(volatile unsigned int *)(0xbf805A20) //SPI output buffer
#define SPIBRG *(volatile unsigned int *)(0xbf805A30) //SPI output buffer
#define SPICON2 *(volatile unsigned int *)(0xbf805A40) //SPI status register
#define SPISTATCLR *(volatile unsigned int *)(0xbf805A14) //SPI status clear register
#endif
#define SPIsend(a) {int j;SPIBUF=a; while((SPISTAT & 0x80)==0); j=SPIBUF;}
#define SPIqueue(a) {while(SPISTAT & 0x02){};SPIBUF=a;}

// set the chip select for the SPI to low (enabled)
// if the SPI is currently set to a different mode or baudrate this will change it accordingly
// also, it checks if the chip select pin needs to be changed
// set the chip select for SPI1 to high (disabled)
void spi_write_data(unsigned char data){
PinSetBit(Option->LCD_CD, LATSET);
PinSetBit(Option->LCD_CS, LATCLR);
SPIsend(data);
PinSetBit(Option->LCD_CS, LATSET);
}
void spi_write_command(unsigned char data){
PinSetBit(Option->LCD_CD, LATCLR);
PinSetBit(Option->LCD_CS, LATCLR);
SPIsend(data);
PinSetBit(Option->LCD_CS, LATSET);
}

/*******************************************************************************
*
* defines start/end coordinates for memory access from host to SSD1963
* also maps the start and end points to suit the orientation
*
* This function is a modified version of the function inside the MMBasic Interpreter
* for MM+ on 'MX470 chips
*
*******************************************************************************/
void DefineRegion(int x1, int y1, int x2, int y2) {


if(Option->DISPLAY_ORIENTATION&1){
spi_write_command(0x15); // Column addr set
spi_write_command(x1);
spi_write_command(x2);

spi_write_command(0x75); // Row addr set
spi_write_command(y1);
spi_write_command(y2);
} else {
spi_write_command(0x75); // Row addr set
spi_write_command(x1);
spi_write_command(x2);

spi_write_command(0x15); // Column addr set
spi_write_command(y1);
spi_write_command(y2);
}

}


//Print the bitmap of a char on the video output
// x, y - the top left of the char
// width, height - size of the char's bitmap
// scale - how much to scale the bitmap
// fc, bc - foreground and background colour
// bitmap - pointer to the bitmap
void DrawBitmapSPI(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){
int i, j, k, m;
unsigned char fhb, flb, bhb, blb;
unsigned int consave=0,brgsave=0,con2save;
int vertCoord, horizCoord, XStart, XEnd, YEnd;
if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return;

// adjust when part of the bitmap is outside the displayable coordinates
vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen
XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn
XEnd = x1 + (width * scale) - 1; if(XEnd >= HRes) XEnd = HRes - 1; // the width of the bitmap will extend beyond the right margin
YEnd = y1 + (height * scale) - 1; if(YEnd >= VRes) YEnd = VRes - 1;// the height of the bitmap will extend beyond the bottom margin
brgsave=SPIBRG; //save any user SPI setup
consave=SPICON;
con2save=SPICON2;
SPICON=0x0;
SPICON=0x018260;
#ifdef MX470
SPIBRG=0;
#else
SPIBRG=0;
#endif
SPICON2=0xC00;
// convert the colours to 565 format
fhb = ((fc >> 16) & 0b11111000) | ((fc >> 13) & 0b00000111);
flb = ((fc >> 5) & 0b11100000) | ((fc >> 3) & 0b00011111);
bhb = ((bc >> 16) & 0b11111000) | ((bc >> 13) & 0b00000111);
blb = ((bc >> 5) & 0b11100000) | ((bc >> 3) & 0b00011111);

DefineRegion(x1, y1, x1 + (width * scale) - 1, y1 + (height * scale) -1);
PinSetBit(Option->LCD_CD, LATSET); //set CD high
PinSetBit(Option->LCD_CS, LATCLR);
for(i = 0; i < height; i++) { // step thru the font scan line by line
for(j = 0; j < scale; j++) { // repeat lines to scale the font
if(vertCoord++ < 0) continue; // we are above the top of the screen
if(vertCoord > VRes) return; // we have extended beyond the bottom of the screen
horizCoord = x1;
for(k = 0; k < width; k++) { // step through each bit in a scan line
for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis
if(horizCoord++ < 0) continue; // we have not reached the left margin
if(horizCoord > HRes) continue; // we are beyond the right margin
if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) {
SPIqueue(fhb); SPIqueue(flb);
} else {
SPIqueue(bhb); SPIqueue(blb);
}
}
}
}
}
while((SPISTAT & 0x80)==0); //wait for all writes to complete
while(!(SPISTAT & 0x20)){i=SPIBUF;} // clean up rx fifo if not empty
SPICON=0;
#ifdef MX470
SPI2STATCLR=0x40;
#else
SPI1STATCLR=0x40;
#endif

SPIBRG=brgsave; //restore user (or my) setup
SPICON=consave;
SPICON2=con2save;
PinSetBit(Option->LCD_CS, LATSET);
}
// Draw a rectangle
// this is the basic drawing primitive used by most drawing routines
// x1, y1, x2, y2 - the coordinates
// c - the colour
void DrawRectangleSPI(int x1, int y1, int x2, int y2, int c){
unsigned int consave=0,brgsave=0,con2save;
int i, t;
unsigned char hb, lb;
brgsave=SPIBRG; //save any user SPI setup
consave=SPICON;
con2save=SPICON2;
SPICON=0x0;
SPICON=0x018260;
#ifdef MX470
SPIBRG=0;
#else
SPIBRG=0;
#endif
SPICON2=0xC00;
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0; if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0; if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0; if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0; if(y2 >= VRes) y2 = VRes - 1;

// convert the colours to 565 format
hb = ((c >> 16) & 0b11111000) | ((c >> 13) & 0b00000111);
lb = ((c >> 5) & 0b11100000) | ((c >> 3) & 0b00011111);

DefineRegion(x1, y1, x2, y2);
PinSetBit(Option->LCD_CD, LATSET); //set CD high
PinSetBit(Option->LCD_CS, LATCLR);
i = x2 - x1 + 1;
i *= (y2 - y1 + 1);
while(i--){
SPIqueue(hb);
SPIqueue(lb);
}
while((SPISTAT & 0x80)==0); //wait for all writes to complete
while(!(SPISTAT & 0x20)){i=SPIBUF;} // clean up rx fifo if not empty
SPICON=0;
#ifdef MX470
SPI2STATCLR=0x40;
#else
SPI1STATCLR=0x40;
#endif

SPIBRG=brgsave; //restore user (or my) setup
SPICON=consave;
SPICON2=con2save;
PinSetBit(Option->LCD_CS, LATSET);
}
#ifdef MX470
void DrawBufferSPI(int x1, int y1, int x2, int y2, char* p) {
unsigned int i, consave=0,brgsave=0,con2save;
brgsave=SPIBRG; //save any user SPI setup
consave=SPICON;
con2save=SPICON2;
SPICON=0x0;
SPICON=0x018260;
#ifdef MX470
SPIBRG=0;
#else
SPIBRG=0;
#endif
SPICON2=0xC00;
unsigned char hb, lb;
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
int xx1=x1, yy1=y1, xx2=x2, yy2=y2, x, y, t ;
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) xx1 = 0; if(x1 >= HRes) xx1 = HRes - 1;
if(x2 < 0) xx2 = 0; if(x2 >= HRes) xx2 = HRes - 1;
if(y1 < 0) yy1 = 0; if(y1 >= VRes) yy1 = VRes - 1;
if(y2 < 0) yy2 = 0; if(y2 >= VRes) yy2 = VRes - 1;


DefineRegion(xx1, yy1, xx2, yy2);
PinSetBit(Option->LCD_CD, LATSET); //set CD high
PinSetBit(Option->LCD_CS, LATCLR);


for(y=y1;y<=y2;y++){
for(x=x1;x<=x2;x++){
if(x>=0 && x<HRes && y>=0 && y<VRes){
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[2]=*p++;
// convert the colours to 565 format
hb = ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
lb = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
SPIqueue(hb);
SPIqueue(lb);
} else p+=3;
}
}

while((SPISTAT & 0x80)==0); //wait for all writes to complete
while(!(SPISTAT & 0x20)){i=SPIBUF;} // clean up rx fifo if not empty
SPICON=0;
#ifdef MX470
SPI2STATCLR=0x40;
#else
SPI1STATCLR=0x40;
#endif

SPIBRG=brgsave; //restore user (or my) setup
SPICON=consave;
SPICON2=con2save;
PinSetBit(Option->LCD_CS, LATSET);
}
#endif

__attribute__((noinline)) void getFPC(void *a, void *b, volatile unsigned int *c)
{
*c = (unsigned int) (__builtin_return_address (0) - (b -a)) ;
}
void pstring(const char *s){
volatile unsigned int libAddr ;
getFPC(NULL,&&getFPCLab,&libAddr) ; // warning can be ignored, stupid editor
getFPCLab: { }
unsigned char * testData = (unsigned char *)((void *)s + libAddr );
MMPrintString(testData);
}

/*******************************************************************************
*
* ST7735 : Initialise the CFunction Driver Sub-System
*
* Function called to initialise the driver SubSystem
*
* ST7735 is ALWAYS called from an MMBasic program
* On exit, vectors DrawRectangleVector, and DrawBitmapVector will
* be set to point to the CFunctions DrawRectangleSPI and
* DrawBitmapSPI respectively
*
* Entry point is function long long main(long long *MyAddress,
* long long *DC,
* long long *RST,
* long long *CS
* long long *orientation)
* long long *size)
*
******************************************************************************/
//CFunction Driver_SSD1331
void main(long long *CD, long long *RST, long long *CS,long long *orientation){
volatile unsigned int libAddr ;
getFPC(NULL,&&getFPCLab,&libAddr) ; // warning can be ignored
getFPCLab: { }
int HorizontalRes=96,VerticalRes=64;
unsigned int consave=0,brgsave=0,con2save;
Option->LCD_Reset=*RST;
Option->LCD_CD=*CD;
Option->LCD_CS=*CS;
Option->DISPLAY_ORIENTATION=*orientation;
Option->DISPLAY_TYPE=20;

ExtCfg(Option->LCD_Reset,EXT_DIG_OUT,0);ExtCfg(Option->LCD_Reset,EXT_BOOT_RESERVED,0);
PinSetBit(Option->LCD_Reset, LATSET);
ExtCfg(Option->LCD_CD,EXT_DIG_OUT,0);ExtCfg(Option->LCD_CD,EXT_BOOT_RESERVED,0);
PinSetBit(Option->LCD_CD, LATSET);
ExtCfg(Option->LCD_CS,EXT_DIG_OUT,0);ExtCfg(Option->LCD_CS,EXT_BOOT_RESERVED,0);
PinSetBit(Option->LCD_CS, LATSET);
if(ExtCurrentConfig[SPI_OUT_PIN] == EXT_RESERVED) { //already open
brgsave=SPIBRG;
consave=SPICON;
con2save=SPICON2;
}
if(ExtCurrentConfig[SPI_OUT_PIN]!=EXT_BOOT_RESERVED){
ExtCfg(SPI_OUT_PIN, EXT_DIG_OUT, 0); ExtCfg(SPI_OUT_PIN, EXT_BOOT_RESERVED, 0);
ExtCfg(SPI_INP_PIN, EXT_DIG_IN, 0); ExtCfg(SPI_INP_PIN, EXT_BOOT_RESERVED, 0);
ExtCfg(SPI_CLK_PIN, EXT_DIG_OUT, 0); ExtCfg(SPI_CLK_PIN, EXT_BOOT_RESERVED, 0);
SPI_PPS_OPEN;
}
SPICON=0x8060;
SPIBRG=3;
SPICON2=0xC00;// this is defined in IOPorts.h
if(!brgsave){ //save my settings
brgsave=SPIBRG;
consave=SPICON;
con2save=SPICON2;
}


//Reset the SSD1331
PinSetBit(Option->LCD_Reset,LATSET);
uSec(10000);
PinSetBit(Option->LCD_Reset,LATCLR);
uSec(10000);
PinSetBit(Option->LCD_Reset,LATSET);
spi_write_command(SSD1331_CMD_DISPLAYOFF); // 0xAE
spi_write_command(SSD1331_CMD_SETREMAP); // 0xA0
if(Option->DISPLAY_ORIENTATION==1) spi_write_command(0x72);
else if(Option->DISPLAY_ORIENTATION==2) spi_write_command(0x63);
else if(Option->DISPLAY_ORIENTATION==3) spi_write_command(0x60);
else spi_write_command(0x71);
spi_write_command(SSD1331_CMD_STARTLINE); // 0xA1
spi_write_command(0x0);
spi_write_command(SSD1331_CMD_DISPLAYOFFSET); // 0xA2
spi_write_command(0x0);
spi_write_command(SSD1331_CMD_NORMALDISPLAY); // 0xA4
spi_write_command(SSD1331_CMD_SETMULTIPLEX); // 0xA8
spi_write_command(0x3F); // 0x3F 1/64 duty
spi_write_command(SSD1331_CMD_SETMASTER); // 0xAD
spi_write_command(0x8E);
spi_write_command(SSD1331_CMD_POWERMODE); // 0xB0
spi_write_command(0x0B);
spi_write_command(SSD1331_CMD_PRECHARGE); // 0xB1
spi_write_command(0x31);
spi_write_command(SSD1331_CMD_CLOCKDIV); // 0xB3
spi_write_command(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
spi_write_command(SSD1331_CMD_PRECHARGEA); // 0x8A
spi_write_command(0x64);
spi_write_command(SSD1331_CMD_PRECHARGEB); // 0x8B
spi_write_command(0x78);
spi_write_command(SSD1331_CMD_PRECHARGEA); // 0x8C
spi_write_command(0x64);
spi_write_command(SSD1331_CMD_PRECHARGELEVEL); // 0xBB
spi_write_command(0x3A);
spi_write_command(SSD1331_CMD_VCOMH); // 0xBE
spi_write_command(0x3E);
spi_write_command(SSD1331_CMD_MASTERCURRENT); // 0x87
spi_write_command(0x06);
spi_write_command(SSD1331_CMD_CONTRASTA); // 0x81
spi_write_command(0x91);
spi_write_command(SSD1331_CMD_CONTRASTB); // 0x82
spi_write_command(0x50);
spi_write_command(SSD1331_CMD_CONTRASTC); // 0x83
spi_write_command(0x7D);
spi_write_command(SSD1331_CMD_DISPLAYON); //--turn on oled panel
if(Option->DISPLAY_ORIENTATION&1){
HRes=HorizontalRes;
VRes=VerticalRes;
} else {
VRes=HorizontalRes;
HRes=VerticalRes;
}

//Set the DrawRectangle vector to point to our function
DrawRectangleVector= (unsigned int)&DrawRectangleSPI + libAddr;

//Set the DrawBitmap vector to point to our function
DrawBitmapVector=(unsigned int)&DrawBitmapSPI + libAddr;

#ifdef MX470
DrawBufferVector=(unsigned int)&DrawBufferSPI + libAddr;
#endif
//CLS
DrawRectangle(0,0,HRes-1,VRes-1,0x000000);
SPIBRG=brgsave; //restore user (or my) setup
SPICON=consave;
SPICON2=con2save;
static const char startup[]="SSD1331 driver loaded\r\n";
pstring(startup);
}
Edited by matherp 2019-01-19
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 971
Posted: 12:30pm 21 Jan 2019
Copy link to clipboard 
Print this post

I have added this LCD panel to the table I have been creating on the Fruit of the Shed wiki. This page is an attempt to identify and link to the various TBS posts about LCDPANEL drivers available for the various MMBasic platforms.


LCD Panel Summary

Regards
Gerry
Latest F4 Latest H7 FotS
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025