fmtx.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Transmit an FM-modulated signal using the USART in SPI master mode.
  3. * As per ABC standard, this signal is transmitted MSB first.
  4. */
  5. #include "usbcas.h"
  6. #define BITS_PER_PATTERN_BYTE 2
  7. #define PATTERN_BIT_MASK ((1 << BITS_PER_PATTERN_BYTE) - 1)
  8. #include "fmpat.h"
  9. #define TX_BUSY 0
  10. #define TX_IDLE (1 << TXC1)
  11. static inline ATTR_ALWAYS_INLINE void fmtx_disable(void)
  12. {
  13. UCSR1B &= ~(1 << UDRIE1);
  14. }
  15. static uint8_t parity;
  16. /*
  17. * Send stuff if we have anything to send
  18. */
  19. ISR(USART1_UDRE_vect)
  20. {
  21. static uint8_t data, left;
  22. uint8_t pattern;
  23. if (!left) {
  24. /* Fetch a new byte if there is one, unless motor is off */
  25. int nd;
  26. nd = motor_relay ? fmtx_next_byte() : -1;
  27. if (nd < 0) {
  28. /*
  29. * Nothing to send. Disable the interrupt and
  30. * send out one last edge. Afterwards, the hardware
  31. * will drive the line high.
  32. */
  33. fmtx_disable();
  34. UCSR1A = TX_IDLE;
  35. UDR1 = parity; /* One last edge before going high */
  36. parity = 0;
  37. return;
  38. }
  39. data = nd;
  40. left = 8;
  41. }
  42. pattern = fm_pat[data & PATTERN_BIT_MASK] ^ ~parity;
  43. UCSR1A = TX_IDLE;
  44. UDR1 = pattern;
  45. data >>= BITS_PER_PATTERN_BYTE;
  46. left -= BITS_PER_PATTERN_BYTE;
  47. parity = -((int8_t)pattern >= 0);
  48. }
  49. /*
  50. * Synchronize transmitter before reconfiguration
  51. */
  52. void fmtx_drain(void)
  53. {
  54. /* Wait until input queue is idle and we have had at least one output */
  55. while ((UCSR1B & (1 << UDRIE1)) || !(UCSR1A & TX_IDLE))
  56. do_usb_task();
  57. }
  58. /*
  59. * Initialize the USART hardware and set transmission baudrate.
  60. * This is mostly the same as SerialSPI_Init().
  61. * Returns the actual baud rate adjusted for underflow.
  62. */
  63. #define FMTX_UBRRVAL(b) (SERIAL_SPI_UBBRVAL((b) * (8/BITS_PER_PATTERN_BYTE)))
  64. #define UBRR_MAX 4095
  65. #define FMTX_MIN_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE) * (UBRR_MAX+1UL)))
  66. #define FMTX_MAX_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE)))
  67. #if FMTX_MIN_BAUD > CAS_BAUDRATE_ABC80
  68. # error "UBRR overflows for standard ABC80 baud rate"
  69. #endif
  70. uint32_t fmtx_real_baudrate(uint32_t baudrate)
  71. {
  72. if (baudrate < FMTX_MIN_BAUD || baudrate > FMTX_MAX_BAUD)
  73. baudrate = CAS_BAUDRATE_ABC80;
  74. return baudrate;
  75. }
  76. void fmtx_init_speed(uint32_t baudrate)
  77. {
  78. parity = 0; /* We start out with a high idle */
  79. UCSR1B = 0; /* Disable transmitter and ISR */
  80. UCSR1A = (1 << TXC1); /* Clear TXC bit */
  81. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  82. PORTD |= 0x28; /* Drive data and clock high while idle */
  83. /*
  84. * SPI master mode, mode 1, LSB first
  85. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  86. * is 1 when idle and the TXLED is OFF.
  87. */
  88. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  89. /* UBRR must be zero when the transmitter is enabled */
  90. UBRR1 = 0;
  91. /* Enable transmitter, but not receiver and not the ISR (yet) */
  92. UCSR1B = (1 << TXEN1);
  93. /* Configure baud rate */
  94. UBRR1 = FMTX_UBRRVAL(baudrate);
  95. /*
  96. * Enable transmitter ISR (which probably will immediately
  97. * go to idle...)
  98. */
  99. fmtx_enable();
  100. }