15
15
#include "esp_intr_alloc.h"
16
16
#include "driver/usb_serial_jtag.h"
17
17
#include "soc/periph_defs.h"
18
+ #include "soc/soc_caps.h"
18
19
#include "esp_check.h"
20
+ #include "esp_private/periph_ctrl.h"
19
21
20
- typedef enum {
21
- FIFO_IDLE = 0 , /*!< Indicates the fifo is in idle state */
22
- FIFO_BUSY = 1 , /*!< Indicates the fifo is in busy state */
23
- } fifo_status_t ;
22
+ /*
23
+ Note: Before you add a workaround for an issue in this driver, please please try
24
+ to figure out the actual root cause first. The USB-serial-JTAG is a simple device,
25
+ it shouldn't need anything more than a simple, straightforward driver.
26
+ */
24
27
25
- // The hardware buffer max size is 64
28
+ // The hardware buffer max size is 64, both for RX and TX.
26
29
#define USB_SER_JTAG_ENDP_SIZE (64)
27
- #define USB_SER_JTAG_RX_MAX_SIZE (64 )
30
+ #define USB_SER_JTAG_RX_MAX_SIZE (USB_SER_JTAG_ENDP_SIZE )
28
31
29
32
typedef struct {
30
33
intr_handle_t intr_handle ; /*!< USB-SERIAL-JTAG interrupt handler */
31
- portMUX_TYPE spinlock ; /*!< Spinlock for usb_serial_jtag */
32
- _Atomic fifo_status_t fifo_status ; /*!< Record the status of fifo */
33
34
34
35
// RX parameters
35
36
RingbufHandle_t rx_ring_buf ; /*!< RX ring buffer handler */
36
- uint32_t rx_buf_size ; /*!< TX buffer size */
37
- uint8_t rx_data_buf [USB_SER_JTAG_ENDP_SIZE ]; /*!< Data buffer to stash FIFO data */
38
37
39
38
// TX parameters
40
- uint32_t tx_buf_size ; /*!< TX buffer size */
41
39
RingbufHandle_t tx_ring_buf ; /*!< TX ring buffer handler */
42
- uint8_t tx_data_buf [USB_SER_JTAG_ENDP_SIZE ]; /*!< Data buffer to stash TX FIFO data */
40
+ uint8_t tx_stash_buf [USB_SER_JTAG_ENDP_SIZE ]; /*!< Data buffer to stash TX FIFO data */
43
41
size_t tx_stash_cnt ; /*!< Number of stashed TX FIFO bytes */
44
42
} usb_serial_jtag_obj_t ;
45
43
46
44
static usb_serial_jtag_obj_t * p_usb_serial_jtag_obj = NULL ;
47
45
48
46
static const char * USB_SERIAL_JTAG_TAG = "usb_serial_jtag" ;
49
47
50
- static size_t usb_serial_jtag_write_and_flush ( const uint8_t * buf , uint32_t wr_len )
48
+ static void usb_serial_jtag_isr_handler_default ( void * arg )
51
49
{
52
- size_t size = usb_serial_jtag_ll_write_txfifo (buf , wr_len );
53
- usb_serial_jtag_ll_txfifo_flush ();
54
- return size ;
55
- }
56
-
57
- static void usb_serial_jtag_isr_handler_default (void * arg ) {
58
- portBASE_TYPE xTaskWoken = 0 ;
50
+ BaseType_t xTaskWoken = 0 ;
59
51
uint32_t usbjtag_intr_status = 0 ;
60
52
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask ();
61
53
62
54
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY ) {
55
+ //Clear interrupt so we won't be called until the next transfer finishes.
56
+ usb_serial_jtag_ll_clr_intsts_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY );
57
+
63
58
// Interrupt tells us the host picked up the data we sent.
64
59
// If we have more data, we can put it in the buffer and the host will pick that up next.
65
- // Send data in isr.
66
- // If the hardware fifo is available, write in it. Otherwise, do nothing.
60
+ // We expect the TX FIFO to be writable for this. If it's not, somehow someone else
61
+ // (ROM print routines?) have snuck in a full buffer before we got here. In that case,
62
+ // we simply ignore the interrupt, a new one will come if the buffer is empty again.
67
63
if (usb_serial_jtag_ll_txfifo_writable () == 1 ) {
68
- // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
69
-
64
+ // Retrieve data from either the stash buffer or, if that's empty, from the ring buffer.
70
65
size_t queued_size ;
71
- uint8_t * queued_buff = NULL ;
72
- bool is_stashed_data = false;
66
+ uint8_t * queued_buf = NULL ;
73
67
if (p_usb_serial_jtag_obj -> tx_stash_cnt != 0 ) {
74
68
// Send stashed tx bytes before reading bytes from ring buffer
75
- queued_buff = p_usb_serial_jtag_obj -> tx_data_buf ;
69
+ queued_buf = p_usb_serial_jtag_obj -> tx_stash_buf ;
76
70
queued_size = p_usb_serial_jtag_obj -> tx_stash_cnt ;
77
- is_stashed_data = true;
78
71
} else {
79
72
// Max 64 data payload size in a single EndPoint
80
- queued_buff = (uint8_t * )xRingbufferReceiveUpToFromISR (p_usb_serial_jtag_obj -> tx_ring_buf , & queued_size , USB_SER_JTAG_ENDP_SIZE );
73
+ queued_buf = (uint8_t * )xRingbufferReceiveUpToFromISR (p_usb_serial_jtag_obj -> tx_ring_buf , & queued_size , USB_SER_JTAG_ENDP_SIZE );
81
74
}
82
75
83
- usb_serial_jtag_ll_clr_intsts_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY );
84
-
85
- if (queued_buff != NULL ) {
86
-
87
- // Although tx_queued_bytes may be larger than 0, we may have
88
- // interrupted before xRingbufferSend() was called.
89
- // Copy the queued buffer into the TX FIFO
90
-
91
- // On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL
92
- if (queued_size > 0 ) {
93
- portENTER_CRITICAL_ISR (& p_usb_serial_jtag_obj -> spinlock );
94
- atomic_store (& p_usb_serial_jtag_obj -> fifo_status , FIFO_BUSY );
95
- uint32_t sent_size = usb_serial_jtag_write_and_flush (queued_buff , queued_size );
96
- portEXIT_CRITICAL_ISR (& p_usb_serial_jtag_obj -> spinlock );
97
-
98
- if (sent_size < queued_size ) {
99
- // Not all bytes could be sent at once; stash the unwritten bytes in a tx buffer
100
- // stash_size will not larger than USB_SER_JTAG_ENDP_SIZE because queued_size is got from xRingbufferReceiveUpToFromISR
101
- size_t stash_size = queued_size - sent_size ;
102
- memcpy (p_usb_serial_jtag_obj -> tx_data_buf , & queued_buff [sent_size ], stash_size );
103
- p_usb_serial_jtag_obj -> tx_stash_cnt = stash_size ;
104
- } else {
105
- p_usb_serial_jtag_obj -> tx_stash_cnt = 0 ;
106
- // assert if sent_size is larger than queued_size.
107
- assert (sent_size <= queued_size );
108
- }
76
+ if (queued_buf != NULL && queued_size > 0 ) {
77
+ // We have some data to send. Send it.
78
+ uint32_t sent_size = usb_serial_jtag_ll_write_txfifo (queued_buf , queued_size );
79
+ usb_serial_jtag_ll_txfifo_flush ();
80
+
81
+ // Check if we were able to send everything.
82
+ if (sent_size < queued_size ) {
83
+ // Not all bytes could be sent at once; stash the unwritten bytes in a buffer
84
+ // This will happen if e.g. the rom output functions manage to sneak a few bytes into the
85
+ // TX FIFO before this interrupt triggers. Note stash_size will not larger than
86
+ // USB_SER_JTAG_ENDP_SIZE because queued_size is obtained from xRingbufferReceiveUpToFromISR.
87
+ size_t stash_size = queued_size - sent_size ;
88
+ memcpy (p_usb_serial_jtag_obj -> tx_stash_buf , & queued_buf [sent_size ], stash_size );
89
+ p_usb_serial_jtag_obj -> tx_stash_cnt = stash_size ;
90
+ } else {
91
+ p_usb_serial_jtag_obj -> tx_stash_cnt = 0 ;
109
92
}
110
- if (is_stashed_data == false) {
111
- vRingbufferReturnItemFromISR (p_usb_serial_jtag_obj -> tx_ring_buf , queued_buff , & xTaskWoken );
93
+ // Return the buffer if we got it from the ring buffer.
94
+ if (queued_buf != p_usb_serial_jtag_obj -> tx_stash_buf ) {
95
+ vRingbufferReturnItemFromISR (p_usb_serial_jtag_obj -> tx_ring_buf , queued_buf , & xTaskWoken );
112
96
}
113
97
} else {
98
+ // No data to send.
114
99
// The last transmit may have sent a full EP worth of data. The host will interpret
115
100
// this as a transaction that hasn't finished yet and keep the data in its internal
116
101
// buffers rather than releasing it to the program listening on the CDC serial port.
117
102
// We need to flush again in order to send a 0-byte packet that ends the transaction.
118
103
usb_serial_jtag_ll_txfifo_flush ();
119
- // Note that since this doesn't re-enable USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY, the
120
- // flush will not by itself cause this ISR to be called again.
104
+
105
+ // We will also disable the interrupt as for now there's no need to handle the
106
+ // TX interrupt again. We'll re-enable this externally if we need data sent.
107
+ usb_serial_jtag_ll_disable_intr_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY );
121
108
}
122
- } else {
123
- atomic_store (& p_usb_serial_jtag_obj -> fifo_status , FIFO_IDLE );
124
- usb_serial_jtag_ll_clr_intsts_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY );
125
109
}
126
110
}
127
111
128
112
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) {
129
- // read rx buffer(max length is 64), and send avaliable data to ringbuffer.
130
- // Ensure the rx buffer size is larger than RX_MAX_SIZE.
113
+ // Acknowledge interrupt
131
114
usb_serial_jtag_ll_clr_intsts_mask (USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT );
132
- uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo (p_usb_serial_jtag_obj -> rx_data_buf , USB_SER_JTAG_RX_MAX_SIZE );
133
- xRingbufferSendFromISR (p_usb_serial_jtag_obj -> rx_ring_buf , p_usb_serial_jtag_obj -> rx_data_buf , rx_fifo_len , & xTaskWoken );
115
+ // Read RX FIFO and send available data to ringbuffer.
116
+ uint8_t buf [USB_SER_JTAG_RX_MAX_SIZE ];
117
+ uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo (buf , USB_SER_JTAG_RX_MAX_SIZE );
118
+ xRingbufferSendFromISR (p_usb_serial_jtag_obj -> rx_ring_buf , buf , rx_fifo_len , & xTaskWoken );
134
119
}
135
120
136
121
if (xTaskWoken == pdTRUE ) {
@@ -145,18 +130,16 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se
145
130
ESP_RETURN_ON_FALSE ((usb_serial_jtag_config -> rx_buffer_size > 0 ), ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , "RX buffer is not prepared" );
146
131
ESP_RETURN_ON_FALSE ((usb_serial_jtag_config -> rx_buffer_size > USB_SER_JTAG_RX_MAX_SIZE ), ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , "RX buffer prepared is so small, should larger than 64" );
147
132
ESP_RETURN_ON_FALSE ((usb_serial_jtag_config -> tx_buffer_size > 0 ), ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , "TX buffer is not prepared" );
148
- p_usb_serial_jtag_obj = (usb_serial_jtag_obj_t * ) heap_caps_calloc (1 , sizeof (usb_serial_jtag_obj_t ), MALLOC_CAP_INTERNAL |MALLOC_CAP_8BIT );
149
- p_usb_serial_jtag_obj -> rx_buf_size = usb_serial_jtag_config -> rx_buffer_size ;
150
- p_usb_serial_jtag_obj -> tx_buf_size = usb_serial_jtag_config -> tx_buffer_size ;
151
- p_usb_serial_jtag_obj -> tx_stash_cnt = 0 ;
152
- p_usb_serial_jtag_obj -> spinlock = (portMUX_TYPE )portMUX_INITIALIZER_UNLOCKED ;
133
+ p_usb_serial_jtag_obj = (usb_serial_jtag_obj_t * ) heap_caps_calloc (1 , sizeof (usb_serial_jtag_obj_t ), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT );
153
134
if (p_usb_serial_jtag_obj == NULL ) {
154
135
ESP_LOGE (USB_SERIAL_JTAG_TAG , "memory allocate error" );
155
- err = ESP_ERR_NO_MEM ;
156
- goto _exit ;
136
+ // no `goto _exit` here as there's nothing to clean up and that would make the uninstall
137
+ // routine unhappy.
138
+ return ESP_ERR_NO_MEM ;
157
139
}
140
+ p_usb_serial_jtag_obj -> tx_stash_cnt = 0 ;
158
141
159
- p_usb_serial_jtag_obj -> rx_ring_buf = xRingbufferCreate (p_usb_serial_jtag_obj -> rx_buf_size , RINGBUF_TYPE_BYTEBUF );
142
+ p_usb_serial_jtag_obj -> rx_ring_buf = xRingbufferCreate (usb_serial_jtag_config -> rx_buffer_size , RINGBUF_TYPE_BYTEBUF );
160
143
if (p_usb_serial_jtag_obj -> rx_ring_buf == NULL ) {
161
144
ESP_LOGE (USB_SERIAL_JTAG_TAG , "ringbuffer create error" );
162
145
err = ESP_ERR_NO_MEM ;
@@ -172,7 +155,6 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se
172
155
173
156
// Enable USB-Serial-JTAG peripheral module clock
174
157
usb_serial_jtag_ll_enable_bus_clock (true);
175
- atomic_store (& p_usb_serial_jtag_obj -> fifo_status , FIFO_IDLE );
176
158
177
159
// Configure PHY
178
160
#if USB_SERIAL_JTAG_LL_EXT_PHY_SUPPORTED
@@ -231,37 +213,29 @@ int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_t
231
213
ESP_RETURN_ON_FALSE (src != NULL , ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , "Invalid buffer pointer." );
232
214
ESP_RETURN_ON_FALSE (p_usb_serial_jtag_obj != NULL , ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , "The driver hasn't been initialized" );
233
215
234
- size_t sent_data = 0 ;
235
216
BaseType_t result = pdTRUE ;
236
- const uint8_t * buff = (const uint8_t * )src ;
237
- if (p_usb_serial_jtag_obj -> fifo_status == FIFO_IDLE ) {
238
- portENTER_CRITICAL (& p_usb_serial_jtag_obj -> spinlock );
239
- atomic_store (& p_usb_serial_jtag_obj -> fifo_status , FIFO_BUSY );
240
- sent_data = usb_serial_jtag_write_and_flush (src , size );
241
- portEXIT_CRITICAL (& p_usb_serial_jtag_obj -> spinlock );
242
- }
243
-
244
- // Blocking method, Sending data to ringbuffer, and handle the data in ISR.
245
- if (size - sent_data > 0 ) {
246
- result = xRingbufferSend (p_usb_serial_jtag_obj -> tx_ring_buf , (void * ) (buff + sent_data ), size - sent_data , ticks_to_wait );
247
- } else {
248
- atomic_store (& p_usb_serial_jtag_obj -> fifo_status , FIFO_IDLE );
249
- }
217
+ result = xRingbufferSend (p_usb_serial_jtag_obj -> tx_ring_buf , (void * )src , size , ticks_to_wait );
218
+ // Re-enable the TX interrupt. If this was disabled, this will immediately trigger the ISR
219
+ // and send the things we just put in the ringbuffer.
250
220
usb_serial_jtag_ll_ena_intr_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY );
251
221
return (result == pdFALSE ) ? 0 : size ;
252
222
}
253
223
224
+ //Note that this is also called when usb_serial_jtag_driver_install errors out and as such should
225
+ //work on a half-initialized driver as well.
254
226
esp_err_t usb_serial_jtag_driver_uninstall (void )
255
227
{
256
- if (p_usb_serial_jtag_obj == NULL ) {
257
- ESP_LOGI (USB_SERIAL_JTAG_TAG , "ALREADY NULL " );
228
+ if (p_usb_serial_jtag_obj == NULL ) {
229
+ ESP_LOGE (USB_SERIAL_JTAG_TAG , "uninstall without install called " );
258
230
return ESP_OK ;
259
231
}
260
232
261
- /* Not disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */
262
- //Disable tx/rx interrupt.
233
+ /* Don't disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */
234
+
263
235
usb_serial_jtag_ll_disable_intr_mask (USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT );
264
- esp_intr_free (p_usb_serial_jtag_obj -> intr_handle );
236
+ if (p_usb_serial_jtag_obj -> intr_handle ) {
237
+ esp_intr_free (p_usb_serial_jtag_obj -> intr_handle );
238
+ }
265
239
266
240
if (p_usb_serial_jtag_obj -> rx_ring_buf ) {
267
241
vRingbufferDelete (p_usb_serial_jtag_obj -> rx_ring_buf );
0 commit comments