From 14b7602a65dedaf51db1c9288144765d43a83a15 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 8 May 2018 15:24:18 -0400 Subject: Adds IS31FL3731 RGB Matrix Implementation (#2910) * adds is31fl3731 rgb matrix implementation * fix build script for force pushes * allow bootloader size to be overwritten * adds planck light implementation * split led config into 2 arrays * idk * betterize register handling * update planck implementation * update planck * refine rgb interface * cleanup names, rgb matrix * start documentation * finish up docs * add effects list * clean-up merge * add RGB_MATRIX_SKIP_FRAMES * add support for at90usb1286 to bootloader options --- drivers/avr/TWIlib.c | 232 ++++++++++++++++++++++++++++++++++++++++++ drivers/avr/TWIlib.h | 82 +++++++++++++++ drivers/avr/is31fl3731.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/avr/is31fl3731.h | 214 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 786 insertions(+) create mode 100644 drivers/avr/TWIlib.c create mode 100644 drivers/avr/TWIlib.h create mode 100644 drivers/avr/is31fl3731.c create mode 100644 drivers/avr/is31fl3731.h (limited to 'drivers') diff --git a/drivers/avr/TWIlib.c b/drivers/avr/TWIlib.c new file mode 100644 index 000000000..b39e3054a --- /dev/null +++ b/drivers/avr/TWIlib.c @@ -0,0 +1,232 @@ +/* + * TWIlib.c + * + * Created: 6/01/2014 10:41:33 PM + * Author: Chris Herring + * http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/ + */ + +#include +#include +#include "TWIlib.h" +#include "util/delay.h" + +void TWIInit() +{ + TWIInfo.mode = Ready; + TWIInfo.errorCode = 0xFF; + TWIInfo.repStart = 0; + // Set pre-scalers (no pre-scaling) + TWSR = 0; + // Set bit rate + TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; + // Enable TWI and interrupt + TWCR = (1 << TWIE) | (1 << TWEN); +} + +uint8_t isTWIReady() +{ + if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) ) + { + return 1; + } + else + { + return 0; + } +} + +uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart) +{ + if (dataLen <= TXMAXBUFLEN) + { + // Wait until ready + while (!isTWIReady()) {_delay_us(1);} + // Set repeated start mode + TWIInfo.repStart = repStart; + // Copy data into the transmit buffer + uint8_t *data = (uint8_t *)TXdata; + for (int i = 0; i < dataLen; i++) + { + TWITransmitBuffer[i] = data[i]; + } + // Copy transmit info to global variables + TXBuffLen = dataLen; + TXBuffIndex = 0; + + // If a repeated start has been sent, then devices are already listening for an address + // and another start does not need to be sent. + if (TWIInfo.mode == RepeatedStartSent) + { + TWIInfo.mode = Initializing; + TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer + TWISendTransmit(); // Send the data + } + else // Otherwise, just send the normal start signal to begin transmission. + { + TWIInfo.mode = Initializing; + TWISendStart(); + } + + } + else + { + return 1; // return an error if data length is longer than buffer + } + return 0; +} + +uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart) +{ + // Check if number of bytes to read can fit in the RXbuffer + if (bytesToRead < RXMAXBUFLEN) + { + // Reset buffer index and set RXBuffLen to the number of bytes to read + RXBuffIndex = 0; + RXBuffLen = bytesToRead; + // Create the one value array for the address to be transmitted + uint8_t TXdata[1]; + // Shift the address and AND a 1 into the read write bit (set to write mode) + TXdata[0] = (TWIaddr << 1) | 0x01; + // Use the TWITransmitData function to initialize the transfer and address the slave + TWITransmitData(TXdata, 1, repStart); + } + else + { + return 0; + } + return 1; +} + +ISR (TWI_vect) +{ + switch (TWI_STATUS) + { + // ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ---- // + case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received + // Set mode to Master Transmitter + TWIInfo.mode = MasterTransmitter; + case TWI_START_SENT: // Start condition has been transmitted + case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received + if (TXBuffIndex < TXBuffLen) // If there is more data to send + { + TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + TWISendTransmit(); // Send the data + } + // This transmission is complete however do not release bus yet + else if (TWIInfo.repStart) + { + TWIInfo.errorCode = 0xFF; + TWISendStart(); + } + // All transmissions are complete, exit + else + { + TWIInfo.mode = Ready; + TWIInfo.errorCode = 0xFF; + TWISendStop(); + } + break; + + // ----\/ ---- MASTER RECEIVER ----\/ ---- // + + case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received + // Switch to Master Receiver mode + TWIInfo.mode = MasterReceiver; + // If there is more than one byte to be read, receive data byte and return an ACK + if (RXBuffIndex < RXBuffLen-1) + { + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + TWISendACK(); + } + // Otherwise when a data byte (the only data byte) is received, return NACK + else + { + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + TWISendNACK(); + } + break; + + case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted. + + /// -- HANDLE DATA BYTE --- /// + TWIReceiveBuffer[RXBuffIndex++] = TWDR; + // If there is more than one byte to be read, receive data byte and return an ACK + if (RXBuffIndex < RXBuffLen-1) + { + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + TWISendACK(); + } + // Otherwise when a data byte (the only data byte) is received, return NACK + else + { + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + TWISendNACK(); + } + break; + + case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission. + + /// -- HANDLE DATA BYTE --- /// + TWIReceiveBuffer[RXBuffIndex++] = TWDR; + // This transmission is complete however do not release bus yet + if (TWIInfo.repStart) + { + TWIInfo.errorCode = 0xFF; + TWISendStart(); + } + // All transmissions are complete, exit + else + { + TWIInfo.mode = Ready; + TWIInfo.errorCode = 0xFF; + TWISendStop(); + } + break; + + // ----\/ ---- MT and MR common ----\/ ---- // + + case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received + case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received + case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received + case TWI_LOST_ARBIT: // Arbitration has been lost + // Return error and send stop and set mode to ready + if (TWIInfo.repStart) + { + TWIInfo.errorCode = TWI_STATUS; + TWISendStart(); + } + // All transmissions are complete, exit + else + { + TWIInfo.mode = Ready; + TWIInfo.errorCode = TWI_STATUS; + TWISendStop(); + } + break; + case TWI_REP_START_SENT: // Repeated start has been transmitted + // Set the mode but DO NOT clear TWINT as the next data is not yet ready + TWIInfo.mode = RepeatedStartSent; + break; + + // ----\/ ---- SLAVE RECEIVER ----\/ ---- // + + // TODO IMPLEMENT SLAVE RECEIVER FUNCTIONALITY + + // ----\/ ---- SLAVE TRANSMITTER ----\/ ---- // + + // TODO IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY + + // ----\/ ---- MISCELLANEOUS STATES ----\/ ---- // + case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition + // Rather, it is there to be manually set between operations + break; + case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error + TWIInfo.errorCode = TWI_ILLEGAL_START_STOP; + TWIInfo.mode = Ready; + TWISendStop(); + break; + } + +} diff --git a/drivers/avr/TWIlib.h b/drivers/avr/TWIlib.h new file mode 100644 index 000000000..23fd1f09a --- /dev/null +++ b/drivers/avr/TWIlib.h @@ -0,0 +1,82 @@ +/* + * TWIlib.h + * + * Created: 6/01/2014 10:38:42 PM + * Author: Chris Herring + * http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/ + */ + + +#ifndef TWILIB_H_ +#define TWILIB_H_ +// TWI bit rate (was 100000) +#define TWI_FREQ 400000 +// Get TWI status +#define TWI_STATUS (TWSR & 0xF8) +// Transmit buffer length +#define TXMAXBUFLEN 20 +// Receive buffer length +#define RXMAXBUFLEN 20 +// Global transmit buffer +uint8_t TWITransmitBuffer[TXMAXBUFLEN]; +// Global receive buffer +volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN]; +// Buffer indexes +volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time. +int RXBuffIndex; // Current index in the receive buffer +// Buffer lengths +int TXBuffLen; // The total length of the transmit buffer +int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN) + +typedef enum { + Ready, + Initializing, + RepeatedStartSent, + MasterTransmitter, + MasterReceiver, + SlaceTransmitter, + SlaveReciever + } TWIMode; + + typedef struct TWIInfoStruct{ + TWIMode mode; + uint8_t errorCode; + uint8_t repStart; + }TWIInfoStruct; +TWIInfoStruct TWIInfo; + + +// TWI Status Codes +#define TWI_START_SENT 0x08 // Start sent +#define TWI_REP_START_SENT 0x10 // Repeated Start sent +// Master Transmitter Mode +#define TWI_MT_SLAW_ACK 0x18 // SLA+W sent and ACK received +#define TWI_MT_SLAW_NACK 0x20 // SLA+W sent and NACK received +#define TWI_MT_DATA_ACK 0x28 // DATA sent and ACK received +#define TWI_MT_DATA_NACK 0x30 // DATA sent and NACK received +// Master Receiver Mode +#define TWI_MR_SLAR_ACK 0x40 // SLA+R sent, ACK received +#define TWI_MR_SLAR_NACK 0x48 // SLA+R sent, NACK received +#define TWI_MR_DATA_ACK 0x50 // Data received, ACK returned +#define TWI_MR_DATA_NACK 0x58 // Data received, NACK returned + +// Miscellaneous States +#define TWI_LOST_ARBIT 0x38 // Arbitration has been lost +#define TWI_NO_RELEVANT_INFO 0xF8 // No relevant information available +#define TWI_ILLEGAL_START_STOP 0x00 // Illegal START or STOP condition has been detected +#define TWI_SUCCESS 0xFF // Successful transfer, this state is impossible from TWSR as bit2 is 0 and read only + + +#define TWISendStart() (TWCR = (1<. + */ + +#include "is31fl3731.h" +#include +#include +#include +#include +#include "TWIlib.h" +#include "progmem.h" + +// This is a 7-bit address, that gets left-shifted and bit 0 +// set to 0 for write, 1 for read (as per I2C protocol) +// The address will vary depending on your wiring: +// 0b1110100 AD <-> GND +// 0b1110111 AD <-> VCC +// 0b1110101 AD <-> SCL +// 0b1110110 AD <-> SDA +#define ISSI_ADDR_DEFAULT 0x74 + +#define ISSI_REG_CONFIG 0x00 +#define ISSI_REG_CONFIG_PICTUREMODE 0x00 +#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08 +#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18 + +#define ISSI_CONF_PICTUREMODE 0x00 +#define ISSI_CONF_AUTOFRAMEMODE 0x04 +#define ISSI_CONF_AUDIOMODE 0x08 + +#define ISSI_REG_PICTUREFRAME 0x01 + +#define ISSI_REG_SHUTDOWN 0x0A +#define ISSI_REG_AUDIOSYNC 0x06 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine' + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[TXMAXBUFLEN]; + +// These buffers match the IS31FL3731 PWM registers 0x24-0xB3. +// Storing them like this is optimal for I2C transfers to the registers. +// We could optimize this and take out the unused registers from these +// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][144]; +bool g_pwm_buffer_update_required = false; + +uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } }; +bool g_led_control_registers_update_required = false; + +// This is the bit pattern in the LED control registers +// (for matrix A, add one to register for matrix B) +// +// reg - b7 b6 b5 b4 b3 b2 b1 b0 +// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01 +// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00 +// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00 +// 0x06 - - , - , - , - , - ,B02,B01,B00 +// 0x08 - - , - , - , - , - , - , - , - +// 0x0A - B17,B16,B15, - , - , - , - , - +// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09 +// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09 +// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09 + + +void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data ) +{ + g_twi_transfer_buffer[0] = (addr << 1) | 0x00; + g_twi_transfer_buffer[1] = reg; + g_twi_transfer_buffer[2] = data; + + // Set the error code to have no relevant information + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + // Continuously attempt to transmit data until a successful transmission occurs + //while ( TWIInfo.errorCode != 0xFF ) + //{ + TWITransmitData( g_twi_transfer_buffer, 3, 0 ); + //} +} + +void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer ) +{ + // assumes bank is already selected + + // transmit PWM registers in 9 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // set the I2C address + g_twi_transfer_buffer[0] = (addr << 1) | 0x00; + + // iterate over the pwm_buffer contents at 16 byte intervals + for ( int i = 0; i < 144; i += 16 ) + { + // set the first register, e.g. 0x24, 0x34, 0x44, etc. + g_twi_transfer_buffer[1] = 0x24 + i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer + for ( int j = 0; j < 16; j++ ) + { + g_twi_transfer_buffer[2 + j] = pwm_buffer[i + j]; + } + + // Set the error code to have no relevant information + TWIInfo.errorCode = TWI_NO_RELEVANT_INFO; + // Continuously attempt to transmit data until a successful transmission occurs + while ( TWIInfo.errorCode != 0xFF ) + { + TWITransmitData( g_twi_transfer_buffer, 16 + 2, 0 ); + } + } +} + +void IS31FL3731_init( uint8_t addr ) +{ + // In order to avoid the LEDs being driven with garbage data + // in the LED driver's PWM registers, first enable software shutdown, + // then set up the mode and other settings, clear the PWM registers, + // then disable software shutdown. + + // select "function register" bank + IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG ); + + // enable software shutdown + IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 ); + // this delay was copied from other drivers, might not be needed + _delay_ms( 10 ); + + // picture mode + IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE ); + // display frame 0 + IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 ); + // audio sync off + IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 ); + + // select bank 0 + IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 ); + + // turn off all LEDs in the LED control register + for ( int i = 0x00; i <= 0x11; i++ ) + { + IS31FL3731_write_register( addr, i, 0x00 ); + } + + // turn off all LEDs in the blink control register (not really needed) + for ( int i = 0x12; i <= 0x23; i++ ) + { + IS31FL3731_write_register( addr, i, 0x00 ); + } + + // set PWM on all LEDs to 0 + for ( int i = 0x24; i <= 0xB3; i++ ) + { + IS31FL3731_write_register( addr, i, 0x00 ); + } + + // select "function register" bank + IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG ); + + // disable software shutdown + IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 ); + + // select bank 0 and leave it selected. + // most usage after initialization is just writing PWM buffers in bank 0 + // as there's not much point in double-buffering + IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 ); +} + +void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) +{ + if ( index >= 0 && index < DRIVER_LED_TOTAL ) { + is31_led led = g_is31_leds[index]; + + // Subtract 0x24 to get the second index of g_pwm_buffer + g_pwm_buffer[led.driver][led.r - 0x24] = red; + g_pwm_buffer[led.driver][led.g - 0x24] = green; + g_pwm_buffer[led.driver][led.b - 0x24] = blue; + g_pwm_buffer_update_required = true; + } +} + +void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) +{ + for ( int i = 0; i < DRIVER_LED_TOTAL; i++ ) + { + IS31FL3731_set_color( i, red, green, blue ); + } +} + +void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue ) +{ + is31_led led = g_is31_leds[index]; + + uint8_t control_register_r = (led.r - 0x24) / 8; + uint8_t control_register_g = (led.g - 0x24) / 8; + uint8_t control_register_b = (led.b - 0x24) / 8; + uint8_t bit_r = (led.r - 0x24) % 8; + uint8_t bit_g = (led.g - 0x24) % 8; + uint8_t bit_b = (led.b - 0x24) % 8; + + if ( red ) { + g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r); + } else { + g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r); + } + if ( green ) { + g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g); + } else { + g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g); + } + if ( blue ) { + g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b); + } else { + g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b); + } + + g_led_control_registers_update_required = true; + + +} + +void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 ) +{ + if ( g_pwm_buffer_update_required ) + { + IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] ); + IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] ); + } + g_pwm_buffer_update_required = false; +} + +void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 ) +{ + if ( g_led_control_registers_update_required ) + { + for ( int i=0; i<18; i++ ) + { + IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] ); + IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] ); + } + } +} + diff --git a/drivers/avr/is31fl3731.h b/drivers/avr/is31fl3731.h new file mode 100644 index 000000000..3d30fc67b --- /dev/null +++ b/drivers/avr/is31fl3731.h @@ -0,0 +1,214 @@ +/* Copyright 2017 Jason Williams + * Copyright 2018 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef IS31FL3731_DRIVER_H +#define IS31FL3731_DRIVER_H + +#include +#include + +typedef struct is31_led { + uint8_t driver:2; + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__((packed)) is31_led; + +extern const is31_led g_is31_leds[DRIVER_LED_TOTAL]; + +void IS31FL3731_init( uint8_t addr ); +void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data ); +void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer ); + +void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ); +void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue ); + +void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue ); + +// This should not be called from an interrupt +// (eg. from a timer interrupt). +// Call this while idle (in between matrix scans). +// If the buffer is dirty, it will update the driver with the buffer. +void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 ); +void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 ); + +#define C1_1 0x24 +#define C1_2 0x25 +#define C1_3 0x26 +#define C1_4 0x27 +#define C1_5 0x28 +#define C1_6 0x29 +#define C1_7 0x2A +#define C1_8 0x2B + +#define C1_9 0x2C +#define C1_10 0x2D +#define C1_11 0x2E +#define C1_12 0x2F +#define C1_13 0x30 +#define C1_14 0x31 +#define C1_15 0x32 +#define C1_16 0x33 + +#define C2_1 0x34 +#define C2_2 0x35 +#define C2_3 0x36 +#define C2_4 0x37 +#define C2_5 0x38 +#define C2_6 0x39 +#define C2_7 0x3A +#define C2_8 0x3B + +#define C2_9 0x3C +#define C2_10 0x3D +#define C2_11 0x3E +#define C2_12 0x3F +#define C2_13 0x40 +#define C2_14 0x41 +#define C2_15 0x42 +#define C2_16 0x43 + +#define C3_1 0x44 +#define C3_2 0x45 +#define C3_3 0x46 +#define C3_4 0x47 +#define C3_5 0x48 +#define C3_6 0x49 +#define C3_7 0x4A +#define C3_8 0x4B + +#define C3_9 0x4C +#define C3_10 0x4D +#define C3_11 0x4E +#define C3_12 0x4F +#define C3_13 0x50 +#define C3_14 0x51 +#define C3_15 0x52 +#define C3_16 0x53 + +#define C4_1 0x54 +#define C4_2 0x55 +#define C4_3 0x56 +#define C4_4 0x57 +#define C4_5 0x58 +#define C4_6 0x59 +#define C4_7 0x5A +#define C4_8 0x5B + +#define C4_9 0x5C +#define C4_10 0x5D +#define C4_11 0x5E +#define C4_12 0x5F +#define C4_13 0x60 +#define C4_14 0x61 +#define C4_15 0x62 +#define C4_16 0x63 + +#define C5_1 0x64 +#define C5_2 0x65 +#define C5_3 0x66 +#define C5_4 0x67 +#define C5_5 0x68 +#define C5_6 0x69 +#define C5_7 0x6A +#define C5_8 0x6B + +#define C5_9 0x6C +#define C5_10 0x6D +#define C5_11 0x6E +#define C5_12 0x6F +#define C5_13 0x70 +#define C5_14 0x71 +#define C5_15 0x72 +#define C5_16 0x73 + +#define C6_1 0x74 +#define C6_2 0x75 +#define C6_3 0x76 +#define C6_4 0x77 +#define C6_5 0x78 +#define C6_6 0x79 +#define C6_7 0x7A +#define C6_8 0x7B + +#define C6_9 0x7C +#define C6_10 0x7D +#define C6_11 0x7E +#define C6_12 0x7F +#define C6_13 0x80 +#define C6_14 0x81 +#define C6_15 0x82 +#define C6_16 0x83 + +#define C7_1 0x84 +#define C7_2 0x85 +#define C7_3 0x86 +#define C7_4 0x87 +#define C7_5 0x88 +#define C7_6 0x89 +#define C7_7 0x8A +#define C7_8 0x8B + +#define C7_9 0x8C +#define C7_10 0x8D +#define C7_11 0x8E +#define C7_12 0x8F +#define C7_13 0x90 +#define C7_14 0x91 +#define C7_15 0x92 +#define C7_16 0x93 + +#define C8_1 0x94 +#define C8_2 0x95 +#define C8_3 0x96 +#define C8_4 0x97 +#define C8_5 0x98 +#define C8_6 0x99 +#define C8_7 0x9A +#define C8_8 0x9B + +#define C8_9 0x9C +#define C8_10 0x9D +#define C8_11 0x9E +#define C8_12 0x9F +#define C8_13 0xA0 +#define C8_14 0xA1 +#define C8_15 0xA2 +#define C8_16 0xA3 + +#define C9_1 0xA4 +#define C9_2 0xA5 +#define C9_3 0xA6 +#define C9_4 0xA7 +#define C9_5 0xA8 +#define C9_6 0xA9 +#define C9_7 0xAA +#define C9_8 0xAB + +#define C9_9 0xAC +#define C9_10 0xAD +#define C9_11 0xAE +#define C9_12 0xAF +#define C9_13 0xB0 +#define C9_14 0xB1 +#define C9_15 0xB2 +#define C9_16 0xB3 + + + +#endif // IS31FL3731_DRIVER_H -- cgit v1.2.3-24-g4f1b