diff options
Diffstat (limited to 'quantum/quantum.c')
| -rw-r--r-- | quantum/quantum.c | 406 |
1 files changed, 169 insertions, 237 deletions
diff --git a/quantum/quantum.c b/quantum/quantum.c index c80975f21..88617412c 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -23,6 +23,10 @@ | |||
| 23 | #define TAPPING_TERM 200 | 23 | #define TAPPING_TERM 200 |
| 24 | #endif | 24 | #endif |
| 25 | 25 | ||
| 26 | #ifndef BREATHING_PERIOD | ||
| 27 | #define BREATHING_PERIOD 6 | ||
| 28 | #endif | ||
| 29 | |||
| 26 | #include "backlight.h" | 30 | #include "backlight.h" |
| 27 | extern backlight_config_t backlight_config; | 31 | extern backlight_config_t backlight_config; |
| 28 | 32 | ||
| @@ -618,7 +622,17 @@ bool process_record_quantum(keyrecord_t *record) { | |||
| 618 | } | 622 | } |
| 619 | 623 | ||
| 620 | send_keyboard_report(); | 624 | send_keyboard_report(); |
| 625 | return false; | ||
| 621 | } | 626 | } |
| 627 | |||
| 628 | #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_BREATHING) | ||
| 629 | case BL_BRTG: { | ||
| 630 | if (record->event.pressed) | ||
| 631 | breathing_toggle(); | ||
| 632 | return false; | ||
| 633 | } | ||
| 634 | #endif | ||
| 635 | |||
| 622 | default: { | 636 | default: { |
| 623 | shift_interrupted[0] = true; | 637 | shift_interrupted[0] = true; |
| 624 | shift_interrupted[1] = true; | 638 | shift_interrupted[1] = true; |
| @@ -831,6 +845,7 @@ void matrix_scan_quantum() { | |||
| 831 | 845 | ||
| 832 | static const uint8_t backlight_pin = BACKLIGHT_PIN; | 846 | static const uint8_t backlight_pin = BACKLIGHT_PIN; |
| 833 | 847 | ||
| 848 | // depending on the pin, we use a different output compare unit | ||
| 834 | #if BACKLIGHT_PIN == B7 | 849 | #if BACKLIGHT_PIN == B7 |
| 835 | # define COM1x1 COM1C1 | 850 | # define COM1x1 COM1C1 |
| 836 | # define OCR1x OCR1C | 851 | # define OCR1x OCR1C |
| @@ -841,17 +856,18 @@ static const uint8_t backlight_pin = BACKLIGHT_PIN; | |||
| 841 | # define COM1x1 COM1A1 | 856 | # define COM1x1 COM1A1 |
| 842 | # define OCR1x OCR1A | 857 | # define OCR1x OCR1A |
| 843 | #else | 858 | #else |
| 844 | # define NO_BACKLIGHT_CLOCK | 859 | # define NO_HARDWARE_PWM |
| 845 | #endif | 860 | #endif |
| 846 | 861 | ||
| 847 | #ifndef BACKLIGHT_ON_STATE | 862 | #ifndef BACKLIGHT_ON_STATE |
| 848 | #define BACKLIGHT_ON_STATE 0 | 863 | #define BACKLIGHT_ON_STATE 0 |
| 849 | #endif | 864 | #endif |
| 850 | 865 | ||
| 866 | #ifdef NO_HARDWARE_PWM // pwm through software | ||
| 867 | |||
| 851 | __attribute__ ((weak)) | 868 | __attribute__ ((weak)) |
| 852 | void backlight_init_ports(void) | 869 | void backlight_init_ports(void) |
| 853 | { | 870 | { |
| 854 | |||
| 855 | // Setup backlight pin as output and output to on state. | 871 | // Setup backlight pin as output and output to on state. |
| 856 | // DDRx |= n | 872 | // DDRx |= n |
| 857 | _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); | 873 | _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); |
| @@ -862,83 +878,15 @@ void backlight_init_ports(void) | |||
| 862 | // PORTx |= n | 878 | // PORTx |= n |
| 863 | _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF); | 879 | _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF); |
| 864 | #endif | 880 | #endif |
| 865 | |||
| 866 | #ifndef NO_BACKLIGHT_CLOCK | ||
| 867 | // Use full 16-bit resolution. | ||
| 868 | ICR1 = 0xFFFF; | ||
| 869 | |||
| 870 | // I could write a wall of text here to explain... but TL;DW | ||
| 871 | // Go read the ATmega32u4 datasheet. | ||
| 872 | // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on | ||
| 873 | |||
| 874 | // Pin PB7 = OCR1C (Timer 1, Channel C) | ||
| 875 | // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 | ||
| 876 | // (i.e. start high, go low when counter matches.) | ||
| 877 | // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 | ||
| 878 | // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 | ||
| 879 | |||
| 880 | TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010; | ||
| 881 | TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; | ||
| 882 | #endif | ||
| 883 | |||
| 884 | backlight_init(); | ||
| 885 | #ifdef BACKLIGHT_BREATHING | ||
| 886 | breathing_defaults(); | ||
| 887 | #endif | ||
| 888 | } | 881 | } |
| 889 | 882 | ||
| 890 | __attribute__ ((weak)) | 883 | __attribute__ ((weak)) |
| 891 | void backlight_set(uint8_t level) | 884 | void backlight_set(uint8_t level) {} |
| 892 | { | ||
| 893 | // Prevent backlight blink on lowest level | ||
| 894 | // #if BACKLIGHT_ON_STATE == 0 | ||
| 895 | // // PORTx &= ~n | ||
| 896 | // _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 897 | // #else | ||
| 898 | // // PORTx |= n | ||
| 899 | // _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF); | ||
| 900 | // #endif | ||
| 901 | |||
| 902 | if ( level == 0 ) { | ||
| 903 | #ifndef NO_BACKLIGHT_CLOCK | ||
| 904 | // Turn off PWM control on backlight pin, revert to output low. | ||
| 905 | TCCR1A &= ~(_BV(COM1x1)); | ||
| 906 | OCR1x = 0x0; | ||
| 907 | #else | ||
| 908 | // #if BACKLIGHT_ON_STATE == 0 | ||
| 909 | // // PORTx |= n | ||
| 910 | // _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF); | ||
| 911 | // #else | ||
| 912 | // // PORTx &= ~n | ||
| 913 | // _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 914 | // #endif | ||
| 915 | #endif | ||
| 916 | } | ||
| 917 | #ifndef NO_BACKLIGHT_CLOCK | ||
| 918 | else if ( level == BACKLIGHT_LEVELS ) { | ||
| 919 | // Turn on PWM control of backlight pin | ||
| 920 | TCCR1A |= _BV(COM1x1); | ||
| 921 | // Set the brightness | ||
| 922 | OCR1x = 0xFFFF; | ||
| 923 | } | ||
| 924 | else { | ||
| 925 | // Turn on PWM control of backlight pin | ||
| 926 | TCCR1A |= _BV(COM1x1); | ||
| 927 | // Set the brightness | ||
| 928 | OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 929 | } | ||
| 930 | #endif | ||
| 931 | |||
| 932 | #ifdef BACKLIGHT_BREATHING | ||
| 933 | breathing_intensity_default(); | ||
| 934 | #endif | ||
| 935 | } | ||
| 936 | 885 | ||
| 937 | uint8_t backlight_tick = 0; | 886 | uint8_t backlight_tick = 0; |
| 938 | 887 | ||
| 939 | void backlight_task(void) { | 888 | void backlight_task(void) { |
| 940 | #ifdef NO_BACKLIGHT_CLOCK | 889 | if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) { |
| 941 | if ((0xFFFF >> ((BACKLIGHT_LEVELS - backlight_config.level) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) { | ||
| 942 | #if BACKLIGHT_ON_STATE == 0 | 890 | #if BACKLIGHT_ON_STATE == 0 |
| 943 | // PORTx &= ~n | 891 | // PORTx &= ~n |
| 944 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | 892 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); |
| @@ -955,232 +903,216 @@ void backlight_task(void) { | |||
| 955 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | 903 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); |
| 956 | #endif | 904 | #endif |
| 957 | } | 905 | } |
| 958 | backlight_tick = (backlight_tick + 1) % 16; | 906 | backlight_tick = backlight_tick + 1 % 16; |
| 959 | #endif | ||
| 960 | } | 907 | } |
| 961 | 908 | ||
| 962 | #ifdef BACKLIGHT_BREATHING | 909 | #ifdef BACKLIGHT_BREATHING |
| 910 | #error "Backlight breathing only available with hardware PWM. Please disable." | ||
| 911 | #endif | ||
| 963 | 912 | ||
| 964 | #ifdef NO_BACKLIGHT_CLOCK | 913 | #else // pwm through timer |
| 965 | void breathing_defaults(void) {} | 914 | |
| 966 | void breathing_intensity_default(void) {} | 915 | #define TIMER_TOP 0xFFFFU |
| 967 | #else | 916 | |
| 917 | // See http://jared.geek.nz/2013/feb/linear-led-pwm | ||
| 918 | static uint16_t cie_lightness(uint16_t v) { | ||
| 919 | if (v <= 5243) // if below 8% of max | ||
| 920 | return v / 9; // same as dividing by 900% | ||
| 921 | else { | ||
| 922 | uint32_t y = (((uint32_t) v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare | ||
| 923 | // to get a useful result with integer division, we shift left in the expression above | ||
| 924 | // and revert what we've done again after squaring. | ||
| 925 | y = y * y * y >> 8; | ||
| 926 | if (y > 0xFFFFUL) // prevent overflow | ||
| 927 | return 0xFFFFU; | ||
| 928 | else | ||
| 929 | return (uint16_t) y; | ||
| 930 | } | ||
| 931 | } | ||
| 932 | |||
| 933 | // range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val. | ||
| 934 | static inline void set_pwm(uint16_t val) { | ||
| 935 | OCR1x = val; | ||
| 936 | } | ||
| 937 | |||
| 938 | __attribute__ ((weak)) | ||
| 939 | void backlight_set(uint8_t level) { | ||
| 940 | if (level > BACKLIGHT_LEVELS) | ||
| 941 | level = BACKLIGHT_LEVELS; | ||
| 942 | |||
| 943 | if (level == 0) { | ||
| 944 | // Turn off PWM control on backlight pin | ||
| 945 | TCCR1A &= ~(_BV(COM1x1)); | ||
| 946 | } else { | ||
| 947 | // Turn on PWM control of backlight pin | ||
| 948 | TCCR1A |= _BV(COM1x1); | ||
| 949 | } | ||
| 950 | // Set the brightness | ||
| 951 | set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS)); | ||
| 952 | } | ||
| 953 | |||
| 954 | void backlight_task(void) {} | ||
| 955 | |||
| 956 | #ifdef BACKLIGHT_BREATHING | ||
| 968 | 957 | ||
| 969 | #define BREATHING_NO_HALT 0 | 958 | #define BREATHING_NO_HALT 0 |
| 970 | #define BREATHING_HALT_OFF 1 | 959 | #define BREATHING_HALT_OFF 1 |
| 971 | #define BREATHING_HALT_ON 2 | 960 | #define BREATHING_HALT_ON 2 |
| 961 | #define BREATHING_STEPS 128 | ||
| 972 | 962 | ||
| 973 | static uint8_t breath_intensity; | 963 | static uint8_t breathing_period = BREATHING_PERIOD; |
| 974 | static uint8_t breath_speed; | 964 | static uint8_t breathing_halt = BREATHING_NO_HALT; |
| 975 | static uint16_t breathing_index; | 965 | static uint16_t breathing_counter = 0; |
| 976 | static uint8_t breathing_halt; | ||
| 977 | 966 | ||
| 978 | void breathing_enable(void) | 967 | bool is_breathing(void) { |
| 979 | { | 968 | return !!(TIMSK1 & _BV(TOIE1)); |
| 980 | if (get_backlight_level() == 0) | 969 | } |
| 981 | { | ||
| 982 | breathing_index = 0; | ||
| 983 | } | ||
| 984 | else | ||
| 985 | { | ||
| 986 | // Set breathing_index to be at the midpoint (brightest point) | ||
| 987 | breathing_index = 0x20 << breath_speed; | ||
| 988 | } | ||
| 989 | 970 | ||
| 990 | breathing_halt = BREATHING_NO_HALT; | 971 | #define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0) |
| 972 | #define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0) | ||
| 973 | #define breathing_min() do {breathing_counter = 0;} while (0) | ||
| 974 | #define breathing_max() do {breathing_counter = breathing_period * 244 / 2;} while (0) | ||
| 991 | 975 | ||
| 992 | // Enable breathing interrupt | 976 | void breathing_enable(void) |
| 993 | TIMSK1 |= _BV(OCIE1A); | 977 | { |
| 978 | breathing_counter = 0; | ||
| 979 | breathing_halt = BREATHING_NO_HALT; | ||
| 980 | breathing_interrupt_enable(); | ||
| 994 | } | 981 | } |
| 995 | 982 | ||
| 996 | void breathing_pulse(void) | 983 | void breathing_pulse(void) |
| 997 | { | 984 | { |
| 998 | if (get_backlight_level() == 0) | 985 | if (get_backlight_level() == 0) |
| 999 | { | 986 | breathing_min(); |
| 1000 | breathing_index = 0; | ||
| 1001 | } | ||
| 1002 | else | 987 | else |
| 1003 | { | 988 | breathing_max(); |
| 1004 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 1005 | breathing_index = 0x21 << breath_speed; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | breathing_halt = BREATHING_HALT_ON; | 989 | breathing_halt = BREATHING_HALT_ON; |
| 1009 | 990 | breathing_interrupt_enable(); | |
| 1010 | // Enable breathing interrupt | ||
| 1011 | TIMSK1 |= _BV(OCIE1A); | ||
| 1012 | } | 991 | } |
| 1013 | 992 | ||
| 1014 | void breathing_disable(void) | 993 | void breathing_disable(void) |
| 1015 | { | 994 | { |
| 1016 | // Disable breathing interrupt | 995 | breathing_interrupt_disable(); |
| 1017 | TIMSK1 &= ~_BV(OCIE1A); | 996 | // Restore backlight level |
| 1018 | backlight_set(get_backlight_level()); | 997 | backlight_set(get_backlight_level()); |
| 1019 | } | 998 | } |
| 1020 | 999 | ||
| 1021 | void breathing_self_disable(void) | 1000 | void breathing_self_disable(void) |
| 1022 | { | 1001 | { |
| 1023 | if (get_backlight_level() == 0) | 1002 | if (get_backlight_level() == 0) |
| 1024 | { | 1003 | breathing_halt = BREATHING_HALT_OFF; |
| 1025 | breathing_halt = BREATHING_HALT_OFF; | 1004 | else |
| 1026 | } | 1005 | breathing_halt = BREATHING_HALT_ON; |
| 1027 | else | ||
| 1028 | { | ||
| 1029 | breathing_halt = BREATHING_HALT_ON; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | //backlight_set(get_backlight_level()); | ||
| 1033 | } | 1006 | } |
| 1034 | 1007 | ||
| 1035 | void breathing_toggle(void) | 1008 | void breathing_toggle(void) { |
| 1036 | { | 1009 | if (is_breathing()) |
| 1037 | if (!is_breathing()) | 1010 | breathing_disable(); |
| 1038 | { | 1011 | else |
| 1039 | if (get_backlight_level() == 0) | 1012 | breathing_enable(); |
| 1040 | { | ||
| 1041 | breathing_index = 0; | ||
| 1042 | } | ||
| 1043 | else | ||
| 1044 | { | ||
| 1045 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 1046 | breathing_index = 0x21 << breath_speed; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | breathing_halt = BREATHING_NO_HALT; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | // Toggle breathing interrupt | ||
| 1053 | TIMSK1 ^= _BV(OCIE1A); | ||
| 1054 | |||
| 1055 | // Restore backlight level | ||
| 1056 | if (!is_breathing()) | ||
| 1057 | { | ||
| 1058 | backlight_set(get_backlight_level()); | ||
| 1059 | } | ||
| 1060 | } | 1013 | } |
| 1061 | 1014 | ||
| 1062 | bool is_breathing(void) | 1015 | void breathing_period_set(uint8_t value) |
| 1063 | { | 1016 | { |
| 1064 | return (TIMSK1 && _BV(OCIE1A)); | 1017 | if (!value) |
| 1018 | value = 1; | ||
| 1019 | breathing_period = value; | ||
| 1065 | } | 1020 | } |
| 1066 | 1021 | ||
| 1067 | void breathing_intensity_default(void) | 1022 | void breathing_period_default(void) { |
| 1068 | { | 1023 | breathing_period_set(BREATHING_PERIOD); |
| 1069 | //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS); | ||
| 1070 | breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 1071 | } | 1024 | } |
| 1072 | 1025 | ||
| 1073 | void breathing_intensity_set(uint8_t value) | 1026 | void breathing_period_inc(void) |
| 1074 | { | 1027 | { |
| 1075 | breath_intensity = value; | 1028 | breathing_period_set(breathing_period+1); |
| 1076 | } | 1029 | } |
| 1077 | 1030 | ||
| 1078 | void breathing_speed_default(void) | 1031 | void breathing_period_dec(void) |
| 1079 | { | 1032 | { |
| 1080 | breath_speed = 4; | 1033 | breathing_period_set(breathing_period-1); |
| 1081 | } | 1034 | } |
| 1082 | 1035 | ||
| 1083 | void breathing_speed_set(uint8_t value) | 1036 | /* To generate breathing curve in python: |
| 1084 | { | 1037 | * from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)] |
| 1085 | bool is_breathing_now = is_breathing(); | 1038 | */ |
| 1086 | uint8_t old_breath_speed = breath_speed; | 1039 | static const uint8_t breathing_table[BREATHING_STEPS] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 1087 | |||
| 1088 | if (is_breathing_now) | ||
| 1089 | { | ||
| 1090 | // Disable breathing interrupt | ||
| 1091 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | breath_speed = value; | ||
| 1095 | |||
| 1096 | if (is_breathing_now) | ||
| 1097 | { | ||
| 1098 | // Adjust index to account for new speed | ||
| 1099 | breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed; | ||
| 1100 | |||
| 1101 | // Enable breathing interrupt | ||
| 1102 | TIMSK1 |= _BV(OCIE1A); | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | } | ||
| 1106 | 1040 | ||
| 1107 | void breathing_speed_inc(uint8_t value) | 1041 | // Use this before the cie_lightness function. |
| 1108 | { | 1042 | static inline uint16_t scale_backlight(uint16_t v) { |
| 1109 | if ((uint16_t)(breath_speed - value) > 10 ) | 1043 | return v / BACKLIGHT_LEVELS * get_backlight_level(); |
| 1110 | { | ||
| 1111 | breathing_speed_set(0); | ||
| 1112 | } | ||
| 1113 | else | ||
| 1114 | { | ||
| 1115 | breathing_speed_set(breath_speed - value); | ||
| 1116 | } | ||
| 1117 | } | 1044 | } |
| 1118 | 1045 | ||
| 1119 | void breathing_speed_dec(uint8_t value) | 1046 | /* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run |
| 1047 | * about 244 times per second. | ||
| 1048 | */ | ||
| 1049 | ISR(TIMER1_OVF_vect) | ||
| 1120 | { | 1050 | { |
| 1121 | if ((uint16_t)(breath_speed + value) > 10 ) | 1051 | uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS; |
| 1122 | { | 1052 | // resetting after one period to prevent ugly reset at overflow. |
| 1123 | breathing_speed_set(10); | 1053 | breathing_counter = (breathing_counter + 1) % (breathing_period * 244); |
| 1124 | } | 1054 | uint8_t index = breathing_counter / interval % BREATHING_STEPS; |
| 1125 | else | 1055 | |
| 1126 | { | 1056 | if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) || |
| 1127 | breathing_speed_set(breath_speed + value); | 1057 | ((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1))) |
| 1128 | } | 1058 | { |
| 1129 | } | 1059 | breathing_interrupt_disable(); |
| 1060 | } | ||
| 1130 | 1061 | ||
| 1131 | void breathing_defaults(void) | 1062 | set_pwm(cie_lightness(scale_backlight((uint16_t) pgm_read_byte(&breathing_table[index]) * 0x0101U))); |
| 1132 | { | ||
| 1133 | breathing_intensity_default(); | ||
| 1134 | breathing_speed_default(); | ||
| 1135 | breathing_halt = BREATHING_NO_HALT; | ||
| 1136 | } | 1063 | } |
| 1137 | 1064 | ||
| 1138 | /* Breathing Sleep LED brighness(PWM On period) table | 1065 | #endif // BACKLIGHT_BREATHING |
| 1139 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 1140 | * | ||
| 1141 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 1142 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 1143 | */ | ||
| 1144 | static const uint8_t breathing_table[64] PROGMEM = { | ||
| 1145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, | ||
| 1146 | 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, | ||
| 1147 | 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, | ||
| 1148 | 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 1149 | }; | ||
| 1150 | 1066 | ||
| 1151 | ISR(TIMER1_COMPA_vect) | 1067 | __attribute__ ((weak)) |
| 1068 | void backlight_init_ports(void) | ||
| 1152 | { | 1069 | { |
| 1153 | // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity; | 1070 | // Setup backlight pin as output and output to on state. |
| 1154 | 1071 | // DDRx |= n | |
| 1155 | 1072 | _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); | |
| 1156 | uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F; | 1073 | #if BACKLIGHT_ON_STATE == 0 |
| 1157 | 1074 | // PORTx &= ~n | |
| 1158 | if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F))) | 1075 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); |
| 1159 | { | 1076 | #else |
| 1160 | // Disable breathing interrupt | 1077 | // PORTx |= n |
| 1161 | TIMSK1 &= ~_BV(OCIE1A); | 1078 | _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF); |
| 1162 | } | 1079 | #endif |
| 1163 | 1080 | // I could write a wall of text here to explain... but TL;DW | |
| 1164 | OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity; | 1081 | // Go read the ATmega32u4 datasheet. |
| 1082 | // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on | ||
| 1083 | |||
| 1084 | // Pin PB7 = OCR1C (Timer 1, Channel C) | ||
| 1085 | // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 | ||
| 1086 | // (i.e. start high, go low when counter matches.) | ||
| 1087 | // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 | ||
| 1088 | // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 | ||
| 1089 | |||
| 1090 | /* | ||
| 1091 | 14.8.3: | ||
| 1092 | "In fast PWM mode, the compare units allow generation of PWM waveforms on the OCnx pins. Setting the COMnx1:0 bits to two will produce a non-inverted PWM [..]." | ||
| 1093 | "In fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGMn3:0 = 5, 6, or 7), the value in ICRn (WGMn3:0 = 14), or the value in OCRnA (WGMn3:0 = 15)." | ||
| 1094 | */ | ||
| 1095 | |||
| 1096 | TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010; | ||
| 1097 | TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; | ||
| 1098 | // Use full 16-bit resolution. Counter counts to ICR1 before reset to 0. | ||
| 1099 | ICR1 = TIMER_TOP; | ||
| 1165 | 1100 | ||
| 1101 | backlight_init(); | ||
| 1102 | #ifdef BACKLIGHT_BREATHING | ||
| 1103 | breathing_enable(); | ||
| 1104 | #endif | ||
| 1166 | } | 1105 | } |
| 1167 | 1106 | ||
| 1168 | #endif // NO_BACKLIGHT_CLOCK | 1107 | #endif // NO_HARDWARE_PWM |
| 1169 | #endif // breathing | ||
| 1170 | 1108 | ||
| 1171 | #else // backlight | 1109 | #else // backlight |
| 1172 | 1110 | ||
| 1173 | __attribute__ ((weak)) | 1111 | __attribute__ ((weak)) |
| 1174 | void backlight_init_ports(void) | 1112 | void backlight_init_ports(void) {} |
| 1175 | { | ||
| 1176 | |||
| 1177 | } | ||
| 1178 | 1113 | ||
| 1179 | __attribute__ ((weak)) | 1114 | __attribute__ ((weak)) |
| 1180 | void backlight_set(uint8_t level) | 1115 | void backlight_set(uint8_t level) {} |
| 1181 | { | ||
| 1182 | |||
| 1183 | } | ||
| 1184 | 1116 | ||
| 1185 | #endif // backlight | 1117 | #endif // backlight |
| 1186 | 1118 | ||
