2022-02-08 09:39:38 +00:00
/*
2024-01-02 10:08:35 +00:00
* SPDX - FileCopyrightText : 2021 - 2024 Espressif Systems ( Shanghai ) CO LTD
2022-02-08 09:39:38 +00:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
2021-04-23 07:46:02 +00:00
# include <string.h>
# include <stdbool.h>
2023-11-28 10:50:21 +00:00
# include <stdatomic.h>
2021-04-23 07:46:02 +00:00
# include "esp_log.h"
# include "hal/usb_serial_jtag_ll.h"
# include "freertos/FreeRTOS.h"
# include "freertos/semphr.h"
# include "freertos/ringbuf.h"
# include "esp_intr_alloc.h"
# include "driver/usb_serial_jtag.h"
# include "soc/periph_defs.h"
2023-10-27 10:23:50 +00:00
# include "soc/soc_caps.h"
2021-04-23 07:46:02 +00:00
# include "esp_check.h"
2023-10-27 10:23:50 +00:00
# include "esp_private/periph_ctrl.h"
# if !SOC_RCC_IS_INDEPENDENT
# define USJ_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
# else
# define USJ_RCC_ATOMIC()
# endif
2021-04-23 07:46:02 +00:00
2023-11-28 10:50:21 +00:00
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 ;
2021-04-23 07:46:02 +00:00
// The hardware buffer max size is 64
# define USB_SER_JTAG_ENDP_SIZE (64)
# define USB_SER_JTAG_RX_MAX_SIZE (64)
2024-01-02 10:08:35 +00:00
typedef struct {
2021-04-23 07:46:02 +00:00
intr_handle_t intr_handle ; /*!< USB-SERIAL-JTAG interrupt handler */
2023-11-28 10:50:21 +00:00
portMUX_TYPE spinlock ; /*!< Spinlock for usb_serial_jtag */
_Atomic fifo_status_t fifo_status ; /*!< Record the status of fifo */
2021-04-23 07:46:02 +00:00
// RX parameters
RingbufHandle_t rx_ring_buf ; /*!< RX ring buffer handler */
uint32_t rx_buf_size ; /*!< TX buffer size */
2023-09-18 11:28:09 +00:00
uint8_t rx_data_buf [ USB_SER_JTAG_ENDP_SIZE ] ; /*!< Data buffer to stash FIFO data */
2021-04-23 07:46:02 +00:00
// TX parameters
uint32_t tx_buf_size ; /*!< TX buffer size */
RingbufHandle_t tx_ring_buf ; /*!< TX ring buffer handler */
2023-05-09 03:37:06 +00:00
uint8_t tx_data_buf [ USB_SER_JTAG_ENDP_SIZE ] ; /*!< Data buffer to stash TX FIFO data */
size_t tx_stash_cnt ; /*!< Number of stashed TX FIFO bytes */
2021-04-23 07:46:02 +00:00
} usb_serial_jtag_obj_t ;
static usb_serial_jtag_obj_t * p_usb_serial_jtag_obj = NULL ;
static const char * USB_SERIAL_JTAG_TAG = " usb_serial_jtag " ;
2023-09-18 11:28:09 +00:00
static size_t usb_serial_jtag_write_and_flush ( const uint8_t * buf , uint32_t wr_len )
2021-04-23 07:46:02 +00:00
{
2023-09-18 11:28:09 +00:00
size_t size = usb_serial_jtag_ll_write_txfifo ( buf , wr_len ) ;
2021-04-23 07:46:02 +00:00
usb_serial_jtag_ll_txfifo_flush ( ) ;
2023-05-09 03:37:06 +00:00
return size ;
2021-04-23 07:46:02 +00:00
}
2024-01-02 10:08:35 +00:00
static void usb_serial_jtag_isr_handler_default ( void * arg )
{
2023-07-31 15:10:34 +00:00
BaseType_t xTaskWoken = 0 ;
2021-04-23 07:46:02 +00:00
uint32_t usbjtag_intr_status = 0 ;
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask ( ) ;
if ( usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY ) {
2023-05-09 03:37:06 +00:00
// Interrupt tells us the host picked up the data we sent.
// If we have more data, we can put it in the buffer and the host will pick that up next.
2021-04-23 07:46:02 +00:00
// Send data in isr.
2023-09-18 11:28:09 +00:00
// If the hardware fifo is available, write in it. Otherwise, do nothing.
2021-04-23 07:46:02 +00:00
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.
2023-11-28 10:50:21 +00:00
2021-04-23 07:46:02 +00:00
size_t queued_size ;
2023-05-09 03:37:06 +00:00
uint8_t * queued_buff = NULL ;
bool is_stashed_data = false ;
if ( p_usb_serial_jtag_obj - > tx_stash_cnt ! = 0 ) {
// Send stashed tx bytes before reading bytes from ring buffer
queued_buff = p_usb_serial_jtag_obj - > tx_data_buf ;
queued_size = p_usb_serial_jtag_obj - > tx_stash_cnt ;
is_stashed_data = true ;
2023-09-18 11:28:09 +00:00
} else {
2023-05-09 03:37:06 +00:00
// Max 64 data payload size in a single EndPoint
queued_buff = ( uint8_t * ) xRingbufferReceiveUpToFromISR ( p_usb_serial_jtag_obj - > tx_ring_buf , & queued_size , USB_SER_JTAG_ENDP_SIZE ) ;
}
usb_serial_jtag_ll_clr_intsts_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY ) ;
if ( queued_buff ! = NULL ) {
// Although tx_queued_bytes may be larger than 0, we may have
// interrupted before xRingbufferSend() was called.
// Copy the queued buffer into the TX FIFO
// On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL
if ( queued_size > 0 ) {
2023-11-28 10:50:21 +00:00
portENTER_CRITICAL_ISR ( & p_usb_serial_jtag_obj - > spinlock ) ;
atomic_store ( & p_usb_serial_jtag_obj - > fifo_status , FIFO_BUSY ) ;
2023-05-09 03:37:06 +00:00
uint32_t sent_size = usb_serial_jtag_write_and_flush ( queued_buff , queued_size ) ;
2023-11-28 10:50:21 +00:00
portEXIT_CRITICAL_ISR ( & p_usb_serial_jtag_obj - > spinlock ) ;
2023-05-09 03:37:06 +00:00
if ( sent_size < queued_size ) {
2023-11-24 09:37:22 +00:00
// Not all bytes could be sent at once; stash the unwritten bytes in a tx buffer
2023-09-18 11:28:09 +00:00
// stash_size will not larger than USB_SER_JTAG_ENDP_SIZE because queued_size is got from xRingbufferReceiveUpToFromISR
size_t stash_size = queued_size - sent_size ;
2023-05-09 03:37:06 +00:00
memcpy ( p_usb_serial_jtag_obj - > tx_data_buf , & queued_buff [ sent_size ] , stash_size ) ;
p_usb_serial_jtag_obj - > tx_stash_cnt = stash_size ;
2023-09-18 11:28:09 +00:00
} else {
2023-05-09 03:37:06 +00:00
p_usb_serial_jtag_obj - > tx_stash_cnt = 0 ;
2023-09-18 11:28:09 +00:00
// assert if sent_size is larger than queued_size.
assert ( sent_size < = queued_size ) ;
2023-05-09 03:37:06 +00:00
}
}
if ( is_stashed_data = = false ) {
vRingbufferReturnItemFromISR ( p_usb_serial_jtag_obj - > tx_ring_buf , queued_buff , & xTaskWoken ) ;
}
2023-11-24 09:37:22 +00:00
} else {
// 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
// buffers rather than releasing it to the program listening on the CDC serial port.
// We need to flush again in order to send a 0-byte packet that ends the transaction.
usb_serial_jtag_ll_txfifo_flush ( ) ;
// Note that since this doesn't re-enable USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY, the
// flush will not by itself cause this ISR to be called again.
2021-04-23 07:46:02 +00:00
}
} else {
2023-11-28 10:50:21 +00:00
atomic_store ( & p_usb_serial_jtag_obj - > fifo_status , FIFO_IDLE ) ;
2021-07-29 01:57:47 +00:00
usb_serial_jtag_ll_clr_intsts_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY ) ;
2021-04-23 07:46:02 +00:00
}
}
if ( usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) {
2024-03-25 06:11:33 +00:00
// read rx buffer(max length is 64), and send available data to ringbuffer.
2021-04-23 07:46:02 +00:00
// Ensure the rx buffer size is larger than RX_MAX_SIZE.
2021-07-29 01:57:47 +00:00
usb_serial_jtag_ll_clr_intsts_mask ( USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) ;
2021-04-23 07:46:02 +00:00
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 ) ;
xRingbufferSendFromISR ( p_usb_serial_jtag_obj - > rx_ring_buf , p_usb_serial_jtag_obj - > rx_data_buf , rx_fifo_len , & xTaskWoken ) ;
}
if ( xTaskWoken = = pdTRUE ) {
portYIELD_FROM_ISR ( ) ;
}
}
esp_err_t usb_serial_jtag_driver_install ( usb_serial_jtag_driver_config_t * usb_serial_jtag_config )
{
esp_err_t err = ESP_OK ;
ESP_RETURN_ON_FALSE ( ( p_usb_serial_jtag_obj = = NULL ) , ESP_ERR_INVALID_STATE , USB_SERIAL_JTAG_TAG , " Driver already installed " ) ;
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 " ) ;
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 " ) ;
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 " ) ;
2024-01-02 10:08:35 +00:00
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 ) ;
2021-04-23 07:46:02 +00:00
if ( p_usb_serial_jtag_obj = = NULL ) {
ESP_LOGE ( USB_SERIAL_JTAG_TAG , " memory allocate error " ) ;
err = ESP_ERR_NO_MEM ;
goto _exit ;
}
2024-06-06 08:14:40 +00:00
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_stash_cnt = 0 ;
p_usb_serial_jtag_obj - > spinlock = ( portMUX_TYPE ) portMUX_INITIALIZER_UNLOCKED ;
2021-04-23 07:46:02 +00:00
p_usb_serial_jtag_obj - > rx_ring_buf = xRingbufferCreate ( p_usb_serial_jtag_obj - > rx_buf_size , RINGBUF_TYPE_BYTEBUF ) ;
if ( p_usb_serial_jtag_obj - > rx_ring_buf = = NULL ) {
ESP_LOGE ( USB_SERIAL_JTAG_TAG , " ringbuffer create error " ) ;
err = ESP_ERR_NO_MEM ;
goto _exit ;
}
p_usb_serial_jtag_obj - > tx_ring_buf = xRingbufferCreate ( usb_serial_jtag_config - > tx_buffer_size , RINGBUF_TYPE_BYTEBUF ) ;
if ( p_usb_serial_jtag_obj - > rx_ring_buf = = NULL ) {
ESP_LOGE ( USB_SERIAL_JTAG_TAG , " ringbuffer create error " ) ;
err = ESP_ERR_NO_MEM ;
goto _exit ;
}
2023-10-27 10:23:50 +00:00
// Enable USB-Serial-JTAG peripheral module clock
USJ_RCC_ATOMIC ( ) {
usb_serial_jtag_ll_enable_bus_clock ( true ) ;
}
2023-11-28 10:50:21 +00:00
atomic_store ( & p_usb_serial_jtag_obj - > fifo_status , FIFO_IDLE ) ;
2023-10-27 10:23:50 +00:00
2022-07-22 07:52:54 +00:00
// Configure PHY
2024-04-02 11:55:44 +00:00
# if USB_SERIAL_JTAG_LL_EXT_PHY_SUPPORTED
2024-03-14 13:20:33 +00:00
usb_serial_jtag_ll_phy_enable_external ( false ) ; // Use internal PHY
usb_serial_jtag_ll_phy_enable_pad ( true ) ; // Enable USB PHY pads
2024-04-02 11:55:44 +00:00
# else // USB_SERIAL_JTAG_LL_EXT_PHY_SUPPORTED
usb_serial_jtag_ll_phy_set_defaults ( ) ; // External PHY not supported. Set default values.
# endif // USB_WRAP_LL_EXT_PHY_SUPPORTED
2022-07-22 07:52:54 +00:00
2024-01-02 10:08:35 +00:00
usb_serial_jtag_ll_clr_intsts_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY |
USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) ;
usb_serial_jtag_ll_ena_intr_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY |
2021-04-23 07:46:02 +00:00
USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) ;
2021-07-29 01:57:47 +00:00
err = esp_intr_alloc ( ETS_USB_SERIAL_JTAG_INTR_SOURCE , 0 , usb_serial_jtag_isr_handler_default , NULL , & p_usb_serial_jtag_obj - > intr_handle ) ;
2021-04-23 07:46:02 +00:00
if ( err ! = ESP_OK ) {
goto _exit ;
}
return ESP_OK ;
_exit :
usb_serial_jtag_driver_uninstall ( ) ;
return err ;
}
int usb_serial_jtag_read_bytes ( void * buf , uint32_t length , TickType_t ticks_to_wait )
{
uint8_t * data = NULL ;
size_t data_read_len = 0 ;
if ( length = = 0 ) {
return 0 ;
}
2024-03-25 06:11:33 +00:00
// Receive new data from ISR
2022-02-08 09:39:38 +00:00
data = ( uint8_t * ) xRingbufferReceiveUpTo ( p_usb_serial_jtag_obj - > rx_ring_buf , & data_read_len , ( TickType_t ) ticks_to_wait , length ) ;
2021-04-23 07:46:02 +00:00
if ( data = = NULL ) {
// If there is no data received from ringbuffer, return 0 directly.
return 0 ;
}
memcpy ( ( uint8_t * ) buf , data , data_read_len ) ;
vRingbufferReturnItem ( p_usb_serial_jtag_obj - > rx_ring_buf , data ) ;
data = NULL ;
return data_read_len ;
}
int usb_serial_jtag_write_bytes ( const void * src , size_t size , TickType_t ticks_to_wait )
{
ESP_RETURN_ON_FALSE ( size ! = 0 , ESP_ERR_INVALID_ARG , USB_SERIAL_JTAG_TAG , " size should be larger than 0 " ) ;
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 " ) ;
2023-11-28 10:50:21 +00:00
size_t sent_data = 0 ;
BaseType_t result = pdTRUE ;
2023-02-22 06:39:06 +00:00
const uint8_t * buff = ( const uint8_t * ) src ;
2023-11-28 10:50:21 +00:00
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 ) ;
}
2023-02-22 06:39:06 +00:00
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
2023-11-28 10:50:21 +00:00
if ( size - sent_data > 0 ) {
2024-01-02 10:08:35 +00:00
result = xRingbufferSend ( p_usb_serial_jtag_obj - > tx_ring_buf , ( void * ) ( buff + sent_data ) , size - sent_data , ticks_to_wait ) ;
2023-11-28 10:50:21 +00:00
} else {
atomic_store ( & p_usb_serial_jtag_obj - > fifo_status , FIFO_IDLE ) ;
}
2023-08-23 08:04:57 +00:00
usb_serial_jtag_ll_ena_intr_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY ) ;
return ( result = = pdFALSE ) ? 0 : size ;
2021-04-23 07:46:02 +00:00
}
esp_err_t usb_serial_jtag_driver_uninstall ( void )
{
2024-01-02 10:08:35 +00:00
if ( p_usb_serial_jtag_obj = = NULL ) {
2021-04-23 07:46:02 +00:00
ESP_LOGI ( USB_SERIAL_JTAG_TAG , " ALREADY NULL " ) ;
return ESP_OK ;
}
2023-10-27 10:23:50 +00:00
/* Not disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */
2021-04-23 07:46:02 +00:00
//Disable tx/rx interrupt.
usb_serial_jtag_ll_disable_intr_mask ( USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT ) ;
esp_intr_free ( p_usb_serial_jtag_obj - > intr_handle ) ;
2024-01-02 10:08:35 +00:00
if ( p_usb_serial_jtag_obj - > rx_ring_buf ) {
2021-04-23 07:46:02 +00:00
vRingbufferDelete ( p_usb_serial_jtag_obj - > rx_ring_buf ) ;
p_usb_serial_jtag_obj - > rx_ring_buf = NULL ;
}
2024-01-02 10:08:35 +00:00
if ( p_usb_serial_jtag_obj - > tx_ring_buf ) {
2021-04-23 07:46:02 +00:00
vRingbufferDelete ( p_usb_serial_jtag_obj - > tx_ring_buf ) ;
p_usb_serial_jtag_obj - > tx_ring_buf = NULL ;
}
heap_caps_free ( p_usb_serial_jtag_obj ) ;
p_usb_serial_jtag_obj = NULL ;
return ESP_OK ;
}