Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 3 FirstFirst 1 2 3 LastLast
Results 26 to 50 of 59

Thread: Teensyduino 1.56 Beta #2

  1. #26
    Junior Member
    Join Date
    May 2020
    Location
    South East England
    Posts
    14
    Quote Originally Posted by PaulStoffregen View Post
    I don't understand. FreqCount is still included with the installer. Its 3 examples should still be in the Examples menu.

    Not sure what timing constraint you're talking about. On each Teensy model, that library can count at fast as the external clocking of hardware timers allows.

    @Paul
    Thank you for replying to my query.

    My system consists of :
    Teensy 4.1 plus custom PC board and touchscreen.
    Windows 10 PC
    Recently installed Arduino 1.8.15 and Teensyduino 1.56-beta1
    The Library manager indicates I have FreqCount 1.3.0
    I see no FreqCount() examples.

    My application includes a frequency meter for RF purposes up to 60 MHz with a programmable gate period the user can set to any decade value between 10uSec and 10Sec. The input buffering is achieved with a high speed Schmidt trigger and some other routing. The input to the T4.1 is full amplitude and nice and clean.

    The Teensy FreqCount function works well when tested with the original sample code but gives strange results when the period between measurements is made longer than the gate period. The interval between measurements should not influence the value of the measurement.

    With a gate time of 1000 uSec and a delay of 13mSec simulating the other functions a 10MHz input displays 13,0001. (Error)

    With a gate time of 1000 uSec and a delay of 900uSec simulating the other functions a 10MHz input displays 10,000. (Correct)

    The attached code clearly shows the problem I'm experiencing, please see the comments.
    Regards,
    RichardL

    PS: I tried an alternative to delayMicroseconds() just in case that was causing a conflict; no change.

    Code:
    #include <FreqCount.h>
    long FCount;
    
    
    // Frequency measurement gate time which is 
    // user configurable between 10uS to 10Sec.
    long GateTime = 1000;     //Ex: 1000 for a 1mSec gate
    
    
    // uSec taken by several other functions, SD card buffer writes, serial, etc.
    // Typically in range 5 to 15 mSec.
    long SimTime  = 13000;    // Ex: 13000 for a 13mSec aggregate delay
    
    
    // What I see... 
    // With any input frequency between 1MHz and 25MHz. Broadly:
    //    If SimTime > GateTime the value of FCount is in error and looks
    //    like the gate period is controlled by SimTime. 
    
    
    //    If GateTime > SimTime FCount value is OK.
    
    
    void setup() {
      Serial.begin(57600);
      FreqCount.begin(GateTime);  // Gate time is in uSec
    }
    void loop() {
      delayMicroseconds(SimTime); // Simulates lots of other things happening.
      // MyDelay(13);
      if (FreqCount.available()) {
        FCount = FreqCount.read();
        Serial.println(FCount);
       }
    }
    
    
    void MyDelay(long WaitTime){
      unsigned long ExitTime = millis() + WaitTime;
        while (millis() < ExitTime){};
      }

  2. #27
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,356
    Complete aside:
    your MyDelay isn't safe from wraparound, code it like this:
    Code:
    void MyDelay(unsigned long WaitTime){
      unsigned long StartTime = millis();
      while (millis() - StartTime < WaitTime)  // safe at wraparound due to the subtraction.
      {}
    }

  3. #28
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    457
    Quote Originally Posted by MarkT View Post
    Complete aside:
    your MyDelay isn't safe from wraparound, code it like this:
    Code:
    void MyDelay(unsigned long WaitTime){
      unsigned long StartTime = millis();
      while (millis() - StartTime < WaitTime)  // safe at wraparound due to the subtraction.
      {}
    }
    I can't see how that is safe. By way of example lets assume that millis starts at 0, goes to 100 then wraps round to 0 again. I know it doesn't but this is to demonstrate the problem with your code above.
    OK, continuing.
    Let's assume that at the time of entry to the routine that millis is 90 and the long wait time is 30. The spreadsheet below shows what happens.
    There is NO exit from the routine.
    Code:
    Millis	StartTime WaitTime (millis-StartTime) (millis-startTime) <WaitTime
    90	90	  30	        0	              TRUE
    91	90	  30	        1	TRUE
    92	90	  30	        2	TRUE
    93	90  	  30	        3	TRUE
    94	90	  30	        4	TRUE
    95	90	  30	        5	TRUE
    96	90	  30	        6	TRUE
    97	90	  30	        7	TRUE
    98	90	  30	        8	TRUE
    99	90	  30	        9	TRUE
    100	90	  30	       10	TRUE
    0	90	  30	      -90 	TRUE
    1	90	  30	      -89	TRUE
    2	90	  30	      -88	TRUE
    3	90	  30	      -87	TRUE
    4	90	  30	      -86	TRUE
    5	90	  30	-85	TRUE
    6	90	  30	-84	TRUE
    7	90	  30	-83	TRUE
    8	90	  30	-82	TRUE
    9	90	  30	-81	TRUE
    10	90	  30	-80	TRUE
    11	90	  30	-79	TRUE
    12	90	  30	-78	TRUE
    13	90	  30	-77	TRUE
    14	90	  30	-76	TRUE
    15	90	  30	-75	TRUE
    16	90	  30	-74	TRUE
    17	90	  30	-73	TRUE
    18	90	  30	-72	TRUE
    19	90	  30	-71	TRUE
    20	90	  30	-70	TRUE
    21	90	  30	-69	TRUE
    22	90	  30	-68	TRUE
    23	90	  30	-67	TRUE
    24	90	  30	-66	TRUE
    25	90	  30	-65	TRUE
    26	90	  30	-64	TRUE
    27	90	  30	-63	TRUE
    28	90	  30	-62	TRUE
    29	90	  30	-61	TRUE
    30	90	  30	-60	TRUE
    31	90	  30	-59	TRUE
    32	90	  30	-58	TRUE
    33	90	  30	-57	TRUE
    34	90	  30	-56	TRUE
    35	90	  30	-55	TRUE
    36	90	  30	-54	TRUE
    37	90	  30	-53	TRUE
    38	90	  30	-52	TRUE
    39	90	  30	-51	TRUE
    40	90	  30	-50	TRUE
    41	90	  30	-49	TRUE
    42	90	  30	-48	TRUE
    43	90	  30	-47	TRUE
    44	90	  30	-46	TRUE
    45	90	  30	-45	TRUE
    46	90	  30	-44	TRUE
    47	90	  30	-43	TRUE
    48	90	  30	-42	TRUE
    49	90	  30	-41	TRUE
    50	90	  30	-40	TRUE
    51	90	  30	-39	TRUE
    52	90	  30	-38	TRUE
    53	90	  30	-37	TRUE
    54	90	  30	-36	TRUE
    55	90	  30	-35	TRUE
    56	90	  30	-34	TRUE
    57	90	  30	-33	TRUE
    58	90	  30	-32	TRUE
    59	90	  30	-31	TRUE
    60	90	  30	-30	TRUE
    61	90	  30	-29	TRUE
    62	90	  30	-28	TRUE
    63	90	  30	-27	TRUE
    64	90	  30	-26	TRUE
    65	90	  30	-25	TRUE
    66	90	  30	-24	TRUE
    67	90	  30	-23	TRUE
    68	90	  30	-22	TRUE
    69	90	  30	-21	TRUE
    70	90	  30	-20	TRUE
    71	90	  30	-19	TRUE
    72	90	  30	-18	TRUE
    73	90	  30	-17	TRUE
    74	90	  30	-16	TRUE
    75	90	  30	-15	TRUE
    76	90	  30	-14	TRUE
    77	90	  30	-13	TRUE
    78	90	  30	-12	TRUE
    79	90	  30	-11	TRUE
    80	90	  30	-10	TRUE
    81	90	  30	-9	TRUE
    82	90	  30	-8	TRUE
    83	90	  30	-7	TRUE
    84	90	  30	-6	TRUE
    85	90	  30	-5	TRUE
    86	90	  30	-4	TRUE
    87	90	  30	-3	TRUE
    88	90	  30	-2	TRUE
    89	90	  30	-1	TRUE
    90	90	  30	0	TRUE
    Oh, I gave up trying to format the output, but I am sure you can see what happens.

  4. #29
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,404
    Quote Originally Posted by BriComp View Post
    I can't see how that is safe. By way of example lets assume that millis starts at 0, goes to 100 then wraps round to 0 again. I know it doesn't
    And exactly this is your understanding problem. The trick is the unsigned arithmetic.

  5. #30
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,356
    Quote Originally Posted by BriComp View Post
    I can't see how that is safe. By way of example lets assume that millis starts at 0, goes to 100 then wraps round to 0 again.
    integer variables in C are modular, so you need to do the subtraction modulo the relevant power of two. For instance with uint32_t:
    Code:
    millis      start       millis-start
    0xFFFFFFF0  0xFFFFFFF0  0x00000000
    0xFFFFFFFF  0xFFFFFFF0  0x0000000F
    0x00000000  0xFFFFFFF0  0x00000010
    Carry/borrow bits are simply discarded, so the operations are modulo 2^32

  6. #31
    Senior Member BriComp's Avatar
    Join Date
    Apr 2014
    Location
    Cheltenham, UK
    Posts
    457
    Ok, Got it. I had to write a small sketch to prove it to myself.
    You learn something new each day. Thanks.

  7. #32
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,404
    Here are some instruction and code to print a full stacktrace.
    Found that by accident.

    Might be useful for someone or a future TD version:
    https://github.com/FrankBoesing/free...nsyduino-usage (scroll down to "Teensy 4")
    Code:
    https://github.com/tsandmann/freerto...nsy_4.cpp#L328

  8. #33
    Junior Member
    Join Date
    May 2020
    Location
    South East England
    Posts
    14
    @MarkT, @BriComp, @FrankB
    Thanks for your comments relating to roll over / wrap around in MyDelay(), certainly something that needs to be taken account of in a developed program but not really relevant to the problem I'm seeing. (If you look at my code snip the call to MyDelay() was commented out anyway...)
    RichardL

  9. #34
    Junior Member
    Join Date
    May 2020
    Location
    South East England
    Posts
    14
    @Paul
    I still find that FreqCount() fails to show a correct value when the interval between readings is longer than the gate period. It looks to me like a reset or a latching failure or something along those lines. The result is that FreqCount() is useless in any program where the loop() time is longer than the gate period. That is a big problem if an agile gate period is needed or a short gate time provides sufficient precision.

    For my purposes, another irritation of the current version of FreqCount() is that there appears to be a data pipeline that needs to be flushed of each time the gate period is changed. Changing from a 10 Second gate period down to a shorter one is currently a tedious activity! It would be a distinct improvement if the pipeline were to be cleared (or able to be cleared) when the gate period was changed.

    My preference would be to have an option that allows the program to initiate a frequency measuring cycle directly and for FreqCount() to NOT loop internally; this would provide gate period agility and the ability to initiate a frequency measurement at a user chosen instant.

    You may be interested in this montage showing the project I have been working on for over a year now and would benefit from a solution to this problem.

    Best regards,
    RichardL

    Click image for larger version. 

Name:	LIAB Montage.jpg 
Views:	24 
Size:	193.6 KB 
ID:	26377

  10. #35
    @RichardL, you're right that this is a problem with FreqCount. It's actually a pretty complex library because there are abstractions for all of the different platforms, from AVR to T4.x, which are quite different. It might not be easy to fix the FreqCount library, and since you are using T4.1, it might be better to focus on finding a solution specific to T4.x. What pin are you using for your frequency input?

  11. #36
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,264
    Wondering if these statements that just poll and ask for known data (?) - not doing anything unsafe in an interrupt:
    Code:
      if (FreqCount.available()) {
        FCount = FreqCount.read();
    Could be called with an Interval timer with period shorter than the GateTime.

    That would assure timely reading when .available().

    Then in loop() when GateTime is changed the queue'd data could be emptied with : while ( .available() ) { .read(); }

    And the next series could be started where the intervalTimer isr() does as needed to buffer the data locally ( in an array with volatiles as needed ) for processing in loop().

  12. #37
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,213
    Yup, looks like the Teensy 4 code is handling the previous count substract inside the read function rather than the interrupt. I probably should have reviewed the pull request more carefully than just running the examples and seeing it working. Then again, it's an issue which just hasn't come up (as far as I know) until now.

  13. #38
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Quote Originally Posted by PaulStoffregen View Post
    Yup, looks like the Teensy 4 code is handling the previous count substract inside the read function rather than the interrupt. I probably should have reviewed the pull request more carefully than just running the examples and seeing it working. Then again, it's an issue which just hasn't come up (as far as I know) until now.
    When we were testing those changes never seemed to be an issue on getting the correct counts that we could tell think all that was done in the T4 beta thread. Think you need to also look in FreqCountTimers.h on how the timers and callback is handled for the 1062 about line 360.
    Code:
    #elif defined(TIMER_USE_INTERVALTIMER_T4)
    static IntervalTimer itimer;
    volatile uint32_t count;
    
    static void timer_callback()
    {
      count = TMRx->CH[2].CNTR | TMRx->CH[3].HOLD << 16; // atomic
      count_ready = 1;
    }
    
    static inline uint16_t timer_init(uint32_t usec)
    {
    	itimer.begin(timer_callback, usec);  //timer correction
    	return usec;
    }
    so when count is ready available returns true and count should return the lasted value.

    You might start with this post: https://forum.pjrc.com/threads/54711...l=1#post195935 and follow the links to the other posts where we (me and manitou) changed things around). Was quite a bit of testing to get the timers correct way back when using a Adafruit clock generator to verify values.

  14. #39
    Quote Originally Posted by mjs513 View Post
    so when count is ready available returns true and count should return the lasted value.
    As Paul said, delta = count - prev and prev = count should be in the interrupt callback. The delta is computed in read(), so if more than one interrupt occurs between reads, the reported frequency will be higher than actual. It probably just didn't get tested with long delays between calls to read().

  15. #40
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Quote Originally Posted by joepasquariello View Post
    As Paul said, delta = count - prev and prev = count should be in the interrupt callback. The delta is computed in read(), so if more than one interrupt occurs between reads, the reported frequency will be higher than actual. It probably just didn't get tested with long delays between calls to read().
    Note:
    Code:
    ISR(TIMER_ISR_VECTOR)
    is not used for Teensy 4.x (__IMXRT1060__), that interrupt is ifdef out:
    Code:
    #if(!defined(__IMXRT1062__))
    so all that Gate stuff is not applicable.

    When the timer interrupt hits avail sets count_ready = 1. Which is predicated on the interval timer interrupt in util:
    Code:
    #elif defined(TIMER_USE_INTERVALTIMER_T4)
    static IntervalTimer itimer;
    volatile uint32_t count;
    
    static void timer_callback()
    {
      count = TMRx->CH[2].CNTR | TMRx->CH[3].HOLD << 16; // atomic
      count_ready = 1;
    }
    
    static inline uint16_t timer_init(uint32_t usec)
    {
    	itimer.begin(timer_callback, usec);  //timer correction
    	return usec;
    }
    Note count is in the callback for the timer. Only the delta is computed in the read. Easy enough to fix though. Maybe just don't understand the issue - will have to test.

  16. #41
    Quote Originally Posted by mjs513 View Post
    Note count is in the callback for the timer. Only the delta is computed in the read. Easy enough to fix though. Maybe just don't understand the issue - will have to test.
    Yes, that's the issue. The delta should be computed in the callback. Let's say counter starts at 0, gate time is 100 ms, and read() is called every 200 ms. When read() is called, timer_callback() will have been called twice, and count will be 2 x freq. read() will compute delta = count - prev, which will be 2 x freq. If read() is called every 500 ms, it will return 5 x freq, etc. If delta is computed in callback, output will always be 1 x f, even if interrupt occurs multiple times between calls to read().

  17. #42
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Quote Originally Posted by joepasquariello View Post
    Yes, that's the issue. The delta should be computed in the callback. Let's say counter starts at 0, gate time is 100 ms, and read() is called every 200 ms. When read() is called, timer_callback() will have been called twice, and count will be 2 x freq. read() will compute delta = count - prev, which will be 2 x freq. If read() is called every 500 ms, it will return 5 x freq, etc. If delta is computed in callback, output will always be 1 x f, even if interrupt occurs multiple times between calls to read().
    Actually if you do something like this based on what you said:
    Code:
      analogWriteFrequency(8, 50000000);  // test jumper 11 to 25
      analogWrite(8, 128);
      
      FreqCount.begin(100000);  //Time in microseconds
    }
    
    void loop() {
      if (FreqCount.available()) {
        unsigned long count = FreqCount.read();
        Serial.println(count);
      }
    
      delay(500);
      
    }
    count is actually half of the frequency. Measures 25000000 vs 50000000. I am assuming this is what you are talking about then. Think we tested with long delays but we kept the begins to around 1sec.

  18. #43
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Ok here is a potential fix - besides moving the delta to the timer_callback had to do one more thing to work with the default case as well. I am attaching an updated copy of the FreqCount library if some one wants to try it with their application:
    Attached Files Attached Files

  19. #44
    Quote Originally Posted by mjs513 View Post
    count is actually half of the frequency. Measures 25000000 vs 50000000. I am assuming this is what you are talking about then. Think we tested with long delays but we kept the begins to around 1sec.
    I put in the changes shown below, and it seems to work correctly, i.e. I do get 50000000. High frequencies other than 50MHz are not exact because they are close to the maximum for PWM. Are you clocking at 600 MHz?

    Code:
    static void timer_callback()
    {
      count = TMRx->CH[2].CNTR | TMRx->CH[3].HOLD << 16; // atomic
      count_output = count - count_prev;
      count_prev = count;
      count_ready = 1;
    }
    
    uint32_t FreqCountClass::read(void)
    {
        count_ready = 0;
        return count_output;
    }

  20. #45
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Actually - those are the exact same changes I put in as well

    Yes I am clocked at 600Mhz.

    High frequencies other than 50MHz are not exact because they are close to the maximum for PWM.
    That is correct - we saw that in testing as well.

    I tested the changes with the default sketch as well as the changes I posted above and they both seem to work well even with the available fairly reasonably if you wait for a x number of cycles or time is short enough.

  21. #46
    I don't think you should set count = 0 in read(), or at least there is no need to do so.

  22. #47
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Quote Originally Posted by joepasquariello View Post
    I don't think you should set count = 0 in read(), or at least there is no need to do so.
    Try running the example without setting it to zero - you see alternating values of 0 and 50000000.

  23. #48
    I still don't see it, and I see no difference in results with/without count = 0 in read(). That's good, because setting count = 0 in read() should have no effect on the ISR.

  24. #49
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,664
    Quote Originally Posted by joepasquariello View Post
    I still don't see it, and I see no difference in results with/without count = 0 in read(). That's good, because setting count = 0 in read() should have no effect on the ISR.
    Well thats good. Ok so maybe guess will issue the PR

  25. #50
    Quote Originally Posted by mjs513 View Post
    Well thats good. Ok so maybe guess will issue the PR
    I'll do some testing with a function generator and report back, perhaps not until tomorrow.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •