Unable to set the state of a pin

I am a retired embedded systems engineer, and have been programming for over 50 years. I don’t have much knowledge of the startup process of the Arduino, but have have done a number of Arduino projects.

I am developing an application for an Arduino Mega that uses stepper motors to control a camera gimbal. The hardware is an Elegoo Mega 2560 with a Keeyees motor controller shield using DRV8825 controllers to drive two Stepperonline stepper motors. The code to control the motors was working, but after I added some more features to the program, the motors are no longer enabled. That is, when the program starts, the motors don’t lock their position as they did in the previous version. I know, first thing to check is the code to control the motors. I have done that. In order to troubleshoot, I isolated the code that enables the controllers. That consists of setting pin 8 for output and then setting it low. In order to verify that this is happening, I moved the code to do that to the beginning of setup(), and followed it with a while (1) dead loop. The motors do not activate when I run that code. However, if I load a sketch that consists of only setting pin 8, the motors activate. (By “activate” I mean that they hold their position, and do not allow you to move them manually. Pin 8 set to low activates this condition.) The small sketch contains the same code to enable the motors as the program I’m developing. The only difference is that the program that doesn’t work includes all the other code, but with the while (1), none of it executes. I conclude that something that is loading before setup() starts prevents me from setting pin 8. By the way, I have the version of the program that does not contain the latest mods, and it is able to control the motors.

I will include copies of all of the code, but it’s quite a bit. The main app is around 3000 lines of code. The newer version that does not work is called GROOD.ino. The version that does work is called Hallgimbal.ino. I renamed it. There are two other things in the attached zip file, a library that does astronomical calculations called Ephemeris, and the small test program that activates the motors, called lockemup.ino.

Now, I’m not asking you to debug my program. That would be an unreasonable request. I include my code for reference. What I am hoping is that I can get some guidance on where to look. I don’t have a clue what might be loading that could keep me from setting pin 8.

BTW, here’s the stats that the IDE prints when GROOD.ino compiles:
Sketch uses 131338 bytes (51%) of program storage space. Maximum is 253952 bytes.
Global variables use 3735 bytes (45%) of dynamic memory, leaving 4457 bytes for local variables. Maximum is 8192 bytes.

wthalliii.zip (307 KB)

wthalliii:
I don't have much knowledge of the startup process of the Arduino...

Initialize the timers. Initialize the ADC. I think that's it. In any case, it's open source. (If you ask for a link I'll hunt one down. It's too close to bedtime to do it now.)

wthalliii:
...and the small test program that activates the motors, called lockemup.ino...

Are you saying that lockemup.ino does not work as expected?

That's part of my problem. lockemup does work. The motors lock as they should. But the exact same code as is in lockemup is at the very beginning of the setup function of GROOD. But it doesn't work there. No only is that the only code in GROOD that does anything to port 8, but if I put a while(1); statement right after that in setup so that it doesn't do anything else, it doesn't lock the motors. But, on the other hand, the older version of GROOD, which is called HallGimbal, DOES lock up the motors as it should. So the question is, why isn't GROOD able to set pin 8 to low even if I make it do only that and no other code?

This morning, I took the shield off, and put a voltmeter between pin 8 and ground. When I run lockemup, pin 8 is set to 0V. When I run GROOD, it is floating like it has not been set. I'm about to write a small set of code to set the pin low and then high with a delay so I can see it go up and down. I will put that same code in lockemup and in the beginning of the setup for GROOD. I fully expect that it will work in lockemup and not in GROOD. I will report back here if that is not the case.

Just to clarify: You take GROOD.ino as it is and change nothing else but setup() to do this:

void setup() 
{
    char c;
    // set controller ports
    pinMode(EN, OUTPUT);
    digitalWrite(EN, LOW);
    while(1);                // <-- add
    
    pinMode(X_DIR, OUTPUT); 
.
.
.

and you do not see the motor lock?

Doing anything with timer 4? Pin 8 is OC4B on the Mega. There are peripheral states that can override the output latch state.

wthalliii:
I conclude that something that is loading before setup() starts prevents me from setting pin 8.

By the way, I have the version of the program that does not contain the latest mods, and it is able to control the motors.

doesn't this last statement suggest the cause of the problem is in the "latest mods", not something unknown "before setup() starts"?

have you put an LED on pin 8 to confirm your conclusion?

Blackfin:
Just to clarify: You take GROOD.ino as it is and change nothing else but setup() to do this:

void setup() 

{
   char c;
   // set controller ports
   pinMode(EN, OUTPUT);
   digitalWrite(EN, LOW);
   while(1);                // ← add
   
   pinMode(X_DIR, OUTPUT);
.
.
.




and you do not see the motor lock?

Yes, that’s correct. And this morning, I took the motor shield off and put a voltmeter between pin 8 and ground. In my little test program, lockemup, I see pin 8 go to 0V. In GROOD, it does not. So, I put this code into both lockemup and the setup function of GROOD:
#define EN 8

void setup() {
int i;
Serial.begin(9600); // USB terminal
pinMode(EN, OUTPUT);
while (true) {
digitalWrite(EN, LOW);
Serial.print(“H”);
delay(2000);
digitalWrite(EN, HIGH);
Serial.print(“L”);
delay(2000);
}
}

void loop() {

};

And, running lockemup, I see pin 8 go alternately to 5V and to 0V. In GROOD, running exactly the same code, it does not. In both cases, I see the “H” and “L” on the monitor.

Blackfin:
Just to clarify: You take GROOD.ino as it is and change nothing else but setup() to do this:

void setup() 

{
    char c;
    // set controller ports
    pinMode(EN, OUTPUT);
    digitalWrite(EN, LOW);
    while(1);                // ← add
   
    pinMode(X_DIR, OUTPUT);
.
.
.




and you do not see the motor lock?

aarg:
Doing anything with timer 4? Pin 8 is OC4B on the Mega. There are peripheral states that can override the output latch state.

I don’t know how to write code to use timer 4, so if I am doing something that would affect it, it is accidental. I just did a search for timer 4, and did not find any information on how to use it. Can you point me to that information?
At any rate, if I did have code for timer 4 in my sketch, it would not run because of the while(1); in setup(). That’s why I’m guessing that something is happening that occurs before setup is executed.
I did add code to use the EEPROM. If that uses timer 4, and gets initialized before setup() runs, then maybe that’s my problem. If the EEPROM code is using pin 8, then that would prevent me from using it, if I’m understanding you.

gcjr:
doesn't this last statement suggest the cause of the problem is in the "latest mods", not something unknown "before setup() starts"?

have you put an LED on pin 8 to confirm your conclusion?

I agree. It does indeed suggest that. That's why I put the while(1) in setup() so that NONE of the old or new code is executed.
I have not put an LED on pin 8, but I have used a voltmeter to measure the voltage. In my test program, lockemup, pin 8 goes to 0V. In GROOD, it does not. It's floating. As I pointed out in another answer, I also put in code to toggle that pin from high to low in a loop with delays. (See the other post for the code.) In lockemup, the code does go from 0V to 5V alternatively. But in GROOD, it does not.

Maybe there is some weird side effect from the size of your code. Have you tried putting the huge arrays in object.h in PROGMEM? Actually, it's a little surprising that they aren't already...

aarg:
Maybe there is some weird side effect from the size of your code. Have you tried putting the huge arrays in object.h in PROGMEM? Actually, it's a little surprising that they aren't already...

That occurred to me. They are in PROGMEM, AFAIK. I also spent several hours moving all of the text strings in the program to PROGMEM. One of the definitions in one of the .hpp files included with the Ephemeris library is:
#define CONST const PROGMEM

And my code does copy elements of them using memcpy_P. However, just to make sure I'm not missing anything, I will change all of my use of the CONST definition in my program to const PROGMEM. I'll let you know if it solves the problem.

not a fan of voodoo and mysticism

any chance something elsewhere is unintentionally turning the pin off?

wthalliii:
That occurred to me. They are in PROGMEM, AFAIK. I also spent several hours moving all of the text strings in the program to PROGMEM. One of the definitions in one of the .hpp files included with the Ephemeris library is:
#define CONST const PROGMEM

And my code does copy elements of them using memcpy_P. However, just to make sure I'm not missing anything, I will change all of my use of the CONST definition in my program to const PROGMEM. I'll let you know if it solves the problem.

No, the arrays in object.h do not use PROGMEM:

CONST object_struct NGC1[5000] = {

gcjr:
not a fan of voodoo and mysticism

any chance something elsewhere is unintentionally turning the pin off?

The monolithic design of this code makes it extremely difficult to discover the answer to this question. Any small problem instantly becomes the "needle in the haystack".

gcjr:
not a fan of voodoo and mysticism

any chance something elsewhere is unintentionally turning the pin off?

I assume by "something elsewhere", you mean something in my code. No. There is no chance because, as I explained, I made a temporary change to the setup so that the first thing it does is to set that pin low (which is what it's supposed to be), and then after that I coded a while(1); statement. Which means at that point the code goes into an infinite loop testing 1 for true. Which it always is. So, no, it's not executing any other part of my code because of that temporary test patch. And there is no other code in the sketch that changes pin 8. I checked, and have checked several times to make sure. Please pardon me if it seems I'm reacting to your comments. And, believe me, I'm not being superstitious. I cannot find anything in my code that is setting that pin wrong. I appreciate your help.

aarg:
No, the arrays in object.h do not use PROGMEM:

CONST object_struct NGC1[5000] = {

CONST is not the same as const. It is a #define:
#define CONST const PROGMEM
It's in one of the .hpp files with that library called Ephemeris.
However, I changed all of those CONST definitions to "const PROGMEM" and that didn't fix the problem.

Thanks, guys. I hope I don’t sound argumentative. But I have listened to and tried the things you have suggested and have been unable to solve the problem. I’ll continue to try to find a solution, and if anyone thinks of something else, please do post it here. I appreciate it.

There’s definitely something weird going on. I put this at the top of your setup() function:

void setup() 
{
    char c;

    // set controller ports
#if 1    
    DDRB = 0b10000000;
    PORTB &= 0b01111111;
    while(1)
    {
        PORTB |= 0b10000000;
        delay(125);
        PORTB &= 0b01111111;
        delay(125);
    
    }//while
#else    
    pinMode( 13, OUTPUT );
    digitalWrite( 13, LOW );
    //pinMode(EN, OUTPUT);
    //digitalWrite(EN, LOW);
    while(1)
    {
        digitalWrite( 13, HIGH );
        delay(125);
        digitalWrite( 13, LOW );
        delay(125);
    
    }//while
#endif

Using pin 13 (for visual reference as it’s the LED_BUILTIN), I found that using library functions pinMode and digitalWrite the LED refused to blink whereas with direct port access it does. Same pin, just bypassing the API commands.

I guess you already knew but your code and/or your library is somehow not playing nicely.

With verbose compilation I noticed a boatload of warnings of the following nature:

...GROOD.h:206:1: warning: invalid conversion from 'const char*' to 'char*' [-fpermissive]
.
.
.
...GROOD.ino:277:124: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
 char *planet_name[] = {"The Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "The Moon"};
.
.
.
...GROOD.ino:277:124: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
.
.
.
...GROOD.ino:2454:31: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     bada(sp_start_x, "start x");
.
.
.

etc. There’s scads of them. Might be worthwhile getting down to zero warnings and seeing if that affects run-time operation.

Using pin 13 (for visual reference as it's the LED_BUILTIN), I found that using library functions pinMode and digitalWrite the LED refused to blink whereas with direct port access it does. Same pin, just bypassing the API commands.

So, compiling for the wrong board?

The while(1) fix suggests that something is subsequently happening to pin 8 to set it back to HIGH or floating - as in, immediately after.

But it doesn't work there. No only is that the only code in GROOD that does anything to port 8,

I'd suggest that that's not the case. I'd be looking for #defines or constants that are 8 when they should be some other pin number, and I'd be looking for calls to constructors or other initializers for hardware where you have miscounted or scrambles up the arguments.

And there's always good old C memory overrun.

And you mentioned using direct port mapping somewhere? That is very easy to screw up. I'd be looking for a signed 8-bit value that is being extended to 16 bits in an expression somewhere, resulting in sign extension filling the high byte of that 16-bit number with spurious 1s.

PaulMurrayCbr:
So, compiling for the wrong board?

The while(1) fix suggests that something is subsequently happening to pin 8 to set it back to HIGH or floating - as in, immediately after.

Tested on a Mega2560. When using the OPs code as is but inserting a while(1) immediately after the setup of pin 8 I found that the pin setup still failed when using pinMode and digitalWrite. Aside from what's in the while(1) loop, nothing else is running aside from timer 0 interrupts.

I tried pin 8 and also used pin 13 with the same result. Direct port access seems to work but it's obviously concerning that the API funcs don't work anymore.