Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 15 of 15

Thread: Teensy 3.2 Timming inaccuracy

  1. #1

    Teensy 3.2 Timming inaccuracy

    Hello,

    I'm trying to generate a precise 2Mhz Manchester encoded waveform with the Teensy 3.2. The waveform is correct most of the time, but sometimes there appear to be a timing glitch. The waveform will be stuck in high or low state for 0.5-1 us and then continue as previously.

    I have tried to generate a waveform purely in inline assembly with just alternating 0 and but the issue is still there.

    The assembly code to generate waveform:

    Code:
           asm volatile (
    
          "MOV r10,#0x28"                 "\n\t"
    
          "1:"                           "\n\t"
    
          "MOV r11,#0x40000000"                 "\n\t"
    
          "ORR r11,#0x000F0000"                 "\n\t"
    
          "ORR r11,#0x0000F000"                 "\n\t"
    
          "ORR r11,#0x00000080"                 "\n\t"
    
    
          "MOV r2, #0x80"                      "\n\t"
    
          "STR r2, [r11]"                       "\n\t" 
    
      
          "MOV r12, #13"                          "\n\t"
    
          "2:"                           "\n\t"
    
          "MOV r0,r0"                             "\n\t"
    
          "SUBS r12, r12, #1"                     "\n\t"
    
          "bne 2b"                        "\n"
    
          "MOV r0,r0"                             "\n\t"
     
    
          "MOV r11,#0x40000000"                 "\n\t"
    
          "ORR r11,#0x000F0000"                 "\n\t"
    
          "ORR r11,#0x0000F000"                 "\n\t"
    
          "ORR r11,#0x00000080"                 "\n\t"
    
    
          "MOV r2, #0x10"                      "\n\t"
    
          "STR r2, [r11]"                       "\n\t" 
    
      
          "MOV r12, #12"                          "\n\t"
    
          "2:"                                    "\n\t"
    
          "MOV r0,r0"                             "\n\t"
    
          "SUBS r12, r12, #1"                     "\n\t"
    
          "bne 2b"                                "\n"
    
          "MOV r0,r0"                             "\n\t"
    
          "MOV r0,r0"                             "\n\t"
    
          "MOV r0,r0"                             "\n\t"
    
    
          "SUBS r10, r10, #1"                     "\n\t"
    
          "bne 1b"                                "\n"
    
    
          );
    Below is a lin to a video to show what i'm seeing.

    https://www.dropbox.com/s/auj2msx38d...45514.mp4?dl=0

    Does anybody have clue what the problem could be. Maybe some interrupt, although i have tried in all kinds of ways to diasble them.

    Any help would be greatly appreciated. Thank you in advance!
    Attached Files Attached Files

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,153
    Quote Originally Posted by aweasomeasmus View Post
    Does anybody have clue what the problem could be. Maybe some interrupt, although i have tried in all kinds of ways to diasble them.
    It's probably the ARM Systick interrupt.

    Maybe put __disable_irq() before you call your ASM function. Don't forget __enable_irq() afterwards, or at least before you call delay(), since it depends on the timing maintained by Systick.

    You might also use FASTRUN so your code is placed in the no-wait-state RAM. If running from ordinary flash, the precise timing can vary slightly depending on the flash controller's cache. Here's a prior conversation with useful info.

    https://forum.pjrc.com/threads/27690...is-not-precise

  3. #3
    Quote Originally Posted by PaulStoffregen View Post

    Maybe put __disable_irq() before you call your ASM function.
    That did not help, i'll try to look into the other solution. Any other suggestions?

  4. #4
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    2,710
    you could try overriding yield with a blank one added anywhere in your sketch:

    Code:
    void yield(void) {};

  5. #5
    Quote Originally Posted by tonton81 View Post
    you could try overriding yield with a blank one added anywhere in your sketch:

    Code:
    void yield(void) {};
    I tried to google around for the yield function, it seems a bit mysterious what overriding it would do to my system. In which way would it improve the timing accuracy?

  6. #6
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,571
    yield() is a weak reference that is called each time through loop(), hardware/teensy/avr/cores/teensy3/yield.cpp

    yield() checks on serial events and such.

    You could try overriding it, but your timed/scoped event seems contained within loop() and not across it, so i don't think it would solve your problem.

    if i run your sketch on T3.2@120mhz with a scope on pin 4, i don't see the glitch. i have a steady 2mhz sq wave, 50% duty. ?

    EDIT: ok, i guess i should be looking at pin 10 with scope ... i do see jitter, and adding yield() {} didn't help nor did FASTRUN. Here is snapshot of the glitch
    Click image for larger version. 

Name:	manchester.png 
Views:	25 
Size:	36.2 KB 
ID:	14153
    though the position of the glitch can vary as well as either an extended (2 us) HIGH or LOW.

    I don't know if there is a way for the scope to catch the frequency of the glitch -- that might be useful info.
    Last edited by manitou; 07-08-2018 at 11:12 AM.

  7. #7
    Quote Originally Posted by manitou View Post
    EDIT: ok, i guess i should be looking at pin 10 with scope ...
    Yeah, i forgot to mention that i was measuring pin 12, but pin 10 should be the same.

    I haven't either had any luck with the previous suggestions. Measuring the frequency og the glitch could be a good idea to guess the origin but the frequency seems to be highly irregular.

    Is there a definitive way to disable interrupt on the teensy other than _disable_irq()? I can't think of any other reason to this problem than a system interrupt.

  8. #8
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,571
    if i comment out the PRIMASK asm code, the jitter/glitch seems to go away on pin 12.

    Code:
    //  asm volatile (
     //   "MOVS r0, #0 \n\t" 
     //   "MSR PRIMASK, r0"
     //   );
    EDIT: well, on re-running test, i still sometimes see an artifact at the end of the 40 bits but only on pin 10, and using the cycle counter SYST_CVR to measure duration of send_milbus_cmd_asm(), i mostly see 4814 cycles and occasionally 5005

    EDIT 2: results above were with enable_irq. with no enable_irq, both pins 10 and 12 seem jitter free, using 4808 cycles

    EDIT 3: Alas, even with enable_irq commented out, SYST_CVR cycles are occasionally 4913 and 4988, though mostly 4808 cycles. But i don't see the jitter on the scope, so the cycle-count variation could be from interrupts sneaking in to the cycle-count logic around send_milbus_cmd_asm() and not being a factor in the pin toggling.
    Last edited by manitou; 07-09-2018 at 11:09 PM.

  9. #9
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    1,770
    I'm not a manchester code expert. But since each bit seems to be encoded either as hi-lo or lo hi, I could imagine encoding for example a 8bit data into the corresponding 16bit hi-lo-lo-hi-whatever sequence first and use the integrated hardware SPI module at 4MHz to output that encoded sequence independent of CPU load and interrupts on the MOSI pin

  10. #10
    Junior Member
    Join Date
    Jul 2018
    Posts
    10
    I come from arduino, pretty much new here. My only experience on a "jitter" there, is of course because of interrupt, the influence of millis(). Atmel suggests disabling it
    Code:
     TIMSK0 &= ~(1 << TOIE0); //disable millis()
    Sorry if it doesnt make sense on teensy

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,153
    Yes indeed, TIMSK0 is specific to AVR chip, and not even all of the AVRs, only some of them. Code writing to TIMSK0 won't work on other boards with non-AVR chips, or even the AVR chips with different timers.

    For this case, you probably want to disable ALL interrupts, not just one particular timer. That's relatively easy. You can use the Arduino function noInterrupts(). Or use cli() or __disable_irq(). All 3 of those do the same thing. Arduino's noInterrupts() is the most portable between all boards, if you use the Arduino software.

    If you *really* want to disable just the Systick timer but not any other interrupts, I believe you would use this:

    Code:
    SYST_CSR &= ~SYST_CSR_TICKINT;
    It's basically the same, just the chip-specific register controlling the timer is SYST_CSR rather than TIMSK0. Like using TIMSK0, this code will be rather specific to the Teensy 3.x board you're using. If you really want to see the definitions of these, look in kinetis.h. If you *really* want to dive into learning the ARM hardware, this stuff is covered in the Definitive Guide book.

    But really, for this application why would you bother with disabling only the timer interrupt but leaving all other enabled?

  12. #12
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,153
    Quote Originally Posted by manitou View Post
    EDIT 3: Alas, even with enable_irq commented out, SYS_CVR cycles are occasionally 4913 and 4988, though mostly 4808 cycles. But i don't see the jitter on the scope, so the cycle-count variation could be from interrupts sneaking in to the cycle-count logic around send_milbus_cmd_asm() and not being a factor in the pin toggling.
    Maybe try reading ARM_DWT_CYCCNT instead?

  13. #13
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    6,758
    I found this to enable the cycle counter:
    Code:
        // Enable CPU Cycle Counter
        ARM_DEMCR |= ARM_DEMCR_TRCENA;
        ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
    Subsequent checks like 'CyCnt = ARM_DWT_CYCCNT;' just returns current 32 bit unsigned counter that rolls over based on CPU speed.

  14. #14
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,571
    Quote Originally Posted by PaulStoffregen View Post
    Maybe try reading ARM_DWT_CYCCNT instead?
    Tried ARM_DWT_CYCCNT, most readings are 4813 ... but eventually saw a 4913 and 4918. So not really different from SYST_CVR behavior.

  15. #15
    I finally got my program to run jitter free!

    I used to call the __disable_irq() in the setup() routine and since i'm used to AVR i figured why not just disable all interrupts from the start. Apparently this does not work well, i suspect that __disable_irq() does not have any impact when called from setup().

    Instead i'm calling the function just before i output the waveform and enable intterupts immediately after. This did the trick!

    Thanks for the help!

Posting Permissions

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