This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Question about PEC

Hi again,

I am using C167. I am using PEC for AD-conversion.
I configure PEC as follows:
ADCIC = 0x007B;
PECC3 = 0x00FF;
SRCP3 = (int) (&ADDAT);
DSTP3 = (int) (&P3);
ADCON = 0x0090;
I works fine to transfer values to from ADDAT to port P3. . Now I want to determine how many times AD-conversion has taken place.

In PECCx there are 8-LSB are:
COUNT (PEC Transfer Count)

Now I wonder if I am on right track or there are other way to do what I want.
Even if I use the 8-LSB of PECCx I can have the max value 2 raised to power 8 i.e. 256,
what happens if the nr of AD-conversion exceed 256?

Can someone help me in this regard?
Send me mail if something is not clear.
thanks in advance
regards
/M

  • Hi Mohammad,

    Read the microcontroller manual, Interrupt and Trap Functions, Operation of the PEC Channels.
    According to the manual, if you put the PEC channel in continuous mode (as you did in your example by setting the COUNT field of PECC3 to 0xFF,) there will be no way to find out how many transfers have taken place. It will go on forever, unless you modify control registers or trigger a reset or cut the power...

    Regards,
    - Mike

  • Hi Mohammad,
    don't use the PEC in continous transfer mode, use it in the decrement count mode. You need to have a PEC Ready interrupt service function in which you can count the number of interruptoccurence. Together with the Count value of the PECCx register you can calculate the number of done ADC scans.
    Hope this helps
    regards
    Uwe

  • Hi Uwe,
    Thanks for reply.

    Efter reading the manual, I am truing to calculate the 100 AD-conversion values.
    I have written the following code to initialize the PEC.

    void ADCinit(void)
    {
    ADCIC = 0x0079; // (ILVL) = 14, (GLVL) = 1
    ADCON = 0x0090; // load ADC control register
    PECC1 = 0x00FF; // count 100, transfer a word, inc dst pointer
    SRCP1 = (unsigned int)&ADDAT;
    DSTP1 = (unsigned int)&AD_buffer;

    }


    interrupt (ADCINT) void AverageADC(void)
    {
    dprintf("Average %i", AD_buffer/100);
    }



    Does anybody see anything missing in this code?

    Any comment will be appreciated.
    regards
    /M

  • Sorry,

    I sent my mail too fast with wrong code.
    The right one comes here:

    I am trying to calculate the 100 AD-conversion values.
    I have written the following code to initialize the PEC.

    interrupt (ADCINT) void AverageADC(void);
    unsigned int AD_buffer[10];

    void ADCinit(void)
    {
    ADCIC = 0x0079; // (ILVL) = 14, (GLVL) = 1
    ADCON = 0x0090; // load ADC control register
    PECC1 = 0x0264; // count 100, transfer a word, inc dst pointer SRCP1 = (unsigned int)&ADDAT;
    DSTP1 = (unsigned int)&AD_buffer;

    }


    interrupt (ADCINT) void AverageADC(void)
    {
    dprintf("Average %i", AD_buffer/100);
    }



    Does anybody see anything missing in this code?
    Of course "main" and some display code is missing delibrately.
    Any comment will be appreciated.
    regards
    /M

  • HI Mohammad

    Your array needs place for 100 entries if you want to do 100 PEC transfers.
    unsigned int AD_buffer[100];

    I always use the following syntax to init the PEC Destination pointer
    DSTP0 = _sof_ (AD_buffer);
    I don't know if your syntax runs correctly.

    During the interrupt function you have to reinitialize all the PEC registers if you want to have a continous conversion mode.
    regards
    Uwe

  • Hi all again,

    As I told in my previous mail. I am trying to calculate the average value for 100 AD-conversion values (in volts) using PEC.

    I have written a small code as below:

    
    
    
    int value;
    int counter = 0;
    float x, y,z, m;
    
    void main(void)
    {
     
     
      ADCIC          =  0x0079;     // (ILVL) = 14, (GLVL) = 1 
      ADCON          =  0x0090;     // load ADC control register 
      PECC1          =  0x00FF;     // count continours
      IEN = 1;
     while(1)
     {
           if(counter<=100)
    	{
    	ADST=1;			//Start AD conversion
    	SRCP1=(int)(&ADDAT);	//Get data from ADDAT
    	DSTP1=(int)(&value);	//Move data till variabeln value
    	ADST=0;                 //Stop AD conversion
           	x=value;		//change type of value to float
    	y=x/1023*5;		//Calculate voltage. Vref =5,0V.
    	z=z+y;			//Accumulate result in variable z
           	m=z/antal;		//Save average in variable m
    	counter++;
      	}	
     }
    }
    

    I get only first time AD-conversion value and then nothing happens.
    I would appreciate if someone can give comments on my code and guide me on the right track.
    thanks in advance
    regards
    /M



  • Dear Mohammad,
    this sounds like a totally new approach.
    Your code looks like you are polling the ADC Result register. Therefore you do not need the PEC transfer mechanism.
    But between starting and reading the ADC you must wait the ADC conversion time. Check the busy flag of the ADC (ADBSY). If ready then read ADDAT and accumulate the values as described.
    BTW your code accumulate 101 ADC values.
    regards
    Uwe

  • This is code I used to implement an 8-channel, 4-samples per channel, round-robin, PEC based ADC system. It stores the results as an array of 32 integers, every 4th one is from the same channel.

    #pragma PECDEF( 3 )                 // Reserve PEC ptr space
    
    /*===========================================================================
                                     VARIABLES
    ===========================================================================*/
    #define ADC_CHANNELS          (8)
    #define ADC_SAMPLES_PER_CYCLE (4)
    #define ADC_BUFFER_CNT        (ADC_CHANNELS * ADC_SAMPLES_PER_CYCLE)
    
                                                    // Storage for one cycle of AD readings (PEC target)
    static UINT volatile sdata ui16_Adc_Buffer_Array[ ADC_BUFFER_CNT ];
    
    UINT volatile ui16_Adc_Count;                   // Flag counting fill cycles
    
    BIT Initialize_ADC( void ) {
    
       UINT i;
       _atomic_( 0 );
       ADCON = 0xB000;                                    // Stop A/D
       ADCIC = ADC_IRQ_LVL;
       _endatomic_();
       for ( i = 0; i < ADC_BUFFER_CNT; ++i )             // Clear buffer
          ui16_Adc_Buffer_Array[i] = 0;
       ui16_Adc_Count = 0;
       ADEIC = 0x0004;                                    // Disable error intr
       SRCP3 = _sof_( &ADDAT );                           // Init PEC control
       DSTP3 = _sof_( &ui16_Adc_Buffer_Array[0] );
       PECC3 = 0x0200 | ADC_BUFFER_CNT;                   //  Word/Incr/Cycle cnt loops
       _atomic_( 0 );
       ADCON = 0xB2B7;                                    // A/D control - start/seq/Ch 7/slow
       ADCIC = ADC_IRQ_LVL | 0x0040;
       _endatomic_();
       while ( ui16_Adc_Count == 0 );                     // Wait for one cycle (2 msec)
       return ( TRUE );
    }
    
    void ADC_ISR( void ) interrupt ADCINT using adc_Rbank {
    
       ADST = 0;                                          // A/D control - stop
       ++ui16_Adc_Count;
       DSTP3 = _sof_( &ui16_Adc_Buffer_Array[0] );
       PECC3 = 0x0200 | ADC_BUFFER_CNT;                   //  Word/Incr/Cycle cnt loops
       _atomic_( 0 );
       ADST = 1;                                          // A/D control - start
       ADCIC = ADC_IRQ_LVL | 0x0040;                      // Clear pending requests
       _endatomic_();
    }
    
    
    This system allows the foreground to ask for either the latest reading from a channel or the average of the last 4 readings for a channel. You can easily modify it to support only one channel with 100 readings. This was originally written to be run under RTX so the atomic stuff is to prevent preemption and higher priority ISRs.
    Best luck
    Scott