<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="bbPress/1.0.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>LeafLabs Garden &#187; Topic: How to improve the maple mini&#039;s ADC sample rate to 1MHz?</title>
		<link>http://forums.leaflabs.com/topic.php?id=74213</link>
		<description>A place to share, learn, and grow...</description>
		<language>en-US</language>
		<pubDate>Fri, 22 Jan 2016 00:23:57 +0000</pubDate>
		<generator>http://bbpress.org/?v=1.0.2</generator>
		<textInput>
			<title><![CDATA[Search]]></title>
			<description><![CDATA[Search all topics from these forums.]]></description>
			<name>q</name>
			<link>http://forums.leaflabs.com/search.php</link>
		</textInput>
		<atom:link href="http://forums.leaflabs.com/rss.php?topic=74213" rel="self" type="application/rss+xml" />

		<item>
			<title>gbulmer on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105116</link>
			<pubDate>Wed, 25 Dec 2013 11:53:27 +0000</pubDate>
			<dc:creator>gbulmer</dc:creator>
			<guid isPermaLink="false">105116@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;tomxue - Very well done for cracking using the dual-ADC! Also thank you for sharing your results. &#60;/p&#62;
&#60;p&#62;&#60;em&#62;&#34;ADC_PRE_PCLK2_DIV_2 may not be the key factor&#34;&#60;/em&#62;&#60;br /&#62;
I was only suggesting simplifying and removing anything that might trigger a problem.&#60;/p&#62;
&#60;p&#62;When I wrote &#60;em&#62;&#34;I currently believe that the ADC is unlikely to be working reliably for all bits of the conversion because it is out of spec.&#34;&#60;/em&#62;, the key points were &#34;reliably&#34; and &#34;all bits&#34;.&#60;/p&#62;
&#60;p&#62;First, 18MHz isn't enormously bigger than 14MHz. Several people have reported 'overclocking' the STM32F, for example:&#60;br /&#62;
&#60;a href=&#34;http://forums.leaflabs.com/topic.php?id=31&#34; rel=&#34;nofollow&#34;&#62;http://forums.leaflabs.com/topic.php?id=31&#60;/a&#62;&#60;br /&#62;
used 128MHz. It invalidated the warranty. AFAIK there was little testing done on peripherals.&#60;br /&#62;
So 18MHz for the ADC clock does sound possible, though 36MHz sounds too good to be true. (STM32F303 can do 5msps, but that is likely different electronics)&#60;/p&#62;
&#60;p&#62;There are many ways to make Analogue to Digital Converters. Some ADC architectures do generate the high-order, most-significant bits before the least-significant bits, so I can easily believe that it gets broadly reasonable results. In fact some of the latter STM32F families have ADC's which can yield lower resolution, fewer bits, results more quickly than full-precision conversions.&#60;br /&#62;
(I couldn't find anything about that on STM32F103 in RM0008, though I have a feeling I have read something somewhere, maybe someone else can gives us a pointer?)&#60;/p&#62;
&#60;p&#62;So I am willing to believe the results look plausible, and the errors are either systematic (and may reproduce) or are mostly confined to the least-significant-bits. If that is good enough, then carry-on, keeping in mind that weird results may indicate the ADC's might generate errors, or do some testing to characterise the behaviour.&#60;/p&#62;
&#60;p&#62;My comment on libmaple was unclear, sorry. libmaple has two parts, the C++ 'wirish' part which looks like some of the Arduino libraries, and the 'low-level' C part. I was trying to ask if you had used only the low-level C, without using direct register access. In that case, it'd be much easier to get dual ADCs working. However, you were way ahead :-)&#60;/p&#62;
&#60;p&#62;&#60;em&#62;&#34;the environment light's strength can not be adjusted easily&#34;&#60;/em&#62;&#60;br /&#62;
I expect you have this solved, however this comment might help other people; if it is AC-lighting then it might not be good enough, as the light intensity will drop in synch with the mains voltage. A constant DC voltage driven light may make things much easier.&#60;/p&#62;
&#60;p&#62;The 'integration time' could be kept small, but still provide time for the ADC, by scanning the sensor multiple times and ignoring some of the pixel values. For example, if the sensor were scanned at 2MHz, but only alternate values were sampled and converted with the ADC, then conversion might work okay. Of course, that might not be possible if you're using the sensor to capture very rapid motion.&#60;/p&#62;
&#60;p&#62;Many Thanks for sharing.&#60;br /&#62;
I am especially happy because I am considering using a similar sensor for a potential project in the New Year !-)&#60;/p&#62;
&#60;p&#62;(Full disclosure: I am not a member of LeafLabs staff.)
&#60;/p&#62;</description>
		</item>
		<item>
			<title>tomxue on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105115</link>
			<pubDate>Wed, 25 Dec 2013 02:05:11 +0000</pubDate>
			<dc:creator>tomxue</dc:creator>
			<guid isPermaLink="false">105115@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;I made the maple mini's two ADCs work normally under &#34;Dual regular simultaneous mode&#34;!&#60;br /&#62;
Please check my code below:&#60;br /&#62;
&#60;a href=&#34;https://github.com/tomxuetoy/Maplemini_HighSpeedADC/blob/65e68d12b5938149069851c03ab55259db74c4a4/HighSpeedADC.cpp&#34; rel=&#34;nofollow&#34;&#62;https://github.com/tomxuetoy/Maplemini_HighSpeedADC/blob/65e68d12b5938149069851c03ab55259db74c4a4/HighSpeedADC.cpp&#60;/a&#62;&#60;/p&#62;
&#60;p&#62;The key factor I missed is below, RM0008 page 219:&#60;br /&#62;
&#34;&#60;code&#62;Note: In dual ADC mode, to read the slave converted data on the master data register, the DMA bit must be enabled even if it is not used to transfer converted regular channel data.&#60;/code&#62;&#34;&#60;/p&#62;
&#60;p&#62;So even if that I don't use DMA, but I still need to set the DMA bit in register ADC_CR2. By setting the DMA bit, I get the correct data at once. The run result is followed in my above code.
&#60;/p&#62;</description>
		</item>
		<item>
			<title>tomxue on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105113</link>
			<pubDate>Tue, 24 Dec 2013 21:22:28 +0000</pubDate>
			<dc:creator>tomxue</dc:creator>
			<guid isPermaLink="false">105113@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;Hi gbulmer, thanks for your help!&#60;br /&#62;
I am sorry to post the long code and cause inconvenience. Now I can not remove them any more. I will just give Github link from now on.&#60;/p&#62;
&#60;p&#62;The evidence I believe that my sensor amd maple mini (under 72MHz and ADC_PRE_PCLK2_DIV_2) works well is that: if I use a phone flashlight to irradiate the sensor, then the X value maple mini reads will go high accordingly. Closer makes bigger value, untill 4095. And I shield part of the sensor, then some of the sensor data will become smaller accordingly. While in the whole process, Y value is always zero.&#60;/p&#62;
&#60;p&#62;You are totally right that I do not need to read two ADC simultaneously, and I can read them one by one. And even that I don't have to use so high speed. But in my office, on my desktop, the environment light's strength can not be adjusted easily. So slower ADC speed will cause the sensor value got to 4095 easily. And the biggest reason may be that I hope to use this chance to learn something, maple is powerful and I hope to grasp it better.&#60;/p&#62;
&#60;p&#62;I tested that to comment out &#60;code&#62;adc_set_prescaler(ADC_PRE_PCLK2_DIV_2)&#60;/code&#62; in my code, and cause the ADC speed to be slower and X sensor data bigger but Y snesor data is still all zero. So that means ADC2 does not work at all and ADC_PRE_PCLK2_DIV_2 may not be the key factor.&#60;/p&#62;
&#60;p&#62;For your last question, maybe my understanding is not right. My current code uses libmaple. It could work (X and Y sensor have right value generated) with only analogRead(), I did that but without using libmaple.&#60;/p&#62;
&#60;p&#62;I will make it work with single ADC and let the project go forward. While I will use my rest time to dig further to make this dual regular mode work, it is amazing and I do not want to give up.
&#60;/p&#62;</description>
		</item>
		<item>
			<title>gbulmer on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105112</link>
			<pubDate>Tue, 24 Dec 2013 15:21:53 +0000</pubDate>
			<dc:creator>gbulmer</dc:creator>
			<guid isPermaLink="false">105112@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;tomxue - the github link is much better. If it is the same code, it is better to delete the code within your post.&#60;br /&#62;
(Long pieces of code make the thread harder to read, and long lines in the code make the page wide, which is unplesant to read.)&#60;/p&#62;
&#60;p&#62;&#60;em&#62;&#34;I connect my sensor and roughly test it, with adc_set_prescaler(ADC_PRE_PCLK2_DIV_2) it looks like working fine, at least the data it reads via ADC seems right.&#34;&#60;/em&#62;&#60;/p&#62;
&#60;p&#62;I currently believe that the ADC is unlikely to be working reliably for all bits of the conversion because it is out of spec. Are you certain that the data is good? What are the tests and evidence that most of the 12 bits are working?&#60;/p&#62;
&#60;p&#62;I have experimented with a lower-cost part from TAOS using an Arduino, which digitises 100x slower than Maple.&#60;/p&#62;
&#60;p&#62;The TSL202 can be read at a very wide range of speeds. AFAIK, the rate at which the sensor performs best is set by the brightness of the light it is sensing and the integration time. So to get everything working, and reliably reading analogue values, you could even use dimmer light. &#60;/p&#62;
&#60;p&#62;The sensor has two independent sections. AFAICT they do not have to be read simultaneously, so one half could be read, then the other half.&#60;/p&#62;
&#60;p&#62;So, it is the specific use-case which is driving the need to do ADC conversion at 1Msps, and not the sensor.&#60;/p&#62;
&#60;p&#62;I haven't used both ADC's.  There are threads discussing it. The two halves of the sensor do not have to be sampled at exactly the same time. So the code can achieve an effective ADC rate of well above 1Msps by sampling the two signals with two ADCs.&#60;/p&#62;
&#60;p&#62;I've never run the Maple at 56MHz. I'd have to go digging through the manual and do quite a lot of experiments to do that.&#60;br /&#62;
I believe changing the primary system clock to 56MHz will effect a lot of other subsystems, like SysTick, the timers, USB etc. So it isn't something I have experimented with, or plan on experimenting with. I don't know if anyone here knows how to do that. I'd suggest posting on the ST.com STM32F forum to get help.&#60;/p&#62;
&#60;p&#62;Have you got code using libmaple (no direct access, only &#60;code&#62;analogRead&#60;/code&#62;, and no &#60;code&#62;adc_set_prescaler&#60;/code&#62;) working?
&#60;/p&#62;</description>
		</item>
		<item>
			<title>tomxue on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105110</link>
			<pubDate>Tue, 24 Dec 2013 11:15:09 +0000</pubDate>
			<dc:creator>tomxue</dc:creator>
			<guid isPermaLink="false">105110@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;Hi gbulmer, thanks again for your help!&#60;br /&#62;
I connect my sensor and roughly test it, with &#60;code&#62;adc_set_prescaler(ADC_PRE_PCLK2_DIV_2)&#60;/code&#62; it looks like working fine, at least the data it reads via ADC seems right.&#60;/p&#62;
&#60;p&#62;The sensor I am using is TSL202, its spes is here:&#60;br /&#62;
&#60;a href=&#34;http://www.mouser.com/ds/2/588/TSL202R-E-198539.pdf&#34; rel=&#34;nofollow&#34;&#62;http://www.mouser.com/ds/2/588/TSL202R-E-198539.pdf&#60;/a&#62;&#60;br /&#62;
As you can see, I need to generate 129 clocks (by GPIO) and for each clock the chip will generate an analog signal which I need to detect via ADC. And the total period (called integration time, including 129 clock jumps and 129 ADC read time) should be as small as better in my case.&#60;/p&#62;
&#60;p&#62;In my hardware, I will apply two sensors, one is X axis and another one is Y axis. So I turned my code to use &#34;Dual regular simultaneous mode&#34;, but I met new problem.&#60;br /&#62;
Please check my code (deleted from post by gbulmer) below. Or you may find it here (better format): &#60;a href=&#34;https://github.com/tomxuetoy/Maplemini_HighSpeedADC/blob/master/HighSpeedADC.cpp&#34; rel=&#34;nofollow&#34;&#62;https://github.com/tomxuetoy/Maplemini_HighSpeedADC/blob/master/HighSpeedADC.cpp&#60;/a&#62;&#60;/p&#62;
&#60;pre&#62;&#60;code&#62;Starting loops:
Stop loops:
Elapsed Time: 30545 us (for 25800 analog reads)
1.18 us (for 1 sample) 305.45 us (for 1 sensor)  pixelVal_x =
153
141  142  141  139  142  143  140  142  141  141
  141  141  142  145  143  143 142  143  142  145
142  143  134  134  143  145  144  143  143  143
  147  143  143  143  143  143 143  143  143  143
143  143  142  143  143  143  142  143  146  146
  143  143  145  145  143  143 146  143  147  145
145  147  149  158  143  146  146  146  142  147
  142  147  142  145  145  149 145  145  141  148
143  146  143  146  145  148  145  138  143  145
  145  148  145  147  150  148 143  151  146  147
143  146  143  149  143  147  146  147  144  148
  142  149  143  147  143  146 144  146  142  146
143  147  143  147  143  147  148
                                    pixelVal_y =
0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0  0  0  0  0  0  0
                      PCLK2 = 72000000

 ADC1-&#38;gt;regs-&#38;gt;CR1 = 393216

 ADC2-&#38;gt;regs-&#38;gt;CR1 = 0&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;As you can see, the ADC2 channel doesn't work at all. Due to I need to operate GPIO each time I read ADC value, so I might not apply DMA mode (Am I right?).&#60;br /&#62;
What is wrong with this code?&#60;br /&#62;
Thanks!&#60;/p&#62;
&#60;p&#62;And still I don't know how to change the system clock from 72MHz to 56MHz, could anyone please help?&#60;br /&#62;
And for the typo in the above post, &#34;millisecond should be us&#34;, it seems that I cann't edit the post any more. I'm sorry and please notice.&#60;/p&#62;
&#60;p&#62;&#60;em&#62;Edit (gbulmer): The printed values of pixelVal_x caused very, very long lines, which I've editted. However, I have caused the code to differ from the layout of results. Apologies.&#60;/em&#62;
&#60;/p&#62;</description>
		</item>
		<item>
			<title>gbulmer on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105104</link>
			<pubDate>Sun, 22 Dec 2013 12:35:14 +0000</pubDate>
			<dc:creator>gbulmer</dc:creator>
			<guid isPermaLink="false">105104@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;tomxue - I don't understand what is happening. Edit: I think I understand what is happening.&#60;/p&#62;
&#60;p&#62;1. &#34;0.96us/sample&#34; is faster than theoretically possible at 72MHz, it should be no better than 1.167us, and&#60;br /&#62;
2. 100000 samples should take a little longer than 1.167us/sample anyway because it should contain a bit of time for: starting then retrieving the value from the ADC conversion, the while loop overhead, and about 100 USB and 100 SysTick timer interrupt service routines.&#60;/p&#62;
&#60;p&#62;Edit:&#60;br /&#62;
Okay, I've got it, the code does &#60;code&#62;adc_set_prescaler(ADC_PRE_PCLK2_DIV_2);&#60;/code&#62;&#60;br /&#62;
That sets the ADC clock to 36MHz (I think, or 18Mhz).&#60;br /&#62;
The STM32F will run the ADC to convert the sampled value, but it is likely unreliable or inaccurate because it is beyond the ADC's specification. You might find that it does work for some bits, but I have no idea exactly what it will do. You'll need to do some experiments to find out how well it works as I don't think anyone has done those and shared their results already&#60;br /&#62;
I'd suggest, don't use adc_set_prescaler, or set the CPU clock to 56MHz, and use a prescaler of 4.&#60;br /&#62;
(You might try 'overclocking', and running the CPU at 80MHz, which has worked for some folks, then a prescaler of 6 would give a 13.3MHz ADC clock which seems safer than 18MHz ADC clock)&#60;/p&#62;
&#60;p&#62;Edit 2:&#60;br /&#62;
The number of instructions executed by analogRead and the low-level alternative is deterministic; it always takes the same number of cycles. So there is little benefit to doing something 10000 times. &#60;/p&#62;
&#60;p&#62;In one way, timing many iterations is misleading. An unknown number of interrupt service routines will have executed during a large number of iterations. Gross timing of many iterations will include that unknown interrupt service time. If it is significant, because there were many, many interrupts, but they are relatively consistent in number during the gross-timing period, then the gross-timing will be inflated a significant amount, but appear to contain little jitter. IMHO this can be misleading.&#60;/p&#62;
&#60;p&#62;IMHO, it would be better to count using SysTick ticks directly, or a hardware timer. Let's call that &#60;code&#62;ticks()&#60;/code&#62;.&#60;br /&#62;
Then it is possible to get the time consumed by the timing mechanism:&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;// ...
  start = ticks();
  stop = ticks();
  uint32 overhead = stop-start;    // calculate overhead for ticks() calls&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Then it is possible to time analogRead() directly:&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;// ...
  start = ticks();
  uint16 val1 = analogRead(analogPin);
  stop = ticks();
  uint32 analogRead_time = stop-start-overhead; // calculate analogRead ticks&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Also the lower level version, e.g.:&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;//...
  start = ticks();
  regs-&#38;gt;CR2 &#124;= ADC_CR2_SWSTART;
  while (!(regs-&#38;gt;SR &#38;amp; ADC_SR_EOC)) {}
  uint16 val2 = (uint16)(regs-&#38;gt;DR &#38;amp; ADC_DR_DATA);
  stop = ticks();
  uint32 low_level_adc_ticks = stop-start-overhead; // calculate ADC ticks&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;Then it is relatively straightforward to see how long the code takes, and also see which measurement contains background interrupt service routine overhead.&#60;/p&#62;
&#60;p&#62;My results are:&#60;br /&#62;
analogRead: Elapsed Time: 160 ticks (for 1 analog read) [2.2us]&#60;br /&#62;
low-level:     Elapsed Time: 115 ticks (for 1 analog read) [1.6us]&#60;/p&#62;
&#60;p&#62;Using &#60;code&#62;adc_set_sample_rate(ADC1, ADC_SMPR_1_5);&#60;/code&#62; and without &#60;code&#62;adc_set_prescaler(ADC_PRE_PCLK2_DIV_2)&#60;/code&#62;&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Summary&#60;/strong&#62;:&#60;br /&#62;
1. The &#34;0.96us/sample&#34; result may be invalid because the ADC is being operated beyond its 14MHz clock specification. It'll take more tests to discover how inaccurate it is.&#60;br /&#62;
2. The result will be inaccurate (and slower) because the timing will include many USB and SysTick interrupts.&#60;/p&#62;
&#60;p&#62;What is the use-case that needs the fastest possible conversion? You might be better using 'Dual ADC' mode, which should give a conversion rate significantly faster than 1us.&#60;br /&#62;
What is the electronics that is driving the low-impedance signal to make it possible to sample at such a high-rate?&#60;/p&#62;
&#60;p&#62;Have you considered using an STM32F303-based board? That has multiple 5msps ADCs, if the signal is good enough.&#60;/p&#62;
&#60;p&#62;It might be helpful to replace &#34;milliseconds&#34; with &#34;microseconds&#34; in the printed messages to avoid confusion.
&#60;/p&#62;</description>
		</item>
		<item>
			<title>tomxue on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105103</link>
			<pubDate>Sun, 22 Dec 2013 07:20:18 +0000</pubDate>
			<dc:creator>tomxue</dc:creator>
			<guid isPermaLink="false">105103@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;Hi gbulmer, thank you very much for this great help!&#60;br /&#62;
I made some change to my code based on your suggestion, and got big improvement of the speed. Currently, just for ADC conversion, the speed I can achieve is about 0.96us/sample.&#60;br /&#62;
Please check it below, and notice that the code is followed with the test result.&#60;br /&#62;
You may also find it here: &#60;a href=&#34;https://github.com/tomxuetoy/Maplemini_HighSpeedADC.git&#34; rel=&#34;nofollow&#34;&#62;https://github.com/tomxuetoy/Maplemini_HighSpeedADC.git&#60;/a&#62;&#60;br /&#62;
I will keep the source code updated and open to everyone.&#60;/p&#62;
&#60;p&#62;The main change achieved is by modifying the function: move the unchanged parts out of the loop. This helped a lot.&#60;br /&#62;
And I changed from millis() to micros(), this causes more accurate result.&#60;/p&#62;
&#60;p&#62;But for USBSerial, if I make it execute begin() and end() within the loop(), then my serial port monitor will lose it. For Windows' device manager, I can see that it refreshes frequently.&#60;/p&#62;
&#60;p&#62;The big problem is that currently I still use the default 72MHz. I don't know how to modify the ADC clock to 14MHz or to change the system clock to 56MHz, how? And I wonder if I change the system clock to 56MHz, whether it will influence other part, e.g. SPI or I2C?&#60;/p&#62;
&#60;p&#62;If you check my code, you could see that I need to control some GPIO to jump before and after one ADC conversion. Can DMA also do this kind of work? That means DMA needs to control ADC plus GPIO jump automatically, is it possible?&#60;/p&#62;
&#60;pre&#62;&#60;code&#62;#include &#38;lt;wirish/wirish.h&#38;gt;
#include &#38;lt;libmaple/adc.h&#38;gt;

#define COMM SerialUSB // use this for Maple
// #define COMM Serial // use this for Arduino
unsigned long start = 0;
unsigned long stop = 0;
unsigned long counter = 0;
unsigned long limit = 100000;
int outPin = 18;
int analogPin = 3;
int val = 0;

void setup()
{
    // the following line is needed for Maple
    pinMode(analogPin, INPUT_ANALOG);
    pinMode(outPin, OUTPUT);
    // adc_init(ADC1); //rcc_clk_enable(ADC1-&#38;gt;clk_id), Must be the first adc command!
    // adc_init(ADC2);
    //
    // adc_enable(ADC1); //ADC_CR2_ADON_BIT = 1
    // adc_enable(ADC2);
    //
    // adc_calibrate(ADC1); //Optional
    // adc_calibrate(ADC2);
    // 采样率优化的关键寄存器参数
    adc_set_prescaler(ADC_PRE_PCLK2_DIV_2);
    adc_set_sample_rate(ADC1, ADC_SMPR_1_5);
    // the following line is needed for Arduino
    // COMM.begin(57600);
}

void loop()
{
    COMM.println(&#38;quot;\nStarting loops:&#38;quot;);
    counter = 0;

    // digitalWrite() preparation work
    gpio_dev *gpiodev = PIN_MAP[outPin].gpio_device;
    uint8 pin = PIN_MAP[outPin].gpio_bit; // pin = 4 when outPin is 18

    // analogRead() preparation work
    const adc_dev *dev = PIN_MAP[analogPin].adc_device;
    adc_reg_map *regs = dev-&#38;gt;regs;
    adc_set_reg_seqlen(dev, 1);
    regs-&#38;gt;SQR3 = PIN_MAP[analogPin].adc_channel;

    start = micros();
    while (counter++ &#38;lt; limit)
    {
//        digitalWrite(outPin, HIGH);
        gpiodev-&#38;gt;regs-&#38;gt;BSRR = (1U &#38;lt;&#38;lt; pin);
//      gpiodev-&#38;gt;regs-&#38;gt;BSRR = 0x10;

//        val = analogRead(analogPin);
	regs-&#38;gt;CR2 &#124;= ADC_CR2_SWSTART;
	while (!(regs-&#38;gt;SR &#38;amp; ADC_SR_EOC))
            ;
	val = (uint16)(regs-&#38;gt;DR &#38;amp; ADC_DR_DATA);

//        digitalWrite(outPin, LOW);
        gpiodev-&#38;gt;regs-&#38;gt;BSRR = (1U &#38;lt;&#38;lt; pin)&#38;lt;&#38;lt;16;
//      gpiodev-&#38;gt;regs-&#38;gt;BSRR = 0x100000;
    }
    stop = micros();
//    COMM.begin();
    COMM.println(&#38;quot;Stop loops:&#38;quot;);
    COMM.print(&#38;quot;Elapsed Time: &#38;quot;);
    COMM.print(stop - start);
    COMM.print(&#38;quot; milliseconds (for &#38;quot;);
    COMM.print(limit);
    COMM.println(&#38;quot; analog reads)&#38;quot;);
    COMM.println(&#38;quot; val = &#38;quot;);
    COMM.println(val);
    COMM.println(&#38;quot; PCLK2 = &#38;quot;);
    COMM.println(PCLK2);
    COMM.println(&#38;quot; pin = &#38;quot;);
    COMM.println(pin);
//    COMM.end();
}

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
__attribute__((constructor)) void premain() {
    init();
}

int main(void) {
    setup();
    while (true) {
        loop();
    }
    return 0;
}

/*
Case 1: simplified analogRead() + simplified digitalWrite()
Elapsed Time: 107186 milliseconds (for 100000 analog reads)
Elapsed Time: 107185 milliseconds (for 100000 analog reads)

Case 2: simplified analogRead + without GPIO control
Elapsed Time: 96064 milliseconds (for 100000 analog reads)
Elapsed Time: 96065 milliseconds (for 100000 analog reads)

Case 3: original analogRead + without GPIO control,
Elapsed Time: 199089 milliseconds (for 100000 analog reads)
Elapsed Time: 199085 milliseconds (for 100000 analog reads)

Case 4: simplified analogRead() + simplified (and precalculated) digitalWrite()
Elapsed Time: 108584 milliseconds (for 100000 analog reads)
Elapsed Time: 108583 milliseconds (for 100000 analog reads)

Case 5: simplified analogRead() + original digitalWrite()
Elapsed Time: 243624 milliseconds (for 100000 analog reads)
Elapsed Time: 243621 milliseconds (for 100000 analog reads)

Case 6: original analogRead() + original digitalWrite()
Elapsed Time: 324387 milliseconds (for 100000 analog reads)
Elapsed Time: 324394 milliseconds (for 100000 analog reads)

*/&#60;/code&#62;&#60;/pre&#62;</description>
		</item>
		<item>
			<title>gbulmer on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105100</link>
			<pubDate>Sat, 21 Dec 2013 11:38:43 +0000</pubDate>
			<dc:creator>gbulmer</dc:creator>
			<guid isPermaLink="false">105100@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;tomxue - There are several causes for the ADC conversion time.&#60;/p&#62;
&#60;p&#62;The fastest ADC sample and conversion rate is 14 cycles, that is 1.5 ADC clock cycles to sample, and 12.5 ADC clock cycles to convert.&#60;/p&#62;
&#60;p&#62;1. Maximum ADC clock is 14MHz, divided down from system clock.&#60;br /&#62;
The ADC's clock divider is limited to a few division factors.&#60;br /&#62;
Dividing a 72MHz system clock by 6 (the nearest divider) gives a clock of 12MHz.&#60;br /&#62;
14 cycles at 12MHz is about 1.17us&#60;br /&#62;
If you want 1MHz conversion rate, then you need to change the system clock to 56MHz.&#60;/p&#62;
&#60;p&#62;2. There is quite a lot of instructions being executed within &#60;code&#62;analogRead()&#60;/code&#62; which are being repeated for every &#60;code&#62;analogRead()&#60;/code&#62;, but which may need to be done only once.&#60;br /&#62;
If you want to get closer to the raw-speed of the ADC, you'll need to understand the source of &#60;code&#62;analogRead()&#60;/code&#62;, and &#60;code&#62;adc_read()&#60;/code&#62;, so that you can strip away the parts which are constant for your application.&#60;/p&#62;
&#60;p&#62;You could get an estimate of the amount of time spent in extraneous code by commenting out the lines in &#60;code&#62;adc_read()&#60;/code&#62;&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;regs-&#38;gt;CR2 &#124;= ADC_CR2_SWSTART;
    while(!(regs-&#38;gt;SR &#38;amp; ADC_SR_EOC))
        ;&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;and running your measurements again. I guess it is a significant chunk of 0.5us.&#60;/p&#62;
&#60;p&#62;3. There are two interrupts running which will consume time.&#60;br /&#62;
One interrupt is the SysTick timer, which provides the timing for millis(). It is quite short, and only triggers each millisecond, so is probably adding less than 1% error.&#60;br /&#62;
The other interrupt is for USB. It this is a bit bigger than SysTick, and you might want to experiment with switching it off using:&#60;br /&#62;
&#60;code&#62;USBSerial::end()&#60;/code&#62;&#60;br /&#62;
before running the measurements, then on again, using:&#60;br /&#62;
&#60;code&#62;USBSerial::begin()&#60;/code&#62;&#60;/p&#62;
&#60;p&#62;You might also use two nested loops of tests, to get some results without the added overhead of interrupts. Maybe run test that last 50-100us. Store their results into an array, and at the end of your tests print them out, and throw away the outliers, which will contain interrupt time.&#60;/p&#62;
&#60;p&#62;To get a clock to measure the ADC conversion time, either use the micros() clock instead of millis(), or look at the source of micros() and use &#60;code&#62;systick_get_count()&#60;/code&#62; directly. That is counting at 72MHz, so it will give you a lot more precision. &#60;/p&#62;
&#60;p&#62;To use the systick count, instead of micros, copy and modify micros():&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;res = (ms * US_PER_MS) +
        (SYSTICK_RELOAD_VAL + 1 - cycle_cnt) / CYCLES_PER_MICROSECOND;&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62; to:&#60;br /&#62;
&#60;code&#62;res = (ms * US_PER_MS) + (SYSTICK_RELOAD_VAL + 1 - cycle_cnt);&#60;/code&#62;&#60;/p&#62;
&#60;p&#62;NOTE: The rate at which a signal can be sampled and converted is not only constrained by the sample and conversion speed of the ADC. The sampled signal needs to be able to drive enough current to charge the ADC's sample and hold. To reach a sample time of 1.5 ADC clocks (which gives a total sample and conversion rate of 14 ADC clock cycles), will require a low-output impedance signal source. Table 47 of the STM32F103xB data sheets says that the output impedance needs to be better than 0.4K, which is quite low.&#60;/p&#62;
&#60;p&#62;If the signal source has a bigger impedance, then the ADC's sample and hold circuit won't track the signal.&#60;/p&#62;
&#60;p&#62;&#60;strong&#62;Summary&#60;/strong&#62;:&#60;br /&#62;
- 1.17us is the ADC conversion time for a 72MHz system clock, only use 56MHz if it is essential to reach 1us&#60;br /&#62;
- there is code, which may be refactored out of the critical path, in &#60;code&#62;analogRead()&#60;/code&#62;, which likely improves speed by, maybe, 0.5us&#60;br /&#62;
- USBSerial interrupts may be stealing time, making the measurements look worse, so use shorter tests or disable it&#60;br /&#62;
- Make the tests much shorter than 1ms, and use &#60;code&#62;micros()&#60;/code&#62; or &#60;code&#62;systick_get_count()&#60;/code&#62; to time with enough precision.&#60;br /&#62;
- If the signal being sampled has an output impedance bigger than 0.4K, then the ADC sample and hold won't track it anyway; using the ADC at a high sample rate won't do any good.&#60;/p&#62;
&#60;p&#62;It is possible to use two ADC's to sample the same signal, called Dual ADC mode, which could double the conversion rate, though it is still constrained by the signals output impedance. There are a few threads on this forum discussing how to do that.&#60;/p&#62;
&#60;p&#62;(Full disclosure: I am not a member of LeafLabs staff.)
&#60;/p&#62;</description>
		</item>
		<item>
			<title>tomxue on "How to improve the maple mini&#039;s ADC sample rate to 1MHz?"</title>
			<link>http://forums.leaflabs.com/topic.php?id=74213#post-105093</link>
			<pubDate>Sat, 21 Dec 2013 02:42:53 +0000</pubDate>
			<dc:creator>tomxue</dc:creator>
			<guid isPermaLink="false">105093@http://forums.leaflabs.com/</guid>
			<description>&#60;p&#62;Hi,&#60;/p&#62;
&#60;p&#62;I used the code written by StephenFromNYC and modified it to try to achieve the highest ADC speed of maple mini, but failed. The code is below. My board is maple mini.&#60;/p&#62;
&#60;pre&#62;&#60;code&#62;#include &#38;lt;wirish/wirish.h&#38;gt;
#include &#38;lt;libmaple/adc.h&#38;gt;

#define COMM SerialUSB // use this for Maple
// #define COMM Serial // use this for Arduino

unsigned long start=0;
unsigned long stop=0;

unsigned long counter=0;

unsigned long limit=100000;
int outPin = 18;
int val = 0;

void setup()
{
  // the following line is needed for Maple
  pinMode(3, INPUT_ANALOG);
  pinMode(outPin, OUTPUT);

//  adc_init(ADC1);    //rcc_clk_enable(ADC1-&#38;gt;clk_id), Must be the first adc command!
//  adc_init(ADC2);
//
//  adc_enable(ADC1);  //ADC_CR2_ADON_BIT = 1
//  adc_enable(ADC2);
//
//  adc_calibrate(ADC1);  //Optional
//  adc_calibrate(ADC2);

  adc_set_prescaler(ADC_PRE_PCLK2_DIV_2);
  adc_set_sample_rate(ADC1, ADC_SMPR_1_5);
  // the following line is needed for Arduino
  // COMM.begin(57600);
}

void loop()
{
  COMM.println(&#38;quot;\nStarting loops:&#38;quot;);

  start=millis();

  counter=0;

  while (counter++ &#38;lt; limit)
  {
    //digitalWrite(outPin, HIGH);
    val = analogRead(3);
    //digitalWrite(outPin, LOW);
  }

  stop=millis();

  COMM.println(&#38;quot;Stop loops:&#38;quot;);
  COMM.print(&#38;quot;Elapsed Time: &#38;quot;);
  COMM.print(stop-start);
  COMM.print(&#38;quot; milliseconds (for &#38;quot;);
  COMM.print(limit);
  COMM.println(&#38;quot; analog reads)&#38;quot;);
  COMM.println(&#38;quot; val = &#38;quot;);
  COMM.println(val);
  COMM.println(&#38;quot; PCLK2 = &#38;quot;);
  COMM.println(PCLK2);
}

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
__attribute__((constructor)) void premain() {
    init();
}

int main(void) {
    setup();

    while (true) {
        loop();
    }

    return 0;
}&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;For the above code, if I apply those lines below, there will be nothing from my Serial Port monitor. So I have to comment them out. Why?&#60;/p&#62;
&#60;pre&#62;&#60;code&#62;//  adc_init(ADC1);    //rcc_clk_enable(ADC1-&#38;gt;clk_id), Must be the first adc command!
//  adc_init(ADC2);
//
//  adc_enable(ADC1);  //ADC_CR2_ADON_BIT = 1
//  adc_enable(ADC2);
//
//  adc_calibrate(ADC1);  //Optional
//  adc_calibrate(ADC2);&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;My Serial Port monitor shows:&#60;br /&#62;
&#60;pre&#62;&#60;code&#62;Starting loops:
Stop loops:
Elapsed Time: 190 milliseconds (for 100000 analog reads)
 val =
2119
 PCLK2 =
72000000

Starting loops:
Stop loops:
Elapsed Time: 189 milliseconds (for 100000 analog reads)
 val =
2138
 PCLK2 =
72000000&#60;/code&#62;&#60;/pre&#62;
&#60;p&#62;As you can see, the ADC read speed is around 1.9us/sample. But it could reach to 1us at most, how to achieve it then?
&#60;/p&#62;</description>
		</item>

	</channel>
</rss>
