-
Notifications
You must be signed in to change notification settings - Fork 8.4k
drivers: timer: infineon pdl lp_timer #97831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
drivers: timer: infineon pdl lp_timer #97831
Conversation
90e628b to
fcc5925
Compare
fcc5925 to
c5d6069
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there was some fundamental misunderstanding of how timers work in Zephyr when this was written, and I see it was mostly copied from the existing cat1-lp-timer driver and updated to the new HAL API if I understand this right. So likely both need fixing to correctly work.
This is maybe one of those few occasions where only the base address of the register block for the IP is needed and the few registers (typically 2-3..) are kept in C and Zephyr #define's rather than using the HAL.
| .clock_frequency = DT_INST_PROP(n, clock_frequency), \ | ||
| }; \ | ||
| \ | ||
| DEVICE_DT_INST_DEFINE(n, lptimer_init, NULL, &ifx_cat1_lptimer_data##n, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to make the timer a device, its a singleton in Zephyr's view. Just a couple of static variables tied to the compilation unit for the hardware timer being used as the kernel timer.
Take a look at how cortex_m_systick.c is written for example. It sets up an initialization function with SYS_INIT and a few static variables tied to the compilation unit to stash some state (mostly the last announced tick or cycle count), along with the appropriate sys_clock functions implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teburd , Don't I need this for a multi-core device? Where each core has its own lptimer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can still use DT nodes and attributes, but you don't need to deal with struct device.
There's other multicore devices in the tree to peruse on how they might go about this. See NXP's RT1170 for example of an AMP design. But yes, each AMP core running an instance of Zephyr needs its own timer. In SMP this isn't the case, a single timer is expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teburd , I am not finding "NXP's RT1170". Can you point me to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teburd ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See for example mcux lptmr https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/timer/mcux_lptmr_timer.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teburd, the driver should now be updated to this flow.
|
|
||
| lptimer_value = Cy_MCWDT_GetCount(config->reg_addr, CY_MCWDT_COUNTER2); | ||
|
|
||
| /* Gives the value of LPTIM counter (ms) since the previous 'announce' */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the number of elapsed kernel ticks (kernel ticks are a synthesized clock running at SYS_CLOCK_TICKS_PER_SEC) since the last announce call was made. So I think there's a misunderstanding below in the math.
What you want is something that converts delta_cycles to delta_ticks where each tick is equal to some number of cycles.
E.g.
uint32_t delta_cycles = current_cycle_count - announced_cycle_count;
uint32_t delta_ticks = delta_cycles/cycles_per_tick;
return delta_ticks;However, some special care typically needs to happen for rollovers and things like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
| } | ||
|
|
||
| /* Set the delay value for the next wakeup interrupt */ | ||
| lptimer_set_delay(lptimer_dev, ((uint32_t)(ticks)*config->clock_frequency) / |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be setting the counter compare register to some cycle count into the future based on ticks*cycles_per_tick, like...
uint32_t timer_compare = current_cycle_count + ticks*cycles_per_tick;
sys_write32(SOME_TIMER_REG, timer_compare);With some protection around short timeouts (usually some minimum cycle delay), and error checking for rollovers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to mention that the timer compare should also be tick aligned or the timer may trigger early which is an error. Meaning timer_compare % cycles_per_tick == 0 && timer_compare >= (cycle_count + ticks*cycles_per_tick) should be true or a programming error has occurred. The assertion above assumes no rollover which is possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
| if ((data->isr_instruction & LPTIMER_ISR_CALL_USER_CB_MASK) != 0) { | ||
| /* announce the elapsed time in ms */ | ||
| uint32_t lptimer_value = Cy_MCWDT_GetCount(config->reg_addr, CY_MCWDT_COUNTER2); | ||
| int32_t delta_ticks = ((uint64_t)(lptimer_value - last_lptimer_value) * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This math is also not quite right. It should be something like...
uint32_t current_cycle_count = sys_read32(SOME_TIMER_COUNT_REG);
uint32_t delta_ticks = (current_cycle_count - announced_cycle_count)/cycles_per_tick;
announced_cycle_count = delta_ticks*cycles_per_tick;
sys_clock_announce(....);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
@teburd , you are correct, this is just a port of the existing driver from using the HAL to the PDL. Thanks for your feedback. I will work on that now. |
c5d6069 to
4973287
Compare
4973287 to
654c554
Compare
25be703 to
b938b87
Compare
|
Rebasing PR onto main |
b938b87 to
98fd223
Compare
98fd223 to
927df19
Compare
Add PDL-based low-power timer for the E84 board Signed-off-by: Bill Waters <bill.waters@infineon.com>
927df19 to
2ff73a7
Compare
|



Add PDL-based low-power timer for the E84 board