text:
Limit of EthernetClient connections
I'm working on a project on which I need to have multiple EthernetClient connections to different servers. All of these connections must be kept alive simultaneously and by this I mean I cannot stop or close one of these clients before starting the other.
Currently I can keep 2 simultaneous successful EthernetClient connections. After this, any subsequent client fails to connect to any server. The following code is running on an ESP32-S3 with a W5500 Ethernet module.
#include <Arduino.h>
#include <EthernetLarge.h>
#include <SPI.h>

#define     SPI_MOSI    35
#define     SPI_MISO    37
#define     SPI_SCK     36
#define     ETHERNET_CS 38

SPIClass SPI_Ethernet;
EthernetClient ethCli1;
EthernetClient ethCli2;
EthernetClient ethCli3;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

void setup()
{
  Serial0.begin(115200);
  SPI_Ethernet.begin(SPI_SCK, SPI_MISO, SPI_MOSI, ETHERNET_CS);

  pinMode(39, OUTPUT);
  pinMode(47, OUTPUT);
  digitalWrite(47, HIGH);
  digitalWrite(39, LOW);
  delay(500);
  digitalWrite(39, HIGH);

  Ethernet.init(ETHERNET_CS);
  Ethernet.begin(mac);
  Serial0.println(Ethernet.localIP());

  if( !(ethCli1.connect("httpbin.org", 80)) )
      Serial0.println("connection > 1 < failed");
  else
    Serial0.println("connection > 1 < succeeded");

  if( !(ethCli2.connect("httpbin.org", 80)) )
    Serial0.println("connection > 2 < failed");
  else
    Serial0.println("connection > 2 < succeeded");

  if( !(ethCli3.connect("httpbin.org", 80)) )
    Serial0.println("connection > 3 < failed");
  else
    Serial0.println("connection > 3 < succeeded");
}

void loop()
{
}

Which outputs:
connection > 1 < succeeded
connection > 2 < succeeded
connection > 3 < failed

In this code I'm using the OPEnSLab-OSU/EthernetLarge Ethernet library. But I also tried to run it with the Ethernet.h with the same output. In the W5500 documentation I was able to find the information that it can keep up to 8 connections open, but I wasn't able to find if the ESP32 has any restrictions like a max of simultaneous connections. Is it possible to keep more than 2 connections alive simultaneously?
In short:

I'm using an ESP32-S3 with a W5500 Ethernet Module.
I can keep 2 simultaneous connections and closing previous connections before opening a new one works, but in my project I need to keep at least 3 simultaneous connections.
Changing from OPEnSLab-OSU/EthernetLarge Ethernet library to Ethernet.h produced the same output.
Adding a delay between the connections didn't work.
In the example code all the connections are being established to the same server, but in my official project these connections are established to different servers. Either way the output is the same.
The W5500 documentation says that it can keep up to 8 simultaneous connections. I wasn't able to find if ESP32 has any restrictions on the limit of simultaneous connections.

The OPEnSLab-OSU/EthernetLarge library by default defines MAX_SOCK_NUM to 2. Increasing this value allowed me to keep more simultaneous connections.
Regarding the Ethernet.h library, I also checked it and it was already setting MAX_SOCK_NUM to 8. Testing the code again with it also allowed me to keep more simultaneous connections. Why I wasn't able to keep them before when using Ethernet.h it is still a mystery to me.


text:
Arduino Nano is performing really slowly, even though the calculations are simple and there are no delays
I'm working on a tiny ping-pong game based on Arduino Nano. Its modes are "person vs person" and "person vs computer" (the computer just tries to keep its racket at the same Y position as the ball). There are 2 "up" buttons, 2 "down" buttons, two 7-segment score indicators and 2 shift registers controlling them. The display is SSD1306 (128x32 pixels).
I'm posting here the entire code because I don't know where the issue lies.
#include <Adafruit_SSD1306.h>

// Up/down buttons
#define UP1 2
#define DOWN1 3
#define UP2 4
#define DOWN2 5

// Shift registers that control score indicators
#define DATA1 6
#define CLOCK1 7
#define LATCH1 8
#define DATA2 9
#define CLOCK2 10
#define LATCH2 11

#define RANDOM_NUMBERS A0  // This port isn't connected to anything and is used to get random seed
#define WRAP 118  // Text on display wraps on this position

#define SSD1306_ADDRESS 0x3C  // I2C address of display

Adafruit_SSD1306 ssd1306;

const byte numbers[10] = {  // Arab numbers for score indicators
  0b1111110, 0b0011000, 0b1101101, 0b0111101, 0b0011011, 0b0110111, 0b1110111, 0b0011100, 0b1111111, 0b0111111
};

short currentDirection = -1;
short directionState = -1;  // The sequence number of next move in the period of ball trajectory
short nextMove = -1;
short ballX = 63;
short ballY = 15;
short racket1 = 12;
short racket2 = 12;

short score1 = 0;
short score2 = 0;
bool gameOver = false;

bool playingWithComputer = false;

void setup() {
  pinMode(UP1, INPUT_PULLUP);
  pinMode(DOWN1, INPUT_PULLUP);
  pinMode(UP2, INPUT_PULLUP);
  pinMode(DOWN2, INPUT_PULLUP);
  pinMode(DATA1, OUTPUT);
  pinMode(CLOCK1, OUTPUT);
  pinMode(LATCH1, OUTPUT);
  pinMode(DATA2, OUTPUT);
  pinMode(CLOCK2, OUTPUT);
  pinMode(LATCH2, OUTPUT);

  randomSeed(analogRead(RANDOM_NUMBERS));

  updateScores();

  ssd1306.begin(SSD1306_SWITCHCAPVCC, SSD1306_ADDRESS);
  ssd1306.display();
  delay(2000);  // A delay to show the Adafruit logo
  ssd1306.clearDisplay();

  ssd1306.setTextSize(1);
  ssd1306.setTextColor(WHITE);
  ssd1306.setCursor(0, 0);  // Cursor should be at this position to draw objects correctly

  printLongText(5, 0, "Press \"up\" to play with computer, otherwise press \"down\"");

  while (true) {
    if (!digitalRead(UP1) || !digitalRead(UP2)) {  // Both "up" buttons (as well as both "down" ones) are treated the same unless there's a game "person vs person"
      playingWithComputer = true;
      break;
    }
    if (!digitalRead(DOWN1) || !digitalRead(DOWN2)) break;

    delay(5);  // This delay is here to avoid overloading the processor
  }

  ssd1306.clearDisplay();
  ssd1306.display();

  delay(100);  // This delay is intended to show user that they don't need to hold button any more
}

void loop() {
  if (gameOver) {
    delay(1000);
    return;
  }

  if (nextMove < 0) {
    pickDirection();
    return;
  }

  short oldDirection = currentDirection;
  switch (getBounceType()) {
    case 0:
      verticalFlipDirection();
      ballY++;
      break;
    case 1:
      verticalFlipDirection();
      ballY--;
      break;
    case 2:
      if (ballY < (racket1 - 1) || ballY > (racket1 + 8)) {  // This determines if the ball ran shorto the racket or not (true if it did not)
        score2++;

        // Ball goes to the center of the screen after goal
        ballX = 63;
        ballY = 15;
        pickDirection();

        updateScores();
      }
      else {
        horizontalFlipDirection();
        ballX++;
      }

      break;
    case 3:
      if (ballY < (racket2 - 1) || ballY > (racket2 + 8)) {
        score1++;
        ballX = 63;
        ballY = 15;
        pickDirection();
        updateScores();
      }
      else {
        horizontalFlipDirection();
        ballX--;
      }

      break;
    case 4:
      if (racket1 > 1) {
        score2++;
        ballX = 63;
        ballY = 15;
        pickDirection();
        updateScores();
      }
      else {
        reverseDirection();  // This occurs when the ball rans exactly shorto the corner of its zone
        ballX++;
        ballY++;
      }

      break;
    case 5:
      if (racket2 > 1) {
        score1++;
        ballX = 63;
        ballY = 15;
        pickDirection();
        updateScores();
      }
      else {
        ballX--;
        ballY++;
        reverseDirection();
      }

      break;
    case 6:
      if (racket1 > 1) {
        score2++;
        ballX = 63;
        ballY = 15;
        pickDirection();
        updateScores();
      }
      else {
        reverseDirection();
        ballX++;
        ballY--;
      }

      break;
    case 7:
      if (racket2 > 1) {
        score1++;
        ballX = 63;
        ballY = 15;
        pickDirection();
        updateScores();
      }
      else {
        ballX--;
        ballY--;
        reverseDirection();
      }

      break;
  }
  if (oldDirection != currentDirection) directionState = 0;  // Resetting direction state if the ball bounced
  pickMove();  // Next move may have changed if the ball bounced

  switch (nextMove) {
    case 0:
      ballY--;
      break;
    case 1:
      ballX++;
      break;
    case 2:
      ballY++;
      break;
    case 3:
      ballX--;
      break;
  }
  directionState++;
  pickMove();

  ssd1306.clearDisplay();
  ssd1306.drawRect(ballX, ballY, 2, 2, WHITE);

  if (playingWithComputer) {
    if (!digitalRead(UP1) || !digitalRead(UP2)) {
      if (racket1 > 0) racket1--;
    }
    if (!digitalRead(DOWN1) || !digitalRead(DOWN2)) {
      if (racket1 < 24) racket1++;
    }

    // This is the algorithm used by computer — it just tries to keep the computer-controlled racket at the same Y position as the ball
    if ((racket2 + 3) > ballY) {
      if (racket2 > 0) racket2--;
    }
    if ((racket2 + 3) < ballY) {
      if (racket2 < 24) racket2++;
    }
  } else {
    if (!digitalRead(UP1)) {
      if (racket1 > 0) racket1--;
    }
    if (!digitalRead(DOWN1)) {
      if (racket1 < 24) racket1++;
    }
    if (!digitalRead(UP2)) {
      if (racket2 > 0) racket2--;
    }
    if (!digitalRead(DOWN2)) {
      if (racket2 < 24) racket2++;
    }
  }

  ssd1306.drawRect(0, racket1, 2, 8, WHITE);
  ssd1306.drawRect(126, racket2, 2, 8, WHITE);

  ssd1306.display();
}

// This function picks a random direction for the ball
void pickDirection() {
  currentDirection = random(0, 20);
  directionState = 0;
  pickMove();
}

// This function determines the next move of the ball (up/right/down/left) based on its current direction and direction state
void pickMove() {
  short sector = getSector();  // Directions that go to up-right are in sector 0, those going to down-right are in sector 1, etc

  switch (currentDirection) {
    case 0:
    case 5:
    case 10:
    case 15:
      directionState = directionState % 5;  // Resetting direction state when the ball reaches next period of its trajectory

      // At certain direction states the ball goes to its primary direction (e.g. in an almost vertical trajectory the primary direction would be up)
      // At other states it goes to the secondary direction, which when added to the primary one forms the actual trajectory of the ball
      // Sectors divide into 2 parts. The first part includes 3 trajectories which have their primary direction number (up - 0, right - 1, down - 2, left - 3) same as sector number
      // Secondary directions in first part are sector number plus 1
      // In the second part the primary direction is (sector_number + 1) % 4 and the secondary one is the sector number
      // There are 20 supported trajectories (5 in each of 4 sectors). They are presented in Ping-Pong.png
      // First trajectories in each sector (as well as second ones etc) have the same structure, so there's only one code block
      // for handling first trajectories of all sectors. However, their primary and secondary directions differ in each sector
      // The following line determines if the ball should now go to the primary or secondary direction and based on that sets nextMove
      nextMove = (directionState == 0 || directionState == 1 || directionState == 3) ? sector : (sector + 1) % 4;
      return;
    case 1:
    case 6:
    case 11:
    case 16:
      directionState = directionState % 4;
      nextMove = (directionState < 2) ? sector : (sector + 1) % 4;
      return;
    case 2:
    case 7:
    case 12:
    case 17:
      directionState = directionState % 4;
      nextMove = (directionState == 0 || directionState == 2) ? sector : (sector + 1) % 4;
      return;
    case 3:
    case 8:
    case 13:
    case 18:
      directionState = directionState % 4;
      nextMove = (directionState < 2) ? getSecondPartMove(sector) : sector;
      return;
    case 4:
    case 9:
    case 14:
    case 19:
      directionState = directionState % 5;
      nextMove = (directionState == 0 || directionState == 1 || directionState == 3) ? getSecondPartMove(sector) : sector;
      return;
  }
}

// Just a helper for pickMove (determines primary direction of second-part trajectories in a certain sector)
short getSecondPartMove(short sector) {
  return (sector + 1) % 4;
}

// This function determines the current bounce type (-1 - currently no bounce, 0 - bounce from upper wall,
// 1 - bounce from lower wall, 2 - facing the first player's wall, 3 - facing the second player's wall,
// 4 - facing upper-left corner, 5 - upper-right corner, 6 - bottom-left, 7 - bottom right
// On 4-7 the ball reverses its trajectory
short getBounceType() {
  if (ballX <= 2 && ballY <= 0) return 4;  // Made ballX indents so that the ball bounces from rackets and not bounds of screen
  if (ballX >= 124 && ballY <= 0) return 5;
  if (ballX <= 2 && ballY >= 30) return 6;
  if (ballX >= 124 && ballY >= 30) return 7;

  if (ballX <= 2) return 2;
  if (ballX >= 124) return 3;

  if (ballY <= 0) return 0;
  if (ballY >= 30) return 1;

  return -1;
}

// This function flips the current trajectory of the ball vertically to bounce from the upper/lower wall
// (source and flipped trajectories have a relationship that differs in different sectors of the source trajectory, see this function)
void verticalFlipDirection() {
  short sector = getSector();

  switch (sector) {
    case 0:
    case 1:
      currentDirection = 9 - currentDirection;
      return;
    case 2:
    case 3:
      currentDirection = 10 + (9 - (currentDirection - 10));
      return;
  }

  directionState = 0;
}

// Same as previous function but the translation is horizontal here
// (the relationship between source and flipped trajectories is different)
void horizontalFlipDirection() {
  short sector = getSector();

  switch (sector) {
    case 0:
    case 3:
      currentDirection = 19 - currentDirection;
      return;
    case 1:
    case 2:
      currentDirection = 5 + (9 - (currentDirection - 5));
      return;
  }

  directionState = 0;
}

// This function reverses the trajectory of the ball
void reverseDirection() {
  currentDirection = (currentDirection + 10) % 20;
  directionState = 0;
}

// This function determines the sector of the current trajectory
short getSector() {
  if (currentDirection < 5) return 0;
  else if (currentDirection < 10) return 1;
  else if (currentDirection < 15) return 2;
  else return 3;
}

// This function prints text on the display, wrapping it at a certain X position
void printLongText(short cursorX, short cursorY, String text) {
  ssd1306.setCursor(cursorX, cursorY);

  int16_t x, y;
  uint16_t w, h;

  short lastSpace = -1;
  short i;

  // Adding character by character to current line until the wrapping position is reacher
  // In parallel finding the last space before wrap (it will be where the line breaks)
  for (i = 0; i < text.length(); i++) {
    if (text.charAt(i) == ' ') lastSpace = i;

    ssd1306.getTextBounds(text.substring(0, i + 1), 0, 0, &x, &y, &w, &h);

    if (x + w > WRAP && lastSpace >= 0) {
      ssd1306.println(text.substring(0, lastSpace + 1));  // Wrapping position reached; breaking the current line at the index of last space in it and printing it
      text = text.substring(lastSpace + 1);

      i = -1;  // Now the same with next line
      lastSpace = -1;
      ssd1306.setCursor(cursorX, ssd1306.getCursorY());
    }
  }
  ssd1306.println(text);  // printing the rest of text

  ssd1306.display();

  ssd1306.setCursor(0, 0);  // Cursor should be at this position to draw objects correctly
}

// This function displays the scores on corresponding indicators and checks if the game if over
// (i.e. one of the players has a score of 7)
void updateScores() {
  digitalWrite(LATCH1, false);
  shiftOut(DATA1, CLOCK1, MSBFIRST, numbers[score1]);  // Sending the necessary mask to the shift registers
  digitalWrite(LATCH1, true);

  digitalWrite(LATCH2, false);
  shiftOut(DATA2, CLOCK2, MSBFIRST, numbers[score2]);
  digitalWrite(LATCH2, true);

  if (score1 >= 7) {
    ssd1306.clearDisplay();
    printLongText(10, 12, "Player 1 wins!");
    ssd1306.display();

    gameOver = true;
  }
  if (score2 >= 7) {
    ssd1306.clearDisplay();
    printLongText(10, 12, "Player 2 wins!");
    ssd1306.display();

    gameOver = true;
  }
}

Look how slowly does the ball move, even though a loop iteration doesn't include any delays at all, and there are no complex calculations. Conversion to GIF didn't change the speed.
My circuit looks like this (it's just a test, so no buttons, just pull-ups, and no score indicators).

simulate this circuit – Schematic created using CircuitLab
Answers here didn't help. Changing the I2C clock speed to 400 KHz didn't help either.
So — is such slowness caused by the (not very high) complexity of my code? Or is it some kind of glitch? Please don't suggest using libraries instead of my own moving and bouncing logic.

Have you tried checking, what exactly is taking so long on each loop() iteration by using millis() or micros()? My guess is, that the display code is taking rather long. You could also try to not clear the display on every iteration, but drawing over the previous rectangles with new black rectanges. Might work faster

I've reproduced this problem, as I happened to have one of these displays lying around. Commenting out the clear of the screen didn't help.

The code is taking around 167 ms per loop iteration.

Good question, BTW. You have described the problem well, shown the schematic, shown the code, described things that you have already tried, and explained in detail what the problem was. Plus you had a video of the problem. Overall an excellent job!

Regarding your edit about SPI, the speed difference would be significant. According to my page about protocols SPI can be 30 times as fast as I2C (depending on the I2C clock speed) so I suggest that getting the SPI version of that board would indeed give you a significantly faster refresh rate. You may then need to rework how you show scores but bit banged SPI could be an option for the scores. The scores hardly need to update all that fast, and in any case there would be a lot less data.

@NickGammon But I noted in my question that changing the I2C clock speed to 400 KHz (which is 4 times as fast as its regular speed) didn't affect the situation at all. I don't think that using SPI would give that significant improvement.

Yes, but I've read elsewhere that the library you use changes the I2C clock speed to 400 kHz anyway so your change would have no effect. That's why you didn't see any improvement. But going to SPI would give you a 10 times improvement (since the I2C clock is 400 kHz rather than 100 kHz, based on my figures on the linked page.)

Re “What a pity it is that the guy who published this post didn't explain how he achieved that high frame rate!”: He does mention he is using an SPI interface.

@EdgarBonet When I wrote that I didn't know that SPI is faster than I2C. "I don't think that the communication interface, I2C in my case and SPI in his case, makes much difference."

I put in some timing into your code. As a tip for you and others who may want to time code, here is a simple way of doing that ...
Timer class
Define a timer class as follows:
class timer
  {
  unsigned long start;
  const char sReason [50];

  public:

    // constructor remembers time it was constructed
    timer (const char * s)
      {
      strncpy (sReason, s, sizeof (sReason) - 1);
      start = micros ();
      Serial.print (F("Start:  "));
      Serial.println (sReason);
      };

    // destructor gets current time, displays difference
    ~timer ()
      {
      unsigned long t = micros ();
      Serial.print (F("Finish: "));
      Serial.print (sReason);
      Serial.print (F(" = "));
      Serial.print (t - start);
      Serial.println (F(" µs"));
      }
  };    // end of class timer

How to use the timer class
If you want to time "loop" then just put this at the start of it:
void loop() {
  timer t ("Loop");
  ... other code ...
}  // end of loop

The constructor starts timing, and the destructor (when loop is exited) works out the difference and displays it.
To time some specific code, make a "block" like this:
  {    // start of block
  timer t ("Draw ball");
  ssd1306.clearDisplay();
  ssd1306.drawRect(ballX, ballY, 2, 2, WHITE);
  }    // end of block

Inside the block the timer instance is created, it times what is inside the block, and displays the result after the } is passed.
Naturally, for all this to work you need to do a Serial.begin (115200); in setup.

Results of timing
I added the above two timing calls, plus for drawing the rackets and updating the display:
  {
  timer t ("Draw rackets");
  ssd1306.drawRect(0, racket1, 2, 8, WHITE);
  ssd1306.drawRect(126, racket2, 2, 8, WHITE);
  }

  {
  timer t ("ssd1306.display");
  ssd1306.display();
  }

The results I got were:
Start:  Loop
Start:  Draw ball
Finish: Draw ball = 1812 µs
Start:  Draw rackets
Finish: Draw rackets = 1956 µs
Start:  ssd1306.display
Finish: ssd1306.display = 168944 µs
Finish: Loop = 178516 µs

Clearly, updating the display is taking almost all the time (169 ms each time, which means you will be doing around 5 loops per second).
Following on from a suggestion in the Adafruit forum I changed your constructor for ssd1306 to be:
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 ssd1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

Now the timing is:
Start:  Loop
Start:  Draw ball
Finish: Draw ball = 1780 µs
Start:  Draw rackets
Finish: Draw rackets = 1956 µs
Start:  ssd1306.display
Finish: ssd1306.display = 21192 µs
Finish: Loop = 30648 µs

So that is around 33 FPS rather than 5 FPS. A big improvement!

Further speed improvements
Following on from your edit about changing from I2C to SPI "not making much difference", the speed difference would indeed be significant. According to my page about protocols SPI can be 30 times as fast as I2C (depending on the I2C clock speed) so I suggest that getting the SPI version of that board would indeed give you a significantly faster refresh rate — at least 10 times as fast.
You may then need to rework how you show scores but bit banged SPI could be an option for the them. The scores hardly need to update all that quickly, and in any case there would be a lot less data. (The screen has 4096 pixels, and the scores would only be a handful of digits).

From a comment by SNBS:

But I noted in my question that changing the I2C clock speed to 400 KHz (which is 4 times as fast as its regular speed) didn't affect the situation at all.

Yes, well the default behaviour for the constructor is to use a 400 kHz clock, see the constructor declaration:
Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi = &Wire,
                   int8_t rst_pin = -1, uint32_t clkDuring = 400000UL,
                   uint32_t clkAfter = 100000UL);

The constructor definition saves clkDuring into wireClk.
Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi,
                                   int8_t rst_pin, uint32_t clkDuring,
                                   uint32_t clkAfter)
    : Adafruit_GFX(w, h), spi(NULL), wire(twi ? twi : &Wire), buffer(NULL),
      mosiPin(-1), clkPin(-1), dcPin(-1), csPin(-1), rstPin(rst_pin)
#if ARDUINO >= 157
      ,
      wireClk(clkDuring), restoreClk(clkAfter)
#endif

At the start of the display function it calls TRANSACTION_START
void Adafruit_SSD1306::display(void) {
  TRANSACTION_START

This is a define:
#define TRANSACTION_START                                                      \
  if (wire) {                                                                  \
    SETWIRECLOCK;                                                              \
  } else {                                                                     \
    if (spi) {                                                                 \
      SPI_TRANSACTION_START;                                                   \
    }                                                                          \
    SSD1306_SELECT;                                                            \
  } ///< Wire, SPI or bitbang transfer setup

And SETWIRECLOCK sets the I2C clock speed for you:
#define SETWIRECLOCK wire->setClock(wireClk)    ///< Set before I2C transfer

Thank you for your work! Did it, the ball now moves quite fast, which was my goal.

A much faster frame rate should be achievable with I2C by updating only the parts of the display buffer that have actually changed since the previous frame. The SSD1306 supports this but, alas, the Adafruit_SSD1306 library doesn't.

@EdgarBonet True, especially with something simple like Pong.

source: Stack Exchange

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

sort: votes


text:
Micropython installation on Arduino nano
I am currently trying to use micropython on an arduino Nano 33 BLE using MacOS. Following the instructions from arduino website I was able to complete steps 1-3. At step 4, I can find the bossac file but when I try to run the provided command:
bossac -e -w —offset=0x16000 —port=usbmodem14201 -i -d -U -R file.bin
the terminal says no device found on usbmodem14201 which is a port appearing under the nano board in the IDE.
As a sanity check I ran serialportlist in matlab and the same port was returned when the Nano is plugged in.
I even ran ioreg -p IOUSB in terminal and found the nano:
‘’’ Arduino Nano 33 BLE@14200000 <class AppleUSBDevice, id 0x100008674, re$ ‘’’
That 142… number didn’t work either.
What am I doing wrong?

Welcome to Arduino StackExchange:

Firstly your computer translates double dashes into single long dashes. the dashes should be double dashes (--) for options such as --offset, --port, etc. The command should be:
bossac -e -w --offset=0x16000 --port=usbmodem14201 -i -d -U -R file.bin

but I can see that your computer translated these -- to those — ?

Before you try to upload code confirm that the board is recognized by the system using the ls command:
ls /dev/cu.*

This should list all serial devices and you should see something like /dev/cu.usbmodem14201 in the list if your board is connected.

Ensure that you have the necessary permissions to access the serial port. You can try running the bossac command with sudo to run it as the superuser:
sudo bossac -e -w --offset=0x16000 --port=usbmodem14201 -i -d -U -R file.bin

Instead of just the port name usbmodem14201, you might need to use the full path like /dev/cu.usbmodem14201:
bossac -e -w --offset=0x16000 --port=/dev/cu.usbmodem14201 -i -d -U -R file.bin

Check that the Arduino Nano 33 BLE is in the bootloader mode. Typically, this can be achieved by double pressing the reset button. When it's in bootloader mode, the board might appear on a different port. Check the ports again with ls /dev/cu.* after you double press the reset button.

If you try all those and still it doesn't work maybe you should try installing latest drivers or check compatibility. Anyways, good luck.

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


text:
Reading a string from the serial port and comparing to another string
I'm using an Arduino Mega 2560 and writing a really simple piece of code that doesn't work.
String a, letra;
#define led 13

void setup() {
  Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
  pinMode(led, OUTPUT);
}

void loop() {
  while(Serial.available()) {
    letra= Serial.readStringUntil('\n');
    letra.trim();
    Serial.println(letra);

    if(letra.equals("aa\r\n")){
      Serial.println("ABRE 1");
    }
    if(letra == "aa\r\n"){
      Serial.println("ABRE 2");
    }
    if(letra.compareTo("aa\r\n") == 0){
      Serial.println("ABRE 3");
    }
  }
}

It's returning what I typed, but it's not entering any of the if conditions...
Can someone help me with that ?

there can be no \r\n in the string after trim()

Additionally, the terminating \n is removed from the input buffer, but excluded from the returned result, even without trim.

Trim removes whitespace, and you are comparing for \r and \n to be there. Since they are whitespace naturally the compare fails.
See here for one definition of whitespace for C.


text:
how to make this code work with spiffs?
So, I have a page to select a txt file from the user's device and save it to SD card:
<!DOCTYPE html>

  <title>File Upload </title>

File Upload

<form method='POST' action='/upload' enctype='multipart/form-data'>
<input type='file' name='upload'>
<input type='submit' value='Upload'>
</form>

and here is my esp8266 code for handling the form :

  controlserver.on("/UPL", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", upl);
  });
 controlserver.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
        request->send(200); }, handleUpload);

void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
  String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();

  if (!index) {
    logmessage = "Upload Start: " + String(filename);
    request->_tempFile = SD.open("/" + filename, "w");
  }

  if (len) {
    request->_tempFile.write(data, len);
    logmessage = "Writing file: " + String(filename) + " index=" + String(index) + " len=" + String(len);
  }

  if (final) {
    logmessage = "Upload Complete: " + String(filename) + ",size: " + String(index + len);
    request->_tempFile.close();
    request->redirect("/");
  }
}

My project is not big and it doesn't require SD card, and esp8266 has 4mb memory, I have tried to replace SD with spiffs, but I wasn't successful. I don't know that if it's possible to directly write the txt file to spiffs, but it will be ok if I could save it to a string the write it to a file in spiffs.

reduce your code to writing "x" to spiffs and reading it back

Thanks to this post, I did solve the problem.
Here is the full code,
My html code for the upload page, the form is in the  tag:

<!DOCTYPE html>

  <title>File Upload Example</title>

File Upload Example

<form method="POST" action="/upload" enctype="multipart/form-data" target="iframe"><input type="file" name="upload"><input type="submit" value="Upload">
</form>

code for ESP:

void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
if (!index) {
    request->_tempFile = SPIFFS.open("/" + filename, "w");
    Serial.println("1");
}
if (len) {
    request->_tempFile.write(data, len);
     Serial.println("2");
}
if (final) {
   Serial.println("3");
    request->_tempFile.close();
    request->redirect("/");
}
}

 controlserver.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) {
        request->send(200); }, handleUpload);

  controlserver.on("/UPL", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", upl);
  });

  readFile(SPIFFS, "/11.txt"); // show the content of the uploaded file, obviously you should know the name of the uploaded file!

you can write a function like this to make sure the file was delivered:
  readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);
  File file = fs.open(path, "r");
  if(!file || file.isDirectory()){
    Serial.println("- empty file or failed to open file");
    return String();
  }
  Serial.println("- read from file:");
  String fileContent;
  while(file.available()){
    fileContent+=String((char)file.read());
  }
  file.close();
  Serial.println(fileContent);

}


text:
reading device or board specific properties from the Arduino MKR WiFi 1010 device
How to read programmatically the device specific properties from the Arduino MKR WiFi 1010 chip or board?
For example, following properties of the device:

any identification number, that can uniquely identify the physical device, integer or GUID or string or any other, how to read that from the code?
SerialNumber of the MRK WiFi 1010 device
ModelNumber of the MRK WiFi 1010 device

I have tried to check the documentation and examples, however I couldn't find anything at all.

MAC address is unique. https://www.arduino.cc/reference/en/libraries/wifinina/wifi.macaddress/

MAC address could be of use to you, but remember that it can be spoofed. Aside from that Serial and Model numbers are not accessible from software layer.
Here is a simple implementation for fetching the MAC address
    #include <WiFiNINA.h>

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

      if (WiFi.status() == WL_NO_MODULE) {
        Serial.println("Communication with WiFi module failed!");
        while (true);
      }

      byte mac[6];
      WiFi.macAddress(mac);
      Serial.print("MAC: ");
      for (int i = 5; i >= 0; i--) {
        if (mac[i] < 16) {
          Serial.print("0");
        }
        Serial.print(mac[i], HEX);
        if (i > 0) {
          Serial.print(":");
        }
      }
      Serial.println();
    }

    void loop() {}

Another solution that I can think of is writing your own unique identifier such as UUID to EEPROM memory for each board.
If you're generating a UUID in the context of a server or a device with more resources, there are libraries and tools that can create these for you based on various factors to ensure uniqueness (like timestamp, MAC address, etc.). However, with a microcontroller like the one on the Arduino MKR WiFi 1010, you have a more constrained environment, and the process can be more manual.
You can use an online UUID generator or can generate it using Python:
    import uuid
    print(uuid.uuid4())

After generating your UUID's, you can write them on EEPROM but make sure to not over-write EEPROM since it has very limited call boundaries.
Writing to EEPROM
#include <EEPROM.h>

const char* MY_UUID = "550e8400-e29b-41d4-a716-446655440000";
const int EEPROM_UUID_ADDRESS = 0;  // starting address in EEPROM

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

  // Write UUID to EEPROM
  for (int i = 0; i < strlen(MY_UUID); i++) {
    EEPROM.write(EEPROM_UUID_ADDRESS + i, MY_UUID[i]);
  }
  Serial.println("UUID written to EEPROM");
}

void loop() {}

"starting address in EEPROM" is the address of the first box (or byte) where the program begins storing our UUID. By specifying const int EEPROM_UUID_ADDRESS = 0;, we are saying we'll start storing the UUID from the very first byte (box) of the EEPROM. If you were storing other data in EEPROM, you would need to ensure that the addresses don't overlap. For example, if you had other data stored in the first 10 bytes, you might set EEPROM_UUID_ADDRESS to 10 to start storing the UUID from the 11th byte.
Reading from the EEPROM:
#include <EEPROM.h>

const int UUID_LENGTH = 36;  // Length of the UUID string
char readUUID[UUID_LENGTH + 1];  // +1 for the null terminator
const int EEPROM_UUID_ADDRESS = 0;  // starting address in EEPROM

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

  // Read UUID from EEPROM
  for (int i = 0; i < UUID_LENGTH; i++) {
    readUUID[i] = EEPROM.read(EEPROM_UUID_ADDRESS + i);
  }
  readUUID[UUID_LENGTH] = '\0';  // Null terminate the string

  Serial.print("UUID read from EEPROM: ");
  Serial.println(readUUID);
}

void loop() {}

+1 for the null terminator:
In the C and C++ programming languages, strings are represented as an array of characters. The end of the string is marked by a special character known as the "null terminator" or "null character", which is represented by the value '\0' (a byte with all bits set to 0).
When we read or write strings to/from memory (like EEPROM), we often need to account for this null terminator to ensure the string is properly terminated and can be safely used with string functions.
In the code, the UUID is 36 characters long. When we declare an array to hold this UUID with the line:
char readUUID[UUID_LENGTH + 1];

We're allocating space for the 36 characters of the UUID plus an additional character for the null terminator, hence UUID_LENGTH + 1.
Later, after reading the UUID from EEPROM, we ensure this array is a properly terminated string by adding the null terminator:
readUUID[UUID_LENGTH] = '\0';

This ensures that when we use readUUID in functions that expect a string, they'll recognize where the string ends. Without the null terminator, these functions wouldn't know where the string finishes, leading to unpredictable behavior or errors.
I hope that this is helpful.

thanks. There are few more ways to get the board information, it is USB device serial number, which is stored in the FTDI chip. However, the Arduino can't read from the FTDI chip, and second way is like this: if defined (__AVR_ATmega2560__)

yes, I am aware that FTDI chip contains the USB device serial number but I have came to realise that sometimes chip producers assign the same VID and PID numbers to different boards they produce. if you want to read values from the FTDI chip you can use Python by the way. using serial and ftdi you can get the first available FTDI device serial number and send it to Arduino via COM3 Serial. if you wish i can demonstrate how to do it. using "if defined (AVR_ATmega2560) " would not distinguish between two ATmega boards would it?

correct, using if defined (__AVR_ATmega2560__), won't allow to distinguish between two ATmega boards.

would you like to try the -very hard way of- reading the FTDI on your OS and then sending it to ArduinoIDE? looks like a nice challenge to work on.

I think, that there is no much difference between storing the UUID and serial number from the FTDI chip into the EEPROM. It has to be stored in the same way

there is no FTDI on MKR WiFi 1010. the MCU has native USB. and it has an accesible serial number

Ah, thanks for letting us know Juraj, you seem correct. I assumed it uses FTDI as shekhovtsov claimed so. MKR WIFI 1010 uses SAMD21 which has a datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D21_DA1_Family_DataSheet_DS40001882F.pdf
and it seems like the addresses for serial number are: 0x0080A00C, 0x0080A040, 0x0080A044, 0x0080A048 ----- word 0 to 3. one could just read them like: id[0] = *(volatile uint32_t *)0x0080A00C; and so on...

The IDE shows the serial number so I looked into the SAMD core and found the function which reads the serial number from registers. It is in the CDC.cpp file
uint8_t Serial_::getShortName(char* name) {
    // from section 9.3.3 of the datasheet
    #define SERIAL_NUMBER_WORD_0    *(volatile uint32_t*)(0x0080A00C)
    #define SERIAL_NUMBER_WORD_1    *(volatile uint32_t*)(0x0080A040)
    #define SERIAL_NUMBER_WORD_2    *(volatile uint32_t*)(0x0080A044)
    #define SERIAL_NUMBER_WORD_3    *(volatile uint32_t*)(0x0080A048)

    utox8(SERIAL_NUMBER_WORD_0, &name[0]);
    utox8(SERIAL_NUMBER_WORD_1, &name[8]);
    utox8(SERIAL_NUMBER_WORD_2, &name[16]);
    utox8(SERIAL_NUMBER_WORD_3, &name[24]);
    return 32;
}

from the datasheet of SAMD21:

Each device has a unique 128-bit serial number which is a concatenation of four 32-bit words contained at the
following addresses:

The uniqueness of the serial number is guaranteed only when using all 128 bits


text:
How to control camera lens by Arduino's PWM? What FOCUS A+, FOCUS A- wires means?
I have a camera lens which I want to control by arduino (like this https://vi.aliexpress.com/item/1005004141070063.html)
I have an info about wires description but I can't understand what focus A+, A-, B+, B- means? I guess I need to send PWM pulses to A and B wires to move focus in straigt and opposite direction but I can't understand what + and - means. Is it just signal and ground?

It looks like you will be dealing with bipolar stepper motors. Most
likely, A+ and A− are connected to one coil, whereas B+ and B− are
connected to the other coil.
See the Arduino documentation: Arduino and Stepper Motor
Configurations for instructions on driving this kind of motor.


text:
Is it possible to use UART0 freely when connecting ESP32 s3 via USB (D+, D-)?
I've designed a test PCB that utilizes an ESP32 S3 and testing pins. During program uploads, I use the USB interface over GPIO20 and GPIO19 as D+ and D-. Everything works fine in this configuration. However, I've encountered an issue where UART0 becomes inactive after using the USB interface. Now, I want to connect the TX pin of a GPS module (NEO 6m) to UART0's RX pin, but I'm unable to do so. It's impractical to run the code as is because when data is received on RX0, it floods the continuous serial screen. I'm looking for a solution to completely disconnect UART0 from the USB interface so that I can use it independently.
In Short How I can receive date from UART0 and than Serial.print to Serial monitor over the USB interface?
#define RXD2 6
#define TXD2 7

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  while (!Serial)
    delay(200);
  Serial.println("start GPS...");

  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() {
  while (Serial.available()) {
    Serial.print(char(Serial.read()));
  }
}

Serial is 'com' port over USB on esp32 with native USB (and "USB CDC On Boot" option selected in Tools menu). For UART0 the core then creates Serial0.
From documentation:

To use the UART as serial output, you can use Serial0.print("Hello World!"); instead of Serial.print("Hello World!"); which will be printed using USB CDC.


text:
Respond to all WiFi probe requests with ESP8266?
I'm wondering if there's a way to program an ESP8266 such that it responds to all WiFi beacon probe requests. For example, if a device sends a probe request for a WiFi network name, e.g. "homewifi", the ESP8266 will send a response frame to that and have that device connect to it. Is this possible to do?


text:
Can TFT displays share the same RST?
I am trying to connect up to 5 TFT displays to one Arduino Uno R3 and use a multiplexer to control the output to each display. At the moment I am stuck being able to only write to a single one. Every time I try to add a second one I fail.
The displays I am using are here along with the pin allocations. https://www.waveshare.com/wiki/1.69inch_LCD_Module#Arduino
The process I am following is detailed here along with the schematic I am following. https://forum.arduino.cc/t/multiple-tft-displays-with-due-using-multiplexed-spi-cs/917473.
In the schematic you can see they are sharing the one reset pin. Additionally that pin is connected to the Arduino's native Reset pin.
I have copied the same design so that all my pins are shared apart from the CS pin. The CS pin from the Arduino goes to the signal pin of the multiplexer.
I can get that setup to work with a single display. However, as soon as I put the second displays reset pin into the same channel on the breadboard as the first displays pin, both screens no longer work. They are backlit, but there is no text appearing. Pull the second RST pin out again, reset the Arduino, and the first screen outputs text again.
I have taken the code from the example above and modified it a little to suit my displays. Below is the code I am using with comments that I hope explains it adequately.
After the initialization, I am adding a delay of 1000 ms in case the displays needed time to reset. Unfortunately, this didn't help either. I feel that adding the delay inside of the initialization loop won't help because as I understand it, the reset happens when the display gets power.
I am not an electronics person but I am a programmer by trade. So it's the code I understand and can modify. Where I am lacking is in being able to wire this up so that I can have the 5 displays hooked up.
I "think" that if I can solve the RST issue, that I should be able to write to the screens no problem, but right now that's a guess.
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library
#include <SPI.h>

#define BLACK 0x0000
#define RED 0xF800
#define GREEN 0x07E0
#define WHITE 0xFFFF

// rst is declared as pin 8 but there is no pin in that socket
Adafruit_ST7789 tft = Adafruit_ST7789(10, 7, 8); // 10 = CS, dc, rst

void setup(void)
{
  // these outputs control the multiplexer chip
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);

  for (int n = 1; n < 3; n++)
  {
    SetDisplay(n); // selects the display
    tft.init(240, 280);

    tft.setTextColor(WHITE);
    tft.setRotation(2); // rotate to portrait

    tft.fillScreen(BLACK);
    tft.setCursor(15, 18);
    tft.print("DISPLAY ");
    tft.print(n);
  }
  delay(1000);
}

int value = 0; // this is what is rendered on screen
void loop()
{
  // Scroll through the two displays
  for (int M = 1; M < 3; M++)
  {
    SetDisplay(M);
    tft.fillRect(0, 25, 159, 128, BLACK); // fill the variable text area which clears the previous text
    tft.setCursor(15, 50);
    tft.print(String(value));
    value++;
  }
  delay(1000);
}

// This function selects the display by setting two binary outputs to the multiplexer chip
void SetDisplay(int DNo)
{
  if (DNo == 1)
  {
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    tft.setTextColor(RED);
  }
  else if (DNo == 2)
  {
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    tft.setTextColor(GREEN);
  }
}

Why the downvote? This seems like a pretty legit question with enough detail in it!

I did not vote down... -- Please [edit] your question and add the schematic, especially how you wired the CSs and RSTs. The analog multiplexer of the linked forum post is -hrm- not the best solution, as comments there say, too. -- For the given design, you need a voltage meter to measure the level on the RST wire. Measure the voltage for the different situations: 1st display alone, 2nd alone, or both displays, RST applied or not, any combination. You might need to write a simple extra sketch for this. -- What happens if connect the 2nd display just by power and RST, but no communication line?

@thebusybee, So you think it might be a power issue by the sounds of it? Let me try your questions later on tonight and get back to you. Thanks for the comment.

Well, "power" in the sense of existing impedances/resistors. For example, the schematic of the Uno R3 (which one do you use?) has just a 10kOhm pull-up on RESET.

I do have the R3 yes. Let me try those few things you suggested and get back to you likely tomorrow now. Again, thank you


text:
How can I compensate for a joysticks offset value in neutral position?
I have a joystick that outputs the values 0 - 4095. I want to map these values in this fashion (Yes, the reversed mapping is intended):
outputValue = map(inputValue, 4095, 0, -2048, 2047);

However, the neutral central position of the joystick is offset, outputting 145 instead of 0.
Is there a way to map these values - taking the offset value in account - and still have the output values ranging from -2048 to 2047? I fail to do this with the map() function alone, and could need some help with the specific math involved.

your joystick may have a mechanical adjustment

You can only approximate it, you have to sacrifice something.
The basic problem is that your input range is asymmetric in respect to the mid point. Let's visualize it this way (with a bit of visual exaggeration):
min                     mid      max
0----------------------2193-----4095

Another problem is that the whole range 0..4095 may not be physically reachable by the joystick, so your usable range may actually look like this:
min                mid        max
433---------------2193-------3722

So, to calibrate your joystick, you need to measure the min, mid and max points that you can physically reach with exactly that joystick on the input scale (joysticks are analog devices, so their actual ranges can differ from joystick to joystick and even from axis to axis in the same physical joystick).
Now, if you have these numbers (I call those calibration values joy_min, joy_mid and joy_max), you need to map both parts of your range separately:
if( joy_input < joy_mid ) {
  output = map(joy_input, joy_min, joy_mid, -2048, 0);
} else {
  output = map(joy_input, joy_mid, joy_max, 0, 2047);
}

The downside is that any step in the output may represent a slightly different distance in the movement, depending on whether you are currently lower or higher than the measured midpoint. But I expect that to be negligible.
Also, keep in mind that this is only for one axis of the joystick. You may need completely different calibration values for the other axis. In addition, you may want to implement a "dead zone" around the midpoint, i.e. always returning output = 0 for joy_mid-10 < joy_input < joy_mid+10 or something like that.
And as the joystick range may drift (with temperature, age, etc...) and map does not constrain the output range, it might be a good idea to apply a output = constrain(output, -2048, 2047) afterwards.
(In my code, I assume that you want to map 0..4095 to -2048..2047 as you say in the text; but in your code, you map 4095..0 to -2048..2047, basically flipping the direction. If that part of your code is correct and the text is not, just swap -2048 with 2047 in my code.)

Thanks for your reply. With regards to the reversed mapping, it's intended. I've updated my question.


text:
Confusing stepper reaction to increase in delayMicroseconds()
I have been following this tutorial using the same hardware, TB6600 driver, 42HS48-1704A (yes I think its supposed to be 42hs40 but thats not what it says the sticker) stepper but am controlling via a Nano.
The code,
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;

int num_steps = 200;
int dt = 1000;

void setup() {

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

}

void loop() {

  digitalWrite(dirPin, HIGH); // Enables the motor to move in a particular direction

  for(int x = 0; x < num_steps; x++) {

    digitalWrite(stepPin, HIGH);
    delayMicroseconds(dt);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(dt);

  }

  delay(1000); // One second delay
  digitalWrite(dirPin, LOW); //Changes the direction of rotation

  for(int x = 0; x < num_steps; x++) {

    digitalWrite(stepPin, HIGH);
    delayMicroseconds(dt);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(dt);

  }

  delay(1000);
}

I added dt so I could control the step speed but its not behaving as I thought it would.
The original code has dt = 500 which needed 15V to run & runs not quite chunky movement but bordering on it & just over 1 revolution when num_steps = 2000
I changed to dt = 1000 & now its got really smooth faster motion & doing quite a few revolutions (too fast for me to count with my eyes) but if reduce num_steps = 200 that results in 1 revolution & now only needs 9V to run.
So, how come when I increase the delay it runs faster? Is this some kind of clocking/synching issue?

With dt = 500 you get one step per millisecond. This is probably too fast for the motor/driver combination. When the driver tries to execute another step, while the previous is not fully executed by the motor shaft (which needs some time due to the shafts inertia), the magnets will misalign and the coil current of the current step will not result in a proper rotation of the shaft. Some of the pulses are aligned enough to the motor shaft position just by chance and can result in a correct step. So the motor skips some of the pulses due to its inertia. Increasing the voltage will increase the force of the motor coils, which drive the shaft. Thus it can overcome the described problems easier (the shaft moving faster by the force of one pulse than before)
Increasing to dt = 1000 gives the motor enough time to follow each step. You aren't loosing steps because the magnets and coils in the motor always align correctly.


text:
OpenCV on ESP32 Arduino Nano
I am implementing a program on Arduino Nano ESP32: the KY-037 microphone is connected to the board and collects five seconds of analog signal. Then, an algorithm is applied to create a 128 x 128 matrix from the five-second signal. Now, I would like to apply the HOGDescriptor function from OpenCV.
Are there any possibilities to do so? How can OpenCV be installed on Arduino?

I vote to reopen. The question that is marked as duplicate only talks about the classic AVR based Arduinos. OpenCV on an ESP32 is possible, though in a reduced form. One seems to need the ESP32-DOWDQ6 chip for it. A quick search gave me this github project with OpenCV for ESP32 cross-compiled and this article on hackaday and the associated video about the ESP32-CAM.

@chrisl I seen that library. Another way to solve this limitation is to run the arduino code until before the OpenCV library, which will run on a Python script on PC. Not perfect but I will try


text:
How can I host a WiFi network from an Arduino getting a connection from a SIM card?
My friend and I are doing a project and we're stuck on a problem. We tried looking stuff up but it looks like no one documented something similar before.
Basically, what we want to do is have one Arduino (we thought a MKR NB 1500) in a remote location without any available WiFi (or Ethernet) connection be able to host its own Wifi Network. We thought that giving it a SIM card would allow it to communicate to our webserver (API) and to our surprise, it does (yay)! However, we also want people near the Arduino to be able to access the internet. However, that's where we're stuck...
I know that hosting an access point on an Arduino with WiFi is possible. But is it possible for that access point to link the user to the real internet, itself provided by the SIM card?
P.S. : We are open to having two different Arduinos linked together (or more) in order to make this work. We just need to be able to transfer the SIM network to an access point (hotspot basically).
P.P.S : We are also open to using different technologies like ESP controllers... We're just not using a cellular hotspot because of the cost of these things and we want to make it with Arduino or different controllers.

A sim card gives access to mobile data.  Do you really want to use mobile data for your internet?

This might be useful : https://www.iot-bots.com/products/qboard-a-arduino-mkr-compatible-wifi-bt-ble-iot-controller            and if you want to extend the range of your Wi-Fi network cheap, you can use this lib, it is very well documented :https://github.com/martin-ger/esp_wifi_repeater

@RohitGupta I understand it's not ideal but I didn't think of anything else that could work. If I got something like a 1-2gb/month plan for cheap then limited bandwith it could've worked. Do you suggest something else?

@MAK thanks a lot that seems to be what I am looking for. I'll continue to do some research and see if maybe that shield can talk with the MKR and take its connection...

Bridging of two networks at TCP/IP level is done in the TCP/IP stack. It translates addresses from one network interface to other network interface, but both interfaces are handled by the same TCP/IP stack.
An example on an MCU would be translating between esp8266 SoftAP and STA network interface. They are two network interfaces handled by the same TCP/IP stack. And now esp8266 Arduino can handle some Ethernet modules as additional network interfaces of that TCP/IP stack too.
With MKR NB 1500 or any other (mobile) network module attached to Arduino you can't do bridging because the TCP/IP stack is in the firmware of the module and the WiFi or Ethernet shield you would attach to the MKR would have its own TCP/IP stack in the firmware too.
If you are on esp8266, esp32 or other MCU where the TCP/IP stack runs in the MCU, you still can't make it work together with the TCP/IP stack in the external module. Those Ethernet modules esp8266 can use as netwok interaces with its TCP/IP stack are interfaced on the software layer closer to hardware, but the mobile network modules use AT commands without exposing access to lower layers.
What you can do is to proxy some network services as I write in this answer.

This is wrong Bridging of two networks at TCP/IP level is done with IP Network Address Translation (NAT) Protocol.. NAT is a routing solution not bridging.

@MatsK isn't 'bridging' routing?

No, bridging is on layer 2 and routing on layer 3.

@MatsK, ok. I removed mentions of NAT


text:
Ubuntu - TinyISP is not recognized
I got a Pocket AVR Programmer.
https://learn.sparkfun.com/tutorials/pocket-avr-programmer-hookup-guide
I hooked it up on Ubuntu Linux, opened up a sketch in the Arduino IDE, selected Programmer: USBTinyISP and then Upload Using Programmer.
However, I am getting this error:
An error occured while uploading the sketch
avrdude: Warning: cannot open USB device: Permission denied
avrdude: Error: Could not find USBtiny device (0x1781/0xc9f)

I even followed this blog post:
https://www.krekr.nl/content/using-usbtinyisp-with-ubuntu/
and issued these commands:
In a terminal, type:
sudo nano /etc/udev/rules.d/99-USBtiny

Then paste
SUBSYSTEM=="usb", ATTR{idVendor}=="1781", ATTR{idProduct}=="0c9f", GROUP="adm", MODE="0666"

into the new file. Write it out by pressing Ctrl-O.
sudo usermod -a -G plugdev YOURUSERNAME
sudo service udev restart
sudo udevadm control --reload-rules

However, the problem still remains.

Use lsusb or dmesg to confirm that the device is listed.

please do not post picture of text ... copy and paste the text into your question instead ... format as code

Have you installed the libusb?

sudo apt-get install libusb-1.0-0-dev

I'm not sure this actually answers the question that was asked.

Why not? usbtiny needs the libusb driver installed to properly work, if it's now installed it won't work, at least in UBUNTU

Thanks but libusb was already installed....


text:
Incorrect HEX code from DMM IR RS232
I have an Amprobe 38XR-A (sometimes seen as a meterman), these DMM's have a IR RS232 port on top and transmit a HEX code. Using the official cable I get a hex value of:

08000400500A0

I am attempting to read the IR RS232 via Serial1 of a pro-micro and display the output via Serial, but am getting an incorrect HEX code of:

6C666196665665F6793D

I have tried changing the resistor, in case it wasn't turning on/off fully with no change to the output (unless its a drastic change, then nothing is seen).
A buffer size of 15 appears to give repeatable results and is inline with the specification.
In an attempt for repeatability I have a test lead between the common and ohm port of the DMM.
Set-up:

Arduino Code:
const int BUFFER_SIZE = 15;
char buf[BUFFER_SIZE];

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);

  while(!Serial){  }
}

void loop() {
  if(Serial1.available()){
    // read the incoming bytes:
    int rlen = Serial1.readBytesUntil("\r\n", buf, BUFFER_SIZE);

    // prints the received data
    Serial.print("HEX Data: ");
    for(int i = 0; i < rlen; i++)
      Serial.print(buf[i], HEX);
    Serial.println("");
  }
}

Additional links:
Output Codes PDF
DMM Manual
IR photodiode

edit

Original IR receiver circuit.

I find it hard to believe that the signal is not modulated as common IR TV remote control signals are. The only widely known exception I know of is the obsolete IRDA format used in Palm Pilots. I'm betting that the actual 83SW adapter contains one of these COTS ~48KHz all in one demodulator IR receiver.  Do you have an oscilloscope?

Also, it is not clear what data you received and what data you were expecting.  Can you edit your question to include both and clearly say which is which?

RS232 uses 10 bits, or more, for every byte ... you have to look at the binary data, not hex ... don't use serial input ... sample the raw data on the pin at regular intervals instead, then examine the bits

hex 6C666196665665F6793D is binary 0110 1100 0110 0110 0110 0001 1001 0110 0110 0110 0101 0110 0110 0101 1111 0110 0111 1001 0011 1101 ... there are a lot of 11 and 00 ... that may be an indication that the signal baud rate is lower than you think

@st2000 yes I have an oscilloscope and 83SW has very little inside, transistor, diode a couple of resistors and caps - will take a pic Monday. Also, I am after the 83SW output, so 08000400500A0

@jsotola When I sampled the raw pin, there was nothing regular and the datasheet (at the bottom of the post) states it's as HEX and a baud rate of 9600

Could it be that the thing you think is a photo sensitive transistor or photo sensitive diode inside a real 83SW could actually be a complex integrated circuit such as this device?  If you built a circuit using an ordinary photo sensitive transistor or diode and you view the photo sensitive device's output do you see what looks like an RS323 signal or do you see bursts of an about 48KHz signal?

I've added an image of the original PCB to the post


text:
With TIMER1 in CTC mode can't get above ~200khz in arduino UNO runnning @ 16MHZ with no prescaller?
I got the following code, and based on the datasheet the Freq should be clk / 2 * Prescaller * (1 + OCR1A) making it that if I set the OCR1A to 0, I should get something close to 8Mhz, but the maximum I can get is ~200kHZ.  Can anyone help me understand why?
In FAST PWM MODE I can reach those speeds, just wanted to know why i can't in CTC MODE.
    void setup() {

        DDRB |= (1 << PINB1) ;
        TCCR1A = 0;
        TCCR1B = 0;
        OCR1A = 0;
        TCCR1B |= (1<<CS10) | (1<<WGM12);

        TIMSK1 |= (1<<OCIE1A);
        sei();
    }

    void loop() {

    }

    ISR (TIMER1_COMPA_vect){
        PORTB ^= 1 << PINB1;
    }

You cannot dispatch an ISR and return fast enough to get anywhere near 8MHz in CTC. But you also cannot do this for Fast PWM mode either. So, I don't know what to make of your question. Did you mean using the actual PWM functionality and just put the ISR in your code as a mistake? Alternately if you were able to get 8 MHz doing this same thing with an ISR and Fast PWM mode, I'm curious to see how.

Hello, thanks for your reply.
No, i can get the 8mhz using fast pwm without interrupts (yes to your question on the using the pwm functionality), just using the ICR and OCR1A registers and set them to 0.
I imagined it was something related to the time being consumed by the interrupt calls, but couldn,'t figure out the timings that jumping to the ISR takes.

I even went to the Microchip IDE and emulated the atmega, but it doesn't implement the ISR very well (either that or i don't know how to), cos i could only trigger the the ISR call when "playing" the debug and couldn't trigger it using the step by step instruction but i manage to get that for a 8MHZ clock the isr was triggered every 5us or something like that i think it was 38 instruction cycles, or close to that, but i coulnd't figure out where did those instructions came from.

I think i got thrown off by this on the atmega datasheet : The waveform generated will have a maximum frequency
of fOC1A = fclk_I/O/2 when OCR1A is set to zero (0x0000). The waveform frequency is
defined by the following equation:
So i was expecting a ~8mhz pulse.

I disassembled your program. Below is the code for the ISR. Next to each
instruction, I wrote the number of CPU cycles it takes, as a comment:
; Prologue: save some registers to the stack.
push r1         ; 2
push r0         ; 2
in   r0, 0x3f   ; 1
push r0         ; 2
clr  r1         ; 1
push r24        ; 2
push r25        ; 2

; ISR body: PORTB ^= 0x02;
in   r24, 0x05  ; 1
ldi  r25, 0x02  ; 1
eor  r24, r25   ; 1
out  0x05, r24  ; 1

; Epilogue: restore registers and return.
pop  r25        ; 2
pop  r24        ; 2
pop  r0         ; 2
out  0x3f, r0   ; 1
pop  r0         ; 2
pop  r1         ; 2
reti            ; 4

I count a total of 31 CPU cycles, most of them spent in the
prologue and epilogue. Then, there is some overhead:

The CPU always executes at least one instruction of the main program
between two interrupts. Given that the main program is in a tight loop
containing only two double-cycle instructions, that will take two CPU
cycles.

The CPU takes four cycles to enter interrupt mode: prevent nested
interrupts, save the program counter and load the address of the
interrupt vector.

The interrupt vector is a jmp instruction that jumps to the ISR.
This takes three cycles.

The minimal interrupt period is then given by this sum:
 2  one loop instruction
 4  enter interrupt mode
 3  jump to ISR
31  execute ISR
────────────────────────
40  total cycles

This takes 2.5 µs, giving an interrupt frequency of 400 kHz.
Given that you need two interrupts for a full cycle of the output
signal, the maximum you can see on the output is then 200 kHz.
You can save 10 CPU cycles by toggling the pin with:
    PINB |= 1 << PINB1;

This line compiles to a single double-cycle sbi machine instruction.
As this instruction doesn't access any CPU registers, you don't need to
save and restore r24 and r25. Actually, you don't need to save and
restore any register, so you could just remove the prologue, and replace
the epilogue by a single reti instruction:
ISR (TIMER1_COMPA_vect, ISR_NAKED) {
    PINB |= 1 << PINB1;
    asm("reti");  // return from interrupt
}

This gives an ISR that executes in six cycles, and the total interrupt
period can then be as small as 15 cycles. Beware though, that you
should not write a naked ISR unless you are absolutely sure that the
code within it will not clobber any CPU register, nor the status
register.

Clarification: On the face of it, the instruction
PINB |= 1 << PINB1;

seems to mean: “Load PINB, do a bitwise OR with 0x02, then write the
result back to PINB”. This is, however, not how the compiler
interprets it. Instead, it takes it to mean “set bit 1 of register
PINB to one”. This happens to be a single machine instruction, as
PINB is a bit-addressable I/O registers.
Yes, the avr-gcc compiler may be a bit peculiar in this respect.

First of all, thanks so much for that detailed explanation. i did tried to include that ISR_NAKED option, and it doubled the frequency.
One thing i didn't understand is that you said you can toggle the pin with the |= ? i tried it and it stays always on, i can only toggle with the ^= operator, am i doing anything wrong?

PINB |= 1 << PINB1; can just be PINB = 1 << PINB1;

But that doesn't toggle the pin, do i need to set any register?

@NunoSantos the behaviour of writing to  1-bit to PINx causes that pin to toggle in PORTx. I know it looks weird, but that's how it works on these chips.

Wait, not sure if i totally understand you, bare with me, i'm a noob...
So, i had the pin toggling, with the XOR operator., but when i change to the OR ou even just setting the pin with the Equal sign, i get no tggling on that pin, after reading your comment i went to the datasheet because i remember reading that there was one bit in a register that did just that, so i updated my code with the line TCCR1A |= (1<<COM1A0); and NOW it toggles if i set the PIN to HIGH inside the interrupt, not sure if it was this you were talking about.

Cos in my posted version of the code, when i switched the XOR for the OR or just pin assignment, i get no toggling on that pin.

@timemage: PINB = 1 << PINB1; is no faster than PINB |= 1 << PINB1;. Also, setting the pin with = clobbers a CPU register that you would have to save and restore. You then cannot do without the prologue and epilogue.

@NunoSantos: You should not replace a XOR by an OR: you should replace PORTB ^= 1 << PINB1; by PINB |= 1 << PINB1;. Notice that we are acting on a different I/O register: PINB instead of PORTB.

@EdgarBonet regarding the faster part, that wasn't the point of it. Regarding the second part: odd.

Ohhhh i see now, you are setting the PINB not the PORTB, i just tried and works without setting the COM1A0 bit, why is that? why setting the PIN directly toggles a pin off?
And once again, thanks for you time, and sorry for this noob questions

with your code i get 517kHZ, thats more than double what i had before.

@NunoSantos: The AVR I/O ports have this toggle functionality built-in. It has been piggy-backed on the PIN register, for which a write operation would otherwise be meaningless. Likely a way to save on I/O address space. See the ATmega datasheet.

@EdgarBonet i was reading the datasheet, and the PINx register is marked as a R only register, while the PORTx and DDRx and R/W, but this is good to know, altough even if you write to them the change won't stay, it's nice to have that functionality. Didn't know that! Thanks so much.


text:
Arduino pin erratic behavior?
I've built a switch key matrix (thus the diode, contextually useful schematics below) and me being me, I realised after that I misunderstood a few things about how button really works, to say the least...  So anyway, I want to save it so I plan on a solution which, to my surprise, is half-working: When I remake the entier circuit on a breadboard (mistake & solution), it's working but when I do it with my PCB, it doesn't...
The 5V+ is from a digital pin set to HIGH and I've mesured w/ an oscilloscope the tension between the ground and a digital pin ("Arduino INPUT") on the breadboard and on the PCB, with the input pin connected and not connected:

Connected
Not Connected

BreadBoard
2.5V+
5V+

PCB
0V+
5V+

So it's seems like the pin is becoming one with the ground but I can't find anything that could explain this.
I've been testing and trying to understand what the hell was going on for multiple hours now and I runned out of ideas... Does anyone here have an idea of whats might happening ?

this may help ... https://electronics.stackexchange.com/questions/562412/4x4-keyboard-matrix-why-no-pull-down-resistors

Well, that is helpful ! I still need to really understand it but this link seems to help a lot:
https://www.gammon.com.au/forum/?id=14175

look at the "initial case" circuit ... change arduino input to arduino output .... add arduino input to switch pin 1

Yup, I got it but I still would like to understand why it "sinks" the tension...

Are you supplying the breadboard from a 5v power source, other than the one that is supplying the Arduino?
Is there any reason why you are using a diode between the button and the arduino pin?
Arduino can sink and source current and with the 10k resistor that diode is just "dropping" some voltage, i would remove it if you really don't have any other use for it.
If you are supplying the PCB with a different power source than the arduino, you have to "join" the 2 grounds, connect the groud from the power source of the PCB to any ground pin of the arduino. if you could take a photo that could help.
Something like this :

There's a diode because it's a part of a key matrix. The 5V+ is from a digital pin set to HIGH so the breadboard is fed with that.
Regarding the 10k resistor, I know it's a mistake and I'm trying to fix it. The thing is, the fix is acting strangely...
What are you using for your schematics btw ?

But can't you bypass the diode? can you post a picture of how you have the thing connected?
I'm using an old software called Circuit Wizard

It«s really important that you connect the ground of the pcb power supply (if there is a different one) to the arduino ground

@O'Schell the info about the diode belongs in the question ... please edit your question and add the info

Diode info added and the ground on the PCB isn't used in the circuit: I only use the arduino one


text:
ATTINY 85 - use host laptop's internet
Suppose I enable USB tethering (internet) on my laptop. Will it be possible to use that internet on an ATTINY 85 connected to USB.

no, the processing power of the microcontroller is insufficient ... your laptop has to act as a gateway between a serial port and the internet

Since there are uncounted applications for an internet connection, what specifically do you want to do?

No, the attiny85 is simply too slow and not powerful enough to process your laptop's internet connection and begin something with it. If you only have to make API Request, you can hard code them into the firmware, and send the api-request-string to your computer, make your computer execute the API-request and then send the API response from the computer to the attiny to process the response there.
Regards
Dario


text:
Read byte and time into EEPROM, then display with a comma between the time and the value?
I have bytes of natural numbers 1-60 coming in at random times:
Example of send data
// Uno send

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

  int integersToSend[] = {1, 22, 30, 4, 50};
  for (int i = 0; i < 5; i++)
  {
    Serial.print(integersToSend[i]);  // send as characters
    delay(1000);
  }
}

void loop() {}

I want to log the time (any time format) and what value was received into EEPROM:
#include <EEPROM.h>

const int timeRefreshDisplay = 30000;
const int EEPROM_SIZE = 100; // Define size of EEPROM available
int addr = 0; // EEPROM address pointer

unsigned long programStartTime;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600); // Initialize Serial1 for data input
  programStartTime = millis(); // Record program start time
}

void loop()
{
  if (Serial1.available())
  {
    int receivedData = Serial1.read();

    if (receivedData != 0 && receivedData <= 60)
    {
      byte receivedValue = receivedData; // Convert?

      // Calculate the timestamp based on program start time
      unsigned long currentTime = programStartTime + millis();

      // Store the received timestamp and value in EEPROM
      EEPROM.put(addr, currentTime);
      addr += sizeof(unsigned long);
      EEPROM.put(addr, receivedValue);
      addr += sizeof(int);
    }
  }

  if (millis() - programStartTime >= timeRefreshDisplay)
  {
    programStartTime = millis();
    displayEEPROMData();
  }
}

void displayEEPROMData() {
  // Display all positions stored in EEPROM
  Serial.println("EEPROM:");

  for (int i = 0; i < EEPROM_SIZE; i += sizeof(unsigned long) + sizeof(int)) {
    if (i >= EEPROM_SIZE) {
      i = 0; // Start reading from the beginning when reaching the end of EEPROM
    }

    unsigned long timestamp;
    int value;
    EEPROM.get(i, timestamp);
    EEPROM.get(i + sizeof(unsigned long), value);

    // Display position data with timestamp in HH:MM:SS format
    Serial.print(String(i / (sizeof(unsigned long) + sizeof(int)) + 1) + ": ");
    Serial.println(String(timestamp) + ", " + String(value));
  }
}

Serial monitor
EEPROM:
1: 17330, 22272
2: 101, 27943
3: 4143972352, 116
4: 0, 0
5: 0, 0
6: 0, 0
7: 0, 0
8: 0, 0
9: 0, 0
10: 0, 0
11: 0, 0
12: 0, 0
13: 0, 0
14: 0, 0
15: 0, 0
16: 0, 0
17: 0, 0

I'm not quite sure how it is reading data into EEPROM. That has to be where the issue is. I just don't know how to fix it. I tried clearing out the memory:
    #include <EEPROM.h>

    void setup() {
       // initialize the LED pin as an output.
       pinMode(13, OUTPUT);

       for (int i = 0 ; i < 22; i++) /*EEPROM.length()*/
          EEPROM.write(i, 0);

       // turn the LED on when we're done
       digitalWrite(13, HIGH);
    }

    void loop() {}

Serial monitor again
EEPROM:
1: 0, 0
2: 0, 0
3: 0, 0
4: 0, 4
5: 70, 1
6: 22, 3
7: 230, 2
8: 182, 4
9: 134, 50
10: 234, 49
11: 209, 50
12: 213, 50
13: 185, 51
14: 189, 48
15: 161, 52
16: 137, 53
17: 140, 48

I'm using a Leonardo to receive.

An EEPROM cell can tolerate only a limited number of write cycles. You should be very careful when writing to it continuously in the loop().
You are writing 2 associated data items to the EEPROM per cycle. It would be better to use a struct to pack the two items and do the write operation in one go using the put() method. For unpacking, use the get() method.

It could be that you have already damaged some EEPROM cells by exceeding the write cycle limit. You could start at say cell 100 instead of cell 0 to see if the results are more consistent. Hovever, don't allow the code to write endlessly to the EEPROM and remember that an unwritten to EEPROM cell is '1' filled.

My EEPROM library supports update which will only write if there is a change. Try using that. Also you can use FRAM and have unlimited R/W cycles.

This works.
#include <EEPROM.h>

const int EEPROM_SIZE = 100; // Define size of EEPROM available
int addr = 0; // EEPROM address pointer

unsigned long programStartTime;

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

  programStartTime = millis(); // Record program start time

  // Initialize EEPROM data
  //  for (int i = 0; i < EEPROM_SIZE; i++) {
  //    EEPROM.write(i, 0);
  //  }
  displayEEPROMData();
}

void loop()
{
  if (Serial1.available())
  {
    int receivedData = Serial1.read();

    if (receivedData >= 1 && receivedData <= 60)
    {
      byte receivedValue = static_cast<byte>(receivedData); // Convert to byte

      // Calculate the timestamp based on program start time
      unsigned long currentTime = millis() - programStartTime;

      // Store the received timestamp and value in EEPROM
      EEPROM.put(addr, currentTime);
      addr += sizeof(currentTime);
      EEPROM.put(addr, receivedValue);
      addr += sizeof(receivedValue);

      displayEEPROMData();
    }
  }

  if (addr >= EEPROM_SIZE) {
    addr = 0; // Wrap around if the EEPROM is full
  }

}

void displayEEPROMData() {
  // Display all positions stored in EEPROM
  Serial.println("EEPROM:");

  for (int i = 0; i < EEPROM_SIZE; i += sizeof(unsigned long) + sizeof(byte)) {
    unsigned long timestamp;
    byte value;
    EEPROM.get(i, timestamp);
    EEPROM.get(i + sizeof(timestamp), value);

    // Display position data with timestamp in HH:MM:SS format
    Serial.print(String(i / (sizeof(unsigned long) + sizeof(byte)) + 1) + ": ");
    Serial.println(String(timestamp) + ", " + String(value));
  }
}

Well done, answering your own question, really. For future visitors including your future self in some weeks, you might extend your answer with some explanation what was wrong. Comparing source code shows the result, but not the way to it.

You appear to have another problem that you are sending integers (int datatype) from a Uno to the receiver. An int is represented as two bytes on the Uno. On the receiver you are getting individual bytes but making no attempt to collect pairs of these to reconstruct the original int.


text:
Why am I getting wrong compass heading using magnetometer readings?
I have been trying to calculate the compass heading using the magnetometer in an MPU9250 sensor. But the result is not making sense to me. I am completely new in this and do not have much understanding in how magnetometers work and just trying to find resources in the internet to make it work. I am calculating the atan2 of the y and x axis readings of the sensor to find out the angle:
float mx = imu.mag_x_ut();
float my = imu.mag_y_ut();
float mz = imu.mag_z_ut();

float heading = atan2(my, mx) * 180 / PI;

Serial.print(mx);
Serial.print(",");
Serial.print(my);
Serial.print(",");
Serial.print(mz);
Serial.print(",");
Serial.println(heading);

My understanding is that when the x axis of my magnetometer faces the north direction the value of heading should be 0, for east 90, south 180 and then for west 270. But my calculations are nowhere near the expected results. I am not even getting a zero reading in any directon. I am attaching the screenshots of the direction reading :
This is when x axis points to north.

Rotated x axis towards east.

x towards south.

x towards west.

I have also added the raw readings from the magnetometer represnted by mx, my and mz. Is something wrong with my sensor or there is some misunderstanding from my part.
EDIT: Readings after hard iron offset compensation.

The displayed heading seems consistent with the measured mx and my. These values, however, seem wrong: The modulus of the magnetic field changes as you turn the device. It should not. Either you are doing something wrong while getting the readings, or there is something magnetic next to (or on) your device that affects the local field.

@EdgarBonet, hi can you elaborate a bit on your statement " the modulus of the magnetic field changes as you turn the device", sorry if that's a newb question. I used this library for mpu9250 https://github.com/bolderflight/invensense-imu and just calling the methods for getting the data.

I mean the norm of the vector. You can plot it: it should not depend on the orientation of the sensor. 2. Re “just calling the methods”: can you post the complete code?

Consider calibrating your magnetometer.  Off the shelf, almost all magnetometers require calibration before making use of their data.  The offset (commonly referred to as Hard Iron) and the magnitude (commonly referred to as Soft Iron) need to be found for each of the 3 sensors (X, Y & Z) for individual magnetometers.
As there is no accelerometer in this design let us simplify the problem and assume the magnetometer will always be used on a flat surface with its Z axis normal to the surface of the Earth.  Let us also assume the X and Y sensors in the magnetometer are perfectly orthogonal to one another.
To calibrate the magnetometer remove metal objects from the local vicinity and avoid large metal object such as cars by 10s of meters.  Sample the X and Y sensors many times as these sensors point toward and away from north.  Find the maximum and minimum X and Y values.
Find the offset calibration value by adding the minimum and maximum values then divining by 2.  Find the magnitude calibration value by arbitrarily picking one axis and adjusting the magnitude of the other to match.  Picking X, we subtract the X minimum from the X maximum to find the X range.  We do the same for Y to find the Y range.  Then we assume the X magnitude calibration value to be 1 and the Y magnitude calibration value to be x-range divided by y-range.
Once calibration is done, to get calibrated X and Y values we subtract the X and Y offset respectively.  Then we multiply the offset adjusted Y value by the Y magnitude calibration value.
Note, this type of calibrated compass is difficult to carry around by hand because it may not be held level with the surface of the earth.  Also, because the inclination of the magnetic field points deeper into the earth the more one travels away from the equator, it will require re-calibration when traveling to a different latitude.
Calibration calculations based on data in question:
X max to min is 42 to -22 so offset is 10 and range is 64
Y max to min is 120 to 48 so offset is 84 and range is 72
So Y magnitude calibration is 64/72 or 0.889

Data when sensors are pointed East:
Y ~48 & X ~11
bearing = atan2(((48 - Y_offset) * Y_magnitude), ((11 - X_offset) * X_magnitude))
bearing = atan2(((48 - 84) * 0.889), ((11 - 10) * 1))
bearing = atan2(((-36) * 0.889), (1 * 1))
bearing = atan2(-32.004, 1)
bearing = -1.540 rad = -88.236 degrees

If instead of -88.236 degrees the value of approximately 90 degrees is desired, change the sign of the Y sensor as part of the calibration process.
The C programming function atan2 is an enhanced form of the math arc tan operation.  The C programming function atan2 will calculate to a full 2-Pi circle.  To verify how this works use this online atan2 calculator.

You could almost derive offset and magnitude calibration values from the data posted.  But it would be better if you rotated the sensor all the way around and observe the maximum and minimum values.  Because they may not be where you expect them.  Magnetic declination changes (in what appears like a random pattern) all around the world.

Hi thanks for your response, I will try with the calibration. However is there a way to tell if the readings by the sensor are accurate? For example in case of an accelerometer I can use gravity vector as reference.  @st2000

You don't need to change the X and Y values to any of the dozens of different magnetic measurement standards!  You are only interested in the relationship between the X and Y sensors.  Since the C programming atan2 function essentially divides one by the other, you will cancel out any effort you make at calculating a given magnetic dimension standard.  BTW, I think your X and Y sensor data looks good.  I think you just need to calibrate and apply that calibration before using the atan2 function.

Okay thanks, I will work on the calibration and get back here. @st2000

Thank you for your guidance, I calibrated the sensor for hard iron offset and it's working reasonably well now. Just one quick question, even when I have kept the sensor still, the heading is not fixed, it constantly changes in a range of 5-6 degrees, how can I make this stable?

@SayantanDas: Smooth your readings using a digital low-pass filter, e.g. an exponentially weighted moving average. Beware, though, that you will have to handle the angles wrapping around at 0°/360°. I suggest you try the runningAngle library, which takes care of correctly handling the wrapping for you.


text:
Why is my LED strip value always equal to 255 on my potentiometer?
I'm pretty new to Arduino and this is my first project I'm working on and I'm really struggling with why my code isn't working properly.
The LED strip should be able to adjust the colour with one potentiometer that I can take out to so I don't use 3 potentiometers and just use that can adjust all colours. Then once it's on mode 4 it should keep the colour and blink repeatedly.
I'm using an Arduino Uno but once my project if finished I'll use the Arduino Nano. I don't know if I'll need to change the code but if I do I think I could do that on my own.
I just don't know why my LED strip is always stuck on off (255).
// set pin numbers:
int ledPinR = 11; // the number of the LED R pin
int ledPinG = 10; // the number of the LED G pin
int ledPinB = 9; // the number of the LED B pin
int buttonPin = 7; // the number of the push button pin
int mode = 0; //to change the mode
int bluelev = 0; //save the blue led value
int greenlev = 0; //save thegreen led value
int redlev = 0; // save the red led value

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPinR, OUTPUT);
  pinMode(ledPinG, OUTPUT);
  pinMode(ledPinB, OUTPUT);

  //make the led strip white at boot
  digitalWrite(ledPinR, 0);
  digitalWrite(ledPinG, 0);
  digitalWrite(ledPinB, 0);
}

void loop() {
  // when the button is pressed changes the mode value by one
  if (digitalRead(buttonPin) == LOW) {
    ++mode;
    delay(500);
  }

  if (mode == 1) { //red config
    int adcValue; // Define a variable to save the ADC value
    // Convert analog of A0 port into digital, and work as PWM duty cycle of ledPinR port
    adcValue = analogRead(A0);
    analogWrite(ledPinR, map(adcValue, 0, 1023, 0, 255));
    (redlev = ledPinR); // saves the red led level
  }

  if (mode == 2) { //green config
    int adcValue; // Define a variable to save the ADC value
    // Convert analog of A1 port into digital, and work as PWM duty cycle of ledPinG port
    adcValue = analogRead(A1);
    analogWrite(ledPinG, map(adcValue, 0, 1023, 0, 255));
    (greenlev = ledPinG); // saves the green led level
  }

  if (mode == 3) { //Blue config
    int adcValue; // Define a variable to save the ADC value
    // Convert analog of A2 port into digital, and work as PWM duty cycle of ledPinB port
    adcValue = analogRead(A2);
    analogWrite(ledPinB, map(adcValue, 0, 1023, 0, 255));
    (bluelev = ledPinB); // saves the blue led level
  }

  if (mode == 4) {
    digitalWrite(ledPinR, 255); // switch off LED
    digitalWrite(ledPinG, 255); // switch off LED
    digitalWrite(ledPinB, 255); // switch off LED
    digitalWrite(8, 0); // switch on LED
    delay(1000); //wait 1 second
    digitalWrite(ledPinR, redlev); // switch on LED
    digitalWrite(ledPinG, greenlev); // switch on LED
    digitalWrite(ledPinB, bluelev); // switch on LED
    digitalWrite(8, 225); // switch on LED
    delay(1000); //wait 1 second
  }

  if (mode == 5) {
    mode -= 5; //sets the mode value back to 0
  }
}

Here is the setup.
Pretend the RGB LED is a LED strip and the potentiometers are just slots for one to be put in to change the colour when I want to. So when I'm not changing the colours I can use the potentiometer for other projects and not waste 3.

There are at least these errors in your code:
1. You cannot read back the analog value set to a pin.
You try this:
    analogWrite(ledPinR, map(adcValue, 0, 1023, 0, 255));
    (redlev = ledPinR); // saves the red led level

You correctly set the analog value at the pin for the red LED. But then you try to read it back. Look at the definition of ledPinR: It is an int with the fixed value of 11. So redlev is always 11.
Note 1: The output is not really analog, but pulse width modulated.
Note 2: You don't need the parentheses in the second statement.
Instead, store the mapped value in redlev:
    redlev = map(adcValue, 0, 1023, 0, 255);
    analogWrite(ledPinR, redlev);

Note 3: Use good variable names, like redLevel. Some time or later you will confuse things because of abbreviated names.
2. You are not repeating the analog write in mode4.
You wrote this, which is apparently wrong:
  if (mode == 4) {
    digitalWrite(ledPinR, 255); // switch off LED
    // other statements...
    delay(1000); //wait 1 second
    digitalWrite(ledPinR, redlev); // switch on LED
    // other statements...
    delay(1000); //wait 1 second
  }

Instead you want this (if 255 is really "off"):
  if (mode == 4) {
    analogWrite(ledPinR, 255); // switch off LED
    // other statements...
    delay(1000); //wait 1 second
    analogWrite(ledPinR, redlev); // switch on LED
    // other statements...
    delay(1000); //wait 1 second
  }

There are more issues, but this will take you a step forward. Most important, keep an indentation style, I cleaned up your source in the question to make it readable.

thank you so much

You're welcome! BTW, you are supposed to mark the answer that fits you best as "accepted" instead of commenting a "thanks"...

My first project was also the same, to set the strip color with one potentiometer. I used the function getColorValue, that returns you a Struct. This struct contains the value for red, green, and blue. Here is the example code:
#define PIN_POTENTIOMETER A0

struct RGB
{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} color;

RGB getColorValue(uint16_t inputValue);

void setup()
{
    Serial.begin(9600);
    pinMode(PIN_POTENTIOMETER, INPUT);
}

void loop()
{
    uint16_t inputValue = analogRead(PIN_POTENTIOMETER);
    color = getColorValue(inputValue);

    Serial.print("R: ");
    Serial.print(color.red);
    Serial.print(" G: ");
    Serial.print(color.green);
    Serial.print(" B: ");
    Serial.println(color.blue);
    delay(100);
}

RGB getColorValue(uint16_t inputValue)
{
    RGB color;
    color.red = 0;
    color.green = 0;
    color.blue = 0;

    map(inputValue, 0, 1023, 0, 255);

    if (inputValue <= 42.5)
    {
        color.red = 255;
        color.green = inputValue * 6;
        color.blue = 0;
    }
    else if (inputValue <= 85)
    {
        color.red = 255 - (inputValue - 43) * 6;
        color.green = 255;
        color.blue = 0;
    }
    else if (inputValue <= 127.5)
    {
        color.red = 0;
        color.green = 255;
        color.blue = (inputValue - 85) * 6;
    }
    else if (inputValue <= 170)
    {
        color.red = 0;
        color.green = 255 - (inputValue - 127.5) * 6;
        color.blue = 255;
    }
    else if (inputValue <= 212.5)
    {
        color.red = (inputValue - 170) * 6;
        color.green = 0;
        color.blue = 255;
    }
    else if (inputValue <= 255)
    {
        color.red = 255;
        color.green = 0;
        color.blue = 255 - (inputValue - 212.5) * 6;
    }

    return color;
}

If you need any further help, you can comment here or contact me directly with my mail in the bio.
Regards
Dario

analogWrite and analogRead doesn't require pinMode.

@Juraj You are right, my fault.

thank you so much