Help me understand ADCs in microcontrollers

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello all,

 

this is an humble request, and I hope to find the right help as I have found before now on this forum. This particular phase of my project should have been completed, but I am stuck with the ADC which seems to be affecting the data received over the UART on my AT32UC3A1512 microcontroller.

using a data acquisition device such as the NI DAQ 6008/9, the graphical settings allow specifying values such as sampling rate, reference voltages, single ended or differential inputs, but this is not the case with microcontrollers. None of the tutorials, videos or blogs I have read/seen mentioned how to specify sampling frequency (this seems to be my major concern).

 

in my project, I need to specify a sampling frequency of 250Hz, how does a microcontroller do this effectively? Suggestions have been to use Interrupts. I have fairly new to programming, and do not know how to get this done. Yet to come across a suitable material as well. can someone please give me some guidance? What other alternatives are there to use of interrupts? how do i use them?

 

regards,

obabarin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For a 250 Hz sampling rate you need to trigger an ADC conversion every 4ms.  You could do this by setting up a timer that 'ticks' every 4ms.  You can detect and service that tick either by polling or (more likely and more efficient) by having the timer generate an interrupt.  In that interrupt code (ISR) you can trigger a new ADC conversion, do whatever else is useful (and you will probably find a 4ms tick very useful for other timing-related operations as well), and finally, read the new ADC value (after making sure the ADC conversion is complete).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR analog/digital converters have fairly narrow windows for their clock rate if you need full precision. They can't be too fast or too slow.

 

So, if you need to vary the sample rate beyond those limits, then you need to look for a different strategy. One that is frequently used is to trigger the ADC with a separate timing source. When this is done, it is common to run the ADC at the fastest available clock rate so that you have the greatest possible trigger frequency range.

 

How do you get these "triggers"? It is also quite common to use one of the internal timers to trigger the ADC. You can certainly use external trigger sources via an interrupt, but timers tend to be the most compact. Use of a timer does have on down-side: there is a timing granularity that is set by the timer's "clock prescaler" which down-counts from the MCU's clock to make a clock for the timer. You do not have a lot of flexibility on prescale values so you may not always be able to get the precise sample rate that you want. With tbis process, you can reduce the sample rate to fairly long intervals. To go longer, you need to count the trigger timer output and trigger the ADC after some number of triggers.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you wanting to sample only one channel (easy) or sequentially sample multiple channels (some what harder to do)? 

What AVR are you (wanting to use) are using?

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for all the responses.

 

@ki0bk, I am using the AT32UC3A1512 (https://www.microchip.com/wwwpro...), which has 8 channels from which I am using 2 channels to sample signals from a IQ-mixer. The sampled signals are then to be acquired, formatted and transmitted over UART to a Raspberry Pi.

 

@ka7ehk and @kiobk, I think I am using the internal timers to trigger the ADC as you stated, but my acquired signal at the receiver misses some values. My clocks are as follows:

OSC0 - 16MHz

PLL0 - 96Mhz

MainClock - 48MHz

PBA/PBB Clock -24MHz

CLK_ADC = PBA CLK = 24Mhz

AVR32_ADC.mr |= 0x2 << AVR32_ADC_MR_PRESCAL_OFFSET;   //adc clock of 4Mhz, throughput of 307.69kbps (following setup from microcontroller manual)

 

The ADC block of my whole code is as follows:

for(j=0;j<25;j++){//for2
			
			// launch conversion on all enabled channels
			adc_start(adc);
			
			// Acquire the I/Q channels
			Isample = adc_get_value(adc, I_CHANNEL);
			Qsample = adc_get_value(adc, Q_CHANNEL);
			
			// Creating byte 1
			temp1=0x8000;
			temp2 =((Isample & 0x00000300) << 5 );
			temp1=(temp1 | temp2);
			temp1= ((temp1 | 0x1000) >> 8  );
			temp2=((Isample & 0x000000F0) >> 4);
			IQsamples[k] = (uint8_t)(temp1 | temp2);
			
			// Creating byte 2
			temp1 =((Isample & 0x0000000F) << 4 );
			temp1= (temp1 | 0x08);
			temp2= ((Qsample & 0x380) >> 7);
			IQsamples[k+1] = (uint8_t)(temp1 | temp2);
			
			// Creating byte 3
			temp1=0x80;
			temp2= ((Qsample & 0x7F));
			IQsamples[k+2] = (uint8_t)(temp1 | temp2);
			
			
			if (k<75) {//specifies sampling frequency?
			cpu_delay_us(4000, 3*BOARD_OSC0_HZ); //sample rate of 4ms or 250Hz
			
			
			}//if
			
			k=k+3;
				
			
			}//for2

Where I have 2 channels; I_CHANNEL and Q_CHANNEL, and a buffer IQsamples that is to hold 75 bytes (of converted/formatted) samples every 4ms, which is expected to have 750bytes every second. The problem now is that, I do not get to read 750bytes/s at the receiver( a raspberry pi). The received data is mostly about 600bytes/s

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't see any evidence that you're using internal timers - the cpu_delay_us() just wastes cpu cycles. You want to use a real timer. Because there is only one ADC, the I and Q are sampled at different times - how are you compensating for this phase difference? Usually, with only one ADC, you would use an external sample and hold circuit for your inputs so they get sampled at the same time, then individually converted by the one ADC.

 

You've told us nothing about your uart code - could that be a bottleneck? Everything takes time - how long and how significant is the question.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now I must agree I have little or no understanding of internal timers and interrupts. All this while, I thought the cpu_delay_us was providing sampling frequency ( the codes are not entirely original to me). May I ask please, where/how can I get started with learning the use of timers/interrupts. You passed too much information I am having a hard time to wrap my head around.

 

For the uart code, I 'developed' (using internet resources) some C/C++ and Python programs to capture data from serial port. They both had same issues of acquiring 'insufficient' data. I then found grabserial on github (https://github.com/tbird20d/grab...) which I suppose was developed by someone with better expertise. All codes worked only to acquire sufficient data is the issue.

 

Given your submission and from experience, I am ruling out the possibility of the uart having a problem, and narrowing down the issue to the adc/microcontroller. Though, when used matlab on a windows pc, I could capture a preset amount of data. Such that if I need capture 750 bytes, I just specify the amount, but that usually take matlab longer than 1 second to capture it- not in real time. I want a real time solution, and using matlab/pc is not suitable for site deployment.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Before we get to bogged down in the finer details, what time precision do you require from the system? You say 4ms plus or minus what?

Your uart code is probably contributing to your timing problems. And why are you using an AVR32? Not many people around here use them and are not likely to due them going obsolete.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A sampling of 4ms is quite good for my application. It could be a higher but lowest will be 100Hz.

 

And why the choice of AVR32?

It is not entirely my choice, and from what I have read on this forum, I will not be using it in the future for other projects.

I came to be using it in an effort to continue/conclude a previous project whose first phase was terminated in 2015. From 2016 onwards, I started with the other phase, but it will be impossible for me to just change the microcontroller abruptly. The controllers are to program the PLL on a radar board, and sadly, some of the components on the radar boards are going obsolete as well, so a new design is necessary. Irrespective, I have to conclude this phase, and that has to do with transmitting acquired data to Raspberry Pi and storing for further processing.

 

On the side of the Raspberrry Pi, I got to know that there are 2 uart ports, I configured mine to use the faster. Though I did not notice much difference in both.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why don’t you sample the data using a sound card with the raspberry pi? The stereo inputs are sampled concurrently and at fairly precise intervals.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestion. But that could complicate my projects. More so, with the previous explanation as above, it does not look like I am having a hardware problem, looks more like coding/programming problem.

 

I am considering Texas Instrument's ADS1115 just in case I have an hardware problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What baud rate is your serial comms?

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
static const usart_options_t USART_OPTIONS =
	{
	
		.baudrate     = 115200,
		////.baudrate     = 230400,
		////.baudrate     = 9600,
		.charlength   = 8,
		.paritytype   = USART_NO_PARITY,
		.stopbits     = USART_1_STOPBIT,
		.channelmode  = USART_NORMAL_CHMODE
	};

My baudrate is 115200. I did use up to 230400 and as low as 9600, but still wont achieve the 750bytes per second desired.