GR KURUMI + フルカラーLEDマトリクス(その2)

前回、フルカラーLEDマトリクスを使ってみたのですが、やはりちらつきが気になるので色々試してみました。

TLC5940がらみの処理を見直しまして、まあまあ納得いく出来にはなったかと思うのですが、いかがでしょう。

TLC5940はGSCLKというピンに4096回パルスを入れると、事前にシリアルI/Fで設定した0〜4095の数値に応じてPWM動作するのですが、ここに時間がかかっており、ダイナミック点灯時のちらつきの原因となっていました。

4096回=4096段階に輝度が調節できるというのがTLC5940のウリではあるのですが、背に腹は変えられず512回に減らしました。BLANKピンをHIGHにするとGSCLKの処理を中断できるので、512回パルス入れた後にその操作を行っています。

/*GR-KURUMI Sketch Template Version: V1.00*/
#include <RLduino78.h>

#define NUM_5940    2

#define GSCLK_PIN   3

#define COM0_PIN    4
#define COM1_PIN    5
#define COM2_PIN    6

#define VPRG_PIN    7
#define BLANK_PIN   8
#define XLAT_PIN    9

#define SIN_PIN     11
#define SCLK_PIN    13

#define COLOR_DEPTH 512
#define COLOR_MULTIPLIER (COLOR_DEPTH/256)

void set_dc( void );
void set_gs_setting( int index );
void proc_gsclk( int index );
void proc_update(unsigned long u32ms);
void disp_update( void );
void set_gsval( int index );
void set_row( int index );
void shift_color( void );

int gsupdate = 0;
int dispindex = 0;

byte dcval[NUM_5940][16] = {
    {0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30},
    {0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30},
};

word gsval[NUM_5940][16];

typedef unsigned long RGB;

#define GetRED(x) (byte)(((x)>>16)&0xff)
#define GetGREEN(x) (byte)(((x)>>8)&0xff)
#define GetBLUE(x) (byte)((x)&0xff)

#define SetRGB(r,g,b) (((r)<<16)|((g)<<8)|(b))
RGB dots[8][8] = {
    { 0x000001, 0x000002, 0x000008, 0x000010, 0x000020, 0x000040, 0x000080, 0x0000E0 },
    { 0x000100, 0x000200, 0x000800, 0x001000, 0x002000, 0x004000, 0x008000, 0x00E000 },
    { 0x010000, 0x020000, 0x080000, 0x100000, 0x200000, 0x400000, 0x800000, 0xE00000 },
    { 0x000001, 0x000002, 0x000008, 0x000010, 0x000020, 0x000040, 0x000080, 0x0000E0 },
    { 0x000100, 0x000200, 0x000800, 0x001000, 0x002000, 0x004000, 0x008000, 0x00E000 },
    { 0x010000, 0x020000, 0x080000, 0x100000, 0x200000, 0x400000, 0x800000, 0xE00000 },
    { 0x000001, 0x000002, 0x000008, 0x000010, 0x000020, 0x000040, 0x000080, 0x0000E0 },
    { 0x000100, 0x000200, 0x000800, 0x001000, 0x002000, 0x004000, 0x008000, 0x00E000 }
};    

typedef struct {
  byte red;
  byte green;
  byte blue;
} s_dir_colors;
s_dir_colors dir_colors;

int row_index = 0;
int current_temp = 0;

// the setup routine runs once when you press reset:
void setup() {
  int i, j;

  row_index = 0;
  gsupdate = 0;
  dispindex = 0;

  dir_colors.red = 1;
  dir_colors.green = 0;
  dir_colors.blue = 0;

  for( i = 0; i < NUM_5940; i ++ ){
    for( j = 0; j < 16; j ++ ){
      gsval[i][j] = 0;
    }
  }

  pinMode(COM0_PIN, OUTPUT);
  pinMode(COM1_PIN, OUTPUT);
  pinMode(COM2_PIN, OUTPUT);

  pinMode(VPRG_PIN, OUTPUT);
  pinMode(BLANK_PIN, OUTPUT);
  pinMode(XLAT_PIN, OUTPUT);        // SS(STCP)

  pinMode(SIN_PIN, OUTPUT);
  pinMode(SCLK_PIN, OUTPUT);

  pinMode(GSCLK_PIN, OUTPUT);

  digitalWrite(COM0_PIN, LOW);
  digitalWrite(COM1_PIN, LOW);
  digitalWrite(COM2_PIN, LOW);

  digitalWrite(VPRG_PIN, HIGH);
  digitalWrite(BLANK_PIN, HIGH);
  digitalWrite(XLAT_PIN, LOW);

  digitalWrite(GSCLK_PIN, LOW);

  // start work
  set_dc();

  // 1st
  set_row( 0 );
  set_gs_setting( 0 );

  attachCyclicHandler(1, proc_update, 200);
}

// the loop routine runs over and over again forever:
void loop() {
  // check update
  disp_update();        // update

  // set row
  set_row( row_index );

  // set grayscale data
  set_gs_setting( row_index );
  proc_gsclk( row_index );

  // increment row
  row_index ++;
  if( row_index >= 8 ){
    row_index = 0;
  }
}

void set_dc( void )
{
  int i = 0;
  int j = 0;
  byte k = 0;

  // Dot Correction
  noInterrupts();

  P0.BIT.bit0 = 1;  // VPRG
  P1.BIT.bit3 = 0;  // XLAT

  P7.BIT.bit0 = 0;  // SCLK

  for( i = 0; i < NUM_5940; i ++  ){
    for( j = 0; j < 16; j ++ ){
      for( k = 0x20; k != 0x00; k >>= 1 ){
        P7.BIT.bit2 = ( ( dcval[i][j] & k ) == 0 ) ? 0 : 1;  // SIN

        P7.BIT.bit0 = 1;  // SCLK
        P7.BIT.bit0 = 0;  // SCLK
      }
    }
  }

  P1.BIT.bit3 = 1;  // XLAT
  P1.BIT.bit3 = 0;  // XLAT

  interrupts();
}

void set_gs_setting( int index )
{
  int i = 0;
  int j = 0;
  int k = 0;

  // Gray Scale
  set_gsval( index );

  noInterrupts();

  P0.BIT.bit0 = 0;  // VPRG
  P0.BIT.bit1 = 1;  // BLANK

  P1.BIT.bit3 = 0;  // XLAT
  P7.BIT.bit0 = 0;  // SCLK

  for( i = 1; i >= 0; i -- ){
    for( j = 0; j < 16; j ++ ){
      for( k = 11; k >= 0 ; k -- ){
        if( ( gsval[i][j] & ( 0x1 << k ) ) == 0 ){
          P7.BIT.bit2 = 0;
        }
        else{
          P7.BIT.bit2 = 1;
        }
        
        P7.BIT.bit0 = 1;  // SCLK
        P7.BIT.bit0 = 0;  // SCLK
      }
    }
  }

  P1.BIT.bit3 = 1;  // XLAT
  P1.BIT.bit3 = 0;  // XLAT

  P7.BIT.bit0 = 1;  // SCLK
  P7.BIT.bit0 = 0;  // SCLK

  P0.BIT.bit1 = 0;  // BLANK

  interrupts();
}

void proc_gsclk( int index )
{
  int i = 0;
  int gscnt = 0;

  // Gray Scale
  noInterrupts();

  P0.BIT.bit0 = 0;  // VPRG

  P1.BIT.bit3 = 0;  // XLAT
  P0.BIT.bit1 = 0;  // BLANK
  P7.BIT.bit0 = 0;  // SCLK

  gscnt = COLOR_DEPTH;

  for( i=0; i < gscnt; i ++ ){

    P1.BIT.bit6 = 1;  // GSCLK
    NOP();
    P1.BIT.bit6 = 0;  // GSCLK
    NOP();
  }

  P0.BIT.bit1 = 1;  // BLANK
  P0.BIT.bit1 = 0;  // BLANK

  interrupts();
}


void set_row( int index)
{
  // set ROW
  noInterrupts();

  switch( index ){
    case 0:
      P3.BIT.bit1 = 0;  // COM0
      P1.BIT.bit5 = 0;  // COM1
      P1.BIT.bit0 = 0;  // COM2
      break;
      
    case 1:
      P3.BIT.bit1 = 1;  // COM0
      P1.BIT.bit5 = 0;  // COM1
      P1.BIT.bit0 = 0;  // COM2
      break;

    case 2:
      P3.BIT.bit1 = 0;  // COM0
      P1.BIT.bit5 = 1;  // COM1
      P1.BIT.bit0 = 0;  // COM2
      break;

    case 3:
      P3.BIT.bit1 = 1;  // COM0
      P1.BIT.bit5 = 1;  // COM1
      P1.BIT.bit0 = 0;  // COM2
      break;

    case 4:
      P3.BIT.bit1 = 0;  // COM0
      P1.BIT.bit5 = 0;  // COM1
      P1.BIT.bit0 = 1;  // COM2
      break;

    case 5:
      P3.BIT.bit1 = 1;  // COM0
      P1.BIT.bit5 = 0;  // COM1
      P1.BIT.bit0 = 1;  // COM2
      break;

    case 6:
      P3.BIT.bit1 = 0;  // COM0
      P1.BIT.bit5 = 1;  // COM1
      P1.BIT.bit0 = 1;  // COM2
      break;

    case 7:
      P3.BIT.bit1 = 1;  // COM0
      P1.BIT.bit5 = 1;  // COM1
      P1.BIT.bit0 = 1;  // COM2
      break;
  
    default:
      break;
  }
  interrupts();
}

void proc_update( unsigned long u32ms )
{
  gsupdate = 1;
}

void set_gsval( int index )
{
  /* set gsval */
  gsval[0][0] = GetRED(dots[index][5]) * COLOR_MULTIPLIER;
  gsval[0][1] = GetBLUE(dots[index][4]) * COLOR_MULTIPLIER;
  gsval[0][2] = GetGREEN(dots[index][4]) * COLOR_MULTIPLIER;
  gsval[0][3] = GetRED(dots[index][4]) * COLOR_MULTIPLIER;
  gsval[0][4] = GetBLUE(dots[index][3]) * COLOR_MULTIPLIER;
  gsval[0][5] = GetGREEN(dots[index][3]) * COLOR_MULTIPLIER;
  gsval[0][6] = GetRED(dots[index][3]) * COLOR_MULTIPLIER;
  gsval[0][7] = GetBLUE(dots[index][2]) * COLOR_MULTIPLIER;
  gsval[0][8] = GetGREEN(dots[index][2]) * COLOR_MULTIPLIER;
  gsval[0][9] = GetRED(dots[index][2]) * COLOR_MULTIPLIER;
  gsval[0][10] = GetBLUE(dots[index][1]) * COLOR_MULTIPLIER;
  gsval[0][11] = GetGREEN(dots[index][1]) * COLOR_MULTIPLIER;
  gsval[0][12] = GetRED(dots[index][1]) * COLOR_MULTIPLIER;
  gsval[0][13] = GetBLUE(dots[index][0]) * COLOR_MULTIPLIER;
  gsval[0][14] = GetGREEN(dots[index][0]) * COLOR_MULTIPLIER;
  gsval[0][15] = GetRED(dots[index][0]) * COLOR_MULTIPLIER;

  gsval[1][0] = 0;
  gsval[1][1] = 0;
  gsval[1][2] = 0;
  gsval[1][3] = 0;
  gsval[1][4] = 0;
  gsval[1][5] = 0;
  gsval[1][6] = 0;
  gsval[1][7] = 0;
  gsval[1][8] = GetBLUE(dots[index][7]) * COLOR_MULTIPLIER;
  gsval[1][9] = GetGREEN(dots[index][7]) * COLOR_MULTIPLIER;
  gsval[1][10] = GetRED(dots[index][7]) * COLOR_MULTIPLIER;
  gsval[1][11] = GetBLUE(dots[index][6]) * COLOR_MULTIPLIER;
  gsval[1][12] = GetGREEN(dots[index][6]) * COLOR_MULTIPLIER;
  gsval[1][13] = GetRED(dots[index][6]) * COLOR_MULTIPLIER;
  gsval[1][14] = GetBLUE(dots[index][5]) * COLOR_MULTIPLIER;
  gsval[1][15] = GetGREEN(dots[index][5]) * COLOR_MULTIPLIER;
}

void disp_update( void )
{
  if( gsupdate == 1 ){
    shift_color();
    gsupdate = 0;
  }
}  

void shift_color( void )
{
  int y, x;
  RGB store;

  for( y=0; y<8; y++ ){
    store = dots[y][7];
    dots[y][7] = dots[y][6];
    dots[y][6] = dots[y][5];
    dots[y][5] = dots[y][4];
    dots[y][4] = dots[y][3];
    dots[y][3] = dots[y][2];
    dots[y][2] = dots[y][1];
    dots[y][1] = dots[y][0];
    dots[y][0] = store;
  }
}    

ご覧の通り、もはやArduino互換とは言いがたいソースになってしまいました。予算が許すならFPGAとか使った方が良いかもしれませんね。泣