Timing is everything - Page 1
Forum section: electronics / general

author: PerranOak
author_rank: Frequent Contributor
timestamp: August 12, 2020, 02:42:37 pm
content: I have got to grips with assembly and the timing of outputs, say, for accurate square wave creation or clock (as in alarm clock, etc.) updating.What I can't figure out is how you do this in C. Surely, it compiles in a way that can't be relied upon for accurate timing purposes?Even using timers, how do you know exactly how long it will take to perform the tasks after the triggering of the timer?

author: agehall
author_rank: Frequent Contributor
timestamp: August 12, 2020, 02:59:50 pm
content: I don't think you should ever rely on C to be cycle exact. The code produced by a C compiler will probably be efficient but you can, in general, create more exact timings in assembly.If you actually have the need for a instruction cycle perfect timing, why not mix and match? Write that bit in assembly and then the bulk of the code in C. Just make sure you disable all interrupts during the timing critical segments otherwise you never know what the timing will be.Real question here though is if you really need that cycle exact timing? If so, maybe you are better off digging into FPGA land to ensure that your design executes in a predictable manner.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 12, 2020, 03:03:36 pm
content: With C code one does not know the exact time a calculation will take. It can change with different compiler runs and optimization. With modern µCs that use caches or similar buffers even in ASM the run time is not so easy and can be effected from the context.In C one does need to use hardware support to get exact timing. Usually something like timers can create an accurate frequency or set some pins with a defined delay. Other HW parts may be used too, like DMA. For some tasks it simply does not work in C and one may have to use ASM at least for the time critical part or use different hardware.

author: PerranOak
author_rank: Frequent Contributor
timestamp: August 12, 2020, 03:44:20 pm
content: I see, thanks both.Can you actually mix the two. Is it possible to write some assembly code then call it like a function?

author: Kleinstein
author_rank: Super Contributor
timestamp: August 12, 2020, 04:00:09 pm
content: One can mix C and ASM code. The details depend on the compiler used. Usually there are two options: one is using inline ASM to add a few ASM instruction directly inside the C code.The other option is to use a separate ASM file to provide some functions (as a separate object file) that are than used in the C code. For the ASM function there would than be a header-file (xxx-.h) to define the interface.A very common example is inserting an instruction to block and later re-enable interrupts. This may be hidden in a predefined macro.

author: tggzzz
author_rank: Super Contributor
timestamp: August 12, 2020, 04:13:30 pm
content: Kleinstein notes the fundamentals, especially w.r.t. caches and interrupts.However, there is one alternative where exact timing can be guaranteed due to:FPGA-like i/o ports with timers, where you can specify the exact clock cycle on which the next output will occur (or record the clock cycle on which the last clock cycle did occur). Direct support for that in the language helpsno interrupts, no cachesIDE tool support that analyses the optimised code to determine all the possible timings betweenhereandthereThat is the XMOS xCORE devices and xC.Here's a code fragment that bit-twiddles the control and data lines going to a simple LCD display controller. The timing of all the outputs are guaranteed to be correct with a resolution of 10ns.Code:// lcdE, lcdRW, are 1-bit ports connected to the LCD's enable and read/write lines// lcdData is a 4-bit port connected to the LCD's data lines// lcdE @ (x) <: 1 outputs a 1 when the timer is x// interface timing in 100MHz ticks, taken directly from the LCD data sheet with margin added to assuage my pessimism#define Tsp1 (6) // min 40ns#define Tsp2 (10) // min 80ns#define Thd2 (2) // min 10ns#define Tpw (26) // min 230ns#define Td (14) // min 120ns#define Tcyc (60) // min 500nsstatic void lcdWriteByteNoWait(int byte) {uint32_t tStart;lcdRW <: 0 @ tStart;// high nybblelcdE @ (tStart+Tsp1) <: 1 ;lcdData @ (tStart+Tsp1+Tpw-Tsp2) <: (byte >> 4);lcdE @ (tStart+Tsp1+Tpw) <: 0;// low nybblelcdE @ (tStart+Tsp1+Tcyc) <: 1 ;lcdData @ (tStart+Tsp1+Tcyc+Tpw-Tsp2) <: (byte & 0xf);lcdE @ (tStart+Tsp1+Tcyc+Tpw) <: 0;// complete the two cycles; use RW to avoid optimisation// and to give an external hint it has finishedlcdRW @ (tStart+Tsp1+Tcyc+Tcyc) <: 1;}FFI, see the XMOS literature

author: Twoflower
author_rank: Frequent Contributor
timestamp: August 12, 2020, 04:36:39 pm
content: Do you really need cycle exact timings? In that case I would think about to do some things in hardware (e.g. FPGA) as small changes (IRQs, different clock trees of internal busses vs. core) will potentially cause an unwanted jitter.Depending on what your actual needs are you might check if the processor has some dedicated HW supporting you. Like Timers or PWM outputs can be used to generate an exact clock signal or other function blocks.And I'm sure you're aware that if your application can accept some kind of jitter for the function but you need an exact timing over long time (e.g. second counter for a watch it doesn't matter if one call is after 1002ms and the next after 998ms) you don't stop and re-arm the timer that generates the interrupt just let it run all the time. It just triggers every 1000ms no matter what. Depending for example how much time the context switch takes the interrupt will be served might start sooner or later.

author: NorthGuy
author_rank: Super Contributor
timestamp: August 12, 2020, 04:50:05 pm
content: Your MCU probably has a PWM module which can produce the output without CPU. You can use it in C. If it's too slow, you may also need DMA to automatically move data to PWM.

author: David Hess
author_rank: Super Contributor
timestamp: August 12, 2020, 07:40:44 pm
content: A trick I have used is to precompute values to be stored in the *next* cycle, after storing the values in the current cycle. So the first thing which happens after the interrupt is triggered is to store the values computed last cycle, and only then compute values for the next cycle which can involve a variable number of instruction cycles. This removes jitter between the interrupt and store operations.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 12, 2020, 08:12:49 pm
content: With many µCs the time when an interrupt is actually executed can vary a little, e.g. depending on the instruction that is interrupted. So there can be some additional jitter at the start of the interrupt.In some cases PWM mode can be programmed to change a pin at a predefined time, not effected by the exact time when the PWM registers are updated.If nothing else help one can have an external flipflop to synchronize the output signal(s) to an external slower clock. This way one can also get around µC internal phase shifts that can happen from µC internal HW. I have seen the ADC and UART effect the phase of IO port changes with an AVR µC - not much (sub ns), but visible.

author: jnz
author_rank: Frequent Contributor
timestamp: August 12, 2020, 11:37:16 pm
content: Quote from: NorthGuy on August 12, 2020, 04:50:05 pmThis is the right answer. Waveform timing is exactly what PWM with DMA is for.Quote from: David Hess on August 12, 2020, 07:40:44 pmThis is a good answer for doing it the harder way.

author: David Hess
author_rank: Super Contributor
timestamp: August 12, 2020, 11:40:38 pm
content: Quote from: jnz on August 12, 2020, 11:37:16 pmIf you are making the most of limited hardware, it may be the only way. I do not think it is anymore difficult but it does require a change in perspective.

author: tggzzz
author_rank: Super Contributor
timestamp: August 13, 2020, 07:03:44 am
content: Quote from: Kleinstein on August 12, 2020, 08:12:49 pmJust so.As you note below, that's avoided if you can ensure your general purpose i/o occurs when a timer times outwithoutprocessor intervention.QuotePWM is a very boring example of such an output change, of course!If interrupt latency variations caused a problem with PWM outputs, then I'll bet it would be better to use a conventional DAC.