fix(usb_serial_jtag): Fix issue that buffer seems not flush when TX buffer is full and flush slow,

Closes https://github.com/espressif/esp-idf/issues/12628
This commit is contained in:
Cao Sen Miao 2023-11-28 18:50:21 +08:00
parent 28e2ab09ea
commit 93b2297dc1

View File

@ -6,6 +6,7 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdatomic.h>
#include "esp_log.h" #include "esp_log.h"
#include "hal/usb_serial_jtag_ll.h" #include "hal/usb_serial_jtag_ll.h"
#include "hal/usb_fsls_phy_ll.h" #include "hal/usb_fsls_phy_ll.h"
@ -17,12 +18,19 @@
#include "soc/periph_defs.h" #include "soc/periph_defs.h"
#include "esp_check.h" #include "esp_check.h"
typedef enum {
FIFO_IDLE = 0, /*!< Indicates the fifo is in idle state */
FIFO_BUSY = 1, /*!< Indicates the fifo is in busy state */
} fifo_status_t;
// The hardware buffer max size is 64 // The hardware buffer max size is 64
#define USB_SER_JTAG_ENDP_SIZE (64) #define USB_SER_JTAG_ENDP_SIZE (64)
#define USB_SER_JTAG_RX_MAX_SIZE (64) #define USB_SER_JTAG_RX_MAX_SIZE (64)
typedef struct{ typedef struct{
intr_handle_t intr_handle; /*!< USB-SERIAL-JTAG interrupt handler */ intr_handle_t intr_handle; /*!< USB-SERIAL-JTAG interrupt handler */
portMUX_TYPE spinlock; /*!< Spinlock for usb_serial_jtag */
_Atomic fifo_status_t fifo_status; /*!< Record the status of fifo */
// RX parameters // RX parameters
RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler */ RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler */
@ -59,7 +67,7 @@ static void usb_serial_jtag_isr_handler_default(void *arg) {
// If the hardware fifo is available, write in it. Otherwise, do nothing. // If the hardware fifo is available, write in it. Otherwise, do nothing.
if (usb_serial_jtag_ll_txfifo_writable() == 1) { if (usb_serial_jtag_ll_txfifo_writable() == 1) {
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
size_t queued_size; size_t queued_size;
uint8_t *queued_buff = NULL; uint8_t *queued_buff = NULL;
bool is_stashed_data = false; bool is_stashed_data = false;
@ -83,7 +91,10 @@ static void usb_serial_jtag_isr_handler_default(void *arg) {
// On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL // On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL
if (queued_size > 0) { if (queued_size > 0) {
portENTER_CRITICAL_ISR(&p_usb_serial_jtag_obj->spinlock);
atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_BUSY);
uint32_t sent_size = usb_serial_jtag_write_and_flush(queued_buff, queued_size); uint32_t sent_size = usb_serial_jtag_write_and_flush(queued_buff, queued_size);
portEXIT_CRITICAL_ISR(&p_usb_serial_jtag_obj->spinlock);
if (sent_size < queued_size) { if (sent_size < queued_size) {
// Not all bytes could be sent at once; stash the unwritten bytes in a tx buffer // Not all bytes could be sent at once; stash the unwritten bytes in a tx buffer
@ -100,7 +111,6 @@ static void usb_serial_jtag_isr_handler_default(void *arg) {
if (is_stashed_data == false) { if (is_stashed_data == false) {
vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buff, &xTaskWoken); vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buff, &xTaskWoken);
} }
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
} else { } else {
// The last transmit may have sent a full EP worth of data. The host will interpret // The last transmit may have sent a full EP worth of data. The host will interpret
// this as a transaction that hasn't finished yet and keep the data in its internal // this as a transaction that hasn't finished yet and keep the data in its internal
@ -111,6 +121,7 @@ static void usb_serial_jtag_isr_handler_default(void *arg) {
// flush will not by itself cause this ISR to be called again. // flush will not by itself cause this ISR to be called again.
} }
} else { } else {
atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE);
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
} }
} }
@ -139,6 +150,7 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se
p_usb_serial_jtag_obj->rx_buf_size = usb_serial_jtag_config->rx_buffer_size; p_usb_serial_jtag_obj->rx_buf_size = usb_serial_jtag_config->rx_buffer_size;
p_usb_serial_jtag_obj->tx_buf_size = usb_serial_jtag_config->tx_buffer_size; p_usb_serial_jtag_obj->tx_buf_size = usb_serial_jtag_config->tx_buffer_size;
p_usb_serial_jtag_obj->tx_stash_cnt = 0; p_usb_serial_jtag_obj->tx_stash_cnt = 0;
p_usb_serial_jtag_obj->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
if (p_usb_serial_jtag_obj == NULL) { if (p_usb_serial_jtag_obj == NULL) {
ESP_LOGE(USB_SERIAL_JTAG_TAG, "memory allocate error"); ESP_LOGE(USB_SERIAL_JTAG_TAG, "memory allocate error");
err = ESP_ERR_NO_MEM; err = ESP_ERR_NO_MEM;
@ -161,6 +173,7 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se
// Enable USB-Serial-JTAG peripheral module clock // Enable USB-Serial-JTAG peripheral module clock
usb_serial_jtag_ll_enable_bus_clock(true); usb_serial_jtag_ll_enable_bus_clock(true);
atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE);
// Configure PHY // Configure PHY
usb_fsls_phy_ll_int_jtag_enable(&USB_SERIAL_JTAG); usb_fsls_phy_ll_int_jtag_enable(&USB_SERIAL_JTAG);
@ -210,10 +223,22 @@ int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_t
ESP_RETURN_ON_FALSE(src != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "Invalid buffer pointer."); ESP_RETURN_ON_FALSE(src != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "Invalid buffer pointer.");
ESP_RETURN_ON_FALSE(p_usb_serial_jtag_obj != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized"); ESP_RETURN_ON_FALSE(p_usb_serial_jtag_obj != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized");
size_t sent_data = 0;
BaseType_t result = pdTRUE;
const uint8_t *buff = (const uint8_t *)src; const uint8_t *buff = (const uint8_t *)src;
if (p_usb_serial_jtag_obj->fifo_status == FIFO_IDLE) {
portENTER_CRITICAL(&p_usb_serial_jtag_obj->spinlock);
atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_BUSY);
sent_data = usb_serial_jtag_write_and_flush(src, size);
portEXIT_CRITICAL(&p_usb_serial_jtag_obj->spinlock);
}
// Blocking method, Sending data to ringbuffer, and handle the data in ISR. // Blocking method, Sending data to ringbuffer, and handle the data in ISR.
BaseType_t result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*) (buff), size, ticks_to_wait); if (size - sent_data > 0) {
// Now trigger the ISR to read data from the ring buffer. result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*) (buff+sent_data), size-sent_data, ticks_to_wait);
} else {
atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE);
}
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
return (result == pdFALSE) ? 0 : size; return (result == pdFALSE) ? 0 : size;
} }