Announcement

Collapse
No announcement yet.

Jazzing up the Arduino PI - full recipe

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Jazzing up the Arduino PI - full recipe

    Introducing my latest ArduinoPI software masterpiece!

    Key Features:
    • All pulses (Tx, mainSample, and efeSample) are rock-solid stable and powered by hardware PWM magic, oblivious to any conspiracies by the loop() code (add you own fatures!).
    • Tx and mainSample dance to the beat of 16-bit Timer1, while the efeSample grooves to the rhythm of an 8-bit Timer0. Both timers are synchronized to a 1ms period.
    • The Tx and mainSample can be defined in increments of 1us, but the efeSample only in cool 4us steps (8 bit pixelated simplicity).
    • Ensure your mainSample on-time is a smooth multiple of 4 to match the duration of the efeSample on-time.
    • You stay flexible with the mainSample delay! tune in 1us increments, even as early as 1us.
    • Precision only where needed! If not a multiple of 4us, the true calculated efeSample delay will be within +-4us from the desired value (but still constant). No big deal cause EFE stays constant once the signal fades out – it's a cool cat. But if you want your efeSample delay to be exact, make sure your Tx time is also a multiple of 4us. You won't notice any difference though.

    Extras in the Sketch Folder:
    • Dive into a visual delight with a figure of the essential PCB mod and the optional mods. It's like a treasure map for PI bliss!
    • Spice things up by uncommenting one line to make the sketch control a petite 128x32 OLED. Watch it light up with the delay value as you twirl the pot – it's like magic!
    • To pamper your, uncomment another line to make the audio change its pitch and amplitude when a target is near (requires mod 2). It's like doubling the sensitivity.

    Under the Hood:
    • We keep the internals of Timers and OLED discreetly tucked away in header files Timers.h and Oled.h. These files come with directions in the comments, guiding you to unleash the hidden features.
    ArduinoPI_fullPWM.zip

    Dive into the sketch, activate those features, and let the tech party begin!​
    Attached Files

  • #2
    You should be in advertising

    Do these mods work for standard nanos or just for the Lgt8f328p variants? Have you tried both and does the 32Mhz extra speed improve things?
    I have a Lgt8f328p and oled display on order to try out your magic.

    BTW the Lgt8f328p also has differential ADC inputs which could, potentially, replace one analog stage. The 40 pin variant could allow the unlocking of more potential improvements .

    I feel a board redesign coming on.

    Comment


    • #3
      The mods are for standard Nanos.

      OLED display at work with delays as low as 1us.



      Comment


      • #4
        Teleno - very good work!
        Unfortunately I have zero time to test this myself at the moment, but I plan to do so eventually.

        Comment


        • #5
          in Setup() boostPin is set to OUTPUT instead of INPUT_PULLUP

          I'm going to add a switch for the delay range and shift the potValue directly to get the range

          voidsetup(){
          pinMode(boostPin, INPUT_PULLUP); // Set Boost switch pin to input mode with pullup resistor
          pinMode(rangePin, INPUT_PULLUP); // Set range switch pin to input mode with pullup resistor
          Timers_init(); // Configure and start timers
          #ifdefUSE_OLED
          Oled_init(); // Initialize OLED display
          #endif
          }

          voidloop()
          {
          // Read potentiometer and shift right into 0-63 or 0-127 uS depending on range
          if(digitalRead(rangePin)) delayVal = analogRead(delayPin)>>4 ; // convert 10bit value to 0-127 high range uS
          else delayVal = analogRead(delayPin)>>5 ; // or 0-63 low range uS

          // If the value has changed update the display
          #ifdefUSE_OLED
          if(delayVal != delayVal_last)Oled_show(defMainDelay + delayVal);
          delayVal_last = delayVal; // new previous value
          #endif
          }

          Comment


          • #6
            Originally posted by Gunghouk View Post
            in Setup() boostPin is set to OUTPUT instead of INPUT_PULLUP
            Thanks for the heads up!

            Corrected.

            ArduinoPI_fullPWM.zip

            I've also fixed some errors in the comments.

            I believe Arduino's map function is a more tinable and user-friendly eay yo map the pit readings to the delay. For example:

            delayVal = map(analogRead(delayPin), 0 1023, 1, 15);

            will have the same noise filtering effect as shifting/masking but the delay values are easily tunable.

            By the way, I've never used delays longer than 12us, what's the need for 60us or more? The signal has long vanished into obivion.

            I don't know if it's useful for detecting buried tanks or stuff like that. Guys, what are you looking for?
            Attached Files

            Comment


            • #7
              Version: 1.0.1

              Changes:

              - Pot filtering by Arduino map() function. User editable delay range (defMainDelay, defMaxDelay)
              - Fixed errata.

              ArduinoPI_fullPWM_1.0.1.zip

              The default minimum / maximum sample delays are 5us / 16us (user editable), which I think is the most common range in practice.
              Attached Files

              Comment


              • #8
                Version: 1.0.2

                Changes:

                - Mapped pot reading no longer added to defMainDelay but constrained between defMainDelay and maxMainDelay.
                - Errata fixed.​

                ArduinoPI_fullPWM_1_0_2.zip

                Comment


                • #9
                  Originally posted by Teleno View Post

                  By the way, I've never used delays longer than 12us, what's the need for 60us or more? The signal has long vanished into obivion.

                  I don't know if it's useful for detecting buried tanks or stuff like that. Guys, what are you looking for?
                  That'll be my bad due to lack of delay setting knowledge

                  BTW the oled ifdef update in the main loop could be inside the pot value update of 20/sec.

                  Comment


                  • #10
                    In my experiments I've noticed that masking/shifting the ADC reading is not enough to stop the noise.

                    For example, if a binary value of 100111 is read, masking 3 LSBs gives 100000 and shifting gives 100. Now if the next reading is 101000, it only differs by 1 more bit, but still it toggles the 4th LSB from 0 to 1 (masked value is 101). So a tiny change still can affect the higher bits that passed the masking/shifting filter.

                    I've seen this on the bench. By fiddling with the pot there are positions where the display flickers between two values despite all the filtering.

                    What I've done is add hysteresis so that a change of more than 1 LSB is required to accept a new reading.

                    So version 1.0.3 is coming soon.

                    PHP Code:
                    word threshold_low threshold_high 0;
                    ...
                    if (
                    reading threshold_high || reading thresold_low){
                      
                    // readjust the thresholds. n is a number of bits
                      
                    threshold_high reading n;
                      
                    threshold_low reading n;
                      
                    // accept reading and map to a delay value
                      
                    delayValue map(reading01023defMainDelaydefMaxDelay);

                    Basic code for clarity. The actual code includes checks to make sure the threshold values don't overflow or underflow.

                    Comment


                    • #11
                      In order to get from 1023 to 15 the shift is six so any jittery bits should be gone and the measured step size, of 5/16 volts , is a huge amount of noise. I don't get it

                      delayValue = (reading>>6)+1 ; // 1-16 uS

                      I think there's got to be some rounding error using map. You could try this, which is divisible by 4

                      delayValue = map(reading,0,1024,defMainDelay,defMaxDelay);

                      or

                      delayValue = map(reading+1,0,1024,defMainDelay,defMaxDelay);

                      Comment


                      • #12
                        Originally posted by Gunghouk View Post
                        In order to get from 1023 to 15 the shift is six so any jittery bits should be gone and the measured step size, of 5/16 volts , is a huge amount of noise. I don't get it
                        Reading: 1011111
                        Reading >> 3 = 1011

                        Now the ADC increaes by 1 bit

                        new Reading : 1100000
                        Reading >> 3 = 1100.

                        So one bit change in the ADC can cause one bit change in the shifted value too.

                        With hysteresis thresholds this doesn't happen.

                        Comment


                        • #13
                          Gotcha. I think 2 or more LSB hysterisis is going to be required.

                          Comment


                          • #14
                            OK i determined this modification after putting the MAP maths into Excel.

                            For the mathematically inclined, here’s the whole MAP function


                            long map(long x, long in_min, long in_max, long out_min, long out_max)
                            {
                            return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
                            }

                            It works as expected and gives whole 1us increments from defMainDelay to defMaxDelay

                            // Read potentiometer, map to user range of min & max delays.
                            if(readPot){
                            delayVal = round(defMainDelay+map(analogRead(delayPin), 0, 1023, defMainDelay, defMaxDelay)); // new delay value
                            // delayVal = constrain(delayVal, defMainDelay, defMaxDelay); not required
                            readPot = false;
                            }

                            Comment


                            • #15

                              Correction:

                              delayVal = round(map(analogRead(delayPin), 0, 1023, defMainDelay, defMaxDelay)); // new delay value

                              Comment

                              Working...
                              X