2017-12-18 12:32:29 +00:00
|
|
|
/* CAN 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 CAN 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
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
#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/can.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 21
|
|
|
|
#define RX_GPIO_NUM 22
|
|
|
|
#define EXAMPLE_TAG "CAN 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 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 can_message_t ping_message = {.identifier = ID_MASTER_PING, .data_length_code = 0,
|
|
|
|
.flags = CAN_MSG_FLAG_SS, .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,
|
|
|
|
.flags = CAN_MSG_FLAG_NONE, .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,
|
|
|
|
.flags = CAN_MSG_FLAG_NONE, .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 can_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) {
|
|
|
|
can_message_t rx_msg;
|
|
|
|
can_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) {
|
|
|
|
can_message_t rx_msg;
|
|
|
|
can_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) {
|
|
|
|
can_message_t rx_msg;
|
|
|
|
can_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);
|
|
|
|
}
|
|
|
|
|
2019-02-11 06:57:43 +00:00
|
|
|
static void can_transmit_task(void *arg)
|
|
|
|
{
|
2017-12-18 12:32:29 +00:00
|
|
|
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) {
|
|
|
|
can_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);
|
|
|
|
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);
|
|
|
|
ESP_LOGI(EXAMPLE_TAG, "Transmitted stop command");
|
|
|
|
} else if (action == TX_TASK_EXIT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vTaskDelete(NULL);
|
|
|
|
}
|
|
|
|
|
2019-02-11 06:57:43 +00:00
|
|
|
static void can_control_task(void *arg)
|
|
|
|
{
|
2017-12-18 12:32:29 +00:00
|
|
|
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_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(can_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()
|
|
|
|
{
|
|
|
|
//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(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);
|
|
|
|
|
|
|
|
//Install CAN driver
|
|
|
|
ESP_ERROR_CHECK(can_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());
|
|
|
|
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);
|
|
|
|
}
|