Close

Flow Control

A project log for MicroPort

USB-CDC Serial port for PIC18F, in under 1KiB. Refactored down from a USB-DFU bootloader, hand written in assembler to be light and fast

jesseJesse 12/29/2016 at 01:250 Comments

Next is exploring the possibility of adding RTS/CTS signalling to the demo.

Doing the outbound RTS/DTR signals were pretty easy, and only add an additional 22 bytes to the code. (22 bytes, I just happened to have made available) Just set up an IO port for the signals (3 instructions, 6 bytes) and add an additional case to the class request handler (8 instructions, 16 bytes). However, putting out these signals is only somewhat useful if we can't detect these signals from a remote device using the CTS&DSR inputs.

CASE	CDC_SETCONTROLSTA
	read2w	wValueL
	xorwf	LATB, W, ACCESS
	andlw	0x03
	xorwf	LATB, F, ACCESS     ;bit 0=DTR, 1=RTS
	bra	setdone_xmitzero

Adding support for CTS/DSR is where it gets ugly. I've considered using interrupts for this, however, noisy inputs could easily generate unwanted state updates to the host. The next best solution is to check if the input pins for CTS/DSR change when handling the USB Start Of Frame (SOF) interrupt. This works, and guarantees we see at most 1 update per millisecond, however sending this SERIAL_STATUS message to the USB host requires not only this change detection, but also sending a 10-byte message to the host.

	lfsr	FSR1, 0x418
	rcall	fsr2_to_fsr1
	movlw	0xA1
	movwf	POSTINC2, ACCESS	;bmRequestType
	movlw	0x20
	movwf	POSTINC2, ACCESS	;bRequest
	clrf	POSTINC2, ACCESS	;wValue
	clrf	POSTINC2, ACCESS
	movlw	0x01
	movwf	POSTINC2, ACCESS	;wIndex
	clrf	POSTINC2, ACCESS
	movlw	0x02
	movwf	POSTINC2, ACCESS	;wLength
	clrf	POSTINC2, ACCESS
	rrncf	ctsdtr, W, BANKED
	andlw	0x03
	movwf	POSTINC2, ACCESS	;UART state
	clrf	POSTINC2, ACCESS
	
	movlw	0x0A
	movwf	PREINC1, ACCESS	; respond with 10 bytes
	decf	FSR1L, F, ACCESS
	movlw	0x80 | USBPARITY
	movwf	INDF1, ACCESS

My naive attempts to do this add at most 37 instructions, totaling 74 bytes! Even under ideal circumstances, like more USB ram for data buffering will still require at least 62 additional bytes of code.

Lets consider for a moment, instead of sending the SERIAL_STATE header inline as in the snippet above, what if I load the 8 byte-header into flash and send it from there? The 8 byte header is currently 12 instructions, that take 24 bytes of code space. Instead, it could be 8 bytes for the header itself, and the existing send_descriptor function used to send at a cost of 4 instructions for 8 bytes to setup and make the function call. That could reduce the size to a possible 54 additional bytes.

At this point, I doubt that kind of memory is hiding in the code base to be scavenged. Though, perhaps it would be possible if I scrap the baud-rate divider, and hard-code support for 2 or 3 baudrates.

Sorry flow control, looks like you won't make the cut.

Discussions