ergodox_infinity.c (11454B)
1 #include "ergodox_infinity.h" 2 #include <ch.h> 3 #include <hal.h> 4 #include <string.h> 5 #include "eeconfig.h" 6 7 #define RED_PIN 1 8 #define GREEN_PIN 2 9 #define BLUE_PIN 3 10 #define CHANNEL_RED FTM0->CHANNEL[0] 11 #define CHANNEL_GREEN FTM0->CHANNEL[1] 12 #define CHANNEL_BLUE FTM0->CHANNEL[2] 13 14 #define RGB_PORT PORTC 15 #define RGB_PORT_GPIO GPIOC 16 17 // Base FTM clock selection (72 MHz system clock) 18 // @ 0xFFFF period, 72 MHz / (0xFFFF * 2) = Actual period 19 // Higher pre-scalar will use the most power (also look the best) 20 // Pre-scalar calculations 21 // 0 - 72 MHz -> 549 Hz 22 // 1 - 36 MHz -> 275 Hz 23 // 2 - 18 MHz -> 137 Hz 24 // 3 - 9 MHz -> 69 Hz (Slightly visible flicker) 25 // 4 - 4 500 kHz -> 34 Hz (Visible flickering) 26 // 5 - 2 250 kHz -> 17 Hz 27 // 6 - 1 125 kHz -> 9 Hz 28 // 7 - 562 500 Hz -> 4 Hz 29 // Using a higher pre-scalar without flicker is possible but FTM0_MOD will need to be reduced 30 // Which will reduce the brightness range 31 #define PRESCALAR_DEFINE 0 32 void lcd_backlight_hal_init(void) { 33 // Setup Backlight 34 SIM->SCGC6 |= SIM_SCGC6_FTM0; 35 FTM0->CNT = 0; // Reset counter 36 37 // PWM Period 38 // 16-bit maximum 39 FTM0->MOD = 0xFFFF; 40 41 // Set FTM to PWM output - Edge Aligned, Low-true pulses 42 #define CNSC_MODE FTM_SC_CPWMS | FTM_SC_PS(4) | FTM_SC_CLKS(0) 43 CHANNEL_RED.CnSC = CNSC_MODE; 44 CHANNEL_GREEN.CnSC = CNSC_MODE; 45 CHANNEL_BLUE.CnSC = CNSC_MODE; 46 47 // System clock, /w prescalar setting 48 FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_PS(PRESCALAR_DEFINE); 49 50 CHANNEL_RED.CnV = 0; 51 CHANNEL_GREEN.CnV = 0; 52 CHANNEL_BLUE.CnV = 0; 53 54 RGB_PORT_GPIO->PDDR |= (1 << RED_PIN); 55 RGB_PORT_GPIO->PDDR |= (1 << GREEN_PIN); 56 RGB_PORT_GPIO->PDDR |= (1 << BLUE_PIN); 57 58 #define RGB_MODE PORTx_PCRn_SRE | PORTx_PCRn_DSE | PORTx_PCRn_MUX(4) 59 RGB_PORT->PCR[RED_PIN] = RGB_MODE; 60 RGB_PORT->PCR[GREEN_PIN] = RGB_MODE; 61 RGB_PORT->PCR[BLUE_PIN] = RGB_MODE; 62 } 63 64 static uint16_t cie_lightness(uint16_t v) { 65 // The CIE 1931 formula for lightness 66 // Y = luminance (output) 0-1 67 // L = lightness input 0 - 100 68 69 // Y = (L* / 902.3) if L* <= 8 70 // Y = ((L* + 16) / 116)^3 if L* > 8 71 72 float l = 100.0f * (v / 65535.0f); 73 float y = 0.0f; 74 if (l <= 8.0f) { 75 y = l / 902.3; 76 } else { 77 y = ((l + 16.0f) / 116.0f); 78 y = y * y * y; 79 if (y > 1.0f) { 80 y = 1.0f; 81 } 82 } 83 return y * 65535.0f; 84 } 85 86 void ergodox_infinity_lcd_color(uint16_t r, uint16_t g, uint16_t b) { 87 CHANNEL_RED.CnV = cie_lightness(r); 88 CHANNEL_GREEN.CnV = cie_lightness(g); 89 CHANNEL_BLUE.CnV = cie_lightness(b); 90 } 91 92 __attribute__ ((weak)) void matrix_init_user(void) {} 93 94 __attribute__ ((weak)) void matrix_scan_user(void) {} 95 96 97 void keyboard_pre_init_kb(void) { 98 // The backlight always has to be initialized, otherwise it will stay lit 99 lcd_backlight_hal_init(); 100 #ifdef ST7565_ENABLE 101 ergodox_infinity_lcd_color(UINT16_MAX / 2, UINT16_MAX / 2, UINT16_MAX / 2); 102 #endif 103 keyboard_pre_init_user(); 104 } 105 106 void matrix_init_kb(void) { 107 // put your keyboard start-up code here 108 // runs once when the firmware starts up 109 110 #ifdef LED_MATRIX_ENABLE 111 /* 112 * Since K20x is stuck with a 32 byte EEPROM (see tmk_core/common/chibios/eeprom_teensy.c), 113 * and neither led_matrix_eeconfig.speed or .flags fit in this boundary, just force their values to default on boot. 114 */ 115 led_matrix_set_speed(LED_MATRIX_DEFAULT_SPD); 116 led_matrix_set_flags(LED_FLAG_ALL); 117 #endif 118 119 matrix_init_user(); 120 } 121 122 __attribute__ ((weak)) void ergodox_board_led_on(void) {} 123 124 __attribute__ ((weak)) void ergodox_right_led_1_on(void) {} 125 126 __attribute__ ((weak)) void ergodox_right_led_2_on(void) {} 127 128 __attribute__ ((weak)) void ergodox_right_led_3_on(void) {} 129 130 __attribute__ ((weak)) void ergodox_board_led_off(void) {} 131 132 __attribute__ ((weak)) void ergodox_right_led_1_off(void) {} 133 134 __attribute__ ((weak)) void ergodox_right_led_2_off(void) {} 135 136 __attribute__ ((weak)) void ergodox_right_led_3_off(void) {} 137 138 __attribute__ ((weak)) void ergodox_right_led_1_set(uint8_t n) {} 139 140 __attribute__ ((weak)) void ergodox_right_led_2_set(uint8_t n) {} 141 142 __attribute__ ((weak)) void ergodox_right_led_3_set(uint8_t n) {} 143 144 #ifdef SWAP_HANDS_ENABLE 145 __attribute__ ((weak)) 146 const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = { 147 {{0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}}, 148 {{0, 10}, {1, 10}, {2, 10}, {3, 10}, {4, 10}}, 149 {{0, 11}, {1, 11}, {2, 11}, {3, 11}, {4, 11}}, 150 {{0, 12}, {1, 12}, {2, 12}, {3, 12}, {4, 12}}, 151 {{0, 13}, {1, 13}, {2, 13}, {3, 13}, {4, 13}}, 152 {{0, 14}, {1, 14}, {2, 14}, {3, 14}, {4, 14}}, 153 {{0, 15}, {1, 15}, {2, 15}, {3, 15}, {4, 15}}, 154 {{0, 16}, {1, 16}, {2, 16}, {3, 16}, {4, 16}}, 155 {{0, 17}, {1, 17}, {2, 17}, {3, 17}, {4, 17}}, 156 {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}, 157 {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}}, 158 {{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}}, 159 {{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}}, 160 {{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}}, 161 {{0, 5}, {1, 5}, {2, 5}, {3, 5}, {4, 5}}, 162 {{0, 6}, {1, 6}, {2, 6}, {3, 6}, {4, 6}}, 163 {{0, 7}, {1, 7}, {2, 7}, {3, 7}, {4, 7}}, 164 {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}}, 165 }; 166 #endif 167 168 #ifdef LED_MATRIX_ENABLE 169 const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT] = { 170 // The numbers in the comments are the led numbers DXX on the PCB 171 /* Refer to IS31 manual for these locations 172 * driver 173 * | LED address 174 * | | */ 175 // Left half 176 // 45 44 43 42 41 40 39 177 { 0, C2_2 }, { 0, C1_2 }, { 0, C5_1 }, { 0, C4_1 }, { 0, C3_1 }, { 0, C2_1 }, { 0, C1_1 }, 178 // 52 51 50 49 48 47 46 179 { 0, C4_3 }, { 0, C3_3 }, { 0, C2_3 }, { 0, C1_3 }, { 0, C5_2 }, { 0, C4_2 }, { 0, C3_2 }, 180 // 58 57 56 55 54 53 181 { 0, C5_4 }, { 0, C4_4 }, { 0, C3_4 }, { 0, C2_4 }, { 0, C1_4 }, { 0, C5_3 }, 182 // 67 66 65 64 63 62 61 183 { 0, C4_6 }, { 0, C3_6 }, { 0, C2_6 }, { 0, C1_6 }, { 0, C5_5 }, { 0, C4_5 }, { 0, C3_5 }, 184 // 76 75 74 73 72 185 { 0, C4_8 }, { 0, C3_8 }, { 0, C2_8 }, { 0, C1_8 }, { 0, C4_7 }, 186 // 60 59 187 { 0, C2_5 }, { 0, C1_5 }, 188 // 68 189 { 0, C5_6 }, 190 // 71 70 69 191 { 0, C3_7 }, { 0, C2_7 }, { 0, C1_7 }, 192 // Right half (mirrored) 193 // Due to how LED_MATRIX_SPLIT is implemented, only the first half of g_is31fl3731_leds is actually used. 194 // Luckily, the right half has the same LED pinouts, just mirrored. 195 // 45 44 43 42 41 40 39 196 { 0, C2_2 }, { 0, C1_2 }, { 0, C5_1 }, { 0, C4_1 }, { 0, C3_1 }, { 0, C2_1 }, { 0, C1_1 }, 197 // 52 51 50 49 48 47 46 198 { 0, C4_3 }, { 0, C3_3 }, { 0, C2_3 }, { 0, C1_3 }, { 0, C5_2 }, { 0, C4_2 }, { 0, C3_2 }, 199 // 58 57 56 55 54 53 200 { 0, C5_4 }, { 0, C4_4 }, { 0, C3_4 }, { 0, C2_4 }, { 0, C1_4 }, { 0, C5_3 }, 201 // 67 66 65 64 63 62 61 202 { 0, C4_6 }, { 0, C3_6 }, { 0, C2_6 }, { 0, C1_6 }, { 0, C5_5 }, { 0, C4_5 }, { 0, C3_5 }, 203 // 76 75 74 73 72 204 { 0, C4_8 }, { 0, C3_8 }, { 0, C2_8 }, { 0, C1_8 }, { 0, C4_7 }, 205 // 60 59 206 { 0, C2_5 }, { 0, C1_5 }, 207 // 68 208 { 0, C5_6 }, 209 // 71 70 69 210 { 0, C3_7 }, { 0, C2_7 }, { 0, C1_7 }, 211 }; 212 213 int led_matrix_led_index(int index) { 214 return index; 215 } 216 #endif 217 218 #ifdef ST7565_ENABLE 219 __attribute__((weak)) void st7565_on_user(void) { 220 ergodox_infinity_lcd_color(UINT16_MAX / 2, UINT16_MAX / 2, UINT16_MAX / 2); 221 } 222 223 __attribute__((weak)) void st7565_off_user(void) { 224 ergodox_infinity_lcd_color(0, 0, 0); 225 } 226 227 static void format_layer_bitmap_string(char* buffer, uint8_t offset) { 228 for (int i = 0; i < 16 && i + offset < MAX_LAYER; i++) { 229 if (i == 0 || i == 4 || i == 8 || i == 12) { 230 *buffer = ' '; 231 ++buffer; 232 } 233 234 uint8_t layer = i + offset; 235 if (layer_state_cmp(default_layer_state, layer)) { 236 *buffer = 'D'; 237 } else if (layer_state_is(layer)) { 238 *buffer = '1'; 239 } else { 240 *buffer = '_'; 241 } 242 ++buffer; 243 } 244 *buffer = 0; 245 } 246 247 __attribute__((weak)) void st7565_task_user(void) { 248 if (is_keyboard_master()) { 249 // Draw led and layer status 250 led_t leds = host_keyboard_led_state(); 251 if(leds.num_lock) { st7565_write("Num ", false); } 252 if(leds.caps_lock) { st7565_write("Cap ", false); } 253 if(leds.scroll_lock) { st7565_write("Scrl ", false); } 254 if(leds.compose) { st7565_write("Com ", false); } 255 if(leds.kana) { st7565_write("Kana", false); } 256 st7565_advance_page(true); 257 258 char layer_buffer[16 + 5]; // 3 spaces and one null terminator 259 st7565_set_cursor(0, 1); 260 format_layer_bitmap_string(layer_buffer, 0); 261 st7565_write_ln(layer_buffer, false); 262 format_layer_bitmap_string(layer_buffer, 16); 263 st7565_write_ln(layer_buffer, false); 264 st7565_write_ln(" 1=On D=Default", false); 265 } else { 266 // Draw logo 267 static const char qmk_logo[] = { 268 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 269 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 270 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00 271 }; 272 273 st7565_write(qmk_logo, false); 274 st7565_write(" Infinity Ergodox ", false); 275 } 276 } 277 #endif 278 279 #if defined(SPLIT_KEYBOARD) 280 void usart_master_init(SerialDriver **driver) { 281 PORTA->PCR[1] = PORTx_PCRn_PE | PORTx_PCRn_PS | PORTx_PCRn_PFE | PORTx_PCRn_MUX(2); 282 PORTA->PCR[2] = PORTx_PCRn_DSE | PORTx_PCRn_SRE | PORTx_PCRn_MUX(2); 283 284 // driver is set to SD1 in config.h 285 } 286 287 void usart_slave_init(SerialDriver **driver) { 288 PORTE->PCR[0] = PORTx_PCRn_PE | PORTx_PCRn_PS | PORTx_PCRn_PFE | PORTx_PCRn_MUX(3); 289 PORTE->PCR[1] = PORTx_PCRn_DSE | PORTx_PCRn_SRE | PORTx_PCRn_MUX(3); 290 291 *driver = &SD2; 292 } 293 #endif