- Updated port switching pins (split USB and UART switching) - Added basic support for 2nd i2c bus - Updated key matrix - Fixed udev rules - Added missing register definesICPad
@@ -4,7 +4,7 @@ ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", ENV{MTP_NO_PROBE}="1" | |||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", MODE:="0666" | |||
# Kiibohd Serial Interface | |||
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", SYMLINK+="kiibohd", MODE:="0666", | |||
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", SYMLINK+="kiibohd", MODE:="0666" | |||
KERNEL=="ttyACM*", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="b04d", SYMLINK+="kiibohd", MODE:="0666" | |||
KERNEL=="ttyACM*", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="f05c", SYMLINK+="kiibohd", MODE:="0666" | |||
@@ -1,7 +1,7 @@ | |||
/* Teensyduino Core Library | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2013 PJRC.COM, LLC. | |||
* Modified by Jacob Alexander 2014-2015 | |||
* Modified by Jacob Alexander 2014-2016 | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining | |||
* a copy of this software and associated documentation files (the | |||
@@ -1457,6 +1457,20 @@ typedef struct { | |||
#define I2C0_SLTH *(volatile uint8_t *)0x4006600A // I2C SCL Low Timeout Register High | |||
#define I2C0_SLTL *(volatile uint8_t *)0x4006600B // I2C SCL Low Timeout Register Low | |||
#define I2C1_A1 *(volatile uint8_t *)0x40067000 // I2C Address Register 1 | |||
#define I2C1_F *(volatile uint8_t *)0x40067001 // I2C Frequency Divider register | |||
#define I2C1_C1 *(volatile uint8_t *)0x40067002 // I2C Control Register 1 | |||
#define I2C1_S *(volatile uint8_t *)0x40067003 // I2C Status register | |||
#define I2C1_D *(volatile uint8_t *)0x40067004 // I2C Data I/O register | |||
#define I2C1_C2 *(volatile uint8_t *)0x40067005 // I2C Control Register 2 | |||
#define I2C1_FLT *(volatile uint8_t *)0x40067006 // I2C Programmable Input Glitch Filter register | |||
#define I2C1_RA *(volatile uint8_t *)0x40067007 // I2C Range Address register | |||
#define I2C1_SMB *(volatile uint8_t *)0x40067008 // I2C SMBus Control and Status register | |||
#define I2C1_A2 *(volatile uint8_t *)0x40067009 // I2C Address Register 2 | |||
#define I2C1_SLTH *(volatile uint8_t *)0x4006700A // I2C SCL Low Timeout Register High | |||
#define I2C1_SLTL *(volatile uint8_t *)0x4006700B // I2C SCL Low Timeout Register Low | |||
// Chapter 45: Universal Asynchronous Receiver/Transmitter (UART) | |||
#define UART0_BDH *(volatile uint8_t *)0x4006A000 // UART Baud Rate Registers: High | |||
#define UART0_BDL *(volatile uint8_t *)0x4006A001 // UART Baud Rate Registers: Low |
@@ -111,7 +111,7 @@ PixelBuf Pixel_Buffers[] = { | |||
// Pixel Mapping | |||
#define Pixel_TotalPixels 128 // TODO Generate | |||
#define Pixel_TotalPixels 127 // TODO Generate | |||
PixelElement Pixel_Mapping[] = { | |||
// Function Row (1-16) | |||
Pixel_RGBChannel(0,33,49), // 1 | |||
@@ -2593,7 +2593,8 @@ inline void Pixel_process() | |||
uint16_t ch; | |||
// Only update 50 positions at a time | |||
for ( ch = Pixel_testPos; ch < Pixel_testPos + 50 && ch < Pixel_TotalChannels; ch++ ) | |||
for ( ch = Pixel_testPos; ch < Pixel_TotalChannels; ch++ ) | |||
//for ( ch = Pixel_testPos; ch < Pixel_testPos + 50 && ch < Pixel_TotalChannels; ch++ ) | |||
{ | |||
// Toggle channel | |||
Pixel_channelToggle( ch ); |
@@ -39,6 +39,9 @@ | |||
#include <arm/usb_serial.h> | |||
#endif | |||
// KLL | |||
#include <kll_defs.h> | |||
// Local Includes | |||
#include "output_com.h" | |||
@@ -117,15 +120,25 @@ uint8_t USBKeys_SentCLI = 0; | |||
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | |||
volatile uint8_t USBKeys_LEDs = 0; | |||
// Currently pressed mouse buttons, bitmask, 0 represents no buttons pressed | |||
volatile uint16_t USBMouse_Buttons = 0; | |||
// Relative mouse axis movement, stores pending movement | |||
volatile uint16_t USBMouse_Relative_x = 0; | |||
volatile uint16_t USBMouse_Relative_y = 0; | |||
// Protocol setting from the host. | |||
// 0 - Boot Mode | |||
// 1 - NKRO Mode (Default, unless set by a BIOS or boot interface) | |||
volatile uint8_t USBKeys_Protocol = 1; | |||
volatile uint8_t USBKeys_Protocol = USBProtocol_define; | |||
// Indicate if USB should send update | |||
// OS only needs update if there has been a change in state | |||
USBKeyChangeState USBKeys_Changed = USBKeyChangeState_None; | |||
// Indicate if USB should send update | |||
USBMouseChangeState USBMouse_Changed = 0; | |||
// the idle configuration, how often we send the report to the | |||
// host (ms * 4) even when it hasn't changed | |||
uint8_t USBKeys_Idle_Config = 125; | |||
@@ -511,6 +524,63 @@ void Output_flashMode_capability( uint8_t state, uint8_t stateType, uint8_t *arg | |||
Output_firmwareReload(); | |||
} | |||
// Sends a mouse command over the USB Output buffer | |||
// XXX This function *will* be changing in the future | |||
// If you use it, be prepared that your .kll files will break in the future (post KLL 0.5) | |||
// Argument #1: USB Mouse Button (16 bit) | |||
// Argument #2: USB X Axis (16 bit) relative | |||
// Argument #3: USB Y Axis (16 bit) relative | |||
void Output_usbMouse_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Output_usbMouse(mouseButton,relX,relY)"); | |||
return; | |||
} | |||
// Determine which mouse button was sent | |||
// The USB spec defines up to a max of 0xFFFF buttons | |||
// The usual are: | |||
// 1 - Button 1 - (Primary) | |||
// 2 - Button 2 - (Secondary) | |||
// 3 - Button 3 - (Tertiary) | |||
uint16_t mouse_button = *(uint16_t*)(&args[0]); | |||
// X/Y Relative Axis | |||
uint16_t mouse_x = *(uint16_t*)(&args[2]); | |||
uint16_t mouse_y = *(uint16_t*)(&args[4]); | |||
// Adjust for bit shift | |||
uint16_t mouse_button_shift = mouse_button - 1; | |||
// Only send mouse button if in press or hold state | |||
if ( stateType == 0x00 && state == 0x03 ) // Release state | |||
{ | |||
// Release | |||
if ( mouse_button ) | |||
USBMouse_Buttons &= ~(1 << mouse_button_shift); | |||
} | |||
else | |||
{ | |||
// Press or hold | |||
if ( mouse_button ) | |||
USBMouse_Buttons |= (1 << mouse_button_shift); | |||
if ( mouse_x ) | |||
USBMouse_Relative_x = mouse_x; | |||
if ( mouse_y ) | |||
USBMouse_Relative_y = mouse_y; | |||
} | |||
// Trigger updates | |||
if ( mouse_button ) | |||
USBMouse_Changed |= USBMouseChangeState_Buttons; | |||
if ( mouse_x || mouse_y ) | |||
USBMouse_Changed |= USBMouseChangeState_Relative; | |||
} | |||
// ----- Functions ----- |
@@ -1,6 +1,6 @@ | |||
Name = ISSILedCapabilities; | |||
Version = 0.2; | |||
Author = "HaaTa (Jacob Alexander) 2015"; | |||
Author = "HaaTa (Jacob Alexander) 2015-2016"; | |||
KLL = 0.3d; | |||
# Modified Date | |||
@@ -22,12 +22,35 @@ Date = 2015-10-09; | |||
# i.e. 23 then 144 | |||
ledControl => LED_control_capability( mode : 1, amount : 1, index : 2 ); | |||
# Defines available to the ISSILed sub-module | |||
# Driver Chip | |||
# Selects which driver chip being used | |||
# Set to 1 to enable | |||
# Valid Chips | |||
# 31FL3731 - http://www.issi.com/WW/pdf/31FL3731.pdf (31FL3731C has the same datasheet) | |||
# 31FL3732 - http://www.issi.com/WW/pdf/31FL3732.pdf | |||
ISSI_Chip_31FL3731 => ISSI_Chip_31FL3731_define; | |||
ISSI_Chip_31FL3732 => ISSI_Chip_31FL3732_define; | |||
ISSI_Chip_31FL3731 = 0; | |||
ISSI_Chip_31FL3732 = 0; | |||
# Global Brightness | |||
# 31FL3732 only | |||
# 0 to 0xFF (255) | |||
# See datasheet for current calculation, depends on Rext | |||
ISSI_Global_Brightness => ISSI_Global_Brightness_define; | |||
ISSI_Global_Brightness = 0xFF; | |||
# Available ISSI Chips | |||
ISSI_Chips => ISSI_Chips_define; | |||
ISSI_Chips = 1; # 1 by default | |||
# I2C Buses | |||
ISSI_I2C_Buses => ISSI_I2C_Buses_define; | |||
ISSI_I2C_Buses = 1; # 1 by default | |||
# Default animation speed | |||
# Can be set from 0 to 63 (A) | |||
# Formula is TxA (T is approx 11ms) | |||
@@ -40,9 +63,9 @@ ISSI_Chips = 1; # 1 by default | |||
# For a 400 kHz I2C, with a single chip, updating all 144 channels, generally 30 fps is the max for continuous animations | |||
# Each additional chip consumes more bandwidth | |||
# 20 - 4.5 fps - Slow, but should always work without glitches | |||
# See (http://www.issi.com/WW/pdf/31FL3731C.pdf) for details | |||
# See chip datasheet (above) for details | |||
ISSI_AnimationSpeed => ISSI_AnimationSpeed_define; | |||
ISSI_AnimationSpeed = 20; # 20 by default | |||
ISSI_AnimationSpeed = 4; # 20 by default | |||
# LED Default Enable Mask | |||
# |
@@ -1,6 +1,6 @@ | |||
/* | |||
* Copyright ( C ) 2014 Jan Rychter | |||
* Modifications ( C ) 2015 Jacob Alexander | |||
* Copyright (C) 2014 Jan Rychter | |||
* Modifications (C) 2015-2016 Jacob Alexander | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files ( the "Software" ), to deal | |||
@@ -28,6 +28,7 @@ | |||
// Project Includes | |||
#include <print.h> | |||
#include <kll_defs.h> | |||
// Local Includes | |||
#include "i2c.h" | |||
@@ -36,38 +37,78 @@ | |||
// ----- Variables ----- | |||
volatile I2C_Channel i2c_channels[1]; | |||
volatile I2C_Channel i2c_channels[ISSI_I2C_Buses_define]; | |||
uint32_t i2c_offset[] = { | |||
0x0, // Bus 0 | |||
0x1000, // Bus 1 | |||
}; | |||
// ----- Functions ----- | |||
inline void i2c_setup( ) | |||
inline void i2c_setup() | |||
{ | |||
// Enable I2C internal clock | |||
SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0 | |||
// External pull-up resistor | |||
PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
// SCL Frequency Divider | |||
// 1.8 MBaud ( likely higher than spec ) | |||
// 0x82 -> 36 MHz / (4 * 3) = 2.25 MBaud | |||
// 0x80 => mul(4) | |||
// 0x05 => ICL(5) | |||
I2C0_F = 0x84; | |||
I2C0_FLT = 4; | |||
I2C0_C1 = I2C_C1_IICEN; | |||
I2C0_C2 = I2C_C2_HDRS; // High drive select | |||
// Enable I2C Interrupt | |||
NVIC_ENABLE_IRQ( IRQ_I2C0 ); | |||
for ( uint8_t ch = 0; ch < ISSI_I2C_Buses_define; ch++ ) | |||
{ | |||
volatile uint8_t *I2C_F = (uint8_t*)(&I2C0_F) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_FLT = (uint8_t*)(&I2C0_FLT) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_C2 = (uint8_t*)(&I2C0_C2) + i2c_offset[ch]; | |||
switch ( ch ) | |||
{ | |||
case 0: | |||
// Enable I2C internal clock | |||
SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0 | |||
// External pull-up resistor | |||
PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
break; | |||
case 1: | |||
// Enable I2C internal clock | |||
SIM_SCGC4 |= SIM_SCGC4_I2C1; // Bus 1 | |||
// External pull-up resistor | |||
PORTC_PCR10 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
PORTC_PCR11 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2); | |||
break; | |||
} | |||
// SCL Frequency Divider | |||
// 1.8 MBaud ( likely higher than spec ) | |||
// 0x82 -> 36 MHz / (4 * 3) = 2.25 MBaud | |||
// 0x80 => mul(4) | |||
// 0x05 => ICL(5) | |||
*I2C_F = 0x84; | |||
*I2C_FLT = 4; | |||
*I2C_C1 = I2C_C1_IICEN; | |||
*I2C_C2 = I2C_C2_HDRS; // High drive select | |||
switch ( ch ) | |||
{ | |||
case 0: | |||
// Enable I2C Interrupt | |||
NVIC_ENABLE_IRQ( IRQ_I2C0 ); | |||
break; | |||
case 1: | |||
// Enable I2C Interrupt | |||
NVIC_ENABLE_IRQ( IRQ_I2C1 ); | |||
break; | |||
} | |||
} | |||
} | |||
uint8_t i2c_busy() | |||
uint8_t i2c_busy( uint8_t ch ) | |||
{ | |||
volatile I2C_Channel *channel = &( i2c_channels[0] ); | |||
volatile I2C_Channel *channel = &( i2c_channels[ch] ); | |||
if ( channel->status == I2C_BUSY ) | |||
{ | |||
return 1; | |||
@@ -76,19 +117,35 @@ uint8_t i2c_busy() | |||
return 0; | |||
} | |||
uint8_t i2c_any_busy() | |||
{ | |||
for ( uint8_t ch = 0; ch < ISSI_I2C_Buses_define; ch++ ) | |||
{ | |||
if ( i2c_busy( ch ) ) | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
// These are here for readability and correspond to bit 0 of the address byte. | |||
#define I2C_WRITING 0 | |||
#define I2C_READING 1 | |||
int32_t i2c_send_sequence( | |||
uint8_t ch, | |||
uint16_t *sequence, | |||
uint32_t sequence_length, | |||
uint8_t *received_data, | |||
void ( *callback_fn )( void* ), | |||
void *user_data | |||
) { | |||
volatile I2C_Channel *channel = &( i2c_channels[0] ); | |||
volatile I2C_Channel *channel = &( i2c_channels[ch] ); | |||
volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_S = (uint8_t*)(&I2C0_S) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_D = (uint8_t*)(&I2C0_D) + i2c_offset[ch]; | |||
int32_t result = 0; | |||
uint8_t status; | |||
@@ -118,13 +175,13 @@ int32_t i2c_send_sequence( | |||
// reads_ahead does not need to be initialized | |||
// Acknowledge the interrupt request, just in case | |||
I2C0_S |= I2C_S_IICIF; | |||
I2C0_C1 = ( I2C_C1_IICEN | I2C_C1_IICIE ); | |||
*I2C_S |= I2C_S_IICIF; | |||
*I2C_C1 = ( I2C_C1_IICEN | I2C_C1_IICIE ); | |||
// Generate a start condition and prepare for transmitting. | |||
I2C0_C1 |= ( I2C_C1_MST | I2C_C1_TX ); | |||
*I2C_C1 |= ( I2C_C1_MST | I2C_C1_TX ); | |||
status = I2C0_S; | |||
status = *I2C_S; | |||
if ( status & I2C_S_ARBL ) | |||
{ | |||
warn_print("Arbitration lost"); | |||
@@ -133,34 +190,42 @@ int32_t i2c_send_sequence( | |||
} | |||
// Write the first (address) byte. | |||
I2C0_D = *channel->sequence++; | |||
*I2C_D = *channel->sequence++; | |||
// Everything is OK. | |||
return result; | |||
i2c_send_sequence_cleanup: | |||
I2C0_C1 &= ~( I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX ); | |||
*I2C_C1 &= ~( I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX ); | |||
channel->status = I2C_ERROR; | |||
return result; | |||
} | |||
void i2c0_isr() | |||
void i2c_isr( uint8_t ch ) | |||
{ | |||
volatile I2C_Channel* channel = &i2c_channels[0]; | |||
volatile I2C_Channel* channel = &i2c_channels[ch]; | |||
volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_S = (uint8_t*)(&I2C0_S) + i2c_offset[ch]; | |||
volatile uint8_t *I2C_D = (uint8_t*)(&I2C0_D) + i2c_offset[ch]; | |||
uint8_t element; | |||
uint8_t status; | |||
status = I2C0_S; | |||
status = *I2C_S; | |||
// Acknowledge the interrupt request | |||
I2C0_S |= I2C_S_IICIF; | |||
*I2C_S |= I2C_S_IICIF; | |||
// Arbitration problem | |||
if ( status & I2C_S_ARBL ) | |||
{ | |||
warn_print("Arbitration error"); | |||
I2C0_S |= I2C_S_ARBL; | |||
warn_msg("Arbitration error. Bus: "); | |||
printHex( ch ); | |||
print(NL); | |||
*I2C_S |= I2C_S_ARBL; | |||
goto i2c_isr_error; | |||
} | |||
@@ -174,17 +239,17 @@ void i2c0_isr() | |||
// switch to TX mode, either to generate a repeated start condition, or to avoid triggering another I2C read | |||
// when reading the contents of the data register. | |||
case 0: | |||
I2C0_C1 |= I2C_C1_TX; | |||
*I2C_C1 |= I2C_C1_TX; | |||
// Perform the final data register read now that it's safe to do so. | |||
*channel->received_data++ = I2C0_D; | |||
*channel->received_data++ = *I2C_D; | |||
// Do we have a repeated start? | |||
if ( ( channel->sequence < channel->sequence_end ) && ( *channel->sequence == I2C_RESTART ) ) | |||
{ | |||
// Generate a repeated start condition. | |||
I2C0_C1 |= I2C_C1_RSTA; | |||
*I2C_C1 |= I2C_C1_RSTA; | |||
// A restart is processed immediately, so we need to get a new element from our sequence. This is safe, because | |||
// a sequence cannot end with a RESTART: there has to be something after it. Note that the only thing that can | |||
@@ -192,7 +257,7 @@ void i2c0_isr() | |||
channel->txrx = I2C_WRITING; | |||
channel->sequence++; | |||
element = *channel->sequence; | |||
I2C0_D = element; | |||
*I2C_D = element; | |||
} | |||
else | |||
{ | |||
@@ -202,12 +267,12 @@ void i2c0_isr() | |||
case 1: | |||
// do not ACK the final read | |||
I2C0_C1 |= I2C_C1_TXAK; | |||
*channel->received_data++ = I2C0_D; | |||
*I2C_C1 |= I2C_C1_TXAK; | |||
*channel->received_data++ = *I2C_D; | |||
break; | |||
default: | |||
*channel->received_data++ = I2C0_D; | |||
*channel->received_data++ = *I2C_D; | |||
break; | |||
} | |||
@@ -234,7 +299,7 @@ void i2c0_isr() | |||
// Do we have a restart? If so, generate repeated start and make sure TX is on. | |||
if ( element == I2C_RESTART ) | |||
{ | |||
I2C0_C1 |= I2C_C1_RSTA | I2C_C1_TX; | |||
*I2C_C1 |= I2C_C1_RSTA | I2C_C1_TX; | |||
// A restart is processed immediately, so we need to get a new element from our sequence. | |||
// This is safe, because a sequence cannot end with a RESTART: there has to be something after it. | |||
@@ -242,7 +307,7 @@ void i2c0_isr() | |||
element = *channel->sequence; | |||
// Note that the only thing that can come after a restart is a write. | |||
I2C0_D = element; | |||
*I2C_D = element; | |||
} | |||
else | |||
{ | |||
@@ -260,29 +325,29 @@ void i2c0_isr() | |||
} | |||
// Switch to RX mode. | |||
I2C0_C1 &= ~I2C_C1_TX; | |||
*I2C_C1 &= ~I2C_C1_TX; | |||
// do not ACK the final read | |||
if ( channel->reads_ahead == 1 ) | |||
{ | |||
I2C0_C1 |= I2C_C1_TXAK; | |||
*I2C_C1 |= I2C_C1_TXAK; | |||
} | |||
// ACK all but the final read | |||
else | |||
{ | |||
I2C0_C1 &= ~( I2C_C1_TXAK ); | |||
*I2C_C1 &= ~( I2C_C1_TXAK ); | |||
} | |||
// Dummy read comes first, note that this is not valid data! | |||
// This only triggers a read, actual data will come in the next interrupt call and overwrite this. | |||
// This is why we do not increment the received_data pointer. | |||
*channel->received_data = I2C0_D; | |||
*channel->received_data = *I2C_D; | |||
channel->reads_ahead--; | |||
} | |||
// Not a restart, not a read, must be a write. | |||
else | |||
{ | |||
I2C0_D = element; | |||
*I2C_D = element; | |||
} | |||
} | |||
} | |||
@@ -292,13 +357,14 @@ void i2c0_isr() | |||
i2c_isr_stop: | |||
// Generate STOP ( set MST=0 ), switch to RX mode, and disable further interrupts. | |||
I2C0_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE | I2C_C1_TXAK ); | |||
*I2C_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE | I2C_C1_TXAK ); | |||
channel->status = I2C_AVAILABLE; | |||
// Call the user-supplied callback function upon successful completion (if it exists). | |||
if ( channel->callback_fn ) | |||
{ | |||
// Delay 10 microseconds before starting linked function | |||
// TODO, is this chip dependent? -HaaTa | |||
delayMicroseconds(10); | |||
( *channel->callback_fn )( channel->user_data ); | |||
} | |||
@@ -306,8 +372,18 @@ i2c_isr_stop: | |||
i2c_isr_error: | |||
// Generate STOP and disable further interrupts. | |||
I2C0_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE ); | |||
*I2C_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE ); | |||
channel->status = I2C_ERROR; | |||
return; | |||
} | |||
void i2c0_isr() | |||
{ | |||
i2c_isr( 0 ); | |||
} | |||
void i2c1_isr() | |||
{ | |||
i2c_isr( 1 ); | |||
} | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Copyright (C) 2014 Jan Rychter | |||
* Modifications (C) 2015 Jacob Alexander | |||
* Modifications (C) 2015-2016 Jacob Alexander | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files (the "Software"), to deal | |||
@@ -58,16 +58,10 @@ typedef struct { | |||
// ----- Variables ----- | |||
extern volatile I2C_Channel i2c_channels[1]; | |||
// ----- Functions ----- | |||
/* | |||
* I2C Module Setup - Channel 0 only | |||
* I2C Module Setup | |||
*/ | |||
void i2c_setup(); | |||
@@ -95,6 +89,7 @@ void i2c_setup(); | |||
*/ | |||
int32_t i2c_send_sequence( | |||
uint8_t ch, | |||
uint16_t *sequence, | |||
uint32_t sequence_length, | |||
uint8_t *received_data, | |||
@@ -105,11 +100,12 @@ int32_t i2c_send_sequence( | |||
/* | |||
* Convenience macros | |||
*/ | |||
#define i2c_send(seq, seq_len) i2c_send_sequence( seq, seq_len, 0, 0, 0 ) | |||
#define i2c_read(seq, seq_len, rec) i2c_send_sequence( seq, seq_len, rec, 0, 0 ) | |||
#define i2c_send(ch, seq, seq_len) i2c_send_sequence( ch, seq, seq_len, 0, 0, 0 ) | |||
#define i2c_read(ch, seq, seq_len, rec) i2c_send_sequence( ch, seq, seq_len, rec, 0, 0 ) | |||
/* | |||
* Check if busy | |||
*/ | |||
uint8_t i2c_busy(); | |||
uint8_t i2c_busy( uint8_t ch ); | |||
uint8_t i2c_any_busy(); | |||
@@ -52,34 +52,65 @@ | |||
// ISSI Addresses | |||
// IS31FL3731 (max 4 channels per bus) | |||
#if 1 | |||
#if ISSI_Chip_31FL3731_define == 1 | |||
#define ISSI_Ch1 0xE8 | |||
#define ISSI_Ch2 0xEA | |||
#define ISSI_Ch3 0xEC | |||
#define ISSI_Ch4 0xEE | |||
// IS31FL3732 (max 16 channels per bus) | |||
#elif ISSI_Chip_31FL3732_define == 1 | |||
#define ISSI_Ch1 0xA0 | |||
#define ISSI_Ch2 0xA2 | |||
#define ISSI_Ch3 0xA4 | |||
#define ISSI_Ch4 0xA6 | |||
#define ISSI_Ch5 0xA8 | |||
#define ISSI_Ch6 0xAA | |||
#define ISSI_Ch7 0xAC | |||
#define ISSI_Ch8 0xAE | |||
#define ISSI_Ch9 0xB0 | |||
#define ISSI_Ch10 0xB2 | |||
#define ISSI_Ch11 0xB4 | |||
#define ISSI_Ch12 0xB6 | |||
#define ISSI_Ch13 0xB8 | |||
#define ISSI_Ch14 0xBA | |||
#define ISSI_Ch15 0xBC | |||
#define ISSI_Ch16 0xBE | |||
#else | |||
#define ISSI_Ch1 0xB0 | |||
#define ISSI_Ch2 0xB2 | |||
#define ISSI_Ch3 0xB4 | |||
#define ISSI_Ch4 0xB6 | |||
#error "ISSI Driver Chip not defined in Scan defaultMap.kll..." | |||
#endif | |||
// TODO Generate in KLL | |||
#define LED_MapCh1_Bus_define 0x0 | |||
#define LED_MapCh1_Addr_define ISSI_Ch1 | |||
#define LED_MapCh2_Bus_define 0x0 | |||
#define LED_MapCh2_Addr_define ISSI_Ch2 | |||
#define LED_MapCh3_Bus_define 0x1 | |||
#define LED_MapCh3_Addr_define ISSI_Ch1 | |||
#define LED_MapCh4_Bus_define 0x1 | |||
#define LED_MapCh4_Addr_define ISSI_Ch2 | |||
// ----- Macros ----- | |||
#define LED_ChannelMapDefine(ch) \ | |||
{ \ | |||
LED_MapCh##ch##_Bus_define, /* I2C bus number */ \ | |||
LED_MapCh##ch##_Addr_define, /* I2C address */ \ | |||
} | |||
#define LED_MaskDefine(ch) \ | |||
{ \ | |||
ISSI_Ch##ch, /* I2C address */ \ | |||
LED_MapCh##ch##_Addr_define, /* I2C address */ \ | |||
0x00, /* Starting register address */ \ | |||
{ ISSILedMask##ch##_define }, \ | |||
} | |||
#define LED_BrightnessDefine(ch) \ | |||
{ \ | |||
ISSI_Ch##ch, /* I2C address */ \ | |||
LED_MapCh##ch##_Addr_define, /* I2C address */ \ | |||
0x24, /* Starting register address */ \ | |||
{ ISSILedBrightness##ch##_define }, \ | |||
} | |||
@@ -100,6 +131,11 @@ typedef struct LED_EnableBuffer { | |||
uint16_t buffer[LED_EnableBufferLength]; | |||
} LED_EnableBuffer; | |||
typedef struct LED_ChannelMap { | |||
uint8_t bus; | |||
uint8_t addr; | |||
} LED_ChannelMap; | |||
// ----- Function Declarations ----- | |||
@@ -129,7 +165,7 @@ CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = { | |||
}; | |||
volatile LED_Buffer LED_pageBuffer[ ISSI_Chips_define ]; | |||
volatile LED_Buffer LED_pageBuffer[ISSI_Chips_define]; | |||
uint8_t LED_FrameBuffersReady; // Starts at maximum, reset on interrupt from ISSI | |||
volatile uint8_t LED_FrameBufferReset; // INTB interrupt received, reset available buffer count when ready | |||
@@ -138,6 +174,21 @@ volatile uint8_t LED_FrameBufferReset; // INTB interrupt received, reset availa | |||
uint8_t LED_displayFPS; // Display fps to cli | |||
// TODO - Autogenerate for each keyboard | |||
// ISSI Driver Channel to Bus:Address mapping | |||
const LED_ChannelMap LED_ChannelMapping[ISSI_Chips_define] = { | |||
LED_ChannelMapDefine( 1 ), | |||
#if ISSI_Chips_define >= 2 | |||
LED_ChannelMapDefine( 2 ), | |||
#endif | |||
#if ISSI_Chips_define >= 3 | |||
LED_ChannelMapDefine( 3 ), | |||
#endif | |||
#if ISSI_Chips_define >= 4 | |||
LED_ChannelMapDefine( 4 ), | |||
#endif | |||
}; | |||
// Enable mask and default brightness for ISSI chip channel | |||
const LED_EnableBuffer LED_ledEnableMask[ISSI_Chips_define] = { | |||
LED_MaskDefine( 1 ), | |||
@@ -192,7 +243,7 @@ void portb_isr() | |||
// ----- Functions ----- | |||
void LED_zeroPages( uint8_t addr, uint8_t startPage, uint8_t numPages, uint8_t startReg, uint8_t endReg ) | |||
void LED_zeroPages( uint8_t bus, uint8_t addr, uint8_t startPage, uint8_t numPages, uint8_t startReg, uint8_t endReg ) | |||
{ | |||
// Clear Page | |||
// Max length of a page + chip id + reg start | |||
@@ -207,20 +258,20 @@ void LED_zeroPages( uint8_t addr, uint8_t startPage, uint8_t numPages, uint8_t s | |||
uint16_t pageSetup[] = { addr, 0xFD, page }; | |||
// Setup page | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
// Zero out page | |||
while ( i2c_send( clearPage, 2 + endReg - startReg ) == -1 ) | |||
while ( i2c_send( bus, clearPage, 2 + endReg - startReg ) == -1 ) | |||
delay(1); | |||
} | |||
// Wait until finished zero'ing | |||
while ( i2c_busy() ) | |||
while ( i2c_busy( bus ) ) | |||
delay(1); | |||
} | |||
void LED_sendPage( uint8_t addr, uint16_t *buffer, uint32_t len, uint8_t page ) | |||
void LED_sendPage( uint8_t bus, uint8_t addr, uint16_t *buffer, uint32_t len, uint8_t page ) | |||
{ | |||
/* | |||
info_msg("I2C Send Page Addr: "); | |||
@@ -236,11 +287,11 @@ void LED_sendPage( uint8_t addr, uint16_t *buffer, uint32_t len, uint8_t page ) | |||
uint16_t pageSetup[] = { addr, 0xFD, page }; | |||
// Setup page | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
// Write page to I2C Tx Buffer | |||
while ( i2c_send( buffer, len ) == -1 ) | |||
while ( i2c_send( bus, buffer, len ) == -1 ) | |||
delay(1); | |||
} | |||
@@ -253,9 +304,10 @@ void LED_syncReg( uint8_t reg, uint8_t val, uint8_t page ) | |||
// Setup each of the pages | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
pageSetup[0] = LED_pageBuffer[ ch ].i2c_addr; | |||
pageSetup[0] = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
} | |||
@@ -265,20 +317,21 @@ void LED_syncReg( uint8_t reg, uint8_t val, uint8_t page ) | |||
// Write to all the registers | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
writeData[0] = LED_pageBuffer[ ch ].i2c_addr; | |||
writeData[0] = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
// Delay very little to help with synchronization | |||
while ( i2c_send( writeData, sizeof( writeData ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, writeData, sizeof( writeData ) / 2 ) == -1 ) | |||
delayMicroseconds(10); | |||
} | |||
// Delay until written | |||
while ( i2c_busy() ) | |||
while ( i2c_any_busy() ) | |||
delay(1); | |||
} | |||
// Write address | |||
void LED_writeReg( uint8_t addr, uint8_t reg, uint8_t val, uint8_t page ) | |||
void LED_writeReg( uint8_t bus, uint8_t addr, uint8_t reg, uint8_t val, uint8_t page ) | |||
{ | |||
// Page Setup | |||
uint16_t pageSetup[] = { addr, 0xFD, page }; | |||
@@ -287,37 +340,37 @@ void LED_writeReg( uint8_t addr, uint8_t reg, uint8_t val, uint8_t page ) | |||
uint16_t writeData[] = { addr, reg, val }; | |||
// Setup page | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
// Write register | |||
while ( i2c_send( writeData, sizeof( writeData ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, writeData, sizeof( writeData ) / 2 ) == -1 ) | |||
delay(1); | |||
// Delay until written | |||
while ( i2c_busy() ) | |||
while ( i2c_busy( bus ) ) | |||
delay(1); | |||
} | |||
// Read address | |||
// TODO Not working? | |||
uint8_t LED_readReg( uint8_t addr, uint8_t reg, uint8_t page ) | |||
uint8_t LED_readReg( uint8_t bus, uint8_t addr, uint8_t reg, uint8_t page ) | |||
{ | |||
// Software shutdown must be enabled to read registers | |||
LED_writeReg( addr, 0x0A, 0x00, 0x0B ); | |||
LED_writeReg( bus, addr, 0x0A, 0x00, 0x0B ); | |||
// Page Setup | |||
uint16_t pageSetup[] = { addr, 0xFD, page }; | |||
// Setup page | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
// Register Setup | |||
uint16_t regSetup[] = { addr, reg }; | |||
// Configure register | |||
while ( i2c_send( regSetup, sizeof( regSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, regSetup, sizeof( regSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
// Register Read Command | |||
@@ -325,11 +378,11 @@ uint8_t LED_readReg( uint8_t addr, uint8_t reg, uint8_t page ) | |||
uint8_t recv_data; | |||
// Request single register byte | |||
while ( i2c_read( regReadCmd, sizeof( regReadCmd ) / 2, &recv_data ) == -1 ) | |||
while ( i2c_read( bus, regReadCmd, sizeof( regReadCmd ) / 2, &recv_data ) == -1 ) | |||
delay(1); | |||
// Disable software shutdown | |||
LED_writeReg( addr, 0x0A, 0x01, 0x0B ); | |||
LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B ); | |||
return recv_data; | |||
} | |||
@@ -352,13 +405,15 @@ void LED_reset() | |||
// Enable LEDs based upon mask | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
LED_zeroPages( addr, 0x00, 8, 0x00, 0xB4 ); // LED Registers | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_zeroPages( bus, addr, 0x00, 8, 0x00, 0xB4 ); // LED Registers | |||
// For each page | |||
for ( uint8_t pg = 0; pg < LED_FrameBuffersMax * 2; pg++ ) | |||
{ | |||
LED_sendPage( | |||
bus, | |||
addr, | |||
(uint16_t*)&LED_ledEnableMask[ ch ], | |||
sizeof( LED_EnableBuffer ) / 2, | |||
@@ -367,20 +422,33 @@ void LED_reset() | |||
} | |||
} | |||
// Set global brightness control | |||
#if ISSI_Chip_31FL3732_define == 1 | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
// See, 31FL3732 datasheet for details on calculation | |||
// Depends on Rext | |||
LED_writeReg( bus, addr, 0x04, ISSI_Global_Brightness_define, 0x0B ); | |||
} | |||
#endif | |||
// Setup ISSI auto frame play, but do not start yet | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
// CNS 1 loop, FNS 4 frames - 0x14 | |||
LED_writeReg( addr, 0x02, 0x14, 0x0B ); | |||
LED_writeReg( bus, addr, 0x02, 0x14, 0x0B ); | |||
// Default refresh speed - TxA | |||
// T is typically 11ms | |||
// A is 1 to 64 (where 0 is 64) | |||
LED_writeReg( addr, 0x03, ISSI_AnimationSpeed_define, 0x0B ); | |||
LED_writeReg( bus, addr, 0x03, ISSI_AnimationSpeed_define, 0x0B ); | |||
// Set MODE to Auto Frame Play | |||
LED_writeReg( addr, 0x00, 0x08, 0x0B ); | |||
LED_writeReg( bus, addr, 0x00, 0x08, 0x0B ); | |||
} | |||
// Do not disable software shutdown of ISSI chip unless current is high enough | |||
@@ -391,8 +459,9 @@ void LED_reset() | |||
// Disable Software shutdown of ISSI chip | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
LED_writeReg( addr, 0x0A, 0x01, 0x0B ); | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B ); | |||
} | |||
} | |||
} | |||
@@ -407,18 +476,18 @@ inline void LED_setup() | |||
i2c_setup(); | |||
// Setup LED_pageBuffer addresses and brightness section | |||
LED_pageBuffer[0].i2c_addr = ISSI_Ch1; | |||
LED_pageBuffer[0].i2c_addr = LED_MapCh1_Addr_define; | |||
LED_pageBuffer[0].reg_addr = 0x24; | |||
#if ISSI_Chips_define >= 2 | |||
LED_pageBuffer[1].i2c_addr = ISSI_Ch2; | |||
LED_pageBuffer[1].i2c_addr = LED_MapCh2_Addr_define; | |||
LED_pageBuffer[1].reg_addr = 0x24; | |||
#endif | |||
#if ISSI_Chips_define >= 3 | |||
LED_pageBuffer[2].i2c_addr = ISSI_Ch3; | |||
LED_pageBuffer[2].i2c_addr = LED_MapCh3_Addr_define; | |||
LED_pageBuffer[2].reg_addr = 0x24; | |||
#endif | |||
#if ISSI_Chips_define >= 4 | |||
LED_pageBuffer[3].i2c_addr = ISSI_Ch4; | |||
LED_pageBuffer[3].i2c_addr = LED_MapCh4_Addr_define; | |||
LED_pageBuffer[3].reg_addr = 0x24; | |||
#endif | |||
@@ -431,8 +500,9 @@ inline void LED_setup() | |||
// This needs to be done before disabling the hardware shutdown (or the leds will do undefined things) | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
LED_zeroPages( addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_zeroPages( bus, addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers | |||
} | |||
// Disable Hardware shutdown of ISSI chip (pull high) | |||
@@ -455,6 +525,7 @@ inline void LED_setup() | |||
// LED Linked Send | |||
// Call-back for i2c write when updating led display | |||
// TODO Optimize linked send for multiple i2c buses | |||
uint8_t LED_chipSend; | |||
void LED_linkedSend() | |||
{ | |||
@@ -476,6 +547,9 @@ void LED_linkedSend() | |||
// Update ISSI Frame State | |||
Pixel_FrameState = FrameState_Sending; | |||
// Lookup bus number | |||
uint8_t bus = LED_ChannelMapping[ LED_chipSend ].bus; | |||
// Debug | |||
/* | |||
dbug_msg("Linked Send: chip("); | |||
@@ -500,6 +574,7 @@ void LED_linkedSend() | |||
// Send, and recursively call this function when finished | |||
while ( i2c_send_sequence( | |||
bus, | |||
(uint16_t*)&LED_pageBuffer[ LED_chipSend ], | |||
sizeof( LED_Buffer ) / 2, | |||
0, | |||
@@ -527,8 +602,9 @@ inline void LED_scan() | |||
// Enable Software shutdown of ISSI chip | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
LED_writeReg( addr, 0x0A, 0x00, 0x0B ); | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_writeReg( bus, addr, 0x0A, 0x00, 0x0B ); | |||
} | |||
} | |||
else | |||
@@ -536,8 +612,9 @@ inline void LED_scan() | |||
// Disable Software shutdown of ISSI chip | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
LED_writeReg( addr, 0x0A, 0x01, 0x0B ); | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B ); | |||
} | |||
} | |||
@@ -602,11 +679,12 @@ inline void LED_scan() | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
// Page Setup | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
uint16_t pageSetup[] = { addr, 0xFD, LED_FrameBufferPage }; | |||
// Send each update | |||
while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 ) | |||
delay(1); | |||
} | |||
@@ -699,7 +777,12 @@ void LED_control( LedControl *control ) | |||
// TODO Support multiple frames | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
LED_sendPage( LED_pageBuffer[ ch ].i2c_addr, (uint16_t*)&LED_pageBuffer[ ch ], sizeof( LED_Buffer ) / 2, 0 ); | |||
LED_sendPage( | |||
LED_ChannelMapping[ ch ].bus, | |||
LED_ChannelMapping[ ch ].addr, | |||
(uint16_t*)&LED_pageBuffer[ ch ], | |||
sizeof( LED_Buffer ) / 2, 0 | |||
); | |||
} | |||
} | |||
@@ -806,6 +889,7 @@ void LED_control_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
// TODO Currently not working correctly | |||
void cliFunc_i2cSend( char* args ) | |||
{ | |||
/* | |||
char* curArgs; | |||
char* arg1Ptr; | |||
char* arg2Ptr = args; | |||
@@ -850,6 +934,7 @@ void cliFunc_i2cSend( char* args ) | |||
print( NL ); | |||
i2c_send( buffer, bufferLen ); | |||
*/ | |||
} | |||
/* | |||
@@ -917,8 +1002,11 @@ void cliFunc_ledReset( char* args ) | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
LED_zeroPages( LED_ledEnableMask[ ch ].i2c_addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers | |||
LED_zeroPages( | |||
LED_ChannelMapping[ ch ].bus, | |||
LED_ChannelMapping[ ch ].addr, | |||
0x0B, 1, 0x00, 0x0C | |||
); // Control Registers | |||
} | |||
// Clear buffers | |||
@@ -928,6 +1016,18 @@ void cliFunc_ledReset( char* args ) | |||
} | |||
LED_reset(); | |||
// TODO Remove me | |||
/* | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
LED_sendPage( | |||
LED_ChannelMapping[ ch ].bus, | |||
LED_ChannelMapping[ ch ].addr, | |||
0x0B, 1, 0x00, 0x0C | |||
); // Control Registers | |||
} | |||
*/ | |||
} | |||
void cliFunc_ledSpeed( char* args ) | |||
@@ -969,12 +1069,13 @@ void cliFunc_ledSpeed( char* args ) | |||
// Set refresh speed per ISSI chip | |||
for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ ) | |||
{ | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
// Default refresh speed - TxA | |||
// T is typically 11ms | |||
// A is 1 to 64 (where 0 is 64) | |||
LED_writeReg( addr, 0x03, speed, 0x0B ); | |||
LED_writeReg( bus, addr, 0x03, speed, 0x0B ); | |||
} | |||
} | |||
@@ -1039,8 +1140,10 @@ void cliFunc_ledNFrame( char* args ) | |||
// XXX It is more efficient to only send positions that are used | |||
// However, this may actually have more addressing overhead | |||
// For simplicity, just sending the full 144 positions per ISSI chip | |||
uint8_t addr = LED_pageBuffer[ ch ].i2c_addr; | |||
uint8_t addr = LED_ChannelMapping[ ch ].addr; | |||
uint8_t bus = LED_ChannelMapping[ ch ].bus; | |||
LED_sendPage( | |||
bus, | |||
addr, | |||
(uint16_t*)&LED_pageBuffer[ ch ], | |||
sizeof( LED_Buffer ) / 2, |
@@ -1,6 +1,6 @@ | |||
Name = KType; | |||
Version = 0.1; | |||
Author = "HaaTa (Jacob Alexander) 2015"; | |||
Version = 0.2; | |||
Author = "HaaTa (Jacob Alexander) 2015-2016"; | |||
KLL = 0.3c; | |||
# Modified Date | |||
@@ -115,11 +115,20 @@ S0x5D : U"Down"; | |||
S0x5E : U"Right"; | |||
# Driver Chip | |||
ISSI_Chip_31FL3732 = 1; | |||
# Global Brightness | |||
ISSI_Global_Brightness = 0xFF; # 0xFF by default (max) | |||
# Available ISSI Chips | |||
ISSI_Chips = 4; # 1 by default | |||
ISSI_Chips = 4; # 2 by default | |||
# I2C Buses | |||
ISSI_I2C_Buses = 2; # 1 by default | |||
# Default animation speed | |||
ISSI_AnimationSpeed = 14; # 20 by default | |||
ISSI_AnimationSpeed = 6; # 20 by default | |||
# LED Default Enable Mask | |||
# | |||
@@ -175,19 +184,6 @@ ISSILedMask4 = " | |||
0xFF, 0xFF, /* C9-1 -> C9-16 */ | |||
"; | |||
# Disabled for now | |||
#ISSILedMask4 = " | |||
# 0x00, 0x00, /* C1-1 -> C1-16 */ | |||
# 0x00, 0x00, /* C2-1 -> C2-16 */ | |||
# 0x00, 0x00, /* C3-1 -> C3-16 */ | |||
# 0x00, 0x00, /* C4-1 -> C4-16 */ | |||
# 0x00, 0x00, /* C5-1 -> C5-16 */ | |||
# 0x00, 0x00, /* C6-1 -> C6-16 */ | |||
# 0x00, 0x00, /* C7-1 -> C7-16 */ | |||
# 0x00, 0x00, /* C8-1 -> C8-16 */ | |||
# 0x00, 0x00, /* C9-1 -> C9-16 */ | |||
#"; | |||
ISSILedBrightness1 = " | |||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* C1-1 -> C1-16 */ | |||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* C2-1 -> C2-16 */ |
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2014-2015 by Jacob Alexander | |||
/* Copyright (C) 2014-2016 by Jacob Alexander | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files (the "Software"), to deal | |||
@@ -49,8 +49,8 @@ | |||
// PTC1..5 | |||
// Define Rows (Sense) and Columns (Strobes) | |||
GPIO_Pin Matrix_cols[] = { gpio(B,2), gpio(B,3), gpio(B,18), gpio(B,19), gpio(C,0), gpio(C,8), gpio(C,9), gpio(C,10), gpio(C,11), gpio(D,0) }; | |||
GPIO_Pin Matrix_rows[] = { gpio(D,1), gpio(D,4), gpio(D,5), gpio(D,6), gpio(D,7), gpio(C,1), gpio(C,2), gpio(C,3), gpio(C,4), gpio(C,5) }; | |||
GPIO_Pin Matrix_cols[] = { gpio(B,2), gpio(B,3), gpio(B,18), gpio(B,19), gpio(C,0), gpio(C,8), gpio(C,9), gpio(D,0), gpio(D,1), gpio(D,4) }; | |||
GPIO_Pin Matrix_rows[] = { gpio(D,5), gpio(D,6), gpio(D,7), gpio(C,1), gpio(C,2), gpio(C,3), gpio(C,4), gpio(C,5), gpio(C,6), gpio(C,7) }; | |||
// Define type of scan matrix | |||
Config Matrix_type = Config_Pulldown; |
@@ -82,7 +82,7 @@ inline uint8_t Scan_loop() | |||
Port_scan(); | |||
// Scan Matrix | |||
Matrix_scan( Scan_scanCount++ ); | |||
//Matrix_scan( Scan_scanCount++ ); | |||
// Process any interconnect commands | |||
Connect_scan(); |
@@ -409,7 +409,15 @@ void Matrix_scan( uint16_t scanNum ) | |||
case KeyState_Invalid: | |||
default: | |||
erro_print("Matrix scan bug!! Report me!"); | |||
erro_msg("Matrix scan bug!! Report me! - "); | |||
printHex( state->prevState ); | |||
print(" Col: "); | |||
printHex( strobe ); | |||
print(" Row: "); | |||
printHex( sense ); | |||
print(" Key: "); | |||
printHex( key ); | |||
print( NL ); | |||
break; | |||
} | |||
@@ -10,5 +10,8 @@ Date = 2015-10-23; | |||
portCross => Port_cross_capability(); | |||
# Capability to swap the USB port mapping | |||
portSwap => Port_swap_capability(); | |||
portSwapUSB => Port_usb_capability(); | |||
# Capability to swap the interconnect port mapping | |||
portSwapInter => Port_uart_capability(); | |||
@@ -1,4 +1,4 @@ | |||
/* Copyright (C) 2015 by Jacob Alexander | |||
/* Copyright (C) 2015-2016 by Jacob Alexander | |||
* | |||
* This file is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
@@ -52,7 +52,8 @@ | |||
// CLI Functions | |||
void cliFunc_portCross( char* args ); | |||
void cliFunc_portSwap ( char* args ); | |||
void cliFunc_portUART ( char* args ); | |||
void cliFunc_portUSB ( char* args ); | |||
@@ -62,11 +63,13 @@ uint32_t Port_lastcheck_ms; | |||
// Scan Module command dictionary | |||
CLIDict_Entry( portCross, "Cross interconnect pins." ); | |||
CLIDict_Entry( portSwap, "Swap USB ports manually, forces usb and interconnect to re-negotiate if necessary." ); | |||
CLIDict_Entry( portUSB, "Swap USB ports manually, forces usb and interconnect to re-negotiate if necessary." ); | |||
CLIDict_Entry( portUART, "Swap interconnect ports." ); | |||
CLIDict_Def( portCLIDict, "Port Swap Module Commands" ) = { | |||
CLIDict_Item( portCross ), | |||
CLIDict_Item( portSwap ), | |||
CLIDict_Item( portUART ), | |||
CLIDict_Item( portUSB ), | |||
{ 0, 0, 0 } // Null entry for dictionary end | |||
}; | |||
@@ -74,18 +77,26 @@ CLIDict_Def( portCLIDict, "Port Swap Module Commands" ) = { | |||
// ----- Functions ----- | |||
void Port_swap() | |||
void Port_usb_swap() | |||
{ | |||
info_print("USB Port Swap"); | |||
// PTA13 - USB Swap | |||
GPIOA_PTOR |= (1<<13); | |||
// PTA4 - USB Swap | |||
GPIOA_PTOR |= (1<<4); | |||
// Re-initialize usb | |||
// Call usb_configured() to check if usb is ready | |||
usb_init(); | |||
} | |||
void Port_uart_swap() | |||
{ | |||
info_print("Interconnect Line Swap"); | |||
// PTA13 - UART Swap | |||
GPIOA_PTOR |= (1<<13); | |||
} | |||
void Port_cross() | |||
{ | |||
info_print("Interconnect Line Cross"); | |||
@@ -103,13 +114,19 @@ inline void Port_setup() | |||
// Register Scan CLI dictionary | |||
CLI_registerDictionary( portCLIDict, portCLIDictName ); | |||
// PTA4 - USB Swap | |||
// Start, disabled | |||
GPIOA_PDDR |= (1<<4); | |||
PORTA_PCR4 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||
GPIOA_PCOR |= (1<<4); | |||
// PTA12 - UART Tx/Rx cross-over | |||
// Start, disabled | |||
GPIOA_PDDR |= (1<<12); | |||
PORTA_PCR12 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||
GPIOA_PCOR |= (1<<12); | |||
// PTA13 - USB Swap | |||
// PTA13 - UART Swap | |||
// Start, disabled | |||
GPIOA_PDDR |= (1<<13); | |||
PORTA_PCR13 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); | |||
@@ -136,7 +153,7 @@ inline uint8_t Port_scan() | |||
// USB not initialized, attempt to swap | |||
if ( !usb_configured() ) | |||
{ | |||
Port_swap(); | |||
Port_usb_swap(); | |||
} | |||
} | |||
@@ -155,12 +172,29 @@ void Port_currentChange( unsigned int current ) | |||
// ----- Capabilities ----- | |||
void Port_swap_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
void Port_uart_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Port_uart_capability()"); | |||
return; | |||
} | |||
// Only only release | |||
// TODO Analog | |||
if ( state != 0x03 ) | |||
return; | |||
Port_uart_swap(); | |||
} | |||
void Port_usb_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
{ | |||
// Display capability name | |||
if ( stateType == 0xFF && state == 0xFF ) | |||
{ | |||
print("Port_swap_capability()"); | |||
print("Port_usb_capability()"); | |||
return; | |||
} | |||
@@ -169,7 +203,7 @@ void Port_swap_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
if ( state != 0x03 ) | |||
return; | |||
Port_swap(); | |||
Port_usb_swap(); | |||
} | |||
void Port_cross_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
@@ -193,10 +227,16 @@ void Port_cross_capability( uint8_t state, uint8_t stateType, uint8_t *args ) | |||
// ----- CLI Command Functions ----- | |||
void cliFunc_portSwap( char* args ) | |||
void cliFunc_portUART( char* args ) | |||
{ | |||
print( NL ); | |||
Port_uart_swap(); | |||
} | |||
void cliFunc_portUSB( char* args ) | |||
{ | |||
print( NL ); | |||
Port_swap(); | |||
Port_usb_swap(); | |||
} | |||
void cliFunc_portCross( char* args ) |
@@ -1161,7 +1161,7 @@ void Connect_scan() | |||
} | |||
// Limit how often we do cable checks | |||
//uint32_t time_compare = 0x007; // Used for debugging cables -HaaTa | |||
//uint32_t time_compare = 0x007; // XXX Used for debugging cables -HaaTa | |||
uint32_t time_compare = 0x7FF; // Must be all 1's, 0x3FF is valid, 0x4FF is not | |||
uint32_t current_time = systick_millis_count; | |||
if ( Connect_lastCheck != current_time |