Problems with DigitalWrite

I'm having difficulty getting DigitalWrite to behave as expected on an ESP32 board (behaviour confirmed on several different ESP32 boards).

Arduino IDE : version 2.0.3 (On OS X)
Date : 2022-12-05T09....
CLI Version : 0.29.0

The issue is as follows : I set digitalWrite to HIGH in my code, and the test case which involves querying the output register AND using an LED on said both appear to confirm the output is LOW.

The output I get is as follow:
19:02:15.292 -> Moving Forward
19:02:20.303 -> 1
19:02:20.303 -> Motor stopped
19:02:20.303 -> Pin state is 0

Code :

#include "esp_system.h"
#include "Arduino.h"
#include <wiring_private.h>

int period = 5000; 
unsigned long time_trig = 0; 
unsigned long currentTime = 0;

int state_machine = 0; 
int pin_state; 

// Motor A
#define motorAPin1 16 
#define motorAPin2  19 

// Motor B
#define motorBPin1 25 
#define motorBPin2 26 



void setup() {
  // sets the pins as outputs:
  pinMode(motorAPin1, OUTPUT);
  pinMode(motorAPin2, OUTPUT);

  pinMode(motorBPin1, OUTPUT);
  pinMode(motorBPin2, OUTPUT);

  Serial.begin(115200);
  Serial.print("Testing DC Motor...");
}

void loop() {
  while(millis() > (time_trig + period)){
    Serial.println(state_machine);
    state_machine++; 

    switch (state_machine) {
      case 1: 
        Serial.println("Moving Forward");
        digitalWrite(motorAPin1, 1);
        digitalWrite(motorAPin2, 0); 
        digitalWrite(motorBPin1, 1);
        digitalWrite(motorBPin2, 0); 
        break; 

      case 2:
        Serial.println("Motor stopped");
        digitalWrite(motorAPin1, 1);        
        digitalWrite(motorAPin2, 1);
        digitalWrite(motorBPin1, 1);
        digitalWrite(motorBPin2, 1);
        pin_state = digitalReadOutputPin(motorAPin1);
        Serial.print("Pin state is ");
        Serial.print(pin_state);
        Serial.println();
        break;

      case 3:
        Serial.println("Motor backwards");
        digitalWrite(motorAPin1, 0);
        digitalWrite(motorAPin2, 1);
        digitalWrite(motorBPin1, 0);
        digitalWrite(motorBPin2, 1);
        break;

      case 4:
          Serial.println("Motor FULL STOP");
          digitalWrite(motorAPin1, 0);
          digitalWrite(motorAPin2, 0);
          digitalWrite(motorBPin1, 0);
          digitalWrite(motorBPin2, 0);
          break;

    } //end of state_machine SWITCH
    if(state_machine>=5){
      state_machine = 0; 
    }
    time_trig = millis(); 
  }  //end of while_millis


} //end of main_loop

int digitalReadOutputPin(uint8_t pin)
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  if (port == NOT_A_PIN) 
    return LOW;

  return (*portOutputRegister(port) & bit) ? HIGH : LOW;
}
 

I looked for anyone having similar issues to no avail.

Expected behavior: setting a digital output to high results in the output in question remaining high for 5 seconds, with LED to confirm.
Result : output is low, testcase shows as low, led confirms output low.

`while(millis()  - time_trig >= period){` ???
while(millis()  - time_trig <= period){

It does indeed cycle through the case switch as expected, so that doesn't appear to be the problem.

LED blinks in certain cases and is coherent with the read digitalWrite output as well...

To what is the motor pin connected? Perhaps you are exceeding the output current limit.

It's for a L298n motor driver, but the behavior was not as expected with digitalWrite so I reverted to checking with LEDs connected in lieu of the motor driver board.

It's not over current either...

There is something wrong with this function

int digitalReadOutputPin(uint8_t pin)
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  if (port == NOT_A_PIN) 
    return LOW;

  return (*portOutputRegister(port) & bit) ? HIGH : LOW;
}

If in the code you replace it with a simple digitalRead of the pin the output is correct

pin_state = digitalRead(motorAPin1);
//pin_state = digitalReadOutputPin(motorAPin1);
Testing DC Motor...0
Moving Forward
1
Motor stopped
Pin state is 1

You are absolutely right. I confirm the behaviour on an ESP32 TTGO T-Energy Board (T18-v3.0).

Here's whats weird :
Test-case with :
'pin_state = digitalRead(motorAPin1) '
==> Works well :slight_smile:

with an LED on gpio number 13 :
Confirmed working variably, because in :

  • state_machine = 1 (OK // LED on, should be on),
  • state_machine = 2 (NOK // LED off, should be on),
  • state_machine = 3 (OK // LED off, should be off)
  • state_machine = 4 (OK // LED off, should be off) ;

How strange is this. Does anyone else manage to reproduce the behaviour?

Does anyone else manage to reproduce the behaviour?

No. The led tracks the states correctly on in 1 and 2 and off in 3 and 4.

You may be confusing yourself with the Serial printing of the case and the incrementing of the case number.

Try this order

 //Serial.println(state_machine);
    state_machine++;
    Serial.println(state_machine);

That'd be fine if this were an AVR, but you said ESP32, and it's GPIO structure is quite different, with digitalWrite() calling gpio_set_level(), which calls gpio_hal_set_level(), and then gpio_ll_set_level() (some of those are macros or inline functions, but it's ... not pretty.)

uint8_t bit = digitalPinToBitMask(pin);

I don't know whether the various digitalPinToXxx macros do reasonable things on an ESP32 or not, but you'd need to at least take into account that the ESP32 IO ports (and thus bitmasks) are 32bits, rather than 8.

1 Like

Your code simulation in Wokwi:

The plot of each motor output reveals similar similar timing characteristics ...

Logic Analyzer ...

2 Likes

Ooh. Such magic!

1 Like

Agreed. Using 'pin_state = digitalRead(motorAPin1);'

SOLVED and working as expected.
Big thanks to @cattledog & @westfw.

Cleaned up code is :

#include "esp_system.h"
#include "Arduino.h"

int period = 10000; 
unsigned long time_trig = 0; 
unsigned long currentTime = 0;

int state_machine = 0; 
int pin_state; 

// Motor A
#define motorAPin1 13 
#define motorAPin2  12 

// Motor B
#define motorBPin1 25 
#define motorBPin2 26 

void setup() {
  // sets the pins as outputs:
  pinMode(motorAPin1, OUTPUT);
  pinMode(motorAPin2, OUTPUT);

  pinMode(motorBPin1, OUTPUT);
  pinMode(motorBPin2, OUTPUT);
  
  Serial.begin(115200);

  Serial.print("Testing DC Motor...");
}

void loop() {

  
   

  while(millis() > (time_trig + period)){
    state_machine++;
    
    if(state_machine>=5){
      state_machine = 1; 
    }

    Serial.print("State machine is :");
    Serial.print(state_machine);

    switch (state_machine) {
      case 1: 
        Serial.print(" --  Moving Forward\n");
        digitalWrite(motorAPin1, 1);
        digitalWrite(motorAPin2, 0); 
        digitalWrite(motorBPin1, 1);
        digitalWrite(motorBPin2, 0); 
        pin_state = digitalRead(motorAPin1);
        Serial.print("PinA1 state is ");
        Serial.print(pin_state);
        Serial.print(" versus 1 expected.\n");
        break; 

      case 2:
        Serial.print(" -- Motor stopped\n");
        digitalWrite(motorAPin1, 1);        
        digitalWrite(motorAPin2, 1);
        digitalWrite(motorBPin1, 1);
        digitalWrite(motorBPin2, 1);
        pin_state = digitalRead(motorAPin1);
        Serial.print("PinA1 state is ");
        Serial.print(pin_state);
        Serial.print(" versus 1 expected.\n");
        break;

      case 3:
        Serial.print(" -- Motor backwards\n");
        digitalWrite(motorAPin1, 0);
        digitalWrite(motorAPin2, 1);
        digitalWrite(motorBPin1, 0);
        digitalWrite(motorBPin2, 1);
        pin_state = digitalRead(motorAPin1);
        Serial.print("PinA1 state is ");
        Serial.print(pin_state);
        Serial.print(" versus 0 expected.\n");
        break;

      case 4:
          Serial.print(" -- Motor FULL STOP\n");
          digitalWrite(motorAPin1, 0);
          digitalWrite(motorAPin2, 0);
          digitalWrite(motorBPin1, 0);
          digitalWrite(motorBPin2, 0);
          pin_state = digitalRead(motorAPin1);
          Serial.print("PinA1 state is ");
          Serial.print(pin_state); 
          Serial.print(" versus 0 expected.\n");
          break;

    } //end of state_machine SWITCH
 
    time_trig = millis(); 
  }  //end of while_millis


} //end of main_loop

Output of the code is :

Testing DC Motor...State machine is :1 -- Moving Forward
PinA1 state is 1 versus 1 expected.
State machine is :2 -- Motor stopped
PinA1 state is 1 versus 1 expected.
State machine is :3 -- Motor backwards
PinA1 state is 0 versus 0 expected.
State machine is :4 -- Motor FULL STOP
PinA1 state is 0 versus 0 expected.

==> LED now tracks as predicted on all outputs. Now to connect to L298N and the real fun begins :slight_smile:

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.