Hello,
I have tried to look for PWM chopper module example project in control suite, but couldnt find any. Can anyone let me know how can I get better understanding of it. I need to generate 7 pwms with a gap before the next 7 pwms.
Regards-
What device are you using?
F28069 experimenter's kit....
Unfortunately, we do not have any examples in controlSUITE for this device as you mentioned. Have you looked over the PWM Chopper section of the PWM User's Guide? It is 3 pages (283-286) available here: http://www.ti.com/lit/ug/spruh18c/spruh18c.pdf
If you poke around with the chopper registers I think you will find it is a relatively simple submodule. Specifically, you will want to play with the CHPFREQ and CHPDUTY bits in PCCTL.
Kris
Yes, I have gone through it and tried my hands on it. But that didnt help much and therefore I tried searching for an example. The submodule description in the piccolo reference is quite insufficient for clear understanding.
Can you post the code you have so far and a detailed description of what you are trying to do? For example, I believe you said you wanted 7 pulses. What frequency / duty cycle are you looking for? Is the first pulse the same width as the following pulses?
I am trying to interface an analog front end(16 channels) for EMG recordings out of which I want to access 1st 8 channels and it is through SPI protocol and I need to have 3 pwms for this operation. Step, which tells the analog front end to go to next channel(for mux), reset(active low) that tells the chip to start from 1st channel again and convert signal, which tells the ADC to start the conversion.
I am at home now and will send you the code tomorrow when I reach office. By the way, what I am doing now is my reset signal is having 4KHz freq(TPRD = 10000) and step signal is having 32KHz and CNV signal is same but inverted. But I dont want the step to be continuous train of pulse. I must have a gap after 7 pulses after which reset is used. You can get a better idea by having a look at the attachment (page 10).
void InitEPwm1Reset(){ // Setup TBCLK EPwm1Regs.TBPRD = 10000; // Set timer period 801 TBCLKs EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm1Regs.TBCTR = 0x0000; // Clear counter // Set Compare values EPwm1Regs.CMPA.half.CMPA = 1250; // Set compare A value EPwm1Regs.CMPB = 125; // Set Compare B value
// Setup counter mode EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Set actions EPwm1Regs.AQCTLA.bit.CBU = AQ_CLEAR; // clear PWM1A on event B, up count EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // set PWM1A on event A, up count
}
void InitEPwm2Cnv(){ // Setup TBCLK EPwm2Regs.TBPRD = 1250; // Set timer period 801 TBCLKs EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm2Regs.TBCTR = 0x0000; // Clear counter // Setup counter mode EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Set actions EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Clear PWM2A on event zero EPwm2Regs.AQCTLA.bit.PRD = AQ_SET; // Set PWM2A on period}
void InitEPwm3Step(void){ // Setup TBCLK EPwm3Regs.TBPRD = 1250; // Set timer period EPwm3Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm3Regs.TBCTR = 0x0000; // Clear counter
EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;// Count up/down EPwm3Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm3Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm3Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Set Actions EPwm3Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM3A on zero EPwm3Regs.AQCTLA.bit.PRD = AQ_CLEAR; // Clear PWM3A on period
// Interrupt where we will receive data from the ADC EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event EPwm3Regs.ETSEL.bit.INTEN = 1; // Enable INT EPwm3Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event }
Thank you for the information. Please allow me some time to review it. I will get back to you by the end of the week.
Ok Kris. Thank you.
If you have a GPIO (one with a TZ option on it) to spare, I think using a CBC trip is really a better solution for this. You would just externally connect the reset PWM output to this and set each of the step and CNV waveforms to be forced low on a CBC trip action. I think we could make the chopper work sufficiently, but using the trip function makes this a true active low reset function. Let me know your thoughts.
Actually, I cannot figure out how CBC(TZ) will solve the purpose or in other words, how can I make use of it. Can you let me know how?
Sure,
So what we would do in this case is configure your step signal to generate the proper frequency and duty cycle, not worrying about blanking out the 8th pulse (the trip will take care of this). We set the other PWM channel to be complimentary of the generated STEP signal for the CNV signal. So for simplicity let's say STEP is on PWM2A and CNV is on PWM2B.
Now let's take PWM1A and generate the reset signal. We would set this up to operate at a 87.5% duty cycle (87.5 = 7/8 since it is only low for 1 pulse out of 8) at whatever frequency gave the low pulse the desired width (the same width as your step/cnv pulses). Now if we tie the output of this PWM to a TZ and configure PWM2A and PWM2B outputs to always be forced low while the trip is active, this will automatically blank out the 8th pulse for you. The CBC trip works such that the condition is evaluated every TBCLK- so as long as PWM1A is low, the outputs of PWM2A and PWM2B will stay low. When the condition clears the PWM2A/B outputs will continue as normal. I think this will give you more control over your outputs than the chopper would. For example, if you want to stop transmitting now you can just set the PWM1A output low and the other 2 signals are automatically stopped until you resume operation.
Hello Kris,
Let me summarize to let you know if I understood you correctly. So, the trip signal is the reset (when low), and the TZCTL(TZA and TZB) registers must be used to set the action when the trip signal is encountered. I have never worked with this before, so will give it a try and let you know. By the way, what did you mean by saying -
'' We would set this up to operate at a 87.5% duty cycle (87.5 = 7/8 since it is only low for 1 pulse out of 8) at whatever frequency gave the low pulse the desired width (the same width as your step/cnv pulses). Now if we tie the output of this PWM to a TZ ''.
Correct, PWM2A and PWM2B (or whichever PWMs you decide to use for the STEP / CNV) signal would use the TZ submodule to force the outputs low while the reset signal is low.
The RESET signal will be generated by another PWM. From the waveform, it looked like the RESET low pulse was the same width as the high pulses on STEP / CNV. I'm not sure if this is a requirement by your application or not. If it's not, you can ignore that statement. Basically, I was wanting to run the RESET PWM at a slower frequency so that you wouldn't have to modify the registers inbetween periods. So essentially, 1/8 of the period on the RESET PWM (the low pulse) would be the equivalent to 1/2 the period (the high pulse) on the STEP PWM (assuming this is running at 50% duty cycle). This is certainly a bit confusing, but running the RESET at a slower frequency keeps the RESET period without ever having to interact with the PWM registers. Maybe I'm over thinking your application though :)
EDIT: I think the 87.5% is incorrect now that I'm thinking about it. But the idea stays the same. Might need to play with the numbers some.
am not very clear:)....Am I correct in the following code...I guess I made some mistake..
void init(void){
/* Step 1. Initialize System Control: PLL, WatchDog, enable Peripheral Clocks*/ InitSysCtrl();
/* Step 2. Initialize GPIO:*/ InitSpiaGpio(); //Setup GPI/O for SPI-A functionality InitSciaGpio(); //Setup GPI/O for SCI-A functionality
InitEPwm1Gpio(); //Setup GPI/O for ePWM1 functionality InitEPwm2Gpio(); //Setup GPI/O for ePWM2 functionality // InitEPwm3Gpio(); //Setup GPI/O for ePWM3 functionality InitTzGpio();
/* Step 3. Clear all interrupts and initialize PIE vector table: Disable CPU interrupts */ DINT;
/* Initialize PIE control registers to their default state. The default state is all PIE interrupts disabled and flags are cleared..*/ InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags: IER = 0x0000; IFR = 0x0000;
/* Initialize the PIE vector table with pointers to the shell Interrupt// Service Routines (ISR). // This will populate the entire table, even if the interrupt// is not used in this example. This is useful for debug purposes.*/ InitPieVectTable(); EALLOW; // This is needed to write to EALLOW protected registers PieVectTable.EPWM3_INT = &epwmstep_isr; //Enable interrupt on pwn3 EDIS; // This is needed to disable write to EALLOW protected registers
// Interrupts that are used in this example are re-mapped to // ISR functions found within this file. EALLOW; // This is needed to write to EALLOW protected registers PieVectTable.EPWM2_TZINT = &epwm2_tzint_isr; EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize all the Device Peripherals:// This function is found in F2806x_InitPeripherals.c spi_init(); // Initialize SPI spi_fifo_init(); // Initialize the SPI FIFO
scia_fifo_init(); // Initialize the SCI FIFO scia_echoback_init(); // Initialize SCI for echoback
EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; EDIS; InitEPwm1Reset(); InitEPwm2Cnv(); InitEPwm2Step(); InitEPwm2Example(); EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS;
// Enable CPU INT3 which is connected to EPWM1-3 INT: IER |= M_INT3; // Enable CPU INT3 which is connected to EPWM1-3 INT: IER |= M_INT2;
// Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
// Enable EPWM INTn in the PIE: Group 2 interrupt 1-3 PieCtrlRegs.PIEIER2.bit.INTx2 = 1;
// Enable global Interrupts and higher priority real-time debug events: EINT; // Enable Global interrupt INTM ERTM; // Enable Global real-time interrupt DBGM
__interrupt void epwm2_tzint_isr(void) {
// Clear the flags - we will continue to take // this interrupt until the TZ pin goes high // EALLOW; EPwm2Regs.TZCLR.bit.CBC = 1; EPwm2Regs.TZCLR.bit.INT = 1; EDIS;
// Acknowledge this interrupt to receive more interrupts from group 2 PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
void InitEPwm2Example() {
// Enable TZ1 and TZ2 as one cycle-by-cycle trip sources EALLOW; EPwm2Regs.TZSEL.bit.CBC1 = 1; EPwm2Regs.TZSEL.bit.CBC2 = 1;
// What do we want the TZ1 and TZ2 to do? EPwm2Regs.TZCTL.bit.TZA = TZ_FORCE_LO; EPwm2Regs.TZCTL.bit.TZB = TZ_FORCE_LO;
// Enable TZ interrupt EPwm2Regs.TZEINT.bit.CBC = 1; EDIS;
// Setup TBCLK EPwm2Regs.TBPRD = 1250; // Set timer period 801 TBCLKs EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm2Regs.TBCTR = 0x0000; // Clear counter
// Setup counter mode EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up/down EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Set actions EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Clear PWM2A on event zero EPwm2Regs.AQCTLA.bit.PRD = AQ_SET;
// Set Actions EPwm2Regs.AQCTLB.bit.ZRO = AQ_SET; // Set PWM3A on zero EPwm2Regs.AQCTLB.bit.PRD = AQ_CLEAR; // Clear PWM3A on period
void InitEPwm2Step(void){ // Setup TBCLK EPwm2Regs.TBPRD = 1250; // Set timer period EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // Phase is 0 EPwm2Regs.TBCTR = 0x0000; // Clear counter
EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;// Count up/down EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Interrupt where we will receive data from the ADC EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event EPwm2Regs.ETSEL.bit.INTEN = 1; // Enable INT EPwm2Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event}