-
Notifications
You must be signed in to change notification settings - Fork 28
ESWIN timer driver, ethernet/echo server support for P550 #499
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?
Conversation
f46d2c7 to
8c06db1
Compare
0c2c39c to
87e58a7
Compare
Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au> Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
Signed-off-by: Ivan Velickovic <i.velickovic@unsw.edu.au>
a78814d to
c8fb05a
Compare
| uint64_t value_whole_seconds = value_ticks / TIMER_TICKS_PER_SECOND; | ||
| uint64_t value_subsecond_ticks = value_ticks % TIMER_TICKS_PER_SECOND; | ||
| uint64_t value_subsecond_ns = (value_subsecond_ticks * NS_IN_S) / TIMER_TICKS_PER_SECOND; | ||
| uint64_t value_ns = value_whole_seconds * NS_IN_S + value_subsecond_ns; |
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 method of converting is wonky and you should instead calculate this using clock periods.
The conventional way is to use 1/f = T (period), but since we use integer arithmetic we want to convert it to nanos at the same time, so 1/f/1e-9 = 1e9/f = T_nanos. To avoid integer division we want the largest possible numerator and divisor as this avoids integer error and gives a more acccurate calculation. You can then multiple T_nanos by the number of ticks to get a result.
For example: if the current value_ticks = 8440832771 (5 minutes 51.7014 seconds or 351701365458)
Your method:
- value_whole_seconds = floor(8440832771/ 24000000) = floor(351.7) = 351
- value_subsecond_ticks = 8440832771 % 24000000) = 16832771
- value_subsecond_ns = floor((16832771*1e9) / 24000000) = floor(701365458.3) = 701365458
- value_ns = 351 * 1e9 + 16832771 = 351001682771ns -> error of 699682687ns (700ms)!
Standard method (combine multiplying ticks with NANOS_IN_S and divide):
ns = (ticks * 1e9)/f_clk;
so, substituting this for the p550:
- tick_nano_inv = (8440832771 * 1e9) = 8440832771000000000
- ns = tick_nano_inv / f_clk = 8440832771000000000 / 24000000 = 351701365458ns
-> error of 0ns!
note that C always rounds towards zero, hence all these positive valued divisions are floored. I know this method is in a bunch of our timer drivers but we should get rid of it everywhere as the standard method is more compact, more efficient and more accurate.
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.
It may be advantageous to perform manual arithmetic simplification here, from ns = (ticks * 1e9) / f_clk to ns = ticks * 125 / 3 (based on
The compiler is not able to perform such simplification due to modular arithmetic (godbolt), and doing so results in both a smaller application binary and faster execution.
An even better sequence might be ns = ticks * 41 + ticks * 2 / 3.
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.
When implemented in the rk3568 timer it overflows after 758 seconds and we get bogus timeout data later.
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.
A simpler and more explicit alternative is ns = ticks * (1e9 / 24000000) + ticks * (1e9 % 24000000) / 2400000.
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.
@JDuchniewicz you should explicitly split the constant part where you divide nano_inv / f_clk and the multiply after. I've messed around with this a bit and it seems that the compiler indeed can do weird things with this. We should write a single implementation of these tick and timer handling functions to share probably... Doesn't make sense to have a separate one for every device! I'm busy writing something up now.
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.
Yeah already fixed that and now the timer works fine with the sddf example.
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.
It may be advantageous to perform manual arithmetic simplification here, from
ns = (ticks * 1e9) / f_clktons = ticks * 125 / 3(based on 1 e 9 / f clk = 125 / 3 ).The compiler is not able to perform such simplification due to modular arithmetic (godbolt), and doing so results in both a smaller application binary and faster execution.
An even better sequence might be
ns = ticks * 41 + ticks * 2 / 3.
Thinking about this more, we probably need to descend to picosecond resolution if we are representing periods with integers. 1GHz^-1 = 1ns, so we are guaranteed to lose all distinctions above that (very common and relatively low) clock frequency.
|
|
||
| timeout_timer_elapses = 0; | ||
|
|
||
| uint64_t ticks_whole_seconds = (ns / NS_IN_S) * TIMER_TICKS_PER_SECOND; |
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.
Same issue as previous note. You can just flip the math upside down.
| assert(device_resources.num_regions == 1); | ||
|
|
||
| counter_timer_regs = device_resources.regions[0].region.vaddr; | ||
| timeout_timer_regs = device_resources.regions[0].region.vaddr + 0x14; |
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.
Magic number (0x14)
| counter_timer_regs->ctrl &= 0xfffffffd; | ||
| counter_timer_regs->load_count = TIMER_MAX_TICKS; | ||
| // 3. Enable timer | ||
| counter_timer_regs->ctrl |= (1 << 0); |
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.
May be a good idea to #define some of these
Draft because I need to cleanup and double check the code for the timer driver, please do not comment until I have marked ready for review.