AD conversion slows down PIC?

Discussion in 'Embedded Systems and Microcontrollers' started by AlucardSensei, Aug 19, 2012.

  1. AlucardSensei

    Thread Starter New Member

    Aug 7, 2012
    20
    0
    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:

    Code ( (Unknown Language)):
    1. int readAD(char channel)
    2. {
    3.     int value;
    4.     ADCON0 = 64 + (channel << 3) + 1;
    5.     DelayUs(2);
    6.    
    7.     ADRESL = 0;
    8.     ADRESH = 0;
    9.    
    10.     GO_DONE = 1;
    11.     while (GO_DONE);
    12.    
    13.     value = ADRESL;
    14.     value += ADRESH * 256;
    15.    
    16.     return value;
    17. }
    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?
     
  2. jwilk13

    Member

    Jun 15, 2011
    228
    12
    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).
     
  3. AlucardSensei

    Thread Starter New Member

    Aug 7, 2012
    20
    0
    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
     
  4. Markd77

    Senior Member

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

    Thread Starter New Member

    Aug 7, 2012
    20
    0
    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. :)
     
  6. jwilk13

    Member

    Jun 15, 2011
    228
    12
    Glad you got it figured out. Next step: use interrupts :)
     
  7. AlucardSensei

    Thread Starter New Member

    Aug 7, 2012
    20
    0
    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.
     
  8. jwilk13

    Member

    Jun 15, 2011
    228
    12
    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 ;)
     
  9. nigelwright7557

    Senior Member

    May 10, 2008
    487
    71
    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.
     
  10. AlucardSensei

    Thread Starter New Member

    Aug 7, 2012
    20
    0
    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?
     
  11. jwilk13

    Member

    Jun 15, 2011
    228
    12
    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.
     
Loading...