mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
Merge branch 'feature/esp32c3_usbjtag_console_blocking_v4.3' into 'release/v4.3'
usb_serial_jtag: Add blocking driver to support vfs (backport v4.3). See merge request espressif/esp-idf!17330
This commit is contained in:
@ -114,6 +114,21 @@ typedef struct {
|
||||
{ \
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
/**
|
||||
* @brief Parameters for console device: USB-SERIAL-JTAG
|
||||
*
|
||||
* @note It's an empty structure for now, reserved for future
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
} esp_console_dev_usb_serial_jtag_config_t;
|
||||
|
||||
#define ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT() {}
|
||||
|
||||
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
|
||||
/**
|
||||
* @brief initialize console module
|
||||
* @param config console configuration
|
||||
@ -339,6 +354,29 @@ esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_con
|
||||
*/
|
||||
esp_err_t esp_console_new_repl_usb_cdc(const esp_console_dev_usb_cdc_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
/**
|
||||
* @brief Establish a console REPL (Read-eval-print loop) environment over USB-SERIAL-JTAG
|
||||
*
|
||||
* @param[in] dev_config USB-SERIAL-JTAG configuration
|
||||
* @param[in] repl_config REPL configuration
|
||||
* @param[out] ret_repl return REPL handle after initialization succeed, return NULL otherwise
|
||||
*
|
||||
* @note This is a all-in-one function to establish the environment needed for REPL, includes:
|
||||
* - Initializes linenoise
|
||||
* - Spawn new thread to run REPL in the background
|
||||
*
|
||||
* @attention This function is meant to be used in the examples to make the code more compact.
|
||||
* Applications which use console functionality should be based on
|
||||
* the underlying linenoise and esp_console functions.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_jtag_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl);
|
||||
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
|
||||
/**
|
||||
* @brief Start REPL environment
|
||||
* @param[in] repl REPL handle returned from esp_console_new_repl_xxx
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include "esp_console.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "esp_vfs_cdcacm.h"
|
||||
#include "esp_vfs_usb_serial_jtag.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
|
||||
static const char *TAG = "console.repl";
|
||||
@ -54,6 +56,9 @@ typedef struct {
|
||||
static void esp_console_repl_task(void *args);
|
||||
static esp_err_t esp_console_repl_uart_delete(esp_console_repl_t *repl);
|
||||
static esp_err_t esp_console_repl_usb_cdc_delete(esp_console_repl_t *repl);
|
||||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *repl);
|
||||
#endif //CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
static esp_err_t esp_console_common_init(esp_console_repl_com_t *repl_com);
|
||||
static esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *repl_com);
|
||||
static esp_err_t esp_console_setup_history(const char *history_path, uint32_t max_history_len, esp_console_repl_com_t *repl_com);
|
||||
@ -122,6 +127,84 @@ _exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
esp_err_t esp_console_new_repl_usb_serial_jtag(const esp_console_dev_usb_serial_jtag_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)
|
||||
{
|
||||
esp_console_repl_universal_t *usb_serial_jtag_repl = NULL;
|
||||
if (!repl_config | !dev_config | !ret_repl) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
// allocate memory for console REPL context
|
||||
usb_serial_jtag_repl = calloc(1, sizeof(esp_console_repl_universal_t));
|
||||
if (!usb_serial_jtag_repl) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Disable buffering on stdin */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Enable non-blocking mode on stdin and stdout */
|
||||
fcntl(fileno(stdout), F_SETFL, 0);
|
||||
fcntl(fileno(stdin), F_SETFL, 0);
|
||||
|
||||
usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
|
||||
|
||||
/* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */
|
||||
ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
|
||||
if (ret != ESP_OK) {
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// initialize console, common part
|
||||
ret = esp_console_common_init(&usb_serial_jtag_repl->repl_com);
|
||||
if (ret != ESP_OK) {
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Tell vfs to use usb-serial-jtag driver */
|
||||
esp_vfs_usb_serial_jtag_use_driver();
|
||||
|
||||
// setup history
|
||||
ret = esp_console_setup_history(repl_config->history_save_path, repl_config->max_history_len, &usb_serial_jtag_repl->repl_com);
|
||||
if (ret != ESP_OK) {
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// setup prompt
|
||||
esp_console_setup_prompt(repl_config->prompt, &usb_serial_jtag_repl->repl_com);
|
||||
|
||||
/* spawn a single thread to run REPL */
|
||||
if (xTaskCreate(esp_console_repl_task, "console_repl", repl_config->task_stack_size,
|
||||
&usb_serial_jtag_repl->repl_com, repl_config->task_priority, &usb_serial_jtag_repl->repl_com.task_hdl) != pdTRUE) {
|
||||
ret = ESP_FAIL;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
usb_serial_jtag_repl->uart_channel = CONFIG_ESP_CONSOLE_UART_NUM;
|
||||
usb_serial_jtag_repl->repl_com.state = CONSOLE_REPL_STATE_INIT;
|
||||
usb_serial_jtag_repl->repl_com.repl_core.del = esp_console_repl_usb_serial_jtag_delete;
|
||||
*ret_repl = &usb_serial_jtag_repl->repl_com.repl_core;
|
||||
return ESP_OK;
|
||||
_exit:
|
||||
if (usb_serial_jtag_repl) {
|
||||
esp_console_deinit();
|
||||
free(usb_serial_jtag_repl);
|
||||
}
|
||||
if (ret_repl) {
|
||||
*ret_repl = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
|
||||
esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_config, const esp_console_repl_config_t *repl_config, esp_console_repl_t **ret_repl)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
@ -347,6 +430,28 @@ _exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
static esp_err_t esp_console_repl_usb_serial_jtag_delete(esp_console_repl_t *repl)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_console_repl_com_t *repl_com = __containerof(repl, esp_console_repl_com_t, repl_core);
|
||||
esp_console_repl_universal_t *usb_serial_jtag_repl = __containerof(repl_com, esp_console_repl_universal_t, repl_com);
|
||||
// check if already de-initialized
|
||||
if (repl_com->state == CONSOLE_REPL_STATE_DEINIT) {
|
||||
ESP_LOGE(TAG, "already de-initialized");
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
goto _exit;
|
||||
}
|
||||
repl_com->state = CONSOLE_REPL_STATE_DEINIT;
|
||||
esp_console_deinit();
|
||||
esp_vfs_usb_serial_jtag_use_nonblocking();
|
||||
usb_serial_jtag_driver_uninstall();
|
||||
free(usb_serial_jtag_repl);
|
||||
_exit:
|
||||
return ret;
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
|
||||
static void esp_console_repl_task(void *args)
|
||||
{
|
||||
esp_console_repl_universal_t *repl_conf = (esp_console_repl_universal_t *) args;
|
||||
|
@ -67,6 +67,7 @@ if(IDF_TARGET STREQUAL "esp32c3")
|
||||
list(APPEND srcs "gdma.c"
|
||||
"spi_slave_hd.c"
|
||||
"adc_common.c"
|
||||
"usb_serial_jtag.c"
|
||||
"esp32c3/adc.c"
|
||||
"esp32c3/adc2_init_cal.c"
|
||||
"esp32c3/rtc_tempsensor.c")
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Component Makefile
|
||||
#
|
||||
COMPONENT_SRCDIRS := . $(IDF_TARGET)
|
||||
COMPONENT_OBJEXCLUDE += spi_slave_hd.o dedic_gpio.o gdma.o
|
||||
COMPONENT_OBJEXCLUDE += spi_slave_hd.o dedic_gpio.o gdma.o usb_serial_jtag.o
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include $(IDF_TARGET)/include $(IDF_TARGET)/include/driver
|
||||
|
||||
|
93
components/driver/include/driver/usb_serial_jtag.h
Normal file
93
components/driver/include/driver/usb_serial_jtag.h
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for the usb-serial-jtag-driver. Can be expanded in the future
|
||||
*
|
||||
* @note tx_buffer_size and rx_buffer_size must be > 0
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t tx_buffer_size; /* Size of the buffer (in bytes) for the TX direction */
|
||||
uint32_t rx_buffer_size; /* Size of the buffer (in bytes) for the RX direction */
|
||||
} usb_serial_jtag_driver_config_t;
|
||||
|
||||
#define USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT() (usb_serial_jtag_driver_config_t) {\
|
||||
.rx_buffer_size = 256,\
|
||||
.tx_buffer_size = 256,\
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Install USB-SERIAL-JTAG driver and set the USB-SERIAL-JTAG to the default configuration.
|
||||
*
|
||||
* USB-SERIAL-JTAG driver's ISR will be attached to the same CPU core that calls this function. Thus, users
|
||||
* should ensure that the same core is used when calling `usb_serial_jtag_driver_uninstall()`.
|
||||
*
|
||||
* @note Blocking mode will result in usb_serial_jtag_write_bytes() blocking until all bytes have been written to the TX FIFO.
|
||||
*
|
||||
* @param usb_serial_jtag_driver_config_t Configuration for usb_serial_jtag driver.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Failed for some reason.
|
||||
*/
|
||||
esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_serial_jtag_config);
|
||||
|
||||
/**
|
||||
* @brief USB_SERIAL_JTAG read bytes from USB_SERIAL_JTAG buffer
|
||||
*
|
||||
* @param buf pointer to the buffer.
|
||||
* @param length data length
|
||||
* @param ticks_to_wait Timeout in RTOS ticks
|
||||
*
|
||||
* @return
|
||||
* - The number of bytes read from USB_SERIAL FIFO
|
||||
*/
|
||||
int usb_serial_jtag_read_bytes(void* buf, uint32_t length, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Send data to the USB-UART port from a given buffer and length,
|
||||
*
|
||||
* Please ensure the `tx_buffer_size is larger than 0`, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
|
||||
* USB_SERIAL_JTAG ISR will then move data from the ring buffer to TX FIFO gradually.
|
||||
*
|
||||
* @param src data buffer address
|
||||
* @param size data length to send
|
||||
* @param ticks_to_wait Timeout in RTOS ticks
|
||||
*
|
||||
* @return
|
||||
* - The number of bytes pushed to the TX FIFO
|
||||
*/
|
||||
int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Uninstall USB-SERIAL-JTAG driver.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t usb_serial_jtag_driver_uninstall(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
213
components/driver/usb_serial_jtag.c
Normal file
213
components/driver/usb_serial_jtag.c
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#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"
|
||||
|
||||
// The hardware buffer max size is 64
|
||||
#define USB_SER_JTAG_ENDP_SIZE (64)
|
||||
#define USB_SER_JTAG_RX_MAX_SIZE (64)
|
||||
|
||||
typedef struct{
|
||||
intr_handle_t intr_handle; /*!< USB-SERIAL-JTAG interrupt handler */
|
||||
|
||||
// RX parameters
|
||||
RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler */
|
||||
uint32_t rx_buf_size; /*!< TX buffer size */
|
||||
uint8_t rx_data_buf[64]; /*!< Data buffer to stash FIFO data */
|
||||
|
||||
// TX parameters
|
||||
uint32_t tx_buf_size; /*!< TX buffer size */
|
||||
RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler */
|
||||
} 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";
|
||||
|
||||
static void usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len)
|
||||
{
|
||||
usb_serial_jtag_ll_write_txfifo(buf, wr_len);
|
||||
usb_serial_jtag_ll_txfifo_flush();
|
||||
}
|
||||
|
||||
static void usb_serial_jtag_isr_handler_default(void *arg) {
|
||||
portBASE_TYPE xTaskWoken = 0;
|
||||
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) {
|
||||
// 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.
|
||||
// Send data in isr.
|
||||
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.
|
||||
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
size_t queued_size;
|
||||
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, 64);
|
||||
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
|
||||
if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called.
|
||||
//Copy the queued buffer into the TX FIFO
|
||||
usb_serial_jtag_ll_clr_intr_sts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
usb_serial_jtag_write_and_flush(queued_buff, queued_size);
|
||||
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 {
|
||||
usb_serial_jtag_ll_clr_intr_sts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
|
||||
// read rx buffer(max length is 64), and send avaliable data to ringbuffer.
|
||||
// Ensure the rx buffer size is larger than RX_MAX_SIZE.
|
||||
usb_serial_jtag_ll_clr_intr_sts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
|
||||
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;
|
||||
if (p_usb_serial_jtag_obj != NULL) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "Driver already installed");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (usb_serial_jtag_config->rx_buffer_size <= USB_SER_JTAG_RX_MAX_SIZE) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "RX buffer is not prepared or is perpared so small");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (usb_serial_jtag_config->tx_buffer_size <= 0) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "TX buffer is not prepared");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
if (p_usb_serial_jtag_obj == NULL) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "memory allocate error");
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
usb_serial_jtag_ll_clr_intr_sts_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|
|
||||
USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
|
||||
|
||||
err = esp_intr_alloc(ETS_USB_INTR_SOURCE, 0, usb_serial_jtag_isr_handler_default, NULL, &p_usb_serial_jtag_obj->intr_handle);
|
||||
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;
|
||||
}
|
||||
|
||||
// Recieve new data from ISR
|
||||
data = (uint8_t*) xRingbufferReceiveUpTo(p_usb_serial_jtag_obj->rx_ring_buf, &data_read_len, (portTickType) ticks_to_wait, length);
|
||||
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)
|
||||
{
|
||||
if (size == 0) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "size should be larger than 0");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (src == NULL) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "Invalid buffer pointer");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (p_usb_serial_jtag_obj == NULL) {
|
||||
ESP_LOGE(USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized");
|
||||
}
|
||||
|
||||
const uint8_t *buff = (const uint8_t *)src;
|
||||
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
|
||||
xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*) (buff), size, ticks_to_wait);
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
return size;
|
||||
}
|
||||
|
||||
esp_err_t usb_serial_jtag_driver_uninstall(void)
|
||||
{
|
||||
if(p_usb_serial_jtag_obj == NULL) {
|
||||
ESP_LOGI(USB_SERIAL_JTAG_TAG, "ALREADY NULL");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
if(p_usb_serial_jtag_obj->rx_ring_buf) {
|
||||
vRingbufferDelete(p_usb_serial_jtag_obj->rx_ring_buf);
|
||||
p_usb_serial_jtag_obj->rx_ring_buf = NULL;
|
||||
}
|
||||
if(p_usb_serial_jtag_obj->tx_ring_buf) {
|
||||
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;
|
||||
}
|
@ -37,7 +37,7 @@ typedef enum {
|
||||
USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1 = (1 << 8),
|
||||
USB_SERIAL_JTAG_INTR_BUS_RESET = (1 << 9),
|
||||
USB_SERIAL_JTAG_INTR_EP1_ZERO_PAYLOAD = (1 << 10),
|
||||
} usb_serial_jtag_intr_t;
|
||||
} usb_serial_jtag_ll_intr_t;
|
||||
|
||||
/**
|
||||
* @brief Enable the USB_SERIAL_JTAG interrupt based on the given mask.
|
||||
@ -51,6 +51,18 @@ static inline void usb_serial_jtag_ll_ena_intr_mask(uint32_t mask)
|
||||
USB_SERIAL_JTAG.int_ena.val |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the USB_SERIAL_JTAG interrupt based on the given mask.
|
||||
*
|
||||
* @param mask The bitmap of the interrupts bits need to be cleared.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void usb_serial_jtag_ll_clr_intr_sts_mask(uint32_t mask)
|
||||
{
|
||||
USB_SERIAL_JTAG.int_clr.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the USB_SERIAL_JTAG interrupt based on the given mask.
|
||||
*
|
||||
@ -156,6 +168,9 @@ static inline int usb_serial_jtag_ll_txfifo_writable(void)
|
||||
* @brief Flushes the TX buffer, that is, make it available for the
|
||||
* host to pick up.
|
||||
*
|
||||
* @note When fifo is full (with 64 byte), HW will flush the buffer automatically.
|
||||
* It won't be executed if there is nothing in the fifo.
|
||||
*
|
||||
* @return na
|
||||
*/
|
||||
static inline void usb_serial_jtag_ll_txfifo_flush(void)
|
||||
|
@ -114,6 +114,20 @@ void esp_vfs_dev_uart_use_nonblocking(int uart_num);
|
||||
*/
|
||||
void esp_vfs_dev_uart_use_driver(int uart_num);
|
||||
|
||||
/**
|
||||
* @brief set VFS to use USB-SERIAL-JTAG driver for reading and writing
|
||||
* @note application must configure USB-SERIAL-JTAG driver before calling these functions
|
||||
* With these functions, read and write are blocking and interrupt-driven.
|
||||
*/
|
||||
void esp_vfs_usb_serial_jtag_use_driver(void);
|
||||
|
||||
/**
|
||||
* @brief set VFS to use simple functions for reading and writing UART
|
||||
* Read is non-blocking, write is busy waiting until TX FIFO has enough space.
|
||||
* These functions are used by default.
|
||||
*/
|
||||
void esp_vfs_usb_serial_jtag_use_nonblocking(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -26,9 +26,12 @@
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
#include "esp_vfs_usb_serial_jtag.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
|
||||
// Token signifying that no character is available
|
||||
#define NONE -1
|
||||
@ -383,3 +386,43 @@ esp_err_t esp_vfs_dev_usb_serial_jtag_register(void)
|
||||
// "/dev/usb_serial_jtag" unfortunately is too long for vfs
|
||||
return esp_vfs_register("/dev/usbserjtag", &vfs, NULL);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* VFS uses USB-SERIAL-JTAG driver part.
|
||||
**********************************************************/
|
||||
|
||||
static int usbjtag_rx_char_via_driver(int fd)
|
||||
{
|
||||
uint8_t c;
|
||||
int n = usb_serial_jtag_read_bytes(&c, 1, portMAX_DELAY);
|
||||
if (n <= 0) {
|
||||
return NONE;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void usbjtag_tx_char_via_driver(int fd, int c)
|
||||
{
|
||||
char ch = (char) c;
|
||||
usb_serial_jtag_write_bytes(&ch, 1, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void esp_vfs_usb_serial_jtag_use_nonblocking(void)
|
||||
{
|
||||
_lock_acquire_recursive(&s_ctx.read_lock);
|
||||
_lock_acquire_recursive(&s_ctx.write_lock);
|
||||
s_ctx.tx_func = usb_serial_jtag_tx_char;
|
||||
s_ctx.rx_func = usb_serial_jtag_rx_char;
|
||||
_lock_release_recursive(&s_ctx.write_lock);
|
||||
_lock_release_recursive(&s_ctx.read_lock);
|
||||
}
|
||||
|
||||
void esp_vfs_usb_serial_jtag_use_driver(void)
|
||||
{
|
||||
_lock_acquire_recursive(&s_ctx.read_lock);
|
||||
_lock_acquire_recursive(&s_ctx.write_lock);
|
||||
s_ctx.tx_func = usbjtag_tx_char_via_driver;
|
||||
s_ctx.rx_func = usbjtag_rx_char_via_driver;
|
||||
_lock_release_recursive(&s_ctx.write_lock);
|
||||
_lock_release_recursive(&s_ctx.read_lock);
|
||||
}
|
||||
|
@ -56,6 +56,9 @@ void app_main(void)
|
||||
#elif CONFIG_ESP_CONSOLE_USB_CDC
|
||||
esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl));
|
||||
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl));
|
||||
#endif
|
||||
|
||||
register_i2ctools();
|
||||
|
@ -204,6 +204,9 @@ void app_main(void)
|
||||
#elif CONFIG_ESP_CONSOLE_USB_CDC
|
||||
esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &s_repl));
|
||||
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl));
|
||||
#endif
|
||||
|
||||
/* register command `ping` */
|
||||
|
@ -38,6 +38,9 @@ void app_main(void)
|
||||
#elif CONFIG_ESP_CONSOLE_USB_CDC
|
||||
esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl));
|
||||
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl));
|
||||
#endif
|
||||
|
||||
/* Register commands */
|
||||
|
@ -243,6 +243,9 @@ void app_main(void)
|
||||
#elif CONFIG_ESP_CONSOLE_USB_CDC
|
||||
esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl));
|
||||
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
|
||||
esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl));
|
||||
#endif
|
||||
|
||||
/* Register commands */
|
||||
|
Reference in New Issue
Block a user