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とか使った方が良いかもしれませんね。泣