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

PIC 24HJ ADC sampling at 150khz+

 
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

PIC 24HJ ADC sampling at 150khz+
PostPosted: Wed Apr 25, 2012 9:10 am     Reply with quote

Hello!
I need to sample a signal at a frequency above 150khz! I Use a pic 24hj but with the code I have until now I can not go above 40khz! Can anyone please help me?

Code:


#if !defined(__PCD__)
#error This example will only compile for the PCD 24 bit compiler
#endif
#include <24HJ128GP504.h>
#device adc=10

#fuses HS,NOWDT,noprotect
//#fuses FRC,FRC_PLL,NOWDT,NOPROTECT,
#use delay(clock=7350000)

#pin_select U1TX = PIN_C9
#pin_select U1RX = PIN_C8
#use rs232(baud=9600, xmit=PIN_C9, rcv=PIN_C8,parity=N,bits=8)


#include <stdlib.h>
#include <stdio.h>

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

int16 Number_of_Ticks = 65000;


#int_timer1
void timer1_isr(){
int k;

  set_timer1(Number_of_Ticks);


    if (get_block)
        {
        for(k=0;k<15;k++){
           ad_vals[array_address]=read_adc(ADC_START_AND_READ);
           array_address=array_address+1;
           if (array_address==90)
               {
               array_address=0;
               get_block=FALSE;
               }
           }
        }


void main(){
char c ;

 
    setup_spi(FALSE);                           
    setup_wdt(WDT_OFF);                           
               
    setup_low_volt_detect(FALSE);               
    SET_TRIS_B(0xFF);
    // B7,B6,B5,B4 are outputs
    // B15,B14,B13,B12,B11,B10,B9,B8, B3,B2,B1,B0 are inputs
    setup_timer1(TMR_INTERNAL|TMR_DIV_BY_1);         
  //  setup_timer2(TMR_INTERNAL|TMR_DIV_BY_1);         

    //set ADC
    setup_adc_ports( ALL_ANALOG ); //setup_adc_ports(AN0);
    delay_us(20);
    set_adc_channel(0);                 //the next read_adc call will read channel 0
     setup_adc(ADC_CLOCK_INTERNAL);          //enables the a/d module and sets the clock to internal adc clock 

// initial values
HALF_PERIOD=1;
//read_adc(ADC_START_AND_READ);


array_address=0;
get_block=TRUE;


    enable_interrupts(int_timer1);
    enable_interrupts(INTR_GLOBAL);

do {
for(i=0;i<90;i++)
    {
    printf("%lu ",ad_vals[i]);
   // delay_ms(1000);
    }
 printf("ADC\n\r");
printf("\n\r");
get_block=TRUE;
   } while (TRUE);
}



Thank you!
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Wed Apr 25, 2012 9:35 am     Reply with quote

The obvious problem is using 'START_AND_READ'. This means you will sit waiting at this point for the entire conversion.
Use 'READ_ONLY, and use Timer3, for your tick, and set this to automatically trigger the ADC, and interrupt on the ADC completing, instead of the timer. This way the conversion has been completed before you arrive in the interrupt.
Clock the chip faster, and switch to using the master oscillator, rather than the internal RC, and you can just about double the speed of the ADC - minimum Tad is 117.6nSec, while the internal RC, gives 250nSec typically.
Obviously for the fastest short burst, you can switch to using DMA.
However you should be able to get to about 200KHz best case without doing this, but probably only by raising the master clock to the processor.

Best Wishes
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Thu Apr 26, 2012 4:03 am     Reply with quote

I tried to follow your instructions but I had no success! At this point I do not get any value printed...

Can you see what am I doing wrong?

Timer3 calls for INT_ADC1 every 150us (3k at this point) and INT_ADC1 should take a number of readings (50 for now) and then the values of the samples should be printed! But nothing happens! Sad

Code:
#if !defined(__PCD__)
#error This example will only compile for the PCD 24 bit compiler
#endif
#include <24HJ128GP504.h>
#device adc=10 // resolution

#fuses HS,NOWDT,noprotect
//#fuses FRC,FRC_PLL,NOWDT,NOPROTECT,
#use delay(clock=7350000)

#pin_select U1TX = PIN_C9
#pin_select U1RX = PIN_C8
#use rs232(baud=9600, xmit=PIN_C9, rcv=PIN_C8,parity=N,bits=8)


#include <stdlib.h>
#include <stdio.h>

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

int i,HALF_PERIOD;

int16 Number_of_Ticks = 65000;
int LOGIC = 0 ;

/**************************************************************************************************/
//Timers
/**************************************************************************************************/

#int_timer3
void timer3_isr(){
   set_timer3(Number_of_Ticks);
       clear_interrupt(INT_ADC1);
       get_block=TRUE;
       enable_interrupts(INT_ADC1);
       enable_interrupts(INTR_GLOBAL);

if(HALF_PERIOD == 0)  // test for interup
    {
    output_low(PIN_B4);
    HALF_PERIOD = 1;
    }
else
    {
    output_high(PIN_B4);
    HALF_PERIOD = 0 ;
    }
}


#INT_ADC1
void adc_ready(void) {

    if (get_block)
        {
        //for(k=0;k<10;k++){
           ad_vals[array_address]=read_adc(ADC_READ_ONLY);//ADC_START_AND_READ    ADC_READ_ONLY
           array_address=array_address+1;
           if (array_address==50)
               {
               array_address=0;
               get_block=FALSE;
               }
        //   }
        }
}




/*************************************************************************************************/
// Main
/*************************************************************************************************/

void main(){

    //Configuration of the microcontroler
 
    setup_spi(FALSE);       //no SPI
    setup_wdt(WDT_OFF);    //no watchdog
    setup_low_volt_detect(FALSE);               
    SET_TRIS_B(0xFF);
    // B7,B6,B5,B4 are outputs
    // B15,B14,B13,B12,B11,B10,B9,B8, B3,B2,B1,B0 are inputs
    setup_timer1(TMR_INTERNAL|TMR_DIV_BY_1);          // Internal clock
    setup_timer3(TMR_INTERNAL|TMR_DIV_BY_1);          // Internal clock




    //set ADC
    setup_adc_ports(sAN0); // sAN0 ALL_ANALOG
    delay_us(20);
    set_adc_channel(0);                 //the next read_adc call will read channel 0
    setup_adc(ADC_CLOCK_INTERNAL);          //enables the a/d module and sets the clock to internal adc clock
   read_adc(ADC_START_ONLY);   // is this correct?



// initial values
HALF_PERIOD=1;

array_address=0;
get_block=TRUE;


    enable_interrupts(int_timer3);
    set_timer3(Number_of_Ticks);
    enable_interrupts(INTR_GLOBAL);

do {
       /*
       set_timer3(Number_of_Ticks);
       clear_interrupt(INT_ADC1);
       get_block=TRUE;
       enable_interrupts(INT_ADC1);
       enable_interrupts(INTR_GLOBAL);
*/
   do {
       } while (get_block); //Now wait for the readings
   disable_interrupts(INT_ADC1);
   for(i=0;i<50;i++)
       {
       printf("%lu ",ad_vals[i]);
          delay_ms(400);
       }
   printf("ADC\n\r");
   printf("\n\r");
   get_block=TRUE;
   }while (TRUE);
}
Sad Sad Sad Sad Sad
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Fri Apr 27, 2012 3:04 am     Reply with quote

OK.
You seem to be ignoring, or not understanding most of what I said. So:
First, you need to clock faster.
Think about it. At 7.37MHz, you execute just over 3.5Mips. Sampling every 1/200000th second, would give you just 17 machine instructions between each sample. Simply writing the data to the array, takes about 10 instructions, add the loop etc., and you have 'no hope'. Remember, you can't have two oscillator fuse selections...

Then I said _not_ to use the timer interrupt. The point is the timer 'event', can be programmed to start the ADC. So what you do, is set this up, and then when the ADC interrupts, it has taken the reading _already_, and the number can just be read.

Now, Have not tested this, but just typed something to give the idea:
Code:

#include <24HJ128GP504.h>
#FUSES FRC_PLL,NOWDT,NOBSS, NOIESO, NOCKSFSM, NOPROTECT, NOJTAG
#use delay(clock=66.8MHz)

int16 adc_buffer[256];
int8 adc_index=0;
int1 complete=TRUE;
#WORD AD1CON1=getenv("SFR:AD1CON1")

#int_ADC1
void  ADC1_isr(void){
   if (complete) return;
   adc_buffer[adc_index]=read_adc(ADC_READ_ONLY);
   if (adc_index<255)
      adc_index++;
   else {
      complete=TRUE;
   }   
}

void main(void){
   setup_oscillator(OSC_INTERNAL,66800000);
   setup_spi( FALSE );
   setup_spi2( FALSE );

   setup_adc_ports(sAN0);
   setup_adc(ADC_CLOCK_DIV_4); //This gives ADC clocked at 8.29MHz = 120.63nSec
   //Almost the max allowed....

   setup_timer2(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer4(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer5(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);

   setup_timer3(TMR_INTERNAL |TMR_DIV_BY_1 ,156);
   //Now use Timer3, since this can trigger the ADC
   //To trigger every 5uSec, require total division by 334 - remember timer is
   //fed off Fosc/2, and count is period+1, so 156 counts.
   setup_adc_ports(sAN0);
   //Now none of the internal functions appear to allow you to select to trigger
   //the ADC on the timer, so go manual
   AD1CON1=(AD1CON1 & 0xFFF8) | 2;
   
   enable_interrupts(INT_ADC1);
   enable_interrupts(INTR_GLOBAL);
   
   do {
      //Use whatever you want to start the conversion - following must happen
      //when you want the conversion to run:
      //index set to '0' and complete set to false.
      adc_index=0;
      complete=FALSE;
      //Now wait for conversion
      while (!complete) ;
      //Here 256 samples have been read. Do what you want with them.
   } while (TRUE);
}


No idea if it is even close, but it might be a start.

Best Wishes
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Fri Apr 27, 2012 5:01 am     Reply with quote

Yes,you are right I did not understood your advices! I have problems in understanding the PIC programming, and the documentation from CCS is maybe helpful for those who have the basic notions of PIC programminng but difficult to understand by the beginers!
Thank you very much for your help and for your code example! I will try my best to make it work!
If you have same usefull reading that can help me undestand and improve my pic programming skills I would greathly apreciate it!
Once again thank you Ttelmah!
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Fri Apr 27, 2012 9:10 am     Reply with quote

It still does not work! There is something I don't do it right! I tried to do something based on your example but I don't get to any result!
Code:

#if !defined(__PCD__)
#error This example will only compile for the PCD 24 bit compiler
#endif

#include <24HJ128GP504.h>
#FUSES FRC_PLL,NOWDT,NOBSS, NOIESO, NOCKSFSM, NOPROTECT, NOJTAG
//#fuses HS,NOWDT,noprotect
#use delay(clock=66.8MHz)

#pin_select U1TX = PIN_C9
#pin_select U1RX = PIN_C8
#use rs232(baud=9600, xmit=PIN_C9, rcv=PIN_C8,parity=N,bits=8)

#include <stdlib.h>
#include <stdio.h>

int16 adc_buffer[256];
int8 adc_index=0;
int1 complete=TRUE;
int half_period;
#WORD AD1CON1=getenv("SFR:AD1CON1")

#int_ADC1
void  ADC1_isr(void){
   if (complete) return;
   adc_buffer[adc_index]=read_adc(ADC_READ_ONLY);
   if (adc_index<255)
      adc_index++;
   else {
      complete=TRUE;
   }   
}
/*
#int_timer3
void timer3_isr(){
  // set_timer3(Number_of_Ticks);
     //  clear_interrupt(INT_ADC1);
   //   adc_index=0;
   //   complete=FALSE;
       enable_interrupts(INT_ADC1);
  //     enable_interrupts(INTR_GLOBAL);

}
*/
void main(void){
   int i;
   setup_oscillator(OSC_INTERNAL,66800000);
   setup_spi( FALSE );
   setup_spi2( FALSE );

   setup_adc_ports(sAN0);
   setup_adc(ADC_CLOCK_DIV_4); //This gives ADC clocked at 8.29MHz = 120.63nSec
   //Almost the max allowed....

   setup_timer2(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer4(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer5(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);

   setup_timer3(TMR_INTERNAL |TMR_DIV_BY_1 ,156);
   //Now use Timer3, since this can trigger the ADC
   //To trigger every 5uSec, require total division by 334 - remember timer is
   //fed off Fosc/2, and count is period+1, so 156 counts.
   setup_adc_ports(sAN0);
   //Now none of the internal functions appear to allow you to select to trigger
   //the ADC on the timer, so go manual
   AD1CON1=(AD1CON1 & 0xFFF8) | 2;
   
HALF_PERIOD=1;
   enable_interrupts(INT_ADC1);
   enable_interrupts(INTR_GLOBAL);
   
   do {
      adc_index=0;
      complete=FALSE;
   enable_interrupts(INT_ADC1);
   enable_interrupts(INTR_GLOBAL);
/*
       clear_interrupt(INT_ADC1);
       enable_interrupts(INT_ADC1);

        set_timer3(0);
       enable_interrupts(int_timer3);
      enable_interrupts(INTR_GLOBAL);
*/
      //Now wait for conversion
do{}
      while (!complete) ;
      //Here 256 samples have been read.
      disable_interrupts(INT_ADC1);
         for(i=0;i<255;i++)
             {
             printf("%lu ",adc_buffer[i]);
          //   delay_ms(400);
             }
         printf("ADC\n\r");
         printf("\n\r");
         complete=FALSE;
      adc_index=0;
   enable_interrupts(INT_ADC1);
   enable_interrupts(INTR_GLOBAL);

   } while (TRUE);
}

Sad Sad
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Wed May 02, 2012 2:32 am     Reply with quote

I had tried different variations based on the code but since I use these fuses setting I get nothing printed!
Code:

#FUSES FRC_PLL,NOWDT,NOBSS, NOIESO, NOCKSFSM, NOPROTECT, NOJTAG
//#fuses HS,NOWDT,noprotect
#use delay(clock=66.8MHz)

Here is a code version that it seems fine for me (but it is not fine)!
Code:

#if !defined(__PCD__)
#error This example will only compile for the PCD 24 bit compiler
#endif

#include <24HJ128GP504.h>
#FUSES FRC_PLL,NOWDT,NOBSS, NOIESO, NOCKSFSM, NOPROTECT, NOJTAG
//#fuses HS,NOWDT,noprotect
#use delay(clock=66.8MHz)

#pin_select U1TX = PIN_C9
#pin_select U1RX = PIN_C8
#use rs232(baud=9600, xmit=PIN_C9, rcv=PIN_C8,parity=N,bits=8)

#include <stdlib.h>
#include <stdio.h>

int16 adc_buffer[256];
int8 adc_index=0;
int1 complete=TRUE;
int half_period;
#WORD AD1CON1=getenv("SFR:AD1CON1")

#int_ADC1
void  ADC1_isr(void){
   if (complete) return;
   adc_buffer[adc_index]=read_adc(ADC_READ_ONLY);
   if (adc_index<255)
      adc_index++;
   else {
      complete=TRUE;
   } 
}

#int_timer3
void timer3_isr(){
int k;

   enable_interrupts(INT_ADC1);

   if(HALF_PERIOD == 0)  // test for interup frequency
       {
       output_low(PIN_B4);
       HALF_PERIOD = 1;
       }
   else
       {
       output_high(PIN_B4);
       HALF_PERIOD = 0 ;
       }
}

void main(void){
    int i;
   setup_oscillator(OSC_INTERNAL,66800000);
   setup_spi( FALSE );
   setup_spi2( FALSE );

   setup_adc_ports(sAN0);
   setup_adc(ADC_CLOCK_DIV_4); //This gives ADC clocked at 8.29MHz = 120.63nSec
   //Almost the max allowed....

   setup_timer2(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer4(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer5(TMR_DISABLED |TMR_DIV_BY_1 ,0);
   setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);

   setup_timer3(TMR_INTERNAL |TMR_DIV_BY_1 ,156);
   //Now use Timer3, since this can trigger the ADC
   //To trigger every 5uSec, require total division by 334 - remember timer is
   //fed off Fosc/2, and count is period+1, so 156 counts.
   setup_adc_ports(sAN0);
   //Now none of the internal functions appear to allow you to select to trigger
   //the ADC on the timer, so go manual

      AD1CON1=(AD1CON1 & 0xFFF8) | 2;
 
       HALF_PERIOD=1;
        adc_index=0;
        complete=FALSE;
       //   enable_interrupts(INT_ADC1);
       enable_interrupts(int_timer3);
          enable_interrupts(INTR_GLOBAL);
 
   do {
        adc_index=0;
        complete=FALSE;
       set_timer3(0);
 
      //Now wait for conversion
do{}
      while (!complete) ;
      //Here 256 samples have been read.
        disable_interrupts(INT_ADC1);
           for(i=0;i<255;i++)
               {
               printf("%lu ",adc_buffer[i]);
              delay_ms(500);
               }
           printf("ADC\n\r");
           printf("\n\r");

   } while (TRUE);
}


Any suggestion?
Thank you!
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Sat May 05, 2012 11:56 pm     Reply with quote

tepes wrote:
Yes,you are right I did not understood your advices! I have problems in understanding the PIC programming, and the documentation from CCS is maybe helpful for those who have the basic notions of PIC programminng but difficult to understand by the beginers!


I'm sorry -- but if you want to learn to program, buy education/instructional books on the language you want to learn.

If you want to learn to program for PIC's, you need to read the datasheet for the device in question... and then read it again... and then read it again... and then use the device...

And read the datasheet AGAIN.

The CCS compiler comes with a manual mostly for reference, not instruction. It also comes with lots of examples... So does microchip's website. (and their almost free compiler).

Ultimately, *you* have you do your homework. No one else will do it for you.

Cheers,

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
tepes



Joined: 25 Jan 2012
Posts: 18

View user's profile Send private message

PostPosted: Mon May 07, 2012 1:09 am     Reply with quote

I am determined to learn PIC programming and I know this will be a long journey!
Regarding my homework I try to do it but sometimes even if I do my best with it, there is something missing and for someone without experience it can take a lot of time to fix the problem! Like now for instantace, I made more than 10 different versions, first based on my own knowlledge, and then based on ttelmahs advices to get to the point where I wanted to get!

Thank you!
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