AD conversion slows down PIC?

Thread Starter

AlucardSensei

Joined Aug 7, 2012
20
Hey guys, got some problems with my PIC again. :D I was trying to set up an AD converter for my pic16f877a and I've managed to with moderate success, but I've encountered a problem here: seems that the converter cannot keep up with the speed of the rest of the system and clogs it up. I've got almost the entire space in terms of pins used up, got an LCD screen, a rotary encoder and almost 2 dozen of other pins used as output, so might it have something to do with it? The rest of the system works at around 250Hz, but once I start up the reading of the analog inputs, it slows down to maybe 3-4 cycles per second. Here's the code for the reading of the encoder:

Rich (BB code):
int readAD(char channel)
{
	int value;
	ADCON0 = 64 + (channel << 3) + 1;
	DelayUs(2);
	
	ADRESL = 0;
	ADRESH = 0;
	
	GO_DONE = 1;
	while (GO_DONE);
	
	value = ADRESL;
	value += ADRESH * 256;
	
	return value;
}
A pretty simple code, but there seems to be a problem somewhere in there, I'm guessing it takes too long to read the voltage? I've tried fiddling with different frequencies for the converter and even setting it to work only once every several (dozen) cycles, but to no avail. Did I push my PIC to its limits or is something else at play here?
 

jwilk13

Joined Jun 15, 2011
228
I imagine the DelayUs(2) is slowing it down. It sits there and doesn't do anything else during those 2 us. What frequency is your PIC operating at? I'm guessing that's not 250 Hz...

Also, you might try doing it on an interrupt basis, then you don't have to use delays. You can set an interrupt to occur when the A/D is done taking a reading, that might help make it go a bit quicker (see page 25 of the datasheet for the proper register).
 

Thread Starter

AlucardSensei

Joined Aug 7, 2012
20
Yeah, the oscillator of the PIC is at 8Mhz, but I've put in a delay of 4ms for every cycle of the program, since I need to measure time, and I don't really need smaller increments than that. On the other hand, the readAD function I copied from a book, and I never could've imagined that delay could cause such an issue, let alone a delay as little as 2 microseconds, i thought the problem was in the while loop. But then again, if it works at 8Mhz, that's only a 0.125 μs from one cycle to the other? Anyway, excuse my ignorance, since I'm new at microcontrollers, and thanks for your help, it's greatly appreciated. :D
 

Markd77

Joined Sep 7, 2009
2,806
I'm not a C programmer, but I'd recommend stepping through it in the simulator and seeing which line causes the biggest delay.
 

Thread Starter

AlucardSensei

Joined Aug 7, 2012
20
Actually jwilk13 was right about what was causing the issue (i might've worded that confusingly in the last post), and it's sorted out now. :)
 

Thread Starter

AlucardSensei

Joined Aug 7, 2012
20
I actually am, I've got the incremental encoder working with interrupt on change, but for 16f877a there's only PORTB pins 4-7 for the interrupt on change, so I've pretty much used up my pins.
 

jwilk13

Joined Jun 15, 2011
228
I actually am, I've got the incremental encoder working with interrupt on change, but for 16f877a there's only PORTB pins 4-7 for the interrupt on change, so I've pretty much used up my pins.
Oh, I was talking about using the "A/D Conversion Complete" interrupt. Page 129 of the datasheet has some info on that. Maybe you're already doing that too though ;)
 
But then again, if it works at 8Mhz, that's only a 0.125 μs from one cycle to the other?
The PIC requires 4 cycles for an instruction and 8 if its a call/branch.
So its 500nS per instruction cycle at 8MHz.
Bear in mind the A2D conversion takes quite a few clock cycles. It makes up the a2d value one bit at a time so takes a while.
 

Thread Starter

AlucardSensei

Joined Aug 7, 2012
20
Oh, I was talking about using the "A/D Conversion Complete" interrupt. Page 129 of the datasheet has some info on that. Maybe you're already doing that too though ;)
Ah, I actually wasn't using that. I've tried now changing it to use the interrupts, but then I got another problem. I've enabled peripheral interrupts (PEIE bit), AD conversion interrupts (ADIE bit), I'm checking for the AD interrupt flag in my interrupt routine and I've set up a starting reading of the AD conversion to jump start the interrupts, like I've read somewhere on the internet, but then everything else in my main loop stops working (which is basically button presses and interrupt on change routines, all on other ports than the AD convertors). What's the problem here? Does the AD interrupt somehow override the behavior of other pins or is something else the matter here?
 

jwilk13

Joined Jun 15, 2011
228
Ah, I actually wasn't using that. I've tried now changing it to use the interrupts, but then I got another problem. I've enabled peripheral interrupts (PEIE bit), AD conversion interrupts (ADIE bit), I'm checking for the AD interrupt flag in my interrupt routine and I've set up a starting reading of the AD conversion to jump start the interrupts, like I've read somewhere on the internet, but then everything else in my main loop stops working (which is basically button presses and interrupt on change routines, all on other ports than the AD convertors). What's the problem here? Does the AD interrupt somehow override the behavior of other pins or is something else the matter here?
Hmmmmm...I guess the A/D conversions could be happening too fast...

What I normally do is set a timer (like Timer0) to overflow every so often (you can pick a number based on how often you need to take readings). When this timer overflows, I get an interrupt. Inside the ISR I do the following:

1) Stop the timer
2) Start my A/D readings (GO bit of ADCON0 for me)
3) Reset the interrupt flag
4) Push a value into Timer0 (to get the proper interrupt rate)
5) Restart the timer

This way, you get ADC readings at preset time intervals. Might be worth trying. Then I have a separate ISR for the A/D interrupt. Everything in my main loop still functions properly, as long as I space the A/D readings far enough apart.
 
Top