Inline assembly (PASM), injecting delays
ypapelis
Posts: 99
I have been very successfully converting my PASM programs into C (love it!), but one place where I am consistently getting in trouble is finding ways to inject precise delays in the code. I am using COG mode for C, so the C output program is running in a cog by itself, although the same problem probably would occur in LMM (or other models) for loops that end up cached into COG memory.
Using waitcnt/waitcnt2 can only generate delays higher than about 7 micro seconds, which does not cut it for tweaking clock pulses and clock-data pulse offsets. In pasm, for 'large' delays I could call a subroutine that loops around, and I could get a precise delay knowing the loop iterations. For shorter delays, simply inserting 'NOP' instructions did the trick. I tried to call a delay function in cogc, but unless the function is doing something 'meaty', it gets 'optimized' away, and not knowing (or having to look into the assembly is inconvenient). Incrementing a volatile variable appears to do the trick but is awkward. So I was wondering, is there a way to inject PASM code inside C? Some other embedded C systems provide pseudo functions that do exactly that. Or any other suggestion on how to achieve instruction-level delays would be welcomed!
Using waitcnt/waitcnt2 can only generate delays higher than about 7 micro seconds, which does not cut it for tweaking clock pulses and clock-data pulse offsets. In pasm, for 'large' delays I could call a subroutine that loops around, and I could get a precise delay knowing the loop iterations. For shorter delays, simply inserting 'NOP' instructions did the trick. I tried to call a delay function in cogc, but unless the function is doing something 'meaty', it gets 'optimized' away, and not knowing (or having to look into the assembly is inconvenient). Incrementing a volatile variable appears to do the trick but is awkward. So I was wondering, is there a way to inject PASM code inside C? Some other embedded C systems provide pseudo functions that do exactly that. Or any other suggestion on how to achieve instruction-level delays would be welcomed!
Comments
I've been able to make pins toggle as fast as 400ns (possibly 250ns) in COGC code using waitcnt2 (with 80MHz clock).
Here is a COG mode example.
Even in LMM mode 2us delays are possible. CMM programs are slower, so the demo below won't work by default - change wait = CLKFREQ/250000; to get about a 5us wait.
I'm not much of a GNU ASM user, so I don't feel comfortable answering that question without having time for more reading.
Yes, the __asm__ instruction. There's a section on it in the GCC manual, and various documentation online. To insert two nops you would do something like:
The string inside the __asm__ is passed through directly to the assembler. To insert multiple lines, use "\n" (and remember to indent at least one space so the instruction is not interpreted as a label). The "volatile" says not to optimize around the asm (not to move instructions past it, for example).
Note that the syntax for __asm__ is GAS, not PASM. They are mostly the same; the main thing to watch out for is that GAS addresses are always byte addresses, not long addresses.
Eric
For resetting to command line options you can use:
#pragma GCC optimize(initial)