![]() |
Forum Index : Microcontroller and PC projects : Micromite: 7.5Msps 8-chan, logic analyser
Author | Message | ||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
Using the same basic approach as for the oscilloscope, I've written the guts of a 8-channel (6 channel on 28 and 44-pin parts) 7.5 million samples per second (3 million of 28 and 44-pin parts) logic analyser. The picture shows a capture of an SPI command "SPI write 2,&H55,&HAA" and is triggered on the negative going edge of CS. The example code allows labels for the channels to be assigned in a string array for display. As with the oscilloscope, the same code runs on all Micromite variants and supports both SSD1963 (800x480) and ILI9341 displays. Also as with the oscilloscope, I've created the guts of the application but it needs a GUI. There are two CSUBs that do the work: Subroutine "Capturelogic" captures 8 channels of data Parameters are: 1: Number of CPU ticks per sample; use function "tickspersample" to calculate this from the desired # of samples per second. This is calculated based on CPU speed but the higher the speed the faster you can sample It is rounded to be exactly divisible into the CPU speed and the actual speed reported It cannot be below 8 in order for the capture code to complete in time 2: Number of samples to take; this is also used to scale the integer array "buff", 8 samples are packed into each array element 3: Buffer to receive the data 4: Pin number used to trigger capture Set to zero to start immediately Set positive number to trigger on positive going edge on selected pin Set negative to trigger on negative going edge on selected pin The second CSUB is Drawlogic: Subroutine "Drawlogic" draws on the screen up to 8 traces Parameters are: 1: Start position in record (0-samples%) 2: Scaling to use Positive numbers cause the display to skip every "scale" records, i.e zoom out Negative numbers cause the display to repeat every "scale" record, i.e zoom in 3: Start position when last drawn: Use the same as "start position" for first time called Used to remove the previous display when scrolling or zooming in or out 4: scaling when last drawn: Use the same as "scaling" for first time called Used to remove the previous display when scrolling or zooming in or out 5: Channel mask : set bits to enable display of a particular channel 6: Number of samples in record; this is used to ensure the display does not try and read outside of the valid data 7: Buffer containing the data The second picture shows the same capture zoomed x2 and the start point scrolled Drawlogic is the key routine. This allows one data view to be replaced by another using the same dataset very quickly by first erasing the previous data and then replacing it with new. A GUI could allow zoom-in, zoom-out, jump to location, scroll left and right all of which are supported My Basic test program for the 44-pin Micromite (also tested on 64-pin)captures the data by triggering on pin 23 and then displays it zoomed x2 and continuously scrolling right to left: CPU 48 option explicit option default none const samples%=40000 dim labels$(7)=("CLK","DAT","CS","3","4","5","6","7") 'set labels for the 8 channels DIM samplespersecond%=750000 dim integer i,j,buff(samples%\8) ' ' The logic capture uses the first 8-pins on PORTB of the PIC ' These statements set up those pins as inputs depending on which chip is in use ' NB PortB4 is used for console TX on the MX170 micromites so is not set up ' Also: Remove any any pins you are using for other things ' if npins()=28 then 'valid pins for 28-pin part, NB channel 4 & 5 cannot be used as allocated to console and SPI setpin 4,DIN: SETPIN 5,DIN: SETPIN 6,DIN: SETPIN 7,DIN: SETPIN 15,DIN: setpin 16,DIN ENDIF if npins()=44 then 'valid pins for 44-pin part, NB channels 4 & 5 cannot be used as allocated to console and SPI setpin 21,DIN: SETPIN 22,DIN: SETPIN 23,DIN: SETPIN 24,DIN: SETPIN 42,DIN: setpin 43,DIN ENDIF if npins()=64 then 'valid pins for 64-pin part setpin 16,DIN: SETPIN 15,DIN: SETPIN 14,DIN: SETPIN 13,DIN: SETPIN 12,DIN: SETPIN 11,DIN: setpin 17,DIN: setpin 18,DIN ENDIF if npins()=100 then 'valid pins for 100-pin part setpin 25,DIN: SETPIN 24,DIN: SETPIN 23,DIN: SETPIN 22,DIN: SETPIN 21,DIN: SETPIN 20,DIN: setpin 26,DIN: setpin 27,DIN ENDIF ' pwm 2,1000,50 'required for my development board to control backlight on display ' FONT MM.VRES/240 'scale the font to the display in use ' colour rgb(white),rgb(blue) cls ' for i=0 to 7 text 0,MM.VRES/12+i*25*MM.VRES/240+2,labels$(i) 'annotate the rows next i ' for i=0 to MM.HRES step MM.HRES/20 'write some arbitrary graticule lines line i,0,i,MM.VRES-1,1,&H808080 next i ' ' Subroutine "Capturelogic" captures 8 channels of data ' ' Parameters are: ' Number of CPU ticks per sample; use function "tickspersample" to calculate this from the desired # of samples per second ' This is calculated based on CPU speed ' It is rounded to be exactly divisible into the CPU speed and the actual speed reported ' It cannot be below 8 in order for the capture code to complete in time ' Number of samples to take; this is also used to scale the array "buff", 8 samples are packed into each array element ' Buffer to receive the data ' Pin number used to trigger capture ' Set to zero to start immediately ' Set positive number to trigger on positive going edge on selected pin ' Set negative to trigger on negative going edge on selected pin ' Capturelogic(tickspersample%(samplespersecond%),samples%,buff(),-23) ' trigger on pin 23: must be valid pin for Micromite in use ' ' Subroutine "drawlogic" draws on the screen up to 8 traces ' ' Parameters are: ' Start position in record (0-samples%) ' Scaling to use ' Positive numbers cause the display to skip every "scale" records, i.e zoom out ' Negative numbers cause the display to repeat every "scale" record, i.e zoom in ' Start position when last drawn: Use the same as "start position" for first display ' Used to remove the previous display when zooming in or out ' scaling when last drawn: Use the same as "scaling" for first display ' Used to remove the previous display when zooming in or out ' Channel mask : set bits to enable display of a particular channel ' Number of samples in record; this is also used to ensure the display does not try and read outside of the valid data ' Buffer containing the data ' Drawlogic(0,-2,0,-2, &H7,samples%,buff()) 'first plot of the data zoomed in x2 from the first data point, channels 0,1,2 j=0:i=1 do drawlogic(i,-2,j,-2, &H7,samples%,buff()) 'scroll the display left 1 sample at a time i=i+1:j=j+1 loop end ' ' helper functions ' function tickspersample%(i%) const fastest%=8 tickspersample%=cpuspeed()\i%\2 if tickspersample%<fastest% then tickspersample%=fastest% PRINT "Setting maximum rate at this CPU speed of",cpuspeed()\tickspersample%," samples/second" ELSE if tickspersample%*i%*2<>cpuspeed() then print "Using a rate of",cpuspeed()\tickspersample%," samples/second" endif endif end function ' CSUB Capturelogic 00000000 8CE20000 27BDFFC8 AFB2001C AFB10018 AFB00014 AFBF0034 AFB70030 AFB6002C AFB50028 AFB40024 AFB30020 00A08021 00C08821 10400032 8C920000 0440004B 3C039D00 8C630028 0060F809 00402021 3C14BF88 3C030008 3C13BF88 AE831064 AE601068 3C03BF88 8C636120 24150001 0055A804 02A31824 1060000B 3C03BF88 3C179D00 3C16BF88 8EE20038 0040F809 00000000 8EC26120 02A21024 5440FFFB 8EE20038 3C03BF88 8C626120 02A21024 1040FFFD 00001021 40824800 8E030000 1C600019 02402021 8FBF0034 3C020008 AE821064 8FB70030 AE621068 8FB6002C 8FB50028 8FB40024 8FB30020 8FB2001C 8FB10018 8FB00014 03E00008 27BD0038 3C14BF88 3C13BF88 3C020008 AE821064 AE601068 00001021 40824800 8E030000 1860FFE9 02402021 00002821 10000002 3C07BF88 40024800 0044182A 1460FFFD 00000000 8CE66120 02251821 A0660000 8E030000 24A50001 00A3182A 1060FFDA 00922021 1000FFF5 0044182A 8C630028 0060F809 00022023 3C14BF88 3C030008 3C13BF88 AE831064 AE601068 3C03BF88 8C636120 24150001 0055A804 02A31824 1460000B 3C03BF88 3C179D00 3C16BF88 8EE20038 0040F809 00000000 8EC26120 02A21024 5040FFFB 8EE20038 3C03BF88 8C626120 02A21024 1440FFFD 00001021 1000FFCD 00000000 End CSUB ' CSUB Drawlogic 00000000 27BDFFA8 AFB50044 8CB50000 AFBE0050 AFB60048 AFBF0054 AFB7004C AFB40040 AFB3003C AFB20038 AFB10034 AFB00030 AFA5005C AFA70064 AFA40058 AFA60060 8FBE0068 8FA3006C 06A000A3 8CF60000 24020001 06C000A3 AFA2001C 24040001 AFA40020 AFA00018 3C029D00 8C420094 8FA80018 8C420000 24050001 1040007B 0105A004 00009821 00009021 00008021 10000049 3C119D00 8FA40020 8D660000 10800055 0266B821 8FA80060 8D040000 02443821 8C620000 02E2102A 50400038 8E220094 3C028888 34428889 00A20019 3C0BAAAA 00004010 356BAAAB 000841C2 00085140 000810C0 01421023 00481021 00AB0019 8FA80018 00004810 70485002 000948C2 10C4006C 01491021 8FAA0070 01473821 90E40000 00942024 10800045 8E240048 240500FF AFA50010 8C880000 00402821 00403821 AFA20024 AFA30028 02002021 0100F809 02003021 8FA20024 8FA30028 8FAB0070 0177B821 92E40000 00942024 5080002B 8E240098 3C0500FF 34A5FFFF 8E240048 AFA50010 00402821 8C820000 02003021 AFA30028 02002021 0040F809 00A03821 8FA30028 8E220094 26100001 8C420000 02569021 0202102B 1040002E 02759821 93C20000 8E240098 02821024 1040FFF5 8C850000 8FAA001C 1540FFB1 8FAB0058 0215001A 02A001F4 8FA20058 8FA40020 8C460000 0000B812 1480FFAD 02E6B821 0216001A 02C001F4 8FA20060 8C440000 00003812 1000FFA9 00E43821 8C850000 8E240048 00052902 00452821 3C0200FF 3442FFFF 1000FFD4 AFA20010 240600FF AFA60010 00052902 8C880000 00452821 AFA20024 AFA30028 02002021 02003021 0100F809 00A03821 8FA30028 1000FFBB 8FA20024 8FA20018 24420001 AFA20018 8FA40018 24020008 5482FF7A 3C029D00 8FBF0054 8FBE0050 8FB7004C 8FB60048 8FB50044 8FB40040 8FB3003C 8FB20038 8FB10034 8FB00030 03E00008 27BD0058 8FAB005C 8FA80064 8D660000 8D040000 14C4FF91 8FAA0070 1000FFA1 8FAB0070 0015A823 06C1FF5F AFA0001C 0016B023 1000FF5E AFA00020 End CSUB ' CFunction npins 00000000 3C03BF81 8C65F220 3C020661 7CA5D800 3444A053 50A40009 2402002C 8C64F220 2443A053 7C84D800 00832026 2402001C 2403002C 0064100A 3C03BF81 8C66F220 8C64F220 3C030580 3463A053 7CC6D800 00C33026 24050040 7C84D800 24631000 10830006 00A6100A 00022FC3 00402021 00801021 03E00008 00A01821 24040064 00002821 00801021 03E00008 00A01821 End CFunction ' CFunction cpuspeed 00000000 3C029D00 8C420000 00001821 03E00008 8C420000 End CFunction C- code is: void logic(long *tickspersample, long *count, unsigned char *cbuffer, long *trig){ long loop=0,current_ticks=0,pin,dir=1,mytrig, nexttick=*tickspersample, tickincrement = nexttick; mytrig=*trig; if(mytrig){ //trigger channel specified if(mytrig<0){ mytrig=-mytrig; dir=0; } pin=1<<GetPinBit(mytrig); mT4IntEnable(0); // disable clock interrupt if(dir){ //positive going trigger while(bread & pin)CheckAbort(); //wait for trigger to be or go low while(!(bread & pin)); //wait for it to go high } else { //negative going trigger while(!(bread & pin))CheckAbort(); //wait for it to go or be high while(bread & pin); //wait for trigger to go low } } else { mT4IntEnable(0); // disable clock interrupt } asm volatile("mtc0 %0, $9": "+r"(current_ticks)); //set the current number of ticks to 0 while(loop< *count) { while(current_ticks<nexttick){ asm volatile("mfc0 %0, $9" : "=r"(current_ticks));//get the time in ticks since zeroed } nexttick+= tickincrement; cbuffer[loop++] = bread; } mT4IntEnable(1); } void drawlogic(long *startrecord, long *scale, long *laststart, long *lastscale, unsigned char *tracks, long *count, unsigned char *cbuffer){ int j=0, l=0, x, y, ylast, mask, buffpos, lastbuffpos, multiplier=*scale,expand=1, lastmultiplier=*lastscale,lastexpand=1; if(multiplier<0){ //decide if I am expanding or contracting the display multiplier=-multiplier; expand=0; } if(lastmultiplier<0){ //decide if I am expanding or contracting the display lastmultiplier=-lastmultiplier; lastexpand=0; } for(j=0;j<8;j++){//step though each track mask=1<<j; //create the bit mask for this track for(x=0;x<HRes;x++){ //step through the screen y=j*25*(VRes/240)+VRes/12; if(mask & *tracks){ if(expand){ buffpos=x*multiplier + *startrecord; } else { buffpos=x/multiplier + *startrecord; } if(lastexpand){ lastbuffpos=x*lastmultiplier + *laststart; } else { lastbuffpos=x/lastmultiplier + *laststart; } if(buffpos< *count){ if(*startrecord!=*laststart || *scale!=*lastscale){//delete last trace if track is enabled if(cbuffer[lastbuffpos] & mask){ DrawPixel(x,y,0xFF); } else { DrawPixel(x,y+VRes/16,0xFF); } } if(cbuffer[buffpos] & mask){ //only draw if this track is enabled DrawPixel(x,y,0xFFFFFF); } else { DrawPixel(x,y+VRes/16,0xFFFFFF); } } } } } } |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2946 |
Absolutely BRILLIANT ![]() One question: On a 64pinner, are you saying 7.5 million samples/s equates to just under 1MHz per channel? If so, is there a potential for higher sampling? And if not at CPU 120, would this increase the samples/s? Haven't finished reading your post yet so apologies if answer is within your post ![]() WW |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
No 7.5Msps on each and every one of the 8 channels at 120MHz ![]() |
||||
twofingers![]() Guru ![]() Joined: 02/06/2014 Location: GermanyPosts: 1619 |
Hi Peter, looks like magic. I can't believe it! (But I have to, probably*! ![]() What will be your next step, a journey to mars? ![]() Thanks a lot! Michael * have not tested it yet. causality ≠ correlation ≠ coincidence |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2946 |
WOW! ![]() I see this being VERY useful . . . |
||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1140 |
Very cool. In the basic program, you have DIM samplespersecond%=750000 Is that as intended or is there a missing zero?
Also, would it make sense to test CheckAbort() while waiting for the start of the trigger in void logic(...)? Visit Vegipete's *Mite Library for cool programs. |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
You can set it to whatever you want to match the input signal within the constraints imposed by tickspersample%. For the photo, I slowed the SPI down to 100K so that the gaps between CS going low and the start of the transmission and then going high again wasn't too long compared to the signal duration. You can really see the effect of Basic parsing even on something as simple as PIN(CS)=0 compared to the actual SPI data transmission. This was deliberate so that recording happens as soon as possible after the trigger. CheckAbort takes time and if the trigger happens after the pin test but before CheckAbort quite a bit of data could be lost. Worst case, press the reset button to exit the loop ![]() |
||||
Chris Roper Senior Member ![]() Joined: 19/05/2015 Location: South AfricaPosts: 280 |
Hi Peter, Great work. I wondered if you have ever seen OLS, if not you may find it interesting. It is an open source replacement for SUMP and is a portable JAVA based client for devices like this. It uses the simple ASCII SUMP Protocol to transfer both Digital and Analog Data Captured by the hardware and displays the waveforms much as you are doing on the LCD. The added benefit is that it can then do Protocol analysis on that data and displays the ASCII or HEX results of the decoded data along with the waveform. Cheers Chris links: OLS: http://ols.lxtreme.nl/ SUMP: http://www.sump.org/projects/analyzer/protocol/ http://caroper.blogspot.com/ |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4067 |
Using STM32F4 as a logic analyser (SUMP/8channels/21MHz) - (not 23MHz) http://jjmz.free.fr/?p=148 STM32F4-based Logic Analyser www.fussylogic.co.uk/blog/?p=1226 Panalyzer - a RaspberryPi based Logic Analyzer www.raspberrypi.org/phpBB3/viewtopic.php?f=37&t=7696 http://dangerousprototypes.com/docs/Open_Bench_Logic_Sniffer http://hackaday.com/2010/02/28/open-source-logic-analyzer-2/ John |
||||
isochronic Guru ![]() Joined: 21/01/2012 Location: AustraliaPosts: 689 |
Nice...obviously it is sampling digitally ie without the A/D involved, and getting very fast !! It raises the idea of using a SPI port, I think they can go to 25 Mbits/sec, don't know what the jitter is like though. There used to be small CRO-type thingos being sold, typically a 320x240 screen and roughly a 200 kHz max capability (ed - implying about a Msample/sec), haven't seen them for a while. |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
Bump |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5193 |
Hi Matherp, Haven't seen this before. Looks like an easy entry into logic analyzers (although speed is not overwhelming, it is usable for I2C and "throttled down" SPI). The critical point in the capture Cfunction is the trigger. 1/ can the trigger be part of the 6/8 bits (double pin assignment), or is it separate. 2/ what change is needed to get the trigger in the middle of buff(). In many cases the trigger is an "error" and you want to know what preceeds the error. 3/ Is there (CPU) time to allow some basic logic in the trigger, and still maintain the sampling pace (needed when trigger is in the middle of buff())? Something like "if A and B both high". If well set up it will take minimal 2 MIPS instructions (a mask on port B, and a compare with preset value). Guess the compare exists already. Regards, Volhout PicomiteVGA PETSCII ROBOTS |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9630 |
No, I missed this one too! Brilliant! Hey Peter - would this be something that could be ported to the CMM2 with it's lovely graphics speed? Perhaps not, as this concept uses Cfunctions, so the interpreter in the CMM2 might not be fast enough. But if it COULD be, that would be another feather in the hat of the capabilities of the CMM2 unit! Smoke makes things work. When the smoke gets out, it stops! |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5193 |
Hi Grogster, Peter "bumped" this one up. After a deep sleep of 5 years. Peter never does anything without a reason. He wants us to pick it up. Volhout PicomiteVGA PETSCII ROBOTS |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9630 |
Yes, I know, and 5-years IS a long sleep, I agree. ![]() But I am wondering if his reason for the bump, was that he is indeed working on a CMM2 version of this - you never know! ![]() ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
It seemed to answer a requirement someone posted on another thread. If it doesn't then the C code should give someone the guts of a solution. The CMM2 now has CSUBs so examples like this can be created for the CMM2 without them having to be part of the core firmware |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9630 |
Owwwwww - can you point to the CMM2 CSUB info? I think I missed that also.... ![]() Sorry, but busy with CMM2 orders! Smoke makes things work. When the smoke gets out, it stops! |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10375 |
Here |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |