How to debug microcontrollers in the "real world"? - Page 1
Forum section: electronics / general

author: ksoviero
author_rank: Contributor
timestamp: July 21, 2020, 04:40:40 pm
content: I've been using Arduinos for a while now, but I want to start using AVRs directly without the "crutch" of Arduino.One of the issues I've run into is debugging my programs when programming them with an ISP. How does one get feedback when using an ISP, they don't have any kind of serial interface.For example, with Arduino, I'd just print stuff to the screen using the serial interface and that would give me visibility into what it's doing. How would I replicate that workflow with an ISP?Thanks!

author: Bassman59
author_rank: Super Contributor
timestamp: July 21, 2020, 04:46:29 pm
content: Quote from: ksoviero on July 21, 2020, 04:40:40 pmModern microcontrollers come with JTAG or SWD (for ARM) or C2 (for SiLabs micros) or other debug interfaces which connect to a debug pod which connects to your computer, and the computer runs a source-level debugger which allows setting breakpoints, watching registers and variables and all sorts of goodies.We used to use "print to terminal" back when that was all that was available.The biggest fail of Arduino is not exposing the micro's debug port.That said, I still toggle port pins in ISRs and monitor them on an oscilloscope.

author: Bassman59
author_rank: Super Contributor
timestamp: July 21, 2020, 04:48:00 pm
content: I still have scars from the Nohau 8051 bond-out pod emulator.

author: rstofer
author_rank: Super Contributor
timestamp: July 21, 2020, 05:32:11 pm
content: It's just the same as with the Arduino - except you have to do the work. There are two approaches: write all of your own code (I prefer to do this) or use avr-libc.Own code:First thing: Set up the clocks/dividers and then get the UART to send a character by writing the code for putchar(). Now write the code for puts() using putchar().Write some hex output functions that will send hex character strings for 32 bit, 16 bit, 8 bit and 4 bit entities, with or without the leading 0X. Now you have a way to send messages containing hex results of whatever you want along with strings.Now, open your copy of "The C Programming Language" (Kernighan and Ritchie), ANSI edition, and copy the code for reverse() and itoa(). Now you can display integer values in messages.While you're there, copy a bunch of string functions.I'm not sure but I think the ANSI edition has the same code as the original edition. In other words, the string functions don't use a heap and I don't want to implement a heap.Use avr-libc:https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.htmlThere is a bunch of interface code to write and it's much more complex than just rolling your own.

author: mikerj
author_rank: Super Contributor
timestamp: July 21, 2020, 05:40:17 pm
content: Get yourself an Atmel ICE and experience the power of proper source level debugging. By Arduino standards it might look expensive, but by professional debugger standards it's very cheap.A budget solution might be the ATmega328P Xplained board which has an integrated Atmeol Studio compatible debugger, though I've never used it.The dowside of these is the number of pins required on a device that already starts with relatively few pins.

author: SilverSolder
author_rank: Super Contributor
timestamp: July 21, 2020, 05:54:41 pm
content: Just write error free code - what's the problem?!?

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 21, 2020, 05:58:55 pm
content: Quote from: rstofer on July 21, 2020, 05:32:11 pmYou've just described debugging circa 1976. The world has moved on since then and now uses on-chip debugging aids like JTAG to do source-level debugging. This is the professional standard--every company I've worked for in the last 25 years has done it this way. Sure, there are still a few grizzled holdouts that insist on debugging by sprinkling printfs in their code, but that's not the norm.

author: rstofer
author_rank: Super Contributor
timestamp: July 21, 2020, 06:04:05 pm
content: Quote from: SilverSolder on July 21, 2020, 05:54:41 pmI came to that realization about 50 years ago when I was writing FORTRAN for the IBM 1130 and CDC 6400. If I didn't put bugs in my code, I wouldn't have to spend time digging bugs out of my code. Alas, it hasn't always worked out...

author: coppice
author_rank: Super Contributor
timestamp: July 21, 2020, 06:09:28 pm
content: Quote from: Sal Ammoniac on July 21, 2020, 05:58:55 pm25 years ago most devices had some form of JTAG for test purposes, but didn't offer debug through this. Certainly these days hardware debug is pretty much standard, and some kind of built in logic analysis is quite common, and should be used where possible. It doesn't displace things like printfs, though. Good debug strategies use a mix of approaches to debug at different levels.

author: TK
author_rank: Super Contributor
timestamp: July 21, 2020, 06:09:47 pm
content: You need a combination of HW debugging with a logic analyzer and oscilloscope and source level debugging with an ICE. If your project involves interrupts / timers, it is hard to rely only on an ICE. You can do single step execution but I did not find it to be friendly when you have external interrupts and timers.

author: ejeffrey
author_rank: Super Contributor
timestamp: July 21, 2020, 06:31:35 pm
content: Quote from: ksoviero on July 21, 2020, 04:40:40 pmI agree with most, get a source level debug interface working. That said if you have a spare serial port, definitely configure it as a logging output. Without the arduino libs you will need to spend a bit of effort to hook that up but it isn't too hard. I really like to have both whenever possible.ARM has some nice options to send a serial data stream over the debug interface which is nice and doesn't take up any of your pins. I don't know if AVR supports anything like that. ARM has at least 3 options: semi-hosting is slow and bloated but very flexible. SWO is fast and lightweight, but not widely supported. Segger has their RTT thing which is fast but proprietary. It also requires a dedicated memory buffer and can drop data.

author: MK14
author_rank: Super Contributor
timestamp: July 21, 2020, 06:41:15 pm
content: Quote from: SilverSolder on July 21, 2020, 05:54:41 pmEvery piece of software by me, has worked first time, and perfectly. (Honest).The problem I haven't solved, is why the original software specification, suddenly mysteriously (as if by magic), changes, as soon as I first run the software.E.g. I thought the software was suppose to do, this and that. But, the original spec changes to "It should produce 153 Compile errors. 107 Warnings", and when those are fixed it should crash and produce no output, in such a way that it takes many hours to figure out why.

author: rstofer
author_rank: Super Contributor
timestamp: July 21, 2020, 07:04:11 pm
content: Here is the collection of functions I described above. This was for an ARM project I did several years ago but the idea still works. Get the uC sending stuff to the serial port and bury debugging statements throughout the code. I don't really like single stepping even with a really nice source level debugger. It just doesn't seem productive.I can surround the debug statements with #ifdef DEBUG ... #endif as I wish. I can bury the equivalent of ASSERT statements within the #ifdef DEBUG ... #endif block. I can turn DEBUG off and things should work well without the annoying output.

author: SilverSolder
author_rank: Super Contributor
timestamp: July 21, 2020, 07:05:47 pm
content: Quote from: rstofer on July 21, 2020, 07:04:11 pmSingle stepping is OK for assembler, but only occasionally useful with higher level languages, in my experience.

author: ksoviero
author_rank: Contributor
timestamp: July 21, 2020, 07:17:59 pm
content: Quote from: mikerj on July 21, 2020, 05:40:17 pmAre you referring to this?https://www.digikey.com/product-detail/en/microchip-technology/ATATMEL-ICE/ATATMEL-ICE-ND/4753379

author: TK
author_rank: Super Contributor
timestamp: July 21, 2020, 07:27:14 pm
content: Quote from: ksoviero on July 21, 2020, 07:17:59 pmThere are cheaper options like buying only the PCB if you can make 1.27mm pitch to 2.54mm header cables. It is called Atmel ICE PCBA or they also have a Basic option that comes with the case but not many adapters, only the basic cable

author: ksoviero
author_rank: Contributor
timestamp: July 21, 2020, 07:28:22 pm
content: Quote from: TK on July 21, 2020, 07:27:14 pmOh, I don't mind spending money. $140 is nothing in the grand scheme of things. Especially in this hobby. I was just making sure that was the right one.

author: mikerj
author_rank: Super Contributor
timestamp: July 21, 2020, 07:38:09 pm
content: That's the correct one. It will also work with the SAM 32 bit ARM Cortex parts when you decide you need a bit more horsepower.Quote from: SilverSolder on July 21, 2020, 07:05:47 pmBeing able to single step through source is invaluable IMO.

author: tggzzz
author_rank: Super Contributor
timestamp: July 21, 2020, 08:02:07 pm
content: Quote from: Sal Ammoniac on July 21, 2020, 05:58:55 pmWhen I came back to embedded programming 5 years ago, I was horrified and delighted about now quickly I picked it up at again.1982: 8 bit micros with ADCs and DACs, C, cross compilation plus download and run, in circuit emulators (breakpoints, single stepping same as JTAG). The only significant difference is that back then the tools would have cost a years salary!But the key point is to learn to use whatever tools are available. Printf or waggle an I/o pin are always available, and are one of the tools in a toolbox.

author: ksoviero
author_rank: Contributor
timestamp: July 21, 2020, 08:11:01 pm
content: Quote from: tggzzz on July 21, 2020, 08:02:07 pmTiny bit confused: How is printf "always available"? Don't you need serial or something set up to be able to see the output?

author: rstofer
author_rank: Super Contributor
timestamp: July 21, 2020, 08:18:49 pm
content: Quote from: Sal Ammoniac on July 21, 2020, 05:58:55 pm1976 is precisely when I started debugging 8080/8085 systems with either the front panel toggle switches or the Digital Research DDT debugger. Prior to that I got core dumps on the 1130 - that was truly ugly. I don't recall the details but the IBM 1130 had a TRACE option for FORTRAN - you could get a printout of the branches. That was kind of handy with 3 way branches (-, 0, +). Next time I'm playing with the machine (my FPGA incantation), I'll have to look into how tracing worked. It's been about 48 years and my memory is fading fast.I've used source level JTAG debugging although I will admit that I prefer the Rowley toolchain and dongle to anything where I have to try to configure OpenOCD myself. I haven't messed with it much in the last several years but I NEVER had any success getting it to work. Not EVER!Maybe that's why I gave up on JTAG debugging - I simply couldn't get it to work. UART output ALWAYS works (as long as I have a couple of pins). I don't have to worry about gdb compatibility, I don't have to mess with Eclipse integration, I can just dump some print statements here and there and trace the changes in critical values.The new boards, like the STM32 devices, have very nice debugging capabilities. The online mbed toolchain has none - back to printf(). Toggling an LED (which I can capture on a scope) or dumping text crumbs works well if the other methods fail.It's best to have an assortment of tools.

author: tggzzz
author_rank: Super Contributor
timestamp: July 21, 2020, 08:26:01 pm
content: Quote from: ksoviero on July 21, 2020, 08:11:01 pmThat is one way. It is easy to create a 1-pin UART using bit banging, if a real one isn't available.There are variants, if you think about it. One is to create a formatted string in the target memory, then stop on breakpoint after the string is created. Or create an in-memory log, and write very terse messages there.All you do is a little research into whatever techniques other people are using in the environment. Then apply imagnation to make best to see of them.

author: MK14
author_rank: Super Contributor
timestamp: July 21, 2020, 08:31:00 pm
content: Quote from: ksoviero on July 21, 2020, 08:11:01 pmYou're right. You do indeed need serial or something, to be able to see the output.In extreme circumstances (no other equipment available, and mcu doesn't even have any serial capabilities), you can bit-bang (i.e. write software which turns the port pins on and off, as if you had a proper serial capability), and then read it with an oscilloscope or some kind of serial adaptor.The printf method, is useful, up to around 90% of time, depending on programmers experience level. But, 10% or more, the bug(s), can easily make that method very inefficient. Especially when the software mysteriously crashes, in random places, or seems to have weird data corruption etc.You are likely to learn far more, if you can see the source code, running. Line by line, and be able to examine ram (variables), to see what values they have. Not to mention the hardware I/O registers and things, which can easily get confusing.E.g. You setup the PWM to output a 2 KHz signal, and nothing happens.Why ?Being able to see the registers getting the right values, and checking/watching the software, helps narrow down, what has gone wrong.

author: nctnico
author_rank: Super Contributor
timestamp: July 21, 2020, 09:01:10 pm
content: Quote from: MK14 on July 21, 2020, 08:31:00 pmThe latter can easily be implemented by having a 'mem' command together with a command line interface.Stepping through code sounds nice but for realtime processes (like on a microcontroller) it runs out of steam quickly. What I have been doing for the past 20 years:- have a command line interface on a UART- have status commands which shows stuff like character received, number of interrupts- if available, implement hard fault handlers and make these print a stack dump- add extra commands to query status or dump memories (think about an eeprom for example; how can you be sure the correct data is written to it?)- write complicated routines on a PC first + use a test bench to verify- allow to dump measured and status data in CSV format for analysisOnce you have a basic command line interface going you have a very simple eco system which is portable as well. There are debuggers which allow to read variables realtime over JTAG/SWD but these aren't very cheap. And they won't do you any good solving problems in the field. If you have a problem in the field (IOW: a board mounted somewhere in a machine far away from you) you can ask a field engineer to connect to the serial port and query the status of the device or just dump data.

author: MK14
author_rank: Super Contributor
timestamp: July 21, 2020, 09:19:10 pm
content: Quote from: nctnico on July 21, 2020, 09:01:10 pmThat sounds like a very good way, as well!Some people, actually implement, what amounts to small/light resource scripting/interpretive languages, such as tcl, lua or Forth etc. Allowing quick examination of memory (like you described), or even running small scripts, to check out I/O functionality.But, there are (thankfully rare), highly complicated bugs, which can be very difficult, without the right debugging equipment.But, yes. You are right. Once you are experienced enough at this, a full/proper debugger, is only very rarely needed.Your method, as described, can even handle most or even all, of what I just said, as well. if done well enough.But, if it was a very big and important project. I would still like to see proper debugging equipment used, where possible. But, as you say, it sometimes isn't possible or practicable.E.g. A remote controlled, model boat project, where it will be in the water, 50 metres away, sailing at speed, when you are trying to debug the software. A 50 metre long ribbon-cable, would probably sink the boat, and collide with other lake users.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 21, 2020, 09:22:43 pm
content: Quote from: rstofer on July 21, 2020, 08:18:49 pmI also use Rowley and itjust works. Every time. OpenOCD, on the other hand, is a piece of shit "solution" for guys too cheap to spring for something like a J-Link.

author: tggzzz
author_rank: Super Contributor
timestamp: July 21, 2020, 10:22:17 pm
content: Quote from: nctnico on July 21, 2020, 09:01:10 pmPleasingly, the last time I had to do that, there werezeroproblems with the USB comms altering the hard realtime behaviour. The time critical processes still took exactly the same number of clock cycles, with/without logging.I'm surprised d nobody has mentioned the other standard technique: output the minimum possible information on i/o pins, and connect those to a logic analyser for triggering and capture.

author: brucehoult
author_rank: Super Contributor
timestamp: July 21, 2020, 10:47:28 pm
content: Quote from: ksoviero on July 21, 2020, 04:40:40 pm(I've read the rest of the thread)There is pretty much always a way to make a serial interface, or write the same information to a network port or memory card or even RAM if you've got a lot of it.Printf messages with ms-level or better timestamps are a fantastic resource for debugging problems, especially in a multi-threaded program or one that communicates with other devices in real-time.I see interactive debuggers as useful in only two circumstances:1) beginners who don't understand how their programming language works and/or write code with a bug every few lines of code.2) if recompiling and linking your program (and downloading it to the device, if necessary) and setting up the test conditions take an extremely long timeOne of the best things about message logs is that you can write programs (typically in perl or python or so) to analyze them and find patterns that represent your bug.Even the slowest microcontroller now executes around 10 million instructions per second. Some are around a billion instructions per second e.g. NXP iMXRT1062, the Cortex M7 chip in the $20 Teensy 4. If you're single-stepping through code manually you're wasting your life.

author: Bassman59
author_rank: Super Contributor
timestamp: July 21, 2020, 11:36:06 pm
content: Quote from: brucehoult on July 21, 2020, 10:47:28 pmYou forgot #3: Using a third-party or vendor-provided library with inadequate documentation and you're trying to figure out where in that code everything went to hell.

author: Bassman59
author_rank: Super Contributor
timestamp: July 21, 2020, 11:39:56 pm
content: Quote from: ksoviero on July 21, 2020, 07:17:59 pmI have that exact debug pod. It is actually two pods in one -- one port is for AVRs and the other is for the SAM ARM devices. I bought it to use with the latter.It has sat in the closet for too long so if you want to buy it, it's for sale.

author: SilverSolder
author_rank: Super Contributor
timestamp: July 22, 2020, 12:48:50 am
content: Quote from: mikerj on July 21, 2020, 07:38:09 pmI guess it depends on the kinds of errors we like to make!

author: SilverSolder
author_rank: Super Contributor
timestamp: July 22, 2020, 12:57:36 am
content: Quote from: tggzzz on July 21, 2020, 10:22:17 pmOr even a MSO. You can do a lot with e.g. 4 bits, and you can set up triggers on the scope to catch interesting stuff (illegal states or whatever).

author: tggzzz
author_rank: Super Contributor
timestamp: July 22, 2020, 07:24:25 am
content: Quote from: SilverSolder on July 22, 2020, 12:57:36 amYup, or even just a voltmeter, e.g. for measuring the average cpu utilisation.You use the tools at hand, with the attitude in the aphorism in my .sig

author: GeorgeOfTheJungle
author_rank: Super Contributor
timestamp: July 22, 2020, 08:46:58 am
content: Quote from: SilverSolder on July 22, 2020, 12:57:36 amAnd today's scopes can also trigger on serial data.

author: brucehoult
author_rank: Super Contributor
timestamp: July 22, 2020, 09:05:56 am
content: Quote from: tggzzz on July 22, 2020, 07:24:25 amYou might understand if I say I'm one of the few who enjoys a PW5 as much as a DG1000 ... for different reasons.

author: tggzzz
author_rank: Super Contributor
timestamp: July 22, 2020, 09:31:27 am
content: Quote from: brucehoult on July 22, 2020, 09:05:56 amThe nearest I've been in are a PW6 and DG505. I've also had fun in ASK8/13, and Pilatus B4

author: brucehoult
author_rank: Super Contributor
timestamp: July 22, 2020, 09:54:31 am
content: Quote from: tggzzz on July 22, 2020, 09:31:27 amThat's pretty darn near. You've got to look pretty closely to tell a 505 and 1000 apart -- the more so from in the cockpit. And of course the PW6 is the ideal trainer to transition people quickly to the PW5. At my club we do 5 solo in the DG1000 before the PW5, but I think from PW6 you could sensibly do it after just one or two.

author: mikerj
author_rank: Super Contributor
timestamp: July 22, 2020, 10:16:19 am
content: Quote from: SilverSolder on July 22, 2020, 12:48:50 amMy preference appears to be of the hard to find variety! Not only do I find stepping useful, the ability to move the execution point back and repeat something (e.g. after changing a variable via the watch window) is extremely handy, though needs to be treated with some care.My favourite tool for realtime debugging is Segger's RTT, a very fast semihosting solution that works really well for high speed data logging.

author: SilverSolder
author_rank: Super Contributor
timestamp: July 22, 2020, 11:20:44 am
content: Quote from: GeorgeOfTheJungle on July 22, 2020, 08:46:58 amYes. Flapping a few pins is handy where you don't have serial and can't be bothered to implement it just to show the status of a couple of flags or something like that. It is also faster than serial, when that matters!

author: SilverSolder
author_rank: Super Contributor
timestamp: July 22, 2020, 11:24:25 am
content: Quote from: mikerj on July 22, 2020, 10:16:19 amI agree that it is sometimes useful, but as applications get more complex it gets less useful. E.g. a multi threaded PC application. Having a separate console window hanging off your application during development (conceptually, similar to a serial port on a mcu) is often the fastest/simplest/easiest path back from orbit to a safe landing!

author: GeorgeOfTheJungle
author_rank: Super Contributor
timestamp: July 22, 2020, 01:34:32 pm
content: Quote from: SilverSolder on July 22, 2020, 11:20:44 amI use to send single chars, "a" or "b" etc, to signal the points in the code. It's cool that with nowadays scopes, you can set it to trigger on specific chars.

author: SilverSolder
author_rank: Super Contributor
timestamp: July 22, 2020, 01:56:25 pm
content: Quote from: GeorgeOfTheJungle on July 22, 2020, 01:34:32 pmThat is a very cool idea - and of course it would be synced with whatever else you are feeding the scope. I'll try that!

author: TK
author_rank: Super Contributor
timestamp: July 22, 2020, 03:50:13 pm
content: Quote from: SilverSolder on July 22, 2020, 01:56:25 pmmake sure the scope has the latest firmware. Siglent SDS1104x-e had a bug I reported that it could trigger on the character you indicated. Just a tip so you dont waste time wondering what is wrong with your project when the bug is in the scope

author: snarkysparky
author_rank: Frequent Contributor
timestamp: July 22, 2020, 05:47:44 pm
content: I put a variant of this code in all projects for sending 16 bit words to the scope.This is the pic version

author: Bassman59
author_rank: Super Contributor
timestamp: July 22, 2020, 05:58:45 pm
content: Quote from: GeorgeOfTheJungle on July 22, 2020, 01:34:32 pmIf there's a spare SPI port available, use that -- a 25 MHz SPI port beats a 115,200 bps UART!And yeah, I've used the trick of sending an obvious printable ASCII character over a UART for specific events. It's a great way to have a log of events to see if one got missed. (A FIFO in front of the transmitter is helpful.)

author: nctnico
author_rank: Super Contributor
timestamp: July 22, 2020, 07:51:02 pm
content: Quote from: tggzzz on July 21, 2020, 10:22:17 pmI forgot to mention that; I'm using that trick as well to see if interrupts behave the way they should and do some profiling as well just to make sure.But sometimes you just need to byte the bullet and get some insight on what a CPU is actually doing. And in that case a debugger (or logic analyser connected to the address/data bus) is the only way to get that information. For me those cases are extremely rare though.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: July 22, 2020, 10:29:33 pm
content: I've been tinkering with uC's as a hobby from before arduino existed. Back then there were no "real debuggers for uC's, at least no affordable ones, and the uC I used did not have any debugging facility.C is a portable language, and I debug all "general" functions on a PC, such as for example, a CRC calculation function, and sometimes use single stepping, watches, etc there.For debugging timing sensitive stuff on a Microcontroller I use single byte serial output (can be any spare peripheral), and wrote a few lines of code as a debugging "library". I just started experimenting with a "Blue Pill", which does (or should, clones...) have a "real" debug port, but I have not used it yet.With the snippet below I can quickly turn my debug code on or off. The great thing about sending single bytes to a Uart (or other spare peripheral) is that it only takes 1 or 2 asm instructions to write a constant to the uart data registers. ( STM32F103C8T6 has 3 serial ports, so you're likely to have a spare port).Code://==================================================== DEBUG Lib Definitions.#if 1// Set to zero to disable debugging.#define BLUE_DEBUG_OUTPUT_ENABLE()(Debug_Enable_Func( ))/* The idea is to send hex data as execution markers. Which can be tracedwith a logic analyser.First nibble is function, second nibble is places in that function.So there is room for 16 functions, with 16 locations each.Extra meaning for Lowest nibble:'0' = function entry.'f' = return statement or fault.I put debug statements near the right margin.This has minimal influence on normal reading of source, while also making itvery obvious when looking for debug info.*/void Debug_Enable_Func( void) {/* USART3_TX = PB10 */gpio_set_mode( GPIOB, GPIO_MODE_OUTPUT_50_MHZ,GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART3_TX);rcc_periph_clock_enable( RCC_USART3);usart_set_baudrate(USART3, 2000000);// 2020-07-21 2M Seems highest for Blue Pill.usart_set_databits(USART3, 8);usart_set_stopbits(USART3, USART_STOPBITS_1);usart_set_mode(USART3, USART_MODE_TX);usart_set_parity(USART3, USART_PARITY_NONE);usart_set_flow_control( USART3, USART_FLOWCONTROL_NONE);usart_enable(USART3);_delay_us( 50);// Bug: 2020-07-19 Some func for waiting till uart is ready?}#define DEBUG( x)(USART3_DR = x)#define DEBUG_BLOCKING( x)(usart_send_blocking( USART3, (x)))#else// Debug off. Empty macro's.#define BLUE_DEBUG_OUTPUT_ENABLE()#define DEBUG(x)#define DEBUG_BLOCKING(x)#endifThis is the code snippet from one of the ISR routines. Note the "DEBUG()" statements near the right margin. They are easy to ignore when reading the normal code flow, yet easy to find if you need them. The DEBUG() statements for this ISR al start with 0x6... so I can very quickly see in the logic analyser which is what.Code://======================================== uC ISR definitions: Not for Linux.#if BLUE_PILLvoid Mumarnet_Tx_isr( void) {#elseISR (USART_UDRE_vect) {/* Uart Data Register Empty interrupt routine.Sends the Next byte of A Packet to the UART. If the last bye is put in UDRthis interrupt disables itself and enables the transmission complete interruptto clean up. *//* Disable 9-bit mode. STM32 does not buffer this, so has to be doneafter the first byte is send. ( 2nd byte is then already in shift register).*/MUMAR_8BIT_MODE;MUMAR_USART_DATA_REGISTER = *pTxd;DEBUG( 0x60);TxDBytes--;// A byte has been transmitted, so decrement...pTxd++;if( ! TxDBytes) {DEBUG( 0x61);// If the last byte has been send.MUMAR_TX_ISR_DISABLE;MUMAR_TX_COMPLETE_ISR_ENABLE;// Bug: Clear interrupt flag for txcie before enabling interrupt?}}Then for the actual debugging I use Sigrok / Pulseview together with a USD 7 LA from China.Here is a screenshot of a (fully debugged) sending of a packet.The Purple UART is RS485 data. Not it lines up perfectly with the blue "RS485" -enable trace. Below at "UART: RX warnings" you see an framing error on the first byte, this is on purpose to mark the first byte of the packet on the RS485 bus.The green "dbg" is the output from the debug trace. It does some special things just before the packet is send, and after that you see a small blob for each RS485 byte, (except the last). I've triggered on a rising edge of "RS485" (See yellow marker on the right and the vertical blue line) and used a pre trigger buffer of 10%.Then, when zoomed in near the end of the packet you see the the last 0x60 and a 0x61 debug output from the ISR above. Send out at 2Mbaud, and for the uC it's maybe 20ns of execution time. @ 2Mbaud the whole debug output (mostly handled by USART hardware) is output in less than a bit time of the 115k2 of the normal RS485 communication.Then at the end of the transmission, there is no debug output for the last byte, because of buffering in the uC. The 0x61 from the previous screenshot showed that another ISR was enabled. After the last stop bit is shifted out of the Uart for RS485, this ISR is triggered, and it turns off the blue "RS485" trace.Zoomed in even further, I used a measurement to show that the RS485 line is released 840ns after the stop bit has ended, and the 0x50 debug trace starts 2 Logic Analyser samples (@12MHz later).With this technique you can sprinkle around lots of debug info, and when there is something going wrong, you can zoom in with Pulseview to examine it closer. You can also extend it with more debug output on another trace of the logic analyser, which makes it easier to see "special" stuff happening on another trace when zoomed out.Sigrok / Pulseview is FOSS, and steadily improved. It already has more then 100 decoders, which are typically a few pages of python code, and are easy to extend or modify. You can get it at:https://sigrok.org/The cheap LA dongles from China have 8 channels and input protection (resistors and diodes)A generic CY7C68013A board works with up to 16 channels (at reduced sample rate), but these boards do not have input protection.I find this combination of FOSS software and USD7 hardware truly amazing. I do have a Rigol scope (DS1052E) but Pulseview works much better for debugging uC firmware. More channels, bigger screen with more pixels. And the mouse also works really convenient for working with Pulseview.

author: westfw
author_rank: Super Contributor
timestamp: July 23, 2020, 12:56:56 am
content: QuoteShort answer: first implement reliable serial functions, add a USB-Serial dongle, and do the same thing.QuoteThese days, I think I'd recommend a Microchip PICKit4, or maybe even a SNAP (the current cheap debugger.) Atmel ICE is getting old and doesn't seem to be in Microchip's vision of the future.In the short term, you might try one of the eval boards with built-in debugging, like an"Atmel Xplained Mini Atmega328p"(almost Arduino-Uno compatible, but cheaper.)QuoteA real debugger is swell, but there is a significant learning curve in figuring out how to use it effectively.Single-stepping is over-rated.The closest thing to Serial.print() debugging, without implementing serial, probably involves creating a "debugStop()" function, and then putting a "breakpoint" there with the debugger. Then, when you call that function the dbeugger will pop into a mode where you can look at variables, registers, etc. You can breakpoint on individual lines of code as well, but that's less "focussed" and can get confusing when optimization is taken into account. AVRs have a limited number of "hardware breakpoints" (0 on ATmega328), so breakpoints are implemented by re-writing program memory each time you insert or delete one.Other people have made arguments for still using serial debugging. Breakpoints and/or single stepping interfere with program timing in a significantly diffrent way than output to a high speed serial interface of some kind.You have more capabilities on newer processors (ARM, etc.)QuoteThey did say "AVR." UART will run up to 2 or 4MHz, SPI only up to 8MHz.All you folks saying that the OP will surely understand the greater power of a "real debugger" over "Arduino Prints", as soon as they get a debug probe ($100++), Oscilloscope ($300+), and maybe a logic analyzer ($100+++) are ... hilarious!"Real debuggers" are a useful tool for developing very low-level code, or figuring out compiler bugs, but pretty much all of the high-level program debugging I've ever done has been with "context-aware" explicit statements in the code itself. Something like:00:06:20: TCP0: bad seg from 172.21.9.11 -- Couldn't process packet in SYNSENT state.: seq 2817798823 ack 3578087592 rcvnxt 0 rcvwnd 8192is SO much easier to interpret than setting a breakpoint and gathering all that data by hand...

author: brucehoult
author_rank: Super Contributor
timestamp: July 23, 2020, 01:14:47 am
content: Quote from: westfw on July 23, 2020, 12:56:56 amExactly.Plus, you can leave generally useful ones in the code, commented if #ifdef'd out and enable them one by one or in related sets as needed.I also agree with using just one "debugBreak()" function and inserting calls to it as needed. It might have an actual hardware breakpoint in it, or it can have an explicit call/trap to the debugger -- or it can *be* the debugger if you want to build a little REPL into your code.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 23, 2020, 03:53:04 pm
content: There is no one-size-fits-all here, obviously. What works for one problem domain might be totally useless for another.Using prints in code that, for example, is processing a few network packets a second is one thing, but using the same technique to debug a context switcher that's switching context a thousand times a second is a non-starter. There are even cases where a low-level debugger isn't adequate and I need to use a trace tool that can do instruction trace in realtime.It's nice that these advanced tools are available, even if I don't need them very often.

author: rstofer
author_rank: Super Contributor
timestamp: July 23, 2020, 04:55:41 pm
content: Quote from: MK14 on July 21, 2020, 09:19:10 pmNow we're talking! Back in the early '80s, I did quite a bit of development with 8085s. The first EEPROM I would install would have the Intel Monitor which allowed for manipulating memory and branching to code. The next EEPROM would have a jazzed up version of Palo Alto Tiny Basic. I added a mem[] variable and a mem() function and now I could write higher level test programs to debug the peripheral gadgets.I haven't done that in years but it is still a viable approach when there is no file system to hold and load executable files.It is going to depend on the complexity of the system which approach makes sense. PATB worked for me, way back when. We have much better tools today (or at least they are finally affordable) so debugging is both easier and more necessary.FWIW, if you use a debugger, it just about has to have 'source level' capability. It is nearly impossible to figure out what the C compiler has done to your code, particularly if you have turned on any level of optimization. That's another hint: turn off optimization!When it comes to debugging code running under an RTOS, all bets are off in terms of hardware debuggers. In my opinion, you are back to printf(). Of course, you could create a debug task and have error messages posted to a queue. It could be quite elegant!None of which makes any sense for very small uCs.One of the neat new features of Xilinx Vivado is the ability to probe a running FPGA in real time using the Integrated Logic Analyzer. Finally, we can debug an operating FPGA! But all we get is traces, no commentary. I suppose that is the reason for simulation - another huge time sink!https://www.xilinx.com/products/intellectual-property/ila.html

author: 0db
author_rank: Frequent Contributor
timestamp: July 23, 2020, 05:24:06 pm
content: Quote from: rstofer on July 21, 2020, 06:04:05 pmError free code is ... an imagined state of things in which everything is perfect.Call it a "computer science" vision of Utopia.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 23, 2020, 05:46:35 pm
content: Quote from: rstofer on July 23, 2020, 04:55:41 pmI disagree. I debug code running under an RTOS all the time and use hardware debuggers routinely. It helps to have a debugger that's RTOS-aware (mine is).

author: 0db
author_rank: Frequent Contributor
timestamp: July 23, 2020, 06:04:47 pm
content: Quote from: Sal Ammoniac on July 23, 2020, 05:46:35 pmWhat do you use? On which MPU?

author: Siwastaja
author_rank: Super Contributor
timestamp: July 23, 2020, 06:22:13 pm
content: There is a grain of truth in that "do not produce bugs" ideas: single stepping algorithmic/logical microcontroller code through a debugger is a colossal waste of time. You can choose not to do this.State space in a microcontroller project tends to be quite small. If you have an algorithm, test it first on a PC, feeding every possible input and verifying every possible output. It's so much easier to do on a good development platform.But peripherals are the elephants in the room. 90% of the "debugging" I have to do on microcontrollers is somehow, directly or a bit more indirectly related tothe peripherals; they may be too complex, or poorly documented, or not conforming to the documentation, or I just made a mistake; in any case, I need to debug how the peripheral works, or how it interacts with my own program logic. Debugger has absolutely no idea about how to deal with this. And peripherals tend to be stupidly timing-sensitive, preventing testing with breakpoints or single-stepping. And, peripherals have funky design ideas like "a register is cleared / operation is acknowledged / interrupt is cleared / FIFO element is popped by reading a register", preventing the memory view in a debugger, or worse, using the debugger to see the memory seeminglyfixesthe bug, or causes another (possibly rare) bug, and so on...So I end up adding my own structures, in the code.The idea is not to directly and stupidly sprinkle the code with printf calls. That would perform equally poorly than attaching a debugger and stupidly looking at memory or stepping through code.Instead, recognise the parts of code that are timing-sensitive, and do not touch them. Recognise patterns that must go unchanged, i.e., reading peripheral registers where the read has side effects. Store the value you are interested in another temporary variable - this is a small and quick operation. Look at it at the debugger later - or printf() that later.Store minimum, average, maximum values. Create a trace; in a motor control / DC/DC current control loop ISR, store current_trace[trace_idx++] = value;, and after you have a long trace, then stop the thing and printf() it in a csv format. Write a Matlab/Octave/gnuplot/Excel/whatever script to automagically load that csv through UART and plot the current waveform you. No oscillosscope needed. But what's best, you canalso trace intermediate calculation values, things like how much the P, I, and D terms contribute separately at the current plant output.Use asserts() on microcontrollers, too. Roll your own assert: check values during run-time and write a simple error handler. Error handler can spew things out to a memory card, UART or whatever your application already has "on the field". If nothing else, it can blink an error code on an LED so if you didn't have your probe connected, you still know where you failed (after running for a month, for example)!I just had a team member put his phone next to the speaker on my design which was beeping the error code, so I could immediately see where it failed and come up with an explanation and workaround 100 kilometers away. This is because I wrote the logic of error detection and left it in place. Having to drive there with a debugger probe would have sucked.Add telemetry structures to your code. It's handy when the code fails unexpectedly,withoutdebugger cable being attached. You can now collect data on the field, as well.All of this is fairly simple to implement. It's more about the attitude. If you only have a hammer, everything looks like a nail. And if you only have a debug probe and an IDE...

author: ehughes
author_rank: Frequent Contributor
timestamp: July 23, 2020, 06:43:29 pm
content: QuoteSegger J-Link + Ozone.You can look at internal data structures, etc in real time with zero code to instrument anything. You can plot variables, etc as they change. The only penalty is the AHB accesses to the variable over SWD. That however is an order of magnitude less intrusive than the code needed to instrument and the printf's to get it out. If you buy the fast j-trace it is wicked fast and has long tracebuffers.You also get RTT. You can do your printf's there if you want. It is a of bringing things up even before you have UART, etc work. Everything happens over SWD or JTAG.I still use printf's as a debug console but that is for very high level configuration/monitoring.I just debugged a USB host issue. It would have been 10x more difficult to trace with printfs.That all being said, if you are debugging these low level issues in the field, they something is really wrong. Systems that require that level of debug generally have high price tags attached and you should have real time event logging, etc over standard interfaces (USB, ethernet, RS-485, etc).The debugger is most useful during initial board bring up and development. Once something is deployed in the world, you should have additional logging, etc to see what is going on if you really need it. That however is a different type of "debugging".QuoteNot true. Doing it right now with a J-Link and Ozone....

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 23, 2020, 09:38:52 pm
content: Quote from: 0db on July 23, 2020, 06:04:47 pmOzone on STM32F7.

author: brucehoult
author_rank: Super Contributor
timestamp: July 23, 2020, 10:11:53 pm
content: Quote from: Sal Ammoniac on July 23, 2020, 03:53:04 pm1000 times a second is absolutely fine. With reasonable message lengths that's only a few 10s of KB per second. Even us level logging can be doable on a mobile phone or PC with GHz CPU speeds and hundreds of MB/s (if not GB/s) bandwidth to the flash storage. Less on a microcontroller with 8 MHz or 48 MHz clock speed, obviously. If processing the printf starts to be a problem you can defer the formatting until analysis time and keep the format strings on the host and just send an ID for the format string plus the parameters in binary -- basically RPC, logging the arguments to the printf() not the results.You might also use a circular buffer for the log messages and only actually dump them when an error condition is detected.Modern hardware trace facilities are of course even better. With a compression scheme built into the trace hardware even logging the result of every instruction can take only a few bits on average, and simple control flow tracing can be under a bit per conditional or indirect branch. It's the moral equivalent of printf()s everywhere, and completely different to an interactive debugger.The key to printf() and trace is that you can log what happens around an event of interest without affecting the performance of the code significantly, and analyse it later at your leisure.

author: mikerj
author_rank: Super Contributor
timestamp: July 24, 2020, 08:44:08 am
content: Quote from: brucehoult on July 23, 2020, 10:11:53 pmTry this on a slow 8 bit micro and you likely wouldn't even have time to get the debug messages out, let alone any additional time to actualy execute the code you are trying to debug.

author: brucehoult
author_rank: Super Contributor
timestamp: July 24, 2020, 10:32:20 am
content: Quote from: mikerj on July 24, 2020, 08:44:08 amSure, it all depends on what CPU performance you've got -- and what I/O bandwidth. If you're pushing it then, as I said, don't do the actual printf() formatting, don't convert values to decimal, just dump an ID for the format string (its address if you want) and the arguments in binary. At most, convert them to hex. It's easy to take that (and a link map or hex file) on the host computer and format the debug messages there.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: July 24, 2020, 03:44:02 pm
content: Quote from: brucehoult on July 24, 2020, 10:32:20 amIf I needed to output lots of debug data in (semi) realtime, I wouldn't bother with a serial UART. I'd use something like Segger's RTT.https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/

author: westfw
author_rank: Super Contributor
timestamp: July 24, 2020, 11:14:30 pm
content: QuoteI am also amused by the way that people keep switching CPU categories to match their arguments:"My Cortex M7 with SWD, DWT, and fancy Segger probe with RTT ($600+) does neat things""Try doing YYY with a slow 8bit micro!"I am easily amused :-)It does highlight that "real" debuggers are NOT all the same. Neither are the chip debugging capabilities.I tend to think of most debuggers as "essentially similar", but I'mwrong. Most of the free debuggers seem to be pretty similar (Atmel Studio, MPLABX, gdb) - breakpoints, step-into, step-over, step-instruction, watch, examine... But I guess the high-end debuggers like Segger's Ozone or <visit any trade show> have more capabilities. You can just read the datasheet of a high-end ARM Cortex-M to see all of the debug features that (AFAIK) don't have much support in many of the debuggers. (Even the basic SWD capability includes a virtual UART-like comm path, for example.)OTOH The "Debugwire" protocol used on most AVRs is async serial based, and operates at speeds similar to the UARTs. The low-cost 32u4-based debuggers (like you get on an Xplained Mini) are relatively slow as CPUs, only support "full speed" USB, and are well-known to be "slow overall" (perhaps intentionally?) And the AVR debugging capabilities are pretty primitive and are also proprietary.Is there some sort of "debugger comparison" chart somewhere?

author: ADI8421
author_rank: Newbie
timestamp: July 24, 2020, 11:21:40 pm
content: I've always used Atmel Studio's single step Debug simulator if I needed to. If you know how to write code for starters, that's all you need.I started with a VIC20 computer and machine code programming in the 80s, with no chance of debugging then. You had to just write your code correctly or your program just wouldn't run. AVR micros and single step debugging is luxury !Most of your code is written for you in Arduino and has already had any bugs sorted out, I would hope. What more do you 'coders' want ?

author: nuclearcat
author_rank: Unknown
timestamp: July 24, 2020, 11:22:13 pm
content: If you are into opensource and ARM, try blackmagic probe.It is just GDB embedded to your mcu. Incredibly cool, if you are familiar with this tool.

author: brucehoult
author_rank: Super Contributor
timestamp: July 24, 2020, 11:36:03 pm
content: Quote from: ADI8421 on July 24, 2020, 11:21:40 pmIs it fair to say I started programming in the late 70s with the TI 57/58/59 and HP 67/97 ? They had a number of registers, conditionals, subroutines, and (except the TI57) pointers (aka indirect addressing) and therefore arrays, stacks, graphs. Pretty comparable to an ATTiny, PIC or 8051 in capacity, though a lot slower.The 6502 and Z80 in the Pet, Apple ][, and TRS-80 were a *huge* upgrade (and still in the 70s). By the time the VIC-20 came out I'd graduated to PDP-11 and VAX :-)

author: Siwastaja
author_rank: Super Contributor
timestamp: July 25, 2020, 06:32:57 am
content: Quote from: westfw on July 24, 2020, 11:14:30 pmYes, this easily becomes arms race. Worst, these tools tend to be vendor-specific, you have to learn to use many different tools, which are not available on another platform.This is why I presented generally applicable ideas and concepts above. They can be implemented on any CPU or MCU; obviously, on a more capable platform, you can do more, like collectlongertraces to the internal memory, or sprinkle more asserts without filling up program memory and wasting too many precious instruction cycles with the checks, but the principles are scalable.

author: tggzzz
author_rank: Super Contributor
timestamp: July 25, 2020, 07:14:29 am
content: Quote from: Siwastaja on July 25, 2020, 06:32:57 amJust so.Learning which buttons to press on this month's fashionable tool is not something that should be taught.Why not? The fundamentalsshouldbe taught because they last a lifetime. Once you understand the fundamentals, figuring out which buttons to press becomes a simple boring chore. And if there aren't any buttons available, you can (probably) still accomplish what you need to do.In this arena, distressingly little has changed in the past 40 years. In 1982 I was compiling and debugging embedded software on a unix host, then cross compiling it and downloading it to an 8-bit micro. There I could single step and set breakpoints using an in circuit emulator. The only differences are that now I use JTAG, and the cost of the tools is not a year's salary.

author: GeorgeOfTheJungle
author_rank: Super Contributor
timestamp: July 25, 2020, 07:31:35 am
content: Quote from: brucehoult on July 24, 2020, 11:36:03 pmAhhh yes, those were good times! I never had an hp67, but the 65 :-)

author: GeorgeOfTheJungle
author_rank: Super Contributor
timestamp: July 25, 2020, 07:39:29 am
content: Quote from: ADI8421 on July 24, 2020, 11:21:40 pmThe 6502 could single step with SYNC/RDY:http://wilsonminesco.com/6502primer/MysteryPins.html

author: westfw
author_rank: Super Contributor
timestamp: July 25, 2020, 08:04:45 am
content: QuoteTo be fair, early microprocessors (8080, Z80, 8086, 68000. Not sure about 6800/6502) were capable of doing pretty nice self-hosted debuggers with the "usual" features, and then when microcontrollers came along that became essentially impossible for quite a while. Your only choice was very expensive ICE boxes with special bond-out chips and similar hacks (or print/toggleTheLED/probeThePin debugging.)Early 8051s, PICs, and AVRs had essentially no "real" debugging capabilities.

author: tggzzz
author_rank: Super Contributor
timestamp: July 25, 2020, 08:39:13 am
content: Quote from: westfw on July 25, 2020, 08:04:45 amThe self-hosted debuggers relied on replacing instructions for breakpoints. In the 6800 the SWI one-byte software interrupt instruction was used to enter the debugger.I'm not sure if single stepping was possible in all debuggers. The two obvious techniques would be by forcing an NMI, or by inserting another SWI breakpoint after the current instruction - but that requires determining how many bytes there are in the current instruction.

author: brucehoult
author_rank: Super Contributor
timestamp: July 25, 2020, 10:01:10 am
content: Quote from: tggzzz on July 25, 2020, 08:39:13 amDetermining the number of bytes in an instruction on 6502 or 8080 is dead easy as that is completely determined by the first byte, so a 256 byte lookup table is sufficient -- and in fact this can be compressed by making it multi-level. z80 is a bit harder with the extra code pages for IX, IY, EXTD, BITS.Of course the technique of poking a BRK after the instruction works fine for code in RAM, but not in ROM.I believe some CPUs have had a "trap after instruction" bit in their status flags, in which case you can just set that in wherever interrupts save the status register and then do a return from interrupt to execute one instruction. Sadly, neither the Z80 nor the 6502 have that.Another technique that works for code in both RAM and ROM is to copy the next instruction into a temporary buffer, add a BRK after it, and then execute it (again using return from interrupt). The 6502 has instructions up to 3 bytes in length while the Z80 has a very small number of 4 byte instructions. So a 4 or 5 byte temporary area is sufficient.Conditional and unconditional branch/jump instructions need to be handled specially. In the case of a conditional branch you'd probably want to replace the offset with a constant value that points to a different BRK instruction so the debugger can tell which one was hit by examining the return address.

author: tggzzz
author_rank: Super Contributor
timestamp: July 25, 2020, 11:14:55 am
content: Quote from: brucehoult on July 25, 2020, 10:01:10 amYes. I was never a fan of the Z80 sparse instruction set, after having used a 6800. Never had the opportunity to use a 6809, unfortunately.QuoteThat rings a bell, but I never (knowingly) came across it.QuoteThe only advantage of that is that it would work with ROM.QuoteAnd at this point is is becoming messy, especially with short offset branch instructions (typically +-127 bytes). I never envied hardware engineers that had todo fixup-and-resume processing in hardware!

author: westfw
author_rank: Super Contributor
timestamp: July 25, 2020, 10:38:32 pm
content: Huh. I could swear that the 8080 an Z80 both had a single-step mode, where you'd set a status bit, and an interrupt would occur after each instruction (and the ISR would clear that bit on entry, and restore it on exit.)But looking at the data sheets now, it seems that I was wrong, and this didn't appear until the 8086.That sort-of completely invalidates my arguments about early self-hosted debuggers; I was counting on that feature! Hmmph.("Never mind.")The fact that many early microprocessors were very RAM-centric was helpful, though.

author: Renate
author_rank: Super Contributor
timestamp: July 29, 2020, 10:02:56 pm
content: Hello???Did anybody mention DGI, Data Gateway Interface?You're programming your AVR8 thing with ISP on an Atmel ICE interface with the 10 pin 0.050 to 6 pin 0.1 adapterIt's got that other interface, DGI.You have your code spit out SPI ASCII at 8 Mb/s or so.No separate connector, just the ribbon on the Atmel ICE.Code:atmelice atmega328p /e /p /v /b250 blinky.hex32768 flash, 1024 eeprom, 2048 ramLoaded blinky.hex0 - aebErase succeededProgram succeededVerify succeededdgimonHi, I am blinky coming to you over the SPI interface at 8Mb/sec!Hi, I am blinky coming to you over the SPI interface at 8Mb/sec!Hi, I am blinky coming to you over the SPI interface at 8Mb/sec!There is one fine point, you have to ground the /CS on the Atmel ICE.This pin is one of the 10, but not one of the 6, so it doesn't interfere with anything.

author: 0db
author_rank: Frequent Contributor
timestamp: July 30, 2020, 06:28:13 am
content: Quote from: tggzzz on July 25, 2020, 11:14:55 amThat's the typical Motorola 68k approach.

author: 0db
author_rank: Frequent Contributor
timestamp: July 30, 2020, 06:39:10 am
content: Quote from: Sal Ammoniac on July 24, 2020, 03:44:02 pmLike when you develop a sensors-fusion algorithm (IMU, for example) and you have fours sensors streaming data and you need to catch what's going wrong realtime.Sometimes you are just lucky and there is some trick.Like when I had to develop a seismic sensor, and since it was not practically possible, neither it made sense, to be install sensor on a rock face just to collect data streams, I chose to produce a kind of "synthetic" stream by sampling data on breaking some blocks of cement mortar.Then I used the "synthetic" stream to test my algorithm. And it also opened doors to the so called "equivalent time" testing.I was a student, no money for a DSO, LA ... and printfs and puts were just too slow. But not so slow in the "equivalent time" environment.

author: tggzzz
author_rank: Super Contributor
timestamp: July 30, 2020, 07:05:15 am
content: Quote from: 0db on July 30, 2020, 06:39:10 amSounds like a good example of the aphorism in my .sigIn a pure electronics environment, that attitude is essential when, for example, developing the world's fastest scope or highest precision DMM.

author: brucehoult
author_rank: Super Contributor
timestamp: July 30, 2020, 07:24:58 am
content: Quote from: tggzzz on July 30, 2020, 07:05:15 amFor those unfamiliar, here is what is meant by "span"See alsoLook ma! No engine!

author: tggzzz
author_rank: Super Contributor
timestamp: July 30, 2020, 08:16:13 am
content: You don't need to understand what "span" is in order to get the gist of the aphorism; "span" could have been replaced with "wirlbleator"I've been in an ASH25 twice. The first winch launch flight lasted 5 mins; the sky was less than cooperative. The second, 15 mins later, lasted a couple of hours and could have been longer.My favourite and short video showing span is of an ETA. Watch the wing bend!Or, more simply,But this is too far off topic for me to want to continue.