#include "outputselect.h"
#endif
-#ifndef TAPPING_TERM
-#define TAPPING_TERM 200
-#endif
-
#ifndef BREATHING_PERIOD
#define BREATHING_PERIOD 6
#endif
bootloader_jump();
}
-// Shift / paren setup
-
-#ifndef LSPO_KEY
- #define LSPO_KEY KC_9
-#endif
-#ifndef RSPC_KEY
- #define RSPC_KEY KC_0
-#endif
-
-#ifndef LSPO_MOD
- #define LSPO_MOD KC_LSFT
-#endif
-#ifndef RSPC_MOD
- #define RSPC_MOD KC_RSFT
-#endif
-
-// Shift / Enter setup
-#ifndef SFTENT_KEY
- #define SFTENT_KEY KC_ENT
-#endif
-
-static bool shift_interrupted[2] = {0, 0};
-static uint16_t scs_timer[2] = {0, 0};
-
/* true if the last press of GRAVE_ESC was shifted (i.e. GUI or SHIFT were pressed), false otherwise.
* Used to ensure that the correct keycode is released if the key is released.
*/
static bool grave_esc_was_shifted = false;
-bool process_record_quantum(keyrecord_t *record) {
+/* Convert record into usable keycode via the contained event. */
+uint16_t get_record_keycode(keyrecord_t *record) {
+ return get_event_keycode(record->event);
+}
+
- /* This gets the keycode from the key pressed */
- keypos_t key = record->event.key;
- uint16_t keycode;
+/* Convert event into usable keycode. Checks the layer cache to ensure that it
+ * retains the correct keycode after a layer change, if the key is still pressed.
+ */
+uint16_t get_event_keycode(keyevent_t event) {
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
/* TODO: Use store_or_get_action() or a similar function. */
if (!disable_action_cache) {
uint8_t layer;
- if (record->event.pressed) {
- layer = layer_switch_get_layer(key);
- update_source_layers_cache(key, layer);
+ if (event.pressed) {
+ layer = layer_switch_get_layer(event.key);
+ update_source_layers_cache(event.key, layer);
} else {
- layer = read_source_layers_cache(key);
+ layer = read_source_layers_cache(event.key);
}
- keycode = keymap_key_to_keycode(layer, key);
+ return keymap_key_to_keycode(layer, event.key);
} else
#endif
- keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
+ return keymap_key_to_keycode(layer_switch_get_layer(event.key), event.key);
+}
+
+/* Main keycode processing function. Hands off handling to other functions,
+ * then processes internal Quantum keycodes, then processes ACTIONs.
+ */
+bool process_record_quantum(keyrecord_t *record) {
+ uint16_t keycode = get_record_keycode(record);
// This is how you use actions here
// if (keycode == KC_LEAD) {
#ifdef HAPTIC_ENABLE
process_haptic(keycode, record) &&
#endif //HAPTIC_ENABLE
- process_record_kb(keycode, record) &&
- #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_KEYPRESSES)
+ #if defined(RGB_MATRIX_ENABLE)
process_rgb_matrix(keycode, record) &&
#endif
+ process_record_kb(keycode, record) &&
#if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED)
process_midi(keycode, record) &&
#endif
#endif
#ifdef TERMINAL_ENABLE
process_terminal(keycode, record) &&
+ #endif
+ #ifdef SPACE_CADET_ENABLE
+ process_space_cadet(keycode, record) &&
#endif
true)) {
return false;
return false;
case DEBUG:
if (record->event.pressed) {
- debug_enable = true;
+ debug_enable ^= 1;
+ if (debug_enable) {
print("DEBUG: enabled.\n");
+ } else {
+ print("DEBUG: disabled.\n");
+ }
}
return false;
case EEPROM_RESET:
if (!record->event.pressed) {
#endif
rgblight_toggle();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_MODE_FORWARD:
else {
rgblight_step();
}
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_MODE_REVERSE:
else {
rgblight_step_reverse();
}
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_HUI:
if (!record->event.pressed) {
#endif
rgblight_increase_hue();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_HUD:
if (!record->event.pressed) {
#endif
rgblight_decrease_hue();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_SAI:
if (!record->event.pressed) {
#endif
rgblight_increase_sat();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_SAD:
if (!record->event.pressed) {
#endif
rgblight_decrease_sat();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_VAI:
if (!record->event.pressed) {
#endif
rgblight_increase_val();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_VAD:
if (!record->event.pressed) {
#endif
rgblight_decrease_val();
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_SPI:
case RGB_MODE_PLAIN:
if (record->event.pressed) {
rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
- #ifdef SPLIT_KEYBOARD
- RGB_DIRTY = true;
- #endif
}
return false;
case RGB_MODE_BREATHE:
return false;
}
break;
- case KC_LSPO: {
- if (record->event.pressed) {
- shift_interrupted[0] = false;
- scs_timer[0] = timer_read ();
- register_mods(MOD_BIT(KC_LSFT));
- }
- else {
- #ifdef DISABLE_SPACE_CADET_ROLLOVER
- if (get_mods() & MOD_BIT(RSPC_MOD)) {
- shift_interrupted[0] = true;
- shift_interrupted[1] = true;
- }
- #endif
- if (!shift_interrupted[0] && timer_elapsed(scs_timer[0]) < TAPPING_TERM) {
- #ifdef DISABLE_SPACE_CADET_MODIFIER
- unregister_mods(MOD_BIT(KC_LSFT));
- #else
- if( LSPO_MOD != KC_LSFT ){
- unregister_mods(MOD_BIT(KC_LSFT));
- register_mods(MOD_BIT(LSPO_MOD));
- }
- #endif
- register_code(LSPO_KEY);
- unregister_code(LSPO_KEY);
- #ifndef DISABLE_SPACE_CADET_MODIFIER
- if( LSPO_MOD != KC_LSFT ){
- unregister_mods(MOD_BIT(LSPO_MOD));
- }
- #endif
- }
- unregister_mods(MOD_BIT(KC_LSFT));
- }
- return false;
- }
-
- case KC_RSPC: {
- if (record->event.pressed) {
- shift_interrupted[1] = false;
- scs_timer[1] = timer_read ();
- register_mods(MOD_BIT(KC_RSFT));
- }
- else {
- #ifdef DISABLE_SPACE_CADET_ROLLOVER
- if (get_mods() & MOD_BIT(LSPO_MOD)) {
- shift_interrupted[0] = true;
- shift_interrupted[1] = true;
- }
- #endif
- if (!shift_interrupted[1] && timer_elapsed(scs_timer[1]) < TAPPING_TERM) {
- #ifdef DISABLE_SPACE_CADET_MODIFIER
- unregister_mods(MOD_BIT(KC_RSFT));
- #else
- if( RSPC_MOD != KC_RSFT ){
- unregister_mods(MOD_BIT(KC_RSFT));
- register_mods(MOD_BIT(RSPC_MOD));
- }
- #endif
- register_code(RSPC_KEY);
- unregister_code(RSPC_KEY);
- #ifndef DISABLE_SPACE_CADET_MODIFIER
- if ( RSPC_MOD != KC_RSFT ){
- unregister_mods(MOD_BIT(RSPC_MOD));
- }
- #endif
- }
- unregister_mods(MOD_BIT(KC_RSFT));
- }
- return false;
- }
-
- case KC_SFTENT: {
- if (record->event.pressed) {
- shift_interrupted[1] = false;
- scs_timer[1] = timer_read ();
- register_mods(MOD_BIT(KC_RSFT));
- }
- else if (!shift_interrupted[1] && timer_elapsed(scs_timer[1]) < TAPPING_TERM) {
- unregister_mods(MOD_BIT(KC_RSFT));
- register_code(SFTENT_KEY);
- unregister_code(SFTENT_KEY);
- }
- else {
- unregister_mods(MOD_BIT(KC_RSFT));
- }
- return false;
- }
case GRAVE_ESC: {
uint8_t shifted = get_mods() & ((MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT)
#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_BREATHING)
case BL_BRTG: {
- if (record->event.pressed)
+ if (record->event.pressed) {
breathing_toggle();
+ }
return false;
}
#endif
-
- default: {
- shift_interrupted[0] = true;
- shift_interrupted[1] = true;
- break;
- }
}
return process_action_kb(record);
0, 0, 0, 1, 1, 1, 1, 0
};
+__attribute__ ((weak))
+const bool ascii_to_altgr_lut[0x80] PROGMEM = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
__attribute__ ((weak))
const uint8_t ascii_to_keycode_lut[0x80] PROGMEM = {
0, 0, 0, 0, 0, 0, 0, 0,
}
void send_char(char ascii_code) {
- uint8_t keycode;
- keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]);
- if (pgm_read_byte(&ascii_to_shift_lut[(uint8_t)ascii_code])) {
- register_code(KC_LSFT);
- register_code(keycode);
- unregister_code(keycode);
- unregister_code(KC_LSFT);
- } else {
- register_code(keycode);
- unregister_code(keycode);
+ uint8_t keycode = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)ascii_code]);
+ bool is_shifted = pgm_read_byte(&ascii_to_shift_lut[(uint8_t)ascii_code]);
+ bool is_altgred = pgm_read_byte(&ascii_to_altgr_lut[(uint8_t)ascii_code]);
+
+ if (is_shifted) {
+ register_code(KC_LSFT);
+ }
+ if (is_altgred) {
+ register_code(KC_RALT);
+ }
+ tap_code(keycode);
+ if (is_altgred) {
+ unregister_code(KC_RALT);
+ }
+ if (is_shifted) {
+ unregister_code(KC_LSFT);
}
}
#ifdef HAPTIC_ENABLE
haptic_init();
#endif
+ #ifdef OUTPUT_AUTO_ENABLE
+ set_output(OUTPUT_AUTO);
+ #endif
matrix_init_kb();
}
-uint8_t rgb_matrix_task_counter = 0;
-
-#ifndef RGB_MATRIX_SKIP_FRAMES
- #define RGB_MATRIX_SKIP_FRAMES 1
-#endif
-
void matrix_scan_quantum() {
#if defined(AUDIO_ENABLE) && !defined(NO_MUSIC_MODE)
matrix_scan_music();
#ifdef RGB_MATRIX_ENABLE
rgb_matrix_task();
- if (rgb_matrix_task_counter == 0) {
- rgb_matrix_update_pwm_buffers();
- }
- rgb_matrix_task_counter = ((rgb_matrix_task_counter + 1) % (RGB_MATRIX_SKIP_FRAMES + 1));
#endif
#ifdef ENCODER_ENABLE
matrix_scan_kb();
}
-#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
+#if defined(BACKLIGHT_ENABLE) && (defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS))
-static const uint8_t backlight_pin = BACKLIGHT_PIN;
+// The logic is a bit complex, we support 3 setups:
+// 1. hardware PWM when backlight is wired to a PWM pin
+// depending on this pin, we use a different output compare unit
+// 2. software PWM with hardware timers, but the used timer depends
+// on the audio setup (audio wins other backlight)
+// 3. full software PWM
-// depending on the pin, we use a different output compare unit
#if BACKLIGHT_PIN == B7
+# define HARDWARE_PWM
# define TCCRxA TCCR1A
# define TCCRxB TCCR1B
# define COMxx1 COM1C1
# define OCRxx OCR1C
+# define TIMERx_OVF_vect TIMER1_OVF_vect
+# define TOIEx TOIE1
# define ICRx ICR1
+# define TIMSKx TIMSK1
#elif BACKLIGHT_PIN == B6
+# define HARDWARE_PWM
# define TCCRxA TCCR1A
# define TCCRxB TCCR1B
# define COMxx1 COM1B1
# define OCRxx OCR1B
+# define TIMERx_OVF_vect TIMER1_OVF_vect
+# define TOIEx TOIE1
# define ICRx ICR1
+# define TIMSKx TIMSK1
#elif BACKLIGHT_PIN == B5
+# define HARDWARE_PWM
# define TCCRxA TCCR1A
# define TCCRxB TCCR1B
# define COMxx1 COM1A1
# define OCRxx OCR1A
+# define TIMERx_OVF_vect TIMER1_OVF_vect
+# define TOIEx TOIE1
# define ICRx ICR1
+# define TIMSKx TIMSK1
#elif BACKLIGHT_PIN == C6
+# define HARDWARE_PWM
# define TCCRxA TCCR3A
# define TCCRxB TCCR3B
-# define COMxx1 COM1A1
+# define COMxx1 COM3A1
# define OCRxx OCR3A
+# define TIMERx_OVF_vect TIMER3_OVF_vect
+# define TOIEx TOIE3
# define ICRx ICR3
+# define TIMSKx TIMSK3
+#elif defined(__AVR_ATmega32A__) && BACKLIGHT_PIN == D4
+# define TCCRxA TCCR1A
+# define TCCRxB TCCR1B
+# define COMxx1 COM1B1
+# define OCRxx OCR1B
+# define TIMERx_OVF_vect TIMER1_OVF_vect
+# define TOIEx TOIE1
+# define ICRx ICR1
+# define TIMSKx TIMSK1
#else
-# define NO_HARDWARE_PWM
+# if !defined(BACKLIGHT_CUSTOM_DRIVER)
+# if !defined(B5_AUDIO) && !defined(B6_AUDIO) && !defined(B7_AUDIO)
+ // timer 1 is not used by audio , backlight can use it
+#pragma message "Using hardware timer 1 with software PWM"
+# define HARDWARE_PWM
+# define BACKLIGHT_PWM_TIMER
+# define TCCRxA TCCR1A
+# define TCCRxB TCCR1B
+# define OCRxx OCR1A
+# define TIMERx_COMPA_vect TIMER1_COMPA_vect
+# define TIMERx_OVF_vect TIMER1_OVF_vect
+# define OCIExA OCIE1A
+# define TOIEx TOIE1
+# define ICRx ICR1
+# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
+# define TIMSKx TIMSK
+# else
+# define TIMSKx TIMSK1
+# endif
+# elif !defined(C6_AUDIO) && !defined(C5_AUDIO) && !defined(C4_AUDIO)
+#pragma message "Using hardware timer 3 with software PWM"
+// timer 3 is not used by audio, backlight can use it
+# define HARDWARE_PWM
+# define BACKLIGHT_PWM_TIMER
+# define TCCRxA TCCR3A
+# define TCCRxB TCCR3B
+# define OCRxx OCR3A
+# define TIMERx_COMPA_vect TIMER3_COMPA_vect
+# define TIMERx_OVF_vect TIMER3_OVF_vect
+# define OCIExA OCIE3A
+# define TOIEx TOIE3
+# define ICRx ICR1
+# define TIMSKx TIMSK3
+# else
+#pragma message "Audio in use - using pure software PWM"
+#define NO_HARDWARE_PWM
+# endif
+# else
+#pragma message "Custom driver defined - using pure software PWM"
+#define NO_HARDWARE_PWM
+# endif
#endif
#ifndef BACKLIGHT_ON_STATE
#define BACKLIGHT_ON_STATE 0
#endif
-#ifdef NO_HARDWARE_PWM // pwm through software
+void backlight_on(uint8_t backlight_pin) {
+#if BACKLIGHT_ON_STATE == 0
+ writePinLow(backlight_pin);
+#else
+ writePinHigh(backlight_pin);
+#endif
+}
-__attribute__ ((weak))
+void backlight_off(uint8_t backlight_pin) {
+#if BACKLIGHT_ON_STATE == 0
+ writePinHigh(backlight_pin);
+#else
+ writePinLow(backlight_pin);
+#endif
+}
+
+
+#if defined(NO_HARDWARE_PWM) || defined(BACKLIGHT_PWM_TIMER) // pwm through software
+
+// we support multiple backlight pins
+#ifndef BACKLIGHT_LED_COUNT
+#define BACKLIGHT_LED_COUNT 1
+#endif
+
+#if BACKLIGHT_LED_COUNT == 1
+#define BACKLIGHT_PIN_INIT { BACKLIGHT_PIN }
+#else
+#define BACKLIGHT_PIN_INIT BACKLIGHT_PINS
+#endif
+
+#define FOR_EACH_LED(x) \
+ for (uint8_t i = 0; i < BACKLIGHT_LED_COUNT; i++) \
+ { \
+ uint8_t backlight_pin = backlight_pins[i]; \
+ { \
+ x \
+ } \
+ }
+
+static const uint8_t backlight_pins[BACKLIGHT_LED_COUNT] = BACKLIGHT_PIN_INIT;
+
+#else // full hardware PWM
+
+// we support only one backlight pin
+static const uint8_t backlight_pin = BACKLIGHT_PIN;
+#define FOR_EACH_LED(x) x
+
+#endif
+
+#ifdef NO_HARDWARE_PWM
+__attribute__((weak))
void backlight_init_ports(void)
{
// Setup backlight pin as output and output to on state.
- // DDRx |= n
- _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
- #if BACKLIGHT_ON_STATE == 0
- // PORTx &= ~n
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
- #else
- // PORTx |= n
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
- #endif
+ FOR_EACH_LED(
+ setPinOutput(backlight_pin);
+ backlight_on(backlight_pin);
+ )
}
__attribute__ ((weak))
#ifndef BACKLIGHT_CUSTOM_DRIVER
void backlight_task(void) {
if ((0xFFFF >> ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2))) & (1 << backlight_tick)) {
- #if BACKLIGHT_ON_STATE == 0
- // PORTx &= ~n
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
- #else
- // PORTx |= n
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
- #endif
- } else {
- #if BACKLIGHT_ON_STATE == 0
- // PORTx |= n
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
- #else
- // PORTx &= ~n
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
- #endif
+ FOR_EACH_LED(
+ backlight_on(backlight_pin);
+ )
+ }
+ else {
+ FOR_EACH_LED(
+ backlight_off(backlight_pin);
+ )
}
backlight_tick = (backlight_tick + 1) % 16;
}
#endif
#endif
-#else // pwm through timer
+#else // hardware pwm through timer
+
+#ifdef BACKLIGHT_PWM_TIMER
+
+// The idea of software PWM assisted by hardware timers is the following
+// we use the hardware timer in fast PWM mode like for hardware PWM, but
+// instead of letting the Output Match Comparator control the led pin
+// (which is not possible since the backlight is not wired to PWM pins on the
+// CPU), we do the LED on/off by oursleves.
+// The timer is setup to count up to 0xFFFF, and we set the Output Compare
+// register to the current 16bits backlight level (after CIE correction).
+// This means the CPU will trigger a compare match interrupt when the counter
+// reaches the backlight level, where we turn off the LEDs,
+// but also an overflow interrupt when the counter rolls back to 0,
+// in which we're going to turn on the LEDs.
+// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz.
+
+// Triggered when the counter reaches the OCRx value
+ISR(TIMERx_COMPA_vect) {
+ FOR_EACH_LED(
+ backlight_off(backlight_pin);
+ )
+}
+
+// Triggered when the counter reaches the TOP value
+// this one triggers at F_CPU/65536 =~ 244 Hz
+ISR(TIMERx_OVF_vect) {
+#ifdef BACKLIGHT_BREATHING
+ if(is_breathing()) {
+ breathing_task();
+ }
+#endif
+ // for very small values of OCRxx (or backlight level)
+ // we can't guarantee this whole code won't execute
+ // at the same time as the compare match interrupt
+ // which means that we might turn on the leds while
+ // trying to turn them off, leading to flickering
+ // artifacts (especially while breathing, because breathing_task
+ // takes many computation cycles).
+ // so better not turn them on while the counter TOP is very low.
+ if (OCRxx > 256) {
+ FOR_EACH_LED(
+ backlight_on(backlight_pin);
+ )
+ }
+}
+
+#endif
#define TIMER_TOP 0xFFFFU
level = BACKLIGHT_LEVELS;
if (level == 0) {
+ #ifdef BACKLIGHT_PWM_TIMER
+ if (OCRxx) {
+ TIMSKx &= ~(_BV(OCIExA));
+ TIMSKx &= ~(_BV(TOIEx));
+ FOR_EACH_LED(
+ backlight_off(backlight_pin);
+ )
+ }
+ #else
// Turn off PWM control on backlight pin
TCCRxA &= ~(_BV(COMxx1));
+ #endif
} else {
+ #ifdef BACKLIGHT_PWM_TIMER
+ if (!OCRxx) {
+ TIMSKx |= _BV(OCIExA);
+ TIMSKx |= _BV(TOIEx);
+ }
+ #else
// Turn on PWM control of backlight pin
TCCRxA |= _BV(COMxx1);
+ #endif
}
// Set the brightness
set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
static uint8_t breathing_halt = BREATHING_NO_HALT;
static uint16_t breathing_counter = 0;
+#ifdef BACKLIGHT_PWM_TIMER
+static bool breathing = false;
+
+bool is_breathing(void) {
+ return breathing;
+}
+
+#define breathing_interrupt_enable() do { breathing = true; } while (0)
+#define breathing_interrupt_disable() do { breathing = false; } while (0)
+#else
+
bool is_breathing(void) {
- return !!(TIMSK1 & _BV(TOIE1));
+ return !!(TIMSKx & _BV(TOIEx));
}
-#define breathing_interrupt_enable() do {TIMSK1 |= _BV(TOIE1);} while (0)
-#define breathing_interrupt_disable() do {TIMSK1 &= ~_BV(TOIE1);} while (0)
+#define breathing_interrupt_enable() do {TIMSKx |= _BV(TOIEx);} while (0)
+#define breathing_interrupt_disable() do {TIMSKx &= ~_BV(TOIEx);} while (0)
+#endif
+
#define breathing_min() do {breathing_counter = 0;} while (0)
#define breathing_max() do {breathing_counter = breathing_period * 244 / 2;} while (0)
return v / BACKLIGHT_LEVELS * get_backlight_level();
}
+#ifdef BACKLIGHT_PWM_TIMER
+void breathing_task(void)
+#else
/* Assuming a 16MHz CPU clock and a timer that resets at 64k (ICR1), the following interrupt handler will run
* about 244 times per second.
*/
-ISR(TIMER1_OVF_vect)
+ISR(TIMERx_OVF_vect)
+#endif
{
uint16_t interval = (uint16_t) breathing_period * 244 / BREATHING_STEPS;
// resetting after one period to prevent ugly reset at overflow.
void backlight_init_ports(void)
{
// Setup backlight pin as output and output to on state.
- // DDRx |= n
- _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
- #if BACKLIGHT_ON_STATE == 0
- // PORTx &= ~n
- _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
- #else
- // PORTx |= n
- _SFR_IO8((backlight_pin >> 4) + 2) |= _BV(backlight_pin & 0xF);
- #endif
+ FOR_EACH_LED(
+ setPinOutput(backlight_pin);
+ backlight_on(backlight_pin);
+ )
+
// I could write a wall of text here to explain... but TL;DW
// Go read the ATmega32u4 datasheet.
// And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
+#ifdef BACKLIGHT_PWM_TIMER
+ // TimerX setup, Fast PWM mode count to TOP set in ICRx
+ TCCRxA = _BV(WGM11); // = 0b00000010;
+ // clock select clk/1
+ TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+#else // hardware PWM
// Pin PB7 = OCR1C (Timer 1, Channel C)
// Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
// (i.e. start high, go low when counter matches.)
"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 [..]."
"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)."
*/
- TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010;
+ TCCRxA = _BV(COMxx1) | _BV(WGM11); // = 0b00001010;
TCCRxB = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
+#endif
// Use full 16-bit resolution. Counter counts to ICR1 before reset to 0.
ICRx = TIMER_TOP;
#endif
}
-#endif // NO_HARDWARE_PWM
+#endif // hardware backlight
-#else // backlight
+#else // no backlight
__attribute__ ((weak))
void backlight_init_ports(void) {}