HDMI 4-Channel Oscilloscope Demo

I was really wanting to see how the scope modes would work to build a simple oscilloscope with trigger. The SCOPE smart pin modes put out 8-bit samples on every clock and perform triggering functions based on signal levels.

So, this little scope program uses the DDS/Goertzel circuit to generate simultaneous sine, triangle, sawtooth, and square wave patterns in an FM mode, so that the frequency wanders between 350KHz and 1MHz. These four DDS output pins can be wired to the scope inputs for stimulus by connecting the following pins together:

P48 and P52
P49 and P53
P50 and P54
P51 and P55

That will give the scope something to trigger off of and display. The scope inputs are:

P52 = channel 0, level-triggers for scope operation
P53 = channel 1
P54 = channel 2
P55 = channel 3

You must drive some signal into channel 0 to generate a trigger, in case you don't use the DDS outputs.

An HDMI monitor connects on P32..P39.

This scope shows four channel traces, sampled every 4th clock in parallel. They could be sampled on every clock, but not much changes in so short of a time. The traces have persistence, so old traces gently fade away as new ones are plotted. It's doing 120 triggers/plots per second, though the monitor refreshes at only 60Hz.

HDMI_Scope.jpg

There is an MP4 at the end of this post.

Here is the code. It's 172 longs:
'*************************************************
'*  Use DDS to demonstrate 4-Channel SCOPE mode  *
'*************************************************

CON		scp_base	= 52		'must be a multiple of 4, 1st pin is level-triggered input
		dds_base	= 48		'must be a multiple of 4, connect these pins to scop_base pins
		hdmi_base	= 32		'must be a multiple of 8

		trigger_level	= $90		'scope trigger level
		arm_level	= $70		'scope arm level
		scope_filter	= 0		'scope filter: 0 = 68-tap, 1 = 45-tap, 2 = 28-tap

		dds_freq	= 700_000.0	'nominal DDS frequency (without FM'ing)

		freq		= 250_000_000.0	'system clock frequency must be 250 MHz for HDMI

		buffer		= $1000		'sample buffer (4 KB)		
		bitmap		= buffer+$1000	'HDMI bitmap (300 KB)

DAT		org

                hubset  ##%1_000001_0000011000_1111_10_00       'config PLL, 20MHz/2*25*1 = 250MHz
                waitx   ##20_000_000 / 200                      'allow crystal+PLL 5ms to stabilize
                hubset  ##%1_000001_0000011000_1111_10_11       'switch to PLL

		setq	##($7FFFF - @end_of_pgm)/4		'clear hub RAM
		wrlong	#0,##@end_of_pgm

		coginit	#2,##@pgm_dds		'launch DDS
		coginit	#1,##@pgm_scp		'launch Scope
		coginit	#0,##@pgm_hdmi		'launch HDMI


'*********
'*  DDS  *
'*********

DAT		org

pgm_dds		cogid	x			'init DAC pins for this cog's DAC channels
		setnib	dacmode,x,#2
		wrpin	dacmode,#3<<6+dds_base
		dirh	#3<<6+dds_base

' Make sine/triangle/sawtooth/square patterns in LUT

		mov	z,#$1FF			'make 512-sample DDS table in LUT

.lut		shl	z,#32-9			'channel 0 = sine
		qrotate	#127,z
		shr	z,#32-9
		getqy	y

		mov	x,z			'channel 1 = triangle
		testb	x,#8	wc
	if_c	not	x
		xor	x,#$80
		setbyte	y,x,#1

		mov	x,z			'channel 2 = sawtooth
		shr	x,#1
		xor	x,#$80
		setbyte	y,x,#2

		setbyte	y,#$81,#3		'channel 3 = square
	if_c	setbyte	y,#$7F,#3

		wrlut	y,z			'write square:sawtooth:triangle:sine into LUT

		djnf	z,#.lut			'loop until 512 samples

' Output DDS patterns and slowly FM

		xcont	dds_d,dds_s		'issue perpetual DDS/Goertzel command

.loop		qrotate	##3_000_000,x		'slowly FM the signals
		getqy	y
		add	y,xfreq
		setxfrq	y
		add	x,#100
		jmp	#.loop

' Data

dacmode		long	%0000_0000_000_10110_00000000_01_00000_0		'DAC mode, cog DAC channels

xfreq		long	round(dds_freq/freq * 65536.0 * 32768.0)		'streamer frequency value

dds_d		long	%1111_1111_0000_0111<<16 + $FFFF			'DDS/Goertzel mode, continuous
dds_s		long	%0000_0000_000_000000000				'DDS/Goertzel mode, no input

x		res	1
y		res	1
z		res	1


'***********
'*  Scope  *
'***********
'
DAT		org

pgm_scp		wrpin	.scpmode,#3<<6+scp_base	'init ADC/scope pins
		wxpin	.scp_x,#3<<6+scp_base
		dirh	#3<<6+scp_base

		setscp	#1<<6 + scp_base	'enable scope channels

		setse1	#%001<<6 + scp_base	'set SE1 event to first scope pin trigger

		setxfrq	##$2000_0000		'set streamer NCO frequency to sample every 4th clock


' Capture waveforms before and after trigger

.loop		wrfast	#$1000/64,##buffer	'set wrfast to wrap 1k-sample circular buffer of 4 scope channels

		xinit	.scp_d,#0		'issue 4-ADC8 capture command

		waitx	##320*4			'allow time to fill first half of buffer

		akpin	#scp_base		'acknowledge trigger pin to clear
		pollse1				'clear any old trigger event
		akpin	#scp_base		'acknowledge trigger pin to clear
		waitse1				'wait for new trigger event

		getptr	.x			'capture write pointer, reflects trigger point

		waitx	##320*4			'allow time to fill second half of buffer

		xstop				'stop streamer, ~640 samples gathered within 1k sample buffer


		sub	.x,##320*4		'determine start of buffer so that trigger point is in the middle
		and	.x,##$0FFC
		or	.x,##buffer

		rdfast	#$1000/64,##buffer	'set rdfast to wrap 1k-sample buffer

.scan		getptr	.y			'advance to starting sample (320 samples before trigger)
		cmp	.y,.x	wz
	if_nz	rflong	.p
	if_nz	jmp	#.scan


' Dim existing pixels in bitmap

		loc	ptra,#bitmap
		mov	.y,#480

.dimline	setq2	#640/4-1		'read in 640 pixels
		rdlong	0,ptra

		mov	ptrb,#0

		rep	@.r,#640/4		'dim 640 rgbi8 pixels
		rdlut	.p,ptrb
		mov	.q,.p
		and	.q,.rgbmasks
		not	.p
		or	.p,.rgbmasks
		addpix	.p,.incbytes
		not	.p
		or	.p,.q
		wrlut	.p,ptrb++
.r
		setq2	#640/4-1		'write back 640 pixels
		wrlong	0,ptra++

		djnz	.y,#.dimline

' Plot waveforms

		mov	.x,#0

.xloop		rflong	.p			'get 4-channel sample

		mov	.q,#480			'plot channel 3 first

		rep	@.plot,#4		'ready to plot 4 channels
		getbyte	.y,.p,#3		'get sample
		shr	.y,#1			'divide by 2 to fit screen
		subr	.y,.q			'flip and vertically position
		mul	.y,.xsize		'get bitmap pixel address
		add	.y,.x
		add	.y,.bitmap
		wrbyte	.color,.y		'plot pixel
		shl	.p,#8			'ready next sample
		sub	.q,#117			'ready next vertical position
		ror	.color,#8		'ready next color
.plot
		incmod	.x,.xlimit	wc	'loop until all pixels plotted
	if_nc	jmp	#.xloop

' Plot trigger level marker

		mov	.y,.scp_x		'get trigger level
		shr	.y,#9
		subr	.y,#128
		mul	.y,.xsize
		add	.y,#320-9
		add	.y,.bitmap
		setq	#4-1
		wrlong	##$FFFFFFFF,.y		'white marker

' Toggle P56 for a speed indicator, then loop

		drvnot	#56

		jmp	#.loop			'loop

' Data

.scpmode	long	%0000_0000_000_100011_0000000_00_11010_0	'ADC/scope mode

.scp_d		long	%1111_0000_1000_0110<<16 + $FFFF		'DDS/Goertzel mode
.scp_x		long	(trigger_level & $FC)<<8 + (arm_level & $FC) + scope_filter
.rgbmasks	long	$E0E0E0E0
.incbytes	long	$01010101

.xlimit		long	640-1
.xsize		long	640
.bitmap		long	bitmap

.color		long	$5F_BF_DF_1F	'initial trace colors

.x		res	1
.y		res	1
.p		res	1
.q		res	1



'*********************************
'*  HDMI 640 x 480 x 8bpp rgbi8  *
'*********************************

DAT             org

pgm_hdmi        setcmod #$100                   'enable HDMI mode
                drvl    #7<<6 + hdmi_base       'enable HDMI pins
                wrpin   ##%111001<<8,#7<<6 + hdmi_base  'set 1.5k low drive on HDMI pins

                setxfrq ##$0CCCCCCC+1           'set streamer freq to 1/10th clk (25 MHz)

                rdfast  ##640*480/64,##bitmap   'set rdfast to wrap on 300KB bitmap

' Field loop

.field          mov     .hsync0,.sync_000       'vsync off
                mov     .hsync1,.sync_001

                callpa  #10,#.blank             'top blanks

                mov     .i,#480                 'set visible lines
.line           call    #.hsync                 'do horizontal sync
                xcont   .m_rf,#0                'do visible line
                djnz    .i,#.line               'another line?

                callpa  #33,#.blank             'bottom blanks

                mov     .hsync0,.sync_222       'vsync on
                mov     .hsync1,.sync_223

                callpa  #2,#.blank              'vertical sync blanks

                jmp     #.field                 'loop

' Subroutines

.blank          call    #.hsync                 'blank lines
                xcont   .m_vi,.hsync0
        _ret_   djnz    pa,#.blank

.hsync          xcont   .m_bs,.hsync0           'horizontal sync
                xzero   .m_sn,.hsync1
        _ret_   xcont   .m_bv,.hsync0

' Data

'.sync_000       long    %1101010100_1101010100_1101010100_10    '
'.sync_001       long    %1101010100_1101010100_0010101011_10    '        hsync
'.sync_222       long    %0101010100_0101010100_0101010100_10    'vsync
'.sync_223       long    %0101010100_0101010100_1010101011_10    'vsync + hsync

.sync_000       long    %1101010100_1101010100_1101010100_10    '
.sync_001       long    %1101010100_1101010100_0010101011_10    '        hsync
.sync_222       long    %1101010100_1101010100_0101010100_10    'vsync
.sync_223       long    %1101010100_1101010100_1010101011_10    'vsync + hsync

.m_bs           long    $70810000 + hdmi_base<<17 + 16          'before sync
.m_sn           long    $70810000 + hdmi_base<<17 + 96          'sync
.m_bv           long    $70810000 + hdmi_base<<17 + 48          'before visible
.m_vi           long    $70810000 + hdmi_base<<17 + 640         'visible
.m_rf           long    $B0830000 + hdmi_base<<17 + 640         'visible rfbyte luma8

.hsync0         res     1
.hsync1         res     1

.i		res	1


end_of_pgm
1024 x 576 - 161K
«1345

Comments

  • Uh, I don't think I have the willpower to follow how all that works.

    I've jumpered P48 to P52 to get the trigger operating, it is using 364 mA at 1.83 Volts on VDD.

    We have the vastness of the internet and yet billions of people decided to spend most of their time within a horribly designed, fake-news emporium of a website that sucks every possible piece of personal information out of you so it can sell it to others. And they see nothing wrong with that.
  • TonyB_TonyB_ Posts: 1,350
    edited 2019-11-25 - 14:46:04
    Thanks for the demo, Chip. 1080p60 & 1080p50 analogue could show all four channels full-scale. Is the step halfway up the sawtooth (high in screenshot, low in mp4) any cause for concern?

    EDIT:
    Low step is because mp4 is upside down and the step is actually a high point.
    Formerly known as TonyB
  • jmgjmg Posts: 14,149
    TonyB_ wrote: »
    Is the step halfway up the sawtooth (high in screenshot, low in mp4) any cause for concern?
    That does look strange, a bit like crosstalk to the square edges ?
    What is the bandwidth/rise time of the Analog here ?

  • TonyB_ wrote: »
    Thanks for the demo, Chip. 1080p60 & 1080p50 analogue could show all four channels full-scale. Is the step halfway up the sawtooth (high in screenshot, low in mp4) any cause for concern?

    1080p could show all those channels at full scale, but the P2 would need 2MB of hub RAM. Shy of that, we'd have to do some coding to get around needing so much RAM. We could not do persistence and get by with much less, at maybe two bits per pixel.

    Yes, that little ripple reveals that adjacent I/O pins capacitively couple into their neighbors' high-impedance ADC nodes. Next time we make a layout change, we need to put a ground cage around the ADC innards.
  • jmg wrote: »
    TonyB_ wrote: »
    Is the step halfway up the sawtooth (high in screenshot, low in mp4) any cause for concern?
    That does look strange, a bit like crosstalk to the square edges ?
    What is the bandwidth/rise time of the Analog here ?

    In the case of the sawtooth and square wave signals, it's a full 3.3 volt step in about 3ns.
  • This is really neat, Chip. Could be the start of a hardware product or an educational tutorial. I recently received a few e-mails from customers who were interested in a new version of the PropScope.

    Ken Gracey
  • Nicely done, Chip! I'll have to test this.

    Kind regards, Samuel Lourenço
  • samuell wrote: »
    Nicely done, Chip! I'll have to test this.

    Kind regards, Samuel Lourenço

    Thanks. I was always wondering how exactly to get the trigger into the center of the display. I realized that you need to gather at least half a screen of information, wait for a trigger, record the address it was writing to, and then load let it load another half screen of information. Then, your trigger is right in the middle of the screen every time.
  • cgraceycgracey Posts: 11,954
    edited 2019-11-23 - 21:54:58
    Looking at that bump on the long side of the sawtooth wave, it is curious that it spans the length of the square wave's filter transition, not the actual 3ns pin transition. How could that be?
  • samuellsamuell Posts: 517
    edited 2019-11-23 - 22:26:21
    Works a treat, Chip, although in my case the colors are different. My TV reports 640x480, and the current consumption averages 192mA for the whole board (I'm using a RevB, by the way).
    cgracey wrote: »
    Looking at that bump on the long side of the sawtooth wave, it is curious that it spans the length of the square wave's filter transition, not the actual 3ns pin transition. How could that be?
    That's crosstalk, definitely, and its outside the chip. This could be solved using controlled impedance and trace separation using ground planes. This looks like the effect of capacitive coupling between two adjacent traces on the board.

    Kind regards, Samuel Lourenço
    1024 x 768 - 106K
  • jmgjmg Posts: 14,149
    cgracey wrote: »
    Looking at that bump on the long side of the sawtooth wave, it is curious that it spans the length of the square wave's filter transition, not the actual 3ns pin transition. How could that be?

    If you space the ADC pins more, does that issue reduce ?
  • Just loaded and ran it. Very nice, Chip!

    I'll have to put in something different now into my demo. I had started a somewhat similar thing with a frequency shifting sine wave on the screen yesterday and was going to add some AM to it, but it was not taking any real pin data, purely synthetic. You went next level and used real IO data! Awesome.

    Having the built in scope mode is going to be very handy when working with real waveforms.



  • potatoheadpotatohead Posts: 9,922
    edited 2019-11-24 - 01:49:46
    We should pin a thread with the useful programs. Logic analyzer, scope... Having that much on board is going to be seriously attractive to some people. Might as well start on getting the word out.

    Do not taunt Happy Fun Ball! @opengeekorg ---> Be Excellent To One Another SKYPE = acuity_doug
  • We have the vastness of the internet and yet billions of people decided to spend most of their time within a horribly designed, fake-news emporium of a website that sucks every possible piece of personal information out of you so it can sell it to others. And they see nothing wrong with that.
  • samuell wrote: »
    Works a treat, Chip, although in my case the colors are different. My TV reports 640x480, and the current consumption averages 192mA for the whole board (I'm using a RevB, by the way).
    cgracey wrote: »
    Looking at that bump on the long side of the sawtooth wave, it is curious that it spans the length of the square wave's filter transition, not the actual 3ns pin transition. How could that be?
    That's crosstalk, definitely, and its outside the chip. This could be solved using controlled impedance and trace separation using ground planes. This looks like the effect of capacitive coupling between two adjacent traces on the board.

    Kind regards, Samuel Lourenço

    Your picture looks 10x better than mine. Yes, it does seem to be external, based on its duration. I think we do have small ground traces between signal traces on the inner layers. They are also sandwiched with power and ground. What I will do to determine if this is, indeed the case, is make one of the DACs 990 ohms, while leaving the others at 123 ohms. I will see if it gets pushed around even further. I am pretty sure you are right, that it is outside of the chip. Much better than having cross-talk problems inside the chip.
  • Try changing frequency of the DDS waveforms too. If its capacitive the effect will increase with frequency.

    Yes there were thin ground guard traces between the P2 signal traces last time I looked at the gerbers
  • roglohrogloh Posts: 1,689
    edited 2019-11-24 - 05:32:50
    Why is there a fairly slow slew rate for square/sawtooth waves? Is that some internal filtering/smoothing happening, or a limited analog bandwidth?
  • rogloh wrote: »
    Why is there a fairly slow slew rate for square/sawtooth waves? Is that some internal filtering/smoothing happening, or a limited analog bandwidth?

    I suspect that is related to what i'm experiencing with the hyperram timing too.
    Melbourne, Australia
  • What's weird is that the waveforms were recorded that way. When they are being shown on the monitor, they are not live, but exist in the data. Very strange that the duration of the bump is the duration of the filter transition, not the actual signal transition. Wait! That bump in the filter output could be an impulse making its way through the filter. That's got to be what it is. I can test this, somewhat, by tying a victim signal to ground and seeing how much coupling it receives from an aggressor. This phenomenon is limited to even/odd pin pairs which have no power/ground pads between them. It seems likely, after all, that there is some on-chip coupling between the high-impedance internal nodes of the ADC, and the big metal structure of the adjacent pin's raw signal. This can be fixed with better layout.
  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 08:09:55
    Indeed, we are getting coupling between all of the GIO, VIO, PINa, and PINb channels within the ADC. I now see what's causing it.

    The problem is that a common-centroid resistor array brings in all four signals before they go to selector switches which pick just one. By the time one is picked, it has noise in it coupled from the other three signals.

    This is going to be a problem which is not entirely solvable. If you want to measure just one dynamic signal precisely, you could bring it into two pins, an even/odd pair, and then not worry about crosstalk. Or, make sure the even/odd companion pin isn't changing during measurements. You could not, however, get rid of coupling between the GIO and VIO input channels and the incoming signal from the pin. So, GIO/VIO calibration is only reasonable if you have near-DC signals that are not very dynamic.

    To solve this, the resistor array needs to be redesigned to separate and not interleave resistor segments of different signals. Or, better, the switches need to be put BEFORE the resistor array, so nothing bad ever gets into the array, in the first place.

    This will take a layout change to fully remedy.

    I will post some pictures of the degree of crosstalk in the scope demo. I wish I would have simulated for this kind of problem. It would have been easily solved if I had known about it. It should have occurred to me.
  • Chip,
    Hindsight is wonderful. But you have done a splendid job in getting the P2 done!!!

    These things can be solved on the next variant (eg 4 cogs). Meanwhile, we will live with current issues, whatever they may be. There are no show-stoppers here.
    My Prop boards: P8XBlade2 , RamBlade , CpuBlade , TriBlade
    P1 Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
    Website: www.clusos.com
    P1: Tools (Index) , Emulators (Index) , ZiCog (Z80)
    P2: Tools & Code , Tricks & Traps
  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 08:18:08
    The worst case for GIO and VIO calibration coupling are both PINa and PINb receiving the same square wave. This is a double attack on GIO and VIO input channels:

    double_attack_GIO_calibration.jpg
    double_attack_VIO_calibration.jpg


    Here are two square waves incoming on an even/odd pin pair, coupling transitions onto eachother's flat spots:

    quadrature_attack.jpg

    These are all worst-case coupling scenarios.

    For audio-frequency signals, these couplings may be barely audible, but for high-speed signals, they are visually apparent.

    1139 x 735 - 135K
    1012 x 970 - 151K
    1127 x 850 - 132K
  • I spent a moment rearranging the four signals today. Things can be improved slightly by doing this
    I put square wave at the top,
    then sine wave,
    then sawtooth,
    then ramp

    I'm not convinced you can't pass the data through some kind of deconvolution to recover the original signals. What you're seeing is a matrix a bit like
    [ 0.9 0.1 0.0 0.0
    0.1 0.8 0.1 0.0
    0.0 0.1 0.8 0.1
    0.0 0.0 0.1 0.9 ] which gets multiplied by the 4 signals [A B C D]' to produce what we see. Only the coefficients may be frequency dependent if the effects are capacitive. If this is the case we could find the inverse matrix (model) that represents the coupling and apply that to approximate the original signals, at least improve them

    It struck me today just how impressive the scope mode actually is. If you have a 1 MHz input signal and want to plot 10 cycles of that on a 640 px wide display, you want about 60 samples per 1 MHz cycle, ie a tradition SAR ADC converter would want to sample at 60 Msps to achieve this. And here things are happening simultaneously on 4 channels. Its a great demo despite the crosstalk.


  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 09:21:58
    Tubular, thanks for thinking about this. I think, too, math could fix it.

    We need to calculate the differences between adjacent samples for each channel, and then subtract those differences from each other channel.

    PinA_delta = PinA_new - PinA_old
    PinB_delta = PinB_new - PinB_old

    PinA_final = PinA_new - PinB_delta * scale
    PinB_final = PinB_new - PinA_delta * scale

    I am going to try this now...
  • Yes thats a good starting point as its sensitive to rate of change (rise time etc)
  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 10:07:43
    I performed compensation as posited above.

    Here it is uncompensated, where the adjacent pin input attacks the primary pin input within an odd/even pin pair:

    quadrature_uncompensated.jpg


    Here it is with compensation applied. You can see that while it nulls out long transition effects, it needs to be offset by a sample or two, in order to register in time properly:

    quadrature_compensated.jpg


    This is good enough for a window-filtered oscilloscope display which is limited to 8 bits.
    719 x 428 - 61K
    805 x 436 - 73K
  • Nice that certainly helps

    Does it hold as you go up or down in frequency?
  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 11:11:46
    I applied the compensation two samples later and it now looks a lot better:

    delay_compensated.jpg


    The chip is running at 250MHz and the SCOPE channels are being captured every 2nd clock. So, a two-sample delay is a 4-clock delay, which at 250MHz is a 16ns delay. The deltas are computed from -20ns to -16ns relative to the sample at 0ns. The scale factor applied to the delta is 200/256 (0.78125).



    733 x 404 - 55K
  • cgraceycgracey Posts: 11,954
    edited 2019-11-25 - 11:48:05
    Here are the original four signals with delayed compensation:

    SCOPE_4ch_compensated.jpg

    This is sampled on every 4th clock. The deltas are computed from the 2nd and 3rd samples behind the current. Compensation scale factor is 100/256.

    916 x 535 - 113K
  • wow that really cleaned up nicely
Sign In or Register to comment.