mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(twai): support multiple twai controllers
Closes https://github.com/espressif/esp-idf/issues/11383
This commit is contained in:
parent
239bc3b96f
commit
2ae3d4d7c4
@ -124,77 +124,7 @@ menu "Driver Configurations"
|
||||
|
||||
endmenu # SPI Configuration
|
||||
|
||||
menu "TWAI Configuration"
|
||||
depends on SOC_TWAI_SUPPORTED
|
||||
|
||||
config TWAI_ISR_IN_IRAM
|
||||
bool "Place TWAI ISR function into IRAM"
|
||||
default n
|
||||
help
|
||||
Place the TWAI ISR in to IRAM. This will allow the ISR to avoid
|
||||
cache misses, and also be able to run whilst the cache is disabled
|
||||
(such as when writing to SPI Flash).
|
||||
Note that if this option is enabled:
|
||||
- Users should also set the ESP_INTR_FLAG_IRAM in the driver
|
||||
configuration structure when installing the driver (see docs for
|
||||
specifics).
|
||||
- Alert logging (i.e., setting of the TWAI_ALERT_AND_LOG flag)
|
||||
will have no effect.
|
||||
|
||||
config TWAI_ERRATA_FIX_BUS_OFF_REC
|
||||
bool "Add SW workaround for REC change during bus-off"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
When the bus-off condition is reached, the REC should be reset to 0 and frozen (via LOM) by the
|
||||
driver's ISR. However on the ESP32, there is an edge case where the REC will increase before the
|
||||
driver's ISR can respond in time (e.g., due to the rapid occurrence of bus errors), thus causing the
|
||||
REC to be non-zero after bus-off. A non-zero REC can prevent bus-off recovery as the bus-off recovery
|
||||
condition is that both TEC and REC become 0. Enabling this option will add a workaround in the driver
|
||||
to forcibly reset REC to zero on reaching bus-off.
|
||||
|
||||
config TWAI_ERRATA_FIX_TX_INTR_LOST
|
||||
bool "Add SW workaround for TX interrupt lost errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when a transmit interrupt occurs, and interrupt register is read on the same APB clock
|
||||
cycle, the transmit interrupt could be lost. Enabling this option will add a workaround that checks the
|
||||
transmit buffer status bit to recover any lost transmit interrupt.
|
||||
|
||||
config TWAI_ERRATA_FIX_RX_FRAME_INVALID
|
||||
bool "Add SW workaround for invalid RX frame errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when receiving a data or remote frame, if a bus error occurs in the data or CRC field,
|
||||
the data of the next received frame could be invalid. Enabling this option will add a workaround that
|
||||
will reset the peripheral on detection of this errata condition. Note that if a frame is transmitted on
|
||||
the bus whilst the reset is ongoing, the message will not be receive by the peripheral sent on the bus
|
||||
during the reset, the message will be lost.
|
||||
|
||||
config TWAI_ERRATA_FIX_RX_FIFO_CORRUPT
|
||||
bool "Add SW workaround for RX FIFO corruption errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when the RX FIFO overruns and the RX message counter maxes out at 64 messages, the entire
|
||||
RX FIFO is no longer recoverable. Enabling this option will add a workaround that resets the peripheral
|
||||
on detection of this errata condition. Note that if a frame is being sent on the bus during the reset
|
||||
bus during the reset, the message will be lost.
|
||||
|
||||
config TWAI_ERRATA_FIX_LISTEN_ONLY_DOM
|
||||
bool "Add SW workaround for listen only transmits dominant bit errata"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
default y
|
||||
help
|
||||
When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send
|
||||
any dominant bits). However, while in listen only mode on the ESP32/ESP32-S2/ESP32-S3/ESP32-C3, the
|
||||
TWAI controller will still transmit dominant bits when it detects an error (i.e., as part of an active
|
||||
error frame). Enabling this option will add a workaround that forces the TWAI controller into an error
|
||||
passive state on initialization, thus preventing any dominant bits from being sent.
|
||||
|
||||
endmenu # TWAI Configuration
|
||||
orsource "./twai/Kconfig.twai"
|
||||
|
||||
menu "Temperature sensor Configuration"
|
||||
depends on SOC_TEMP_SENSOR_SUPPORTED
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -86,14 +86,11 @@ TEST_CASE("twai_mode_std_no_ack_25kbps", "[twai-loop-back]")
|
||||
|
||||
TEST_CASE("twai_mode_ext_no_ack_250kbps", "[twai-loop-back]")
|
||||
{
|
||||
twai_handle_t twai_buses[SOC_TWAI_CONTROLLER_NUM] = {0};
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
|
||||
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
// bind the TX and RX to the same GPIO to act like a loopback
|
||||
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(0, 0, TWAI_MODE_NO_ACK);
|
||||
printf("install twai driver\r\n");
|
||||
TEST_ESP_OK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
TEST_ESP_OK(twai_start());
|
||||
|
||||
twai_message_t tx_msg = {
|
||||
.identifier = 0x12345,
|
||||
.data_length_code = 6,
|
||||
@ -101,17 +98,33 @@ TEST_CASE("twai_mode_ext_no_ack_250kbps", "[twai-loop-back]")
|
||||
.self = true, // Transmitted message will also received by the same node
|
||||
.extd = true, // Extended Frame Format (29bit ID)
|
||||
};
|
||||
|
||||
printf("install twai driver\r\n");
|
||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
g_config.controller_id = i;
|
||||
g_config.tx_io = i;
|
||||
g_config.rx_io = i;
|
||||
TEST_ESP_OK(twai_driver_install_v2(&g_config, &t_config, &f_config, &twai_buses[i]));
|
||||
TEST_ESP_OK(twai_start_v2(twai_buses[i]));
|
||||
}
|
||||
|
||||
printf("transmit message\r\n");
|
||||
TEST_ESP_OK(twai_transmit(&tx_msg, pdMS_TO_TICKS(1000)));
|
||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
TEST_ESP_OK(twai_transmit_v2(twai_buses[i], &tx_msg, pdMS_TO_TICKS(1000)));
|
||||
}
|
||||
|
||||
printf("receive message\r\n");
|
||||
twai_message_t rx_msg;
|
||||
TEST_ESP_OK(twai_receive(&rx_msg, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_TRUE(rx_msg.data_length_code == 6);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
TEST_ASSERT_EQUAL(tx_msg.data[i], rx_msg.data[i]);
|
||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
TEST_ESP_OK(twai_receive_v2(twai_buses[i], &rx_msg, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_TRUE(rx_msg.data_length_code == 6);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
TEST_ASSERT_EQUAL(tx_msg.data[i], rx_msg.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ESP_OK(twai_stop());
|
||||
TEST_ESP_OK(twai_driver_uninstall());
|
||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||
TEST_ESP_OK(twai_stop_v2(twai_buses[i]));
|
||||
TEST_ESP_OK(twai_driver_uninstall_v2(twai_buses[i]));
|
||||
}
|
||||
}
|
||||
|
71
components/driver/twai/Kconfig.twai
Normal file
71
components/driver/twai/Kconfig.twai
Normal file
@ -0,0 +1,71 @@
|
||||
menu "TWAI Configuration"
|
||||
depends on SOC_TWAI_SUPPORTED
|
||||
|
||||
config TWAI_ISR_IN_IRAM
|
||||
bool "Place TWAI ISR function into IRAM"
|
||||
default n
|
||||
help
|
||||
Place the TWAI ISR in to IRAM. This will allow the ISR to avoid
|
||||
cache misses, and also be able to run whilst the cache is disabled
|
||||
(such as when writing to SPI Flash).
|
||||
Note that if this option is enabled:
|
||||
- Users should also set the ESP_INTR_FLAG_IRAM in the driver
|
||||
configuration structure when installing the driver (see docs for
|
||||
specifics).
|
||||
- Alert logging (i.e., setting of the TWAI_ALERT_AND_LOG flag)
|
||||
will have no effect.
|
||||
|
||||
config TWAI_ERRATA_FIX_BUS_OFF_REC
|
||||
bool "Add SW workaround for REC change during bus-off"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
When the bus-off condition is reached, the REC should be reset to 0 and frozen (via LOM) by the
|
||||
driver's ISR. However on the ESP32, there is an edge case where the REC will increase before the
|
||||
driver's ISR can respond in time (e.g., due to the rapid occurrence of bus errors), thus causing the
|
||||
REC to be non-zero after bus-off. A non-zero REC can prevent bus-off recovery as the bus-off recovery
|
||||
condition is that both TEC and REC become 0. Enabling this option will add a workaround in the driver
|
||||
to forcibly reset REC to zero on reaching bus-off.
|
||||
|
||||
config TWAI_ERRATA_FIX_TX_INTR_LOST
|
||||
bool "Add SW workaround for TX interrupt lost errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when a transmit interrupt occurs, and interrupt register is read on the same APB clock
|
||||
cycle, the transmit interrupt could be lost. Enabling this option will add a workaround that checks the
|
||||
transmit buffer status bit to recover any lost transmit interrupt.
|
||||
|
||||
config TWAI_ERRATA_FIX_RX_FRAME_INVALID
|
||||
bool "Add SW workaround for invalid RX frame errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when receiving a data or remote frame, if a bus error occurs in the data or CRC field,
|
||||
the data of the next received frame could be invalid. Enabling this option will add a workaround that
|
||||
will reset the peripheral on detection of this errata condition. Note that if a frame is transmitted on
|
||||
the bus whilst the reset is ongoing, the message will not be receive by the peripheral sent on the bus
|
||||
during the reset, the message will be lost.
|
||||
|
||||
config TWAI_ERRATA_FIX_RX_FIFO_CORRUPT
|
||||
bool "Add SW workaround for RX FIFO corruption errata"
|
||||
depends on IDF_TARGET_ESP32
|
||||
default y
|
||||
help
|
||||
On the ESP32, when the RX FIFO overruns and the RX message counter maxes out at 64 messages, the entire
|
||||
RX FIFO is no longer recoverable. Enabling this option will add a workaround that resets the peripheral
|
||||
on detection of this errata condition. Note that if a frame is being sent on the bus during the reset
|
||||
bus during the reset, the message will be lost.
|
||||
|
||||
config TWAI_ERRATA_FIX_LISTEN_ONLY_DOM
|
||||
bool "Add SW workaround for listen only transmits dominant bit errata"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
default y
|
||||
help
|
||||
When in the listen only mode, the TWAI controller must not influence the TWAI bus (i.e., must not send
|
||||
any dominant bits). However, while in listen only mode on the ESP32/ESP32-S2/ESP32-S3/ESP32-C3, the
|
||||
TWAI controller will still transmit dominant bits when it detects an error (i.e., as part of an active
|
||||
error frame). Enabling this option will add a workaround that forces the TWAI controller into an error
|
||||
passive state on initialization, thus preventing any dominant bits from being sent.
|
||||
|
||||
endmenu # TWAI Configuration
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -69,6 +69,11 @@ extern "C" {
|
||||
|
||||
/* ----------------------- Enum and Struct Definitions ---------------------- */
|
||||
|
||||
/**
|
||||
* @brief TWAI controller handle
|
||||
*/
|
||||
typedef struct twai_obj_t *twai_handle_t;
|
||||
|
||||
/**
|
||||
* @brief TWAI driver states
|
||||
*/
|
||||
@ -85,6 +90,8 @@ typedef enum {
|
||||
* @note Macro initializers are available for this structure
|
||||
*/
|
||||
typedef struct {
|
||||
int controller_id; /**< TWAI controller ID, index from 0.
|
||||
If you want to install TWAI driver with a non-zero controller_id, please use `twai_driver_install_v2` */
|
||||
twai_mode_t mode; /**< Mode of TWAI controller */
|
||||
gpio_num_t tx_io; /**< Transmit GPIO number */
|
||||
gpio_num_t rx_io; /**< Receive GPIO number */
|
||||
@ -138,6 +145,26 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config);
|
||||
|
||||
/**
|
||||
* @brief Install TWAI driver and return a handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_driver_install` that can return a driver handle, so that it allows you to install multiple TWAI drivers.
|
||||
* Don't forget to set the proper controller_id in the `twai_general_config_t`
|
||||
* Please refer to the documentation of `twai_driver_install` for more details.
|
||||
*
|
||||
* @param[in] g_config General configuration structure
|
||||
* @param[in] t_config Timing configuration structure
|
||||
* @param[in] f_config Filter configuration structure
|
||||
* @param[out] ret_twai Pointer to a new created TWAI handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Successfully installed TWAI driver
|
||||
* - ESP_ERR_INVALID_ARG: Arguments are invalid, e.g. invalid clock source, invalid quanta resolution, invalid controller ID
|
||||
* - ESP_ERR_NO_MEM: Insufficient memory
|
||||
* - ESP_ERR_INVALID_STATE: Driver is already installed
|
||||
*/
|
||||
esp_err_t twai_driver_install_v2(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, twai_handle_t *ret_twai);
|
||||
|
||||
/**
|
||||
* @brief Uninstall the TWAI driver
|
||||
*
|
||||
@ -154,6 +181,20 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
||||
*/
|
||||
esp_err_t twai_driver_uninstall(void);
|
||||
|
||||
/**
|
||||
* @brief Uninstall the TWAI driver with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_driver_uninstall` that can uninstall a TWAI driver with a given handle.
|
||||
* Please refer to the documentation of `twai_driver_uninstall` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Successfully uninstalled TWAI driver
|
||||
* - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed
|
||||
*/
|
||||
esp_err_t twai_driver_uninstall_v2(twai_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Start the TWAI driver
|
||||
*
|
||||
@ -169,6 +210,20 @@ esp_err_t twai_driver_uninstall(void);
|
||||
*/
|
||||
esp_err_t twai_start(void);
|
||||
|
||||
/**
|
||||
* @brief Start the TWAI driver with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_start` that can start a TWAI driver with a given handle.
|
||||
* Please refer to the documentation of `twai_start` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: TWAI driver is now running
|
||||
* - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed
|
||||
*/
|
||||
esp_err_t twai_start_v2(twai_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Stop the TWAI driver
|
||||
*
|
||||
@ -188,6 +243,20 @@ esp_err_t twai_start(void);
|
||||
*/
|
||||
esp_err_t twai_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Stop the TWAI driver with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_stop` that can stop a TWAI driver with a given handle.
|
||||
* Please refer to the documentation of `twai_stop` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: TWAI driver is now Stopped
|
||||
* - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed
|
||||
*/
|
||||
esp_err_t twai_stop_v2(twai_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Transmit a TWAI message
|
||||
*
|
||||
@ -219,6 +288,26 @@ esp_err_t twai_stop(void);
|
||||
*/
|
||||
esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Transmit a TWAI message via a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_transmit` that can transmit a TWAI message with a given handle.
|
||||
* Please refer to the documentation of `twai_transmit` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
* @param[in] message Message to transmit
|
||||
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block on the TX queue
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Transmission successfully queued/initiated
|
||||
* - ESP_ERR_INVALID_ARG: Arguments are invalid
|
||||
* - ESP_ERR_TIMEOUT: Timed out waiting for space on TX queue
|
||||
* - ESP_FAIL: TX queue is disabled and another message is currently transmitting
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not in running state, or is not installed
|
||||
* - ESP_ERR_NOT_SUPPORTED: Listen Only Mode does not support transmissions
|
||||
*/
|
||||
esp_err_t twai_transmit_v2(twai_handle_t handle, const twai_message_t *message, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Receive a TWAI message
|
||||
*
|
||||
@ -240,6 +329,24 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
*/
|
||||
esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Receive a TWAI message via a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_receive` that can receive a TWAI message with a given handle.
|
||||
* Please refer to the documentation of `twai_receive` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
* @param[out] message Received message
|
||||
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block on RX queue
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Message successfully received from RX queue
|
||||
* - ESP_ERR_TIMEOUT: Timed out waiting for message
|
||||
* - ESP_ERR_INVALID_ARG: Arguments are invalid
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
|
||||
*/
|
||||
esp_err_t twai_receive_v2(twai_handle_t handle, twai_message_t *message, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Read TWAI driver alerts
|
||||
*
|
||||
@ -261,6 +368,24 @@ esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait);
|
||||
*/
|
||||
esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Read TWAI driver alerts with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_read_alerts` that can read TWAI driver alerts with a given handle.
|
||||
* Please refer to the documentation of `twai_read_alerts` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
* @param[out] alerts Bit field of raised alerts (see documentation for alert flags)
|
||||
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block for alert
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Alerts read
|
||||
* - ESP_ERR_TIMEOUT: Timed out waiting for alerts
|
||||
* - ESP_ERR_INVALID_ARG: Arguments are invalid
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
|
||||
*/
|
||||
esp_err_t twai_read_alerts_v2(twai_handle_t handle, uint32_t *alerts, TickType_t ticks_to_wait);
|
||||
|
||||
/**
|
||||
* @brief Reconfigure which alerts are enabled
|
||||
*
|
||||
@ -277,6 +402,22 @@ esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait);
|
||||
*/
|
||||
esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts);
|
||||
|
||||
/**
|
||||
* @brief Reconfigure which alerts are enabled, with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_reconfigure_alerts` that can reconfigure which alerts are enabled with a given handle.
|
||||
* Please refer to the documentation of `twai_reconfigure_alerts` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
* @param[in] alerts_enabled Bit field of alerts to enable (see documentation for alert flags)
|
||||
* @param[out] current_alerts Bit field of currently raised alerts. Set to NULL if unused
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Alerts reconfigured
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
|
||||
*/
|
||||
esp_err_t twai_reconfigure_alerts_v2(twai_handle_t handle, uint32_t alerts_enabled, uint32_t *current_alerts);
|
||||
|
||||
/**
|
||||
* @brief Start the bus recovery process
|
||||
*
|
||||
@ -295,6 +436,20 @@ esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_ale
|
||||
*/
|
||||
esp_err_t twai_initiate_recovery(void);
|
||||
|
||||
/**
|
||||
* @brief Start the bus recovery process with a given handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_initiate_recovery` that can start the bus recovery process with a given handle.
|
||||
* Please refer to the documentation of `twai_initiate_recovery` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Bus recovery started
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed
|
||||
*/
|
||||
esp_err_t twai_initiate_recovery_v2(twai_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get current status information of the TWAI driver
|
||||
*
|
||||
@ -307,6 +462,22 @@ esp_err_t twai_initiate_recovery(void);
|
||||
*/
|
||||
esp_err_t twai_get_status_info(twai_status_info_t *status_info);
|
||||
|
||||
/**
|
||||
* @brief Get current status information of a given TWAI driver handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_get_status_info` that can get current status information of a given TWAI driver handle.
|
||||
* Please refer to the documentation of `twai_get_status_info` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
* @param[out] status_info Status information
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Status information retrieved
|
||||
* - ESP_ERR_INVALID_ARG: Arguments are invalid
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
|
||||
*/
|
||||
esp_err_t twai_get_status_info_v2(twai_handle_t handle, twai_status_info_t *status_info);
|
||||
|
||||
/**
|
||||
* @brief Clear the transmit queue
|
||||
*
|
||||
@ -321,6 +492,20 @@ esp_err_t twai_get_status_info(twai_status_info_t *status_info);
|
||||
*/
|
||||
esp_err_t twai_clear_transmit_queue(void);
|
||||
|
||||
/**
|
||||
* @brief Clear the transmit queue of a given TWAI driver handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_clear_transmit_queue` that can clear the transmit queue of a given TWAI driver handle.
|
||||
* Please refer to the documentation of `twai_clear_transmit_queue` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Transmit queue cleared
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed or TX queue is disabled
|
||||
*/
|
||||
esp_err_t twai_clear_transmit_queue_v2(twai_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Clear the receive queue
|
||||
*
|
||||
@ -335,6 +520,20 @@ esp_err_t twai_clear_transmit_queue(void);
|
||||
*/
|
||||
esp_err_t twai_clear_receive_queue(void);
|
||||
|
||||
/**
|
||||
* @brief Clear the receive queue of a given TWAI driver handle
|
||||
*
|
||||
* @note This is an advanced version of `twai_clear_receive_queue` that can clear the receive queue of a given TWAI driver handle.
|
||||
* Please refer to the documentation of `twai_clear_receive_queue` for more details.
|
||||
*
|
||||
* @param[in] handle TWAI driver handle returned by `twai_driver_install_v2`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Transmit queue cleared
|
||||
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
|
||||
*/
|
||||
esp_err_t twai_clear_receive_queue_v2(twai_handle_t handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -36,14 +36,10 @@
|
||||
return (ret_val); \
|
||||
} \
|
||||
})
|
||||
#define TWAI_CHECK_FROM_CRIT(cond, ret_val) ({ \
|
||||
if (!(cond)) { \
|
||||
TWAI_EXIT_CRITICAL(); \
|
||||
return ret_val; \
|
||||
} \
|
||||
})
|
||||
|
||||
#define TWAI_SET_FLAG(var, mask) ((var) |= (mask))
|
||||
#define TWAI_RESET_FLAG(var, mask) ((var) &= ~(mask))
|
||||
|
||||
#ifdef CONFIG_TWAI_ISR_IN_IRAM
|
||||
#define TWAI_MALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
@ -65,8 +61,9 @@
|
||||
/* ------------------ Typedefs, structures, and variables ------------------- */
|
||||
|
||||
//Control structure for TWAI driver
|
||||
typedef struct {
|
||||
typedef struct twai_obj_t {
|
||||
int controller_id;
|
||||
twai_hal_context_t hal; // hal context
|
||||
//Control and status members
|
||||
twai_state_t state;
|
||||
twai_mode_t mode;
|
||||
@ -87,20 +84,15 @@ typedef struct {
|
||||
uint32_t alerts_triggered;
|
||||
//Power Management Lock
|
||||
esp_pm_lock_handle_t pm_lock;
|
||||
portMUX_TYPE spinlock;
|
||||
} twai_obj_t;
|
||||
|
||||
static twai_obj_t *p_twai_obj = NULL;
|
||||
static portMUX_TYPE twai_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define TWAI_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&twai_spinlock)
|
||||
#define TWAI_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&twai_spinlock)
|
||||
#define TWAI_ENTER_CRITICAL() portENTER_CRITICAL(&twai_spinlock)
|
||||
#define TWAI_EXIT_CRITICAL() portEXIT_CRITICAL(&twai_spinlock)
|
||||
|
||||
static twai_hal_context_t twai_context;
|
||||
static twai_handle_t g_twai_objs[SOC_TWAI_CONTROLLER_NUM];
|
||||
static portMUX_TYPE g_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
/* -------------------- Interrupt and Alert Handlers ------------------------ */
|
||||
|
||||
static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
||||
static void twai_alert_handler(twai_obj_t *p_twai_obj, uint32_t alert_code, int *alert_req)
|
||||
{
|
||||
if (p_twai_obj->alerts_enabled & alert_code) {
|
||||
//Signify alert has occurred
|
||||
@ -120,41 +112,41 @@ static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void twai_handle_rx_buffer_frames(BaseType_t *task_woken, int *alert_req)
|
||||
static inline void twai_handle_rx_buffer_frames(twai_obj_t *p_twai_obj, BaseType_t *task_woken, int *alert_req)
|
||||
{
|
||||
#ifdef SOC_TWAI_SUPPORTS_RX_STATUS
|
||||
uint32_t msg_count = twai_hal_get_rx_msg_count(&twai_context);
|
||||
uint32_t msg_count = twai_hal_get_rx_msg_count(&p_twai_obj->hal);
|
||||
|
||||
for (uint32_t i = 0; i < msg_count; i++) {
|
||||
twai_hal_frame_t frame;
|
||||
if (twai_hal_read_rx_buffer_and_clear(&twai_context, &frame)) {
|
||||
if (twai_hal_read_rx_buffer_and_clear(&p_twai_obj->hal, &frame)) {
|
||||
//Valid frame copied from RX buffer
|
||||
if (xQueueSendFromISR(p_twai_obj->rx_queue, &frame, task_woken) == pdTRUE) {
|
||||
p_twai_obj->rx_msg_count++;
|
||||
twai_alert_handler(TWAI_ALERT_RX_DATA, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_DATA, alert_req);
|
||||
} else { //Failed to send to queue
|
||||
p_twai_obj->rx_missed_count++;
|
||||
twai_alert_handler(TWAI_ALERT_RX_QUEUE_FULL, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_QUEUE_FULL, alert_req);
|
||||
}
|
||||
} else { //Failed to read from RX buffer because message is overrun
|
||||
p_twai_obj->rx_overrun_count++;
|
||||
twai_alert_handler(TWAI_ALERT_RX_FIFO_OVERRUN, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_FIFO_OVERRUN, alert_req);
|
||||
}
|
||||
}
|
||||
#else //SOC_TWAI_SUPPORTS_RX_STATUS
|
||||
uint32_t msg_count = twai_hal_get_rx_msg_count(&twai_context);
|
||||
uint32_t msg_count = twai_hal_get_rx_msg_count(&p_twai_obj->hal);
|
||||
bool overrun = false;
|
||||
//Clear all valid RX frames
|
||||
for (int i = 0; i < msg_count; i++) {
|
||||
twai_hal_frame_t frame;
|
||||
if (twai_hal_read_rx_buffer_and_clear(&twai_context, &frame)) {
|
||||
if (twai_hal_read_rx_buffer_and_clear(&p_twai_obj->hal, &frame)) {
|
||||
//Valid frame copied from RX buffer
|
||||
if (xQueueSendFromISR(p_twai_obj->rx_queue, &frame, task_woken) == pdTRUE) {
|
||||
p_twai_obj->rx_msg_count++;
|
||||
twai_alert_handler(TWAI_ALERT_RX_DATA, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_DATA, alert_req);
|
||||
} else {
|
||||
p_twai_obj->rx_missed_count++;
|
||||
twai_alert_handler(TWAI_ALERT_RX_QUEUE_FULL, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_QUEUE_FULL, alert_req);
|
||||
}
|
||||
} else {
|
||||
overrun = true;
|
||||
@ -163,20 +155,20 @@ static inline void twai_handle_rx_buffer_frames(BaseType_t *task_woken, int *ale
|
||||
}
|
||||
//All remaining frames are treated as overrun. Clear them all
|
||||
if (overrun) {
|
||||
p_twai_obj->rx_overrun_count += twai_hal_clear_rx_fifo_overrun(&twai_context);
|
||||
twai_alert_handler(TWAI_ALERT_RX_FIFO_OVERRUN, alert_req);
|
||||
p_twai_obj->rx_overrun_count += twai_hal_clear_rx_fifo_overrun(&p_twai_obj->hal);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RX_FIFO_OVERRUN, alert_req);
|
||||
}
|
||||
#endif //SOC_TWAI_SUPPORTS_RX_STATUS
|
||||
}
|
||||
|
||||
static inline void twai_handle_tx_buffer_frame(BaseType_t *task_woken, int *alert_req)
|
||||
static inline void twai_handle_tx_buffer_frame(twai_obj_t *p_twai_obj, BaseType_t *task_woken, int *alert_req)
|
||||
{
|
||||
//Handle previously transmitted frame
|
||||
if (twai_hal_check_last_tx_successful(&twai_context)) {
|
||||
twai_alert_handler(TWAI_ALERT_TX_SUCCESS, alert_req);
|
||||
if (twai_hal_check_last_tx_successful(&p_twai_obj->hal)) {
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_TX_SUCCESS, alert_req);
|
||||
} else {
|
||||
p_twai_obj->tx_failed_count++;
|
||||
twai_alert_handler(TWAI_ALERT_TX_FAILED, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_TX_FAILED, alert_req);
|
||||
}
|
||||
|
||||
//Update TX message count
|
||||
@ -188,86 +180,83 @@ static inline void twai_handle_tx_buffer_frame(BaseType_t *task_woken, int *aler
|
||||
twai_hal_frame_t frame;
|
||||
int res = xQueueReceiveFromISR(p_twai_obj->tx_queue, &frame, task_woken);
|
||||
if (res == pdTRUE) {
|
||||
twai_hal_set_tx_buffer_and_transmit(&twai_context, &frame);
|
||||
twai_hal_set_tx_buffer_and_transmit(&p_twai_obj->hal, &frame);
|
||||
} else {
|
||||
assert(false && "failed to get a frame from TX queue");
|
||||
}
|
||||
} else {
|
||||
//No more frames to transmit
|
||||
twai_alert_handler(TWAI_ALERT_TX_IDLE, alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_TX_IDLE, alert_req);
|
||||
}
|
||||
}
|
||||
|
||||
static void twai_intr_handler_main(void *arg)
|
||||
{
|
||||
twai_obj_t *p_twai_obj = (twai_obj_t *)arg;
|
||||
BaseType_t task_woken = pdFALSE;
|
||||
int alert_req = 0;
|
||||
uint32_t events;
|
||||
TWAI_ENTER_CRITICAL_ISR();
|
||||
if (p_twai_obj == NULL) { //In case intr occurs whilst driver is being uninstalled
|
||||
TWAI_EXIT_CRITICAL_ISR();
|
||||
return;
|
||||
}
|
||||
events = twai_hal_get_events(&twai_context); //Get the events that triggered the interrupt
|
||||
portENTER_CRITICAL_ISR(&p_twai_obj->spinlock);
|
||||
events = twai_hal_get_events(&p_twai_obj->hal); //Get the events that triggered the interrupt
|
||||
|
||||
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
|
||||
if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) {
|
||||
twai_hal_prepare_for_reset(&twai_context);
|
||||
twai_hal_prepare_for_reset(&p_twai_obj->hal);
|
||||
TWAI_RCC_ATOMIC() {
|
||||
twai_ll_reset_register(p_twai_obj->controller_id);
|
||||
}
|
||||
twai_hal_recover_from_reset(&twai_context);
|
||||
p_twai_obj->rx_missed_count += twai_hal_get_reset_lost_rx_cnt(&twai_context);
|
||||
twai_alert_handler(TWAI_ALERT_PERIPH_RESET, &alert_req);
|
||||
twai_hal_recover_from_reset(&p_twai_obj->hal);
|
||||
p_twai_obj->rx_missed_count += twai_hal_get_reset_lost_rx_cnt(&p_twai_obj->hal);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_PERIPH_RESET, &alert_req);
|
||||
}
|
||||
#endif
|
||||
if (events & TWAI_HAL_EVENT_RX_BUFF_FRAME) {
|
||||
//Note: This event will never occur if there is a periph reset event
|
||||
twai_handle_rx_buffer_frames(&task_woken, &alert_req);
|
||||
twai_handle_rx_buffer_frames(p_twai_obj, &task_woken, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) {
|
||||
twai_handle_tx_buffer_frame(&task_woken, &alert_req);
|
||||
twai_handle_tx_buffer_frame(p_twai_obj, &task_woken, &alert_req);
|
||||
}
|
||||
|
||||
//Handle events that only require alerting (i.e. no handler)
|
||||
if (events & TWAI_HAL_EVENT_BUS_OFF) {
|
||||
p_twai_obj->state = TWAI_STATE_BUS_OFF;
|
||||
twai_alert_handler(TWAI_ALERT_BUS_OFF, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_BUS_OFF, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_BUS_RECOV_CPLT) {
|
||||
p_twai_obj->state = TWAI_STATE_STOPPED;
|
||||
twai_alert_handler(TWAI_ALERT_BUS_RECOVERED, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_BUS_RECOVERED, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_BUS_ERR) {
|
||||
p_twai_obj->bus_error_count++;
|
||||
twai_alert_handler(TWAI_ALERT_BUS_ERROR, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_BUS_ERROR, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_ARB_LOST) {
|
||||
p_twai_obj->arb_lost_count++;
|
||||
twai_alert_handler(TWAI_ALERT_ARB_LOST, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_ARB_LOST, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_BUS_RECOV_PROGRESS) {
|
||||
//Bus-recovery in progress. TEC has dropped below error warning limit
|
||||
twai_alert_handler(TWAI_ALERT_RECOVERY_IN_PROGRESS, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_RECOVERY_IN_PROGRESS, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_ERROR_PASSIVE) {
|
||||
//Entered error passive
|
||||
twai_alert_handler(TWAI_ALERT_ERR_PASS, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_ERR_PASS, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_ERROR_ACTIVE) {
|
||||
//Returned to error active
|
||||
twai_alert_handler(TWAI_ALERT_ERR_ACTIVE, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_ERR_ACTIVE, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_ABOVE_EWL) {
|
||||
//TEC or REC surpassed error warning limit
|
||||
twai_alert_handler(TWAI_ALERT_ABOVE_ERR_WARN, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_ABOVE_ERR_WARN, &alert_req);
|
||||
}
|
||||
if (events & TWAI_HAL_EVENT_BELOW_EWL) {
|
||||
//TEC and REC are both below error warning
|
||||
twai_alert_handler(TWAI_ALERT_BELOW_ERR_WARN, &alert_req);
|
||||
twai_alert_handler(p_twai_obj, TWAI_ALERT_BELOW_ERR_WARN, &alert_req);
|
||||
}
|
||||
|
||||
TWAI_EXIT_CRITICAL_ISR();
|
||||
portEXIT_CRITICAL_ISR(&p_twai_obj->spinlock);
|
||||
|
||||
if (p_twai_obj->alert_semphr != NULL && alert_req) {
|
||||
//Give semaphore if alerts were triggered
|
||||
@ -280,11 +269,10 @@ static void twai_intr_handler_main(void *arg)
|
||||
|
||||
/* -------------------------- Helper functions ----------------------------- */
|
||||
|
||||
static void twai_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout, gpio_num_t bus_status)
|
||||
static void twai_configure_gpio(int controller_id, gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout, gpio_num_t bus_status)
|
||||
{
|
||||
// assert the GPIO number is not a negative number (shift operation on a negative number is undefined)
|
||||
assert(tx >= 0 && rx >= 0);
|
||||
int controller_id = p_twai_obj->controller_id;
|
||||
// if TX and RX set to the same GPIO, which means we want to create a loop-back in the GPIO matrix
|
||||
bool io_loop_back = (tx == rx);
|
||||
gpio_config_t gpio_conf = {
|
||||
@ -366,7 +354,7 @@ static esp_err_t twai_alloc_driver_obj(const twai_general_config_t *g_config, tw
|
||||
ret = esp_intr_alloc(twai_controller_periph_signals.controllers[controller_id].irq_id,
|
||||
g_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED,
|
||||
twai_intr_handler_main,
|
||||
NULL,
|
||||
p_obj,
|
||||
&p_obj->isr_handle);
|
||||
if (ret != ESP_OK) {
|
||||
goto err;
|
||||
@ -399,22 +387,21 @@ err:
|
||||
}
|
||||
|
||||
/* ---------------------------- Public Functions ---------------------------- */
|
||||
|
||||
esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config)
|
||||
esp_err_t twai_driver_install_v2(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, twai_handle_t *ret_twai)
|
||||
{
|
||||
//Check arguments
|
||||
TWAI_CHECK(g_config != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(t_config != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(f_config != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(g_config->controller_id < SOC_TWAI_CONTROLLER_NUM, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(g_config->rx_queue_len > 0, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(g_config->tx_io), ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(GPIO_IS_VALID_GPIO(g_config->rx_io), ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_TWAI_ISR_IN_IRAM
|
||||
TWAI_CHECK(!(g_config->intr_flags & ESP_INTR_FLAG_IRAM), ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
TWAI_ENTER_CRITICAL();
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj == NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_EXIT_CRITICAL();
|
||||
int controller_id = g_config->controller_id;
|
||||
TWAI_CHECK(g_twai_objs[controller_id] == NULL, ESP_ERR_INVALID_STATE);
|
||||
|
||||
//Get clock source resolution
|
||||
uint32_t clock_source_hz = 0;
|
||||
@ -434,36 +421,37 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
||||
TWAI_CHECK(twai_ll_check_brp_validation(brp), ESP_ERR_INVALID_ARG);
|
||||
|
||||
esp_err_t ret;
|
||||
twai_obj_t *p_twai_obj_dummy;
|
||||
// TODO: Currently only controller 0 is supported by the driver. IDF-4775
|
||||
const int controller_id = 0;
|
||||
twai_obj_t *p_twai_obj;
|
||||
|
||||
//Create a TWAI object (including queues, semaphores, interrupts, and PM locks)
|
||||
ret = twai_alloc_driver_obj(g_config, clk_src, controller_id, &p_twai_obj_dummy);
|
||||
ret = twai_alloc_driver_obj(g_config, clk_src, controller_id, &p_twai_obj);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Initialize flags and variables. All other members are already set to zero by twai_alloc_driver_obj()
|
||||
p_twai_obj_dummy->controller_id = controller_id;
|
||||
p_twai_obj_dummy->state = TWAI_STATE_STOPPED;
|
||||
p_twai_obj_dummy->mode = g_config->mode;
|
||||
p_twai_obj_dummy->alerts_enabled = g_config->alerts_enabled;
|
||||
portMUX_INITIALIZE(&p_twai_obj->spinlock);
|
||||
p_twai_obj->controller_id = controller_id;
|
||||
p_twai_obj->state = TWAI_STATE_STOPPED;
|
||||
p_twai_obj->mode = g_config->mode;
|
||||
p_twai_obj->alerts_enabled = g_config->alerts_enabled;
|
||||
|
||||
//Assign the TWAI object
|
||||
TWAI_ENTER_CRITICAL();
|
||||
if (p_twai_obj == NULL) {
|
||||
p_twai_obj = p_twai_obj_dummy;
|
||||
portENTER_CRITICAL(&g_spinlock);
|
||||
if (g_twai_objs[controller_id] == NULL) {
|
||||
g_twai_objs[controller_id] = p_twai_obj;
|
||||
} else {
|
||||
//Check if driver is already installed
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&g_spinlock);
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
goto err;
|
||||
}
|
||||
portEXIT_CRITICAL(&g_spinlock);
|
||||
|
||||
//Enable TWAI peripheral register clock
|
||||
TWAI_RCC_ATOMIC() {
|
||||
twai_ll_enable_bus_clock(p_twai_obj->controller_id, true);
|
||||
twai_ll_reset_register(p_twai_obj->controller_id);
|
||||
twai_ll_enable_bus_clock(controller_id, true);
|
||||
twai_ll_reset_register(controller_id);
|
||||
}
|
||||
|
||||
//Initialize TWAI HAL layer
|
||||
@ -471,65 +459,95 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
||||
.clock_source_hz = clock_source_hz,
|
||||
.controller_id = controller_id,
|
||||
};
|
||||
bool res = twai_hal_init(&twai_context, &hal_config);
|
||||
bool res = twai_hal_init(&p_twai_obj->hal, &hal_config);
|
||||
assert(res);
|
||||
twai_hal_configure(&twai_context, t_config, f_config, DRIVER_DEFAULT_INTERRUPTS, g_config->clkout_divider);
|
||||
TWAI_EXIT_CRITICAL();
|
||||
twai_hal_configure(&p_twai_obj->hal, t_config, f_config, DRIVER_DEFAULT_INTERRUPTS, g_config->clkout_divider);
|
||||
|
||||
//Assign GPIO and Interrupts
|
||||
twai_configure_gpio(g_config->tx_io, g_config->rx_io, g_config->clkout_io, g_config->bus_off_io);
|
||||
twai_configure_gpio(controller_id, g_config->tx_io, g_config->rx_io, g_config->clkout_io, g_config->bus_off_io);
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
//Acquire PM lock
|
||||
if (p_twai_obj->pm_lock) {
|
||||
ESP_ERROR_CHECK(esp_pm_lock_acquire(p_twai_obj->pm_lock)); //Acquire pm_lock during the whole driver lifetime
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
//Enable interrupt
|
||||
ESP_ERROR_CHECK(esp_intr_enable(p_twai_obj->isr_handle));
|
||||
|
||||
*ret_twai = p_twai_obj;
|
||||
|
||||
return ESP_OK; //TWAI module is still in reset mode, users need to call twai_start() afterwards
|
||||
|
||||
err:
|
||||
twai_free_driver_obj(p_twai_obj_dummy);
|
||||
twai_free_driver_obj(p_twai_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config)
|
||||
{
|
||||
// the handle-less driver API only supports one TWAI controller, i.e. the g_twai_objs[0]
|
||||
TWAI_CHECK(g_config->controller_id == 0, ESP_ERR_INVALID_ARG);
|
||||
return twai_driver_install_v2(g_config, t_config, f_config, &g_twai_objs[0]);
|
||||
}
|
||||
|
||||
esp_err_t twai_driver_uninstall_v2(twai_handle_t handle)
|
||||
{
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
int controller_id = handle->controller_id;
|
||||
twai_obj_t *p_twai_obj;
|
||||
|
||||
portENTER_CRITICAL(&g_spinlock);
|
||||
//Check state
|
||||
if (g_twai_objs[controller_id] == NULL) {
|
||||
portEXIT_CRITICAL(&g_spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
p_twai_obj = g_twai_objs[controller_id];
|
||||
if (!(p_twai_obj->state == TWAI_STATE_STOPPED || p_twai_obj->state == TWAI_STATE_BUS_OFF)) {
|
||||
portEXIT_CRITICAL(&g_spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
g_twai_objs[controller_id] = NULL;
|
||||
portEXIT_CRITICAL(&g_spinlock);
|
||||
|
||||
//Clear registers by reading
|
||||
twai_hal_deinit(&p_twai_obj->hal);
|
||||
TWAI_RCC_ATOMIC() {
|
||||
twai_ll_enable_bus_clock(controller_id, false);
|
||||
}
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (p_twai_obj->pm_lock) {
|
||||
//Release and delete power management lock
|
||||
ESP_ERROR_CHECK(esp_pm_lock_release(p_twai_obj->pm_lock));
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
//Disable interrupt
|
||||
ESP_ERROR_CHECK(esp_intr_disable(p_twai_obj->isr_handle));
|
||||
//Free twai driver object
|
||||
twai_free_driver_obj(p_twai_obj);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_driver_uninstall(void)
|
||||
{
|
||||
twai_obj_t *p_twai_obj_dummy;
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
//Check state
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj->state == TWAI_STATE_STOPPED || p_twai_obj->state == TWAI_STATE_BUS_OFF, ESP_ERR_INVALID_STATE);
|
||||
//Clear registers by reading
|
||||
twai_hal_deinit(&twai_context);
|
||||
TWAI_RCC_ATOMIC() {
|
||||
twai_ll_enable_bus_clock(p_twai_obj->controller_id, false);
|
||||
}
|
||||
p_twai_obj_dummy = p_twai_obj; //Use dummy to shorten critical section
|
||||
p_twai_obj = NULL;
|
||||
TWAI_EXIT_CRITICAL();
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (p_twai_obj_dummy->pm_lock) {
|
||||
//Release and delete power management lock
|
||||
ESP_ERROR_CHECK(esp_pm_lock_release(p_twai_obj_dummy->pm_lock));
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
//Disable interrupt
|
||||
ESP_ERROR_CHECK(esp_intr_disable(p_twai_obj_dummy->isr_handle));
|
||||
//Free can driver object
|
||||
twai_free_driver_obj(p_twai_obj_dummy);
|
||||
return ESP_OK;
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_driver_uninstall_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
||||
esp_err_t twai_start(void)
|
||||
esp_err_t twai_start_v2(twai_handle_t handle)
|
||||
{
|
||||
//Check state
|
||||
TWAI_ENTER_CRITICAL();
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj->state == TWAI_STATE_STOPPED, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
if (p_twai_obj->state != TWAI_STATE_STOPPED) {
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
//Reset RX queue, RX message count, amd TX queue
|
||||
xQueueReset(p_twai_obj->rx_queue);
|
||||
@ -538,21 +556,32 @@ esp_err_t twai_start(void)
|
||||
}
|
||||
p_twai_obj->rx_msg_count = 0;
|
||||
p_twai_obj->tx_msg_count = 0;
|
||||
twai_hal_start(&twai_context, p_twai_obj->mode);
|
||||
twai_hal_start(&p_twai_obj->hal, p_twai_obj->mode);
|
||||
|
||||
p_twai_obj->state = TWAI_STATE_RUNNING;
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_stop(void)
|
||||
esp_err_t twai_start(void)
|
||||
{
|
||||
//Check state
|
||||
TWAI_ENTER_CRITICAL();
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj->state == TWAI_STATE_RUNNING, ESP_ERR_INVALID_STATE);
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_start_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
||||
twai_hal_stop(&twai_context);
|
||||
esp_err_t twai_stop_v2(twai_handle_t handle)
|
||||
{
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
//Check state
|
||||
if (p_twai_obj->state != TWAI_STATE_RUNNING) {
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
twai_hal_stop(&p_twai_obj->hal);
|
||||
|
||||
//Reset TX Queue and message count
|
||||
if (p_twai_obj->tx_queue != NULL) {
|
||||
@ -561,22 +590,34 @@ esp_err_t twai_stop(void)
|
||||
p_twai_obj->tx_msg_count = 0;
|
||||
p_twai_obj->state = TWAI_STATE_STOPPED;
|
||||
|
||||
TWAI_EXIT_CRITICAL();
|
||||
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
esp_err_t twai_stop(void)
|
||||
{
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_stop_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
||||
esp_err_t twai_transmit_v2(twai_handle_t handle, const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
{
|
||||
//Check arguments
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(message != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK((message->data_length_code <= TWAI_FRAME_MAX_DLC) || message->dlc_non_comp, ESP_ERR_INVALID_ARG);
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
//Check State
|
||||
TWAI_CHECK_FROM_CRIT(!(p_twai_obj->mode == TWAI_MODE_LISTEN_ONLY), ESP_ERR_NOT_SUPPORTED);
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj->state == TWAI_STATE_RUNNING, ESP_ERR_INVALID_STATE);
|
||||
if (p_twai_obj->mode == TWAI_MODE_LISTEN_ONLY) {
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (p_twai_obj->state != TWAI_STATE_RUNNING) {
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
//Format frame
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
twai_hal_frame_t tx_frame;
|
||||
@ -585,11 +626,11 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
//Check if frame can be sent immediately
|
||||
if (p_twai_obj->tx_msg_count == 0) {
|
||||
//No other frames waiting to transmit. Bypass queue and transmit immediately
|
||||
twai_hal_set_tx_buffer_and_transmit(&twai_context, &tx_frame);
|
||||
twai_hal_set_tx_buffer_and_transmit(&p_twai_obj->hal, &tx_frame);
|
||||
p_twai_obj->tx_msg_count++;
|
||||
ret = ESP_OK;
|
||||
}
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (p_twai_obj->tx_queue == NULL) {
|
||||
@ -597,10 +638,10 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
ret = ESP_FAIL;
|
||||
} else if (xQueueSend(p_twai_obj->tx_queue, &tx_frame, ticks_to_wait) == pdTRUE) {
|
||||
//Copied to TX Queue
|
||||
TWAI_ENTER_CRITICAL();
|
||||
if ((!twai_hal_check_state_flags(&twai_context, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED)) && uxQueueMessagesWaiting(p_twai_obj->tx_queue) > 0) {
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
if ((!twai_hal_check_state_flags(&p_twai_obj->hal, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED)) && uxQueueMessagesWaiting(p_twai_obj->tx_queue) > 0) {
|
||||
//If the TX buffer is free but the TX queue is not empty. Check if we need to manually start a transmission
|
||||
if (twai_hal_check_state_flags(&twai_context, TWAI_HAL_STATE_FLAG_BUS_OFF) || !twai_hal_check_state_flags(&twai_context, TWAI_HAL_STATE_FLAG_RUNNING)) {
|
||||
if (twai_hal_check_state_flags(&p_twai_obj->hal, TWAI_HAL_STATE_FLAG_BUS_OFF) || !twai_hal_check_state_flags(&p_twai_obj->hal, TWAI_HAL_STATE_FLAG_RUNNING)) {
|
||||
//TX buffer became free due to bus-off or is no longer running. No need to start a transmission
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
} else {
|
||||
@ -608,7 +649,7 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
int res = xQueueReceive(p_twai_obj->tx_queue, &tx_frame, 0);
|
||||
assert(res == pdTRUE);
|
||||
(void)res;
|
||||
twai_hal_set_tx_buffer_and_transmit(&twai_context, &tx_frame);
|
||||
twai_hal_set_tx_buffer_and_transmit(&p_twai_obj->hal, &tx_frame);
|
||||
p_twai_obj->tx_msg_count++;
|
||||
ret = ESP_OK;
|
||||
}
|
||||
@ -617,7 +658,7 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
p_twai_obj->tx_msg_count++;
|
||||
ret = ESP_OK;
|
||||
}
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
} else {
|
||||
//Timed out waiting for free space on TX queue
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
@ -626,39 +667,54 @@ esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait)
|
||||
esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait)
|
||||
{
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_transmit_v2(g_twai_objs[0], message, ticks_to_wait);
|
||||
}
|
||||
|
||||
esp_err_t twai_receive_v2(twai_handle_t handle, twai_message_t *message, TickType_t ticks_to_wait)
|
||||
{
|
||||
//Check arguments and state
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(message != NULL, ESP_ERR_INVALID_ARG);
|
||||
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
//Get frame from RX Queue or RX Buffer
|
||||
twai_hal_frame_t rx_frame;
|
||||
if (xQueueReceive(p_twai_obj->rx_queue, &rx_frame, ticks_to_wait) != pdTRUE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
p_twai_obj->rx_msg_count--;
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
//Decode frame
|
||||
twai_hal_parse_frame(&rx_frame, message);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait)
|
||||
esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait)
|
||||
{
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_receive_v2(g_twai_objs[0], message, ticks_to_wait);
|
||||
}
|
||||
|
||||
esp_err_t twai_read_alerts_v2(twai_handle_t handle, uint32_t *alerts, TickType_t ticks_to_wait)
|
||||
{
|
||||
//Check arguments and state
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(alerts != NULL, ESP_ERR_INVALID_ARG);
|
||||
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
//Wait for an alert to occur
|
||||
if (xSemaphoreTake(p_twai_obj->alert_semphr, ticks_to_wait) == pdTRUE) {
|
||||
TWAI_ENTER_CRITICAL();
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
*alerts = p_twai_obj->alerts_triggered;
|
||||
p_twai_obj->alerts_triggered = 0; //Clear triggered alerts
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_OK;
|
||||
} else {
|
||||
*alerts = 0;
|
||||
@ -666,28 +722,47 @@ esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts)
|
||||
esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait)
|
||||
{
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_read_alerts_v2(g_twai_objs[0], alerts, ticks_to_wait);
|
||||
}
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
esp_err_t twai_reconfigure_alerts_v2(twai_handle_t handle, uint32_t alerts_enabled, uint32_t *current_alerts)
|
||||
{
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
//Clear any unhandled alerts
|
||||
if (current_alerts != NULL) {
|
||||
*current_alerts = p_twai_obj->alerts_triggered;
|
||||
}
|
||||
p_twai_obj->alerts_triggered = 0;
|
||||
p_twai_obj->alerts_enabled = alerts_enabled; //Update enabled alerts
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_initiate_recovery(void)
|
||||
esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts)
|
||||
{
|
||||
TWAI_ENTER_CRITICAL();
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_reconfigure_alerts_v2(g_twai_objs[0], alerts_enabled, current_alerts);
|
||||
}
|
||||
|
||||
esp_err_t twai_initiate_recovery_v2(twai_handle_t handle)
|
||||
{
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
//Check state
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj->state == TWAI_STATE_BUS_OFF, ESP_ERR_INVALID_STATE);
|
||||
if (p_twai_obj->state != TWAI_STATE_BUS_OFF) {
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
//Reset TX Queue/Counters
|
||||
if (p_twai_obj->tx_queue != NULL) {
|
||||
@ -696,27 +771,34 @@ esp_err_t twai_initiate_recovery(void)
|
||||
p_twai_obj->tx_msg_count = 0;
|
||||
|
||||
//Trigger start of recovery process
|
||||
twai_hal_start_bus_recovery(&twai_context);
|
||||
twai_hal_start_bus_recovery(&p_twai_obj->hal);
|
||||
p_twai_obj->state = TWAI_STATE_RECOVERING;
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_get_status_info(twai_status_info_t *status_info)
|
||||
esp_err_t twai_initiate_recovery(void)
|
||||
{
|
||||
//Check parameters and state
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(status_info != NULL, ESP_ERR_INVALID_ARG);
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_initiate_recovery_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
esp_err_t twai_get_status_info_v2(twai_handle_t handle, twai_status_info_t *status_info)
|
||||
{
|
||||
//Check parameters
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(status_info != NULL, ESP_ERR_INVALID_ARG);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
if (p_twai_obj->mode == TWAI_MODE_LISTEN_ONLY) {
|
||||
//Error counters are frozen under listen only mode thus are meaningless. Simply return 0 in this case.
|
||||
status_info->tx_error_counter = 0;
|
||||
status_info->rx_error_counter = 0;
|
||||
} else {
|
||||
status_info->tx_error_counter = twai_hal_get_tec(&twai_context);
|
||||
status_info->rx_error_counter = twai_hal_get_rec(&twai_context);
|
||||
status_info->tx_error_counter = twai_hal_get_tec(&p_twai_obj->hal);
|
||||
status_info->rx_error_counter = twai_hal_get_rec(&p_twai_obj->hal);
|
||||
}
|
||||
status_info->msgs_to_tx = p_twai_obj->tx_msg_count;
|
||||
status_info->msgs_to_rx = p_twai_obj->rx_msg_count;
|
||||
@ -726,35 +808,55 @@ esp_err_t twai_get_status_info(twai_status_info_t *status_info)
|
||||
status_info->arb_lost_count = p_twai_obj->arb_lost_count;
|
||||
status_info->bus_error_count = p_twai_obj->bus_error_count;
|
||||
status_info->state = p_twai_obj->state;
|
||||
TWAI_EXIT_CRITICAL();
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_get_status_info(twai_status_info_t *status_info)
|
||||
{
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_get_status_info_v2(g_twai_objs[0], status_info);
|
||||
}
|
||||
|
||||
esp_err_t twai_clear_transmit_queue_v2(twai_handle_t handle)
|
||||
{
|
||||
//Check parameters
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(handle->tx_queue != NULL, ESP_ERR_NOT_SUPPORTED);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
//If a message is currently undergoing transmission, the tx interrupt handler will decrement tx_msg_count
|
||||
p_twai_obj->tx_msg_count = twai_hal_check_state_flags(&p_twai_obj->hal, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED) ? 1 : 0;
|
||||
xQueueReset(p_twai_obj->tx_queue);
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_clear_transmit_queue(void)
|
||||
{
|
||||
//Check State
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_CHECK(p_twai_obj->tx_queue != NULL, ESP_ERR_NOT_SUPPORTED);
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_clear_transmit_queue_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
//If a message is currently undergoing transmission, the tx interrupt handler will decrement tx_msg_count
|
||||
p_twai_obj->tx_msg_count = twai_hal_check_state_flags(&twai_context, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED) ? 1 : 0;
|
||||
xQueueReset(p_twai_obj->tx_queue);
|
||||
TWAI_EXIT_CRITICAL();
|
||||
esp_err_t twai_clear_receive_queue_v2(twai_handle_t handle)
|
||||
{
|
||||
//Check parameters
|
||||
TWAI_CHECK(handle != NULL, ESP_ERR_INVALID_ARG);
|
||||
twai_obj_t *p_twai_obj = handle;
|
||||
|
||||
portENTER_CRITICAL(&handle->spinlock);
|
||||
p_twai_obj->rx_msg_count = 0;
|
||||
xQueueReset(p_twai_obj->rx_queue);
|
||||
portEXIT_CRITICAL(&handle->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t twai_clear_receive_queue(void)
|
||||
{
|
||||
//Check State
|
||||
TWAI_CHECK(p_twai_obj != NULL, ESP_ERR_INVALID_STATE);
|
||||
|
||||
TWAI_ENTER_CRITICAL();
|
||||
p_twai_obj->rx_msg_count = 0;
|
||||
xQueueReset(p_twai_obj->rx_queue);
|
||||
TWAI_EXIT_CRITICAL();
|
||||
|
||||
return ESP_OK;
|
||||
// the handle-less driver API only support one TWAI controller, i.e. the g_twai_objs[0]
|
||||
return twai_clear_receive_queue_v2(g_twai_objs[0]);
|
||||
}
|
||||
|
@ -3,12 +3,6 @@ Two-Wire Automotive Interface (TWAI)
|
||||
|
||||
.. -------------------------------- Overview -----------------------------------
|
||||
|
||||
.. only:: esp32c6
|
||||
|
||||
.. warning::
|
||||
|
||||
{IDF_TARGET_NAME} has {IDF_TARGET_SOC_TWAI_CONTROLLER_NUM} TWAI controllers, but at the moment, the driver can only support ``TWAI0`` due to the limitation of the driver structure.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
@ -86,6 +80,13 @@ The TWAI controller's interface consists of 4 signal lines known as **TX, RX, BU
|
||||
|
||||
.. ------------------------------ Configuration --------------------------------
|
||||
|
||||
API Naming Conventions
|
||||
----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
The TWAI driver provides two sets of API. One is handle-free and is widely used in IDF versions earlier than v5.2, but it can only support one TWAI hardware controller. The other set is with handles, and the function name is usually suffixed with "v2", which can support any number of TWAI controllers. These two sets of API can be used at the same time, but it is recommended to use the "v2" version in your new projects.
|
||||
|
||||
Driver Configuration
|
||||
--------------------
|
||||
|
||||
@ -397,6 +398,64 @@ The following code snippet demonstrates how to configure, install, and start the
|
||||
|
||||
The usage of macro initializers is not mandatory and each of the configuration structures can be manually.
|
||||
|
||||
Install Multiple TWAI Instances
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following code snippet demonstrates how to install multiple TWAI instances via the use of the :cpp:func:`twai_driver_install_v2` function.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
void app_main()
|
||||
{
|
||||
twai_handle_t twai_bus_0;
|
||||
twai_handle_t twai_bus_1;
|
||||
//Initialize configuration structures using macro initializers
|
||||
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_0, GPIO_NUM_1, TWAI_MODE_NORMAL);
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
|
||||
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
|
||||
//Install driver for TWAI bus 0
|
||||
g_config.controller_id = 0;
|
||||
if (twai_driver_install_v2(&g_config, &t_config, &f_config, &twai_bus_0) == ESP_OK) {
|
||||
printf("Driver installed\n");
|
||||
} else {
|
||||
printf("Failed to install driver\n");
|
||||
return;
|
||||
}
|
||||
//Start TWAI driver
|
||||
if (twai_start_v2(twai_bus_0) == ESP_OK) {
|
||||
printf("Driver started\n");
|
||||
} else {
|
||||
printf("Failed to start driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//Install driver for TWAI bus 1
|
||||
g_config.controller_id = 1;
|
||||
g_config.tx_io = GPIO_NUM_2;
|
||||
g_config.rx_io = GPIO_NUM_3;
|
||||
if (twai_driver_install_v2(&g_config, &t_config, &f_config, &twai_bus_1) == ESP_OK) {
|
||||
printf("Driver installed\n");
|
||||
} else {
|
||||
printf("Failed to install driver\n");
|
||||
return;
|
||||
}
|
||||
//Start TWAI driver
|
||||
if (twai_start_v2(twai_bus_1) == ESP_OK) {
|
||||
printf("Driver started\n");
|
||||
} else {
|
||||
printf("Failed to start driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//Other Driver operations must use version 2 API as well
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
Message Transmission
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user