ARM NOP - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: January 12, 2022, 08:15:53 pm
content: I need some rather small delays that will likely not be worth setting up counters and interrupts for. I think there is some sort of NOP instruction? how would I use that in the ARM-GCC compiler? (Microchip Studio)

author: westfw
author_rank: Super Contributor
timestamp: January 12, 2022, 08:30:07 pm
content: In theory, __NOP() is defined by CMSIS, and should exist…Note that a nop may not consume a cpu cycle…

author: Simon
author_rank: Unknown
timestamp: January 12, 2022, 08:41:28 pm
content: OK, how would it not consume a CPU cycle?

author: snarkysparky
author_rank: Frequent Contributor
timestamp: January 12, 2022, 09:04:29 pm
content: I use this to eat cyclesasm volatile ("nop");

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 12, 2022, 09:05:46 pm
content: Because it might not even be executed:https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/nop?lang=en

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 12, 2022, 09:08:50 pm
content: In C, a way to consume cycles for sure would be to use a small loop with a volatile-qualified counter, such as:Code:for (volatile int i = 0; i < xxx; i++) {}Of course, though, while it WILL consume cycles, it's hard to predict how many.

author: ataradov
author_rank: Super Contributor
timestamp: January 12, 2022, 09:17:32 pm
content: Here is my standard way of generating small blocking delays:Code:__attribute__((noinline, section(".ramfunc")))void delay_cycles(uint32_t cycles){cycles /= 4;asm volatile ("1: sub %, %, #1 \n"" nop \n"" bne 1b \n":  "+l"(cycles));}Code is located in SRAM so that execution time is not subject to flash wait states.This is better than a plain C loop, since it does not depend on the compiler and optimization settings.

author: Simon
author_rank: Unknown
timestamp: January 12, 2022, 10:26:45 pm
content: The only other thing I can think of it just increment a variable, so like "dummy_counter++;" I don't know how many clocks that takes but surely that is predictable. I may only need 4 cycles of delay and so maybe if that takes even 2 cycles is fine.

author: Benta
author_rank: Super Contributor
timestamp: January 12, 2022, 10:43:35 pm
content: Welcome to the world of assembler programming@atadarov's way seems to me to be how to do it.

author: ataradov
author_rank: Super Contributor
timestamp: January 12, 2022, 11:26:34 pm
content: Quote from: Simon on January 12, 2022, 10:26:45 pmThe issue here is that this is not be predictable. And on some devices the execution time would depend on the location of the code in the flash.For example, on SAM V7x if your whole loop fits into a 64-bit aligned block, it will be very fast, as it will be executed from the prefetch buffer. But as soon as it moves and crosses the boundary between the two 64-bit blocks, it would take way longer. Counting cycles is pointless if you are running from the flash. Caches (specifically I cache) help a lot, but are not a full solution.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 13, 2022, 12:04:59 am
content: And, with all that said, if you absolutely need sorta accurate delays down to a few cycles on modern 32-bit MCUs, you're probably doing something wrong. Very short software delays were good on good old, fully predictable cores, often for bit-banging some IOs to emulate some peripherals. On any modern MCU, this is ridden with potential pitfalls, and there's usually another way of achieving the same, using the right peripheral. Of course, that's a general thought, there may be a very good reason for doing that - but certainly this would often be the last resort.

author: Bassman59
author_rank: Super Contributor
timestamp: January 13, 2022, 12:53:09 am
content: Quote from: Simon on January 12, 2022, 08:15:53 pmWhat's your use case?

author: westfw
author_rank: Super Contributor
timestamp: January 13, 2022, 02:14:27 am
content: Older ARM architectures apparently didn't have a separate NOP instruction, so the assembler/compiler would generate a "mov r8, r8" instruction, or maybe "mov r0, r0"There are of course MANY instructions like this that don't actually do anything, and many more than "only" affect the flags.ARM v6m ARM says:QuoteSadly, there aren't any clear indications of what WOULD be "suitable for timing loops."

author: ataradov
author_rank: Super Contributor
timestamp: January 13, 2022, 02:43:52 am
content: None of ARM architectures have a dedicated NOP. It is always assembled from an instruction without side effects.While in theory it is not guaranteed, the behaviour is fixed to the core, and for all Cortex-Mx cores it would take at least one cycle to execute. And for Cortex-Ax you have a whole new set of problems anyway.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 13, 2022, 02:53:09 am
content: I like using the DWT cycle counter on hardware that has it (ARM_DWT_CYCCNT), although it does mean DWT needs to be enabled, and I don't know how that affects power consumption.

author: westfw
author_rank: Super Contributor
timestamp: January 13, 2022, 03:36:16 am
content: QuoteAre you sure?ARMv7m and ARMv6m ARMs both say that NOP should encode to 0b1011 1111 0000 0000, and that doesn't seem to match any other instruction encoding?(leading 1011 means "miscellaneous", the second 1111 means "hints", and the zeros make it a no-op...)

author: ataradov
author_rank: Super Contributor
timestamp: January 13, 2022, 03:45:17 am
content: Quote from: westfw on January 13, 2022, 03:36:16 amOk, I stand corrected.My statement mostly comes from looking at assembly all day long, and GCC encodes "nop" as "mov r8, r8" for all platforms. I think IAR does the same, as I'm so used to the encoding 0x46c0. So this avoids the timing issue, but this dummy move could be optimized too, of course.

author: westfw
author_rank: Super Contributor
timestamp: January 13, 2022, 03:59:49 am
content: (I think the chances that anything in the Cortex-M class would actually have a pipeline smart enough to discard "mov r8,r8" instructions and similar without executing them would be about zero. But then I don't understand why the "architecture" allows the "real nop" to have such non-deterministic timing, either. Surely it would be easier to omit that possibility?)+1 on using DWT if it's available.You can also use systick.https://github.com/WestfW/Duino-hacks/blob/master/systick_delay/systick_delay.ino

author: emece67
author_rank: Frequent Contributor
timestamp: January 13, 2022, 08:42:37 am
content: .

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 08:56:10 am
content: Quote from: SiliconWizard on January 13, 2022, 12:04:59 amYou hit the nail on the head. I am controlling a good old Hitachi style character display (ST7066U) with a parallel port...... because.... all the serial port ones sold out.It's not imperative here. The minimum delay between checking the busy signal is 80µs with a clock cycle at 48MHz of 20.8666ns so nearly 4000 cycles in there and worth a bit of delay code or using a timer with an interrupt.This is a SAMC M0+, I doubt anyone would want to use an old character display on a wizz bang anything above that, this is just the easy way until I have time to go graphic and find serial stock.

author: wek
author_rank: Frequent Contributor
timestamp: January 13, 2022, 09:10:03 am
content: The architectural NOP is optional, and may not be configured in a given incarnation of the Cortex-M core, see SCB ID_ISAR3.TrueNOP_instrs.I've just checked, in STM32F427 it is set. Upon second reading of ID_ISAR3.TrueNOP_instrs description, it says0 None supported, ARMv7-M reserved.which means that this value can't occur in ARMv7-M. In other words, architectural-NOP is always supported in Cortex-M3/4/7.I did not know about the architectural-NOP being different from the traditional mov rx,rx. Thanks westfw for pointing this out.BTW it might be an interesting idea to build a table of how these optional featuers are configured in various Cortex-M incarnations. Anybody is in?JW

author: Siwastaja
author_rank: Super Contributor
timestamp: January 13, 2022, 09:18:03 am
content: Also M7 has dual issue, i.e., can run two instructions in parallel if they do not depend on each other. And obviously, since NOP does nothing, it does not depend on anything around it, so NOP can always run in parallel with any other instruction, or another NOP.I noticed this behavior when hand-adjusting timing-critical M7 assembly code: adding single NOP may or may not add delay of 1 CPU cycle, depending on what's going on around the NOP, but adding two NOPs back-to-back always did add at least one CPU cycle of delay.Use ataradov's code. If you need super-small delay of just a single CPU cycle, then try NOP:__asm__ __volatile__ ("nop");Unless it's M7, this is very very likely to add one CPU cycle of delay.But indeed, what's the use case? If you, for example, want to add a tiny dead time between high and low side transistors, just writing as two separate IO operations already gives you longer delay than 1 CPU cycle (depending on the bus clock to the IO port). Typical would be like 2-5, with possibly a cycle or two of jitter. If this is not long enough, then I fail to see how adding just one cycle more would change anything, so just use ataradov's code even though it does have a minimum delay of 4 cycles, plus the function call overhead (a few cycles, don't remember offhand how many).Also remember, as others have mentioned, higher end ARM CPUs can't access the flash at the CPU core frequency, meaning they pop more instructions at once, so that linear code can run at full CPU speed. This makes jumps possibly take longer time, as the CPU has to wait for the flash access.

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 09:19:37 am
content: Having looked at the datasheet for the display controller it looks like the smallest time I need to wait is 80µs or up to 4000 cycles, for this it makes sense to use a counter. Now I need to work out how I run my display updating with interruptsI think it will come down to a single array variable that holds the display contents that things can write the data into and the display code residing in an interrupt routine to just move through the process of updating the characters. While the minimum time I need to compute is 80µs this is the minimum time I must allow between checking the ready pin, but it looks like most operations take 37µs to complete in the display. However the data read setup time is 320ns which i assume applies to when i read the busy flag which is 64 cycles so still timbale. with a counter.So it looks like my code will be establishing where it got to in the process of sending a character and then set the time value to what wait time is required for the next step, zero's the counter and then arms the interrupt again.

author: brucehoult
author_rank: Super Contributor
timestamp: January 13, 2022, 09:36:06 am
content: Quote from: westfw on January 13, 2022, 02:14:27 amI don't know what plans they had for ARMv6-M when they wrote that manual, but it's used in Cortex M0, M0+. M1 *only*, none of which are ever going to optimise out a NOP.Some cores executing ARMv6 were more sophisticated, up to as a limit of the 1.0 GHz ARM11 in the BCM2835 in the Pi Zero and Zero W. But that is still a simple single-issue in-order core that is never going to optimise out NOPs.I don't think you have to worry for anything below a Cortex A-15 or A-57.Obviously, if you have a dual-issue core such as a Cortex M7 or A7/A8/A9/A53/A55 then a NOP will occupy only one pipeline and some other instruction will execute in the other pipeline. If you are putting a lot of NOPs then they will be executed two in every cycle.That's why it might be better to use something like ADD #1 or SUB #1 for a short delay. If you put a few dozen of them in a row then any CPU no matter how sophisticated has no choice but to execute them sequentially at one per clock cycle.But write that in assembly language not C, if you don't want 100 a++'s to be optimised to a+=100 -- or even removed completely if it doesn't look like the result is used.

author: tggzzz
author_rank: Super Contributor
timestamp: January 13, 2022, 10:08:55 am
content: Quote from: SiliconWizard on January 13, 2022, 12:04:59 am... except for the XMOS xCORE devices, where the hardware/software ecosystem precisely defines timing during design. None of this "measure it and hope" nonsense.Bonus: lots of parallel cores, so up to 4000MIPS/chip

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 10:16:08 am
content: Looking at the display driver datasheet it almost looks like the enable/clock, really is meant to be a clock signal of at least 80µs period, this kind of helps a lot as basically I use that as my base timer and use a hardware PWM that will clock any other software counters.

author: Kleinstein
author_rank: Super Contributor
timestamp: January 13, 2022, 10:20:49 am
content: Quote from: SiliconWizard on January 13, 2022, 12:04:59 amWith bit banging one may still need short delays, often no need to be accurate, more like at least some 100 ns to give external HW time to recognize a pulse / HS signal.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 13, 2022, 10:23:43 am
content: Yes, display designers have a weird tradition of calling the signal that all other industries (even academics) call "clock", "enable". Whenever they have actual enable, they need to come up with something else. This causes confusion for everyone the first time.

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 10:42:51 am
content: Well they do go all out to make it confusing, having declared the minimum low time to be 80µs when checking the busy flag they then state that the clock cycle is to be 1.2µs so it's also a 2 speed clock based on what you are doing.

author: wek
author_rank: Frequent Contributor
timestamp: January 13, 2022, 10:46:12 am
content: Quote from: Siwastaja on January 13, 2022, 10:23:43 amThat's a Motorola 68xx legacy. Its bus was clocked by a signal they called Enable. Hitachi (as maybe all japanese chipmakers) took over the basic idea of the 68xx architecture and together with it also the bus style and terminology.JW

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 02:29:19 pm
content: https://www.newhavendisplay.com/app_notes/ST7066U.pdfSo it looks like I may as well just run a PWM output at 6 kHz or less into the enable, every time the interrupt for the signal going high/low fires do whatever is the next step, that way I have one single timing to worry about.what confuses me is the 1.2µs cycle time for the enable, but it wants 80µs minimum low pulse when testing for a busy flag on D7, so really I run on a 160µs cycle time, or has someone got their ns and µs mixed up here.

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 02:40:25 pm
content: This is all further complicated by all instructions taking 37µs to execute except the ones that take over 1.5ms so I may as wel run a clock that runs at 25-50kHz not the 800kHz that the 1.2µs cycle time suggests.

author: wek
author_rank: Frequent Contributor
timestamp: January 13, 2022, 03:07:45 pm
content: You can also reprogram the timer on the fly, always to provide the optimum delay until the next operation.

author: nctnico
author_rank: Super Contributor
timestamp: January 13, 2022, 03:38:25 pm
content: Quote from: wek on January 13, 2022, 03:07:45 pmThat is how I create small delays on ARM controllers as well. I use a hardware timer that stops counting when it hits the number of counts. With the prescaler set so it counts in micro seconds I just load it with the number of microseconds and wait until the counter stops.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 13, 2022, 03:39:08 pm
content: Quote from: wek on January 13, 2022, 03:07:45 pmThis. Timers are not some fixed frequency or PWM generators that could be only adjusted at program startup. They are, after all, timers. Use them to create the interrupts and state changes you need, exactly when you need.Whenever the delay is significantly longer than interrupt latencies, it's fruitful to make the timer trig an interrupt, so other code can run during the wait. If the delay is say < 50 clock cycles - or if you just have nothing else to do anyway - then you can just block until the completion of the timer, making it a simple flag poll.Use interrupt priorities to your advantage.

author: Simon
author_rank: Unknown
timestamp: January 13, 2022, 04:11:20 pm
content: Yes timings can be changed on the fly. But here I am doubting the display driver datasheet for mentioning something that did not need mentioning, given the speed of update I need 1kHz will probably do, really I just need to go fast enough that the user does not see half of an old display and half of a new one, but that is like 100ms. If the display takes 100ms to update no one will notice the characters changing one at a time.With the clock slow enough the whole thing can just sit there updating the screen all the time and running the rest of the program in between. With a display clock of less than 10kHz and a CPU clock in the MHz it's not even worth worrying about starting a screen refresh, just do it perpetually.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 13, 2022, 10:58:07 pm
content: Quote from: wek on January 13, 2022, 03:07:45 pmFunnily enough, I use exactly the same approach in application development in Linux, to create timeouts and such.Essentially, I have a binary min-heap of the timeout times (and associated linear array so that timeouts can be canceled etc.), with the root element containing the time of the next timeout event. Works well, for any number of timeouts, and after one once works out the corner cases (like multiple timeouts elapsing at the same time, trying to set a timeout that is in the past at the moment one re-arms the timer, et cetera), it is quite robust, too.

author: emece67
author_rank: Frequent Contributor
timestamp: January 14, 2022, 12:07:10 am
content: .

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 14, 2022, 01:04:59 am
content: Quote from: ataradov on January 12, 2022, 09:17:32 pmI've tested SRAM execution before and noticed it was slower than flash in most cases.No flash wait states, but due the bus sharing (The SRAM bus has to be shared between the instruction fetch and the data access), you might get the same effect.If the device has CCRAM, any code there will be executed at 100% core speed (unless you also access the CCRAM as data), as it has it's own dedicated bus, no collision will happen with flash, sram or other busses.

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 14, 2022, 01:22:11 am
content: Quote from: emece67 on January 14, 2022, 12:07:10 amSure, that's one name you can use.In practice, I usually use a dedicated POSIX thread for this, with it blocking inpthread_cond_timedwait()for either the next event or a signal on the condition variable that there are changes in the event set. This means there usually isn't any userspace timers involved at all, and it is just the kernel waking up the blocking thread at a suitable time.I've also usedPOSIX signalsand a simple linear array. Signals (if installed without SA_RESTART flag) have the benefit of interrupting a blocking call (with errno==EINTR) in the thread used to run the userspace signal handler function; but, in a multithreaded program, the dedicated thread approach is still more efficient (and can optionally dispatch the interrupting signal via e.g.pthread_kill()).Many ways to solve the same problem. If there are less than say a dozen concurrent timeouts, a linear array will do just fine; the search (to find an unused slot, and to find the next one to elapse) is not too slow, and the code will be simpler and much more maintainable.What I have never tried, is using a timer and a DMA channel (set up to copy only one byte or word) when the timer elapses, for automagic timeout flags. This would not necessarily interrupt anything (except to set up thenextelapsing timeout flag), but not cause (measurable) latencies either and would work even when interrupts disabled, so it might work well for co-operative timeouts on hardware capable of it and having an otherwise unused timer and a dma channel.

author: westfw
author_rank: Super Contributor
timestamp: January 14, 2022, 01:26:41 am
content: QuoteI've been wondering about that. Which CPUs did you test?Presumably, the sort of cycle-counting busy loop we're talking about here would not have any data accesses.Trying to get deterministic timing out of most ARM chips, by cycle-counting your instructions, is difficult.IO on these sorts of timeframes (80us, 3000+ cycles) is annoying. That's too slow to feel great about busy-looping, and ... somewhat fast for interrupts. (although, a 115200bps UART interrupts about every 90us, and no one bats an eye at using interrupts for that, even on slower CPUs.) I suppose a lot depends on whether you have anything else to do during that 80us...

author: ataradov
author_rank: Super Contributor
timestamp: January 14, 2022, 01:35:19 am
content: There is probably some pathological cases where running from SRAM would be slower, but it is not generally the case. Most instructions are fetched 2 at a time and on fast devices with more than 1 WS running from SRAM would almost always win. It may be a toss up on a typical 48 MHz Cortex-M0+ with 1 WS flash.Also, if instructions are fetched from the flash anyway, then you have to share the bus no matter what, so I really don't see how running from the flash can ever be faster.And on CM4/CM7 is not an issue at all, since they have two buses and usually require a ton of wait states.

author: DavidAlfa
author_rank: Super Contributor
timestamp: January 14, 2022, 08:49:26 am
content: Yep, last time I tried was a basic ARM core, STM32F103.There was a small function to clock I2C data (Software Mode), using .ramfunc section was actually slower than normal flash.Probably beefier devices (F4,F7 series) perform better.Didn't investigate further, as anyways the speed had to be much lower, made a small test and compared the waveforms in flash and RAM execution.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 14, 2022, 09:33:52 am
content: Are there MCUs where sequential instructions all incur the flash wait state penalty?Probably yes, but I don't think I have seen any? Until some point, CPU and FLASH run at the same frequency with no wait states. After this point, CPU runs faster and FLASH uses wait states, but at the same time, usually, FLASH will transition into wider word than a single instruction, allowing prefetch. Simplest implementations have no cache or "acceleration" of any kind, but linear code runs at full speed. Average speed is definitely not 1 / WAIT_STATES.I have never been huge fan of running from normal SRAM (if core-coupled memory isn't available) because while it might improve the performance a bit, it does not make it predictable, bus is still shared with DMA for example.Whereas, running from ITCM is greatest thing after sliced bread, with no compromises really. M7 devices are not the only ones with ITCM, for example the STM32F334 comes with CCM (the same thing with different name).

author: wek
author_rank: Frequent Contributor
timestamp: January 14, 2022, 10:17:18 am
content: Quote from: ataradov on January 14, 2022, 01:35:19 amQuote from: ataradov on January 14, 2022, 01:35:19 amAdd CM3, and add one bus. In CM7 the picture is further blurred by... all the stuff...including the massive conventional L1 caches on the AXI... so the timing picture is very complex there, with results all over the place depending on particularities... so let's just ignore CM7 now.What David talks about is running from SRAM on the S bus, vs. FLASH on both I and D buses (for fetches/constant data reads) while user data are still in SRAM on S bus.S bus is architecturally made so that it imposes one extra cycle on *every* read - the reason is, that it is heavily loaded by all the slave buses the processor can access (except FLASH), whereas I and D are loaded only by the FLASH (and in some cases SRAM intended for fast code execution, which is then called CCM at least in STM32s). Also, as David said, when code is fetched through the same port as data are read and written, there are collisions; and writing to and especially reading from peripherals may be surprisingly expensive. Sure, there's prefetch in the processor, that helps a bit, but damage is already done.OTOH, latency of FLASH is mitigated by the FLASH being 128/256 bits wide, automatic prefetch from FLASH (although that's a slightly two-edged thing, as pessimal jump patters do exist). In STM32F2/F4 (and 'F7 although I said I won't talk about that :-)) even nonlinear code is treated through the jumpcache, and constant data (which usually means the address pool, i.e. a continuous space) through a small data cache (ART is the marketing name for this combo). They can be similar jumpcache or conventional caches in other manufacturers' implementations, I don't follow.So yes, depending on circumstances, execution from FLASH may win over execution from SRAM. As part of marketing push of the then new 'F2/'F4, ST produced a comparison (unfortunately without publishing source code), seehttps://community.st.com/sfc/servlet.shepherd/document/download/0690X0000060I7OQAUpp36-45.JW

author: Siwastaja
author_rank: Super Contributor
timestamp: January 14, 2022, 10:56:21 am
content: CM7 has been easiest for me, timing-wise, really!Why? Because they come with ITCM and DTCM*, enabling predictable code execution under all conditions, and predictable, fast variable access (stack or something else), independent from everything else going on - DMA's for example.*) well not always, those are optional features of the core, but STM32F7 and H7 series which I do use, have fairly large ITCM and DTCM.Also just the "raw power" can compensate quite a bit. I don't have to worry about interrupt latency of 12 cycles at 400MHz. At 20MHz, it might matter.Caches are uninteresting. I have never enabled caches. They are not meant for anything where timing is important, they are "easy" solution to improving average case whenever worst case is not important: UIs for example.It's those mid-range devices where timing is iffy. You have limited CPU clock, limited bus clock, DMAs consuming significant part of bus cycles, and usually no core-coupled memories.

author: wek
author_rank: Frequent Contributor
timestamp: January 14, 2022, 01:00:30 pm
content: Quote from: Siwastaja on January 14, 2022, 10:56:21 amI see your points, I really do, but beg to differ.You claim that this provides predictible timing - but timing of what? On that STM32H7xx, a single write to GPIO traverses through three* bus matrices and buffers/bridges between them - and *none* of those is documented, timing-wise.I'd formulate differently: no matter what the raw clock and architecture of processor is, techniques used by the designers to achieve high clocks result in roughly same outwards signals' timing/jitter/latencies/whatever. Faster chips introduce more uncertainties. You can do better in the higher-end chips, but it requires extra care, and depending on particularities, sometimes you simply just can't. For better timing, always go for hardware.2 eurocents.JW * two, I had a look and there is a D1-to-D3 interconnect; however, that means one of those matrices is AXIM...

author: MK14
author_rank: Super Contributor
timestamp: January 14, 2022, 05:12:36 pm
content: Quote from: Simon on January 13, 2022, 10:42:51 amI agree it seems confusing. I've only had a relaitively quick look at the datasheet, so could easily be confused/wrong, myself. But I attempt to explain why there are fast, around 1MHz/1µs elements, and much slower 80µs/1ms/100's of ms timing things.The 'fast' (if you call 1MHz/1µs fast these days!) timings are the actual hardware interface timings itself. Which seems to prefer to have a clock which is regularly active. I.e. some kind of low level serial/parallel etc, hardware peripheral chips.The much slower timings, such as the 80µs, for the busy flag to be active. Are probably the (worst case scenario, with suitable active clock(s) and active enable signals) time the displays internal MCU and/or graphics cpu/hardware takes (via software/microcode/hardwired-graphics/character-functions), to perform the requested tasks.E.g. 80µs to set/reset the busy flag, or many milliseconds (and much, much longer) to perform more complicated display functions.

author: tggzzz
author_rank: Super Contributor
timestamp: January 14, 2022, 05:30:59 pm
content: Quote from: wek on January 14, 2022, 01:00:30 pmConsider a separate timer directly attached to each and every i/o port, connected to several cores via a connection matrix. With that the cores can tell each port the clock cycle on which to do output (or input), or record the clock cycle on which input occurred. That should ensure the time taken to transit the connection matrix is irrelevant.Consider each core acting independently, with no caches and no interrupts. That removes timing jitter, so the exact number of clock cycles for an instruction sequence can be defined in advance, without measurement and hoping you've stumbled on the worst case timing. Might as well use the same connection matrix between the cores.Consider having a toolset that automates that, and a simple language designed for parallelism.No, it isn't a dream of the future! It has been a reality since 2007.You can buy XMOS xCORE processors at DigiKey, program them in xC, and use the free Eclipse-based IDE.Oh, there aren't pages and pages of errata for the software and hardware - it just works as advertised.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 14, 2022, 07:18:44 pm
content: Quote from: wek on January 14, 2022, 01:00:30 pmYeah, non-zero jitter, in clock cycles, but quite tight in actual time, because of high clock frequencies.Obviously, if you need zero-jitter IO with completely predictable timing, a general purpose modern MCU simply isn't the right tool. You need a PLD, or special purpose MCU like the tggzzz's favorite. Maybe in some very limited cases where coarse time unit and low performance is acceptable and predictability and low jitter is the main goal, an old 8-bitter with handwritten assembly does the trick.But there are many many cases where timing accuracy within ~100-200ns is acceptable. In such cases, an M7 running running just bog standard C code, without special considerations, using interrupts and interrupt priorities to create the application, is the easiest and good enough solution.When counting clock cycles and proving cycle accuracy, we often fail to see the forest from the trees: the fact that actual time, in seconds and not clock cycles, is all that matters, and in physical world, jitter and uncertainty is always there, we just need to define what we can accept. Even XMOS has jitter, just maybe ~2-3 orders of magnitude less than a bare metal Cortex M7 application, which again has maybe ~2-3 orders of magnitude less jitter than one written by inexperienced trainee using example codes and libraries.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 14, 2022, 07:28:37 pm
content: But in any case, sorry for bringing that up again, but relying on a specific execution time on modern CPUs is something to be avoided. At worst, it won't work, and at best, it will just look like tinkering. If all you need is some *minimum* delay, then sure, it's fine (as long as you don't rely on instructions that may never get executed...) But anything accurate and reproducible? Use appropriate resources in your MCU, such as timers, or other peripherals - if you typically need to bit bang GPIOs with accurate timings, there's usually a peripheral that will do this for you. If there isn't anything that quite fits (for instance, because you need to toggle some GPIOs with a specific timing relationship relative to, say, some SPI peripheral), there are now many MCUs out there that have a peripheral chaining ability (called in various ways, usually under the name of "trigger" something), with which you can trigger a peripheral from another one. So for instance, you can configure your MCU to trigger a SPI transfer from a PWM output, for instance, which you could use in a single-shot mode. Read datasheets, and use hardware features as much as you can when accurate timings are involved. Or use an old 8-bitter with 100% predictable and reproducible timings down to the cycle for any operation. Your pick. =)

author: tggzzz
author_rank: Super Contributor
timestamp: January 14, 2022, 08:41:14 pm
content: Quote from: Siwastaja on January 14, 2022, 07:18:44 pmThere are two fundamental granularities of jitter relevant here:algorithms with variable execution times, e.g. think malloc/freevariable numbers of instructions/clocks, e.g. due to data variability, caches, or interruptsjitter in the clock periodYou are less likely to get algorithm problems with a hardware implementation, but it can be acheived!Jitter in the clock period is often introduced intentionally, to minimise EMI problems.The XMOS xCORE xC devices avoid the cache/interrupt/data problems, by apprropriate architecture and implementation. Hence they can be regarded as:showing what mainstream technologiesfailto achieveoffering some of the advantages of traditional softwareandhardware technologies

author: Simon
author_rank: Unknown
timestamp: January 15, 2022, 09:50:18 am
content: Quote from: MK14 on January 14, 2022, 05:12:36 pmOriginally I thought I would have to run a display update every so often but I had not realized that the enable is a clock ani may just run, I thought it was just an enable to signal that the but had valid data. If the clock is to just run then the timing is not an issue anymore as I just send a PWM signal that is only fast enough to achieve the required refresh rate. Given the slow speed the bus needs to work at the time taken to run it is minimal to the overall program so it can run continually. I can of course run in bursts by disabling the counter between refreshes.

author: Simon
author_rank: Unknown
timestamp: January 15, 2022, 10:15:40 am
content: what is confusing is pages 27 and 28 versus page 30. 27 is the 4 bit mode, very clearly the clock is shown to be unequal in high/low with emphasis on the low time after the display has started executing the instruction so that the data is asserted and the busy flag returned. In the 8 bit mode it shows equal high/low periods with again emphasis on the time to wait for a valid busy flag. this delay is a whopping 80µs, but coincidentally the data setup time to read data is 80ns which I assume is what you would call this period. the data is accepted and the bus interface sets the busy flag.The issue would be that if the busy flag is checked less than the 80µ/ns later it would not yet be asserted so the MPU would think the display is clear to take more data when it is just starting to respond to the instruction.Then going to page 30 you have the diagram of timing of sending data with the timings table on page 32. This is where the data hold time is shown in ns and the whole clock cycle is said to be 1.2µs. It really feels like there is an error.assuming these displays were meant to work on a standard bus with other devices surely the Bus master cannot be expected to change the clock just to suit the display. I take this to mean that the clock must have a cycle time of at least 1.2µs or no more than 800kHz.What is also evident is that the clock being the enable cannot be free running to every device on this bus so presumably and given it's name "enable" the clock was akin to the CS pin on SPI devices but it doubled up as the clock. I assume there was some address multiplexer in the system that the bus master would put an address to and that would route the clock to the desired device.Is there a standard anywhere for this bus?

author: MK14
author_rank: Super Contributor
timestamp: January 15, 2022, 03:14:25 pm
content: Quote from: Simon on January 15, 2022, 10:15:40 amI think what is causing confusion, is the fact that the E clock, is performing TWO roles here. One role is that it needs to be pulsed/clocked, to 'clock' the data into the chip(s)/display. Which for 4 bits, seems to require, two complete (high/low) clock cycles, so that it receives the entire 8 bits.But for 8 bit interfacing, it only needs one such high/low E clock cycle.Then it moves into the, what they call/show as INTERNAL OPERATION - FUNCTIONING part of the datasheet timing diagram (but which I have been calling the displays MCU/GPUs internal software/microcode part of the delays).The other E clock function, is that it mostly needs to be kept low, while the (displays software) INTERNAL OPERATION - FUNCTIONING, is running. With the exception that in order to check the busy flag status, you need to send further commands into the display, in order to determine when it has finished its internal processing (software).tl;drSo yes, the E clock does need to be mostly low, while the INTERNAL OPERATION - FUNCTIONING (I'm intentionally trying to use the same terms as the datasheet, as if I keep on calling it internal software operations, I might also cause confusion). Except when you are clocking the E line, to check for the busy flag to eventually become clear (finished, ready for more commands).I don't think there are errors in that datasheet. It is just that it gets rather confusing, because some of the timings are about physically getting the 8 bits of command data (which needs a pair of 4 bit operations, in 4 bit communication methods), into its internal peripheral chips/registers etc, and so are fairly quick, such as 450ns or 1.2µs. But, it then goes into (what they are calling the) INTERNAL OPERATION - FUNCTIONING bits. The timings become considerably longer, because you are waiting for the internal mechanisms inside the display (mcu(s), simple graphic processors etc, and their internal software), to process the information for you, which can take quite a while, such as 80µs, or many milliseconds.

author: Simon
author_rank: Unknown
timestamp: January 15, 2022, 06:08:03 pm
content: No it's not that simple I am afraid. Looking at the busy flag check timings it is clear that as the data goes in on a falling edge it takes time to register in the displays controller. Only once it has registered can the same pins that were just used as inputs now give an output as the data 7 pin sets the flag.As you can see from the busy flag check diagram the "functioning" starts with the clock/e going low, there is then a minimum delay of 80µ/ns and then it may go high. surely this timeframe is needed for the data on the lines to be transferred into a latch in the display controller to be held onto once the clock goes high and data is then sent to the screen.As soon as the clock/e goes high again and the data is latched D7 may now be used as the flag output and instantly goes high, I saw somewhere that the flag setup time is "0".It looks like the flag is asserted when the clock is high but does not read when low so the time to read the busy flag is during the high part of the clock as the flag asserts on it's rising edge, but it has to see a clock rising edge. If you compare the "functioning" to the busy flag you can see that the flag does not change until the rising edge of the clock.So the real time critical bit is making sure that the clock is low for long enough to latch the data, which I would have thought is the 80ns data setup time in the table on page 32.The entire instruction is usually executed in 37µs which is why having just one little period of the whole cycle lasting 80µs which is over twice that time seems odd.Looking at the data transfer diagram the 80ns setup time is the time between the data appearing and the clock going low for it to be latched in. So maybe what they are trying to convey is an 80ns time of valid data before and after the clock falls (which may take 25ns).Back at the busy flag checking diagram they show multiple clocks happening during a "functioning" period which is usually 37µs, but these are the clocks that have to be something like 160µs but that in the timing table must be at least 1.2µs with at least 460ns of high time but no spec on the low time so if the 80 is ns not µs that could be a 1120ns high time and a 80ns low time which seems silly anyway as I would run on a 50/50 clock.So i still do not see where the 80µs comes from as it is so much longer than all other timings not to mention equivalent to 6.25kHz when the display controller is working at 270kHz, I think this alone shows that it's an error. In the time to do a 50/50 160µs cycle the display controller has done 43 ticks, if it's going to un-assert a busy flag you would think that would happen well within a couple of ticks. The 37µs instruction execution time is 10 clock cycles of the display controller.

author: ozcar
author_rank: Frequent Contributor
timestamp: January 15, 2022, 09:13:07 pm
content: I thought these displays could all be traced back to the 35+ year old HD44780. I have seen differences in the timing specifications, but such differences were improvements on the original, such that something designed to work with the HD44780 would be guaranteed to function on the look-alike (but not necessarily the other way around). For example the HD44780 setup time for RS and RW to be valid before raising E had to be a minimum of 140ns, while for the later Samsung KS0076 clone, this setup time could be as low as 40ns (and I note that for this ST7066U the figure is 0ns).So I always thought it safest to design according to the ancient HD44780 specification. However I'm a bit surprised to find now that may not always be a good idea. I see that this ST7066U has minimum E cycle time of 1200ns, while for the HD44780 it was 1000ns.Unless this display is really totally different to HD44780 (I did not look that closely) then there is no reason to have a continuous signal on E (there is a minimum cycle time, but no maximum). Nor is it necessary for the high and low times of E to be different, so long as the high time is at least 140ns, and the cycle time at least 1200ns.

author: MK14
author_rank: Super Contributor
timestamp: January 15, 2022, 10:35:29 pm
content: Quote from: Simon on January 15, 2022, 06:08:03 pmYes, it is, I agree. Now taking some of your other points, one at a time:QuoteI agree.QuoteIF the F.osc or F.ext (whichever you are using), is exactly 270KHz, then it is 37µs. But at the minimum allowed F.ext (and clock frequency) on the datasheet, which is shown as 125KHz, datasheet, near top of page 32, then it would be 80µs.QuoteRemember the 10 clock cycles you just mentioned (last bit of your post), and the 125KHz minimum external frequency (clock F.ext (look at OSC1, OSC2 pins), NOT to be confused with the E signal). 125KHz = 8µs x 10 clock cycles (see bottom of your own post) = the 80µs minimum time.Unfortunately (I'd prefer it, if the datasheet was considerably easier for everyone, to understand), many of the timings it mentions, are actually dependent on the actual F.osc or F.ext clock frequency, which has defined min and max limits, page 32 of datasheet. Page 8 seems to mention the OSC1, OSC2 stuff.Once you have a specific circuit (schematic) defined, and know the component values, you will know whatF.osc or F.ext are and/or can set them by programming (or changing component values) of your unit, to make them what you desire them to be. I haven't looked into that part of the datasheet, have no idea what schematic and/or hardware you are going to be using, so can't really speculate on what OSC1, OSC2, F.osc or F.ext, are going to be for your stuff (unless I've missed it, in the rest of this thread).There is a 80ns, you keep on referring to, but that is the data setup time, T.DSW, Which is about setting up data, ready to write into the chip, rather than the busy flag timing.

author: Simon
author_rank: Unknown
timestamp: January 15, 2022, 11:47:41 pm
content: This chip is used on a display module I am using from newhaven. I'm not actually putting this chip on a PCB myself or making any of the functional choices, but the newhaven datasheet refers to this one.Yes the datasheet is crap! they talk about a 2MHz MPU bus speed on the first page but then hey that is 500ns, so still this 80µs seems to make no sense other than taking into account the 10 cycles at the lowest theoretical speed. So they don't want the clock to be high all the time but it must not be low too long, it goes round in circles. The 2MHz is clearly bollocks as the timing clearly states a 1.2µs cycle which is 833kHz not to mention the 6.25kHz speed if we use the 80µs figure. The datasheet seems to assume 270kHz as the usual speed. I have been refering to the timings at 2.7V when I am actually using 3.3V, timings at 5V are much faster.I now question the cycle timing figure that is shown as a minimum, maybe they meant maximum but put it under the slower clock it relates to (time is the inverse of frequency). I just don't get it, they just made this shit up, the clock timings are just totally irrelevant. All they needed to say was that each instruction takes "x" cycles (10) to complete and that this is about the time to clear the busy flag. But they show multiple 80µs cycles so it's all bollocks unless that diagram relates to the couple of instructions that take 1.5ms to complete. but why the need to wait 2 display instruction cycles? if it's busy it's busy, that is the point of the flag, you check as often as you like one the data is latched, this is the only time you need to make sure you don't screw the timings and fail to assert the data.

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 12:02:50 am
content: The original hitachi driver datasheet:https://www.sparkfun.com/datasheets/LCD/HD44780.pdfdoes not seem to mention the delay for checking the busy flag. But they mention that for 4 bit operation 2 cycles are needed to check the busy flag.... So this delay may still be a thing but now it is unmentioned, so there is a particular clock cycle that is done one pulse at a time, then there is a delay between pulses, my what a flipping mess this looks like. Now I know why I really wanted the serial displays but they were all sold out.I take it no one knows if anyone ever wrote a library in C for these displays? you know one that can actually be understood with instructions?

author: MK14
author_rank: Super Contributor
timestamp: January 16, 2022, 12:03:31 am
content: Quote from: Simon on January 15, 2022, 11:47:41 pmYes, I agree (with way too many of your points in the full version of the post I said '<SNIP>' to save space, to list them all). Some of the timings do seem to be at a minimum, significantly confusing, or even ambiguous, the longer I think about it.It does look rather confusing (the datasheet), and makes me suspicious, that they did a rushed job, copy and pasted stuff from other sources (hence the strange references to 2MHz you speak of), and other issues.I wish they would properly name the multiple clock types (ones related to the E cycle transfers), and ones related to the internal clock (OSC1/2, F.ext etc). Then they could cause less confusion.

author: Bassman59
author_rank: Super Contributor
timestamp: January 16, 2022, 12:26:52 am
content: Quote from: Simon on January 16, 2022, 12:02:50 amThe problem is that the Hitachi chip was designed to interface to a processor that's no longer used. I don't think Hitachi even makes the chips any more. It's all clones. And it's inertia that keeps these things in production, even though driving them with a modern chip is a pain.And yeah, I wrote a C library to talk to them, for SiLabs 8-bit parts. Obviously that bit-bang can't be directly translated to an ARM.You mentioned that you were going to use a display with a serial interface, but those become impossible to find. I think there's a reason why you can still buy the parallel-interface parts ...

author: MK14
author_rank: Super Contributor
timestamp: January 16, 2022, 12:31:29 am
content: I tried googling for more explanations on the chip, for you. There is not much, but I did find this:https://electronics.stackexchange.com/questions/535092/programming-an-lcd-interface-with-a-st7066u

author: Bassman59
author_rank: Super Contributor
timestamp: January 16, 2022, 12:47:51 am
content: Quote from: MK14 on January 16, 2022, 12:31:29 amThe point made in a response to that post about reading the Busy flag is spot on.

author: ozcar
author_rank: Frequent Contributor
timestamp: January 16, 2022, 12:57:15 am
content: Quote from: Simon on January 15, 2022, 11:47:41 pmBesides the 80µs, which I agree is crazy, I suspect the 2MHz bus cycle claim may be correct, and it is the min cycle time that is bollocks. Probably should be 500ns, as it is for say KS0076.

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 09:02:32 am
content: Quote from: ozcar on January 16, 2022, 12:57:15 amThe problem I start to have here is how can the MPU bus be 2MHz when the display controller clock es always 270kHz or there abouts? I can only assume they are trying to say that the chip will tolerate the timings of 2MHz for the sake of other chips on the same bus but in fact if the 80µs is anything like true then unless you want to keep messing about with re-timing the clock cycle by cycle you may as well call it 6.25kHz, but if you have to run the clock at 6.25kHz then that's not 2MHz as nothing else will move any faster than the clock.

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 09:04:30 am
content: Quote from: Bassman59 on January 16, 2022, 12:26:52 amYes quite. I thought the time to write the parallel interface would be no worse than the hassle in dealing with getting serial stock. I think I need to look for serial stock and get it pre ordered.

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 09:15:44 am
content: Quote from: Bassman59 on January 16, 2022, 12:26:52 amYea I had a go with peter fleury's library having felt rather pleased with myself for adapting it to work on the new mega micro-controllers but arm is totally different and I would rather avoid the delays so it all needs running in an interrupt.I'm thinking that I I interrupt on the overflow of a counter, have a variable that represents the state I am currently in and therefore directs to the next stage I need to carry out. Yes quite the mess. If I do this rather than do actual PWM for the clock I can adjust the timings to suit. Speed is not really a goal here, as long as I can round robin the display fast enough and the main code will run in between that.

author: ozcar
author_rank: Frequent Contributor
timestamp: January 16, 2022, 10:13:53 am
content: Quote from: Simon on January 16, 2022, 09:02:32 amI'm not sure where the conflict is. Except for the case of reading the busy flag / address, it does not have to do anything at a 2MHz rate. It has only to latch the data (one or two chunks) and then has a leisurely 37µs to complete the operation (or way longer for some instructions).

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 10:25:02 am
content: there is not much of a conflict width the 2MHz, I just assume it is copy and pasted BS. The enable cycle is said to be at least 1.2µs, that is no more than 833kHz, that is the fastest thing going. Then there is this 80µs wait time but that does not have to affect the overall clock timing for the whole bus as it just means the MPU must not send the clock for 80µs after the data is latched. but still the abs top bus speed here is 833kHz. I will probably run on something like 6.25kHz anyway, even with it taking 2 cycles to put a character on the display that is 78 refreshes a second which is plenty.

author: ozcar
author_rank: Frequent Contributor
timestamp: January 16, 2022, 11:12:12 am
content: Quote from: Simon on January 16, 2022, 10:25:02 amI agree that the datasheet is full of BS, but I'm still inclined to believe the 2MHz could be correct. That is not out of line with the specifications for other similar chips. The 80µs delay before reading busy is total codswallop imo. I've never seen anything like that specified for similar chips. Also, a perfectly valid, and very common thing with these displays is to not bother with reading the busy flag at all, but to just delay for long enough for the instruction to complete. Which for this chip, would mean either you wait < 40µs (most instructions), or else wait 80µs and then read busy - why on earth would you choose the latter? As for the 1.2µs cycle time, not only is that out of line with the 2MHz claim, it also makes it the slowest chip of this nature that I've encountered.I'd be inclined to do as I usually do, and follow the original HD44780 timing specification, or if feeling adventurous, go for the 500ns cycle time.

author: Simon
author_rank: Unknown
timestamp: January 16, 2022, 01:35:25 pm
content: Well I will probe the one I have on an arduino board just so I know what definitely works. It's not a major issue but it's annoying. I would not provide data like this.