timer02.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. //timer02.c
  2. // use atmega timer2 as main system timer instead of timer0
  3. // timer0 is used for fast pwm (OC0B output)
  4. // original OVF handler is disabled
  5. #include <avr/io.h>
  6. #include <avr/interrupt.h>
  7. #include <Arduino.h>
  8. uint8_t timer02_pwm0 = 0;
  9. void timer02_set_pwm0(uint8_t pwm0)
  10. {
  11. if (timer02_pwm0 == pwm0) return;
  12. if (pwm0)
  13. {
  14. TCCR0A |= (2 << COM0B0);
  15. OCR0B = pwm0 - 1;
  16. }
  17. else
  18. {
  19. TCCR0A &= ~(2 << COM0B0);
  20. OCR0B = 0;
  21. }
  22. }
  23. void timer02_init(void)
  24. {
  25. //save sreg
  26. uint8_t _sreg = SREG;
  27. //disable interrupts for sure
  28. cli();
  29. //mask timer0 interrupts - disable all
  30. TIMSK0 &= ~(1<<TOIE0);
  31. TIMSK0 &= ~(1<<OCIE0A);
  32. TIMSK0 &= ~(1<<OCIE0B);
  33. //setup timer0
  34. TCCR0A = 0x00; //COM_A-B=00, WGM_0-1=00
  35. TCCR0B = (1 << CS00); //WGM_2=0, CS_0-2=011
  36. //switch timer0 to fast pwm mode
  37. TCCR0A |= (3 << WGM00); //WGM_0-1=11
  38. //set OCR0B register to zero
  39. OCR0B = 0;
  40. //disable OCR0B output (will be enabled in timer02_set_pwm0)
  41. TCCR0A &= ~(2 << COM0B0);
  42. //setup timer2
  43. TCCR2A = 0x00; //COM_A-B=00, WGM_0-1=00
  44. TCCR2B = (3 << CS20); //WGM_2=0, CS_0-2=011
  45. //mask timer2 interrupts - enable OVF, disable others
  46. TIMSK2 |= (1<<TOIE2);
  47. TIMSK2 &= ~(1<<OCIE2A);
  48. TIMSK2 &= ~(1<<OCIE2B);
  49. //set timer2 OCR registers (OCRB interrupt generated 0.5ms after OVF interrupt)
  50. OCR2A = 0;
  51. OCR2B = 128;
  52. //restore sreg (enable interrupts)
  53. SREG = _sreg;
  54. }
  55. //following code is OVF handler for timer 2
  56. //it is copy-paste from wiring.c and modified for timer2
  57. //variables timer0_overflow_count and timer0_millis are declared in wiring.c
  58. // the prescaler is set so that timer0 ticks every 64 clock cycles, and the
  59. // the overflow handler is called every 256 ticks.
  60. #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
  61. // the whole number of milliseconds per timer0 overflow
  62. #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
  63. // the fractional number of milliseconds per timer0 overflow. we shift right
  64. // by three to fit these numbers into a byte. (for the clock speeds we care
  65. // about - 8 and 16 MHz - this doesn't lose precision.)
  66. #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
  67. #define FRACT_MAX (1000 >> 3)
  68. extern volatile unsigned long timer0_overflow_count;
  69. extern volatile unsigned long timer0_millis;
  70. unsigned char timer0_fract = 0;
  71. ISR(TIMER2_OVF_vect)
  72. {
  73. // copy these to local variables so they can be stored in registers
  74. // (volatile variables must be read from memory on every access)
  75. unsigned long m = timer0_millis;
  76. unsigned char f = timer0_fract;
  77. m += MILLIS_INC;
  78. f += FRACT_INC;
  79. if (f >= FRACT_MAX)
  80. {
  81. f -= FRACT_MAX;
  82. m += 1;
  83. }
  84. timer0_fract = f;
  85. timer0_millis = m;
  86. timer0_overflow_count++;
  87. }