knob_v2.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #include "knob_v2.h"
  2. bool knob_prev_a = false;
  3. static knob_report_t knob_report = {.dir = 0, .phase = 0};
  4. void knob_init(void) {
  5. // I use pins D1 (ISR1) & D4 for a knob.
  6. // Set pin mode for D4 as input.
  7. DDRD &= ~(0UL << ENCODER_PIN_2);
  8. // Enable internal pull-up for D4.
  9. // This is done by "writing" 1 to a pin that has its mode set to input.
  10. PORTD |= (1 << ENCODER_PIN_2);
  11. // Enable interrupt for D1
  12. // For more info on the below flags see this awesome section 11.1 (pages 89-90) here:
  13. // https://cdn-shop.adafruit.com/datasheets/atmel-7766-8-bit-avr-atmega16u4-32u4_datasheet.pdf
  14. // Set pin mode & pull-up.
  15. DDRD &= ~(0UL << ENCODER_PIN_1);
  16. PORTD |= (1UL << ENCODER_PIN_1);
  17. // INT: 33221100
  18. EICRA |= 0b00010000; // 0b01 - any edge
  19. // INT: 6 3210
  20. EIMSK |= 0b00000100;
  21. }
  22. ISR(ENCODER_INT) {
  23. bool a = PIND & (1 << ENCODER_PIN_1);
  24. if (knob_prev_a != a) {
  25. // "A" channel has REALLY changed.
  26. knob_report.phase = a;
  27. knob_prev_a = a;
  28. bool b = PIND & (1 << ENCODER_PIN_2);
  29. if (a == b) {
  30. // Halfway through CCW rotation (A == B)
  31. //
  32. // +---YOU ARE HERE (A=1, B=1)
  33. // | +---OR HERE (A=0, B=0)
  34. // | |
  35. // v v
  36. // A: _____/^^^^^\__
  37. // B: __/^^^^^\_____
  38. knob_report.dir++;
  39. } else {
  40. // Halfway through CW rotation (A != B)
  41. //
  42. // +---YOU ARE HERE (A=1, B=0)
  43. // | +---OR HERE (A=0, B=1)
  44. // | |
  45. // v v
  46. // A: _____/^^^^^\_____
  47. // B: ________/^^^^^\__
  48. knob_report.dir--;
  49. }
  50. }
  51. }
  52. knob_report_t knob_report_read(void) {
  53. // Return knob report.
  54. return knob_report;
  55. }
  56. void knob_report_reset(void) {
  57. // Call this ASAP once you've processed the previous knob report.
  58. // TODO: This should probably be called within `knob_report_read`.
  59. knob_report.dir = 0;
  60. knob_report.phase = 0;
  61. }