Browse Source

Motor relay sense support

H. Peter Anvin 3 years ago
parent
commit
78286d6748
4 changed files with 138 additions and 26 deletions
  1. 11 12
      USBCAS/fmtx.c
  2. BIN
      USBCAS/usbcas-pin.ods
  3. 126 14
      USBCAS/usbcas.c
  4. 1 0
      USBCAS/usbcas.h

+ 11 - 12
USBCAS/fmtx.c

@@ -21,13 +21,18 @@ ISR(USART1_UDRE_vect)
 	uint8_t pattern;
 
 	if (!left) {
-		/* Fetch a new byte if there is one */
-		int nd = fmtx_next_byte();
+		/* Fetch a new byte if there is one, unless motor is off */
+		int nd = motor_relay ? fmtx_next_byte() : -1;
 		if (nd < 0) {
 			/*
-			 * Nothing to send. Disable interrupt.
+			 * Nothing to send. Disable the interrupt and
+			 * send out an idle zero to make sure the output
+			 * is low when not used; otherwise the motor
+			 * detect won't work.
 			 */
 			UCSR1B &= ~(1 << UDRIE1);
+			UCSR1A  = (1 << TXC1); /* Make TXC1 bit useful */
+			UDR1    = parity = 0;
 			return;
 		}
 		data = nd;
@@ -36,7 +41,6 @@ ISR(USART1_UDRE_vect)
 
 	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;
@@ -82,7 +86,7 @@ void fmtx_init_speed(uint32_t baudrate)
 	UCSR1A = (1 << TXC1);	/* Clear TXC bit */
 
 	DDRD |= 0x28; /* PD3 = outdata, PD5 = XCK/TXLED */
-	PORTD = (PORTD & ~0x28) | 0x20 | (parity & 0x08);
+	PORTD = (PORTD & ~0x28) | 0x20;
 
 	/*
 	 * SPI master mode, mode 1, LSB first
@@ -101,13 +105,8 @@ void fmtx_init_speed(uint32_t baudrate)
 	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...)
+	 * Enable transmitter ISR (which probably will immediately
+	 * go to idle...)
 	 */
 	fmtx_enable();
 }

BIN
USBCAS/usbcas-pin.ods


+ 126 - 14
USBCAS/usbcas.c

@@ -76,6 +76,65 @@ USB_ClassInfo_CDC_Device_t vcpif = {
 	},
 };
 
+/*
+ * Motor relay sense. The motor relay is connected to PD1/INT1#, but
+ * the interrupt isn't being used for that purpose. Rather, it is used
+ * to latch an upward flank as on ABC800 this will have the output data
+ * fed back to it. Thus, we can check if *either* it is grounded *or*
+ * there has been a flank.
+ *
+ * Set up timer 3 to wrap around at 100 Hz, use this to poll and
+ * debounce/deglitch the relay, and to delay the sensing of the
+ * motor relay switch with ~160 ms.
+ */
+static void motor_sense_init(void)
+{
+	/*
+	 * Set up INT1# to latch a rising edge, but mask the resulting
+	 * interrupt request.
+	 */
+	EIMSK = 0;		/* all external interrupts masked */
+	EICRA = 3 << ISC10;	/* rising edge */
+	EIFR  = -1;		/* clear all external interrupt flags */
+
+	/*
+	 * Set up timer 3 to count at fosc/8 in CTC mode,
+	 * with wraparound at 20000 = 100 Hz.
+	 */
+	TCCR3B = 0;			/* Disable timer */
+	TCCR3A = 0;			/* No capture, no waveforms */
+	ICR3   = (F_CPU/(8*100)) - 1;	/* Top of counter */
+	TCNT3  = 0;
+	TIMSK3 = TIFR3 = (1 << ICF3);	   /* Interrupt on ICR3 match */
+	TCCR3B = (3 << WGM32)|(2 << CS30); /* fosc/8, CTC mode, TOP=ICR3 */
+}
+
+bool motor_relay;
+
+ISR(TIMER3_CAPT_vect)
+{
+	static uint8_t relay_ctr;
+	bool relay;
+
+	if (!(PORTD & 2) || (EIFR & 2)) {
+		/* Relay active */
+		EIFR = 2;	/* Clear edge detect */
+		if (relay_ctr < 16) {
+			relay_ctr++;
+		} else if (!motor_relay) {
+			motor_relay = true;
+			fmtx_enable();
+		}
+	} else {
+		/* Relay not active */
+		if (relay_ctr) {
+			relay_ctr--;
+		} else {
+			motor_relay = false;
+		}
+	}
+}
+
 /*
  * Probe for modem control status bits and send them if changed,
  * or if forced. DSR is always set, DCD indicates if the cassette
@@ -86,16 +145,9 @@ static void update_modem_status(USB_ClassInfo_CDC_Device_t * const cii,
 {
 	uint16_t lines = CDC_CONTROL_LINE_IN_DSR;
 
-	if (!(PINB & (1 << 4))) /* Cassette relay active */
+	if (motor_relay) /* Cassette relay active */
 		lines |= CDC_CONTROL_LINE_IN_DCD;
 
-#if 0
-	if (lines & CDC_CONTROL_LINE_IN_DCD)
-		PORTB &= ~(1U << 0);
-	else
-		PORTB |= (1U << 0);
-#endif
-
 	if (forced || cii->State.ControlLineStates.DeviceToHost != lines) {
 		cii->State.ControlLineStates.DeviceToHost = lines;
 		CDC_Device_SendControlLineStateChange(cii);
@@ -166,7 +218,8 @@ int main(void)
 			 */
 			if (byte >= 0) {
 				RingBuffer_Insert(&u2c_ringbuf, byte);
-				fmtx_enable();
+				if (motor_relay)
+					fmtx_enable();
 			}
 		}
 
@@ -211,21 +264,80 @@ static uint32_t current_baudrate;
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
 void SetupHardware(void)
 {
-#if (ARCH == ARCH_AVR8)
 	/* Disable watchdog if enabled by bootloader/fuses */
 	MCUSR &= ~(1 << WDRF);
 	wdt_disable();
 
 	/* Disable clock division */
 	clock_prescale_set(clock_div_1);
-#endif
+
+	/*
+	 * Configure ports.
+	 * NC: not connected, but have pads on board.  Input/pullup.
+	 * NT: not terminated on board. Output/GND.
+	 */
+
+	/*
+	 * PORT B:
+	 *   PB0 - RXLED#
+	 *   PB1 - NC
+	 *   PB2 - NC
+	 *   PB3 - NC
+	 *   PB4 - NC
+	 *   PB5 - NC
+	 *   PB6 - NC
+	 *   PB7 - NT
+	 */
+	DDRB  = 0x81;
+	PORTB = 0x7f;
+
+	/*
+	 * PORT C:
+	 *   PC6 - NC
+	 *   PC7 - NP
+	 */
+	DDRC  = 0x80;
+	PORTC = 0x40;
+
+	/*
+	 * PORT D:
+	 *   PD0 - data in (alt)
+	 *   PD1 - motor sense#
+	 *   PD2 - NC
+	 *   PD3 - data out
+	 *   PD4 - data in (main)
+	 *   PD5 - TXLED#
+	 *   PD6 - NT
+	 *   PD7 - NC
+	 */
+	DDRD  = 0x68;
+	PORTD = 0x93;
+
+	/*
+	 * PORT E:
+	 *   PE6 - NC
+	 *   PE2 - hardware bootloader, tied to GND on board
+	 */
+	DDRE  = 0x00;
+	PORTE = 0x40;
+
+	/*
+	 * PORT F:
+	 *   PF0 - NT
+	 *   PF1 - NT
+	 *   PF4 - NC
+	 *   PF5 - NC
+	 *   PF6 - NC
+	 *   PF7 - NC
+	 */
+	DDRF  = 0x03;
+	PORTF = 0xf0;
 
 	/* Hardware Initialization */
 	USB_Init();
 
-	/* PORTB: PB0 - RXLED, PB4 - Relay (pullup), PB5 - relay out */
-	PORTB |= (1 << 0) | (1 << 4);
-	DDRB  =  (DDRB & ~((1 << 4))) | ((1 << 0) | (1 << 5));
+	/* Initialize motor sense setup */
+	motor_sense_init();
 
 	/* Initialize receiver and transmitter */
 	fmrx_init();

+ 1 - 0
USBCAS/usbcas.h

@@ -70,6 +70,7 @@ void fmtx_init_speed(uint32_t baudrate);
 static inline ATTR_ALWAYS_INLINE void fmtx_enable(void) {
 	UCSR1B |= (1 << UDRIE1);
 }
+extern bool motor_relay;
 
 void fmrx_init(void);
 void fmrx_set_speed(uint32_t baudrate);