text:
Arduino MKR wifi 1010 ssl certificate protection
I'm using Arduino IDE v2.1.1 and Arduino MKR wifi 1010. Everything works fine and at this moment I have a need to protect the wifi connection with ssl certificate. I have generated the ssl certificate using the openssl tool and now I have following files that needs to be set in the controller:

ca.crt
client.crt
client.key

how can I set these three files to the MKR wifi 1010 to enable the SSL certificate protected communication? I couldn't find the tutorial or example on the internet.
let me explain how I do that at the moment. I do have a valid self-signed CA certificate and I'm trying to establish a SSL / TLS connection using the CA sertificate only. This is my code which doesn't work unfortunately:
#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <ArduinoMqttClient.h>
#include <ArduinoBearSSL.h>
#include <ArduinoECCX08.h>
#include "secrets.h"

char wifiSsid[] = SECRET_WiFi_SSID;
char wifiPass[] = SECRET_WiFi_PASS;
char mqttUserId[] = MQTT_USERID;
char mqttPass[] = MQTT_PASS;
int status = WL_IDLE_STATUS;
const char* rootCAcertificate  = \
"-----BEGIN CERTIFICATE-----\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"-----END CERTIFICATE-----\n";

bool dev_debug_mode = IS_DEBUG;

WiFiClient    wifiClient;         // Used for the TCP socket connection
BearSSLClient bearSslClient(wifiClient); // Used for SSL/TLS connection, integrates with ECCX08
MqttClient    mqttClient(bearSslClient); // Used for MQTT protocol usage

const char mqttBroker[] = MQTT_BROKER_HOST;
int mqttPort = 8883;

const char deviceRegisterTopic[] = "device/register";

//set interval for sending the Observation (the measurement from the sensor) messages (milliseconds)
const long interval = 3000;

unsigned long previousMillis = 0;

bool deviceIsRegistered = false;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (dev_debug_mode && !Serial) {
    ; // wait for serial port to connect. Needed for native USB port only - development mode. It has to be removed when releasing to live!!!
  }

  // Check the crypto chip module presence (needed for BearSSL)
  if (!ECCX08.begin()) {
    Serial.println("No ECCX08 present!");
    while (1);
  }

  bearSslClient.setEccSlot(0, rootCAcertificate); // inserting a certificate into the slot 0 (zero)

  // ================ SSL SETUP ================
  // Set a callback to get the current time
  // (used to validate the servers certificate)
  ArduinoBearSSL.onGetTime(getTime);

  // attempt to connect to the Wifi network
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to network: ");
    Serial.println(wifiSsid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(wifiSsid, wifiPass);

    Serial.print("Attempt status: ");
    Serial.println(status);

    if(status != WL_CONNECTED) {
      // waiting 10 seconds before trying to connect if it is needed:
      delay(10000);
    }
  }

  // WiFi network connection established! sending some messages to the console
  Serial.println("You're connected to the network");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(mqttBroker);
  Serial.println(mqttPort);

  mqttClient.setId(mqttUserId);

  // adding first level of proptection using MQTT broker username and password
  mqttClient.setUsernamePassword(mqttUserId, mqttPass);

  delay(30000);
  while (!mqttClient.connect(mqttBroker, mqttPort)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    delay(10000);
  }

  // MQTT broker connection established! sending some messages to the console
  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
}

void loop() {

  // call poll() regularly to allow the library to send MQTT keep alive which
  // avoids being disconnected by the broker
  mqttClient.poll();

  // if this current device is not registered yet, registering the device for the first time
  if(!deviceIsRegistered) {
    Serial.print("Sending Device Register message to topic: ");
    Serial.println(deviceRegisterTopic);
    // DO SOMETHING
  }

  unsigned long currentMillis = millis();

  // sending the actual measurement data to the FHIR Server with some time interval, like few seconds. To be defined later.
  if (currentMillis - previousMillis >= interval) {

    // save the last time a message was sent
    previousMillis = currentMillis;

    Serial.println();
  }
}

// ================================== Auxiliary functions ===================================
unsigned long getTime() {
   Serial.print("Current WiFi time:");
   Serial.println(WiFi.getTime());
  // Get the current time from the WiFi module
  return WiFi.getTime();
}

in the code above, I'm using the BearSSLClient and the certificate is set manually (I prefer this way as it is more transparent for me) bearSslClient.setEccSlot(0, certificate); - this is how the certificate is set. Also I do the following call: ArduinoBearSSL.onGetTime(getTime); - to get the proper time. The CA certificate is validated using the openssl tool. It is a valid self-signed root certificate.   Please, any help is much appreciated. I'm really confused as it should work since the certificate is a valid self-signed certificate and it is confirmed and verified using the openssl tool. When something should work but it doesnt work and I don't have any details except the -2 error message it makes me feel completely crazy ((((
@b1n3t thank's dude for your help. I appreaciate that. Let me start with one thing, I do software developent for more than 16 years, but I was working with hardware like microcontrollers and i8086 architecture based hardware more than 10 years ago. I was never investigating the SSL /  TLS issues deeply. Now, I go through your questions one by one: yes, I'm sure that Arduino's internal clock is accurate because I have configured myself a mutual TLS connection to the AWS (Amazon) MQTT broker with this clock engaged and everything works fine. The private key might not be properly stored within the ECC608, this might be the issue because I'm not 100% sure that I've done that right. Yes, I have verified that mosquitto MQTT broker's domain and port are accessible from the device, because it connnects successfully without the mutual TLS. I can send message back anf force from the device to the mosquitto MQTT broker server without mutual TLS and without SSL. Yes, I have configured the linux server to enable the 8883 for external connection. I have used the MQTT Explorer tool to establish a mutual TLS connection using the CA root certificate, client and server certificates from another physical device over my LAN network, everything works smoothly, it connects with the CA and client certificate to the MQTT broker server and I can send and receive messages. All is good here. Let me capture the logs and get back. Broker is configured to trust the CA, however all the certificates are self-signed. I have been struggling with this for about five days now and I figured out few important things: the ECC608 is by default (from the factory) in the unlocked state, it can't be used until it is locked (manually from the code). The certificate sign request should be generated on the MRK WiFi 1010 device and the private key is stored internally within the MKR WiFi 1010 device, tha'ts very important detail. Afte that, the CSR should be passed to the certification provider and the sercret certificate should be generated based on that CSR (certificate sign request). Another very important detail is that the self-signed certificate that I'm using for the development might be an issue as it is marked ALWAYS as invalid just because it is self-signed.
update 22 September
I'm still struggling with this problem. At this moment, everything is setup and configured on the microcontroller side. The microcontroller can connect to any online test MQTT broker via ssl/tls protocol. I have checked that and double checked. Everything is good on the microcontroller side. My MQTT broker is configured to use TLS v 1.2 it is deployed live, the cetificate is valid, it is generated by the zerossl trusted authority and it just works. I can connect from the test clients to my Mosquitto MQTT broker. I have tried multiple clients and everythig works fine. At this point, I have verified that client is valid and server is valid, both can connect to another party using TLS secure protocol. But, when I'm trying to pair my microcontroller with my Mosquitto MQTT broker - TLS SSL error is thrown, saying that the handshake failed. ssl tls 1.2 error ACCEPT_SR_KEY_EXCH ssl handshake failure. I have tried to debug it using the Wireshark, but there are no details at all. when I try to debug the SSL/TLS using the Wireshark, I see that there is a Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done and it repeats in a sequence again:
Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done
Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done
Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done
any help is appreciated.

Can you provide me with the following details? I have also dealt with the -2 message recently so those might help troubleshooting. Are you sure that Arduino's internal clock is accurate? Are you storing your private key inside the ECC608? Error -2 means a connection issue at the socket level. Did you ensure your MQTT broker's domain and port are accessible from the device? Did you make sure that port 8883 is open and a firewall doesn't block MQTT traffic over SSL? Can you share your MQTT Broker logs? Can you capture SSL traffic with WireShark and share? Is the broker configured to trust CA?

@b1n3t really appreciate your input, can't answer in the comments because it has a limit of characters, that's why I have update the post with the answers.

seems like you have made quite a progress. Frankly, I believe that the problem lies behind not storing your private key in the ECC608.
If the private key is not correctly stored in the ECC608 TLS Handshake will fail. You mentioned the ECC608 is unlocked by default. You're correct that to use the secure functionalities of the chip, it has to be locked. However, as far as I know once it's locked, it can't be unlocked. Make sure you've followed the necessary steps to store your private key in the ECC608 and then locked it to secure the key. I think you can use ArduinoECCX08 library since it seems to have ECCX08.begin(), ECCX08.lock(), ECCX08.generatePrivateKey(slot) functions. Your approach to generating the CSR directly on the MKR WiFi 1010 device is on point. This method ensures the private key never leaves the device. Consequently, only the public part is sent to the CA, even if it's self-signed. With the CSR, obtain your device certificate. This certificate, coupled with the private key securely housed in the ECC608, should facilitate the TLS handshake.
TL;DR: Make sure that you've stored the private key appropriately in the ECC608. Before locking the ECC608, test to ensure that the private key functions as expected. Check your MQTT Broker Logs for further debugging (when provided and when I get time for that I will try my best to pinpoint the error) and try using WireShark to capture SSL traffic.
That is as far as my knowledge goes, all the best luck to you. I hope that I could be of help dude.

hi. can you please take a look at the updates in my question from today. This ssl/tls issue is still not solved and I don't have any idea how to handle that.

@SemenShekhovtsov i'm kinda busy for a couple of days, when i have time i will try my best to be of help.


text:
Arduino MKR WiFi 1010 memory management
according to the official documentation of the Arduino, the SRAM memory (which is allocated for the local variables) should be automatically released after calling any function. For example, I have a function memory_allocate_test2, which declares a large char array and this function is called in the loop(). I expect, that every time, after the function memory_allocate_test2 is executed, the SRAM memory that I allocated for the local variables within that function should be freed or released. However, it is not working like that. When I call that function in a loop() the microcontroller hangs and stops working because it runs out of the available SRAM memory. Let me provide an example code:
void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only - development mode. It has to be removed when releasing to live!!!
  }
}

void loop() {
  delay(2000);
  memory_allocate_test2();
}

void memory_allocate_test2() {
  Serial.println("memory_allocate_test2 STARTING ");
  display_freeram();
  Serial.println("------------------------------------------------------------");
  Serial.println("Allocating the memory for the MKR: ");
  char* memory_usage_test = new char[2000];
  Serial.println("Allocated memory!");
  display_freeram();
  Serial.println("------------------------------------------------------------");
}

extern "C" char* sbrk(int incr);

void display_freeram(){
  Serial.print(F("- SRAM left: "));
  Serial.println(freeRam());
}

int freeRam() {
  char top;
  return &top - reinterpret_cast<char*>(sbrk(0));
}

why it doesn't work as it states in the documentation? what I'm doing wrong? why the SRAM memory is not released each time after the memory_allocate_test2 function execution?
https://www.seeedstudio.com/blog/2021/04/26/managing-arduino-memory-flash-sram-eeprom/
when I execute that program, here is what happens:
memory_allocate_test2 STARTING

SRAM left: 7163

Allocating the memory for the MKR:
Allocated memory!

SRAM left: 5155

memory_allocate_test2 STARTING

SRAM left: 5155

Allocating the memory for the MKR:
Allocated memory!

SRAM left: 3147

memory_allocate_test2 STARTING

SRAM left: 3147

Allocating the memory for the MKR:
Allocated memory!

SRAM left: 1139

memory_allocate_test2 STARTING

SRAM left: 1139

Allocating the memory for the MKR:
Allocated memory!

SRAM left: -869

memory_allocate_test2 STARTING

SRAM left: -869

Allocating the memory for the MKR:
at that point the device just hangs and stops working. That's not what I expect!
since the functionality differs for each board and microcontroller, here are my specs:
the board name is "Arduino® MKR WiFi 1010", the microcontroller name is "SAMD21 Cortex®-M0+ 32bit low power ARM MCU"

what documentation?

it's not the microcontroller that controls the allocation and the release of the memory ... it is the program that does that ... also, there is no such thing as an Arduino microcontroller

also asked at https://forum.arduino.cc/t/arduino-mkr-wifi-1010-memory-management/1174122

@Juraj the only documentation article about the memory structure and management of the MKR WiFi 1010 that is I have found is provided in the question above. Could you please point me to the official documentation, because I saw so many different articles and examples, which often say a different thing.

@jsotola right, sorry for my mistake, the board name is "Arduino® MKR WiFi 1010", the microcontroller name is "SAMD21 Cortex®-M0+ 32bit low power ARM MCU". I have updated the question content.

You are mixing two different ways of memory allocation.
The automatic memory allocation and release you cite works with defined local variables. These variables are allocated on the stack. At the end of their scope, their memory is released. To mimic your example:
void memory_allocate_test3() {
  Serial.println("memory_allocate_test3 STARTING ");
  display_freeram();
  Serial.println("------------------------------------------------------------");
  Serial.println("Allocating the memory for the MKR: ");
  char memory_usage_test[2000] = "Some content...";
  Serial.println("Allocated memory!");
  display_freeram();
  Serial.println("------------------------------------------------------------");
}

But what you use is heap-allocated memory because of the new operator. This kind of allocation is under complete responsibility of the programmer, this is you. Since you only allocate and never release, each loop reduces the remaining RAM. Use delete (actually delete[]) to release:
void memory_allocate_test2() {
  Serial.println("memory_allocate_test2 STARTING ");
  display_freeram();
  Serial.println("------------------------------------------------------------");
  Serial.println("Allocating the memory for the MKR: ");
  char* memory_usage_test = new char[2000];
  Serial.println("Allocated memory!");
  display_freeram();
  Serial.println("------------------------------------------------------------");
  delete[] memory_usage_test;
}

Beware: There are different allocation methods, malloc/calloc/alloca/free and new/delete. The former method uses functions of the C standard library, the latter method uses keywords of C++.
The pointers returned by the different methods are not compatible. You cannot release memory by free that you allocated by new. The same holds true for delete/malloc.
However, you can use both methods in the same program.
Please learn about memory allocation before attempting to use it. C and C++ are error-prone to the unsuspecting user.
As a side note, C and C++ are different languages, even though you can build a mixed program.

is it same as calling free(memory_usage_test)? I saw somewhere during the research that it is not recommended to use the malloc(...) and free(...) functions for the MKR WiFi 1010, do you know something about that? This question is raised because I'm using some classes in my code, that internally use the malloc(...) and free(...) functions.

See the extended answer.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Get address of a I2C transaction when multiple addresses are registered
I have an application polling 4 ADCs by I2C. The application shall also write on some ADC registers. In order to test it, I'd like to use a single Arduino UNO, enabling it for receiving I2C messages over 4 different addresses by masking the TWAMR register. In this way I can have 4 ADCs "emulated" on a single Arduino.
When the application asks for a read to Arduino at some address, I'm able to get the value of the required address by reading the TWDR register:
void requestEvent(){
  byte addr = TWDR >> 1;
  if (0x4A == addr){ // do something }
  else if (0x4B == addr){ // do something }
  // ...
}

void setup(){
  // ...
  Wire.onRequest(requesEvent);
}

However, when the application requests to write something to a certain ADC (with its own address), I'm not able to get the address value in the onReceive(int) callback:
void receiveEvent(int howMany){
  byte addr = TWDR >> 1; // returns the first byte AFTER the address in the I2C message
}

Am I doing something wrong? Is there a way to reach my goal?
Thanks.
Luca
Edit:
Reading the ATmega datasheet (sec. 22.9.4, p. 241), the problem with reading the TWDR register is that it contains the last byte received, that in slave receiver mode is not the address but the last data sent by the master.
Anyway, is there any workaround for this problem?

This seems unnecessarily complicated to me. You say you are polling, so why not just send a request to 0x4A, and wait for a response, then 0x4B, and wait for a response, and so on?

Actually I've written something incorrect. The application is not only polling. but also writing to some registers of ADC in order to configure it. In particular, the procedure for each ADC is: 1) write to ADC config register to trigger a conversion; 2) poll it continuously until the conversion is completed; 3) request the measure when the conversion is completed. I'm not sure why the application is written in that way, I took it as is. Probably there are some possible improvements on this side, but I'm working on the other end, that is a simulator to test the application

It still seems simpler to me to do a round-robin approach. First, tell each ADC to start the conversion (ie. Start A, Start B, Start C, Start D), then  (Poll A, Poll B, Poll C, Poll D), until some or all have finished the conversion, then  (Read A, Read B, Read C, Read D). It seems too complex to me to be fiddling around with hardware registers when it isn't necessary.

I'm not sure if I've understood your answer. If your advise is to change the design of the device that my arduino is communicating with, unfortunately I can't control it.

I'm not advocating any hardware changes. Why not just send the commands to one ADC after another? If you ask a particular ADC for its response, and wait for it, then surely you know which ADC replied?

As said in the other thread, I'm simulating the behaviour of the ADC using arduino. Arduino implements the simulation of the ADC. Another piece of hardware (that I cannot control) is communicating with arduino believing it's the actual ADC.
Actually the thing is a bit more complex, since a single arduino simulates multiple ADCs.
Basically the actual hardware believes that it is communicating with ADC_i (with i = 1,...,6), but it's actually communicating with only one arduino that implements the logics of the multiple ADCs. I guess this is a common case in HIL simulation.

In this sense I cannot change what the real HW does and how it sends commands to the ADCs. The real HW (that is a microcontroller with its own control algorithms) is developed by others and I have only its requirements to understand how it communicates with the multiple ADCs. I shall make the ADCs simulation in arduino capable of handling all the stuff that the microcontroller is sending on the two wire interface. Hope this is clearer now.

Oh I see. You are pretending to be an ADC, not talking to other ADCs. That is clearer now. In that case what chrisl said makes sense.

Reading the TWDR register in the onReceive() callback doesn't give you the address because of the time, that it is called at. The onReceive() callback is called when all bytes have already been received and put in the Wire libraries internal buffer. Thus in that callback TWDR will still hold the last received data byte.
The onRequest() callback on the other hand is called right after the address was received. Thus TWDR still holds the received address.
You will need to modify the Wire library to achieve your goal. Similar to the onRequest() callback you can introduce a third kind of callback function, which will be executed after receiving the slave address to save the received address for later use (the address matching is still done via hardware, so you still need to mask the address via TWAMR).
You can find the files for the Wire library inside your used core (for me the Uno uses the path ~/.arduino15/packages/arduino/hardware/avr/1.8.5/libraries/Wire). Look at line 581 of src/utility/twi.c. This is inside the TWI ISR, the case clause TW_SR_SLA_ACK, which will be executed on address receive/match. Here you can insert your callback function.
If you want to do this in a similar handy way, that the Wire library does with the other callbacks, then you need to change a few other things:

Insert a function pointer for this at the start of the twi.c file, right besides the other function pointers:
 static void (*twi_onSlaveAddressMatch)(uint8_t);

Add the execution of that function to the case in the ISR described above and provide the content of TWDR (shifted to eliminate the direction bit) as a parameter:
 twi_onSlaveAddressMatch(TWDR >> 1);

Add a function to set the callback function pointer in twi.c:
 void twi_attachSlaveAddressMatchEvent( void (*function)(uint8_t) ){
     twi_onSlaveAddressMatch = function;
 }

Add the callback set function as a function prototype to twi.h:
 void twi_attachSlaveAddressMatchEvent( void (*function)(uint8_t) );

In Wire.h  add a function pointer for the new callback and the corresponding service function inside the private: section:
 static void (*user_onSlaveAddressMatch)(uint8_t);
 static void onSlaveAddressMatchService(uint8_t);

In Wire.h add a function to set the user callback function to the public: section:
 void onSlaveAddressMatch( void (*)(uint8_t) );

In Wire.cpp add the implementation of the service function:
 void TwoWire::onSlaveAddressMatchService(uint8_t address){
     if(!user_onSlaveAddressMatch){
         return;
     }
     user_onSlaveAddressMatch(address);
 }

In Wire.cpp add the implementation of the callback setter function:
 void TwoWire::onSlaveAddressMatch( void (*function)(uint8_t) ) {
     user_onSlaveAddressMatch = function;
 }

In Wire.cpp, TwoWire::begin(void) add the initialization of the callback service function:
 twi_attachSlaveAddressMatchEvent(onSlaveAddressMatchService);

Now you should be able to set a callback for the address receive in your main code and save the address for later use:
uint8_t received_address = 0;

void getAddress(uint8_t address){
    received_address = address;
}

void setup(){
    ...
    Wire.onSlaveAddressMatch(getAddress);
}

In the onReceive() callback you can then check for that global variable.
Note: I have not tested or compiled this. I just looked at the logic of the Wire library and copied the way it already defines its existing callback functions.

Hi @chrisl, thanks for the reply. I asked here as my last hope not to rebuild the core libraries. I expected that.
Another workaround to solve my issue could be to add the following lines in twi.c (in case TW_SR_SLA_ACK):
if (twi_sr_store_address){ twi_rxBuffer[twi_rxBufferIndex++] = TWDR >> 1; }
where twi_sr_store_address is just a boolean that can be set through Wire. This way the Wire.read() method now will return also the address byte.
Do you think this solution could work as well as yours? If not, why?
I'm just asking to learn.
Thanks again for the help,
Luca

Sure, that would also work. Though I think using a callback function is a cleaner solution. For both solutions you need to modify the library.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Timer setup interferes with LED blinking logic
This example is a simplified version of what I really need to do, but I think it demonstrates the problem (= my misunderstanding?).  I need to use a timer to count microseconds; my code shows how I set up the timer and indeed the timer produces 1 MHz square wave on pin 11 if setup_timer2() is active.
However, when setup_timer2() is active, the LED does not blink.  If I comment out setup_timer2(), the LED blinks as expected. In my more complex sketch, it appears that whatever I put in the loop is blocked when activating the timer.
It seems that activating the timer interferes with the blinking logic and I cannot figure out why.  Relatively new to this stuff so quite possibly something simple.

// Logic to control on board LED derived from
// https://forum.arduino.cc/t/demonstration-code-for-several-things-at-the-same-time/217158

const int on_board_LED_pin = 13;
const int on_board_LED_interval = 3000;
const int on_board_LED_duration = 500;
byte on_board_LED_state = LOW;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting Demo");
  pinMode(on_board_LED_pin, OUTPUT);
  pinMode(11, OUTPUT); // 1 MHz square wave on this pin if timer activated
  setup_timer2();
}

void loop() {
  currentMillis = millis();
  toggle_on_board_LED();
}

void toggle_on_board_LED() {
  // change the state as needed
  if (on_board_LED_state == LOW) {
    if (currentMillis - previousMillis >= on_board_LED_interval) {
      on_board_LED_state = HIGH;
      previousMillis += on_board_LED_interval;
    }
  }
  if (on_board_LED_state == HIGH) {
    if (currentMillis - previousMillis >= on_board_LED_duration) {
      on_board_LED_state = LOW;
      previousMillis += on_board_LED_duration;
    }
  }
  // implement the state
  digitalWrite(on_board_LED_pin, on_board_LED_state);
}

void setup_timer2() {
  cli();       //stop interrupts globally
  TCCR2A = 0;  // set entire TCCR0A register to 0
  TCCR2B = 0;  // same for TCCR0B
  TCNT2 = 0;   //initialize counter value to 0
  OCR2A = 0;
  TCCR2A |= (1 << WGM21);   // CTC mode
  TCCR2A |= (1 << COM2A0);  // toggle pin OC2A on compare match (= pin 11)
  TCCR2B |= (1 << CS21);    // prescale by 8
  TIMSK2 |= (1 << OCIE2A);  // enable timer compare interrupt
  sei();                    // allow interrupts globally
}

EDIT
If I add the following declaration and ISR:
volatile unsigned long u_sec;

ISR(TIMER2_COMPA_vect) {
  volatile unsigned long u_sec;
  u_sec++;
}

The LED still does not blink.

There's already a function called micros() to count microseconds that works.  You don't have to re-invent it.  It uses Timer0.

Thanks, I am aware of micros() but I also need the reference waveform and need to have them synchronized.  So there will be an ISR from the timer that counts micros.

It takes longer than 1 microsecond to even enter an ISR.  What you propose won't work.  You've got a 16mHz microcontroller.  You're pretty limited in what you can do in on microsecond in code.

I was wondering about that -- is there a source that gives the overhead times for various operations?  I see many comments about operation X takes Y amount of time, but I don't know where people get these numbers from.  Thank you.

after compiling, look at the resultant assembly code ... refer to the microcontroller programming datasheet to learn how many clock cycles each instruction takes

I guess I'll use micros() for general counting and worry about the phase of the reference signal by some other means. Thanks again.

feed the 1 MHz output into an external counter circuit to generate an interrupt

First thing: setting OCR2A to 0 is wrong: if you want the interrupt to
fire every microsecond (16 CPU cycles, 2 timer cycles), you should set
OCR2A to 1.
Then, as stated in some comments, there is no way your poor ATmega could
execute this ISR every microsecond. So let's try to make it a little bit
shorter:
ISR(TIMER2_COMPA_vect){}

If you try this, you may notice it's still too much. Disassembling the
ISR gives the following:
__vector_7:
    push r1
    push r0
    in   r0, SREG
    push r0
    clr  r1
    pop  r0
    out  SREG, r0
    pop  r0
    pop  r1
    reti

All this takes 19 CPU cycles. Add the 4 cycles taken by the CPU to enter
the interrupt, and the 3 cycles of the interrupt vector (a jmp
instruction) and you get... too much to do in a microsecond (which is
only 16 cycles). At this point you may wonder: why so many instructions
for an empty function? It turns out it is all boilerplate. Everything up
to clr r1 is an interrupt prologue meant to save the CPU context and
clear the register r1 (which is required by the gcc AVR programming
model). The rest is the epilogue meant to restore the saved context and
return from the interrupt.
We can make the ISR still shorter this way:
EMPTY_INTERRUPT(TIMER2_COMPA_vect)

This compiles to a single reti instruction, which executes in 3 CPU
cycles. Now the whole interrupt processing only takes 11 cycles... and
the program works! With some caveats:

processing these interrupts eats almost 69% of the CPU power

since other ISRs take more than one microsecond to execute, our
empty ISR will miss many interrupts (not that it matters...)

In summary: you should probably avoid interrupting your CPU every
microsecond.

Thanks Edgar, this is really helpful!

You are enabling the timer compare interrupt, but you do not have an interrupt handler defined for it.  You don't need to set that bit if you just want to output PWM.
I think you should either remove this line or define an interrupt handler for this vector.
TIMSK2 |= (1 << OCIE2A);  // enable timer compare interrupt

When the compare match happens, the code is trying to jump to an undefined interrupt handler and that is locking up the board.

Thanks... you are correct that if I comment out that line it works, and I see your logic.  However, I had previously had an ISR in there, and it wasn't working, so I removed it to get to the minimum erroring example.  I will append the code example so you can see what I tried.


text:
Can Vin of ESP handle many voltage sensors and relays?
My project is Charging Battery via Solar and Piezoelectric sensor while also getting the Realtime  Voltage of the Battery, Capacitor, and Solar.
I want to use Vin as the source to get 5V because ESP8266 NodeMCU only has 3.3V output.
As the diagram shows, can it power 3 Voltage sensors and 2 Relays?
or should i use an external power source?
Ps: The solar is the 'normally closed'

I don't see how your layout would work, as there + terminal of your battery isn't really connected to anything except the voltage sensor.

Vin is for powering the ESP via the onboard voltage regulator which converts Vin to 3.3V for the ESP. It's not a source of 5V unless connected via USB.


text:
Creating firmware redundancy on Arduino Nano
Is there an established system, that, if a new version of the application is uploaded to Flash, switches to it automatically, but keeps the old one for the cases if, due to some problems, we need to return to it?
I ask for such a system in general, but also for the one, that operates with a CAN transceiver.

More powerful MCU with large flash memory have partitioning or flash memory banks where they can switch between different versions of the firmware. They have a register to set the start address so the application compiled for a specific start address can run on different real addresses in the flash memory.
Th Arduino Nano can't run a binary compiled for start address 0 on any other location in the flash memory.
InternalStorageAVR in my ArduinoOTA library can store the OTA uploaded update in upper half of the flash memory of a classic AVR. But the program can't run there. The bootloader must copy it to address 0 and start it from there. So the previous version is lost. In a large flash of Arduino Mega maybe it could store a copy of the previous version, but not for Nano. Any logic for this would make the sketch larger than a third of the flash memory.
EDIT:
If the bootloader does the transfer of the updated binary, then it can first copy the old sketch to upper half of the flash and then write the new sketch from address 0. At watchdog reset the bootloader could copy the old sketch back.
Optiboot could be modified to do this. As starting point, here is my copy_flash_pages function for Optiboot.

Thank you for a comprehensive answer. I really don't mind the scetch taking a third of the flash or more. Do I understand correctly, that if you could store two versions of a firmware in Nano's flash, you could switch between them just by letting the bootloader copy one to the address 0?

I would be grateful, if you would outline (or provide a link to a documentation, where it is cleared up), how a bootloader can be triggered to execute different instructions? I think, I need two: one for saving the new version and using it, and one for switching to the old version.

Writing the new version of sketch received over UART is what the bootolade does normally. See the source code of Optiboot. There is a code which detects upload so there you would activate the backup copying. To switch to backup, it depends on how do you want to detect that you need to switch to backup.

I need to signal it from the base station to a node using CAN Protocol, if it's possible

that would assume that the sketch is running and you want to signal to it that it should activate the bootloader with a flag in EEPROM that it should copy the old version to address 0.

I tried to put it into other words in another question, maybe you can answer it as well: https://arduino.stackexchange.com/questions/95912/create-a-system-of-hot-swap-firmware-update-on-arduino-nano

that question ask something a little different. as I understand it, there is no previous version, just an update over CAN ?

there is a previous version, I just didn't metnion it for the sake of simplicity, you can imagine it as the third block of code


text:
My code got my Nano ESP32 into a <500ms reboot loop
I have done a lot of reading and learning after previous help here and it has been great.
I have uploaded and tried many iterations of my code which all worked (Assuming my code was actually good) and i though i had finally cracked my project today.
I was writing a bunch at work without my ESP with me so i did a lot of changes and only uploaded it when i got home.
The issue is, as soon as i did the ESP got stuck in a really short <500ms reboot loop.
I had to ground GPIO0 to get it out of the loop and upload code that does work to get the ESP stable again. My previous versions upload and work as they did before but my latest version just gets it into the loop and i have to again ground GPOI0 to get out.
I have compared as best as i know how and i cannot see how the code is so broken.
It compiles correctly and the upload output has no errors.
Please help.
Todays edits were mostly writing and editing the LED Logic, Timer Logic and Gate Logic
Purpous.
This project is a timer i have built for calculating the time and speed of a model rocket traveling along a cable. It would use 3 light gates (Currently buttons for dev).
Gs is the start gate, G1 is the second gate but the first of the speed trap, G2 if the final gate.
The first timer starts when the rocket leaves the first gate (Gs),
When the rocket passes the second gate (First speed trap gate) (G1) a second timer starts.
When it reaches the 3rd and final gate (G2), both timers stop and the system takes the time it took to travel between gate S and 2 to calculate average speed then the time between G1 and G2 to calculate the speed through the speed trap.
Distance is entered in a "menu".
I am still new to code this complex (Well for me it is) so i have no idea how it broke.
I can upload previous working versions if it would help.
#include <LiquidCrystal_I2C.h>

const int startPin = 12;                                    // Start button Pin
const int stopPin = 11;                                     // Stop button Pin
const int resetPin = 10;                                    // Reset button Pin
const int menuPin = 5;                                      // Menu button Pin
const int Gs = 6;                                           // Start Gate (White)
const int G1 = 7;                                           // Finish Gate 1 Pin (Yellow)
const int G2 = 8;                                           // Finish Gate 2 Pin (Blue)
const int ledr = 2;                                         // Red LED Pin
const int ledg = 3;                                         // Green LED Pin
const int ledy = 4;                                         // Yellow LED Pin

bool WaitM = false;                                         // Timer (Main) waiting for start
bool WaitG = false;                                         // Timer (Gate) waiting to start
bool RunningM = false;                                      // State of speed main timer
bool RunningG = false;                                      // State of speed gate timer
bool Run = false;                                           // Is timer program running?
bool SysState = false;                                      // Is system up?
bool clearscreen = false;                                   // Clear screen state
bool menu = false;                                          // Is the range menu active on the display

int ledgState = LOW;                                        // the current state of the Green LED output pin
int ledyState = LOW;                                        // the current state of the Yellow LED output pin
int ledrState = LOW;                                        // the current state of the Red LED output pin

int startbuttonState;                                       // the current reading from the start button input pin
int startbuttonStateLatch = LOW;                            // start button latch state after debounce
int laststartbuttonState = LOW;                             // the previous reading from the start button input pin
int stopbuttonState;                                        // the current reading from the stop button input pin
int stopbuttonStateLatch = LOW;                             // stop button latch state after debounce
int laststopbuttonState = LOW;                              // the previous reading from the stop button input pin
int resetbuttonState;                                       // the current reading from the reset button input pin
int resetbuttonStateLatch = LOW;                            // reset button latch state after debounce
int lastresetbuttonState = LOW;                             // the previous reading from the reset button input pin
int menubuttonState;                                        // the current reading from the menu button input pin
int menubuttonStateLatch = LOW;                             // menu button latch state after debounce
int lastmenubuttonState = LOW;                              // the previous reading from the menu button input pin

int GsState;                                                // State of Start Gate sensor
int lastGsState = LOW;                                      // Last state of Stare Gate button (To be reomved when sensor replaced button)
int G1State;                                                // State of Gate 1 (speed trap start) Sensor
int lastG1State = LOW;                                      // Last state of G1 button (To be reomved when sensors replace buttons)
int G2State;                                                // Stage of Gate 2 (Speed trap and full run) sensor
int lastG2State = LOW;                                      // Last state of G2 button (To be removed when sensors replace buttons)

int Range = 50;                                             // Range length input in M(eters)
int TrapLength = 2;                                         // Trap light gates distance apart in M(eters)

unsigned long lastDebounceTime = 0;                         // the last time the output pin was toggled
unsigned long debounceDelay = 25;                           // the debounce time; increase if the output flickers
unsigned long StartMMillis;                                 // millis at start if Main run
unsigned long StartGMillis;                                 // millis at start of speed trap
unsigned long EndMillis;                                    // millis at end of run
unsigned long RunM;                                         // millis time for main run
unsigned long RunG;                                         // millis time for speed trap
unsigned int TrapS = 0;                                     // Speed between Gate 2(B) & 3(C) (M/S)
unsigned int TrapSMPH = 0;                                  // Speed between Gate 2(B) & 3(C) (MPH)
unsigned int SpeedAVG = 0;                                  // Speed average between Gate 1(A) & 3(C)

LiquidCrystal_I2C lcd(0x27, 20, 4);                         // LCD setup

void setup() {
  Serial.begin(9600);                                       // Start Serial

  lcd.init();                                               // Start and config for LCD, backlight and cursor
  lcd.backlight();
  lcd.setCursor(0,0);

  pinMode(startPin, INPUT_PULLDOWN);                        // Pin setup for buttons, LED's and gate sensors
  pinMode(stopPin, INPUT_PULLDOWN);
  pinMode(resetPin, INPUT_PULLDOWN);
  pinMode(menuPin, INPUT_PULLDOWN);
  pinMode(Gs, INPUT_PULLDOWN);
  pinMode(G1, INPUT_PULLDOWN);
  pinMode(G2, INPUT_PULLDOWN);
  pinMode(ledr, OUTPUT);
  pinMode(ledg, OUTPUT);
  pinMode(ledy, OUTPUT);

  digitalWrite(ledr, ledrState);                       // Output for LED's
  digitalWrite(ledg, ledgState);
  digitalWrite(ledy, ledyState);

  Run = false;                                         // Set RUN to false at start
  SysState = false;                                    // Set System State to false at start

}
void loop() {

                                                                  // BUTTON DEBOUNCE LOGIC (Adding buttons as needed)

  //Start Button debounce filter
  int readingstart = digitalRead(startPin);                        //Read state of button into local variable
                                                                   //Check to see if button was just pushed (Went from LOW to HIGH), And if you have waited long enough
                                                                   //since the last press to ignore any noise
  if (readingstart != laststartbuttonState) {                      //if the switch changed, due to noise or pressing,
    lastDebounceTime = millis();                                   //reset debouce millis timer
  }
if ((millis() - lastDebounceTime) > debounceDelay ) {              // whatever the reading is at, it's been there for longer than the debounce delay, so take it as the actual current state:

  if (readingstart != startbuttonState) {                          // if the button state has changed:
    startbuttonState = readingstart;

    if (startbuttonState == HIGH) {                                //only toggle filtered state if the new button state is HIGH
        startbuttonStateLatch = !startbuttonStateLatch;
    }
  }
}
laststartbuttonState = readingstart;

  //Stop Button debounce filter
  int readingstop = digitalRead(stopPin);
  if (readingstop != laststopbuttonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay ) {

    if (readingstop != stopbuttonState) {
      stopbuttonState = readingstop;

      if (stopbuttonState == HIGH) {
        stopbuttonStateLatch = !stopbuttonStateLatch;
      }
    }
  }
  laststopbuttonState = readingstop;

  //Reset Button debounce filter
  int readingreset = digitalRead(resetPin);
  if (readingreset != lastresetbuttonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay ) {

    if (readingreset != resetbuttonState) {
      resetbuttonState = readingreset;

      if (resetbuttonState == HIGH) {
       resetbuttonStateLatch = !resetbuttonStateLatch;

      }
    }
  }
  lastresetbuttonState = readingreset;

  //menu Button debounce filter
  int readingmenu = digitalRead(menuPin);
  if (readingmenu != lastmenubuttonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay ) {

    if (readingmenu != menubuttonState) {
      menubuttonState = readingmenu;

      if (menubuttonState == HIGH) {
       menubuttonStateLatch = !menubuttonStateLatch;

      }
    }
  }
  lastmenubuttonState = readingmenu;
                                                                      // Once fitted, test lights sensors without debounce to reduce CPU load

  //Gs button debaounce (No latch state required)
  int readingGs = digitalRead(Gs);
  if (readingGs != lastGsState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (readingGs != GsState) {
      GsState = readingGs;
    }
  }

  //G1 button debounce  (No latch state required)
  int readingG1 = digitalRead(G1);
  if (readingG1 != lastG1State) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (readingG1 != G1State) {
      G1State = readingG1;
    }
  }

  //G2 button debounce (No latch state required)
  int readingG2 = digitalRead(G2);
  if (readingG2 != lastG2State) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (readingG2 != G2State) {
      G2State = readingG2;
    }
  }

                                              // LED Logic
  if (Run) {
    digitalWrite(ledg, HIGH);
  }
  else {
    digitalWrite(ledg, LOW);
  }

  if (WaitM && !RunningM && WaitG && !RunningG){
    digitalWrite(ledy, HIGH);
  }
  else {
    digitalWrite(ledy, LOW);
  }

  if (!Run && !WaitM && !RunningM && !WaitG && !RunningG){
    digitalWrite(ledg, LOW);
    digitalWrite(ledy, LOW);
    digitalWrite(ledr, HIGH);
  }

                                              // Gate LOGIC

if ((startbuttonState == HIGH) && (GsState == 1) && (G1State == 1) && (G2State == 1)) {     //if start button & all 3 gate buttons are true then set both Wait, Run and SysState to true
  stopbuttonStateLatch = LOW;
  WaitM = true;
  WaitG = true;
  Run = true;
  SysState = true;
}

if (stopbuttonState == HIGH) {                                                    // if stop button pressed, set Run to false, Keep SysState True
  startbuttonStateLatch = LOW;
  Run = false;
  SysState = true;
  }

if (resetbuttonState == HIGH) {                                                   // if reset button pressed,
  Run = false;                                                                    // set Run and SysState to false,
  SysState = false;
  startbuttonStateLatch = LOW;                                                    // Set button latch to off and turn off LED's
  digitalWrite(ledg, LOW);
  stopbuttonStateLatch = LOW;
  digitalWrite(ledr, LOW);
}

if ((GsState == 1) && (G1State == 1) && (G2State == 1)){                          // if all 3 gates are true
  WaitM = true;                                                                   // set both wait states to true
  RunningM = false;                                                               // set both Running states to false (Should be anyway in normal startup)
  WaitG = true;
  RunningG = false;
}

if ((GsState == 0) && (G1State == 1) && (G2State == 1)){                          // When first gate opens (State goes off) WaitM set to false
  WaitM = false;
}

if ((GsState == 0) && (G1State == 0) && (G2State == 1)){                          // When first and second gates open, WaitG (2nd) wait state goes false
  WaitG = false;
}

if ((GsState == 0) && (G1State == 0) && (G2State == 0)){                          // WHen final gate opens, set Run to false
  Run = false;
}

                                                              // TIMER Logic
                                                    //Rocket leaves start gate
  if (Run && !WaitM && !RunningM){
    StartMMillis = millis();
    RunningM = true;
  }
                                                    // Rocket passes first speed gate
  if (Run && !WaitG && !RunningG){
    StartGMillis = millis();
    RunningG = true;
  }
                                                    // Rocket passes 2nd speed gate, ending run
  if (!Run && RunningM && RunningG){
    EndMillis = millis();
    RunningM = false;
    RunningG = false;
  }
                                                    // At end, calculate speed in M/s
  if (!Run && !RunningM && !RunningG) {
    RunM = (EndMillis - StartMMillis);
    RunG = (EndMillis - StartGMillis);
    TrapS = (TrapLength / RunG)/1000;
    TrapSMPH = TrapS * 2.237;
    SpeedAVG = ((Range / RunM)/1000)*2.237;
  }

                                                              // SCREEN OPTIONS
                                                              // RANGE ADJUST MENU

  if (menubuttonStateLatch == HIGH) {
    menu = true;
  }
  else {
    menu = false;
  }

  if(menubuttonState == HIGH) {
    lcd.clear();
  }

    if (menu) {
  if(digitalRead(startPin) == HIGH){
    Range = Range + 1;
  lcd.setCursor(0,2);
  lcd.print("     ");
  }
  if(digitalRead(stopPin) == HIGH){
    Range = Range - 1;
  lcd.setCursor(0,2);
  lcd.print("     ");
    }

  // lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Range in full M");
  lcd.setCursor(0,1);
  lcd.print(Range);
    }

                                                                // MAIN SCREEN WITH TIMER AND SPEED DISPLAY
  else {
  lcd.setCursor(0,0);
  lcd.print("Run Time (ms)- ");
  lcd.print(RunM);
  lcd.setCursor(0,1);
  lcd.print("Speed (AVG)  - ");
  lcd.print(SpeedAVG);
  lcd.setCursor(0,2);
  lcd.print("Speed (MAX)  - ");
  lcd.print(TrapSMPH);
  lcd.setCursor(0,3);
  lcd.print("Gate|A");
  lcd.print(digitalRead(Gs));
  lcd.print("|B");
  lcd.print(digitalRead(G1));
  lcd.print("|C");
  lcd.print(digitalRead(G2));
  lcd.print("|");

  if (!SysState && !Run) {
    lcd.print(" OFF  ");
  }
  if (SysState && Run && WaitM && !RunningM) {
    lcd.print(" Wait ");
  }
  if (SysState && Run && !WaitM && RunningM) {
    lcd.print(" Run  ");
  }
  if (SysState && !Run) {
    lcd.print(" Stop ");
  }
  }
                                                                  // Serial output
  Serial.print ("Button states : Mom|Lat : ");
  Serial.print ("Start = ");
  Serial.print (startbuttonState);
  Serial.print (startbuttonStateLatch);
  Serial.print (" || Stop = ");
  Serial.print (stopbuttonState);
  Serial.print (stopbuttonStateLatch);
  Serial.print (" || Reset = ");
  Serial.print (resetbuttonState);
  Serial.print (resetbuttonStateLatch);
  Serial.print (" || Menu = ");
  Serial.print (menubuttonState);
  Serial.print (menubuttonStateLatch);
  Serial.println("Gate States: ");
  Serial.print(" Gs (A)-");
  Serial.print(digitalRead(Gs));
  Serial.print(" || G1 (B)-");
  Serial.print(digitalRead(G1));
  Serial.print(" || G2 (C)-");
  Serial.print(digitalRead(G2));
  Serial.println ("System States: ");
  Serial.print("Menu:");
  Serial.print (menu);
  Serial.print (" || Run = ");
  Serial.print (Run);
  Serial.print (" || System State = ");
  Serial.print (SysState);
  Serial.println ("Timer State: ");
  Serial.print ("WaitM = ");
  Serial.print (WaitM);
  Serial.print (" || RunningM: ");
  Serial.print (RunningM);
  Serial.print (" || WaitG: ");
  Serial.print (WaitG);
  Serial.print (" || RunningG: ");
  Serial.println (RunningG);

}

please edit your post ... copy and paste the content of the serial monitor into your question ... format it as code for readability... no screenshots

the logic of your code is unnecessarily complex ... for example, there is no reason to debounce the inputs ... start by watching only the first sensor ... when the first sensor is tripped, make note of the value of millis() and continue watching only the second sensor ... etc. etc

Did you send this much data over serial in the working version? At 9600baud that may take like 200ms each loop iteration (as the buffer is not that big I think). And have you tried removing parts of the code, like the LCD code, to narrow down where the problem is

Thanks for the comments so far.
@jsotola, there is no serial monitor output to upload. The code does not run as the ESP ends up in a ~500ms reboot loop.
I also do need SW debounce. I do not want to have to add discreet circuits to HW debounce this and without the SW, i get a lot of stray operations when using the buttons.

please add that info to the question

I'd love to know how to code to a level where a dirty input is not a problem but i am not there yet. As for the SW debounce for the gate inputs, that will not be there in the final form as the buttons for those inputs will be replaced by solid state light sensors that have a clean state change

@chrisl, yes i did. i do not plan on using the Serial monitor in the final version but as i am still learning, i needed a visual on how my IO was working. It took me a while to get the debounce and states to work to having a huge Serial output helped a lot in knowing what the code was doing when i did not have much on the screen.

I have isolated enough code to know the loop is being caused by the following
  if (!Run && !RunningM && !RunningG) {
    RunM = (EndMillis - StartMMillis);
    RunG = (EndMillis - StartGMillis);
    TrapS = (TrapLength / RunG)/1000;
    TrapSMPH = TrapS * 2.237;
    SpeedAVG = ((Range / RunM)/1000)*2.237;
  } ```
But i still cannot see how the loop is caused.
I am trying to re-write it in a way where it would only run this section once but it is takign me a while

OK: If you've narrowed it down to around here: RunG = (EndMillis - StartGMillis);     TrapS = (TrapLength / RunG)/1000; then if EndMillis equals StartGMillis then RunG is zero so you will get a divide by zero crash. You should at least check its value before using it in a division.

Thank you @6v6gt.
The setup would not allow for the calculation to occur when both values were 0 but i think i found it in a similar way.
I had not set those 5 unsigned long's a value in setup to i believe it was cracshing before it even go to that point in the code.
All sorted now.
Thanks again.

code to a level where a dirty input is not a problem ... in your use case, it is not a problem ... multiple contact bounces do not affect the operation ... first contact closure indicates that the event has occured ... subsequent closures are ignored if you no longer watch the contact


text:
Slider servo doesn't give the right output
#include <HCPCA9685.h>
#include <Wire.h>
#define I2CAdd 0x40

HCPCA9685 HCPCA9685(I2CAdd);
String state = "";

int servo5Pos;
int servo5PPos;

void setup() {
  Wire.begin();
  Serial.begin(4800);
  HCPCA9685.Init(SERVO_MODE);
  HCPCA9685.Sleep(false);
  servo5PPos = 63;

}

void loop(){
  if (Serial.available() > 0){
    state = Serial.readString(); // Read the data as string
    Serial.print(state + "\n");
    // If "Waist" slider has changed value - Move Servo 5 to position
    if (state.startsWith("s5")){
      String stateS = state.substring(2, state.length()); // Extract only the number. E.g. from "s1120" to "120"
      servo5Pos = stateS.toInt(); // Convert the string into integer
      // We use for loops so we can control the speed of the servo
      // If previous position is bigger then current position
      Serial.print(servo5Pos);
      if (servo5PPos > servo5Pos){
        for (int pos = servo5PPos; pos >= servo5Pos; pos--) {
          HCPCA9685.Servo(5, pos);
          delay(20);
        }
      }
      if (servo5PPos < servo5Pos){
        for (int pos = servo5PPos; pos <= servo5Pos; pos++) {
          HCPCA9685.Servo(5, pos);
          delay(20);
        }
      }
      servo5PPos = servo5Pos;
    }
  }
}

I'm trying to communicate my MIT Block Code to this Arduino Code, to control a servo via slider. By giving it a ''s5'' text to move the servo. However, I get this output instead when I'm printing the data received. Below is the code output and MIT block code.

what were you expecting to see in the output? ... please replace the picture of text with the text

what is your question? ... please add a focused, answerable question to your post

Welcome to SE/Arduino! Please take the [tour] to learn how this site works, and read "[ask]". Please [edit] your question to replace the image of text with actual text. -- This "code output" you show, which device generates that? -- Your sketch expects just an integer after the servo number, but the text you show has a floating point number. Are you aware of this? -- How do you think are the different messages separated? The text you show has no separator between them. Did you consider to add for example a \n?

Do not use Serial.readString()
Your main issue here is that you seem to assume that the serial port
transmits messages from your computer to your Arduino. It doesn't. It
only transmits a stream of bytes (ASCII characters here), which is what
the Arduino gets ate the other end.
Serial.readString() has no way of knowing where one message ends and
the next one begins. Instead, it relies on a very simple heuristic: if
one full second has elapsed with no byte being received, then it assumes
whatever has been received so far is a complete message. This works
reasonably well for messages manually typed at the serial monitor,
because you are unlikely to type two messages within one second.
When you move the slider, however, your block code sends messages in
quick succession: “s539.7”, then “s540.8”, then “s543”... The Arduino
then receives a string of characters: 's', '5', '3', '9', '.',
'7', 's', '5', '4', '0', '.', '8', 's', '5', '4',
'3', ... This is interpreted as a single message by
Serial.readString().
Solution: Use an “end of message” indicator instead of (or in
addition to) the “start of message” indicator. The characters CR (\r)
and LF (\n) are popular choices. You can then use
Serial.readStringUntil() to get a full message.
Or, better yet, do not use the String class at all. See
Reading Serial on the Arduino.


text:
Using RN-42 as HID Mouse
I am using RN-42 with Arduino Micro and able to connect RN-42 in HID mode and it's connected to the PC as Mouse. I am using BPLib (https://github.com/witnessmenow/BPLib) for Bluetooth communication. I am not sure where I am making a mistake as whenever I roll the ball on my trackball there is no movement detected. But it is working fine when using it as a wired solution with a mouse library with Arduino.
Here is the code using Serial1
#include <Wire.h>
#include "I2Cdev.h"
#include <PMW3360.h>
#include <BPLib.h>

// Mouse Movement Variables
#define SS  17          // Slave Select pin. Connect this to SS on the module
PMW3360 sensor;
const unsigned long accumulationTime = 10; // Accumulate data for --- milliseconds
const int sensitivity = 500;
const int DPI = 400;

// Bluetooth Variables
// Bluetooth Variables
#define RX_PIN 0 // connect to TXD of module
#define TX_PIN 1 // connect to RXD of module (logic level 3.3v!)

Serial1 swSer(RX_PIN, TX_PIN, false); // Only three arguments
BPLib *BPMod;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600); // Set the baud rate for hardware serial
  BPMod = new BPLib(Serial1);
  BPMod->begin(BP_MODE_HID, BP_HID_MOUSE);

  if (sensor.begin(SS)) // Initialize the PMW3360 sensor
  {
    Serial.println("Sensor initialization succeeded");
  }
  else
  {
    Serial.println("Sensor initialization failed");
  }
  sensor.setCPI(DPI);
  //Mouse.begin();
}

void loop()
{
  float Acc_X = 0;
  float Acc_Y = 0;
  bool movementDetected = false;

  unsigned long startTime = millis(); // Record the start time

  // Accumulate readings for the --- duration
  while (millis() - startTime < accumulationTime) {
    PMW3360_DATA data = sensor.readBurst();
    if (data.isOnSurface && data.isMotion) {
      float mdx = constrain(data.dx, -127, 127);
      float mdy = constrain(data.dy, -127, 127);

      Acc_X += mdx;
      Acc_Y += mdy;
      movementDetected = true;
    }
  }

  Acc_X /= DPI;
  Acc_Y /= DPI;

  // Move the mouse based on accumulated values if movement was detected
  if (movementDetected) {
    BPMod->mouseMove(-Acc_X * sensitivity, Acc_Y * sensitivity);
    //Mouse.move(-Acc_X * sensitivity, Acc_Y * sensitivity);
  }
}

Anyone could help to solve the issue? or point out where I am making a mistake.

The Arduino Micro has a hardware UART on pins 0 and 1 that is usable as Serial1. It is independent of the Serial connection to the PC/serial monitor. SoftwareSerial has caveats. If your error is unrelated to SoftwareSerial you will still have the issue over Serial1 and can eliminate a distraction from your actual problem. Either that or you'll have proven that it plays a significant role in the problem, which would also be good to know. Ultimately you probably don't want SoftwareSerial anyway.

I tried to use Serial1, but no luck. Any other suggestions?

Suggestion: replace your code in the question with your code making use of Serial1, eliminating any doubt that SoftwareSerial is related to the problem.

I edit the code. Please Check.


text:
Controlling a NEMA 17 with PID on TB6600, motor too slow
I'm writing there as I am kinda desperate to find a solution after many trials, back and forth with online solutions and ChatGPT, so maybe someone here can help.
My project is quite simple: I'm trying to make an inverted pendulum with an Arduino, a NEMA 17 and a TB6600 controller. The angle of the pendulum is given by an encoder, which works very well. My mechanical system works quite well too, no issue there.
My problem is that I am unable to correctly control the motor to answer to fast commands. I want the motor to move according to a basic PID output, and while my PID is not set yet, I am unable to make the motor move fast enough at all. No matter how I tune my PID, the motor wont be fast enough to keep the pendulum upright. Otherwise, the motor moves well, right when the pendulum is falling on the right, and left when it's falling on the left, so I have no issue controlling the direction of the motor. Also, I know that my cabling should be good, as prior to using the PID, I have an initialisation phase where I place the pendulum in the middle of the rails, which requires me to move the motor. And I am able to do it very fast using the AccelStepper library, so I know that my hardware is sufficient for my need.
The TB6600 is set on full steps and allows up to 3 A, which I know is more than enough as said earlier.
Here is the code that I am using :
#include <AccelStepper.h>
#include <Encoder.h>

//################# CONNECTION HARDWARE ################
// Connection encoder
#define enc_green_pin 2
#define enc_white_pin 3

// Connection motor
#define motor_dirPin 8 // Connected to DIR+(+5V)
#define motor_stepPin 9 // Connected to PUL+(+5V)
#define motorInterfaceType 1 // stepper driver

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, motor_stepPin, motor_dirPin);

// Encoder
Encoder encod(enc_green_pin,enc_white_pin);

void setup() {
  Serial.begin (115200);

  // motor settings
  stepper.setMaxSpeed(5000);
  stepper.setAcceleration(50000);

  delay(2000); // seconds to wait before starting

  initialisation();
}

// Initialisation, moves stepper and init encoder
void initialisation(){
  Serial.print("Position before : ");
  Serial.println(stepper.currentPosition());

  // Moves stepper to the middle
  stepper.moveTo(-1000);
  stepper.runToPosition();
  Serial.print("Position : ");
  Serial.println(stepper.currentPosition());
  stepper.setCurrentPosition(0);

  delay(2000); // seconds to wait before starting
}

void loop() {

  // Read encoder and convert angle
  long pos_brut = encod.read();
  float angle_deg = int(conv_angle(pos_brut));

  int error = -(180-angle_deg); // error : setpoint=180

  /*
  float error =-5*(180 - angle_deg_int);
  errSum += (error * 0.01);
  float dErr = (error - lastErr) / 0.01;

  output = Kp * error + Ki * errSum + Kd * dErr;
  lastErr = error;

  // Limits output
  if (output > 255) output = 255;
  if (output < -255) output = -255;

  */

  // Method 1
  if (error  > 0) {
    digitalWrite(motor_dirPin, HIGH);
    analogWrite (motor_stepPin,error);
  }
  else {
    digitalWrite(motor_dirPin, LOW);
    analogWrite (motor_stepPin,-error);
  }

  /* Method 2
  if (output  > 0) {
    digitalWrite(motor_dirPin, HIGH);
    stepMotor(output );
  } else {
    digitalWrite(motor_dirPin, LOW);
    stepMotor(-output );
  }
  */
}

void stepMotor(int steps) {
  for (int i = 0; i < steps; i++) {
    digitalWrite(motor_stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(motor_stepPin, LOW);
    delayMicroseconds(500);
  }
}

// Convert angle from encoder
float conv_angle(long compteur) {
  float val_deg;
  val_deg = float(compteur) * 180./1200.;
  return (val_deg);
}

As you can see, I tried different approaches :
For the control output, I tried:

Computing an error by myself (used in the code)

Using a homemade PID found online (commented in the code)

Using the PID_V2 Arduino library (not visible in the code)

For the control of the motor, I tried:

Using the AccelStepper library with moveTo() and run() (not visible in the code)

Using a digitalWrite/analogWrite directly in the loop (used in the code)

Using a for loop for digitalWrite (commented in the loop)

I tried playing with all the values seen above, and to add delays here and there.
I am afraid that I do not completely understand how the stepper is supposed to be controlled, but all these trials are based on what I saw online.

angle_deg_int is not defined. angle_deg is defined but not used. So you probably have a typo there. And the movement you witness is probably due to floating point arithmetics.

You can integrate the PID_v1.h library with the AccelStepper Library for PID Control. The AccelStepper library is well-suited for controlling stepper motors, and it's better to use it for handling speed and acceleration rather than direct digitalWrite or analogWrite calls. This will ensure smoother and more precise movements. Here is the link of  PID_v1.h. https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h

I guess I can try with the PID_v1, but I doubt this is the issue. As I said, I tried with different PID, and also with my own value, and I tried a lot of different combination. Also, as written, I tried using the AccelStepper library with moveTo() and run(), but it didn't work. I may be doing something wrong with it, but I don't really see what. I made sure that moveTo() and run() were both in the same while loop to get called each time.

Sorry, this is a type when I simplified the code to post it here. The code is working well, i just did the int() operation using one more variable that I removed here but forgot to change.
On the floating point thing, what do you mean ? I didn't really pay attention about the types of my variables so it could be something to look at


text:
Input/Output error upload with arduino-cli / avrdude
Unpacked my first Arduino today, an Uno. Went to try the instructions from the arduino-cli getting started tutorial.
When I connect the unit with USB, I get three quick flashes, then slow continual flash on L. ON is green and static on.
When uploading, I get:
$ ./arduino-cli upload -v -p/dev/ttyACM0 --fqbn arduino:avr:uno --log-level trace --log /home/lash/src/tests/arduino/first

[...]

TRAC[0000] Executing upload tool: "/home/lash/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude" "-C/home/lash/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega328p -carduino "-P/dev/ttyACM0" -b115200 -D "-Uflash:w:/tmp/arduino/sketches/DEB5FC46AAF7CC866DBCF1FB0E7F766A/first.ino.hex:i"  phase=upload
"/home/lash/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude" "-C/home/lash/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf" -v -V -patmega328p -carduino "-P/dev/ttyACM0" -b115200 -D "-Uflash:w:/tmp/arduino/sketches/DEB5FC46AAF7CC866DBCF1FB0E7F766A/first.ino.hex:i"

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/home/lash/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf"
         User configuration file is "/home/lash/.avrduderc"

         Using Port                    : /dev/ttyACM0
         Using Programmer              : arduino
         Overriding Baud Rate          : 115200
avrdude: ser_open(): can't open device "/dev/ttyACM0": Input/output error

avrdude done.  Thank you.

ERRO[0010] Upload port detection failed, watcher closed  task=port_detection
DEBU[0010] Received message type: remove, port: /dev/ttyACM0  discovery="builtin:serial-discovery"
Failed uploading: uploading error: exit status 1

Full log here: https://g33k.holbrook.no/86ce60598e75aad78d57cb5c3dc779a58dfda580f8b815f1fdc304601b6a4c52
Seems correctly identified by kernel:
[458984.503600] usb 3-2.1.3: USB disconnect, device number 31
[458985.992061] usb 3-2.1.3: new full-speed USB device number 32 using xhci_hcd
[458986.090224] usb 3-2.1.3: New USB device found, idVendor=2341, idProduct=0043, bcdDevice= 0.01
[458986.090229] usb 3-2.1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=220
[458986.090231] usb 3-2.1.3: Product: Arduino Uno
[458986.090232] usb 3-2.1.3: Manufacturer: Arduino (www.arduino.cc)
[458986.090233] usb 3-2.1.3: SerialNumber: XXXXXXXXXXXXXXXXXX
[458986.099511] cdc_acm 3-2.1.3:1.0: ttyACM0: USB ACM device

Have write permission:
$ cat /etc/udev/rules.d/01-ttyusb.rules
SUBSYSTEMS=="tty", TAG+="uaccess", MODE="0666"
$ groups lash
tty uucp lash
$ ls -l /dev/ttyACM0
crw-rw-rw-+ 1 root uucp 166, 0 Oct 14 03:58 /dev/ttyACM0

Consulted arduino archlinux wiki page, which implied the following command that also doesn't work:
$ stty -F /dev/ttyACM0 cs8 115200 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
stty: /dev/ttyACM0: Input/output error

Any tips on how I can troubleshoot this further?

archlinux 6.10.10
arduino-cli 1.0.3 (archlinux package) and 1.0.4 (built from go source)

https://docs.arduino.cc/software/ide-v1/tutorials/Linux/#please-read

not helpful. this is not a permission issue, it is clearly stated in the question that I have permission to write, and the error doesn't even match. @Juraj


text:
Battery voltage measurement with voltage divider
I am using the following circuit to measure the Li-ion 3.7V battery capacity.

Figure 1 – Schematic for 3.7 V batteries.
This setup works fine for the 3.7V batteries.
To be able to measure 9V batteries, I modified the circuit with a voltage divider so that the Arduino sees max 5v at the analog input. However Arduino reports 0V. I have measured the output of voltage divider with a DMM and it shows 5V. I wonder why doesn't Arduino report the correct voltage. Could you please help me fix it?

Figure 2 – Modified schematic for 9 V batteries which doesn't work.
My code:
#include "LCD5110_Graph.h"
LCD5110 myGLCD(5, 6, 7, 9, 8); // Setup Nokia 5110 Screen SCLK/CLK=5, DIN/MOSI/DATA=6, DC/CS=7, RST=9 Chip Select/CE/SCE=8,
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

#define gatePin 10
#define highPin A0
#define lowPin A1

boolean finished = false;
int printStart = 0;
int interval = 5000; // Interval (ms) between measurements

float mAh = 0.0;
float shuntRes = 1.0; // In Ohms – Shunt resistor resistance
float voltRef = 4.71; // Reference voltage
float current = 0.0;
float battVolt = 0.0;
float shuntVolt = 0.0;
float battLow = 2.9;

unsigned long previousMillis = 0;
unsigned long millisPassed = 0;

void setup()
{
    Serial.begin(9600);
    Serial.println("Battery Capacity Checker v1.1");
    Serial.println("battVolt current mAh");

    pinMode(gatePin, OUTPUT);
    digitalWrite(gatePin, LOW);

    myGLCD.InitLCD(); // initialize LCD with default contrast of 70
    myGLCD.setContrast(68);
    myGLCD.setFont(SmallFont); // Set default font size. tinyFont 4×6, smallFont 6×8, mediumNumber 12×16, bigNumbers 14×24
    myGLCD.clrScr();

    myGLCD.print("Battery", CENTER, 0);
    myGLCD.print("Check", CENTER, 12);
    myGLCD.print("Please Wait", CENTER, 24);
    myGLCD.print("AdamWelch.Uk", 8, 40);
    myGLCD.update();
    delay(2000);
    myGLCD.clrScr();
}

void loop()
{
    battVolt = analogRead(highPin) * voltRef / 1024.0;
    shuntVolt = analogRead(lowPin) * voltRef / 1024.0;

    if (battVolt >= battLow && finished == false)
    {
        digitalWrite(gatePin, HIGH);
        millisPassed = millis() – previousMillis;
        current = (battVolt – shuntVolt) / shuntRes;
        mAh = mAh + (current * 1000.0) * (millisPassed / 3600000.0);
        previousMillis = millis();

        myGLCD.clrScr();
        myGLCD.print("Discharge", CENTER, 0);
        myGLCD.print("Voltage:", 0, 10);
        myGLCD.printNumF(battVolt, 2, 50, 10);
        myGLCD.print("v", 77, 10);
        myGLCD.print("Current:", 0, 20);
        myGLCD.printNumF(current, 2, 50, 20);
        myGLCD.print("a", 77, 20);
        myGLCD.printNumI(mAh, 30, 30);
        myGLCD.print("mAh", 65, 30);
        myGLCD.print("Running", CENTER, 40);
        myGLCD.update();

        Serial.print(battVolt);
        Serial.print("\t");
        Serial.print(current);
        Serial.print("\t");
        Serial.println(mAh);

        delay(interval);
    }
    if (battVolt < battLow)
    {
        digitalWrite(gatePin, LOW);

        finished = true;

        if (mAh < 10)
        {
            printStart = 40;
        }
        else if (mAh < 100)
        {
            printStart = 30;
        }
        else if (mAh < 1000)
        {
            printStart = 24;
        }
        else if (mAh < 10000)
        {
            printStart = 14;
        }
        else
        {
            printStart = 0;
        }

        myGLCD.clrScr();
        myGLCD.print("Discharge", CENTER, 0);
        myGLCD.print("Voltage:", 0, 10);
        myGLCD.printNumF(battVolt, 2, 50, 10);
        myGLCD.print("v", 77, 10);
        myGLCD.setFont(MediumNumbers);
        myGLCD.printNumI(mAh, printStart, 21);
        myGLCD.setFont(SmallFont);
        myGLCD.print("mAh", 65, 30);
        myGLCD.print("Complete", CENTER, 40);
        myGLCD.update();

        delay(interval * 2);
    }
}

Circuit with modifications

Figure 3 – Schematic for 9 V batteries.

Why such tiny resistor values?

Sorry it wasn't the correct schematic. I have updated the post with the correct one. I suppose you were referring to the voltage divider resistors?

Actually, ignore that - I was looking at the resistors wrong. The small ones are current sense and load, not the battery divider.

A load of 4.3ohm on a 9volt battery draws 2amps???

Yes that's indeed high so I am planning to use Rload = 10 ohm. My 9V nominal Li-ion battery has max voltage of 8V so with a total 11 ohm resistance the current will be limited around 819 mA. Since the resistors can take upto 10 W so it should be fine .

The problem comes because you are powering your load through the voltage divider you use for reading your battery voltage.
You cannot do high-side current reading like that with a voltage higher than the ADC voltage. Instead you need to do the current sensing before your voltage divider and then divide that result down again.
Your circuit should look more like:

simulate this circuit – Schematic created using CircuitLab

Thanks for the explanation. I have uploaded a new schematic and I hope I have incorporated your suggestion correctly. Can you please have a look? :)


text:
Please help with my tinkercad code. Debouncing stopwatch with lcd
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int ssPin = 8;
int resetPin = 9;

bool cntrRunning = false;

int sec = 0;
int min = 0;
double currentMillis;

void setup()
{
    Serial.begin(9600);
    lcd.begin(16, 2);
    lcd.print("00:00");
    pinMode(ssPin, INPUT);
    pinMode(resetPin, INPUT);
}

void loop()
{
    if (digitalRead(ssPin) == HIGH)
    {
        if (cntrRunning)
        {
            stop();
        }
        else
        {
            start();
        }
    }
    else
    {
        if (cntrRunning)
        {
            keepRunning();
        }
        else
        {
            stop();
        }
    }

    if (digitalRead(resetPin) == HIGH)
    {
        if (cntrRunning)
        {
            stop();
            reset();
        }
        else
        {
            reset();
        }
    }
    delay(10);
}

void start()
{
    currentMillis = millis();
    cntrRunning = true;
    Serial.println("started");
}

void keepRunning()
{
    cntrRunning = true;

    if ((millis() - currentMillis) >= 1000)
    {
        sec++;
        currentMillis = millis();
        Serial.println(sec);

        if (sec < 10)
        {
            lcd.setCursor(4,0);
            lcd.print(sec);
        }
        else if (sec == 60)
        {
            min++;
            sec = 0;
            lcd.setCursor(3,0);
            lcd.print("00");
        }
        else
        {
            lcd.setCursor(3,0);
            lcd.print(sec);
        }

        if (min < 10)
        {
            lcd.setCursor(1,0);
            lcd.print(min);
        }
        else if (min == 60)
        {
            min = 0;
            lcd.setCursor(0,0);
            lcd.print("00");
        }
        else
        {
            lcd.setCursor(0,0);
            lcd.print(min);
        }
    }
}

void stop()
{
    cntrRunning = false;
    Serial.println("stopped");
}

void reset()
{
    if (cntrRunning)
    {
        stop();
    }
    reset();
    int sec=0;
    int min=0;
}

My professor wants us to add debouncing to the set/stop button but I'm a little confused on how to implement it.

do you understand the reason why debouncing is required?

No not entirely.

ok ... imagine a tennis ball ... hold it high over your head and drop it ... the ball represents the moving contact of a switch ... the floor represents the fixed contact of a switch ... actual switch contacts do something similar to the ball, but in the millisecond realm .... the probem arises in the fact that the microcontroller sees each of the bounces as a keypress

@Amy, a typical tactile button finishes bouncing and achieves stability after about 50 ms. To test for stability, repeatedly sample the input pin looking for a series of equal values, i.e. 1,1,1,1,1 or 0,0,0,0,0. Your loop() runs once every 10 ms, so 5 equal values in a row is 50 ms of stability. Now base your if decisions on this stable value.


text:
i want to combine below two codes
*****1st code
int sensoroutput = 3; // the analog pin connected to the sensor
int sensorinput = A0;
int THRESHOLD = 100;

void setup()
{
    pinMode(3, OUTPUT);
    pinMode(A0, INPUT);   // this function is used to declare gsm connected pin as output
}

void loop()
{
    int value = analogRead(sensorinput);  // function to read analog voltage from sensor
    if (value >= THRESHOLD)                    // function to check voltage level from sensor
    {
        digitalWrite(3, HIGH);
        delay(100);
    }
    else
        digitalWrite(3, LOW);
}

2nd code****
#include <SoftwareSerial.h>

SoftwareSerial sim800l(0, 1); // RX,TX for Arduino and for the module it's TXD RXD, they should be inverted

#define button1 7 //Button pin, on the other pin it's wired with GND

bool button_State; //Button state

void setup()
{
    pinMode(button1, INPUT_PULLUP); //The button is always on HIGH level, when pressed it goes LOW
    sim800l.begin(9600);   //Module baude rate, this is on max, it depends on the version
    Serial.begin(9600);
    delay(1000);
}

void loop()
{
    button_State = digitalRead(button1);   //We are constantly reading the button State

    if (button_State == LOW) {            //And if it's pressed
        Serial.println("Button pressed");   //Shows this message on the serial monitor
        delay(200);                         //Small delay to avoid detecting the button press many times

        SendSMS();                          //And this function is called
    }

    if (sim800l.available()) {            //Displays on the serial monitor if there's a communication from the module
        Serial.write(sim800l.read());
    }
}

void SendSMS()
{
    Serial.println("Sending SMS...");               //Show this message on serial monitor
    sim800l.print("AT+CMGF=1\r");                   //Set the module to SMS mode
    delay(100);
    sim800l.print("AT+CMGS=\"+918707578617\"\r");  //Your phone number don't forget to include your country code, example +212123456789"
    delay(500);
    sim800l.print("SIM800l is working");       //This is the text to send to the phone number, don't make it too long or you have to modify the SoftwareSerial buffer
    delay(500);
    sim800l.print((char)26);// (required according to the datasheet)
    delay(500);
    sim800l.println();
    Serial.println("Text Sent.");
    delay(500);

}

So... what's stopping you combining those two codes?

what is your question? ... this is a Q&A site ... a specific, answerable question is required


text:
Assistance with PID DC Motor Acceleration
I'm working on a project that uses an Arduino UNO and a motorized fader to send and receive MIDI data from my computer/musical keyboard. I'm trying to set up my motor with PID to control the position and speed of the motor - Been having some difficulty, but after watching a few tutorials I think I'm starting to grasp the idea.
Here's the code that I came up with so far - I'm not sure if this is correct for PID control or not, but it makes my motor respond very strangely to any positioning data that is coming in.
#include <SoftwareSerial.h>
#define rxPin 2
#define txPin 1

SoftwareSerial midiSerial (rxPin, txPin);

const byte wiper = 0; //Position of fader relative to GND (Analog 0)

const byte motorUp   = 4;
const byte motorDown = 5;
const byte motorPWM  = 6;

double faderMax = 0;
double faderMin = 0;

byte motorSpeed = 150;  // Raise if the fader is too slow (0-255)
byte tolerance  = 10;  // Raise if the fader is too shaky (0-1023)

int incomingCommand;
int incomingNote;
int incomingVelocity;

int currentPosition;
unsigned targetPosition;
unsigned long distanceToTarget;
unsigned PIDspeed;

void setup() {
  midiSerial.begin(31250);
  Serial.begin(250000);
  analogWrite(motorPWM, motorSpeed);
  calibrateFader();
}

void calibrateFader() {
  digitalWrite(motorUp, HIGH);
  analogWrite(motorPWM, motorSpeed);
  delay(300);
  digitalWrite(motorUp, LOW);
  faderMax = analogRead(wiper) - tolerance;
  digitalWrite(motorDown, HIGH);
  analogWrite(motorPWM, motorSpeed);
  delay(300);
  digitalWrite(motorDown, LOW);
  faderMin = analogRead(wiper) + tolerance;
}

void loop() {

  while ( midiSerial.available() > 0) {
    incomingCommand = midiSerial.read();
    incomingNote = midiSerial.read();
    incomingVelocity = midiSerial.read();
    midiSerial.write( incomingCommand);
    midiSerial.write( incomingNote);
    midiSerial.write( incomingVelocity);
    targetPosition = incomingVelocity*8.05511811024;
    currentPosition = analogRead(A0);
    distanceToTarget = targetPosition-currentPosition;
  }
  PIDspeed = abs(distanceToTarget)/6;

  if (distanceToTarget >=0) {
    analogWrite(motorPWM, PIDspeed);
    digitalWrite(motorUp, HIGH);
    digitalWrite(motorDown, LOW);
  }

  if (distanceToTarget <=0) {
    analogWrite(motorPWM, PIDspeed);
    digitalWrite(motorDown, HIGH);
    digitalWrite(motorUp, LOW);
  }
}

Updated code:
#include <SoftwareSerial.h>
#define rxPin 2
#define txPin 1

SoftwareSerial midiSerial(rxPin, txPin);

const byte wiper = 0; //Position of fader relative to GND (Analog 0)

const byte motorUp = 4;
const byte motorDown = 5;
const byte motorPWM = 6;

double faderMax = 1023;
double faderMin = 0;

byte motorSpeed = 150;  // Raise if the fader is too slow (0-255)
byte tolerance = 10;  // Raise if the fader is too shaky (0-1023)
byte Proportional = 12;

unsigned int incomingCommand;
unsigned int incomingNote;
unsigned int incomingVelocity;

unsigned int PIDspeed;
int currentPosition;
int targetPosition;
int distanceToTarget;

void setup()
{
    midiSerial.begin(31250);
    Serial.begin(250000);
    calibrateFader();
}

void calibrateFader()
{
    digitalWrite(motorUp, HIGH);
    analogWrite(motorPWM, motorSpeed);
    delay(300);
    digitalWrite(motorUp, LOW);
    faderMax = analogRead(wiper) - tolerance;
    digitalWrite(motorDown, HIGH);
    analogWrite(motorPWM, motorSpeed);
    delay(300);
    digitalWrite(motorDown, LOW);
    faderMin = analogRead(wiper) + tolerance;
}

void loop()
{
    while (midiSerial.available() >= 3)
    {
        incomingCommand = midiSerial.read();
        incomingNote = midiSerial.read();
        incomingVelocity = midiSerial.read();
        if (targetPosition <= 1023)
        {
            midiSerial.write(incomingCommand);
            midiSerial.write(incomingNote);
            midiSerial.write(incomingVelocity);
        }
        targetPosition = incomingVelocity * 8.05511811024;
    }
    currentPosition = analogRead(A0);
    distanceToTarget = (targetPosition - currentPosition);
    PIDspeed = (abs(distanceToTarget) / Proportional) + 90;
    analogWrite(motorPWM, PIDspeed);
    if (targetPosition <= 1023)
    {
        if (distanceToTarget > 60)
        {
            digitalWrite(motorUp, HIGH);
        }
        if (distanceToTarget < 60)
        {
            digitalWrite(motorDown, HIGH);
        }
        if ((distanceToTarget >= -60) && (distanceToTarget <= 60))
        {
            digitalWrite(motorDown, LOW);
            digitalWrite(motorUp, LOW);
        }
    }
}

In this version, the motor is actually less responsive than before. I think it must have to do with the data that's coming in from my DAW, which isn't consistently a piece of command, note or velocity data. For example, if I select a different track in my DAW, it sends data into my Arduino. When I read anything greater than 0 bytes, the data still comes in, but the note, command and velocity readings are more sporadically located. It was suggested by another that I try using a MIDI parser, but that's a different topic I suppose.

what were you expecting to happen? ... what happened instead?

I was hoping to add a proportional speed control that would allow the motor to accelerate and decelerate to a specific 'target position', which is being fed into my Arduino via a MIDI cable. What happened is that my motor began behaving very sluggishly when receiving any data. In order to get the motor to move at all, I'd have to feed data into it constantly

i would start at the beginning ... write the minimum code required to turn the motor in one direction at slow speed ... then edit to minimum code to turn slow for 5 seconds and  change speed to medium and run for 5 seconds, repeat .... from that you will learn what is required to keep the motor happy

You are not doing any PID calculations. Is that really, what you want? Or do you want to accelerate and deccelerate your motor symmetrically?

Everything that I've heard from previous users of these motorized faders swear that to have fluid movement, you must use PID rather than PWM. I was thinking that the 'Proportional' value would accelerate my motor proportionally slower as it gets to the target position? Is that not correct?

PID is a type of (feedback loop) control. PWM is just the way a motor can be driven with variable speed. Totally different things. And you need PWM to actually drive the motor. With with PID you could then calculate the PWM value needed. Yes, PID will make it slower near the target position (depending on your chosen parameters for the PID) though I think you won't get a smooth start. Its definitely not the same as ramping up and down with fixed acceleration. So it depends on what you want. PID might work well for you

IMO this sounds more like an interpolation issue (e.g., Ramp library I mentioned the other day): go from x to y following this acceleration/etc curve.

I see 2 main problems with your code, that would make it behave strangely:

You are calculating the new motor speed and decide about the direction based on the variable distanceToTarget. But this variable is only updated, when there is data coming from your MIDI interface. I guess thats only happening, when you want to change the target position. But the motor control runs on every loop iteration, which will be way more often, than you can get the MIDI data. To solve this please move the lines
  currentPosition = analogRead(A0);
  distanceToTarget = targetPosition-currentPosition;

out of the while(midiSerial.available() > 0) loop. Just put then right after it.

At the start of your midi code you check for more than zero bytes being available from midiSerial, but then you are reading 3 bytes in total, without knowing, if there are actually 3 bytes to read. SoftwareSerial.read() will not wait for a byte to come in, it will just return -1. So it can very well be that, just one byte is already received, when the midi code is executed. The rest will be received later. So the rest of the variables is just garbage/invalid. Also this means that sender and receiver are now misaligned. The other 2 bytes (which are received later) will then be handled by the midi code next time as if they were byte 1 and 2 (not 2 and 3). So the next transitions will also be garbage/invalid, until it aligns itself again by chance.
To solve this you should check for at least 3 bytes being available (since you want to read 3 bytes):
  while ( midiSerial.available() >= 3 ) {

Note: As of your comments you seem to have a misunderstanding, what PID and PWM actually is.

PWM is just a way to drive the motor with variable speed by turning the pin on and off very fast, with different ratios between on and off time. With a high ratio towards on time the motor will turn faster than with a low ratio towards on time. This ratio translates to the range from 0 to 255 on an Arduino. So you need PWM to drive a motor with variable speed on the Arduino. You cannot cut that out.

PID is a closed feedback loop control. It denotes a way to calculate a new output value (PWM motor value) based on the measured input value (measured current position). PID stands for Proportional Integral Differential, so for the different terms in the calculations. With PID first the deviation between measured input and target/setpoint is calculated then the PID function is evaluated (with its proportional, integral and differential part of the deviation). With that you get the output value, that you can feed to your output device (the motor here).
PID has nothing to do with PWM. They are totally different things. Only when driving an electromechanical device you might need PWM in the same system as PID. PWM is the hardware way of driving the motor, PID is the way to calculate the output value in a closed feedback loop to reach the target position smoothly and fast.

Actually with your current code (when corrected as described above) already does the proportional part of PID (since you calculate the new speed from the distance to target, so the deviation from the target position). To get full PID you would also need to implement the rest. I would suggest using the Arduino PID library, which already handles the calculation for you. You just need to call it correctly (refer to the examples of the library).

Thanks so much for the details! I'll try this out asap

I'm definitely still trying to understand the concept of PID. I'm glad I've at least got the Proportional section correct (thanks to Majenko in a previous post). I'll try out that library with this and see if I can get it to work out.

There is a fundamental problem with the way you are reading the serial data. Read this excellent article by @Majenko:
https://majenko.co.uk/blog/reading-serial-arduino
The following code will read the last 3 bytes. If, for example, there are 9 bytes available, it will ignore the first 6 bytes:
while (midiSerial.available() >= 3)
{
    incomingCommand = midiSerial.read();
    incomingNote = midiSerial.read();
    incomingVelocity = midiSerial.read();
. . .
}

This will read the next 3 bytes:
if (midiSerial.available() >= 3)
{
    incomingCommand = midiSerial.read();
    incomingNote = midiSerial.read();
    incomingVelocity = midiSerial.read();
. . .
}

Here is the tweaked loop() which:

uses if (midiSerial.available() >= 3) to read the next 3 bytes.
clips the targetPosition if it's out of bounds (0 to 1023).
clips the PIDspeed if it's out of range (0 to 255).
switches the other motor control signal off before enabling the current one just in case the targetPosition crossed zones between loop() iterations.

const int QUIESCENT_BOUNDARY = 60;
const float INCOMING_VELOCITY_SCALE = 1023.0 / 255.0;

byte incomingCommand;
byte incomingNote;
byte incomingVelocity;

void loop()
{
    if (midiSerial.available() >= 3)                // Use `if` to get the next 3 bytes available.
    {
        incomingCommand = midiSerial.read();
        incomingNote = midiSerial.read();
        incomingVelocity = midiSerial.read();
        midiSerial.write(incomingCommand);
        midiSerial.write(incomingNote);
        midiSerial.write(incomingVelocity);
        targetPosition = incomingVelocity * INCOMING_VELOCITY_SCALE;
        if (targetPosition > 1023)                  // Clip if out of bounds.
        {
            targetPosition = 1023;
        }
    }
    currentPosition = analogRead(A0);
    distanceToTarget = targetPosition - currentPosition;
    PIDspeed = abs(distanceToTarget) / 6;           // TODO: Tune the PID equation.
    if (PIDspeed > 255)                             // Clip if out of range.
    {
        PIDspeed = 255;
    }
    analogWrite(motorPWM, PIDspeed);
    if (distanceToTarget > QUIESCENT_BOUNDARY)      // Above the positive bound of the quiescent zone.
    {
        digitalWrite(motorDown, LOW);               // Switch the down control off before switching the up control on.
        digitalWrite(motorUp, HIGH);
    }
    else if (distanceToTarget < -QUIESCENT_BOUNDARY)// Below the negative bound of the quiescent zone.
    {
        digitalWrite(motorUp, LOW);                 // Switch the up control off before switching the down control on.
        digitalWrite(motorDown, HIGH);
    }
    else                                            // In the quiescent zone.
    {
        digitalWrite(motorDown, LOW);
        digitalWrite(motorUp, LOW);
    }
}

That should help you to tune the PID equation.