Skip to content

Commit

Permalink
fx2 firmware: Mapping CDC-ACM to hardware UART.
Browse files Browse the repository at this point in the history
Based on my CDC-to-UART example in fx2lib.
  • Loading branch information
mithro committed Nov 2, 2015
1 parent d723926 commit e9a936a
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 126 deletions.
2 changes: 1 addition & 1 deletion firmware/fx2/Makefile
Expand Up @@ -44,7 +44,7 @@ USE_16K := 1
# Must only be hex numbers
FIRMWARE_VERSION := $(shell date +%Y%m%d)

CC_SRCS := app.c cdc.c debug.c softserial.c uvc.c firmware.c read-serialno.c
CC_SRCS := app.c cdc.c debug.c softserial.c uvc.c firmware.c read-serialno.c to-uart.c
AS_SRCS := descriptors_hdmi2usb.a51
CC_OBJS := $(CC_SRCS:%.c=%.rel)
AS_OBJS := $(AS_SRCS:%.a51=%.rel)
Expand Down
31 changes: 14 additions & 17 deletions firmware/fx2/app.c
Expand Up @@ -33,6 +33,7 @@ void TD_Poll(void);

// Called once at startup
//
extern void uart_init();
void mainInit(void) {
#ifdef BOARD_opsis
patch_usb_serial_number_with_eeprom_macaddress();
Expand All @@ -53,8 +54,11 @@ void mainInit(void) {
PORTACFG = 0x00;

I2CTL |= bm400KHZ;

TD_Init();

uart_init();

#ifdef DEBUG
usartInit();
{
Expand Down Expand Up @@ -85,14 +89,15 @@ void mainInit(void) {
//
void mainLoop(void) {
TD_Poll();
cdc_receive_poll();
}

// Called when a vendor command is received
//
uint8 handleVendorCommand(uint8 cmd) {
if (handleUVCCommand(cmd))
return true;
if (handleCDCCommand(cmd))
if (cdc_handle_command(cmd))
return true;

return false; // unrecognised command
Expand Down Expand Up @@ -128,7 +133,9 @@ void TD_Init(void) // Called once at startup
* Required to be 0b11 for Slave FIFO. See Page 15-16 TRM
*/

SYNCDELAY; IFCONFIG = 0xE3; // Internal Clock, 48MHz, IFCLK output enable to pin, Normal Polarity, Synchronous FIFO, Nothing to do with GSTATE, Set interface mode to Slave FIFO.
// Internal Clock, 48MHz, IFCLK output enable to pin, Normal Polarity,
// Synchronous FIFO, Nothing to do with GSTATE, Set interface mode to Slave FIFO.
SYNCDELAY; IFCONFIG = 0xE3;

// EP1OUT & EP1IN
/*
Expand Down Expand Up @@ -185,30 +192,20 @@ void TD_Init(void) // Called once at startup
* |______|______|___________|
*/

// Used by the CDC serial port (EP2 == TX, EP4 == RX)
SYNCDELAY; EP2CFG = 0xA2; // Activate, OUT Direction, BULK Type, 512 bytes Size, Double buffered
SYNCDELAY; EP4CFG = 0xE2; // Activate, IN Direction, BULK Type, 512 bytes Size, Double buffered
// Used by the video data
SYNCDELAY; EP6CFG = 0xDA; // Activate, IN Direction, ISO Type, 1024 bytes Size, Double buffered
SYNCDELAY; EP8CFG = 0x00; // Disable Endpoint 8

// 0 INFM1 OEP1 AUTOOUT AUTOIN ZEROLENIN 0 WORDWIDE
SYNCDELAY; EP2FIFOCFG = 0x10; // Auto
SYNCDELAY; EP4FIFOCFG = 0x0C;
SYNCDELAY; EP6FIFOCFG = 0x0C;
SYNCDELAY; EP8FIFOCFG = 0x00;

SYNCDELAY; EP4AUTOINLENH = 0x02;
SYNCDELAY; EP4AUTOINLENL = 0x00;
SYNCDELAY; EP6AUTOINLENH = 0x04;
SYNCDELAY; EP6AUTOINLENL = 0x00;

SYNCDELAY; EP8FIFOCFG = 0x00;

SYNCDELAY; REVCTL = 0x03; // REVCTL.0 and REVCTL.1 set to 1
SYNCDELAY; FIFORESET = 0x80; // Reset the FIFO
SYNCDELAY; FIFORESET = 0x82;
SYNCDELAY; FIFORESET = 0x84;
SYNCDELAY; FIFORESET = 0x86;
SYNCDELAY; FIFORESET = 0x00;
//SYNCDELAY; REVCTL = 0x03; // REVCTL.0 and REVCTL.1 set to 1
SYNCDELAY; REVCTL = 0x00; // REVCTL.0 and REVCTL.1 set to 1
RESETFIFOS();
}

void TD_Poll(void) // Called repeatedly while the device is idle
Expand Down
28 changes: 28 additions & 0 deletions firmware/fx2/cdc-config.h
@@ -0,0 +1,28 @@
// The endpoint which data is sent **from** the host down to the CDC serial
// port.

#define CDC_H2D_RESET(x) \
RESET ## x(0x02);

#define CDC_H2D_EP(x) \
EP2 ## x

#define bmCDC_H2D_EP(x) \
bmEP2 ## x

// The endpoint which data is sent **to** the host from the CDC serial port.
#define CDC_D2H_RESET(x) \
RESET ## x(0x80|0x04);

#define CDC_D2H_EP(x) \
EP4 ## x

#define bmCDC_D2H_EP(x) \
bmEP4 ## x

// The endpoint which is used to notify the host about the CDC state changes.
#define CDC_INT_EP(x) \
EP1OUT ## x

#define bmCDC_INT_EP(x) \
bmEP1OUT ## x
118 changes: 74 additions & 44 deletions firmware/fx2/cdc.c
Expand Up @@ -7,48 +7,78 @@

#define SYNCDELAY SYNCDELAY4

BYTE __xdata LineCode[7] = {0x60,0x09,0x00,0x00,0x00,0x00,0x08};

BOOL handleCDCCommand(BYTE cmd) {
int i;

switch(cmd) {
case SET_LINE_CODING:

EUSB = 0 ;
SUDPTRCTL = 0x01;
EP0BCL = 0x00;
SUDPTRCTL = 0x00;
EUSB = 1;

while (EP0BCL != 7);
SYNCDELAY;

for (i=0;i<7;i++)
LineCode[i] = EP0BUF[i];

return TRUE;

case GET_LINE_CODING:

SUDPTRCTL = 0x01;

for (i=0;i<7;i++)
EP0BUF[i] = LineCode[i];

EP0BCH = 0x00;
SYNCDELAY;
EP0BCL = 7;
SYNCDELAY;
while (EP0CS & 0x02);
SUDPTRCTL = 0x00;

return TRUE;

case SET_CONTROL_STATE:
return TRUE;

default:
return FALSE;
}
volatile WORD cdc_queued_bytes = 0;

struct usb_cdc_line_coding cdc_current_line_coding = {
.bDTERate0 = LSB(2400),
.bDTERate1 = MSB(2400),
.bDTERate2 = 0,
.bDTERate3 = 0,
.bCharFormat = USB_CDC_1_STOP_BITS,
.bParityType = USB_CDC_NO_PARITY,
.bDataBits = 8
};

void cdc_receive_poll() {
if ( !(EP2468STAT & bmCDC_H2D_EP(EMPTY)) ) {
WORD bytes = MAKEWORD(CDC_H2D_EP(BCH),CDC_H2D_EP(BCL));
cdcuser_receive_data(CDC_H2D_EP(FIFOBUF), bytes);
CDC_H2D_EP(BCL) = 0x80; // Mark us ready to receive again.
}
// FIXME: Send the interrupt thingy
}

BOOL cdc_handle_command(BYTE cmd) {
int i;
BYTE* line_coding = (BYTE*)&cdc_current_line_coding;
DWORD baud_rate = 0;

switch(cmd) {
case USB_CDC_REQ_SET_LINE_CODING:
EUSB = 0 ;
SUDPTRCTL = 0x01;
EP0BCL = 0x00;
SUDPTRCTL = 0x00;
EUSB = 1;

while (EP0BCL != 7);
SYNCDELAY;

for (i=0;i<7;i++)
line_coding[i] = EP0BUF[i];

// FIXME: Make this following line work rather then the if statement chain!
// baud_rate = MAKEDWORD(
// MAKEWORD(cdc_current_line_coding.bDTERate3, cdc_current_line_coding.bDTERate2),
// MAKEWORD(cdc_current_line_coding.bDTERate1, cdc_current_line_coding.bDTERate0));
baud_rate = MAKEDWORD(
MAKEWORD(line_coding[3], line_coding[2]),
MAKEWORD(line_coding[1], line_coding[0]));

if (!cdcuser_set_line_rate(baud_rate))
; //EP0STALL();

return TRUE;

case USB_CDC_REQ_GET_LINE_CODING:
SUDPTRCTL = 0x01;

for (i=0;i<7;i++)
EP0BUF[i] = line_coding[i];

EP0BCH = 0x00;
SYNCDELAY;
EP0BCL = 7;
SYNCDELAY;
while (EP0CS & 0x02);
SUDPTRCTL = 0x00;

return TRUE;

case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
return TRUE;

default:
return FALSE;
}
}
142 changes: 138 additions & 4 deletions firmware/fx2/cdc.h
@@ -1,12 +1,146 @@

#ifndef CDC_H
#define CDC_H

#include <fx2types.h>

#define SET_LINE_CODING (0x20)
#define GET_LINE_CODING (0x21)
#define SET_CONTROL_STATE (0x22)
#include "cdc-config.h"

void cdcuser_receive_data(BYTE* data, WORD length);
BOOL cdcuser_set_line_rate(DWORD baud_rate);

// Handles the "vendor commands" for a CDC device.
BOOL cdc_handle_command(BYTE cmd);

//void cdc_setup();

// Send the CDC interrupt poll thingy.
void cdc_receive_poll();

// You are able to send data.
//BOOL cdc_can_send();
#define cdc_can_send() \
!(EP2468STAT & bmCDC_D2H_EP(FULL))

extern volatile WORD cdc_queued_bytes;
// Queue a byte in the output CDC data queue.
//void cdc_queue_data(BYTE data);
#define cdc_queue_data(data) \
CDC_D2H_EP(FIFOBUF)[cdc_queued_bytes++] = data;
// Send all queue bytes from the output CDC data queue to the host.
//void cdc_send_queued_data();
#define cdc_send_queued_data() \
CDC_D2H_EP(BCH)=MSB(cdc_queued_bytes); \
SYNCDELAY; \
CDC_D2H_EP(BCL)=LSB(cdc_queued_bytes); \
SYNCDELAY; \
cdc_queued_bytes = 0;


/* ------------------------------------------------------------------------ */

/**
* The defines and structures found below comes from the Linux kernel and are
* found in include/uapi/linux/usb/cdc.h
*/

/* The 8051 is an 8bit processor, so doesn't actually have any endian
* naturally, instead the endian comes from the compiler. sdcc choses to be
* little endian, as does the USB specification.
*/
#define __u8 BYTE
#define __le16 WORD
#define __le32 DWORD

// #define USB_CDC_SUBCLASS_ACM 0x02
// #define USB_CDC_PROTO_NONE 0
// #define USB_CDC_ACM_PROTO_AT_V25TER 1
// #define USB_CDC_ACM_PROTO_AT_PCCA101 2
// #define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3
// #define USB_CDC_ACM_PROTO_AT_GSM 4
// #define USB_CDC_ACM_PROTO_AT_3G 5
// #define USB_CDC_ACM_PROTO_AT_CDMA 6
// #define USB_CDC_ACM_PROTO_VENDOR 0xff
//
// /* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
// struct usb_cdc_acm_descriptor {
// __u8 bLength;
// __u8 bDescriptorType;
// __u8 bDescriptorSubType;
//
// __u8 bmCapabilities;
// /* capabilities from 5.2.3.3 */
// #define USB_CDC_COMM_FEATURE 0x01
// #define USB_CDC_CAP_LINE 0x02
// #define USB_CDC_CAP_BRK 0x04
// #define USB_CDC_CAP_NOTIFY 0x08
// };

/*
* Class-Specific Control Requests (6.2)
*
* section 3.6.2.1 table 4 has the ACM profile, for modems.
* section 3.8.2 table 10 has the ethernet profile.
*
* Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
* heavily dependent on the encapsulated (proprietary) command mechanism.
*/

//#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
//#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define USB_CDC_REQ_SET_LINE_CODING 0x20
#define USB_CDC_REQ_GET_LINE_CODING 0x21
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
//#define USB_CDC_REQ_SEND_BREAK 0x23

/* Line Coding Structure from CDC spec 6.2.13 */
struct usb_cdc_line_coding {
// __le32 dwDTERate;
__u8 bDTERate0;
__u8 bDTERate1;
__u8 bDTERate2;
__u8 bDTERate3;

__u8 bCharFormat;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2

__u8 bParityType;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4

__u8 bDataBits;
};

// /*
// * Class-Specific Notifications (6.3) sent by interrupt transfers
// *
// * section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
// * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
// * RNDIS also defines its own bit-incompatible notifications
// */
//
// #define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00
// #define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01
// #define USB_CDC_NOTIFY_SERIAL_STATE 0x20
// #define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a
//
// struct usb_cdc_notification {
// __u8 bmRequestType;
// __u8 bNotificationType;
// __le16 wValue;
// __le16 wIndex;
// __le16 wLength;
// };
//
// struct usb_cdc_speed_change {
// __le32 DLBitRRate; /* contains the downlink bit rate (IN pipe) */
// __le32 ULBitRate; /* contains the uplink bit rate (OUT pipe) */
// };

BOOL handleCDCCommand(BYTE cmd);

#endif // CDC_H

0 comments on commit e9a936a

Please sign in to comment.