mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
TWAI: Add ESP32-S2 support
This commit adds TWAI driver support for the ESP32-S2. The following features were added: - Expanded BRP support - Expanded CLKOUT Divider Support - Updated example READMEs
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# CAN Alert and Recovery Example
|
||||
|
||||
## Overview
|
||||
The CAN Alert and Recovery Example demonstrates the usage of alerts and bus
|
||||
recovery in the CAN driver. This example **requires only a single ESP32 module
|
||||
to run**.
|
||||
|
||||
The CAN Alert and Recovery Example will do the following...
|
||||
|
||||
1. Initialize and start the CAN driver on the ESP32 module
|
||||
2. Repeatedly transmit messages (no acknowledgement required)
|
||||
3. Reconfigure alerts to detect bus-off state
|
||||
4. Purposely trigger errors on transmissions
|
||||
5. Detect Bus Off condition
|
||||
6. Initiate bus recovery
|
||||
7. Deinitialize CAN driver on ESP32 module
|
||||
|
||||
## External Transceiver and Pin Assignment
|
||||
The CAN controller in the ESP32 **does not contain an internal transceiver**.
|
||||
Therefore users are responsible for providing an external transceiver compatible
|
||||
with the physical layer specifications of their target ISO standard (such as
|
||||
SN65HVD23X transceivers for ISO 11898-2 compatibility)
|
||||
|
||||
The CAN controller in the ESP32 represents dominant bits to the transceiver as
|
||||
logic low, and recessive bits as logic high. The Alert and Recovery Example
|
||||
utilizes the following default pin assignments
|
||||
|
||||
* TX Pin is routed to GPIO21
|
||||
* RX Pin is routed to GPIO22
|
@@ -1,21 +0,0 @@
|
||||
# Need Python 3 string formatting functions
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
# CAN Self Test Example constants
|
||||
STR_EXPECT = ("CAN Alert and Recovery: Driver installed", "CAN Alert and Recovery: Driver uninstalled")
|
||||
EXPECT_TIMEOUT = 20
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_CAN1')
|
||||
def test_can_alert_and_recovery_example(env, extra_data):
|
||||
dut = env.get_dut('dut1', 'examples/peripherals/can/can_alert_and_recovery', dut_class=ttfw_idf.ESP32DUT)
|
||||
dut.start_app()
|
||||
|
||||
for string in STR_EXPECT:
|
||||
dut.expect(string, timeout=EXPECT_TIMEOUT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_can_alert_and_recovery_example()
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "can_alert_and_recovery_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -1,70 +0,0 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# CAN Network Example
|
||||
|
||||
## Overview
|
||||
The CAN Network Example demonstrates communication between two ESP32 modules (master
|
||||
and slave) using the CAN2.0B protocol. CAN is a multi-master protocol, therefore
|
||||
the concept of master/slave in this example refers to which node initiates
|
||||
and stops the transfer of a stream of data messages. The example also includes
|
||||
an optional **Listen Only module** which can passively receive the CAN messages
|
||||
sent between the master and slave module without participating in any CAN bus activity.
|
||||
|
||||
The CAN Network Example will execute the following steps over multiple iterations:
|
||||
|
||||
1. Both master and slave go through initialization process
|
||||
2. The master repeatedly sends **PING** messages until it receives a **PING_RESP**
|
||||
from the slave. The slave will only send a **PING_RESP** message when it receives
|
||||
a **PING** message from the master.
|
||||
3. Once the master has received the **PING_RESP** from the slave, it will send a
|
||||
**START_CMD** message to the slave.
|
||||
4. Upon receiving the **START_CMD** message, the slave will start transmitting
|
||||
**DATA** messages until the master sends a **STOP_CMD**. The master will send
|
||||
the **STOP_CMD** after receiving N **DATA** messages from the slave (N = 50 by
|
||||
default).
|
||||
5. When the slave receives the **STOP_CMD**, it will confirm that it has stopped
|
||||
by sending a **STOP_RESP** message to the master.
|
||||
|
||||
## External Transceiver and Pin Assignment
|
||||
The CAN controller in the ESP32 **does not contain an internal transceiver**.
|
||||
Therefore users are responsible for providing an external transceiver compatible
|
||||
with the physical layer specifications of their target ISO standard (such as
|
||||
SN65HVD23X transceivers for ISO 11898-2 compatibility)
|
||||
|
||||
The CAN controller in the ESP32 represents dominant bits to the transceiver as
|
||||
logic low, and recessive bits as logic high. The Network Example utilizes the
|
||||
following default pin assignments
|
||||
|
||||
* TX Pin is routed to GPIO21
|
||||
* RX Pin is routed to GPIO22
|
||||
|
||||
The following diagram illustrates an example network
|
||||
|
||||
~~~~
|
||||
---------- ---------- --------------
|
||||
| Master | | Slave | | Listen Only |
|
||||
| | | | | |
|
||||
| 21 22 | | 21 22 | | 21 22 |
|
||||
---------- ---------- --------------
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
---------- ---------- ----------
|
||||
| D R | | D R | | D R |
|
||||
| | | | | |
|
||||
| VP230 | | VP230 | | VP230 |
|
||||
| | | | | |
|
||||
| H L | | H L | | H L |
|
||||
---------- ---------- ----------
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|--x------|-----x------|-----x------|--| H
|
||||
| | |
|
||||
|---------x------------x------------x--| L
|
||||
|
||||
~~~~
|
||||
|
||||
## Note
|
||||
If there appears to be no activity on the CAN bus when running the example, users
|
||||
can try running the `can_self_test` example to verify if their transceivers are
|
||||
wired properly.
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "can_network_example_listen_only_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "can_network_example_master_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "can_network_example_slave_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -1,36 +0,0 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# CAN Self Test Example
|
||||
|
||||
## Overview
|
||||
The CAN Self Test Example demonstrates the self testing capabilities of the
|
||||
ESP32 CAN peripheral and **only requires a single ESP32 module to run**.
|
||||
The Self Test Example can be used to verify that the wiring between the ESP32
|
||||
and an external transceiver operates correctly.
|
||||
|
||||
The CAN Self Test Example will do the following over multiple iterations:
|
||||
|
||||
1. Start the CAN driver
|
||||
2. Simultaneously transmit and receive messages using the self reception request.
|
||||
3. Stop the CAN driver
|
||||
|
||||
## External Transceiver and Pin Assignment
|
||||
The CAN controller in the ESP32 **does not contain an internal transceiver**.
|
||||
Therefore users are responsible for providing an external transceiver compatible
|
||||
with the physical layer specifications of their target ISO standard (such as
|
||||
SN65HVD23X transceivers for ISO 11898-2 compatibility)
|
||||
|
||||
The CAN controller in the ESP32 represents dominant bits to the transceiver as
|
||||
logic low, and recessive bits as logic high. The Self Test Example utilizes the
|
||||
following default pin assignments
|
||||
|
||||
* TX Pin is routed to GPIO21
|
||||
* RX Pin is routed to GPIO22
|
||||
|
||||
## Note
|
||||
If the Self Test Example does not receive any messages, it is likely that the
|
||||
wiring between the ESP32 and the external transceiver is incorrect. To verify
|
||||
that the CAN controller in the ESP32 is operating correctly, users can bypass
|
||||
the external transceiver by connecting the TX Pin directly to the RX Pin when
|
||||
running the Self Test Example.
|
@@ -1,23 +0,0 @@
|
||||
# Need Python 3 string formatting functions
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
# CAN Self Test Example constants
|
||||
STR_EXPECT = ("CAN Self Test: Driver installed", "CAN Self Test: Driver uninstalled")
|
||||
EXPECT_TIMEOUT = 20
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_CAN1')
|
||||
def test_can_self_test_example(env, extra_data):
|
||||
# Get device under test, flash and start example. "dut1" must be defined in EnvConfig
|
||||
dut = env.get_dut('dut1', 'examples/peripherals/can/can_self_test', dut_class=ttfw_idf.ESP32DUT)
|
||||
dut.start_app()
|
||||
|
||||
for string in STR_EXPECT:
|
||||
dut.expect(string, timeout=EXPECT_TIMEOUT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_can_self_test_example()
|
@@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "can_self_test_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := can_alert_and_recovery_example
|
||||
PROJECT_NAME := twai_alert_and_recovery_example
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
91
examples/peripherals/twai/twai_alert_and_recovery/README.md
Normal file
91
examples/peripherals/twai/twai_alert_and_recovery/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# TWAI Alert and Recovery Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use the alert and bus recovery features of the TWAI driver. The alert feature allows the TWAI driver to notify the application layer of certain TWAI driver or bus events. The bus recovery feature is used to recover the TWAI driver after it has entered the Bus-Off state. See the TWAI driver reference for more details.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example requires only a single target (e.g., an ESP32 or ESP32-S2). The target must be connected to an external transceiver (e.g., a SN65HVD23X transceiver). This connection usually consists of a TX and an RX signal.
|
||||
|
||||
Note: If you don't have an external transceiver, this example can still be run by simply connecting the TX GPIO and RX GPIO with a jumper.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Set the target of the build (where `{IDF_TARGET}` stands for the target chip such as `eszp32` or `esp32s2`).
|
||||
* Then run `menuconfig` to configure the example.
|
||||
|
||||
```
|
||||
idf.py set-target {IDF_TARGET}
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Under `Example Configuration`, configure the pin assignments using the options `TX GPIO Number` and `RX GPIO Number` according to how the target was connected to the transceiver. By default, `TX GPIO Number` and `RX GPIO Number` are set to the following values:
|
||||
* On the ESP32, `TX GPIO Number` and `RX GPIO Number` default to `21` and `22` respectively
|
||||
* On the ESP32-S2, `TX GPIO Number` and `RX GPIO Number` default to `20` and `21` respectively
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (330) TWAI Alert and Recovery: Driver installed
|
||||
I (340) TWAI Alert and Recovery: Driver started
|
||||
I (340) TWAI Alert and Recovery: Starting transmissions
|
||||
W (350) TWAI Alert and Recovery: Trigger TX errors in 3
|
||||
W (1350) TWAI Alert and Recovery: Trigger TX errors in 2
|
||||
W (2350) TWAI Alert and Recovery: Trigger TX errors in 1
|
||||
I (3350) TWAI Alert and Recovery: Trigger errors
|
||||
I (3650) TWAI Alert and Recovery: Surpassed Error Warning Limit
|
||||
I (3650) TWAI Alert and Recovery: Entered Error Passive state
|
||||
I (4300) TWAI Alert and Recovery: Bus Off state
|
||||
W (4300) TWAI Alert and Recovery: Initiate bus recovery in 3
|
||||
W (5300) TWAI Alert and Recovery: Initiate bus recovery in 2
|
||||
W (6300) TWAI Alert and Recovery: Initiate bus recovery in 1
|
||||
I (7300) TWAI Alert and Recovery: Initiate bus recovery
|
||||
I (7350) TWAI Alert and Recovery: Bus Recovered
|
||||
I (7350) TWAI Alert and Recovery: Driver uninstalled
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```
|
||||
I (3350) TWAI Alert and Recovery: Trigger errors
|
||||
```
|
||||
|
||||
If the example does not progress pass triggering errors, check that the target is correctly connected to the transceiver.
|
||||
|
||||
```
|
||||
I (3350) TWAI Alert and Recovery: Trigger errors
|
||||
I (3650) TWAI Alert and Recovery: Surpassed Error Warning Limit
|
||||
I (3650) TWAI Alert and Recovery: Entered Error Passive state
|
||||
```
|
||||
|
||||
If the example is able to trigger errors but does not enter the bus off state (i.e., stays in the error passive state), check that the triggering of the bit error is properly set to the examples operating bit rate. By default, the example runs at a bit rate of 125kbits/sec, and the bit error should be triggered after the arbitration phase of each transmitted message.
|
||||
|
||||
## Example Breakdown
|
||||
|
||||
The TWAI Alert and Recovery Example will do the following...
|
||||
|
||||
1. Initialize the TWAI driver in No Acknowledgement mode (so that another node is not required).
|
||||
2. Create a transmit task to handle message transmission, and a control task to handle alerts.
|
||||
3. Control task starts the TWAI driver, then reconfigures the alerts to trigger when the error passive or bus off state is entered. The control task then waits for those alerts.
|
||||
4. The transmit repeatedly transmits single shot messages (i.e., message won't be retried if an error occurs).
|
||||
5. When a message is being transmitted, the transmit task will purposely invert the TX pin to trigger a bit error. **Note that the triggering of the bit error is timed to occur after the arbitration phase of the transmitted message**.
|
||||
6. The triggering of a bit error on each transmitted message eventually puts the TWAI driver into the Bus-Off state.
|
||||
7. Control tasks detects the Bus-Off state via an alert, and triggers the Bus-Off recovery process after a short delay. Alerts are also reconfigured to trigger on the completion of Bus-Off recovery.
|
||||
8. Once the Bus-Off recovery completion alert is detected by the control task, the TWAI driver is stopped and uninstalled.
|
@@ -0,0 +1,21 @@
|
||||
# Need Python 3 string formatting functions
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
# TWAI Self Test Example constants
|
||||
STR_EXPECT = ("TWAI Alert and Recovery: Driver installed", "TWAI Alert and Recovery: Driver uninstalled")
|
||||
EXPECT_TIMEOUT = 20
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_TWAI1')
|
||||
def test_twai_alert_and_recovery_example(env, extra_data):
|
||||
dut = env.get_dut('dut1', 'examples/peripherals/twai/twai_alert_and_recovery', dut_class=ttfw_idf.ESP32DUT)
|
||||
dut.start_app()
|
||||
|
||||
for string in STR_EXPECT:
|
||||
dut.expect(string, timeout=EXPECT_TIMEOUT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_twai_alert_and_recovery_example()
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "twai_alert_and_recovery_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TX_GPIO_NUM
|
||||
int "TX GPIO number"
|
||||
default 20 if IDF_TARGET_ESP32S2
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the TX signal. Connect the
|
||||
TX signal to your transceiver.
|
||||
|
||||
config EXAMPLE_RX_GPIO_NUM
|
||||
int "RX GPIO number"
|
||||
default 21 if IDF_TARGET_ESP32S2
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the RX signal. Connect the
|
||||
RX signal to your transceiver.
|
||||
|
||||
endmenu
|
@@ -1,4 +1,4 @@
|
||||
/* CAN Alert and Recovery Example
|
||||
/* TWAI Alert and Recovery Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
/*
|
||||
* The following example demonstrates how to use the alert and bus recovery
|
||||
* features of the CAN driver. The example will do the following:
|
||||
* 1) Install and start the CAN driver
|
||||
* features of the TWAI driver. The example will do the following:
|
||||
* 1) Install and start the TWAI driver
|
||||
* 2) Have the TX task periodically broadcast messages expecting no ACK
|
||||
* 3) Reconfigure alerts to detect bus-off state
|
||||
* 4) Trigger bus errors by inverting TX GPIO
|
||||
* 5) Initiate bus-off recovery and wait for completion
|
||||
* 6) Uninstall CAN driver
|
||||
* 6) Uninstall TWAI driver
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -26,22 +26,22 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/can.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
//Example Configuration
|
||||
#define TX_GPIO_NUM 21
|
||||
#define RX_GPIO_NUM 22
|
||||
#define TX_GPIO_NUM CONFIG_EXAMPLE_TX_GPIO_NUM
|
||||
#define RX_GPIO_NUM CONFIG_EXAMPLE_RX_GPIO_NUM
|
||||
#define TX_TASK_PRIO 9
|
||||
#define CTRL_TASK_PRIO 10
|
||||
#define ERR_DELAY_US 800 //Approximate time for arbitration phase at 25KBPS
|
||||
#define ERR_PERIOD_US 80 //Approximate time for two bits at 25KBPS
|
||||
#define EXAMPLE_TAG "CAN Alert and Recovery"
|
||||
#define EXAMPLE_TAG "TWAI Alert and Recovery"
|
||||
|
||||
static const can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
|
||||
static const can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, CAN_MODE_NO_ACK);
|
||||
static const can_message_t tx_msg = {.identifier = 0, .data_length_code = 0};
|
||||
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NO_ACK);
|
||||
static const twai_message_t tx_msg = {.identifier = 0, .data_length_code = 0};
|
||||
|
||||
static SemaphoreHandle_t tx_task_sem;
|
||||
static SemaphoreHandle_t ctrl_task_sem;
|
||||
@@ -53,10 +53,10 @@ static void invert_tx_bits(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
//Inverts output of TX to trigger errors
|
||||
gpio_matrix_out(TX_GPIO_NUM, CAN_TX_IDX, true, false);
|
||||
gpio_matrix_out(TX_GPIO_NUM, TWAI_TX_IDX, true, false);
|
||||
} else {
|
||||
//Returns TX to default settings
|
||||
gpio_matrix_out(TX_GPIO_NUM, CAN_TX_IDX, false, false);
|
||||
gpio_matrix_out(TX_GPIO_NUM, TWAI_TX_IDX, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ static void tx_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(tx_task_sem, portMAX_DELAY);
|
||||
while (1) {
|
||||
if (can_transmit(&tx_msg, 0) == ESP_ERR_INVALID_STATE) {
|
||||
if (twai_transmit(&tx_msg, 0) == ESP_ERR_INVALID_STATE) {
|
||||
break; //Exit TX task when bus-off state is reached
|
||||
}
|
||||
if (trigger_tx_error) {
|
||||
@@ -82,13 +82,13 @@ static void tx_task(void *arg)
|
||||
static void ctrl_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
ESP_ERROR_CHECK(can_start());
|
||||
ESP_ERROR_CHECK(twai_start());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
ESP_LOGI(EXAMPLE_TAG, "Starting transmissions");
|
||||
xSemaphoreGive(tx_task_sem); //Start transmit task
|
||||
|
||||
//Prepare to trigger errors, reconfigure alerts to detect change in error state
|
||||
can_reconfigure_alerts(CAN_ALERT_ABOVE_ERR_WARN | CAN_ALERT_ERR_PASS | CAN_ALERT_BUS_OFF, NULL);
|
||||
twai_reconfigure_alerts(TWAI_ALERT_ABOVE_ERR_WARN | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_OFF, NULL);
|
||||
for (int i = 3; i > 0; i--) {
|
||||
ESP_LOGW(EXAMPLE_TAG, "Trigger TX errors in %d", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
@@ -98,31 +98,31 @@ static void ctrl_task(void *arg)
|
||||
|
||||
while (1) {
|
||||
uint32_t alerts;
|
||||
can_read_alerts(&alerts, portMAX_DELAY);
|
||||
if (alerts & CAN_ALERT_ABOVE_ERR_WARN) {
|
||||
twai_read_alerts(&alerts, portMAX_DELAY);
|
||||
if (alerts & TWAI_ALERT_ABOVE_ERR_WARN) {
|
||||
ESP_LOGI(EXAMPLE_TAG, "Surpassed Error Warning Limit");
|
||||
}
|
||||
if (alerts & CAN_ALERT_ERR_PASS) {
|
||||
if (alerts & TWAI_ALERT_ERR_PASS) {
|
||||
ESP_LOGI(EXAMPLE_TAG, "Entered Error Passive state");
|
||||
}
|
||||
if (alerts & CAN_ALERT_BUS_OFF) {
|
||||
if (alerts & TWAI_ALERT_BUS_OFF) {
|
||||
ESP_LOGI(EXAMPLE_TAG, "Bus Off state");
|
||||
//Prepare to initiate bus recovery, reconfigure alerts to detect bus recovery completion
|
||||
can_reconfigure_alerts(CAN_ALERT_BUS_RECOVERED, NULL);
|
||||
twai_reconfigure_alerts(TWAI_ALERT_BUS_RECOVERED, NULL);
|
||||
for (int i = 3; i > 0; i--) {
|
||||
ESP_LOGW(EXAMPLE_TAG, "Initiate bus recovery in %d", i);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
can_initiate_recovery(); //Needs 128 occurrences of bus free signal
|
||||
twai_initiate_recovery(); //Needs 128 occurrences of bus free signal
|
||||
ESP_LOGI(EXAMPLE_TAG, "Initiate bus recovery");
|
||||
}
|
||||
if (alerts & CAN_ALERT_BUS_RECOVERED) {
|
||||
if (alerts & TWAI_ALERT_BUS_RECOVERED) {
|
||||
//Bus recovery was successful, exit control task to uninstall driver
|
||||
ESP_LOGI(EXAMPLE_TAG, "Bus Recovered");
|
||||
break;
|
||||
}
|
||||
}
|
||||
//No need call can_stop(), bus recovery will return to stopped state
|
||||
//No need call twai_stop(), bus recovery will return to stopped state
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
@@ -132,19 +132,19 @@ void app_main(void)
|
||||
tx_task_sem = xSemaphoreCreateBinary();
|
||||
ctrl_task_sem = xSemaphoreCreateBinary();
|
||||
|
||||
xTaskCreatePinnedToCore(tx_task, "CAN_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(ctrl_task, "CAN_ctrl", 4096, NULL, CTRL_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(tx_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(ctrl_task, "TWAI_ctrl", 4096, NULL, CTRL_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
//Install CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_install(&g_config, &t_config, & f_config));
|
||||
//Install TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, & f_config));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver installed");
|
||||
|
||||
xSemaphoreGive(ctrl_task_sem); //Start control task
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY); //Wait for completion
|
||||
|
||||
//Uninstall CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_uninstall());
|
||||
//Uninstall TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
//Cleanup
|
184
examples/peripherals/twai/twai_network/README.md
Normal file
184
examples/peripherals/twai/twai_network/README.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# TWAI Network Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use the TWAI driver to program a target (ESP32 or ESP32-S2) as a TWAI node, and have the two nodes (Network Master and Network Slave) communicate on a TWAI network. The Listen Only node is optional and acts as a network monitor meaning that it only receives messages and does not influence the bus in any way (i.e. doesn't not acknowledge or send error frames).
|
||||
|
||||
Note that concept of master/slave in this example refers to which node initiates
|
||||
and stops the transfer of a stream of data messages.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example requires at least two targets (e.g., an ESP32 or ESP32-S2) to act as the Network Master and Network Slave. The third target (Listen Only) is optional. Each target must be connected to an external transceiver (e.g., a SN65HVD23X transceiver). The transceivers must then be interconnected to form a TWAI network.
|
||||
|
||||
The following diagram illustrates an example network:
|
||||
|
||||
```
|
||||
---------- ---------- --------------
|
||||
| Master | | Slave | | Listen Only |
|
||||
| | | | | |
|
||||
| TX RX | | TX RX | | TX RX |
|
||||
---------- ---------- --------------
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
---------- ---------- ----------
|
||||
| D R | | D R | | D R |
|
||||
| | | | | |
|
||||
| VP230 | | VP230 | | VP230 |
|
||||
| | | | | |
|
||||
| H L | | H L | | H L |
|
||||
---------- ---------- ----------
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
|--x------|-----x------|-----x------|--| H
|
||||
| | |
|
||||
|---------x------------x------------x--| L
|
||||
|
||||
```
|
||||
|
||||
Note: If you don't have an external transceiver, you can still run the [TWAI Self Test example](../twai_self_test/README.md)
|
||||
|
||||
### Configure the project
|
||||
|
||||
For each node in the TWAI network (i.e., Master, Slave, Listen Only)...
|
||||
|
||||
* Set the target of the build (where `{IDF_TARGET}` stands for the target chip such as `eszp32` or `esp32s2`).
|
||||
* Then run `menuconfig` to configure the example.
|
||||
|
||||
```
|
||||
idf.py set-target {IDF_TARGET}
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Under `Example Configuration`, configure the pin assignments using the options `TX GPIO Number` and `RX GPIO Number` according to how the target was connected to the transceiver. By default, `TX GPIO Number` and `RX GPIO Number` are set to the following values:
|
||||
* On the ESP32, `TX GPIO Number` and `RX GPIO Number` default to `21` and `22` respectively
|
||||
* On the ESP32-S2, `TX GPIO Number` and `RX GPIO Number` default to `20` and `21` respectively
|
||||
|
||||
|
||||
### Build and Flash
|
||||
|
||||
For each node, build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
Network Master
|
||||
```
|
||||
I (345) TWAI Master: Driver installed
|
||||
I (345) TWAI Master: Driver started
|
||||
I (345) TWAI Master: Transmitting ping
|
||||
I (3105) TWAI Master: Transmitted start command
|
||||
I (3105) TWAI Master: Received data value 339
|
||||
...
|
||||
I (5545) TWAI Master: Received data value 584
|
||||
I (5545) TWAI Master: Transmitted stop command
|
||||
I (5595) TWAI Master: Driver stopped
|
||||
I (6595) TWAI Master: Driver started
|
||||
I (6595) TWAI Master: Transmitting ping
|
||||
I (7095) TWAI Master: Transmitted start command
|
||||
I (7095) TWAI Master: Received data value 738
|
||||
...
|
||||
I (9535) TWAI Master: Received data value 983
|
||||
I (9535) TWAI Master: Transmitted stop command
|
||||
I (9585) TWAI Master: Driver stopped
|
||||
I (10585) TWAI Master: Driver started
|
||||
I (10585) TWAI Master: Transmitting ping
|
||||
I (11085) TWAI Master: Transmitted start command
|
||||
I (11085) TWAI Master: Received data value 1137
|
||||
...
|
||||
I (13525) TWAI Master: Received data value 1382
|
||||
I (13525) TWAI Master: Transmitted stop command
|
||||
I (13575) TWAI Master: Driver stopped
|
||||
I (14575) TWAI Master: Driver uninstalled
|
||||
```
|
||||
|
||||
Network Slave
|
||||
```
|
||||
Slave starting in 3
|
||||
Slave starting in 2
|
||||
Slave starting in 1
|
||||
I (6322) TWAI Slave: Driver installed
|
||||
I (6322) TWAI Slave: Driver started
|
||||
I (6462) TWAI Slave: Transmitted ping response
|
||||
I (6712) TWAI Slave: Start transmitting data
|
||||
I (6712) TWAI Slave: Transmitted data value 339
|
||||
...
|
||||
I (9162) TWAI Slave: Transmitted data value 584
|
||||
I (9212) TWAI Slave: Transmitted stop response
|
||||
I (9312) TWAI Slave: Driver stopped
|
||||
I (10312) TWAI Slave: Driver started
|
||||
I (10452) TWAI Slave: Transmitted ping response
|
||||
I (10702) TWAI Slave: Start transmitting data
|
||||
I (10702) TWAI Slave: Transmitted data value 738
|
||||
...
|
||||
I (13152) TWAI Slave: Transmitted data value 983
|
||||
I (13202) TWAI Slave: Transmitted stop response
|
||||
I (13302) TWAI Slave: Driver stopped
|
||||
I (14302) TWAI Slave: Driver started
|
||||
I (14442) TWAI Slave: Transmitted ping response
|
||||
I (14692) TWAI Slave: Start transmitting data
|
||||
I (14692) TWAI Slave: Transmitted data value 1137
|
||||
...
|
||||
I (17142) TWAI Slave: Transmitted data value 1382
|
||||
I (17192) TWAI Slave: Transmitted stop response
|
||||
I (17292) TWAI Slave: Driver stopped
|
||||
I (18292) TWAI Slave: Driver uninstalled
|
||||
```
|
||||
|
||||
Network Listen Only
|
||||
```
|
||||
I (326) TWAI Listen Only: Driver installed
|
||||
I (326) TWAI Listen Only: Driver started
|
||||
I (366) TWAI Listen Only: Received master ping
|
||||
...
|
||||
I (1866) TWAI Listen Only: Received master ping
|
||||
I (1866) TWAI Listen Only: Received slave ping response
|
||||
I (2116) TWAI Listen Only: Received master start command
|
||||
I (2116) TWAI Listen Only: Received data value 329
|
||||
...
|
||||
I (4566) TWAI Listen Only: Received data value 574
|
||||
I (4566) TWAI Listen Only: Received master stop command
|
||||
I (4606) TWAI Listen Only: Received slave stop response
|
||||
I (5606) TWAI Listen Only: Received master ping
|
||||
I (5856) TWAI Listen Only: Received master ping
|
||||
I (5856) TWAI Listen Only: Received slave ping response
|
||||
I (6106) TWAI Listen Only: Received master start command
|
||||
I (6106) TWAI Listen Only: Received data value 728
|
||||
...
|
||||
I (8556) TWAI Listen Only: Received data value 973
|
||||
I (8556) TWAI Listen Only: Received master stop command
|
||||
I (8596) TWAI Listen Only: Received slave stop response
|
||||
I (9596) TWAI Listen Only: Received master ping
|
||||
I (9846) TWAI Listen Only: Received master ping
|
||||
I (9846) TWAI Listen Only: Received slave ping response
|
||||
I (10096) TWAI Listen Only: Received master start command
|
||||
I (10096) TWAI Listen Only: Received data value 1127
|
||||
...
|
||||
I (12546) TWAI Listen Only: Received data value 1372
|
||||
I (12546) TWAI Listen Only: Received master stop command
|
||||
I (12586) TWAI Listen Only: Received slave stop response
|
||||
I (12586) TWAI Listen Only: Driver stopped
|
||||
I (12586) TWAI Listen Only: Driver uninstalled
|
||||
|
||||
```
|
||||
|
||||
## Example Breakdown
|
||||
|
||||
The communication between the Network Master and Network Slave execute the following steps over multiple iterations:
|
||||
|
||||
1. Both master and slave go through install and start their TWAI drivers independently.
|
||||
2. The master repeatedly sends **PING** messages until it receives a **PING_RESP** (ping response message) from the slave. The slave will only send a **PING_RESP** message when it receives a **PING** message from the master.
|
||||
3. Once the master has received the **PING_RESP** from the slave, it will send a **START_CMD** message to the slave.
|
||||
4. Upon receiving the **START_CMD** message, the slave will start transmitting **DATA** messages until the master sends a **STOP_CMD**. The master will send the **STOP_CMD** after receiving N **DATA** messages from the slave (N = 50 by default).
|
||||
5. When the slave receives the **STOP_CMD**, it will confirm that it has stopped by sending a **STOP_RESP** message to the master.
|
@@ -6,9 +6,9 @@ from threading import Thread
|
||||
import ttfw_idf
|
||||
|
||||
# Define tuple of strings to expect for each DUT.
|
||||
master_expect = ("CAN Master: Driver installed", "CAN Master: Driver uninstalled")
|
||||
slave_expect = ("CAN Slave: Driver installed", "CAN Slave: Driver uninstalled")
|
||||
listen_only_expect = ("CAN Listen Only: Driver installed", "CAN Listen Only: Driver uninstalled")
|
||||
master_expect = ("TWAI Master: Driver installed", "TWAI Master: Driver uninstalled")
|
||||
slave_expect = ("TWAI Slave: Driver installed", "TWAI Slave: Driver uninstalled")
|
||||
listen_only_expect = ("TWAI Listen Only: Driver installed", "TWAI Listen Only: Driver uninstalled")
|
||||
|
||||
|
||||
def dut_thread_callback(**kwargs):
|
||||
@@ -27,15 +27,15 @@ def dut_thread_callback(**kwargs):
|
||||
result[0] = True
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_CAN2')
|
||||
def test_can_network_example(env, extra_data):
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_TWAI2')
|
||||
def test_twai_network_example(env, extra_data):
|
||||
|
||||
# Get device under test. "dut1", "dut2", and "dut3" must be properly defined in EnvConfig
|
||||
dut_master = env.get_dut("dut1", "examples/peripherals/can/can_network/can_network_master",
|
||||
dut_master = env.get_dut("dut1", "examples/peripherals/twai/twai_network/twai_network_master",
|
||||
dut_class=ttfw_idf.ESP32DUT)
|
||||
dut_slave = env.get_dut("dut2", "examples/peripherals/can/can_network/can_network_slave",
|
||||
dut_slave = env.get_dut("dut2", "examples/peripherals/twai/twai_network/twai_network_slave",
|
||||
dut_class=ttfw_idf.ESP32DUT)
|
||||
dut_listen_only = env.get_dut("dut3", "examples/peripherals/can/can_network/can_network_listen_only",
|
||||
dut_listen_only = env.get_dut("dut3", "examples/peripherals/twai/twai_network/twai_network_listen_only",
|
||||
dut_class=ttfw_idf.ESP32DUT)
|
||||
|
||||
# Flash app onto each DUT, each DUT is reset again at the start of each thread
|
||||
@@ -71,4 +71,4 @@ def test_can_network_example(env, extra_data):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_can_network_example()
|
||||
test_twai_network_example()
|
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(can_network_listen_only)
|
||||
project(twai_network_listen_only)
|
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := can_network_listen_only
|
||||
PROJECT_NAME := twai_network_listen_only
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "twai_network_example_listen_only_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TX_GPIO_NUM
|
||||
int "TX GPIO number"
|
||||
default 20 if IDF_TARGET_ESP32S2
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the TX signal. Connect the
|
||||
TX signal to your transceiver.
|
||||
|
||||
config EXAMPLE_RX_GPIO_NUM
|
||||
int "RX GPIO number"
|
||||
default 21 if IDF_TARGET_ESP32S2
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the RX signal. Connect the
|
||||
RX signal to your transceiver.
|
||||
|
||||
endmenu
|
@@ -1,4 +1,4 @@
|
||||
/* CAN Network Listen Only Example
|
||||
/* TWAI Network Listen Only Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following example demonstrates a Listen Only node in a CAN network. The
|
||||
* Listen Only node will not take part in any CAN bus activity (no acknowledgments
|
||||
* The following example demonstrates a Listen Only node in a TWAI network. The
|
||||
* Listen Only node will not take part in any TWAI bus activity (no acknowledgments
|
||||
* and no error frames). This example will execute multiple iterations, with each
|
||||
* iteration the Listen Only node will do the following:
|
||||
* 1) Listen for ping and ping response
|
||||
@@ -25,15 +25,15 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/can.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
//Example Configuration
|
||||
#define NO_OF_ITERS 3
|
||||
#define RX_TASK_PRIO 9
|
||||
#define TX_GPIO_NUM 21
|
||||
#define RX_GPIO_NUM 22
|
||||
#define EXAMPLE_TAG "CAN Listen Only"
|
||||
#define TX_GPIO_NUM CONFIG_EXAMPLE_TX_GPIO_NUM
|
||||
#define RX_GPIO_NUM CONFIG_EXAMPLE_RX_GPIO_NUM
|
||||
#define EXAMPLE_TAG "TWAI Listen Only"
|
||||
|
||||
#define ID_MASTER_STOP_CMD 0x0A0
|
||||
#define ID_MASTER_START_CMD 0x0A1
|
||||
@@ -42,21 +42,21 @@
|
||||
#define ID_SLAVE_DATA 0x0B1
|
||||
#define ID_SLAVE_PING_RESP 0x0B2
|
||||
|
||||
static const can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
|
||||
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
//Set TX queue length to 0 due to listen only mode
|
||||
static const can_general_config_t g_config = {.mode = CAN_MODE_LISTEN_ONLY,
|
||||
static const twai_general_config_t g_config = {.mode = TWAI_MODE_LISTEN_ONLY,
|
||||
.tx_io = TX_GPIO_NUM, .rx_io = RX_GPIO_NUM,
|
||||
.clkout_io = CAN_IO_UNUSED, .bus_off_io = CAN_IO_UNUSED,
|
||||
.clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED,
|
||||
.tx_queue_len = 0, .rx_queue_len = 5,
|
||||
.alerts_enabled = CAN_ALERT_NONE,
|
||||
.alerts_enabled = TWAI_ALERT_NONE,
|
||||
.clkout_divider = 0};
|
||||
|
||||
static SemaphoreHandle_t rx_sem;
|
||||
|
||||
/* --------------------------- Tasks and Functions -------------------------- */
|
||||
|
||||
static void can_receive_task(void *arg)
|
||||
static void twai_receive_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(rx_sem, portMAX_DELAY);
|
||||
bool start_cmd = false;
|
||||
@@ -64,8 +64,8 @@ static void can_receive_task(void *arg)
|
||||
uint32_t iterations = 0;
|
||||
|
||||
while (iterations < NO_OF_ITERS) {
|
||||
can_message_t rx_msg;
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_message_t rx_msg;
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_MASTER_PING) {
|
||||
ESP_LOGI(EXAMPLE_TAG, "Received master ping");
|
||||
} else if (rx_msg.identifier == ID_SLAVE_PING_RESP) {
|
||||
@@ -100,22 +100,22 @@ static void can_receive_task(void *arg)
|
||||
void app_main(void)
|
||||
{
|
||||
rx_sem = xSemaphoreCreateBinary();
|
||||
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
//Install and start CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_install(&g_config, &t_config, &f_config));
|
||||
//Install and start TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver installed");
|
||||
ESP_ERROR_CHECK(can_start());
|
||||
ESP_ERROR_CHECK(twai_start());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
|
||||
xSemaphoreGive(rx_sem); //Start RX task
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
xSemaphoreTake(rx_sem, portMAX_DELAY); //Wait for RX task to complete
|
||||
|
||||
//Stop and uninstall CAN driver
|
||||
ESP_ERROR_CHECK(can_stop());
|
||||
//Stop and uninstall TWAI driver
|
||||
ESP_ERROR_CHECK(twai_stop());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
|
||||
ESP_ERROR_CHECK(can_driver_uninstall());
|
||||
ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
//Cleanup
|
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(can_network_master)
|
||||
project(twai_network_master)
|
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := can_network_slave
|
||||
PROJECT_NAME := twai_network_master
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "twai_network_example_master_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TX_GPIO_NUM
|
||||
int "TX GPIO number"
|
||||
default 20 if IDF_TARGET_ESP32S2
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the TX signal. Connect the
|
||||
TX signal to your transceiver.
|
||||
|
||||
config EXAMPLE_RX_GPIO_NUM
|
||||
int "RX GPIO number"
|
||||
default 21 if IDF_TARGET_ESP32S2
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the RX signal. Connect the
|
||||
RX signal to your transceiver.
|
||||
|
||||
endmenu
|
@@ -1,4 +1,4 @@
|
||||
/* CAN Network Master Example
|
||||
/* TWAI Network Master Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following example demonstrates a master node in a CAN network. The master
|
||||
* The following example demonstrates a master node in a TWAI network. The master
|
||||
* node is responsible for initiating and stopping the transfer of data messages.
|
||||
* The example will execute multiple iterations, with each iteration the master
|
||||
* node will do the following:
|
||||
* 1) Start the CAN driver
|
||||
* 1) Start the TWAI driver
|
||||
* 2) Repeatedly send ping messages until a ping response from slave is received
|
||||
* 3) Send start command to slave and receive data messages from slave
|
||||
* 4) Send stop command to slave and wait for stop response from slave
|
||||
* 5) Stop the CAN driver
|
||||
* 5) Stop the TWAI driver
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/can.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
//Example Configuration
|
||||
@@ -37,9 +37,9 @@
|
||||
#define RX_TASK_PRIO 8
|
||||
#define TX_TASK_PRIO 9
|
||||
#define CTRL_TSK_PRIO 10
|
||||
#define TX_GPIO_NUM 21
|
||||
#define RX_GPIO_NUM 22
|
||||
#define EXAMPLE_TAG "CAN Master"
|
||||
#define TX_GPIO_NUM CONFIG_EXAMPLE_TX_GPIO_NUM
|
||||
#define RX_GPIO_NUM CONFIG_EXAMPLE_RX_GPIO_NUM
|
||||
#define EXAMPLE_TAG "TWAI Master"
|
||||
|
||||
#define ID_MASTER_STOP_CMD 0x0A0
|
||||
#define ID_MASTER_START_CMD 0x0A1
|
||||
@@ -62,15 +62,15 @@ typedef enum {
|
||||
RX_TASK_EXIT,
|
||||
} rx_task_action_t;
|
||||
|
||||
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
|
||||
static const can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, CAN_MODE_NORMAL);
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NORMAL);
|
||||
|
||||
static const can_message_t ping_message = {.identifier = ID_MASTER_PING, .data_length_code = 0,
|
||||
static const twai_message_t ping_message = {.identifier = ID_MASTER_PING, .data_length_code = 0,
|
||||
.ss = 1, .data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
static const can_message_t start_message = {.identifier = ID_MASTER_START_CMD, .data_length_code = 0,
|
||||
static const twai_message_t start_message = {.identifier = ID_MASTER_START_CMD, .data_length_code = 0,
|
||||
.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
static const can_message_t stop_message = {.identifier = ID_MASTER_STOP_CMD, .data_length_code = 0,
|
||||
static const twai_message_t stop_message = {.identifier = ID_MASTER_STOP_CMD, .data_length_code = 0,
|
||||
.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
|
||||
static QueueHandle_t tx_task_queue;
|
||||
@@ -81,7 +81,7 @@ static SemaphoreHandle_t done_sem;
|
||||
|
||||
/* --------------------------- Tasks and Functions -------------------------- */
|
||||
|
||||
static void can_receive_task(void *arg)
|
||||
static void twai_receive_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
rx_task_action_t action;
|
||||
@@ -90,8 +90,8 @@ static void can_receive_task(void *arg)
|
||||
if (action == RX_RECEIVE_PING_RESP) {
|
||||
//Listen for ping response from slave
|
||||
while (1) {
|
||||
can_message_t rx_msg;
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_message_t rx_msg;
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_SLAVE_PING_RESP) {
|
||||
xSemaphoreGive(stop_ping_sem);
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
@@ -102,8 +102,8 @@ static void can_receive_task(void *arg)
|
||||
//Receive data messages from slave
|
||||
uint32_t data_msgs_rec = 0;
|
||||
while (data_msgs_rec < NO_OF_DATA_MSGS) {
|
||||
can_message_t rx_msg;
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_message_t rx_msg;
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_SLAVE_DATA) {
|
||||
uint32_t data = 0;
|
||||
for (int i = 0; i < rx_msg.data_length_code; i++) {
|
||||
@@ -117,8 +117,8 @@ static void can_receive_task(void *arg)
|
||||
} else if (action == RX_RECEIVE_STOP_RESP) {
|
||||
//Listen for stop response from slave
|
||||
while (1) {
|
||||
can_message_t rx_msg;
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_message_t rx_msg;
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_SLAVE_STOP_RESP) {
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
break;
|
||||
@@ -131,7 +131,7 @@ static void can_receive_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_transmit_task(void *arg)
|
||||
static void twai_transmit_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
tx_task_action_t action;
|
||||
@@ -141,16 +141,16 @@ static void can_transmit_task(void *arg)
|
||||
//Repeatedly transmit pings
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitting ping");
|
||||
while (xSemaphoreTake(stop_ping_sem, 0) != pdTRUE) {
|
||||
can_transmit(&ping_message, portMAX_DELAY);
|
||||
twai_transmit(&ping_message, portMAX_DELAY);
|
||||
vTaskDelay(pdMS_TO_TICKS(PING_PERIOD_MS));
|
||||
}
|
||||
} else if (action == TX_SEND_START_CMD) {
|
||||
//Transmit start command to slave
|
||||
can_transmit(&start_message, portMAX_DELAY);
|
||||
twai_transmit(&start_message, portMAX_DELAY);
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitted start command");
|
||||
} else if (action == TX_SEND_STOP_CMD) {
|
||||
//Transmit stop command to slave
|
||||
can_transmit(&stop_message, portMAX_DELAY);
|
||||
twai_transmit(&stop_message, portMAX_DELAY);
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitted stop command");
|
||||
} else if (action == TX_TASK_EXIT) {
|
||||
break;
|
||||
@@ -159,14 +159,14 @@ static void can_transmit_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_control_task(void *arg)
|
||||
static void twai_control_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
tx_task_action_t tx_action;
|
||||
rx_task_action_t rx_action;
|
||||
|
||||
for (int iter = 0; iter < NO_OF_ITERS; iter++) {
|
||||
ESP_ERROR_CHECK(can_start());
|
||||
ESP_ERROR_CHECK(twai_start());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
|
||||
//Start transmitting pings, and listen for ping response
|
||||
@@ -190,7 +190,7 @@ static void can_control_task(void *arg)
|
||||
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
|
||||
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
ESP_ERROR_CHECK(can_stop());
|
||||
ESP_ERROR_CHECK(twai_stop());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
|
||||
vTaskDelay(pdMS_TO_TICKS(ITER_DELAY_MS));
|
||||
}
|
||||
@@ -213,19 +213,19 @@ void app_main(void)
|
||||
ctrl_task_sem = xSemaphoreCreateBinary();
|
||||
stop_ping_sem = xSemaphoreCreateBinary();
|
||||
done_sem = xSemaphoreCreateBinary();
|
||||
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_transmit_task, "CAN_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_control_task, "CAN_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_control_task, "TWAI_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
//Install CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_install(&g_config, &t_config, &f_config));
|
||||
//Install TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver installed");
|
||||
|
||||
xSemaphoreGive(ctrl_task_sem); //Start control task
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for completion
|
||||
|
||||
//Uninstall CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_uninstall());
|
||||
//Uninstall TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
//Cleanup
|
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(can_network_slave)
|
||||
project(twai_network_slave)
|
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := can_network_master
|
||||
PROJECT_NAME := twai_network_slave
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "twai_network_example_slave_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TX_GPIO_NUM
|
||||
int "TX GPIO number"
|
||||
default 20 if IDF_TARGET_ESP32S2
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the TX signal. Connect the
|
||||
TX signal to your transceiver.
|
||||
|
||||
config EXAMPLE_RX_GPIO_NUM
|
||||
int "RX GPIO number"
|
||||
default 21 if IDF_TARGET_ESP32S2
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the RX signal. Connect the
|
||||
RX signal to your transceiver.
|
||||
|
||||
endmenu
|
@@ -1,4 +1,4 @@
|
||||
/* CAN Network Slave Example
|
||||
/* TWAI Network Slave Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following example demonstrates a slave node in a CAN network. The slave
|
||||
* The following example demonstrates a slave node in a TWAI network. The slave
|
||||
* node is responsible for sending data messages to the master. The example will
|
||||
* execute multiple iterations, with each iteration the slave node will do the
|
||||
* following:
|
||||
* 1) Start the CAN driver
|
||||
* 1) Start the TWAI driver
|
||||
* 2) Listen for ping messages from master, and send ping response
|
||||
* 3) Listen for start command from master
|
||||
* 4) Send data messages to master and listen for stop command
|
||||
* 5) Send stop response to master
|
||||
* 6) Stop the CAN driver
|
||||
* 6) Stop the TWAI driver
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/can.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
//Example Configuration
|
||||
@@ -38,9 +38,9 @@
|
||||
#define RX_TASK_PRIO 8 //Receiving task priority
|
||||
#define TX_TASK_PRIO 9 //Sending task priority
|
||||
#define CTRL_TSK_PRIO 10 //Control task priority
|
||||
#define TX_GPIO_NUM 21
|
||||
#define RX_GPIO_NUM 22
|
||||
#define EXAMPLE_TAG "CAN Slave"
|
||||
#define TX_GPIO_NUM CONFIG_EXAMPLE_TX_GPIO_NUM
|
||||
#define RX_GPIO_NUM CONFIG_EXAMPLE_RX_GPIO_NUM
|
||||
#define EXAMPLE_TAG "TWAI Slave"
|
||||
|
||||
#define ID_MASTER_STOP_CMD 0x0A0
|
||||
#define ID_MASTER_START_CMD 0x0A1
|
||||
@@ -63,15 +63,15 @@ typedef enum {
|
||||
RX_TASK_EXIT,
|
||||
} rx_task_action_t;
|
||||
|
||||
static const can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, CAN_MODE_NORMAL);
|
||||
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
|
||||
static const can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const can_message_t ping_resp = {.identifier = ID_SLAVE_PING_RESP, .data_length_code = 0,
|
||||
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NORMAL);
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const twai_message_t ping_resp = {.identifier = ID_SLAVE_PING_RESP, .data_length_code = 0,
|
||||
.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
static const can_message_t stop_resp = {.identifier = ID_SLAVE_STOP_RESP, .data_length_code = 0,
|
||||
static const twai_message_t stop_resp = {.identifier = ID_SLAVE_STOP_RESP, .data_length_code = 0,
|
||||
.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
//Data bytes of data message will be initialized in the transmit task
|
||||
static can_message_t data_message = {.identifier = ID_SLAVE_DATA, .data_length_code = 4,
|
||||
static twai_message_t data_message = {.identifier = ID_SLAVE_DATA, .data_length_code = 4,
|
||||
.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};
|
||||
|
||||
static QueueHandle_t tx_task_queue;
|
||||
@@ -82,16 +82,16 @@ static SemaphoreHandle_t done_sem;
|
||||
|
||||
/* --------------------------- Tasks and Functions -------------------------- */
|
||||
|
||||
static void can_receive_task(void *arg)
|
||||
static void twai_receive_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
rx_task_action_t action;
|
||||
xQueueReceive(rx_task_queue, &action, portMAX_DELAY);
|
||||
if (action == RX_RECEIVE_PING) {
|
||||
//Listen for pings from master
|
||||
can_message_t rx_msg;
|
||||
twai_message_t rx_msg;
|
||||
while (1) {
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_MASTER_PING) {
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
break;
|
||||
@@ -99,9 +99,9 @@ static void can_receive_task(void *arg)
|
||||
}
|
||||
} else if (action == RX_RECEIVE_START_CMD) {
|
||||
//Listen for start command from master
|
||||
can_message_t rx_msg;
|
||||
twai_message_t rx_msg;
|
||||
while (1) {
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_MASTER_START_CMD) {
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
break;
|
||||
@@ -109,9 +109,9 @@ static void can_receive_task(void *arg)
|
||||
}
|
||||
} else if (action == RX_RECEIVE_STOP_CMD) {
|
||||
//Listen for stop command from master
|
||||
can_message_t rx_msg;
|
||||
twai_message_t rx_msg;
|
||||
while (1) {
|
||||
can_receive(&rx_msg, portMAX_DELAY);
|
||||
twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (rx_msg.identifier == ID_MASTER_STOP_CMD) {
|
||||
xSemaphoreGive(stop_data_sem);
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
@@ -125,7 +125,7 @@ static void can_receive_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_transmit_task(void *arg)
|
||||
static void twai_transmit_task(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
tx_task_action_t action;
|
||||
@@ -133,7 +133,7 @@ static void can_transmit_task(void *arg)
|
||||
|
||||
if (action == TX_SEND_PING_RESP) {
|
||||
//Transmit ping response to master
|
||||
can_transmit(&ping_resp, portMAX_DELAY);
|
||||
twai_transmit(&ping_resp, portMAX_DELAY);
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitted ping response");
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
} else if (action == TX_SEND_DATA) {
|
||||
@@ -145,7 +145,7 @@ static void can_transmit_task(void *arg)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
data_message.data[i] = (sensor_data >> (i * 8)) & 0xFF;
|
||||
}
|
||||
can_transmit(&data_message, portMAX_DELAY);
|
||||
twai_transmit(&data_message, portMAX_DELAY);
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitted data value %d", sensor_data);
|
||||
vTaskDelay(pdMS_TO_TICKS(DATA_PERIOD_MS));
|
||||
if (xSemaphoreTake(stop_data_sem, 0) == pdTRUE) {
|
||||
@@ -154,7 +154,7 @@ static void can_transmit_task(void *arg)
|
||||
}
|
||||
} else if (action == TX_SEND_STOP_RESP) {
|
||||
//Transmit stop response to master
|
||||
can_transmit(&stop_resp, portMAX_DELAY);
|
||||
twai_transmit(&stop_resp, portMAX_DELAY);
|
||||
ESP_LOGI(EXAMPLE_TAG, "Transmitted stop response");
|
||||
xSemaphoreGive(ctrl_task_sem);
|
||||
} else if (action == TX_TASK_EXIT) {
|
||||
@@ -164,14 +164,14 @@ static void can_transmit_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_control_task(void *arg)
|
||||
static void twai_control_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
tx_task_action_t tx_action;
|
||||
rx_task_action_t rx_action;
|
||||
|
||||
for (int iter = 0; iter < NO_OF_ITERS; iter++) {
|
||||
ESP_ERROR_CHECK(can_start());
|
||||
ESP_ERROR_CHECK(twai_start());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
|
||||
//Listen of pings from master
|
||||
@@ -202,14 +202,14 @@ static void can_control_task(void *arg)
|
||||
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
//Wait for bus to become free
|
||||
can_status_info_t status_info;
|
||||
can_get_status_info(&status_info);
|
||||
twai_status_info_t status_info;
|
||||
twai_get_status_info(&status_info);
|
||||
while (status_info.msgs_to_tx > 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
can_get_status_info(&status_info);
|
||||
twai_get_status_info(&status_info);
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(can_stop());
|
||||
ESP_ERROR_CHECK(twai_stop());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
|
||||
vTaskDelay(pdMS_TO_TICKS(ITER_DELAY_MS));
|
||||
}
|
||||
@@ -240,19 +240,19 @@ void app_main(void)
|
||||
ctrl_task_sem = xSemaphoreCreateBinary();
|
||||
stop_data_sem = xSemaphoreCreateBinary();;
|
||||
done_sem = xSemaphoreCreateBinary();;
|
||||
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_transmit_task, "CAN_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_control_task, "CAN_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_control_task, "TWAI_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
//Install CAN driver, trigger tasks to start
|
||||
ESP_ERROR_CHECK(can_driver_install(&g_config, &t_config, &f_config));
|
||||
//Install TWAI driver, trigger tasks to start
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver installed");
|
||||
|
||||
xSemaphoreGive(ctrl_task_sem); //Start Control task
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for tasks to complete
|
||||
|
||||
//Uninstall CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_uninstall());
|
||||
//Uninstall TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
//Cleanup
|
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(can_self_test_example)
|
||||
project(twai_self_test_example)
|
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := can_self_test_example
|
||||
PROJECT_NAME := twai_self_test_example
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
83
examples/peripherals/twai/twai_self_test/README.md
Normal file
83
examples/peripherals/twai/twai_self_test/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# TWAI Self Test Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The TWAI Self Test Example demonstrates how a node can transmit TWAI messages to itself using the TWAI driver's "No Acknowledgement" mode and Self Reception Requests. The Self Test Example can be run as a simple test to determine whether a target (ESP32 or ESP32-S2) is properly connected to a working external transceiver.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example requires only a single target (e.g., an ESP32 or ESP32-S2). The target must be connected to an external transceiver (e.g., a SN65HVD23X transceiver). This connection usually consists of a TX and an RX signal.
|
||||
|
||||
Note: If you don't have an external transceiver, this example can still be run by simply connecting the TX GPIO and RX GPIO with a jumper.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Set the target of the build (where `{IDF_TARGET}` stands for the target chip such as `eszp32` or `esp32s2`).
|
||||
* Then run `menuconfig` to configure the example.
|
||||
|
||||
```
|
||||
idf.py set-target {IDF_TARGET}
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Under `Example Configuration`, configure the pin assignments using the options `TX GPIO Number` and `RX GPIO Number` according to how the target was connected to the transceiver. By default, `TX GPIO Number` and `RX GPIO Number` are set to the following values:
|
||||
* On the ESP32, `TX GPIO Number` and `RX GPIO Number` default to `21` and `22` respectively
|
||||
* On the ESP32-S2, `TX GPIO Number` and `RX GPIO Number` default to `20` and `21` respectively
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (345) TWAI Self Test: Driver installed
|
||||
I (345) TWAI Self Test: Driver started
|
||||
I (355) TWAI Self Test: Msg received - Data = 0
|
||||
...
|
||||
I (1335) TWAI Self Test: Msg received - Data = 99
|
||||
I (1335) TWAI Self Test: Driver stopped
|
||||
I (1435) TWAI Self Test: Driver started
|
||||
I (1435) TWAI Self Test: Msg received - Data = 0
|
||||
...
|
||||
I (2425) TWAI Self Test: Msg received - Data = 99
|
||||
I (2425) TWAI Self Test: Driver stopped
|
||||
I (2525) TWAI Self Test: Driver started
|
||||
I (2525) TWAI Self Test: Msg received - Data = 0
|
||||
...
|
||||
I (3515) TWAI Self Test: Msg received - Data = 99
|
||||
I (3515) TWAI Self Test: Driver stopped
|
||||
I (3615) TWAI Self Test: Driver uninstalled
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```
|
||||
I (345) TWAI Self Test: Driver installed
|
||||
I (345) TWAI Self Test: Driver started
|
||||
```
|
||||
|
||||
If the TWAI driver is installed and started but no messages are received, check that the target is correctly connected to the external transceiver, and that the external transceiver is operating properly (i.e., properly powered and not in sleep mode).
|
||||
|
||||
## Example Breakdown
|
||||
|
||||
The TWAI Self Test Example will do multiple iterations of the following steps:
|
||||
|
||||
1. Install the TWAI driver
|
||||
2. Start the TWAI driver
|
||||
3. Simultaneously transmit and receive multiple messages using the self reception request.
|
||||
4. Stop the TWAI driver
|
||||
5. Repeat steps 2 to 4 for multiple iterations
|
||||
6. Uninstall the TWAI driver
|
23
examples/peripherals/twai/twai_self_test/example_test.py
Normal file
23
examples/peripherals/twai/twai_self_test/example_test.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Need Python 3 string formatting functions
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
# TWAI Self Test Example constants
|
||||
STR_EXPECT = ("TWAI Self Test: Driver installed", "TWAI Self Test: Driver uninstalled")
|
||||
EXPECT_TIMEOUT = 20
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_TWAI1')
|
||||
def test_twai_self_test_example(env, extra_data):
|
||||
# Get device under test, flash and start example. "dut1" must be defined in EnvConfig
|
||||
dut = env.get_dut('dut1', 'examples/peripherals/twai/twai_self_test', dut_class=ttfw_idf.ESP32DUT)
|
||||
dut.start_app()
|
||||
|
||||
for string in STR_EXPECT:
|
||||
dut.expect(string, timeout=EXPECT_TIMEOUT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_twai_self_test_example()
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "twai_self_test_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_TX_GPIO_NUM
|
||||
int "TX GPIO number"
|
||||
default 20 if IDF_TARGET_ESP32S2
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the TX signal. Connect the
|
||||
TX signal to your transceiver.
|
||||
|
||||
config EXAMPLE_RX_GPIO_NUM
|
||||
int "RX GPIO number"
|
||||
default 21 if IDF_TARGET_ESP32S2
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
help
|
||||
This option selects the GPIO pin used for the RX signal. Connect the
|
||||
RX signal to your transceiver.
|
||||
|
||||
endmenu
|
@@ -1,4 +1,4 @@
|
||||
/* CAN Self Test Example
|
||||
/* TWAI Self Test Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following example demonstrates the self testing capabilities of the CAN
|
||||
* The following example demonstrates the self testing capabilities of the TWAI
|
||||
* peripheral by utilizing the No Acknowledgment Mode and Self Reception Request
|
||||
* capabilities. This example can be used to verify that the CAN peripheral and
|
||||
* capabilities. This example can be used to verify that the TWAI peripheral and
|
||||
* its connections to the external transceiver operates without issue. The example
|
||||
* will execute multiple iterations, each iteration will do the following:
|
||||
* 1) Start the CAN driver
|
||||
* 1) Start the TWAI driver
|
||||
* 2) Transmit and receive 100 messages using self reception request
|
||||
* 3) Stop the CAN driver
|
||||
* 3) Stop the TWAI driver
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -25,28 +25,28 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/can.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
|
||||
//Example Configurations
|
||||
#define NO_OF_MSGS 100
|
||||
#define NO_OF_ITERS 3
|
||||
#define TX_GPIO_NUM 21
|
||||
#define RX_GPIO_NUM 22
|
||||
#define TX_GPIO_NUM CONFIG_EXAMPLE_TX_GPIO_NUM
|
||||
#define RX_GPIO_NUM CONFIG_EXAMPLE_RX_GPIO_NUM
|
||||
#define TX_TASK_PRIO 8 //Sending task priority
|
||||
#define RX_TASK_PRIO 9 //Receiving task priority
|
||||
#define CTRL_TSK_PRIO 10 //Control task priority
|
||||
#define MSG_ID 0x555 //11 bit standard format ID
|
||||
#define EXAMPLE_TAG "CAN Self Test"
|
||||
#define EXAMPLE_TAG "TWAI Self Test"
|
||||
|
||||
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
//Filter all other IDs except MSG_ID
|
||||
static const can_filter_config_t f_config = {.acceptance_code = (MSG_ID << 21),
|
||||
.acceptance_mask = ~(CAN_STD_ID_MASK << 21),
|
||||
static const twai_filter_config_t f_config = {.acceptance_code = (MSG_ID << 21),
|
||||
.acceptance_mask = ~(TWAI_STD_ID_MASK << 21),
|
||||
.single_filter = true};
|
||||
//Set to NO_ACK mode due to self testing with single module
|
||||
static const can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, CAN_MODE_NO_ACK);
|
||||
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NO_ACK);
|
||||
|
||||
static SemaphoreHandle_t tx_sem;
|
||||
static SemaphoreHandle_t rx_sem;
|
||||
@@ -55,30 +55,30 @@ static SemaphoreHandle_t done_sem;
|
||||
|
||||
/* --------------------------- Tasks and Functions -------------------------- */
|
||||
|
||||
static void can_transmit_task(void *arg)
|
||||
static void twai_transmit_task(void *arg)
|
||||
{
|
||||
can_message_t tx_msg = {.data_length_code = 1, .identifier = MSG_ID, .self = 1};
|
||||
twai_message_t tx_msg = {.data_length_code = 1, .identifier = MSG_ID, .self = 1};
|
||||
for (int iter = 0; iter < NO_OF_ITERS; iter++) {
|
||||
xSemaphoreTake(tx_sem, portMAX_DELAY);
|
||||
for (int i = 0; i < NO_OF_MSGS; i++) {
|
||||
//Transmit messages using self reception request
|
||||
tx_msg.data[0] = i;
|
||||
ESP_ERROR_CHECK(can_transmit(&tx_msg, portMAX_DELAY));
|
||||
ESP_ERROR_CHECK(twai_transmit(&tx_msg, portMAX_DELAY));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_receive_task(void *arg)
|
||||
static void twai_receive_task(void *arg)
|
||||
{
|
||||
can_message_t rx_message;
|
||||
twai_message_t rx_message;
|
||||
|
||||
for (int iter = 0; iter < NO_OF_ITERS; iter++) {
|
||||
xSemaphoreTake(rx_sem, portMAX_DELAY);
|
||||
for (int i = 0; i < NO_OF_MSGS; i++) {
|
||||
//Receive message and print message data
|
||||
ESP_ERROR_CHECK(can_receive(&rx_message, portMAX_DELAY));
|
||||
ESP_ERROR_CHECK(twai_receive(&rx_message, portMAX_DELAY));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Msg received - Data = %d", rx_message.data[0]);
|
||||
}
|
||||
//Indicate to control task all messages received for this iteration
|
||||
@@ -87,12 +87,12 @@ static void can_receive_task(void *arg)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void can_control_task(void *arg)
|
||||
static void twai_control_task(void *arg)
|
||||
{
|
||||
xSemaphoreTake(ctrl_sem, portMAX_DELAY);
|
||||
for (int iter = 0; iter < NO_OF_ITERS; iter++) {
|
||||
//Start CAN Driver for this iteration
|
||||
ESP_ERROR_CHECK(can_start());
|
||||
//Start TWAI Driver for this iteration
|
||||
ESP_ERROR_CHECK(twai_start());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
|
||||
//Trigger TX and RX tasks to start transmitting/receiving
|
||||
@@ -100,7 +100,7 @@ static void can_control_task(void *arg)
|
||||
xSemaphoreGive(tx_sem);
|
||||
xSemaphoreTake(ctrl_sem, portMAX_DELAY); //Wait for TX and RX tasks to finish iteration
|
||||
|
||||
ESP_ERROR_CHECK(can_stop()); //Stop the CAN Driver
|
||||
ESP_ERROR_CHECK(twai_stop()); //Stop the TWAI Driver
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); //Delay then start next iteration
|
||||
}
|
||||
@@ -116,12 +116,12 @@ void app_main(void)
|
||||
ctrl_sem = xSemaphoreCreateBinary();
|
||||
done_sem = xSemaphoreCreateBinary();
|
||||
|
||||
xTaskCreatePinnedToCore(can_control_task, "CAN_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_receive_task, "CAN_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(can_transmit_task, "CAN_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_control_task, "TWAI_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
//Install CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_install(&g_config, &t_config, &f_config));
|
||||
//Install TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver installed");
|
||||
|
||||
//Start control task
|
||||
@@ -129,8 +129,8 @@ void app_main(void)
|
||||
//Wait for all iterations and tasks to complete running
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY);
|
||||
|
||||
//Uninstall CAN driver
|
||||
ESP_ERROR_CHECK(can_driver_uninstall());
|
||||
//Uninstall TWAI driver
|
||||
ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
//Cleanup
|
Reference in New Issue
Block a user