fmtx.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. static uint8_t parity = 0;
  10. /*
  11. * Send stuff if we have anything to send
  12. */
  13. ISR(USART1_UDRE_vect)
  14. {
  15. static uint8_t data, left;
  16. uint8_t pattern;
  17. if (!left) {
  18. /* Fetch a new byte if there is one */
  19. int nd = fmtx_next_byte();
  20. if (nd < 0) {
  21. /*
  22. * Nothing to send. Disable interrupt.
  23. */
  24. UCSR1B &= ~(1 << UDRIE1);
  25. return;
  26. }
  27. data = nd;
  28. left = 8;
  29. }
  30. pattern = fm_pat[data & PATTERN_BIT_MASK] ^ parity;
  31. UCSR1A = (1 << TXC1); /* Make TXC1 bit useful */
  32. UDR1 = pattern;
  33. data >>= BITS_PER_PATTERN_BYTE;
  34. left -= BITS_PER_PATTERN_BYTE;
  35. parity = -((int8_t)pattern < 0);
  36. }
  37. /*
  38. * Synchronize transmitter before reconfiguration
  39. */
  40. void fmtx_drain(void)
  41. {
  42. const uint8_t ucsr1a_mask = (1 << UDRE1) + (1 << TXC1);
  43. /* Wait until UDRE1 and TXC1 are both set */
  44. while ((UCSR1A & ucsr1a_mask) != ucsr1a_mask)
  45. do_usb_task();
  46. }
  47. /*
  48. * Initialize the USART hardware and set transmission baudrate.
  49. * This is mostly the same as SerialSPI_Init().
  50. * Returns the actual baud rate adjusted for underflow.
  51. */
  52. #define FMTX_UBRRVAL(b) (SERIAL_SPI_UBBRVAL((b) * (8/BITS_PER_PATTERN_BYTE)))
  53. #define UBRR_MAX 4095
  54. #define FMTX_MIN_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE) * (UBRR_MAX+1UL)))
  55. #define FMTX_MAX_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE)))
  56. #if FMTX_MIN_BAUD > CAS_BAUDRATE_ABC80
  57. # error "UBRR overflows for standard ABC80 baud rate"
  58. #endif
  59. uint32_t fmtx_real_baudrate(uint32_t baudrate)
  60. {
  61. if (baudrate < FMTX_MIN_BAUD || baudrate > FMTX_MAX_BAUD)
  62. baudrate = CAS_BAUDRATE_ABC80;
  63. return baudrate;
  64. }
  65. void fmtx_init_speed(uint32_t baudrate)
  66. {
  67. UCSR1B = 0; /* Disable transmitter and ISR */
  68. UCSR1A = (1 << TXC1); /* Clear TXC bit */
  69. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  70. PORTD = (PORTD & ~0x28) | 0x20 | (parity & 0x08);
  71. /*
  72. * SPI master mode, mode 1, LSB first
  73. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  74. * is 1 when idle and the TXLED is OFF.
  75. */
  76. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  77. /* UBRR must be zero when the transmitter is enabled */
  78. UBRR1 = 0;
  79. /* Enable transmitter, but not receiver and not the ISR (yet) */
  80. UCSR1B = (1 << TXEN1);
  81. /* Configure baud rate */
  82. UBRR1 = FMTX_UBRRVAL(baudrate);
  83. /*
  84. * Output the current idle state of the line. This will also
  85. * cause the TXC bit to get set afterwards.
  86. */
  87. UDR1 = parity;
  88. /*
  89. * Enable transmitter ISR (which may immediately disable itself...)
  90. */
  91. fmtx_enable();
  92. }