diff --git a/examples/esp32can_rtos/esp32can_rtos.ino b/examples/esp32can_rtos/esp32can_rtos.ino new file mode 100644 index 0000000..9132b62 --- /dev/null +++ b/examples/esp32can_rtos/esp32can_rtos.ino @@ -0,0 +1,112 @@ +/* ESP32 Arduino CAN RTOS Example + * This example will send and receive messages on the CAN bus using RTOS tasks + * + * When controlling a device over CAN bus that device may expect a CAN message to be received at a specific frequency. + * Using RTOS tasks simplifies sending dataframes and makes the timing more consistent. + * + * An external transceiver is required and should be connected + * to the CAN_tx and CAN_rx gpio pins specified by CANInit. Be sure + * to use a 3.3V compatable transceiver such as the SN65HVD23x + * + */ + +#include +#include + +/* RTOS priorities, higher number is more important */ +#define CAN_TX_PRIORITY 3 +#define CAN_RX_PRIORITY 1 + +#define CAN_TX_RATE_ms 500 +#define CAN_RX_RATE_ms 1000 + +/* can frame to send */ +twai_message_t tx_frame; + +/* CAN RTOS callback functions */ +void canSend(void *pvParameters); +void canReceive(void *pvParameters); + +/* CAN RTOS task handles */ +static TaskHandle_t canTxTask = NULL; +static TaskHandle_t canRxTask = NULL; + +void setup() { + Serial.begin(115200); + Serial.println("ESP32-Arduino-CAN RTOS Example"); + + /* initialize and start, use pin 5 as CAN_tx and pin 4 as CAN_rx, CAN bus is set to 500kbps */ + ESP32Can.CANInit(GPIO_NUM_5, GPIO_NUM_4, ESP32CAN_SPEED_500KBPS); + + /* setup can send RTOS task */ + xTaskCreatePinnedToCore(canSend, /* callback function */ + "CAN TX", /* name of task */ + 1024, /* stack size (bytes in ESP32, words in FreeRTOS */ + NULL, /* parameter to pass to function */ + CAN_TX_PRIORITY, /* task priority (0 to configMAX_PRIORITES - 1 */ + &canTxTask, /* task handle */ + 1); /* CPU core, Arduino runs on 1 */ + + /* setup can receive RTOS task */ + xTaskCreatePinnedToCore(canReceive, /* callback function */ + "CAN RX", /* name of task */ + 2048, /* stack size (bytes in ESP32, words in FreeRTOS */ + NULL, /* parameter to pass to function */ + CAN_RX_PRIORITY, /* task priority (0 to configMAX_PRIORITES - 1 */ + &canRxTask, /* task handle */ + 1); /* CPU core, Arduino runs on 1 */ + + + /* setup can send frame */ + tx_frame.extd = 0; /* standard 11bit ID */ + tx_frame.identifier = 0x123; /* CAN ID */ + tx_frame.data_length_code = 8; /* 8 bytes of data */ + for (int8_t i= 0; i<8; i++) { + tx_frame.data[i] = 0xFF; /* pad frame with 0xFF */ + } +} + +void loop() { + /* place time in seconds into first two bytes of dataframe */ + uint16_t time = millis()/1000; + tx_frame.data[0] = highByte(time); + tx_frame.data[1] = lowByte(time); + + delay(500); +} + +/* CAN Send function called by RTOS can send task */ +void canSend(void *pvParameters) { + TickType_t xLastWakeTime; /* keep track of last time can message was sent */ + TickType_t xFrequency = CAN_TX_RATE_ms / portTICK_PERIOD_MS; /* set the transmit frequency */ + + /* this task will run forever at frequency set above + * to stop this task from running call vTaskSuspend(canTxTask) in the main loop */ + for (;;) { + ESP32Can.CANWriteFrame(&tx_frame); /* send dataframe */ + + vTaskDelayUntil(&xLastWakeTime, xFrequency); /* do something else until it is time to send again */ + /* the above delay function was used since it specifies an absolute wake time. + * Make sure the code in the forever for loop can run faster then desired send frequency or this task will take all of the CPU time available */ + } +} + +void canReceive(void *pvParameters) { + const TickType_t xDelay = CAN_RX_RATE_ms / portTICK_PERIOD_MS; + twai_message_t rx_frame; + + for (;;) { + if (ESP32CAN_OK == ESP32Can.CANReadFrame(&rx_frame)) { /* only print when CAN message is received*/ + Serial.print(rx_frame.identifier, HEX); /* print the CAN ID*/ + Serial.print(" "); + Serial.print(rx_frame.data_length_code); /* print number of bytes in data frame*/ + + for (int i=0; i