Norns Display Gamma

As it seems, Norns’ OLED screen is displaying its brightness values 0-15 linearly. This has the effect that there is a big perceptual brightness change between 0 and 1, with fewer and fewer perceived changes up to 15.

You’ve probably noticed that screenshots from Norns look darker on a computer screen than what you see on the OLED too. This is because computer screens have a gamma correction built-in, to make images and their brightness changes seem more natural to the human eye, which (like most human senses) does not register stimuli linearly.

Would it be possible to implement a display gamma correction in a future Norns update? With this we could use the OLED’s brightness range more efficiently when designing our user interfaces and screenshots would also perceptually match (more or less) when viewed on computer screens.

A display gamma value for computer screens and TVs is typically 2.2 (I know, I know, there’s also 2.4, but let’s not overcomplicate things :wink: ).

There’s more detailed information on this topic here:

EDIT: My girlfriend says she wants colors too, please. Thx! :stuck_out_tongue:

Info from the thread:

OLED Driver Code

OLED Driver Specs

nmDisplayTest: a Norns script displaying various test patches for visual gamma assessment and measuring

Info on building a new Kernel


I’ve been wondering if some kind of a film on the screen could achieve some of this.

hacking the OLED driver is tricky business. here’s the code and it takes a substantial familiarity with the datasheet regarding the chip’s actual capabilities.

back at the start of the project i was deep into this stuff, spent a good amount of time discussing tuning with the manufacturer. at some point other priorities took precedent, and i had to move on. i agree, i’d like a nicer gamma curve.

also i really wanted 60fps rather than 15fps— this is a much trickier problem— the linux framebuffer could be optimized to check for changed regions of the screen and only update those rather than full frame— at some point i found some code for this which would’ve needed to be adapted to our chip, but alas, this was some very heavy engineering.

so in short, no, nicer gamma isn’t coming quickly— but it’d be amazing if someone versed in the above were interested in taking it on!


Is the same part (ssd1322) used on both the stock and shield versions?

yes indeed. same screen different headers.

I’d be willing to team up with someone on this, have some embedded experience and always looking for more (+ I like screens :slight_smile: ).


Poked into it a little bit, looks like the code to setup the grayscale table is commented out.

The #def gamma values cover less than half of the brightness range available. Re-enabling and choosing new values might be enough to get it going in the right direction.

1 Like

I’ve noticed that as well.

#define DEFAULT_GAMMA "1 1 1 1 1 2 2 3 3 4 4 5 5 6 6"

I believe that the values in the lookup table might be actual gamma values for each of the 15 steps and not display brightness levels though. Otherwise we wouldn’t see a difference between levels 0-5 for example, as the lookup table defines a value of 1 for all of those.

When I’m back home on the weekend I will take some luminance measurements off the OLED screen with my spectroradiometer (:nerd_face:) and report back with a gamma graph to see what the display does for each brightness level.

From the spec, the values range from [0-180].

The driver accumulates the values in DEFAULT_GAMMA i.e. 1 2 3 4 5 7 9 etc. The code is commented out, not sure if there was an issue or if it was just too dim because the values were too small.

Nice, that’d be super helpful to get a more accurate curve. Was just figuring we’d have to eyeball it.

Got a link or any other context on this? Scripts that draw a lot might stutter if the fps drops, guess it depends on how tight the performance limitation is.

Might be interesting to dig in on the frame rate stuff together.


Yes, sorry, that’s what I meant by “gamma values”. The values are the brightness change for each step. By accumulating them, we can derive an absolute brightness value per step then.

I suppose we need to figure out how the accumulated values are mapped to the display, or rather to Norn’s 0-15 range, then.

We still might need to do that too. I’ll write a little Norns script with display test patterns for visual judgement over the next couple of days :slight_smile:

Interesting discussion. I assumed the 15 brightness levels was hard-coded into the display hardware. I wonder what the actual luminosity resolution of the display is.

Might it actually be possible to make the display brighter? Or is the current maximum brightness “full on”?

I’ve found the white display particularly to be quite dim.

Yes, it is - the display allows for configuring the brightness of 15 distinct levels.

Maybe - the spec I looked at indicates that the default level 15 brightness is set to 112 (max value 180). The value is a number of clock cycles to keep a voltage high. Unclear if that maps linearly to brightness - it may look similar.

1 Like

Interesting. I guess 112 must have been deemed an acceptable compromise between brightness and power-consumption.

The yellow display (which I have on my Fates) is nice and bright. I like to use the white one with a coloured gel over it though, and it does end up quite dim, after that (though a pretty blue colour, in the case of my Norns Shield).

With OLEDs you also need to keep burn-in in mind (something the TE OP-1 also suffered from, just as much as modern OLED TVs, etc). So the brighter the pixel, the quicker it ages and deteriorates. If you show one bright area all the time (like TV Station logos in the corner of a screen), those pixels will become duller more quickly than the rest of the screen.

20 character of true

Alright, I whipped up a little Norns script. Use any encoder or K2 and K3 to switch between the test patterns:

  • Stepped gradients
  • Full-screen brightness patches (for measuring off the OLED)
  • Alternating lines
  • Flicker

Install from Maiden:

GitHub ZIP

If we want to make a game out of it (in case we’re already that far), each of you can suggest eye-balled brightness values for levels 1-15 and the one who’s closest to a 2.2 gamma, as measured by my spectro, wins :smiley:

How would one go about “uploading” a modified OLED driver file to Norns? I’m really not knowledgeable when it comes to Linux :frowning: I assume one has to compile the .c file?


Figure out how to build it then load it with modprobe (guessing).

I think everything gets compiled and built running ./waf in the ~/norns directory. At least that’s how it works when making changes to the core library.

The process for building kernel modules is completely separate from building the norns software stack and will take some effort. The script which builds the norns kernel can be found here:

…but that won’t be very convenient for iterating on a single kernel module. That script uses docker to pull down a cross-compilation environment and assumes you are doing a full kernel build. Within the build container the following script does the actual build:

To efficiently iterate on a single module one would probably have to familiarize themselves with the linux kernel build system. It may be possible to compile just the one module directly on a norns device if one has several GB free space to hold the kernel source.

I’ve not personally tried to load kernel modules at run time much so I don’t know if a modprobe of a new build of a previously loaded module would take effect.

If it were me I would start by setting up a cross-compilation environment on another Linux machine (or vm) and iterate by building locally then copying the kernel module in place on norns and rebooting. For reference my kernel hacking is mostly done in a Debian 10 VM with 6 cores and 24GB RAM - with that a full clean kernel build with the script takes ~10-12 minutes.

UPDATE: I stand corrected. If one doesn’t mind the up front cost of doing a full kernel build the script will do a decent job of incremental recompiles… so it could be used as is to iteratively build after changing the kernel module.


Thank you for this information! This is way out of my league unfortunately. I can barely install a copy of Nethack on a Linux machine. I’d be happy to provide the screen measurements and any other low-complexity support, but I’m afraid when it comes to the implementation then I won’t be of much help :confused: