fmrx.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Receive an FM-modulated signal by using a timer with input capture
  3. */
  4. #include "usbcas.h"
  5. static uint16_t one_bit_lo, one_bit_hi; /* Range for an edge being a "1" */
  6. static inline void fmrx_led_on(void)
  7. {
  8. PORTB &= ~(1 << 0);
  9. }
  10. static inline void fmrx_led_off(void)
  11. {
  12. PORTB |= (1 << 0);
  13. }
  14. void fmrx_init(void)
  15. {
  16. uint8_t tccr1b;
  17. /* ICP1/PD4 is input, with pullup */
  18. DDRD &= ~(1 << 4);
  19. PORTD |= (1 << 4);
  20. /* PB0 is RXLED */
  21. DDRB |= (1 << 0);
  22. fmrx_led_off();
  23. /* Stop counter */
  24. TCCR1B = 0;
  25. /* Normal mode, no comparators */
  26. TCCR1A = 0;
  27. /* Enable interrupts on input capture */
  28. TIMSK1 = (1 << ICIE1);
  29. /* Clear interrupt flag if set */
  30. TIFR1 = (1 << ICF1);
  31. /* Clear timer counter */
  32. TCNT1 = 0;
  33. /*
  34. * Input capture noise canceler on, normal mode; not counting yet
  35. */
  36. tccr1b = (1 << ICNC1) + (0 << CS10);
  37. if (!(PIND & (1 << 4)))
  38. tccr1b |= 1 << ICES1;
  39. TCCR1B = tccr1b;
  40. }
  41. static uint16_t bytes;
  42. void fmrx_set_speed(uint32_t baudrate)
  43. {
  44. uint8_t prescale = 1; /* No prescaling */
  45. /* Enable prescaler for low baud rates to reduce wraparound */
  46. if (baudrate < 976) {
  47. baudrate <<= 3; /* ... for calculation purposes ... */
  48. prescale++; /* Prescale by 8 */
  49. }
  50. one_bit_lo = F_CPU / (4 * baudrate);
  51. one_bit_hi = 3 * one_bit_lo;
  52. bytes = 0;
  53. TCCR1B = (TCCR1B & ~7) | prescale;
  54. }
  55. /* We "hunt" for a block until we find this bit pattern; same as ABC800 */
  56. #define CAS_SYNC_PATTERN 0x0216 /* SYNC + STX */
  57. #define CAS_BLOCK_LEN (1+2+253+1+2) /* type+num+data+ETX+checksum */
  58. /* Interrupt routine for edge capture */
  59. ISR(TIMER1_CAPT_vect)
  60. {
  61. static uint16_t last_edge;
  62. static uint16_t data;
  63. static uint8_t bits;
  64. uint16_t edge, delta;
  65. TCCR1B ^= (1 << ICES1); /* Next edge -> opposite polarity */
  66. edge = ICR1;
  67. delta = edge - last_edge;
  68. if (delta < one_bit_lo) {
  69. /* Early edge, no action */
  70. return;
  71. } else if (delta < one_bit_hi) {
  72. /* A data bit edge */
  73. data |= (1 << 15);
  74. } else {
  75. /* Clock edge */
  76. last_edge = edge;
  77. if (bytes) {
  78. if (--bits == 0) {
  79. uint8_t outbyte = data >> 8;
  80. fmrx_recv_byte(outbyte);
  81. data = 0; /* To avoid false sync */
  82. bits = 8;
  83. if (--bytes == 0)
  84. fmrx_led_off();
  85. }
  86. } else {
  87. sprintf(tbuf, "[%04x]", data);
  88. say(tbuf);
  89. if (data == CAS_SYNC_PATTERN) {
  90. bits = 8;
  91. bytes = CAS_BLOCK_LEN;
  92. fmrx_led_on();
  93. }
  94. }
  95. data >>= 1;
  96. }
  97. }