|
|
View previous topic :: View next topic |
Author |
Message |
Maniac0Maniac2
Joined: 26 Feb 2014 Posts: 6
|
A/D Double Sleep Problem |
Posted: Wed Feb 26, 2014 6:02 pm |
|
|
Hi everyone!
I'm trying to do an A/D conversion once a second, while keeping the PIC asleep for as long as possible. I want to sleep during the A/D conversion (a very short sleep, woken by the ADC interrupt), then execute another sleep (a longer 1 second sleep, woken by the watchdog timer).
I just cant get it to work! Run separately, I can get the sleep to work during the A/D conversion, and I can get the chip to sleep for 1 second so that the watchdog timer wakes it. But, when I put the two together it does not work. It looks like the A/D complete interrupt never fires and the WDT has to wake the chip. That means the A/D conversion takes a second to complete instead of a very short time.
I've been pouring over this for days and can't see why this is happening. Can anyone see anything I missed? I'm using PCH 5.008
Thanks
Code: |
//***********CHIP CONFIG***********
#include <18F14K50.h>
#device PIC18F14K50
#device ADC=10
#fuses INTRC_IO,NOPROTECT,NOLVP,NOBROWNOUT,PUT,CPUDIV1,NOMCLR,NODEBUG //,WDT,WDT256
#use delay(clock=32M)
//*************MACROS*************
#define LED_Green(){output_high(PIN_C5);}
#define LED_Off(){output_low(PIN_C5);}
//************MAIN LOOP************
void main() {
//Setup WatchDog Timer (for 1s wakeup from sleep)
SETUP_WDT(WDT_1S|WDT_ON);
//Setup the ADC
setup_vref (VREF_2v048);
setup_adc_ports(sAN4|sAN5|VSS_FVR);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(4);
delay_ms(1);
//Disable Interrupts
disable_interrupts(GLOBAL); //Don't need interrupts
while(1){
//Kick off ADC conversion and sleep
enable_interrupts(INT_AD); //We want the ADC to wake from sleep
clear_interrupt(INT_AD); //Clear ADC interrupt just in case
restart_wdt(); //Make sure WDT is reset
LED_Green(); //Turn on LED
read_adc(ADC_START_ONLY); //Trigger the ADC to start the process
sleep(); //Go to sleep and wait for ADC interrupt
delay_cycles(1); //NOP
//Woke up by ADC interrupt, so conversion is done.
int16 valADC;
valADC=read_adc(ADC_READ_ONLY); //Get the ADC value
//Disable ADC intterrupts
disable_interrupts(INT_AD); //No longer needed
//Short delay then turn off LED
restart_wdt(); //Make sure chip doesn't reset
delay_ms(50); //Delay 50ms so LED flashes
LED_Off(); //Turn LED Off
//delay_ms(800); //Wait a while before next conversion
sleep(); //Sleep until next loop is due (WDT to wake PIC)
delay_cycles(1);
}
}
|
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Feb 26, 2014 6:19 pm |
|
|
have you tried 5.020?
i'd start there. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Feb 26, 2014 7:12 pm |
|
|
There are parameters for sleep() given in the 18F14K50.h file:
Code: |
// Constants for calls to sleep() are:
#define SLEEP_FULL 0 // Default
#define SLEEP_IDLE 1 // Clock and peripherals don't stop
|
Read the PIC data sheet and pick the one that works. |
|
|
Maniac0Maniac2
Joined: 26 Feb 2014 Posts: 6
|
|
Posted: Thu Feb 27, 2014 4:42 pm |
|
|
PCM programmer -- spot on with that suggestion!
Sleep(SLEEP_IDLE) in the A/D section
Sleep(SLEEP_FULL) at the bottom
Works as expected - brought the power consumption right down! It's odd that Sleep(SLEEP_FULL) works for both separately, but not when I use them together.
Just blind curiosity, but it would be nice to know why this happens if someone out there has any insights!
My problem is solved thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Fri Feb 28, 2014 2:53 am |
|
|
You'd have to look at the assembler listing, but a 'guess', is that if you have just the ADC being used, and sleep,it doesn't clear the IDLEN bit, so gives sleep_idle. However when the watchdog is seen being used to wake it explicitly clears this bit. For either on it's own, this then works, but when both are being used, sleep_full will stop the ADC....
So when multiple sleeps are used, with one requiring the peripheral clock to stay running, you have to go 'explicit'.
Just a guess. Haven't got that particular compiler release.
As a comment, keep to the original C standard, and declare your variables either at the start of a function, or code segment. 'mid block' declaration, is a feature that was added to ANSI C, with C99. CCS allows it, but it has a 'habit' of causing some oddities, especially when used with more complex types, so better to stick to the older form. Stick to the C89 form for safety. It has gradually improved in CCS, and I haven't seen a problem for some months now, but I don't believe in 'looking for trouble'. There is no point in it in CCS (historically the idea is to reduce the scope of the variable, but as handled in CCS, the scope remains the same as when declared at the top of the code segment).
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|