AT91SAM7 firmware for RC632 based reader. 0. Architecture We have a Philips CL RC632 connected via SPI to the AT91SAM7. The AT91SAM7 has a USB device port that is connected to a USB host. 1. USB Protocol / Interface The AT91SAM7 has four USB endpoints, of which one is used for the control pipe, and three are available for the user application. Ideally, the device will provide two configurations, each with one interface providing three endpoints: IN, OUT, INTERRUPT. 2. Interface configurations 2.1 Dumb interface In this mode, the AT91SAM7 acts as a stupid interface between SPI and USB. It provides access to the following primitives: - Write Register - Read Register - Write FIFO - Read FIFO - Write Virtual FIFO - Read Virtual FIFO - Signal Interrupt Since the FIFO of the RC632 are only 64byte deep, and the USB latency is too big to facilitate FIFO refill while transmit, esp. at 424/848kbps RFID bitrate, the AT91SAM7 has to provide bigger 'virtual' FIFO buffers to the USB host. Thus, the USB host can fill a 1024byte-sized buffer using multiple USB packets, and then ask the AT91SAM7 to write the first 64bytes to the FIFO. The RC632 will be programmed by the USB host to generate FIFO Level interrupts, to which the AT91SAM7 will react automatically and re-fill the RC632 FIFO until all host data has been sent to the RC632. For the FIFO RX path, the opposite pattern is used: The AT91SAM7 has a 1024 byte sized buffer, into which data can be read from the FIFO. 2.2 Intelligent interface This interface will be optionally implemented at some later point. It provides a 14443 protocol implementation inside the AT91SAM7. 2. Interface configurations 2.1 Dumb interface EP0 control EP1 bulk in EP2 bulk out EP3 interrupt 3. USB Protocol 3.1 dumb interface struct usb_pcd_out_hdr { u_int8_t cmd; /* command */ u_int8_t flags; u_int8_t reg; /* register */ u_int8_t res; u_int16_t len; u_int8_t data[0]; } __attribute__ ((packed)); #define USB_PCD_CMD_WRITE_REG 0x01 #define USB_PCD_CMD_WRITE_FIFO 0x02 #define USB_PCD_CMD_WRITE_VFIFO 0x03 #define USB_PCD_CMD_READ_REG 0x11 #define USB_PCD_CMD_READ_FIFO 0x12 #define USB_PCD_CMD_WRITE_VFIFO 0x13 TBD 3.2 Intelligent interface TBD 4. Firmware code flow architecture The general idea is to make the firmware as interrupt-driven as possible. Synchronous waiting for I/O (SPI, USB, ...) should be avoided, and restricted to slow path operations (such as USB configuration) only. Another design goal is to avoid using a dynamic memory allocator. Dynamic memory allocation can be costly, leads to all sorts of fragmentation problems, and will lead to the question of what to do in the case of an OOM situation. Therefore, all data structures such as buffers will be pre-allocated and declared as static variables. 4.x Data structures Any action of the PCD is host-driven. Therefore, the UDC maintains a set (2..32) request context structures. Upon completion of a USB OUT EP DMA, the corresponding request context is passed on to other parts of the code. Once the reply to that request has been processed, the context structure is released. The context structures are statically allocated, and a single u_int32_t represents a bitmask of busy context structures. ffs() or a similar function is used to search for a free buffer using which the UDC RX DMA can be refilled. 4.1 Examples 4.1.1 Performing SPI Register Read [ UDC has configured RX FIFO for reception of usb packets ] - UDC issues interrupt that USB endpoint receive has completed (FIFO) - UDC driver defragments multiple packets into one transfer [optional] - UDC driver submits another buffer for DMA reception - UDC driver parses PCD ommand header and calls rc632 API - RC632 driver configures SPI DMA transceive - End of UDC interrupt - idle loop - SPI DMA completion interrupt happens for TX [do nothing] - SPI DMA completion interrupt happens for RX - callback into UDC driver using request state data - UDC driver sends IN packet/transfer back to host - End of SPI DMA interrupt 4.1.2 Performing SPI register read much like register write, although the deferred completion could be skipped and the usb transfer approved immediately after having submitted the SPI write request to the RC632 5.1.3 Performing FIFO read much like register read. Only difference is size and duration of transfer 5.1.4 Performing FIFO write much like register write. Only difference is size and duration of transfer 5.1.5 Performing virtual FIFO read much like a FIFO write, but make sure to enable FIFO watermark IRQ in RC632. 5.1.6 Performing virtual FIFO write much like a FIFO read, but make sure to enable FIFO watermark IRQ in RC632. Response to USB host is only sent after the full virtual FIFO has been emptied into the physical FIFO. 5.1.6 Reporting RC632 interrupts Upon reception of a RC632 interrupt, the primary and secondary status registers are read from the IRQ handler, and an USB packet on the Interrupt In enddpoint is created and submitted for transmission. Some special handling (filtering) of FIFO over/underrun interrupts has to be implemented for transparent handling of the virtual FIFO. 5.1.7 Reporting virtual FIFO interrupts The virtual FIFO itself can generate over/underrun interrupts on the USB. They are signalled pretty much like real RC632 interrupts. 6. Interrupt priorities UDC DMA low priority, since we don't want to overflow with usb packets? SPI DMA higher than UDC since it might complete while in UDC code? RC632_IRQ high priority, since FIFO refill might be required DEBUG_UART do we want it to use IRQ at all? if yes it should have highest prio.