fmtx.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Transmit an FM-modulated signal using the USART in SPI master mode.
  3. * As per ABC standard, this signal is transmitted LSB 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. static uint8_t data;
  11. static uint8_t left;
  12. static inline bool fmtx_send_ready(void) ATTR_ALWAYS_INLINE;
  13. static inline bool fmtx_send_ready(void)
  14. {
  15. return !!(UCSR1A & (1 << UDRE1));
  16. }
  17. /*
  18. * Sends another chunk of output.
  19. */
  20. uint8_t fmtx_send_more(void)
  21. {
  22. uint8_t l = left;
  23. if (!fmtx_send_ready())
  24. return l; /* Not ready yet */
  25. uint8_t d = data;
  26. uint8_t pattern = fm_pat[d & PATTERN_BIT_MASK] ^ parity;
  27. UCSR1A = (1 << TXC1);
  28. UDR1 = pattern;
  29. data = d >> BITS_PER_PATTERN_BYTE;
  30. left -= BITS_PER_PATTERN_BYTE;
  31. parity = -((int8_t)pattern < 0);
  32. return left;
  33. }
  34. /*
  35. * Begin sending a new byte. Use when fmtx_send_*() has returned zero.
  36. */
  37. uint8_t fmtx_send_byte(uint8_t d)
  38. {
  39. data = d;
  40. left = 8;
  41. return fmtx_send_more();
  42. }
  43. /*
  44. * Synchronize transmitter before reconfiguration
  45. */
  46. void fmtx_drain(void)
  47. {
  48. while (!(UCSR1A & (1 << TXC1)))
  49. ;
  50. }
  51. /*
  52. * Initialize the USART hardware and set transmission baudrate.
  53. * This is mostly the same as SerialSPI_Init().
  54. * Returns the actual baud rate adjusted for underflow.
  55. */
  56. #define FMTX_UBRRVAL(b) (SERIAL_SPI_UBBRVAL((b) * (8/BITS_PER_PATTERN_BYTE)))
  57. #define UBRR_MAX 4095
  58. #define FMTX_MIN_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE) * (UBRR_MAX+1UL)))
  59. #define FMTX_MAX_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE)))
  60. #if FMTX_MIN_BAUD > CAS_BAUDRATE_ABC80
  61. # error "UBRR overflows for standard ABC80 baud rate"
  62. #endif
  63. uint32_t fmtx_real_baudrate(uint32_t baudrate)
  64. {
  65. if (baudrate < FMTX_MIN_BAUD || baudrate > FMTX_MAX_BAUD)
  66. baudrate = CAS_BAUDRATE_ABC80;
  67. return baudrate;
  68. }
  69. void fmtx_init_speed(uint32_t baudrate)
  70. {
  71. uint32_t ubrrval;
  72. ubrrval = FMTX_UBRRVAL(baudrate);
  73. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  74. PORTD = (PORTD & ~0x28) | (parity & 0x20) | 0x08;
  75. UCSR1B = 0; /* Disable USART */
  76. UCSR1A = 0; /* Clear error bits */
  77. /*
  78. * SPI master mode, mode 1, LSB first
  79. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  80. * is 1 when idle and the TXLED is OFF.
  81. */
  82. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  83. /* UBRR must be zero when the transmitter is enabled */
  84. UBRR1 = 0;
  85. /* Enable transmitter, but not receiver */
  86. UCSR1B = (1 << TXEN1);
  87. /* Configure baud rate */
  88. UBRR1 = ubrrval;
  89. /* Output the current idle state of the line */
  90. UDR1 = parity;
  91. }