If you took in the Borg representation from part 1, then you now know of the gap that is between the analog world and the digital one. We need to setup our hardware to sample this analog universe and to do this we are going to be using the MicroChip dsPIC33EP512MU810 MCU to do it.
Some parts aren't made like the others. There are MCUs manufactured today that have the processing of analog signals core to its functionalities. Most notably are those CPUs with a DSP peripheral, also known as a hardware accelerator. Speed is important and should be selected based on the type of signal you are going to be evaluating. One potentially fatal mistake is selecting an ADC that you will be pushing to its published limits. For example: I need to sample a frequency of 450 kHz at high resolution. The published maximum for the ADC on my MCU is 500 kHz. At first blush it looks like it would fit into your window but in reality, if your MCU is going to be doing something other than sampling data, chances are you are going to be missing sampling times, over-running your buffer, or simply not going to be able to keep up with the data inflow. Some experimentation may be involved but as a rule of thumb, if your stated maximum is 500 ksps (500 thousand samples per second) you would look at it as half. That will allow you some CPU headroom to do other tasks if needed. If you are looking for single shot readings, like measuring battery level or light levels, then any hardware will do.
As part of the component selection, we turn to our best friend in the whole world, the datasheet. In the datasheet for the dsPIC33EP MCUs in the ADC section we find the following:
When using a 10-bit sample, conversion speeds up to 1.1 Msps (million samples per second) or when sampling at a higher resolution, 12 bits, up to 500 ksps. This means that not only do you have to consider your frequency you want to sample but the resolution as well. Any reason why the number of samples are so different from one another? Clock cycles?
ADC Peripheral Setup
MikroC has a beautiful library included with each compiler. The ADC library. Inside each library you have just a handful of functions:
ADC_Init() initializes the ADC.
ADC_Get_Sample() retrieves a sample from an already initialized ADC.
ADC_Read() Initializes a non-initialized ADC and samples a reading from the selected channel.
An important distinction needs to be made between the Get_Sample() and Read() functions. Get_Sample is the fastest way to read from and ADC, it assumes you have already called ADC_Init() and have an already initialized ADC peripheral. Read() on the other hand is a very code compact way of getting a single sample by initializing the ADC, reading the value, and returning that 1 sample back to the calling function.
The question remains, can we use this library in a signal analysis type of scenario? The answer, not really. The ADC library was meant for static ADC measurements in a single shot fashion. No timing information is known on the ADC so you have no idea of the conversion time. These calls are primarily for things like reading battery voltage, metered readings in things like current levels, or in sensors that the swings in readings do not rapidly change, like humidity.
Speed -> Timing
Timing is critical because it takes time to convert the analog world to a digital one. This conversion time takes a number of clock cycles and by doing so, we need to know how fast the clock cycles are moving the ADC. If we have a slow clock, then we have slow ADC results. A faster clock means faster results, but of course everything has a cost.
So how would I setup the ADC to read at a measured and precise time period? We need to setup a known number of clock cycles. For this we need to turn to our oracle, the datasheet.
Our ADC has a clock apparently! Clocks are used for timing, therefore we can assume that our ADC conversions can be timed. To modify the timing, from the above diagram, we are going to be using a clock source and possibly a PLL or clock multiplier to adjust the clocks "tick" period. This is a crucial concept to understand, our ADC clock requires a number of cycles to complete a conversion. It takes 12 cycles for a 10 bit conversion and 14 cycles for a 12 bit conversion (Tconv Time). This does not, however, mean that we can drive the clock at light speed to get faster results. The hardware itself has a minimum of 333.33 ns when operating at 4.5 Volts and 666.7 ns when below this voltage.
You might ask, "hey, where did you find the number of cycles per conversion"? Glad you asked. The answer, datasheet:
We can also choose between alternate clocking sources. From the diagram we can change the source based on the ADxCON3<15> register bit 15. The choices appear to be an internal clock or system clock that can be multiplied via the ADxCON3<7:0> register bits 0 through 7. To get more details about the registers we go to the register definition in the datasheet.
We can also see the detailed description of each bit just below the chart:
And the Conversion clock select bits:
Like all our datasheets, the engineers who wrote them play a sick joke on us by replacing simple words with acronyms.
"OK, OK, so how do I figure out how much time I need to set my ADC clock to?? Just tell me the answer, don't bore me with details..."
To calculate the ADC clock, we need to know beforehand what speed we want to sample at and what speed our CPU will be running at.
Want to sample at 70 kHz at 10 bit resolution. I'm looking for frequencies between 10 kHz and 35 kHz. (You would know why we chose those numbers based on ADC Part 1)
What we are looking for: 70,000 * 12 = 840,000 Tad cycles
So our sample speed needs to be 1 seconds / 840,000 cycles = 1.19 e-6 or 1.19 us.
Our main CPU is running at 140 MHz or 1 seconds / 140,000,000 cycles = 7.14e-9 or 7.14 ns.
Our formula to calculate Tad is in the datasheet:
Tp * (ADCS < 7:0 > + 1) = 1 * Tcy = Tad
We want to find out what our ADC bit selection needs to be to get us the speed on the ADC needed. With a little bit of algebra, solving for ADC we get:
X * Tcy = Tad = x * 7.14e-9 = 1.19 e-6 = 166.667
So our ADC bits need to be 166.667 rounded to 166.
If we were going to be sampling on ADC 1, our initialization would start with:
AD1CON3 |= 0xA6; // Clock selection of system clock source and clock select bits of 166
From here we could enable the ADC and the channel we wanted to read and the ADC would take care of the data, all we would need to do is read it at the right speed. You could setup a timer interrupt of 70 kHz and read the ADC. That's one way. We will get into more productive ways of sampling data in part 3.
We want to digitize our world but first step is to evaluate what we are looking for. Once we have established what frequencies we are looking for, we can start laying the ground work for ADC conversion. The clock is one of the more crucial parts because it will be the regulator on the timing of those conversions. We've established the clock but does our hardware support it? This is where we consider the hardware and the underlying silicon that we must rely on to do our digital conversion. In the next section we will take this idea further and decide on how we sample, do you have the ADC sample on its own or do you manually command the conversion process. We will also look at where the converted sample goes once it is finished. All important concepts.