text:
Arduino FFT results of "beautiful" signal seem inconsistent
I have a BEAUTIFUL doppler radar signal here from a 24.050-24.250 GHZ sensor measuring a very small object at 143 fps speed (speed from another 10 GHZ radar) in a measuring area of about 300mm-500mm in front of the sensor(s). The signal was limited to around 3V with a zener diode.
I took several measurements (at this speed and object size and distance from the sensors) and there were about 8-20 wave peaks on the average above the trigger threshold level (2.58V) until the end of the trigger threshold level box where the peaks start falling off.
Looking at the graph, one can discard the first 3 peaks and the last 2-3 peaks above the trigger threshold which leaves a decent area (orange box) for sampling of the peaks for frequency/period. So in this case we have about 17 "good" peaks inside the orange box to be measured. In this case the orange box (measuring sample area) is 5 x 500 us = 2500 us in length.
I know that an FFT would be the best way to measure, but the one FFT program I used with Arduino gave me inconsistent results. Not sure how to set the sample size (must be in power of 2 increment from 2 to 256). And the maximum sampling frequency is 10kHz (hardware limitations).
I set sample sizes to 4 and 16 and 128 at 10Khz frequency, but get inconsistent results. I suspect logarithmic results, but even those do not add up. At times I get within 2-3% but at times it's off by 30% with no apparent correlation.
What I know:

with this 24 GHZ radar (no angles) the speed = frequency / 44 to arrive to km/h  (km/h x 1.097 = fps)
in this case the o-scope measured 6613 Hz with a 151.2 us period, but that was for the entire area above the 2.58V trigger threshold. But it also had some much more varying readings as noticeable in the first 2-3 peaks after the trigger and the last 2-3 peaks that are falling off to below the trigger threshold. I excluded these from the orange box.

How do I set up this FFT, or another FFT, or similar method, that would determine the dominant frequency from data inside the orange box?  The orange box sample size will always seems to be between the 8-20 number of peaks range. I measured frequency and periods from "positive rising edge to positive rising edge".
I tried with an Adafruit nRF52840 Express (16 Mhz clock) and an Adafruit 32u4 Bluefruit  (8 Mhz clock).
I am using this Arduino FFT library:  https://github.com/kosme/arduinoFFT
Some broad info about this FFT itself: https://www.norwegiancreations.com/2017/08/what-is-fft-and-how-can-you-implement-it-on-an-arduino/
Thank you.
    #include "arduinoFFT.h"

#define SAMPLES 4         //Must be a power of 2     128, 256?
#define SAMPLING_FREQUENCY 10000 //Hz, must be less than 10000 due to ADC

arduinoFFT FFT = arduinoFFT();

unsigned int sampling_period_us;
unsigned long microseconds;

double vReal[SAMPLES];
double vImag[SAMPLES];

void setup() {
    Serial.begin(115200);

    sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}

void loop() {

  if (analogRead(A0) >600) {

    /*SAMPLING*/
    for(int i=0; i<SAMPLES; i++)
    {
        microseconds = micros();    //Overflows after around 70 minutes!

        vReal[i] = analogRead(A0);
        vImag[i] = 0;

        while(micros() < (microseconds + sampling_period_us)){
        }
    }

    /*FFT*/
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
    double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);

    /*PRINT RESULTS*/
    Serial.println(peak);     //Print out what frequency is the most dominant.

  //  for(int i=0; i<(SAMPLES/2); i++)
   // {
        /*View all these three lines in serial terminal to see which frequencies has which amplitudes*/

        //Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
        //Serial.print(" ");
      // Serial.println(vReal[i], 1);    //View only this line in serial plotter to visualize the bins
  //  }

 }

    //delay(1000);  //Repeat the process every second OR:
   // while(1);       //Run code once
}

EDIT:
@Dorian  After several days of tribulations and frustrations, I read and re-read your additional info and helped me clarify things better. I think I have some hardware limitations.  By the way...yes I do have a 27pf capacitor to the GND with a 3.3K resistor and a 3V zener in parallel at the OP AMP's outlet.
But let me explain first: I decided to add a comparator after the sensor and OP AMP.  Now I have a baseline voltage at HIGH (3.1V).  Previously, as I posted, the OP AMP had baseline of 1.65V and when motion is detected the voltage bounces between HIGHs (2.5V-3.1V)  and LOWs (1V-0V) for about 10-20 times until it settles at the 1.65V baseline again.  I suspected that the HIGH and LOW thresholds were not that clear. In order to get a clear HIGH or LOW I added the comparator.  These readings go to an MCU's digital Capture pin capable of 62.5ns ticks (16 MHZ). The Arduino program that counts the pulses is verified to work.  In the specs the MCU at 3.3V has 1V and below as LOW and 2.5V and above as HIGH.
See the new oscope reading (attached).  I get accurate pulse captures (matching the oscope), but I only get about 3 or 4 pulse readings instead of the 10-20 showing on the scope.    I used LOW capture (below 1V).  But even if I switch to TOGGLE capture (double) I seems to be getting only the last 3-4 complete waves (1/3rd) and seem to be missing the first 2/3rds. Or may getting every 2nd or 3rd?
My OP AMP is fast at 50 MHZ and I used to measure 100us-800us pulses with it accurately. And my comparator (after the OP AMP) is a MAX 9052 with a 400ns propagation delay. 40-80ns rise/fall time.  So I should not be missing any pulses.  The Arduino program cannot be that slow either.
EDIT #2:
//the best resolution you can achieve is 1/16us.

#include <Arduino.h>

#define FREQ_MEASURE_PIN 8  // actual 6 is PIN D11 and 8 is PIN D12 on Adafruit Feather Express nRF52840 LE, pin 11 is D12 itsybitsy 52840
#define PPI_CHANNEL 1u
#define GPIOTE_CHANNEL 1   //just picked channel #1

volatile int pulseCount = 0;
volatile unsigned long duration; //Pulse2 - Pulse1 = count of time ticks at 62.5 ns each tick (16 Mhz clock scaled at 0)     (expected value example: 792.5620  => 7925620)
volatile unsigned long pulseTime;   // first signal reading
volatile unsigned long lastTime;   //  most current signal reading

void setup() {

    Serial.begin(115200);

  initCounter();
}

void loop()
{

  if  ((pulseCount == 2) && (duration>0))  {

    Serial.println(duration);   //

   }

}

//must use extern "C" because IRQ will not compile since it's "C" coded
extern "C"
{
void GPIOTE_IRQHandler(void)
{

  lastTime = pulseTime;

  if (NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL] == 1)    //if an input pulse is detected on pin 6 then...
  {
    NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL] = 0;     //  reset event detection to zero to ready for next event detection?
    pulseTime = NRF_TIMER2->CC[0];                     // save Timer value at same time when signal was read on pin 6

    //pulseCounter
    pulseCount++;
    duration =(((pulseTime*10000) - (lastTime*10000))/16); //multiply by 10000 to avoid float, and divide by 16 for 16 Mhz clock tick = 62.5 ns per tick

   // goes from here to Loop if pulse = 2 (complete PULSE) so a reading can be sent
    }
  }
}

void initCounter()
{
  NRF_P0->PIN_CNF[FREQ_MEASURE_PIN] = GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos |        //sets up PIN 6 for event read
                                      GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos |  //pos going signal
                                    //  GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos |   //pulldown LOW so no floating of pin voltage
                                   //   GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos;      //a HIGH POS signal is the trigger

                                      GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos |   //Pullup or Pulldown LOW so no floating of pin voltage
                                      GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos;      //a HIGH POS signal is the trigger .... or a LOW POS

  NRF_PPI->CHEN |= 1 << PPI_CHANNEL;
  NRF_PPI->CH[PPI_CHANNEL].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL];
  NRF_PPI->CH[PPI_CHANNEL].TEP = (uint32_t)&NRF_TIMER2->TASKS_CAPTURE[0];   //sets up Timer channel

  NRF_GPIOTE->CONFIG[GPIOTE_CHANNEL] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos |         //sets up pin for event capture
                                    FREQ_MEASURE_PIN << GPIOTE_CONFIG_PSEL_Pos |                   //sets up event capture on pin 6
                                    GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos;   //sets event capture signal trigger type:  LoToHi   or HiToLo or  Toggle
  NRF_GPIOTE->INTENSET = (1 << GPIOTE_CHANNEL);    //  Interrupt routine setup on a pin
  NVIC_EnableIRQ(GPIOTE_IRQn);                     //  Interrupt routine setup if signal detected on pin 6

  NRF_TIMER2->TASKS_STOP = 1;    //stops timer
  NRF_TIMER2->TASKS_CLEAR = 1;    //clear timer to zero
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;   //sets up TIMEr mode as "Timer"
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos;    // sets values for Timer input
  NRF_TIMER2->PRESCALER = 0;       //read at max resolution (at MCU speed)
  NRF_TIMER2->TASKS_START = 1;      // starts the Timer
}

EDIT #3:  ================================================
I added the OP AMP circuit below. This circuit worked fine with an inductive sensor using eddy-currents. I measured @ 700-800us single-shot pulses very accurately, but did not have the R1 (22k) resistor. Added the R1 resistor and the GND immediately after it when replaced the inductive sensor with the 24 GHZ radar sensor because I was not getting readings. This circuit provides the first graph I posted, centered at around 1.6V. I took the comparator after the OP AMP off as not to complicate the circuit, and also it had some artifacts.
In summary:  the suspicion is that the Arduino program I posted for the nRF52 is not fast enough to capture 100us pulses in fast succession.  I tried to use BLE only and uncommented the SerialPrint and SerialBegin, etc....but even with BLE I got the same limited pulse readings.  For example: there were 10-20 pulses, I was only able to capture the last 1/3 of the pulses (3-4).  I tried HIGH and LOW (HiToLo/LoToHi/Toggle) as well.
The radar sensor is:  3.3V supply. IF out (signal read) is between 60mV-250mV.  60mv being the zero signal state.
Here are some sample period (wave pulse) readings in micro seconds:

97.0000
53.2500
45.2500
42.0625
40.8125
**40.9375**

And the actual period that it should read based on reference measurement:  **38.4435**us

==========================
Another set of period (wave pulse) readings in micro seconds:

95.6875
55.0000
46.7500
41.7500
**40.2500**

And the actual period that it should read based on reference measurement: **39.1703**us

So the last reading is quite close, but not proportionally close where I can "estimate" the actual value reliably.  So it's not for example off by 5.13% every time, but it's off by 3-6%.
Graph of example wave pulses (smaller means shorter pulse):

The ZENER at the output is there to clip the waves from going over 3.3V which can damage the MCU's input capture pin.

Thank you for your assistance!
For information only: THESE WERE THE OSCOPE READINGS WITH THE COMPARATOR CIRCUIT ADDED ON TO THE OP AMP'S OUTPUT BUT I SINCE REMOVED THE COMPARATOR CIRCUIT:

EDIT #4:   It's been quite a delay as I needed to do something else after not getting anywhere with this project.  Then today as I was struggling again I think I arrived to the solution.  It requires more work, but at least I have a cobbled together version that seems to work well.
The problem seem to have been with the signal itself being a sine-wave or a quasi-square wave.   Using an Arduino AVR sketch for the internal comparator that is being assisted by the comparator's ISR to "square" the incoming signal with timers and interrupts by toggling another pin into the Ref pin of the comparator, I was able to get reliable readings.   I actually ended up using an external comparator with the AVR and an nRF52 to count to periods.  This is the program and looks another person also went through hell:
https://electronics.stackexchange.com/questions/357131/random-and-unpredictable-analog-comparator-behaviour/566974#566974
I prefer to use the nRF52 because of the BLE integration, but I think I can make the AVR work first stand-alone by figuring out how to edit the library to reverse the interrupt from Low to High to High to Low...since the output of the comparator is opposite of my signal input.
Of course I still need to process the readings to sort out the dominant frequency, but manually I was able to calculate 5 out of 5 events within 2-5% of the valid value.
However, it seems that the key in the input signal being read reliably is the additional pin that is used to "convert" the sine wave into a square as part of the comparator's interrupt routine.
I still need to wrap my head around how the AVR program's additional pin toggled LOW/HIGH connected to VREF of the comparator "shapes" the sine wave and acts as a feedback for hysteresis.  I believe that which ever way I arrive to a "nice" square wave for the AVR's or nRF52's input counter to read will be a winner.  But I will open an new topic if I get stuck.  Thank you for your help and any inputs suggestions are welcomed.
EDIT #5: Based on a suggestion in another post I decided to use a 74xx14 Schmitt Trigger at the output of the op amp and it worked really well.  The square pulses were well defined (4ns rise time in specs) that I was able to identify every one of the pulses (usually between 5-20) in the software.  Manual calculations lead to accurate frequencies too.
Now I need to figure a way to identify the dominant frequency that has to be done on software.  I tried several FFT/FHT and ADC averaging programs, but none of them worked right.  Will bring this up in a separate question.  Thank you all for your help. Seems like the root problem was signal conditioning on my part.

I would suggest FFT is not the way you want to go. Since you only care about the dominant frequency, and you essentially have a square wave there, you can use the input-capture peripheral present in most MCUs to measure the time between leading edges, and calculate the frequency from that.

Thank you. I was wondering about that too.   I actually have a program for the freq/period at 62.5 ns resolution.  But I was expecting some FFT magic.  However, I think you are right, I need to do some legwork and try to extract the dominant freq from these 8-17 readings.I do not know statistics, but I can read up on it.  Any suggestions on what to apply?  Average, deviation, etc?  These is a sample period reading after I took out the outliers from beginning/end/zeros/duplicates: 2703750
2603125
2326250
2391250
2426250
2335625
2090625
2046875
2239375
2145000
2763750
2685625

I have no idea what those numbers represent. If you measure the time between successive rising edges and discard the first X results you can then take a simple average. That would give you the average speed across that sample set. Or you could take the mode (most common result) or median (middle value) or whatever you like. It all depends what you want to do with the data. A simple mean average is probably simplest.

Thank you.  Those numbers are the period values between consecutive rising edges.  They need to be divided by 10,000 to get 239.125 us , 242.625 us , etc  Pretty consistent AFTER I took out the outliers" by hand".   Will work on a formula for automating the taking out the outliers.

Maybe a "mode" average would do it for you.

Reading up on the "mode" average, I think you are correct, as this would give the best representation of the "dominant" frequency.  Will try that.

Using analogRead() in a loop gives a minimum sampling period of 112 µs (i.e. 8.929 kS/s). At this sampling rate, an input signal at 6.613 kHz is aliased to 2.316 kHz. But with only 4 samples, the spectral resolution is f_samp/4 = 2.232 kHz.

@Edgar Bonet   Thank you for your repeat assistance.  The first couple of Arduino programs I used were Nick Gammon's AVR register-level digital input-pin capture mixed with AnalogRead() as the threshold.  But then when using the hardware comparator I switched to an nRF52 with Arduino register-level TOGGLE and LOW interrupt-based input capture (16 MHZ) without analogRead().   The Oscope has the near correct freq/period readings once I zoom in to a sample of 2-3 waves. With the same program I can capture a single pulse of around 780 us (or even down to 100us.- have not tried yet)

@ Edgar Bonet continued: with doppler I get 50-250us pulses as LOW to LOW signal (half wave?)    Added the new nRF52 Arduino program above under EDIT #2.

The graph looks pretty bad. Post the schematic please. But the missed pulses might be due the serial.print() taking to much time. It's 8 us x 10 bits  x at least two bytes = 160us, vrey close to the pulse width.

@Dorian  Thank you for the reply/tip.  I was thinking about the SerialPrint as a possible problem but dismissed it.  Now that you mention it I will switch over to BLE which is what the final program will use anyway.  I need to revise the schematic with the comparator added and a resistor by the Op AMP inputs...and then post it.  But let me try the BLE first because I suspect that may be the issue.  I changed the SerialPrint from 115200 to 500000 during a couple of my tests but can't recall any huge difference.  So BLE first and will report back!  Thank you.

@Dorian Added EDIT #3. Reconfigured Arduino program with BLE but same results, with only about last 1/3 of pulses registering only. Uncommented all "Serial" lines. Posted OP AMP circuit but took off the comparator add-on to make it simpler. Please, note that R1 (22k) resistor and GND after that are my "improvisations" when switched from an inductive sensor (worked great) to the current 24GHZ radar sensor. This circuit provided the "beautiful" graph (1st one) in my original post.  Also, the OSCOPE does give correct freq/period after I focus down to a full wave near the end of the pulse train.

I have a simple frequency generator and will set it for a steady pulse of 700us to feed into the OP AMP instead of the sensor.   Will gradually start reducing the period (pulse) from 700us to 20us and see how the input capture program and Arduino BLE and/or Serial readings turn out..  Maybe able to determine if there is a software limitation.

Using the freq generator it seems that the program hangs at around 500us and below with a 10% duty-cycle wave of around 1.9khz.  I made some temporary modifications to the program where it just splits out raw data...and was able to go down to 15us pulses.  Still checking...

All specifications for the speed of the opamp are given assuming the linear region of the opamp which is not the case here, the opamp output as you see is limited to 0v and 3.3v which also makes the zenner useless. Try to replace R27 with a higher value until you get a clean, not limited output then use the comparator or just use only the comparator without opamp.

Also something is really weird with the comparator output, certainly something is wrong in the way you use the comparator. This comparator has hysteresis, I can't figure how you got to these graphs.

To have a meaningful result from the Fourier transform the input signal must filtered to a bandwidth at most half of the sample rate.
Your 10khz maximum sample rate which I suppose is given by the maximum sample rate of the ADC is less than double of 6.61 kHz , the base frequency of your signal.
Even more, you limit the signal adding high frequency components to the signal that already doesn't fit into the required bandwidth.
You better stick to zero cross detection using both rising and falling edges to have more data to average.
You might also check which part of the signal has the correct speed data against the real speed or to check  for a pattern, I see the middle period is lower then at the beginning and the end of the signal.
Later edit. Some things you should check and explanation on why is pointless to use FFT on this.
First, I see you have a clean middle centered signal between -0.7 and 3V.  Maybe there is an output capacitor on the sensor that auto limits itself between Zener voltage and the lower clamp diode. The middle is somewhere at 1.5V.  But the middle of the logic voltage is somewhere at half VDD, 2.5V.
Maybe that's why you have variations of pulse length from the beginning to the end of the train pulse because the decision line is above the middle line.
Of course setting the decision around the middle line might give a lot of noise but you can either use an envelope detector to see when the pulse begins or a Schmidt trigger so only signal above the hysteresis will pass.
I think that truly detecting the passes around the middle point will give you more reliable and consistent results.
About using discrete Fourier transform (fast or not) for finding the base frequency of the signal, there is no way to obtain a reasonable resolution using such a short signal.
The DFT is discreete not only in time but in frequency to. Anybody who has some basic knowledge about DFT knows that the maximum resolution in frequency that you can obtain in a t timeframe is 1/t, here for 2.5ms the frequency will be in steps of 400Hz, if you have maximum 8kHz signal you will have 20 fixed frequency values from 0 to 8kHz no matter how many samples you take, no matter on what software you make the processing or platform. It's a dead end.

Thank you @ Dorian.  I spent hours yesterday on Arduino and with a reference doppler radar (for actual speed) trying to extract data patterns that are repeatable and match the real speed at least remotely.  My test conditions are ideal, but getting considerable variances that should not be the case.  I need to re-visit the theory/etc behind doppler and also read up on signal-processing.  I need to take a 30,000 feet view because I think I am running down rabbit holes.

@ Dorian   Please see my edits above in the original post.  I added a comparator to get a clear LOW instead of zero-crossing.  When I pick apart my oscope readings and manually examine each wave they do match up with the pulses captured by the MCU.  But seem to be missing the first 2/3 and the last wave or two.

Posted above that I need to setup from scratch an OP AMP ob breadboard and revise my comparator also, because the current OP AMP is on a soldered PCB and can only do so much for "re-arranging" the two inputs.   Will report back.  Will make sure that the Op AMP and comparators are fast enough for a 50us period signal (double freq minimum).

I understand that it's difficult to unsolder R27. You might also use a smaller R23 to reduce the gain by piggybacking with a parallel resistor.

Unfortunately, I have most of the op amp entombed in hot glue.  I am making a new one and carefully selecting the bandwidth, etc. Also a comparator chip to get clear High/Lows.  Should get it this weekend.  At times frustrating (because I have huge gaps in my knowledge) but small victories make up for it! :)

Any reason for cowardly silent downvote? - See Why isn't providing feedback mandatory on downvotes, and why are ideas suggesting such negatively received?. Comments are not required on downvotes, and the absence of a comment is not cowardly. Read the link to see why. If you had to comment on downvotes, then surely upvotes without a comment are also cowardly? Don't let it worry you. I get downvotes on my posts and just ignore them. :)

@NickGammon Thank you Nick  I explained why I downvoted the other answer so others appreciate by themselves and in exchange shortly after I received a silent down-vote, I can only guess that It was from the fellow I down-voted. Why should I explain an upvote to a good and complete answer? You could do something at least where the downvoter has his own answer.

@Dorian Making assumptions about who downvoted and/or why will lead down paths of frustration--don't go down that path. It's not clear what would be reasonable to do if a downvoter-with-an-answer downvotes a different answer: randomly assigning downvote motivation on the part of the general public is fraught enough--putting any sort of official mechanism in place for that would be even worse.

@DaveNewton You're both right. Nothing is simple. Fixing something can break something else. That's life. Thanks for deleting the comment. It sure didn't helped anybody. Oh, you didn't, I thought It cant be deleted after all this time. I did.

I don't know and can't find out who up-votes or down-votes. Sometime there is "revenge" downvoting - it happens to me too and I am a moderator. (People don't like something I did and then start down-voting my posts, lol). Serial revenge-downvoting can be picked up by Stack Exchange's automated systems. One or two is nothing to worry about.

I cannot really understand why you can't catch pulses at 6613 Hz.
That is not that fast, even for an Uno.
I did the following experiment with an Uno: I use Timer 2 to
generate a short burst of pulses on pin 11 (PB3 = OC2A). This pin
is connected to pin 8 (ICP1), where I use Timer 1 to capture
the falling edges. In the input capture ISR I count the number of edges
received, and I also record the timestamps of the first and the last
edge. This way I can compute the received frequency.
The result of the experiment is that this way I can reliably measure
frequencies up to 125 kHz. This is about 19 times the
frequency of your burst. The measurement becomes unreliable if I keep
increasing the frequency.
Here is my test code:
// CPU cycles per half-period of the pulse burst.
const uint16_t half_period = 64;

// Statistics recorded by the input capture ISR.
volatile uint16_t capture_count;
volatile uint16_t timer_start;
volatile uint16_t timer_end;

// Input capture ISR.
ISR(TIMER1_CAPT_vect) {
    uint16_t now = ICR1;
    uint16_t count = capture_count;
    if (count == 0)
        timer_start = now;
    else
        timer_end = now;
    capture_count = count+1;
}

void setup() {
    Serial.begin(9600);
    Serial.print("Expected frequency: ");
    Serial.print((float) F_CPU / (2*half_period));
    Serial.println(" Hz");
    Serial.println("Measured frequency:");
    Serial.flush();

    // Configure Timer 2 for fast PWM.
    DDRB  |= _BV(PB3);    // digital 11 = PB3 = OC2A as output
    TCCR2A = _BV(COM2A0)  // toggle OC2A on compare match
           | _BV(WGM21);  // mode 2 = CTC, TOP = OCR2A
    TCCR2B = 0;           // keep timer stopped
    OCR2A  = half_period - 1;

    // Configure Timer 1 for input capture.
    TCCR1A = 0;           // normal mode
    TCCR1B = _BV(CS10);   // clock @ F_CPU
    TIFR1  = _BV(ICF1);   // clear input capture flag
    TIMSK1 = _BV(ICIE1);  // enable input capture interrupt
}

void loop() {
    // Reset the counter.
    capture_count = 0;

    // Send a burst of pulses.
    TCCR2B = _BV(CS20);   // clock Timer 2 @ F_CPU
    delayMicroseconds(1000);
    TCCR2B = 0;           // stop Timer 2

    // Report results.
    uint16_t timer_cycles = timer_end - timer_start;
    uint16_t pulse_count = capture_count - 1;
    Serial.print(pulse_count);
    Serial.print(" pulses in ");
    Serial.print(timer_cycles);
    Serial.print(" timer cycles -> ");
    Serial.print((float) pulse_count / timer_cycles * F_CPU);
    Serial.println(" Hz");
    delay(500);
}

And here is the output:
Expected frequency: 125000.00 Hz
Measured frequency:
255 pulses in 32640 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz

Thank you @Edgar Bonet very much for the sample program and the suggestion.  Will switch over to the AVR (currently using nRF52) and test it with your method.  I am having a go at Dorian's recommendation on cleaning up the input signal to the OP AMP first that is better adopted to the current doppler sensor vs the single-shot inductive sensor I used it with previously.

I tested the code and worked as you posted it @Edgar Bonet (except overflowing over 65535 in my case) but could not get the readings to correlate. I spent a considerable time massaging the OP AMP signal by rearranging the resistors on both inputs, but I am constrained by the previous soldered PCB setup that was for the other sensor type.  I need to setup a new clean OP AMP breadboard from scratch, along with a comparator example as also suggested by Dorian.  Will report back.

@TommyS: The overflow of the timer is not an issue, as long as the burst fits in 16 bits, i.e. is shorter than 4.096 ms. For longer bursts, you can set the timer prescaler to 8, which will increase the max burst duration to 32.768 ms, at the cost of degraded resolution. Alternatively, you can count the overflows in TIMER1_OVF_vect, but then it is tricky to avoid a race condition when the overflow fires very close to the capture.

Updated status and identified most likely problem and work-around solution,  Will open new Question on best path forward in squaring a sine wave.


text:
Input Capture with Sleep Enabled on ATM32u4 board only works every second reading in SLEEP mode
In short: I have an Input Capture code and a Power-Saving code combined into one program.  Both are adapted from Nick Gammon's examples that work fine independently.  When I combined them into one code it only reads the data every other time a single pulse is sent to be captured every 20 seconds. The board sleeps during one idle cycle between the 20 second readings, then wakes up but misses the first reading, and then it stays awake during the next idle cycle and reads the pulse correctly at the 40 second mark for the second reading.  And repeats.  The references of these two Nick Gammon codes are listed in the program.
Details: Adafruit BlueFruit Feather 32u4 w/nrf51 in the Arduino 1.8.10 IDE.  Using Nick Gammon's example for Input Capture an external incoming pulse of around 800 us (micro sec) long pulse is being measured by (ICP3) Input Capture #3 (rewritten from ICP1) on Pin D13 (PC7) (removed the LED). Works good.
Then I had a separate program that puts the board into deep-sleep and using INT0 (D3) to wake it up with an external interrupt signal.    Since I was not able to figure out how to use the Input Capture as an ISR Interrupt to wake up the board, I ran the same external pulse signal also to the D3 (INT0) pin. So when the pulse hits both D3 (INT0) and D13 (ICP3) at the same time, and D3 wakes up the board via INT0 and then the ICP3 can capture the pulse and measure it.  Then right after that, or several seconds later, can go back to sleep until the next pulse arrives on D13 (ICP3).  I spaced the external 800us single pulses 20 seconds apart to make it easier to diagnose.  If I remove the line that places the board into sleep "sleep_cpu ();" I get a nice single-shot signal pulse measurement every 20 seconds.   Since I am not using the USB-detach and reconnect feature, after the board goes to sleep it disconnects, but I am monitoring the power usage  via a Fluke mA meter and I can see when it sleep and when it wakes up, and also monitoring the external pulse going to D13 (ICP3) and D3 (INT0) on the Oscope.
Notes: The Input Capture is listed under the Interrupts, but at a much lower priority then INTo or INT1.
I do not need an active USB during the readings or sleep, because using  BLE to send the data.  The code I posted has the BLE portion removed the make it simpler to troubleshoot. The 800us external single-shot pulse is rock solid I have it showing on the Oscope, at the proper magnitude (0 to 3.3V) and intervals. I am trying to have the CPU sleep between readings.  Can be right after the reading or a few seconds later. Interrupts have to be alive and ready to capture in case the 20 seconds becomes 1 or 2 seconds intervals (in real life).
// Time the interval between two consecutive pulses.Frequency timer using input //capture unit #3 on 32u4
// Author: Nick Gammon
// Date: 31 August 2013  http://www.gammon.com.au/timers
//  References: here:  http://www.gammon.com.au/forum/?id=11504&reply=12#reply12    //and  here:  https://www.gammon.com.au/power Sketch J
// Info here: http://gammon.com.au/interrupts
//Freq (Hz)     Per (µs)
// 8,000,000*   0.125us  or 125ns per clock tick at 8mghz

#include "LowPower.h"
//part of work around for BOSD missing functionality in 32u4.
//Not needed for 328p MCUs for sleep.

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include "avr/io.h"
#include <math.h>
#include <Arduino.h>

// Input: Pin D13 (PC7, ICP3) adafruit 32u  which is Timer3 Capture Input pin ,   //removed D13 LED by cutting trace or by removing resistor before LED13

const int wakeUpPin = 3;
volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;
volatile unsigned long elapsedTime;

//////START: ISR TIMER/COUNTER PULSE ROUTINE ON D13 INPUT-CAPTURE #3 on 32u4 ////
//https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html   //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3

// timer overflows (every 65536 counts)
ISR (TIMER3_OVF_vect) //1 3

{
        overflowCount++;
}  // end of TIMER3_OVF_vect

ISR (TIMER3_CAPT_vect)   // 1 3
  {
       // cancel sleep as a precaution  (added here from Power Save)
      sleep_disable();

   // grab counter value before it changes any more
  unsigned int timer3CounterValue;
  timer3CounterValue = ICR3;
// see datasheet, page 117 (accessing 16-bit registers)
  unsigned long overflowCopy = overflowCount;

  // if just missed an overflow
  if ((TIFR3 & bit (TOV3)) && timer3CounterValue < 0x7FFF)  // 1 3     //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3
    overflowCopy++;

  // wait until we noticed last one
  if (triggered)
    return;

  if (first)
    {
    startTime = (overflowCopy << 16) + timer3CounterValue;
    first = false;
    return;
    }

  finishTime = (overflowCopy << 16) + timer3CounterValue;
  triggered = true;
  TIMSK3 = 0;    // no more interrupts for now   // 1 3    //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3
  }  // end of TIMER3_CAPT_vect

/////////////////////////ENF OF: TIMER/COUNTER PULSE MEASURE ROUTINE////////////

////////PREPARE FOR INTERRUPTS ROUTINE FOR TIMER/COUNTER CAPTURE////////////////

void prepareForInterrupts ()
  {

  noInterrupts ();  // protected code
  first = true;
  triggered = false;  // re-arm for next time
  // reset Timer 1
  TCCR3A = 0;   // 1 3
  TCCR3B = 0;    // 1 3

  TIFR3 = bit (ICF3) | bit (TOV3);  // clear flags so we don't get a bogus interrupt    // 1 3
  TCNT3 = 0;          // Counter to zero   // 1 3
  overflowCount = 0;  // Therefore no overflows yet

  // Timer 3 - counts clock pulses
  TIMSK3 = bit (TOIE3) | bit (ICIE3);   // interrupt on Timer 3 overflow and input capture
  // start Timer 1, no prescaler
  TCCR3B =  bit (CS30) | bit (ICES3);

// plus Input Capture Edge Select (rising on D13)
//TCCR1B &= ~(1<<ICES1);
//ICP set to trigger on falling/rising edge
//   Bit 6 - ICES1: Input Capture Edge select    Select edge detection for //input capture function.          0 = Capture on falling edge  1 = Capture on //rising edge

  interrupts ();
  }  // end of prepare For Interrupts

///END OF:   PREPARE FOR INTERRUPTS ROUTINE FOR TIMER/COUNTER////////////

///POWER SAVING -SIGNAL INTERRUPT WAKEUP ISR ON D3 on 32u4 or D2 on 328p///

void wakeUp ()
 {
  // cancel sleep as a precaution
     sleep_disable();
  // precautionary while we do other stuff
   detachInterrupt(digitalPinToInterrupt(wakeUpPin));
//D3 for 32u4 and D2 for 328p (INT0)
 }  // end of wakeUp
////POWER SAVING ROUTINE - WAKEUP ISR-END/////////////////

////////SET UP VOID ///////////////////////////////////////////

void setup(void)
{
 pinMode(wakeUpPin, INPUT); //this is pin D3 (INT0) on 32u4 and D2 (INT0) on 328p
digitalWrite (wakeUpPin, LOW);
// enable pull-down on D3 (on 32u4 D3 is INT0) for Wake INTERRUPT   - PART OF //POWER SAVING ROUTINE WITH INT0 SIGNAL on D3 on 32u4 (or D2 on 328p)

 Serial.begin(115200);

  pinMode(13, INPUT);
//This is the input/measure pin (LED taken off or LED13 resistor removed)
   analogWrite(13, LOW);  //must pull up or down to stop noise and floating

  // set up for interrupts
  prepareForInterrupts ();

}   // <= this is for the SET UP () ///////

////////////////////////END OF SETUP SEGMENT/////////////////

//////START OF MAIN LOOP/////////////

void loop(void)
{

   // wait till we have a reading
if (!triggered) //if "triggered" is NOT TRUE  (i.e. NOT TRIGGERED) then STOP HERE
 return;

unsigned long  elapsedTime = (finishTime - startTime);
//period count between start and stop times

Serial.print ("Start time: ");
Serial.print(startTime);
Serial.print (" counts.  ");
Serial.print ("Finish time: ");
Serial.print(finishTime );
Serial.print (" counts.  ");
Serial.print ("Elapsed time: ");
Serial.print (elapsedTime);
Serial.println (" counts.   ");

 // Delay before next measurement update
 delayMicroseconds(1000) ;

 prepareForInterrupts ();
//  goes back up outside LOOP to RESET conditions for next INPUT CAPTURE ISR AND //OVERFLOW ISR TIMER/COUNTER reading, clear registers, etc

///START: POWER SAVING ROUTINE USING D3 (INT0) on 32u4  (D2 is INT0 on 328p) //INTERRUPT FROM PULSE OR USER SWITCH////////////

//delayMicroseconds(3000000) ;
// DELAY SO SLEEP ONLY CAN HAPPEN EVERY 3 sec =>  3000000 us (micro sec)

 delay(500);// MUST have delay to allow power down process to proceed

      // disable ADC
      ADCSRA = 0;

      set_sleep_mode (SLEEP_MODE_PWR_DOWN);
      sleep_enable();

  // Do not interrupt before we go to sleep, or the ISR will detach interrupts and we won't wake.
      noInterrupts ();

  // will be called when INT0 (pin D2 for 328p) or D3 for 32u4 goes HIGH//
     attachInterrupt(digitalPinToInterrupt(wakeUpPin), wakeUp, RISING);

// [External Interrupts] //3 for 32u4 and 2 for 328p (INT0)  Use RISING as //trigger for (INT0 on D2 for 328p and) INT0 on D3 on 32u4 from op AMP.  Same //signal as the D13 INPUT CAPTURE TIMER from op Amp OUT
     EIFR = bit (INTF0);  // clear flag for interrupt 0
     EIFR = bit (INTF1);  // clear flag for interrupt 1
//  added just for good measure to cover both D2 and D3 INT pins

// turn off brown-out enable in software, BODS does not work with 32u4, only //328p.  Work around is to use "low-power.h" library, not implemented here
// BODS must be set to one and BODSE must be set to zero within four clock cycles
       // MCUCR = bit (BODS) | bit (BODSE);
       // The BODS bit is automatically cleared after three clock cycles
       // MCUCR = bit (BODS);

//We are guaranteed that the sleep_cpu call will be done as the processor //executes the next instruction after interrupts are turned on.
        interrupts ();  // one cycle
     // sleep_cpu ();   // one cycle    //*****DISABLED BECAUSE KEEPS DOUBLING
                                        //DATA SEND TIME, AND ONLY WAKES UP HALF
                                        //THE TIME

///////END OF POWER SAVING ROUTINE///////////////////////////////////////////////

}
///////////////////////END OF MAIN LOOP///////////////////

It seems to me your problem lies here:

set_sleep_mode (SLEEP_MODE_PWR_DOWN);

In this mode, all the synchronous peripherals are turned off, including
your timer. However, you need this timer for generating the input
capture interrupt. You also want it to be running in order to count the
overflows, otherwise the values captured would be meaningless.
In order to keep the timer running, you have to use SLEEP_MODE_IDLE,
which is the default sleep mode anyway. This mode puts the CPU to sleep
while keeping the peripherals running. If you are afraid this may have
too high a power consumption, you can selectively turn off all the
peripherals you do not need. Note that you cannot selectively
enable peripherals in other sleep modes.

Thank you for the suggestion & link. Saw an example for IDLE mode. Will check if shutting down unused peripherals lowers close to same as consumption as in SLEEP_MODE_POWERDOWN.  My assumption was that using an INT0-type interrupt would wake up the CPU so the INPUT CAPTURE TIMER would be fully ready. Works half of the time, on every 2nd external pulse, so I thought that  there is some sort of an interrupt-sequence/priority conflict in my code, or some of the flags (which are still murky for me) are not set properly as a result of the two combined codes. I suspect "if !triggered" and "return".

Edgar Bonet. Implemented & worked w/IDLE! Much lower mA. However, there maybe a coding solution to the problem outlined in my post.Convinced that when I combined Mr. Nick Gammon's two examples "InputCaptureCounter/Timer" & "Deep Sleep" the issue is in Void Loop=> if (!triggered) return;  This stops the program until a flag inside the ISR Capture is "true". When the attacheInterrupt on INT0/D3 fires same time as the ISR Capture reads on D13, the program may not make past WakeUp ISR, added by me. As a consequence the ISRs Capture & Overflow cannot read the pulse on D13 (PC7 on 32u4).

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Arduino Atmega32U with nRF51 BLE by Adafruit limited to 5 second update rate?
Would like to ask for assistance with the code below.  It's the Adafruit Bluefruit Atmega32U LE module with Adafruit's Arduino IDE example "heart-rate monitor" sketch.   The code uses the hardware SPI setup with Adafruit's BLE code between the Atmega32U and the nRF51822 using AT Commands built into a BLE stack by Adafruit.
It works at the same speed in real-time on the PC's Arduino IDE USB serial terminal and also on the Android phone's nRF Connect app or any other BLE app that can read "notifications".
Problem:  If remove the module from the PC's USB (thus the serial stopped and only using BLE) the update rate on the BLE Android app slows down to 5 second intervals compared to the near real-time speed while connected to USB.   I tried many things, including commenting out the Serial commands  in the void loop() and also the delay(), but no change.  As if the BLE stack by Adafruit would have a update period limitation.  According to Adafruit, they do not give access to to their BLE stack.  But I could possibly load another BLE stack on this nRF51822 chip.   Also I do have the Adafruit Sniffer with Wireshark, but not an expert using it.
How can I get less than 1 second update rates?  The data stream is not in 1 second intervals. Maybe 10-15 seconds between readings, but I need it updated within 1 second of being read from the sensor.
https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le?view=all
#include <Arduino.h>
#include <SPI.h>
#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"

#include "BluefruitConfig.h"

#if SOFTWARE_SERIAL_AVAILABLE
  #include <SoftwareSerial.h>
#endif

// Create the bluefruit object, either software serial...uncomment these lines
/*
SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN);

Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                      BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
*/

/* ...or hardware serial, which does not need the RTS/CTS pins. Uncomment this line */
// Adafruit_BluefruitLE_UART ble(BLUEFRUIT_HWSERIAL_NAME, BLUEFRUIT_UART_MODE_PIN);

/* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */
Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

/* ...software SPI, using SCK/MOSI/MISO user-defined SPI pins and then user selected CS/IRQ/RST */
//Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_SCK, BLUEFRUIT_SPI_MISO,
//                             BLUEFRUIT_SPI_MOSI, BLUEFRUIT_SPI_CS,
//                             BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

/* The service information */

int32_t hrmServiceId;
int32_t hrmMeasureCharId;
int32_t hrmLocationCharId;
/**************************************************************************/
/*!
    @brief  Sets up the HW an the BLE module (this function is called
            automatically on startup)
*/
/**************************************************************************/
void setup(void)
{
  while (!Serial); // required for Flora & Micro
  delay(500);

  boolean success;

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit Heart Rate Monitor (HRM) Example"));
  Serial.println(F("---------------------------------------------------"));

  randomSeed(micros());

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  /* Perform a factory reset to make sure everything is in a known state */
  Serial.println(F("Performing a factory reset: "));
  if (! ble.factoryReset() ){
       error(F("Couldn't factory reset"));
  }

  /* Disable command echo from Bluefruit */
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  // this line is particularly required for Flora, but is a good idea
  // anyways for the super long lines ahead!
  // ble.setInterCharWriteDelay(5); // 5 ms

  /* Change the device name to make it easier to find */
  Serial.println(F("Setting device name to 'Bluefruit HRM': "));

  if (! ble.sendCommandCheckOK(F("AT+GAPDEVNAME=Bluefruit HRM")) ) {
    error(F("Could not set device name?"));
  }

  /* Add the Heart Rate Service definition */
  /* Service ID should be 1 */
  Serial.println(F("Adding the Heart Rate Service definition (UUID = 0x180D): "));
  success = ble.sendCommandWithIntReply( F("AT+GATTADDSERVICE=UUID=0x180D"), &hrmServiceId);
  if (! success) {
    error(F("Could not add HRM service"));
  }

  /* Add the Heart Rate Measurement characteristic */
  /* Chars ID for Measurement should be 1 */
  Serial.println(F("Adding the Heart Rate Measurement characteristic (UUID = 0x2A37): "));
  success = ble.sendCommandWithIntReply( F("AT+GATTADDCHAR=UUID=0x2A37, PROPERTIES=0x10, MIN_LEN=2, MAX_LEN=3, VALUE=00-40"), &hrmMeasureCharId);
    if (! success) {
    error(F("Could not add HRM characteristic"));
  }

  /* Add the Body Sensor Location characteristic */
  /* Chars ID for Body should be 2 */
  Serial.println(F("Adding the Body Sensor Location characteristic (UUID = 0x2A38): "));
  success = ble.sendCommandWithIntReply( F("AT+GATTADDCHAR=UUID=0x2A38, PROPERTIES=0x02, MIN_LEN=1, VALUE=3"), &hrmLocationCharId);
    if (! success) {
    error(F("Could not add BSL characteristic"));
  }

  /* Add the Heart Rate Service to the advertising data (needed for Nordic apps to detect the service) */
  Serial.print(F("Adding Heart Rate Service UUID to the advertising payload: "));
  ble.sendCommandCheckOK( F("AT+GAPSETADVDATA=02-01-06-05-02-0d-18-0a-18") );

  /* Reset the device for the new service setting changes to take effect */
  Serial.print(F("Performing a SW reset (service changes require a reset): "));
  ble.reset();

  Serial.println();
}

/** Send randomized heart rate data continuously **/
void loop(void)
{
  int heart_rate = random(50, 100);

  //Serial.print(F("Updating HRM value to "));
  //Serial.print(heart_rate);
 // Serial.println(F(" BPM"));

  /* Command is sent when \n (\r) or println is called */
  /* AT+GATTCHAR=CharacteristicID,value */
  ble.print( F("AT+GATTCHAR=") );
  ble.print( hrmMeasureCharId );
  ble.print( F(",00-") );
  ble.println(heart_rate, HEX);

  /* Check if command executed OK */
 // if ( !ble.waitForOK() )
 // {
   // Serial.println(F("Failed to get response!"));
  //}

  /* Delay before next measurement update */
 // delay(1000);
}

/////////////////AND BELOW IS THE BluefruitConfig.h TAB in ARDUINO IDE --This is a separate file under a new tab in the IDE////////////////..

    // COMMON SETTINGS
// ----------------------------------------------------------------------------------------------
// These settings are used in both SW UART, HW UART and SPI mode
// ----------------------------------------------------------------------------------------------
#define BUFSIZE                        128   // Size of the read buffer for incoming data
#define VERBOSE_MODE                   true  // If set to 'true' enables debug output

// SOFTWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins that will be used for 'SW' serial.
// You should use this option if you are connecting the UART Friend to an UNO
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SWUART_RXD_PIN       9    // Required for software serial!
#define BLUEFRUIT_SWUART_TXD_PIN       10   // Required for software serial!
#define BLUEFRUIT_UART_CTS_PIN         11   // Required for software serial!
#define BLUEFRUIT_UART_RTS_PIN         8    // Optional, set to -1 if unused

// HARDWARE UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the HW serial port you are using. Uncomment
// this line if you are connecting the BLE to Leonardo/Micro or Flora
// ----------------------------------------------------------------------------------------------
#ifdef Serial1    // this makes it not complain on compilation if there's no Serial1
  #define BLUEFRUIT_HWSERIAL_NAME      Serial1
#endif

// SHARED UART SETTINGS
// ----------------------------------------------------------------------------------------------
// The following sets the optional Mode pin, its recommended but not required
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_UART_MODE_PIN        12    // Set to -1 if unused

// SHARED SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for HW and SW SPI communication.
// SCK, MISO and MOSI should be connected to the HW SPI pins on the Uno when
// using HW SPI.  This should be used with nRF51822 based Bluefruit LE modules
// that use SPI (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_CS               8
#define BLUEFRUIT_SPI_IRQ              7
#define BLUEFRUIT_SPI_RST              4    // Optional but recommended, set to -1 if unused

// SOFTWARE SPI SETTINGS
// ----------------------------------------------------------------------------------------------
// The following macros declare the pins to use for SW SPI communication.
// This should be used with nRF51822 based Bluefruit LE modules that use SPI
// (Bluefruit LE SPI Friend).
// ----------------------------------------------------------------------------------------------
#define BLUEFRUIT_SPI_SCK              13
#define BLUEFRUIT_SPI_MISO             12
#define BLUEFRUIT_SPI_MOSI             11

Thank you @Edgar Bonet for helping with the code format edit. Appreciate it. I was a bit late figuring it out.

first remove while (!Serial);

I removed the "while (!Serial)" and still has the 5 second lag on both Android and iOS apps receiving data. It's quite regular 5 seconds, not random intervals. Also, there is nothing left in the void loop() that can slow things down.  If I open the serial terminal box in the Arduino IDE then the data streams at full-speed in real-time.   I wonder, if there is some bug in the Adafruit BLE stack?  No source code is given out.  Wondering, if there is any way to add in the code to run the serial terminal (or something to that effect) without actually having the USB cable plugged in the PC?

How can I test the BLE for max speed?  I ran an Adafruit BLE example program that tested the UART side of the BLE and had about 1-2 Kbs datastream, but this heartrate program uses GATT BLE and not UART.

try to remove Serial.begin or add Serial.end() at the end of setup()

Uncommented Serial.begin  and added Serial.end() and same 5 second delay, but when the Arduino IDE serial terminal is active on the PC the data flows fast.  I added a 10 second delay in the void loop(), and the data came in at 10 sec intervals on the iOS app, Then I activated the Arduino IDE serial.terminal window on the PC and the data remained at 10 sec intervals. I think the delay is in the Adafruit BLE stack. The BLE uses hardware SPI, not familiar with SPI...going to check into it.

I am also going to reinstall the Adafruit BLE support Arduino library files.

Looks like it's working now.  I am going to verify it, but it seems that the "verbose" error check mode slowed down the flow of BLE data. I changed it from "true" to "false" to turn it off.

@Juraj, thank you for your assistance. It helped me narrow down what to focus on and eventually led to the solution.

The "verbose" error check mode for debug in the "BluefruitConfig.h" tab slowed down the flow of BLE data. I changed it from "true" to "false" to turn it off.
#define VERBOSE_MODE true  // If set to 'true' enables debug output

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Possible impedance problem when moving to new power supply
I'm working on building an LED matrix and I'm using an LED strip to create it. I've worked through a simple wiring setup using my bench top power supply and got a strip test working.
Now that I have the actual fabrication done I want to move the power from my bench top supply to a regular wall adapter supply.
The problem I'm running into is that when I provide power from the wall supply the led strip no longer gets the data from the signal pin.While troubleshooting I connected my multimeter to the signal pin and all of a sudden the strip's first LED got the signals and started lighting up.
I'm assuming I'm running into an impedance issue, but I'm not sure why or how to solve it other than trying different resistor values on the signal pin to overcome the issue.
Here's a rough diagram. there's not a lot to it:

I couldn't find info on the forward voltage of the strip or a datasheet for it, so I turned all of the LEDs white and looked at the current draw on my bench top supply:

So the whole matrix is pulling 1.5 amps.
The trinket M0's GPIO voltage is 3.3v, so if I'm thinking about this right to figure out the resistor I need I would use ohms law:
r = V/I

So in my case:
r = 3.3/1.5 = 2.2ohm

Is that right? While I know some I still feel like a novice and I'm working alone and teaching myself, so I'm not sure if I'm thinking of everything correctly.
I also shot a video showing what's happening if that helps: https://vimeo.com/496062949
UPDATE
And actually to simplify things further, I just tried moving the trinket over to the external power supply as well and I get the same issue.
So even with this diagram:

Update
A closer look at the all-on-the-wall-adapter circuit:

The resistor is on a signal line. There should hardly be any current there. I don't thing it's anything to do with that resistor. Have you tried powering the trinket from the same 5V brick, instead of USB? I think it might be a eathing problem. The bench power supply is mains earth referenced, while the brick is probably floating. Are you also really sure the grounds are connected? Maybe there's a loose breadboard connection.

WS2811 expected a minimum of 0.7xVdd for a logic high signal, which is 3.5V. You're marginal at best even if everything is grounded properly. You should level-shift that signal. (And indeed that LED isn't a dropping resistor - your Trinket would have blown up long ago if you tried to feed 1.5A through one of its pins.)

Yeah I moved everything to the wall adapter and  I double checked the ground connection and it's good, but still have the issue. I'm adding a new pic in of the circuit.

@Mat how would i do that level shift? Is this a case where I'd need to add a transistor to provide a higher voltage signal (e.g. pull the 3.3 from the trinket's top right pin) and then control the transistor with my signal pin? Ah wait, I forgot it can't be the 3.3v pin b/c we'd need 3.5, so maybe a voltage divider coming off the 5v power?

go back to the two power supply setup ... remove the ground connection between the two power supplies ... connect a ground wire directly from the trinket to the LED strip

@jsotola, what's the reasoning behind it? Don't the grounds need to be common?

For level shifting up you need a transistor, that switches the higher voltage via the lower voltage pin. Try it, then we can go further

What happens if you replace the brick with your lab-power-supply (without the USB)? Have you measured the voltage coming out the the brick?

@ChrisSchmitz the ground is common between the triket and LED strip ... the difference is that the grounds are not connected through the power supply wires   .... my thinking is that the power supply wires could introduce a voltage drop, which would raise the ground pin of the LED strip with respect to the ground pin of the trinket


text:
converting an unsigned integer into a const char pointer
I know this is simple basic C stuff, but I can't quite figure it out or find a solution when searching and reading.
I have a method I want to call from a library that wants a const char pointer
someclass::send(const char *data)

And the value I want to send is actually an unsigned integer:
enum messageTypeEnum
{
  REGISTER_CLIENT = 0x04,
  CLIENT_REGISTERED,
  UPDATE_CREDENTIALS,
  ADD_BRICK,
  GAME_FRAME,
  ERROR
};

enum clientTypeEnum
{
  GAMEBOARD = 0x01,
  BRICK_CONTROLLER,
  PLAYER_CONTROLLER,
  TOUCH_CONTROLLER
};

uint16_t message = GAMEBOARD;
message <<= 8;
message += REGISTER_CLIENT;

So I want to convert it, but I can't quite figure it out.
I know fundamentally the char pointer is just a pointer to a memory address and that c strings are null terminated, so I should be able to create the pointer, add the enum's underlying bytes to the pointer array, and then add a 0 at the end to terminate it, but I don't know how I would do that exactly.
I tried doing it via casting:
const char *data = (char *)&message;

So here I'm saying (if I'm thinking about it correctly), is:

&message take the memory address of message, our uint16
`(char *) interpret it as a pointer for a character string
const char * store that address in this const pointer

Even typing that out I feel like I'm misunderstanding parts.
This compiles, but it crashes my esp32 and I'm sure it's because I don't have a null terminator at the end, but I'm not sure how to add it (I tried to add it via array index but that failed).
What's the proper way of doing this (I'm sure there's a non-casting way that's probably easier)?
Update
More detail re: PMF and Edgar's comments.
I definitely want to send the binary numbers behind the enums up. I'm building a websocket based interactive project where "controller" websocket clients can drive interactions on "gameboards". Websockets don't have a concept of differentiating between client types (I know socket.io does, but I'm wanting to write it all with regular websockets), so I built a registration system into the server that looks at the first two bytes of an array buffer or blob message to determine the client and message type (it seems overly complicated, but I'm building this to give a talk on binary operations and I'm doing it give functional examples of data parsing).
So yeah, all of that to say I definitely want to send the underlying number values from the enums.
The library I'm using is ArduinoWebsockets and they do have a client method called sendBinary that does have a signature like the Serial.write:

Though when I tried this with a non-null terminated c-string my esp32 crashed. That said, I was fumbling around in the code so it may have been something else that caused the crash.
When I follow the method calls down, the library ultimately uses std::string to pull the data out of the passed in c string and takes in the length (meaning it doesn't need to be null terminated(?)):

So maybe I can use the casting to turn my two byte number into a c string and pass in the length of 16?

Are you sure you want to send a binary 0x01 value? I guess that it's rather your library that crashes because of this instead of the calling function. Although it is incorrect (as you're correctly assuming) the message is actually binary 0x01 0x00 (the esp32 is little endian) and so it does have a terminating 0 as long as the value is smaller than 256.

Serial.write() has the overload write(const uint8_t *buffer, size_t size) which lets you output an arbitrary array of bytes and doesn't require a NUL terminator (0 is a valid value to output). I have seen this kind of overload in other libraries. Your someclass may offer something similar for sending binary data. If it doesn't, it's probably not meant to send anything but text, in which case you have to serialize your data as text.

I do want to send the binary values up because I'm parsing the messages on the server as 8 bit array buffers or blobs and I have the same enums on the server and other clients to coordinate the message and client identification.

Ah @EdgarBonet  yeah the library does have a sendBinary method that takes a c string and a length, though I ran into issues when trying to use it. That said, I'm probably understanding it wrong. I'll update my question with more detail.

CORRECTED ANSWER
I dug back into my code after a comment from  Edgar and figured out some needed adjustments. My original solution was mostly correct, but there were some inaccuracies that I want to correct so I'm not goofing up anyone else in the future that may find this answer useful.

So I was overthinking things a bit. I still don't know that this is the best way of handling it, but it is working on the client side.
So, c-strings are just arrays of 8bit values with a null terminator at the end.
I want to end up my enum values, and my enums are define with byte enum-bases:
enum messageTypeEnum
{
  REGISTER_CLIENT = 0x04,
  CLIENT_REGISTERED,
  UPDATE_CREDENTIALS,
  ADD_BRICK,
  GAME_FRAME,
  ERROR
};

enum clientTypeEnum
{
  GAMEBOARD = 0x01,
  BRICK_CONTROLLER,
  PLAYER_CONTROLLER,
  TOUCH_CONTROLLER
};

So, to send up my bytes, I can just build a character array, set each byte in little endian order, and manually terminate it:
NOTE: this is the original assembly that was incorrect.
I put the null terminator at the beginning of the buffer thinking "oh, it's little endian so the terminator needs to be at the beginning". Classic sleepy brain mistake :|

void registerAsAGameBoard()
{
  char buffer[3] = {0, GAMEBOARD, REGISTER_CLIENT};
client.sendBinary((const char *)buffer, 3);
}

void registerAsAGameBoard()
{
  char data[3] = {GAMEBOARD, REGISTER_CLIENT, 0};

  const char *buffer = data;
  size_t size = strlen(buffer);

  client.sendBinary(buffer, size);
}

Now when I call sendBinary with my byte array and the length of the buffer my esp32 doesn't crash (hurray!) and the server receives the buffer correctly!!

I need to make a couple of adjustments on either the client and/or server side to account for the fact that the ESP32 is little endian and the server is already coded to receive payloads in big endian, but that shouldn't be too much of a lift.

Note that in char buffer[3] = {0, GAMEBOARD, REGISTER_CLIENT};, the 0 byte is not a “null terminator”: It's the first byte of the buffer, whereas a “terminator” is by definition at the end.

@EdgarBonet, you are correct, and I'm glad you pointed that out. I didn't understand why this particular setup prevented the crash. I dug in further and found that when put the null terminator in the correct place the controller still crashed, but it crashed in a different portion of the code where we handle different messages from the server. I commented that part out and the controller stopped crashing at both spots. I then updated the code with the correct null terminator and got everything ironed out. I'm updating my answer.


text:
Condition in a while loop not updated on my mkr1010
I am using a server-client system where i send data from the server to the client to turn on a led (the onboard led). Led must be turned off using digital input (labeled 7 on the connector).
I use therefore a while loop that checks the value of the input (button press). As long as value is not equal to LOW the led remains on (i use also a second led on pin 13 as doublecheck). I assume that the while loop will be left once i press the button, unfortunately this doesn't happen. The result of the condition seems not updated (remains HIGH).
I measured the voltage on the input when pressing the button and it goes from 3.3V to 0.0V so hardware seems to be OK.
From my undestanding the while loop is always (before each loop) checking the condition ? why doesn't this happen here ? did i do something wrong ?
I must use a while because i never know in advance when the button will be pressed.
this my code :
#include <SPI.h>
#include <WiFiNINA.h>
#include <utility/wifi_drv.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

//int keyIndex = 0;            // your network key Index number (needed only for WEP)

const int buttonPin = 7;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
int buttonState;         // variable for reading the pushbutton status

int status = WL_IDLE_STATUS;
IPAddress ServerIP(192,168,0,157);
WiFiClient client;

int i;
String response;

void setup() {

  WiFiDrv::pinMode(25, OUTPUT); //GREEN
  WiFiDrv::pinMode(26, OUTPUT); //RED
  WiFiDrv::pinMode(27, OUTPUT); //BLUE

 pinMode(buttonPin, INPUT);
 pinMode(ledPin, OUTPUT);

  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
   ; // wait for serial port to connect. Needed for native USB port only
  }
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
  Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }

    // you're connected now, so print out the status:
  printWifiStatus();
}

void loop() {

if (client.connect(ServerIP, 23)) {
  client.print("90");
  String response = client.readStringUntil('\n');

  Serial.println(response);

if (response == "9") {
  buttonState = digitalRead(buttonPin);
 // Serial.println(buttonState);
  while (buttonState != LOW){
    // turn LED on:
    digitalWrite(ledPin, HIGH);
     WiFiDrv::digitalWrite(25, 255); // for full brightness
     Serial.println(buttonState);
  }
  digitalWrite(ledPin, LOW);
  WiFiDrv::digitalWrite(25, LOW); // for full brightness
        }
  }

  client.stop();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
 Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

thanks a lot for helping me out !

 while (buttonState != LOW){
    // turn LED on:
    digitalWrite(ledPin, HIGH);
     WiFiDrv::digitalWrite(25, 255); // for full brightness
     Serial.println(buttonState);
  }

You never update the value of buttonState in this while loop.  If buttonState is not LOW to get into the while loop, nothing inside the while loop will ever change it so every time it gets checked it will still not be LOW.  It's not going to surmise that you meant to read a pin just because you used that variable to read a pin once before.
But do you really need this while loop?  Couldn't you just write the led pin low when you first get a press and then write it high when it first gets released?  See the "State Change Example".  Let the loop function be the loop.  It will lead to better code.  You don't see this now because you are a novice, but you are about to paint yourself into a corner with this approach and you'll soon be rewriting the whole thing.  It's a trap that gets most new coders.  Better to get it right now.

Yeah. As a rule you don't want to use while loops inside your sketch's loop function. It's almost always the wrong approach.

You don't want to use while loops anywhere in your code waiting for things in the outside world to happen.  A while loop is for like, while I still have more characters in this string or while I haven't cleared the whole array.  You should never have while loops blocking your code waiting on things to physically happen.  That traps you so that you can't have anything else happen during the wait.

Good way of explaining it.

thanks a lot to both of you! it's working now. I was not aware of that (no whiles when detecting outside events).


text:
sending numbers from server to client (arduino mkr1010)
I want to send basic information from a server to a client. 4 numbers representing a random sequence
for example 0100. I have put this in byte array and use the "server.write" to send it to the client. At the client side I always get 4 times "255" when i print it on the monitor (when i print in on serial monitor on the server side it shows the right sequence numbers).
This is (only relevant part of ) my code on the server:
int sequence;
byte myseq[4]={0,0,0,0};
int i;
byte a;

void loop() {
  // wait for a new client:
  WiFiClient client = server.available();

  sequence=random(0,3);

for (i = 0; i < 4; i = i + 1) {
  if (i == sequence){
  a=1;
  }
  else{
  a=0;
  }
   myseq[i] = a;
     }

  // when the client sends the first byte, say hello:
  if (client) {
    if (!alreadyConnected) {
      // clead out the input buffer:
      client.flush();
      Serial.println("We have a new client");
      client.println("Hello, client!");
      alreadyConnected = true;
    }

    if (client.available() > 0) {
      // read the bytes incoming from the client:
      char request = client.read();
      Serial.print(request);
      for (i = 0; i < 4; i = i + 1) {
      Serial.print(myseq[i]);
      server.write(myseq[i]);

      }

    }
  }
}

the code on the client side
byte response[4]={0,0,0,0};

void loop() {

if (client.connect(ServerIP, 23)) {
  client.print("741G");
  //String response = client.readStringUntil('\n');
  for (i = 0; i < 4; i = i + 1) {
  response[i] = client.read();
  Serial.println(response[i]);

  }

  //client.stop();
}

Can somebody help me in explaining what i'm doing wrong ? what happens with the numbers once they get sent ? Apparently they arrive in a different format ?
thanks in advance !
ps : i see now that my sequence numbers are always 4 booleans (half a byte) maybe there is an easier way?

you don't test with client.available() if the bytes arrived so read returns -1


text:
How to make the motor move after a certain period of time?
Basically I want my motor to run after let's say 10 seconds passed since the program started up.
The amount of time is determined by user input, and I have already coded for that. The motor is connected to a breadboard and powered by a 9v battery, also connected to the breadboard.
The thing is, the motor runs as soon as I connect it to the breadboard. How can I use the Arduino board to make the motor wait 10 seconds before it moves? I am new to both circuitry and code... Sorry for my cluelessness.
Thanks so much.

Please first post your current code so we have somethign to start from.

You will need to add a logic level mosfet of the appropriate size and specs to control the power to the motor.  You can drive the gate of the mosfet from a pin through a current limiting resistor with a larger bleed resistor.  For a brushed motor you'll need a ceramic RF supressor cap plus flyback diode for back EMF protection:

simulate this circuit – Schematic created using CircuitLab
For greater RF supression (if your motor is pretty beefy) you can use a 0.1uF between each input lead and the motor case.
When you turn the pin on, motor turns on, low turns off.  Using analog and appropriate R values you can control motor speed (setting 0-255):
int motorControl = [your pin];

void setup()
{
  pinMode(motorControl, OUTPUT);
}

void loop()
{
  delay(10000); // delay 10 seconds plus board boot time
  analogWrite(motorControl, 255); // turn motor on full
}

You can time the delay with a stop watch and adjust to be exactly 10s by dropping the delay() call to compensate for the boot up time of the board.
More about MOSFETS here:
https://electronics.stackexchange.com/questions/81935/mosfet-usage-and-p-vs-n-channel

Just a question: why the 220 Ohm resistor?

As mentioned several times, it serves to limit the current to protect the arduino when having to charge the capacitance of the MOSFET gate. The outputs expect something on the order of pF so trying to charge the nF capacitance overstresses.  Without the current limiting resistor, the arduino will eventually fail and likely take the MOSFET (and possibly other pieces) with it if the MOSFET goes linear and overheats.

I would recommend connecting the motor to a controller of some sort of a controller, maybe a relay or something like that, and then write some code that waits 10 seconds, and then turns on your controller / relay. That will turn on the motor.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Adding to the counter only ONCE while R2 =<200
I am very new to Arduino and I have this little bit of code:
if (R2 <= 200){
  counter=counter+1;
  Serial.print("counter: ");
  Serial.println(counter);
}

I want it to count every time R2 is less than or equal to 200, but I only want it to count once. Right now it adds to the counter 3-2 times while R2 is less than 200. I'd like it to only count once while in that range before R2 becomes greater than 200.
Any suggestions or links to helpful information would be very appreciated. Thank you!

Your question doesn't make sense. I want it to count every time R2 is less than or equal to 200, - OK "every time" you want to count. but I only want it to count once - so not every time?

Do you mean: I want to add one to a counter if R2 is <= 200, but only once. Then if R2 is > 200 then I want to reset this process and do it again.

You can set a flag to indicate that R2 is or has been above 200 since it last was low, much as follows.
// before loop() ...
byte Rhi = true;  // at outset, say that R2 has been high
...

// in loop() ...
  if (R2 > 200)          // Has R2 gone high?
    Rhi = true;
  if (Rhi && R2 <= 200){ // Has R2 gone low from high?
    Rhi = false;
    ++counter;
    Serial.print("counter: ");
    Serial.println(counter);
  }
  ...

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Typing into ESP8266 with a USB keyboard
I need to be able to connect a USB keyboard, like a tiny Xbox keyboard, or a nice wireless one, into an ESP8266-based thing to type passwords into the MCU. Adapting the PS2 lib for AVRs (PS2==USB pinouts for KBs) proved unreliable, so I tried a fake Pro Mini.
It worked much better, perfect with PS2, but only with a subset of my USB keyboards, namely a 104 Das Keyboard and an old-school Dell one. My 2002-era Mac keyboard doesn't work, none of my 5 wireless keyboards work, and neither do Xbox or foldable keyboards. Nothing that presents as a composite device works (like a keyboard with USB slots), only dead-simple (no fancy keys/knobs) keyboards seem to work.

Would a USB host module (like the Uno shield, but not a shield) let me read from more than just basic PS2-emulating USB keyboards?
Is the code to read basic alphanumeric keys consistent among different keyboards, or will each model need special instructions? (much like a driver would provide an actual OS)
If it's anything but "plug and play", what would be a simple way (no soldering) to securely input passwords into an MCU?

EDIT:
Early USB keyboards and PS2 keyboards have the same pinout and behavior, so you can use a Pro Mini and the Arduino ps2keyboard demo to read such USB keyboards, either with a passive USB keyboard to PS2 male adapter for less than $1 USD, or via a female USB wired the same. Fancier keyboards don't work as such, at all, hence the possible need for a USB host module.

it is unclear what you are describing .... you say that you want to use a USB keyboard, but you talk about PS2 keyboard ... please update your question to make it clear

look at this https://arduino.stackexchange.com/questions/48447/how-to-detect-host-computer-when-boot-power-on-just-use-usb-without-any-sens    ......  use arduino nano

@jsotola: i want to type into the ESP w/ a USB keyboard, hopefully wireless, no PC in sight...

some, maybe most, usb keyboards have a "boot keyboard mode" ( or something like that), that is used to allow keyboard functionality when navigating bios menus. .... arduino usb host module should work for you.  ... the problem is figuring out the software

My 2002-era Mac keyboard doesn't work,

That doesn't surprise me - modern Macs have never needed PS/2 support.

none of my 5 wireless keyboards work,

That's because they're not keyboards, they're wireless transceivers that provide USB HID interfaces.

and neither do Xbox or foldable keyboards.

Too modern, and of course XBox has never needed PS/2 support.

Nothing that presents as a composite device works (like a keyboard with USB slots), only dead-simple (no fancy keys/knobs) keyboards seem to work.

Of course, they aren't PS/2 keyboards, they're USB devices.
Older keyboards provided dual operation - USB and PS/2. This is a function provided by the keyboard, not the USB standard. Mac keyboards, since the Apple computers never had PS/2 ports (since PS/2 is an IBM standard from the PS/2 computers back in the 80s & 90s). Modern keyboards that provide more than just a simple keyboard functionality cannot really provide PS/2 as well since that can't provide the other features of the keyboard. The same goes for composite devices, or wireless devices - they facilities they provide are in excess of what PS/2 can provide, so it would be illogical trying to provide PS/2 support - especially as PS/2 ports are getting rarer on computers now.

Would a USB host module (like the Uno shield, but not a shield) let me read from more than just basic PS2-emulating USB keyboards?

Sure, if you can get the libraries working on the ESP8266, which may well be a huge challenge in- and of itself.

Is the code to read basic alphanumeric keys consistent among different keyboards, or will each model need special instructions? (much like a driver would provide an actual OS)

All USB keyboards are class-compliant HID devices. They send HID reports in a standard format, maybe with custom additions. The basics are always the same though.

If it's anything but "plug and play", what would be a simple way (no soldering) to securely input passwords into an MCU?

It'd be far from "plug and play" getting a USB host interface working with the ESP8266.  Consider other more simple routes, such as using serial, or configuring the ESP8266 as an access point and using a web browser to configure it.

i feel slightly battered, but much more informed; thanks for your time. i guess i'll have to have it "learn" a cheap IR kb...

The USB Host Shield Library 2.0 has supported the ESP8266 for about a year. Support for the ESP32 was added more recently.
The following is a link to the project README listing the supported boards and microcontrollers.
https://github.com/felis/USB_Host_Shield_2.0#boards


text:
Is there a way to get about a 10ns Timer resolution from an AVR CPU?
I have an 8Mhz ATM32u4 that is able to read external pulse inputs at 125ns ticks using InputCapture3 (PC7) on its 16-bit timer.  Is there a magical way (bitbanging?) to get around 10ns tick resolution to read pulses?  Edit:  like ADC conversions to allow 16-bit systems 24-bit accuracy via creative coding, etc.
If there is no magic, I should use a faster CPU?  I am limited in coding pretty much to AVR type CPUs in the Arduino IDE.  So wondering what AVR CPU would be fast enough for a 10ns tick that is incorporated already into like a Nano, UNO, etc?
Unless I am able to use Pin Interrupts that are able to read at 10ns intervals, then I could use ARM CPU types with Arduino IDE code which does not require me to dive deep into register level language.
Or, is there a stand-alone analog or digital IC that is able to read at 10ns intervals pulses that an Arduino can process?
Thank you.
Edit:  I would need to measure the length of a one-shot pulse only, not a continuous or changing signal. Down to 70us length with an accuracy of at least 18ns tick, but preferably 10ns to account for hardware, etc inaccuracies. This one-shot pulse could repeat not more frequently then 1 second apart, but likely several seconds apart. The signal is two positive square waves forming a pulse measuring not less than 70us from the positive rising edge to rising edge. The system measures the pulse length and sends it the user (serial, BLE, etc).
Edit 2: someone suggested a "one-shot pulse stretcher". Interesting concept...   The more I am looking into it, the more I think it's a very viable hardware solution to the AVR's processing speed limitation. One may say that this is hardware "bitbanging" by streching out the short pulse to a proportionally longer one that the MCU capture process can measure reliably/accurately. An example is this old IC from Linear Tech. See Fig 12 and Fig 13.    https://www.analog.com/media/en/technical-documentation/data-sheets/6752fc.pdf
http://www.anderswallin.net/2014/02/pulse-stretcher-v1/

The shortest expected pulse would be about 70us which needs to be measured at (around) a resolution of 18ns for the accuracy I need.  So I went with 10ns for design to allow for some accuracy "overhead".  That is between 4000-7000 counts/ticks  (18ns-10ns ticks) for the 70us signal.
If I stretch this same 70us signal to be measured with the pulse-stretcher to 700us and use the currently available 125ns tick interval of the ATM32u4, I should arrive in theory to about the same accuracy as using an 18ns tick for a 70us signal to be measured.
Here is a similar problem that was answered: https://electronics.stackexchange.com/questions/46922/lengthening-a-5-ns-pulse

You have a clock and it only ticks once per hour.  What bits are you going to bang that will let you measure seconds with that clock?  Same problem with the micro.  The smallest unit of time it knows is 125ns for an 8MHz clock.  There is nothing smaller than that.

What exactly is it that you think "bitbanging" means?  Or is it just a term you heard?

you are talking about a 100 MHz event ... how often does the event occur?

jsotola   It is a one shot pulse that can happen not less than in 1 second intervals, but can happen several seconds apart.

Delta_G   yes, I heard the term "bitbanging" (in general) when hardware does not cut the mustard and "creative" software methods are used to extrapolate the data to achieve accuracy/resolution that cannot be achieved with the given hardware. Could you describe it in a way that would correct my faulty understanding?

Delta_G could you address the other parts of my question which was not related to "bitbanging", which identify completely different potential solutions? Thank you for your constructive assistance!  What makes this forum great is to hear suggestions from folks like you who are willing spend time on a positive guidance focused on the correct portions of one's questions while also pointing out the incorrect ones..

Do you need to “capture” a 10ns event that occurs at most once per second? It’s unclear what you need to do with these events. Do you need to measure the amount of time between events? Do you need to react to such an event? With some external (TTL or dedicated I2C/SPI) timer components you could build an external timer that’s capable of doing this.

There are some Arduino-compatible boards based on the ATtiny85. This has a fast asynchronous timer that can be clocked off a PLL at 64 MHz. It's probably the fastest you can get on an AVR, but it doesn't have an input capture unit.

Do you need to measure the length or the pulse, or just it's existence? If you latter you'd need to stretch this 10ns pulse to something longer that 125ns. Something like an RC filter.

@ Edgar Bonet thank you for the excellent suggestion.  It's a great feature to get a 64Mhz timer from an 8 MHz internal RC clock by using an 8x scaled software solution!  That would get me to 15.625 ns, which could work if all theoretical cals are accurate in real life hardware.   I looked into it. It requires some pin mapping to Timer1 as the 64 Mhz clock after enabling the PLL,  but then would still need to setup a counter etc. and unfortunately due to my limited knowledge in coding at the registry level I rather not proceed that way.  .

@ StarCat and Gerben. I would need to measure the length of a one-shot pulse only, not a continuous or changing signal.  Down to 70us length with an accuracy of at least 18ns tick, but preferably 10ns to account for hardware, etc inaccuracies.  This one-shot pulse could repeat not more frequently then 1 second apart, but likely several seconds apart. The signal is two positive square waves forming a pulse measuring not less than 70us from the positive rising edge to rising edge. The system measures the pulse length and sends it the user (serial, BLE, etc).

Please [edit] your question to add information. I spent several minutes to find the relevant stuff down here, and I did this just for curiosity. Most others will not do it.

someone suggested a "pulse stretcher". Interesting concept...  http://www.anderswallin.net/2014/02/pulse-stretcher-v1/

@the busybee   At first I was a bit "annoyed" at your comment, but I did fix it immediately.  Now that I have gone back and edited, I want to thank you for pointing out that important changes/updates need to go up in the main post. It certainly made my review/progress easier and I am sure it also serves the same for other readers.  At the end it helps me by helping others better help me.  Thanks again!

There is nothing you can do on the AVR processors that I know of, which can run on from a quite slow clock, and I think up to 24 MHz. Since your Uno / Leonardo / Micro run at 16 MHz that would be only an incremental speed improvement (to clock them at 24 MHz).
Your idea of bit-banging is interesting, but in general bit-banging is a last resort when you need extra things the hardware doesn't provide (like an extra SPI port) and in general will be slower, not faster, because it involves code rather than inbuilt hardware.
Running at 16 MHz each clock pulse is 62.5 ns which means that is the absolute most resolution it could count. I don't see why you can't count at the rate of 62.5 ns (rather than 125 ns), however that isn't 10 ns resolution.

Or, is there a stand-alone analog or digital IC that is able to read at 10ns intervals pulses that an Arduino can process?

Very likely. There are probably dedicated counting chips that would do that for you. I haven't looked, but it is the sort of thing there would be a market for. Such a chip would probably use I2C or SPI to communicate, which is easy enough to interface to.

Mr. Gammon. Really appreciate your input. I've been studying your website's Microprocessor guides/examples & incorporated them into various projects.They are very clear & cover exhaustively the topic for people like me that are not that experienced. Thank you very much for that, sincerely. So based on your and the other comments above, including Edgar Bonet's, the closet one for an AVR is an Atiny85 with an internal oscillator scaled 8x to 64 MHz via PLL that theoretically can give 15.625 ns ticks for a timer that needs to be set up, etc but beyond my skills. Will look for faster non-AVR CPUs.

Mr. Gammon  If I may have the audacity to ask you two related questions? #1: reference the 328p and 32u4 using the InputCaptureCounter/Timer (16-bit) and implementing an external pulse-read (like in your #12 reply example under "Timers").  You used an ISR timer/counter and an ISR for overflow. Comparing that with using attachInterrupt based pulse-read on the INT0/1 pin(s) and accounting for the time it take to enter/leave the ISR (@5us), would both solutions have the same inherent accuracy?

Mr. Gammon   This is the #2 related question: I combined your InputCaptureCounter/Timer example and your CPU Deep Sleep example for the 328p (using the 32u4).  That is the code that I was hoping to "beef up" to read 70us pulses at 10ns resolution and is located here: https://arduino.stackexchange.com/questions/77978/input-capture-with-sleep-enabled-on-atm32u4-board-only-works-every-second-readin/77981#77981

Perhaps if you explain in more detail your project? Why do you need to measure such short pulses?

Mr. Gammon  Someone suggested a "one-shot pulse stretcher". Interesting concept...   The more I am looking into it, the more I think it's a very viable hardware solution to the AVR's processing speed limitation. One may say that this is hardware "bitbanging" by streching out the short pulse (via an RC "timer") to a proportionally longer one that the MCU capture process can measure reliably/accurately. Only requires three extra components. An example is this old LTC6752 from Linear Tech. See Fig 12 and Fig 13.    https://www.analog.com/media/en/technical-documentation/data-sheets/6752fc.pdf

If you make this work I suggest you post your own answer to your question, giving details about how you did it, for the benefit of future readers.

Mr. Gammon   I will do.  Thank you for your help.

1 ns is a billionth of a second. A 1 gHz clock has a cycle time of 1 ns. If you have a timer that's able to count single clock pulses you'd need a 1 gHz clock to get to 1 ns resolution. for 10 ns, you'd need a 100 mHz clock.
You won't get close to 10 ns resolution with an 8 mHz clocked device.

Duncan C, thank you for breaking it down to the numbers.  Yes, clearly would need an MCU with a faster input capture/timer, or a dedicated external IC that can do the same.  Wondering, if a fast ADC would do?  I suspect that Freq-to-Volt converter would be too inaccurate at these periods. And using a Freq dow-counter by 10 or 12 for example is would not work with a single-shot pulse that is only 70us in length/period,

10 ns is a very short duration. No way would you use something like frequency to voltage to measure durations that short.


text:
Is it possible to run two small motors off an Arduino and have the motors move separately based on a random number generator?
I am a 2nd year design engineering student working on a design project where we are tasked with automating the movement of a rainfall simulator. One of our design ideas consists of two small motors running perpendicular to each other with the movements based on a random number generator. I was told that this would be fairly easy if we used a Siemens Program Logic Controller, but we have a very limited budget so I thought I would check out other options.
I am not familiar with the Arduino or much of anything to do with programming so I thought it would be beneficial to ask for advice from some people who know what they are doing. I attached an initial sketch of the idea and a picture of the rainfall simulator to hopefully clarify what I am hoping to accomplish. The most the device can move from its rested state is only 0.5".
Is this a path worth working towards? Or is this not the proper choice of equipment?
Any advice would be greatly appreciated!
Thanks,
Nick

What is a PLC? And it is not clear, what exactly you want. You could easily generate a random number between -1 and 1 and let the motor move for a time based on that, or with a speed based on that. I also don't understand, what exactly a "rainfall simulator" does here. How big are the motors, that you want to control (in terms of needed current and voltage)? You should give us more information

Thanks for letting me know it was unclear! I added a sketch of the idea and a picture of the rainfall simulator. I don't currently information on current and voltage as it is still a conceptual idea and we are in the process of figuring everything out.

I'm not sure, what I should write as an answer here, because your question is very broad. Surely you can build this with an Arduino and depending on your exact requirements, it will be rather easy. But that is too few for a real answer. So I suggest, you ask mores specific

Random is hard. Pseudo-random is easy.

Leaving your mechanical equipment uncommented *), an Arduino itself cannot drive 7.4V 1A Stepper Motors. An Arduino itself cannot drive any motor. You need a sufficient power supply and motor driver electronics. And there's a vast amount of different devices to choose from.
But then, the answer to "is it possible (random, two motors, moving independently)" is yes.
*) Well, regarding "uncommented" :
200 lbs is quite heavy to simulate/produce a few raindrops. Small motors won't move such gear as in your pic.

The Rainfall simulator itself can weigh a maximum of 200lbs when it is completely filled with water. The rainfall is produced through a vacuum in the tanks and drips out of small holes by itself. Currently the lab tech needs to stand beside the machine and push it every so often.  The task we are assigned with is just moving it side to side in a "random" sense. Thank you for your answer though as that was all I was looking for at the time! I will continue to pursue this design with my group with the information you provided.


text:
Determine if Arduino is rapidly pulsed on and off several times
Greetings fellow humans!
I've set myself the task of ascertaining whether an Arduino has been rapidly power cycled to force it into a setup state, a feature common with many IoT devices. So I essentially need to keep a count - of, say, three - prior on/off cycles. I could look at a custom bootloader that stores a power-on count in EEPROM then check if the attempts are >= 3 once the sketch is running (resetting the count), but I'm concerned that the EEPROM data could become corrupted during the cycle, or the the power cycle would be so rapid for even a bootloader to complete the count at all.
So, I figure I need another solution: an external counter, powered by the Arduino, that increments each time the Arduino receives power, but doesn't rely on the Arduino getting so far as running anything of consequence to keep count.
Could some kind soul point me in the direction of a discrete counter solution that would fit the task?  The simpler (fewer discrete components) the better.
Thanks!
SOLVED: less-than-discrete but fully functional solution adopted; noted in comments. Thanks for the feedback.

Greetings fellow humans! -- How dare you! I am not human!

Hello, Voldemort, good to see, that you are also an enthusiast of muggle technology XD

delete the bootloader and count the resets as first in sketch. on some MCUs a reset doesn't erase SRAM so a not initialized variable could hold the count. some MCUs have RTC memory, which is not cleared at reset.

@Juraj: Keeping the count in SRAM (in the .noinit section) would only work for warm resets. The OP seems to be concerned with power cycles.

Thanks for the feedback guys. I settled on a reasonably trivial additive resistance PWM signal fed by a decade counter. Works a treat.

Normally you wouldn't.
How I would implement it is:

Have the MCU monitor the incoming power
Provide a large-ish reservoir of power (capacitor) to run the MCU for a short time
Isolate the incoming power monitoring from the reservoir with a diode

When the power is removed the MCU runs off the stored power in the capacitor. The MCU then sees that the power is removed (by 1 above) and maybe reduces its power by turning off as much as it can to prolong the runtime. If the power is re-applied before the reservoir runs out then it enters the setup state.  If the reservoir runs out, then not much really happens.
For example:

simulate this circuit – Schematic created using CircuitLab
The size of the capacitor will determine the runtime. You may also choose to replace the capacitor with an "LC PI" filter to give more runtime but at the cost of space:

simulate this circuit

Thanks for the feedback. I use a similar technique to buy enough time on power loss to ensure a graceful shutdown where necessary. However...  I dug out a bunch of 74LS90s and, through additive serial resistance, came up with a solution that near enough fits the criteria.