The sampling rate of an ADC is directly proportional to the SPI clock rate, meaning faster SPI clocks enable faster sampling. For the MCP3008 ADC, at 3.3V power, the recommended SPI clock rate is 2.34 MHz, which allows reading all 8 channels at approximately 70,000 samples per second (8,777 samples per channel). This is significantly faster than I²C ADCs like the ADS1115 (860 samples per second). The minimum pulse width that can be reliably detected depends on the sampling rate: at 2.34 MHz, pulses as narrow as 114 microseconds can be detected, while at the slower 1.35 MHz rate, pulses need to be at least 178 microseconds wide to ensure detection.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
MCP3008 ADC - Sample Rate in Arduino at 3.3v?
Added:I'm using this test setup to see how fast I can get the MCP3008 10-bit ADC working. It has eight channels, can operate between 2.7 and 5.5 volts, and has an SPI interface, so it should be way faster than an I²C ADC.
I'm using an ESP32 S3 to interface with the ADC over SPI, and I'm using the cheap yellow display serial terminal, so I can see output from the ESP without needing to be near a laptop. So, what I'm doing is for intervals of 1 second, I'm reading all eight inputs as fast as I can, calculating how many samples per second I'm getting, and I'm changing the SPI clock and retesting for three different clock rates just to see how that impacts my ability to read inputs as fast as possible. And because I'm using the surface-mount version of the chip, I'm using one of those surface-mount to through-hole adapters to use it in a breadboard, and right on the VDD to ground pins, I have a 1 micro 0805 surface-mount capacitor for local decoupling, and VDD is tied in common with Vref, so the ADC is going to have a reference voltage the same as whatever I'm powering at. In my case, I'm running at 3.3 volts, so Vref is also 3.3, and my inputs can read between 0 and 3.3 volts. If I were to power this at 5 volts, which is the max, Vref would also be 5 volts, and I could read from 0 to 5 volts. So, in my case, all I want to test is how fast can I get this going.
I'm not really testing things like linearity across the input voltage range. All I really want to be able to do is pick up some sudden transient pulses of a narrow width, So, if it happens to go from say a center line between 0 and 3.3, if it goes from 1.65 volts up to 3.2, I don't even mind if it tells me it's 3.15 or something, as long as it can pick up a narrow spike. We could get theoretically up to 200 kilosamples per second if we were running at 5 volts.
And if we're down at 2.7 volts, we could get 75k samples per second max. And in table 6-1 in the data sheet, it says at 3.3 volts, we may be able to get 130k samples per second. And the data sheet suggests, depending on our power supply voltage, it's recommended to use 1.35 megahertz SPI clock if using 2.7 volts or a 2.34 megahertz clock at 3.3 volts. And we may be able to go 3.6 megahertz or more at 5 volts. Because it also depends on our wiring, and I'm not using a custom PCB with ideal short connections for the SPI, but I'm also not using unnecessarily long Dupont jumpers. I just cut a bunch of 22 gauge solid wires just for the length I needed to go from the module to the ESP32 S3. And I'm using a function generator to generate pulses. The frequency is 1 hertz. So, we're getting one pulse per second, then the next pulse. And it's measuring the top voltage, 3.28.
So, to get some more of the measurements for time of the pulse and its voltage, I'm going to zoom back in. Now, it's 200 microseconds per division. So, the on time of the pulse right now is 1.7 or so milliseconds. And then it's going to be low for the rest of the 1 second interval, and then just another narrow pulse. And that's what I'm trying to see how narrow can I make this and still pick it up on the ADC. So, right now it's saying the max voltage is 3.28 volts, and the low signal is slightly above ground. So, on the ADC, it's not going to measure zero. It's going to be zero point something. And on the function generator, as I change duty cycle, I can make that pulse very narrow, and I will do that while testing. As for the schematic for this, I don't really have one, but in the sketch for this ESP32-S3, it'll say what pins I used for SPI. And to go to the serial monitor, I'm on this transmit pin on UART zero, and I'm powering the serial monitor from 5 volts and ground. But, a note, I couldn't take it from the USB 5 volts on the 5 volt pin of this ESP module. It was actually measuring only barely 4 volts, so it must be going through a heavy diode drop. But, I wasn't able to get this to power up. So, I'm just using this other USB connector up here, plugged into a charger, so I can just get 5 volts and ground, and I tie the ground in common.
So, 5 volts and ground from that extra USB to power this, tying that USB ground in common with the ESP. Then, the receive in of the serial terminal is connected to the transmit out up in the corner of this ESP module, which is UART zero transmit out. And in order to get the text showing up on that pin, in the Arduino IDE tools settings, I had to disable USB CDC on boot, because that's what chooses whether we get our serial output going over USB or going to this GPIO. So, I had to disable CDC on boot and then I was getting external UART serial text here. So, aside from looking in the sketch to see what pins I'm using for SPI connections, here I wrote down actually the GPIO on the ESP32-S3 being used for these various SPI connections to the chip. Digital and analog ground are just connected to ground. Vref for the ADC, I soldered a jumper over to VDD and I'm running it at 3.3 and I have that 0805 1 micro directly connected between these two pins and this ground pin right on the module as close as I could get. Then I just connect my analog inputs over here and run the sketch. And I'll check some voltages. So, input channels 0 and 1 are in common and they're going to that function generator sending out the pulse that I'm trying to detect. Then, channels 2, 3, and 4 all go to 3.3 and 5, 6, and 7 just go to ground. So, if I probe between ground and the actual ground input, it's reading basically 0 V on the voltmeter, but on the ADC, of course, we're going to pick up some fluctuations. And probing the 3.3 V connection directly on the input, I'm measuring 3.29.
So, those are the benchmarks to be looking for on the serial monitor. I'm letting this run at each SPI frequency, then I'm going to pause. Now I can scroll in the buffer. What I'm doing is reading all eight channels as fast as I can and I'm trying to log the minimum and maximum measured voltage within each of the 1-second intervals. So, as I read samples, I check is this a new minimum or a new maximum voltage? And if so, we log it. Then at the end of 1 second of acquisition time, I've got min and max readings for all eight channels. So, in this case at 1.35 MHz, the final three channels that are connected to ground, the minimum was 0.0 V and the maximum for the grounded input is something like 0.08 V. For the three channels measuring the 3.3 rail, which the multimeter said 3.29 something, and the ADC measures min and max 3.3. So, I guess because we're at the upper end of the range, and we know in reality we're very close to 3.3, that's good enough. And those first two channels both measuring the same oscilloscope pulse, on both channels the minimum voltage picked up is around 0.17 or 0.18 V, which is okay cuz we know on the scope it's above ground somewhat.
And for the maximum, it's measuring around 3.24 V top. And on the scope, I maximize the vertical scale, we're getting 3.28 as a top. But also, we can kind of see it's a little higher right at this peak and then it kind of droops a little bit. If this says the top is 3.28, it probably means right at the first part of the pulse and then it drops a bit. So, if I'm picking up 3.24, somewhere along the middle or end of the pulse, that's good enough for me. And at the SPI clock of 1.35 MHz, we've calculated on an individual channel out of the eight, we're getting 5636 samples per second, so 5.6 K. And overall, considering we are measuring eight channels, our sample rate is 45 K samples per second. So, if we weren't measuring all eight, if we were just measuring one channel over and over to get it as fast as we can, it should be around 45 K samples a second. So, this is way better than using one of those I squared C modules like ADS1115 where you can get maybe 860 samples per second, but we can do even better if we scroll at 2.34 MHz SPI clock, which should be considered reliable at 3.3 volts when reading all eight channels.
Per channel, we're getting 8.77 K samples a second or overall, if we were just reading one channel, it's around 70 K samples a second. And we're getting the same kind of readings on the inputs when we increase the SPI clock rate to 3.6 MHz, that's only considered stable for 5 volts, but I just wanted to see.
If we really wanted to push it, we could run it at this. I'm seeing more accuracy on the 3.3 because now it catches that the minimum is actually 3.29 or so and the max it saw was 3.3. So, I'll resume the serial logging and I want to focus on the 2.34 MHz data now.
So, 8777 samples a second for one channel. 1 / 8777, that is 114 microseconds, which is the interval between reading one sample and reading another sample.
So, I just changed the scale to 100 microseconds per division. So, the ADC, if it reads a sample at this point in time, just over 100 microseconds later, it's going to read another sample on the input and just over for microseconds again, it's going to read and then on and on. So, this pulse, I'll bring the scale back. This being 900 microseconds, we would have multiple chances to read this peak if we were trying to detect this sudden rise to 3.3. So, I just reduced the pulse width down to 130 microseconds.
So, I should be able to get at least one reading in this pulse. And on the ADC, that should register as the maximum voltage detected within 1 second. And the low detected in 1 second is going to be whichever was the lowest out of all the ground readings. So, I'm going to let it go right here, 2.34 MHz, and pause. The minimum low is 0.18, and the maximum, 3.235 V. So, it did pick up our narrow pulse width of 130 microseconds. And looking back at the slower 1.35 MHz SPI clock, we also picked up 3.23 V as the max. So, we were able to pick up that narrow pulse. Now, I'm changing it 99.18 microseconds wide. So, that's a little bit narrower. The target is to be able to pick up something 114 microseconds wide. So, we're not quite that wide, but let's see if we happen to land on it at 1.35 MHz SPI. We're still measuring 3.23 V max. Although, at the faster SPI, 2.34 MHz, one of those two input channels, because we have two in common, it measured the 3.23, but the other analog input with the exact same signal was only measuring 0.2. So, that's fine, because we know we're only going to pick up this signal by chance now. Sometimes we might sample right when it went high, and the next time we might miss it and sample just after it and get a low reading. So, with the signal generator, I can only set the pulse widths in certain increments when it's this narrow. So, I have it at 114.44 microseconds as measured here. If I change the horizontal scale, it's still 114.44 microseconds. So, that's right on the edge of being able to detect a max 3.3 V when we're running the SPI at 2.34 MHz.
So, we're doing enough samples per second to lock on to a logic high. Going down to the serial monitor, I'm waiting for this to spin around. So, at 2.34 MHz, we did pick up the logic high on both of those inputs that are in common, same on the even faster SPI bus. But, on the slow 1.35 MHz, one channel saw 3.3, but the other one didn't pick it up. It looked like it picked up ground. And that makes sense because when we say we're looking to be able to detect a 3.3 V signal that lasts 114 or more microseconds, that's when the SPI is at 2.34 MHz. If we're running SPI slower, we may very well not pick this up because we aren't sampling as fast, so we miss the occasional pulse. So, just looking at the number of samples per second, we are reading at the slowest 1.35 MHz SPI clock rate, one over that many samples, we should be able to pick up a pulse that is, let's say, 178 microseconds wide or wider. Now I changed it to 183 microseconds at 3.3 volts every 1 second. So now even at the slowest 1.35 MHz SPI rate where we are sampling the slowest, we should still be able to always say the maximum voltage we see in a 1 second interval is 3.3 because we are holding this long enough that we should take a reading maybe somewhere at the beginning sometimes and if so, we might even get a second reading close to the end of this. So we might actually get two 3.3 volt samples within a second, but we should get at least one whether we land toward the beginning, the middle, or the end, we should be able to always pick up 3.3. So I'm going to wait for this to show the 1.35 MHz clock and we do have 3.2 something volts on both of those inputs. And of course, when the clocks running even faster, I expect to pick up 3.3 volts. Back at 1.35 MHz, both inputs are 3.3 volts max.
So that's what I was testing with this setup and that's with this sketch as optimized as I could get by looking at example sketches out there. I'm controlling the SPI chip select with direct GPIO access bypassing the Arduino digital write, which is slower. But as I add more functionality to a sketch to get something actually doing something useful with these readings, this is going to start reading slower. I don't know how it's going to go, but for now, I know the width of a pulse I'm able to detect at various SPI clock rates, so I can make some decisions and be able to pick up a momentary transient spike here and there. For example, if I'm using a transducer to pick up voltage impulses like when you strike this, you send out a momentary pulse. I don't know the characteristics of the signals I'm going to be picking up, but that's what I'm trying to get toward. I want to be able to have a possibly narrow peak that I can detect the maximum and then process that I picked up a signal. So, still working toward the overall final project, but so far so good.
Related Videos
BMW Built A Radial Engine So Good It Made The Spitfire Obsolete Overnight
MachineTitans999
123 views•2026-06-18
UÇAK MOTOLARI ÇALIŞMA PRENSİMİ
PistonTV
428 views•2026-06-17
The Bizarre Design Flaw That Ruined The Convair 990
Jet-Deck
631 views•2026-06-19
Why Are Rocket Nozzles Bell-Shaped? Propulsion | Aerospace engineering | GATE | Viru Sir IITian
conceptlibrary
189 views•2026-06-15
US Navy's Helios laser tech
Striketech0310
6K views•2026-06-18
NEW ENGINEERING DESIGN FOR IAM MARWA APPALOOSA FARM @iammarwa
findingian001
443 views•2026-06-17
The Air Force Built a Jet With Wings Swept the Wrong Way
TheAbsurdArchiveYT
639 views•2026-06-16
China Is Building a Machine the World Can’t Stop
TechAIVision-f6p
192 views•2026-06-15











