Its a fun little project and well worth building just for the entertainment value. Currently bandwidth is a little limited, but with a little extra effort it would be possible to make a fully functional 2MHz Scope for next to nothing. Ideal for probing i2c, audio and other low speed signals.
EDIT: We managed to squeeze the maximum speed out of the ADC, read further through the thread for details. The github code includes all of the enhancements made of the course of this thread.
Replies20
ahull Fri Oct 21, 2016 11:51 pm
Per the previous post from @CrtSuznik..
The Arduino STM32 board manager package can be added to the IDE by following the instructions found here…
The RTC library is only part of the story, you also need the “Time” library
// Time library - https://github.com/PaulStoffregen/Time#include "Time.h"//If you have issues with the default Time library change the name of this library to Time1 for example.
ag123 Sat Oct 22, 2016 5:47 am
wow this is a very cool project would try it out
CrtSuznik Sat Oct 22, 2016 11:42 am
I’ve gotten the sketch tu upload without any errors (i’m using a serial adapter). I haven’t connected anything to it yet, since i’m still waiting for the display to arive from ebay.
I tried seeing the random outputs in the serial monitor, but there seems to be no output. As i understand it, i’m supposed to send it a ‘s’ for it to start, but when i type in s and send it…there’s no change.
What am I doing wrong?
Also, I’m using Arduino IDE 1.6.9
ahull Sat Oct 22, 2016 12:18 pm
The scope should respond to the following commands.
sCmd.addCommand("s", toggleSerial); // Turns serial sample output on/offsCmd.addCommand("h", toggleHold); // Turns triggering on/offsCmd.addCommand("t", decreaseTimebase); // decrease Timebase by 10xsCmd.addCommand("T", increaseTimebase); // increase Timebase by 10xsCmd.addCommand("z", decreaseZoomFactor); // decrease ZoomsCmd.addCommand("Z", increaseZoomFactor); // increase ZoomsCmd.addCommand("r", scrollRight); // start onscreen trace further rightsCmd.addCommand("l", scrollLeft); // start onscreen trae further leftsCmd.addCommand("e", incEdgeType); // increment the trigger edge type 0 1 2 0 1 2 etcsCmd.addCommand("y", decreaseYposition); // move trace DownsCmd.addCommand("Y", increaseYposition); // move trace UpsCmd.addCommand("g", decreaseTriggerPosition); // move trigger position DownsCmd.addCommand("G", increaseTriggerPosition); // move trigger position UpsCmd.addCommand("P", toggleTestPulseOn); // Toggle the test pulse pin from high impedence input to square wave output.sCmd.addCommand("p", toggleTestPulseOff); // Toggle the Test pin from square wave test to high impedence input.
CrtSuznik Sat Oct 22, 2016 12:35 pm
I now tried connecting B0 and B1 and the red light started flashing, so that’s good.
However there still wasn’t any data on the serial monitor. Which baud rate should I be using?
ahull Sat Oct 22, 2016 1:11 pm
CrtSuznik wrote:I now tried connecting B0 and B1 and the red light started flashing, so that’s good.
However there still wasn’t any data on the serial monitor. Which baud rate should I be using?
ag123 Sat Oct 22, 2016 6:41 pm
for now somewhat caught up to play with this, but just adding my 2 cents thoughts, another ‘boring’ way to do the scope may be to do the dma bulk read from adc and pass that over usb (e.g. usb bulk transports) to the connected host computer, and for the host computer to display the graph (scope) & do further processing (e.g. fft).
there are various advantages though, one of which is that the host computer has possibly much more resources e.g. storage and ram (possibly in gigabytes vs 20k on stm32f103cb) & much faster cpu (say multi-core i3, i5, i7 etc).
there is also a possibility to connect multiple maple-mini making it ‘parallel’ acquisition. a thing though is how to keep the start ilnes in sync across multiple maple-mini if doing ‘parallel’ scopes or for that matter to present it in a way such that it seemed ‘in-sync’ (that would turn the batteries of maple minis into a ‘multi-channel’ digital signal analyzer)
the other downside would be that an app possibly needs to be written to interface with the maple-mini to be a complete scope.
but i think what has become rather apparent so far is stm32 f1 makes ‘good scopes’. its precision is good 12 bits e.g. displays all the harmonics / tiny signals / noise riding on the main signals (e.g. square wave) and pretty much fast 1-2 msamples per sec comparable to some ‘real’ scopes. stm32 f4 with 3 adcs each 2+ m samples/s would likely be even more impressive in this aspects.
maple minis is the ‘new’ $5 ‘professional’ 1mhz scopes
ag123 Sat Oct 22, 2016 7:28 pm
STM32 f4 can even stand in place for those 10s of m samples per sec parallel logic analyzer, not sure if it is ever possible to top 100m samples per sec https://www.fussylogic.co.uk/blog/?p=1226
BeagleLogic turns your BeagleBone Black/Green into a 100Msps Logic Analyzer with up to 14 channels. All you need is a BeagleBone, an SD card and the BeagleLogic cape to get up and running.
SanjuPrakash Thu Oct 27, 2016 9:26 am
Hello!
I have been trying to get the ADC on the stm32f103c8t6 minimum development board to sample at 1Msps using the Arduino IDE. I have tried out most of the codes on stm32duino and none of them seem to upload well. I have written a simple datalogger sketch that is able to log 10K samples/sec into an SD card . The pig o scope sketch says that it is possible to get nearly 1Msps . But i am not able to decipher the sketch. Could you help me out in pointing out methods by which i can get a higher sampling rate with logging it into an SD card or by printing it out on the serial monitor?
constint chipSelect = PB12;int x = 0;unsigned long t = 0;File dataFile;void setup(){Serial.begin(250000);delay(1000);while (!Serial) {}Serial.print("Initializing SD card...");if (!SD.begin(chipSelect)) {Serial.println("Card failed, or not present");return;}Serial.println("card initialized.");adc_set_sample_rate(ADC1, ADC_SMPR_1_5);dataFile = SD.open("1.txt", FILE_WRITE);t = millis();}void loop() {
if (!dataFile) return; if(Serial)
if(Serial.read()=='0') //Enter 0 to stop logging and close file{dataFile.close();}
//Serial.println(analogRead(PA0)); dataFile.println(adc_read(ADC1,0)); x++; if (millis()-t>=1000)
{Serial.println("X=");Serial.print(x);
x = 0; t=millis(); //dataFile.close(); }
}
ahull Thu Oct 27, 2016 3:54 pm
The way we get fast ADC performance is by using two ADC interleaved and relying on interrupts and DMA.. its slightly complex at first glance, but the main parts of the solution are the code block below.
...adc_calibrate(ADC1);adc_calibrate(ADC2);setADCs (); //Setup ADC peripherals for interleaved continuous mode....
int pinMapADCin = PIN_MAP[analogInPin].adc_channel;adc_set_sample_rate(ADC1, ADC_SMPR_1_5); //=0,58uS/sample. ADC_SMPR_13_5 = 1.08uS - use this one if Rin>10Kohm,adc_set_sample_rate(ADC2, ADC_SMPR_1_5); // if not may get some sporadic noise. see datasheet.
// Grab the samples from the ADC
// Theoretically the ADC can not go any faster than this.
//
// According to specs, when using 72Mhz on the MCU main clock,the fastest ADC capture time is 1.17 uS. As we use 2 ADCs we get double the captures, so .58 uS, which is the times we get with ADC_SMPR_1_5.
// I think we have reached the speed limit of the chip, now all we can do is improve accuracy.
// See; http://stm32duino.com/viewtopic.php?f=19&t=107&p=1202#p1194
void takeSamples (){// This loop uses dual interleaved mode to get the best performance out of the ADCs//dma_init(DMA1);dma_attach_interrupt(DMA1, DMA_CH1, DMA1_CH1_Event);adc_dma_enable(ADC1);dma_setup_transfer(DMA1, DMA_CH1, &ADC1->regs->DR, DMA_SIZE_32BITS,dataPoints32, DMA_SIZE_32BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// Receive buffer DMAdma_set_num_transfers(DMA1, DMA_CH1, maxSamples / 2);dma1_ch1_Active = 1;// regs->CR2 |= ADC_CR2_SWSTART; //moved to setADCdma_enable(DMA1, DMA_CH1); // Enable the channel and start the transfer.//adc_calibrate(ADC1);//adc_calibrate(ADC2);samplingTime = micros();while (dma1_ch1_Active);samplingTime = (micros() - samplingTime);dma_disable(DMA1, DMA_CH1); //End of trasfer, disable DMA and Continuous mode.// regs->CR2 &= ~ADC_CR2_CONT;
/**
* @brief Enable DMA requests
* @param dev ADC device on which to enable DMA requests
*/
Hello! I would like to say Thank You to Author, for revisited STM-O-Scope! Thing is, recently I was collecting projects and solutions for simple DIY scopes, and, there are quite a lot, especially found in russian-speaking resources (i am latvian, but I know that language). I decided, that this modified O-Scope will be the first thing I try, to see if I got my things right – it is first touch to STM for me. And everything went well! I got scope display on first switch on. Very good feeling and encouragement to go further Here is visual joy: http://bildites.lv/a/684af4cb#v6edchda
By the way, I had to fix “UTouch” library usage, because it is now called “URTouch”, and also had to rename “Time” library, as it was proposed in sketch comments. After that, all went well. Did not try serial output yet. Clock shows year 1970. I was two back then
Thank You, and I will follow if any advances in this particular project (or a new ones too maybe)!
EDIT: i am not sure how to get serial interaction working. Should I add typical serial begin to sketch, and set baud rate?
SanjuPrakash Fri Oct 28, 2016 8:25 am
ahull wrote:The way we get fast ADC performance is by using two ADC interleaved and relying on interrupts and DMA.. its slightly complex at first glance, but the main parts of the solution are the code block below.
...adc_calibrate(ADC1);adc_calibrate(ADC2);setADCs (); //Setup ADC peripherals for interleaved continuous mode....
int pinMapADCin = PIN_MAP[analogInPin].adc_channel;adc_set_sample_rate(ADC1, ADC_SMPR_1_5); //=0,58uS/sample. ADC_SMPR_13_5 = 1.08uS - use this one if Rin>10Kohm,adc_set_sample_rate(ADC2, ADC_SMPR_1_5); // if not may get some sporadic noise. see datasheet.
// Grab the samples from the ADC
// Theoretically the ADC can not go any faster than this.
//
// According to specs, when using 72Mhz on the MCU main clock,the fastest ADC capture time is 1.17 uS. As we use 2 ADCs we get double the captures, so .58 uS, which is the times we get with ADC_SMPR_1_5.
// I think we have reached the speed limit of the chip, now all we can do is improve accuracy.
// See; http://stm32duino.com/viewtopic.php?f=19&t=107&p=1202#p1194
void takeSamples (){// This loop uses dual interleaved mode to get the best performance out of the ADCs//dma_init(DMA1);dma_attach_interrupt(DMA1, DMA_CH1, DMA1_CH1_Event);adc_dma_enable(ADC1);dma_setup_transfer(DMA1, DMA_CH1, &ADC1->regs->DR, DMA_SIZE_32BITS,dataPoints32, DMA_SIZE_32BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// Receive buffer DMAdma_set_num_transfers(DMA1, DMA_CH1, maxSamples / 2);dma1_ch1_Active = 1;// regs->CR2 |= ADC_CR2_SWSTART; //moved to setADCdma_enable(DMA1, DMA_CH1); // Enable the channel and start the transfer.//adc_calibrate(ADC1);//adc_calibrate(ADC2);samplingTime = micros();while (dma1_ch1_Active);samplingTime = (micros() - samplingTime);dma_disable(DMA1, DMA_CH1); //End of trasfer, disable DMA and Continuous mode.// regs->CR2 &= ~ADC_CR2_CONT;
/**
* @brief Enable DMA requests
* @param dev ADC device on which to enable DMA requests
*/
SanjuPrakash wrote:
This is the writing code i am using and it takes more than a minute to log the samples.
Also is there any way i can store the values on the flash memory provided on the board ?
SanjuPrakash Fri Oct 28, 2016 8:58 am
rexnanet wrote:
How much data do you need to store?
Writing to flash memory will always take some time, either on SD-card or in the internal microcontroller flash… Also you only have 128KB max. on the internal flash (and some of it will be used by the code).
Depending on the amount of data and rate you can try to use a temporary SPI RAM as a buffer…
rexnanet Fri Oct 28, 2016 9:15 am
SanjuPrakash wrote:
I’ll need to store atleast 6 seconds of data, that is about 6Msps.
RogerClark Fri Oct 28, 2016 9:19 am
The ADC’s are bigger than 8 bits,
So if the OP is using the full range of the ADC then 2 bytes per sample would be needed.
Hence twice the data rate (12 M)
rexnanet Fri Oct 28, 2016 9:22 am
Yep
I was “trimming” it to make it simpler
If he needs more than 8 bits yes, it will double things up…
SanjuPrakash Fri Oct 28, 2016 9:25 am
Is there a way to use DMA to transfer data onto the SD card ?
And I don’t mind having a trade-off between the number of samples I get per second as long as I get more than 100Ksps.
RogerClark Fri Oct 28, 2016 9:40 am
I think the latest SD lib has DMA.
Try googling “site:stm32duino.com SD DMA”
ThunderOwl Tue Nov 08, 2016 7:11 pm
I would be very thankful, if Author, or, anyone who knows and can, could make small instructions “for dummies” about serial interaction of this Scope. I have used terminals and serial connections before, problem is, that I am very new in this STM area. Thanks in advance!
P.S.: is there planned advances, changes for this Scope? Or, it was just a quick exercise that is not planned to become “bigger”? I hope it grows… Thanks!