Jump to content
Javascript Disabled Detected
You currently have javascript disabled. Several functions may not work. Please re-enable javascript to access full functionality.
The Netduino forums have been replaced by new forums at
community.wildernesslabs.co .
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
netduino driver for the AdaFruit SSD1306 OLED display
Started by
Fabien Royer
, Jan 17 2011 06:50 AM
12 replies to this topic
#1
Fabien Royer
Posted 17 January 2011 - 06:50 AM
Back in January, I adapted the Arduino driver written by Limor Fried for the SSD1306 monochrome OLED display to the netduino.
At the time, I could not figure out why I was unable to communicate with the display over hardware SPI and had resorted to bit banging data, which was quite slow. Last night, I revisited the driver and figured out the issue I had in January. I overhauled the code which now works properly @ 40 MHz using hardware SPI.
http://www.youtube.com/watch?v=kzfLVBSOO_I
The driver and the sample code is located here .
Cheers,
-Fabien.
Edited by Fabien Royer, 01 June 2011 - 04:17 PM.
#2
Fabien Royer
Posted 01 June 2011 - 04:18 PM
Bump!
#3
Stefan
Stefan
Location Breda, the Netherlands
Posted 01 June 2011 - 04:37 PM
subtle bumb
Nice work, didn't see it before. Fabien, perhaps you could add your drivers to the wiki as well? It will be better archived then on a forum.
#4
Fabien Royer
Posted 01 June 2011 - 06:18 PM
Hi Stephan,
The repository for the drivers is here:
http://netduinohelpers.codeplex.com/
I believe that it would be preferable to reference the codeplex repository in the Wiki instead of actually checking code in a Wiki.
Cheers,
-Fabien.
#5
Stefan
Stefan
Location Breda, the Netherlands
Posted 01 June 2011 - 06:21 PM
Hi Stephan,
Who?
I believe that it would be preferable to reference the codeplex repository in the Wiki instead of actually checking code in a Wiki.
Absolutely, that was what I ment
By the way, I see that repository is ment for generic Netduino libraries, am I right?
#6
Fabien Royer
Posted 01 June 2011 - 07:07 PM
Who?
Oops! Sorry
Stefan
By the way, I see that repository is ment for generic Netduino libraries, am I right?
Yes, the netduino.helpers library is generally designed to work with all netduino SKUs, with few exceptions.
-Fabien.
#7
Fabien Royer
Posted 01 June 2011 - 07:57 PM
FYI, I just added a starter Wiki page for netduino libraries:
http://wiki.netduino...-libraries.ashx
Cheers,
-Fabien.
#8
Stefan
Stefan
Location Breda, the Netherlands
Posted 01 June 2011 - 09:06 PM
Thanks
#9
dino4net
Posted 04 November 2013 - 04:37 PM
public const int Width = 128; public const int Height = 32; private const int I2CTransactionTimeout = 1000; // ms public AdaFruitSSD1306(ushort I2C_ADDRESS = 0x3C, int I2C_ClockRateKHz = 400, Cpu.Pin reset = (Cpu.Pin) 54) { AutoRefreshScreen = false; I2c = new I2CDevice.Configuration(I2C_ADDRESS, I2C_ClockRateKHz); //SoftwareI2CBus i2cbus = new SoftwareI2CBus(SecretLabs.NETMF.Hardware.Netduino.Pins.GPIO_PIN_A4, SecretLabs.NETMF.Hardware.Netduino.Pins.GPIO_PIN_A5); //I2c = i2cbus.CreateI2CDevice(new I2CDevice.Configuration(0x3C, I2CTransactionTimeout)); //Connect the RST pin of the display to this Netduino pin resetPin = new OutputPort(SecretLabs.NETMF.Hardware.NetduinoPlus.Pins.GPIO_PIN_D10, false); //resetPin = new OutputPort(reset, false); } protected void SendCommand(Command cmd) { SpiBuffer[0] = (byte)cmd; if (Spi != null) Spi.Write(SpiBuffer); if (I2c != null) { I2CBus.GetInstance().Write(I2c, new byte[] {0x00, (byte)cmd}, I2CTransactionTimeout); } } public void InvertDisplay(bool cmd) { if (Spi != null) dcPin.Write(DisplayCommand); if (cmd) { SendCommand(Command.INVERTDISPLAY); } else { SendCommand(Command.NORMALDISPLAY); } if (Spi != null) dcPin.Write(Data); } public virtual void Refresh() { if (Spi != null) Spi.Write(displayBuffer); else if (I2c != null) { byte[] I2CCommand = new byte[displayBuffer.Length + 1]; I2CCommand[0] = 0x40; Array.Copy(displayBuffer, 0, I2CCommand, 1, displayBuffer.Length); I2CBus.GetInstance().Write(I2c, I2CCommand, I2CTransactionTimeout); } } public void Initialize(VccType vcctype = VccType.SWITCHCAPVCC) { if (Spi != null) { resetPin.Write(true); Thread.Sleep(1); // VDD (3.3V) goes high at start, lets just chill for a ms resetPin.Write(false); // bring reset low Thread.Sleep(10); // wait 10ms resetPin.Write(true); // bring out of reset dcPin.Write(DisplayCommand); SendCommand(Command.DISPLAYOFF); // 0xAE SendCommand(Command.SETLOWCOLUMN | (Command)0x0); // low col = 0 SendCommand(Command.SETHIGHCOLUMN | (Command)0x0); // hi col = 0 SendCommand(Command.SETSTARTLINE | (Command)0x0); // line #0 SendCommand(Command.SETCONTRAST); // 0x81 if (vcctype == VccType.EXTERNALVCC) { SendCommand((Command)0x9F); // external 9V } else { SendCommand((Command)0xCF); // chargepump } SendCommand((Command)0xA1); // setment remap 95 to 0 (?) SendCommand(Command.NORMALDISPLAY); // 0xA6 SendCommand(Command.DISPLAYALLON_RESUME); // 0xA4 SendCommand(Command.SETMULTIPLEX); // 0xA8 //SendCommand((Command)0x3F); // 0x3F 1/64 duty SendCommand((Command)0x1F); // 0x1F 1/32 duty SendCommand(Command.SETDISPLAYOFFSET); // 0xD3 SendCommand((Command)0x0); // no offset SendCommand(Command.SETDISPLAYCLOCKDIV); // 0xD5 SendCommand((Command)0x80); // the suggested ratio 0x80 SendCommand(Command.SETPRECHARGE); // 0xd9 if (vcctype == VccType.EXTERNALVCC) { SendCommand((Command)0x22); // external 9V } else { SendCommand((Command)0xF1); // DC/DC } SendCommand(Command.SETCOMPINS); // 0xDA //SendCommand((Command)0x12); // disable COM left/right remap SendCommand((Command)0x02); ////128_32 = 02 128_64 = 12 SendCommand(Command.SETVCOMDETECT); // 0xDB SendCommand((Command)0x40); // 0x20 is default? SendCommand(Command.MEMORYMODE); // 0x20 SendCommand((Command)0x00); // 0x0 act like ks0108 // left to right scan SendCommand(Command.SEGREMAP | (Command)0x1); //0xA0 SendCommand(Command.COMSCANDEC); //0xC8 SendCommand(Command.CHARGEPUMP); //0x8D if (vcctype == VccType.EXTERNALVCC) { SendCommand((Command)0x10); // disable } else { SendCommand((Command)0x14); // disable } SendCommand(Command.DISPLAYON);//--turn on oled panel // Switch to 'data' mode dcPin.Write(Data); } else { resetPin.Write(true); Thread.Sleep(1); // VDD (3.3V) goes high at start, lets just chill for a ms resetPin.Write(false); // bring reset low Thread.Sleep(10); // wait 10ms resetPin.Write(true); // bring out of reset byte[] intBuffer; if (Height == 32) { intBuffer = new byte[] { (byte)Command.DISPLAYOFF, //turn off display(RESET=OFF) 0x00,0x00, //low column nibble(RESET=0),high column nibble(RESET=0) 0xB0, //start page address(RESET=0) (byte)Command.MEMORYMODE,0x00, //memory address mode(RESET=02 [page]) (byte)Command.SETDISPLAYCLOCKDIV,0x80, //oscillator frequency and divider(RESET=80)00 (byte)Command.SETMULTIPLEX,0x1F, //mux ratio(RESET=3F [64 lines] (byte)Command.SETDISPLAYOFFSET,0x00, //display offset,COM vertical shift(RESET=0) (byte)Command.CHARGEPUMP,(byte)(vcctype == VccType.EXTERNALVCC? 0x10 : 0x14), //enable charge pump(RESET=10 [OFF]) 0xA1,0x00, //segment remap(RESET=SEG0, COL0) 00 mirror image (byte)Command.COMSCANDEC, //COM output scan(RESET=C0, C8 flips display) (byte)Command.SETCOMPINS,0x02, //COM pins hardware config(RESET=12[alternate]) (byte)Command.SETCONTRAST,0xCF, //contrast CF(RESET=7F) (byte)Command.SETPRECHARGE,(byte)(vcctype == VccType.EXTERNALVCC? 0x22 : 0xF1), //pre-charge period F1(RESET=22) (byte)Command.SETVCOMDETECT,0x30, //Vcom deselect(RESET=20) (byte)Command.DISPLAYALLON_RESUME, //turn all on ignore RAM A5/RAM A4(RESET=A4) (byte)Command.NORMALDISPLAY, //normal display A6/inverted A7(RESET=A6) (byte)Command.DISPLAYON}; //turn on display } else if (Height == 64) { intBuffer = new byte[] { (byte)Command.DISPLAYOFF, //turn off display(RESET=OFF) 0x00,0x00, //low column nibble(RESET=0),high column nibble(RESET=0) 0xB0, //start page address(RESET=0) (byte)Command.MEMORYMODE,0x00, //memory address mode(RESET=02 [page]) (byte)Command.SETDISPLAYCLOCKDIV,0x80, //oscillator frequency and divider(RESET=80)00 (byte)Command.SETMULTIPLEX,0x3F, //mux ratio(RESET=3F [64 lines] (byte)Command.SETDISPLAYOFFSET,0x00, //display offset,COM vertical shift(RESET=0) (byte)Command.CHARGEPUMP,(byte)(vcctype == VccType.EXTERNALVCC? 0x10 : 0x14), //enable charge pump(RESET=10 [OFF]) 0xA1,0x00, //segment remap(RESET=SEG0, COL0) 00 mirror image (byte)Command.COMSCANDEC, //COM output scan(RESET=C0, C8 flips display) (byte)Command.SETCOMPINS,0x12, //COM pins hardware config(RESET=12[alternate]) (byte)Command.SETCONTRAST,0xCF, //contrast CF(RESET=7F) (byte)Command.SETPRECHARGE,(byte)(vcctype == VccType.EXTERNALVCC? 0x22 : 0xF1), //pre-charge period F1(RESET=22) (byte)Command.SETVCOMDETECT,0x40, //Vcom deselect(RESET=20) (byte)Command.DISPLAYALLON_RESUME, //turn all on ignore RAM A5/RAM A4(RESET=A4) (byte)Command.NORMALDISPLAY, //normal display A6/inverted A7(RESET=A6) (byte)Command.DISPLAYON}; //turn on display } I2CBus.GetInstance().Write(I2c, intBuffer, I2CTransactionTimeout); } } Hey Fabien,
I got this working with the I2C version and it's tested with 64 and 32 lines. Do you want to add it to your driver?
Posted 18 February 2014 - 04:24 PM
Great work, Dino4net! I'm waiting for my 128x32 display to arrive, and this will be VERY VERY helpful!
Posted 20 February 2014 - 11:14 PM
A few notes after playing around with the SSD1306 display, using a combination of Fabien Royer and Dino4net's codespieces.
I'm using two 4.7K resistors as pull-up resistors to 5V.
In the I2CBus class found on the forum I had to comment out the two last lines in the Write() method, the two lines where it throws an exception if the transferred data length isn't correct. Half of the time the exception would be raised.
I also made a change to the DrawString method, so that it looks like this:
public void DrawString(int x, int line, string str){ foreach (Char c in str) { DrawCharacter(x, line, c); x += 6; // 6 pixels wide if (line >= Height / 8) { break; // ran out of space :( } if (x + 6 >= Width) { x = 0; // ran out of this line line++; } } if (AutoRefreshScreen) { Refresh(); }}public enum Align{ Left, Center, Right}public void DrawString(Align align, int line, string str){ switch (align) { case Align.Left: DrawString(0, line, str); break; case Align.Center: DrawString((127 / 2) - (str.Length * 6 / 2), line, str); break; case Align.Right: DrawString((127 - (6 * str.Length)), line, str); break; default: DrawString(0, line, str); break; }} I changed the original DrawString so that it doesn't blank out the entire screen when you write more text than the display has room for, and it also fixes a bug where the bottom right character didn't work.
Also, the DrawString(Align, int, str) overload makes it easy to do center and right aligning of a text.
Here is an example of how to use the class:
Display.AdaFruitSSD1306 oled = new Display.AdaFruitSSD1306(0x3C);oled.Initialize();oled.AutoRefreshScreen = true;oled.DrawString(Display.AdaFruitSSD1306.Align.Left, 0, "Left");oled.DrawString(Display.AdaFruitSSD1306.Align.Center, 1, "Center");oled.DrawString(Display.AdaFruitSSD1306.Align.Right, 2, "Right"); I hope this is helpful for the next guy.
#12
dino4net
Posted 15 May 2014 - 03:46 PM
Hello,
As the code here became a little hard to read and many asked for a complete solution.
Here it is ... with a tool to create the image array ...
Posted 05 August 2015 - 09:03 PM
I'm currently working on support for the very similar SH1106 OLED driver. I was able to get I2C version working with very few modifications, but I cannot get the SPI version to work correctly(which I prefer at this point). Anyone want to collaborate on getting SH1106 working?
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users
Reply to quoted posts Clear
Netduino Forums
→ General
→ Project Showcase
Privacy Policy