Arduino based crank/cam wheel simulator: ardu-stim

Arduino based crank/cam wheel simulator: ardu-stim

UPDATE 07/14/2015:  Precompiled binaries of the Ardu-Stim arduino code are available at:

UPDATE 03/26/2015:  The git repository has changed as per this link to  Apologies for the confusion!

UPDATE 9/19/2014: ardustim now has analog pot control for when you don’t want to use the serial interface.  Connect a pot between 5V and ground with the wiper connected to Analog-0.   5 seconds after power-up it’ll default to reading the pot for it’s RPM source, resolution is a bit poor at low RPM’s (about 16 RPM) but the control is liquid smooth, range is 16-16,000 RPM which should cover the majority of cases.  Firing up druid4arduino will take control away from the Pot, and closing druid4arduino will reconnect to the pot after 5 seconds.

We are pleased to announce a rapidly developing tool for generating precise crank/cam trigger wheel patterns with an Arduino. This tool is called “ardu-stim”, thus it leverages an off-the-shelf Arduino Uno or clone, an inexpensive, low cost, super easy to program micro-controller. Arduino’s and their clones are currently very popular, inexpensive, and readily available from multiple places like SparkFunAdafruit, and Ebay among others.  There’s a huge amount of easy to access tutorials and knowledge out there, and they work well for all sorts of special purpose applications.

Ardu-stim is currently in heavy development, but even at it’s young age it is capable of simulating 30+ wheels at in excess of 12,000 “virtual” RPM, and most wheel patterns are precisely emitted to well over 65,000 virtual RPM (user controlled via a USB/serial interface with either druid4arduino or a simple serial terminal).  This tool is designed at current to be used for regression testing ECU firmware, and to test edge cases.  “Bad” wheel patterns can be created to test how well different ECU’s deal with suspect/marginal and garbage patterns.

Right now, development is done on an Arduino Uno or clone, (ATMega 328 CPU ONLY).  It has NOT BEEN TESTED on other ardunio capable CPU’s, however we recommend that you stay with the Uno for the time being, as its developed on that platform.  The code utilizes processor specific low level resources (Timers 1 and 2 in CTC  mode).  So for optimal compatibility if you want to try it,  we’d recommend you pick up an Arduino Uno (from $15-30 depending where you find it).

Why did we create this, when there’s other solutions out there (JimStim, FreeEMS+Lacerated Pempheridae (winner of the most interesting name award) Well: Jimstim is closed source, somewhat expensive, and has signal/pattern degradation at high rpm and cannot do all the wheel types that we needed for our project (LibreEMS), and tends to brick itself at the most inopportune moment (happened on 4 separate occasions to yours truly).  FREEMS+LP requires a whole ECU or TA card which is very expensive (for a pattern generator), and cannot do all wheel patterns either.  Ardu-stim is Open-Source, cheap, extensible, and reasonably easy to use, can handle 1-deg resolution wheel patterns up to 12,000+ RPM, and other less complex patterns to much higher RPM ranges.

The code is located at the following git repository and you’ll need the Arduino tools (available for Mac, Linux (check your repo’s) and Windows).  You’ll need to setup the SerialUI arduino library on your end as well as it’s required to compile the ardu-stim code for your Arduino device.  It’s by far easiest to setup on Linux (apt-get install arduino for debian/ubuntu systems) as there’s no need to worry about USB->serial drivers like on windows or OS-X as they tend to”just work” on linux, unlike windows and Mac which require manually installing the driver specific to the USB->Serial bridge chip soldered onto your arduino or clone board.

The primary (typically crank) signal is output on Arduino digital pin 8, and the (secondary) cam signal (or inner ring signal on dual ring crank/cam wheels) is on pin 9.   Pin 7 is currently a debug signal used to verify ISR timing, so don’t use that pin.  Interaction is provided by the Arduino SerialUI Library, in conjunction with either Druid4Arduino or a generic serial terminal client (minicom, cutecom, putty, etc).  The Arduino SerialUI library provides simple interactive menus to work with ardu-stim.

An issue tracker is set up at to file bug reports or feature requests.

To clone the repository run the following: git clone  Due to heavy development there are usually changes often,  so pull often to stay current…

[gmedia id=10]

Tagged with: , , , , ,

139 Comments on “Arduino based crank/cam wheel simulator: ardu-stim

  1. I used Ardu-stim for 2 weeks and it was the exact tool I need. I was prototyping an engine controller and needed to give it reliable inputs in order to accurately gauge how my controller was reacting.

    At my engine research lab at the University of Alberta, we used to mimic engine signals for prototyping by using an electric motor to turn a gear with a few missing teeth. That gear was then read by a hall effect sensor. However this system was always a pain to setup and wasn’t perfect. Break down and large amounts of noise made just getting clean signals to a controller lots of work. Ardu-stim saved me a ton of time and effort.

    Thanks for all your hard work.

    • I’m very happy to hear it’s helped someone out. I recently pushed up fixes (Sept 11 2014) that improved/fixed the (semi)linear RPM sweep, especially at low RPMs, which should work far better than it did previously. Building has changed to using, as I work faster in a CLI environment, though it is still possible to build/upload using the arduino IDE if a simple symlink (src->ardustim (ln -sf src ardustim)) is made. Let me know if you need additional crank/cam patterns added, as they are trivial to add, I just need angular data describing the wheel(s) and their relationships to each other. Pointers to other patterns are strongly welcomed.

  2. Hi David, sounds great. I’m quite new to this programming and Arduino. Just a quick question, can I modify (when I learn how to:) ) this or how easy is it to modify so i can output 3 signal (ie 1xcrank and 2xcams) and implement a pot (like jimstim) control rpm?

    • It’s open source so its code is available to anyone willing to adhere to the license terms (GPLv2). Tri output is easy, the output pin mask needs changing and it just requires designing the pattern array appropriately, the values in the array are the decimal equivalent of the port value at each transition, so single output patterns only have 0/1, dual output patterns would have potential values of 0,1,2,3 (all low, primary high with secondary low, secondary high with primary low, both primary and secondary high), tri output would have potential values of 0,1,2,3,4,5,6,7 for all possible pin combinations. The problem will be flash space, there’s only about 29.5K usable and we already use 27.5k, so if your pattern is complex, it may be up to 720 bytes if its pattern isn’t divisible, it limits how much can be added. Right now pattern specs are NOT well documented, but I’ll remedy that shortly. If you could provide details on the pattern you want implemented, I can examine it and provide feedback. Typically I’ll need the angular values between transitions and their relations to each other (if it’s separate wheels, versus a cam angle sensor wheel with multiple tracks like mazda/nissan). A pot should be feasable, I just hadn’t bothered to code that in yet, though it was intended to be PC controlled, so it could be driven by some form of automated test suite allowing an unattended test process without having to have someone sit there and twiddle knobs.

    • Additional outputs are trivial as long as they are periodic with the remaining set. You just need to set the bits appropriately in the wheel definition (wheel_defs.h), the pattern is the decimal equivalent of the bits you want set or cleared, so 1 is first bit, 2 is second bit, 3 is both first and second, 4 is 3rd bit, 5 is 3rd and 5th and so on and so forth.

      As the code sits it’s capable of 3 outputs currently, more requires altering the setup() function slightly to set additional pins as outputs (I figured no one would ever need more than 3)

  3. Shan: I added in RPM pot control in eb2ee (current master in git). It needs to be connected with the ends of the pot to 5V and gnd, and the wiper to analog port 0. As long as druid4arduino is NOT running it’ll read the pot 5 seconds after powerup until either druid4arduino or a serial connection is made, onmce either ofthose is closed or times out, it’ll return to POT control.

  4. I repair ecu, engine computers and one of my biggest problems is to trigger all the different ecu with there crank to cam relations ship signals but I was looking for something that I can use with my test bench to test run these ecu’s,the only problem I have is that I scope out these crank and cam waveform on an digital oscilloscope and all readings is in milliseconds,can you help me please ?


  5. hi i’m using windows and mw down Druid4Arduino not work for me with respect to the code could load prefect also I had problem with the SerialUI I can not make it work I would love to use the Ardustim but I lack the part of the soft that serial the SerialUI and Droid4arduino thank code and qu have a workshop and I used to test the ECU really thank you very much admire Mr. DAVID greetings from Argentina

  6. Hi. I am a “dummy” as far as code/programming is concerned. I need to simulate cam and crank signal for 6 cylinder volvo truck engines. Basically i need a tool to test ecu’s after repair. So i purchased the Arduino Uno and downloaded and installed the software. Now where to? I have imported the Ardu-Stim code and am now completely lost as what to do. Full details will be highly appreciated. Thank you in advance.

  7. Hi Dave. I am a newbie to the programming world. Basically I have no Idea what Im looking at when trying to read the ardustim code. I would like to simulate a six cylinder diesel engine with crank and cam signals. Please could you explain to me in detail how to do this.

    Many thanks in advance

  8. Hi David. Some info on the flywheel.. +-485mm(485.5) diameter, 3 sections of 18 notches (17 flat edges), each seperation is a flat edge, i would say equivalent to 3 flat edges with 2 notches. So if im correct it would be 20-3 x 3 or 60-9, I think… The cam is slightly different, a picture with measurements would probably be best. However for the time being i need only simulate either or as the engine can run on just one, it does not need to have both signal to activate the injectors.

  9. Hi Dave,

    I’m trying to compile the ArduStim firmware. I’m on Windows with the 1.05 version of the Arduino IDE. I am getting a ” ‘logf not declared error in the serialmenu.cpp file.”
    I’m fairly new to this Arduino stuff. I want to to use the Stim for some ECU work I’m doing and the JimStim is driving me crazy.

  10. ArduStim is working great. Thx for this very helpful project!!
    I would like to set inverted crank as standard, but because I’m a very beginner in programming I failed. I already adjusted volatile “uint8_t output_invert_mask = 0x00” to “0x01” but there was no change at all.

    Another thing is the initial rpm value. I can’t adjust it too. I tried with adjusting “static uint16_t wanted_rpm = 2000;” but initial rpm value is always 1600rpm. even information button returns curret rpm of 2000. But ECU shows 1600rpm until I set new rpm value which is working reliable then.

  11. Hello and thank you for the program!

    Me and my colleague have a bit of a problem. When we open ardustim and upload it to the Arduino Uno board, everything works fine. Druid4Arduino also opens as intended and the RPM selection as well as the wheel selection works fine. Although, when we set different Swept RPM’s, nothing happens and no sweep chart opens. Is an extra program for this needed or should the chart open when we set the Sept RPM?


    • It should sweep, can you provide me with the wheel type you’ve chosen and the sweep string you are feeding it in druid4arduino that causes it not to sweep? The format is “start rpm,end rpm,rpm/second”, so “100,1000,900” means sweep from 100 rpm to 1000 rpm at 900 rpm per second, it should take about 1 second to sweep across that range in one direction.

      • The chosen wheel pattern is 5: 60-2 crank and cam. We’ve tried different sweep strings, for example “100,1000,900” as you just mentioned. The program just answers “Sweeping from: 1001000 at: 900 RPM/sec”, but no graph occurs.

        • I tested that on my end and it IS sweeping as expected..

          What is the git hash of your ardu-stim repository? ( run “git log |head” within the working copy)

          It should be “85f021ae913c68c9a1955867647caacfd2ea24bb”, if not, check that you’ve updated the “url” in .git/config (within your working copy) to point to the new git server “” instead of “”, all of the rest of the URL line stays the same, then issue a “git pull” and you should pickup the latest changes and you can build/load to your arduino in whatever manner you use now.

  12. Hi David,

    I am trying to retrieve the Ardustim code from the git repository, but sadly an error 404 occurs. Can you help me out with retrieving the Ardustim. In the context of my graduation I am developing an engine simulator. The Ardustim seems like a good tool to simulate my crank/camshaft signal.

    Could you perhaps sent me an email? I have got some additional questions concerning the applicability of the Ardustim.

    Thankyou in advance!

    Kind Regards,
    Yannick Erkelens

  13. Hello again David!

    As you mentioned, ardustim is only compatible for Arduino UNO. However, I tried setting it up with an Arduino DUE board, but got some errors. Any ideas how to modify the code to make it compatible for an Arduino DUE board?


    • The ardustim uses very low level resources of the Atmega 328 CPU (very specific use of the low lever timeers) so it’s not directly portable to different cpu’s or architectures. The Due uses the Cortex M3 which is VERY different from the atmega 328, and that board costs about 4x as much, hence I don’t have not done any development on that board, nor do I have any low level knowledge of that CPU in order to setup timers in a similar fashion. I suggest getting an Uno or Uno compatible board as they are dirt cheap (I have seen clones available for less than $10).

  14. Hi there, I am looking to use the ardustim to feed a 12-3 toothed wheel input, but want to measure the output of the ignition to measure the timing of the ECU. I realize that out of the box, you likely aren’t set up for that, but I’m new to the Arduino. In your opinion, would it be able to accurately measure the output of the ECU compared to the input that it feeds it?

    • It’s not possible currently on the Uno/atmega328p as there are not any more timers available to do the time measurement, as they are all in use. It MIGHT be possible with a the mega 2560 (which has 3 more high res timers), but I don’t have one of those nor the time to work on that at this time..

        • I don’t know as I don’t have a 2560 to test against. It would probably require modification to work properly there as the number of timers is different as is the amount of IO and default clock rates.

          • I have a 2560 on order and will let you know how it goes.
            As mentioned I will be interested in seeing ignition timing from the ECU using ardustim for the toothed wheel input. I would be happy to share the code if your interested.

          • Sure, it shouldn’t be too difficult to measure that on the 2560, with it’s 3 extra timers, you just need to pick an appropriate pin and set it up for triggering on pin state change and count the number of ticks with reference to a reference point (the wheel’s TDC point perhaps?) The important thing is ot make the interrupt handler AS SHORT AS POSSIBLE, most arduino libs do a terrible job at setting things up to be fast (digital_write is about 50x slower than the “manual” method as an example), hence why ardu-stim’s code as it is is not readily portable to other targets.

  15. Hello David!

    I have some questions regarding how the different pins of the Arduino board gets high or low. I understand how the different wheel patterns are constructed in the header file “wheels_defs.h” (for example: 1,0,1,0), but it seems like I can’t find the part where these values are transmitted to the output pins. So my question is, how is this done? As far as I understand they are saved to different PROGMEM variables, but i can’t see the use of them anywhere.

    Hopefully you understand what I mean (I’m new to Arduino).
    Have a nice day!

    // Emil

    • Pins are defined for input and output in “setup(); in ardustim.ino around line 180.
      Pin 7 is a debug pin (i used wiht my logic analyzer for testing, don’t use this pin)
      Pin 8 is the primary (crank) output pin
      Pin 9 is the secondary (cam) output pin
      pin10 is an experimental signal that shouldn’t be used, it’s for internal development for special purposes..

      Actual outputting of the signal is done in ISR(TIMER1_COMPA_vect) (interrupt service routine for timer1 output compare)

      The actual output call is: (pins 7-10 are part of portb), and I basically hijack the whole thing. (I should mask out only the bits of interest, but I cheated, as that removes an additional opcode and makes the code faster, and the ISR shorter)

      PORTB = output_invert_mask ^ pgm_read_byte(&Wheels[selected_wheel].edge_states_ptr[edge_counter]); /* Write it to the port */

      Use google to lookup bitwise operations to understand the various operators. The output_invert_mask is used to flip the polarity of the crank/cam/(other) signals on a per-bit basis.

      The remaining bits in that ISR do the following:
      1. step to the next position in the tooth array or loop around.
      2. Check the “reset_prescaler” bool, if set, reprogram the timer’s prescaler (sometimes necessary when using very slow RPM’s where the timer will overflow.

      “Wheels” is an array of structures, containing pointers to the Progmem locations of each wheel’s table as well as some factors needed to calculate the timer prescalers properly. it’s indexed by the selected wheel (chosen by the user in druid4arduino), hence how you are able to get to the right pattern and walk it through the output pins..

      Does that make sense??

  16. Hi David and thank you for the awesome program!

    However, this has a few extra functions that isn’t necessary for me. What I’d like to have is the exact program but without the sweeping function, with other words – only the fixed RPM. (And from what I can see the swept part is a bunch of code)

    Therefore I don’t dare to erase some parts, as I’m not exactly sure what everything does. So my question is (if it’s not to much to ask for) if you could take some small time and do it for me, and then upload the simplified version. Would appreciate this a lot!

    Best regards,

    • Just comment out mainMenu->addCommand(sweep_key,sweep_rpm_cb,sweep_help); in serialmenu.cpp and recompile/upload and that functionality will be hidden from the UI (though the code will still be present, it just won’t be end-user visible).

      • I was thinking about to get rid of the code that includes the sweep, not just comment out the code.
        The problem is that I’m afraid of destroying the program if I take away wrong parts of the code.

        • Why bother removing it, it hurts nothing being there and is a core part of its function for the userbase. If you want to modify it, make a fork of the repo and start hacking away (note you’re obligated to release that sourcecode if you share any binaries built off modified code (GPLv2 license).

          The best way to learn is to dive in head first and TRY! Read the code, its fairly self explanatory leverage google for the parts you don’t understand. Teach yourself and learn, don’t expect everyone to hand you what you want on a silver platter. 🙂

  17. Hi there.

    What a great program you’ve created. However, is it possible to create two different crank signals for two pins (e.g. pin 7-8) and two different cam signals for two pins (e.g. pin 9-10), to later add them to get a zero crossing signal. And if so, would this be a complicated thing to do in the program?

    • And another thing that’s on my mind, the same thing as Emil asked the 17 of april. I understand how patterns are created, but what I did not understand from your explanation was how a “1” in pattern can make pin 8 high, a “2” in pattern can make pin 9 high and a “3” in pattern makes both pins high.

      • The pattern bits are stored in decimal for in an unsigned byte (value range of 0-255), so

        Wheel value  Output BITS (far right is the crank output pin, next one to the left is the cam pin, etc...)
        0            0000 0000  # Both crank and cam are low
        1            0000 0001  # Crank pin is high (pin8 is the "crank" bit and corresponds to bit0 of portB)
        2            0000 0010  # CAm pin is high, crank pin low (pin9 is the "cam" bit and corresponds to bit1 of portB)
        3            0000 0011  # Crank AND cam pins are high (both pins 8 and 9 are high)

        Right now ardu-stim is configured only to use the lower two bits of PORTB, hence the wheel patterns should only have values of 0,1,2 or 3 in their arrays.

        Make sense?

        NOTE: The current method is VERY wasteful in terms of flash space (limiting the number of available patterns), so at some point it’ll be changed to a format that is more memory friendly.

        • Oh okay. It’s like I thought then.. but the thing I got confused about is that I thought pin7 correspond to bit0 of PORTB, and pin8 correspond to bit1. Shouldn’t it be that way?

          And regarding having 4 output pins, how can I modify it in that way? Since you said it only uses pin8 and pin9 at the moment. How come pin7 is gone from PORTB?

          • pin 7 is not part of portB, that’s part of portD (PD7 specifically)..
            Signals are outputted on pins 8 and 9 (crank,cam respectively)
            study this image: Ardunio uno pinout and you can see which pins have which functions.

            You could use pins 10 and 11 if you wanted additional signals. you would just need to add lines to set this pins as outputs in the setup(); function within ardustim.ino around line 184.

    • It is possible, but remember the signals are digital (on or off), the output pins are either at 0 volts or 5 volts, so unless you need to have multiple patterns for crank (i.e. two different wheels), I’m not sure what it’ll gain you.

      • Hi David, I’m guessing that Patrick is trying to create an output signal that will ‘mimic’ a typical 2-wire variable reluctance sensor….
        With a couple of additional components we can ‘combine’ two independent digital outputs to create a signal that’s surprisingly close to that produced by a genuine VR sensor. (Admittedly, it doesn’t quite have the same RPM to amplitude variation).
        Having said all that, it’s also feasible to get something similar from a SINGLE digital output using a basic high pass filter (series capacitor and resistor to some ‘bias’ voltage level).
        Perhaps Patrick should first see if this would suit his needs?

        • The latter method (R/C filter) is preferable and simpler though it’s RPM band may be limited depending on how picky the target ECU is.. The former method is possible, but requires a specialized set of patterns created, esp if he has a CANM signal needed. I’m not too familiar with that method however and the extra component requirements, so if you could describe it in detail it would be interesting to try on the bench.

  18. Hi!

    I have read some comments here and I hope that you can answer a question that I have. I’ve been trying to connect a LCD-display to my arduino board to show the current RPM (for when a pot is used). In the void setup() I managed to write “RPM: “, but when I try to print something in the void loop() (according to, the LCD-display goes nuts.

    I have a feeling this should be done somewhere else, since you’ve commented “Just handle the Serial UI, everything else is in interrupt handlers or callbacks from SerialUI.” under the void loop() in the code. Maybe you have a suggestion where this should be done?

    And at last, I can’t seem to get the variable “wanted_rpm” that holds the RPM value printed, since it’s in another file. Even if I try to include it with the help of “extern”, it can’t be compiled and says that it’s “outside the scope”.

    It doesn’t help that I’m new to arduino, but hopefully this is easy tasks for you! Would really appreciate the help.

    Have a nice day

    • Without seeing the code I cannot offer much, I suspect that either the LiquidCrystal library is trying to use one of the timers that is used by Ardu-stim’s code and causing a conflict, or not all of the pins used by the LCD are properly configured to do what you want. If you fork the code and post it someplace (, github, etc) I’ll look at it and see what i can find. The reason why you aren’t able to access wanted_rpm is because it’s defined as static outside of any functions within serialmenu.cpp (meaning it’s only available within the scope of THAT FILE). So, either put your function that uses it in that file, or remove the “static” and in your other file define it as “extern unint16_t wanted_rpm;” and it should link fine.

      • Okay! After i removed static in the serialmenu.cpp file, I got access to the wanted_rpm in the main file.

        Under void setup() in the main file I coded:

        lcd.begin(16, 2);
        lcd.print(“RPM: “);
        lcd.setCursor(5, 0);

        This prints “RPM: 6000” on my display on startup, but since this is in the void setup(), it doesnt update when the RPM changes. So I tried to move the last 2 rows to void loop(), but then the display goes nuts. Haven’t tried doing it with a separate function since I have no idea how it should be written.

        • try this in loop()
          lcd.setCursor(5, 0);

          See if it displays that, if it DOES NOT, I suggest using different pins for the LCD interface as you are likely getting some artifact from the code or timer’s that is messing up your LCD display.

          Please post your code someplace as well.

          • After i tried using “analog0 * 16”, I got the right RPM values! However, when I put my code in the ISR(ADC_vect) the display works as intended with the pot, but the signal is way to slow and doesn’t change with the RPM in the oscilloscope. So I guess you are right about the timer’s messing it up.

            In the initialization the code “LiquidCrystal lcd(12, 11, 5, 4, 3, 2)” is used, and pin 11-12 is a part of a timer already used? What could be used instead of 12 and 11, since I want to remember that all the timers already are in use?

            Here is a link to the code, although I didn’t know how to use gitlab etc, so hopefully this works.


            At the moment the LCD-related code is under void loop(), but that doesnt work. That was just to put it somewhere.

      • Maybe I shouldn’t use the variable “wanted_rpm” when I’m trying to print the RPM at the time the pot is active? Since wanted_rpm is used when the SerialUI is active.

        Although I can’t find the RPM value that that is chosen from the pot in the code… and I can’t even find where it’s connected to analog pin0 :S

        • The analog side is a little confusing. Most arduino tutorials use “loop()” to run everything, this is caleld “polling” and it’s expensive and not the only way to do things. A better methods in many cases is to use Interrupt service routines. Ardustim uses the timer’s to generate the output waveform and also programs the internal ADC to continuously sample the analog inputs and stores the value from analog port 0 in a variable called “analog0”. the issue is that this is 10 bits in size (0-1024), whereas RPM range is significantly higher. Within “loop()” a flag is checked (“adc_read_complete”, which is set in the ISR) which then takes the analog0 value, shifts it to the left by 4 (each left shift multiplies by 2, so it multiplies the value by 16) and reprograms the timer for that RPM value, so the pot can set the RPM between 0 and 16384 with 16RPM resolution.

          So to output to your LCD , you’d take the analog0 value and multiply by 16 (or << 4)/

  19. After i tried using “analog0 * 16”, I got the right RPM values! However, when I put my code in the ISR(ADC_vect) the display works as intended with the pot, but the signal is way to slow and doesn’t change with the RPM in the oscilloscope. So I guess you are right about the timer’s messing it up.

    In the initialization the code “LiquidCrystal lcd(12, 11, 5, 4, 3, 2)” is used, and pin 11-12 is a part of a timer already used? What could be used instead of 12 and 11, since I want to remember that all the timers already are in use?

    Here is a link to the code, although I didn’t know how to use gitlab etc, so hopefully this works.

    At the moment the LCD-related code is under void loop(), but that doesnt work. That was just to put it somewhere.

    • You cannot do the LCD update call within the interrupt service routine. ISR’s need to be as short as possible as they essentially block everything else from happening. Updating the LCD is considered a “slow” operation and is inappropriate to stick within an ISR.

      I looked at the LiquidCrystal Source code and it uses the timers for various delays which will likely conflict with ardu-stim’s use of the timers as well. So we have a problem, disabling use of the timers to make your LCD work will cease the output signal generation.

      Right now all my stuff is packed away (moving) so I cannot do any deeper testing, contact me in a month.

  20. I think i know the problem, I’m writing to portB (pins 8-13) assuming i can have all the pins which i can’t when you are using some for the LCD, so do this: Pull my latest code from gitlab

    Don’t use pins 8-13, as my write for outputting the signal patterns is stomping on your LCD signals.

    Setup your LCD to use arduino pins 2,3,4,5,6 for your LCD, move your rpm update into loop(); and build and install. Take out anything from the ISRs that you put in there before.

    Note: it may not display RPM for 15-30 seconds which is the druid4arduino serial wait timeout, which will temporarily stall loop().

    • Thanks! I changed pin 11-12 in LiquidCrystal to 6-7 (since 7 is a debug pin currently not connected, I just commented it out). Then I put the lcd-code in the void loop() and things worked as intended! Awesome 🙂

      • One last question!

        I’m using an own wheel pattern of 2880 edges, so the program won’t work after a certain RPM. I’m trying to set the max possible RPM to 3500 (when the pot is used), but I can’t understand how to do it.

        With other words: I want the RPM to increase when I rotate the pot, but when I reach 3500 RPM I want the RPM to stay at that value, even if I continue rotating the pot. Any idea of how to make this happen?

        Thanks so much for helping me out

        • Just use math and a conditional test. i.e. if the value of the pot exceeds X, output Y (capped value) instead, otherwise output as normal.

          • That’s what I did, but nothing happened…

            I tried this:

            if (analog0 >= 225) // 3600 RPM
            analog0 = 225;

            But when the pot rotates, it can still go over 3600 RPM. I tried doing this directly in the void loop and even inside the if-funtion:

            if (adc_read_complete == true)
            reset_new_OCR1A(analog0 << 4);
            adc_read_complete = false;

            However, none of the above worked. =/

          • You cannot change the value of the variable that the ADC is WRITING INTO every time it updates, but you can in a temporary variable..
            if (analog0 >= 225)
            myrpm = 225;
            myrpm = analog0;

            reset_new_OCR1A(myrpm << 4);

          • Aah of course! You’re a god at this.

            It would be fun to see if the thing Roberto asked would work aswell. 🙂

  21. Hello there

    Is it posible to make a potentiometer change wheel paterns? Because I couldnt for some raeson…

    When I connect a potentiometer to A1 (since A0 already in use), i cant even get serial connection in the serial monitor…

    I used the build-in exampel “AnalogInput”, similar to this one:

    and it worked when i uploaded that solo. But when i included the same codes in the ardustim, it didtn work for some raeson…

    Hope u understand me. Have a nice day

    • it may be possible, however you cannot use the code from that example, Ardu-stim uses interrupt based reads, not polled reads (which that example uses), polling will block everything on the druid4arduino serial interface code completely. I’ll look into it when i get time.

        • I have looked into it, however there are a few problems.
          1. The code I’m using isn’t properly sampling multiple channels correctly (data ends up in the wrong variables, so there’s a race/timing problem that I haven’t solved yet)
          2. it would result in 37 (and likely many more) “spots” in the pot travel making it rather difficult to actually get to the right wheel pattern, as more patterns are added this will get worse.

          A better solution would be up/down buttons (digital) though that has it’s own potential pitfalls. IF you only need to use a single specific pattern, edit user_defaults.h and set it there and it’ll default to that on powerup.

  22. Hey Dave!

    I have read your code and wondering how you determine the RPM scaling factor, i dont really get it.
    Some time you divide with 120 and sometimes with 240? It would be great if you could take your time and describe how you are thinking.

    Best regards!

    • The scaling factor has to do with the number of edges in each wheel pattern’s array and if the pattern repeats with each crank revolution or if it requires two crank revolutions before the pattern repeats. The patterns that have the ratio of 240 have a pattern that repeats every TWO crankshaft revolutions, the ones that have a ratio of 120, have a pattern that repeats EVERY crank revolution. (typically patterns without a cam signal)

  23. I understand that 120 is for one crank revolution and 240 for two with a cam, but I still dont know why you use the values 120 and 240, where do they come from?

    Thanks for helping me , I appreciate it.

    • 120/240 is the ratio of the steps in the wheel array, which is variable (as they can be as few as two and as high as 720 or more) and the scaling factor to calculate out RPM.

      That scaling factor is needed to appropriately program the timers (TCNT (“timer count” variables for the output compare interrupts which emit the pattern)) to generate the signals at the correct rate for the users’ requested RPM, since the number of edges per wheel is variable and wheel dependent this factor is required so that regardless of the wheel chosen the signal is outputted at the correct RPM.

  24. What do you mean by “the ratio of the steps in the wheel array”? I still dont get how the values 120/240 have been calculated. I don’t get it…

    • if you look at ardustim.ino there is an array of structures called “Wheels[]” (described in structures.h)
      here’s an example:
      { dizzy_four_cylinder_friendly_name, dizzy_four_cylinder, 0.03333, 4 },

      the 120/240 come from dividing the last field (wheel_max_edges) in that structure with the second last (rpm_scaler), i.e. 4/0.03333 Wheels that repeat their pattern in 1 crank revolution have a result of 120, others that complete in two crank revs (i.e. cam patterns or crank&cam patterns) have a factor of 240. It’s just how things worked out.

      The “4” in this case is the number of values in the array to “describe” this pattern, and the 0.03333 is a scaling factor used elsewhere in the math to scale things appropriately so when the user requests a specific RPM, the arduino’s timers are programmed appropriately to output the signal at that rate.

  25. Thanks a lot for the program. I added a 58x wheel with the 4x cam wheel that is used in GM applications for my project and it works well.

    • Can you provide a diff or your code changes so I can add it for everyone else to use? as well as a description of what engine/vehicle combinations this will work on?

  26. Hey David,
    thank you for this very useful tool. I use it a lot in ECM development. Currently I’m using it to verify injection timing related things. Therefore I tried to simulated engine jerking with “Set Swept RPM” but it seems there is a strange behavior:

    The command 1000,1200, 20 results in a sweep from 1000 to 1115.
    The faster it should oscillate the worse it gets:
    1000,1300,5000 results in 1030 to 1130 rpm. this means, the higher the oscillate rate, the smaller the amplitude.. 1000,1300,10000 results in
    1064-1096 rpm sweeps…
    A general fault is when Droid4Arduino is disconnected the whole UNO stops to output rpm. It is only working for me if Druid4Arduino is connected.

    If you want to have measurements or further details just let me know!

    • Sweep is not perfect for the main reason that the arduino can NOT do floating point math natively (it can be done in a library consuming lots of memory but it is incredibly slow). Due to the way RPM is converted to timer ticks, it is non-linear (exponential I believe), so the RPM sweep isn’t entirely linear, the code uses some creative tricks to try it linearilze it as much as possible. The end points are subject to rounding errors (worse with higher RPM rate of change), so in your case try setting the sweep limits BEYOND to compensate, i.e. 990,1250,20 until the code is improved to reduce the error.

      Closing druid4arduino or loosing the connection will cause the code to drop out of sweep mode (by design, see loop()) and fall to simple “POT” mode where the RPM is set by a pot connected to Analog0, where you could manipulate the RPM manually or via an external analog signal.

      How did you do the measurements of RPM, based on your ECU’s output datastream or via direct measurement with a DSO or logic analyzer? Which wheel patterns were you using?

  27. Just saw

    I’m also using 60-2 with 4X Cam. Here is the code:

    /* Bosch 60-2 pattern with 2nd trigger on rotation 2,
    * GM 4X CAM */
    const unsigned char sixty_minus_two_with_4X_cam[] PROGMEM =
    { /* 60-2 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 1-5 */
    3,2,3,2,3,0,1,0,1,0, /* teeth 6-10 */
    1,0,1,0,3,2,3,2,3,2, /* teeth 11-15 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 16-20 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 21-25 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 26-30 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 31-35 */
    3,2,3,2,3,0,1,0,1,0, /* teeth 36-40 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 41-45 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 46-50 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 51-55 */
    1,0,1,0,1,0,0,0,0,0, /* teeth 56-58 and 59-60 MISSING */
    1,0,1,0,3,2,3,2,3,2, /* teeth 1-5 */
    3,2,3,2,3,0,1,0,1,0, /* teeth 6-10 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 11-15 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 16-20 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 21-25 */
    1,0,1,0,1,0,1,0,1,0, /* teeth 26-30 */
    1,0,1,0,3,2,3,2,3,2, /* teeth 31-35 */
    3,2,3,2,3,0,1,0,1,0, /* teeth 36-40 */
    1,0,1,0,3,2,3,2,3,2, /* teeth 41-45 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 46-50 */
    3,2,3,2,3,2,3,2,3,2, /* teeth 51-55 */
    3,2,3,2,3,2,2,2,2,2 /* teeth 56-58 and 59-60 MISSING */

    Additionally I think I found another bug. When rpm sweeps are used, there is a problem with teeth length at the point where the rpm slope starts to turn into another direction. E.g. 1000, 4000,500. At 3999-4000-3999 rpm it seems like something got wrong. My ECM interprets this as a change of direction and it results with a DTC.

    • I’ve incorporated your pattern and pushed the code. Is it possible to get a scope or logic analyzer trace of the anomaly during sweep?

    • Contact me,( as I maintain “ardu-stim”, a crank/cam pattern simulator. I’ll need detailed information about both the crank and cam wheels, dimensions, angular measurements are great (only if accurate), high res in focus photos instead, and details on how the crank and cam wheels are related to each other, i.e TDC on #1 corresponds to which points/positions on the crank and cam wheels.

  28. Hello David, Congratulations for such a great project !

    I’m trying to make it work to use it as part of my ECU bench testing equipment. I uploaded the files manually on the library’s directory first. but I’m getting a compilation error:

    “ardustim.ino:22:21: fatal error: defines.h: No such file or directory ”

    I also tried to upload the Hex file (ardustim-firmware_639cf667.hex)
    Using XLoader, it uploaded the file fine, but when I start Druid4Arduino or serial monitor(Arduino IDE) doesn’t show any menus or activity.

    I’m Using a original Arduino one, R3, it’s working perfectly with the example programs in the library. I’m new to Arduino, so I guess that I missing something… so any light/help would be very appreciated,

    Best regards,

    • I would suggest starting with a basic arduino tutorial/howto to get used to the tools first and gettign your arduino to do something (blink a LED for instance) once you are familiar with that then I would suggest checking out a working copy of ardu-stim from git, and installing the SerialUI library into your environment and compiling it and uploading that… Baby steps makes it easier… 🙂

    • The output from the arduino will resemble a HALL signal (digital square wave), however you could add additional analog circuitry to give you something closer to a “VR” style signal.

  29. Is there a way for Ardustim to output an analog signal, or am I better off building a DAC? I love the idea and simplicity of this project!

    • it cannot output analog since the Arduino doesn’t have a DAC. The wheel patterns are also digital, but your could in theory use all 8 bits of the port and re-work the tables in the code to give you a closer to analog output, but beware the output rate is dependent on RPM, it’s synchronous with the pattern, which isn’t typically how you’d drive a DAC (which is typically at a constant rate)

      • Thanks for your thoughts. Maybe I’ll try to build an external DAC designed around one RPM range. That would at least allow me to test that the computer is telling the injectors to fire.

        Thanks for your hard work and making this available. It’s really a great tool!

  30. One other thing that would be very helpful is to add two wheel speed outputs. The rear wheel speed should be based on RPM (ratio) and front wheel input based on rear wheel speed (ratio). If those ratios could be varied based on potentiometer inputs, that would add a whole new dimension of engine braking and traction control testing.

    • Not enough timers on an Uno to do it, I’m using all of them just to do the crank+cam signals and handle the serial. A Mega2560 would be capable of it as it has 6 timers (4 16 bit, 1 8 bit) vs 3 on the uno (of which only 1 is 16 bit, the others are 8 bit).

  31. How difficult is it to send the desired RPM via serial to the arduino (on an ongoing variable basis) via Labview? This way you could really do an ongoing HIL testing of an ECU.

    • its possible, but due to serial speed, it’ll result in “jumpy” rpm.. druid4arduino isn’t necessary, you can control it all via a serial terminal so wiht labview it would be possible. Use a terminal program and run through the sequence to set the RPM. it won’t be very fast though due to the serial ui overhead.

  32. Hi
    This is something Ive been after for so long. Today I tried it out on my Volvo Motronic 4.4 ECU, Sadly, I can’t get the ECU to read the RPM that is generated. Can anyone offer any suggestions?


    • If your ecu needs a VR signal you’ll need an additional circuit to transform the digital output of ardustim into that, or bypass the input processing circuitry on your ecu (which converts the VR semi-sine wave into a digital square wave)

      • Spesial thank for david,he was supported me to finish 7 pattern of crank and i have question,can i choose select wheel just from push botton without re upload can see our project on youtube(Ecusamdruino)

        • It’s possible, though available memory on the arduino is very tight which is limiting things until I can refactor the code and patterns to be more compact.

  33. Hello David, very nice work !
    Your code works fine for me but i want to only use the sixty_minus_two_with_cam pattern without the SerialUI.

    I want a simple program that change de RPM with an analog pot and also the cam in the same time. That means I need to keep the ISRs.

    But I can’t find a way to do that, every file of your project is connected and if I change something, the program doesn’t work.

    How can I do that ?

  34. Hi!
    I know, maybe it´s a very latter interaction.

    Where scketchs i must place new whell formats? The new formats must be in sequence or can be placed in any order?

    Roger (Brazil)

  35. Hi, thank you for your work on the arduino simulator. I have it working but cannot get my Motec M48 to recognize the cam (sync) signal. I do not have a oscilloscope to check yet but am looking to purchase one. Any other suggestions? RPM signal works fine.

    Is there a way to register for the forum? I tried but never received any response.

  36. Hi David, and thanks for implementing the Mazda MX5 NC crank/cam pattern some years ago. I have used it quite a lot.
    But I have a feature request:

    Support for cam/crank trigger signal inputs that will be converted to selectable cam/crank trigger outputs. So a real time conversion of signals following rpm.

    OR if not possible:
    Support for reading “standard” Tach output of 2 pulses/sec that outputs selected cam/crank pattern.

    This will be very usable for parallel installs where the EMS is doing performance related stuff while the stock ECU will continue to get the trigger signals for cluster and non performance related stuff like EGR, VTCS, Generator voltage control and anything CAN-based.

    • I don’t quite understand what you’re asking for. If you want to input “pattern A” and have it output “pattern B” that is angle locked to input “A”, we have several constraints that will limit what combinations would be even remotely possible. i.e. it will NEVER be possible to take a lower resolution input (lets say 36-1) to output a 60-2 pattern. Also it wouldn’t be possible if the two patterns are NOT divisible by each other. i.e. a 36-1 input could allow the following outputs, 12-1, 9-1, 6-1, 3-1. Jitter would also add some significant difficulty into knowing if this would even be possible. The real time nature is also an issue, as it’s likely that the output will lag the input by some amount which may or not be fixed versus RPM and pattern complexity. You need to explain a bit more deeply what you’re thinking of.

      • Ok. The problem I’m trying to solve:
        I’m using an AEM Infinity EMS on my 2006 Mazda MX-5 to control spark,fuel,DBW,fan,VVT ++ by reading factory sensors plus some additional ones. ( AEM now supports the NC trigger patterns).
        The stock ECU is used in parallel. AEM does not have user configurable CAN yet, so without the stock ECU pretty much everything from the firewall and back is dead as it controls/communicates with cluster, locks, windows+++. It’s also doing some boring non performance related engine stuff as listed in my previous post.

        The stock ECU will happily cooperate as long as it sees trigger signals.
        I tried sharing the signal from the AEM without luck due to some internal pull-up/down resistors in the AEM that is beyond my understanding. I also tried relaying the signals with optocuplers with no luck.

        So right now I’m feeding the stock ECU a static RPM via Ardu-Stim which at least keeps the stock ECU and cluster alive but not optimal for rpm dependent functions like generator control, intake runner control, egr etc.

        Reading your reply I understand that converting trigger signals might not be possible and have limited interest for the rest of the world since it will be jitter/lag. So ignore that one.

        But my second suggestion by accepting a tach signal would make it possible to feed the stock ECU a somewhat correct trigger signal for the remaining basic functions.
        It would be of great help for any parallel install regarding reversibility, saving EMS GPIO’s usage and even have working OBDII logging for the remaining stock ECU functions.
        I did a quick search and the tach signal output and it seems like a common feature on most EMS’s.

          • Ok. So what would be the best input signal ? AEM and Haltech both have fully configurable PWM outptus for frequency and duty. Both high side and lowside.

          • It depends on the complexity of the output signal you want ardustim to synthesize. Ideally you would need an input that has AT LEAST as many edges as the wheel you wanted to synthesize, if more it would need to be a multiple of the output (something the output edge count would divide into). The input would need to be basically a high resolution tach signal from your source ECU.

          • Ok. Sorry for the slow feedback. Busybusy.
            I just verified that the pwm outputs can be configured to any hz. My 36 wheel ended up like this in AEM:
            If you find the time and reason to implement this feature I will be forever grateful as all my other attempts of duplicating the trigger pattern have failed.


    • It’s not possible to generate an analog output directly with the arduino at the frequencies required, You’d need a high speed DSP to do that. Thus you would need to use an Analog circuit to “massage” the digital output into something your ECU would accept, An Integrator (google it) may do what you need but it would need to be tailored for the appropriate frequency range of the signal(s) of interest.

  37. Would there be any way to pass the sequence in a different way to put together the signals? Up to how many signals is it possible to add?

  38. Hello David,
    This is such an amazing code.. Works perfectly. The only thing is that I want to display the current rpm on an LCD(16*2) display. Can you please help me out.

  39. Hello David!
    Your code is amazing! I now have a portable device instead of a bulky oscilloscope..
    Can you help me displaying the current rpm on an LCD display.

    • There is not enough flash space left currently to do this, and the pattern generation is very timing/load sensitive, so any additional “gee whiz” features degrade pattern purity, so it’s not planned at this time.

  40. hello
    thanks very much for your program
    i want to connect LCD with arduino
    can you help me for this and i want to change the Wheel pattern without computer can we do this by push button

  41. David
    Do you know why the pot isn’t working?
    It’s connected properly GND, 5V and A0
    With mulimeter I can measure the voltage changes on A0, but the frequency remains the same.

  42. Hello David,
    this has been asked before, but I would really like to be able to set the RPM by a simple serial link and not use SerialUI or DeviceDruid (it keeps timing out on me and I can’t get it to reconnect(I think the W10 COM port reset is my issue).
    Can you give a little guidance on how to replace the SerialUI stuff with a simple RS232 channel please?

  43. David,
    I have got ArduStim working fine. Once set up, I would like to simply control the RPM by a serial link from another microcontroller or PC. The control would be continuous and dynamic (in response to other outside influences such as turbo speed, throttle position, manifold pressures etc.

    Can you point me to the correct spot in the ArduStim code where I could inject the RPM control.

  44. Hi David,
    This looks exactly what I have been looking for but rather new to Arduino so a couple of quick questions. I rebuild/repair ECMs/PCMs/BCMs, instrument clusters etc.
    Will this unit drive by cam and crankshaft signals to a point that these components can read and understand them and react to them? For example, can I feed and ECM and expect an injector pulse to come from it?
    Is there a list of possible crank signals available for it? Example 36-1, 60-2 etc?
    If this is what i think it is, you are e genius in my books. Looking forward to hearing back from you. Please stay healthy in these troubled times.

    • Yes with some caveats. If your ECU is expecting an input from a VR sensor (analog with a wide voltage range) then ardustim may not be able to successfully trigger it without an external signal conditioner (integrator + optional level shifter/amplifier)). If your ECU takes a TTL (digital) input (Hall sensor), then ardu-stim should be able to drive it directly. If you connect to ardu-stim with a terminal emulator and use “W” to get to the wheel menu and “L” to list wheels you should get something like this:
      1: 4 cylinder dizzy
      2: 6 cylinder dizzy
      3: 8 cylinder dizzy
      4: 60-2 crank only
      5: 60-2 crank and cam
      6: 36-1 crank only
      7: 4-1 crank wheel with cam
      8: 8-1 crank only (R6)
      9: 6-1 crank with cam
      10: 12-1 crank with cam
      11: 40-1 crank only (Ford V10)
      12: Distributor style 4 cyl 50deg off, 40 deg on
      13: odd fire 90 deg pattern 0 and 135 pulses
      14: GM OptiSpark LT1 360 and 8
      15: 12-3 oddball
      16: 36-2-2-2 Crank only
      17: 36-2-2-2 Crank and cam
      18: GM 4200 crank wheel
      19: Mazda FE3 36-1 with cam
      20: Mitsubishi 6g72 with cam
      21: Buell Oddfire CAM wheel
      22: GM LS1 crank and cam
      23: Odd Lotus 36-1-1-1-1 flywheel
      24: Honda RC51 with cam
      25: 36-1 crank with 2nd trigger on teeth 33-34
      26: 36-1+1 crank with cam pattern NGC4
      27: Weber-Marelli 8 crank+2 cam pattern
      28: Fiat 1.8 16V crank and cam
      29: Nissan 360 CAS with 6 slots
      30: Mazda CAS 24-2 with single pulse outer ring
      31: Yamaha 2002-03 R1 8 even-tooth crank with 1 tooth cam
      32: GM 4 even-tooth crank with 1 tooth cam
      33: GM 6 even-tooth crank with 1 tooth cam
      34: GM 8 even-tooth crank with 1 tooth cam
      35: Volvo d12[acd] crank with 7 tooth cam
      36: Mazda 36-2-2-2 with 6 tooth cam
      37: GM 60-2 with 4X cam
      38: Dodge Viper Gen IV SRT V10 60-2 with 5 tooth cam
      39: Suzuki GSX-1300R 24-1 crank and 1 tooth cam during missing crank tooth
      40: Mitsubishi & Mazda 4g63 with cam
      41: Standard SeaDoo 36-2, 50% DC

      Work is being done to create a better interface and to support custom wheels defined programmatically, though there is no ETA for this new set of features yet.

Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.