Blog der Heimetli Software AG

SenseHat: LED-Steuerung über den Framebuffer

Den SenseHat habe ich schon im letzten Post beschrieben.

Damals hatte ich noch gehofft, einen Film der LEDs zustande zu bringen. Das übersteigt aber meine Fähigkeiten ganz eindeutig. Die LEDs überstrahlen alles, und dazu kommt noch das Multiplexing. Egal wie oft ich es versucht habe, ich habe es nicht geschafft ein vernünftiges Video zu drehen.

Aus diesem Grunde gibt es hier nur eine Simulation der LEDs auf dem SenseHat.

Der Framebuffer

Wenn der Raspberry mit dem SenseHat bootet, dann wird automatisch ein Framebuffer für die LEDs auf dem Board erzeugt. Vermutlich liest Raspbian die Konfiguration aus einem FLASH-Memory auf dem Hat und erstellt nach diesen Angaben das Device.

Auf meinem Pi wird der Framebuffer als /dev/fb1 eingerichtet.

Der Framebuffer lässt sich wie ein File beschreiben und auch lesen. Was ins Device-File geschrieben wird transferiert der Mikrokontroller auf dem Board direkt auf die LED-Steuerung.

Dadurch ist es möglich, die Anzeige mit beliebigen Programmen zu steuern ohne irgendwelche speziellen Libraries zu benützen. Im einfachsten Fall kopiert man ein vorbereitetes File mit cp in den Framebuffer und erhält die gewünschte Anzeige!

Simulation der LEDs auf dem SenseHat

Das Java-Programm für diese Show

Wie oben beschrieben kann man jede beliebige Sprache verwenden um das Display zu steuern. In diesem Fall habe ich Java gewählt.

Speziell ist nur etwas: Java hat seine eigenen Ansichten zur Byte-Order in Files. Da die Farbe für ein Pixel mit zwei Bytes festgelegt wird, musste ich die Farben so definieren dass sie richtig im Framebuffer landen. Wenn dieses Programm in eine andere Sprache portiert wird, muss das angepasst werden.

import java.io.* ;

/**
 * Displays patterns on the LEDs of the Sense Hat
 * for the Raspberry Pi
 *
 * @version 0.01
 * @author  P. Tellenbach
 */
public class Waves
{
   // Definions in Java byte order !
   public static final int BLACK = 0x0000 ;
   public static final int RED   = 0x0038 ;
   public static final int GREEN = 0xE001 ;
   public static final int BLUE  = 0x0e00 ;

   private static int[] COLORS = { RED, GREEN, BLUE } ;

   int[][] pixels ;

   public Waves()
   {
      pixels = new int[8][8] ;
   }

   /**
    *  Copies the pixels to the frame buffer
    */
   public void displayPixels()
   {
      try
      {
         FileOutputStream fos = new FileOutputStream( "/dev/fb1" ) ;
         DataOutputStream os  = new DataOutputStream( fos ) ;

         for( int row = 7; row >= 0; row-- )
         {
            for( int col = 0; col < 8; col++ )
            {
               os.writeShort( pixels[row][col] ) ;
            }
         }

         os.close() ;
         fos.close() ;
      }
      catch( IOException e )
      {
         System.out.println( e.getMessage() ) ;
      }
   }

   /**
    * Clears an area in the center of the pixel array
    *
    * @param size The size of the area
    */
   public void clear( int size )
   {
      int start = (8 - size) / 2 ;

      for( int r = 0; r < size; r++ )
      {
         for( int c = 0; c < size; c++ )
         {
             pixels[start + r][start + c] = BLACK ;
         }
      }
   }

   /**
    * Sleep for 100ms
    */
   public void delay()
   {
      try
      {
         Thread.sleep( 100 ) ;
      }
      catch( InterruptedException e )
      {
         System.out.println( e.getMessage() ) ;
      }
   }

   /**
    * Draws a wave on the display
    *
    * @param row   The starting row
    * @param col   The starting column
    * @param len   The length of the lines
    * @param color The color of the pixels
    * @param size  The area to clear before drawing
    */
   public void showWave( int row, int col, int len, int color, int size )
   {
      clear( size ) ;

      pixels[row--][col] = color ;

      for( int p = 1; p < len; p++ )
      {
         pixels[row--][col] = color ;
      }

      for( int p = 0; p < len; p++ )
      {
         pixels[row][col--] = color ;
      }

      for( int p = 0; p < len; p++ )
      {
         pixels[row++][col] = color ;
      }

      for( int p = 0; p < len; p++ )
      {
         pixels[row][col++] = color ;
      }

      displayPixels() ;
      delay() ;
   }

   /**
    * Increment the color index modulo the
    * list size
    *
    * @param index The number to increment
    */
   private int inc( int index )
   {
      if( ++index >= COLORS.length )
      {
         return 0 ;
      }

      return index ;
   }

   /**
    * Shows a few patterns on the pixels
    */
   public void show()
   {
      int index  = 0 ;
      int top    = 7 ;

      for( int len = 8; len > 0; len -= 2 )
      {
         for( int i = 0; i < len; i++ )
            showWave( top, 7 - top + i, i, COLORS[index], len ) ;
         index = inc( index ) ;

         for( int i = 0; i < len; i++ )
            showWave( top, top, i, COLORS[index], len ) ;
         index = inc( index ) ;

         for( int i = 0; i < len; i++ )
            showWave( 7 - top + i, top, i, COLORS[index], len ) ;
         index = inc( index ) ;

         for( int i = 0; i < len; i++ )
            showWave( 7 - top + i, 7 - top + i, i, COLORS[index], len ) ;
         index = inc( index ) ;

         --top ;
      }
   }

   /**
    * The program starts here
    *
    * @param args Ignored
    */
   public static void main( String[] args )
   {
      Waves waves = new Waves() ;
      waves.show() ;
   }
}