Re: Creating The BMW Kinetic Sculpture

Ok, another IDE issue compiling for a Mega.
I changed from 16 if:then blocks to switch:case with the 16 blocks, thinking a jump right to a motor would execute faster than up to all those if tests every time I commanded a motor.

After compiling for cases 0 to 9, when #10 is added I get this block of errors.
What is going on?
IDE 1.8.12, turned other apps off, reset the computer, and restarted the IDE. Didn’t help.

C:\arduino-1.8.12\arduino-builder -dump-prefs -logger=machine -hardware C:\arduino-1.8.12\hardware -hardware C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\hardware -tools C:\arduino-1.8.12\tools-builder -tools C:\arduino-1.8.12\hardware\tools\avr -built-in-libraries C:\arduino-1.8.12\libraries -libraries C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\libraries -fqbn=arduino:avr:mega:cpu=atmega2560 -vid-pid=0X2341_0X0042 -ide-version=10812 -build-path C:\Users\CROSSR~1.CRO\AppData\Local\Temp\arduino_build_107753 -warnings=none -build-cache C:\Users\CROSSR~1.CRO\AppData\Local\Temp\arduino_cache_1311 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avr-gcc.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino5.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.arduinoOTA.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avrdude.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=C:\arduino-1.8.12\hardware\tools\avr -verbose C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\Kinetics\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino
C:\arduino-1.8.12\arduino-builder -compile -logger=machine -hardware C:\arduino-1.8.12\hardware -hardware C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\hardware -tools C:\arduino-1.8.12\tools-builder -tools C:\arduino-1.8.12\hardware\tools\avr -built-in-libraries C:\arduino-1.8.12\libraries -libraries C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\libraries -fqbn=arduino:avr:mega:cpu=atmega2560 -vid-pid=0X2341_0X0042 -ide-version=10812 -build-path C:\Users\CROSSR~1.CRO\AppData\Local\Temp\arduino_build_107753 -warnings=none -build-cache C:\Users\CROSSR~1.CRO\AppData\Local\Temp\arduino_cache_1311 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avr-gcc.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avr-gcc-7.3.0-atmel3.6.1-arduino5.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.arduinoOTA.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.arduinoOTA-1.3.0.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avrdude.path=C:\arduino-1.8.12\hardware\tools\avr -prefs=runtime.tools.avrdude-6.3.0-arduino17.path=C:\arduino-1.8.12\hardware\tools\avr -verbose C:\Users\CrossRoadsFencing.CrossRoads\Documents\ArduinoStuff\Kinetics\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino
Using board 'mega' from platform in folder: C:\arduino-1.8.12\hardware\arduino\avr
Using core 'arduino' from platform in folder: C:\arduino-1.8.12\hardware\arduino\avr
Detecting libraries used...
"C:\\arduino-1.8.12\\hardware\\tools\\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10812 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\cores\\arduino" "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\variants\\mega" "C:\\Users\\CROSSR~1.CRO\\AppData\\Local\\Temp\\arduino_build_107753\\sketch\\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino.cpp" -o nul
Alternatives for digitalWriteFast.h: [digitalWriteFast]
ResolveLibrary(digitalWriteFast.h)
  -> candidates: [digitalWriteFast]
"C:\\arduino-1.8.12\\hardware\\tools\\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10812 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\cores\\arduino" "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\variants\\mega" "-IC:\\Users\\CrossRoadsFencing.CrossRoads\\Documents\\ArduinoStuff\\libraries\\digitalWriteFast" "C:\\Users\\CROSSR~1.CRO\\AppData\\Local\\Temp\\arduino_build_107753\\sketch\\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino.cpp" -o nul
Generating function prototypes...
"C:\\arduino-1.8.12\\hardware\\tools\\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -flto -w -x c++ -E -CC -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10812 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\cores\\arduino" "-IC:\\arduino-1.8.12\\hardware\\arduino\\avr\\variants\\mega" "-IC:\\Users\\CrossRoadsFencing.CrossRoads\\Documents\\ArduinoStuff\\libraries\\digitalWriteFast" "C:\\Users\\CROSSR~1.CRO\\AppData\\Local\\Temp\\arduino_build_107753\\sketch\\MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino.cpp" -o "C:\\Users\\CROSSR~1.CRO\\AppData\\Local\\Temp\\arduino_build_107753\\preproc\\ctags_target_for_gcc_minus_e.cpp"
runtime: out of memory: cannot allocate 12673024-byte block (1731985408 in use)
fatal error: out of memory


runtime stack:
runtime.throw(0xa35f12, 0xd)
	/home/jenkins/go-latest/src/runtime/panic.go:774 +0x64
runtime.largeAlloc(0xc15030, 0x12240100, 0x1)
	/home/jenkins/go-latest/src/runtime/malloc.go:1140 +0x108
runtime.mallocgc.func1()
	/home/jenkins/go-latest/src/runtime/malloc.go:1033 +0x39
runtime.systemstack(0x0)
	/home/jenkins/go-latest/src/runtime/asm_386.s:399 +0x53
runtime.mstart()
	/home/jenkins/go-latest/src/runtime/proc.go:1146


goroutine 1 [running]:
runtime.systemstack_switch()
	/home/jenkins/go-latest/src/runtime/asm_386.s:360 fp=0x1203fa50 sp=0x1203fa4c pc=0x454380
runtime.mallocgc(0xc15030, 0x0, 0x0, 0xffffffff)
	/home/jenkins/go-latest/src/runtime/malloc.go:1032 +0x684 fp=0x1203faa4 sp=0x1203fa50 pc=0x40ace4
[bunch more like this deleted for this post]
github.com/arduino/arduino-cli/legacy/builder.RunBuilder(...)
	/home/jenkins/workspace/arduino-builder-all-cross-cli-inception/src/github.com/arduino/arduino-cli/legacy/builder/builder.go:211
main.main()
	/home/jenkins/workspace/arduino-builder-all-cross-cli-inception/src/github.com/arduino/arduino-builder/main.go:399 +0x689 fp=0x1203ffb0 sp=0x1203fe80 pc=0x905e39
runtime.main()
	/home/jenkins/go-latest/src/runtime/proc.go:203 +0x1e6 fp=0x1203fff0 sp=0x1203ffb0 pc=0x42e326
runtime.goexit()
	/home/jenkins/go-latest/src/runtime/asm_386.s:1325 +0x1 fp=0x1203fff4 sp=0x1203fff0 pc=0x455c91


goroutine 6 [syscall, 1 minutes]:
os/signal.signal_recv(0x0)
	/home/jenkins/go-latest/src/runtime/sigqueue.go:147 +0x12f
os/signal.loop()
	/home/jenkins/go-latest/src/os/signal/signal_unix.go:23 +0x1a
created by os/signal.init.0
	/home/jenkins/go-latest/src/os/signal/signal_unix.go:29 +0x37
C:\arduino-1.8.12\arduino-builder returned 2
Error compiling for board Arduino Mega or Mega 2560.

After 9, it had compiled ok

Sketch uses 4426 bytes (1%) of program storage space. Maximum is 253952 bytes.
Global variables use 291 bytes (3%) of dynamic memory, leaving 7901 bytes for local variables. Maximum is 8192 bytes.

MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino (49.3 KB)

You give a compact and highly technical description of the issue. Downloaded the sketch.

There are if:s commented out. Counting active if:s I land at this line:

    if (upDown == 3 && homing == 1) { // stop

Correct?

Yes, there are some if’s commented out, I am using that to read Serial.print data from the Serial Monitor, or Software Serail from a 1284P board.

I did see a couple lines like you found where the && homing ==1 ; those were to be deleted and I missed them. I took those out and reviewed the closed braces.
It appeared that seemed to have fixed things. Until I closed the IDE, and restarted, and the problem was back again.

Here it is with the homing tests fixed up. I can get up thru Case 11 if I recompile a couple of times. It thinks on the “Generating function prototypes…” for a while, then finishes the compile. I haven’t been able to get any farther tho.

MegaDirectrDriveTestULN2003WriteFastDiscreteCaseMotorNumber.ino (49.3 KB)

CrossRoads:
Here it is with the homing tests fixed up. shes the compile. I haven't been able to get any farther tho.

I downloaded that program and it compiled first time.

(Well, second time, because I had to change to #include "digitalWriteFast.h" because I don't have that in my libraries system)

I use IDE 1.8.6

Why not put the blocks of code for the motors into functions ?
Won't you need a separate stepNumber for each motor?

I wonder if you could use digitalWriteFast() in a Class? This project is crying out for a Class

...R

Hmm. Reverted to 1.8.4, the latest I have set up on my start menu, compiled no problem.
Wonder what's broken in 1.8.12?

Thanks for the suggestion to use an earlier version.

How would having each motor in a function offer an advantage over having each one in a switch:case block?
Or in a class? (I've never written a class; or a library.)

The pins in digitalWriteFast need to be called out discretely so they are known at compile time, vs being passed around as variables. This way seems to do that.

CrossRoads:
How would having each motor in a function offer an advantage over having each one in a switch:case block?

The advantage IMHO would be neater code.

Or in a class? (I’ve never written a class; or a library.)

With a class you only need to write the code once for all the instances. Then you can create an array of the instances and iterate over that. Also a class (like struct) is a neat way to hold all the data for a single instance.

What I don’t know is whether the requirement of digitalWriteFast() to identify the pin numbers at compile time is compatible with creating a class and then creating a series of instances of the class each with it’s own set of pin numbers.

Given the scope of your project I’m inclined to think it would be worth making a special version of digitalWriteFast() that does work in your system - you could drop all the junk from the library that deals with other microprocessors.

…R

PS … I’m fascinated by this project but I don’t have the space to make one myself

Following some experimentation I don’t think it works with a class. The essence of a class is that you define the data and code and then at a slightly stage you create the instances of the class and provide the data (in this case the pin numbers). Even though the numbers are just numbers the compiler does not see them as constants and the standard digitalWriteFast() defaults to using the regular digitalWrite()

When I removed the code that checks if it is a constant from the digitalWriteFast library the ordinary use of digitalWriteFast() was unaffected but the time for the class was about twice as slow as the regular digitalWrite()

I wonder is there some way to trick the compiler into thinking that the “variables” holding the pin numbers are “constant”?

This is my very crude test code (with the normal digitalWriteFast library)

// python-build-start
// action, upload
// board, arduino:avr:mega:cpu=atmega2560
// port, /dev/ttyACM0
// ide, 1.8.6
// python-build-end

const byte stepperPin1 = 4;
const byte stepperPin2 = 5;
const byte stepperPin3 = 6;
const byte stepperPin4 = 7;

unsigned long startMicros;
unsigned long endMicros;

char tableDirection = 'F';

#include "digitalWriteFast.h"

class SlowClass {
    public:
        SlowClass(byte p1, byte p2, byte p3, byte p4) {
            stepperPin1 = p1;
            stepperPin2 = p2;
            stepperPin3 = p3;
            stepperPin4 = p4;

            pinMode(stepperPin1, OUTPUT);
            pinMode(stepperPin2, OUTPUT);
            pinMode(stepperPin3, OUTPUT);
            pinMode(stepperPin4, OUTPUT);
        }

        void moveOneFullStepSlow(char dir) {

        static byte stepSequence = 0;

        if(dir == 'F'){
            stepSequence ++;
        }else{
            stepSequence --;
        }

        if(stepSequence > 3){
            stepSequence = 0;
        }
        if(stepSequence < 0){
            stepSequence = 3;
        }

        switch(stepSequence){
            case 0:
                 digitalWrite(stepperPin1, HIGH);
                 digitalWrite(stepperPin2, HIGH);
                 digitalWrite(stepperPin3, LOW);
                 digitalWrite(stepperPin4, LOW);
                break;
            case 1:
                 digitalWrite(stepperPin1, LOW);
                 digitalWrite(stepperPin2, HIGH);
                 digitalWrite(stepperPin3, HIGH);
                 digitalWrite(stepperPin4, LOW);
                break;
            case 2:
                 digitalWrite(stepperPin1, LOW);
                 digitalWrite(stepperPin2, LOW);
                 digitalWrite(stepperPin3, HIGH);
                 digitalWrite(stepperPin4, HIGH);
                break;
            case 3:
                 digitalWrite(stepperPin1, HIGH);
                 digitalWrite(stepperPin2, LOW);
                 digitalWrite(stepperPin3, LOW);
                 digitalWrite(stepperPin4, HIGH);
                break;
        }
    }
    private:
        byte stepperPin1;
        byte stepperPin2;
        byte stepperPin3;
        byte stepperPin4;
};



class FastClass {
    public:
        byte stepperPin1;
        byte stepperPin2;
        byte stepperPin3;
        byte stepperPin4;

        FastClass(byte p1, byte p2, byte p3, byte p4) {
            stepperPin1 = p1;
            stepperPin2 = p2;
            stepperPin3 = p3;
            stepperPin4 = p4;

            pinMode(stepperPin1, OUTPUT);
            pinMode(stepperPin2, OUTPUT);
            pinMode(stepperPin3, OUTPUT);
            pinMode(stepperPin4, OUTPUT);
        }

        void moveOneFullStepFast(char dir) {

        static byte stepSequence = 0;

        if(dir == 'F'){
            stepSequence ++;
        }else{
            stepSequence --;
        }

        if(stepSequence > 3){
            stepSequence = 0;
        }
        if(stepSequence < 0){
            stepSequence = 3;
        }

        switch(stepSequence){
            case 0:
                 digitalWriteFast(stepperPin1, HIGH);
                 digitalWriteFast(stepperPin2, HIGH);
                 digitalWriteFast(stepperPin3, LOW);
                 digitalWriteFast(stepperPin4, LOW);
                break;
            case 1:
                 digitalWriteFast(stepperPin1, LOW);
                 digitalWriteFast(stepperPin2, HIGH);
                 digitalWriteFast(stepperPin3, HIGH);
                 digitalWriteFast(stepperPin4, LOW);
                break;
            case 2:
                 digitalWriteFast(stepperPin1, LOW);
                 digitalWriteFast(stepperPin2, LOW);
                 digitalWriteFast(stepperPin3, HIGH);
                 digitalWriteFast(stepperPin4, HIGH);
                break;
            case 3:
                 digitalWriteFast(stepperPin1, HIGH);
                 digitalWriteFast(stepperPin2, LOW);
                 digitalWriteFast(stepperPin3, LOW);
                 digitalWriteFast(stepperPin4, HIGH);
                break;
        }
    }
    private:

};

SlowClass slow(4,5,6,7);

FastClass fast(4,5,6,7);

void setup() {
    Serial.begin(115200);
    Serial.println("Starting NoLibraryTest.ino");

    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        moveOneFullStepSlow('F');
    }
    endMicros = micros();
    Serial.print("SLOW   ");
    Serial.println(endMicros - startMicros); // 2788

    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        moveOneFullStepFast('F');
    }
    endMicros = micros();
    Serial.print("Fast   ");
    Serial.println(endMicros - startMicros); // 288



    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        fast.moveOneFullStepFast('F');
    }
    endMicros = micros();
    Serial.print("Fast Class   ");
    Serial.println(endMicros - startMicros); // 2700

    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        slow.moveOneFullStepSlow('F');
    }
    endMicros = micros();
    Serial.print("Slow Class   ");
    Serial.println(endMicros - startMicros); // 2700
}

void loop() {

}

void moveOneFullStepFast(char dir) {

    static char stepSequence = 0;

    if(dir == 'F'){
        stepSequence ++;
    }else{
        stepSequence --;
    }

    if(stepSequence > 3){
        stepSequence = 0;
    }
    if(stepSequence < 0){
        stepSequence = 3;
    }

    switch(stepSequence){
        case 0:
             digitalWriteFast(stepperPin1, HIGH);
             digitalWriteFast(stepperPin2, HIGH);
             digitalWriteFast(stepperPin3, LOW);
             digitalWriteFast(stepperPin4, LOW);
            break;
        case 1:
             digitalWriteFast(stepperPin1, LOW);
             digitalWriteFast(stepperPin2, HIGH);
             digitalWriteFast(stepperPin3, HIGH);
             digitalWriteFast(stepperPin4, LOW);
            break;
        case 2:
             digitalWriteFast(stepperPin1, LOW);
             digitalWriteFast(stepperPin2, LOW);
             digitalWriteFast(stepperPin3, HIGH);
             digitalWriteFast(stepperPin4, HIGH);
            break;
        case 3:
             digitalWriteFast(stepperPin1, HIGH);
             digitalWriteFast(stepperPin2, LOW);
             digitalWriteFast(stepperPin3, LOW);
             digitalWriteFast(stepperPin4, HIGH);
            break;
    }


}

void moveOneFullStepSlow(char dir) {

    static char stepSequence = 0;

    if(dir == 'F'){
        stepSequence ++;
    }else{
        stepSequence --;
    }

    if(stepSequence > 3){
        stepSequence = 0;
    }
    if(stepSequence < 0){
        stepSequence = 3;
    }

    switch(stepSequence){
        case 0:
             digitalWrite(stepperPin1, HIGH);
             digitalWrite(stepperPin2, HIGH);
             digitalWrite(stepperPin3, LOW);
             digitalWrite(stepperPin4, LOW);
            break;
        case 1:
             digitalWrite(stepperPin1, LOW);
             digitalWrite(stepperPin2, HIGH);
             digitalWrite(stepperPin3, HIGH);
             digitalWrite(stepperPin4, LOW);
            break;
        case 2:
             digitalWrite(stepperPin1, LOW);
             digitalWrite(stepperPin2, LOW);
             digitalWrite(stepperPin3, HIGH);
             digitalWrite(stepperPin4, HIGH);
            break;
        case 3:
             digitalWrite(stepperPin1, HIGH);
             digitalWrite(stepperPin2, LOW);
             digitalWrite(stepperPin3, LOW);
             digitalWrite(stepperPin4, HIGH);
            break;
    }


}

…R

Yes, when I had the pins in an array called them out index, that tested out to be 16uS slower per step then having them all discrete like I have now.
I'm rearranging the pin callouts now to make cable harnesses more straightforward.

[Edit - picture replaced. I had the Double Row names reversed.]

It has occurred to me that my sense of how the class (in Reply #6 above) would work was wrong. The digitalWriteFast library needs to know the pin number at the moment the macro is expanded and not, more generally, “at compile time”.

It also seems to me that it should be possible to write some code that translates something like myDigitalWrite(myPin, value) into the appropriate low level port manipulation code and calls the low level code directly. As it is only needed for one type of Arduino and as all the manipulations are in the digitalWriteFast library it should not be quite so difficult.

I might explore this later.

…R

I was originally thinking to do something like this:
Say these pins were all on PORTF, bits 3-0:

             switch (stepNumber) {         // 0110, 1100, 1001, 0011
                case 0:
                  digitalWriteFast (23, 0); // 0110
                  digitalWriteFast (25, 1);
                  digitalWriteFast (27, 1);
                  digitalWriteFast (29, 0);
                  stepNumber = 1;
                  delayMicroseconds (onTime);
                  break;
                case 1:
                  digitalWriteFast (23, 1); // 1100
                  digitalWriteFast (25, 1);
                  digitalWriteFast (27, 0);
                  digitalWriteFast (29, 0);
                  stepNumber = 2;
                  delayMicroseconds (onTime);
                  break;
                case 2:
                  digitalWriteFast (23, 1); // 1001
                  digitalWriteFast (25, 0);
                  digitalWriteFast (27, 0);
                  digitalWriteFast (29, 1);
                  stepNumber = 3;
                  delayMicroseconds (onTime);
                  break;
                case 3:
                  digitalWriteFast (23, 0); // 0011
                  digitalWriteFast (25, 0);
                  digitalWriteFast (27, 1);
                  digitalWriteFast (29, 1);
                  stepNumber = 0;
                  delayMicroseconds (onTime);
                  break;
              }
            break; // upDown1

Then replace each section like so:

             switch (stepNumber) {         // 0110, 1100, 1001, 0011
                case 0:
                 PORTF = PORTF & 0xF0; // clear lower bits
                 PORTF = PORTF | 0b00110;
                  stepNumber = 1;
                  delayMicroseconds (onTime);
                  break;
                case 1:
                 PORTF = PORTF & 0xF0; // clear lower bits
                 PORTF = PORTF | 0b00001100; // bring in new bits
                  stepNumber = 2;
                  delayMicroseconds (onTime);
                  break;
                case 2:
                 PORTF = PORTF & 0xF0; // clear lower bits
                 PORTF = PORTF | 0b00001001;
                  stepNumber = 3;
                  delayMicroseconds (onTime);
                  break;
                case 3:
                 PORTF = PORTF & 0xF0; // clear lower bits
                 PORTF = PORTF | 0b00000011;
                  stepNumber = 0;
                  delayMicroseconds (onTime);
                  break;
              }
            break; // upDown1

Makes for terrible wiring a Mega tho, as the ports are mapped all over the board

/* Mega port assignments
    Port A, A7-A0: 29,28,27,26,25,24,23,22
    Port B, B7-B0: 13,12,11,10,50,51,52,53
    Port C, C7-C0: 30,31,32,33,34,35,36,37
    Port D, D7-D0: 38,na,na,na,18,19,20,21 38 + RX1, TX1, SDA, SCL
    Port E, E7-E0: na,na,3, 2, 5, na,1, 0
    Port F, F7-F0: 61,60,59,58,57,56,55,54  ADC7-ADC0
    Port G, G7-G0: na,na,4, na,na,39,40,41
    Port H, H7-H0: na,9, 8, 7, 6, na,16,17 9,8,7,6 + RX2, TX2
    Port J, J7-J0; na,na,na,na,na,na,14,15 RX3, TX3
    Port K, K7-K0: 69,68,67,66,65,64,63,62 ADC15-ADC8
    Port L, L7-L0: 42,43,44,45,46,47,48,49
*/

I wanted to use 1x4 headers going out to each motor.
Only 5 of the ports support that.
On the double row header, they go back and forth across the header, so 2x2 headers are needed.
I suppose I could use 8-pin connectors for all headers, and just grab the needed wires from here & there to go out to a motor, but that is pretty messy mechanically and not very modular.
So I'll stick with digitalWriteFast for now

I have been attempting to take digitalWriteFast() out of its shell but so far without success.

This simple program works as expected (lights an LED on pin 4).

#include "digitalWriteFast.h"

byte stepperPin = 4;
byte port1;
byte port1pin;



void setup() {
    Serial.begin(115200);
    Serial.println("Starting DPMbasicsDWF.ino");

    pinMode(stepperPin, OUTPUT);
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);

    digitalWriteFast(stepperPin, HIGH);
    delay(1000);
    digitalWriteFast(stepperPin, LOW);

    Serial.println("Finished");
}

//=========

void loop() {

}

In this version I have copied the MACRO stuff for the Atmega 2560 from the digitalWriteFast.h file an included it directly in the .ino flle. And I have created a couple of short functions to get the Port and Pin values using the macros. Then I use the BIT_WRITE macro to set the state of the I/O pin - but the LED does not light.

I suspect I am missing something that will be very obvious to the C++ experts.

#ifndef BIT_READ
# define BIT_READ(value, bit)            ((value) &   (1UL << (bit)))
#endif
#ifndef BIT_SET
# define BIT_SET(value, bit)             ((value) |=  (1UL << (bit)))
#endif
#ifndef BIT_CLEAR
# define BIT_CLEAR(value, bit)           ((value) &= ~(1UL << (bit)))
#endif
#ifndef BIT_WRITE
# define BIT_WRITE(value, bit, bitvalue) (bitvalue ? BIT_SET(value, bit) : BIT_CLEAR(value, bit))
#endif

#define __digitalPinToPortReg(P) \
(((P) >= 22 && (P) <= 29) ? &PORTA : \
((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PORTB : \
(((P) >= 30 && (P) <= 37) ? &PORTC : \
((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PORTD : \
((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PORTE : \
(((P) >= 54 && (P) <= 61) ? &PORTF : \
((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PORTG : \
((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PORTH : \
(((P) == 14 || (P) == 15) ? &PORTJ : \
(((P) >= 62 && (P) <= 69) ? &PORTK : &PORTL))))))))))

#define __digitalPinToBit(P) \
(((P) >=  7 && (P) <=  9) ? (P) - 3 : \
(((P) >= 10 && (P) <= 13) ? (P) - 6 : \
(((P) >= 22 && (P) <= 29) ? (P) - 22 : \
(((P) >= 30 && (P) <= 37) ? 37 - (P) : \
(((P) >= 39 && (P) <= 41) ? 41 - (P) : \
(((P) >= 42 && (P) <= 49) ? 49 - (P) : \
(((P) >= 50 && (P) <= 53) ? 53 - (P) : \
(((P) >= 54 && (P) <= 61) ? (P) - 54 : \
(((P) >= 62 && (P) <= 69) ? (P) - 62 : \
(((P) == 0 || (P) == 15 || (P) == 17 || (P) == 21) ? 0 : \
(((P) == 1 || (P) == 14 || (P) == 16 || (P) == 20) ? 1 : \
(((P) == 19) ? 2 : \
(((P) == 5 || (P) == 6 || (P) == 18) ? 3 : \
(((P) == 2) ? 4 : \
(((P) == 3 || (P) == 4) ? 5 : 7)))))))))))))))

byte stepperPin = 4;
byte port1;
byte port1pin;



void setup() {
    Serial.begin(115200);
    Serial.println("Starting DPMbasicsXX.ino");

    pinMode(stepperPin, OUTPUT);
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);

    port1 = pinToPort(stepperPin);
    port1pin = pinToPortPin(stepperPin);

        // view some of the values
    Serial.print("PORT1 "); Serial.println(port1);
    Serial.print("PIN "); Serial.println(port1pin);
    unsigned int PORTGval = &PORTG;
    Serial.print("PORTG "); Serial.println(PORTGval);

    BIT_WRITE(port1, port1pin, HIGH);
    delay(1000);
    //~ BIT_WRITE(port1, port1pin, LOW);

    Serial.println("Finished");
}

//=========

void loop() {

}

//============

        byte* pinToPort(byte pin) {
            byte* portVal;
            portVal = __digitalPinToPortReg(pin);
            return portVal;
        }


//===========
        byte pinToPortPin(byte pin) {
            byte portPin;
            portPin = __digitalPinToBit(pin);
            return portPin;
        }

…R

Just realised that I don't need to copy the code out of the digitalWriteFast library. I believe the following shorter program is equivalent to the second program in Reply #10.

Of course the outcome is the same as the code in Reply #10 - the LED does not light.

#include "digitalWriteFast.h"

byte stepperPin = 4;
byte port1;
byte port1pin;



void setup() {
    Serial.begin(115200);
    Serial.println("Starting DPMbasicsBB.ino");

    pinMode(stepperPin, OUTPUT);
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);

    port1 = pinToPort(stepperPin);
    port1pin = pinToPortPin(stepperPin);

        // view some of the values
    Serial.print("PORT1 "); Serial.println(port1);
    Serial.print("PIN "); Serial.println(port1pin);
    unsigned int PORTGval = &PORTG;
    Serial.print("PORTG "); Serial.println(PORTGval);

    BIT_WRITE(port1, port1pin, HIGH);
    delay(1000);
    //~ BIT_WRITE(port1, port1pin, LOW);

    Serial.println("Finished");
}

//=========

void loop() {

}

//============

        byte* pinToPort(byte pin) {
            byte* portVal;
            portVal = __digitalPinToPortReg(pin);
            return portVal;
        }


//===========
        byte pinToPortPin(byte pin) {
            byte portPin;
            portPin = __digitalPinToBit(pin);
            return portPin;
        }

...R

I figured it out - I had my pointers confused. It should be like the following. I will leave the previous Reply for anyone who is interested to follow the developments.

Next thing will be to build this into a class - and see how it performs.

#include "digitalWriteFast.h"

byte stepperPin = 4;
byte *port1;
byte port1pin;



void setup() {
    Serial.begin(115200);
    Serial.println("Starting DPMbasicsBB.ino");

    pinMode(stepperPin, OUTPUT);
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);

    port1 = pinToPort(stepperPin);
    port1pin = pinToPortPin(stepperPin);
    BIT_WRITE(*port1, port1pin, HIGH);
    delay(1000);
    BIT_WRITE(*port1, port1pin, LOW);

    Serial.println("Finished");
}

//=========

void loop() {

}

//============

        byte* pinToPort(byte pin) {
            byte *portVal;
            portVal = __digitalPinToPortReg(pin);
            return portVal;
        }


//===========
        byte pinToPortPin(byte pin) {
            byte portPin;
            portPin = __digitalPinToBit(pin);
            return portPin;
        }

...R

The code below is my speed test.

Using the regular digitalWrite() the 100 iterations take 2844 µsecs.
Using digitalWriteFast() in the normal way only takes 288 µsecs - a huge improvement
Using the concepts of digitalWriteFast in a class results in a disappointing 1344 µsecs - nearly 5 times as long as the normal digitalWriteFast.

I presume it is so slow in a class because the values have to retrieved from variables and I can’t think of how that could be avoided.

My conclusion is that when speed is important it will be necessary to use the digitalWriteFast library directly even if that means a lot of code repetition.

// python-build-start
// action, upload
// board, arduino:avr:mega:cpu=atmega2560
// port, /dev/ttyACM0
// ide, 1.8.6
// python-build-end

const byte stepperPin1 = 4;
const byte stepperPin2 = 5;
const byte stepperPin3 = 6;
const byte stepperPin4 = 7;

unsigned long startMicros;
unsigned long endMicros;

char tableDirection = 'F';

#include "digitalWriteFast.h"

class DPMClass {
    public:
        byte stepperPin1;
        byte stepperPin2;
        byte stepperPin3;
        byte stepperPin4;

        byte *port1;
        byte *port2;
        byte *port3;
        byte *port4;

        byte port1pin;
        byte port2pin;
        byte port3pin;
        byte port4pin;

        //============

        DPMClass(byte p1, byte p2, byte p3, byte p4) {
            stepperPin1 = p1;
            stepperPin2 = p2;
            stepperPin3 = p3;
            stepperPin4 = p4;

            pinMode(stepperPin1, OUTPUT);
            pinMode(stepperPin2, OUTPUT);
            pinMode(stepperPin3, OUTPUT);
            pinMode(stepperPin4, OUTPUT);

            port1 = pinToPort(stepperPin1);
            port2 = pinToPort(stepperPin2);
            port3 = pinToPort(stepperPin3);
            port4 = pinToPort(stepperPin4);

            port1pin = pinToPortPin(stepperPin1);
            port2pin = pinToPortPin(stepperPin2);
            port3pin = pinToPortPin(stepperPin3);
            port4pin = pinToPortPin(stepperPin4);
        }

        //============

        byte* pinToPort(byte pin) {
            byte *portVal;
            portVal = __digitalPinToPortReg(pin);
            return portVal;
        }

        byte pinToPortPin(byte pin) {
            byte portPin;
            portPin = __digitalPinToBit(pin);
            return portPin;
        }

        //============

        void moveOneFullStepDPM(char dir) {

            static byte stepSequence = 0;

            if(dir == 'F'){
                stepSequence ++;
            }else{
                stepSequence --;
            }

            if(stepSequence > 3){
                stepSequence = 0;
            }
            if(stepSequence < 0){
                stepSequence = 3;
            }

            switch(stepSequence){
                case 0:
                     BIT_WRITE(*port1, port1pin, HIGH);
                     BIT_WRITE(*port2, port2pin, HIGH);
                     BIT_WRITE(*port3, port3pin, LOW);
                     BIT_WRITE(*port4, port4pin, HIGH);
                    break;
                case 1:
                     BIT_WRITE(*port1, port1pin, LOW);
                     BIT_WRITE(*port2, port2pin, HIGH);
                     BIT_WRITE(*port3, port3pin, HIGH);
                     BIT_WRITE(*port4, port4pin, LOW);
                    break;
                case 2:
                     BIT_WRITE(*port1, port1pin, LOW);
                     BIT_WRITE(*port2, port2pin, LOW);
                     BIT_WRITE(*port3, port3pin, HIGH);
                     BIT_WRITE(*port4, port4pin, HIGH);
                    break;
                case 3:
                     BIT_WRITE(*port1, port1pin, HIGH);
                     BIT_WRITE(*port2, port2pin, LOW);
                     BIT_WRITE(*port3, port3pin, LOW);
                     BIT_WRITE(*port4, port4pin, HIGH);
                    break;
            }
        }
    private:

};


DPMClass dpm(4,5,6,7);

void setup() {
    Serial.begin(115200);
    Serial.println("Starting ClassTestWithDPM.ino");

    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        moveOneFullStepSlow('F');
    }
    endMicros = micros();
    Serial.print("SLOW - no class   ");
    Serial.println(endMicros - startMicros); // 2812 µsecs


    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        moveOneFullStepFast('F');
    }
    endMicros = micros();
    Serial.print("Fast - no class   ");
    Serial.println(endMicros - startMicros); // 288 µsecs


    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        dpm.moveOneFullStepDPM('F');
    }
    endMicros = micros();
    Serial.print("DPM Class   ");
    Serial.println(endMicros - startMicros); // 1344 µsecs
}

void loop() {

}

void moveOneFullStepFast(char dir) {

    static char stepSequence = 0;

    if(dir == 'F'){
        stepSequence ++;
    }else{
        stepSequence --;
    }

    if(stepSequence > 3){
        stepSequence = 0;
    }
    if(stepSequence < 0){
        stepSequence = 3;
    }

    switch(stepSequence){
        case 0:
             digitalWriteFast(stepperPin1, HIGH);
             digitalWriteFast(stepperPin2, HIGH);
             digitalWriteFast(stepperPin3, LOW);
             digitalWriteFast(stepperPin4, LOW);
            break;
        case 1:
             digitalWriteFast(stepperPin1, LOW);
             digitalWriteFast(stepperPin2, HIGH);
             digitalWriteFast(stepperPin3, HIGH);
             digitalWriteFast(stepperPin4, LOW);
            break;
        case 2:
             digitalWriteFast(stepperPin1, LOW);
             digitalWriteFast(stepperPin2, LOW);
             digitalWriteFast(stepperPin3, HIGH);
             digitalWriteFast(stepperPin4, HIGH);
            break;
        case 3:
             digitalWriteFast(stepperPin1, HIGH);
             digitalWriteFast(stepperPin2, LOW);
             digitalWriteFast(stepperPin3, LOW);
             digitalWriteFast(stepperPin4, HIGH);
            break;
    }


}

void moveOneFullStepSlow(char dir) {

    static char stepSequence = 0;

    if(dir == 'F'){
        stepSequence ++;
    }else{
        stepSequence --;
    }

    if(stepSequence > 3){
        stepSequence = 0;
    }
    if(stepSequence < 0){
        stepSequence = 3;
    }

    switch(stepSequence){
        case 0:
             digitalWrite(stepperPin1, HIGH);
             digitalWrite(stepperPin2, HIGH);
             digitalWrite(stepperPin3, LOW);
             digitalWrite(stepperPin4, LOW);
            break;
        case 1:
             digitalWrite(stepperPin1, LOW);
             digitalWrite(stepperPin2, HIGH);
             digitalWrite(stepperPin3, HIGH);
             digitalWrite(stepperPin4, LOW);
            break;
        case 2:
             digitalWrite(stepperPin1, LOW);
             digitalWrite(stepperPin2, LOW);
             digitalWrite(stepperPin3, HIGH);
             digitalWrite(stepperPin4, HIGH);
            break;
        case 3:
             digitalWrite(stepperPin1, HIGH);
             digitalWrite(stepperPin2, LOW);
             digitalWrite(stepperPin3, LOW);
             digitalWrite(stepperPin4, HIGH);
            break;
    }


}

…R

Finally got the better of it :slight_smile: This class version does the 100 iterations in 420 µsecs. That’s only about 50% longer than the normal digitalWriteFast() and it’s nearly 7 times faster than the normal digitalWrite()

unsigned long startMicros;
unsigned long endMicros;

#include "digitalWriteFast.h"


class FastClass {
    public:
        byte stepperPin1;
        byte stepperPin2;
        byte stepperPin3;
        byte stepperPin4;

        byte *port1;
        byte *port2;
        byte *port3;
        byte *port4;

        byte port1pin;
        byte port2pin;
        byte port3pin;
        byte port4pin;

        byte port1pinBIN;
        byte port2pinBIN;
        byte port3pinBIN;
        byte port4pinBIN;

        //============

        FastClass(byte p1, byte p2, byte p3, byte p4) {
            stepperPin1 = p1;
            stepperPin2 = p2;
            stepperPin3 = p3;
            stepperPin4 = p4;

            pinMode(stepperPin1, OUTPUT);
            pinMode(stepperPin2, OUTPUT);
            pinMode(stepperPin3, OUTPUT);
            pinMode(stepperPin4, OUTPUT);

            port1 = pinToPort(stepperPin1);
            port2 = pinToPort(stepperPin2);
            port3 = pinToPort(stepperPin3);
            port4 = pinToPort(stepperPin4);

            port1pin = pinToPortPin(stepperPin1);
            port2pin = pinToPortPin(stepperPin2);
            port3pin = pinToPortPin(stepperPin3);
            port4pin = pinToPortPin(stepperPin4);

            port1pinBIN = 1 << port1pin;
            port2pinBIN = 1 << port2pin;
            port3pinBIN = 1 << port3pin;
            port4pinBIN = 1 << port4pin;


        }

        //============

        byte* pinToPort(byte pin) {
            byte *portVal;
            portVal = __digitalPinToPortReg(pin);
            return portVal;
        }

        byte pinToPortPin(byte pin) {
            byte portPin;
            portPin = __digitalPinToBit(pin);
            return portPin;
        }

        //============

        void moveOneFullStepFast(char dir) {

            static byte stepSequence = 0;

            if(dir == 'F'){
                stepSequence ++;
            }else{
                stepSequence --;
            }

            if(stepSequence > 3){
                stepSequence = 0;
            }
            if(stepSequence < 0){
                stepSequence = 3;
            }

            switch(stepSequence){
                case 0:
                    *port1 |= port1pinBIN;
                    *port2 |= port2pinBIN;
                    *port3 &= ~port3pinBIN;
                    *port4 &= ~port4pinBIN;
                    break;
                case 1:
                    *port1 &= ~port1pinBIN;
                    *port2 |= port2pinBIN;
                    *port3|= port3pinBIN;
                    *port4 &= ~port4pinBIN;
                    break;
                case 2:
                    *port1 &= ~port1pinBIN;
                    *port2 &= ~port2pinBIN;
                    *port3 |= port3pinBIN;
                    *port4 |= port4pinBIN;
                    break;
                case 3:
                    *port1 |= port1pinBIN;
                    *port2 &= ~port2pinBIN;
                    *port3 &= ~port3pinBIN;
                    *port4 |= port4pinBIN;
                    break;
            }
        }
    private:

};


FastClass fast(4,5,6,7);



void setup() {
    Serial.begin(115200);
    Serial.println("Starting PORTXclassTest.ino");

    startMicros = micros();
    for (byte n = 0; n < 100; n++) {
        fast.moveOneFullStepFast('F');
    }
    endMicros = micros();
    Serial.print("Fast Class   ");
    Serial.println(endMicros - startMicros); // 420


    //~ Serial.println("Moving motor");

    //~ for (int n = 0; n < 2048; n++) {
        //~ fast.moveOneFullStepFast('F');
        //~ delay(10);
    //~ }

    //~ Serial.println("Motor finished");




}

void loop() {

}

…R

How does the direct port writes of reply #9 compare?

Okay, back to here for more hardware related discussion

CrossRoads:
How does the direct port writes of reply #9 compare?

I have not tried that - I needed to leave something for you.

I don't expect it to be a whole lot better - the code in Reply #14 is pretty much using direct port writes

*port1 |= port1pinBIN;

rather than

PORTG |= port1pinBIN;

Using PORTG is a little faster but then you have the trouble of manually figuring out which PORT each pin belongs to.

And using PORTG |= 0b00100000; would be a bit faster still (not sure that binary is correct) but then you have the additional hassle of figuring out all the binary values manually.

Remember your code is going to have a lot of other stuff to do and I suspect the differences I am talking about will be very small compared to the time taken by all the other stuff.

...R