View previous topic :: View next topic |
Author |
Message |
tonymcc
Joined: 27 Jul 2010 Posts: 15 Location: Northampton UK Home of the 'Big Sheds'
|
First use of 18F4620 - Internal oscillator and adc |
Posted: Fri Jan 14, 2011 5:41 am |
|
|
I am moving a simple T/C scanner from an obsolete Forth single board computer to a 18F4620 processor. I want to run the processor from the internal oscillator block at 8MHz but I cannot find the Fuse associated with this in the comments of the PIC18F4620 header. I set the INTRC fuse and find that I get operation at 1MHz. Can anyone explain where the fast internal oscillator has gone?
I wish to use the internal ADC for some analog inputs and a 12 bit MAX186 for others. I wrote code for both and both convert, but I am losing precision. In the case of the internal ADC I am using the following:
Code: |
//variable declaration
int16 cal_value; //internal ADC conversion RA0 -
//intialisation
setup_adc_ports(AN0_TO_AN2); //set internal adc analog ports
setup_adc(ADC_CLOCK_INTERNAL); //set internal adc
//read
void read_calibrate(void) //get current value of RV1
{
set_adc_channel(0);
delay_us(10);
cal_value = read_adc(); //read adc
}
|
..all in appropriate parts of, as yet, a very small program. The result is limited to 8 bits spread over the full input range, not the 10 bits expected. I seem to have lost the 2 least significant bits of the conversion.
I borrowed the MAX186 code from a forum entry and it operates fine apart from a similar loss in precision to that above. The final piece of the conversion code involves combining the msb and lsb of the 12 bit conversion-
Code: |
retval = make16(msb, lsb); // Convert two bytes into 16-bit
retval >>= 4; // Right justify for the 12-bit result
|
If a change the shift right 4 to shift right 3 then I get the range I expect. Again, I wonder why? Any help or comments would be appreciated. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19509
|
|
Posted: Fri Jan 14, 2011 6:22 am |
|
|
Start of code:
Code: |
#include <18F4620.h>
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES PUT //No Power Up Timer
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOWRT //Program memory not write protected
#fuses INTRC
#use delay(clock=8000000)
|
You _must_ have a #use delay, with 8MHz selected, and a #device with ADC=10.
Also, read the data sheet. ADC_CLOCK_INTERNAL, is _not_ recommended for operation above 1MHz (unless you put the chip to sleep for the conversion).
What you are doing on the MAX186 code, just multiplies the value by 2. Are you sure you understand what the value should be?. Are you sure what value you should get, given your reference voltage and signal voltage?.
Also, _what compiler version_. You should _always_ post this. On some compilers you may need to have a 'setup_oscillator' line, with OSC_8MHZ selected.
Best Wishes |
|
|
tonymcc
Joined: 27 Jul 2010 Posts: 15 Location: Northampton UK Home of the 'Big Sheds'
|
|
Posted: Fri Jan 14, 2011 8:22 am |
|
|
Hi Ttelmah,
Many thanks for the quick response. Compiler is PCWHD V4.114 and the 18F4620 seems to select PCH 16 bit version under the PCW editor Project Wizard. I am using a ICD-U64 running under V4.027 as a device programmer, V2.87 firmware and Rev 2 hardware. Sorry for the omissions!
Yes, the inclusion of the adc = 10 in the main.h file sorted the internal adc conversion problem. I have also modified the clock down to /64.
I am still getting a report of MCU at 1.00MHz within debug no matter what I include in #use delay. There is a #OCS directive that appears to be just another form of #use delay. I have gone through section 2 in the 18F4620 data sheet where it mentions, in addition to the normal array of external oscillators, INTOSC an internal 8MHz oscillator with with fairly comprehensive prescaling and a separate INTRC oscillator at 31kHz, presumably for a RTC. The main selection is carried in CONFIG1H, which should read 0x09 for the simplest monitoring - no clock monitoring or switching, output seen at OSC pins Using the ICU-U64 in its device programmer mode I read CONFIG1H as 0x09 and I can read 2Mhz here. It looks as if I need access to the OSCCON register to set the frequency required in INTOSC. Interestingly, the power on reset value of this selection is 1Mhz! OSCCON is at 0xFD3 so I tried writing a value for 8Mhz 0x70 using #rom but I am way out of my comfort zone here and cannot be sure that bank bits are set by the compiler.
In the MAX186 I clock in 8 bits to configure and start the conversion and then send a further two sets of 8 bits to read back the conversion, first byte containing the upper 8 bits of the 12 bit conversion and the second the lower the remaining 4 bits in its upper nibble. Shifting right 4 times should create the required 12 bits of data. I guess that I must be getting nothing clocked through on the first of my read clock cycles, leaving the whole 16 bits read already shifted right one bit. I increased the delay for conversion by a factor of 10 (100uS) but no change.
I can live with both the oscillator and the MAX186 anomalies but it would be good to know what is going on. Thanks again for your help and encouraging me to think and research a little deeper. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Fri Jan 14, 2011 8:50 am |
|
|
I am using the ICD-U64 with an 18F46K22 and it reports I am running at 1MHZ even though I have verified I am running at 64MHZ using a scope.
As Ttelmah said earlier, try using setup_oscillator(). From the header:
Code: |
////////////////////////////////////////////////////////////////// INTERNAL RC
// Constants used in setup_oscillator() are:
// First param:
#define OSC_31KHZ 0
#define OSC_125KHZ 0x10
#define OSC_250KHZ 0x20
#define OSC_500KHZ 0x30
#define OSC_1MHZ 0x40
#define OSC_2MHZ 0x50
#define OSC_4MHZ 0x60
#define OSC_8MHZ 0x70
#define OSC_16MHZ 0x4060
#define OSC_32MHZ 0x4070
// The following may be OR'ed in with the above using |
#define OSC_TIMER1 1
#define OSC_INTRC 2
#define OSC_NORMAL 0
// The following may be OR'ed in with the above using |
#define OSC_IDLE_MODE 0x80
#define OSC_31250 0x8000
#define OSC_PLL_ON 0x4000
#define OSC_PLL_OFF 0
// A second optional parameter may be used with this part to fine
// tune the speed (signed int,0-31)
// Result may be (ignore all other bits)
#define OSC_STATE_STABLE 4
#define OSC_STATE_EXT_RUNNING 8
|
_________________ Google and Forum Search are some of your best tools!!!! |
|
|
tonymcc
Joined: 27 Jul 2010 Posts: 15 Location: Northampton UK Home of the 'Big Sheds'
|
Thanks dyeatman |
Posted: Fri Jan 14, 2011 9:25 am |
|
|
I must be going blind to have missed this section in the processor header and not associate with OSCCON in the data sheet. I have tried now using setup_oscillator(OSC_INTRC | OSC_8MHZ);
but still get my 2MHz at pin 14. Well, it is Friday, thanks very much for your advice. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Fri Jan 14, 2011 9:35 am |
|
|
From the datasheet:
Quote: |
2.6.1 INTIO MODES
Using the internal oscillator as the clock source
eliminates the need for up to two external oscillator
pins, which can then be used for digital I/O. Two distinct
configurations are available:
• In INTIO1 mode, the OSC2 pin outputs FOSC/4,
while OSC1 functions as RA7 for digital input and
output.
• In INTIO2 mode, OSC1 functions as RA7 and
OSC2 functions as RA6, both for digital input and
output. |
So 8MHZ/4=2MHZ is correct on pin 14. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
tonymcc
Joined: 27 Jul 2010 Posts: 15 Location: Northampton UK Home of the 'Big Sheds'
|
|
Posted: Fri Jan 14, 2011 9:41 am |
|
|
Thanks again. You are, of course, correct. So, my original #fuse INTRC plus the #use_delay(clock=8000000) directive did work, I just misinterpreted the results. I checked with a few other frequencies and all is well. A learning day. |
|
|
|