fmtx.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. PORTB |= (1 << 0);
  15. }
  16. static uint8_t parity;
  17. /*
  18. * Send stuff if we have anything to send
  19. */
  20. ISR(USART1_UDRE_vect)
  21. {
  22. static uint8_t data, left, gap;
  23. static uint16_t block_bytes;
  24. uint8_t pattern;
  25. if (!left) {
  26. /* Fetch a new byte if there is one, unless motor is off */
  27. int nd;
  28. if (!motor_relay() || (nd = fmtx_next_byte()) < 0) {
  29. /*
  30. * Nothing to send. Hold the line for some
  31. * number of byte-times in case we suffered an
  32. * underrun. Afterwards, the hardware will
  33. * drive the line high.
  34. */
  35. UCSR1A = TX_IDLE;
  36. UCSR1A = parity;
  37. if (!++gap)
  38. fmtx_disable();
  39. return;
  40. }
  41. data = nd;
  42. if (!block_bytes) {
  43. if (data == 0x02) {
  44. /*
  45. * Beginning of a data block, suppress
  46. * FF = silence until the end of the block
  47. *
  48. * STX+header+data+ETX+csum
  49. */
  50. block_bytes = 1+3+253+1+2;
  51. }
  52. } else {
  53. block_bytes--;
  54. }
  55. data = nd;
  56. left = 8;
  57. gap = 0;
  58. }
  59. if (!block_bytes && data == 0xff) {
  60. pattern = parity;
  61. } else {
  62. pattern = fm_pat[data & PATTERN_BIT_MASK] ^ parity;
  63. data >>= BITS_PER_PATTERN_BYTE;
  64. parity = -((int8_t)pattern < 0);
  65. }
  66. left -= BITS_PER_PATTERN_BYTE;
  67. UCSR1A = TX_IDLE;
  68. UDR1 = pattern;
  69. }
  70. /*
  71. * Synchronize transmitter before reconfiguration
  72. */
  73. void fmtx_drain(void)
  74. {
  75. /* Wait until input queue is idle and we have had at least one output */
  76. while ((UCSR1B & (1 << UDRIE1)) || !(UCSR1A & TX_IDLE))
  77. do_usb_tasks();
  78. }
  79. /*
  80. * Initialize the USART hardware and set transmission baudrate.
  81. * This is mostly the same as SerialSPI_Init().
  82. * Returns the actual baud rate adjusted for underflow.
  83. */
  84. #define FMTX_UBRRVAL(b) (SERIAL_SPI_UBBRVAL((b) * (8/BITS_PER_PATTERN_BYTE)))
  85. #define UBRR_MAX 4095
  86. #define FMTX_MIN_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE) * (UBRR_MAX+1UL)))
  87. #define FMTX_MAX_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE)))
  88. #if FMTX_MIN_BAUD > CAS_BAUDRATE_ABC80
  89. # error "UBRR overflows for standard ABC80 baud rate"
  90. #endif
  91. uint32_t fmtx_real_baudrate(uint32_t baudrate)
  92. {
  93. if (baudrate < FMTX_MIN_BAUD || baudrate > FMTX_MAX_BAUD)
  94. baudrate = CAS_BAUDRATE_ABC80;
  95. return baudrate;
  96. }
  97. void fmtx_init_speed(uint32_t baudrate)
  98. {
  99. parity = 0xff; /* We start out with a high idle */
  100. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  101. PORTD |= 0x28; /* Drive data and clock high while idle */
  102. UCSR1B = 0; /* Disable transmitter and ISR */
  103. /*
  104. * SPI master mode, mode 1, LSB first
  105. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  106. * is 1 when idle and the TXLED is OFF.
  107. */
  108. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  109. /* UBRR must be zero when the transmitter is enabled */
  110. UBRR1 = 0;
  111. /* Enable transmitter, but not receiver and not the ISR (yet) */
  112. UCSR1B = (1 << TXEN1);
  113. /* Configure baud rate */
  114. UBRR1 = FMTX_UBRRVAL(baudrate);
  115. /*
  116. * Enable transmitter ISR (which probably will immediately
  117. * go to idle...)
  118. */
  119. fmtx_enable();
  120. }