Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Problem with dsPIC ADC and Timer

Status
Not open for further replies.

galib.tan

Newbie level 6
Newbie level 6
Joined
Jan 5, 2012
Messages
11
Helped
2
Reputation
4
Reaction score
2
Trophy points
1,283
Visit site
Activity points
1,379
Hi everybody

I'm facing some problems with the following code. I'm using dsPIC 30F2010 and clocking it at 128MHz (overclocking 8MHz crystal and 16x PLL). I'm generating a PWM of 100kHz. I want to make the AD conversion start with the special event trigger from the PWM module. The AD conversion is supposed to start when the PTMR value reaches the peak (up/down PWM mode). I'm checking the ADC interrupt by toggling the RD1 pin. I'm also trying to display the adc value on a 16x2 lcd after every second with timer1. I'm however facing the following problems.

1. The pwm starts as expected after power up but the adc interrupt occurs after a significant delay. This delay varies. If the timer1 interrupt frequency is reduced this delay increases. One more problem is that the RD1 should toggle at 50kHz but it's toggling at 25kHz.

NewFile0.jpg

channel1: PWM, channel2: RD1

2. After start up it takes a good length of time (several minutes) to show the ADC value. This delay also varies with the timer1 interrupt frequency (and device clock maybe). After showing for the first time the value refreshes after every second as expected.

Please have a look and help with the problems. Thanks.

Code:
sbit LCD_RS at LATE5_bit;
sbit LCD_EN at LATD0_bit;
sbit LCD_D4 at LATE1_bit;
sbit LCD_D5 at LATE2_bit;
sbit LCD_D6 at LATE3_bit;
sbit LCD_D7 at LATE4_bit;

sbit LCD_RS_Direction at TRISE5_bit;
sbit LCD_EN_Direction at TRISD0_bit;
sbit LCD_D4_Direction at TRISE1_bit;
sbit LCD_D5_Direction at TRISE2_bit;
sbit LCD_D6_Direction at TRISE3_bit;
sbit LCD_D7_Direction at TRISE4_bit;



void ADC_init(void);
void pwm_init(void);
void timer1_init(void);
void InitTimer1();


volatile unsigned adc_value = 0;
char adc_txt[6];
char txt1[11];
volatile unsigned ticks_lcd;



void main() {


     unsigned val = 0;
     unsigned long clk=0;


     trisd1_bit = 0;
     latd1_bit = 0;
     
     InitTimer1();
     
     pwm_init();
     
     ADC_init();

     LCD_init();

     lcd_cmd(_lcd_cursor_off);
     lcd_cmd(_lcd_clear);
     
     
     ADIF_bit = 0;

     INTCON1bits.NSTDIS = 1;   // interrupt nesting disabled
     PTCONbits.PTEN = 1;       // pwm enabled
     ADON_bit = 1;             // adc enabled
     ADCON1bits.ASAM = 1;      // auto sampling enabled
     ADIE_bit = 1;             // adc interrupt enabled
     

     clk = clock_MHz();
     longwordtostr(clk, txt1);
     lcd_out(2, 1, txt1);
     delay_ms(1000);
     lcd_cmd(_lcd_clear);



     
     while(1)
     {


             if(ticks_lcd == 1000)
             {
                val = adc_value;
                wordtostr(val, adc_txt);
                lcd_out(2, 4, adc_txt);
                ticks_lcd = 0;
             }
             
     }



}


void ADC_init(void)
{

  ADCON1 = 0x0060;       // continue idle mode, integer format, motor control trigger, sequential sampling, SAMP auto = 0
  ADCHS = 0x0000;        // ch0 positve input AN0, ch0 negative -VREF, CH1 positive AN0, CH1 negative -VREF
  ADCSSL = 0;            // no scan
  ADCON3 = 0x0009;       // auto sample time = 0Tad, system clock, ADCS<5:0> = 9
  ADCON2 = 0x0104;       // converts CH0 and CH1, 2 conversions per interrupt
  IPC0 = IPC0 | 0x7000;  // priority 7
  ADPCFG = 0xFFFE;       // AN0 is analog
  
}

void pwm_init(void)
{
     PTCON.PTEN = 0;           // pwm timebase off
     PWMCON1.PEN1L = 1;        // PWM1L pin is configured for pwm operation
     PWMCON1bits.PMOD1 = 1;    // PWM1L and PWM1H pair is independent
     PTCONbits.PTMOD = 2;       // free running mode
     PTCONbits.PTOPS = 0;       // 1:1
     PTCONbits.PTCKPS = 0;      // 1:1  pwm timebase input clock is Tcy
     PTCONbits.PTSIDL = 0;      // pwm runs in idle mode
     SEVTCMP =  159;            // Triggers the ADC in the middle of PWM off time
     PTPER = 159;               // period register value. 100kHz for up-down mode
     PDC1 = 160;                // duty cycle 0.5

}


//Timer1
//Prescaler 1:1; PR1 Preload = 32000; Actual Interrupt Time = 1 ms

void InitTimer1(){
  T1CON = 0x8000;
  TMR1 = 0;
  T1IE_bit = 1;
  T1IF_bit = 0;
  IPC0 = IPC0 | 0x6000;     // priority 6

  PR1 = 32000;              // 1ms
}


void ADCInt() iv IVT_ADDR_ADCINTERRUPT ics ICS_AUTO
{

  adc_value = ADCBUF0;
  latd1_bit = !latd1_bit;
  ADIF_bit = 0;

}

void T1Int() iv IVT_ADDR_T1INTERRUPT ics ICS_AUTO
{
   ticks_lcd++;
   T1IF_bit = 0;
}
 

Between Timer interrupt and ADC interrupt which has higher priority ?

Zip and post complete mikroC PRO dsPIC project files.
 

Hi milan.rajik
Thanks for your reply.
ADC interrupt has higher priority.
 

Attachments

  • test_prog.zip
    52.2 KB · Views: 121

Maybe Timer1 Has more priority. Check again. 25 KHz is half of 50 KHz. Maybe you configured the Timer Interrupt incorrectly. Rising edge of a pulse to next rising edge of next pulse is Period.

F = 50 KHz, T = 1 / 50 KHz = 20 us. Did you create a timer interrupt for 20 us ?


20 ms is the time in which the pulse remains high for 10 us and low for 10 us. So a interrupt od 10 us should be created so that in 20 us the pin toggles twice.

You say that you have overclocked the dsPIC. It might also be a reason for incorrect Timer1 Interrupt timing.
 
Last edited:

Hi,

i´m not familiar with C... i can read it somehow.


You say it takes too long for the first display.
maybe ticks_lcd is not initialized properly. Either you do this at startup or you check on ">= 1000".
My thought is when ticks_lcd accidentely is not processed at "1000" then it is incremented to 1001 or even more.
Then it is not reset to 0 until the variable has an overflow at 65535 (+1). Then it starts with 0 and is incremented to "1000" until processed.
So you have 65536 additional count ticks.


Another reliable solution is:
Within the ISR, where you increment ticks_lcd,
immediately after that check on "= 1000" (here you can´t miss a tick) and if equal: clear it to zero and set a flag for the main loop to process the LCD routine.
Clear the flag within the LCD routine.

Klaus
 
Hi KlausST
Thank you very much. Your solution worked. The delay is gone now. :smile:
The other problem still exists. If you've time please have a look.

Hi milan.rajik
I'm afraid, I might not have expressed the problem clearly. Actually, I'm not using the timer interrupt to toggle the pin. I'm toggling the pin inside the ADC isr to check if the ADC and PWM is synchronized. I've to update the duty cycle every cycle. But the way it's happening, one cycle will be missed.
Thanks for your time, anyway.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top