void cliFunc_ledReset( char* args ) { print( NL ); // No \r\n by default after the command is entered // Reset I2C bus #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 GPIO_Ctrl( iirst_pin, GPIO_Type_DriveSetup, GPIO_Config_Pullup ); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); delay_us(50); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); #endif i2c_reset(); // Clear control registers LED_zeroControlPages(); // Clear buffers for ( uint8_t buf = 0; buf < ISSI_Chips_define; buf++ ) { memset( (void*)LED_pageBuffer[ buf ].buffer, 0, LED_BufferLength * 2 ); } // Reset LEDs LED_reset(); }
// Called during each loop of the main bootloader sequence void Device_process() { // For keyboards with dual usb ports, doesn't do anything on keyboards without them // If a USB connection is not detected in 2 seconds, switch to the other port to see if it's plugged in there // USB not initialized, attempt to swap if ( usb.state != USBD_STATE_ADDRESS ) { // Only check for swapping after delay uint32_t wait_ms = systick_millis_count - last_ms; if ( wait_ms < USBPortSwapDelay_ms + attempt / 2 * USBPortSwapDelay_ms ) { return; } last_ms = systick_millis_count; print("USB not initializing, port swapping"); GPIO_Ctrl( usb_swap_pin, GPIO_Type_DriveToggle, GPIO_Config_None ); attempt++; } // Check for S1 being pressed if ( GPIO_Ctrl( sense_pin, GPIO_Type_Read, GPIO_Config_Pulldown ) ) { print( "Reset key pressed." NL ); SOFTWARE_RESET(); } }
// Called during bootloader initialization void Device_setup() { // Set LCD backlight on ICED to Red GPIO_Ctrl( red_chan_screen, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( red_chan_screen, GPIO_Type_DriveHigh, GPIO_Config_None ); // Cols (strobe) GPIO_Ctrl( strobe_pin, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( strobe_pin, GPIO_Type_DriveHigh, GPIO_Config_None ); // Rows (sense) GPIO_Ctrl( sense_pin, GPIO_Type_ReadSetup, GPIO_Config_Pulldown ); }
// Setup inline void Port_setup() { // Register Scan CLI dictionary CLI_registerDictionary( portCLIDict, portCLIDictName ); #if Port_SwapMode_define == USBSwap // USB Swap // Start, disabled GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); #elif Port_SwapMode_define == USBInterSwap // USB Swap // Start, disabled GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); // UART Tx/Rx cross-over // Start, disabled GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); // UART Swap // Start, disabled GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); #else warn_print("Unsupported"); #endif // Starting point for automatic port swapping Port_lastcheck_ms = systick_millis_count; // Allocate latency measurement resource portLatencyResource = Latency_add_resource("PortSwap", LatencyOption_Ticks); }
// Called during each loop of the main bootloader sequence void Device_process() { // Check for S7 being pressed if ( GPIO_Ctrl( sense_pin, GPIO_Type_Read, GPIO_Config_Pulldown ) ) { print( "Reset key pressed." NL ); SOFTWARE_RESET(); } }
// Called during bootloader initialization void Chip_setup() { // Disable WDT WDT->WDT_MR = WDT_MR_WDDIS; // Enable Debug LED const GPIO_Pin debug_led = gpio(B,0); GPIO_Ctrl( debug_led, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( debug_led, GPIO_Type_DriveHigh, GPIO_Config_None ); // Initialize non-volatile storage storage_init(); // Make sure USB transceiver is reset (in case we didn't do a full reset) udc_stop(); // Start USB stack udc_start(); }
// Called during bootloader initialization void Device_setup() { // PTA4 - USB Swap // Start, disabled GPIO_Ctrl( usb_swap_pin, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( usb_swap_pin, GPIO_Type_DriveLow, GPIO_Config_None ); // Setup parameters for USB port swap last_ms = systick_millis_count; attempt = 0; // Setup scanning for S1 // Col 1 (strobe) GPIO_Ctrl( strobe_pin, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( strobe_pin, GPIO_Type_DriveHigh, GPIO_Config_None ); // Row 1 (sense) GPIO_Ctrl( sense_pin, GPIO_Type_ReadSetup, GPIO_Config_Pulldown ); }
// Called during bootloader initialization void Chip_setup() { // XXX McHCK uses B16 instead of A19 // Enabling LED to indicate we are in the bootloader // Setup pin - A19 - See Lib/pin_map.mchck for more details on pins GPIO_Ctrl( debug_led, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( debug_led, GPIO_Type_DriveHigh, GPIO_Config_None ); /* print( "Cur Secure Code - "); printHex_op( Chip_secure1, 8 ); printHex_op( Chip_secure2, 8 ); print( NL ); print( "New Secure Code - "); printHex_op( VBAT_SECURE1, 8 ); printHex_op( VBAT_SECURE2, 8 ); print( NL ); */ }
void Port_uart_swap() { #if Port_SwapMode_define == USBInterSwap info_print("Interconnect Line Swap"); // UART Swap GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); #else warn_print("Unsupported"); #endif }
void Port_cross() { #if Port_SwapMode_define == USBInterSwap info_print("Interconnect Line Cross"); // UART Tx/Rx cross-over GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); // Reset interconnects Connect_reset(); #else warn_print("Unsupported"); #endif }
void Port_usb_swap() { #if Port_SwapMode_define == USBSwap || Port_SwapMode_define == USBInterSwap info_print("USB Port Swap"); // USB Swap GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); // Re-initialize usb // Call usb_configured() to check if usb is ready usb_reinit(); #else warn_print("Unsupported"); #endif }
inline void LED_scan() { // Latency measurement start Latency_start_time( ledLatencyResource ); // Check for current change event if ( LED_currentEvent ) { // Turn LEDs off in low power mode if ( LED_currentEvent < 150 ) { LED_enable_current = 0; // Pause animations and clear display Pixel_setAnimationControl( AnimationControl_WipePause ); } else { LED_enable_current = 1; // Start animations Pixel_setAnimationControl( AnimationControl_Forward ); } LED_currentEvent = 0; } // Check if an LED_pause is set // Some ISSI operations need a clear buffer, but still have the chip running if ( LED_pause ) goto led_finish_scan; // Check enable state if ( LED_enable && LED_enable_current ) { // Disable Hardware shutdown of ISSI chips (pull high) GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); } // Only write pages to I2C if chip is enabled (i.e. Hardware shutdown is disabled) else { // Enable hardware shutdown GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); goto led_finish_scan; } // Check if any I2C buses have errored // Reset the buses and restart the Frame State if ( i2c_error() ) { i2c_reset(); Pixel_FrameState = FrameState_Update; } // Only start if we haven't already // And if we've finished updating the buffers if ( Pixel_FrameState == FrameState_Sending ) goto led_finish_scan; // Only send frame to ISSI chip if buffers are ready if ( Pixel_FrameState != FrameState_Ready ) goto led_finish_scan; // Adjust frame rate (i.e. delay and do something else for a bit) Time duration = Time_duration( LED_timePrev ); if ( duration.ms < LED_framerate ) goto led_finish_scan; // FPS Display if ( LED_displayFPS ) { // Show frame calculation dbug_msg("1frame/"); printInt32( Time_ms( duration ) ); print("ms + "); printInt32( duration.ticks ); print(" ticks"); // Check if we're not meeting frame rate if ( duration.ms > LED_framerate ) { print(" - Could not meet framerate: "); printInt32( LED_framerate ); } print( NL ); } // Emulated brightness control // Lower brightness by LED_brightness #if ISSI_Chip_31FL3731_define == 1 for ( uint8_t chip = 0; chip < ISSI_Chips_define; chip++ ) { for ( uint8_t ch = 0; ch < LED_EnableBufferLength; ch++ ) { LED_pageBuffer_brightness[ chip ].ledctrl[ ch ] = LED_pageBuffer[ chip ].ledctrl[ ch ]; } for ( uint8_t ch = 0; ch < LED_BufferLength; ch++ ) { // Don't modify is 0 if ( LED_pageBuffer[ chip ].buffer[ ch ] == 0 || LED_brightness == 0 ) { LED_pageBuffer_brightness[ chip ].buffer[ ch ] = 0; continue; } // XXX (HaaTa) Yes, this is a bit slow, but it's pretty accurate LED_pageBuffer_brightness[ chip ].buffer[ ch ] = (LED_pageBuffer[ chip ].buffer[ ch ] * LED_brightness) / 0xFF; } } #endif // Update frame start time LED_timePrev = Time_now(); // Set the page of all the ISSI chips // This way we can easily link the buffers to send the brightnesses in the background for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) { uint8_t bus = LED_ChannelMapping[ ch ].bus; // Page Setup LED_setupPage( bus, LED_ChannelMapping[ ch ].addr, ISSI_LEDPwmPage ); } // Send current set of buffers // Uses interrupts to send to all the ISSI chips // Pixel_FrameState will be updated when complete LED_chipSend = 0; // Start with chip 0 LED_linkedSend(); led_finish_scan: // Latency measurement end Latency_end_time( ledLatencyResource ); }
// Setup inline void LED_setup() { // Register Scan CLI dictionary CLI_registerDictionary( ledCLIDict, ledCLIDictName ); #if Storage_Enable_define == 1 Storage_registerModule(&LedStorage); #endif // Zero out FPS time LED_timePrev = Time_now(); // Initialize framerate LED_framerate = ISSI_FrameRate_ms_define; // Global brightness setting LED_brightness = ISSI_Global_Brightness_define; // Initialize I2C error counters i2c_initial(); // Initialize I2C i2c_setup(); // Setup LED_pageBuffer addresses and brightness section LED_pageBuffer[0].i2c_addr = LED_MapCh1_Addr_define; LED_pageBuffer[0].reg_addr = ISSI_LEDPwmRegStart; #if ISSI_Chips_define >= 2 LED_pageBuffer[1].i2c_addr = LED_MapCh2_Addr_define; LED_pageBuffer[1].reg_addr = ISSI_LEDPwmRegStart; #endif #if ISSI_Chips_define >= 3 LED_pageBuffer[2].i2c_addr = LED_MapCh3_Addr_define; LED_pageBuffer[2].reg_addr = ISSI_LEDPwmRegStart; #endif #if ISSI_Chips_define >= 4 LED_pageBuffer[3].i2c_addr = LED_MapCh4_Addr_define; LED_pageBuffer[3].reg_addr = ISSI_LEDPwmRegStart; #endif // Brightness emulation #if ISSI_Chip_31FL3731_define // Setup LED_pageBuffer addresses and brightness section LED_pageBuffer_brightness[0].i2c_addr = LED_MapCh1_Addr_define; LED_pageBuffer_brightness[0].reg_addr = ISSI_LEDPwmRegStart; #if ISSI_Chips_define >= 2 LED_pageBuffer_brightness[1].i2c_addr = LED_MapCh2_Addr_define; LED_pageBuffer_brightness[1].reg_addr = ISSI_LEDPwmRegStart; #endif #if ISSI_Chips_define >= 3 LED_pageBuffer_brightness[2].i2c_addr = LED_MapCh3_Addr_define; LED_pageBuffer_brightness[2].reg_addr = ISSI_LEDPwmRegStart; #endif #if ISSI_Chips_define >= 4 LED_pageBuffer_brightness[3].i2c_addr = LED_MapCh4_Addr_define; LED_pageBuffer_brightness[3].reg_addr = ISSI_LEDPwmRegStart; #endif #endif // LED default setting LED_enable = ISSI_Enable_define; LED_enable_current = ISSI_Enable_define; // Needs a default setting, almost always unset immediately // Enable Hardware shutdown (pull low) GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveSetup, GPIO_Config_Pullup ); GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 // Reset I2C bus (pull high, then low) // NOTE: This GPIO may be shared with the debug LED GPIO_Ctrl( iirst_pin, GPIO_Type_DriveSetup, GPIO_Config_Pullup ); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); delay_us(50); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); #endif // Zero out Frame Registers // This needs to be done before disabling the hardware shutdown (or the leds will do undefined things) LED_zeroControlPages(); // Disable Hardware shutdown of ISSI chips (pull high) if ( LED_enable && LED_enable_current ) { GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); } // Reset LED sequencing LED_reset(); // Allocate latency resource ledLatencyResource = Latency_add_resource("ISSILed", LatencyOption_Ticks); }
void LED_reset() { // Force PixelMap to stop during reset Pixel_FrameState = FrameState_Sending; // Disable FPS by default LED_displayFPS = 0; // Enable Hardware shutdown (pull low) GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveSetup, GPIO_Config_Pullup ); GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); delay_us(50); #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 // Reset I2C bus GPIO_Ctrl( iirst_pin, GPIO_Type_DriveSetup, GPIO_Config_Pullup ); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); delay_us(50); GPIO_Ctrl( iirst_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup ); #endif // Disable Hardware shutdown of ISSI chips (pull high) if ( LED_enable && LED_enable_current ) { GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup ); } // Clear LED Pages // Enable LEDs based upon mask for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) { uint8_t addr = LED_ChannelMapping[ ch ].addr; uint8_t bus = LED_ChannelMapping[ ch ].bus; #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 // POR (Power-on-Reset) // Clears all registers to default value (i.e. zeros) LED_readReg( bus, addr, 0x11, ISSI_ConfigPage ); // Set the enable mask LED_sendPage( bus, addr, (uint16_t*)&LED_ledEnableMask[ ch ], sizeof( LED_EnableBuffer ) / 2, 0 ); #else // Clear LED control pages LED_zeroPages( bus, addr, 0x00, ISSI_LEDPages, 0x00, ISSI_PageLength ); // LED Registers // Copy enable mask to send buffer for ( uint8_t reg = 0; reg < LED_EnableBufferLength; reg++ ) { LED_pageBuffer[ ch ].ledctrl[ reg ] = LED_ledEnableMask[ ch ].buffer[ reg ]; } #endif } // Reset global brightness LED_brightness = settings.brightness; #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 // Enable pull-up and pull-down anti-ghosting resistors // Set global brightness control for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) { uint8_t addr = LED_ChannelMapping[ ch ].addr; uint8_t bus = LED_ChannelMapping[ ch ].bus; LED_writeReg( bus, addr, 0x01, LED_brightness, ISSI_ConfigPage ); LED_writeReg( bus, addr, 0x0F, 0x07, ISSI_ConfigPage ); // Pull-up LED_writeReg( bus, addr, 0x10, 0x07, ISSI_ConfigPage ); // Pull-down } #elif ISSI_Chip_31FL3732_define == 1 // Set global brightness control for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) { uint8_t addr = LED_ChannelMapping[ ch ].addr; uint8_t bus = LED_ChannelMapping[ ch ].bus; LED_writeReg( bus, addr, 0x04, LED_brightness, ISSI_ConfigPage ); } #endif // Setup ISSI frame and sync modes; then disable software shutdown for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) { uint8_t addr = LED_ChannelMapping[ ch ].addr; uint8_t bus = LED_ChannelMapping[ ch ].bus; #if ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 // Enable master sync for the last chip and disable software shutdown // XXX (HaaTa); The last chip is used as it is the last chip all of the frame data is sent to // This is imporant as it may take more time to send the packet than the ISSI chip can handle // between frames. if ( ch == ISSI_Chips_define - 1 ) { LED_writeReg( bus, addr, 0x00, 0x41, ISSI_ConfigPage ); } // Slave sync for the rest and disable software shutdown else { LED_writeReg( bus, addr, 0x00, 0x81, ISSI_ConfigPage ); } #elif ISSI_Chip_31FL3732_define == 1 // Enable master sync for the first chip if ( ch == 0 ) { LED_writeReg( bus, addr, 0x00, 0x40, ISSI_ConfigPage ); } // Slave sync for the rest else { LED_writeReg( bus, addr, 0x00, 0x80, ISSI_ConfigPage ); } // Disable Software shutdown of ISSI chip LED_writeReg( bus, addr, 0x0A, 0x01, ISSI_ConfigPage ); #else // Set MODE to Picture Frame LED_writeReg( bus, addr, 0x00, 0x00, ISSI_ConfigPage ); // Disable Software shutdown of ISSI chip LED_writeReg( bus, addr, 0x0A, 0x01, ISSI_ConfigPage ); #endif } // Force PixelMap to be ready for the next frame Pixel_FrameState = FrameState_Update; // Un-pause ISSI processing LED_pause = 0; }
// Called early-on during ResetHandler void Chip_reset() { // Generating Secure Key print( "Generating Secure Key..." NL ); // Read current 64 bit secure number Chip_secure1 = GPBR_SECURE1; Chip_secure2 = GPBR_SECURE2; // Generate 64 bit random numbers while ( !rand_available() ); GPBR_SECURE1 = rand_value32(); while ( !rand_available() ); GPBR_SECURE2 = rand_value32(); // Disable rand generation rand_disable(); // Secure indicator string (lsusb), iInterface uint16_t *indicator_string = dfu_device_str_desc[4]->bString; uint16_t replacement = u' '; // Replace with space in secure mode // If using an external reset, disable secure validation // Or if the flash is blank if ( // PIN (External Reset Pin/Switch) (REG_RSTC_SR & RSTC_SR_RSTTYP_Msk) == RSTC_SR_RSTTYP_UserReset // WDOG (Watchdog timeout) || (REG_RSTC_SR & RSTC_SR_RSTTYP_Msk) == RSTC_SR_RSTTYP_WatchdogReset // Blank flash check || _app_rom == 0xffffffff || (Chip_secure1 == 0 && Chip_secure2 == 0) ) { print( "Secure Key Bypassed." NL ); Chip_secure1 = 0; Chip_secure2 = 0; // Replace with \0 to hide part of string replacement = u'\0'; } // Modify iInterface delimiter for ( uint8_t pos = 0; indicator_string[ pos ] != u'\0'; pos++ ) { // Looking for | character if ( indicator_string[ pos ] == u'|' ) { indicator_string[ pos ] = replacement; // If shortening, also change length if ( replacement == u'\0' ) { dfu_device_str_desc[4]->bLength = pos * 2 + 2; } } } print( "Secure Key Generated." NL ); // Make sure debug LED is off const GPIO_Pin debug_led = gpio(B,0); GPIO_Ctrl( debug_led, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( debug_led, GPIO_Type_DriveLow, GPIO_Config_None ); }
// Setup GPIO pins for matrix scanning void Matrix_setup() { // Register Matrix CLI dictionary CLI_registerDictionary( matrixCLIDict, matrixCLIDictName ); #if defined(_sam_) // 31.5.8 Reading the I/O line levels requires the clock of the PIO Controller to be enabled PMC->PMC_PCER0 = (1 << ID_PIOA) | (1 << ID_PIOB); #endif // Setup Strobe Pins for ( uint8_t pin = 0; pin < Matrix_colsNum; pin++ ) { GPIO_Ctrl( Matrix_cols[ pin ], GPIO_Type_DriveSetup, Matrix_type ); } // Setup Sense Pins for ( uint8_t pin = 0; pin < Matrix_rowsNum; pin++ ) { GPIO_Ctrl( Matrix_rows[ pin ], GPIO_Type_ReadSetup, Matrix_type ); } // Clear out Debounce Array for ( uint8_t item = 0; item < Matrix_maxKeys; item++ ) { Matrix_scanArray[ item ].prevState = KeyState_Off; Matrix_scanArray[ item ].curState = KeyState_Off; Matrix_scanArray[ item ].activeCount = 0; Matrix_scanArray[ item ].inactiveCount = DebounceDivThreshold; // Start at 'off' steady state Matrix_scanArray[ item ].prevDecisionTime = 0; } // Reset strobe position matrixCurrentStrobe = 0; // Debug mode matrixDebugMode = 0; // Debug counter reset matrixDebugStateCounter = 0; // Debounce expiry time debounceExpiryTime = MinDebounceTime_define; // Strobe delay setting strobeDelayTime = StrobeDelay_define; // Setup tick duration (multiples of 1 second) activity_tick_duration = Time_init(); activity_tick_duration.ms = 1000 * ActivityTimerMultiplier_define; // Setup Activity and Inactivity tick resources Time_tick_start( &activity_tickstore, activity_tick_duration, TickStore_MaxTicks ); Time_tick_start( &inactivity_tickstore, activity_tick_duration, TickStore_MaxTicks ); // Clear matrixStateActiveCount for activity check matrixStateActiveCount = 0; matrixStatePressCount = 0; matrixStateReleaseCount = 0; // Setup latency module matrixLatencyResource = Latency_add_resource("MatrixARMPeri", LatencyOption_Ticks); }
// Single strobe matrix scan // Only goes through a single strobe // This module keeps track of the next strobe to scan uint8_t Matrix_single_scan() { // Start latency measurement Latency_start_time( matrixLatencyResource ); // Read systick for event scheduling uint32_t currentTime = systick_millis_count; // Current strobe uint8_t strobe = matrixCurrentStrobe; // XXX (HaaTa) // Before strobing drain each sense line // This helps with faulty pull-up resistors (particularily with SAM4S) for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveSetup, Matrix_type ); #if ScanCodeMatrixInvert_define == 2 // GPIO_Config_Pulldown GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveLow, Matrix_type ); #elif ScanCodeMatrixInvert_define == 1 // GPIO_Config_Pullup GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_DriveHigh, Matrix_type ); #endif GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_ReadSetup, Matrix_type ); } // Strobe Pin GPIO_Ctrl( Matrix_cols[ strobe ], GPIO_Type_DriveHigh, Matrix_type ); // Used to allow the strobe signal to propagate, generally not required if ( strobeDelayTime > 0 ) { delay_us( strobeDelayTime ); } // Scan each of the sense pins for ( uint8_t sense = 0; sense < Matrix_rowsNum; sense++ ) { // Key position uint16_t key = Matrix_colsNum * sense + strobe; #if ScanCodeRemapping_define == 1 uint16_t key_disp = matrixScanCodeRemappingMatrix[key]; #else uint16_t key_disp = key + 1; // 1-indexed for reporting purposes #endif // Check bounds, before attempting to scan // 1-indexed as ScanCode 0 is not used if ( key_disp > MaxScanCode_KLL || key_disp == 0 ) { continue; } volatile KeyState *state = &Matrix_scanArray[ key ]; // Signal Detected // Increment count and right shift opposing count // This means there is a maximum of scan 13 cycles on a perfect off to on transition // (coming from a steady state 0xFFFF off scans) // Somewhat longer with switch bounciness // The advantage of this is that the count is ongoing and never needs to be reset // State still needs to be kept track of to deal with what to send to the Macro module // Compared against the default state value (ScanCodeMatrixInvert_define), usually 0 if ( GPIO_Ctrl( Matrix_rows[ sense ], GPIO_Type_Read, Matrix_type ) != ScanCodeMatrixInvert_define ) { // Only update if not going to wrap around if ( state->activeCount < DebounceDivThreshold ) state->activeCount += 1; state->inactiveCount >>= 1; } // Signal Not Detected else { // Only update if not going to wrap around if ( state->inactiveCount < DebounceDivThreshold ) state->inactiveCount += 1; state->activeCount >>= 1; } // Check for state change // But only if: // 1) Enough time has passed since last state change // 2) Either active or inactive count is over the debounce threshold // Update previous state state->prevState = state->curState; // Determine time since last decision uint32_t lastTransition = currentTime - state->prevDecisionTime; // Attempt state transition switch ( state->prevState ) { case KeyState_Press: case KeyState_Hold: if ( state->activeCount > state->inactiveCount ) { state->curState = KeyState_Hold; } else { // If not enough time has passed since Hold // Keep previous state if ( lastTransition < debounceExpiryTime ) { state->curState = state->prevState; Macro_keyState( key_disp, state->curState ); continue; } state->curState = KeyState_Release; } break; case KeyState_Release: case KeyState_Off: if ( state->activeCount > state->inactiveCount ) { // If not enough time has passed since Hold // Keep previous state if ( lastTransition < debounceExpiryTime ) { state->curState = state->prevState; Macro_keyState( key_disp, state->curState ); continue; } state->curState = KeyState_Press; } else { state->curState = KeyState_Off; } break; case KeyState_Invalid: default: erro_msg("Matrix scan bug!! Report me! - "); printHex( state->prevState ); print(" Col: "); printHex( strobe ); print(" Row: "); printHex( sense ); print(" Key: "); printHex( key_disp ); print( NL ); break; } // Update decision time state->prevDecisionTime = currentTime; // Send keystate to macro module Macro_keyState( key_disp, state->curState ); // Check for activity and inactivity if ( state->curState != KeyState_Off ) { matrixStateActiveCount++; } switch ( state->curState ) { case KeyState_Press: matrixStatePressCount++; break; case KeyState_Release: matrixStateReleaseCount++; break; default: break; } // Matrix Debug, only if there is a state change if ( matrixDebugMode && state->curState != state->prevState ) { // Basic debug output if ( matrixDebugMode == 1 && state->curState == KeyState_Press ) { printInt16( key_disp ); print(":"); printHex( key_disp ); print(" "); } // State transition debug output else if ( matrixDebugMode == 2 ) { printInt16( key_disp ); Matrix_keyPositionDebug( state->curState ); print(" "); } else if ( matrixDebugMode == 3 ) { print("\033[1m"); printInt16( key_disp ); print("\033[0m"); print(":"); Matrix_keyPositionDebug( Matrix_scanArray[ key ].prevState ); Matrix_keyPositionDebug( Matrix_scanArray[ key ].curState ); print(" 0x"); printHex_op( state->activeCount, 2 ); print(" 0x"); printHex_op( state->inactiveCount, 2 ); print(" "); printInt32( lastTransition ); print( NL ); } } }