CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

USB and Sleep

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jspencer



Joined: 22 Dec 2003
Posts: 57
Location: Boise, ID USA

View user's profile Send private message

USB and Sleep
PostPosted: Tue Mar 21, 2006 9:56 am     Reply with quote

I am working on a project that has a portable unit that needs to sleep when idle, then at some point gets plugged into the usb and downloads some data. When I call sleep() anywhere in the code it appears that the USB will not attach and enumerate. If I take the sleep function out it works just fine, I have a feeling that there is something that I am missing. I've looked through the application note, and it seems like I'm doing everything correctly. Has anyone had any experience with something like this? Also here is a snippet of the code

Code:

#define DEBUG_PLATFORM
//#define RELEASE_PLATFORM

#ifdef DEBUG_PLATFORM
#include <18F4550.h>       // This must be the FIRST include!
#endif
#ifdef RELEASE_PLATFORM
#include <18F2455.h>       // This must be the FIRST include!
#endif

#include "viper.h"
#include "viper_led.h"
#include "viper_usb_output.h"
#include "viper_globals.h"
#include "viper_tag.h"


//******************************************************************************
// TIMER0_isr()
//    The RTCC timer interrupt occurs a few times a second.  We use the isr to
//    monitor the state of the system and toggle the appropriate LEDs.
//    See comments below for the specific states that are monitored.
//
//    NOTE: the ordering of the state checks is important because although
//    multiple flags could be set at the same time, we only want to process the
//    most important state.
//******************************************************************************
#int_timer0
TIMER0_isr()
{
   // The isr is triggered too quickly for some desired led toggle behavior.
   // This counter is used to keep track of how many times we have entered the
   // isr and only toggle an LED on the n'th entry.
   if( global_interrupt_count++ == 127)
   {
      global_interrupt_count = 0 ;
   }

   // The global usb mode indicates that we are connected via USB.  This
   // puts us in USB mode and we ignore everything else.
   // This is the highest priority state so it is checked first.
   if(global_usb_mode == true)
   {
      // Just keep the green led on constantly...
      led_set_red(false) ;
      led_set_green(true) ;
   }
   // The global memory full state indicates that there is no more room on the
   // device for downloading tags.
   else if(global_memory_full_state == true )
   {
      // The isr is triggered faster than we want the leds to flash in this state
      // so only toggle the leds every 4th time we enter the isr.
      if( (global_interrupt_count % 4) == 0 )
      {
         led_toggle_amber() ;
      }

      if (global_memory_full_counter++ > 50) {
         global_memory_full_counter = 0;
         // Need to make sure that we set this to false so that it doesn't turn
         // green after we turn the memory full state to false.
         global_download_complete = false;
         // Set this to false just so it stops flashing, once you probe again it
         // will flash memory full again until we turn it off.
         global_memory_full_state = false;
      }
   }
   // The global download complete state indicates that we have completed a
   // successful download of data from an external tag.  Be sure that the RED
   // led is turned off, or we will end up with an amber light.
   // We want this led to stay on every time the isr is triggered.
   else if( global_download_complete == true )
   {
      if (global_download_complete_counter >= 40) {
         global_download_complete = false;
         global_download_complete_counter = 0;
         led_set_red(false) ;
         led_set_green(false) ;
      } else {
         led_set_red(false) ;
         led_set_green(true) ;
      }
      global_download_complete_counter++;
      //global_downloading = false;
   }
   // The global downloading state indicates that we are actively downloading
   // data from an external tag.  Be sure that the RED led is turned off, or we
   // will end up with an amber light.
   // We want this led to flash really fast so do it every time the isr is triggered.
   else if( global_downloading == true )
   {
      led_set_red(false) ;
      led_toggle_green() ;
   }
   // The download error state indicates that we had a download failure.
   // We want this state to toggle the led really slowly so only do it every 8th
   // time the isr is triggered.
   // This is the lowest priority state so do it last.
   else if( global_download_error_state == true )
   {
      if( (global_interrupt_count % 8) == 0 )
      {
         led_set_green(false) ;
         led_toggle_red() ;
      }
   }
   // Finally, if we are not in one of the recognized states, make sure the led
   // are off.
   else
   {
      led_set_green(false) ;
      led_set_red(false) ;
   }

}

//******************************************************************************
// ext_isr()
//    This interrupt is triggered by PIN_B0 going from low to high and indicates
//    that the probe was connected to a Tag (or some other conductive surface :-)
//******************************************************************************
#int_ext
ext_isr()
{
   // Set the global tag ready flag.  The main loop waits for this flag and
   // when it is true it will read the tag's eeprom into the internal buffers.
   if (!global_download_complete && !global_downloading && !global_tag_ready) {
      global_tag_ready = true;
   }
}

//******************************************************************************
// viper_device_setup()
//    Perform the device specific setup.
//    Device agnostic setup methods are performed in viper_post()
//******************************************************************************
void viper_device_setup()
{
   #ifdef DEBUG_PLATFORM
      setup_adc_ports(NO_ANALOGS|VSS_VDD);
      setup_adc(ADC_OFF);
      setup_psp(PSP_DISABLED);

      setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
      setup_timer_1(T1_DISABLED);
      setup_timer_2(T2_DISABLED,0,1);
      setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
      setup_comparator(NC_NC_NC_NC);
      setup_vref(FALSE);

      setup_low_volt_detect(FALSE);
      setup_oscillator(False);

      setup_wdt(WDT_ON);
   #endif

   #ifdef RELEASE_PLATFORM
      setup_adc_ports(NO_ANALOGS|VSS_VDD);
      setup_adc(ADC_OFF);
      setup_spi(FALSE);
      setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16);
      setup_timer_1(T1_DISABLED);
      setup_timer_2(T2_DISABLED,0,1);
      setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
      setup_comparator(NC_NC_NC_NC);
      setup_vref(FALSE);
      setup_low_volt_detect(FALSE);
      setup_oscillator(False);
      setup_wdt(WDT_ON);
   #endif
}



//******************************************************************************
// viper_post()
//    Viper Power On Self Test.
//    First, perform the device specific setup.
//    Then do the rest of the setup and self-test.
//******************************************************************************
void viper_post()
{
   boolean status = true ;    // Status of self-tests

   // Visually indicate that the POST has begun.
   led_post_start() ;

   // Setup the device specific settings.
   viper_device_setup() ;
   
   // Initialize USB
   usb_init_cs();

   restart_wdt() ;

   // Turn on the red led just in case one of the self test routines hangs.
   // In all likely hood the user will never see the red led on, but if we hang
   // it will become apparant that something is wrong.
   led_set_red( true ) ;

   // Initialize the non-volitile and volitile global memory variables.
   // Non-volitile memory is stored in the internal eeprom.
   global_init_memory() ;

   // Initialize and test the external eeproms.
   init_ext_eeprom();
   if( !ext_eeprom_ready(BANKA_HW_ADDR))
      status = false ;

   restart_wdt() ;

   if( !ext_eeprom_ready(BANKB_HW_ADDR))
      status = false ;


   // Verify that the self-test routines succeeded.
   if( status )
   {
      // Successful POST, turn of the RED and display the success sequence.
      led_set_red( false ) ;
      led_post_success() ;
      restart_wdt() ;
   }
   else
   {
      // Failure POST.  Display the failure sequence, turn on RED and hang.
      //    The Watchdog Timer will reset us eventually.
      led_post_failure() ;
      led_set_red(true) ;
      while(1) ;
   }
}


//******************************************************************************
// main()
//    Viper main routine.
//    Perform the Power On Self Test
//    Enable Interrupts
//    Enter a loop waiting for either a tag to be probed, or the usb to be
//       connected.  Both of these states are tracked in flags set in interrupt
//       service routines.
//    If a tag is probed, verify that we have a consistent and real electrical
//       connection and then read the tag.
//    If the usb is connected then prepare to download the tag via usb and wait
//       for the PC to request a packet.
//******************************************************************************
void main () {
   int bounces ;
   int pin_b0_high_count ;
   boolean download_connect ;

   int16 packetID = 0 ;
   int16 tagID ;

   // PowerOnSelfTest
   viper_post() ;

   // Enable interrupts
   enable_interrupts(INT_TIMER0);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   ext_int_edge(0, L_TO_H) ;
   set_timer0( 0 ) ;

   led_set_green( false ) ;
   led_set_red(false) ;

   // Wait for either USB to be connected or a tag to be probed.
   while(1)
   {
      restart_wdt() ;
     
      // Check/update the usb state
      usb_task() ;

      // USB is the highest priority.  If USB is attached & enumerated, ignore
      // everything else.
      if( usb_attached() && usb_enumerated() )
      {
         // USB is enumerated, and powered so set the flag to true.
         global_set_usb_mode( true ) ;

         // Wait a while for data from the PC, if there is nothing, then
         // loop back out and start over again.
         while( usb_wait_for_pc_data()== true )
         {
            // Get the packet id requested by the PC
            restart_wdt() ;
            get_packet_request(&packetID, &tagID) ;

            restart_wdt() ;

            if( packetID == 0xff && tagID == 0xff )
            {
               // Erase the eeproms
               viper_eeprom_map_init( &global_eeprom_map ) ;
               global_commit_eeprom_map() ;
               global_set_memory_full_state(false) ;
               global_set_download_error_state(false) ;
               restart_wdt() ;

               send_erase_response() ;
            }
            else
            {
               // Send a USB packet with the requested data.
               send_requested_packet(packetID++, tagID) ;
            }
         }
         restart_wdt() ;
      }
      else
      {
         // USB is NOT enumerated, so set the flag to false.
         global_set_usb_mode( false ) ;

         // Check if a tag is connected and download the data.
         if(( global_tag_ready == true) & (! usb_enumerated() ))
         {
            // We have received an interrupt because PIN_B0 went high.  Use a
            // "bounce" algorithm to verify that the interrupt is legit.

            restart_wdt() ;

            // If a tag has been probed, verify that we have a valid connection.
            // Check that PIN_B0 is high 50 times.  If it is high at least half
            // of the times, then consider it a good connection.
            bounces = 0 ;
            pin_b0_high_count = 0 ;
            download_connect = false ;
            for( bounces = 0 ; bounces < 50 ; bounces++ )
            {
               if( input(PIN_B0))
               {
                  pin_b0_high_count++ ;
                  if( pin_b0_high_count >= 25 )
                  {
                     download_connect = true ;
                  }
               }
               delay_ms(10) ;
            }
            restart_wdt() ;


            if( download_connect == true )
            {
               restart_wdt() ;

               // The interrupt seems legit, try to download the tag data.
               tag_download() ;
            }

            // Set the flag to false so to enable the interrupt.
            global_set_tag_ready( false );         
         }         
      }
      //if (!global_download_complete && !global_downloading)
      //sleep();
   }
}



Here is the viper.h with the fuses
Code:

#ifndef _VIPER_H
#define _VIPER_H
//*************************************************************************
// Copyright 2005 ©
// PakSense, Inc.
// All Rights Reserved
//
//
// Revision:                     1.0
// Written by:                   James Spencer
// Initial start date:           11/08/2005
//
//
//
//**************************************************************************/

//
// Define the environment specific to the 1844550 chip, i.e. the dev platform.
//
#ifdef DEBUG_PLATFORM
#device ICD=true
#FUSES WDT                    //Watch Dog Timer
#FUSES WDT1024                 //1024 ~ 4 seconds.
#FUSES HSPLL                    //High Speed Crystal/Resonator with PLL enabled
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT_SW              //Brownout controlled by configuration bit in special file register
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES NOSTVREN                 //Stack full/underflow will not cause reset
#FUSES DEBUG                    //Debug mode for use with ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOLPT1OSC                //Timer1 configured for higher power operation
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLL5                     //No PLL PreScaler
#FUSES USBDIV
#FUSES CPUDIV1
#FUSES VREGEN

#define GREEN_LED       PIN_D3
#define RED_LED         PIN_D2
#define I2C_SCL         PIN_B5
#define I2C_SDA         PIN_B4
#define USB_CON_SENSE_PIN  PIN_B2
#rom 0xF00000 = { 0xff, 0xff, 0 }
#endif

//
// Define the environment specific to the 18F2455 chip, i.e. Viper1
//
#ifdef RELEASE_PLATFORM
#FUSES WDT                    //Watch Dog Timer
#FUSES WDT1024                //1024 ~ 4 seconds.
#FUSES HSPLL                    //High Speed Crystal/Resonator with PLL enabled
#FUSES PROTECT                //Code protected from reading
#FUSES BROWNOUT_SW              //Brownout controlled by configuration bit in special file register
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES NOSTVREN                 //Stack full/underflow will not cause reset
#FUSES NODEBUG                //NO Debug mode for use with ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOMCLR                 //Master Clear pin disabled
#FUSES NOLPT1OSC                //Timer1 configured for higher power operation
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLL5                     //No PLL PreScaler
#FUSES USBDIV
#FUSES CPUDIV1
#FUSES VREGEN
#define GREEN_LED          PIN_A0
#define RED_LED            PIN_A1
#define I2C_SCL            PIN_C1
#define I2C_SDA            PIN_C0
#define USB_CON_SENSE_PIN  PIN_B2
#rom 0xF00000 = { 0xff, 0xff, 0 }
#endif

//
// Define the common environment
//

// Paksense EEPROM layout definitions
#include "ext_eeprom_layout.h"


#use delay (clock=48000000)


// USB Definitions & includes
#define USB_EP1_TX_ENABLE     USB_ENABLE_INTERRUPT
#define USB_EP1_TX_SIZE       64
#define USB_EP1_RX_ENABLE     USB_ENABLE_INTERRUPT
#define USB_EP1_RX_SIZE       8
#define OUTPUT_REPORT_SIZE    USB_EP1_TX_SIZE
#include <pic18_usb.h>
#include "usb_desc_hid.h"  // the local modified version
#include <usb.c>


// I2C Clock and Data line declarations & includes
#use i2c(master, sda=I2C_SDA, scl=I2C_SCL, fast)
#include "viper_2432_ext_eeprom.h"   // the local modified version


// The data portion of the eeprom consists of a sequence of data points, each
// taking up 16bits.  A datapoint consists of a 4bit count and a 12bit
// temperature value.
// This data is sent to the PC via USB as a sequence of three Bytes, the first
// byte containing the count value and the next two bytes containing the
// A datapoint consists of a count (4 bits) and a temperature value (12 bits)
// In the eeprom this is compressed into 2 bytes as follows:
//    .
// In the eeprom, this is stored as 2 bytes.  4 bits for the count and
// 12 bits for the temperature.
#define DATA_BYTES_EEPROM              2
#define DATA_BYTES_BUFFER              2
#define DATA_POINTS_IN_OUTPUT_REPORT   (OUTPUT_REPORT_SIZE / DATA_BYTES_BUFFER)


// Purpose: read the entire contents of the
//    external eeprom and send via USB.
//
void get_data_ext_eeprom () ;
void viper_init();


#endif // _VIPER_H


Compiler Version is PCWH 3.242, I'm sure that it is something that I simple and am overlooking.

Thanks in advance,

jspencer
Ttelmah
Guest







PostPosted: Tue Mar 21, 2006 10:50 am     Reply with quote

Without looking at the code, one 'problem' with sleep, comes when you are using a crystal oscillator, when the time needed to awaken, can become very significant. Basically, using an RC oscillator, or an external clock, wake-up can be fast, but with the crystal oscillator, the wake-up, can be very long. The internal timer, delays for 1024 clock cycles, when starting the clock. So wake up, is slow. This might be causing your problem.

Best Wishes
jspencer



Joined: 22 Dec 2003
Posts: 57
Location: Boise, ID USA

View user's profile Send private message

PostPosted: Thu Mar 23, 2006 9:37 am     Reply with quote

Ttelmah wrote:
Without looking at the code, one 'problem' with sleep, comes when you are using a crystal oscillator, when the time needed to awaken, can become very significant. Basically, using an RC oscillator, or an external clock, wake-up can be fast, but with the crystal oscillator, the wake-up, can be very long. The internal timer, delays for 1024 clock cycles, when starting the clock. So wake up, is slow. This might be causing your problem.

Best Wishes


I thought that might be the case, and it still might be, but after a little bit of changing stuff around and waiting a second or two before doing any activity on wake up I still can't get it to enumerate. I'll keep at it and maybe I'll figure something out. Thanks for the help.

jspencer
mtoibero27



Joined: 18 Apr 2009
Posts: 1

View user's profile Send private message

Re: USB and Sleep
PostPosted: Tue Oct 13, 2009 6:51 pm     Reply with quote

I have a similar problem.
However, I use timer1 with an external 32K768 crystal in order to wake up the micro from sleep instead of the int_ext.

As I see from your code, I believe that you should consider to configure the oscillator (with the setup_oscillator function) to work under an idle mode. If you only put SLEEP your usb will stop clocking, and as you are only checking if the usb is enumerated or not, in my opinion, this will never happen.

By the way, my problem is:

When I put the micro (18f2550@20MHz with pll) to sleep with
Code:

setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);     
setup_oscillator(OSC_IDLE_MODE|OSC_TIMER1);

I got an interrupt every 2seconds (as expected). So, every 2seconds I
check my usb_con_sense_pin in order to detect a plug in the usb. If this
happens I activate a flag bit in the isr function
Code:

#INT_TIMER1  //every 2seconds...
void timer1int()
{
   delay_ms(35);    //1024times 1/32768seconds
   timer1_access++ ;                              
   if (input(USB_CON_SENSE_PIN))
   {
      USBfirstTime=true;
      return;
   }   
}

to next, in the main function, access the usual usb_init functions
Code:

void main(void)
{
...
while(1)
{
        if (USBfirstTime)
   {
      usb_cdc_init();
        usb_init();
      while(!usb_cdc_connected())
         {
         delay_us(10);
      }
                usb_routine();
         }
}
}

I have to say, that this works perfectly when I set the timer
Code:

setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);

but, the circuit consumes about four times when compared
with the desired configuration.

Besides, when I came back from the interrupt,
the usart does not work anymore...

What am I losing?
Is it something related with the switching between the main oscillator and the timer1 oscillator?

I tried several options but without results yet.
Any advice?

Thanks in advance
marcos.-
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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