comparison Scan/ISSILed/led_scan.c @ 384:82ce1988fefe

Adding basic ISSI led brightness control capabilities - 6 modes * Single led: decrease, increase, set * All leds: decrease, increase, set - Currently update speed limited to once every 30 ms * Likely an I2C driver or ISSI limitation preventing even faster updates
author Jacob Alexander <haata@kiibohd.com>
date Fri, 09 Oct 2015 22:28:31 -0700
parents 86b937945313
children a3825c7fc651
comparison
equal deleted inserted replaced
383:801e7628d977 384:82ce1988fefe
47 uint16_t size; 47 uint16_t size;
48 uint8_t *buffer; 48 uint8_t *buffer;
49 } I2C_Buffer; 49 } I2C_Buffer;
50 50
51 typedef struct LED_Buffer { 51 typedef struct LED_Buffer {
52 uint8_t i2c_addr;
53 uint8_t reg_addr;
52 uint8_t buffer[LED_BufferLength]; 54 uint8_t buffer[LED_BufferLength];
53 } LED_Buffer; 55 } LED_Buffer;
54 56
55 57
56 58
57 // ----- Function Declarations ----- 59 // ----- Function Declarations -----
58 60
59 // CLI Functions 61 // CLI Functions
60 void cliFunc_i2cRecv ( char* args ); 62 void cliFunc_i2cRecv ( char* args );
61 void cliFunc_i2cSend ( char* args ); 63 void cliFunc_i2cSend ( char* args );
64 void cliFunc_ledCtrl ( char* args );
62 void cliFunc_ledRPage( char* args ); 65 void cliFunc_ledRPage( char* args );
63 void cliFunc_ledStart( char* args ); 66 void cliFunc_ledStart( char* args );
64 void cliFunc_ledTest ( char* args ); 67 void cliFunc_ledTest ( char* args );
65 void cliFunc_ledWPage( char* args ); 68 void cliFunc_ledWPage( char* args );
66 void cliFunc_ledZero ( char* args ); 69 void cliFunc_ledZero ( char* args );
75 // ----- Variables ----- 78 // ----- Variables -----
76 79
77 // Scan Module command dictionary 80 // Scan Module command dictionary
78 CLIDict_Entry( i2cRecv, "Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence." NL "\t\tUse |'s to split sequences with a stop." ); 81 CLIDict_Entry( i2cRecv, "Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence." NL "\t\tUse |'s to split sequences with a stop." );
79 CLIDict_Entry( i2cSend, "Send I2C sequence of bytes. Use |'s to split sequences with a stop." ); 82 CLIDict_Entry( i2cSend, "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
83 CLIDict_Entry( ledCtrl, "Basic LED control. Args: <mode> <amount> [<index>]" );
80 CLIDict_Entry( ledRPage, "Read the given register page." ); 84 CLIDict_Entry( ledRPage, "Read the given register page." );
81 CLIDict_Entry( ledStart, "Disable software shutdown." ); 85 CLIDict_Entry( ledStart, "Disable software shutdown." );
82 CLIDict_Entry( ledTest, "Test out the led pages." ); 86 CLIDict_Entry( ledTest, "Test out the led pages." );
83 CLIDict_Entry( ledWPage, "Write to given register page starting at address. i.e. 0x2 0x24 0xF0 0x12" ); 87 CLIDict_Entry( ledWPage, "Write to given register page starting at address. i.e. 0x2 0x24 0xF0 0x12" );
84 CLIDict_Entry( ledZero, "Zero out LED register pages (non-configuration)." ); 88 CLIDict_Entry( ledZero, "Zero out LED register pages (non-configuration)." );
85 89
86 CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = { 90 CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = {
87 CLIDict_Item( i2cRecv ), 91 CLIDict_Item( i2cRecv ),
88 CLIDict_Item( i2cSend ), 92 CLIDict_Item( i2cSend ),
93 CLIDict_Item( ledCtrl ),
89 CLIDict_Item( ledRPage ), 94 CLIDict_Item( ledRPage ),
90 CLIDict_Item( ledStart ), 95 CLIDict_Item( ledStart ),
91 CLIDict_Item( ledTest ), 96 CLIDict_Item( ledTest ),
92 CLIDict_Item( ledWPage ), 97 CLIDict_Item( ledWPage ),
93 CLIDict_Item( ledZero ), 98 CLIDict_Item( ledZero ),
176 181
177 I2C0_C1 = I2C_C1_IICEN; 182 I2C0_C1 = I2C_C1_IICEN;
178 } 183 }
179 else 184 else
180 { 185 {
181 dbug_print("Attempting to read byte"); 186 dbug_msg("Attempting to read byte - ");
187 printHex( I2C_RxBuffer.sequencePos );
188 print( NL );
182 I2C0_C1 = I2C_RxBuffer.sequencePos == 1 189 I2C0_C1 = I2C_RxBuffer.sequencePos == 1
183 ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read 190 ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read
184 : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read 191 : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read
185 } 192 }
186 } 193 }
307 while ( I2C_Send( buffer, len, 0 ) == 0 ) 314 while ( I2C_Send( buffer, len, 0 ) == 0 )
308 delay(1); 315 delay(1);
309 316
310 } 317 }
311 318
312 void LED_readPage( uint8_t len, uint8_t page ) 319 void LED_writeReg( uint8_t reg, uint8_t val, uint8_t page )
313 { 320 {
314 // Page Setup 321 // Page Setup
315 uint8_t pageSetup[] = { 0xE8, 0xFD, page }; 322 uint8_t pageSetup[] = { 0xE8, 0xFD, page };
323
324 // Reg Write Setup
325 uint8_t writeData[] = { 0xE8, reg, val };
316 326
317 // Setup page 327 // Setup page
318 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 ) 328 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
319 delay(1); 329 delay(1);
320 330
321 // Register Setup 331 while ( I2C_Send( writeData, sizeof( writeData ), 0 ) == 0 )
322 uint8_t regSetup[] = { 0xE8, 0x00 };
323
324 // Setup starting register
325 while ( I2C_Send( regSetup, sizeof( regSetup ), 0 ) == 0 )
326 delay(1); 332 delay(1);
327 333 }
328 // Register Read Command 334
329 uint8_t regReadCmd[] = { 0xE9 }; 335 void LED_readPage( uint8_t len, uint8_t page )
330 336 {
331 // Read each register in the page 337 // Software shutdown must be enabled to read registers
332 for ( uint8_t reg = 0; reg < len; reg++ ) 338 LED_writeReg( 0x0A, 0x00, 0x0B );
333 { 339
334 // Request register data
335 while ( I2C_Send( regReadCmd, sizeof( regReadCmd ), 0 ) == 0 )
336 delay(1);
337 }
338 }
339
340 void LED_writeReg( uint8_t reg, uint8_t val, uint8_t page )
341 {
342 // Page Setup 340 // Page Setup
343 uint8_t pageSetup[] = { 0xE8, 0xFD, page }; 341 uint8_t pageSetup[] = { 0xE8, 0xFD, page };
344
345 // Reg Write Setup
346 uint8_t writeData[] = { 0xE8, reg, val };
347 342
348 // Setup page 343 // Setup page
349 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 ) 344 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
350 delay(1); 345 delay(1);
351 346
352 while ( I2C_Send( writeData, sizeof( writeData ), 0 ) == 0 ) 347 // Register Setup
353 delay(1); 348 uint8_t regSetup[] = { 0xE8, 0x00 };
349
350 // Read each register in the page
351 for ( uint8_t reg = 0; reg < len; reg++ )
352 {
353 // Update register to read
354 regSetup[1] = reg;
355
356 // Configure register
357 while ( I2C_Send( regSetup, sizeof( regSetup ), 0 ) == 0 )
358 delay(1);
359
360 // Register Read Command
361 uint8_t regReadCmd[] = { 0xE9 };
362
363 // Request single register byte
364 while ( I2C_Send( regReadCmd, sizeof( regReadCmd ), 1 ) == 0 )
365 delay(1);
366 dbug_print("NEXT");
367 }
368
369 // Disable software shutdown
370 LED_writeReg( 0x0A, 0x01, 0x0B );
354 } 371 }
355 372
356 // Setup 373 // Setup
357 inline void LED_setup() 374 inline void LED_setup()
358 { 375 {
617 return 0; 634 return 0;
618 } 635 }
619 636
620 637
621 638
639 // ----- Capabilities -----
640
641 // Basic LED Control Capability
642 typedef enum LedControlMode {
643 // Single LED Modes
644 LedControlMode_brightness_decrease,
645 LedControlMode_brightness_increase,
646 LedControlMode_brightness_set,
647 // Set all LEDs (index argument not required)
648 LedControlMode_brightness_decrease_all,
649 LedControlMode_brightness_increase_all,
650 LedControlMode_brightness_set_all,
651 } LedControlMode;
652
653 typedef struct LedControl {
654 LedControlMode mode; // XXX Make sure to adjust the .kll capability if this variable is larger than 8 bits
655 uint8_t amount;
656 uint16_t index;
657 } LedControl;
658
659 uint8_t LED_control_timer = 0;
660 void LED_control( LedControl *control )
661 {
662 // Only send if we've completed all other transactions
663 if ( I2C_TxBuffer.sequencePos > 0 )
664 return;
665
666 // XXX
667 // ISSI Chip locks up if we spam updates too quickly (might be an I2C bug on this side too -HaaTa)
668 // Make sure we only send an update every 30 milliseconds at most
669 // It may be possible to optimize speed even further, but will likely require serious time with a logic analyzer
670
671 uint8_t currentTime = (uint8_t)systick_millis_count;
672 int8_t compare = (int8_t)(currentTime - LED_control_timer) & 0x7F;
673 if ( compare < 30 )
674 {
675 return;
676 }
677 LED_control_timer = currentTime;
678
679 // Configure based upon the given mode
680 // TODO Handle multiple issi chips per node
681 // TODO Perhaps do gamma adjustment?
682 switch ( control->mode )
683 {
684 case LedControlMode_brightness_decrease:
685 // Don't worry about rolling over, the cycle is quick
686 LED_pageBuffer.buffer[ control->index ] -= control->amount;
687 break;
688
689 case LedControlMode_brightness_increase:
690 // Don't worry about rolling over, the cycle is quick
691 LED_pageBuffer.buffer[ control->index ] += control->amount;
692 break;
693
694 case LedControlMode_brightness_set:
695 LED_pageBuffer.buffer[ control->index ] = control->amount;
696 break;
697
698 case LedControlMode_brightness_decrease_all:
699 for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
700 {
701 // Don't worry about rolling over, the cycle is quick
702 LED_pageBuffer.buffer[ channel ] -= control->amount;
703 }
704 break;
705
706 case LedControlMode_brightness_increase_all:
707 for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
708 {
709 // Don't worry about rolling over, the cycle is quick
710 LED_pageBuffer.buffer[ channel ] += control->amount;
711 }
712 break;
713
714 case LedControlMode_brightness_set_all:
715 for ( uint8_t channel = 0; channel < LED_BufferLength; channel++ )
716 {
717 LED_pageBuffer.buffer[ channel ] = control->amount;
718 }
719 break;
720 }
721
722 // Sync LED buffer with ISSI chip buffer
723 // TODO Support multiple frames
724 LED_pageBuffer.i2c_addr = 0xE8; // Chip 1
725 LED_pageBuffer.reg_addr = 0x24; // Brightness section
726 LED_sendPage( (uint8_t*)&LED_pageBuffer, sizeof( LED_Buffer ), 0 );
727 }
728
729 void LED_control_capability( uint8_t state, uint8_t stateType, uint8_t *args )
730 {
731 // Display capability name
732 if ( stateType == 0xFF && state == 0xFF )
733 {
734 print("LED_control_capability(mode,amount,index)");
735 return;
736 }
737
738 // Only use capability on press
739 // TODO Analog
740 if ( stateType == 0x00 && state == 0x03 ) // Not on release
741 return;
742
743 // Set the input structure
744 LedControl *control = (LedControl*)args;
745
746 // TODO broadcast to rest of interconnect nodes if necessary
747 LED_control( control );
748 }
749
750
751
622 // ----- CLI Command Functions ----- 752 // ----- CLI Command Functions -----
623 753
754 // TODO Currently not working correctly
624 void cliFunc_i2cSend( char* args ) 755 void cliFunc_i2cSend( char* args )
625 { 756 {
626 char* curArgs; 757 char* curArgs;
627 char* arg1Ptr; 758 char* arg1Ptr;
628 char* arg2Ptr = args; 759 char* arg2Ptr = args;
715 print( NL ); 846 print( NL );
716 847
717 I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip 848 I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip
718 } 849 }
719 850
851 // TODO Currently not working correctly
720 void cliFunc_ledRPage( char* args ) 852 void cliFunc_ledRPage( char* args )
721 { 853 {
722 // Parse number from argument 854 // Parse number from argument
723 // NOTE: Only first argument is used 855 // NOTE: Only first argument is used
724 char* arg1Ptr; 856 char* arg1Ptr;
728 // Default to 0 if no argument is given 860 // Default to 0 if no argument is given
729 uint8_t page = 0; 861 uint8_t page = 0;
730 862
731 if ( arg1Ptr[0] != '\0' ) 863 if ( arg1Ptr[0] != '\0' )
732 { 864 {
733 page = (uint8_t)numToInt( arg1Ptr ); 865 page = (uint8_t)numToInt( arg1Ptr );
734 } 866 }
735 867
736 // No \r\n by default after the command is entered 868 // No \r\n by default after the command is entered
737 print( NL ); 869 print( NL );
738 870
739 LED_readPage( 0xB4, page ); 871 LED_readPage( 0x1, page );
872 //LED_readPage( 0xB4, page );
740 } 873 }
741 874
742 void cliFunc_ledWPage( char* args ) 875 void cliFunc_ledWPage( char* args )
743 { 876 {
744 char* curArgs; 877 char* curArgs;
807 { 940 {
808 print( NL ); // No \r\n by default after the command is entered 941 print( NL ); // No \r\n by default after the command is entered
809 LED_zeroPages( 0x00, 8, 0x24, 0xB4 ); // Only PWMs 942 LED_zeroPages( 0x00, 8, 0x24, 0xB4 ); // Only PWMs
810 } 943 }
811 944
945 void cliFunc_ledCtrl( char* args )
946 {
947 char* curArgs;
948 char* arg1Ptr;
949 char* arg2Ptr = args;
950 LedControl control;
951
952 // First process mode
953 curArgs = arg2Ptr;
954 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
955
956 // Stop processing args if no more are found
957 if ( *arg1Ptr == '\0' )
958 return;
959 control.mode = numToInt( arg1Ptr );
960
961
962 // Next process amount
963 curArgs = arg2Ptr;
964 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
965
966 // Stop processing args if no more are found
967 if ( *arg1Ptr == '\0' )
968 return;
969 control.amount = numToInt( arg1Ptr );
970
971
972 // Finally process led index, if it exists
973 // Default to 0
974 curArgs = arg2Ptr;
975 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
976 control.index = *arg1Ptr == '\0' ? 0 : numToInt( arg1Ptr );
977
978 // Process request
979 LED_control( &control );
980 }
981