Digital out based on analog threshold at high speed (60khz+) possible?

Good afternoon, I’m using a genuine UNO and I am trying to see if I can use it to drive a high speed solenoid. The solenoid requires a boost-peak-hold current driver and my plan was to see if an arduino can perform fast enough to control a FET to accomplish this.

I’m starting my testing using a current shunt fed to analog pin 2 to measure current to a dummy coil being controlled by a FET controlled by pin 13. A function generator gives a 500us pulse to digital pin 12.
To establish a proof of concept, I have the arduino waiting to see pin 12 go high and then it sets pin 13 high until it sees the shunt current signal on pin 2 exceeding 10 counts. It then turns 13 off till the signal drops below 10 counts, and it keeps choping like this to try and keep pin 2 at 10 counts.

The overall duration of the “peak” portion is 500us and based off my measurements of the 1.5ohm coil it will need to be able to get to a chop frequency of 60kHz or better. With the attached code I’m at a chop frequency of ~10kHz. I’ve tried using digitalfast which helps, but I still need to get almost 10x faster.

Is there anything I can do to achieve this in the code I’ve got (I’m a novice at arduino)?

If not, can someone recommend hardware under $1k that would do this?

sketch_cidi001.ino (1.05 KB)

Attached is a screen shot of the results. Yellow is the command signal from the function generator, teal is the control signal from the arduino to the FET, and purple is the current signal from the coil.

Try port manipulation. Use the Arduino pinMode() if you do this, pins default to input.

digitalWriteFast(LED_BUILTIN, HIGH);  == PORTB |= _BV(PB5);

digitalWriteFast(LED_BUILTIN, LOW);   == PORTB &= ~( _BV(PB5) );

It may be worth writing your own analog read. The Arduino stuff figures out the pin & port mapping on the fly, and this slows it down. Analog is already slow.

There are some very fast Arduino compatible boards here:

Thanks for the help. I'm obviously missing how to apply the code you suggested. If I copy it directly I get

sketch_cidi002.ino: In function 'void loop()':
sketch_cidi002:60:43: error: expected primary-expression before '==' token
digitalWriteFast(LED_BUILTIN, HIGH); == PORTB |= _BV(PB5);
sketch_cidi002:64:42: error: expected primary-expression before '==' token
digitalWriteFast(LED_BUILTIN, LOW); == PORTB &= ~( _BV(PB5) );
exit status 1
expected primary-expression before '==' token

I tried commenting out the analog read and temporarily setting it to a digital pin and got very fast outputs, sub 1us, which would be plenty for what I'm doing so I'm guessing my issues are all stemming from the analog read.
I have been trying to get the "analogreadFast" example from Faster analogRead

But some of the links are broken and I don't think I'm getting the right libraries because the IDE keeps having errors around the "stopwatch.h" library. I'm nowhere near an expert at this, not sure where to even start writing my own analog read. I only need one analog channel, would there be any advantage to running the analog signal to all ports so that the switching of the multiplexer doesn't add noise? Is there a way to tell the multiplexer to stay parked at a single channel?

My plan B is to use the arduino PWM pins to generate a dc voltage to a couple of external comparator and then bring the comparator input into additional digital pins but I would like to avoid the additional complication.

I'll order up the tennsy 4.1, should I also look at external ADC's or am I still at the mercy of me learning how to write a faster analogread?

Don’t worry about the missing libraries in the examples for the avdweb_AnalogReadFast.h library.

I had a quick look at it and it’s just a wrapper around the normal analogRead. It modifies the ADSP bits in a similar way to what your code does.

  byte ADCSRAoriginal = ADCSRA; 
  ADCSRA = (ADCSRA & B11111000) | 4; 
  int adc = analogRead(ADCpin);  
  ADCSRA = ADCSRAoriginal;
  return adc;

The below is a stripped down version of the example that compiles (compile purposes only)

#include <avdweb_AnalogReadFast.h>

const byte adcPin = A1; 
void setup()
  int adc2 = analogReadFast(adcPin); // 20us on AVR 

void loop()


I'm obviously missing how to apply the code you suggested

Yes, what tf68 meant was

digitalWriteFast(LED_BUILTIN, HIGH);

can be replaced with

PORTB |= _BV(PB5);

However, if I remember, digitalWriteFast() is a macro, which, if the pin and value can be determined at compile-time, results in pretty much the same code as suggested anyway, so may not be any faster.