Type de processeur
esp32s2
Description de la carte de développement
esp32 - s2 mini / LOLIN S2 MINI
Configuration matérielle
Port USB natif branché sur l'ordinateur
Nom de l'IDE
Arduino IDE
Version
v1.8.18
Système opérateur
Windows 10
Bibliothèques utilisées
esp32 by Espressif systems version 2.0.8
Description
Bonjour
Je cherche à récupérer les informations du canbus confort en 125kbit d'une voiture à l'aide d'un ESP32 LOLIN S2 MINI.
Voici ce que j'ai déjà fait :
- j'ai réussi à lire les données de la voiture et à trouver le bon id de frame de canbus que je devrais utiliser dans mon code. Mais le problème est que j'ai réussi cela avec une carte CANBed de Seeed Studio – Kit de développement de bus CAN pour Arduino (ATmega32U4 avec MCP2515 et MCP2551)
- Cette carte est sur une base de ATmega32U4 avec le bootloader Arduino Leonardo couplée à un Contrôleur de bus CAN MCP2515 et émetteur-récepteur de bus CAN MCP2551
- J'ai utilisé ce code pour récupérer les informations de la climatisation dont j'avais besoin et cela fonctionne parfaitement
/////////////////////
// Libraries //
/////////////////////
#include <SPI.h>
#include <Wire.h>
#include <mcp2515.h> // https://github.com/autowp/arduino-mcp2515 + https://github.com/watterott/Arduino-Libs/tree/master/digitalWriteFast
/////////////////////
// Configuration //
/////////////////////
#define CS_PIN_CAN0 17
#define SERIAL_SPEED 115200
#define CAN_SPEED CAN_125KBPS // Entertainment CAN bus - Low speed
#define CAN_FREQ MCP_16MHZ // Switch to 8MHZ if you have a 8Mhz module
////////////////////
// Initialization //
////////////////////
MCP2515 CAN0(CS_PIN_CAN0); // CAN-BUS Shield N°1
////////////////////
// Variables //
////////////////////
String LeftTemp;
String RightTemp;
// CAN-BUS Messages
struct can_frame canMsgRcv;
void setup() {
// Initalize Serial for debug
Serial.begin(SERIAL_SPEED);
// CAN-BUS from car
Serial.print("Initialization CAN0");
CAN0.reset();
CAN0.setBitrate(CAN_SPEED, CAN_FREQ);
while (CAN0.setNormalMode() != MCP2515::ERROR_OK) {
delay(100);
}
}
void loop() {
// Receive CAN messages from the car
if (CAN0.readMessage( & canMsgRcv) == MCP2515::ERROR_OK) {
int id = canMsgRcv.can_id;
int len = canMsgRcv.can_dlc;
if (id == 464){
char tmp[3];
snprintf(tmp, 3, "%02X", canMsgRcv.data[5]);
LeftTemp = String (tmp);
Serial.print("LeftTemp = ");
Serial.println(LeftTemp);
Serial.println(tmp);
snprintf(tmp, 3, "%02X", canMsgRcv.data[6]);
RightTemp = String (tmp);
Serial.print("RightTemp = ");
Serial.println(RightTemp);
Serial.println(tmp);
Serial.println();
}
}
}
- Je précise que ce code est une adaptation et simplification d'un code récupéré sur internet. Je ne m'en octroie nullement la propriété.
Venons en désormais au pourquoi du passage en ESP32 :
- Pour des raisons de disponibilité de taille mémoire et de rapidité de traitement de travail (même si dans ce projet cela n'était pas forcement nécessaire) je suis donc parti sur une solution d'ESP32 qui propose des cartes avec 4Mo de mémoire voir plus pour une taille assez réduite
- Voici pourquoi j'ai choisi un ESP32-S2 mini car j'ai des animations en .gif à faire tourner dans mon projet
- Cette partie est OK avec l'ESP32-S2
- Il ne me reste plus qu'à récupérer le signal de can bus précédemment évoqué et tester, avec succès, avec la carte Léonardo
- Et c'est là que les choses se compliquent. Afin de récupérer le signal canbus avec un ESP32, il est conseillé d'utiliser un trancreicever du type SN65HVD230 Can Board Connecting MCUs à mettre au niveau des broches TX et RX de la carte
- J'avais trouvé cela sur ce site : Démo 31 : Comment utiliser l'interface CAN Arduino ESP32
- J'ai donc acheté les composants nécessaires et réalisé ce montage :
- J'ai ensuite charger le code pour ESP32 qui permet de traiter le signal canbus renommé TWAI
/* ESP32 TWAI receive example.
Receive messages and sends them over serial.
Connect a CAN bus transceiver to the RX/TX pins.
For example: SN65HVD230
TWAI_MODE_LISTEN_ONLY is used so that the TWAI controller will not influence the bus.
The API gives other possible speeds and alerts:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html
Example output from a can bus message:
-> Message received
-> Message is in Standard Format
-> ID: 604
-> Byte: 0 = 00, 1 = 0f, 2 = 13, 3 = 02, 4 = 00, 5 = 00, 6 = 08, 7 = 00
Example output with alerts:
-> Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.
-> Bus error count: 171
-> Alert: The RX queue is full causing a received frame to be lost.
-> RX buffered: 4 RX missed: 46 RX overrun 0
created 05-11-2022 by Stephan Martin (designer2k2)
*/
#include "driver/twai.h"
// Pins used to connect to CAN bus transceiver:
#define RX_PIN 37
#define TX_PIN 39
// Intervall:
#define POLLING_RATE_MS 1000
static bool driver_installed = false;
void setup() {
// Start Serial:
delay (5000);
Serial.begin(115200);
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_LISTEN_ONLY);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS(); //Look in the api-reference for other speed sets.
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
Serial.println("Driver installed");
} else {
Serial.println("Failed to install driver");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
Serial.println("Driver started");
} else {
Serial.println("Failed to start driver");
return;
}
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
Serial.println("CAN Alerts reconfigured");
} else {
Serial.println("Failed to reconfigure alerts");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
}
static void handle_rx_message(twai_message_t& message) {
// Process received message
if (message.extd) {
Serial.println("Message is in Extended Format");
} else {
Serial.println("Message is in Standard Format");
}
Serial.printf("ID: %x\nByte:", message.identifier);
if (!(message.rtr)) {
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf(" %d = %02x,", i, message.data[i]);
}
Serial.println("");
}
}
void loop() {
if (!driver_installed) {
// Driver not installed
delay(1000);
return;
}
// Check if alert happened
uint32_t alerts_triggered;
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
twai_status_info_t twaistatus;
twai_get_status_info(&twaistatus);
// Handle alerts
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
Serial.println("Alert: TWAI controller has become error passive.");
}
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.");
Serial.printf("Bus error count: %d\n", twaistatus.bus_error_count);
}
if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
Serial.println("Alert: The RX queue is full causing a received frame to be lost.");
Serial.printf("RX buffered: %d\t", twaistatus.msgs_to_rx);
Serial.printf("RX missed: %d\t", twaistatus.rx_missed_count);
Serial.printf("RX overrun %d\n", twaistatus.rx_overrun_count);
}
// Check if message is received
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
// One or more messages received. Handle all.
twai_message_t message;
while (twai_receive(&message, 0) == ESP_OK) {
handle_rx_message(message);
}
}
}
- Cela n'a évidemment pas fonctionné
- En mettant un delay de 5000 ms en début du void setup() j'ai bien les messages d'initialisations qui remontent correctement :
--- Driver installed
--- Driver started
--- CAN Alerts reconfigured - Mais je n'ai que ça et parfois le message d'erreur "Alert: The RX queue is full causing a received frame to be lost." lorsque je déconnecte et reconnecte les fils du bus can
- J'en ai donc déduit que les pins TX et RX étaient mal configurés
Venons en désormais à la problématique :
- l'opération qui semblait simple s'est avéré être un casse tête. Mais où sont les PIN RX et TX sur une carte LOLIN S2 mini?
- Et bien la réponse est qu'il n'y en a pas. Enfin il n'y en a pas en natif. Mais ce que j'ai découvert c'est qu'il est possible d'adresser les pins TX et RX à n'importe quel GPIO des cartes ESP32
Comment utiliser avec esp32S2 l'affichage sur port série? - #21 by al1fch - Et bien devinez quoi. J'ai essayé plein de choses et je n'arrive pas à avoir de retour dans la console série en faisant des simples tests afin de savoir si les pins sont bien attribués
- Voici ce que j'ai testé et qui devrait me renvoyer des informations dans la console
#include <Arduino.h>
// There are two ways to make this sketch work:
// By physically connecting the pins 4 and 5 and then create a physical UART loopback,
// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the
// same loopback internally.
#define USE_INTERNAL_PIN_LOOPBACK 0 // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally
#define DATA_SIZE 26 // 26 bytes is a lower than RX FIFO size (127 bytes)
#define BAUD 115200 // Any baudrate from 300 to 115200
#define TEST_UART 1 // Serial1 will be used for the loopback testing with different RX FIFO FULL values
#define RXPIN 37 // GPIO 4 => RX for Serial1
#define TXPIN 39 // GPIO 5 => TX for Serial1
uint8_t fifoFullTestCases[] = {120, 20, 5, 1};
// volatile declaration will avoid any compiler optimization when reading variable values
volatile size_t sent_bytes = 0, received_bytes = 0;
void onReceiveFunction(void) {
// This is a callback function that will be activated on UART RX events
size_t available = Serial1.available();
received_bytes += available;
Serial.printf("onReceive Callback:: There are %d bytes available: ", available);
while (available --) {
Serial.print((char)Serial1.read());
}
Serial.println();
}
void setup() {
// UART0 will be used to log information into Serial Monitor
Serial.begin(115200);
// UART1 will have its RX<->TX cross connected
// GPIO4 <--> GPIO5 using external wire
Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
#if USE_INTERNAL_PIN_LOOPBACK
uart_internal_loopback(TEST_UART, RXPIN);
#endif
for (uint8_t i = 0; i < sizeof(fifoFullTestCases); i++) {
Serial.printf("\n\n================================\nTest Case #%d\n================================\n", i + 1);
// onReceive callback will be called on FIFO Full and RX timeout - default behaviour
testAndReport(fifoFullTestCases[i], false);
}
Serial.printf("\n\n================================\nTest Case #6\n================================\n");
// onReceive callback will be called just on RX timeout - using onlyOnTimeout = true
// FIFO Full parameter (5 bytes) won't matter for the execution of this test case
// because onReceive() uses only RX Timeout to be activated
testAndReport(5, true);
}
void loop() {
}
void testAndReport(uint8_t fifoFull, bool onlyOnTimeOut) {
// Let's send 125 bytes from Serial1 rx<->tx and mesaure time using diferent FIFO Full configurations
received_bytes = 0;
sent_bytes = DATA_SIZE; // 26 characters
uint8_t dataSent[DATA_SIZE + 1];
dataSent[DATA_SIZE] = '\0'; // string null terminator, for easy printing.
// initialize all data
for (uint8_t i = 0; i < DATA_SIZE; i++) {
dataSent[i] = 'A' + i; // fill it with characters A..Z
}
Serial.printf("\nTesting onReceive for receiving %d bytes at %d baud, using RX FIFO Full = %d.\n", sent_bytes, BAUD, fifoFull);
if (onlyOnTimeOut) {
Serial.println("onReceive is called just on RX Timeout!");
} else {
Serial.println("onReceive is called on both FIFO Full and RX Timeout events.");
}
Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it
Serial1.setRxFIFOFull(fifoFull); // testing diferent result based on FIFO Full setup
Serial1.onReceive(onReceiveFunction, onlyOnTimeOut); // sets a RX callback function for Serial 1
sent_bytes = Serial1.write(dataSent, DATA_SIZE); // ESP32 TX FIFO is about 128 bytes, 125 bytes will fit fine
Serial.printf("\nSent String: %s\n", dataSent);
while (received_bytes < sent_bytes) {
// just wait for receiving all byte in the callback...
}
Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sent_bytes);
Serial.printf("onReceive() has read a total of %d bytes\n", received_bytes);
Serial.println("========================\nFinished!");
Serial1.onReceive(NULL); // resets/disables the RX callback function for Serial 1
}
Ceci est le code d'exemple de la bibliothèque ESP32 de test d'émission / réception et ça ne fonctionne pas
- Vous pouvez constater que la pin RX est définie sur 37 et la pin TX sur 39
- J'ai bien évidemment testé aussi de définir ces pins dans le fichier C:\Users\username\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.8\variants\lolin_s2_mini\pins_arduino.h
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
// Default USB Settings
#define USB_VID 0x303a
#define USB_PID 0x80C2
#define USB_MANUFACTURER "WEMOS.CC"
#define USB_PRODUCT "LOLIN-S2-MINI"
#define USB_SERIAL "0"
// Default USB FirmwareMSC Settings
#define USB_FW_MSC_VENDOR_ID "ESP32-S2" //max 8 chars
#define USB_FW_MSC_PRODUCT_ID "Firmware MSC" //max 16 chars
#define USB_FW_MSC_PRODUCT_REVISION "1.23" //max 4 chars
#define USB_FW_MSC_VOLUME_NAME "S2-Firmware" //max 11 chars
#define USB_FW_MSC_SERIAL_NUMBER 0x00000000
#define EXTERNAL_NUM_INTERRUPTS 46
#define NUM_DIGITAL_PINS 48
#define NUM_ANALOG_INPUTS 20
#define analogInputToDigitalPin(p) (((p)<20)?(analogChannelToDigitalPin(p)):-1)
#define digitalPinToInterrupt(p) (((p)<48)?(p):-1)
#define digitalPinHasPWM(p) (p < 46)
static const uint8_t LED_BUILTIN = 15;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
static const uint8_t TX = 39;
static const uint8_t RX = 37;
static const uint8_t SDA = 33;
static const uint8_t SCL = 35;
static const uint8_t SS = 12;
static const uint8_t MOSI = 11;
static const uint8_t MISO = 9;
static const uint8_t SCK = 7;
static const uint8_t A0 = 1;
static const uint8_t A1 = 2;
static const uint8_t A2 = 3;
static const uint8_t A3 = 4;
static const uint8_t A4 = 5;
static const uint8_t A5 = 6;
static const uint8_t A6 = 7;
static const uint8_t A7 = 8;
static const uint8_t A8 = 9;
static const uint8_t A9 = 10;
static const uint8_t A10 = 11;
static const uint8_t A11 = 12;
static const uint8_t A12 = 13;
static const uint8_t A13 = 14;
static const uint8_t A14 = 15;
static const uint8_t A15 = 16;
static const uint8_t A16 = 17;
static const uint8_t A17 = 18;
static const uint8_t A18 = 19;
static const uint8_t A19 = 20;
static const uint8_t T1 = 1;
static const uint8_t T2 = 2;
static const uint8_t T3 = 3;
static const uint8_t T4 = 4;
static const uint8_t T5 = 5;
static const uint8_t T6 = 6;
static const uint8_t T7 = 7;
static const uint8_t T8 = 8;
static const uint8_t T9 = 9;
static const uint8_t T10 = 10;
static const uint8_t T11 = 11;
static const uint8_t T12 = 12;
static const uint8_t T13 = 13;
static const uint8_t T14 = 14;
static const uint8_t DAC1 = 17;
static const uint8_t DAC2 = 18;
#endif /* Pins_Arduino_h */
-
Pour cela j'ai réalisé le montage suivant comme définit dans le code
-
Malgré tout cela rien ne fonctionne
J'ai réalisé de multiples autres tests tous aussi infructueux que je ne vais pas détailler ici car le post commence à être long.
Je sollicite donc vos compétences afin de m'aider dans cette quête d'accomplissement de mon projet qui je le sens est proche du but.
Merci de m'avoir lu jusqu'au bout en espérant que cela puisse aussi aider d'autres personnes.
Strangistra





