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

12 bit ADC over USB serial @ 10kHz

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



Joined: 10 Feb 2013
Posts: 3

View user's profile Send private message

12 bit ADC over USB serial @ 10kHz
PostPosted: Sun Feb 10, 2013 1:19 pm     Reply with quote

Hello,
I'm trying sample one channel ADC at 10kHz and transmit the data over USB serial. The code is below.

Unfortunately USB halt after transmitting several tens of samples. I think the problem with the speed of "printf(usb_cdc_putc,...)", but have no idea how to solve it.
I'll appreciate for help.

[/code]
Code:
#include <18F2553.h>
#device ADC = 12
//configure a 20MHz crystal to operate at 48MHz
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
//#use rs232(baud = 115200, xmit = PIN_C6, rcv = PIN_C7)

#include <usb_cdc.h>
//#include <input.c>
//#include <stdlib.h>

unsigned int16 adc_data;
int32 i=0;
int8 s2r=1; //s2r - Seconds to record
int32 c2t; //c2r - Cycles to transmit

//Initializing the RTOS Program

#use rtos(timer = 0, minor_cycle = 10us)

#task(rate = 100us, max = 10us) // 100uS -> 10kHz
void transmit_over_usb()
{
        //adc_data = read_adc();
        printf(usb_cdc_putc, "%Lu\n\r", read_adc());
        if(++i==10000)//(i == c2t)
            rtos_terminate( );
}

void main()
{
   #use standard_io(A)
   
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_DIV_64); // for 48MHz OSC
   //setup_adc(ADC_CLOCK_DIV_16); // For 20 MHz OSC
   set_adc_channel(0);
   delay_us(10);
   
   usb_cdc_init();
   usb_init();

   while(!usb_cdc_connected()) {}

   do
   {
      usb_task();
      if (usb_enumerated())
      {
         wait_usb: // Label
         while (usb_cdc_getc() != 'r') ;
         i=0;
         s2r=1;
         
         c2t = (s2r*1e6)/250; // How many cycles to transmit the data. NOTE: Denumerator should be equal to "rate" in main RTOS task
         output_high(PIN_B0);
         
         rtos_run();

         output_low(PIN_B0);
         // printf("Done!\n\r");
         printf(usb_cdc_putc,"5002\n\r");
         goto wait_usb;
      }
   } while (TRUE);
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Sun Feb 10, 2013 3:35 pm     Reply with quote

Time.

You certainly have not got time to do this with the RTOS. 10uSec, is every 120 instructions. The printf, will take at least this long (you are asking it to format the number, so it has to perform repeated divisions. Each int16 division takes 26uSec on it's own.....

Not even close to possible.

Best Wishes
itisme



Joined: 10 Feb 2013
Posts: 3

View user's profile Send private message

PostPosted: Mon Feb 11, 2013 1:01 am     Reply with quote

Hi,
Thank you for reply.
Any idea how can I transmit A/D data without formatting then decode it at PC side?
Best regards!
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Feb 11, 2013 2:00 am     Reply with quote

Don't use the RTOS. This has a significant overhead you don't want....
Just have a timer tick using (say) Timer2, set to interrupt at 10uSec intervals (best timer for this). Then don't use an interrupt handler, just poll the interrupt flag. Save time by starting the new ADC conversion as soon as you have read the last. So (hypothetical only):
Code:
 
    int16 icount,adc_val;

    setup_timer_2(T2_DIV_BY_1, 119,1); //will trigger every 120 instructions
   
    set_timer2(0);
    clear_interrupt(INT_TIMER2);
    read_adc(ADC_START_ONLY);
    delay_us(8); //ensure the first conversion completes
    for (icount=0;icount<10000;icount++) {
        while (!interrupt_active(INT_TIMER2)) ; //wait for interrupt to fire
        //get here when the timer interrupt triggers
        clear_interrupt(INT_TIMER2);
        adc_val=read_adc(ADC_READ_ONLY); //read the already ready ADC
        read_adc(ADC_START_ONLY);
        //Now start the next ADC conversion. This will be going on _while_
        //the data is being sent. Overlapped working.....
        usb_cdc_putc_fast(make8(adc_val,0));
        usb_cdc_putc_fast(make8(adc_val,1)); //send LSB, then MSB
    }


It'll still be very tight on time (two putc's). You might need to do direct I/O to the USB driver instead. As written, it'll throw away characters if the USB can't keep up.

Best Wishes
itisme



Joined: 10 Feb 2013
Posts: 3

View user's profile Send private message

PostPosted: Mon Feb 11, 2013 9:05 am     Reply with quote

I'm really appreciate for idea ...
All the best!
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