123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- /*
- * Receive an FM-modulated signal by using a timer with input capture
- */
- #include "usbcas.h"
- static inline void fmrx_led_on(void)
- {
- //PORTB &= ~(1 << 0);
- }
- static inline void fmrx_led_off(void)
- {
- // PORTB |= (1 << 0);
- }
- void fmrx_init(void)
- {
- uint8_t tccr1b;
- /* ICP1/PD4 is input, with pullup */
- DDRD &= ~(1 << 4);
- PORTD |= (1 << 4);
- /* PB0 is RXLED */
- DDRB |= (1 << 0);
- fmrx_led_off();
- /* Stop counter */
- TCCR1B = 0;
- /* Normal mode, no comparators */
- TCCR1A = 0;
- /* Enable interrupts on input capture */
- TIFR1 = TIMSK1 = 1 << ICIE1;
- /* Clear timer counter */
- TCNT1 = 0;
- /*
- * Input capture noise canceler on, normal mode; not counting yet
- */
- tccr1b = (1 << ICNC1) + (0 << CS10);
- if (!(PIND & (1 << 4)))
- tccr1b |= 1 << ICES1;
- TCCR1B = tccr1b;
- }
- /* Timing constants: start and end of data bit interval, and timeout */
- static uint16_t one_bit_lo, one_bit_hi, one_bit_timeout;
- static uint16_t bytes;
- static uint16_t last_edge;
- static uint16_t data; /* 16 bit for sync pattern detect */
- static uint8_t bits;
- static uint16_t bytes;
- static bool started;
- /* Bit receive timeout on/off */
- static inline void enable_timeout(uint16_t when)
- {
- OCR1A = when;
- TIMSK1 = TIFR1 = (1 << ICIE1) | (1 << OCIE1A);
- }
- static inline void disable_timeout(void)
- {
- TIFR1 = TIMSK1 = (1 << ICIE1);
- }
- void fmrx_set_speed(uint32_t baudrate)
- {
- uint8_t prescale = 1; /* No prescaling */
- /* Enable prescaler for low baud rates to reduce wraparound */
- if (baudrate < 976) {
- baudrate <<= 3; /* ... for calculation purposes ... */
- prescale++; /* Prescale by 8 */
- }
- TCCR1B &= ~7; /* Stop timer */
- one_bit_lo = F_CPU / (4 * baudrate);
- one_bit_hi = 3 * one_bit_lo;
- one_bit_timeout = 16 * one_bit_lo; /* 4 total bit times... */
- disable_timeout();
- started = false;
- bits = bytes = 0;
- last_edge = TCNT1;
- TCCR1B |= prescale; /* Start timer */
- }
- /* We "hunt" for a block until we find this bit pattern; same as ABC800 */
- #define CAS_SYNC_PATTERN 0x0216 /* SYNC + STX */
- #define CAS_BLOCK_LEN (1+2+253+1+2) /* type+num+data+ETX+checksum */
- /* Finish a bit due to clock edge or timeout */
- static inline ATTR_ALWAYS_INLINE void finish_bit(void)
- {
- if (!started)
- return;
- if (bytes) {
- if (--bits == 0) {
- uint8_t outbyte = data >> 8;
- fmrx_recv_byte(outbyte);
- data = 0; /* To avoid false sync */
- bits = 8;
- if (--bytes == 0)
- fmrx_led_off();
- }
- } else if (data == CAS_SYNC_PATTERN) {
- bits = 8;
- bytes = CAS_BLOCK_LEN;
- fmrx_led_on();
- }
- }
- /* Interrupt routine for edge capture */
- ISR(TIMER1_CAPT_vect)
- {
- uint16_t edge, delta;
- TCCR1B ^= (1 << ICES1); /* Next edge -> opposite polarity */
- edge = ICR1;
- delta = edge - last_edge;
- if (delta < one_bit_lo) {
- /* Early edge, no action */
- return;
- } else if (delta < one_bit_hi) {
- /* A data bit edge */
- data |= (1 << 15);
- } else {
- /* Clock edge */
- last_edge = edge;
- enable_timeout(edge + one_bit_timeout);
- finish_bit();
- started = true;
- data >>= 1;
- }
- }
- /* Interrupt routine for bit timeout */
- ISR(TIMER1_COMPA_vect)
- {
- disable_timeout();
- finish_bit();
- started = false;
- }
|