 }
 
 void set_random_colours() {
-  
+
   for (int pixel=0; pixel < RGB_LEDS; pixel++) {
     unsigned long colour = colours[random(colours_length)];
     display_buffer[pixel * 3 + 0] = colour & 0xFF;
     display_buffer[pixel * 3 + 1] = (colour >> 8 ) & 0xFF;
     display_buffer[pixel * 3 + 2] = (colour >> 16) & 0xFF;   
   }
-  
-}
-
-//############################################################################################################################################################
-//Setup - Prozedur                                                                                                                                           #
-//############################################################################################################################################################
-
+
+}
+
+// Configuration of the AVR registers for communication with external
+//  peripherals
 void setup()   
 {               
-  // Pins auf Ein- oder Ausgang stellen und einen Startwert zuweisen 
+  // Set pins as inputs or outputs
+  // Setup the SPI connection pins and the TLC5940 BLANK signal on PORTB
   DDRB |= (1<<1)  | (1<<2)  | (1<<3) | (1<<5) ; // BLANK, SS, MOSI, SCLK as OUTPUTS
+  // Setup the remainder of the TLC5940 signal pins on PORTD
   DDRD |= (1<<3)  | (1<<4) |  (1<<6) | (1<<7) ; // VPRG, XLAT, GSCLK, Debug as OUTPUTS
+  // PORTC is used to cycle the row high-side MOSFETS, and although only 
+  //  pins 0, 1 & 2 are used, set them all as outputs
   DDRC = 255;
-  
+
+  // Configure the initial state of the TLC5940 control lines
   XLAT_Low;
   BLANK_High;
   VPRG_Low;
   Debug_Low;
-  
+
+  // Set an initial random patter in the display buffer
   set_initial_pattern();
-       
-  //Timer 1 (16bit)
+
+  // Set Timer 1 (16bit) in count (capture) mode to count the number of output pulses up to the 
+  //  greyscale depth. This then triggers an ISR to say that this LED has completed it's 
+  //  cycle and to move on to the next row
   TCCR1A  = (1<<WGM11) | (0<<WGM10);            // Fast PWM with ICR1 as top
   TCCR1B  = (1<<WGM13) | (1<<WGM12);            // Fast PWM with ICR1 as top
   TCCR1B |= (1<<CS12)  | (1<<CS11) | (1<<CS10); // external clock (T1) on rising egde
   TIMSK1 |= (1<<TOIE1);                         // enable overflow interupt
   ICR1    = Gray_Scale_Depth;                   // Grey scale depth for TLC-PW
 
-  //Timer 0 (8bit)
+  // Set Timer 0 (8bit) to output a PWM pulse (which is then externally routed into Timer 1),
+  //  which provides the clock source for the TLC5940 ICs.
+  // It is not set as fast as possible because that leaves too much processing for the AVR
+  //  to do, instead it is set a notch back (half speed)
   TCCR0A  = (1<<WGM01) | (0<<WGM00);            // CTC
   TCCR0A |= (0<<COM0A1) | (1<<COM0A0);          // Toggle on Compare Match
   TCCR0B  = (0<<CS02) | (0<<CS01) | (1<<CS00);  // No Prescaler
-  OCR0A   = 0;                                  // f(OCR) = F_CPU/2/Prescaler
-  
-  //UART Initialisation
+  // 0x00 is a bit too quick if you want to do any other processing,
+  //  such as put in random pixels as well as receive data from the
+  //  serial port, so put it up to 0x01. This makes the on time of 
+  //  each colour 1ms, so a complete cycle in 3ms, which is still 
+  //  strobing all colours at > 300Hz, so lots of time to play with
+  OCR0A   = 0x01;                                  // f(OCR) = F_CPU/2/Prescaler
+
+  // Configure the UART to receive data at 1 Mb/s
   UCSR0A |= (1<<U2X0);                                 // Double up UART
   UCSR0B |= (1<<RXEN0)  | (1<<TXEN0) | (1<<RXCIE0);    // UART RX, TX und RX Interrupt enable
   UCSR0C |= (1<<UCSZ01) | (1<<UCSZ00)             ;    // Asynchrous 8N1 
   UBRR0H = 0;
   UBRR0L = 1; //Baud Rate 1 MBit   --> 0% Error at 16MHz :-)
-  
-  //Enable global interrupts
+
+  // Enable global interrupts
   sei();
-   
-  //Configure SPI  
+
+  // Configure and enable SPI  
   SPCR = (1<<SPE)|(1<<MSTR);  
   SPSR = B00000000;   
-  
+
+  // Double buffering doesn't work yet
   /*ptr=display_buffer_2;
-  display_buffer = display_buffer_1;
-  display_buffer_live = 1;
-    */
+   display_buffer = display_buffer_1;
+   display_buffer_live = 1;
+   */
+  //  ptr = display_buffer;
+  // Set the incoming data pointer to the start of the main display buffer
   ptr = display_buffer;
-}
-
+
+  // Prepopulate the random colour buffer
+  if (random_colours_buffer_pixel < RGB_LEDS) {
+    unsigned long colour = colours[random(colours_length)];
+    random_colours_buffer[random_colours_buffer_pixel * 3 + 0] = colour & 0xFF;
+    random_colours_buffer[random_colours_buffer_pixel * 3 + 1] = (colour >> 8 ) & 0xFF;
+    random_colours_buffer[random_colours_buffer_pixel * 3 + 2] = (colour >> 16) & 0xFF; 
+    random_colours_buffer_pixel++;
+  } 
+
+}
+
+// If double buffering worked, we might use this, but it doesn't at the moment
 void flip_buffers() {
   if (display_buffer_live == 1) {
     display_buffer_live = 2;
     display_buffer = display_buffer_2;
     ptr = display_buffer_1;
-  } else {
+  } 
+  else {
     display_buffer_live = 1;
     display_buffer = display_buffer_1;
     ptr = display_buffer_2;
   }
   lastdata_tickcounter = tickcounter;
   cycling = false;
-  
-}
-
-//############################################################################################################################################################
-//Hauptprogramm                                                                                                                                              #
-//############################################################################################################################################################
-
+
+}
+
+// Main loop
 void loop()        
 {     
+  // The loop does nothing until a new set of data needs to be shifted out for the next LED.
+  // Everything else is handled by interrupts.
   if (new_row)
   {    
     shift_out_data(row);
-            
+
     need_xlat = 1;
-                                              
+
     new_row = 0;   
-    tickcounter++;
-   
+    
+    // Every time there is a new row we increment our tick counter, which is our way of keeping
+    //  track of time periods of the order of seconds, and we use this to cycle random colours
+    //  at 1-4Hz. 2Hz is a pleasing cycling pattern.
+        tickcounter++;
+
+    // When we are cycling it can take a while to call random(), so lets do this once per loop.
+    // If this is called many times in succession (e.g. 48), then you get a blip on the LED
+    //  where it presumably should be sending more data (e.g. the xlat thing), but it isn't, so
+    //  it does nothing, or something it shouldn't. either way, it's noticeable
+    if (random_colours_buffer_pixel < RGB_LEDS) {
+      unsigned long colour = colours[random(colours_length)];
+      random_colours_buffer[random_colours_buffer_pixel * 3 + 0] = colour & 0xFF;
+      random_colours_buffer[random_colours_buffer_pixel * 3 + 1] = (colour >> 8 ) & 0xFF;
+      random_colours_buffer[random_colours_buffer_pixel * 3 + 2] = (colour >> 16) & 0xFF; 
+      random_colours_buffer_pixel++;
+    } 
+
     // If we are cycling, then see if we need to cycle again
     if (cycling == true) {
-      if (random_colours_buffer_pixel < RGB_LEDS) {
-        unsigned long colour = colours[random(colours_length)];
-        //colour = colours[0];
-        random_colours_buffer[random_colours_buffer_pixel * 3 + 0] = colour & 0xFF;
-        random_colours_buffer[random_colours_buffer_pixel * 3 + 1] = (colour >> 8 ) & 0xFF;
-        random_colours_buffer[random_colours_buffer_pixel * 3 + 2] = (colour >> 16) & 0xFF; 
-        random_colours_buffer_pixel++;
-      }
+
       if (tickcounter - cycle_tickcounter > cycle_period) {
-        //set_random_colours();
-        for (int i=0; i<BUFFER_SIZE;i++){
-           display_buffer[i] = random_colours_buffer[i];
-        }
+        // Copy the current random colour buffer into the live display buffer
+        // (TODO: If we had double buffering, we could just switch a pointer)
+        memcpy(display_buffer, random_colours_buffer, BUFFER_SIZE);
         random_colours_buffer_pixel = 0;
         cycle_tickcounter = tickcounter;
       }
-    } else {
+    } 
+    else {
       // If we aren't cycling, then see if we need to start
       if (tickcounter - lastdata_tickcounter > timeout) {
         cycling = true;

#define Debug_Low       PORTD &=  ~(1 << 7)
#define Debug_High      PORTD |=   (1 << 7)

# define CMD_NEW_DATA 1

#define MODULE_WIDTH 6
#define MODULE_HEIGHT 8
#define RGB_LEDS MODULE_HEIGHT * MODULE_WIDTH
#define BUFFER_SIZE MODULE_WIDTH*MODULE_HEIGHT*3

unsigned char display_buffer_1[BUFFER_SIZE];
unsigned char display_buffer_2[BUFFER_SIZE];
static unsigned char *display_buffer = display_buffer_1;

unsigned char random_colours_buffer[BUFFER_SIZE];
unsigned int random_colours_buffer_pixel = 0;


volatile byte display_buffer_live = 1;

volatile byte new_row = 0;
volatile byte need_xlat = 0;

static unsigned char *ptr;
static unsigned int pos = 0;

byte row = 0;

unsigned long tickcounter = 0;
unsigned long lastdata_tickcounter = 0;
// 40000 = 20 seconds

}


