Setting the screen contrast

(Pharap) #1

The other day I was reading the SSD1306 datasheet,
and I discovered that it’s possible to set the contrast of the screen.

Here’s a demo program in case anyone wants to mess around with it:

// MIT License
//
// Copyright (c) 2019 Pharap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <Arduboy2.h>

Arduboy2 arduboy;

void setContrast(uint8_t value)
{
	arduboy.LCDCommandMode();
	arduboy.SPItransfer(0x81);
	arduboy.SPItransfer(value);
	arduboy.LCDDataMode();
}

constexpr uint8_t defaultContrast = 0x7F;

void resetContrast()
{
	setContrast(defaultContrast);
}

uint8_t contrast = defaultContrast;

void setup()
{
	arduboy.begin();
	resetContrast();
}

void loop()
{
	if(!arduboy.nextFrame())
		return;

	arduboy.pollButtons();
	
	if(arduboy.pressed(DOWN_BUTTON))
	{
		if(contrast > 0x00)
		{
			--contrast;
			setContrast(contrast);
		}
	}
	
	if(arduboy.pressed(UP_BUTTON))
	{
		if(contrast < 0xFF)
		{
			++contrast;
			setContrast(contrast);
		}
	}
	
	if(arduboy.justPressed(B_BUTTON))
	{
		if(contrast != defaultContrast)
		{
			contrast = defaultContrast;
			setContrast(contrast);
		}
	}

	arduboy.clear();
	arduboy.println(F("Hello World"));
	arduboy.fillRect(0, 10, 40, 32, WHITE);
	arduboy.display();
}

Low contrast is good for playing at night.

4 Likes
(Kevin) #2

The startup routine already sets the contrast to max, I think someone played around with the values before but it doesn’t seem to do much from what I remember?

2 Likes
#3

The Arduboy library sets contrast to 0xCF. Maximum would be 0xFF. I’ve played with contrast before and iirc the difference between minimum and maximum wasn’t that much. Probably because of the limited built in charge pump/booster.

With displays that use an external voltage booster theres a lot more difference though.

2 Likes
(Kevin) #4
1 Like
(Pharap) #5

There isn’t much difference between each step of contrast, but there’s a notable difference between the minimum and the maximum.

Not as drastic as you could expect from a computer monitor,
but not negligible either.

Minimum contrast gives out a lot less light so it’s good for playing at night.

I must have missed that thread first time around,
most of the posts were marked as unread.

Either way, I’ve posted a demo program so I may as well leave it up,
this is more of a direct ‘how to’/demo for setting the contrast rather than a discussion of all the intricacies of affecting the brightness of the screen.

1 Like
(Scott R) #6

I think it has its uses for some games you could dim the screen for say in caves and so on or even just for lower light play.

This video shows what can be achieved with the ssd1306

@Mr.Blinky how about adding some flicker to my favourite fireplace?

3 Likes
#7

Totally mist that.

I played with your example code and the difference is much better then I remember (maybe it was the difference between default contrast and maximum contrast I remembered)

2 Likes
(Pharap) #8

That’s pretty much the same thought @Vampirics had when I told him about it the other day.

That’s reassuring.

With everyone suggesting that changing the contrast didn’t seem to do much I was begining to wonder if I was going mad or had a faulty screen.

Seems plausible.

1 Like
(Michael Gollnick) #9

Actually I did experiments in this thread and found a few things about the precharge and the brightness. It was very impressive on the real hardware.

4 Likes
(Kevin) #10

Thanks @veritazz I was trying to find that post!

3 Likes
(Stephane Hockenhull) #11

I found there’s a side effect to the settings where depending pixel count on lines it can become very uneven causing horizontal lines to be notably darker or brighter.

It’s difficult to capture on a camera but much more visible to the naked eye.

There’s a total current limit per line so if the brightness is cranked too high it will cap out on some lines, physically dividing the brightness between all the lit up pixels.

With some lines having a few active very bright pixels, and others with more lit pixels being down to almost half brightness (at extreme settings.)

Screenshot_2019-04-23_08-16-40

You can see the 3rd line’s brightness (and every line that has dark horizontal strikes in the lettering) compared to the others.

There’s a balance to be struck and it can depend on the type of artwork being displayed.
I tried to get a split between low flicker and even lines.

(Shawn) #12

This is a common problem with multiplexed displays that don’t use some method like per row duty or current compensation. The more pixels in a given line that are on the dimmer the line as a whole will look and vice versa. Overall, this is more evident with static screens, but with moving images it tends to be not as noticeable. Given how cheap these screens are it’s an understandable compromise.

(Kevin) #13

Oh interesting, yeah the banding has always been an issue. Mostly on things that use a mostly white background it becomes obvious. I don’t think I was aware of how the contrast settings effected this, maybe that’s why contrast didn’t get set to maximum?

1 Like