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 CCS Technical Support

Sampling a signal at a given frequency

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



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

Sampling a signal at a given frequency
PostPosted: Thu Feb 16, 2012 9:25 am     Reply with quote

Hello everybody!
I am new in C and in PIC programming and also new on this forum, but i am despered for help! I need to sample a signal at a given frequency (100-200 kHz)! The input signal has a 15 kHz freguency so I need at least 10 samples/period!

Can anyone help me with that?

I am using a PIC 18F2550...

Thank you!
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Thu Feb 16, 2012 9:45 am     Reply with quote

You can't do it.
The ADC on the whole of the PIC18 family, does not support sampling much above audio rates. To get to 200KHz, you are going to have to look at something like a DSPic.
On the 2550, the ADC, has a minimum Tad, of 0.7uSec. It takes 12 times this interval to take a reading, and another 6.4uSec to re-acquire between readings. So _minimum_ sample time (allowing nothing for actually reading the data etc.), is 8.4+6.4uSec. 67KHz _maximum_ sample rate (in practice more like 50K).

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Thu Feb 16, 2012 9:46 am     Reply with quote

you are being too vague

show the CIRCUIT this works with
and the CODE you have created so far to attempt what you
say you want

this is NOT a classwork forum as far as i know
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Thu Feb 16, 2012 10:16 am     Reply with quote

Code:

#define __USB_PIC_PERIF__ 1

#if !defined(__PCH__)
 #error USB CDC Library requires PIC18
#endif

#if __USB_PIC_PERIF__
 #include <18F2550.h>
 #fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
 #use delay(clock=48000000)
#endif   //endif check to see which peripheral to use
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <usb_cdc.h>
#include <usb.h>
#include <usb.c>
#include <string.h>

signed int16 ecart_en_ticks ;
int i;
long adc_value;
int HALF_PERIOD;
int16 Ticks = 65400;

#int_timer1
void timer1_isr(){

  set_timer1(Ticks);

  read_adc(ADC_START_ONLY);             
   

}

void main(){
 
    setup_adc_ports(AN0);   
                                   
    setup_wdt(WDT_OFF);                                   
    setup_timer_0(RTCC_OFF);                       
    setup_timer_2(T2_DISABLED,0,1);                     
    setup_timer_3(T3_DISABLED);                         
    setup_comparator(NC_NC_NC_NC);                       
    setup_vref(FALSE);                                   
    setup_low_volt_detect(FALSE);                       
    setup_oscillator(FALSE);                           
    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
     
    setup_adc(ADC_CLOCK_INTERNAL);         


usb_cdc_init();
usb_init();
usb_task();


set_adc_channel(0);                 
delay_us(10); 

enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);

while(1)
{
adc_value=read_adc();
delay_ms(300);
printf(usb_cdc_putc,"%Lu \n\r",adc_value);
}

}


Here is what I have at this point!
I was thinking to create a timer at high frequency and to make the reading at the frequency of the timer... like I said I am new in this think so it is not to much...

I also found this:
Code:
setup_adc(ADC_CLOCK_INTERNAL);
 //enables the a/d module
 
 
 //and sets the clock to internal adc clock
 
setup_adc_ports(ALL_ANALOG);
 //sets all the adc pins to analog
 
set_adc_channel(0);
 //the next read_adc call will read channel 0
 
delay_us(10);
 //a small delay is required after setting the channel
 
 
 //and before read
 
value=read_adc();
 //starts the conversion and reads the result
 
 
 //and store it in value
 
read_adc(ADC_START_ONLY);
 //only starts the conversion
 
value=read_adc(ADC_READ_ONLY);
 //reads the result of the last conversion and store it in value.  Assuming the device hat a 10bit ADC module, value will range between 0-3FF. If #DEVICE ADC=8 had been used instead the result will yield 0-FF.  If #DEVICE ADC=16 had been used instead the result will yield 0-FFC0

But I don't see were you can set the sampling frequency...

Many thanks to any suggestion.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Thu Feb 16, 2012 4:38 pm     Reply with quote

Read my post. _not possible_.
ADC clock internal is even worse. Typical 2uSec TAD, so maximum sampling rate just over 32KHz.
You can program a CCP, to issue a 'special event trigger' to trigger the ADC at a specific interval, but _you_ need to allow sufficient time for the hardware to actually perform the conversion and re-acquire the signal. The hardware on this PIC, _just does not support sampling this fast_.
Sorry, but you need to rethink your hardware.

Best Wishes
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Fri Feb 17, 2012 1:40 am     Reply with quote

Ttelmah wrote:
Read my post. _not possible_.
ADC clock internal is even worse. Typical 2uSec TAD, so maximum sampling rate just over 32KHz.
You can program a CCP, to issue a 'special event trigger' to trigger the ADC at a specific interval, but _you_ need to allow sufficient time for the hardware to actually perform the conversion and re-acquire the signal. The hardware on this PIC, _just does not support sampling this fast_.
Sorry, but you need to rethink your hardware.

Best Wishes


Thank you very much for you explanations! It would be rely helpful if you could explain how can I do the sampling at 30 kHz.

Thank you once again.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Fri Feb 17, 2012 5:07 am     Reply with quote

Select the right source clock. For your chip at 48MHz, you are going to be out of spec for the ADC (technically the maximum device frequency supported by the ADC, to meet it's specifications, is 40MHz....), and ADC_CLOCK_DIV_64 is needed to meet the Tad specification, so select this.

Code:

//Obviously fuses here and setups to match your needs
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//_always_ have 'ERRORS' when using hardware RS232, unless _you_
//are adding your own error handling code. _Essential_.....

int16 ad_vals[256]; //Array to store block of readings
int1 get_block=FALSE;

//Dummy function - takes no space, and does nothing, except to get rid of the
//compiler error about not using RS232_ERRORS.....
void dummy(void){
   int8 scrap;
   scrap=RS232_ERRORS;
}

#INT_AD
void adc_ready(void) { //retrieve an ADC reading - triggered by the CCP
    static int8 array_address=0;
    if (get_block) {
       ad_vals[array_address++]=read_adc(ADC_READ_ONLY);
       if (array_address==0) get_block=FALSE;
   }
}

void main(void) {
    int16 op_ctr16;
    int8 line_ctr8;
    setup_adc_ports(AN0);   
    set_adc_channel(0); //enable AN0 only, and select it.
    setup_adc(ADC_CLOCK_DIV_64); //Fastest available ADC clock
    //that meets the Tad spec.                                 
    setup_spi(FALSE);     
    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);                       
    setup_comparator(NC_NC_NC_NC);                       
    //Now need to setup T1/CCP  to trigger the ADC every 31.25uSec         
     
    setup_CCP2(CCP_COMPARE_RESET_TIMER);
    CCP_2=399;
    //This will trigger the ADC every 400 instructions

    do {
       //Now generate 256 ADC readings, and dump these to the serial
       set_timer1(0);
       clear_interrupt(INT_AD);
       get_block=TRUE;
       enable_interrupts(INT_AD);
       enable_interrupts(GLOBAL);
       do {
       } while (get_block); //Now wait for the readings
       disable_interrupts(INT_AD);
       printf("Block of values from ADC\n\r");
       for (op_ctr16=0;op_ctr16<256;op_ctr16+=8) {
           for (line_ctr8=0;line_ctr8<8;line_ctr8++) {
               printf("%04lx ",ad_vals[op_ctr16+line_ctr8]);
           }
           printf("\n\r");
       }
       do {
       } while(!kbhit());
       //Wait for a key to be pressed to get another block
       line_ctr8=getc(); //Throw the character
   } while (TRUE);
}


This takes a sequence of 256 ADC readings at 31.25uSec intervals, then displays them as 32 lines of 8 values on the UART.

Best Wishes


Last edited by Ttelmah on Fri Feb 17, 2012 8:50 am; edited 1 time in total
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Fri Feb 17, 2012 5:25 am     Reply with quote

Thank you so very much Ttelmah!
I will test it and tell you how it works!
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Tue Feb 21, 2012 5:09 am     Reply with quote

Once again, thank you Ttelmah!
I have tested the code and it works! I get a maximum sampling freguency of 15khz! In the future I will use a better PIC! Your example helped me understand the basics of sampling using PICs

Best regards!
matheuslps



Joined: 29 Sep 2010
Posts: 73
Location: Brazil

View user's profile Send private message MSN Messenger

PostPosted: Mon Apr 07, 2014 12:09 pm     Reply with quote

Ttelmah, may you explain this code a little bit?

You configured the CCP like this:
Code:
setup_CCP2(CCP_COMPARE_RESET_TIMER);
CCP_2=399;

But, why 399? How this would interact with the 31.25uSec?

Just below that, you configured the reading like this:
Code:
//Now generate 256 ADC readings, and dump these to the serial
set_timer1(0);
clear_interrupt(INT_AD);
get_block=TRUE;
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
do { }
while (get_block); //Now wait for the readings

So you enabled the IN_AD interrupt. But how the CCP2 will interact with it? I can not understand this part.

Thanks for the help.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Mon Apr 07, 2014 2:36 pm     Reply with quote

You need to read the data sheet, and the part about 'special event trigger' on the CCP.
I'm programming the CCP to automatically start the ADC at a specified interval (400 counts of timer1). At this point the ADC starts, and then INT_AD, triggers when the ADC _finishes_ converting. The ADC automatically triggers every 400 instructions.

Best Wishes
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