diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/arm/i2c_master.c | 15 | ||||
-rw-r--r-- | drivers/arm/i2c_master.h | 1 | ||||
-rwxr-xr-x | drivers/avr/i2c_master.c | 2 | ||||
-rw-r--r-- | drivers/avr/ws2812.h | 3 | ||||
-rw-r--r-- | drivers/haptic/DRV2605L.c | 129 | ||||
-rw-r--r-- | drivers/haptic/DRV2605L.h | 394 | ||||
-rw-r--r-- | drivers/issi/is31fl3218.c | 102 | ||||
-rw-r--r-- | drivers/issi/is31fl3218.h | 24 | ||||
-rw-r--r-- | drivers/issi/is31fl3731.c | 1 | ||||
-rw-r--r-- | drivers/issi/is31fl3733.c | 3 | ||||
-rw-r--r-- | drivers/issi/is31fl3736.c | 306 | ||||
-rw-r--r-- | drivers/issi/is31fl3736.h | 172 | ||||
-rw-r--r-- | drivers/qwiic/micro_oled.c | 691 | ||||
-rw-r--r-- | drivers/qwiic/micro_oled.h | 134 | ||||
-rw-r--r-- | drivers/qwiic/qwiic.c | 31 | ||||
-rw-r--r-- | drivers/qwiic/qwiic.h | 28 | ||||
-rw-r--r-- | drivers/qwiic/qwiic.mk | 18 | ||||
-rw-r--r-- | drivers/qwiic/util/font5x7.h | 288 | ||||
-rw-r--r-- | drivers/qwiic/util/font8x16.h | 127 |
19 files changed, 2458 insertions, 11 deletions
diff --git a/drivers/arm/i2c_master.c b/drivers/arm/i2c_master.c index 2a7badd351..385bd97cb8 100644 --- a/drivers/arm/i2c_master.c +++ b/drivers/arm/i2c_master.c @@ -26,12 +26,13 @@ */ #include "i2c_master.h" +#include "quantum.h" #include <string.h> #include <hal.h> static uint8_t i2c_address; -// This configures the I2C clock to 400Mhz assuming a 72Mhz clock +// This configures the I2C clock to 400khz assuming a 72Mhz clock // For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html static const I2CConfig i2cconfig = { STM32_TIMINGR_PRESC(15U) | @@ -41,13 +42,17 @@ static const I2CConfig i2cconfig = { 0 }; +__attribute__ ((weak)) void i2c_init(void) { - palSetGroupMode(GPIOB, GPIOB_PIN6 | GPIOB_PIN7, 0, PAL_MODE_INPUT); // Try releasing special pins for a short time - chThdSleepMilliseconds(10); + // Try releasing special pins for a short time + palSetPadMode(GPIOB, 6, PAL_MODE_INPUT); + palSetPadMode(GPIOB, 7, PAL_MODE_INPUT); - palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); - palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); + chThdSleepMilliseconds(10); + + palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); + palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); //i2cInit(); //This is invoked by halInit() so no need to redo it. } diff --git a/drivers/arm/i2c_master.h b/drivers/arm/i2c_master.h index 591fa7f77d..392760328f 100644 --- a/drivers/arm/i2c_master.h +++ b/drivers/arm/i2c_master.h @@ -34,6 +34,7 @@ void i2c_init(void); uint8_t i2c_start(uint8_t address); uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); +uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length); uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout); uint8_t i2c_stop(uint16_t timeout); diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c index 47c6f8e6c6..a04e6570d7 100755 --- a/drivers/avr/i2c_master.c +++ b/drivers/avr/i2c_master.c @@ -8,7 +8,9 @@ #include "i2c_master.h" #include "timer.h" +#ifndef F_SCL #define F_SCL 400000UL // SCL frequency +#endif #define Prescaler 1 #define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2) diff --git a/drivers/avr/ws2812.h b/drivers/avr/ws2812.h index f7e0c31440..1f9299ffb5 100644 --- a/drivers/avr/ws2812.h +++ b/drivers/avr/ws2812.h @@ -69,7 +69,4 @@ void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask); #define CONCAT_EXP(a, b) CONCAT(a, b) #endif -// #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port) -// #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port) - #endif /* LIGHT_WS2812_H_ */ diff --git a/drivers/haptic/DRV2605L.c b/drivers/haptic/DRV2605L.c new file mode 100644 index 0000000000..97ca292b9b --- /dev/null +++ b/drivers/haptic/DRV2605L.c @@ -0,0 +1,129 @@ +/* Copyright 2018 ishtob + * Driver for DRV2605L written for QMK + * + * 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 <http://www.gnu.org/licenses/>. + */ +#include "DRV2605L.h" +#include "print.h" +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + + +uint8_t DRV2605L_transfer_buffer[20]; +uint8_t DRV2605L_tx_register[0]; +uint8_t DRV2605L_read_buffer[0]; +uint8_t DRV2605L_read_register; + + +void DRV_write(uint8_t drv_register, uint8_t settings) { + DRV2605L_transfer_buffer[0] = drv_register; + DRV2605L_transfer_buffer[1] = settings; + i2c_transmit(DRV2605L_BASE_ADDRESS << 1, DRV2605L_transfer_buffer, 2, 100); +} + +uint8_t DRV_read(uint8_t regaddress) { + DRV2605L_tx_register[0] = regaddress; + if (MSG_OK != i2c_transmit_receive(DRV2605L_BASE_ADDRESS << 1, + DRV2605L_tx_register, 1, + DRV2605L_read_buffer, 1 +)){ + printf("err reading reg \n"); + } + DRV2605L_read_register = (uint8_t)DRV2605L_read_buffer[0]; +return DRV2605L_read_register; +} + +void DRV_init(void) +{ + i2c_init(); + i2c_start(DRV2605L_BASE_ADDRESS); + + /* 0x07 sets DRV2605 into calibration mode */ + DRV_write(DRV_MODE,0x07); + +// DRV_write(DRV_FEEDBACK_CTRL,0xB6); + + #if FB_ERM_LRA == 0 + /* ERM settings */ + DRV_write(DRV_RATED_VOLT, (RATED_VOLTAGE/21.33)*1000); + #if ERM_OPEN_LOOP == 0 + DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (((V_PEAK*(DRIVE_TIME+BLANKING_TIME+IDISS_TIME))/0.02133)/(DRIVE_TIME-0.0003))); + #elif ERM_OPEN_LOOP == 1 + DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (V_PEAK/0.02196)); + #endif + #elif FB_ERM_LRA == 1 + DRV_write(DRV_RATED_VOLT, ((V_RMS * sqrt(1 - ((4 * ((150+(SAMPLE_TIME*50))*0.000001)) + 0.0003)* F_LRA)/0.02071))); + #if LRA_OPEN_LOOP == 0 + DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, ((V_PEAK/sqrt(1-(F_LRA*0.0008))/0.02133))); + #elif LRA_OPEN_LOOP == 1 + DRV_write(DRV_OVERDRIVE_CLAMP_VOLT, (V_PEAK/0.02196)); + #endif + #endif + + DRVREG_FBR FB_SET; + FB_SET.Bits.ERM_LRA = FB_ERM_LRA; + FB_SET.Bits.BRAKE_FACTOR = FB_BRAKEFACTOR; + FB_SET.Bits.LOOP_GAIN =FB_LOOPGAIN; + FB_SET.Bits.BEMF_GAIN = 0; /* auto-calibration populates this field*/ + DRV_write(DRV_FEEDBACK_CTRL, (uint8_t) FB_SET.Byte); + DRVREG_CTRL1 C1_SET; + C1_SET.Bits.C1_DRIVE_TIME = DRIVE_TIME; + C1_SET.Bits.C1_AC_COUPLE = AC_COUPLE; + C1_SET.Bits.C1_STARTUP_BOOST = STARTUP_BOOST; + DRV_write(DRV_CTRL_1, (uint8_t) C1_SET.Byte); + DRVREG_CTRL2 C2_SET; + C2_SET.Bits.C2_BIDIR_INPUT = BIDIR_INPUT; + C2_SET.Bits.C2_BRAKE_STAB = BRAKE_STAB; + C2_SET.Bits.C2_SAMPLE_TIME = SAMPLE_TIME; + C2_SET.Bits.C2_BLANKING_TIME = BLANKING_TIME; + C2_SET.Bits.C2_IDISS_TIME = IDISS_TIME; + DRV_write(DRV_CTRL_2, (uint8_t) C2_SET.Byte); + DRVREG_CTRL3 C3_SET; + C3_SET.Bits.C3_LRA_OPEN_LOOP = LRA_OPEN_LOOP; + C3_SET.Bits.C3_N_PWM_ANALOG = N_PWM_ANALOG; + C3_SET.Bits.C3_LRA_DRIVE_MODE = LRA_DRIVE_MODE; + C3_SET.Bits.C3_DATA_FORMAT_RTO = DATA_FORMAT_RTO; + C3_SET.Bits.C3_SUPPLY_COMP_DIS = SUPPLY_COMP_DIS; + C3_SET.Bits.C3_ERM_OPEN_LOOP = ERM_OPEN_LOOP; + C3_SET.Bits.C3_NG_THRESH = NG_THRESH; + DRV_write(DRV_CTRL_3, (uint8_t) C3_SET.Byte); + DRVREG_CTRL4 C4_SET; + C4_SET.Bits.C4_ZC_DET_TIME = ZC_DET_TIME; + C4_SET.Bits.C4_AUTO_CAL_TIME = AUTO_CAL_TIME; + DRV_write(DRV_CTRL_4, (uint8_t) C4_SET.Byte); + DRV_write(DRV_LIB_SELECTION,LIB_SELECTION); + //start autocalibration + DRV_write(DRV_GO, 0x01); + + /* 0x00 sets DRV2605 out of standby and to use internal trigger + * 0x01 sets DRV2605 out of standby and to use external trigger */ + DRV_write(DRV_MODE,0x00); + + /* 0x06: LRA library */ + DRV_write(DRV_WAVEFORM_SEQ_1, 0x01); + + /* 0xB9: LRA, 4x brake factor, medium gain, 7.5x back EMF + * 0x39: ERM, 4x brake factor, medium gain, 1.365x back EMF */ + + /* TODO: setup auto-calibration as part of initiation */ + +} + +void DRV_pulse(uint8_t sequence) +{ + DRV_write(DRV_GO, 0x00); + DRV_write(DRV_WAVEFORM_SEQ_1, sequence); + DRV_write(DRV_GO, 0x01); +}
\ No newline at end of file diff --git a/drivers/haptic/DRV2605L.h b/drivers/haptic/DRV2605L.h new file mode 100644 index 0000000000..de9d294e9d --- /dev/null +++ b/drivers/haptic/DRV2605L.h @@ -0,0 +1,394 @@ +/* Copyright 2018 ishtob + * Driver for DRV2605L written for QMK + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include "i2c_master.h" + +/* Initialization settings + + * Feedback Control Settings */ +#ifndef FB_ERM_LRA +#define FB_ERM_LRA 1 /* For ERM:0 or LRA:1*/ +#endif +#ifndef FB_BRAKEFACTOR +#define FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */ +#endif +#ifndef FB_LOOPGAIN +#define FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */ +#endif + +#ifndef RATED_VOLTAGE +#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */ +#ifndef V_PEAK +#define V_PEAK 2.8 +#endif +#endif + +/* LRA specific settings */ +#if FB_ERM_LRA == 1 +#ifndef V_RMS +#define V_RMS 2.0 +#endif +#ifndef V_PEAK +#define V_PEAK 2.1 +#endif +#ifndef F_LRA +#define F_LRA 205 +#endif +#endif + +/* Library Selection */ +#ifndef LIB_SELECTION +#if FB_ERM_LRA == 1 +#define LIB_SELECTION 6 /* For Empty:0' TS2200 library A to D:1-5, LRA Library: 6 */ +#else +#define LIB_SELECTION 1 +#endif +#endif + +/* Control 1 register settings */ +#ifndef DRIVE_TIME +#define DRIVE_TIME 25 +#endif +#ifndef AC_COUPLE +#define AC_COUPLE 0 +#endif +#ifndef STARTUP_BOOST +#define STARTUP_BOOST 1 +#endif + +/* Control 2 Settings */ +#ifndef BIDIR_INPUT +#define BIDIR_INPUT 1 +#endif +#ifndef BRAKE_STAB +#define BRAKE_STAB 1 /* Loopgain is reduced when braking is almost complete to improve stability */ +#endif +#ifndef SAMPLE_TIME +#define SAMPLE_TIME 3 +#endif +#ifndef BLANKING_TIME +#define BLANKING_TIME 1 +#endif +#ifndef IDISS_TIME +#define IDISS_TIME 1 +#endif + +/* Control 3 settings */ +#ifndef NG_THRESH +#define NG_THRESH 2 +#endif +#ifndef ERM_OPEN_LOOP +#define ERM_OPEN_LOOP 1 +#endif +#ifndef SUPPLY_COMP_DIS +#define SUPPLY_COMP_DIS 0 +#endif +#ifndef DATA_FORMAT_RTO +#define DATA_FORMAT_RTO 0 +#endif +#ifndef LRA_DRIVE_MODE +#define LRA_DRIVE_MODE 0 +#endif +#ifndef N_PWM_ANALOG +#define N_PWM_ANALOG 0 +#endif +#ifndef LRA_OPEN_LOOP +#define LRA_OPEN_LOOP 0 +#endif + +/* Control 4 settings */ +#ifndef ZC_DET_TIME +#define ZC_DET_TIME 0 +#endif +#ifndef AUTO_CAL_TIME +#define AUTO_CAL_TIME 3 +#endif + +/* register defines -------------------------------------------------------- */ +#define DRV2605L_BASE_ADDRESS 0x5A /* DRV2605L Base address */ +#define DRV_STATUS 0x00 +#define DRV_MODE 0x01 +#define DRV_RTP_INPUT 0x02 +#define DRV_LIB_SELECTION 0x03 +#define DRV_WAVEFORM_SEQ_1 0x04 +#define DRV_WAVEFORM_SEQ_2 0x05 +#define DRV_WAVEFORM_SEQ_3 0x06 +#define DRV_WAVEFORM_SEQ_4 0x07 +#define DRV_WAVEFORM_SEQ_5 0x08 +#define DRV_WAVEFORM_SEQ_6 0x09 +#define DRV_WAVEFORM_SEQ_7 0x0A +#define DRV_WAVEFORM_SEQ_8 0x0B +#define DRV_GO 0x0C +#define DRV_OVERDRIVE_TIME_OFFSET 0x0D +#define DRV_SUSTAIN_TIME_OFFSET_P 0x0E +#define DRV_SUSTAIN_TIME_OFFSET_N 0x0F +#define DRV_BRAKE_TIME_OFFSET 0x10 +#define DRV_AUDIO_2_VIBE_CTRL 0x11 +#define DRV_AUDIO_2_VIBE_MIN_IN 0x12 +#define DRV_AUDIO_2_VIBE_MAX_IN 0x13 +#define DRV_AUDIO_2_VIBE_MIN_OUTDRV 0x14 +#define DRV_AUDIO_2_VIBE_MAX_OUTDRV 0x15 +#define DRV_RATED_VOLT 0x16 +#define DRV_OVERDRIVE_CLAMP_VOLT 0x17 +#define DRV_AUTO_CALIB_COMP_RESULT 0x18 +#define DRV_AUTO_CALIB_BEMF_RESULT 0x19 +#define DRV_FEEDBACK_CTRL 0x1A +#define DRV_CTRL_1 0x1B +#define DRV_CTRL_2 0x1C +#define DRV_CTRL_3 0x1D +#define DRV_CTRL_4 0x1E +#define DRV_CTRL_5 0x1F +#define DRV_OPEN_LOOP_PERIOD 0x20 +#define DRV_VBAT_VOLT_MONITOR 0x21 +#define DRV_LRA_RESONANCE_PERIOD 0x22 + +void DRV_init(void); +void DRV_write(const uint8_t drv_register, const uint8_t settings); +uint8_t DRV_read(const uint8_t regaddress); +void DRV_pulse(const uint8_t sequence); + + +typedef enum DRV_EFFECT{ + clear_sequence = 0, + strong_click = 1, + strong_click_60 = 2, + strong_click_30 = 3, + sharp_click = 4, + sharp_click_60 = 5, + sharp_click_30 = 6, + soft_bump = 7, + soft_bump_60 = 8, + soft_bump_30 = 9, + dbl_click = 10, + dbl_click_60 = 11, + trp_click = 12, + soft_fuzz = 13, + strong_buzz = 14, + alert_750ms = 15, + alert_1000ms = 16, + strong_click1 = 17, + strong_click2_80 = 18, + strong_click3_60 = 19, + strong_click4_30 = 20, + medium_click1 = 21, + medium_click2_80 = 22, + medium_click3_60 = 23, + sharp_tick1 = 24, + sharp_tick2_80 = 25, + sharp_tick3_60 = 26, + sh_dblclick_str = 27, + sh_dblclick_str_80 = 28, + sh_dblclick_str_60 = 29, + sh_dblclick_str_30 = 30, + sh_dblclick_med = 31, + sh_dblclick_med_80 = 32, + sh_dblclick_med_60 = 33, + sh_dblsharp_tick = 34, + sh_dblsharp_tick_80 = 35, + sh_dblsharp_tick_60 = 36, + lg_dblclick_str = 37, + lg_dblclick_str_80 = 38, + lg_dblclick_str_60 = 39, + lg_dblclick_str_30 = 40, + lg_dblclick_med = 41, + lg_dblclick_med_80 = 42, + lg_dblclick_med_60 = 43, + lg_dblsharp_tick = 44, + lg_dblsharp_tick_80 = 45, + lg_dblsharp_tick_60 = 46, + buzz = 47, + buzz_80 = 48, + buzz_60 = 49, + buzz_40 = 50, + buzz_20 = 51, + pulsing_strong = 52, + pulsing_strong_80 = 53, + pulsing_medium = 54, + pulsing_medium_80 = 55, + pulsing_sharp = 56, + pulsing_sharp_80 = 57, + transition_click = 58, + transition_click_80 = 59, + transition_click_60 = 60, + transition_click_40 = 61, + transition_click_20 = 62, + transition_click_10 = 63, + transition_hum = 64, + transition_hum_80 = 65, + transition_hum_60 = 66, + transition_hum_40 = 67, + transition_hum_20 = 68, + transition_hum_10 = 69, + transition_rampdown_long_smooth1 = 70, + transition_rampdown_long_smooth2 = 71, + transition_rampdown_med_smooth1 = 72, + transition_rampdown_med_smooth2 = 73, + transition_rampdown_short_smooth1 = 74, + transition_rampdown_short_smooth2 = 75, + transition_rampdown_long_sharp1 = 76, + transition_rampdown_long_sharp2 = 77, + transition_rampdown_med_sharp1 = 78, + transition_rampdown_med_sharp2 = 79, + transition_rampdown_short_sharp1 = 80, + transition_rampdown_short_sharp2 = 81, + transition_rampup_long_smooth1 = 82, + transition_rampup_long_smooth2 = 83, + transition_rampup_med_smooth1 = 84, + transition_rampup_med_smooth2 = 85, + transition_rampup_short_smooth1 = 86, + transition_rampup_short_smooth2 = 87, + transition_rampup_long_sharp1 = 88, + transition_rampup_long_sharp2 = 89, + transition_rampup_med_sharp1 = 90, + transition_rampup_med_sharp2 = 91, + transition_rampup_short_sharp1 = 92, + transition_rampup_short_sharp2 = 93, + transition_rampdown_long_smooth1_50 = 94, + transition_rampdown_long_smooth2_50 = 95, + transition_rampdown_med_smooth1_50 = 96, + transition_rampdown_med_smooth2_50 = 97, + transition_rampdown_short_smooth1_50 = 98, + transition_rampdown_short_smooth2_50 = 99, + transition_rampdown_long_sharp1_50 = 100, + transition_rampdown_long_sharp2_50 = 101, + transition_rampdown_med_sharp1_50 = 102, + transition_rampdown_med_sharp2_50 = 103, + transition_rampdown_short_sharp1_50 = 104, + transition_rampdown_short_sharp2_50 = 105, + transition_rampup_long_smooth1_50 = 106, + transition_rampup_long_smooth2_50 = 107, + transition_rampup_med_smooth1_50 = 108, + transition_rampup_med_smooth2_50 = 109, + transition_rampup_short_smooth1_50 = 110, + transition_rampup_short_smooth2_50 = 111, + transition_rampup_long_sharp1_50 = 112, + transition_rampup_long_sharp2_50 = 113, + transition_rampup_med_sharp1_50 = 114, + transition_rampup_med_sharp2_50 = 115, + transition_rampup_short_sharp1_50 = 116, + transition_rampup_short_sharp2_50 = 117, + long_buzz_for_programmatic_stopping = 118, + smooth_hum1_50 = 119, + smooth_hum2_40 = 120, + smooth_hum3_30 = 121, + smooth_hum4_20 = 122, + smooth_hum5_10 = 123, +} DRV_EFFECT; + +/* Register bit array unions */ + +typedef union DRVREG_STATUS { /* register 0x00 */ + uint8_t Byte; + struct { + uint8_t OC_DETECT :1; /* set to 1 when overcurrent event is detected */ + uint8_t OVER_TEMP :1; /* set to 1 when device exceeds temp threshold */ + uint8_t FB_STS :1; /* set to 1 when feedback controller has timed out */ + /* auto-calibration routine and diagnostic result + * result | auto-calibation | diagnostic | + * 0 | passed | actuator func normal | + * 1 | failed | actuator func fault* | + * * actuator is not present or is shorted, timing out, or giving out–of-range back-EMF */ + uint8_t DIAG_RESULT :1; + uint8_t :1; + uint8_t DEVICE_ID :3; /* Device IDs 3: DRV2605 4: DRV2604 5: DRV2604L 6: DRV2605L */ + } Bits; +} DRVREG_STATUS; + +typedef union DRVREG_MODE { /* register 0x01 */ + uint8_t Byte; + struct { + uint8_t MODE :3; /* Mode setting */ + uint8_t :3; + uint8_t STANDBY :1; /* 0:standby 1:ready */ + } Bits; +} DRVREG_MODE; + +typedef union DRVREG_WAIT { + uint8_t Byte; + struct { + uint8_t WAIT_MODE :1; /* Set to 1 to interpret as wait for next 7 bits x10ms */ + uint8_t WAIT_TIME :7; + } Bits; +} DRVREG_WAIT; + +typedef union DRVREG_FBR{ /* register 0x1A */ + uint8_t Byte; + struct { + uint8_t BEMF_GAIN :2; + uint8_t LOOP_GAIN :2; + uint8_t BRAKE_FACTOR :3; + uint8_t ERM_LRA :1; + } Bits; +} DRVREG_FBR; + +typedef union DRVREG_CTRL1{ /* register 0x1B */ + uint8_t Byte; + struct { + uint8_t C1_DRIVE_TIME :5; + uint8_t C1_AC_COUPLE :1; + uint8_t :1; + uint8_t C1_STARTUP_BOOST :1; + } Bits; +} DRVREG_CTRL1; + +typedef union DRVREG_CTRL2{ /* register 0x1C */ + uint8_t Byte; + struct { + uint8_t C2_IDISS_TIME :2; + uint8_t C2_BLANKING_TIME :2; + uint8_t C2_SAMPLE_TIME :2; + uint8_t C2_BRAKE_STAB :1; + uint8_t C2_BIDIR_INPUT :1; + } Bits; +} DRVREG_CTRL2; + +typedef union DRVREG_CTRL3{ /* register 0x1D */ + uint8_t Byte; + struct { + uint8_t C3_LRA_OPEN_LOOP :1; + uint8_t C3_N_PWM_ANALOG :1; + uint8_t C3_LRA_DRIVE_MODE :1; + uint8_t C3_DATA_FORMAT_RTO :1; + uint8_t C3_SUPPLY_COMP_DIS :1; + uint8_t C3_ERM_OPEN_LOOP :1; + uint8_t C3_NG_THRESH :2; + } Bits; +} DRVREG_CTRL3; + +typedef union DRVREG_CTRL4{ /* register 0x1E */ + uint8_t Byte; + struct { + uint8_t C4_OTP_PROGRAM :1; + uint8_t :1; + uint8_t C4_OTP_STATUS :1; + uint8_t :1; + uint8_t C4_AUTO_CAL_TIME :2; + uint8_t C4_ZC_DET_TIME :2; + } Bits; +} DRVREG_CTRL4; + +typedef union DRVREG_CTRL5{ /* register 0x1F */ + uint8_t Byte; + struct { + uint8_t C5_IDISS_TIME :2; + uint8_t C5_BLANKING_TIME :2; + uint8_t C5_PLAYBACK_INTERVAL :1; + uint8_t C5_LRA_AUTO_OPEN_LOOP :1; + uint8_t C5_AUTO_OL_CNT :2; + } Bits; +} DRVREG_CTRL5;
\ No newline at end of file diff --git a/drivers/issi/is31fl3218.c b/drivers/issi/is31fl3218.c new file mode 100644 index 0000000000..db44f72564 --- /dev/null +++ b/drivers/issi/is31fl3218.c @@ -0,0 +1,102 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 <http://www.gnu.org/licenses/>. + */ +#include "is31fl3218.h" +#include "i2c_master.h" + +// This is the full 8-bit address +#define ISSI_ADDRESS 0b10101000 + +// These are the register addresses +#define ISSI_REG_SHUTDOWN 0x00 +#define ISSI_REG_PWM 0x01 +#define ISSI_REG_CONTROL 0x13 +#define ISSI_REG_UPDATE 0x16 +#define ISSI_REG_RESET 0x17 + +// Default timeout if no I2C response +#define ISSI_TIMEOUT 100 + +// Reusable buffer for transfers +uint8_t g_twi_transfer_buffer[20]; + +// IS31FL3218 has 18 PWM outputs and a fixed I2C address, so no chaining. +// If used as RGB LED driver, LEDs are assigned RGB,RGB,RGB,RGB,RGB,RGB +uint8_t g_pwm_buffer[18]; +bool g_pwm_buffer_update_required = false; + +void IS31FL3218_write_register( uint8_t reg, uint8_t data ) +{ + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + i2c_transmit( ISSI_ADDRESS, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); +} + +void IS31FL3218_write_pwm_buffer( uint8_t *pwm_buffer ) +{ + g_twi_transfer_buffer[0] = ISSI_REG_PWM; + for ( int i=0; i<18; i++ ) { + g_twi_transfer_buffer[1+i] = pwm_buffer[i]; + } + + i2c_transmit( ISSI_ADDRESS, g_twi_transfer_buffer, 19, ISSI_TIMEOUT); +} + +void IS31FL3218_init(void) +{ + // In case we ever want to reinitialize (?) + IS31FL3218_write_register( ISSI_REG_RESET, 0x00 ); + + // Turn off software shutdown + IS31FL3218_write_register( ISSI_REG_SHUTDOWN, 0x01 ); + + // Set all PWM values to zero + for ( uint8_t i = 0; i < 18; i++ ) { + IS31FL3218_write_register( ISSI_REG_PWM+i, 0x00 ); + } + + // Enable all channels + for ( uint8_t i = 0; i < 3; i++ ) { + IS31FL3218_write_register( ISSI_REG_CONTROL+i, 0b00111111 ); + } + + // Load PWM registers and LED Control register data + IS31FL3218_write_register( ISSI_REG_UPDATE, 0x01 ); +} + +void IS31FL3218_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) +{ + g_pwm_buffer[index * 3 + 0] = red; + g_pwm_buffer[index * 3 + 1] = green; + g_pwm_buffer[index * 3 + 2] = blue; + g_pwm_buffer_update_required = true; +} + +void IS31FL3218_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) +{ + for ( int i = 0; i < 6; i++ ) { + IS31FL3218_set_color( i, red, green, blue ); + } +} + +void IS31FL3218_update_pwm_buffers(void) +{ + if ( g_pwm_buffer_update_required ) { + IS31FL3218_write_pwm_buffer( g_pwm_buffer ); + // Load PWM registers and LED Control register data + IS31FL3218_write_register( ISSI_REG_UPDATE, 0x01 ); + } + g_pwm_buffer_update_required = false; +} diff --git a/drivers/issi/is31fl3218.h b/drivers/issi/is31fl3218.h new file mode 100644 index 0000000000..2d24e51463 --- /dev/null +++ b/drivers/issi/is31fl3218.h @@ -0,0 +1,24 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 <http://www.gnu.org/licenses/>. + */ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +void IS31FL3218_init(void); +void IS31FL3218_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ); +void IS31FL3218_set_color_all( uint8_t red, uint8_t green, uint8_t blue ); +void IS31FL3218_update_pwm_buffers(void); diff --git a/drivers/issi/is31fl3731.c b/drivers/issi/is31fl3731.c index 4d0d6b8a5e..c9155f5a37 100644 --- a/drivers/issi/is31fl3731.c +++ b/drivers/issi/is31fl3731.c @@ -268,4 +268,3 @@ void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 ) } } } - diff --git a/drivers/issi/is31fl3733.c b/drivers/issi/is31fl3733.c index 4098b54689..c198ec5174 100644 --- a/drivers/issi/is31fl3733.c +++ b/drivers/issi/is31fl3733.c @@ -24,10 +24,10 @@ #include "wait.h" #endif -#include "is31fl3733.h" #include <string.h> #include "i2c_master.h" #include "progmem.h" +#include "rgb_matrix.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) @@ -250,4 +250,3 @@ void IS31FL3733_update_led_control_registers( uint8_t addr1, uint8_t addr2 ) } } } - diff --git a/drivers/issi/is31fl3736.c b/drivers/issi/is31fl3736.c new file mode 100644 index 0000000000..c5d4310971 --- /dev/null +++ b/drivers/issi/is31fl3736.c @@ -0,0 +1,306 @@ +/* Copyright 2018 Jason Williams (Wilba) + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +#ifdef __AVR__ +#include <avr/interrupt.h> +#include <avr/io.h> +#include <util/delay.h> +#else +#include "wait.h" +#endif + +#include "is31fl3736.h" +#include <string.h> +#include "i2c_master.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: +// 00 <-> GND +// 01 <-> SCL +// 10 <-> SDA +// 11 <-> VCC +// ADDR1 represents A1:A0 of the 7-bit address. +// ADDR2 represents A3:A2 of the 7-bit address. +// The result is: 0b101(ADDR2)(ADDR1) +#define ISSI_ADDR_DEFAULT 0x50 + +#define ISSI_COMMANDREGISTER 0xFD +#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE +#define ISSI_INTERRUPTMASKREGISTER 0xF0 +#define ISSI_INTERRUPTSTATUSREGISTER 0xF1 + +#define ISSI_PAGE_LEDCONTROL 0x00 //PG0 +#define ISSI_PAGE_PWM 0x01 //PG1 +#define ISSI_PAGE_AUTOBREATH 0x02 //PG2 +#define ISSI_PAGE_FUNCTION 0x03 //PG3 + +#define ISSI_REG_CONFIGURATION 0x00 //PG3 +#define ISSI_REG_GLOBALCURRENT 0x01 //PG3 +#define ISSI_REG_RESET 0x11// PG3 +#define ISSI_REG_SWPULLUP 0x0F //PG3 +#define ISSI_REG_CSPULLUP 0x10 //PG3 + +#ifndef ISSI_TIMEOUT + #define ISSI_TIMEOUT 100 +#endif + +#ifndef ISSI_PERSISTENCE + #define ISSI_PERSISTENCE 0 +#endif + +// Transfer buffer for TWITransmitData() +uint8_t g_twi_transfer_buffer[20]; + +// These buffers match the IS31FL3736 PWM registers. +// The control buffers match the PG0 LED On/Off registers. +// 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 IS31FL3736_write_pwm_buffer() but it's +// probably not worth the extra complexity. +uint8_t g_pwm_buffer[DRIVER_COUNT][192]; +bool g_pwm_buffer_update_required = false; + +uint8_t g_led_control_registers[DRIVER_COUNT][24] = { { 0 }, { 0 } }; +bool g_led_control_registers_update_required = false; + +void IS31FL3736_write_register( uint8_t addr, uint8_t reg, uint8_t data ) +{ + g_twi_transfer_buffer[0] = reg; + g_twi_transfer_buffer[1] = data; + + #if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) + break; + } + #else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT); + #endif +} + +void IS31FL3736_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer ) +{ + // assumes PG1 is already selected + + // transmit PWM registers in 12 transfers of 16 bytes + // g_twi_transfer_buffer[] is 20 bytes + + // iterate over the pwm_buffer contents at 16 byte intervals + for ( int i = 0; i < 192; i += 16 ) { + g_twi_transfer_buffer[0] = i; + // copy the data from i to i+15 + // device will auto-increment register for data after the first byte + // thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer + for ( int j = 0; j < 16; j++ ) { + g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j]; + } + + #if ISSI_PERSISTENCE > 0 + for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) { + if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0) + break; + } + #else + i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT); + #endif + } +} + +void IS31FL3736_init( uint8_t addr ) +{ + // In order to avoid the LEDs being driven with garbage data + // in the LED driver's PWM registers, shutdown is enabled last. + // Set up the mode and other settings, clear the PWM registers, + // then disable software shutdown. + + // Unlock the command register. + IS31FL3736_write_register( addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 ); + + // Select PG0 + IS31FL3736_write_register( addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL ); + // Turn off all LEDs. + for ( int i = 0x00; i <= 0x17; i++ ) + { + IS31FL3736_write_register( addr, i, 0x00 ); + } + + // Unlock the command register. + IS31FL3736_write_register( addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 ); + + // Select PG1 + IS31FL3736_write_register( addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM ); + // Set PWM on all LEDs to 0 + // No need to setup Breath registers to PWM as that is the default. + for ( int i = 0x00; i <= 0xBF; i++ ) + { + IS31FL3736_write_register( addr, i, 0x00 ); + } + |