Hi there! My first post ![]()
It looks like the ECC chip on the Giga R1 uses the same i2c bus as the Touch Panel on the Giga Display Shield: Wire1.
The ECC library (ArduinoECCX08) sets the Wire1 clock frequency to 1Mhz.
The Touch Panel library (Arduino_GigaDisplayTouch) sets the Wire1 clock frequency to 400khz.
I use the ECC chip for SSL connections via MQTT. And when I enable the Touch Panel the MQTT client wont connect about 50% of the times. I get a network error.
I suspect this is because the Touch Panel hijacks the Wire1 bus and the SSL client can not get information from the ECC chip.
My setup is as follows:
Hardware:
- Arduino Giga R1
- Arduino Giga Display Shield. Default connection on the back of the Giga R1
- Arduino Ethernet 2 Shield. Default connection on the top of the Giga R1
I have tried a lot over the last couple of months to fix this. I am a bit new to c++ and Arduino tho, so this is probably my fault ![]()
I also use the SD card on the Ethernet shield, but this, as far as I know, communicates via SPI.
I have tried creating locking logic for Wire1 with communication via RPC.
I have tried setting interrupt priority.
I have tried starting everything from scratch.
I have tried disabling everything else in my project.
I have tried to modify the libraries in question as well as extend them.
I have checked that it is not the MQTT broker that is rejecting the connection.
I also tried doing the same project on a MKR WiFi with an MKR ETH shield and ran into the same issue when I tried to add a keypad via i2c as it seems to conflict with the ECC chip.
Here is my chat with ChatGPT from the last two days regarding this issue.
What am I missing here?
M7 main:
#include "main.h"
String currentCPU() {
if (HAL_GetCurrentCPUID() == CM7_CPUID) {
return "M7";
} else {
return "M4";
}
}
void setup() {
Serial.begin(115200);
while (!Serial){};
// Arduino GIGA needs some time here for some reason to enable Serial monitor
delay(1000);
Serial.print("Booting ");
Serial.print(currentCPU());
Serial.println(" chip");
Serial.println("SETUP DISPLAY");
setupDisplay();
RPC.begin();
// Let RPC bind some essential functions on M4
delay(1100);
setupTouch();
}
void loop() {
loopDisplay();
String buffer = "";
while (RPC.available()) {
buffer += (char)RPC.read(); // Fill the buffer with characters
}
if (buffer.length() > 0) {
Serial.print(buffer);
}
}
M7 display:
#include "display.h"
Arduino_H7_Video Display(480, 800, GigaDisplayShield);
unsigned long lastDisplayUpdate = 0;
unsigned long displayUpdateDelay = 10; // Max (min) every 5 ms
void handleContactItemPress(lv_event_t * e) {
Serial.println("Contact clicked!");
lv_obj_t * table = lv_event_get_current_target_obj(e);
uint32_t col;
uint32_t row;
lv_table_get_selected_cell(table, &row, &col);
// TODO: figure how to use user data here instead of text value
const char *text = lv_table_get_cell_value(table, row, col);
Serial.println(text);
}
void setupDisplay() {
Display.begin();
// Setup lvgl
lv_init();
// Setup ui exported from eez studio
ui_init();
constexpr int numberOfContacts = 12;
lv_obj_t * contactsTable = objects.contacts_table;
lv_table_set_column_width(contactsTable, 0, 476);
lv_table_set_row_count(contactsTable, numberOfContacts); /*Not required but avoids a lot of memory reallocation lv_table_set_set_value*/
lv_table_set_column_count(contactsTable, 1);
lv_obj_add_event(contactsTable, handleContactItemPress, LV_EVENT_VALUE_CHANGED, NULL);
// We do not need this after the next eez studio export
lv_obj_set_style_text_font(contactsTable, &ui_font_playfair_48, LV_PART_MAIN | LV_STATE_DEFAULT);
for (int i = 0; i < numberOfContacts; i++) {
lv_table_set_cell_value_fmt(contactsTable, i, 0, "Mike Portnoy");
// TODO: figure out how to get this value with lv_table_get_cell_user_data it is a void pointer
// std::string userId = "123";
// lv_table_set_cell_user_data(contactsTable, i, 0, &userId);
}
}
void loopDisplay() {
// const unsigned long now = millis();
if ((millis() - lastDisplayUpdate) > displayUpdateDelay) {
lv_timer_handler();
ui_tick();
lastDisplayUpdate = millis();
}
}
void displayDoorOpen() {
}
void displayInvalidCode() {
}
M7 touch:
#include "touch.h"
// Uses Wire1, same as ECC chip, sets clock to 400khz which interferes with ECC chip and makes SSL connections unstable
Arduino_GigaDisplayTouch TouchDetector;
void setupTouch() {
Serial.println("SETUP TOUCH");
TouchDetector.begin();
}
M4 main:
#include "main.h"
String currentCPU() {
if (HAL_GetCurrentCPUID() == CM7_CPUID) {
return "M7";
} else {
return "M4";
}
}
void setup() {
RPC.begin();
// Arduino GIGA needs some time here for some reason to enable Serial monitor
delay(1000);
RPC.print("Hello from M4");
RPC.println(millis());
RPC.println(currentCPU());
RPC.println("MAIN SETUP");
RPC.println("ECC SETUP");
eccSetup();
RPC.println("ECC ENSURE LOCK");
ensureEccLock();
const String serial = getSerialNumber();
RPC.println("S/N: " + serial);
// Ethernet requires ecc to get serial number for consistent MAC
const IPAddress localIp = ethernetInterfaceSetup();
RPC.println("IP: " + localIp.toString());
delay(500); // Allow Ethernet to stabilize
RPC.println("NTP SETUP");
// Bear SSL needs NTP time to make http requests
ntpSetup();
getAndCacheWorldTime();
const String utcTime = getUTCTime();
RPC.println(utcTime);
RPC.println("SD SETUP");
sdCardSetup();
RPC.println("SSL SETUP");
sslClientSetup();
RPC.println("ENSURE REGISTRATION");
ensureCsrAndId(); // Get id from API and generate CSR
ensureIoTSetup(); // Setup certificate, policies and Thing in aws iot and save certificate
RPC.println("MQTT SETUP");
mqttClientSetup();
RPC.println("All good");
}
void loop() {
ensureMqttClient();
loopMqtt();
}
M4 ECC:
#include "ecc.h"
void eccSetup() {
int retryCount = 0;
constexpr int maxRetries = 5;
// Uses Wire1, same as Touch panel, sets clock to 1Mhz which collides with touch panel that wants to run at 400khz
while (!ECCX08.begin() && retryCount < maxRetries) {
RPC.println("No ECCX08 present!");
delay(1000);
retryCount++;
}
if (retryCount == maxRetries) {
RPC.println("ECC initialization failed after retries.");
// TODO: Handle failure, e.g., reboot or enter safe mode
}
}
String getSerialNumber() {
String serialNumber = ECCX08.serialNumber();
return serialNumber;
}
int getRandomNumber(const long max) {
const int res = ECCX08.random(max);
return res;
}
bool ensureEccLock() {
if (!ECCX08.locked()) {
RPC.println("ECCX08 is not locked, locking ...");
if (!ECCX08.writeConfiguration(ECCX08_DEFAULT_TLS_CONFIG)) {
RPC.println("Writing ECCX08 configuration failed!");
return false;
}
if (!ECCX08.lock()) {
RPC.println("Locking ECCX08 configuration failed!");
return false;
}
}
RPC.println("ECCX08 is locked :)");
return true;
}
M4 ethernet:
#include "ethernet_interface.h"
// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);
// Placeholder
uint8_t uniqueMac[] = {0, 0, 0, 0, 0, 0};
IPAddress ethernetInterfaceSetup () {
getPersistentUniqueMac(uniqueMac);
IPAddress localIp;
// EthernetClass::init(5); // MKR ETH Shield
EthernetClass::init(ETH_CS_PIN); // GIGA + Ethernet 2 shield
// start the Ethernet connection:
RPC.println("Initialize Ethernet with DHCP");
RPC.print("With MAC: ");
for (const unsigned char i : uniqueMac) RPC.print(i, HEX);
RPC.println();
if (EthernetClass::begin(uniqueMac) == 0) {
RPC.println("Failed to configure Ethernet using DHCP");
// Check for Ethernet hardware present
if (EthernetClass::hardwareStatus() == EthernetNoHardware) {
RPC.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (EthernetClass::linkStatus() == LinkOFF) {
RPC.println("Ethernet cable is not connected.");
}
// try to configure using IP address instead of DHCP:
EthernetClass::begin(uniqueMac, ip, myDns);
} else {
RPC.print("DHCP assigned IP ");
RPC.println(EthernetClass::localIP());
localIp = EthernetClass::localIP();
}
// give the Ethernet shield a second to initialize:
delay(1000);
return localIp;
}
M4 ssl:
#include "ssl_client.h"
EthernetClient ethernetClient;
BearSSLClient sslClient(ethernetClient);
void sslClientSetup() {
// The SSL lib needs unix time from a NTP server to validate something
ArduinoBearSSL.onGetTime(getUnixTime);
}
void sslClientSetCertificate(const String& certificate) {
const size_t str_len = certificate.length();
char cert_str[str_len];
certificate.toCharArray(cert_str, str_len);
sslClient.setEccSlot(0, cert_str);
}
M4 MQTT:
#include "mqtt_client.h"
unsigned long lastMqttUpdate = 0;
unsigned long mqttUpdateDelay = 250;
constexpr char broker[] = SECRET_IOT_ENDPOINT;
MqttClient mqttClient(sslClient);
String getDeviceIotTopic() {
return ioAccessLockTopicDomain + "/" + getDeviceId();
}
void mqttClientSetup() {
const String certificate = sdCardReadFile(certificatePemFileName);
if (certificate.length() == 0) {
RPC.println("No IOT certificate found");
return;
}
sslClientSetCertificate(certificate);
const String deviceId = getDeviceId();
mqttClient.setId(deviceId);
mqttClient.onMessage(onMessageReceived);
}
// In main loop
void ensureMqttClient() {
if (!mqttClient.connected()) {
RPC.println("MQTT not connected");
connectMQTT();
}
}
void loopMqtt() {
if ((millis() - lastMqttUpdate) > mqttUpdateDelay) {
mqttClient.poll();
lastMqttUpdate = millis();
}
}
void connectMQTT() {
RPC.print("Attempting to connect to MQTT broker...");
RPC.println(broker);
int retryCount = 0;
const int maxRetries = 5;
while (!mqttClient.connect(broker, 8883)) {
int errorCode = mqttClient.connectError();
RPC.print("MQTT connection failed. Error code: ");
RPC.println(errorCode);
switch (errorCode) {
case 1:
RPC.println("Error: Incorrect protocol version.");
break;
case 2:
RPC.println("Error: Invalid client identifier.");
break;
case 3:
RPC.println("Error: Server unavailable.");
break;
case 4:
RPC.println("Error: Bad username or password.");
break;
case 5:
RPC.println("Error: Not authorized.");
break;
default:
RPC.println("Error: Unknown error.");
break;
}
if (retryCount >= maxRetries) {
RPC.println("Max retries reached. Giving up.");
return;
}
int backoffTime = pow(2, retryCount) * 1000;
RPC.print("Retrying in ");
RPC.print(backoffTime);
RPC.println(" ms");
delay(backoffTime);
retryCount++;
}
RPC.println("Connected to MQTT broker.");
// subscribe to a topic
const String topic = getDeviceIotTopic();
RPC.println("Subscribing to topic: " + topic);
mqttClient.subscribe(topic);
}
void publishMessage(const String& subTopic, const String& input) {
RPC.println("Publishing message");
String const topic = ioAccessControlTopicDomain + "/" + subTopic;
RPC.println(topic);
constexpr bool retained = false;
constexpr int qos = 1;
constexpr bool dup = false;
JsonDocument inputDoc;
inputDoc["message"] = input;
String payload = "";
serializeJson(inputDoc, payload);
const size_t contentLength = payload.length();
mqttClient.beginMessage(topic, contentLength, retained, qos, dup);
mqttClient.print(payload);
mqttClient.endMessage();
}
void onMessageReceived(const int messageSize) {
String payload = "";
while (mqttClient.available()) {
payload += static_cast<char>(mqttClient.read());
}
handleMqttMessage(payload);
}
void onMqttDisconnect(int reason) {
RPC.print("MQTT disconnected. Reason: ");
RPC.println(reason);
}
The M4 processor usually freezes on "Attempting to connect to MQTT broker..." or it gives an error code "-2". Both from the connectMQTT() function.