Skip to content

Commit 8345e6f

Browse files
Copied individual files from @stevestong master
1 parent 2cdbbc8 commit 8345e6f

File tree

5 files changed

+159
-131
lines changed

5 files changed

+159
-131
lines changed

STM32F1/cores/maple/libmaple/usb/stm32f1/usb_cdcacm.c

Lines changed: 140 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -261,18 +261,28 @@ static ONE_DESCRIPTOR String_Descriptor[N_STRING_DESCRIPTORS] = {
261261

262262
/* I/O state */
263263

264-
#define CDC_SERIAL_BUFFER_SIZE 512
264+
#define CDC_SERIAL_RX_BUFFER_SIZE 256 // must be power of 2
265+
#define CDC_SERIAL_RX_BUFFER_SIZE_MASK (CDC_SERIAL_RX_BUFFER_SIZE-1)
265266

266267
/* Received data */
267-
static volatile uint8 vcomBufferRx[CDC_SERIAL_BUFFER_SIZE];
268-
/* Read index into vcomBufferRx */
269-
static volatile uint32 rx_offset = 0;
270-
/* Number of bytes left to transmit */
271-
static volatile uint32 n_unsent_bytes = 0;
272-
/* Are we currently sending an IN packet? */
273-
static volatile uint8 transmitting = 0;
274-
/* Number of unread bytes */
275-
static volatile uint32 n_unread_bytes = 0;
268+
static volatile uint8 vcomBufferRx[CDC_SERIAL_RX_BUFFER_SIZE];
269+
/* Write index to vcomBufferRx */
270+
static volatile uint32 rx_head;
271+
/* Read index from vcomBufferRx */
272+
static volatile uint32 rx_tail;
273+
274+
#define CDC_SERIAL_TX_BUFFER_SIZE 256 // must be power of 2
275+
#define CDC_SERIAL_TX_BUFFER_SIZE_MASK (CDC_SERIAL_TX_BUFFER_SIZE-1)
276+
// Tx data
277+
static volatile uint8 vcomBufferTx[CDC_SERIAL_TX_BUFFER_SIZE];
278+
// Write index to vcomBufferTx
279+
static volatile uint32 tx_head;
280+
// Read index from vcomBufferTx
281+
static volatile uint32 tx_tail;
282+
// Are we currently sending an IN packet?
283+
static volatile int8 transmitting;
284+
285+
276286

277287
/* Other state (line coding, DTR/RTS) */
278288

@@ -393,100 +403,108 @@ void usb_cdcacm_putc(char ch) {
393403
;
394404
}
395405

396-
/* This function is blocking.
406+
/* This function is non-blocking.
397407
*
398-
* It copies data from a usercode buffer into the USB peripheral TX
408+
* It copies data from a user buffer into the USB peripheral TX
399409
* buffer, and returns the number of bytes copied. */
400-
uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
401-
/* Last transmission hasn't finished, so abort. */
402-
while ( usb_cdcacm_is_transmitting()>0 ) ; // wait for end of transmission
410+
uint32 usb_cdcacm_tx(const uint8* buf, uint32 len)
411+
{
412+
if (len==0) return 0; // no data to send
403413

404-
/* We can only put USB_CDCACM_TX_EPSIZE bytes in the buffer. */
405-
if (len > USB_CDCACM_TX_EPSIZE) {
406-
len = USB_CDCACM_TX_EPSIZE;
407-
}
414+
uint32 head = tx_head; // load volatile variable
415+
uint32 tx_unsent = (head - tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
408416

409-
/* Queue bytes for sending. */
410-
if (len) {
411-
usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR);
417+
// We can only put bytes in the buffer if there is place
418+
if (len > (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1) ) {
419+
len = (CDC_SERIAL_TX_BUFFER_SIZE-tx_unsent-1);
412420
}
413-
// We still need to wait for the interrupt, even if we're sending
414-
// zero bytes. (Sending zero-size packets is useful for flushing
415-
// host-side buffers.)
416-
usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len);
417-
n_unsent_bytes = len;
418-
transmitting = 1;
419-
usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
421+
if (len==0) return 0; // buffer full
422+
423+
uint16 i;
424+
// copy data from user buffer to USB Tx buffer
425+
for (i=0; i<len; i++) {
426+
vcomBufferTx[head] = buf[i];
427+
head = (head+1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
428+
}
429+
tx_head = head; // store volatile variable
430+
431+
if (transmitting<0) {
432+
vcomDataTxCb(); // initiate data transmission
433+
}
420434

421435
return len;
422436
}
423437

424438

425439

426440
uint32 usb_cdcacm_data_available(void) {
427-
return n_unread_bytes;
441+
return (rx_head - rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
428442
}
429443

430444
uint8 usb_cdcacm_is_transmitting(void) {
431-
return transmitting;
445+
return ( transmitting>0 ? transmitting : 0);
432446
}
433447

434448
uint16 usb_cdcacm_get_pending(void) {
435-
return n_unsent_bytes;
449+
return (tx_head - tx_tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
436450
}
437451

438-
/* Nonblocking byte receive.
452+
/* Non-blocking byte receive.
439453
*
440454
* Copies up to len bytes from our private data buffer (*NOT* the PMA)
441455
* into buf and deq's the FIFO. */
442-
uint32 usb_cdcacm_rx(uint8* buf, uint32 len) {
456+
uint32 usb_cdcacm_rx(uint8* buf, uint32 len)
457+
{
443458
/* Copy bytes to buffer. */
444459
uint32 n_copied = usb_cdcacm_peek(buf, len);
445460

446461
/* Mark bytes as read. */
447-
n_unread_bytes -= n_copied;
448-
rx_offset = (rx_offset + n_copied) % CDC_SERIAL_BUFFER_SIZE;
462+
uint16 tail = rx_tail; // load volatile variable
463+
tail = (tail + n_copied) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
464+
rx_tail = tail; // store volatile variable
449465

450-
/* If all bytes have been read, re-enable the RX endpoint, which
451-
* was set to NAK when the current batch of bytes was received. */
452-
if (n_unread_bytes == 0) {
453-
usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
466+
uint32 rx_unread = (rx_head - tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
467+
// If buffer was emptied to a pre-set value, re-enable the RX endpoint
468+
if ( rx_unread <= 64 ) { // experimental value, gives the best performance
454469
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
455-
}
456-
470+
}
457471
return n_copied;
458472
}
459473

460-
/* Nonblocking byte lookahead.
474+
/* Non-blocking byte lookahead.
461475
*
462476
* Looks at unread bytes without marking them as read. */
463-
uint32 usb_cdcacm_peek(uint8* buf, uint32 len) {
477+
uint32 usb_cdcacm_peek(uint8* buf, uint32 len)
478+
{
464479
int i;
465-
uint32 head = rx_offset;
480+
uint32 tail = rx_tail;
481+
uint32 rx_unread = (rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
466482

467-
if (len > n_unread_bytes) {
468-
len = n_unread_bytes;
483+
if (len > rx_unread) {
484+
len = rx_unread;
469485
}
470486

471487
for (i = 0; i < len; i++) {
472-
buf[i] = vcomBufferRx[head];
473-
head = (head + 1) % CDC_SERIAL_BUFFER_SIZE;
488+
buf[i] = vcomBufferRx[tail];
489+
tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
474490
}
475491

476492
return len;
477493
}
478494

479-
uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) {
495+
uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len)
496+
{
480497
int i;
481-
uint32 head = (rx_offset + offset) % CDC_SERIAL_BUFFER_SIZE;
498+
uint32 tail = (rx_tail + offset) & CDC_SERIAL_RX_BUFFER_SIZE_MASK ;
499+
uint32 rx_unread = (rx_head-tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
482500

483-
if (len + offset > n_unread_bytes) {
484-
len = n_unread_bytes - offset;
501+
if (len + offset > rx_unread) {
502+
len = rx_unread - offset;
485503
}
486504

487505
for (i = 0; i < len; i++) {
488-
buf[i] = vcomBufferRx[head];
489-
head = (head + 1) % CDC_SERIAL_BUFFER_SIZE;
506+
buf[i] = vcomBufferRx[tail];
507+
tail = (tail + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
490508
}
491509

492510
return len;
@@ -495,12 +513,12 @@ uint32 usb_cdcacm_peek_ex(uint8* buf, uint32 offset, uint32 len) {
495513
/* Roger Clark. Added. for Arduino 1.0 API support of Serial.peek() */
496514
int usb_cdcacm_peek_char()
497515
{
498-
if (n_unread_bytes == 0)
516+
if (usb_cdcacm_data_available() == 0)
499517
{
500518
return -1;
501519
}
502520

503-
return vcomBufferRx[rx_offset];
521+
return vcomBufferRx[rx_tail];
504522
}
505523

506524
uint8 usb_cdcacm_get_dtr() {
@@ -534,41 +552,75 @@ int usb_cdcacm_get_n_data_bits(void) {
534552
return line_coding.bDataBits;
535553
}
536554

537-
538555
/*
539556
* Callbacks
540557
*/
541-
542-
static void vcomDataTxCb(void) {
543-
n_unsent_bytes = 0;
544-
transmitting = 0;
558+
static void vcomDataTxCb(void)
559+
{
560+
uint32 tail = tx_tail; // load volatile variable
561+
uint32 tx_unsent = (tx_head - tail) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
562+
if (tx_unsent==0) {
563+
if ( (--transmitting)==0) goto flush; // no more data to send
564+
return; // it was already flushed, keep Tx endpoint disabled
565+
}
566+
transmitting = 1;
567+
// We can only send up to USB_CDCACM_TX_EPSIZE bytes in the endpoint.
568+
if (tx_unsent > USB_CDCACM_TX_EPSIZE) {
569+
tx_unsent = USB_CDCACM_TX_EPSIZE;
570+
}
571+
// copy the bytes from USB Tx buffer to PMA buffer
572+
uint32 *dst = usb_pma_ptr(USB_CDCACM_TX_ADDR);
573+
uint16 tmp = 0;
574+
uint16 val;
575+
int i;
576+
for (i = 0; i < tx_unsent; i++) {
577+
val = vcomBufferTx[tail];
578+
tail = (tail + 1) & CDC_SERIAL_TX_BUFFER_SIZE_MASK;
579+
if (i&1) {
580+
*dst++ = tmp | (val<<8);
581+
} else {
582+
tmp = val;
583+
}
584+
}
585+
if ( tx_unsent&1 ) {
586+
*dst = tmp;
587+
}
588+
tx_tail = tail; // store volatile variable
589+
flush:
590+
// enable Tx endpoint
591+
usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, tx_unsent);
592+
usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
545593
}
546594

547-
static void vcomDataRxCb(void) {
548-
uint32 ep_rx_size;
549-
uint32 tail = (rx_offset + n_unread_bytes) % CDC_SERIAL_BUFFER_SIZE;
550-
uint8 ep_rx_data[USB_CDCACM_RX_EPSIZE];
551-
uint32 i;
552-
553-
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_NAK);
554-
ep_rx_size = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
555-
/* This copy won't overwrite unread bytes, since we've set the RX
556-
* endpoint to NAK, and will only set it to VALID when all bytes
557-
* have been read. */
558-
usb_copy_from_pma((uint8*)ep_rx_data, ep_rx_size,
559-
USB_CDCACM_RX_ADDR);
560595

596+
static void vcomDataRxCb(void)
597+
{
598+
uint32 head = rx_head; // load volatile variable
599+
600+
uint32 ep_rx_size = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
601+
// This copy won't overwrite unread bytes as long as there is
602+
// enough room in the USB Rx buffer for next packet
603+
uint32 *src = usb_pma_ptr(USB_CDCACM_RX_ADDR);
604+
uint16 tmp = 0;
605+
uint8 val;
606+
uint32 i;
561607
for (i = 0; i < ep_rx_size; i++) {
562-
vcomBufferRx[tail] = ep_rx_data[i];
563-
tail = (tail + 1) % CDC_SERIAL_BUFFER_SIZE;
608+
if (i&1) {
609+
val = tmp>>8;
610+
} else {
611+
tmp = *src++;
612+
val = tmp&0xFF;
613+
}
614+
vcomBufferRx[head] = val;
615+
head = (head + 1) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
564616
}
617+
rx_head = head; // store volatile variable
565618

566-
n_unread_bytes += ep_rx_size;
567-
568-
if ( n_unread_bytes == 0 ) {
569-
usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
570-
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
571-
}
619+
uint32 rx_unread = (head - rx_tail) & CDC_SERIAL_RX_BUFFER_SIZE_MASK;
620+
// only enable further Rx if there is enough room to receive one more packet
621+
if ( rx_unread < (CDC_SERIAL_RX_BUFFER_SIZE-USB_CDCACM_RX_EPSIZE) ) {
622+
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
623+
}
572624

573625
if (rx_hook) {
574626
rx_hook(USB_CDCACM_HOOK_RX, 0);
@@ -646,10 +698,11 @@ static void usbReset(void) {
646698
SetDeviceAddress(0);
647699

648700
/* Reset the RX/TX state */
649-
n_unread_bytes = 0;
650-
n_unsent_bytes = 0;
651-
rx_offset = 0;
652-
transmitting = 0;
701+
rx_head = 0;
702+
rx_tail = 0;
703+
tx_head = 0;
704+
tx_tail = 0;
705+
transmitting = -1;
653706
}
654707

655708
static RESULT usbDataSetup(uint8 request) {

STM32F1/cores/maple/libmaple/usb/stm32f1/usb_reg_map.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
/* TODO these could use some improvement; they're fairly
3030
* straightforward ports of the analogous ST code. The PMA blit
3131
* routines in particular are obvious targets for performance
32-
* measurement and tuning. */
32+
* measurement and tuning.
3333
3434
void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) {
3535
uint16 *dst = (uint16*)usb_pma_ptr(pma_offset);
@@ -57,7 +57,7 @@ void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) {
5757
*dst = *src & 0xFF;
5858
}
5959
}
60-
60+
*/
6161
static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) {
6262
uint16 nblocks;
6363
if (count > 62) {
@@ -76,12 +76,12 @@ static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) {
7676
*rxc = nblocks << 10;
7777
}
7878
}
79-
79+
/*
8080
void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count) {
8181
uint32 *rxc = usb_ep_rx_buf0_count_ptr(ep);
8282
usb_set_ep_rx_count_common(rxc, count);
8383
}
84-
84+
*/
8585
void usb_set_ep_rx_count(uint8 ep, uint16 count) {
8686
uint32 *rxc = usb_ep_rx_count_ptr(ep);
8787
usb_set_ep_rx_count_common(rxc, count);

0 commit comments

Comments
 (0)