添加智能灯固件代码

This commit is contained in:
kerwincui
2021-07-13 17:14:51 +08:00
parent 332f74dd17
commit ecc0b91b8b
2568 changed files with 229441 additions and 0 deletions

View 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.

View File

@@ -0,0 +1,74 @@
# Need Python 3 string formatting functions
from __future__ import print_function
from threading import Thread
import ttfw_idf
# Define tuple of strings to expect for each DUT.
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):
# Parse keyword arguments
dut = kwargs['dut'] # Get DUT from kwargs
expected = kwargs['expected']
result = kwargs['result'] # Get result[out] from kwargs. MUST be of mutable type e.g. list
# Must reset again as flashing during start_app will reset multiple times, causing unexpected results
dut.reset()
for string in expected:
dut.expect(string, 20)
# Mark thread has run to completion without any exceptions
result[0] = True
@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/twai/twai_network/twai_network_master",
dut_class=ttfw_idf.ESP32DUT)
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/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
dut_master.start_app()
dut_slave.start_app()
dut_listen_only.start_app()
# Create dict of keyword arguments for each dut
results = [[False], [False], [False]]
master_kwargs = {"dut": dut_master, "result": results[0], "expected": master_expect}
slave_kwargs = {"dut": dut_slave, "result": results[1], "expected": slave_expect}
listen_only_kwargs = {"dut": dut_listen_only, "result": results[2], "expected": listen_only_expect}
# Create thread for each dut
dut_master_thread = Thread(target=dut_thread_callback, name="Master Thread", kwargs=master_kwargs)
dut_slave_thread = Thread(target=dut_thread_callback, name="Slave Thread", kwargs=slave_kwargs)
dut_listen_only_thread = Thread(target=dut_thread_callback, name="Listen Only Thread", kwargs=listen_only_kwargs)
# Start each thread
dut_listen_only_thread.start()
dut_master_thread.start()
dut_slave_thread.start()
# Wait for threads to complete
dut_listen_only_thread.join()
dut_master_thread.join()
dut_slave_thread.join()
# check each thread ran to completion
for result in results:
if result[0] is not True:
raise Exception("One or more threads did not run successfully")
if __name__ == '__main__':
test_twai_network_example()

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(twai_network_listen_only)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := twai_network_listen_only
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "twai_network_example_listen_only_main.c"
INCLUDE_DIRS ".")

View File

@@ -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

View File

@@ -0,0 +1,4 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@@ -0,0 +1,123 @@
/* TWAI Network Listen Only Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* 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
* 2) Listen for start command
* 3) Listen for data messages
* 4) Listen for stop and stop response
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.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 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
#define ID_MASTER_PING 0x0A2
#define ID_SLAVE_STOP_RESP 0x0B0
#define ID_SLAVE_DATA 0x0B1
#define ID_SLAVE_PING_RESP 0x0B2
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 twai_general_config_t g_config = {.mode = TWAI_MODE_LISTEN_ONLY,
.tx_io = TX_GPIO_NUM, .rx_io = RX_GPIO_NUM,
.clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED,
.tx_queue_len = 0, .rx_queue_len = 5,
.alerts_enabled = TWAI_ALERT_NONE,
.clkout_divider = 0};
static SemaphoreHandle_t rx_sem;
/* --------------------------- Tasks and Functions -------------------------- */
static void twai_receive_task(void *arg)
{
xSemaphoreTake(rx_sem, portMAX_DELAY);
bool start_cmd = false;
bool stop_resp = false;
uint32_t iterations = 0;
while (iterations < NO_OF_ITERS) {
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) {
ESP_LOGI(EXAMPLE_TAG, "Received slave ping response");
} else if (rx_msg.identifier == ID_MASTER_START_CMD) {
ESP_LOGI(EXAMPLE_TAG, "Received master start command");
start_cmd = true;
} else if (rx_msg.identifier == ID_SLAVE_DATA) {
uint32_t data = 0;
for (int i = 0; i < rx_msg.data_length_code; i++) {
data |= (rx_msg.data[i] << (i * 8));
}
ESP_LOGI(EXAMPLE_TAG, "Received data value %d", data);
} else if (rx_msg.identifier == ID_MASTER_STOP_CMD) {
ESP_LOGI(EXAMPLE_TAG, "Received master stop command");
} else if (rx_msg.identifier == ID_SLAVE_STOP_RESP) {
ESP_LOGI(EXAMPLE_TAG, "Received slave stop response");
stop_resp = true;
}
if (start_cmd && stop_resp) {
//Each iteration is complete after a start command and stop response is received
iterations++;
start_cmd = 0;
stop_resp = 0;
}
}
xSemaphoreGive(rx_sem);
vTaskDelete(NULL);
}
void app_main(void)
{
rx_sem = xSemaphoreCreateBinary();
xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
//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(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 TWAI driver
ESP_ERROR_CHECK(twai_stop());
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
ESP_ERROR_CHECK(twai_driver_uninstall());
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
//Cleanup
vSemaphoreDelete(rx_sem);
}

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(twai_network_master)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := twai_network_master
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "twai_network_example_master_main.c"
INCLUDE_DIRS ".")

View File

@@ -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

View File

@@ -0,0 +1,4 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@@ -0,0 +1,237 @@
/* TWAI Network Master Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* 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 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 TWAI driver
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/twai.h"
/* --------------------- Definitions and static variables ------------------ */
//Example Configuration
#define PING_PERIOD_MS 250
#define NO_OF_DATA_MSGS 50
#define NO_OF_ITERS 3
#define ITER_DELAY_MS 1000
#define RX_TASK_PRIO 8
#define TX_TASK_PRIO 9
#define CTRL_TSK_PRIO 10
#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
#define ID_MASTER_PING 0x0A2
#define ID_SLAVE_STOP_RESP 0x0B0
#define ID_SLAVE_DATA 0x0B1
#define ID_SLAVE_PING_RESP 0x0B2
typedef enum {
TX_SEND_PINGS,
TX_SEND_START_CMD,
TX_SEND_STOP_CMD,
TX_TASK_EXIT,
} tx_task_action_t;
typedef enum {
RX_RECEIVE_PING_RESP,
RX_RECEIVE_DATA,
RX_RECEIVE_STOP_RESP,
RX_TASK_EXIT,
} rx_task_action_t;
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 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 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 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;
static QueueHandle_t rx_task_queue;
static SemaphoreHandle_t stop_ping_sem;
static SemaphoreHandle_t ctrl_task_sem;
static SemaphoreHandle_t done_sem;
/* --------------------------- Tasks and Functions -------------------------- */
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_RESP) {
//Listen for ping response from slave
while (1) {
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);
break;
}
}
} else if (action == RX_RECEIVE_DATA) {
//Receive data messages from slave
uint32_t data_msgs_rec = 0;
while (data_msgs_rec < NO_OF_DATA_MSGS) {
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++) {
data |= (rx_msg.data[i] << (i * 8));
}
ESP_LOGI(EXAMPLE_TAG, "Received data value %d", data);
data_msgs_rec ++;
}
}
xSemaphoreGive(ctrl_task_sem);
} else if (action == RX_RECEIVE_STOP_RESP) {
//Listen for stop response from slave
while (1) {
twai_message_t rx_msg;
twai_receive(&rx_msg, portMAX_DELAY);
if (rx_msg.identifier == ID_SLAVE_STOP_RESP) {
xSemaphoreGive(ctrl_task_sem);
break;
}
}
} else if (action == RX_TASK_EXIT) {
break;
}
}
vTaskDelete(NULL);
}
static void twai_transmit_task(void *arg)
{
while (1) {
tx_task_action_t action;
xQueueReceive(tx_task_queue, &action, portMAX_DELAY);
if (action == TX_SEND_PINGS) {
//Repeatedly transmit pings
ESP_LOGI(EXAMPLE_TAG, "Transmitting ping");
while (xSemaphoreTake(stop_ping_sem, 0) != pdTRUE) {
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
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
twai_transmit(&stop_message, portMAX_DELAY);
ESP_LOGI(EXAMPLE_TAG, "Transmitted stop command");
} else if (action == TX_TASK_EXIT) {
break;
}
}
vTaskDelete(NULL);
}
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(twai_start());
ESP_LOGI(EXAMPLE_TAG, "Driver started");
//Start transmitting pings, and listen for ping response
tx_action = TX_SEND_PINGS;
rx_action = RX_RECEIVE_PING_RESP;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
//Send Start command to slave, and receive data messages
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
tx_action = TX_SEND_START_CMD;
rx_action = RX_RECEIVE_DATA;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
//Send Stop command to slave when enough data messages have been received. Wait for stop response
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
tx_action = TX_SEND_STOP_CMD;
rx_action = RX_RECEIVE_STOP_RESP;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
ESP_ERROR_CHECK(twai_stop());
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
vTaskDelay(pdMS_TO_TICKS(ITER_DELAY_MS));
}
//Stop TX and RX tasks
tx_action = TX_TASK_EXIT;
rx_action = RX_TASK_EXIT;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
//Delete Control task
xSemaphoreGive(done_sem);
vTaskDelete(NULL);
}
void app_main(void)
{
//Create tasks, queues, and semaphores
rx_task_queue = xQueueCreate(1, sizeof(rx_task_action_t));
tx_task_queue = xQueueCreate(1, sizeof(tx_task_action_t));
ctrl_task_sem = xSemaphoreCreateBinary();
stop_ping_sem = xSemaphoreCreateBinary();
done_sem = xSemaphoreCreateBinary();
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 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 TWAI driver
ESP_ERROR_CHECK(twai_driver_uninstall());
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
//Cleanup
vQueueDelete(rx_task_queue);
vQueueDelete(tx_task_queue);
vSemaphoreDelete(ctrl_task_sem);
vSemaphoreDelete(stop_ping_sem);
vSemaphoreDelete(done_sem);
}

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(twai_network_slave)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := twai_network_slave
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "twai_network_example_slave_main.c"
INCLUDE_DIRS ".")

View File

@@ -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

View File

@@ -0,0 +1,4 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@@ -0,0 +1,264 @@
/* TWAI Network Slave Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* 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 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 TWAI driver
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/twai.h"
/* --------------------- Definitions and static variables ------------------ */
//Example Configuration
#define DATA_PERIOD_MS 50
#define NO_OF_ITERS 3
#define ITER_DELAY_MS 1000
#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 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
#define ID_MASTER_PING 0x0A2
#define ID_SLAVE_STOP_RESP 0x0B0
#define ID_SLAVE_DATA 0x0B1
#define ID_SLAVE_PING_RESP 0x0B2
typedef enum {
TX_SEND_PING_RESP,
TX_SEND_DATA,
TX_SEND_STOP_RESP,
TX_TASK_EXIT,
} tx_task_action_t;
typedef enum {
RX_RECEIVE_PING,
RX_RECEIVE_START_CMD,
RX_RECEIVE_STOP_CMD,
RX_TASK_EXIT,
} rx_task_action_t;
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 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 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;
static QueueHandle_t rx_task_queue;
static SemaphoreHandle_t ctrl_task_sem;
static SemaphoreHandle_t stop_data_sem;
static SemaphoreHandle_t done_sem;
/* --------------------------- Tasks and Functions -------------------------- */
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
twai_message_t rx_msg;
while (1) {
twai_receive(&rx_msg, portMAX_DELAY);
if (rx_msg.identifier == ID_MASTER_PING) {
xSemaphoreGive(ctrl_task_sem);
break;
}
}
} else if (action == RX_RECEIVE_START_CMD) {
//Listen for start command from master
twai_message_t rx_msg;
while (1) {
twai_receive(&rx_msg, portMAX_DELAY);
if (rx_msg.identifier == ID_MASTER_START_CMD) {
xSemaphoreGive(ctrl_task_sem);
break;
}
}
} else if (action == RX_RECEIVE_STOP_CMD) {
//Listen for stop command from master
twai_message_t rx_msg;
while (1) {
twai_receive(&rx_msg, portMAX_DELAY);
if (rx_msg.identifier == ID_MASTER_STOP_CMD) {
xSemaphoreGive(stop_data_sem);
xSemaphoreGive(ctrl_task_sem);
break;
}
}
} else if (action == RX_TASK_EXIT) {
break;
}
}
vTaskDelete(NULL);
}
static void twai_transmit_task(void *arg)
{
while (1) {
tx_task_action_t action;
xQueueReceive(tx_task_queue, &action, portMAX_DELAY);
if (action == TX_SEND_PING_RESP) {
//Transmit ping response to master
twai_transmit(&ping_resp, portMAX_DELAY);
ESP_LOGI(EXAMPLE_TAG, "Transmitted ping response");
xSemaphoreGive(ctrl_task_sem);
} else if (action == TX_SEND_DATA) {
//Transmit data messages until stop command is received
ESP_LOGI(EXAMPLE_TAG, "Start transmitting data");
while (1) {
//FreeRTOS tick count used to simulate sensor data
uint32_t sensor_data = xTaskGetTickCount();
for (int i = 0; i < 4; i++) {
data_message.data[i] = (sensor_data >> (i * 8)) & 0xFF;
}
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) {
break;
}
}
} else if (action == TX_SEND_STOP_RESP) {
//Transmit stop response to master
twai_transmit(&stop_resp, portMAX_DELAY);
ESP_LOGI(EXAMPLE_TAG, "Transmitted stop response");
xSemaphoreGive(ctrl_task_sem);
} else if (action == TX_TASK_EXIT) {
break;
}
}
vTaskDelete(NULL);
}
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(twai_start());
ESP_LOGI(EXAMPLE_TAG, "Driver started");
//Listen of pings from master
rx_action = RX_RECEIVE_PING;
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
//Send ping response
tx_action = TX_SEND_PING_RESP;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
//Listen for start command
rx_action = RX_RECEIVE_START_CMD;
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
//Start sending data messages and listen for stop command
tx_action = TX_SEND_DATA;
rx_action = RX_RECEIVE_STOP_CMD;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
//Send stop response
tx_action = TX_SEND_STOP_RESP;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
//Wait for bus to become free
twai_status_info_t status_info;
twai_get_status_info(&status_info);
while (status_info.msgs_to_tx > 0) {
vTaskDelay(pdMS_TO_TICKS(100));
twai_get_status_info(&status_info);
}
ESP_ERROR_CHECK(twai_stop());
ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
vTaskDelay(pdMS_TO_TICKS(ITER_DELAY_MS));
}
//Stop TX and RX tasks
tx_action = TX_TASK_EXIT;
rx_action = RX_TASK_EXIT;
xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
//Delete Control task
xSemaphoreGive(done_sem);
vTaskDelete(NULL);
}
void app_main(void)
{
//Add short delay to allow master it to initialize first
for (int i = 3; i > 0; i--) {
printf("Slave starting in %d\n", i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
//Create semaphores and tasks
tx_task_queue = xQueueCreate(1, sizeof(tx_task_action_t));
rx_task_queue = xQueueCreate(1, sizeof(rx_task_action_t));
ctrl_task_sem = xSemaphoreCreateBinary();
stop_data_sem = xSemaphoreCreateBinary();;
done_sem = xSemaphoreCreateBinary();;
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 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 TWAI driver
ESP_ERROR_CHECK(twai_driver_uninstall());
ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
//Cleanup
vSemaphoreDelete(ctrl_task_sem);
vSemaphoreDelete(stop_data_sem);
vSemaphoreDelete(done_sem);
vQueueDelete(tx_task_queue);
vQueueDelete(rx_task_queue);
}