You’re just everywhere today (and very helpful).
My image was 2.3 MB and on this windows install I didn’t have any tools for resizing besides paint, so I figured the imgur would be ok. Noted for the future.
By the way, if anyone ever needs to talk to a SSD1325 (as is in a NH 2.7" OLED), the current iteration of the library for SPI is ported and attached, though I will be looking at RLP next weekend for the display write per your comment in my other thread. The non SPI code is tested and doesn’t work currently. I suspect it’s a write speed issue or something. SPI is better anyway- less pins and it can write the whole display about as fast as you can blink.
Clock.cs:
//#define LargeHeap
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
using BTrotter_DotNetMF_Libs;
namespace BTrotter_DotNetMF_Clock
{
public class Program
{
public static OutputPort led;
public static InputPort btn;
public static void btnWait()
{
// wait until unpressed
while (!btn.Read())
{
Thread.Sleep(1);
}
// wait until pressed
while (btn.Read())
{
Thread.Sleep(1);
}
}
public static void Main()
{
#if LargeHeap
// http://wiki.tinyclr.com/index.php?title=Custom_Heap
// set the heap size to 4MB
if (Configuration.Heap.SetCustomHeapSize(4 * 1024 * 1024))
{
// this will only take effect after resetting the system
PowerState.RebootDevice(false);
}
// ...
// you can now use large objects up to 4MB
// allocate a 1MB buffer
//LargeBuffer lb = new LargeBuffer(1024 * 1024);
// use the buffer
//lb.Bytes[5] = 123;
// ....
// when done, dispose the object to empty the memory
//lb.Dispose();
#endif
// no TFT
GHIElectronics.NETMF.Hardware.Configuration.LCD.Set(GHIElectronics.NETMF.Hardware.Configuration.LCD.HeadlessConfig);
led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
btn = new InputPort((Cpu.Pin)GHIElectronics.NETMF.FEZ.FEZ_Pin.Digital.ButtonDown, true, Port.ResistorMode.PullUp);
led.Write(false);
NH2_7.initPorts();
NH2_7.OLED_12864_Init();
led.Write(true);
Bitmap bmp = new Bitmap(128, 64);
Font font = Resources.GetFont(Resources.FontResources.NinaB);
bmp.DrawText("12:00", font, Microsoft.SPOT.Presentation.Media.Color.White, 0, 0);
while (true)
{
NH2_7.Checkerboard_12864();
btnWait();
NH2_7.Grayscale_12864();
btnWait();
NH2_7.DrawBitmap(ref bmp);
btnWait();
}
}
}
}
NH2_7.cs:
#define UseSPI
using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Presentation;
using GHIElectronics.NETMF.FEZ;
namespace BTrotter_DotNetMF_Libs
{
public sealed class NH2_7
{
public const byte Max_Column = 0x3F; // 128/2-1 (Total Columns Devided by 2)
public const byte Max_Row = 0x3F; // 64-1
public const byte Brightness = 0x7F;
//--------------------------------------------------------------------------
// Core Hardware Support for FEZ Cobra
//--------------------------------------------------------------------------
#if UseSPI
/**
* 1 -> ground
* 2 -> VDD
* 3 NC
* 4- CMD/DATA (0/1) IO49
* 5,6 -> must ground
* 7 -> SCLK IO27
* 8 -> SDIN IO24
* 10-14 -> optional(?) ground
* 16 -> /res IO28
* 17 -> /CS IO50
* 18 NC
* 19 -> must ground
* 20 -> must ground
*
* rising edge of SCLK
* positive logic
* MSB first
*/
public static SPI spi;
public static OutputPort spiCMD_Data;
public static OutputPort resControl; // active low
public static void initPorts()
{
resControl = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO28, true); // default to asserted
SPI.Configuration spiconfig = new SPI.Configuration(
(Cpu.Pin)FEZ_Pin.Digital.IO50, // CS line
false, // CS active low
0, // CS setup time in ms
0, // CS hold time (after data) in ms
true, // clock idle high
true, // sample on rising edge
4000, // 4000 KHz = 4 MHz
SPI.SPI_module.SPI1 // spans IO 24 => SPI out, 25 => SPI in, 27 => SCLK
);
spi = new SPI(spiconfig);
spiCMD_Data = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO49, true); // default to data
}
public static void Send(ref byte[] data, bool cmd)
{
spiCMD_Data.Write(!cmd); // 0 = command, 1 = data
spi.Write(data);
}
public static void Send(byte data, bool cmd)
{
spiCMD_Data.Write(!cmd); // 0 = command, 1 = data
spi.Write(new byte[] { data });
}
public static void shutdown()
{
resControl.Write(false); // reset on
spi.Dispose();
spiCMD_Data.Write(true); // data mode
}
#else
///
/// <summary>GPIOC bank index</summary>
///
public enum ControlPin : int
{
RES = 0, // RESET active low
CS1 = 1, // CHIP SELECT active low
RDWR = 2, // R/W, 1 = read, 0 = write
ENA = 3, // OPERATION ENABLE 1->0 start read/write
DC = 4 // COMMAND/DATA 0 = command, 1 = data
}
public const bool InitialState_RES = false; // false = active
public const bool InitialState_CS1 = true; // true = inactive
public const bool InitialState_ENA = true; // high = inactive
public const bool InitialState_DC = true; // true = data
public const bool InitialState_RW = true; // true = read
///
///<summary>Control Pins</summary>
///
public static OutputPort[] GPIOC;
///
///<summary>Data Pins</summary>
///
public static OutputPort[] GPIOB;
public static void GPIO_WriteMSB(byte data)
{
byte x = 128;
for (int i = 7; i >= 0; i--)
{
bool onoff = ((data & x) > 0);
GPIOB[i].Write(onoff);
// D: 7 6 5 4 3 2 1 0
// 128 64 32 16 8 4 2 1
x /= 0x2;
}
}
public static void GPIO_WriteLSB(byte data)
{
byte x = 1;
for (int i = 0; i < 8; i++)
{
GPIOB[i].Write((data & x) > 0);
// D: 7 6 5 4 3 2 1 0
// 128 64 32 16 8 4 2 1
x *= 0x2;
}
}
public static void GPIO_ResetControlBits(int pin)
{
GPIOC[pin].Write(false);
}
public static void GPIO_SetControlBits(int pin)
{
GPIOC[pin].Write(true);
}
public static void initPorts()
{
GPIOC = new OutputPort[5]; // need 5 pins here for control
GPIOB = new OutputPort[8]; // need 8 pins here for data
// Init Control Pins
GPIOC[(int)ControlPin.DC] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO15, InitialState_DC);
GPIOC[(int)ControlPin.RDWR] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO16, InitialState_RW);
GPIOC[(int)ControlPin.ENA] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO17, InitialState_ENA);
GPIOC[(int)ControlPin.CS1] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO18, InitialState_CS1);
GPIOC[(int)ControlPin.RES] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO19, InitialState_RES);
// Init Data Pins
GPIOB[7] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO32, false);
GPIOB[6] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO31, false);
GPIOB[5] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO30, false);
GPIOB[4] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO29, false);
GPIOB[3] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO28, false);
GPIOB[2] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO27, false);
GPIOB[1] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO25, false);
GPIOB[0] = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.IO24, false);
}
public static void shutdown()
{
// clear control pins to initial state
GPIOC[(int)ControlPin.RES].Write(InitialState_RES);
GPIOC[(int)ControlPin.CS1].Write(InitialState_CS1);
GPIOC[(int)ControlPin.ENA].Write(InitialState_ENA);
GPIOC[(int)ControlPin.DC].Write(InitialState_DC);
GPIOC[(int)ControlPin.RDWR].Write(InitialState_RW);
// clear data pins
for (int i = 0; i < 8; i++)
{
GPIOB[i].Write(false);
}
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
public static void oled_Command(byte Data)
{
GPIO_Write(Data);//6800 mode
GPIO_ResetControlBits((int)ControlPin.DC); // set command
GPIO_ResetControlBits((int)ControlPin.CS1); // select chip
GPIO_ResetControlBits((int)ControlPin.RDWR); // write
GPIO_SetControlBits((int)ControlPin.ENA); // set up for 1->0 transition
//OLED_uDelay(1); // 100 usec = 0.1 msec
Thread.Sleep(1);
GPIO_ResetControlBits((int)ControlPin.ENA); // transition to 0, enable
//OLED_uDelay(1); // 100 usec = 0.1 msec
Thread.Sleep(1);
GPIO_SetControlBits((int)ControlPin.RDWR); // switch to read
GPIO_SetControlBits((int)ControlPin.CS1); // de-select
GPIO_SetControlBits((int)ControlPin.DC); // switch to data mode
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
public static void oled_Data(byte Data)
{
GPIO_Write(Data);//6800 mode
GPIO_SetControlBits((int)ControlPin.DC); // set data
GPIO_ResetControlBits((int)ControlPin.CS1); // select chip
GPIO_ResetControlBits((int)ControlPin.RDWR); // write
GPIO_SetControlBits((int)ControlPin.ENA); // set up for 1->0 transition
//OLED_uDelay(100); // 100 usec = 0.1 msec
Thread.Sleep(1);
GPIO_ResetControlBits((int)ControlPin.ENA); // transition to 0, enable
//OLED_uDelay(100); // 100 usec = 0.1 msec
Thread.Sleep(1);
GPIO_SetControlBits((int)ControlPin.RDWR); // switch to read
GPIO_SetControlBits((int)ControlPin.CS1); // de-select
GPIO_SetControlBits((int)ControlPin.DC); // stay in data mode
}
#endif
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Instruction Setting
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Set_Column_Address_12864(byte a, byte b)
{
#if UseSPI
byte[] cmd = new byte[] {0x15, a, b};
Send(ref cmd, true);
#else
oled_Command(0x15); // Set Column Address
oled_Command(a); // Default => 0x00
oled_Command(b); // Default => 0x3F (Total Columns Divided by 2)
#endif
}
public static void Set_Row_Address_12864(byte a, byte b)
{
#if UseSPI
byte[] cmd = new byte[] { 0x75, a, b };
Send(ref cmd, true);
#else
oled_Command(0x75); // Set Row Address
oled_Command(a); // Default => 0x00
oled_Command(b); // Default => 0x4F
#endif
}
public static void Set_Contrast_Current_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] {0x81, d};
Send(ref cmd, true);
#else
oled_Command(0x81); // Set Contrast Value
oled_Command(d); // Default => 0x40
#endif
}
public static void Set_Current_Range_12864(byte d)
{
// oled_Command(0x84|d);
Send((byte) (0x84 | d), true); // Set Current Range
// Default => 0x84
// 0x84 (0x00) => Quarter Current Range
// 0x85 (0x01) => Half Current Range
// 0x86 (0x02) => Full Current Range
}
public static void Set_Remap_Format_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xA0, d };
Send(ref cmd, true);
#else
oled_Command(0xA0); // Set Re-Map & Data Format
oled_Command(d); // Default => 0x00
// Column Address 0 Mapped to SEG0
// Disable Nibble Re-Map
// Horizontal Address Increment
// Scan from COM0 to COM[N-1]
// Disable COM Split Odd Even
#endif
}
public static void Set_Start_Line_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xA1, d };
Send(ref cmd, true);
#else
oled_Command(0xA1); // Set Display Start Line
oled_Command(d); // Default => 0x00
#endif
}
public static void Set_Display_Offset_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xA2, d };
Send(ref cmd, true);
#else
oled_Command(0xA2); // Set Display Offset
oled_Command(d); // Default => 0x00
#endif
}
public static void Set_Display_Mode_12864(byte d)
{
// oled_Command(0xA4|d);
#if UseSPI
Send((byte)(0xA4 | d), true); // Set Display Mode
#else
oled_Command((byte)(0xA4 | d)); // Set Display Mode
#endif
// Default => 0xA4
// 0xA4 (0x00) => Normal Display
// 0xA5 (0x01) => Entire Display On, All Pixels Turn On at GS Level 15
// 0xA6 (0x02) => Entire Display Off, All Pixels Turn Off
// 0xA7 (0x03) => Inverse Display
}
public static void Set_Multiplex_Ratio_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xA8, d };
Send(ref cmd, true);
#else
oled_Command(0xA8); // Set Multiplex Ratio
oled_Command(d); // Default => 0x5F
#endif
}
public static void Set_Master_Config_12864(byte d)
{
// oled_Command(0x02|d);
#if UseSPI
byte[] cmd = new byte[] { 0xAD, (byte)(0x02 | d) };
Send(ref cmd, true);
#else
oled_Command(0xAD); // Set Master Configuration
oled_Command((byte)(0x02 | d)); // Default => 0x03
// 0x02 (0x00) => Select External VCC Supply
// 0x03 (0x01) => Select Internal DC/DC Voltage Converter
#endif
}
public static void Set_Display_On_Off_12864(byte d)
{
// oled_Command(0xAE|d);
#if UseSPI
Send((byte)(0xAE | d), true); // Set Display On/Off
#else
oled_Command((byte)(0xAE | d)); // Set Display On/Off
#endif
// Default => 0xAE
// 0xAE (0x00) => Display Off
// 0xAF (0x01) => Display On
}
public static void Set_Phase_Length_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xB1, d };
Send(ref cmd, true);
#else
oled_Command(0xB1); // Phase 1 & 2 Period Adjustment
oled_Command(d); // Default => 0x53 (5 Display Clocks [Phase 2] / 3 Display Clocks [Phase 1])
// D[3:0] => Phase 1 Period in 1~15 Display Clocks
// D[7:4] => Phase 2 Period in 1~15 Display Clocks
#endif
}
public static void Set_Frame_Frequency_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xB2, d };
Send(ref cmd, true);
#else
oled_Command(0xB2); // Set Frame Frequency (Row Period)
oled_Command(d); // Default => 0x25 (37 Display Clocks)
#endif
}
public static void Set_Display_Clock_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xB3, d };
Send(ref cmd, true);
#else
oled_Command(0xB3); // Display Clock Divider/Osciallator Frequency
oled_Command(d); // Default => 0x41
// D[3:0] => Display Clock Divider
// D[7:4] => Oscillator Frequency
#endif
}
public static void Set_Precharge_Compensation_12864(byte a, byte b = 0)
{
// oled_Command(0x08|a);
#if UseSPI
byte[] cmd;
if (a == 0x20) cmd = new byte[] { 0xB4, b, 0xB0, (byte)(0x08 | a) };
else cmd = new byte[] { 0xB4, b };
Send(ref cmd, true);
#else
oled_Command(0xB4); // Set Pre-Charge Compensation Level
oled_Command(b); // Default => 0x00 (No Compensation)
if (a == 0x20)
{
oled_Command(0xB0); // Set Pre-Charge Compensation Enable
oled_Command((byte) (0x08 | a)); // Default => 0x08
// 0x08 (0x00) => Disable Pre-Charge Compensation
// 0x28 (0x20) => Enable Pre-Charge Compensation
}
#endif
}
public static void Set_Precharge_Voltage_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xBC, d };
Send(ref cmd, true);
#else
oled_Command(0xBC); // Set Pre-Charge Voltage Level
oled_Command(d); // Default => 0x10 (Connect to VCOMH)
#endif
}
public static void Set_VCOMH_12864(byte d)
{
#if UseSPI
byte[] cmd = new byte[] { 0xBE, d };
Send(ref cmd, true);
#else
oled_Command(0xBE); // Set Output Level High Voltage for COM Signal
oled_Command(d); // Default => 0x1D (0.81*VREF)
#endif
}
public static void Set_VSL_12864(byte d)
{
//oled_Command(0x02|d);
#if UseSPI
byte[] cmd = new byte[] { 0xBF, (byte)(0x02 | d) };
Send(ref cmd, true);
#else
oled_Command(0xBF); // Set Segment Low Voltage Level
oled_Command((byte)(0x02 | d)); // Default => 0x0E
// 0x02 (0x00) => Keep VSL Pin Floating
// 0x0E (0x0C) => Connect a Capacitor between VSL Pin & VSS
#endif
}
public static void GA_Option_12864(bool enabled)
{
byte d = (byte)(enabled ? 0x01 : 0x00);
#if UseSPI
byte[] cmd = new byte[] { 0x23, d };
Send(ref cmd, true);
#else
oled_Command(0x23); // Graphic Acceleration Command Options
oled_Command(d); // Default => 0x01
// Enable Fill Rectangle
// Disable Wrap around in Horizontal Direction During Copying & Scrolling
// Disable Reverse Copy
#endif
}
public static void Draw_Rectangle_12864(byte startCol, byte endCol, byte startRow, byte endRow, byte level)
{
#if UseSPI
byte[] cmd = new byte[] { 0x24, startCol, startRow, endCol, endRow, level };
Send(ref cmd, true);
#else
oled_Command(0x24); // Draw Rectangle
oled_Command(startCol); // Column Address of Start
oled_Command(startRow); // Row Address of Start
oled_Command(endCol); // Column Address of End (Total Columns Devided by 2)
oled_Command(endRow); // Row Address of End
oled_Command(level); // Gray Scale Level
#endif
//OLED_uDelay(200);
Thread.Sleep(1);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Regular Pattern (Full Screen)
//
// a: Two Pixels Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Fill_RAM_12864(byte fill)
{
GA_Option_12864(true);
// fill a rectangle covering the whole screen with fill value
Draw_Rectangle_12864(0x00, 0x3F, 0x00, 0x5F, fill);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Regular Pattern (Partial or Full Screen)
//
// a: Column Address of Start
// b: Column Address of End (Total Columns Devided by 2)
// c: Row Address of Start
// d: Row Address of End
// e: Two Pixels Data
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Fill_Block_12864(byte startCol, byte endCol, byte startRow, byte endRow, byte level)
{
GA_Option_12864(true);
Draw_Rectangle_12864(startCol, endCol, startRow, endRow, level);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Checkboard (Full Screen)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Checkerboard_12864()
{
Set_Column_Address_12864(0x00, 0x3F);
Set_Row_Address_12864(0x00, 0x5F);
#if UseSPI
byte[] d = new byte[5120];
int offset = 0;
for (int i = 0; i < 40; i++)
{
for (int j = 0; j < 64; j++)
{
d[offset++] = 0xF0;
}
for (int j = 0; j < 64; j++)
{
d[offset++] = 0x0F;
}
}
Send(ref d, false);
#else
for (int i = 0; i < 40; i++)
{
for (int j = 0; j < 64; j++)
{
oled_Data(0xF0);
}
for (int j = 0; j < 64; j++)
{
oled_Data(0x0F);
}
}
#endif
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Gray Scale Bar (Full Screen)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Grayscale_12864()
{
// Level 16 => Column 1~8
Fill_Block_12864(0x00, 0x03, 0x00, 0x3F, 0xFF);
// Level 15 => Column 9~16
Fill_Block_12864(0x04, 0x07, 0x00, 0x3F, 0xEE);
// Level 14 => Column 17~24
Fill_Block_12864(0x08, 0x0B, 0x00, 0x3F, 0xDD);
// Level 13 => Column 25~32
Fill_Block_12864(0x0C, 0x0F, 0x00, 0x3F, 0xCC);
// Level 12 => Column 33~40
Fill_Block_12864(0x10, 0x13, 0x00, 0x3F, 0xBB);
// Level 11 => Column 41~48
Fill_Block_12864(0x14, 0x17, 0x00, 0x3F, 0xAA);
// Level 10 => Column 49~56
Fill_Block_12864(0x18, 0x1B, 0x00, 0x3F, 0x99);
// Level 9 => Column 57~64
Fill_Block_12864(0x1C, 0x1F, 0x00, 0x3F, 0x88);
// Level 8 => Column 65~72
Fill_Block_12864(0x20, 0x23, 0x00, 0x3F, 0x77);
// Level 7 => Column 73~80
Fill_Block_12864(0x24, 0x27, 0x00, 0x3F, 0x66);
// Level 6 => Column 81~88
Fill_Block_12864(0x28, 0x2B, 0x00, 0x3F, 0x55);
// Level 5 => Column 89~96
Fill_Block_12864(0x2C, 0x2F, 0x00, 0x3F, 0x44);
// Level 4 => Column 97~104
Fill_Block_12864(0x30, 0x33, 0x00, 0x3F, 0x33);
// Level 3 => Column 105~112
Fill_Block_12864(0x34, 0x37, 0x00, 0x3F, 0x22);
// Level 2 => Column 113~120
Fill_Block_12864(0x38, 0x3B, 0x00, 0x3F, 0x11);
// Level 1 => Column 121~128
Fill_Block_12864(0x3C, 0x3F, 0x00, 0x3F, 0x00);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Character (5x7)
//
// a: Database
// b: Ascii
// c: Start X Address
// d: Start Y Address
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*
public static void Show_Font57_12864(byte db, byte asc, byte startX, byte startY)
{
byte *Src_Pointer=0;
byte i,Font,MSB,LSB;
switch(db)
{
case 1:
Src_Pointer=&Ascii_1[(asc-1)][0];
break;
case 2:
//Src_Pointer=&Ascii_2[(b-1)][0];
break;
}
Set_Remap_Format_12864(0x54);
for(i=0;i<=4;i+=2)
{
LSB=*Src_Pointer;
Src_Pointer++;
if(i == 4)
{
MSB=0x00;
}
else
{
MSB=*Src_Pointer;
Src_Pointer++;
}
Set_Column_Address_12864(startX,startX);
Set_Row_Address_12864(startY,startY+7);
Font=((MSB&0x01)<<4)|(LSB&0x01);
Font=Font|(Font<<1)|(Font<<2)|(Font<<3);
oled_Data(Font);
Font=((MSB&0x02)<<3)|((LSB&0x02)>>1);
Font=Font|(Font<<1)|(Font<<2)|(Font<<3);
oled_Data(Font);
Font=((MSB&0x04)<<2)|((LSB&0x04)>>2);
Font=Font|(Font<<1)|(Font<<2)|(Font<<3);
oled_Data(Font);
Font=((MSB&0x08)<<1)|((LSB&0x08)>>3);
Font=Font|(Font<<1)|(Font<<2)|(Font<<3);
oled_Data(Font);
Font=((MSB&0x10)<<3)|((LSB&0x10)>>1);
Font=Font|(Font>>1)|(Font>>2)|(Font>>3);
oled_Data(Font);
Font=((MSB&0x20)<<2)|((LSB&0x20)>>2);
Font=Font|(Font>>1)|(Font>>2)|(Font>>3);
oled_Data(Font);
Font=((MSB&0x40)<<1)|((LSB&0x40)>>3);
Font=Font|(Font>>1)|(Font>>2)|(Font>>3);
oled_Data(Font);
Font=(MSB&0x80)|((LSB&0x80)>>4);
Font=Font|(Font>>1)|(Font>>2)|(Font>>3);
oled_Data(Font);
startX++;
}
Set_Remap_Format_12864(0x50);
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show String
//
// a: Database
// b: Start X Address
// c: Start Y Address
// * Must write "0" in the end...
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Show_String_12864(byte db, byte *Data_Pointer, byte startX, byte startY)
{
byte *Src_Pointer;
Src_Pointer=Data_Pointer;
Show_Font57_12864(1,96,startX,startY); // No-Break Space
// Must be written first before the string start...
while(true)
{
Show_Font57_12864(db,*Src_Pointer,startX,startY);
Src_Pointer++;
startX+=3;
if(*Src_Pointer == 0) break;
}
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Show Pattern (Partial or Full Screen)
//
// a: Column Address of Start
// b: Column Address of End (Total Columns Divided by 2)
// c: Row Address of Start
// d: Row Address of End
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Show_Pattern_12864(byte *Data_Pointer, byte a, byte b, byte c, byte d)
{
byte *Src_Pointer;
byte i,j;
Src_Pointer=Data_Pointer;
Set_Column_Address_12864(a,b);
Set_Row_Address_12864(c,d);
for(i=0;i<(d-c+1);i++)
{
for(j=0;j<(b-a+1);j++)
{
oled_Data(*Src_Pointer);
Src_Pointer++;
}
}
}
*/
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Vertical Scrolling (Full Screen)
//
// a: Scrolling Direction
// "0x00" (Upward)
// "0x01" (Downward)
// b: Set Numbers of Row Scroll per Step
// c: Set Time Interval between Each Scroll Step
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void Set_Gray_Scale_Table_12864()
{
#if UseSPI
byte[] cmd = new byte[] { 0xB8, 0x01, 0x11, 0x22, 0x32, 0x43, 0x54, 0x65, 0x76 };
Send(ref cmd, true);
#else
oled_Command(0xB8); // Set Gray Scale Table
oled_Command(0x01); // Gray Scale Level 1
oled_Command(0x11); // Gray Scale Level 3 & 2
oled_Command(0x22); // Gray Scale Level 5 & 4
oled_Command(0x32); // Gray Scale Level 7 & 6
oled_Command(0x43); // Gray Scale Level 9 & 8
oled_Command(0x54); // Gray Scale Level 11 & 10
oled_Command(0x65); // Gray Scale Level 13 & 12
oled_Command(0x76); // Gray Scale Level 15 & 14
#endif
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Initialization
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
public static void OLED_12864_Init()
{
#if UseSPI
resControl.Write(false); // set reset
#else
GPIO_ResetControlBits((int)ControlPin.RES); // set reset
#endif
// original delay = 201*200=40200 usec = 40.2 msec
/*
for(i=0;i<200;i++)
{
OLED_uDelay(200);
}
*/
Thread.Sleep(41); // stay in reset 40.2 ms
#if UseSPI
resControl.Write(true); // come out of reset
#else
GPIO_SetControlBits((int)ControlPin.RES); // come out of reset
#endif
Set_Display_On_Off_12864(0x00); // Display Off (0x00/0x01)
Set_Display_Clock_12864(0x91); // Set Clock as 135 Frames/Sec
Set_Multiplex_Ratio_12864(0x3F); // 1/64 Duty (0x0F~0x5F)
Set_Display_Offset_12864(0x4C); // Shift Mapping RAM Counter (0x00~0x5F)
Set_Start_Line_12864(0x00); // Set Mapping RAM Display Start Line (0x00~0x5F)
Set_Master_Config_12864(0x00); // Disable Embedded DC/DC Converter (0x00/0x01)
Set_Remap_Format_12864(0x50); // Set Column Address 0 Mapped to SEG0
// Disable Nibble Remap
// Horizontal Address Increment
// Scan from COM[N-1] to COM0
// Enable COM Split Odd Even
Set_Current_Range_12864(0x02); // Set Full Current Range
Set_Gray_Scale_Table_12864(); // Set Pulse Width for Gray Scale Table
Set_Contrast_Current_12864(Brightness); // Set Scale Factor of Segment Output Current Control
Set_Frame_Frequency_12864(0x51); // Set Frame Frequency
Set_Phase_Length_12864(0x55); // Set Phase 1 as 5 Clocks & Phase 2 as 5 Clocks
Set_Precharge_Voltage_12864(0x10); // Set Pre-Charge Voltage Level
Set_Precharge_Compensation_12864(0x20, 0x02); // Set Pre-Charge Compensation
Set_VCOMH_12864(0x1C); // Set High Voltage Level of COM Pin
Set_VSL_12864(0x0D); // Set Low Voltage Level of SEG Pin
Set_Display_Mode_12864(0x00); // Normal Display Mode (0x00/0x01/0x02/0x03)
Fill_RAM_12864(0x00); // Clear Screen
Set_Display_On_Off_12864(0x01); // Display On (0x00/0x01)
}
public static byte[] BitmapToGray4(ref Bitmap bmp)
{
// barf for bad bitmaps
if ((bmp.Width > 128) || (bmp.Height > 64)) return (new byte[]{});
byte[] bmpData = bmp.GetBitmap(); // 64 * 128 * 4 channels * 8 bits = 32768 bytes RGBA
int inOffset = 0;
int outOffset = 0;
byte[] retval = new byte[8192]; // 64 * 128 bytes
byte r,g,b;
for (int y = 0; y < 64; y++)
{
for (int x = 0; x < 128; x++)
{
r = bmpData[inOffset++];
g = bmpData[inOffset++];
b = bmpData[inOffset++];
//a = bmpData[inOffset++];
inOffset++; // skip a
// convert to 4 bit grayscale
retval[outOffset++] = (byte)(((((float)r) * .30) + (((float)g) * .59) + (((float)b) * .11)) / 16.0);
}
}
return retval;
}
public static byte[] BitmapDoubleStuff(ref byte[] bitmapData)
{
// only accept 128x64
if (bitmapData.Length != 8192) return (new byte[] {});
byte[] retval = new byte[4096];
int offset = 0;
bool highNIB = false;
byte last = 0;
// data is arranged in rows bytes 0 - 127 = r0c0-c127, bytes 128-255 = r1c0-c127
for (int y = 0; y < 64; y++)
{
for (int x = 0; x < 128; x++)
{
if (!highNIB) {
last = (byte) (bitmapData[(y * 128) + x] & 0x0F);
highNIB = true;
}
else
{
retval[offset++] = (byte)(((bitmapData[(y * 128) + x] & 0x0F) << 4) | last);
highNIB = false;
}
}
}
return retval;
}
public static void DrawBitmap(ref Bitmap bmp)
{
byte[] bmpData = bmp.GetBitmap(); // 64 * 128 * 4 channels * 8 bits = 32768 bytes RGBA
byte[] retval = new byte[4096];
int inOffset = 0;
int outOffset = 0;
float tmpF = 0;
int tmpI = 0;
byte gray;
bool highNIB = false;
byte grayLast = 0;
// barf for bad bitmaps
if ((bmp.Width > 128) || (bmp.Height > 64)) return;
// go top top left corner
Set_Column_Address_12864(0x00, 0x3F);
Set_Row_Address_12864(0x00, 0x7F);
while (inOffset<32768) {
// convert to 4 bit grayscale
//gray = (byte)(((((float)bmpData[inOffset++]) * .30) + (((float)bmpData[inOffset++]) * .59) + (((float)bmpData[inOffset++]) * .11)) / 16.0);
//gray = (byte)(((float)bmpData[inOffset++] + (float)bmpData[inOffset++] + (float)bmpData[inOffset++]) / 48.0);
for (tmpF = 0, tmpI = 0; tmpI < 3; tmpI++)
{
tmpF += bmpData[inOffset++];
}
gray = (byte)(tmpF / 48.0);
inOffset++; // skip a
if (!highNIB)
{
grayLast = (byte)(gray & 0x0F);
highNIB = true;
}
else
{
retval[outOffset++] = ((byte)(((gray & 0x0F) << 4) | grayLast));
highNIB = false;
}
}
bmpData = new byte[] { }; // free mem
Send(ref retval, false);
return;
}
public static void DrawBitmap(ref byte[] bitmapData)
{
// only accept 128x64 already stuffed
if (bitmapData.Length != 4096) return;
Fill_RAM_12864(0x00); // Clear Screen
// go top top left corner
Set_Column_Address_12864(0x00, 0x3F);
Set_Row_Address_12864(0x00, 0x7F);
Send(ref bitmapData, false);
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Demonstration
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*
public int oled_12864()
{
OLED_12864_Init();
Set_Column_Address_12864(0x00,0x3F);
Set_Row_Address_12864(0x00,0x3F);
int counter = 0;
int datum;
byte[] Buff;
for(int i=0;i<64;i++){ //these loops expand the bitmap data because the bmp file is monochrome image (only ON or OFF, no grayscale)
for(int j=0;j<16;j++){
datum = Buff[counter];
datum = ((datum >> 6) & 0x03);//move over and mask the highest 2 bits
if(datum == 0x03){oled_Data(0xFF);}//if both bits are high, send 0xFF to OLED
else if(datum == 0x02){oled_Data(0x0F);}//if one bit is high, send 0x0F to OLED
else if(datum == 0x01){oled_Data(0xF0);}
else oled_Data(0x00);//if neither bit is high, send 0x00 to OLED
datum = Buff[counter];
datum = ((datum >> 4) & 0x03);//move over and mask the 3&4th bits
if(datum == 0x03){oled_Data(0xFF);}
else if(datum == 0x02){oled_Data(0x0F);}
else if(datum == 0x01){oled_Data(0xF0);}
else oled_Data(0x00);
datum = Buff[counter];
datum = ((datum >> 2) & 0x03);//move over and mask the 5&6th bits
if(datum == 0x03){oled_Data(0xFF);}
else if(datum == 0x02){oled_Data(0x0F);}
else if(datum == 0x01){oled_Data(0xF0);}
else oled_Data(0x00);
datum = Buff[counter];
datum = (datum & 0x03);//mask the lowest 2 bits
if(datum == 0x03){oled_Data(0xFF);}
else if(datum == 0x02){oled_Data(0x0F);}
else if(datum == 0x01){oled_Data(0xF0);}
else oled_Data(0x00);
counter++;
}
}
return 1;
}
*/
}
}