Dual Trace Oscilloscope

86K664172

Intro: Dual Trace Oscilloscope

When I build my previous mini oscilloscope I wanted to see how well I could make my smallest ARM microcontroller a STM32F030 (F030) perform, and it did a nice job.

In one of the comments it was suggested that a "Blue Pill" with a STM32F103 (F103) might be better, smaller than the development board with the F030 and possibly even cheaper. But for the mini oscilloscope I did not use the development board but the F030 on an even smaller SMD-DIP board, so there a Blue Pill would certainly not be any smaller and I doubt that it would be cheaper too.

Code is now available on Gitlab:

https://gitlab.com/WilkoL/dual-trace-oscilloscope

STEP 1: Interleave or SImultaneous Mode

Blue Pill

But the idea was there, and I knew that the F103 has two ADCs! What if I used those two ADCs together in "interleave" mode, something I have done before with the STM32F407 (F407). The sampling speed would double. That, combine that with a faster microcontroller and it would make for a great successor to the mini oscilloscope.

Interleave mode
Oddly the ADCs in the F103 are less advanced than the one in the F030 (and the F407), you cannot choose the resolution. More important is that you also cannot change the timing between the two ADCs. Now, when you use the interleave mode usually you want the sampling as fast as possible with the shortest time between any samples, but with an oscilloscope it is neccessary to change the timing. Maybe it still can be done, I'm not a professional oscilloscope designer, but I dropped the plan to use interleave-mode.

Simultaneous mode

But, having two ADCs gives many more options, the two ADCs can be set to "regular-simultaneous" mode too. How about a dual trace-oscilloscope?

Having decided to try to make a dual trace oscilloscope I also wanted to have variable input sensitivity, an option that I did not have on the mini oscilloscope. That means an attenuator (and amplifier) on the inputs. And maybe I wanted even more? So I made a small list of "nice-to-haves".

WISH LIST

two channels

variable sensitivity on both channels

triggering on both channels

variable trigger level on both channels

variable offset

single battery power

fit in the same box as the mini-oscilloscope

STEP 2: Prototyping

As usual I started this projects on a breadboard. (See picture) And before soldering everything on the perfboard I try to find out if and how it will fit in the chosen project box. It fits, but only just. Some parts are hidden under the screen, other under the Blue Pill. And again, just as for most of my projects, this is a once-only project and I will not design a PCB for it.

STEP 3: Attenuators

In regular oscilloscopes the input attenuators are circuits that change attenuation and amplification by switching in and out resistors with small signal relays. While I have some of those relays, I know they will not switch at less than 4 Volt, that means that they will only work with a fully loaded Lithium Ion battery (4.2V). So I needed another way to switch those resistors. Of course I could just install mechanical switches, but that would certainly no longer fit in the project box in had in mind, perhaps I could try a better digital potentiometer again (the one I have is way too noisy).

Then I thought of "analog switches", with those I can make a digital potentiometer myself. In my parts collection I found the CD4066 with four analog switches. The idea is to make the feedback resistor of an opamp variable by switching in and out resistors parallel to the feedback resistor.

It works very well, but having just 4 switches in the 4066 and having 2 channels it was not possible to make more than three sensitivity levels. I chose 500mV, 1V and 2V per division as those are the voltage levels that I use most. The screen is divided into 6 divisions, so that makes for the ranges -1.5V to +1.5V, -3V to +3V and -6V to 6V.

With the "virtual-ground" you can move these ranges up and down so even 0v to +12V is possible.

STEP 4: Virtual Ground

Because the oscilloscope uses a single power rail (3.3V) the opamps need a virtual ground level or they will not work. This virtual ground level is made with PWM on one output channel of TIM4, the duty cycle of it changes from just a few percent to almost a hundred percent. A low pass filter with a 1k resistor and a 10uF capacitor transforms that into a voltage of (almost) 0V to (almost) 3.3V. The frequency of the squarewave is just under 100kHz, so the simple low pass filter is good enough.

Rather late in the building of this oscilloscope I realized that you cannot have two separate offsets for the channels. This is because of the fact that with a single power supply the input-ground-level has to be separate from the real ground level of the opamps. So both channels move in the same way as you change the GND-setting.

STEP 5: Rotary Encoders and Debugging

On the mini oscilloscope I used just one rotary encoder for all functions. That would make a dual oscilloscope very difficult to use, so here I need two. One encoder for the attenuators and virtual ground level and the other encoder for the timebase and triggering. Sadly, just as in my other project, these rotary encoders are very "noisy". They are so bad that they simply would not work with timers in "encoder-mode", the standard way of reading them. I had to make a debouncing mechanism with timer TIM2, checking the encoders every 100us. This timer in turn is started (only) when there is some activity on the encoders, this is checked with the EXTI functionality on the input ports. Now the encoders work well.

And as you can see, having a display can also be very handy to display debugging information.

STEP 6: Display and Timebase

The display has a resolution of 160 x 128 pixels so there are 160 samples needed for one screenfull, I managed to speed up the ADCs to do 1.6 million samples per second and that, with the much overclocked microcontroller (more on that later), gives a minimum timebase of 20us per division (100us per screen). Thus a waveform of 10kHz will fill the whole screen.

That is only twice as fast a the mini oscilloscope I made before. Oh well, now it is with two channels :-).

As said, the display is 160 pixels wide so only 160 values are needed per screen. But all buffers actually contain 320 samples. So the DMA stores 320 values before it triggers a transmission complete interrupt (TC). This is because the triggering is done in software. The sampling starts at a random moment, so it is very unlikely that the first value in the buffer is the place where the trigger point should be.

Therefore the trigger point is found by reading through the trace_x_buffer, if the value is at the wanted trigger value en if the previous value is just below it, the trigger_point is found. This works quite well, but you need a bigger buffer than the actual display size is.

This too is the reason that the refresh rate on the lower timebase settings is slower than you might expect. When you use the 200ms/div setting one screen full of data is 1 second, but because double the amount of conversions is done, that takes 2 seconds. On the faster timebase settings you will not notice it that much.

TIM3 is used to generate the timebase. It triggers the ADCs with the speed as required by the selected timebase setting. Its clock of TIM3 is 120MHz (see OVERCLOCKING), the maximum number to which it counts (ARR) determines how other it overflows or, in ST language it updates. Via TRGO these update pulses trigger the ADCs. The lowest frequency it generates is 160 Hz, the highest is 1.6MHz.

STEP 7: ADCs and DMA

The two ADCs convert the voltage on their inputs at the same time, they store those two 12 bit values in a single 32bit variable. So the DMA has just one variable per (double) conversion to transfer.

To use these values it is therefore necessary to split them into the two values so they can be used to display the two traces. As said, ADCs in the F103 cannot be set to other resolutions than 12 bits. They are always in 12 bit mode and so conversions always take the same number of clock pulses. Still, with the overclocking of the ADCs , 1.6 MSamples per second can be done (see Extra: Overclocking).

The reference of the ADCs is Vdd, the 3.3V rail. To convert that to more convenient values (per division) I have calculated the values of the attenuators, because I do not have the exact resistor values that come out of those calculations some corrections are done in software.

In this project I use DMA in "regular-mode". In this mode the DMA stops transferring data (from de ADCs to memory) when the number of words (or half-words or bytes) all are transferred. In the other possible mode, "circular mode" the DMA resets itself and continues transferring data un-interrupted. That did not work with the F103, it is so fast that it overwrites the data in the adc_buffer[] before the rest of the program could read it. So now the process is as follows:

- setup DMA to the number of data to be transferred and enable DMA

- start the triggering of the ADCs, these will request DMA transfers after each (double) conversion

- after the set number of conversions are transfered, DMA stops

- immediately also stop triggering of the ADCs

- do all manipulation needed on the data in memory

- show traces on the screen

- start the process again

STEP 8: User Interface

A 160 by 128 pixel screen isn't very big and I want to use as much of it as possible. So there is no part of it reserved for the currents settings. In the last few rows the vertical sensitivity, timebase, trigger level and trigger channel are displayed, but when the signals are big enough they will appear in the same area. The option that is active is shown in yellow, the rest is shown in white.

STEP 9: Building and Possible Improvements

I'm pretty happy about this project. It works fine and does the job, but it could be better.

The project box is too small to fit everything in comfortably, this results in having to put components under the Blue Pill. To make that possible the Blue Pill couldn't be soldered to the "main-board" directly. And because this made it all too high I had to remove many parts from the Blue Pill, such as the jumpers for selecting BOOT0 and BOOT1 (things I never use anyway) and I even had to move the crystal from the top to the bottom of the pcb.

I made life more difficult by using banana connectors instead of BNC or SMA connectors, it meant that a big part of the perfboard was a "no-go-area", to make that clear for myself I put kapton tape over it to prevent myself from putting parts on it.

Another problem with putting it all in such a small project box is that the analog and digital circuits are very close together. You can see that there is quite a lot of noise visible on both traces. This I did not even have on the breadboard! By moving the power lines for analog and digital circuits as far apart as possible a small improvement was made, but not enough for my liking. Reducing all resistor values in the analog circuits even further than I did (the input resistance is 100kOhm instead of 1MOhm) did not help. I suspect that triggering on the fastest timebase setting (20us/div), which isn't great, will also improve with less noise on the signals.

If you make this design on a "real" pcb, with all smd parts and separate layers for analog, digital and power (that's 4 layers!) it will probably work very well. It'll be much smaller, it will not use a complete Blue Pill but just the F103 and that will make it possible to supply it with a separate (clean) analog Vdda for the ADCs.

As a final touch I decided to spray the box black, it makes a change from all the beige boxes it have.

STEP 10: The Code and a Short Video


STEP 11: EXTRA: Overclocking

Just as I did with the F03, I wanted to see how well a F103 can be overclocked. The specifications for this microcontroller claim that the maximum clock speed should not exceed 72MHz (which of course is already faster than the F030) but I had read in several blogs that overclocking it was easy, so why not?

The Blue Pill is provided with an 8MHz crystal, the PLL multiplies that with a factor of 9 to 72MHz. The PLL can be increased up to 16 giving a clock of 128MHz. That was no problem at all for my Blue Pill, in fact, all my Blue Pills work without any problems on 128MHz.

But now I wanted to find out what the real limit is. So I removed the 8MHz crystal and replaced it with one of 12MHz. Again I increased the PLL multiplier until the microcontroller finally gave up. That was at 168MHz ! On 156MHz it still worked well. I left it running at that speed for hours and never saw it crash. In this oscilloscope I settled for 120MHz, a speed that can be selected with a 12MHz crystal and PLL on 10, as well as with an 8 MHz crystal and the PLL on 15. (see SystemClock_Config in main.c)

The ADCs now also work faster, I have them running at 30MHz (instead of 14), they were still working well on 60MHz, STMicroelectronics makes some nice hardware!

STMicroelectronics puts these limits in the datasheet for good reason, they guarantee that the microcontroller works at the specified 72MHz under all conditions.

But as I do not use the microcontroller at -40 Celsius, +85 Celsius, on just 2.0 Volt or 3.6 Volt I think it is safe to overclock it. Do NOT do this when you intent to sell a device with their microcontrollers, you never know where they will be used.

139 Comments

Hi WilkoL I have loaded the much over clocked firmware and it seems to be working fine but I want to build 2 of these into one box to give four channels and I have a resister devider of 100k with pull downs of 10 k and 1k through small mosfets for 10 and 100 times voltage and then using mc1458 op amps with 10k trim-pot on +input from vcc to ground for individual offset control and four switchable resistors for gain not sure exactly what values to go with but from say quarter to 4X gain using some spare adg201 switches one per channel so 4 ic's for both scopes my problem is not being able to figure out what is doing what through which variables pins and timers in your code I have successfully used these encoders I have in encoder mode but it looks like you are only using timer two for encoder debouncing and the rest is done through Gpio. I cant see how the variables are updating ie 'timebase' is set to 9 but can not see where it gets changed to other values as you can probably tell I am more familiar with arduino programing than cubemx and cubeide have been programing with serial adapters but my st-link arrived today keen to learn more what do you suggest ? I am also planning to use a third Mcu for swapping one of three encoders between the two scopes and controlling the input voltage divider directly from third Mcu, when both fet's are off there is no division so just high impedance input. Many thanks for this... Andy Nicholson.
Hi WilkoL. I have your well designed dual channel oscilloscope project working but noticed that you already may have published a new firmware hex file version. Therefore I also like to ask if it is also still for a 8MHz BluPill running circuit and what did you upgrade? Thanks!
Hi Albert, It was a request from Freddy in Costa Rica who at first tried to use a CH32F103 microcontroller that did not want to work at 120 MHz, so I recompiled the code for a lower frequency to see if that helped (it did). But because all the timings are dependent on the SystemClock I adapted all ratios for the TimeBase settings. That way the shown divisions are correct again with a SystemClock of 80 MHz. (and a 8 MHz crystal)

Good luck,
Wilko
Okay Thanks WilkoL. I asked because I got a question from someone who also had built your dual oscilloscope but ended up only getting a white lcd screen instead. And he asked what hex file I used and if I could share mine that works. Because he used the dual_trace_oscilloscope_freddy_80MHz.hex that didn't work. I am unsure what file I originally used. It was probably the ST7735_mini_oscilloscope.hex file but I noticed that you now shared a new file on gitlab being the new_hex_file.hex. So i'm still very confused what versions there are and what files to use when using the original BluPill board with 8MHz or the 12MHz quartz crystal?
Hi Albert, As I no longer have the Dual Trace Oscilloscope I do not know if I had the STM32F103 with a 8 MHz or 12 MHz crystal. But I do know that I built the dual_trace_oscilloscope_freddy_80MHz.hex file with a standard Blue Pill Board, thus with a 8 MHz crystal.

Because 80 MHz isn't so much more than the official maximum SystemClock speciafied by STMicroelectronics (72 MHz) that hex file should work with all Blue Pill boards.

The "new_hex_file.hex was uploaded because someone mentioned that he/she had problems with the original one. There were no changes made in the original code.

Unfortunately I do not remember the value of the crystal I used at that time, but when you load that hex file you will notice immediately that the timebase is wrong when you have the "wrong" crystal on the board.

Succes,
Wilko
Understood WilkoL. Many thanks for that now very clear explanation! Have a great week!
UPDATE: I just checked the 12 july 2020 version of the code (SVN). The crystal used at that time was a 8MHz one, the multiplier in the STM32F104 was 15 so it ran at 120 MHz SystemClock. Not every BluePill will still work at that frequency, esspecially when it isn't a genuineSTMicroelectronics one, but a clone....
Try the 80 MHz hex file, it uses the standard 8 MHz crystal.

Succes,
Wilko
Hi, what a good project I'm putting together and it will be ready soon but I have a big problem that I can't get the MCP6L92 I can't even get it to buy it that another one could be placed for operation
You can use any opamp that functions with a supply voltage of 3.3V that has a bandwidth of around 10 MHz. (If you are content with a slightly lower bandwidth even a 5 MHz one can be fine.)
I just checked Farnell (Europe) and they do not have the MCP6L92 in stock, but they do have the MCP6292E/P, MAX44242AUA, LMV722QDV and the MAX40077AUA in stock.

Succes,
Wilko
Buenas tardes Wilko, ya le cargue el, dual_trace_oscilloscope_freddy_80MHz.hex
y esta funcionando todo bien, muchs gracis por su ayuda, Freddy de Costa Rica.
saludos.
Good to hear, enjoy it.
buenas tardes Wilko muchas gracias propiamente no son los voltajes
disculpe que no especifique, porque si aumenta y baja el tamaño de la señal
es al variar funciones como separar los trazos no responde, voy a probar
otros encoder que tengo para ver si es que esta dañado ese, Freddy Costa Rica
gracias por ayudar, lo del control de tiempo espero paciente no hay problema gracias.
Hi Freddy, changing the timebase settings wasn't very difficult. So on Gitlab you can find the new dual_trace_oscilloscope_freddy_80MHz.hex hex-file. I tried it with a version of the oscilloscope build on breadboard and my (diy) pulse-generator, see picture.
Good luck!
Buenas noches Wilko, soy Freddy de Costa Rica, el archivo Freddy.hex si funciona,
pero el time/div y votl/div no hcen bien todas las funciones si me pede ayudar
se lo agrdesco mucho, con todo respeto, muchas gracias.
Looks good!

Now about your questions about the timing and voltages.

First of all there should not be anything wrong with the voltages as nothing was changed in the code that could cause that, but I'll look into it. It would help if you can tell me how the voltages are different from the real values.

That the timing is wrong was expected, the SystemClock of the microcontroller has changed (lower) and this SystemClock is used to display the traces at regular intervals. I can probably correct this without extra information from you.

But.... I do not have this oscilloscope anymore, I'll make one (very simple one) for checking the timing-values. That might take a while, so please be patient.

I will come back :-)

Wilko

Buenas noches Wilko estoy muy agradecido el archivo .hex funciono con el stm32f103c8t6 con los ch32f103c no funciona voy a probar los tiempos y las divisiones porque solo lo cargue el archivo y vi que salio el trazo,
mañana lo pruebo bien le envío un pequeño video saludos Freddy de Costa Rica
Buenas noches Wilkol aqui estoy de nuevo con ganas de hacer el osciloscopio
no e podido terminar compre ortro stm32f103c8t6 pero le meto el .hex y sale en blanco
con los CH32f103c sale solo el menu y lo mueve pero el trazo no hay manera
de verlo, le mando un pequeño video para que vea como sale.agradezco cualquIer
ayuda o consejo para ver si puedo terminar este proyecto soy freddy de Costa Rica saludos. video.
I watch the short video and I can see that you probably did everything right. The only thing I can imaging is that there is small difference between the CH32 and the STM32 microcontroller preventing the display of the trace. Very odd! Did you try changing the colour of the trace? So by changing it in the code and recompiling it? Perhaps, if you use another color it will show?!

Succes,
Wilko
Benas noches Wilko puede ser que cambiando el color funcione pero
yo estoy trabajando con el archivo ST7735_mini_osciloscope.hex
y no se como cambiar nada en un archivo hex atra cosa, quiro su ayuda
compre un stm32f103c8t6 le cargue el archivo .hex pero sale la pntalla en
blanco pienso que puede ser el cristal que es de 8mhz, que me aconseja
si instalar otro cristal, y de que valor 12mhz o 30mhz, quiero saber si eso
ayudara, como se carga el prgrama primero cambio el cristal y despues le
cargo el hex o viceversa me puede explicar por favor gracias, agradesco
mucho su respuesta vale mucho para mi porque en realidad quiero hacer
este osciloscopio hasta pronto amigo saludos, Freddy de Costa rica..
Hi Freddy,
Let's try something: I changed the SystemCoreClock at 80 MHz instead of 120 MHz, with a crystal of 8 MHz. Because of that the ADC's also have a reduced clock of 20 MHz instead of 30 MHz.

My guess now is that your STM32 might not work well at 120 MHz, remember that STMicroelectronics guarantees the working up to 72 MHz only. And the ADC's up to 14 MHz.
In the article on Instrucatables I said that I overclocked it a lot. Perhaps just too much for your STM32. So now all clocks are closer to the maximum specified and I wonder if it works with you now.

Unfortunately this also means that all values of the timebase no longer are correct. If this hex-file works with you I'll take another look at those values and will correct them.

The new hexfile can be found on https://gitlab.com/WilkoL/dual-trace-oscilloscope
and it is called : dual_trace_oscilloscope_freddy.hex

Good luck,
Wilko
More Comments