qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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