Teensy 3.2 Timming inaccuracy

Status
Not open for further replies.
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/auj2msx38d2itdd/20180706_145514.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!
 

Attachments

  • milbus1553ASM_test.ino
    8.3 KB · Views: 79
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-IntervalTimer-is-not-precise
 
you could try overriding yield with a blank one added anywhere in your sketch:

Code:
void yield(void) {};
 
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?
 
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
manchester.png
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:
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.
 
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:
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
 
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
 
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?
 
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?
 
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.
 
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!
 
Status
Not open for further replies.
Back
Top