From 872a81da6f50d6fda706d7ebd043147cb1be70ad Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> Date: Mon, 3 Jul 2006 11:18:08 +0000 Subject: update git-svn-id: https://svn.openpcd.org:2342/trunk@3 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpcd/firmware.txt | 99 ++++++++++++++++++++ openpcd/firmware/src/dfu.c | 64 +++++++++++++ openpcd/firmware/src/dfu.h | 31 +++++++ openpcd/firmware/src/openpcd.h | 30 ++++++ openpcd/firmware/src/pcd_enumerate.c | 153 ------------------------------- openpcd/firmware/src/pio_irq.c | 65 +++++++++++++ openpcd/firmware/src/pio_irq.h | 9 ++ openpcd/firmware/src/rc632.c | 21 ++++- openpcd/firmware/src/rc632.h | 11 +++ openpcd/hardware/RFID-READER_Bm114_1.pdf | Bin 0 -> 1271562 bytes openpcd/hardware/RFID-READER_Bm115_1.pdf | Bin 0 -> 1271316 bytes 11 files changed, 326 insertions(+), 157 deletions(-) create mode 100644 openpcd/firmware/src/dfu.c create mode 100644 openpcd/firmware/src/dfu.h create mode 100644 openpcd/firmware/src/openpcd.h create mode 100644 openpcd/firmware/src/pio_irq.c create mode 100644 openpcd/firmware/src/pio_irq.h create mode 100644 openpcd/firmware/src/rc632.h create mode 100644 openpcd/hardware/RFID-READER_Bm114_1.pdf create mode 100644 openpcd/hardware/RFID-READER_Bm115_1.pdf diff --git a/openpcd/firmware.txt b/openpcd/firmware.txt index f24b48e..b34113c 100644 --- a/openpcd/firmware.txt +++ b/openpcd/firmware.txt @@ -27,6 +27,8 @@ provides access to the following primitives: - 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 @@ -58,8 +60,105 @@ EP1 bulk in EP2 bulk out EP3 interrupt + 3. USB Protocol 3.1 dumb interface +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 dma 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. diff --git a/openpcd/firmware/src/dfu.c b/openpcd/firmware/src/dfu.c new file mode 100644 index 0000000..85f85ee --- /dev/null +++ b/openpcd/firmware/src/dfu.c @@ -0,0 +1,64 @@ + +/* USB Interface descriptor in Runtime mode */ +struct usb_interface_descriptor desc_if_rt = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x01, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x01, + .iInterface = FIXME, +}; + +/* USB DFU Device descriptor in DFU mode */ +struct usb_device_descriptor desc_dev_dfu = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0100, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 8, + .idVendor = USB_VENDOR, + .idProtuct = USB_PRODUCT, + .bcdDevice = 0x0000, + .iManufacturer = FIXME, + .iProduct = FIXME, + .iSerialNumber = FIXME, + .bNumConfigurations = 0x01, +}; + +/* USB DFU Interface descriptor in DFU mode */ +struct usb_interface_descriptor desc_if_dfu = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x00, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, + .iInterface = FIXME, +}; + + +{ + switch () { + case USB_REQ_DFU_DETACH: + break; + case USB_REQ_DFU_DNLOAD: + break; + case USB_REQ_DFU_GETSTATUS: + break; + case USB_REQ_DFU_CLRSTATUS: + break; + case USB_REQ_DFU_ABORT: + break; + case USB_REQ_GETSTATE: + break; + case USB_REQ_DFU_UPLOAD: + break; + } +} diff --git a/openpcd/firmware/src/dfu.h b/openpcd/firmware/src/dfu.h new file mode 100644 index 0000000..873bc0e --- /dev/null +++ b/openpcd/firmware/src/dfu.h @@ -0,0 +1,31 @@ +#ifndef _USB_DFU_H +#define _USB_DFU_H + +#define USB_DT_DFU 0x21 + +struct usb_dfu_func_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bmAttributs; +#define USB_DFU_CAN_DOWNLOAD (1 << 0) +#define USB_DFU_CAN_UPLOAD (1 << 1) +#define USB_DFU_MANIFEST_TOL (1 << 2) +#define USB_DFU_WILL_DETACH (1 << 3) + __le16 wDetachTimeOut; + __le16 wTransferSize; + __le16 bcdDFUVersion; +} __attribute__ ((packed)); + +#define USB_DT_DFU_SIZE 9 + + +/* DFU class-specific requests (Section 3, DFU Rev 1.1) */ +#define USB_REQ_DFU_DETACH 0x00 +#define USB_REQ_DFU_DNLOAD 0x01 +#define USB_REQ_DFU_UPLOAD 0x02 +#define USB_REQ_DFU_GETSTATUS 0x03 +#define USB_REQ_DFU_CLRSTATUS 0x04 +#define USB_REQ_DFU_GETSTATE 0x05 +#define USB_REQ_DFU_ABORT 0x06 + +#endif /* _USB_DFU_H diff --git a/openpcd/firmware/src/openpcd.h b/openpcd/firmware/src/openpcd.h new file mode 100644 index 0000000..2a293b3 --- /dev/null +++ b/openpcd/firmware/src/openpcd.h @@ -0,0 +1,30 @@ +#ifndef _OPENPCD_H +#define _OPENPCD_H + +#define OPENPCD_RC632_IRQ AT91C_PA30_IRQ1 +#define OPENPCD_RC632_RESET AT91C_PIO_PA29 +#define OPENPCD_LED1_GREEN AT91C_PIO_PA25 +#define OPENPCD_LED2_RED AT91C_PIO_PA26 + +#define MAX_REQSIZE 256 +#define MAX_HDRSIZE 8 + +#define req_buf_payload(x) (x->data[x->hdr_len]) +#define req_buf_hdr(x) (x->data[0]) + +struct req_buf { + u_int16_t hdr_len; + u_int16_t tot_len; + u_int8_t data[MAX_REQSIZE+MAX_HDRSIZE]; +}; + +struct req_ctx { + u_int16_t seq; /* request sequence number */ + + u_int32_t flags; + + struct req_buf rx; + struct req_buf tx; +}; + +#endif /* _OPENPCD_H */ diff --git a/openpcd/firmware/src/pcd_enumerate.c b/openpcd/firmware/src/pcd_enumerate.c index 32bc9bf..f660fda 100644 --- a/openpcd/firmware/src/pcd_enumerate.c +++ b/openpcd/firmware/src/pcd_enumerate.c @@ -28,30 +28,6 @@ typedef unsigned int uint; #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#if 0 -const char devDescriptor[] = { - /* Device descriptor */ - 0x12, // bLength - 0x01, // bDescriptorType - 0x10, // bcdUSBL - 0x01, // - 0x02, // bDeviceClass: CDC class code - 0x00, // bDeviceSubclass: CDC class sub code - 0x00, // bDeviceProtocol: CDC Device protocol - 0x08, // bMaxPacketSize0 - 0xEB, // idVendorL - 0x03, // - 0x24, // idProductL - 0x61, // - 0x10, // bcdDeviceL - 0x01, // - 0x00, // iManufacturer // 0x01 - 0x00, // iProduct - 0x00, // SerialNumber - 0x01 // bNumConfigs -}; -#endif - struct usb_device_descriptor devDescriptor = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -69,99 +45,6 @@ struct usb_device_descriptor devDescriptor = { .bNumConfigurations = 0x01, }; -#if 0 -const char cfgDescriptor[] = { - /* ============== CONFIGURATION 1 =========== */ - /* Configuration 1 descriptor */ - 0x09, // CbLength - 0x02, // CbDescriptorType - 0x43, // CwTotalLength 2 EP + Control - 0x00, - 0x02, // CbNumInterfaces - 0x01, // CbConfigurationValue - 0x00, // CiConfiguration - 0xC0, // CbmAttributes 0xA0 - 0x00, // CMaxPower - - /* Communication Class Interface Descriptor Requirement */ - 0x09, // bLength - 0x04, // bDescriptorType - 0x00, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x01, // bNumEndpoints - 0x02, // bInterfaceClass - 0x02, // bInterfaceSubclass - 0x00, // bInterfaceProtocol - 0x00, // iInterface - - /* Header Functional Descriptor */ - 0x05, // bFunction Length - 0x24, // bDescriptor type: CS_INTERFACE - 0x00, // bDescriptor subtype: Header Func Desc - 0x10, // bcdCDC:1.1 - 0x01, - - /* ACM Functional Descriptor */ - 0x04, // bFunctionLength - 0x24, // bDescriptor Type: CS_INTERFACE - 0x02, // bDescriptor Subtype: ACM Func Desc - 0x00, // bmCapabilities - - /* Union Functional Descriptor */ - 0x05, // bFunctionLength - 0x24, // bDescriptorType: CS_INTERFACE - 0x06, // bDescriptor Subtype: Union Func Desc - 0x00, // bMasterInterface: Communication Class Interface - 0x01, // bSlaveInterface0: Data Class Interface - - /* Call Management Functional Descriptor */ - 0x05, // bFunctionLength - 0x24, // bDescriptor Type: CS_INTERFACE - 0x01, // bDescriptor Subtype: Call Management Func Desc - 0x00, // bmCapabilities: D1 + D0 - 0x01, // bDataInterface: Data Class Interface 1 - - /* Endpoint 1 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x83, // bEndpointAddress, Endpoint 03 - IN - 0x03, // bmAttributes INT - 0x08, // wMaxPacketSize - 0x00, - 0xFF, // bInterval - - /* Data Class Interface Descriptor Requirement */ - 0x09, // bLength - 0x04, // bDescriptorType - 0x01, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints - 0x0A, // bInterfaceClass - 0x00, // bInterfaceSubclass - 0x00, // bInterfaceProtocol - 0x00, // iInterface - - /* First alternate setting */ - /* Endpoint 1 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x01, // bEndpointAddress, Endpoint 01 - OUT - 0x02, // bmAttributes BULK - AT91C_EP_OUT_SIZE, // wMaxPacketSize - 0x00, - 0x00, // bInterval - - /* Endpoint 2 descriptor */ - 0x07, // bLength - 0x05, // bDescriptorType - 0x82, // bEndpointAddress, Endpoint 02 - IN - 0x02, // bmAttributes BULK - AT91C_EP_IN_SIZE, // wMaxPacketSize - 0x00, - 0x00 // bInterval -}; -#endif - struct _desc { struct usb_config_descriptor ucfg; struct usb_interface_descriptor uif @@ -239,25 +122,6 @@ const struct _desc cfgDescriptor = { #define STD_SET_INTERFACE 0x0B01 #define STD_SYNCH_FRAME 0x0C82 -/* CDC Class Specific Request Code */ -#define GET_LINE_CODING 0x21A1 -#define SET_LINE_CODING 0x2021 -#define SET_CONTROL_LINE_STATE 0x2221 - -typedef struct { - unsigned int dwDTERRate; - char bCharFormat; - char bParityType; - char bDataBits; -} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING; - -AT91S_CDC_LINE_CODING line = { - 115200, // baudrate - 0, // 1 Stop Bit - 0, // None Parity - 8 -}; // 8 Data bits - /// mt uint currentReceiveBank = AT91C_UDP_RX_DATA_BK0; static uchar AT91F_UDP_IsConfigured(AT91PS_CDC pCdc); @@ -575,23 +439,6 @@ static void AT91F_CDC_Enumerate(AT91PS_CDC pCdc) } else AT91F_USB_SendStall(pUDP); break; - -#if 0 - // handle CDC class requests - case SET_LINE_CODING: - while (!(pUDP->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ; - pUDP->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0); - AT91F_USB_SendZlp(pUDP); - break; - case GET_LINE_CODING: - AT91F_USB_SendData(pUDP, (char *)&line, - MIN(sizeof(line), wLength)); - break; - case SET_CONTROL_LINE_STATE: - pCdc->currentConnection = wValue; - AT91F_USB_SendZlp(pUDP); - break; -#endif default: AT91F_USB_SendStall(pUDP); break; diff --git a/openpcd/firmware/src/pio_irq.c b/openpcd/firmware/src/pio_irq.c new file mode 100644 index 0000000..3f73001 --- /dev/null +++ b/openpcd/firmware/src/pio_irq.c @@ -0,0 +1,65 @@ + +#define NR_PIO 32 + +static u_int8_t ffs(u_int32_t in) +{ + int i; + + for (i = sizeof(in)*8; i > 0; i++) { + if (in & (1 << i-1)) + return i; + } + + return 0; +} + +static void pio_irq_demux(void) +{ + u_int32_t pio = AT91F_PIO_GetInterruptStatus(AT91C_BASE_PIOA); + + for (i = 0; i < NR_PIO; i++) { + if (pio & (1 << i) && pio_handlers[i]) + pio_handlers[i](i); + } + return; +} + +void pio_irq_enable(u_int32_t pio) +{ + AT91F_PIO_InterruptEnable(AT91C_BASE_PIOA, pio); +} + +void pio_irq_disable(u_int32_t pio) +{ + AT91F_PIO_InterruptDisable(AT91C_BASE_PIOA, pio); +} + +int pio_irq_register(u_int32_t pio, void (*handler)(void)) +{ + u_int8_t num = ffs(pio); + + if (num == 0) + return -EINVAL; + num--; + + if (pio_handlers[num]) + return -EBUSY; + + pio_irq_disable(pio); + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, pio); + pio_handlers[num] = handler; + + return 0; +} + +void pio_irq_unregister(u_int32_t pio) +{ + u_int8_t num = ffs(pio); + + if (num == 0) + return; + num--; + + pio_irq_disable(pio); + pio_handlers[num] = NULL; +} diff --git a/openpcd/firmware/src/pio_irq.h b/openpcd/firmware/src/pio_irq.h new file mode 100644 index 0000000..a71ed75 --- /dev/null +++ b/openpcd/firmware/src/pio_irq.h @@ -0,0 +1,9 @@ + +typedef irq_handler_t (void)(u_int32_t pio); + +static irq_handler_t pio_handlers[NR_PIO]; + +extern void pio_irq_enable(u_int32_t pio); +extern void pio_irq_disable(u_int32_t pio); +extern int pio_irq_register(u_int32_t pio, irq_handler_t func); +extern void pio_irq_unregister(u_int32_t pio); diff --git a/openpcd/firmware/src/rc632.c b/openpcd/firmware/src/rc632.c index 9ff1890..6c83182 100644 --- a/openpcd/firmware/src/rc632.c +++ b/openpcd/firmware/src/rc632.c @@ -3,9 +3,15 @@ * * */ +#include "pio_irq.h" + static void spi_irq(void) { + u_int32_t status = pSPI->SPI_SR; + if (status & (AT91C_SPI_OVRES|AT91C_SPI_MODF)) { + /* FIXME: print error message to debug port */ + } } static u_int8_t spi_outbuf[64+1]; @@ -65,7 +71,7 @@ u_int8_t rc632_read_fifo(u_int8_t max_len, u_int8_t *data) /* RC632 interrupt handling */ -void rc632_irq(void) +static void rc632_irq(void) { /* CL RC632 has interrupted us */ u_int8_t cause = rc632_read_reg(RC632_REG_INTERRUPT_RQ); @@ -95,15 +101,22 @@ void rc632_init(void) AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, F, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + AT91F_SPI_EnableIt(pSPI, AT91C_SPI_MODF|AT91C_SPI_OVRES); AT91F_SPI_CfgMode(AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED); - /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10, + /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz), * DLYBS = 0, DLYBCT = 0 */ AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS8|AT91C_SPI_NCPHA|(10<<8)); - AT91F_SPI_Reset(); + + /* Register rc632_irq */ + pio_irq_register(OPENPCD_RC632_IRQ, &rc632_irq); + pio_irq_enable(OPENPCD_RC632_IRQ); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_RC632_RESET); }; void rc632_exit(void) { - + pio_irq_unregister(OPENPCD_RC632_IRQ); + AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + AT01F_SPI_Disable(); } diff --git a/openpcd/firmware/src/rc632.h b/openpcd/firmware/src/rc632.h new file mode 100644 index 0000000..281e757 --- /dev/null +++ b/openpcd/firmware/src/rc632.h @@ -0,0 +1,11 @@ +#ifndef _RC623_API_H +#define _RC632_API_H + +extern void rc632_write_reg(u_int8_t addr, u_int8_t data); +extern void rc632_write_fifo(u_int8_t len, u_int8_t *data); +extern u_int8_t rc632_read_reg(u_int8_t addr); +extern u_int8_t rc632_read_fifo(u_int8_t max_len, u_int8_t *data); +extern void rc632_init(void); +extern void rc632_exit(void); + +#endif diff --git a/openpcd/hardware/RFID-READER_Bm114_1.pdf b/openpcd/hardware/RFID-READER_Bm114_1.pdf new file mode 100644 index 0000000..62affe8 Binary files /dev/null and b/openpcd/hardware/RFID-READER_Bm114_1.pdf differ diff --git a/openpcd/hardware/RFID-READER_Bm115_1.pdf b/openpcd/hardware/RFID-READER_Bm115_1.pdf new file mode 100644 index 0000000..b2bb3fe Binary files /dev/null and b/openpcd/hardware/RFID-READER_Bm115_1.pdf differ -- cgit v1.2.3