Use PTG module of DSPIC33EP to trigger ADC sample

PTG, Peripheral Trigger Generator, a useful module of DSPIC33EP series MCU. Just like PDB (Programmable Delay Blocks) module of S32K144 series MCU, it can be used to trigger ADC sample when carry out motor control applications. Sometimes you want to sample multi times during one PWM period. It was difficult if only use PWM event, here I give two code examples to show how to use PTG achieve multi sample.

1. Sequence Sampling

If you want to get a high resolution (12-bit) of ADC result, only sequence configuration can be used, and there is only one S&H amplifier in the 12-bit configuration. The PTG and ADC initial code as below:

extern void Init_ADC_SEQ(void)
{
  AD1CON1 = 0;              //Clear
  AD1CON1bits.ADON = 0;     //ADC is off
  AD1CON1bits.ADSIDL = 0;   //0 = Continues module operation in Idle mode
  AD1CON1bits.AD12B = 1;    //12 bits, 1 channel S/H
  AD1CON1bits.FORM = 2;     //10 = Fractional (DOUT = dddd dddd dddd 0000)
  AD1CON1bits.SSRC = 3;     //011 = PTGO12 primary trigger compare ends sampling and starts conversion
  AD1CON1bits.SSRCG = 1;    //1 = Sample Trigger Source Group bit = 1
  AD1CON1bits.SAMP = 0;     //1 = ADC Sample-and-Hold amplifiers are sampling
  AD1CON1bits.ASAM = 1;     //1 = Sampling begins immediately after the last conversion; SAMP bit is auto-set
  AD1CON1bits.SIMSAM = 0;   //0 = Samples multiple channels individually in sequence 
  AD1CON1bits.DONE = 0;     //ADC conversion has not started
  
  AD1CON2 = 0;
  AD1CON2bits.CHPS = 0x00;  //1x = Converts CH0
  AD1CON2bits.VCFG = 0x00;  //ADC Voltage Reference VREFH = AVDD; VREFL = AVSS
  AD1CON2bits.CSCNA = 1;    //Scan Inputs
  AD1CON2bits.SMPI = 5;     //Generates interrupt after completion of every 6th sample/conversion operation
  AD1CON2bits.ALTS = 0;     //0 = Always uses channel input selects for Sample MUXA
  AD1CON2bits.BUFM = 0;     //0 = Starts filling buffer from the Start address  

  //ADC Clock Period (TAD) = TCY*(ADCS<7:0>+1),TCONV = 14*TAD for 12bits
  AD1CON3 = 0;
  AD1CON3bits.SAMC = 2; //Auto-Sample Time bits
  AD1CON3bits.ADRC = 0; //0 = Clock derived from system clock 
  AD1CON3bits.ADCS = 3; //ADC1 Conversion Clock Select bits
  
  AD1CON4 = 0;  //DMA will not be used

  //config MUXA and MUXB,no use here
  AD1CHS0bits.CH0SA = 0;      //00001 = Channel 0 positive input is AN4
  AD1CHS0bits.CH0NA = 0;      //0 = CH0 negative input is VREFL
  AD1CHS123bits.CH123SA = 0;  //CH1,2,3 positive input is AN0,1,2
  AD1CHS123bits.CH123NA = 0;  //0 = CH1,2,3 negative input is VREFL

  AD1CHS0bits.CH0SB = 0;      //00100 = Channel 0 positive input is AN5
  AD1CHS0bits.CH0NB = 0;      //0 = CH0 negative input is VREFL
  AD1CHS123bits.CH123SB = 0;  //CH1,2,3 positive input is AN0,1,2
  AD1CHS123bits.CH123NB = 0;  //0 = CH1,2,3 negative input is VREFL  

  //Selects AN0-AN5 for input scan
  AD1CSSL = 0x003F;
  
  // Enabling ADC1 interrupt.
  IPC3bits.AD1IP = 5;
  IFS0bits.AD1IF = 0; 
  IEC0bits.AD1IE = 1;
  
  AD1CON1bits.ADON = 1; //Enable ADC
}

extern void Init_PTG_ADC_SEQ(void)
{
  PTGCST = (0x8000 & 0x77FF);  // disabling PTGEN bit and PTGSTRT bit  
  // Clock Frequency = 15.0 MHz; PTGWDT disabled; PTGDIV 1; PTGCLK TAD; PTGPWD 1; 
  PTGCON = 0x4000;
  PTGBTE = 0x00;
  PTGHOLD = 0;
  // Timer0 delay = 0.0 ns; PTGT0LIM 0; 
  PTGT0LIM = 14;//seq
  // Timer1 delay = 0.0 ns; PTGT1LIM 0; 
  PTGT1LIM = 0;    
  PTGSDLIM = 0x00;
  PTGC0LIM = 5;//seq
  PTGC1LIM = 0;
  PTGADJ = 0;
  PTGL0 = 0x00;
  PTGQPTR = 0x00;

  /* Step Commands,one loop */
  _STEP0 = PTGWHI  | 0x2;     // Wait for PWM1 low-to-high edge interrupt
  _STEP1 = PTGTRIG | 0xc;     // Sample Trigger for ADC(PTGO12)
  _STEP2 = PTGCTRL | 0x8;     // Start and wait for the PTG Timer0 to match PTGT0LIM
  
#ifndef PTG_INT  
  _STEP3 = PTGJMPC0 | 0x1;    // Jump to STEP1 if PTGC0!= PTGC0LIM, increment PTGC0
  _STEP4 = PTGJMP  | 0x0;     // Jump to STEP0  
#else  
  _STEP3 = PTGIRQ | 0x0;      // generate interrupt
  _STEP4 = PTGJMPC0 | 0x1;    // Jump to STEP1 if PTGC0!= PTGC0LIM, increment PTGC0
  _STEP5 = PTGJMP  | 0x0;     // Jump to STEP0  
  
  //PTG interrupt Enable
  IEC9bits.PTG0IE = 1;  
#endif 
  
  //PTG Enable
  PTGCSTbits.PTGEN = 1;
  //Start Step Sequence
  PTGCSTbits.PTGSTRT = 1;  
}

The effect is as follows:

 

2. Simultaneous Sampling

The phase current of motor shall be sampled at the same time, so mostly we use simultaneous sampling configuration. The PTG and ADC initial code as below:

extern void Init_ADC_SIM(void)
{
  AD1CON1 = 0;              //Clear
  AD1CON1bits.ADON = 0;     //ADC is off
  AD1CON1bits.ADSIDL = 0;   //0 = Continues module operation in Idle mode
  AD1CON1bits.AD12B = 0;    //10 bits, 4 channel S/H
  AD1CON1bits.FORM = 2;     //11 = Signed fractional (DOUT = sddd dddd dd00 0000, where s = .NOT.d[11])
                            //10 = Fractional (DOUT = dddd dddd dd00 0000)
  AD1CON1bits.SSRC = 3;     //011 = PTGO12 primary trigger compare ends sampling and starts conversion
  AD1CON1bits.SSRCG = 1;    //1 = Sample Trigger Source Group bit = 1
  AD1CON1bits.SAMP = 1;     //Samples CH0, CH1, CH2, CH3 simultaneously
  AD1CON1bits.ASAM = 1;     //Sampling begins immediately after the last conversion; SAMP bit is auto-set
  AD1CON1bits.SIMSAM = 1;   //Simultaneously   
  AD1CON1bits.DONE = 0;     //ADC conversion has not started
  
  AD1CON2 = 0;
  AD1CON2bits.CHPS = 0x03;  //1x = Converts CH0, CH1, CH2 and CH3
  AD1CON2bits.VCFG = 0x00;  //ADC Voltage Reference VREFH = AVDD; VREFL = AVSS
  AD1CON2bits.CSCNA = 0;    //0 = Does not scan inputs
  AD1CON2bits.SMPI = 1;     //Generates interrupt after completion of every 2 sample/conversion operation
  AD1CON2bits.ALTS = 1;     //Alternate Input(MUXA/MUXB)
  AD1CON2bits.BUFM = 0;     //0 = Starts filling buffer from the Start address  

  //ADC Clock Period (TAD) = TCY*(ADCS<7:0>+1),TCONV = 12*TAD for 10bits
  AD1CON3 = 0;
  AD1CON3bits.SAMC = 2; //Auto-Sample Time bits
  AD1CON3bits.ADRC = 0; //0 = Clock derived from system clock 
  AD1CON3bits.ADCS = 2; //ADC1 Conversion Clock Select bits
  
  AD1CON4 = 0;  //DMA will not be used
  
  //config MUXA and MUXB
  AD1CHS0bits.CH0SA = 4;      //Channel 0 positive input is AN4
  AD1CHS0bits.CH0NA = 0;      //0 = CH0 negative input is VREFL
  AD1CHS123bits.CH123SA = 0;  //CH1,2,3 positive input is AN0,1,2
  AD1CHS123bits.CH123NA = 0;  //0 = CH1,2,3 negative input is VREFL

  AD1CHS0bits.CH0SB = 5;      //Channel 0 positive input is AN5
  AD1CHS0bits.CH0NB = 0;      //0 = CH0 negative input is VREFL
  AD1CHS123bits.CH123SB = 1;  //CH1,2,3 positive input is AN3,0,6
  AD1CHS123bits.CH123NB = 0;  //0 = CH1,2,3 negative input is VREFL  

  //Selects AN0-AN5 for input scan,no use here
  AD1CSSL = 0x0000;
  
  // Enabling ADC1 interrupt.
  IPC3bits.AD1IP = 5;
  IFS0bits.AD1IF = 0; 
  IEC0bits.AD1IE = 1;
  
  AD1CON1bits.ADON = 1; //Enable ADC    
}

extern void Init_PTG_ADC_SIM(void)
{
  PTGCST = (0x8000 & 0x77FF);  // disabling PTGEN bit and PTGSTRT bit  
  // Clock Frequency = 15.0 MHz; PTGWDT disabled; PTGDIV 1; PTGCLK TAD; PTGPWD 1; 
  PTGCON = 0x4000;
  PTGBTE = 0x00;
  PTGHOLD = 0;
  // Timer0 delay = 0.0 ns; PTGT0LIM 0; 
  PTGT0LIM = 48;//sim
  // Timer1 delay = 0.0 ns; PTGT1LIM 0; 
  PTGT1LIM = 0;    
  PTGSDLIM = 0x00;
  PTGC0LIM = 1;//sim
  PTGC1LIM = 0;
  PTGADJ = 0;
  PTGL0 = 0x00;
  PTGQPTR = 0x00;
 
  /* Step Commands,one loop */
  _STEP0 = PTGWHI  | 0x2;     // Wait for PWM1 low-to-high edge interrupt
  _STEP1 = PTGTRIG | 0xc;     // Sample Trigger for ADC(PTGO12)
  _STEP2 = PTGCTRL | 0x8;     // Start and wait for the PTG Timer0 to match PTGT0LIM
  
#ifndef PTG_INT  
  _STEP3 = PTGJMPC0 | 0x1;    // Jump to STEP1 if PTGC0!= PTGC0LIM, increment PTGC0
  _STEP4 = PTGJMP  | 0x0;     // Jump to STEP0  
#else  
  _STEP3 = PTGIRQ | 0x0;      // generate interrupt
  _STEP4 = PTGJMPC0 | 0x1;    // Jump to STEP1 if PTGC0!= PTGC0LIM, increment PTGC0
  _STEP5 = PTGJMP  | 0x0;     // Jump to STEP0  
  
  //PTG interrupt Enable
  IEC9bits.PTG0IE = 1;  
#endif 
  
  //PTG Enable
  PTGCSTbits.PTGEN = 1;
  //Start Step Sequence
  PTGCSTbits.PTGSTRT = 1;  
}

The effect is as follows:

 

3. PTG interrupt

Sometimes, it is necessary to know the specific trigger moment, so you can enable the PTG interrupt,  add the pulse of GPIO to observe.

void __attribute__ ( ( interrupt, no_auto_psv ) ) _PTG0Interrupt ( void )
{
  // clear the PTG Trigger0 interrupt flag
  IFS9bits.PTG0IF = 0;
  
  // add gpio puls here
  ...
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值