fmtx.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. /*
  7. * FM nybble patters; these should be transmitted LSB first
  8. * and XOR'd with the MSB of the pattern byte last transmitted.
  9. */
  10. static const uint8_t fm_nyb[16] = {
  11. 0x33, 0xcd, 0xcb, 0x35, 0xd3, 0x2d, 0x2b, 0xd5,
  12. 0xb3, 0x4d, 0x4b, 0xb5, 0x53, 0xad, 0xab, 0x55
  13. };
  14. static uint8_t parity = 0;
  15. /*
  16. * Send the least significant nybble of this data item and return
  17. * the next nybble, if any. Check with fmtx_send_ready() before
  18. * calling this function.
  19. */
  20. uint8_t fmtx_send_nybble(uint8_t d)
  21. {
  22. uint8_t nyb = fm_nyb[d & 15] ^ parity;
  23. UCSR1A = (1 << TXC1);
  24. UDR1 = nyb;
  25. parity = -((int8_t)nyb < 0);
  26. return d >> 4;
  27. }
  28. /*
  29. * Synchronize transmitter before reconfiguration
  30. */
  31. void fmtx_drain(void)
  32. {
  33. while (!(UCSR1A & (1 << TXC1)))
  34. ;
  35. }
  36. /*
  37. * Initialize the USART hardware and set transmission baudrate.
  38. * This is mostly the same as SerialSPI_Init().
  39. */
  40. void fmtx_init_speed(uint32_t baudrate)
  41. {
  42. DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
  43. PORTD = (PORTD & ~0x28) | (parity & 0x20) | 0x08;
  44. UCSR1B = 0; /* Disable USART */
  45. UCSR1A = 0; /* Clear error bits */
  46. /*
  47. * SPI master mode, mode 1, LSB first
  48. * UCPHA doesn't matter, but have UCPOL=1 to that the clock
  49. * is 1 when idle and the TXLED is OFF.
  50. */
  51. UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1);
  52. /* UBRR must be zero when the transmitter is enabled */
  53. UBRR1 = 0;
  54. /* Enable transmitter, but not receiver */
  55. UCSR1B = (1 << TXEN1);
  56. /* Configure baud rate (UBBRVAL is a typo in LUFA) */
  57. /* We need two SPI ticks per symbol, hence double... */
  58. UBRR1 = SERIAL_SPI_UBBRVAL(baudrate << 1);
  59. /* Output the current idle state of the line */
  60. UDR1 = parity;
  61. }