backlight.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /**
  2. * Backlighting code for PS2AVRGB boards (ATMEGA32A)
  3. * Kenneth A. (github.com/krusli | krusli.me)
  4. */
  5. #include "backlight.h"
  6. #include "quantum.h"
  7. #include <avr/pgmspace.h>
  8. #include <avr/interrupt.h>
  9. #include "backlight_custom.h"
  10. #include "breathing_custom.h"
  11. // DEBUG
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. // Port D: digital pins of the AVR chipset
  15. #define NUMLOCK_PORT (1 << 0) // 0th pin of Port D (digital)
  16. #define CAPSLOCK_PORT (1 << 1) // 1st pin
  17. #define BACKLIGHT_PORT (1 << 4) // D4
  18. //#define SCROLLLOCK_PORT (1 << 6) // D6
  19. #define TIMER_CLK_DIV64 0x03 ///< Timer clocked at F_CPU/64
  20. #define TIMER1PRESCALE TIMER_CLK_DIV64 ///< timer 1 prescaler default
  21. #define TIMER_PRESCALE_MASK 0x07 ///< Timer Prescaler Bit-Mask
  22. #define PWM_MAX 0xFF
  23. #define TIMER_TOP 255 // 8 bit PWM
  24. extern backlight_config_t backlight_config;
  25. /**
  26. * References
  27. * Port Registers: https://www.arduino.cc/en/Reference/PortManipulation
  28. * TCCR1A: https://electronics.stackexchange.com/questions/92350/what-is-the-difference-between-tccr1a-and-tccr1b
  29. * Timers: http://www.avrbeginners.net/architecture/timers/timers.html
  30. * 16-bit timer setup: http://sculland.com/ATmega168/Interrupts-And-Timers/16-Bit-Timer-Setup/
  31. * PS2AVRGB firmware: https://github.com/showjean/ps2avrU/tree/master/firmware
  32. */
  33. // @Override
  34. // turn LEDs on and off depending on USB caps/num/scroll lock states.
  35. __attribute__ ((weak))
  36. void led_set_user(uint8_t usb_led) {
  37. if (usb_led & (1 << USB_LED_NUM_LOCK)) {
  38. // turn on
  39. DDRD |= NUMLOCK_PORT;
  40. PORTD |= NUMLOCK_PORT;
  41. } else {
  42. // turn off
  43. DDRD &= ~NUMLOCK_PORT;
  44. PORTD &= ~NUMLOCK_PORT;
  45. }
  46. if (usb_led & (1 << USB_LED_CAPS_LOCK)) {
  47. DDRD |= CAPSLOCK_PORT;
  48. PORTD |= CAPSLOCK_PORT;
  49. } else {
  50. DDRD &= ~CAPSLOCK_PORT;
  51. PORTD &= ~CAPSLOCK_PORT;
  52. }
  53. /* YMD96 does not have scroll lock led
  54. if (usb_led & (1 << USB_LED_SCROLL_LOCK)) {
  55. DDRD |= SCROLLLOCK_PORT;
  56. PORTD |= SCROLLLOCK_PORT;
  57. } else {
  58. DDRD &= ~SCROLLLOCK_PORT;
  59. PORTD &= ~SCROLLLOCK_PORT;
  60. }*/
  61. }
  62. #ifdef BACKLIGHT_ENABLE
  63. // sets up Timer 1 for 8-bit PWM
  64. void timer1PWMSetup(void) { // NOTE ONLY CALL THIS ONCE
  65. // default 8 bit mode
  66. TCCR1A &= ~(1 << 1); // cbi(TCCR1A,PWM11); <- set PWM11 bit to HIGH
  67. TCCR1A |= (1 << 0); // sbi(TCCR1A,PWM10); <- set PWM10 bit to LOW
  68. // clear output compare value A
  69. // outb(OCR1AH, 0);
  70. // outb(OCR1AL, 0);
  71. // clear output comparator registers for B
  72. OCR1BH = 0; // outb(OCR1BH, 0);
  73. OCR1BL = 0; // outb(OCR1BL, 0);
  74. }
  75. bool is_init = false;
  76. void timer1Init(void) {
  77. // timer1SetPrescaler(TIMER1PRESCALE)
  78. // set to DIV/64
  79. (TCCR1B) = ((TCCR1B) & ~TIMER_PRESCALE_MASK) | TIMER1PRESCALE;
  80. // reset TCNT1
  81. TCNT1H = 0; // outb(TCNT1H, 0);
  82. TCNT1L = 0; // outb(TCNT1L, 0);
  83. // TOIE1: Timer Overflow Interrupt Enable (Timer 1);
  84. TIMSK |= _BV(TOIE1); // sbi(TIMSK, TOIE1);
  85. is_init = true;
  86. }
  87. void timer1UnInit(void) {
  88. // set prescaler back to NONE
  89. (TCCR1B) = ((TCCR1B) & ~TIMER_PRESCALE_MASK) | 0x00; // TIMERRTC_CLK_STOP
  90. // disable timer overflow interrupt
  91. TIMSK &= ~_BV(TOIE1); // overflow bit?
  92. setPWM(0);
  93. is_init = false;
  94. }
  95. // handle TCNT1 overflow
  96. //! Interrupt handler for tcnt1 overflow interrupt
  97. ISR(TIMER1_OVF_vect, ISR_NOBLOCK)
  98. {
  99. // sei();
  100. // handle breathing here
  101. #ifdef BACKLIGHT_BREATHING
  102. if (is_breathing()) {
  103. custom_breathing_handler();
  104. }
  105. #endif
  106. // TODO call user defined function
  107. }
  108. // enable timer 1 PWM
  109. // timer1PWMBOn()
  110. void timer1PWMBEnable(void) {
  111. // turn on channel B (OC1B) PWM output
  112. // set OC1B as non-inverted PWM
  113. TCCR1A |= _BV(COM1B1);
  114. TCCR1A &= ~_BV(COM1B0);
  115. }
  116. // disable timer 1 PWM
  117. // timer1PWMBOff()
  118. void timer1PWMBDisable(void) {
  119. TCCR1A &= ~_BV(COM1B1);
  120. TCCR1A &= ~_BV(COM1B0);
  121. }
  122. void enableBacklight(void) {
  123. DDRD |= BACKLIGHT_PORT; // set digital pin 4 as output
  124. PORTD |= BACKLIGHT_PORT; // set digital pin 4 to high
  125. }
  126. void disableBacklight(void) {
  127. // DDRD &= ~BACKLIGHT_PORT; // set digital pin 4 as input
  128. PORTD &= ~BACKLIGHT_PORT; // set digital pin 4 to low
  129. }
  130. void startPWM(void) {
  131. timer1Init();
  132. timer1PWMBEnable();
  133. enableBacklight();
  134. }
  135. void stopPWM(void) {
  136. timer1UnInit();
  137. disableBacklight();
  138. timer1PWMBDisable();
  139. }
  140. void b_led_init_ports(void) {
  141. /* turn backlight on/off depending on user preference */
  142. #if BACKLIGHT_ON_STATE == 0
  143. // DDRx register: sets the direction of Port D
  144. // DDRD &= ~BACKLIGHT_PORT; // set digital pin 4 as input
  145. PORTD &= ~BACKLIGHT_PORT; // set digital pin 4 to low
  146. #else
  147. DDRD |= BACKLIGHT_PORT; // set digital pin 4 as output
  148. PORTD |= BACKLIGHT_PORT; // set digital pin 4 to high
  149. #endif
  150. timer1PWMSetup();
  151. startPWM();
  152. #ifdef BACKLIGHT_BREATHING
  153. breathing_enable();
  154. #endif
  155. }
  156. void b_led_set(uint8_t level) {
  157. if (level > BACKLIGHT_LEVELS) {
  158. level = BACKLIGHT_LEVELS;
  159. }
  160. setPWM((int)(TIMER_TOP * (float) level / BACKLIGHT_LEVELS));
  161. }
  162. // called every matrix scan
  163. void b_led_task(void) {
  164. // do nothing for now
  165. }
  166. void setPWM(uint16_t xValue) {
  167. if (xValue > TIMER_TOP) {
  168. xValue = TIMER_TOP;
  169. }
  170. OCR1B = xValue; // timer1PWMBSet(xValue);
  171. }
  172. #endif // BACKLIGHT_ENABLE