LEDLightDistrict/DesignA

From Technologia Incognita
Jump to: navigation, search

Part of the documentation of LEDLightDistrict.

Overview

The goal of this design is to write either monochrome or colour images to an N by N screen, built up out of LEDs. LEDs have a brightness, so PWM is required.

To create an image it is necessary to map colour values from memory, to electronics, to a 2D surface. Each mapping must be understood, to understand how the whole approach will work. But to get a good understanding of how the electronics map the image in memory to the 2D surface, it is practical to learn how the image in memory maps to the 2D surface first.

Mapping pixels in memory to the 2D surface

monochrome

The image is stored in a basic one dimensional array.

To find a pixel's index based on its surface coordinates:


   rowStartIndex           = x * HEIGHT ;
   
   if( x % 2 )
       relativeColumnIndex = y ;
   else
       relativeColumnIndex = HEIGHT - 1 - y ;
   index = rowStartIndex + relativeColumnIndex ;

To illustrate for a 3 by 3 screen an example:

0 5 6

1 4 7

2 3 9


Where the number illustrates the position in the array.

To find (1,0) do:

   rowStartIndex = 1 * HEIGHT = 3 ;
   relativeColumnIndex = HEIGHT - 1 - 0 = 2
  
   index = 3 + 2 = 5 ;


Colour

The image is stored in a basic one dimensional array.


To find a subpixel's index based on its surface coordinates:


rowStartIndex = COLOUR_COUNT * x * HEIGHT ;

   if( x % 2 )
       relativeColumnIndex = y + subPixel ; // sub pixel is either 0 for red, 1 for green or 2 for blue
   else
       relativeColumnIndex =  COLOUR_COUNT * HEIGHT - 1 - y - subPixel ;
   
   index = rowStartIndex + relativeColumnIndex ;
   

To illustrate for a 3 by 3 screen an example:

r 0 17 18

g 1 16 19

b 2 15 20


r 3 14 21

g 4 13 22

b 5 12 23


r 6 11 24

g 7 10 25

b 8 9 26


To find (1,0), 0 (i.e. red) do:

   rowStartIndex =  COLOUR_COUNT *  1 * HEIGHT = 9 ;
   relativeColumnIndex = COLOUR_COUNT * WIDTH - 1 - 0 = 8
   index = 9 + 8 = 17 ;

Electronics, mapping pixels to screen

The pixels can be addressed through a series of shift registers, that are all connected in series. Each position in the shift register corresponds to the position in the array described above. LEDs of the right colour are attached to the concatenated shift registers in the precise order described above.


Computing PWM

Code that works runs on a nanode for a colour screen of 16by 17 pixels with 7 brightness levels at 40fps: https://github.com/guidocalvano/PwmShiftRegister/blob/master/pwmShiftRegister.ino

rough overview of how it works:

   while( true )
       frameDuration = beforeFrame - timeInMillis() ;
       beforeFrame = timeInMillis() ;
   
       for( brightnessLevel = 0 ; brightnessLevel < brightnessLevelCount ; brightnessLevel++ )
           for( i in pixelArray )
       
               pixelHigh = ( ( timeInMillis() ) % frameDuration ) < pixelBrightness ? true : false
               
               pushToScreen( pixelHigh )
   
           openLatch() ;


tractability

This is a tractability computation of a colour screen with colour and 7 brightness levels per pixel:

computationCount = pixelCount * COLOURS_PER_PIXEL * brightnessLevels * frameRate

pixelCount = WIDTH * HEiGHT

computationCount = 17 * 16 * 3 * 7 * 60 = 342 720

This is totally feasible.