| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 | /* * Transmit an FM-modulated signal using the USART in SPI master mode. * As per ABC standard, this signal is transmitted MSB first. */#include "usbcas.h"#define BITS_PER_PATTERN_BYTE	2#define PATTERN_BIT_MASK	((1 << BITS_PER_PATTERN_BYTE) - 1)#include "fmpat.h"static uint8_t parity = 0;/* * Send stuff if we have anything to send */ISR(USART1_UDRE_vect){	static uint8_t data, left;	uint8_t pattern;	if (!left) {		/* Fetch a new byte if there is one */		int nd = fmtx_next_byte();		if (nd < 0) {			/*			 * Nothing to send. Disable interrupt.			 */			UCSR1B &= ~(1 << UDRIE1);			return;		}		data = nd;		left = 8;	}	pattern = fm_pat[data & PATTERN_BIT_MASK] ^ parity;	UCSR1A = (1 << TXC1); /* Make TXC1 bit useful */	UDR1 = pattern;	data >>= BITS_PER_PATTERN_BYTE;	left -= BITS_PER_PATTERN_BYTE;	parity = -((int8_t)pattern < 0);}/* * Synchronize transmitter before reconfiguration */void fmtx_drain(void){	const uint8_t ucsr1a_mask = (1 << UDRE1) + (1 << TXC1);	/* Wait until UDRE1 and TXC1 are both set */	while ((UCSR1A & ucsr1a_mask) != ucsr1a_mask)		do_usb_task();}/* * Initialize the USART hardware and set transmission baudrate. * This is mostly the same as SerialSPI_Init(). * Returns the actual baud rate adjusted for underflow. */#define FMTX_UBRRVAL(b) (SERIAL_SPI_UBBRVAL((b) * (8/BITS_PER_PATTERN_BYTE)))#define UBRR_MAX 4095#define FMTX_MIN_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE) * (UBRR_MAX+1UL)))#define FMTX_MAX_BAUD (F_CPU / (2 * (8/BITS_PER_PATTERN_BYTE)))#if FMTX_MIN_BAUD > CAS_BAUDRATE_ABC80# error "UBRR overflows for standard ABC80 baud rate"#endifuint32_t fmtx_real_baudrate(uint32_t baudrate){	if (baudrate < FMTX_MIN_BAUD || baudrate > FMTX_MAX_BAUD)		baudrate = CAS_BAUDRATE_ABC80;	return baudrate;}void fmtx_init_speed(uint32_t baudrate){	UCSR1B = 0;		/* Disable transmitter and ISR */	UCSR1A = (1 << TXC1);	/* Clear TXC bit */	DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */	PORTD = (PORTD & ~0x28) | 0x20 | (parity & 0x08);	/*	 * 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 and not the ISR (yet) */	UCSR1B = (1 << TXEN1);	/* Configure baud rate */	UBRR1  = FMTX_UBRRVAL(baudrate);	/*	 * Output the current idle state of the line. This will also	 * cause the TXC bit to get set afterwards.	 */	UDR1   = parity;	/*	 * Enable transmitter ISR (which may immediately disable itself...)	 */	fmtx_enable();}
 |