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

18F14K22 - int ref and timer2 issues ..

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



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

18F14K22 - int ref and timer2 issues ..
PostPosted: Sun Nov 28, 2010 10:29 pm     Reply with quote

Greetings again -- I have been working with the 18F14K22 (mask rev A3) and the CCS compiler version 4.114 on the PicKit2 demo board and am getting some strange results that don't seem to match the data sheet (and are not listed in the errata for that chip).

The first issue is with Timer2 - I have the system set to use an internal oscillator of 8mhz (which I have verified - both with my scope as well as looking at OSCCON bits which indicate it is set to internal 8mhz). For timer2 I have it set to:
setup_timer_2(T2_DIV_BY_16,250,10); // see pg 108 for timer2 config info
pg 108 of the data sheet indicates it takes Fosc/4 scales it from there. What I am seeing is a 200hz interrupt with the above settings which indicates it is using the 8mhz direct into the timer (I have the ISR toggling a led and it is toggling every 5ms).

The second issue I have is with the AD converter - I have supposedly set it to use the internal reference at 1x which would be 1.024 volts, however, if I set the A/D channel to "15" which reads the FVR, I am getting a raw reading of about 213 if I have the FVR set to 1x or 430 if I have the FVR set to 2x - this tells me that the A/D is still using the 5v reference not the FVR (see my code where I set the VREFCON0 and ADCON1 to select the internal reference. Below is a relatively simple version of my code that gives the results I have indicated. Any ideas what I am missing ?? (my LCD routine shows the raw A/D read and using both the chan 15 for FVR as well as chan 2 for the actual temp indicate that it is still using the 5v reference) -- note that the timer2 ISR toggles the DS4 LED which allows me to check the ISR timing etc with my scope.


Code:

// Mikeys Hummingbird feeder heater - based on using the Microchip
// low pin count demo board.  Low Pin Count Demo Board with PIC16F690
// (Mfr Part#: DM164120-1) It looks like in addition to the stock
// PIC16F690, a PIC18F14K22 would also fit the board pinout (20 pin).
// The PIC18F14K22 includes an internal Vref instead of using VDD as
// the PIC16F690 does.  It also has 16K bytes (8K words) of program
// memory.  The 18F14K22 is also supported by the PicKit2 programmer.

// NOTE: page numbers listed refer to page numbers in the Microchip
//    18F14K22 data sheet.

// Test version for 18F14K22 only - simplified
//
//   _     _     _     _       _     _     _     _     _     _     _ 
//  / \   / \   / \   / \     / \   / \   / \   / \   / \   / \   / \
// ( T ) ( E ) ( S ) ( T )   ( V ) ( E ) ( R ) ( S ) ( I ) ( O ) ( N )
//  \_/   \_/   \_/   \_/     \_/   \_/   \_/   \_/   \_/   \_/   \_/
//
//  PIC18F14K22 Processor specific stuff
#include <18F14K22.H>
#fuses INTRC_IO        // internal oscillator - no CLKOUT on pin 3
// #fuses INTRC            // int osc. - clkout on clk2 (pin 3)
#fuses NOWDT           // no watch dog timer
#fuses NOPROTECT_0     // don't protect code from reading
#fuses NOPROTECT_1     // don't protect code from reading
#fuses BROWNOUT        // Reset when Brownout detected
#fuses PUT             // Power Up Timer

#device adc=10         // 10 bit AD mode

#use delay(clock=8000000) // configure for 8mhz clock


   // Processor specific ADC config info
   // Define some SFR registers we need access to ...
#BYTE VREFCON0 = 0xFBA  // Vref configuration registers
#BYTE VREFCON1 = 0xFBB
#BYTE VREFCON2 = 0xFBC

#BYTE ADCON0 = 0xFC2    // A/D converter config registers
#BYTE ADCON1 = 0xFC1
#BYTE ADCON2 = 0xFC0

#BYTE ANSEL  = 0xF7E    // Analog Select Registers
#BYTE ANSELH = 0xF7F

#BYTE OSCCON = 0xFD3    // Oscillator control register
#BYTE OSCCON2= 0xFD2


signed int32 Tref = 500;  // 500 mv offset for 0 deg C


#include "Flex_LCD_defs_PK2_LPC.h"
#include "flex_lcd.c"

// heater definitions ...
#define HTR_DRV   PIN_C3                  // DS4 on the PK2 LPC Proto Board
#define heat_on()  output_high(HTR_DRV)
#define heat_off()   output_low(HTR_DRV)

// TicksPerToggle is a counter used to further divide the output of timer2
// down to the PWM rate for the heat control etc. 

#define TicksPerToggle  255    // interrupts to determine low PWM rate - 2.55s

int8 pwidth; // needed pulse width 1-255 - set by heat control code
             // and used in the timer2 interrupt to control duty cycle
             // -- make sure this value is less than "TicksPerToggle" or
             //    it will never turn off.
                         
/****************************************************/
/*  A/D converter and Temp info                     */
/****************************************************/
                 
/* A/D converter and MCP9700A temp sensor calculations.
 * -----------------------------------------
 * For the 18F14K22 processor using the internal 1.024v bandgap reference:
 * A/D converter is 10 bit (1024) with the 1.024 volt reference, each bit
 * represents 1.024/1024 = 1.00 mv per bit. The advantage of using the internal
 * reference with this processor is a) it eliminates the coupling to any
 * fluctuation in the supply voltage to the chip and b) it expands the scale
 * of the A/D for better resolution of the sensor output.
 *
 * Temp Sensor MCP9700A - offset reference at 0 degrees C = 500mv so the
 *     offset in A/D counts for 0 degrees is 500mv/1mv = 500.  Since the
 *     full scale is 1024mv, 1024-500=524  -- at 10mv/degree C, this means
 *     full scale high is 52.4 degrees C (126.3 degrees F) - on the negative
 *     side, we are limited to -50 degrees C (-58 deg F) (-50 * 10mv/deg) is
 *     500mv down from the 0 degree reference at 500mv = 0mv
 *   => If we are outside those temperatures, we have a SERIOUS problem !!
*/

#define AIR_CHAN  2      // ambient air A/D channel (RA2)
#define AIR_PORT  sAN2

#define HTR_CHAN  10     // heater sensor A/D channel
#define HTR_PORT  sAN10

signed int32 AD_raw;     // raw reading from A/D
signed int32 CTemp;      // temp in degrees C * 10
signed int32 FTemp;      // temp in degrees F * 10

int1 do_check_temps=FALSE; // flag for time to check temps - set by timer2 ISR
                           // every "TicksPerToggle" time - main() reads the
                           // temps and clears the flag.


/*****************************************************/
/*  Timer2 ISR  -- runs at 100hz                                     */
/*****************************************************/

#int_timer2
void tick(void)
   {
   static int16 counts=TicksPerToggle;
   static int8 pulse;
   // arrive here 100 times/second
// mjf test - add following line to allow debug of T2 rate - simply toggle
// the output - we should see a 50hz (100hz / "toggle") on scope.
   output_toggle(HTR_DRV);
   
   if (--counts==0)  // counted ticks per toggle
      {
      counts=TicksPerToggle;  // reset counter
      pulse = pwidth;         // reset pulse to specified width - note that pwidth
                              // can NOT be more than TicksPerToggle.
      do_check_temps = TRUE;  // tell main() time to check temps
      }
   if(pulse)      // output high on htr control (on) until pulse = 0
      {
//      output_high(HTR_DRV);
      pulse--;    // decrement pulse width count
      }
   else
      {
//      output_low(HTR_DRV);
      }
   }

// =========================================================
//   _     _     _     _       _     _     _     _ 
//  / \   / \   / \   / \     / \   / \   / \   / \
// ( M ) ( A ) ( I ) ( N )   ( P ) ( G ) ( M ) ( . )
//  \_/   \_/   \_/   \_/     \_/   \_/   \_/   \_/
//
// =========================================================
void main()
{
   // First initialize things ...
// test
setup_oscillator(OSC_8MHZ); // test - should not have to?
// end test

lcd_init();          // Init LCD -- Always call this first.
     
   // Timer_2 setup for 100hz interrupts - processor/clock specific
   // 4mhz/(4*4*250*10)=100hz interrupt
setup_timer_2(T2_DIV_BY_16,250,10);  // see pg 108 for timer2 config info

   // setup AD converter
         setup_adc(ADC_CLOCK_DIV_16);
         VREFCON0 = 0x90; // FVR enabled, 1x (1.024v)  (pg 245)
         VREFCON1 = 0x00; // DAC is disabled  (pg 246)
         VREFCON2 = 0x00; // DAC output disabled (pg 246)
         ADCON1   = 0x08; // pos vref from FVR, neg vref from Vss (pg 214,207)
         ADCON2   = 0x95; // Rt. justify, TAD4,Fosc/16   (pg 215)
 
setup_adc_ports(AIR_PORT | HTR_PORT);  // AN2 (RA2) = ambient temp, AN10 (RA10)=htr temp
pwidth = 25;   //  25/255 duty cycle for testing

   // enable interrupts for use
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);

   // Tell who we are ...
lcd_putc("\fMikeys Magical\n");
lcd_putc("Hummer Htr Tst 1.1");
delay_ms(5000);   // give them time to read our message ...

   // ---- Main Loop - loop here continuously when running
while(1)
   {
   // see if it is time to check the temps yet ...
   if(do_check_temps)
      {
      do_check_temps = FALSE; // clear the flag (set by timer2 ISR)
     
   // read the ambient air temp
   // **** commented out the following line to read the output of the
   //      sensor and replaced with a read of channel 15 which, according
   //      to the data sheet should read the FVR.  If the reference is set
   //      correctly to use the FVR, we should always get full scale from
   //      the AD_raw read of the converter.
// mjf test *** set_adc_channel(AIR_CHAN); // select the air temp channel
      set_adc_channel(15);       // should read FVR - (pg 213)
      delay_us(20);              // let stabilize
      AD_raw = read_adc(ADC_START_AND_READ);
      CTemp = (AD_raw -TRef); // get and adj for 0
      FTemp = (( 9 * CTemp) / 5) + 320;   // 320 = 32 degrees * 10
      printf(lcd_putc,"\fAD= %Ld OC=0x%x\n",AD_raw,OSCCON);
      printf(lcd_putc,"Air = %Ld (%Ld)",CTemp/10, FTemp/10);
     
   // read the heater temp
      }
   }
}


Thanks for looking !!
mikey
[/code]
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Sun Nov 28, 2010 10:54 pm     Reply with quote

OK, I have solved (sort of) the second part with the A/D and the Vref - turns out that setup_adc_ports() overwrites what I was putting in ADCON1. As long as I set ADCON1 *AFTER* doing the setup_adc_ports(), it selects the internal reference as expected.

The timer2 config is still a puzzler though - the data sheet indicates it is getting Fosc/4, but it certainly is working as though it is getting Fosc direct.

[edit]
I guess I am not the only one confused - it appears CCS also has an issue - with the clock running at 8mhz, when I use a "delay_ms(5000)" I get about 1.2 seconds with this chip instead of the 5 seconds (again that missing divide by 4 somehow). With the 16F690, the timing was correct.

In addition, if I define an additional VREF constant using their format from the .h file, I can add that as a second argument to the setup_adc_ports() command and it does indeed select the internal reference ...
#define VSS_VFVR 0x800 works just fine with the following:
setup_adc_ports(AIR_PORT | HTR_PORT,VSS_VFVR);

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
Ttelmah



Joined: 11 Mar 2010
Posts: 19260

View user's profile Send private message

PostPosted: Mon Nov 29, 2010 5:53 am     Reply with quote

How do you verify 8MHz with your scope?. Remember the output, is OSC/4.
Everything you have said, implies a system clocking at 32MHz.

Best Wishes
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Mon Nov 29, 2010 10:04 am     Reply with quote

Ah, that appears to be it - I had configured the int. osc with clkout on pin3 and was seeing 8 mhz and the OSCON was returning 0x6C which indicated 8mhz on the internal osc with the "primary clock determined by the CONFIG1 (FOSC<3:0>) bits". My PicKit2 was showing the config1 word was 0xF800 which does indicate the PLL is enabled. Setting the fuse for NOPLLEN changed the config1 word to 0xE800 indicating NOPLL and now it seems to be running correctly (apparently it was getting set on because according to the data sheet, the reset state is "0" for the PLLEN). On the output from CLKOUT, I had missed the part (pg19) that indicates "the frequency at the pin is the frequency of the internal oscillator divided by 4".

(I did find a misprint in the data sheet for any others using this processor - pg 214, register ADCON1, bit 1-0 should read "Negative Voltage..." NOT "Positive Voltage ... ")

Thanks for the sanity check - setting the NOPLLEN fuse does appear to solve the timing issues. Full speed ahead - back to getting this working to keep the hummingbird feeders from freezing during our cold snaps here - yeah, a hand warmer and bubble wrap works, but this is MUCH more fun !

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
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