Page 1 of 5

Help needed, crank signal generator. <solved>

Posted: Sat Apr 26, 2025 4:57 am
by AngelMarc
Updated with most recent progress https://www.youtube.com/watch?v=EXo97nUB3hk Attached file is Arduino IDE code. By default it should output 1056 RPM crank and cam signals.

Original post~
Arduino code on a PiPico. LS 24x crank signal with 1x cam.
No output on oscilloscope.

Code: Select all

int TPS = 0;
int sequence[48] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0};
int cam[48] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int tooth = 0;
int low = 0;
int high = 0;
int RPMlow = 0;
int RPMhigh = 0;
int math = 1;
int halfdone = 0;
int done = 1;
int currentmicros = 0;
int previousmicros = 0;

void setup() {
pinMode(A0, INPUT);
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
}

void loop() {

if (halfdone == 0) {
  if (currentmicros - previousmicros >= RPMlow) {
      halfdone = 1;
      done = 0;
      digitalWrite(0, 1);
      previousmicros = currentmicros;
    }
  }
if (done == 0) {
  if (currentmicros - previousmicros >= RPMhigh) {
      done = 1;
      math = 1;
      digitalWrite(0, 0);
      previousmicros = currentmicros;
    }
  }
   
if (math == 1) {
tooth++;
if (tooth == 48) {
  tooth = 0;
  }

TPS = analogRead(A0); 
sequence[tooth];
cam[tooth];
if (sequence == 0) {
  low = 1;
  high = 2; 
  }
  else {
    low = 2;
    high = 1;
  }
halfdone = 0;
math = 0;
RPMlow = low * TPS;
RPMhigh = high * TPS;
} 
}

Re: Help needed, crank signal generator.

Posted: Sat Apr 26, 2025 3:01 pm
by antus
I built it in a simulator here, its a free account so you can probably play with it there too: https://wokwi.com/projects/429266389894726657

It was a new tool to me, so I've only got 30 mins experience with it. I could figure out how to get debug output, though with a bit of work you should be able to get println data in a console and be able to use that for basic debugging more easily.

I added some extra LEDs to monitor the state of done, halfdone and math. It looks like its getting stuck every iteration.

Then I realized, I don't think there is any code to read a timer so currentmillis is always 0 and this is why the logic doesn't iterate and there is no output. I added an incrementor to current micros at the bottom but its still not enough.
currentmicros+=1000; // just to make it tick, not a real clock.

Also sequence[tooth]; and cam[tooth]; don't do anything, they resolve to values but then nothing is done with them.
I modified this line: if (sequence[tooth] == 0) to add the [tooth] so it reads the pattern from the array instead of just whatever sequence without the offset is (default offset 0? pointer? never even tried this..).
but I left the 2 that do nothing above as I don't know your intention there.

I updated those 2 lines at code, havnt looked at how to read a timer or what type of timers are available yet.

I was also unsure if you can use pin1 and pin2 as they also connected tot he UART, so I moved them to the GPIOs at the other end of the board.

I moved the logic that sets sequence (and added cam) to the top of the main loop. I think its clearer to group that functionality together and just re-set them all each loop. Personal preference design choice, though.

I also fined the pins to make it easier to see what is what and change them around if the hardware does need further adjustments.

I'll reproduce my version of the code here incase someone messes up the code in the link above.

Its not fixed, but hope it give you some things to think about and an easy way in to that simulator which might help you get it figured.

If you put a delay(500); as the end of the main loop you can see the output leds blinking at a speed visible to the human eye.

Code: Select all

#include <Arduino.h>

#define PIN_HALFDONE  4
#define PIN_DONE      5
#define PIN_MATH      6
#define PIN_SEQUENCE 14
#define PIN_CAM      15
#define PIN_INPUT    A0

int TPS = 0;
int sequence[48] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0};
int cam[48] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int tooth = 0;
int low = 0;
int high = 0;
int RPMlow = 0;
int RPMhigh = 0;
int math = 1;
int halfdone = 0;
int done = 1;
int currentmicros = 0;
int previousmicros = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Hello from the Pico!"); // Not working. But would be nice to have println debugging...
  pinMode(PIN_INPUT, INPUT);
  pinMode(PIN_SEQUENCE, OUTPUT);
  pinMode(PIN_CAM, OUTPUT);
  pinMode(PIN_HALFDONE, OUTPUT);
  pinMode(PIN_DONE, OUTPUT);
  pinMode(PIN_MATH, OUTPUT);
}

void loop() {
  // update outputs
  digitalWrite(PIN_HALFDONE, halfdone);
  digitalWrite(PIN_DONE, done);
  digitalWrite(PIN_MATH, math);
  digitalWrite(PIN_SEQUENCE, sequence[tooth]);
  digitalWrite(PIN_CAM, cam[tooth]);

  if (halfdone == 0) {
    if (currentmicros - previousmicros >= RPMlow) {
      halfdone = 1;
      done = 0;
      previousmicros = currentmicros;
    }
  }

  if (done == 0) {
    if (currentmicros - previousmicros >= RPMhigh) {
      done = 1;
      math = 1;
      previousmicros = currentmicros;
    }
  }

  // increment output state logic
  if (math == 1) {
    tooth++;
    if (tooth == 48) {
      tooth = 0;
    }

    TPS = analogRead(A0);
    sequence[tooth];
    cam[tooth];
    if (sequence[tooth] == 0) {
      low = 1;
      high = 2;
    }
    else {
      low = 2;
      high = 1;
    }
    halfdone = 0;
    math = 0;
    RPMlow = low * TPS;
    RPMhigh = high * TPS;
    //RPMlow = 100;
    //RPMhigh = 100;
    currentmicros+=1000; // just to make it tick, not a real clock.
  }
}

Code: Select all

{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-pi-pico",
      "id": "pico",
      "top": 73.65,
      "left": 13.2,
      "attrs": { "env": "arduino-community" }
    },
    { "type": "wokwi-vcc", "id": "vcc1", "top": 77.56, "left": 172.8, "attrs": {} },
    { "type": "wokwi-gnd", "id": "gnd1", "top": 19.2, "left": 172.2, "attrs": {} },
    { "type": "wokwi-potentiometer", "id": "pot1", "top": 181.1, "left": 143.8, "attrs": {} },
    {
      "type": "wokwi-led",
      "id": "led3",
      "top": 92.4,
      "left": -236.2,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led5",
      "top": 207.6,
      "left": -236.2,
      "attrs": { "color": "limegreen" }
    },
    {
      "type": "wokwi-led",
      "id": "led4",
      "top": 150,
      "left": -236.2,
      "attrs": { "color": "yellow" }
    },
    {
      "type": "wokwi-text",
      "id": "text1",
      "top": 105.6,
      "left": -201.6,
      "attrs": { "text": "halfdone" }
    },
    {
      "type": "wokwi-text",
      "id": "text2",
      "top": 163.2,
      "left": -201.6,
      "attrs": { "text": "done" }
    },
    {
      "type": "wokwi-text",
      "id": "text3",
      "top": 220.8,
      "left": -201.6,
      "attrs": { "text": "math" }
    },
    {
      "type": "wokwi-text",
      "id": "text4",
      "top": 278.4,
      "left": -201.6,
      "attrs": { "text": "sequence" }
    },
    {
      "type": "wokwi-text",
      "id": "text5",
      "top": 326.4,
      "left": -201.6,
      "attrs": { "text": "cam" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": 313.2,
      "left": -236.2,
      "attrs": { "color": "blue" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": 265.2,
      "left": -236.2,
      "attrs": { "color": "cyan" }
    }
  ],
  "connections": [
    [ "pico:GP0", "$serialMonitor:RX", "", [] ],
    [ "pico:GP1", "$serialMonitor:TX", "", [] ],
    [ "pico:GND.8", "gnd1:GND", "black", [ "v-38.4", "h116.4", "v-48" ] ],
    [ "pico:GP26", "pot1:SIG", "green", [ "h30", "v96", "h67.6" ] ],
    [ "vcc1:VCC", "pot1:VCC", "red", [ "v19.2", "h57.6", "v144", "h-47.2" ] ],
    [ "pot1:GND", "gnd1:GND", "black", [ "v38.4", "h86.4", "v-268.8" ] ],
    [ "gnd1:GND", "led3:C", "black", [ "v0", "h-432", "v115.2" ] ],
    [ "gnd1:GND", "led5:C", "black", [ "v0", "h-432", "v230.4" ] ],
    [ "vcc1:VCC", "pico:3V3", "red", [ "v0" ] ],
    [ "vcc1:VCC", "pico:ADC_VREF", "red", [ "v0" ] ],
    [ "led5:A", "pico:GP6", "green", [ "h172.8", "v-76.8", "h0", "v-9.6" ] ],
    [ "pico:GP5", "led4:A", "green", [ "h-76.8", "v48", "h-153.6" ] ],
    [ "pico:GP4", "led3:A", "green", [ "h0" ] ],
    [ "gnd1:GND", "led4:C", "black", [ "v0", "h-432", "v172.8" ] ],
    [ "pico:GP15", "led1:A", "green", [ "h-28.8", "v86.4" ] ],
    [ "gnd1:GND", "led1:C", "black", [ "v0", "h-432", "v336" ] ],
    [ "pico:GP14", "led2:A", "green", [ "h-48", "v48" ] ],
    [ "gnd1:GND", "led2:C", "black", [ "v0", "h-432", "v288" ] ]
  ],
  "dependencies": {}
}

Re: Help needed, crank signal generator.

Posted: Sat Apr 26, 2025 4:07 pm
by antus
I am not sure if the pico has a clock, but it does seem to have timers. It might be worth to play around with this example and get it using callbacks that flash the led based on the timer. https://github.com/raspberrypi/pico-exa ... lo_timer.c

Once you have that, you can add some code that reads the analog and configures the next 'tick' of the timer. Then the callback can walk down down the list of values for the output.

Or since the circuit is only doing one thing you could forgo clocks and timers all together and just have a configurable delay, then run through the logic again. I am not sure how the internal delay operates, but it doesn't matter, even if its just wasting clock cycles it'll work.

Re: Help needed, crank signal generator.

Posted: Sat Apr 26, 2025 4:21 pm
by antus
This version uses the delay approach, might be close to what you need. The speed changes as you change the pot. But I havn't applied any kind of scaling to make the RPM sain.

https://wokwi.com/projects/429275419780333569

Code: Select all

#include <Arduino.h>

#define PIN_SEQUENCE 14
#define PIN_CAM      15
#define PIN_INPUT    A0

int tps = 0;
int tooth;
int sequence[48] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0};
int cam[48] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Hello from the Pico!");
  pinMode(PIN_INPUT, INPUT);
  pinMode(PIN_SEQUENCE, OUTPUT);
  pinMode(PIN_CAM, OUTPUT);
}

void loop() {
  for (tooth=0; tooth<48; tooth++)  {
    digitalWrite(PIN_SEQUENCE, sequence[tooth]);
    digitalWrite(PIN_CAM, cam[tooth]);
    tps = analogRead(A0); // 0-1023
    delay(tps);
  }
}
diagam.json

Code: Select all

{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-pi-pico",
      "id": "pico",
      "top": 73.65,
      "left": 13.2,
      "attrs": { "env": "arduino-community" }
    },
    { "type": "wokwi-vcc", "id": "vcc1", "top": 77.56, "left": 172.8, "attrs": {} },
    { "type": "wokwi-gnd", "id": "gnd1", "top": 115.2, "left": -135, "attrs": {} },
    { "type": "wokwi-potentiometer", "id": "pot1", "top": 171.5, "left": 143.8, "attrs": {} },
    {
      "type": "wokwi-text",
      "id": "text4",
      "top": 192,
      "left": -192,
      "attrs": { "text": "sequence" }
    },
    {
      "type": "wokwi-text",
      "id": "text5",
      "top": 230.4,
      "left": -192,
      "attrs": { "text": "cam" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": 226.8,
      "left": -236.2,
      "attrs": { "color": "blue" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": 178.8,
      "left": -236.2,
      "attrs": { "color": "cyan" }
    }
  ],
  "connections": [
    [ "pico:GP0", "$serialMonitor:RX", "", [] ],
    [ "pico:GP1", "$serialMonitor:TX", "", [] ],
    [ "vcc1:VCC", "pot1:VCC", "red", [ "v19.2", "h57.6", "v144", "h-47.2" ] ],
    [ "pot1:GND", "gnd1:GND", "black", [ "v38.4", "h86.4", "v-249.6", "h-412.8" ] ],
    [ "vcc1:VCC", "pico:3V3", "red", [ "v0" ] ],
    [ "vcc1:VCC", "pico:ADC_VREF", "red", [ "v0" ] ],
    [ "pico:GP15", "led1:A", "green", [ "h-28.8", "v86.4" ] ],
    [ "gnd1:GND", "led1:C", "black", [ "v-86.4", "h-124.8", "v240" ] ],
    [ "pico:GP14", "led2:A", "green", [ "h-220.8", "v-38.4" ] ],
    [ "gnd1:GND", "led2:C", "black", [ "v-86.4", "h-124.8", "v192" ] ],
    [ "pot1:SIG", "pico:GP26", "green", [ "v28.8", "h-67.6", "v-96" ] ]
  ],
  "dependencies": {}
}

Re: Help needed, crank signal generator.

Posted: Sat Apr 26, 2025 11:24 pm
by AngelMarc
A bunch of arbitrary syntax stuff.
I got it working less than a minute ago.
Just need to add back the speed variation input, then figure out some simple analog input hysteresis code.
And I might need to invert polarity.

Code: Select all

int TPS = 0;
int sequence[48] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0};
int cam[48] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int tooth = 0;
int low = 0;
int high = 0;
int RPMlow = 0;
int RPMhigh = 0;
int math = 1;
int halfdone = 1;
int done = 1;
int width = 1;
unsigned long previousmicros = 0;

void setup() {
//pinMode(A0, INPUT);
pinMode(1, OUTPUT);

}

void loop() {

if (halfdone == 0) {
  if (micros() - previousmicros >= RPMlow) {
      halfdone = 1;
      done = 0;
      digitalWrite(1, HIGH);
      previousmicros = micros();
    }
  }
if (done == 0) {
  if (micros() - previousmicros >= RPMhigh) {
      done = 1;
      math = 1;
      digitalWrite(1, LOW);
      previousmicros = micros();
    }
  }
   
if (math == 1) {
tooth++;
if (tooth == 48) {
  tooth = 0;
  }

TPS = 666; 
width = sequence[tooth];
cam[tooth];
if (width == 0) {
  low = 1;
  high = 2; 
  }
if (width == 1) {
    low = 2;
    high = 1;
  }
halfdone = 0;
math = 0;
RPMlow = low * TPS;
RPMhigh = high * TPS;
} 
}


Re: Help needed, crank signal generator.

Posted: Sat Apr 26, 2025 11:27 pm
by AngelMarc
antus wrote: Sat Apr 26, 2025 4:21 pm

Code: Select all

#include <Arduino.h>

#define PIN_SEQUENCE 14
#define PIN_CAM      15
#define PIN_INPUT    A0

int tps = 0;
int tooth;
int sequence[48] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0};
int cam[48] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Hello from the Pico!");
  pinMode(PIN_INPUT, INPUT);
  pinMode(PIN_SEQUENCE, OUTPUT);
  pinMode(PIN_CAM, OUTPUT);
}

void loop() {
  for (tooth=0; tooth<48; tooth++)  {
    digitalWrite(PIN_SEQUENCE, sequence[tooth]);
    digitalWrite(PIN_CAM, cam[tooth]);
    tps = analogRead(A0); // 0-1023
    delay(tps);
  }
}

That looks very professional.

Re: Help needed, crank signal generator. <solved>

Posted: Sat Apr 26, 2025 11:54 pm
by AngelMarc
https://www.youtube.com/watch?v=48IeKSYfaHU
Deleted video when I uploaded a better one with further progress.

Re: Help needed, crank signal generator. <solved>

Posted: Sat Apr 26, 2025 11:59 pm
by AngelMarc
Oh, and the original reason I didn't use delays, was for monitoring analog input levels, so reasons for unexpected outputs could be traced.

Re: Help needed, crank signal generator. <solved>

Posted: Sun Apr 27, 2025 9:56 am
by AngelMarc
According to oscilloscope readings, it currently goes between 810 and 83,160 RPM.
lol I think I'll divide by 8 or something.

Re: Help needed, crank signal generator. <solved>

Posted: Sun Apr 27, 2025 10:15 am
by antus
Good stuff. Can you add the cam and is a PCM reading it ok as a real trigger? I assume this is a part of a bench test suite signal generator?