chg: usb_cdc, it should be similar to official pm3. lets

This commit is contained in:
iceman1001 2017-10-19 13:06:47 +02:00
commit 3b665be5fc
2 changed files with 76 additions and 55 deletions

View file

@ -84,11 +84,11 @@ static void Fatal(void) {
} }
void UsbPacketReceived(uint8_t *packet, int len) { void UsbPacketReceived(uint8_t *packet, int len) {
int i, dont_ack=0; int i, dont_ack = 0;
UsbCommand* c = (UsbCommand *)packet; UsbCommand* c = (UsbCommand *)packet;
volatile uint32_t *p; volatile uint32_t *p;
if ( len != sizeof(UsbCommand)) Fatal(); //if ( len != sizeof(UsbCommand)) Fatal();
uint32_t arg0 = (uint32_t)c->arg[0]; uint32_t arg0 = (uint32_t)c->arg[0];

View file

@ -99,6 +99,38 @@ AT91SAM7S256 USB Device Port
#define MS_WCID_GET_DESCRIPTOR 0xC0 #define MS_WCID_GET_DESCRIPTOR 0xC0
#define MS_WCID_GET_FEATURE_DESCRIPTOR 0xC1 #define MS_WCID_GET_FEATURE_DESCRIPTOR 0xC1
/* USB standard request code */
#define STD_GET_STATUS_ZERO 0x0080
#define STD_GET_STATUS_INTERFACE 0x0081
#define STD_GET_STATUS_ENDPOINT 0x0082
#define STD_CLEAR_FEATURE_ZERO 0x0100
#define STD_CLEAR_FEATURE_INTERFACE 0x0101
#define STD_CLEAR_FEATURE_ENDPOINT 0x0102
#define STD_SET_FEATURE_ZERO 0x0300
#define STD_SET_FEATURE_INTERFACE 0x0301
#define STD_SET_FEATURE_ENDPOINT 0x0302
#define STD_SET_ADDRESS 0x0500
#define STD_GET_DESCRIPTOR 0x0680
#define STD_SET_DESCRIPTOR 0x0700
#define STD_GET_CONFIGURATION 0x0880
#define STD_SET_CONFIGURATION 0x0900
#define STD_GET_INTERFACE 0x0A81
#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
AT91PS_UDP pUdp = AT91C_BASE_UDP;
uint8_t btConfiguration = 0;
uint8_t btConnection = 0;
uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;
static const char devDescriptor[] = { static const char devDescriptor[] = {
/* Device descriptor */ /* Device descriptor */
0x12, // Length 0x12, // Length
@ -127,7 +159,7 @@ static const char cfgDescriptor[] = {
2, // Number of Interfaces 2, // Number of Interfaces
1, // Index value of this Configuration (used in SetConfiguration from Host) 1, // Index value of this Configuration (used in SetConfiguration from Host)
0, // Configuration string index 0, // Configuration string index
_DEFAULT, // Attributes 0xA0 0xC0, // Attributes 0xA0
0xFA, // Max Power consumption 0xFA, // Max Power consumption
// IAD to associate the one CDC interface // IAD to associate the one CDC interface
@ -370,6 +402,7 @@ const char* getStringDescriptor(uint8_t idx) {
} }
} }
// Bitmap for all status bits in CSR which must be written as 1 to cause no effect // Bitmap for all status bits in CSR which must be written as 1 to cause no effect
#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \ #define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \
|AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \ |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \
@ -395,33 +428,6 @@ const char* getStringDescriptor(uint8_t idx) {
while ( ( pUdp->UDP_CSR[(endpoint)] & (flags)) != (flags)) {}; \ while ( ( pUdp->UDP_CSR[(endpoint)] & (flags)) != (flags)) {}; \
} \ } \
/* USB standard request code */
#define STD_GET_STATUS_ZERO 0x0080
#define STD_GET_STATUS_INTERFACE 0x0081
#define STD_GET_STATUS_ENDPOINT 0x0082
#define STD_CLEAR_FEATURE_ZERO 0x0100
#define STD_CLEAR_FEATURE_INTERFACE 0x0101
#define STD_CLEAR_FEATURE_ENDPOINT 0x0102
#define STD_SET_FEATURE_ZERO 0x0300
#define STD_SET_FEATURE_INTERFACE 0x0301
#define STD_SET_FEATURE_ENDPOINT 0x0302
#define STD_SET_ADDRESS 0x0500
#define STD_GET_DESCRIPTOR 0x0680
#define STD_SET_DESCRIPTOR 0x0700
#define STD_GET_CONFIGURATION 0x0880
#define STD_SET_CONFIGURATION 0x0900
#define STD_GET_INTERFACE 0x0A81
#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 { typedef struct {
uint32_t BitRate; uint32_t BitRate;
@ -436,11 +442,6 @@ AT91S_CDC_LINE_CODING line = {
0, // None Parity 0, // None Parity
8}; // 8 Data bits 8}; // 8 Data bits
AT91PS_UDP pUdp = AT91C_BASE_UDP;
uint8_t btConfiguration = 0;
uint8_t btConnection = 0;
uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;
static void SpinDelay(int ms) { static void SpinDelay(int ms) {
int us = ms * 1000; int us = ms * 1000;
int ticks = (48 * us) >> 10; int ticks = (48 * us) >> 10;
@ -490,6 +491,9 @@ void usb_enable() {
// Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock // Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
AT91C_BASE_UDP->UDP_FADDR = 0;
AT91C_BASE_UDP->UDP_GLBSTATE = 0;
// Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO // Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
// Set in PIO mode and Configure in Output // Set in PIO mode and Configure in Output
@ -567,19 +571,18 @@ bool usb_check() {
pUdp->UDP_FADDR = AT91C_UDP_FEN; pUdp->UDP_FADDR = AT91C_UDP_FEN;
// Configure endpoint 0 (enable control endpoint) // Configure endpoint 0 (enable control endpoint)
pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
// clear it
pUdp->UDP_ICR |= AT91C_UDP_ENDBUSRES;
} }
else if (isr & AT91C_UDP_EPINT0) { else if (isr & AT91C_UDP_EPINT0) {
pUdp->UDP_ICR = AT91C_UDP_EPINT0; pUdp->UDP_ICR = AT91C_UDP_EPINT0;
AT91F_CDC_Enumerate(); AT91F_CDC_Enumerate();
//pUdp->UDP_ICR |= AT91C_UDP_EPINT0; }
} /*
else if (isr & AT91C_UDP_EPINT3 ) { else if (isr & AT91C_UDP_EPINT3 ) {
pUdp->UDP_ICR = AT91C_UDP_EPINT3; pUdp->UDP_ICR = AT91C_UDP_EPINT3;
AT91F_CDC_Enumerate(); AT91F_CDC_Enumerate();
pUdp->UDP_ICR |= AT91C_UDP_EPINT3; //pUdp->UDP_ICR |= AT91C_UDP_EPINT3;
} }
*/
return (btConfiguration) ? true : false; return (btConfiguration) ? true : false;
} }
@ -599,7 +602,7 @@ bool usb_poll() {
bool usb_poll_validate_length() { bool usb_poll_validate_length() {
if (!usb_check()) return false; if (!usb_check()) return false;
if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false; if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;
return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0; return ((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0;
} }
//*---------------------------------------------------------------------------- //*----------------------------------------------------------------------------
@ -608,6 +611,8 @@ bool usb_poll_validate_length() {
//*---------------------------------------------------------------------------- //*----------------------------------------------------------------------------
uint32_t usb_read(byte_t* data, size_t len) { uint32_t usb_read(byte_t* data, size_t len) {
if ( len == 0 ) return 0;
uint8_t bank = btReceiveBank; uint8_t bank = btReceiveBank;
uint32_t packetSize, nbBytesRcv = 0; uint32_t packetSize, nbBytesRcv = 0;
uint32_t time_out = 0; uint32_t time_out = 0;
@ -616,11 +621,14 @@ uint32_t usb_read(byte_t* data, size_t len) {
if (!usb_check()) break; if (!usb_check()) break;
if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) {
packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len);
packetSize = (pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16;
packetSize = MIN( packetSize, len);
len -= packetSize; len -= packetSize;
while (packetSize--) while (packetSize--)
data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];
// flip bank
UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank) UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank)
if (bank == AT91C_UDP_RX_DATA_BK0) if (bank == AT91C_UDP_RX_DATA_BK0)
@ -643,19 +651,23 @@ uint32_t usb_write(const byte_t* data, const size_t len) {
if (!len) return 0; if (!len) return 0;
if (!usb_check()) return 0; if (!usb_check()) return 0;
// can we write?
if ( (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) != 0 ) return 0;
size_t length = len; size_t length = len;
uint32_t cpt = 0; uint32_t cpt = 0;
// send first chunk // send first chunk
cpt = MIN(length, AT91C_EP_IN_SIZE); cpt = MIN(length, AT91C_EP_IN_SIZE);
length -= cpt; length -= cpt;
while (cpt--) { while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++; pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
} }
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY) UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (length) { while (length) {
// Send next chunk // Send next chunk
cpt = MIN(length, AT91C_EP_IN_SIZE); cpt = MIN(length, AT91C_EP_IN_SIZE);
@ -664,13 +676,15 @@ uint32_t usb_write(const byte_t* data, const size_t len) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++; pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
} }
// Wait for the first bank to be sent // Wait for previous chunk to be sent
// (iceman) when is the bankswapping done?
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
if (!usb_check()) return length; if (!usb_check()) return length;
} }
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP) UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY) UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
} }
// Wait for the end of transfer // Wait for the end of transfer
@ -703,7 +717,7 @@ void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) {
UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP) UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP)
} }
UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY) UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY);
do { do {
csr = pUdp->UDP_CSR[AT91C_EP_CONTROL]; csr = pUdp->UDP_CSR[AT91C_EP_CONTROL];
@ -766,7 +780,7 @@ void AT91F_CDC_Enumerate() {
wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8); wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);
if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host
UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR) UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);
} }
UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP) UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP)
@ -813,10 +827,17 @@ void AT91F_CDC_Enumerate() {
case STD_SET_CONFIGURATION: case STD_SET_CONFIGURATION:
btConfiguration = wValue; btConfiguration = wValue;
AT91F_USB_SendZlp(pUdp); AT91F_USB_SendZlp(pUdp);
pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
// make sure we are not stalled
UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT , AT91C_UDP_FORCESTALL);
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN , AT91C_UDP_FORCESTALL);
UDP_CLEAR_EP_FLAGS(AT91C_EP_NOTIFY, AT91C_UDP_FORCESTALL);
// enable endpoints
UDP_SET_EP_FLAGS(AT91C_EP_OUT, (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0 ); UDP_SET_EP_FLAGS(AT91C_EP_OUT, (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0 );
UDP_SET_EP_FLAGS(AT91C_EP_IN, (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0 ); UDP_SET_EP_FLAGS(AT91C_EP_IN, (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0 );
UDP_SET_EP_FLAGS(AT91C_EP_NOTIFY, (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0 ); UDP_SET_EP_FLAGS(AT91C_EP_NOTIFY, (wValue) ? AT91C_UDP_EPTYPE_INT_IN : 0 );
// pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0; // pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;
// pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; // pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;
// pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; // pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;
@ -870,15 +891,15 @@ void AT91F_CDC_Enumerate() {
case STD_CLEAR_FEATURE_ENDPOINT: case STD_CLEAR_FEATURE_ENDPOINT:
wIndex &= 0x0F; wIndex &= 0x0F;
if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) { if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {
if (wIndex == 1) { if (wIndex == AT91C_EP_OUT) {
//pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); //pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);
UDP_SET_EP_FLAGS(AT91C_EP_OUT, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) ); UDP_SET_EP_FLAGS(AT91C_EP_OUT, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) );
} }
else if (wIndex == 2) { else if (wIndex == AT91C_EP_IN) {
//pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); //pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);
UDP_SET_EP_FLAGS(AT91C_EP_IN, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) ); UDP_SET_EP_FLAGS(AT91C_EP_IN, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) );
} }
else if (wIndex == 3) { else if (wIndex == AT91C_EP_NOTIFY) {
//pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); //pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);
UDP_SET_EP_FLAGS(AT91C_EP_NOTIFY, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) ); UDP_SET_EP_FLAGS(AT91C_EP_NOTIFY, (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) );
} }