Skip to content

Commit f4df323

Browse files
Cleanup CDC/Uart; modify async reads; add user supplied RX buffer for Uart; move RX ring buffer handling into system layer (CDC flow control); add latency timer to CDC to avoid small packets on TX
1 parent 0d61048 commit f4df323

File tree

15 files changed

+524
-396
lines changed

15 files changed

+524
-396
lines changed

cores/stm32l4/CDC.cpp

Lines changed: 69 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016 Thomas Roell. All rights reserved.
2+
* Copyright (c) 2016-2017 Thomas Roell. All rights reserved.
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to
@@ -32,28 +32,31 @@
3232

3333
#if defined(USBCON)
3434

35-
/* STM32L4x5/STM32L4x6 have USB_OTG_FS with a multi-packet FIFO. However
36-
* to avoid sending ZLP packets, the CDC_TX_PACKET_SIZE is one byte
37-
* less than the maximum FIFO size in terms of 64 byte packets.
38-
*/
39-
#define CDC_TX_PACKET_SIZE (((USBD_CDC_FIFO_SIZE + 63) & ~63) -1)
35+
#define CDC_TX_PACKET_SIZE 128
36+
#define CDC_TX_PACKET_SMALL 64
4037

4138
stm32l4_usbd_cdc_t stm32l4_usbd_cdc;
4239

40+
extern int (*stm32l4_stdio_put)(char, FILE*);
41+
42+
static int serialusb_stdio_put(char data, FILE *fp)
43+
{
44+
return Serial.write(&data, 1);
45+
}
46+
4347
CDC::CDC(struct _stm32l4_usbd_cdc_t *usbd_cdc, bool serialEvent)
4448
{
4549
_usbd_cdc = usbd_cdc;
4650

47-
_rx_read = 0;
48-
_rx_write = 0;
49-
_rx_count = 0;
5051
_tx_read = 0;
5152
_tx_write = 0;
5253
_tx_count = 0;
5354
_tx_size = 0;
5455

5556
_tx_data2 = NULL;
5657
_tx_size2 = 0;
58+
59+
_tx_timeout = 0;
5760

5861
_completionCallback = NULL;
5962
_receiveCallback = NULL;
@@ -75,24 +78,36 @@ void CDC::begin(unsigned long baudrate, uint16_t config)
7578
/* If USBD_CDC has already been enabled/initialized by STDIO, just add the notify.
7679
*/
7780
if (_usbd_cdc->state == USBD_CDC_STATE_INIT) {
78-
stm32l4_usbd_cdc_enable(_usbd_cdc, 0, CDC::_event_callback, (void*)this, (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
81+
stm32l4_usbd_cdc_enable(_usbd_cdc, &_rx_data[0], sizeof(_rx_data), 0, CDC::_event_callback, (void*)this, (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
82+
83+
if (stm32l4_stdio_put == NULL) {
84+
stm32l4_stdio_put = serialusb_stdio_put;
85+
}
7986
} else {
8087
flush();
8188

8289
stm32l4_usbd_cdc_notify(_usbd_cdc, CDC::_event_callback, (void*)this, (USBD_CDC_EVENT_RECEIVE | USBD_CDC_EVENT_TRANSMIT));
8390
}
91+
92+
USBD_SOFCallback(CDC::_sof_callback, (void*)this);
8493
}
8594

8695
void CDC::end()
8796
{
8897
flush();
8998

99+
USBD_SOFCallback(NULL, NULL);
100+
101+
if (stm32l4_stdio_put == serialusb_stdio_put) {
102+
stm32l4_stdio_put = NULL;
103+
}
104+
90105
stm32l4_usbd_cdc_disable(_usbd_cdc);
91106
}
92107

93108
int CDC::available()
94109
{
95-
return _rx_count;
110+
return stm32l4_usbd_cdc_count(_usbd_cdc);
96111
}
97112

98113
int CDC::availableForWrite(void)
@@ -110,67 +125,25 @@ int CDC::availableForWrite(void)
110125

111126
int CDC::peek()
112127
{
113-
if (_rx_count == 0) {
114-
return -1;
115-
}
116-
117-
return _rx_data[_rx_read];
128+
return stm32l4_usbd_cdc_peek(_usbd_cdc);
118129
}
119130

120131
int CDC::read()
121132
{
122-
unsigned int rx_read;
123133
uint8_t data;
124134

125-
if (_rx_count == 0) {
135+
if (!stm32l4_usbd_cdc_count(_usbd_cdc)) {
126136
return -1;
127137
}
128138

129-
rx_read = _rx_read;
139+
stm32l4_usbd_cdc_receive(_usbd_cdc, &data, 1);
130140

131-
data = _rx_data[rx_read];
132-
133-
_rx_read = (unsigned int)(rx_read + 1) & (CDC_RX_BUFFER_SIZE -1);
134-
135-
armv7m_atomic_sub(&_rx_count, 1);
136-
137141
return data;
138142
}
139143

140144
size_t CDC::read(uint8_t *buffer, size_t size)
141145
{
142-
unsigned int rx_read, rx_count;
143-
size_t count;
144-
145-
count = 0;
146-
147-
while (count < size) {
148-
149-
rx_count = _rx_count;
150-
151-
if (rx_count == 0) {
152-
break;
153-
}
154-
155-
rx_read = _rx_read;
156-
157-
if (rx_count > (CDC_RX_BUFFER_SIZE - rx_read)) {
158-
rx_count = (CDC_RX_BUFFER_SIZE - rx_read);
159-
}
160-
161-
if (rx_count > (size - count)) {
162-
rx_count = (size - count);
163-
}
164-
165-
memcpy(&buffer[count], &_rx_data[rx_read], rx_count);
166-
count += rx_count;
167-
168-
_rx_read = (rx_read + rx_count) & (CDC_RX_BUFFER_SIZE -1);
169-
170-
armv7m_atomic_sub(&_rx_count, rx_count);
171-
}
172-
173-
return count;
146+
return stm32l4_usbd_cdc_receive(_usbd_cdc, buffer, size);
174147
}
175148

176149
void CDC::flush()
@@ -276,7 +249,7 @@ size_t CDC::write(const uint8_t *buffer, size_t size)
276249
tx_size = _tx_count;
277250
tx_read = _tx_read;
278251

279-
if (tx_size) {
252+
if (tx_size >= CDC_TX_PACKET_SMALL) {
280253
if (tx_size > (CDC_TX_BUFFER_SIZE - tx_read)) {
281254
tx_size = (CDC_TX_BUFFER_SIZE - tx_read);
282255
}
@@ -350,46 +323,18 @@ void CDC::onReceive(void(*callback)(void))
350323

351324
void CDC::EventCallback(uint32_t events)
352325
{
353-
unsigned int rx_write, rx_count, rx_size, count;
354326
unsigned int tx_read, tx_size;
355-
bool empty;
356-
357-
if (events & USBD_CDC_EVENT_RECEIVE) {
358-
empty = (_rx_count == 0);
359-
360-
count = 0;
361-
362-
do {
363-
rx_size = 0;
364-
rx_count = CDC_RX_BUFFER_SIZE - _rx_count;
365-
366-
if (rx_count == 0) {
367-
break;
368-
}
369-
370-
rx_write = _rx_write;
371-
372-
if (rx_count > (CDC_RX_BUFFER_SIZE - rx_write)) {
373-
rx_count = (CDC_RX_BUFFER_SIZE - rx_write);
374-
}
375-
376-
rx_size = stm32l4_usbd_cdc_receive(_usbd_cdc, &_rx_data[rx_write], rx_count);
377-
378-
_rx_write = (rx_write + rx_size) & (CDC_RX_BUFFER_SIZE -1);
379-
380-
armv7m_atomic_add(&_rx_count, rx_size);
381-
382-
count += rx_size;
383-
384-
} while (rx_size);
385327

386-
if (empty && count && _receiveCallback) {
328+
if (events & USBD_CDC_EVENT_RECEIVE) {
329+
if (_receiveCallback) {
387330
armv7m_pendsv_enqueue((armv7m_pendsv_routine_t)_receiveCallback, NULL, 0);
388331
}
389332
}
390333

391334
if (events & USBD_CDC_EVENT_TRANSMIT) {
392335

336+
_tx_timeout = 0;
337+
393338
tx_size = _tx_size;
394339

395340
if (tx_size != 0) {
@@ -437,11 +382,45 @@ void CDC::EventCallback(uint32_t events)
437382
}
438383
}
439384

385+
void CDC::SOFCallback()
386+
{
387+
unsigned int tx_read, tx_size;
388+
389+
if (_tx_count && !_tx_size && !_tx_size2)
390+
{
391+
_tx_timeout++;
392+
393+
// Small packets get only send after 8ms latency
394+
if (_tx_timeout >= 8)
395+
{
396+
tx_size = _tx_count;
397+
tx_read = _tx_read;
398+
399+
if (tx_size > (CDC_TX_BUFFER_SIZE - tx_read)) {
400+
tx_size = (CDC_TX_BUFFER_SIZE - tx_read);
401+
}
402+
403+
if (tx_size > CDC_TX_PACKET_SIZE) {
404+
tx_size = CDC_TX_PACKET_SIZE;
405+
}
406+
407+
_tx_size = tx_size;
408+
409+
stm32l4_usbd_cdc_transmit(_usbd_cdc, &_tx_data[tx_read], tx_size);
410+
}
411+
}
412+
}
413+
440414
void CDC::_event_callback(void *context, uint32_t events)
441415
{
442416
reinterpret_cast<class CDC*>(context)->EventCallback(events);
443417
}
444418

419+
void CDC::_sof_callback(void *context)
420+
{
421+
reinterpret_cast<class CDC*>(context)->SOFCallback();
422+
}
423+
445424
CDC::operator bool()
446425
{
447426
return stm32l4_usbd_cdc_connected(_usbd_cdc);

cores/stm32l4/USBAPI.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016 Thomas Roell. All rights reserved.
2+
* Copyright (c) 2016-2017 Thomas Roell. All rights reserved.
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to
@@ -110,9 +110,6 @@ class CDC : public HardwareSerial
110110
private:
111111
struct _stm32l4_usbd_cdc_t *_usbd_cdc;
112112
uint8_t _rx_data[CDC_RX_BUFFER_SIZE];
113-
volatile uint16_t _rx_write;
114-
volatile uint16_t _rx_read;
115-
volatile uint32_t _rx_count;
116113
uint8_t _tx_data[CDC_TX_BUFFER_SIZE];
117114
volatile uint16_t _tx_write;
118115
volatile uint16_t _tx_read;
@@ -122,9 +119,13 @@ class CDC : public HardwareSerial
122119
const uint8_t *_tx_data2;
123120
volatile uint32_t _tx_size2;
124121

122+
volatile uint32_t _tx_timeout;
123+
125124
void (*_completionCallback)(void);
126125
void (*_receiveCallback)(void);
127126

128127
static void _event_callback(void *context, uint32_t events);
128+
static void _sof_callback(void *context);
129129
void EventCallback(uint32_t events);
130+
void SOFCallback();
130131
};

0 commit comments

Comments
 (0)