# Question
Title: Read Digital Input from Arduino Pin defined as OUTPUT
I'm working on a Home Automation Project. I can turn on-off ESP32 pin from Alexa and Google Assistant Successfully now.

What I need help is with a way to read if the AC supply is ON/OFF on the Arduino pin. Or if possible to save pins I would want to read it on the same pin which id defined as Digital output to control the relay.

Below attached image of what I have in mind.

1. Normal switch turns On/off supply to load without any requirement of WiFi.
2. Load is also connected to Relay NO, which is controlled by Arduino Pin D13.

What I want is instead of just reading the status of the D13 pin, I want to read the status of the Mechanical Switch which directly provide to Load.

So I'll actual status of the Load whether it's turned on by Switch or Relay with interrupting directly connected switch from load to supply.

Edited: As others suggested it is not possible to use the Same Pin to control the relay and read AC load status. So is there a way to read the AC supply through the GPIO pin of ESP32 maintaining galvanic isolation, (opposite working of Relay)?

# Answer
If you want to know the state of the load, I suggest to put the mechanical switch on the low-voltage side of the relay:

simulate this circuit – Schematic created using CircuitLab

The voltage divider R1/R2 is meant to lower the voltage at the transistor's collector (up to one diode threshold above Vcc) to a value suitable for the Arduino digital input.

Note that you still need two separate inputs for controlling and for sensing the state.
> 2 votes

# Answer
What you want to do is not possible, you'll need an extra pin. The reason is that the relay requires a lot of current (works like a very strong pulldown resistor). So, whatever (high impedance) sense signal you apply to the relay, it will just be "consumed" by the relay.

When reading the state of the switch, i.e. the voltage across it, galvanic isolation is absolutely mandatory (mains voltage can be deadly). This can be achieved with an opto coupler and some lines of code or additional hardware - as it's AC voltage, you can't simply read a steady voltage, so you'd either have to sample the AC signal or incorporate some kind of circuitry (software is simpler and cheaper).

Another issue with your circuit is that you must not drive the relay directly with the GPIO. The relay sinks way to much current, it'll fry the GPIO. Use a transistor to switch it.
> 0 votes

---
Tags: esp32, project, digitalwrite, digital-in
---


# Question
Title: text section exceeds available space in board
When I compile this code it gives the error mentioned above. I saw online a way to resolve this: `Serial.println(F("..."));`

For fixed string literal I changed it but still didn't work. I'm compiling this for ESP32 board.

```
#include "RMaker.h"
#include "WiFi.h"
#include "WiFiProv.h"
#include <DHT.h>
#include <SimpleTimer.h>

const char *service_name = "PROV_SmartHome";
const char *pop = "1234";

// define the Chip Id
uint32_t espChipId = 5;

// define the Node Name
char nodeName[] = "ESP32_Smarthome";

// define the Device Names
char deviceName_1[] = "Switch1";
char deviceName_2[] = "Switch2";
char deviceName_3[] = "Switch3";
char deviceName_4[] = "Switch4";

// define the GPIO connected with Relays and switches
static uint8_t RelayPin1 = 23;  //D23
static uint8_t RelayPin2 = 22;  //D22
static uint8_t RelayPin3 = 21;  //D21
static uint8_t RelayPin4 = 19;  //D19

static uint8_t SwitchPin1 = 13;  //D13
static uint8_t SwitchPin2 = 12;  //D12
static uint8_t SwitchPin3 = 14;  //D14
static uint8_t SwitchPin4 = 27;  //D27

static uint8_t wifiLed      = 2;   //D2
static uint8_t gpio_reset   = 0;
static uint8_t DHTPIN       = 18; // D18  pin connected with DHT
static uint8_t LDR_PIN      = 39; // VN  pin connected with LDR

/* Variable for reading pin status*/
// Relay State
bool toggleState_1 = LOW; //Define integer to remember the toggle state for relay 1
bool toggleState_2 = LOW; //Define integer to remember the toggle state for relay 2
bool toggleState_3 = LOW; //Define integer to remember the toggle state for relay 3
bool toggleState_4 = LOW; //Define integer to remember the toggle state for relay 4

// Switch State
bool SwitchState_1 = LOW;
bool SwitchState_2 = LOW;
bool SwitchState_3 = LOW;
bool SwitchState_4 = LOW;

float temperature1 = 0;
float humidity1   = 0;
float ldrVal  = 0;

DHT dht(DHTPIN, DHT11);  //For DHT 11
//DHT dht(DHTPIN, DHT22);  //For DHT 22

SimpleTimer Timer;

//The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
static Switch my_switch1(deviceName_1, &RelayPin1);
static Switch my_switch2(deviceName_2, &RelayPin2);
static Switch my_switch3(deviceName_3, &RelayPin3);
static Switch my_switch4(deviceName_4, &RelayPin4);
static TemperatureSensor temperature("Temperature");
static TemperatureSensor humidity("Humidity");
static TemperatureSensor ldr("LDR");

void sysProvEvent(arduino_event_t *sys_event)
{
  switch (sys_event->event_id) {
    case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32
      Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
      printQR(service_name, pop, "ble");
#else
      Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
      printQR(service_name, pop, "softap");
#endif
      break;
    case ARDUINO_EVENT_WIFI_STA_CONNECTED:
      Serial.printf("\nConnected to Wi-Fi!\n");
      digitalWrite(wifiLed, true);
      break;
  }
}

void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx)
{
  const char *device_name = device->getDeviceName();
  const char *param_name = param->getParamName();

  if (strcmp(device_name, deviceName_1) == 0) {

    Serial.printf("Lightbulb = %s\n", val.val.b ? "true" : "false");

    if (strcmp(param_name, "Power") == 0) {
      Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name);
      toggleState_1 = val.val.b;
      (toggleState_1 == false) ? digitalWrite(RelayPin1, HIGH) : digitalWrite(RelayPin1, LOW);
      param->updateAndReport(val);
    }

  } else if (strcmp(device_name, deviceName_2) == 0) {

    Serial.printf("Switch value = %s\n", val.val.b ? "true" : "false");

    if (strcmp(param_name, "Power") == 0) {
      Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name);
      toggleState_2 = val.val.b;
      (toggleState_2 == false) ? digitalWrite(RelayPin2, HIGH) : digitalWrite(RelayPin2, LOW);
      param->updateAndReport(val);
    }

  } else if (strcmp(device_name, deviceName_3) == 0) {

    Serial.printf("Switch value = %s\n", val.val.b ? "true" : "false");

    if (strcmp(param_name, "Power") == 0) {
      Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name);
      toggleState_3 = val.val.b;
      (toggleState_3 == false) ? digitalWrite(RelayPin3, HIGH) : digitalWrite(RelayPin3, LOW);
      param->updateAndReport(val);
    }

  } else if (strcmp(device_name, deviceName_4) == 0) {

    Serial.printf("Switch value = %s\n", val.val.b ? "true" : "false");

    if (strcmp(param_name, "Power") == 0) {
      Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name);
      toggleState_4 = val.val.b;
      (toggleState_4 == false) ? digitalWrite(RelayPin4, HIGH) : digitalWrite(RelayPin4, LOW);
      param->updateAndReport(val);
    }

  }
}

void readSensor() {

  ldrVal = map(analogRead(LDR_PIN), 400, 4200, 0, 100);
  Serial.print("LDR - "); Serial.println(ldrVal);
  float h = dht.readHumidity();
  float t = dht.readTemperature(); // or dht.readTemperature(true) for Fahrenheit

  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  else {
    humidity1 = h;
    temperature1 = t;
    Serial.print("Temperature - "); Serial.println(t);
    Serial.print("Humidity - "); Serial.println(h);
  }
}

void sendSensor()
{
  readSensor();
  temperature.updateAndReportParam("Temperature", temperature1);
  humidity.updateAndReportParam("Temperature", humidity1);
  ldr.updateAndReportParam("Temperature", ldrVal);
}

void manual_control()
{
  if (digitalRead(SwitchPin1) == LOW && SwitchState_1 == LOW) {
    digitalWrite(RelayPin1, LOW);
    toggleState_1 = 1;
    SwitchState_1 = HIGH;
    my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1);
    Serial.println("Switch-1 on");
  }
  if (digitalRead(SwitchPin1) == HIGH && SwitchState_1 == HIGH) {
    digitalWrite(RelayPin1, HIGH);
    toggleState_1 = 0;
    SwitchState_1 = LOW;
    my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_1);
    Serial.println("Switch-1 off");
  }
  if (digitalRead(SwitchPin2) == LOW && SwitchState_2 == LOW) {
    digitalWrite(RelayPin2, LOW);
    toggleState_2 = 1;
    SwitchState_2 = HIGH;
    my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2);
    Serial.println("Switch-2 on");
  }
  if (digitalRead(SwitchPin2) == HIGH && SwitchState_2 == HIGH) {
    digitalWrite(RelayPin2, HIGH);
    toggleState_2 = 0;
    SwitchState_2 = LOW;
    my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_2);
    Serial.println("Switch-2 off");
  }
  if (digitalRead(SwitchPin3) == LOW && SwitchState_3 == LOW) {
    digitalWrite(RelayPin3, LOW);
    toggleState_3 = 1;
    SwitchState_3 = HIGH;
    my_switch3.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_3);
    Serial.println("Switch-3 on");
  }
  if (digitalRead(SwitchPin3) == HIGH && SwitchState_3 == HIGH) {
    digitalWrite(RelayPin3, HIGH);
    toggleState_3 = 0;
    SwitchState_3 = LOW;
    my_switch3.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_3);
    Serial.println("Switch-3 off");
  }
  if (digitalRead(SwitchPin4) == LOW && SwitchState_4 == LOW) {
    digitalWrite(RelayPin4, LOW);
    toggleState_4 = 1;
    SwitchState_4 = HIGH;
    my_switch4.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_4);
    Serial.println("Switch-4 on");
  }
  if (digitalRead(SwitchPin4) == HIGH && SwitchState_4 == HIGH) {
    digitalWrite(RelayPin4, HIGH);
    toggleState_4 = 0;
    SwitchState_4 = LOW;
    my_switch4.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, toggleState_4);
    Serial.println("Switch-4 off");
  }
}

void setup()
{

  Serial.begin(115200);

  // Set the Relays GPIOs as output mode
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);
  pinMode(RelayPin3, OUTPUT);
  pinMode(RelayPin4, OUTPUT);
  pinMode(wifiLed, OUTPUT);

  // Configure the input GPIOs
  pinMode(SwitchPin1, INPUT_PULLUP);
  pinMode(SwitchPin2, INPUT_PULLUP);
  pinMode(SwitchPin3, INPUT_PULLUP);
  pinMode(SwitchPin4, INPUT_PULLUP);
  pinMode(gpio_reset, INPUT);

  // Write to the GPIOs the default state on booting
  digitalWrite(RelayPin1, !toggleState_1);
  digitalWrite(RelayPin2, !toggleState_2);
  digitalWrite(RelayPin3, !toggleState_3);
  digitalWrite(RelayPin4, !toggleState_4);
  digitalWrite(wifiLed, LOW);
  dht.begin();    // Enabling DHT sensor

  Node my_node;
  my_node = RMaker.initNode(nodeName);

  //Standard switch device
  my_switch1.addCb(write_callback);
  my_switch2.addCb(write_callback);
  my_switch3.addCb(write_callback);
  my_switch4.addCb(write_callback);

  //Add switch device to the node
  my_node.addDevice(my_switch1);
  my_node.addDevice(my_switch2);
  my_node.addDevice(my_switch3);
  my_node.addDevice(my_switch4);
  my_node.addDevice(temperature);
  my_node.addDevice(humidity);
  my_node.addDevice(ldr);

  Timer.setInterval(2000);

  //This is optional
  RMaker.enableOTA(OTA_USING_PARAMS);
  //If you want to enable scheduling, set time zone for your region using setTimeZone().
  //The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html
  // RMaker.setTimeZone("Asia/Shanghai");
  // Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone
  RMaker.enableTZService();
  RMaker.enableSchedule();

  //Service Name
  for (int i = 0; i < 17; i = i + 8) {
    espChipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
  }

  Serial.printf("\nChip ID:  %d Service Name: %s\n", espChipId, service_name);

  Serial.printf("\nStarting ESP-RainMaker\n");
  RMaker.start();

  WiFi.onEvent(sysProvEvent);
#if CONFIG_IDF_TARGET_ESP32
  WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#else
  WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#endif

  my_switch1.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false);
  my_switch2.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false);
  my_switch3.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false);
  my_switch4.updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, false);
}

void loop()
{
  // Read GPIO0 (external button to reset device
  if (digitalRead(gpio_reset) == LOW) { //Push button pressed
    Serial.printf("Reset Button Pressed!\n");
    // Key debounce handling
    delay(100);
    int startTime = millis();
    while (digitalRead(gpio_reset) == LOW) delay(50);
    int endTime = millis();

    if ((endTime - startTime) > 10000) {
      // If key pressed for more than 10secs, reset all
      Serial.printf("Reset to factory.\n");
      RMakerFactoryReset(2);
    } else if ((endTime - startTime) > 3000) {
      Serial.printf("Reset Wi-Fi.\n");
      // If key pressed for more than 3secs, but less than 10, reset Wi-Fi
      RMakerWiFiReset(2);
    }
  }
  delay(100);

  if (WiFi.status() != WL_CONNECTED)
  {
    //Serial.println("WiFi Not Connected");
    digitalWrite(wifiLed, false);
  }
  else
  {
    //Serial.println("WiFi Connected");
    digitalWrite(wifiLed, true);
    if (Timer.isReady()) {
      //Serial.println("Sending Sensor Data");
      sendSensor();
      Timer.reset();      // Reset a second timer
    }
  }
  manual_control();
}

```

ESP32 Board details here :

# Answer
Maybe I've missed something, but the flash area is partitioned between usable app (roughly sketch code) space and usable filesystem space. I don't see any indication in your question that you're using a filesystem at all.

Keeping your current settings except for switching the partition setting to *"Huge APP (3MB No OTA/1MB SPIFFS)"* resulted in:

```
Sketch uses 1790473 bytes (56%) of program storage space. Maximum is 3145728 bytes.
Global variables use 53260 bytes (16%) of dynamic memory, leaving 274420 bytes for local variables. Maximum is 327680 bytes.

```

I'm not even sure "Huge APP" makes the *most* sense. Only that 3MB is larger than 1.2MB and larger than your current 1.8(ish)MB build apparently needs. It says "no-OTA" but you don't seem to be using that either. So, this seems like something you can do irrespective of whatever contributions you can trim from the text segment by tweaking your code.
> 1 votes

# Answer
You are programming for an embedded processor with limited memory. Both program space and random access memory (RAM). Every letter you put in quotes takes up a byte of memory. If you are only over the limit by a little consider abbreviating your text. For example consider changing strings like:

> "Provisioning Started with name"

... to something along the lines of ...

> "Prov name"

If by a lot then consider changing your code. Many times you quote similar text. For example consider changing the following code:

```
// define the Device Names
char deviceName_1[] = "Switch1";
char deviceName_2[] = "Switch2";
char deviceName_3[] = "Switch3";
char deviceName_4[] = "Switch4";
...
//The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
static Switch my_switch1(deviceName_1, &RelayPin1);
static Switch my_switch2(deviceName_2, &RelayPin2);
static Switch my_switch3(deviceName_3, &RelayPin3);
static Switch my_switch4(deviceName_4, &RelayPin4);

```

... to something along the lines of ...

```
//The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
String stringOne = "Switch";
String stringTwo = "1"
static Switch my_switch1(stringOne + stringTwo, &RelayPin1);
stringTwo = "2"
static Switch my_switch2(stringOne + stringTwo, &RelayPin2);
stringTwo = "3"
static Switch my_switch3(stringOne + stringTwo, &RelayPin3);
stringTwo = "4"
static Switch my_switch4(stringOne + stringTwo, &RelayPin4);

```

... the point here is to avoid using up program and random access memory with repeated strings.
> 1 votes

# Answer
You could use enums to replace all the char strings (which take a lot of memory space) into integers behind the scene.

```
enum deviceNames {Switch1, Switch2, Switch3, Switch4};
deviceNames deviceName; //define variable of type deviceNames

```

for comparison you can use:

```
if (deviceName == Switch1); //Switch1 equals 0 for the compiler, Stich2 equals 1 etc etc.

```

Frist however, you should have a look at the functions getDeviceName() and getParamName(). Could you post them? Would need to see if you can make these changes there aswell. Since you are getting the variable device\_name from there, again as a string. Enums would do no good without additional changes to the functions.

\*Also I noticed you still didn't use Serial.print(F()); Read up on storing strings and variables into PROGMEM if you're interested.

\*EDIT: As user Juraj noted in the comments: "the esp32 toolchain uses string literals from flash automatically. the F macro does nothing".

Perhaps you can benefit form newlib nano formatting for printf? I'm not sure as I don't know what difference it makes on your esp32 version. You'll have to check out.
> 1 votes

---
Tags: esp32, error
---


# Question
Title: ESP32-C3 - undefined reference to `esp_ble_gap_start_advertising'
I have a Bluetooth project for an ESP32 devkit and want to compile it for an ESP32-C3. I use the newest ESP32 Arduino core as a component with esp-idf and the following configuration for `PlatformIO`:

```
[platformio]
src_dir = src
default_envs = debug

# Common build environment that is used for each of the tasks
[env]
platform = espressif32
framework = espidf

board = esp32-c3-devkitm-1

# 4 MB module version
board_upload.flash_size = 4MB
board_upload.maximum_size = 4194304
board_build.partitions = partitions.csv

# Settings for serial upload
upload_speed = 921600
upload_port = COM2

# Settings for serial console
monitor_speed = 115200
monitor_port = COM2
monitor_filters = esp32_exception_decoder

# Additional packages
platform_packages =

# Aditional build scripts for all environments to run before (`pre`) and after (`post`) the main build script
extra_scripts =

# Common build flags for all environments
build_flags =

lib_deps =
    bblanchon/ArduinoJson@^6.18.0

[env:debug]
build_type = debug

build_flags =
    ${env.build_flags}
    -D DEBUG
    -D APP_VERSION_POST='debug'

lib_deps =
    ${env.lib_deps}

extra_scripts =
    ${env.extra_scripts}

[env:release]
build_type = debug

build_flags =
    ${env.build_flags}
    -D RELEASE

lib_deps =
    ${env.lib_deps}

extra_scripts =
    ${env.extra_scripts}

```

I use the following toolchain:

```
 - framework-espidf @ 3.40401.0 (4.4.1)
 - tool-cmake @ 3.16.4
 - tool-esptoolpy @ 1.30300.0 (3.3.0)
 - tool-idf @ 1.0.1
 - tool-mconf @ 1.4060000.20190628 (406.0.0)
 - tool-ninja @ 1.9.0
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch3

```

But I got the following error during the linking:

```
.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld.exe: .pio\build\debug\esp-idf\arduino-esp32\libarduino-esp32.a(BLEAdvertising.o): in function `BLEAdvertising::start()':
components/arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp:247: undefined reference to `esp_ble_gap_start_advertising'
.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld.exe: components/arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp:214: undefined reference to `esp_ble_gap_config_adv_data'
.platformio/packages/toolchain-riscv32-esp/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld.exe: components/arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp:225: undefined reference to `esp_ble_gap_config_adv_data'

```

**Update 1**

A verbose build outputs the following command before the error appears:

```
riscv32-esp-elf-g++ -o .pio\build\debug\firmware.elf -T memory.ld -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u pthread_include_pthread_rwlock_impl -u include_esp_phy_override -u start_app -T sections.ld
-u __ubsan_include -T esp32c3.rom.ld -T esp32c3.rom.api.ld -T esp32c3.rom.libgcc.ld -T esp32c3.rom.newlib.ld -T esp32c3.rom.version.ld -T esp32c3.rom.newlib-time.ld -T esp32c3.rom.eco3.ld -u __assert_func -u vfs_include_syscalls_impl -T esp32c3.peripherals.ld -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -u newlib_include_assert_impl -u __cxa_guard_dummy -u __cxx_fatal_exception --specs=nosys.specs -Wl,--Map=C:/Projects/firmware-loader/.pio/build/debug/Firmware-Loader.map -Wl,--cref -Wl,--gc-sections -Wl,--undefined=uxTopUsedPriority -Wl,--wrap=_Unwind_Backtrace -Wl,--wrap=_Unwind_DeleteException -Wl,--wrap=_Unwind_FindEnclosingFunction -Wl,--wrap=_Unwind_Find_FDE
-Wl,--wrap=_Unwind_ForcedUnwind -Wl,--wrap=_Unwind_GetCFA -Wl,--wrap=_Unwind_GetDataRelBase -Wl,--wrap=_Unwind_GetGR -Wl,--wrap=_Unwind_GetIP -Wl,--wrap=_Unwind_GetIPInfo -Wl,--wrap=_Unwind_GetLanguageSpecificData -Wl,--wrap=_Unwind_GetRegionStart -Wl,--wrap=_Unwind_GetTextRelBase -Wl,--wrap=_Unwind_RaiseException -Wl,--wrap=_Unwind_Resume -Wl,--wrap=_Unwind_Resume_or_Rethrow -Wl,--wrap=_Unwind_SetEnableExceptionFdeSorting -Wl,--wrap=_Unwind_SetGR -Wl,--wrap=_Unwind_SetIP -Wl,--wrap=__cxa_call_unexpected -Wl,--wrap=__deregister_frame_info -Wl,--wrap=__deregister_frame_info_bases -Wl,--wrap=__gxx_personality_v0 -Wl,--wrap=__register_frame -Wl,--wrap=__register_frame_info -Wl,--wrap=__register_frame_info_bases -Wl,--wrap=__register_frame_info_table -Wl,--wrap=__register_frame_info_table_bases -Wl,--wrap=__register_frame_table -fno-lto -fno-rtti -march=rv32imc -nostartfiles -Og -g2 -ggdb2 .pio\build\debug\src\Devices\JERRY\jerry.o .pio\build\debug\src\Devices\Memory\memory.o .pio\build\debug\src\Devices\TOM\I2CM.o .pio\build\debug\src\Devices\TOM\tom.o .pio\build\debug\src\Loader\loader.o .pio\build\debug\src\Version\version.o .pio\build\debug\src\main.o -L.pio\build\debug -LC:\.platformio\packages\framework-espidf\components\bt\controller\lib_esp32c3_family\esp32c3 -LC:\.platformio\packages\framework-espidf\components\esp_wifi\lib\esp32c3 -LC:\.platformio\packages\framework-espidf\components\esp_phy\lib\esp32c3 -L.pio\build\debug\esp-idf\esp_system\ld -LC:\.platformio\packages\framework-espidf\components\esp_rom\esp32c3\ld -LC:\.platformio\packages\framework-espidf\components\esp_wifi\lib\esp32c3 -LC:\.platformio\packages\framework-espidf\components\soc\esp32c3\ld -Wl,--start-group .pio\build\debug\esp-idf\esp_ringbuf\libesp_ringbuf.a .pio\build\debug\esp-idf\asio\libasio.a .pio\build\debug\esp-idf\protobuf-c\libprotobuf-c.a .pio\build\debug\esp-idf\esp_lcd\libesp_lcd.a .pio\build\debug\esp-idf\mdns\libmdns.a .pio\build\debug\esp-idf\protocomm\libprotocomm.a .pio\build\debug\esp-idf\cbor\libcbor.a .pio\build\debug\esp-idf\cmock\libcmock.a .pio\build\debug\esp-idf\unity\libunity.a .pio\build\debug\esp-idf\bt\libbt.a .pio\build\debug\esp-idf\coap\libcoap.a .pio\build\debug\esp-idf\esp_adc_cal\libesp_adc_cal.a .pio\build\debug\esp-idf\esp_hid\libesp_hid.a .pio\build\debug\esp-idf\wear_levelling\libwear_levelling.a .pio\build\debug\esp-idf\esp_local_ctrl\libesp_local_ctrl.a .pio\build\debug\esp-idf\esp_websocket_client\libesp_websocket_client.a .pio\build\debug\esp-idf\expat\libexpat.a .pio\build\debug\esp-idf\fatfs\libfatfs.a .pio\build\debug\esp-idf\freemodbus\libfreemodbus.a .pio\build\debug\esp-idf\spiffs\libspiffs.a .pio\build\debug\esp-idf\openssl\libopenssl.a .pio\build\debug\esp-idf\libsodium\liblibsodium.a .pio\build\debug\esp-idf\jsmn\libjsmn.a .pio\build\debug\esp-idf\mqtt\libmqtt.a .pio\build\debug\esp-idf\json\libjson.a .pio\build\debug\esp-idf\wifi_provisioning\libwifi_provisioning.a .pio\build\debug\esp-idf\arduino-esp32\libarduino-esp32.a .pio\build\debug\esp-idf\RAK3172\libRAK3172.a .pio\build\debug\esp-idf\app_trace\libapp_trace.a .pio\build\debug\esp-idf\app_update\libapp_update.a .pio\build\debug\esp-idf\bootloader_support\libbootloader_support.a .pio\build\debug\esp-idf\console\libconsole.a .pio\build\debug\esp-idf\cxx\libcxx.a .pio\build\debug\esp-idf\driver\libdriver.a .pio\build\debug\esp-idf\efuse\libefuse.a .pio\build\debug\esp-idf\esp-tls\libesp-tls.a .pio\build\debug\esp-idf\esp_common\libesp_common.a .pio\build\debug\esp-idf\esp_event\libesp_event.a .pio\build\debug\esp-idf\esp_gdbstub\libesp_gdbstub.a .pio\build\debug\esp-idf\esp_http_client\libesp_http_client.a .pio\build\debug\esp-idf\esp_http_server\libesp_http_server.a .pio\build\debug\esp-idf\esp_https_ota\libesp_https_ota.a .pio\build\debug\esp-idf\esp_hw_support\libesp_hw_support.a .pio\build\debug\esp-idf\esp_ipc\libesp_ipc.a .pio\build\debug\esp-idf\esp_netif\libesp_netif.a .pio\build\debug\esp-idf\esp_phy\libesp_phy.a .pio\build\debug\esp-idf\esp_pm\libesp_pm.a .pio\build\debug\esp-idf\esp_rom\libesp_rom.a .pio\build\debug\esp-idf\esp_serial_slave_link\libesp_serial_slave_link.a .pio\build\debug\esp-idf\esp_system\libesp_system.a .pio\build\debug\esp-idf\esp_timer\libesp_timer.a .pio\build\debug\esp-idf\esp_wifi\libesp_wifi.a .pio\build\debug\esp-idf\espcoredump\libespcoredump.a .pio\build\debug\esp-idf\freertos\libfreertos.a .pio\build\debug\esp-idf\hal\libhal.a .pio\build\debug\esp-idf\heap\libheap.a .pio\build\debug\esp-idf\log\liblog.a .pio\build\debug\esp-idf\lwip\liblwip.a .pio\build\debug\esp-idf\mbedtls\libmbedtls.a .pio\build\debug\esp-idf\newlib\libnewlib.a .pio\build\debug\esp-idf\nghttp\libnghttp.a .pio\build\debug\esp-idf\nvs_flash\libnvs_flash.a .pio\build\debug\esp-idf\pthread\libpthread.a .pio\build\debug\esp-idf\riscv\libriscv.a .pio\build\debug\esp-idf\sdmmc\libsdmmc.a .pio\build\debug\esp-idf\soc\libsoc.a .pio\build\debug\esp-idf\spi_flash\libspi_flash.a .pio\build\debug\esp-idf\tcp_transport\libtcp_transport.a .pio\build\debug\esp-idf\tcpip_adapter\libtcpip_adapter.a .pio\build\debug\esp-idf\vfs\libvfs.a .pio\build\debug\esp-idf\wpa_supplicant\libwpa_supplicant.a .pio\build\debug\esp-idf\mbedtls\mbedtls\library\libmbedcrypto.a .pio\build\debug\esp-idf\mbedtls\mbedtls\library\libmbedtls.a .pio\build\debug\esp-idf\mbedtls\mbedtls\library\libmbedx509.a -lbtdm_app -lcoexist -lcore -lespnow -lmesh -lnet80211 -lpp -lsmartconfig -lwapi -lphy -lbtbb -lgcov -lc -lm -lstdc++ -lgcc -Wl,--end-group

```

**Update 2**

It looks like `libbt.a` isn´t linked. May this cause this issue? How can I fix it or where do I find the required part in the build system of pio?

# Answer
> -1 votes
I have had a very similar issue just now. In short, the solution was to rename library file from .c to .cpp

Extended explanation. My platformio.ini:

```
[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino

```

I am using third-party library which I build from source. This library is provided by two "lib\_name.c" and "lib\_name.h" files, which I have put into a lib/lib\_name/ directory according to Platformio README file.

It was failing during linkage until I renamed "lib\_name.c" to "lib\_name.cpp", header file remained untouched.

---
Tags: esp32, bluetooth, platformio
---


# Question
Title: Is there a way to strip a library from all unused parts and defines, automatically?
Say you want to investigate part of the code you use from a rather large library, but it's buried between all kinds of #defines and classes etc, that you're never gonna use in your code. Is there a tool for stripping those unused/unnecessary parts away (like the (pre-)compiler), without converting it to machine language? That would make it much easier to see what happens in the code, and what code does what. Would be a great learning tool imho.

# Answer
> 1 votes
The compiler is called in optimization mode (it is even possible to specify how aggressive it will optimize). It will remove all variables and functions, that are not used in your code. Also it can replace variables that never change with literals to make the code smaller. That's already what is happening and you don't need to worry about that.

About the `#define`s: Everything with a # at the start is interpreted by the preprocessor. That means, that these things are done even before the compiler gets to see the code. Lets say you define a pin number via `#define pin 6`, then the preprocessor will replace any mentioning of `pin` with `6` in the code, before it hands the result over to the compiler. The compiler will never see any defines.

I'm not able to tell you, how the compiler optimizes the code. That's probably very complex. Though the avr-gcc compiler is opensource, so if you really want to learn what it does, you can always analyze its source code.

---

> I thought if a compiler can be smart enough to strip all unused variables and functions away and convert what's left in machine language

While I don't know much about how the optimization works, I don't think that it happens in that order. I find it very unlikely, that the compiler would optimize the C++ code. Though it might do that at the assembler level (since avr-gcc first converts the C++ code to assembler and then compiles to machine code). Searching in the assembler code equivalent of the C++ code isn't a real option either.

You are probably stuck with a full text search function of a program of your choice. Most OSs will also provide that function out of the box. I know, that you can search all files of a directory for a term from the Windows explorer. On systems like Ubuntu/Debian/CentOS and similar you can use the `grep` command in recursive mode to search for a term. On Mac you can probably also use `grep`.

# Answer
> 0 votes
The compiler doesn't quite work like that. It compiles each individual .cpp file into an object file (the .ino file becomes a .cpp file after a bit of pre-processing). I have an answer about the exact process the compiler uses there.

The libraries are also collections of .cpp files which also get turned into object files.

Optimization of unused variables would occur at that point. In other words, the compiler can optimize one compilation unit (one source file) because it can see what parts are used and what are not.

Then the linking phase commences which joins all the object files together, looking for places where a function in a library is called. So for example if you call `Serial.begin()` somewhere, then the linker will try to find an object file which implements that.

The linker is smart enough to not include code that is not required, so for example, if you never called `Serial.begin ()` then it would not copy in that part of the Serial library.

In the process of doing that it resolves "jumps" and subroutine calls, so that your calls to library functions end up pointing to the place in the program memory where it has put them.

Because this is done at a late stage (after the source has been compiled) you don't really ever have a copy of the source "as linked".

However what you **can** do is disassemble the object file which gives you the machine code that has actually made it to the final executable. Done properly it will also include the lines of source (C++) code that generated each batch of assembler lines.

If you turn on "verbose compiling" you should see near the end of the compilation output an "ELF" file, and you can then send that to avr-objdump to turn it back into assembler:

```
avr-objdump -S xxx.elf

```

It's not great, if you aren't used to assembler, but it gives you a clue as to what made it into the executable file, and where. For a single line of C++ code you might see something like this:

```
    reg = portModeRegister(port);
 310:   90 e0           ldi r25, 0x00   ; 0
 312:   88 0f           add r24, r24
 314:   99 1f           adc r25, r25
 316:   fc 01           movw    r30, r24
 318:   e8 59           subi    r30, 0x98   ; 152
 31a:   ff 4f           sbci    r31, 0xFF   ; 255
 31c:   a5 91           lpm r26, Z+
 31e:   b4 91           lpm r27, Z+

```

# Answer
> 0 votes
The -E command for gcc generates preprocessed C and CPP source.

I didn't find a way to integrate it into the Arduino build process. Only thing I could do was edit platform.txt and change the compile command so it generates the preprocessed cpp of a compilation unit instated of .o files. Then linking failed of course.

The produced cpp was I think less readable than the original because it contained many generated comments and original line number instructions.

the changed cpp recipe in platform txt:

```
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} -E {includes} "{source_file}" -o "{object_file}.cpp"

```

I added the -E flag and .cpp file extension for the -o option value

You can see the result in the temporary build folder. You can get the location of that folder from the IDE console when you build the sketch with Verify. (you may need to turn on the verbose compile in Preferences).

---
Tags: arduino-uno, arduino-nano, esp32, library, ide
---


# Question
Title: Why doesn't my mcp23s17 interrupts work anymore?
I'm using a teensy 4.0 with two mcp23s17 gpio expanders where #1 has 16 buttons wired to it, and #2 has 4 buttons and six rotary encoders. To run everything I'm using majenkos mcp23s17 library. Recently, I refactored my code, and suddenly I'm unable to setup the mcp's to have interrupts working properly.

I've tried to narrow the problem down by commenting out code, and it appears that as soon as I call `gpioExpander.enableInterrupt(pin, CHANGE);` in `gpioSetup()` the problem occurs. In detail, `loop()` runs fine, but as soon as I press a button, the teensy hangs. Also, to restore the teensy I have to upload the code with the call to `gpioExpander.enableInterrupt(pin, CHANGE);` commented out in order to have the teensy up and running again.

I've been staring myself blind on the code, and I suspect I'm missing something obvious. Your help is appreciated.

```
//main.cpp
#include <Arduino.h>

#include "GPIO.h"
#include "MCP23S17.h"

extern MCP23S17 gpioExpander1;
extern MCP23S17 gpioExpander2;

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

void loop() {
    GPIOtest(gpioExpander1, gpioExpander2);
}

//GPIO.h
#ifndef GPIO_H
#define GPIO_H

#include <Arduino.h>

#include "MCP23S17.h"

constexpr uint8_t address = 0;
constexpr uint8_t interruptPin1 = 8;
constexpr uint8_t interruptPin2 = 22;
constexpr uint8_t chipSelectPin1 = 7;
constexpr uint8_t chipSelectPin2 = 21;

void setGPIO1Pins(MCP23S17 &gpioExpander);
void setGPIO2Pins(MCP23S17 &gpioExpander);
void gpioSetup();
void GPIO1interrupt();
void GPIO2interrupt();
void GPIOtest(MCP23S17 &gpioExpander1, MCP23S17 &gpioExpander2);

#endif

//GPIO.cpp
#include "GPIO.h"

#include <Arduino.h>
#include <MCP23S17.h>

volatile bool interruptFlag1 = false;
volatile bool interruptFlag2 = false;

MCP23S17 gpioExpander1(&SPI, chipSelectPin1, address);
MCP23S17 gpioExpander2(&SPI, chipSelectPin2, address);

//  Set all Port Expander pins to desired mode INPUT_PULLUP
//  Set all Port Expander input pins interrupts
void setGPIOPins(MCP23S17& gpioExpander) {
    for (uint8_t pin = 0; pin <= 15; ++pin) {
        gpioExpander.pinMode(pin, INPUT_PULLUP);
        gpioExpander.enableInterrupt(pin, CHANGE);
    }

    // set Port Expander Interrupt configuratons
    gpioExpander.setMirror(true);
    gpioExpander.setInterruptOD(false);
    gpioExpander.setInterruptLevel(LOW);
}

void gpioSetup() {
    gpioExpander1.begin();
    gpioExpander2.begin();
    digitalWrite(chipSelectPin1, HIGH);
    digitalWrite(chipSelectPin2, HIGH);

    pinMode(interruptPin1, INPUT_PULLUP);
    pinMode(interruptPin2, INPUT_PULLUP);

    attachInterrupt(digitalPinToInterrupt(interruptPin1), GPIO1interrupt, LOW);
    attachInterrupt(digitalPinToInterrupt(interruptPin2), GPIO2interrupt, LOW);

    setGPIOPins(gpioExpander1);
    setGPIOPins(gpioExpander2);

    // GPIO registers are read to be cleared
    gpioExpander1.getInterruptValue();
    gpioExpander2.getInterruptValue();
}

void GPIO1interrupt() {
    interruptFlag1 = true;
}

void GPIO2interrupt() {
    interruptFlag2 = true;
}

void GPIOtest(MCP23S17& gpioExpander1, MCP23S17& gpioExpander2) {
    if (interruptFlag1 == true) {
        Serial.println("interrupt 1 = true");
        interruptFlag1 = false;
    }

    if (interruptFlag2 == true) {
        Serial.println("interrupt 2 = true");
        interruptFlag2 = false;
    }
}

```

# Answer
> 2 votes
### Short version, try:

```
attachInterrupt(digitalPinToInterrupt(interruptPin1), GPIO1interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin2), GPIO2interrupt, FALLING);

```

**`FALLING`** (instead of `LOW`) being the active ingredient. I'm assuming `FALLING` is supported. If not you can try synthesizing this with `CHANGE` and reading the port to see whether or not it is currently `LOW`.

And then call `.getInterruptValue();` to clear the MCP23S17's interrupt condition where you clear the global volatile flags:

```
void GPIOtest(MCP23S17& gpioExpander1, MCP23S17& gpioExpander2) {
    if (interruptFlag1 == true) {
        Serial.println("interrupt 1 = true");
        interruptFlag1 = false;
        gpioExpander1.getInterruptValue(); // <------
    }

    if (interruptFlag2 == true) {
        Serial.println("interrupt 2 = true");
        interruptFlag2 = false;
        gpioExpander2.getInterruptValue(); // <------
    }
}

```

---

### Long version:

This a guess, since I'm unable to test. But this is maybe not a bad guess:

You have configured the MCP23S17 device to **drive** active **low** on/during an MCP23S17 interrupt condition:

```
    gpioExpander.setMirror(true);
    gpioExpander.setInterruptOD(false);
    gpioExpander.setInterruptLevel(LOW);

```

So, were an MCP23S17 interrupt to occur (`gpioExpander.enableInterrupt(pin, CHANGE);`), the interrupt flag within the MCP23S17 would be set, and INTA/INTB of the MCP23S17 would become active low.

The MCP23S17 datasheet says:

> The interrupt condition is cleared after the LSb of the data is clocked out during a read command of GPIO or INTCAP

You have configured your interrupt pins for interrupting on a LOW **level** interrupt:

```
attachInterrupt(digitalPinToInterrupt(interruptPin1), GPIO1interrupt, LOW);

```

So, if I understand this correctly, your Teensy continually re-enter the `GPIO#interrupt()` functions until something read causes the interrupt condition to be cleared. You are not clearing the interrupt condition **inside** the ISR, you're setting a flag to do that later in the main line of execution, which is reasonable by itself. One thing I can guess is that had you'd previous had something to clear the interrupt condition **inside** the interrupt and it is now outside the interrupt, namely your call to `.getInterruptValue()`, which reads the INTCAP register mentioned above. Or perhaps you'd be using one of the functions that reads a pin/port that would have cleared the interrupt condition. Clearing the global variable alone will not clear the interrupt condition, and so you're going to go right back into ISR which will reassign the global variable.

An AVR will execute a single instruction outside of the ISR before reentering the ISR. So the effect of remaining in the interrupt condition is to make your code slow, potentially **very** slow. I don't know off the top of my head what the Teensy 4.x core will do in this case. Either way, it *would* lock up or possibly *look* locked up.

*If* you were reading/getting-interrupt-value inside the ISR it would have cleared it and so it would not re-entered the ISR repeatedly. Or rather, it wouldn't do that in definitely (or just for long). *It possible that the Teensy is so much faster that it might re-enter a few times until the MCP23S17 got around to acknowledging that the interrupt condition had be cleared. I'm not advocating for this so, so I'll leave it at that.*

I believe ultimately what you want is to set a `FALLING` edge interrupt:

```
attachInterrupt(digitalPinToInterrupt(interruptPin1), GPIO1interrupt, FALLING);

```

Anyway, with `FALLING` the initial falling edge of the INTA/INTB line sets the interrupt condition in the Teensy (not MCP23S17) but it is cleared when your ISR executes. So you will not keep re-entering the ISR. So your ISR will enter *once* to set the global `volatile` flag. Later when you pick up on the set value of your global `volatile` flag(s), you need to call `.getInterruptValue()` (or otherwise read a pin) to clear the interrupt condition in your MCP23S17 (not Teensy) which will de-assert/raise INTA/INTB, at which point the ISR in the Teensy is ready for to get trigger by another falling edge of INTA/INTB.

It's also probably possible to do this with a `LOW`-level interrupt, but you'd have keep un-configuring them in the ISR and re-configuring them after you clear the MCP23S17's condition. Not sure that would be recommended. But, I think it's possible.

---
Tags: interrupt, pins
---


# Question
Title: How to count steps of a stepper motor with AccelStepper?
I want to turn on my motor and count how many total rounds it has until my limit switch is switched on. After that, I want to count rounds counterclockwise until another limit switch is pushed. For this, I'm using AccelStepper and ezButton lib.

Here is my code:

```
      if ((limitSwitch_XV.getState() == LOW) && (limitSwitch_XE.getState() == LOW) && rightDirectionX) {
        while (1) {
          stepper1.step(-1);
          stageSizeX++;
        }
      }

```

But here I've got an error which says that I can't use `int` in `step()`: `'virtual void AccelStepper::step(long int)' is protected within this context stepper1.step(1);`

So how can I count the steps and go step by step to the given direction until I reach the limit switch with AccelStepper?

# Answer
> 0 votes
You get that error, because the `step()` method is protected in the AccelStepper class. It is not meant for calling by the user. AccelStepper instead wants you to state, what kind of movement you want (moving a specific distance/to a specific point/with a specific speed) and then frequently call the `AccelStepper.run()` method (or `AccelStepper.runSpeed()`), which will then execute the steps, when it is time to do so based on your planned movement.

---

If you want to solve your problem you have basically two ways to do this:

* With AccelStepper: Set the stepper to run at a specific speed in the correct direction, then in a loop calling `stepper1.runSpped()` and testing your limitswitch with `digitalRead()`. So something along the lines of:

```
  stepper1.setCurrentPosition(0);
  stepper1.setSpeed(20); // Change speed according to your needs, negative values let the motor rotate in the other direction
  while(limitSwitch_XV.getState() == HIGH){ // Assuming, that limit switch is not pressed when HIGH
      stepper1.runSpeed();
  }
  int revolutions = stepper1.currentPosition() / steps_per_revolution;

```
* or without AccelStepper: Depending on your stepper driver you can use a less sophisticated stepper library (like Arduinos `Stepper` library) or just control the stepper directly with `digitalWrite()` calls (to the Dir pin and to the Pulse pin). In that case you can do each step yourself, after each checking for the limit switch with `digitalRead()`. Something along the lines (I assume a stepper driver with dir pin and pulse pin, not one with multiple phase pins):

```
  digitalWrite(dir_pin, direction); // provide HIGH or LOW here depending on wanted direction
  int pos = 0;
  while(limitSwitch_XV.getState() == HIGH){
      digitalWrite(pulse_pin, HIGH);
      delayMicroseconds(10);
      digitalWrite(pulse_pin, LOW);
      pos++;
      delayMicroseconds(50); // Change this value according to the wanted speed
  }
  int revolutions = pos / steps_per_revolution;

```

Note, that both code snippets are totally untested and you need to build the surrounding code yourself. They only highlight the principle.

---
Tags: button, stepper
---


# Question
Title: MFRC522 board not detected. Red LED lighting
Mega 2560.

I can't get the RFID board detected. The code is as below, and outputs `Didn't find MFRC522 board.`. I also tested some other library and test code with success.

I triple checked the wires (3,3V pin, GND, and PWM pin 8 and 9).

I have some questions:

1. All tutorials shows that MOSI, MISO, SCK needs to be hooked up to digital pin 50, 51, 52. But I don't understand why these matter, because they are not referenced in any code I've found? Are they really necessary? And if so, does it have to be 50,51,52? Can't it be any other digital pin?
2. I accidentally connected it to 5V at first, for maybe 1 minute. Could it be burnt? The LED still lights RED when connected with power.
3. If the problem was the (correct) library was not loaded, wouldn't I get a compile error?

I'm running this code:

```
    #include <MFRC522.h>
    #include <SPI.h>

    #define SAD 9
    #define RST 8

    MFRC522 nfc(SAD, RST);

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

      Serial.println("Looking for MFRC522.");
      nfc.begin();

      uint8_t version = nfc.getFirmwareVersion();
      if (! version) {
        Serial.print("Didn't find MFRC522 board.");
        while(1); //halt
      }

      Serial.print("Found chip MFRC522 ");
      Serial.print("Firmware ver. 0x");
      Serial.print(version, HEX);
      Serial.println(".");

      if (nfc.digitalSelfTestPass()) {
          Serial.print("Digital self test by MFRC522 passed.");
      } else {
          Serial.print("Digital self test by MFRC522 failed.");
      }
    }

    void loop() {

    }

```

# Answer
Welcome, hopefully we can help you. You do not have to connect MOSI, MISO, SCK, CS if you do not want to however without them connected properly it will not work. Note you did not mention the CS pin, that is also needed as that is what tells the MFRC522 it has been selected. Those pins are what is used to communicate with the device. The pins may be different for different boards but you need to check the data sheet for that. The numbers appear correct for the Mega.

The LED tells you that there is power there, it in no way tells you if the board is good. Did you fry it, probably probably as the MFRC522 is a 3V3 device but that is not a given as I do not know what pin you connected the 5V to. More than a few nanoseconds on a voltage higher than rated tends to fry things, but you could be lucky I have no way of knowing. The Mega is 5V so that would probably be OK.

You ask: "If the problem was the (correct) library was not loaded, wouldn't I get a compile error?", again no not necessarily. The compiler does not know your design or what you are connecting to. If the library happens to have functions etc appropriately named it will compile with errors but the odds are very slim your code will work.
> 1 votes

---
Tags: arduino-mega, rfid
---


# Question
Title: Voltage reading problem in Arduino mega based 10 cannel battery capacity tester
I want to make a 10 channels Arduino mega-based battery capacity tester using 4.7 ohms 10w resistors controlling them with IRFZ44n MOSFETs with respected digital pins. An 8.4V battery powers the Arduino (do not consider the buck converter in the picture). I am debugging my project step by step. When I read voltages of individual batteries by corresponding analog pins without turning On 'MOSFET-Gate pins' then Arduino measures the voltages correctly but when I turn on the gate pins then Arduino measures voltage incorrectly. Meaning if I connect a battery with an analog pin and a multimeter at the same time and the value is pretty much same. Like 3.70 volt for the multimeter and 3.72 for analog pin but when I turn On the gatepin of the MOSFET then Arduino value is like 3.07V and Multimeter value is 3.48V. Thanks in advance.

Here is the Circuit Diagram of my project:

Simple version to understand:

Code:

```
long readVcc() {
   // Read 1.1V reference against AVcc
   // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
   ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
   ADMUX = _BV(MUX5) | _BV(MUX0) ;
#else
   ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
   ADCSRB &= ~_BV(MUX5);
   delay(2); // Wait for Vref to settle
   ADCSRA |= _BV(ADSC); // Start conversion
   while (bit_is_set(ADCSRA,ADSC)); // measuring

   uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
   uint8_t high = ADCH; // unlocks both

   long result = (high<<8) | low;

   result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000   //1126400L internalRefVolt(1.1) * 1023 * 1000; code can more precse by calculating internalRefVolt(1.1)
   return result; // Vcc in millivolts
}

void setup() {
   Serial.begin(115200);
   delay(3000);
   pinMode(22,OUTPUT);//***Mosfet Gate Pins********
   pinMode(23,OUTPUT);
   pinMode(24,OUTPUT);
   pinMode(25,OUTPUT);
   pinMode(26,OUTPUT);
   pinMode(27,OUTPUT);
   pinMode(28,OUTPUT);
   pinMode(29,OUTPUT);
   pinMode(30,OUTPUT);
   pinMode(31,OUTPUT);

   digitalWrite(22,LOW);//***Initially low the Mosfet Gate Pins********
   digitalWrite(23,LOW);
   digitalWrite(24,LOW);
   digitalWrite(25,LOW);
   digitalWrite(26,LOW);
   digitalWrite(27,LOW);
   digitalWrite(28,LOW);
   digitalWrite(29,LOW);
   digitalWrite(30,LOW);
   digitalWrite(31,LOW);
}

/**********************************Void Loop******************************************************/
void loop() {
   float voltRef = readVcc() / 1000.0;

   digitalWrite(22,HIGH);//*** High the Mosfet Gate Pins********
   digitalWrite(23,HIGH);
   digitalWrite(24,HIGH);
   digitalWrite(25,HIGH);
   digitalWrite(26,HIGH);
   digitalWrite(27,HIGH);
   digitalWrite(28,HIGH);
   digitalWrite(29,HIGH);
   digitalWrite(30,HIGH);
   digitalWrite(31,HIGH);

   float volt0 = analogRead(A0)*(voltRef/1024);
   delay(10);
   volt0 = analogRead(A0)*(voltRef/1024);
   /* if(volt0>3.0){
      digitalWrite(22,HIGH); // High = Mosfet ON
      digitalWrite(36,HIGH); // High = LED Turn OFF

      }*/

   float volt1 = analogRead(A1)*(voltRef/1024);
   delay(10);
   volt1 = analogRead(A1)*(voltRef/1024);

   float volt2 = analogRead(A2)*(voltRef/1024);
   delay(10);
   volt2 = analogRead(A2)*(voltRef/1024);

   float volt3 = analogRead(A3)*(voltRef/1024);
   delay(10);
   volt3 = analogRead(A3)*(voltRef/1024);

   float volt4 = analogRead(A4)*(voltRef/1024);
   delay(10);
   volt4 = analogRead(A4)*(voltRef/1024);

   float volt5 = analogRead(A5)*(voltRef/1024);
   delay(10);
   volt5 = analogRead(A5)*(voltRef/1024);

   float volt6 = analogRead(A6)*(voltRef/1024);
   delay(10);
   volt6 = analogRead(A6)*(voltRef/1024);

   float volt7 = analogRead(A7)*(voltRef/1024);
   delay(10);
   volt7 = analogRead(A7)*(voltRef/1024);

   float volt8 = analogRead(A8)*(voltRef/1024);
   delay(10);
   volt8 = analogRead(A8)*(voltRef/1024);

   float volt9 = analogRead(A9)*(4.95/1024);
   delay(10);
   volt9 = analogRead(A9)*(4.95/1024);

   //*****************************************************************************
   Serial.print("B0= ");
   Serial.println(volt0);

   Serial.print("B1= ");
   Serial.println(volt1);

   Serial.print("B2= ");
   Serial.println(volt2);

   Serial.print("B3= ");
   Serial.println(volt3);

   Serial.print("B4= ");
   Serial.println(volt4);

   Serial.print("B5= ");
   Serial.println(volt5);

   Serial.print("B6= ");
   Serial.println(volt6);

   Serial.print("B7= ");
   Serial.println(volt7);

   Serial.print("B8= ");
   Serial.println(volt8);

   Serial.print("B9= ");
   Serial.println(volt9);

   Serial.println("");
   Serial.println("==========================");
   delay(500);
}

```

# Answer
> 0 votes
The main problem was the battery holder default wire, those wires were have high resistance. After changing those wire the problem was solved. Thank you everyone

# Answer
> 2 votes
Electric wires have resistance. Most of the time this resistance can be ignored, but this is not always the case. Specifically, if the wire is carrying a large amount of current, the voltage drop across it can be significant.

Consider this circuit:

simulate this circuit – Schematic created using CircuitLab

The red wires carry a high current, and experience a significant voltage drop. Wires in black carry almost no current, and are equi-potential. Both voltmeters on the left will measure the same voltage, which is affected by the voltage drops along AB and along DE. The voltmeter on the right measures a lower voltage, because it is also affected by the drops along BC and EF.

In your experiment the problem is compounded by the fact that the ground wire is carrying the current from *all* the batteries. It is therefore responsible of most of the voltage drop you experience.

The takeaway is that you have to make sure the junction points between the current carrying wires and the measurement wires (points B and E for the voltmeters on the left) are as close as possible to the battery. Otherwise your measurement will be biased.

---
Tags: arduino-mega, multiplexer
---


title: Can i use SCL, SDA pin for I2C

text:
# Question
Title: Can i use SCL, SDA pin for I2C
I read this article. In the article, it uses A4 and A5 for I2C. But can I just use SCL and SDA pin directly in the Arduino UNO R3? And do I need a put-up resistor for SCL and SDA pin?

# Answer
Pins A4/A5 and the SCL/SDA pins are *the exact same pins* on the Arduino UNO R3. Not just "they perform the same function", but they are physically the same pins. It is one solid piece of metal from one pin to the other.

You don't *need* pullup resistors on the I2C pins because the `Wire` library turns on the internal pullups by default. However those internal pullups are about a tenth of the strength that I2C pullups *should* be, so I would recommend that you *do* add pullups, certainly for anything more than a couple of inches of wire.
> 2 votes

---
Tags: arduino-uno
---


# Question
Title: On Linux Min21, unable to access tools/port (grayed out)
I have dual boot laptop, Windows 11 & Linux Mint 21 (default boot). when running Arduino IDE 1.8.19 using Linux the port not accessible \[from tools/port\], but if I boot as windows, I can access the port from the Arduino IDE.

Other applications running in Linux can access the USB drive without issue (eg FreeCAD, PrusaSlicer). Arduino IDE is the only app so far with this USB issue.

"dialout" is in my list of groups

Arduino IDE was installed using apt

If I run lsusb when the nano is connected, i see the following extra entry

```
Bus 003 Device 009: ID 1a86:7523 QinHeng Electronics CH340 serial converter

```

On another post it suggested running ls -l /dev/ttyUSB\* and ls -l /dev/ttyACM\*. For both I get the response "No such file or directory". The following files starting with tty\* are in the /dev directory

```
tty    tty11  tty15  tty19  tty22  tty26  tty3   tty33  tty37  tty40  tty44  tty48  tty51  tty55  tty59  tty62  tty9       ttyS10  ttyS14  ttyS18  ttyS21  ttyS25  ttyS29  ttyS4  ttyS8
tty0   tty12  tty16  tty2   tty23  tty27  tty30  tty34  tty38  tty41  tty45  tty49  tty52  tty56  tty6   tty63  ttyprintk  ttyS11  ttyS15  ttyS19  ttyS22  ttyS26  ttyS3   ttyS5  ttyS9
tty1   tty13  tty17  tty20  tty24  tty28  tty31  tty35  tty39  tty42  tty46  tty5   tty53  tty57  tty60  tty7   ttyS0      ttyS12  ttyS16  ttyS2   ttyS23  ttyS27  ttyS30  ttyS6
tty10  tty14  tty18  tty21  tty25  tty29  tty32  tty36  tty4   tty43  tty47  tty50  tty54  tty58  tty61  tty8   ttyS1      ttyS13  ttyS17  ttyS20  ttyS24  ttyS28  ttyS31  ttyS7

```

If I tail the system log and plug the nano into the usb drive I get the following (the answer my be here but I cant see it).

```
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.381626] usb 3-4: new full-speed USB device number 14 using xhci_hcd
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.599105] usb 3-4: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.64
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.599107] usb 3-4: New USB device strings: Mfr=0, Product=2, SerialNumber=0
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.599108] usb 3-4: Product: USB Serial
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.601365] ch341 3-4:1.0: ch341-uart converter detected
Oct  7 17:17:14 HP-Envyl mtp-probe: checking bus 3, device 14: "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-4"
Oct  7 17:17:14 HP-Envyl mtp-probe: bus: 3, device: 14 was not an MTP device
Oct  7 17:17:14 HP-Envyl kernel: [ 8949.601888] usb 3-4: ch341-uart converter now attached to ttyUSB0
Oct  7 17:17:14 HP-Envyl systemd[1]: Starting Braille Device Support...
Oct  7 17:17:14 HP-Envyl brltty[12613]: BRLTTY 6.4 rev BRLTTY-6.4 [https://brltty.app/]
Oct  7 17:17:14 HP-Envyl brltty[12613]: BRLTTY 6.4 rev BRLTTY-6.4 [https://brltty.app/]
Oct  7 17:17:14 HP-Envyl brltty[12613]: executing as the invoking user: root
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: executing as the invoking user: root
Oct  7 17:17:14 HP-Envyl mtp-probe: checking bus 3, device 14: "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-4"
Oct  7 17:17:14 HP-Envyl mtp-probe: bus: 3, device: 14 was not an MTP device
Oct  7 17:17:14 HP-Envyl brltty[12613]: CLDR open error: No such file or directory: /usr/share/unicode/cldr/common/annotations/en.xml
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: CLDR open error: No such file or directory: /usr/share/unicode/cldr/common/annotations/en.xml
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: possible cause: the package that defines the CLDR annotations directory is not installed
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: emoji substitutiion won't be performed
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: BrlAPI Server: release 0.8.3
Oct  7 17:17:14 HP-Envyl brltty[12613]: possible cause: the package that defines the CLDR annotations directory is not installed
Oct  7 17:17:14 HP-Envyl systemd[1]: Started Braille Device Support.
Oct  7 17:17:14 HP-Envyl brltty[12613]: emoji substitutiion won't be performed
Oct  7 17:17:14 HP-Envyl brltty[12613]: BrlAPI Server: release 0.8.3
Oct  7 17:17:14 HP-Envyl brltty[12613]: Linux Screen Driver:
Oct  7 17:17:14 HP-Envyl brltty[12613]: brltty: Linux Screen Driver:
Oct  7 17:17:14 HP-Envyl kernel: [ 8950.123164] input: BRLTTY 6.4 Linux Screen Driver Keyboard as /devices/virtual/input/input49
Oct  7 17:17:15 HP-Envyl brltty[12613]: USB configuration set error 16: Device or resource busy
Oct  7 17:17:15 HP-Envyl brltty[12613]: brltty: USB configuration set error 16: Device or resource busy
Oct  7 17:17:15 HP-Envyl brltty[12613]: USB interface in use: 0 (ch341)
Oct  7 17:17:15 HP-Envyl brltty[12613]: brltty: USB interface in use: 0 (ch341)
Oct  7 17:17:15 HP-Envyl ModemManager[1013]: <info>  [base-manager] port ttyUSB0 released by device '/sys/devices/pci0000:00/0000:00:14.0/usb3/3-4'
Oct  7 17:17:15 HP-Envyl ModemManager[1013]: <info>  [base-manager] couldn't check support for device '/sys/devices/pci0000:00/0000:00:14.0/usb3/3-4': Operation was cancelled
Oct  7 17:17:15 HP-Envyl kernel: [ 8950.239032] usb 3-4: usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1
Oct  7 17:17:15 HP-Envyl kernel: [ 8950.239683] ch341-uart ttyUSB0: ch341-uart converter now disconnected from ttyUSB0
Oct  7 17:17:15 HP-Envyl kernel: [ 8950.239693] ch341 3-4:1.0: device disconnected
Oct  7 17:17:15 HP-Envyl brltty[12613]: NoSpeech Speech Driver:
Oct  7 17:17:15 HP-Envyl brltty[12613]: brltty: NoSpeech Speech Driver:
Oct  7 17:17:18 HP-Envyl rtkit-daemon[3252]: Supervising 10 threads of 3 processes of 1 users.

```

Does anyone have any idea what can cause this issue?

# Answer
OK, i can close this. brtty was the problem. I disabled it (found instructions below on another post)

```
systemctl stop brltty-udev.service
sudo systemctl mask brltty-udev.service
systemctl stop brltty.service
systemctl disable brltty.service

```

After logout and login, it works now.

Thanks for the help. I did not have this issue on Mint 20, so i am guessing that brtty was automatic in Mint 21
> 1 votes

---
Tags: arduino-nano, usb, linux
---


# Question
Title: Wire.requestFrom() not a blocking function, even though it should be(?)
I'm working on creating a simple ACK/NACK handshake between 2 Arduino's that will essentially go like this:

1. Arduino 1 signals Arduino 0 it is available
2. Arduino 0 sends a connect byte to Arduino 1 (say, 'c')
3. Arduino 1 sends a confirmation byte to Arduino 0 (say, 's')

This seems simple enough, so what I'm doing to avoid any kind of multithreading or callback functions is to use `Wire.requestFrom()`. From the wiki, this function "requests" the device at the specified address to send data. From what I understand, this "request" simply entails the master device simply blocking until it receives the necessary data. It doesn't seem to send any signal to the slave device that it should send anything, just does a simple wait. As such, I created a simple demo of this handshake between the two devices as follows:

```
// slave
#include <Wire.h>

void setup() {
  Serial.begin(9600);
  Wire.begin(1);
  Wire.requestFrom(0, 1, false);
  Serial.println("finished");
}

```

```
// master
#include <Wire.h>

bool last = false;

void setup() {
  Serial.begin(9600);
  Wire.begin(0);
  pinMode(2, INPUT);
}

void loop() {
  if (digitalRead(2) && !last) {
    Wire.beginTransmission(1);
    Wire.write('c');
    Wire.endTransmission(1);
  } else if (!digitalRead(2)) {
    last = false;
  }
  delay(1000);
}

```

Here, the master code waits on a signal (pin 2) (which is given by Arduino 1) that it is available, and then on connect, will send one connect byte to Arduino 1. In Arduino 1 (slave)'s code, I've placed the requestFrom call that should block until Arduino 0 sends that connect byte.

The problem here is that it's not actually blocking. Even before I've gotten a chance to run the master's code, the slave's "finished" output has instantly triggered. Am I understanding this function incorrectly or is there something wrong in my implementation?

# Answer
You completely misunderstand how I2C communication (that's what the `Wire` library does) works. I won't explain the full I2C interface here, since that is a bit too much for this answer.

`Wire.requestFrom()` doesn't block until it receives data. It will configure the I2C interface as master (when previously in slave mode this will be temporary). Then it enforces a start condition on the bus, sends the address of the slave and then sends a clock pulse for the acknowledgement bit. During this clock pulse the slave can pull the SDA line low and signal that way, that it is reachable. After that the master continues to generate the clock for all the bytes it wants, expecting the slave to control the SDA line. If the slave doesn't do that (for example because you didn't connect the `onRequest()` callback), then the received data will just be 1s (so each byte 0xFF).

So `Wire.requestFrom()` does only block for the time, that the transmission needs. If the slave doesn't acknowledge its address, the function will exit after that. The transaction will only need a few milliseconds either way.

> avoid any kind of multithreading or callback functions

On AVR based Arduinos (like the Uno or Nano) multithreading isn't really a thing (besides using a time sharing library, but still on only one core), though callbacks from interrupts are. And as long as you use the `Wire` library (and with it the I2C hardware interface of the microcontroller) you have to use interrupts and thus callback functions. And honestly there is normally no reason not to do that.

---

Another problem with what you are currently doing it, that both Arduinos act as masters on the bus. No two masters can send on the bus at the same time. While the I2C protocol has a way to determine, which master can send first, this is often implemented rather buggy. I don't know how good the `Wire` library is with this currently, but you should avoid a multi-master setup if possible.

---

A minor problem: The I2C address space has some reserved sections for special use. You can start your slave addresses at 8 (refer to the I2C specification on the web). Address 0 is meant as a general call address, so for master-write transactions, which target every slave on the bus. You shouldn't have a slave with that address.

---

**What to do now?** Just implement the code with the `Wire` library as it is meant, including the `onRequest()` callback function. Refer to the master-read example of the `Wire` library. Set the second Arduino as master and the first as slave. On the second Arduino you can call `Wire.requestFrom()` with the slaves address. This will trigger the `onReqest()` callback function on the first Arduino, where you can use `Wire.write()` to let the library send the desired data back to the master. On the master (Arduino 2) you an then read that data via `Wire.read()`. And thats it.
> 3 votes

# Answer
Masters request data from the slave, not the other way around.

See http://gammon.com.au/i2c

Slaves set up a "receive" handler to be told that there is incoming data.

```
Wire.onReceive (receiveEvent);

```

> From what I understand, this "request" simply entails the master device simply blocking until it receives the necessary data.

Yes, but you don't have this request on the master, you have it on the slave. There is your problem.
> 1 votes

---
Tags: i2c
---


# Question
Title: Baudrate is set to 9600 automatically even if specifying a different value
You initialize the serial communication via USB with

```
Serial.begin(baudrate);

```

where baudrate is a `long` specifying the number of symbols you want to send over the connection per second. You can put pretty much any number in there, but not every number makes sense.

One thing that I found odd though is that I can't seem to actually use a different baudrate than 9600. The sketch compiles and uploads just fine, but if I check the actual speed of the serial port via

```
setserial -ag port

```

where `port` is the port of my Teensy 4.0 board (that command is something you can use in the terminal of Linux) or with

```
Serial.baud();

```

directly in the sketch it always says 9600. I suspect that this is caused by something inside the code behind `Serial.begin()` since I can manually set the baudrate via the terminal in Linux using

```
stty speed baudrate < port > port

```

where (again) `baudrate` is the speed I want to use and `port` is the port of my board (checking it with the first terminal command: it works). But when restarting the program on the board the baudrate reverts to 9600.

Does anyone know why this is and how to fix this?

# Answer
> 3 votes
The whole concept of Baud Rate with USB communication is completely meaningless. There is no such thing as "baud rate" over USB.

What there is, and what you are confusing with "baud rate" is a configuration item which the host can send to the device which is a "I would like you to communicate with other devices at this speed" configuration item.

This is intended for use with USB to UART adaptors where it is used to configure the baud rate of a physical UART interface for downstream communication.

When you set the baud rate in your code it is ignored, since it has no meaning.

When you set the baud rate on your computer it sends it as this configuration value, which you can then retrieve, should you have an interest in that value, using the `Serial.baud()` function.

# Answer
> 0 votes
The problem may be in flow control, as LukasFun suggested. Obviously, a low speed RS232 device will not be able to handle a continuous data stream at 1.5 Mbps

A quick look at this paper may help. https://www.usconverters.com/index.php?main\_page=page&id=49&chapter=0

---
Tags: serial, teensy, linux, baud-rate, terminal
---


# Question
Title: ESP32 Rebooting while converting String to Hex Array
I wrote this code to convert String to Hex Array.

```
const char* hexstring = "0x21 0x73 0x10 0xfa 0x7a 0x00 0xff .../*40995 character long string*/....0xaa"
void setup() {
    char* temp;
    //Serial.printf("%s",hexstring);
    unsigned int number[8199];

    number[0] = strtoul (hexstring,&temp,16);
    for(int i=1;i<8199;i++)
     number[i]= (int)strtoul(temp, &temp, 16);

    for(int i=0;i<8199;i++)
        {
            if(i%64)
                printf("\n");
            printf("%d, ",number[i]);
        }
}

void loop(){
}

```

But it is causing ESP32 to reboot.

Could anyone help me with the reason why?

# Answer
> 0 votes
```
void setup() {
    char* temp;
    //Serial.printf("%s",hexstring);
    unsigned int number[8199]; <----- too much.

```

So, you're trying to put a 32796 byte object on the stack. I don't know exactly why you're seeing the manifestation that you are, but I'm not surprised.

I just took an ESP32-CAM and started playing with different sizes and found that around 1800 (`unsigned int`s) is where things start to go sideways, failing occasionally rather than constantly. By a 2000 count, it continually reboots with `rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)` transitioning to `rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)`  and later to very roughly around 5000 it becomes `rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)`

I *may* fill out some details later if I look into it deeper. The ESP32 and SDK is complicated enough that there may well be a function can call that will permit a higher stack level. But this is mostly to satisfy curiosity.

Putting very large things (relative to the system size) on the stack is usually not done. I hesitate to try to tell you what exactly you should do; it wouldn't surprise me if you don't need this array at all for what you ultimately want to do, but that's a *different* question). So, I'll just say get it off the stack through either dynamic memory allocation (e.g. through `new` or `malloc`), possibly using a smart pointer (e.g. `std::unique_ptr`) to manage that since those are available on the ESP32, or perhaps just making the variable either a `static` local or global. Or again if possible finding out why you might not need this array.

### Simple minimal change

So, I'm not going to tell you that this is a good idea, but a minimal change would be to `static` qualify this as `static unsigned int number[8199];` Then you won't get that reset cause, here, for this reason.

---

### Some details for anyone curious

If you want to see some of the guts, you look in the ESP32 core for Arduino where it creates the task that ultimately runs `setup()` for you. You can see that it calls `getArduinoLoopTaskStackSize()` returning `ARDUINO_LOOP_STACK_SIZE` which by default is `8192`. 8192 **bytes,** not `unsigned int`s. With `sizeof(unsigned int)` being 4, this is *very roughly* in the vicinity of the 1800 `unsigned int`s where things started to fall apart in my testing above. Rather than chase down the configurion I just made a sketch that does `Serial.println(getArduinoLoopTaskStackSize());` and yeah, it prints 8192.

`getArduinoLoopTaskStackSize` is a weakly defined function which would allow something to redefine in elsewhere in the program to overload the default one. So, just out of curiosity I wrote one as follows:

```
size_t getArduinoLoopTaskStackSize(void) {
  size_t r_size = sizeof(unsigned int [8199]); // exactly the size your array
  r_size += r_size >> 3; // add about 1/8 (or 12.5%) extra
  return r_size;
}

```

It no longer crashes. Should you do this? Probably not. But, if you ever have a legitimate reason to put a 32K array on the stack on an ESP32 it *may* be an option. I mostly just did this to see what would happen. It's barely been tested.

---
Tags: esp32, error
---


title: VP230 CAN Bus Transceiver

text:
# Question
Title: VP230 CAN Bus Transceiver
How does one read can packets from a VP230 Can Bus transceiver? I also have a MCP2515 which I've gotten to work, but the VP230 is a lot smaller.

I haven't been able to find any information about actually implementing the VP230, any help would be great.

# Answer
Welcome. You are talking two compatible CAN parts but they have different functions. The VP230 is the CAN bus bidirectional interface. This converts the signals on the CAN bus to logic signals your CAN controller can use. The MPC2515 is a CAN controller chip that talks to your microprocessor and the bus transceiver. The MCP2515 has only logic signals and is not compatible with the CAN bus. Together they make a good CAN bus interface. Both parts are 3V3 compatible.
> 1 votes

---
Tags: serial, can-bus
---


# Question
Title: Uploading arduino code to race drone flight controller
I am working on VTOL aircraft and currently I am looking for some good board as flight controller (FC). I could made it by myself, but it requests lot of time. I was thinking about one of fpv drone FC (I have avaiable this one:

https://www.banggood.com/cs/Original-Airbot-Omnibus-F4-Pro-V3-Flight-controller-SD-5V-3A-BEC-OSD-Current-Sensor-LC-Filter-p-1319177.html?gmcCountry=CZ&currency=CZK&createTmp=1&utm\_source=googleshopping&utm\_medium=cpc\_bgs&utm\_content=lijing&utm\_campaign=ssc-cz-cs-all-newcustom-ncv80-1118&gclid=CjwKCAjwqJ\_1BRBZEiwAv73uwEgBJQ1B3dcKvZJZy2lR5-wN-XC150Ybn0kZObpUQbgkbvKiN\_fY5BoCCVEQAvD\_BwE&cur\_warehouse=CN

This board has very small dimensions and it has already everything I need. The problem is that it is made for softwares like betaflight etc. It uses STM32 F405 so I tried to add STM 32 support for arduino (https://github.com/stm32duino/Arduino\_Core\_STM32) and upload arduino code in it.

I had to install stm32 cube programmer and because this board is not one of arduino boards I have to build the code for different board with same processor (FEATHER\_F405). Because of it I have to change board pinout in this file (C:\Users\\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.8.0\variants\FEATHER\_F405). I checked if are those pins correct (in code I command to those pins to be High and then Low while I was measuring them with multimeter). So all the pins are correct. I was able to blik the onboard LED and beep the buzzer. **The only problem I have is serial communication.** I tried to send some Strings to computer via serial port, but I didnt received any data. Here is sample code that I used:

```
#include <SoftwareSerial.h>

#define LED 4 //PB_5   //Inverted (High => LED ON)
#define BUZZ 3 //PB_4

#define _RX1 D0 //PA_10
#define _TX1 D1 //PA_9

//#define D_P 35 //PA_11
//#define D_M 36 //PA_12

//SoftwareSerial mySerial(_RX1, _TX1); // RX, TX
HardwareSerial  hwSerial_1(_RX1, _TX1);   // RX, TX

void setup() {

  hwSerial_1.begin(9600);
 //mySerial.begin(9600);

  pinMode(LED,OUTPUT);
  pinMode(BUZZ,OUTPUT);

  //pinMode(_RX1,OUTPUT);
  //pinMode(_TX1,OUTPUT);

  //pinMode(D_P,OUTPUT);
  //pinMode(D_M,OUTPUT);
}

void loop() {

  digitalWrite(LED, HIGH);
  /*
  digitalWrite(_RX1, HIGH);
  digitalWrite(_TX1, HIGH);
  digitalWrite(D_P, HIGH);
  digitalWrite(D_M, HIGH);*/

  delay(1000);

  digitalWrite(LED, LOW);
  /*
  digitalWrite(_RX1, LOW);
  digitalWrite(_TX1, LOW);
  digitalWrite(D_P, LOW);
  digitalWrite(D_M, LOW);*/

  delay(1000);

  digitalWrite(BUZZ, HIGH);
  delay(100);
  digitalWrite(BUZZ, LOW);
  delay(1000);

  hwSerial_1.println("HelloWorld");
  //mySerial.println("HelloWorld");

}

```

I tried to run serial communication via USB and via UART1 (I used USB/ TTL conventer -\> FT232), but non of these works. I also tried to use software serial and hardware serial library, but it didnt helped.

Do you have any advices how to make serial communication work?

# Answer
> 3 votes
Sorry for answering this late to this problem but I stumbled on the very same issue. After many hours of debugging, here is what I've found:

* The default serial (e.g. the serial that you will use through the object `Serial`) is actually what is labelled RX3 and TX3 on the board and is mapped like so:
    + RX3 -\> PB\_11
    + TX3 -\> PB\_10
* Serial6 is connected through an inverter (5v becomes 0v and vice versa) and can be used as an SBUS line. Serial 6 is mapped like so:
    + RX6 -\> PC\_7
    + TX6 -\> PC\_6
* Serial1 is mapped like so:
    + RX1 -\> PA\_10
    + TX1 -\> PA\_9
    + however, PA\_10 and PA\_11 are not used as UARTs on the FEATHER board. In order to enable them, you can edit the file `hardware/stm32/2.3.0/variants/STM32F4xx/F405RGT_F415RGT/PeripheralPins_FEATHER_F405.c`.
        - In the array `PinMap_UART_TX` (line 178), uncomment the line regarding the pin `PA_9` and comment the line regarding the pin `PB_6`.
        - In the array `PinMap_UART_RX` (line 193), uncomment the line regarding the pin `PA_10` and comment the line regarding the pin `PB_7`.
* However, if you try to read from this uart you will probably receive garbage data because the Feather F405 board uses a 12MHz external oscillator, when the omnibus F4 uses a 8MHz clock. To fix this, you can go to the files that define the Feather F405 : `hardware/stm32/2.3.0/variants/STM32F4xx/F405RGT_F415RGT/variant_FEATHER_F405.h` line 178 you will read : `#define HSE_VALUE 12000000U`. This has to be changed into : `#define HSE_VALUE 8000000U`.

---
Tags: arduino-ide, drone, stm32
---


# Question
Title: Arduino outputting 4.7V instead of 3.3V when using I2C communication/sensor?
TOF050C-VL6180X Sensor was not responding, so I checked it with a multi-meter, and the VIN, GND solder pins on it read 4.7V. Double-checked Mega voltage, without anything connected, and it shows stable 3.6V. Connected a different ToF and it works perfectly, with a 3.6V on it.

So that proves that sensor is damaged (might've powered it with 5V at first), but I don't understand how is it taking more than the regulated 3.3V? If it was shorted, it would read 0V, and if something burnt, it would be open circuit and show ~3.3V, right? So how is it just getting 4.7V out of nowhere? Any ideas on what I'm not understanding here?

Thank you!

**EDIT:** More info, tried to isolate issue as much as I could

**1)** The non-working sensor shows 4.7V

**2)** The working sensor shows 3.4V and outputs distance to serial

**3)** This is where it gets weird. I uploaded the simple blink sketch and now the working sensor shows 4.7V too

**4)** So I tried **disconnecting the SDA/SCL**, while leaving power connected, with the blink sketch running, and it's back to 3.3V!

\**Tried the same steps with a different Mega, and **it always shows 3.3V, no matter the configuration!**

Now I'm very lost. So is the Arduino semi-damaged, with the I2C communication acting weird? Is it still safe to use with the project, if it *technically* works?

# Answer
The Arduino Wire enables the internal pullup resistor on SDA and SDL. The internal pull-ups are specified at 20k to 50k. So you *are* providing 5V (or there about) to the sensor, though through a high resistance connection. So, the voltage isn't coming from nowhere.

It is not unlikely that there protection/clamp diodes in the sensor IC or on the sensor board that connect these signals forward through the diode to the IC's 3.3v connection.

So your SCL/SDA can be seen as very weakly (through roughly 35k) trying to backfeed your 3.3V regulator which is probably just blocking the current. If the sensor/board is using no current to speak of, either because it just doesn't normally or because it's dead, you would measure 5V minus a diode drop, or roughly the 4.7V you're seeing.

If you assume the internal resistors are both at 20K as a "worst" case scenario for a calculation, the current needed through one to drop 5v to 3.3v is 85uA. So with 170uA load on the board that would drop the 3.3V pin connection back to its 3.3V level. About 170uA will flow through a 20k resistor with 3.3V across it. So if you want experiment take any resistor from about 470ohms all the way to just shy of 20k in parallel with your 3.3V / GND measurement and see if your 4.7V measurement doesn't drop right down to the normal 3.3V output.
> 1 votes

---
Tags: arduino-mega, i2c, voltage
---


# Question
Title: Conversion from `const char* datac="0x21,0x10,0xfa,0x7a,0xff";` to `uint8_t datat[]={0x21, 0x10, 0xfa, 0x7a, 0xff}`
The below reading data from API:

```
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "****";
const char* pass = "****";

void setup()
{
  Serial.begin(115200);
  WiFi.begin(ssid, pass);
  Serial.print("COnnecting");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.print("\nIP Address");
  Serial.println(WiFi.localIP());
}

void loop() {
  const char* root_0_id ;
  const char* root_0_Title ;
  if (WiFi.status() == WL_CONNECTED)
  {
    long rnd = random(1, 3);
    HTTPClient client;

    client.begin("https://6336d6c365d1e8ef267481aa.mockapi.io/api/bitmap/images?id=1");
    int httpCode = client.GET();

    if (httpCode > 0) {
      String payload = client.getString();
      Serial.println("\nstatuscode: " + String(httpCode));
      if (payload == "[]")
        Serial.println("\nNOT FOUND");
      else
      {

        DynamicJsonDocument doc(49152);
        DeserializationError error = deserializeJson(doc, payload);
        if (error) {
          Serial.print("deserializeJson() failed: ");
          Serial.println(error.c_str());
          return;
        }

        root_0_id = doc[0]["id"]; // "41"
        root_0_Title = doc[0]["Bitmap"];

        Serial.print("\n\nData : ");
        Serial.println(root_0_Title);

        Serial.println(sizeof(root_0_Title));
        client.end();
        dataReceived = 1;
        delay(10000);

      }

    }
    else {
      Serial.println("Error on HTTP request");
    }
  }
}

```

I need help with parsing the `const char* root_0_Title="0x21,0x10,0xfa,0x7a,0xff"`, to uint8\_t\[5\]={0x21, 0x10, 0xfa, 0x7a, 0xff}?

# Answer
> 1 votes
you can use strtok (string tokenizer) and strtol (string to long) C functions.

```
  int count = 0;
  uint8_t bytes[MAX_SIZE];
  char* tok = strtok(root_0_Title, ",");
  while (tok != NULL) {
    bytes[count++] = strtol(tok, NULL, 16);
    tok = strtok(NULL, ",");
  }

```

---
Tags: esp32, data-type
---


# Question
Title: Shiftout only handles one shift register at a time
I am making a 7x10 led matrix and I am having problems with the shiftout function. It is only able to show me the output in one shiftout register at a time. How can I fix it?

For example:

```
void setup(){
    // PORTB as output.
    // Pin 13: Clock 74HC595
    // Pin 12: Latch
    // Pin 11: Data
    // Pin 10: Reset
    // Pin 9: Clock CD4017
    DDRB = 0b111111;
    // Makes sure the 4017 value is 0.
    PORTB = 0b100;
    delayMicroseconds(5);
    PORTB = 0;
}

void loop(){
  shiftOut(11, 13, LSBFIRST, 0b1000111101);
  PORTB = 0b10000;
  delayMicroseconds(800);
  PORTB = 0;
  delay(10000);
}

```

This is the output it produces:

But with numbers of 8 bits or less the output is displayed correctly.

shiftOut(11, 13, LSBFIRST, 0b10001111);

# Answer
`shiftOut` works on bytes. To do more than one byte you have to do more than one `shiftOut`. Also you have to take note of the bit ordering. You should shift the most significant bit first, not the least.

For example, this:

```
  shiftOut(11, 13, LSBFIRST, 0b1000111101);

```

should be:

```
  shiftOut(11, 13, MSBFIRST, 0b10);
  shiftOut(11, 13, MSBFIRST, 0b00111101);

```
> 1 votes

# Answer
Have a look at the implementation of `shiftOut()` (you can find it where you installed the Arduino IDE in the file `hardware/arduino/avr/cores/arduino/wiring_shift.c`):

```
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
  uint8_t i;

  for (i = 0; i < 8; i++)  {
    if (bitOrder == LSBFIRST) {
      digitalWrite(dataPin, val & 1);
      val >>= 1;
    } else {
      digitalWrite(dataPin, (val & 128) != 0);
      val <<= 1;
    }

    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);
  }
}

```

Do you see, that the value (parameter `val`) is of type `uint8_t`, so only 1 byte big? And do you see, that the for loop only counts to 8 (one iteration for each bit in a byte)? This means, that the `shiftOut()` function only handles one byte at a time. When you want to shift out more bits than 8, you need to call it repeatedly.

In your first example the code behaves accordingly. The provided data gets cast to `uint8_t`, cutting away the upper 2 bits.
> 2 votes

---
Tags: arduino-uno, shift-register, led-matrix
---


title: Function call only works if called once

text:
# Question
Title: Function call only works if called once
I have 3 LED chains which are all mapped to concentric rings. Each ring has a its own 2D array with the chain number & LED number. I have a function that is passed a ring array and then lights the appropriate LED. I'm using `FastLED`

```
void lightUp(int ring_arr[][2], int i, int col){

  if(ring_arr[i][0] == 0){
      L0[ring_arr[i][1]] = CHSV(col, 255, 255);
    }
    if(ring_arr[i][0] == 1){
      L1[ring_arr[i][1]] = CHSV(col, 255, 255);
    }
    if(ring_arr[i][0] == 2){
      L2[ring_arr[i][1]] = CHSV(col, 255, 255);
  }
}

```

This works fine BUT only if its called once in `loop()` if I make a 2nd call none of the LEDs light up. So I can light up 1 ring at a time but if I try to light up 2 or more then nothing lights up. Anyone see anything obvious that I'm overlooking?

The full code listing,

```
#include <FastLED.h>

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))
#define DATA_0 5
#define DATA_1 6
#define DATA_2 7
#define NUM_LEDS 50

CRGB L0[NUM_LEDS];
CRGB L1[NUM_LEDS];
CRGB L2[NUM_LEDS];

// Rings
int ring_1[][2] = {{0,0}, {0,1},  {0,2},  {0,3},  {1,49},
                   {1,28}, {1,29}, {1,30}, {1,31}, {1,32},
                   {1,23}, {1,24}, {1,25}, {1,26}, {1,27},
                   {1,2},  {1,3},  {1,4},  {1,5},  {1,6},
                   {1,0},  {1,1},  {2,0},  {2,1},  {2,2},
                   {2,19}, {2,20}, {2,21}, {2,22}, {2,23},
                   {2,24}, {2,25}, {2,26}, {2,27}, {2,28},
                   {2,45}, {2,46}, {2,47}, {2,48}, {2,49},
                   {0,29}, {0,28}, {0,27}, {0,26}, {0,25},
                   {0,4},  {0,5},  {0,6},  {0,7},  {0,8}};

int ring_2[][2] = {{1,48}, {1,33}, {1,22}, {1,7},  {2,3},
                   {2,18}, {2,29}, {2,44}, {0,24}, {0,9}};

int ring_3[][2] = {{1,47}, {1,34}, {1,21}, {1,8},  {2,4},
                   {2,17}, {2,30}, {2,43}, {0,23}, {0,10}};

int ring_4[][2] = {{1,46}, {1,35}, {1,20}, {1,9}, {2,5},
                   {2,16}, {2,31}, {2,42}, {0,22}, {0,11}};

int ring_5[][2] = {{1,45}, {1,36}, {1,19}, {1,10}, {2,6},
                   {2,15}, {2,32}, {2,41}, {0,21}, {0,12}};

int ring_6[][2] = {{1,44}, {1,37}, {1,18}, {1,11}, {2,7},
                   {2,14}, {2,33}, {2,40}, {0,20}, {0,13}};

int ring_7[][2] = {{1,43}, {1,38}, {1,17}, {1,12}, {2,8},
                   {2,13}, {2,34}, {2,39}, {0,19}, {0,14}};

int ring_8[][2] = {{1,42}, {1,39}, {1,16}, {1,13}, {2,9},
                   {2,12}, {2,35}, {2,38}, {0,18}, {0,15}};

int ring_9[][2] = {{1,41}, {1,40}, {1,15}, {1,14}, {2,10},
                   {2,11}, {2,36}, {2,37}, {0,17}, {0,16}};
// Colours
int col_1 = 0;
int col_2 = 160;
int col_3 = 96;

void setup(){

   // LED set up
   FastLED.addLeds<WS2811,DATA_0,RGB>(L0, NUM_LEDS);
   FastLED.addLeds<WS2811,DATA_1,RGB>(L1, NUM_LEDS);
   FastLED.addLeds<WS2811,DATA_2,RGB>(L2, NUM_LEDS);
   FastLED.setBrightness(255);
   clearAll();
}

void loop()
{

  for(int i; i < NELEMS(ring_1); i++){
    lightUp(ring_1, i, col_1);
  }

  for(int i; i < NELEMS(ring_2); i++){

//    lightUp(ring_2, i, col_2); // if I uncomment any of these
//    lightUp(ring_3, i, col_3); // no LEDs light up
//    lightUp(ring_4, i, col_1);
//    lightUp(ring_5, i, col_2);
//    lightUp(ring_6, i, col_3);
//    lightUp(ring_7, i, col_1);
//    lightUp(ring_8, i, col_2);
//    lightUp(ring_9, i, col_3);

  }

  FastLED.show();
  delay(1000);
}

void clearAll(){
  for(int i; i < NUM_LEDS; i++){
    L0[i] = CHSV(0, 0, 0);
    L1[i] = CHSV(0, 0, 0);
    L2[i] = CHSV(0, 0, 0);
  }
  FastLED.show();
}

void lightUp(int ring_arr[][2], int i, int col){

  if(ring_arr[i][0] == 0){
      L0[ring_arr[i][1]] = CHSV(col, 255, 255);
    }
    if(ring_arr[i][0] == 1){
      L1[ring_arr[i][1]] = CHSV(col, 255, 255);
    }
    if(ring_arr[i][0] == 2){
      L2[ring_arr[i][1]] = CHSV(col, 255, 255);
  }
}

```

# Answer
Your `for` loops are missing an initialization. You should write

```
for (int i = 0; i < NELEMS(ring_1); i++)

```

but you missed the `= 0` part. This means the `i` variable ends up uninitialized, and contains whatever was left in this memory location by whatever used that memory before. The behavior in such situation is generally unpredictable. However, one may guess that the `i` of the second loop could be allocated in the same spot as the `i` of the first loop. If this happens, then the second loop starts at `i=3` and ends up being an empty loop.

As a (completely unrelated) side note, you could gather your three `L*` arrays into a single 2D array. This would make `lightUp()` significantly simpler:

```
void lightUp(int ring_arr[][2], int i, int col) {
    L[ring_arr[i][0]][ring_arr[i][1]] = CHSV(col, 255, 255);
}

```

or maybe it would be clearer like this:

```
void lightUp(int *location, int col) {
    L[location[0]][location[1]] = CHSV(col, 255, 255);
}

```

To be called as `lightUp(ring_1[i], col_1);`.
> 3 votes

---
Tags: arduino-nano, c++, led
---


# Question
Title: How do I control the speed of a 2-wire fan with an Arduino and only a potentiometer?
I am trying to vary the speed of a 2-wire fan by using a Arduino Uno and only a potentiometer.

Initially, I assumed that I could go about doing so by using a code that I used for dimming an LED. When I have run the code and varied the potentiometer, the LED on the power supply changed but, the fan did not come on. I assume that this was due to an error in the first code.

In the second code, the fan also did not come on. I am unsure if it was my wiring. I have an voltage supply connected to a breadboard to power the fan.

Additionally, would I require a mosfet or transistor despite using a potentiometer? This could have also be the problem regarding my second attempt.

**First Code Attempt:**

```
int potPin=A2;
int gPin=9;
int potVal;
float LEDVal;
int dt=250;
void setup() {
  // put your setup code here, to run once:
pinMode(potPin, INPUT);
pinMode(gPin, OUTPUT);
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
potVal=analogRead(potPin);
LEDVal=(255./1023.)*potVal;
analogWrite(gPin,LEDVal);
Serial.println(LEDVal);
delay(dt);
}

```

**Second Code:**

int reading;
int value;

void setup() {
  pinMode(CONTROL, OUTPUT);
}

void loop() {
  reading = analogRead(POTENTIOMETER);
  value = map(reading, 0, 1024, 0, 255);
  analogWrite(CONTROL, value);
}```
</code></pre>

# Answer
> 1 votes
Like people have already mentioned in the comments, you likely need to add a FET to drive the fan. The Arduino simply can't put provide the current required to drive the fan. According to the Arduino documentation, the microcontroller can only provide 20mA per output pin, which is enough to drive LEDs but not fan motors.

Luckily, there is a tutorial on the Arduino website for driving motors with PWM through a FET.
https://docs.arduino.cc/learn/electronics/transistor-motor-control

The following program is adapted from the "Analog In, Out Serial" built-in example and should be sufficient to control the speed of the motor.

```
// These constants won't change. They're used to give names to the pins used:

const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to

const int analogOutPin = 9; // Analog output pin that the FET is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

void setup() {

// declare the ledPin as an OUTPUT:
pinMode(analogOutPin, OUTPUT);
}

void loop() {

// read the analog in value:
sensorValue = analogRead(analogInPin);

// map it to the range of the analog out:
outputValue = map(sensorValue, 0, 1023, 0, 255);

// change the analog out value:
analogWrite(analogOutPin, outputValue);

// wait 2 milliseconds before the next loop for the analog-to-digital
// converter to settle after the last reading:
delay(2);
}

```

This program has not been tested and is intended as an example. Make sure that the output for the FET is wired to a pin that can output PWM. Then make sure that your program is referencing the correct pin.

Make sure that your power supply has enough power to control the fan motor as well.

Here are some wiring diagrams from the tutorial webpage.

Note: The particular fan that you are using might not be able to be driven by PWM and you should seek out and read the relevant documentation for the fan.

---
Tags: arduino-uno, programming, potentiometer, mosfet, speed
---


# Question
Title: "Cast" BluetoothSerial to HardwareSerial
I have a function that accept an `HardwareSerial` class as argument:

```
void ProcessLine(HardwareSerial *serial, char *line)
{
    // do something
    serial->write("blablabla");
}

```

In my code I also have a `BluetoothSerial` that shares the required functions (i.e. `write()`) with `HardwareSerial`.

To avoid to duplicate the code of my `ProcessLine()` that is quite long, is there a way to "cast" a `BlutoothSerial` to a `HardwareSerial`?

# Answer
No, you don't "cast" between them. Instead you make use of *polymorphism*.

In the Arduino framework most classes fit into a "tree" with similar classes "hanging off" a common parent "branch". In this case both `BluetoothSerial` and `HardwareSerial`, being both serial classes, are both children of the `Stream` class. Indeed it is this `Stream` class (which itself is a child of the `Print` class) which gives these objects most of their functions.

So unless you *need* access to some function that is specific to the `HardwareSerial` class (such as the `.begin(...)` function) you should always work up the tree to the class that provides the most restrictive set of functions that suit your needs. In this case, since you are only printing data, it would be the `Print` class. If you were reading data you would choose the `Stream` class.

So if you change your function to accept `Print *serial` instead of `HardwareSerial *serial` then it will accept *any* object that ultimately inherits from the `Print` object - so any serial objects, any network stream objects, etc.
> 2 votes

---
Tags: serial, bluetooth
---