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:
ESP32 struggling to trigger relay module consistently
I'm working with a 4-channel, 5 V relay module and an ESP32 which operates on 3.3 V.

The setup seemed to work well initially  but I have started experiencing some inconsistencies. One of the four relays is working perfectly fine, but the other three are not triggering as they should.
Here are the symptoms:

The LEDs on the non-working relays do light up when a signal is sent from the ESP32, indicating some form of communication.
There is no audible 'click' sound from these relays when they are supposed to trigger.
I noticed that if I gently tap the relay casing, the relay will sometimes trigger, and I can hear it closing.

I had previously thought that I might have fried my first relay module, so I replaced it, but the issue reappeared after a few days.
Any guidance would be greatly appreciated as I'm at a loss here.

Is your relay board compatible with 3.3 V logic?

@StarCat i don't understand your question can you help me figure out or explain a bit more it's supposed to be powered by 5V DC but i'm limited to the esp32 board

Maybe it is your code.  Try posting a small example that reproduces the problem

More questions here then you might think are because of under powered project using fresh but weak batteries.  Almost always avoid using 9 Volt batteries.  Certainly avoid them if a motor or relay is involved.  How is this project powered?

right now i'm using the usb type-C cable to power the esp directly how can i make the esp32 generate more power or make the relay use less current to be triggered

do not use the ESP32 as a power supply ... it can easily become an expensive fuse ... use it for control only ... power the relay module from a separate power supply

With "compatible with 3.3 V logic" I mean: does your relay board work with 3.3 V logic signals according to its documentation?

So it turns out that esp32 boards can actually output 5v alongside with 3.3v output pin, You just have to use the VN pin which is used for powering the board when not connected through USB, this is not what the pin is intended for and also might cause some problems and you cannot upload code to the board when VIN pin is connected but so far it works perfectly and outputs consistent 5V that triggers the relays just fine.
Obviously, I was just looking for a solution no matter what risks it imposed, can anyone with a deeper understanding of this topic explain why the power input pin can also work as output and why is this not a feature that comes with esp32 boards

Hi Hach, The way this site works is one question followed by answers.  You edit the original question to provide more information.  Or you ask a new question separately.

i answered the original question but asked if the solution i found is efficient and if it presents any dangers to the board

source: Stack Exchange

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

sort: votes


text:
Uploading a Library to the library manager from a Github branch
I am trying to upload a library to the Arduino Library Manager. I know the GitHub - arduino/library-registry: Arduino Library Manager list repository, and I have already read the instructions, but I have a question that I hope someone can explain to me.
The project I am working on is multiplatform, and to fulfill all the requirements for multiple platforms, many files are not required for the Arduino compilation process. I work around this because, with the help of GitHub actions, I have automated a workflow that publishes a branch within the project with an adequate file structure that complies with the Arduino library specification.
On the library-registry repo, step 7 says: " This should be the URL of the repository home page. For example: https://github.com/arduino-libraries/Servo" I am wondering if, in this section, I can put the link to the Arduino branch on the project.
This would mean to include :
https://github.com/myProfileName/myProjectName/tree/Arduino
Instead of :
https://github.com/myProfileName/myProjectName
With the reasoning that the second URL would contain many files that are not needed in an Arduino environment

What happens when you try it?

I mean, I did not try it because none of the URLs from the repositories.txt seems to have a branch in it, I did a ctrl+f with the keyword tree and found zero results, that's why I opened this question

No. As stated in the instructions for submitting a library to the Arduino Library Manager registry, the URL must be to the home page of the repository.
The way the Library Manager index generation system works:

Clone the repository from the URL that was registered URL.
Check out each Git tag in the repository.
Check to see whether the repository contains an Arduino library at that tag.
Check to see whether the library release at that tag is already in the index.
If it is a valid new library release, add the release to the index.

So there is no problem with having the Arduino library in a different branches in the repository because the indexer doesn't work from branches. It works from tags, which are independent from branches. You must only make sure to make a Git tag at the commit ref in the Arduino library branch of your repository at the point in the revision history where you make a release of the library.
In case you also want to tag other branches, that is fine. Even though tags are the unit of release for Library Manager, the versioning of the library releases is done exclusively using the value of the version field of the library.properties metadata file. So you can add something to the tag names to differentiate the Arduino library release tags from tags made in other branches (e.g., Arduino-1.2.3, 1.2.3).
The one consideration with the release strategy I mentioned above is that the submission validation system that checks for problems with the library when you submit it for inclusion in Library Manager checks out the most recent tag in the repository and does that initial validation on the contents of the repository at that specific tag. So you do need to make sure that the Arduino Library release tag is the most recent tag at the time you submit the library.
Once the submission is accepted, all tags in the repository will always be processed (ignoring those that don't pass Arduino Library validation), so it won't matter if tags from branches that don't contain an Arduino library are the most recent tags in the repository after the library has been registered.

Thanks for your answer. The process makes more sense now. I didn't know that the Library Manager index generation system checked out the git tags. I have to make some adjustments and create the first release for the project. Also, the name differentiation tags are an excellent idea to differentiate releases.

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


text:
SPI with DMA in a Arduino Due
I have a project where I need to store data (~16 Mo) on a memory and be able to fetch the data fast (<36000 bits/s) with DMA because I have other signals to take care of.
Currently I use an SD card with the SD library, but it doesn't seems to use DMA because of the delay between sending.
Many people told me it shouldn't be that hard and I suppose so. My guess is that I can't configure the DMA and/or the SPI correctly.
I tried this a long time ago.
Can someone show me an example of SPI with DMA, or tips on how to configure both?

#include <dmac.h>
#include <SPI.h>
#include <Arduino.h>
#include <sam.h>

uint8_t sourceBuffer[256];

void setup() {
  SPI.begin();
  SPI.setClockDivider(21);  // 4MHz clock (assuming 84MHz system clock)
  setupDMA();
}

void loop() {

  for(int i = 0; i < sizeof(sourceBuffer); i++) {
    sourceBuffer[i] = i;
  }
  startDMATransfer();
  delay(1000);
}

void setupDMA() {
  // Enable the DMA controller
  PMC->PMC_PCER1 |= PMC_PCER1_PID34;  // DMA ID for the Due is 34

  // Disable SPI DMA TX and RX
  SPI0->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS;

  // Setup a DMA channel for the transfer (channel 1 for this example)
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Disable the DMA channel
  channel->DMAC_CHDR = DMAC_CHDR_DIS;

  // Clear any flags and reset the status
  channel->DMAC_CHDR = DMAC_CHDR_RES;

  // Set up source and destination pointers
  channel->DMAC_SADDR = (uint32_t) sourceBuffer;
  channel->DMAC_DADDR = (uint32_t) &(SPI0->SPI_TDR);

  // Configure source and destination pointers: source increments, destination does not
  channel->DMAC_CTRLA = DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;

  // Set source and destination handshake (related to the SPI0 Tx)
  channel->DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | DMAC_CTRLB_DST_DSCR_FETCH_DISABLE |
                        DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING |
                        DMAC_CTRLB_DST_INCR_FIXED;

  channel->DMAC_CFG = DMAC_CFG_SRC_PER(1) | DMAC_CFG_DST_PER(1) | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
}

void startDMATransfer() {
  // Assuming channel 1 is used
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Set up the buffer size
  channel->DMAC_CUBC = sizeof(sourceBuffer);

  // Enable SPI DMA for TX
  SPI0->SPI_PTCR = SPI_PTCR_TXTEN;

  // Enable the DMA channel to start the transfer
  channel->DMAC_CHER = DMAC_CHER_ENA;
}

When you want to send data via SPI using DMA, you can fill the sourceBuffer and call startDMATransfer().
Remember to always refer to the Atmel SAM3X8E datasheet and the Arduino Due's schematic when you are working at this level, as it provides in-depth details on how the hardware functions. I am unable to run the code or test it. But I believe that the code logic is proper. Error handling is up to you.


text:
AccelStepper.h - How can I quickly increase the speed of a NEMA 17 motor?
I'm pretty new to Arduino. I am trying to build a self-balancing robot. I am using A4988 drivers, an ESP32 microcontroller, NEMA 17 motors, and a 6050 MPU.
The problem is that, although the speed variable changes according to the position of the MPU, the motors rotate at a slow and constant speed, without varying according to the inclination of the robot.
Here is the code:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <AccelStepper.h>

#define STEP_IZQ 26
#define DIR_IZQ 27
#define STEP_DER 12
#define DIR_DER 13

AccelStepper stepperizq(AccelStepper::FULL2WIRE,STEP_IZQ,DIR_IZQ);
AccelStepper stepperder(AccelStepper::FULL2WIRE,STEP_DER,DIR_DER);
Adafruit_MPU6050 mpu;

float kp = 20;
float ki = 0.5;
float kd = 30;

float angulo_grad, error, cumError, rateError, output, lastError;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
int speed, outputAbs;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

  pinMode(DIR_IZQ, OUTPUT);
  pinMode(DIR_DER, OUTPUT);

  stepperizq.setMaxSpeed(3000);
  stepperder.setMaxSpeed(3000);
  stepperizq.setAcceleration(1000); // 1000
  stepperder.setAcceleration(1000); // 1000
}

void loop() {
  // Get new sensor events with the readings
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            // 0 to 90 degrees
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // pid
  /////////////////////////////////////////////////////////////////////////////////////////////////

  pid_error_temp = angulo_grad;
  if ((pid_error_temp > -2.0) && (pid_error_temp < 2.0)) pid_error_temp = 0.0;

  pid_i_mem += ki * pid_error_temp;                                 // Calculate the I-controller value and add it to the pid_i_mem variable
  if (pid_i_mem > 800) pid_i_mem = 800;                                       // Limit the I-controller to the maximum controller output
  else if (pid_i_mem < -800) pid_i_mem = -800;
  // Calculate the PID output value
  pid_output = kp * pid_error_temp + pid_i_mem + kd * (pid_error_temp - pid_last_d_error);
  if (pid_output > 5000) pid_output = 5000;                                     // Limit the PI-controller to the maximum controller output
  else if (pid_output < -5000)pid_output = -5000;

  if (output < 50 && output > 50) output = 0;
  pid_last_d_error = pid_error_temp;
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //motors nema 17
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  outputAbs = (int)abs(pid_output);
  speed = map(outputAbs, 0, 5000, 0, 3000);

  stepperizq.setSpeed(speed);
  stepperder.setSpeed(speed);

  if (pid_output<0) {
    digitalWrite(DIR_IZQ, LOW);
    digitalWrite(DIR_DER, HIGH);
  }
  else if (pid_output>0) {
    digitalWrite(DIR_IZQ, HIGH);
    digitalWrite(DIR_DER, LOW);
  }
  stepperizq.runSpeed();
  stepperder.runSpeed();
}

Just a guess, but can it be, that your loop() is running to slow for it to keep up with the necessary steps? If for example the sensor readings are taking too long (in the range of the period between two consecutive steps), then each execution of runSpeed() would find, that it always was time to do a step, doing exactly one step and then exiting to the rest of loop(). That would limit your speed to one step per loop() iteration, which probably has a constant duration. You could try to only get new measurements at set intervals (like every x ms)

Agree with @chrisl.   Try wrapping the measurement & calculations in an if (millis() - last > interval){...} throttle.

I added this:

currentMillis = millis();
if(currentMillis - previousMillis >=100){
previousMillis = currentMillis;
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            //0 to 90 degrees

}

And it worked. Thank you all for ypur help

To write down my guess from the comments in a proper answer:
When a stepper motor driven with AccelStepper shows a constant speed, though the speed is set to different values, it suggests, that the time interval of the steps is defined by something else.
The runSpeed() function works by saving a timestamp of the last step and then checking the elapsed time on the basis of the set speed, to check if the time for another step has come and if yes, then execute exactly one step. For this to work correctly, you need to call this function within intervals smaller than the smallest period between two consecutive steps for your speed.
If for whatever reason you call the function with larger intervals, the runSpeed() function will always see, that the time for a new step has come, but it will always only do one step per execution. Thus you overall get one step per runSpeed() execution, and this is determined by the rest of your code, not the set speed.
The rest of the code in loop() is for getting the measurements of the MPU and calculating the resulting speeds from that. Probably this is taking too long and thus hindering the AccelStepper library from running the motor at the specified speeds. So you need to provide a larger timeslot for the stepper driving on your ESP by cutting down on your MPU sampling rate. This is easiest done by using
// Running MPU sampling and calculation only every 100ms
if(millis() - previousMillis >= 100){
  previousMillis += 100;
  // MPU and calculation code here
}
// Running the stepper code on every loop iteration
stepperizq.runSpeed();
stepperder.runSpeed();

which is the non-blocking coding style used in the BlinkWithoutDelay example. If you don't know how to use millis(), there are many tutorials online for that.


text:
IR Remote control on UNO
I am working on IR remote code run on Arduino UNO
I can already get it work. but when I press the button and hold, the output is sent with the same value repeatly. So,the quesion is how can I do to make it send out only one output while I press and hold the button.
this is my code
#include <IRremote.h>
int RECV_PIN = 5;
#define PB  3392264773 // button code
#define VUP  3476004267 // button code
#define VDN  2998643817 // button code
#define SRC  387001607 // button code
#define MUTE  305976139 // button code

IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}
void loop() {
  if (irrecv.decode(&results)) {

    if (results.value == PB) {
      Serial.println("Power");
    }
    if (results.value == VUP) {
      Serial.println("Vol UP");
    }
    if (results.value == VDN) {
      Serial.println("Vol Down");
    }
    if (results.value == SRC) {
      Serial.println("Select");
    }
    if (results.value == MUTE) {
      Serial.println("Mute");
    }

    irrecv.resume(); // Receive the next value

  }
}

and this is output when I press and hold the button
Power
Power
Power
Power
Power
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP

Thank you for all answers.
Tanwa

you cannot do anything to make it send only one output ... you cannot modify the remote control

one thing has crossed my mind ... the remote control may be using a repeat code instead of key code when a button is held down ... if that is the case, then the IR library could be modified to generate repeated code that is distinct from the keypress code

by adapting chrisl's idea, I got it done. the code is here.
#include <IRremote.h>
int RECV_PIN = 5;
#define PB  3392264773 // button code
#define VUP  3476004267 // button code
#define VDN  2998643817 // button code
#define SRC  387001607 // button code
#define MUTE  305976139 // button code

int pre_p  = 0;
int pre_src  = 0;
int pre_mu  = 0;

//trigger
int p = 0;
int src = 0;
int mu = 0;

int pw = 0;
int s = 0;
int m = 0;

IRrecv irrecv(RECV_PIN);
decode_results results;

unsigned long previous_timestamp;
unsigned long check_timestamp;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}
void loop() {
  if (irrecv.decode(&results)) {

        if (results.value == PB){
           p = 1;
          if(p != pre_p){
           pw = !pw;
            //Serial.println(pw);
              Serial.println("pw");
              Serial.println(pw);
          }
        }
      if (results.value == VUP) {
        Serial.println("Vol UP");
      }
      if (results.value == VDN) {
        Serial.println("Vol Down");
      }
      if (results.value == SRC) {
        src = 1;
          if(src != pre_src){
           s = !s;
          Serial.println("s");
          Serial.println(s);
          //Serial.println("Select");
          }
      }
      if (results.value == MUTE) {
        mu = 1;
          if(mu != pre_mu){
           m = !m;
          //Serial.println("Mute");
          Serial.println("mu");
          Serial.println(m);
          }
      }

    irrecv.resume(); // Receive the next value
    pre_p = p;
    pre_src  = src;
    pre_mu  = mu;

    p=0;
    src = 0;
    mu = 0;

    previous_timestamp = millis();

  }
    if(millis() - previous_timestamp > 200){
    pre_p = 0;
    pre_src  = 0;
    pre_mu  = 0;
  }
}

As noted in the comments, you cannot change what the remote is sending. Though I guess, that it would be OK for you to just react to the first occurence of a specific value send consecutively. For that you first need to check the time between these consecutive values send, when holding the button down. That (plus a small margin) will be the threshold to recognize multiple distinct button presses. Note: Depending on the rate, that the remote is sending when holding a button, this might mean, that you cannot distinguish between holding a button and pressing it multiple times in a fast pace.
First define a variable to hold the previous decode results and a timestamp for saving when it arrived:
decode_results previous_results;
unsigned long previous_timestamp;

On receiving a new value via IR, check if the new value is the same as in previous_results. If yes, don't execute the code checking for the actual value. If no, then update previous_results with the new value and act upon the actual received value. Then set the timestamp to the current millis() value and resume receiving.
if (irrecv.decode(&results)) {
  if(results != previous_results){
    previous_results = results;
    if (results.value == PB) {
      Serial.println("Power");
    }
    ....
  }
  previous_timestamp = millis();
  irrecv.resume(); // Receive the next value
}

Now you need to reset the previous_results variable after a specific time threshold, so that consecutive presses on the same button can be registered. Add a corresponding millis() statement to your loop() function:
if(millis() - previous_timestamp > 500){
  previous_results = 0;
}

Note: The value of 500ms is just a wild guess. As described at the start, you need to find that value yourself, fitting to your remote. Play a bit with this value until you are satisfied.
All in all something like this:
#include <IRremote.h>
int RECV_PIN = 5;
#define PB  3392264773 // button code
#define VUP  3476004267 // button code
#define VDN  2998643817 // button code
#define SRC  387001607 // button code
#define MUTE  305976139 // button code

IRrecv irrecv(RECV_PIN);
decode_results results;
decode_results previous_results;
unsigned long previous_timestamp;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}
void loop() {
  if (irrecv.decode(&results)) {
    if(results != previous_results){
      previous_results = results;
      if (results.value == PB) {
        Serial.println("Power");
      }
      if (results.value == VUP) {
        Serial.println("Vol UP");
      }
      if (results.value == VDN) {
        Serial.println("Vol Down");
      }
      if (results.value == SRC) {
        Serial.println("Select");
      }
      if (results.value == MUTE) {
        Serial.println("Mute");
      }
    }
    previous_timestamp = millis();
    irrecv.resume(); // Receive the next value
  }

  if(millis() - previous_timestamp > 500){
    previous_results = 0;
  }
}

Note: I have not tested this code in any way.

I got it done by adapting your comment. Thank you very much


text:
Sparkfun Pro Micro (5v) as ISP error
I'm trying to use Sparkfun Pro Micro (5v 16MHz) as ISP to program Attiny chips (OS:Windows10Pro). I followed instructions. Installed proper driver and added Sparkfun boards to ArduinoIDE:

Using Arduino IDE uploaded ArduinoISP sketch on it. As you can see there are two options available to choose for programmer:

Arduino as ISP
Arduino Leonardo/Pro Micro as ISP

Which unfortunately both of them give the same error:
Sketch uses 28 bytes (2%) of program storage space. Maximum is 1024 bytes.
Global variables use 0 bytes (0%) of dynamic memory, leaving 64 bytes for local variables. Maximum is 64 bytes.
C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\tools\avrdude\7.1-arduino.1/bin/avrdude -CC:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf -v -pattiny13a -cstk500v1 -PCOM16 -b19200 -Uhfuse:w:0xff:m -Ulfuse:w:0b00111010:m -Uflash:w:C:\Users\K1\AppData\Local\Temp\arduino_build_207900/sketch_aug28a.ino.hex:i

avrdude: Version 7.2
Copyright the AVRDUDE authors;
see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

System wide configuration file is C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0\avrdude.conf

Using Port                    : COM16
Using Programmer              : stk500v1
Overriding Baud Rate          : 19200
avrdude stk500_recv() error: programmer is not responding
avrdude stk500_getsync() warning: attempt 1 of 10: not in sync: resp=0x00
avrdude stk500_recv() error: programmer is not responding
avrdude stk500_getsync() warning: attempt 2 of 10: not in sync: resp=0x00
...

avrdude done.  Thank you.
the selected serial port
 does not exist or your board is not connected

I tried avrdude in command line with these parameters and got the same results:
avrdude -p attiny13a -P COM16 -c avrisp -b 19200 -U flash:w:r.hex -v

I also found out that issue most probably has nothing to do with:

Target chip that I'm using: because changing it has no effect
Wiring: because even when there is no chip connected to SPI pins of ProMicro I get the same error
USB cable is good: I can upload sketches successfully to Pro Micro but cannot use it as ISP and replaced cable to rule that probably out.

This is while in this video the guy does what I want easily and has no issues whatsoever:
https://www.youtube.com/watch?v=7Rz9A9VbDx4
Any ideas appreciated.

GOTCHA...
After two days of search and speculation finally found the solution:
Short answer:
In avrdude command instead of -c avrisp use -c arduino:
avrdude -p attiny13a -P COM16 -c arduino -b 19200 -U flash:w:r.hex -v

Long answer:
My target chip was ATtiny13a, so I had to use MicroCore v2.3.0 which is the only core supporting ATtiny13 for Arduino. Contrary to other cores, in this core's programmers.txt list, each entry should have a upload.protocol line:
arduinoasispatmega32u4.upload.protocol=

otherwise it will give this error:
avrdude programmer_not_found() error: cannot find programmer id {upload.protocol}

I have added this line before to make that error go away but apparently with wrong parameter of stk500v1 that I have imitated from fabric entries! Converting this parameter to arduino solved the problem. This is what that entry should look like for ATtiny13 of MicroCore v2.3.0 (\packages\MicroCore\hardware\avr\2.3.0\programmers.txt):
arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
arduinoasispatmega32u4.communication=serial
arduinoasispatmega32u4.protocol=arduino
arduinoasispatmega32u4.upload.protocol=arduino
arduinoasispatmega32u4.speed=19200
arduinoasispatmega32u4.program.protocol=arduino
arduinoasispatmega32u4.program.speed=19200
arduinoasispatmega32u4.program.tool=avrdude
arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

For other cores, like ATTinyCore v1.5.2 (\packages\ATTinyCore\hardware\avr\1.5.2\programmers.txt) no such line is needed hence this entry works fine:
arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
arduinoasispatmega32u4.communication=serial
arduinoasispatmega32u4.protocol=arduino
arduinoasispatmega32u4.speed=19200
arduinoasispatmega32u4.program.protocol=arduino
arduinoasispatmega32u4.program.speed=19200
arduinoasispatmega32u4.program.tool=avrdude
arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

Also you should update avrdude in the Arduino core manually:
Download latest release from HERE, and replace them IDE's related files. If you can not find them take a look at HERE. If avrdude is not updated you might get an error like this:
Error during upload using programmer
The uploader process failed

The uploader process failed
The uploader returned an error
avrdude: Version 6.3-20201216
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch
         System wide configuration file is "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"
avrdude: error at C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf:421: syntax error
avrdude: error reading system wide configuration file "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"

Third Solusion:
Use this App with this configuration:


text:
ESP32 TTGO T-Call connect to SX1276
I have an ESP32 TTGO T-Call and I want to add a LoRa SX1276. I am new to that and I am trying to write a simple program that, when it receives a packet from a LoRa sender, sends via gsm an HTTP request. GSM communication works fine with the TinyGSM library. My problem is the LoRa connection.
Specific chips according to this issue have some reserved pins. If I use the pins of the above example lora works but GSM does not work, because of the reserved pins for the SIM800. I am posting a piece of code with the LoRa setup that is not working. If there is a need for further explanation please ask. I will appreciate any kind of help.
#define SCK 14
#define SS 15
#define MISO 19
#define MOSI 27
#define RST 34
#define DIO0 33

SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);

while (!LoRa.begin(866E6)) {
    SerialMonitor.println(".");
    delay(500);
}
SerialMonitor.println("LoRa Initializing OK!");

Edited
With setting
#define LORA_MISO 19
#define LORA_MOSI 27
#define LORA_SCK 5
#define LORA_SS 18

#define LORA_RST 14
#define LORA_DIO0 26

Lora works (not sim800) but with the settings of @Juraj comment i am getting

E (11571) gpio: GPIO can only be used as input mode
[ 11575][E][esp32-hal-gpio.c:130] __pinMode(): GPIO config failed
E (11571) gpio: gpio_set_level(226): GPIO output gpio_num error
E (11586) gpio: gpio_set_level(226): GPIO output gpio_num error

Edit
Although the error exists it is working with the above settings:
#define LORA_MISO 2
#define LORA_MOSI 13
#define LORA_SCK 14
#define LORA_SS 15

#define LORA_RST 34
#define LORA_DIO0 25

Some packets from the sender are lost but it seems to be working. I don't know why, but it is working... Also it does not seem very stable.
Finally pins 34-39 can be used as input so #define LORA_RST 34 is not working. But it is not receiving yet from the sender.

try MOSI 12, MISO 19, SCK 18 and any pin as SS so your io 15 would be ok

@Juraj thx for your comment. I will try it and I will give you the feedback

@Juraj thx unfortunately i am getting E (11571) gpio: GPIO can only be used as input mode
[ 11575][E][esp32-hal-gpio.c:130] __pinMode(): GPIO config failed
E (11571) gpio: gpio_set_level(226): GPIO output gpio_num error
E (11586) gpio: gpio_set_level(226): GPIO output gpio_num error

try to swap MISO an MOSI in my suggestion. so MOSI 19, MISO 12, SCK 18

Althought Lora.begin, i am getting before begin same error and of course when sender sends nothing is recieved

Pin 14 looks a bit overloaded: #define SCK 14 and #define LORA_RST 14. Can't you move LORA_RST in an attempt to get both devices working simultateously?

My current settings are ```#define LORA_MISO 12
#define LORA_MOSI 19
#define LORA_SCK 18
#define LORA_SS 15
#define LORA_RST 34
#define LORA_DIO0 25 ```  and according to these settings i am getting the error when try to connect to Lora. Inialy i am trying to get lora work with other pins than the default where the conflict exists with sim800.

The issue seems to be arising from the pin definitions and the fact that the SIM800 and the SX1276 LoRa chip on the board might be competing for the same pins, causing interference
First, let's understand the TTGO T-Call pin mapping for SIM800:
SIM800L IP5306 version 20190610:

4: SIM800L RST
23: SIM800L DTR
26: SIM800L PWR
27: SIM800L TX
32: SIM800L RX
33: SIM800L RI

From the pins you've listed for the LoRa SX1276:

SCK: 14
SS: 15
MISO: 19
MOSI: 27
RST: 34
DIO0: 33

It's clear that MOSI on 27 and DIO0 on 33 interfere with SIM800L's pins.
You need to select pins for LoRa that do not interfere with the SIM800L. However, keep in mind that the ESP32 has certain pins that are not suitable for all types of connections.
a proposed remapping would be as follows:
#define SCK 14
#define SS 15
#define MISO 19
#define MOSI 22
#define RST 34
#define DIO0 25

Tell me if this works.

would like to thank you for the try but i am getting the above: E (4757) gpio: GPIO can only be used as input mode
[  4761][E][esp32-hal-gpio.c:130] __pinMode(): GPIO config failed
E (4757) gpio: gpio_set_level(226): GPIO output gpio_num error
E (4771) gpio: gpio_set_level(226): GPIO output gpio_num error. This happens when try connect to Lora

hi there in that case please change the "RST" to something like 13? if the pin 13 is not being used by some other modules and if available switching to that should work. if 13 is in use I think you can also use 12, 16, 17, 21, 22 as well. please make sure that the pin you assign does not interfere with anything else. just change the "RST" pin in my answer and it should start working. write back to me after checking the available pin and please tell me if it works. good luck. the problem with my first answer was probably 34 was input only but 13 should work. if it works please approve.

With my last edit in pins config and set rst to 33 worked like a harm! Mosi in 27 did not worked. I had to set to other like I did set it to 2.

I am very glad to hear that. Some pins are pre-occupied so they don't work. It seems like 34 was only input pin. 33 or 13 in that aspect would work. does mosi 22 works?

I haven't tested yet and I am done for today . I will check it tomorrow and I will give you feedback. Thx for your time


text:
Weird behaviour with BearSSL on GPIO ESP8266
I use GPIO 5 to trigger a relay. My code also connects with a secure MQTT connection for which I have to use the BearSSL certificate definitions.
Without the BearSSL certificates, when the ESP restarts it does not re-trigger the relay, and the GPIO maintains its state between reboots, but when I use the bearSSL certificates the behavior changes, and GPIO 5 goes low on restart. Any explanation why and how to mitigate it?
I am 100% sure it is because of the import, because I removed components from my code until I could find the piece of code that caused this, and it was because of the declarations.
#include <WiFiClientSecure.h>

static const char AWS_CERT_CA[] PROGMEM = R"EOF(aws root)EOF";
static const char AWS_CERT_CRT[] PROGMEM = R"KEY(device cert)KEY";
static const char AWS_CERT_KEY[] PROGMEM = R"KEY(device key)KEY";

BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

WiFiClientSecure espClient;

void setup() {
  pinMode(5, OUTPUT);
  delay(2000);
  digitalWrite(5, HIGH);
  delay(2000);
  ESP.restart();
}

void loop() {}

Without the following three lines the LED on GPIO 5 does not flicker on restarts, but adding these lines makes them flicker:
BearSSL::X509List cert(AWS_CERT_CA);
BearSSL::X509List client_crt(AWS_CERT_CRT);
BearSSL::PrivateKey key(AWS_CERT_KEY);

Any solution or suggestion towards a solution for this problem will be really helpful.

What worked for me was to move the BearSSL declaration and usage after the pinMode setting of the GPIO.
I had to make the certificate and keys local variables and wrap the entire setting up of WiFi, connecting to it, setting up and connecting to the AWS core in a single function after setting up the GPIO pins.
void setupWiFiAndConnectAWS() {
  BearSSL::X509List cert(AWS_CERT_CA);
  BearSSL::X509List client_crt(AWS_CERT_CRT);
  BearSSL::PrivateKey key(AWS_CERT_KEY);
  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Setting host name\n");
  WiFi.hostname(deviceId);
  DEBUG_MSG("[setupWiFi] Setting station mode\n");
  WiFi.mode(WIFI_STA);

  if (WiFi.getMode() & WIFI_AP) {
    WiFi.softAPdisconnect(true);
  }

  WiFi.persistent(false);
  DEBUG_MSG("[setupWiFi] Loading certificates\n");
  net.setTrustAnchors(&cert);
  net.setClientRSACert(&client_crt, &key);
  loadCredentials();
  connectWiFi();
  attachInputInterrupts(false);
  setupNTP();
  connectAWS();
}

Although this is a workaround, I still don't understand the core problem and would like to understand it.


text:
Using an A4988 stepper motor driver for a low current (15mA) stepper motor
I have a BKA30DR5 stepper motor that operates at 15mA. I want to drive it using an A4988 stepper motor module. I've previously driven stepper motors that use much higher currents (around 1A) successfully with these modules so I figured I'd use it again.
I set the reference voltage on the module according to this method, combined with the information on this page. The current sense resistors on the board read R100 so my formula for calculation the reference voltage is 0.015A * 8 * 0.1 Ohms = 0.012V. That's such a low voltage that I have trouble setting it using the trim pot: I have to make minuscule adjustments once I get below the 0.02V range and even then it just goes from 0.02V to 0.005V seemingly at random. I guess the trim pot becomes inaccurate at that very very low range.
How do I get the module to provide the correct reference voltage to the motor? I guess the motor uses so little power that I could technically skip the module entirely and connect it directly to the pins on the Arduino but I'm not sure if that's safe for the arduino considering back EMF. Perhaps it's also possible to set the module to a higher reference voltage and then use a separate resistor to drop the voltage to the correct amount but I'm not sure if that even works with stepper motors, nor where between the module and the motor the resistor(s?) should be connected.
Any ideas?

Is your motor currently not running at all, or is it stuttering?

I have not hooked it up yet for fear of destroying it.


text:
Why Arduino IDE is brignging wrong board name for ESP32 S3

I am designing a pcb for ESP32 S3 wroom-1 for testing pins which are safe to use.
My PCB look like this:

I program ESP32 S3 via USB interface gpio19 "D-" gpio20 "D+". When I plug in my usb, Arduino ide brings wrong name for my Esp32 board. By the way I use USB TYPE C. Everyday it gives different names. Correct one is "ESP32S3 DEV MODULE".
How can I set it to select the correct module automatically on Arduino Ide as ESP32S3 Dev Module?
WRONG 1

WRONG 2

WRONG 3

same board different names. interesting

I've noticed that some ESP32 boards have a USB-to-Serial chip that is programmed with a confusing (i.e. wrong) identifier. There's no way to change this, but it will not have any effect on the board's functionality as long as you select the right board when you're programming it.

After an Arduino IDE update 2.2, something was solved, yesterday (30,08,2023).
There is a new edit button appearing on the board selection menu and then Arduino ide recognises esp32 even after plugging out and in again.

You can just force Arduino IDE to recognise your board by locating your Boards Configuration File, putting in your VID and PID values, repackage and host the configurations and Point the Arduino IDE to your custom board manager URL.
On my MacBook device I have used ioreg -p IOUSB -l after plugging in a device and copy the idVendor, idProduct properties. These are the VID and PID values. On Windows you may open Device Manager, look under the Ports (COM & LPT), right click on your board (it might appear as a COM port) and choose "properties", go to "details" menu, and there from the dropdown menu, select "Hardware Ids". you should see values like VID_XXXX&PID_YYYY. these are your VID and PID. on Linux you may just use "lsusb" and find the vendor ID and PID there.
After finding those you must go to ESP32 board package directory and find boards.txt (https://github.com/espressif/arduino-esp32/blob/master/boards.txt). Find the line that starts with esp32s3.name=ESP32S3 Dev Module. There you must modify the PID and VID values with your actual VID and PID values that you collected as mentioned above. Replace 0xXXXX with your VID and 0xYYYY with your PID.
After modifying, you'll need to compress the entire board package directory into a ZIP archive. Make sure the directory structure remains intact so that the Arduino IDE can recognize and install it correctly.
Then you can create a new repository on GitHub, upload the ZIP archive to this repository, then click on the ZIP file inside the repository, then click the "Download" button. Copy the link.
Now you must go to the Arduino IDE, go to file -> preferences. in the "Additional Boards Manager URLs" field, click on the icon on the right to open a window where you can insert new lines. Add the direct link to your ZIP file and click OK. Go to Tools -> Board -> Boards Manager. then search for ESP32. your custom package should appear in the list. Click "Install". after it installs you are good to go.
VERY IMPORTANT EDIT: after investigating this issue a little more I have came to realisation that so called "random board names" that show up all have the same VID and PID values. The problem was not the incorrect VID and PID values for your board, the problem was that a bunch of other boards also have the same VID and PID values. A simple yet effective fix would be to assign random names to all the other ones than the one you want to use. Just edit the
adafruit_qtpy_esp32c3.vid.0=0x303a

adafruit_qtpy_esp32c3.pid.0=0x1001

lines for every board other than what you want to use. But never forget to change this text file if you ever start doing long-run development with one of the other boards. Or the other boards (such as u-blox NORA-W10 s3" won't be auto detected.

A comprehensive explanation of this also appears here: https://forum.arduino.cc/t/arduino-nano-esp32-board-is-always-identified-as-adafruit-esp32/1241431/2


text:
Multiple TFT's not displaying
I am trying to connect about 5 TFT's to my Arduino Uno and I got to the point of hooking two of them up without any issues. However, after a code upload, they stopped working. I then took all the code out and tested each in isolation and they still function. However, together only one of them displays data.
The TFT's I am using are the ST7789v2 found here. https://www.waveshare.com/wiki/1.69inch_LCD_Module#Hardware_Connection_3
I have wired them up according to the schematic with "all" pins being shared except the CS pin. Each display has its own.
The code looks like this;
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>

#define TFT_CS1 10
#define TFT_CS2 3

#define TFT_RST        8 // Screens shared
#define TFT_DC         7 // Screens shared
#define TFT_BACKLIGHT  9 // Backlight for all screens

Adafruit_ST7789 tftHour1 = Adafruit_ST7789(TFT_CS1, TFT_DC, TFT_RST);
Adafruit_ST7789 tftHour2 = Adafruit_ST7789(TFT_CS2, TFT_DC, TFT_RST);

Adafruit_ST7789 setupScreen (Adafruit_ST7789 tft){
  tft.init(240, 280);
  tft.fillScreen(ST77XX_BLACK);
  return tft;
}

void setup(void) {
  tftHour1 = setupScreen(tftHour1);
  tftHour2 = setupScreen(tftHour2);
}

void loop(){
  tftHour1.print("1");
  tftHour2.print("2");
}

When this executes, display 2 shows output but display 1 does not. Weirdly if I take the CS from display 1 and pop it into the same line on the breadboard as CS2, and then put it back into its original position, display 1 and 2 seem to work. But only till the next power cycle or upload.
Also oddly, setting the colour of each screen works even if one is blue and the other is say green. Both change to their respective colours. But when I try to write text to them, only one of them has text.
If I comment the code for tftHour2, then tftHour1 starts showing text. If I swap the setup code for ftfHour1 and tftHour2, then the display that is last to init, is the one that shows the text and the other stays blank.
Like I said, I had all this working and then a simple font change upload and it all stopped working.
Any help on this is really appreciated.
I should mention that I am a programmer and very new to electronics so please keep it simple.
#Update. If I have separate RST pins then it works. But I need 5 screen and will run out of pins in that case. Is there a way to get around that?

your code is inconsistent ... there is a definition for two object names tftHour1 and tftHour2 and then you throw in an object name tft

so that's within a function where I can send it a tft object, init that and return. The name of the object, inside the function, is tft. it's for reusability and to cut down on the amount of code and thus space

Off-topic: Your function setupScreen() takes a Adafruit_ST7789 as argument, that is perfect to use the same code. But 1st, why does the function need to return that argument? And 2nd, why do you overwrite the existing objects in tftHour1 and tftHour2 with themselves?

I did that initially because I wasn't quite sure whether the Arduino IDE considered the passed object context as local or not. However, it makes no difference whether I return the object, and overwrite the global one, or not.

@thebusybee he probably needs it because he is passing it as copy of original, so it doesn't affect the original object without making copy back into it :D Hint: he should use pass by reference (or pointer, but reference is more straightforward) void setupScreen (Adafruit_ST7789 & tft) { // now changes to tft will be changing original object too

According to the data sheet, the RST signal is accepted without an active CS, so when sharing this signal, all displays are reset if you initialize just one of them. That explains the behavior you observe.
You found the solution: Do not share the RST signal in all instances of Adafruit_ST7789.

Now you worry about the needed number of pins, and that is indeed an issue.
One possible solution is to use a decoder that takes n inputs to activate 1 of 2n outputs, like this:

simulate this circuit – Schematic created using CircuitLab
To control 5 RST lines you will need only 3 pins. Use a binary value to select one of the unused outputs to deactivate all RST lines.
The same is true of the CS lines.
However, the library in use does not support this kind of control. Therefore, I'm afraid that you need to consider another Arduino model with more pins.

As a work-around, you might want to try this alternative:
Assign the same Arduino pin to all instances of Adafruit_ST7789, as in your first attempt. But do not connect it to the RST inputs of the displays. Leave the Arduino pin unconnected.
Instead, use another Arduino pin and connect that to the displays. Then during initialization, reset all displays with your own code. See the data sheet for correct levels and timing.
Or try to connect the RST inputs of all displays to VCC, as they may work without an explicit hardware reset just fine.

In a comment you brought up the idea of using a multiplexer.
Without any other change, you would need the selection signals as additional pins to the multiple CS pins, in your case 3 more.
Instead you can also share the CS signal in the same way:

simulate this circuit
It is very important that you use multiplexers that output the inactive level as required by the displays on not selected outputs!
Even now you should instantiate as many Adafruit_ST7789 as you have displays, because each instance most probably stores internal information necessary for its correct working. But you can use the same pins on all of them.
Before you call any method of an instance, switch the multiplexers to the associated display.
To be sure that all data is completely transmitted, you might need a small delay after the called method. Perhaps the called method already blocks until all data is completely transmitted. You might try to read the library's source to learn more.

Assigning a single pin. I will try that because I can simply reset them at intervals when a value changes, for example, when the minute changes over.
What if I used a multiplexer? Could I then hook up the RST and the CS to it? Unsure how that might work

@griegs Unless the library code does set CS before doing the Reset, it won't work for you. And the question is if the TTFs can handle CS during RST. Maybe try NOT_A_PIN (or how it's named) for RST passed into tft objects and toggle the real RST pin for some time by yourself before going into TFT init functions

@griegs Is it necessary to reset a display before it can show new content? I don't think so, it would be quite strange. -- Concerning the multiplexer idea, I'll extend my answer.

@griegs add a couple of gates so that the RST can be asserted only when CS is asserted ... that way you would need only one pin to drive the RST line

@thebusybee, pretty sure the screen does not require a reset to draw new content. I "could" reset once a day and simply black out the area I want to write to ahead of any write. Then at 2am, do a reset to clear the cache


text:
Using Internal Timer Interrupt to Read Analog Sensor
I'm having difficultly using an internal timer interrupt with my Arduino Nano to properly capture a specific value from a linear potentiometer and then instantly stopping the actuator.
I basically have the wiper of a linear potentiometer connected to the end of a linear actuator.  The actuator extends/retracts via a L298N module being controlled by a Nano.  From where its positioned, the potentiometer reads around "80" when the actuator is fully extended, and around "25" when fully retracted.  I'm entering numbers via the serial monitor to prompt the actuator to move up or down, these numbers are being stored in the Nano's EEPROM.
My interrupt seems not to work while the actuator is in motion.  For example, if I set the interrupt to stop the motor when the potentiometer reads "50", it just skips past this number without stopping the actuator.  But if I set the interrupt to stop the motor when the potentiometer reads the minimum or maximum (where the actuator is currently located before activation), the actuator correctly doesn't extract or retract.  I would think my interrupt is fast enough at 8Khz, so I feel there is something else prohibiting the actuator from stopping at a specific value between the max and min.
The my current code is below, any help would be much appreciated.
    //timer2 will interrupt at 8kHz

    #include <EEPROM.h>
    #define EEPROM_SIZE

    long number;
    long x;

    int toggle=0;
    int old_x=0;

    const int linPot = A1;

    int MotorSpeed=255;

    int enA = 9;
    int in1 = 8;
    int in2 = 7;

    int currentPosition;

    enum {IdleState, UpState, DownState} State;

    void setup(){

      Serial.begin(9600);

      number = EEPROM.read(0);

      x=number;

      pinMode(enA, OUTPUT);
      pinMode(in1, OUTPUT);
      pinMode(in2, OUTPUT);

      State = IdleState;

    //cli();//stop interrupts

    //set timer2 interrupt at 8kHz
      TCCR2A = 0;// set entire TCCR2A register to 0
      TCCR2B = 0;// same for TCCR2B
      TCNT2  = 0;//initialize counter value to 0
      // set compare match register for 8khz increments
      OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
      // turn on CTC mode
      TCCR2A |= (1 << WGM21);
      // Set CS21 bit for 8 prescaler
      TCCR2B |= (1 << CS21);
      // enable timer compare interrupt
      TIMSK2 |= (1 << OCIE2A);

    sei();//allow interrupts

    }//end setup

    ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz
    //generates pulse wave of frequency 8kHz/2 = 4kHz

    if(currentPosition==50){

      HALT();

    }

    }

    void loop(){

    if ((Serial.available()&&toggle==0)){

            x=Serial.parseInt();
            old_x=x;
            toggle=1;
          }

          if((Serial.available())&&(toggle==1)&&(Serial.parseInt()!=old_x)){
              toggle=0;
          }

            if((toggle==1)&&(Serial.parseInt()==0)){
              toggle=0;
          }

          if(x>78){
            x=78;
          }

           if(x<0){
            x=0;
          }

        EEPROM.write(0, x);
        Serial.print("X :");
        Serial.println(x);

        int data = analogRead(linPot);
        currentPosition = map(data, 0, 1023, 0, 100);
        Serial.print("Potentiometer at ");
        Serial.print(currentPosition);
        Serial.println("%");

        long difference = currentPosition-x;
        Serial.print("Difference :");
        Serial.println(difference);

    if(difference>0){

        State = UpState;

    }

    if(difference>0){

       State = DownState;
    }

    if(difference==0){

       State = IdleState;
    }

     switch (State) {

                   case IdleState:
                   Serial.println("Idle State");
                    HALT();
                    if((currentPosition-number)<0){
                     State = UpState;
                    }
                    if((currentPosition-number)>0){
                     State = DownState;
                    }
                    break;

                  case UpState:
                  Serial.println("Up State");
                    //Need to move down
                    DOWN();
                    if((currentPosition-number)>0){
                     State = DownState;
                    }
                    if((currentPosition-number)==0){
                     State = IdleState;
                    }
                    break;

                  case DownState:
                  Serial.println("Down State");
                    //Need to move up
                    UP();
                    if((currentPosition-number)<0){
                     State = UpState;
                    }
                    if((currentPosition-number)==0){
                     State = IdleState;
                    }
                    break;

     }

    }

    void DOWN(){
        analogWrite(enA, MotorSpeed);
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
      }

    void UP() {
        analogWrite(enA, MotorSpeed);
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);

      }

    void HALT () {
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
    }

how is the potentiometer connected? ... please add a wiring diagram to your question

why are you trying to use an interrupt on a snail-pace event? ... just monitor the potentiometer inside the loop() block

Given that currentPosition is updated in loop(), possibly at a very slow pace (as Serial.parseInt() can block for up to a whole second), it makes no sense to fire an interrupt just to test its value.

I initially tried monitoring the position within the void loop and that didn't work either.  I need the actuator to stop when the  potentiometer hits a specific value which I haven't determined yet (so right now I'm just trying to get the code to stop at random value I choose).   I connected a button to D2 in order to have an external interrupt, which stopped the actuator whenever the button was pressed.  So if an external interrupt had no problem with the Serial.parseInt(), shouldn't the internal interrupt behave the same?

Maybe use Direct Port Manipulation for faster GPIO operations? That would be faster than digitalWrite() and digitalRead()

First, read Nick Gammon's answer: all his points are perfectly valid. He
notes that the serial prints can be quite slow. And indeed, as I counted
the characters, I find that the prints should take at least 54 ms
per loop iteration. This is really very slow. In addition to this, the
calls to parseInt() can be much slower yet, especially considering
that one of them is not conditioned on Serial.available().
Currently, the code that takes care of reading the potentiometer and
stopping the actuator looks like this:
int currentPosition;

// Triggered every 125 µs.
ISR(TIMER2_COMPA_vect) {
    if (currentPosition == 50) HALT();
}

void loop() {
    // Potentially extremely slow code...
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    // Definitely very slow code: takes at least 54 ms.
}

This is reading the potentiometer at best every 54 ms, and
potentially much more slowly. On every read, currentPosition is
updated. In parallel, the value of currentPosition is being tested
every 125 µs.
Note that there is really no point in testing currentPosition that
often. Once the value has been tested, testing it again before it is
updated serves no purpose. Your code would actually be a tiny bit faster
if you test the value right after updating it:
void loop() {
    // Potentially extremely slow code...
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    if (currentPosition >= 50) HALT();
    // Definitely very slow code: takes at least 54 ms.
}

Note that I changed the equality test to an inequality test, for a
reason explained in Nick Gammon's answer.
You still have the problem that the loop is very slow. If you want the
potentiometer to be tested more frequently, you have several options.

The bad option: do it in the interrupt handler:
// Triggered every 125 µs.
ISR(TIMER2_COMPA_vect) {
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    if (currentPosition >= 50) HALT();
}

This is a bad option because analogRead() takes at least
112 µs, which means that the ISR will eat 98.6% of the CPU
cycles. You could make this work kind of reasonably if you lower the
interrupt frequency to something like 1 kHz or below. Still,
such a long ISR is not really good practice.

The better option: make loop non-blocking:
void loop() {
    // Non-blocking, very fast code.
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    if (currentPosition >= 50) HALT();
    // More very fast code.
}

To read the serial port in a non-blocking way, see Reading Serial on
the Arduino. For writing to the serial port in a
non-blocking way, simply refrain to print very frequently.

The hard option: configure the ADC to read continuously.
You can program the ADC in “self-running mode”: it will then take a
reading every 104 µs. You can program it to also deliver an
interrupt every time a new reading is available: you can test the
reading in this interrupt handler. This will give you the best
possible response time:
void setup() {
    // Set the ADC to free running mode.
    // Enable the ADC interrupt.
}

volatile int raw_adc_reading;

// Triggered on every fresh ADC reading.
ISR(ADC_vect) {
    raw_adc_reading = ADC;
    if (raw_adc_reading >= RAW_THRESHOLD) STOP();
}

Note that I prefer to test the raw reading rather than the converted
one. This is because map() is slow (it involves a long division)
and an ISR should ideally be as fast as possible.
You will have to dig into the MCU datasheet to learn how to configure
the ADC in free running mode.

For one thing, currentPosition is not declared volatile so the compiler may be keeping that value in a register, which is not consulted inside the ISR.
I'm also concerned about all the serial prints at 9600 baud (quite slow) which may make the position skip from 49 to 51 while you are busy printing values.
Comparing to be exactly equal in order to do something is always fraught.

   x=Serial.parseInt();
    old_x=x;
    toggle=1;
  }

  if((Serial.available())&&(toggle==1)&&(Serial.parseInt()!=old_x)){
      toggle=0;
  }

    if((toggle==1)&&(Serial.parseInt()==0)){
      toggle=0;
  }

Are you expecting three integers from serial?


text:
How to add one JsonDocument to another in ArduinoJson
I'm utilizing this json library: https://arduinojson.org/
I am attempting to write a function that creates a response object, and wraps an already built json document:
    void sendResponse(
            ResponseType state,
            JsonDocument *response
    ) {
        DynamicJsonDocument doc(256);

        doc[F("state")] = responseTypeFromEnum(state);
        doc[F("response")] = response; //breaks; how to do?

        this->sendJson(&doc);
    }

This fails of course, and I don't see a great solution anywhere...
I know I could use createNestedObject(), but this seems to require re-creating the given json object by hand? This would be a sub-optimal case.
Is there a way to easily wrap an existing JsonDocument in another?
Looking to take
{
  "some": "other document"
}

And wrap it like
{
  "state":"OK"
  "response": {
    "some": "other document"
  }
}

You can add a JsonDocument inside another one, but you must pass the document by value, not by pointer.
Since you receive a pointer, you need to dereference it before trying to assign:
doc[F("response")] = *response;

Node 1: you could avoid this problem by passing response by reference, like so:
void sendResponse(ResponseType state, const JsonDocument &response) {
  DynamicJsonDocument doc(256);

  doc[F("state")] = responseTypeFromEnum(state);
  doc[F("response")] = response;

  this->sendJson(doc);
}

Node 2: calling the assignment operator (=) causes a deep copy of the response document. You could avoid this copy by calling shallowCopy() instead:
doc[F("response")].shallowCopy(response);

Node 3: unfortunately shallowCopy() is unavailable on ArduinoJson 7.

Interesting on Node 3.. Looks like shallowCopy() only came out in 6, so why is it gone in 7? Is there no equivalent there?
Looks like I'm currently using 6 though, compiles fine for me. Thanks for the point

Sorry, "Node" was supposed to be "Note" :-) Indeed, I removed shallowCopy() because JsonDocument doesn't store pointers to variants anymore. Instead, it stores indexes relative to the current document. It would be possible to recreate shallowCopy() but it would require extra plumbing (so extra weight), and I don't think it's worth it.

Thanks for the note!
I might personally argue that some extra code plumbing is worth a potentially large amount of end RAM usage savings to support :) (assuming it's not astronomically hard to do so)

Right, but on the other hand, it's not that difficult to avoid this situation. See the the upgrade guide for an example.


text:
Serial does not read buffer with integer characters greater than 43
I'm trying to write a script to move an object coupled to a linear axis through a stepper motor. The user must send information such as the length to be moved, the speed of movement, the direction of movement, or even if he wants to make millimetric adjustments via the serial. However, I can't read lengths from 43 mm where I send the integer 43 over serial. I tested several methods that I found on the internet. Below is the current code and some alternatives of the serial read section that failed.
void(* resetFunc) (void) = 0;

//Serial read
const int bufferSize = 30; // Tamanho máximo para o buffer de leitura
char buffer[bufferSize];   // Buffer para armazenar os dados lidos via serial

//Step motor
const int stepPin = 3;
const int senPin = 2;
const int enPin = 8;
int sen, sp, len, ad; //sen = forward or backward, sp = speed, len = length, ad = enable steps to adjustment
int REV;//motor revolutions
int time_motor; // interval of pulse (on/off)

void setup()

{

  pinMode(stepPin,OUTPUT);
  pinMode(senPin,OUTPUT);
  pinMode(enPin,OUTPUT);
  digitalWrite(enPin,LOW);

  Serial.begin(9600);

  while (!Serial.available()) {
    delay(10);
  }

  int bytesRead = Serial.readBytesUntil('\n', buffer, bufferSize);

  buffer[bytesRead] = '\0';

  sscanf(buffer, "%d,%d,%d,%d", &ad, &sen, &len, &sp);

  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("sen: ");
  Serial.println(sen);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);

  time_motor = 100;

  REV = int(768 * len);

  if(ad == 0){
    if (sen == 1){
      backward(REV, time_motor);
      }

    else {
      forward(REV, time_motor);
      }

      resetFunc();
  }
  else{
    if(sen == 1){backward(768, time_motor);resetFunc();}
    else{forward(768, time_motor);resetFunc();}
  }
}

void forward(int len_fact, int time_c) {
  digitalWrite(enPin, LOW);
  digitalWrite(senPin, HIGH);
  for (int x = 0; x < len_fact; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(time_c);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(time_c);
  }
}

void backward(int len_fact, int time_c) {
  digitalWrite(enPin, LOW);
  digitalWrite(senPin, LOW);
  for (int x = 0; x < len_fact; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(time_c);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(time_c);
  }
}

void loop()
{

}

An alternative below:
  while (!Serial.available()) {
    // Aguarda até que haja dados disponíveis na porta serial
  }

  delay(100); // Pequeno atraso para garantir que todos os dados tenham chegado

  int bytesRead = 0;
  while (Serial.available() && bytesRead < bufferSize - 1) {
    char c = Serial.read();
    if (c == '\n') {
      break; // Termina a leitura ao encontrar uma quebra de linha
    }
    buffer[bytesRead] = c;
    bytesRead++;
  }

  // Adiciona o caractere nulo para indicar o final da string
  buffer[bytesRead] = '\0';

  // Usa a função sscanf para extrair os números do buffer
  sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

  // Imprime os valores lidos para verificá-los
  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);

And the other:
  while (!Serial.available()) {
    // Aguarda até que haja dados disponíveis na porta serial
  }

  // Lê os dados da porta serial e armazena no buffer até atingir o tamanho máximo
  int bytesRead = 0;
  while (bytesRead < bufferSize - 1) {
    if (Serial.available()) {
      char c = Serial.read();
      if (c == '\n') {
        break; // Termina a leitura ao encontrar uma quebra de linha
      }
      buffer[bytesRead] = c;
      bytesRead++;
    }
  }

  // Adiciona o caractere nulo para indicar o final da string
  buffer[bytesRead] = '\0';

  // Usa a função sscanf para extrair os números do buffer
  sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

  // Imprime os valores lidos para verificá-los
  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);

Serial returns nothing or "?". How should I proceed to solve this problem?
I'm using an original Arduino uno and writing in the arduino IDE. The version is 1.8.19.

maybe you set the wrong baud rate in the serial console

reduce your program. to minimum code that still exhibits the problem

You are sending 4 numbers over serial, right? Please copy and paste the exact numbers that you are sending.

Before the sscanf I would be printing what is in that buffer.

Well, you didn't provided that much info, but i picked up on some of your code (below) and in the serial monitor i can read all the numbers :
    const int bufferSize = 30; // Tamanho máximo para o buffer de leitura
char buffer[bufferSize];   // Buffer para armazenar os dados lidos via serial

//Step motor
const int stepPin = 3;
const int senPin = 2;
const int enPin = 8;
int dir, sp, len, ad; //sen = forward or backward, sp = speed, len = length, ad = enable steps to adjustment
int REV;//motor revolutions
int time_motor; // interval of pulse (on/off)

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
while (!Serial.available()) {
    // Aguarda até que haja dados disponíveis na porta serial
  }

  delay(100); // Pequeno atraso para garantir que todos os dados tenham chegado

  int bytesRead = 0;
  while (Serial.available() && bytesRead < bufferSize - 1) {
    char c = Serial.read();
    if (c == '\n') {
      break; // Termina a leitura ao encontrar uma quebra de linha
    }
    buffer[bytesRead] = c;
    bytesRead++;
  }

  Serial.println(buffer);

  // Adiciona o caractere nulo para indicar o final da string
  buffer[bytesRead] = '\0';

  // Usa a função sscanf para extrair os números do buffer
  sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

  // Imprime os valores lidos para verificá-los
  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);
}


text:
A fatal error occurred: Could not open /dev/ttyUSB0, the port doesn't exist (UART bridge CP2102)
I can't upload my program to ESP32-CAM. It just keeps saying the port doesn't exist. But I can see it in /dev/ttyUSB0 (By the way, I'm on linux, Fedora)
The UART bridge is CP2102 Silicon Labs.
What I've tried:

Using both IDE 1, 2
Removing everything, trying again on IDE 1
upgrading permissions

Any help will be appreciated.

After sudo dmesg -wT | grep cp2102 as suggested by @timemage, I got this:

Please check if your user has access rights to /dev/ttyUSB0. You can add yourself to the dialup group or take similar actions.

@gbg After Posting the question, I did come across some posts suggesting the same. I did that but it didn't help. Is there a need to install any driver of the UART (CP2102) even in Linux? I can get it to work on windows by updating the driver.

@44yu5h It's not going to be a lack of a driver unless you're running some obscure build of the kernel. Post sudo dmesg -wT output from the first line of after insertion downward. Besides diagnosing other options it will also allow you to convince yourself that a driver is loading when you see something like cp210x <bus numbers>: cp210x converter detected

@timemage Thanks for answering. I did sudo dmesg -wT | grep cp2102 did not get anything. I didn't take a screenshot. I will update my question with the ss soon. In a lecture right now.

grep cp2102 in not going to find cp210x. Anyway, I'm sure you have that. The real point of posting it is the potential to see other diagnostically useful things that grepping is only going to remove.

@timemage Yes! sorry my bad. I've attached the screenshot. Still, it returns the same error A fatal error occurred: Could not open /dev/ttyUSB0, the port doesn't exist The RX led is constantly on (as it was on Windows before I updated the driver, so I was just linking things but anyway) Any suggestions?

Not a good suggestion. Because it's an easy test, I would disconnect the ESP32 and perform a loopback test on the cp2102. This would at least eliminate a bunch of stuff, although pretty much everything "arduino" about your question. But on the other hand you'd be able to ask it to a wider audience of Linux users without being shunted right back here.

@timemage Actually I have 2 cp2102. Both don't work. Tried both Arduino 1 and 2. Tried removing the braille screen reader as suggested in some posts. No help. You are right, let me just ask it on linux forum. Thanks

A post by Bee_HapBee on Reddit solved my issue! Thank you!
sudo chmod 666 /dev/ttyUSB0

Yep, I wish esptool.py would've told me that I needed permissions, rather than the port doesn't exist

chmod 666 - "(U)ser / owner can read, can write and can't execute. (G)roup can read, can write and can't execute. (O)thers can read, can write and can't execute"

What about the security implications? Isn't it more standard to use the dialup user or some udev rules?


text:
How to refresh an iframe in a page made with Espasyncwebserver
So, I have this page on esp8266:
  controlserver.on("/UDEL", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", htmltd);
  });

htmltd  is a string, generated by a function and it contains some forms, and they run in iframe tag,
<FORM action="/process" method="post" id="config" target="iframe">

</form>

and processed by:
controlserver.on("/process", HTTP_POST, [](AsyncWebServerRequest *request) {
.
.
.
request->send(200, "text/html", HTML_CSS_STYLING + "");
.
.
.
});

They work perfectly fine, and after clicking on submit button the page shows an alert, and it must be reloaded, because the submitted form must be removed from the page. it happens when I reload the page manually. but I want it to happen automatically after each form submission. it tried many ways like :
<!DOCTYPE html>

    <meta charset="UTF-8" />
    <title>Reload iFrame</title>

  <input onclick="reloadIframe()"  type="button" value="Click me">

but it doesn't work in esp8266.

it doesn't work ... that is an extremely vague description of an observed behavior .... what exactly happens? ... please update your question ... do not add information in comments

form must be removed from the page ... why don't you simply hide it? ... page reload would not be necessary

here is an example of updating a web page without a reload
https://projecthub.arduino.cc/donskytech/nodemcu-esp8266-ajax-enabled-web-server-928fa0

@jsotola yeah you are right, I was working on this all day, I was a little tired. nothing happens when I tried the described method. My project is kind of big and there are many forms in this page, so I wanted to save some space. thank you, I'll look, into it.

your main page could be just skeleton html that uses XHR to load each form as needed ...

From my understanding, your intention is to automatically reload the main page (which contains the form and the iframe) after submitting the form. but the challenge is that the form submits inside the iframe so when you send a response to the iframe, it won't directly impact the main page.
I believe you could use a small trick to work this problem around.
1- After successfully processing the form data inside the iframe, send back a script that communicates with the parent window (the main page) and instructs it to reload
2- In the main page, listen to the received message and then reload.
Here is how to implement the proposed solution:
On your ESP8266 route handler, send a script in the response to post a message to the parent window after processing the form:
controlserver.on("/process", HTTP_POST, [](AsyncWebServerRequest *request) {
    //add your processing code
    String response = HTML_CSS_STYLING +
                      "";
    request->send(200, "text/html", response);
});

window.parent.postMessage will send "reloadPage" string from iframe to parent window. And on your main page (the page that contains the iframe), listen for this message and reload the entire page when the message is received:
<FORM action="/process" method="post" id="config" target="iframe">

</form>

Btw instead of using an iframe, you could use AJAX to submit the form so that you get a response directly from the server and refresh the page using location.reload(). This way you can submit form data (or retrieve data) without refreshing the entire page. Only the necessary parts of the page updates.
I hope that this helps, if not, please inform me.

Thank you soooooo much it worked like a charm! I know nothing about the AJAX :) Basically I started html like 2 weeks ago ;)

I am glad to hear that it worked for u, AJAX is used for asynchronous web applications but don't rush it. You will eventually learn about it. Have a nice day, coding!


text:
ArduinoJson reading `null` from Serial
I have a setup that reads from serial when I sense that there is something to be read (and always assume that what is sent to the arduino is valid json):
void setup(){
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {

    if(Serial.available()){
        StaticJsonDocument<256> doc;

        deserializeJson(doc, Serial);

        serializeJson(doc, Serial);
        Serial.println();
    }
}

Given the following input from ArduinoIDE's serial monitor (Set to newline setting, 9600 baud):
{"hello": "world"}

This produces the following:
{"hello": "world"}
null

I have two questions:

Is this setup correct/ how I should be waiting and retrieving json from serial?
Why the additional null input? Looks like there is something still in the serial buffer even after the first iteration?
How to detect the second case where the resulting document gets re-serialized as null? Comparing to 0, NULL, and nullptr seem to not work Figured this one out, found out about DeserializationError

Upon utilizing DeserializationError, looks like the null parsing had an error of EmptyInput

what is sending the data? ... what is the actual data that is sent?

The Arduino IDE serial console

manual input data then .... what are the serial console settings? ... there is more than one setting

Updated to show setup function

I said serial console settings

Updated to show settings (newline, 9600 baud)

As observed on your serial console settings, it mentions both newline and 9600 baud. Let's break this down:
Issue with Serial Communication

Partial Payloads: You are currently assuming that when Serial.available() returns true, the entire JSON payload has been received. However, due to the nature of serial communication (especially at 9600 baud), data can arrive in fragmented chunks. Invoking deserializeJson() on a partial JSON payload can result in incomplete or corrupted data.

End-of-Message Ambiguity: Lacking a definitive end-of-message marker makes it challenging to discern when a complete JSON payload has been received. For instance, when sending {"hello": "world"} from the Arduino IDE's serial monitor, it automatically appends a newline (or a carriage return based on your configuration). This newline is then misinterpreted as another JSON payload, leading to the undesired null output.

How you can solve this:

Use a Delimiter: Choose a specific character or sequence to act as an end-of-message delimiter. The newline character (\n) is a typical choice, especially if data is exclusively sent from the Arduino IDE's serial monitor. Nevertheless, if you anticipate newlines within your JSON data, you might consider another distinct character, like #.

Read Until Delimiter: Adjust your code to continuously read characters from the serial port until the chosen delimiter is encountered. Upon receipt of the entire message, it can then be parsed.

Code Example
Here's a sample code employing the newline character as a delimiter:
const int maxBuffer = 256;
char serialBuffer[maxBuffer];
int bufferPos = 0;

void setup() {
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {
    if (Serial.available()) {
        char inChar = Serial.read();

        if (inChar == '\n') {  // EOM
            serialBuffer[bufferPos] = '\0';
            processMessage(serialBuffer);
            bufferPos = 0;  // Reset buffer pos
        } else if (bufferPos < maxBuffer - 1) {  // Avoid buffer overflow
            serialBuffer[bufferPos++] = inChar;
        }
    }
}

void processMessage(char* message) {
    StaticJsonDocument<256> doc;

    DeserializationError error = deserializeJson(doc, message);

    if (error) {
        Serial.println("Failed to parse JSON");
    } else {
        serializeJson(doc, Serial);
        Serial.println();
    }
}

This way you ensure the entirety of message is parsed and received and therefore avoiding unwanted null outputs.
I hope this helps ^_^


text:
Arduino Pro Micro not recognizing INPUT or INPUT_PULLUP
I tried to make a controller box with multiple buttons. Sadly, when I tried to connect the buttons, the Arduino Pro Micro didn't recognize them being pressed. I even tried to connect a wire directly (and a directly a resistor from GND to the ports) from GND to the ports but it doesn't seem to matter.
OUTPUT works on the same ports, but INPUT/INPUT_PULLUP does not.
Is there something wrong with the code?
My Arduino Pro Micro is a Chinese knockoff. Keyboard and Mouse are working, OUTPUT is working. It doesn't seem to work with the input.
PS: I have worked with Arduino UNO before (and also the ESP family (ESP8266, ESP32)).
PS2: Sometimes, if I touch the microcontroller's back side some values register (like I pushed all the buttons at once)
#define LED_PIN 4
#define BUTTON_1 10
#define BUTTON_2 16
#define BUTTON_3 14
#define BUTTON_4 9

byte ledState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_1, INPUT_PULLUP);
  pinMode(BUTTON_2, INPUT_PULLUP);
  pinMode(BUTTON_3, INPUT_PULLUP);
  pinMode(BUTTON_4, INPUT_PULLUP);
}

void loop() {

  byte one = digitalRead(BUTTON_1);
  byte two = digitalRead(BUTTON_2);
  byte three = digitalRead(BUTTON_3);
  byte four = digitalRead(BUTTON_4);

  if (one == HIGH) {
    Serial.println("BUTTON_1");
  }
  if (two == HIGH) {
    Serial.println("BUTTON_2");
  }
  if (three == HIGH) {
    Serial.println("BUTTON_3");
  }
  if (four == HIGH) {
    Serial.println("BUTTON_4");
  }

  digitalWrite(LED_PIN, ledState);
  ledState = !ledState;
  delay(1000);
}

Edit: corrected the code
Mention: I wired the buttons the following way (I have to mention it, because the Arduino Pro Micro doesn't have a sepparate 3V/5V pin, it only has RAW output that by my undertanding can fry the board)
Tutorial from where I inspired the button wiring:
https://arduinogetstarted.com/tutorials/arduino-button

try byte one = digitalRead(BUTTON_1);

Or closer to the form you have it: digitalRead(BUTTON_1) == HIGH; though the form jsotola suggests is better. What you have is a typo, unless you basically didn't already know this was incorrect and need an explanation as to why the placement of ) matters.

As mentioned it really matters where you put parentheses. As none of your button pins is pin 1, comparing them with HIGH (== 1) always results into 0 and that exact 0 was used for all digitalReads.

Sorry....I modified the code in the meanwhile (I observed after I posted that I haven't copyed the good code....it looks like so, because the if's were looking the following way, but I started using variables instead: if(digitalRead(BUTTON_1) == HIGH) to rule out the compiler problems (and when I deleted the parantheses, I deleted the wrong ones) => I have corrected the code in the meantime but still it doesn;t work)

With your latest schematic/code (a) the buttons will be LOW when pressed, not HIGH  (b) your schematic shows the connection of a button on pin 7 but your code has no entry for pin 7 and (c) the delay of 1 second in the loop means you may have to hold the button for up to 1 second to see a response. If touching pins on the board has the same effect as pressing a button then the buttons are in a floating state indicating that the wiring is incorrect.

It's confusing showing a Uno when in the text you say you have a Pro Micro, and then you also tag the question with Leonardo.

@6v6gt Of course the image is for the UNO, because it's from a tutorial (the concept of wiring and the code should be similar, in the background the compiler/correct library should be used by Arduino IDE when I select the board) .
Mention: The picture is NOT mine, I only use the same wiring tehnique as in the picture.

@NickGammon I am using an Arduino Micro Pro (small version of Leonardo, that's why I tagged also Leonardo in the question).

OK. It is clear you've used a picture from a tutorial and not your real layout. One classic error with those tactile push buttons is to rotate them through 90 degrees giving the effect that these are permanently in a "pushed" on state. Do you still get the phenomenon that when you touch the board at the back of the pins that this simulates the pressing of the buttons ?

The way you have it wired, INPUT_PULLUP will make the buttons look HIGH, so in your code you need to test if they are going LOW, which is what grounding the button would do.

Yes, this was also a problem. I tried setting the pins previously to HIGH/LOW but it worked only on the first button press, after that it worked as before (could not read button state correctly).
An improvement to the code can be adding a previous state check also.

After looking at many tutorials and trying many approaches with different Arduinos (Uno, because it's easyer to prototype) (and taking a short brake so I can try again from 0 with a new mindset) I made it work.
Before, I could do it because I was using Microcontrollers that had a 3/5V output also (ex. Uno, Mega, Nano, STM32, ESP8266, ESP32), so I could do a pull-up/down circuit, but because the Arduino Micro doesn't have such pins (it has only RAW as output, which can fry the board if it's externally powered) I had to use this method where I only use a GND pin and a Digital Input without any ressistors wired to the button.
Thanks for the answers and suggestions!
The new code (without the LED functionality):
#include "Keyboard.h"

// defining button pin numbers
// TODO: rename variables according to functionality
#define BUTTON_10 10
#define BUTTON_16 16
#define BUTTON_14 14
#define BUTTON_9 9

// giving them a first-state of HIGH
int previousButtonState10 = HIGH;
int previousButtonState16 = HIGH;
int previousButtonState14 = HIGH;
int previousButtonState9 = HIGH;

void setup() {
  // initializing the buttons as INPUTS with PULLUP (internal pull-up resistor from Arduino)
  pinMode(BUTTON_10, INPUT_PULLUP);
  pinMode(BUTTON_16, INPUT_PULLUP);
  pinMode(BUTTON_14, INPUT_PULLUP);
  pinMode(BUTTON_9, INPUT_PULLUP);

  // only for test
  // TODO: Move this only to the function needed when more functionality is added
  Keyboard.begin();

}

void loop() {
  // checking if any of the buttons were pressed and saving the state in a variable
  previousButtonState10 = checkButton(BUTTON_10, previousButtonState10);
  previousButtonState16 = checkButton(BUTTON_16, previousButtonState16);
  previousButtonState14 = checkButton(BUTTON_14, previousButtonState14);
  previousButtonState9 = checkButton(BUTTON_9, previousButtonState9);
}

// function: reads the button state and compares it with the previous state to find out if it was pressed or not
// params: buttonPin => the pin number of the button; previousButtonState => the state corresponding for each button
// return: it returns the red state, so it can be saved as previousState in the coresponding parameter
int checkButton(int buttonPin, int previousButtonState) {
  int buttonState = digitalRead(buttonPin);

  if (buttonState == LOW && previousButtonState == HIGH) {
    Keyboard.println(buttonPin);
    // some minimal debouncing
    // TODO: WIll be a problem when using millis() in the future
    delay(50);
  }

  if (buttonState == HIGH && previousButtonState == LOW) {
    // not needed, but some functionality could be added in the future
    // Keyboard.println("release");
    delay(50);
  }

  return buttonState;
}

Now I can work further on improving and extending the code to make the "Macro Board" project with mouse movement (and I also have to solder the buttons and LEDs to the board :P )