Exemple #1
0
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();
}
Exemple #2
0
// 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 );
}
Exemple #4
0
// 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();
	}
}
Exemple #6
0
// 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();
}
Exemple #7
0
// 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 );
}
Exemple #8
0
// 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 );
	*/
}
Exemple #9
0
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
}
Exemple #10
0
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
}
Exemple #11
0
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
}
Exemple #12
0
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 );
}
Exemple #13
0
// 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);
}
Exemple #14
0
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;
}
Exemple #15
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 );
}
Exemple #16
0
// 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);
}
Exemple #17
0
// 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 );
			}

		}
	}