Mercurial > louis > kiibohd-controller
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 |