CCU4: Measure PWM duty cycle and period

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello everybody!

I would like to measure the PWM duty cycle and the time of the pulse of an external signal. In this respect, I used the CCU4_SLICE_CONFIG App of Dave4, changed the Mode to "Capture" and set Event0, Event1 as rising and falling edge events. An Interrupt is created at Event1. But now I dont know how to go on.

I already read AP32287 - XMC1000, XMC4000 - Capture Compare Unit 4 (CCU4) and had a look at the example of the help page of the app in Dave 4. But in the PDF the code is written without using APPs and in the example a PWM is just generated but not read out.
Does anybody can help and tell me how the timervalue of the pulse is read out?

Board: XMC4500 Relax Kit

Best regards
0 Likes
8 Replies
Not applicable
Really nobody?
0 Likes
User10215
Level 4
Level 4
First like received
Hi Felix,

first of all the App "CCU4_SLICE_CONFIG" is the correct one. Then you can do the following:
- for a first test mark "ignore full flag rules"
- also check "Start during initialization"
- for Event 0 select "capture0" as a Function which means that the timer value will be captured into the register CC4yC0V and CC4yC1V when the event occurs
- for Event 1 select "capture1" as a Function which means that the timer value will be captured into the register CC4yC2V and CC4yC3V when the event occurs

For the following explanation I will assume the the edge selected for Event 0 is the edge that marks the start of the period and the edge selected for Event 1 marks the Duty Cycle.
- select "Cleared on capture into reg 0 and 1" for the "Timer clear control" which will clear the timer when Event 0 occurs (because we selected "capture0" as function for Event 0). This means the timer will be restarted each time a new period begins

Have a look at the tab "HW Signal Connectivity" in Dave...you will see that the block "CCU4_SLICE_CONFIG" has inputs for event 0 and event 1, which means we can connect it to other APPs...for instance a DIGITAL_IO-APP!

- add a DIGITAL_IO-App
- right click on the DIGITAL_IO-App and select "Manual Pin Allocator" and select the pin you want to use...BE AWARE: the pin you choose has to have a hardware connection to a CCU4-Slice! You can see which connections the Pins have in the chapter "2.2.2.1 Port I/O Function Table" of the XMC4500-datasheet
- right click on the DIGITAL_IO-App and select "HW Signal Connections"
- select "pin" as source signal and route it to CCU4_SLICE_CONFIG-App's event 0
- after you press "save" you can choose another hardware connection which you will route to CCU4_SLICE_CONFIG-App's event 1

For this test you won't need interrupts for the "CCU4_SLICE_CONFIG". The capturing will automatically start when "DAVE_Init()" in the main-function is called since we marked "Start during initialization".
When the edge for the period occurs, the timer-value at that moment will be captured into the CC4yC1V. When the edge for the duty cycle occurs, the timer-value at that moment will be captured into the CC4yC3V.
You can read out the values in the capture registers like this in the while-loop:

u16_DebugTimerCaptValPeriod = CCU40_CC40->CV[1];
u16_DebugTimerCaptValDutyCycle = CCU40_CC40->CV[3];


Make sure the variables are at least 16-bit wide. Also, you see the example assumes that CCU40_CC40 is used to capture. If you don''t specify which slice to use (can be done by right clicking on the CCU4_SLICE_CONFIG-App and pressing "Manual Ressource Assignment), DAVE will choose a slice. The slice Dave chose can be seen by pressing the "Report" button.
Replace "CCU40_CC40" in the code above with the CCU4 Unit and Slice that you specified or Dave chose for you.

Regards,
Niclas
0 Likes
User12056
Level 1
Level 1
Welcome! First reply posted
Niclas, That was a great help! I implemented it today and it worked for my application. I have two questions that perhaps you know off the top of your head.

1) I noticed when I disconnected the external PWM generator, the CCU40_CC40->CV[1] register did not go to zero. It held the last value even after I read the register. I need it to go to zero so I can detect that as a system fault condition. I tried writing a zero to the register but the compiler disallowed as the register is Read-Only. Any way to set the CCU4_SLICE_CONFIG to make CCU40_CC40->CV[1] clear on read?
2) How did you know that CCU40_CC40->CV[1] was the name of the CC40 CC40C0V register. I did not find that nomenclature in the User's Manual. I assume there is a list or a decoder ring on how to translate the register names in the user manual into usable variables in the code.
Thanks,
Garret
0 Likes
User10215
Level 4
Level 4
First like received
Hi Garret,
glad it worked for you. To answer your questions:
1) good question. The solution I presented above actually also doesn't account for 0% duty cycle and 100% duty cycle of the input signal, as the capturing only happens when edges occur.
A solution could be the following: our configuration assumes that the timer will be cleared when the edge for the period value occurs (since we selected "Cleared on capture into reg 0 and 1" for the "Timer clear control"). We can utilize this behaviour because when there is no edge on the input signal the timer will happily run until it hits the value given in the "Timer Period Value"-field and then the timer resets automatically.
So when we acitvate the period-match-interrupt we get an interrupt everytime there was no edge in the signal for a given period of time (dependent on the "Timer Period Value"-field and the frequency your timer runs with). Now by looking at the input status of your input pin (you can use the normal GPIO-functions given by DAVE for this) when you are in this interrupt-function you can determine if it was due to a 0% or 100% duty cycle. There is no way to detect a disconnected signal.
Be sure to have a pull-down or pull-up resistor activated on your input pin (!) as this prevents having an undefined signal (with possible edges that could be interpreted as valid PWM-signal!) on the pin when the PWM is disconnected.
Be aware that this solution doesn't give you a direct feedback as it is determined by the value you put into the "Timer Period Value"-field. Choose this value according to your Parameters. If you have a fixed frequency of the input PWM you can choose a Timer-Period-Value slightly above the expected captured value of the period edge. This will give you a fast response.
If you have a varying frequency you should know what the lowest possible frequency is and set the value accordingly. But if it's just for testing set the value to 0xFFFF.

There is no way to clear the capture registers. But there is another way to see if the capture-register holds a valid value: each capture-register has a full flag that is set when a "fresh" value is present in that register. If you read out the register this flag will automatically be cleared. This means that if you have a look at this flag you can see if there was a new capture since the last time you read the register!


2) If a chip manufacurer of Cortex-M processors wants to be CMSIS-compliant he has to give you a possibility to access the registers of the controller with this syntax: "peripheral->register". So they provide you with a header file that has the same name as the microcontroller-family you are working with. In this case it would be "XMC4500.h".
You can find this header in your Dave-project by following the path "Libraries->CMSIS->Infineon->XMC4500_series->include" in the project-explorer. Other IDEs will also have this file present somewhere in the project.
If you scroll all the way down in this header file you will find a very useful list.
In this list you will find our "CCU40_CC40" which is defined as a pointer of the structure-type "CCU4_CC4_TypeDef" that points to the address "CCU40_CC40_BASE". You can find the address by searching for "CCU40_CC40_BASE" in that header file and you will see that it is the address of the first register of that CCU4-slice. Also you can search for "CCU4_CC4_TypeDef" in that header file and you will see that it's a structure type whose members are the registers of that CCU4-Slice. There you see that the capture registers are given as an array of four uint32_t with each capture register being an element of that array.
This is how you can find out how to access the registers of the microcontroller. This header-file also gives you masks and a positions of every bit in all of the registers as a define!

Regards,
Niclas
0 Likes
Not applicable
Thank you, the solution also works for me. The timer value can be read out but unfortunately the timer reaches the max period timer value of 65535 while t_on of the PWM. Then the timer is reset.

Is there an oppurtinity to circumvent the reaching of the max timer value except of changing the CPU clock frequency?

If someone can help me I would be very grateful 🙂
0 Likes
User12056
Level 1
Level 1
Welcome! First reply posted
Hey Fesinator,

Mine originally overflowed as well. I changed the "Prescaler initial value" under the General Settings of CCU_Slice_Config so that my CCU4 clock was slower without affecting the CPU clock frequency. Is that an option for your application?
0 Likes
Not applicable
Hey Garret,

thank you for your hint. Today I thought about it and lighted on the same solution 🙂
And yes, it is an acceptable option for my project.
0 Likes
User8487
Level 2
Level 2
First like received
Hi,
i like to measure the duty and frequency of an PWM-signal,but it doesn't worked for me. Something seems to be wrong configured in the
- CCU4_SLICE_CONFIG - "Function Settings" - and - "Event Settings"
or
- HW Signal Connections.

Would you please post screenshots of these two register-cards and from the "HW Signal Connections"-overview? Or an Example Project?

thx & br, matthias
0 Likes