|
|
View previous topic :: View next topic |
Author |
Message |
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
problem with 18F4550 clock speed |
Posted: Thu Apr 18, 2013 8:00 am |
|
|
Hi everyone,
This is my first post, really happy to be in this forum.
I have a clock speed problem with my PIC. I'm using a PIC 18F4550 it has a clock source of 16MHz crystal and I'm using CCS compiler to compile my program move it on MPLAB 8.89 and from a ICD2 programmer to my μC.
I work it on ccd class which works great, but I'm having a problem with the clock speed. I used spi_xfer to communicate with an 12-bit ADC 1Msps produce 16 clock pulses but the highest speed i get is 45KHz(frequency of all 16 pulses), otherwise the duration for 16 pulses is 22 μsec.
I'm trying to make a hardware SPI. I sent 16 pulses by setting and clearing PIN_C2 but the highest i get with CPUDIV1 is 3 MHz frequency for each clock.
Help would be useful, thanx
Code: |
#include <18f4550.h> //
#include <main.h>
#use delay(clock=32000000)
#use RS232 (BAUD=28800,XMIT=PIN_D4 ,RCV=PIN_C7 ,STREAM=COMA,FORCE_SW)
#USE SPI (MASTER, CLK=PIN_C2, DI=PIN_C1, DO=PIN_D3, MODE=3, BITS=16, STREAM=first, MSB_FIRST, BAUD = 1000000)
#include <usb_cdc.h> //Include the USB CDC library. If you want to see all the functions available look at usb_cdc.h and usb.h.
int16 adc_result(void)
{
int counter;
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
return 100;
}
void main()
{
int c; int i;
unsigned int16 res; //these lines do some initialization
usb_cdc_init();
usb_init();
usb_wait_for_enumeration();
while(true)
{
usb_task(); //handles connections to and disconnections from the computer, registering the PIC with the computer, etc. call this pretty often so that the PIC responds to being plugged in.
if(usb_cdc_kbhit())
{
//did we get some incoming data?
c = usb_cdc_getc(); //get one character of input
output_low(PIN_C0);
//res=spi_xfer(first,i,16);
res = adc_result();
//res>>=1;
//shift to corect adc
output_high(PIN_C0);
printf(" you typed: %c\r\n adc value %Lu \r\n", c,res);
printf(usb_cdc_putc, " you typed: %c\r\n adc value %Lu \r\n", c,res); //print out a response over usb
}
}
}
|
Code: |
#FUSES NOWDT //No Watch Dog Time
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES PLL4 //Divide By 4(16MHz oscillator input)
#FUSES CPUDIV1 //No System Clock Postscaler
#FUSES USBDIV //USB clock source comes from PLL divide by 2
#FUSES HS //High Speed Crystal/Resonator with PLL enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES VREGEN //USB voltage regulator enabled
#FUSES PBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES LPT1OSC //Timer1 configured for low-power operation#FUSES MCLR
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES ICPRT //ICPRT enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPB //No Boot Block code protection
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#use delay(clock=32000000)
|
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Thu Apr 18, 2013 10:52 am |
|
|
There's too much for me to wade through.
Post the SHORTEST possible, complete, compilable code I can copy and paste to test.
Mike |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Thu Apr 18, 2013 11:05 am |
|
|
Remove printf and test again. It is known that printf takes an awefully long time to execute. |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Thu Apr 18, 2013 11:05 am |
|
|
thanks for the reply
Try this, the program has no errors, it compiles.
You need an oscillator to see the frequency that PIN_C2 toggles.
You will need all the main library where the FUSES are written.
Thanks
Code: |
#include <18f4550.h> //
#include <main.h>
#use delay(clock=32000000)
#USE SPI (MASTER, CLK=PIN_C2, DI=PIN_C1, DO=PIN_D3, MODE=3, BITS=16, STREAM=first, MSB_FIRST, BAUD = 1000000)
#include <usb_cdc.h> //Include the USB CDC library. If you want to see all
int16 adc_result(void)
{
int counter;
output_low(PIN_C2);
output_high(PIN_C2);
output_low(PIN_C2);
output_high(PIN_C2);
}
void main()
{
int c; int i;
unsigned int16 res; //these lines do some initialization
usb_cdc_init();
usb_init();
usb_wait_for_enumeration();
while(true)
{
usb_task(); //handles connections to and disconnections from the computer, registering the PIC with the computer, etc. call this pretty often so that the PIC responds to being plugged in.
if(usb_cdc_kbhit())
{
c = usb_cdc_getc(); //get one character of input
output_low(PIN_C0);
//res=spi_xfer(first,i,16);
res = adc_result();
//res>>=1;
//shift to corect adc
output_high(PIN_C0);
printf(" you typed: %c\r\n adc value %Lu \r\n", c,res);
printf(usb_cdc_putc, " you typed: %c\r\n adc value %Lu \r\n", c,res); //print out a response over usb
}
}
} |
|
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Thu Apr 18, 2013 11:09 am |
|
|
Thank you Mike i will try tomorrow removing the printf.
But you think it slows down the speed so much?
It should be working on 32MHz or 48MHz according to
the FUSES set up. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Apr 18, 2013 2:52 pm |
|
|
If you use the HS fuse, the CPU clock comes from the crystal oscillator, not the USB clock source. Your crystal is running at 16MHz, so this is the _maximum_ you can clock your CPU this way. You are using CPUDIV1, so your CPU will be running at 16MHz.
The clocks you can run the CPU at are:
HS
CPUDIV1 16MHz
CPUDIV2 8MHz
CPUDIV3 5.33MHz
CPUDIV4 4MHz
HSPLL
CPUDIV1 48MHz
CPUDIV2 32MHz
CPUDIV3 24MHz
CPUDIV4 16MHz
So to run at your required 32MHz, you need to change the HS fuse to HSPLL, and the CPUDIV fuse to CPUDIV2
The data sheet does explain it (except for the confusion caused by the same divider numbers giving different divisions from the USB clock, which is made very 'non obvious' by CCS calling the divider numbers by the division they give from the crystal only).
Best Wishes |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 12:43 am |
|
|
Quote: | If you use the HS fuse, the CPU clock comes from the crystal oscillator, not the USB clock source |
Sorry guys it's a typing mistake, i already use HSPLL. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Fri Apr 19, 2013 12:50 am |
|
|
probeoil wrote: | Quote: | If you use the HS fuse, the CPU clock comes from the crystal oscillator, not the USB clock source |
Sorry guys it's a typing mistake, i already use HSPLL. |
In which case you need to change your divider to CPUDIV2 to give 32MHz. With CPUDIV1 which you show, you will be running at 48MHz.
Best Wishes |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 12:57 am |
|
|
Quote: | In which case you need to change your divider to CPUDIV2 to give 32MHz. With CPUDIV1 which you show, you will be running at 48MHz.
|
I know but with CPUDIV1 i get 6 MHz CPU speed and with CPUDIV2 i get 4 MHz. |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 1:46 am |
|
|
I commented out printf and did not work, on every loop adc_result function is called and gives 16 pulses, then gives a print and starts another loop. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Fri Apr 19, 2013 3:40 am |
|
|
So, use CPUDIV1, and change your clock statement to 48MHz. Then at least you are using the speed you declare. Otherwise things like serial are never going to work correctly.
Now, you talk about getting a particular speed. You do realise that even at 48MHz, you are only getting 12MIPS, and a C instruction will always be multiple CPU instructions?. If (for instance), you are counting a counter, and shifting out bits from a variable (which is what the software code will have to do), then this will involve several machine instructions per bit. '22uSec' for 16 pulses sounds quite good to me, unless you switch to using hardware SPI....
Throw away 90% of your code (Mike Walne's comment, and _essential_ for debugging). Just send an individual byte in a loop. Time this. Then (since now the code will only be a few dozen instructions), try this in MPLAB simulator. This will tell you how many instructions the code actually is, and how fast it should be at your clock.
Best Wishes |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 4:09 am |
|
|
Thank you for the response Ttelmah.
I'll try it out |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 5:30 am |
|
|
I tried the most simple program.
Code: |
#include <18f4550.h>
#include <main.h>
#use delay(clock=48000000)
void main() {
int c;
int i;
unsigned int16 res;
while(true) {
output_low(PIN_C0);
output_high(PIN_C0);
}
} |
to go from low state to high it needs 169 nsec.
If the controller needs 2 cycles to do this then the cpu is running at 6 MHz and i need at least 24MHz
The fusses are the same as before.
Code: |
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES PLL4 //16 MHz crystal
#FUSES CPUDIV1 //48 MHz speed
#FUSES USBDIV
#FUSES HSPLL Crystal/Resonator with PLL enabled | [/quote] |
|
|
probeoil
Joined: 02 Apr 2013 Posts: 20 Location: greece
|
|
Posted: Fri Apr 19, 2013 5:31 am |
|
|
when i say 2 cycles i mean to do
output_low(PIN_C0);
output_high(PIN_C0); |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 19, 2013 6:50 am |
|
|
Quote: | to go from low state to high it needs 169 nsec.
If the controller needs 2 cycles to do this then the cpu is running at 6 MHz and i need at least 24MHz | Don't confuse MIPS and MHz. The PIC processor needs 4 clock cycles to execute 1 instruction. So, as Ttelmah already pointed out, when running at 48MHz the processor can execute 12 instructions every us.
Executing the high/low commands in 169ns == 2 instructions == 12 instructions / us
Just as expected.
If this is too slow for you, then software SPI is not the right solution for you. Hey, perhaps that's why they invented a hardware SPI module?
I don't know what you want to create, but I see you mention a CCD? Please note that the PIC processors are not very good for image processing, they are relative slow and have very limited memory.
You want to clock in 16 bits at a 1Msample rate, that is 16 bits every microsecond, or a bit rate of 16Mbit/s
The maximum clock speed for SPI in the PIC18F4550 is 1/4 the CPU clock, that requires a minimum PIC CPU speed of 16Mbit/s * 4 = 48MHz.
So, the SPI hardware in your processor is just fast enough to process your data stream. Tricky part is that your CPU also requires time to read the SPI data and save it somewhere in RAM. Seems possible, but depends largely on which memory you want to use for saving the data and how many bytes you want to save. |
|
|
|
|
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
|