/* * Transmit an FM-modulated signal using the USART in SPI master mode. * As per ABC standard, this signal is transmitted LSB first. */ #include "usbcas.h" /* * FM nybble patters; these should be transmitted LSB first * and XOR'd with the MSB of the pattern byte last transmitted. */ static const uint8_t fm_nyb[16] = { 0x33, 0xcd, 0xcb, 0x35, 0xd3, 0x2d, 0x2b, 0xd5, 0xb3, 0x4d, 0x4b, 0xb5, 0x53, 0xad, 0xab, 0x55 }; static uint8_t parity = 0; /* * Send the least significant nybble of this data item and return * the next nybble, if any. Check with fmtx_send_ready() before * calling this function. */ uint8_t fmtx_send_nybble(uint8_t d) { uint8_t nyb = fm_nyb[d & 15] ^ parity; UCSR1A = (1 << TXC1); UDR1 = nyb; parity = -((int8_t)nyb < 0); return d >> 4; } /* * Synchronize transmitter before reconfiguration */ void fmtx_drain(void) { while (!(UCSR1A & (1 << TXC1))) ; } /* * Initialize the USART hardware and set transmission baudrate. * This is mostly the same as SerialSPI_Init(). */ void fmtx_init_speed(uint32_t baudrate) { DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */ PORTD = (PORTD & ~0x28) | (parity & 0x20) | 0x08; UCSR1B = 0; /* Disable USART */ UCSR1A = 0; /* Clear error bits */ /* * SPI master mode, mode 1, LSB first * UCPHA doesn't matter, but have UCPOL=1 to that the clock * is 1 when idle and the TXLED is OFF. */ UCSR1C = (3 << UMSEL10) | (1 << UDORD1) | (1 << UCPOL1); /* UBRR must be zero when the transmitter is enabled */ UBRR1 = 0; /* Enable transmitter, but not receiver */ UCSR1B = (1 << TXEN1); /* Configure baud rate (UBBRVAL is a typo in LUFA) */ /* We need two SPI ticks per symbol, hence double... */ UBRR1 = SERIAL_SPI_UBBRVAL(baudrate << 1); /* Output the current idle state of the line */ UDR1 = parity; }