Skip to content

sys/xtimer: allow frequencies multiple of 921600Hz#6507

Closed
kYc0o wants to merge 4 commits intoRIOT-OS:masterfrom
kYc0o:xtimer_diff_freq
Closed

sys/xtimer: allow frequencies multiple of 921600Hz#6507
kYc0o wants to merge 4 commits intoRIOT-OS:masterfrom
kYc0o:xtimer_diff_freq

Conversation

@kYc0o
Copy link
Contributor

@kYc0o kYc0o commented Jan 27, 2017

This PR will add xtimer compatibility for boards running at frequencies multiple of 576 (e.g. waspmote-pro running at 14.7456 MHz with timers prescaled to this frequency).

Partially (re) fixes #5597. An upcoming PR will fix the xtimer configuration on the waspmote.

@kYc0o kYc0o added the Area: timers Area: timer subsystems label Jan 27, 2017
@kYc0o kYc0o added this to the Release 2017.01 milestone Jan 27, 2017
/**
* @brief Operand for 576/625
*/
#define MUL_576 576ul
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls drop these defines, they don't make sense.

/**
* @brief Operand for 625/576
*/
#define MUL_625 625ul
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to avoid the "ul" everywhere (8 and 16 bit requirement), but I can remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for 625 you don't need UL. That only matters on the left-hand side of an expression (left-hand side defines type being used for calculation), or if the value is >16bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed. Thanks for the explanation.

*/
static inline uint64_t div_u64_by_625div576(uint64_t val)
{
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you measure this? or C&P?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, copy-paste, I'll check if it does but I think it makes exactly the same as before. Moreover, it makes sense to take care of the overflow, I can just remove the comment but the code seems ok for me.

*/
static inline uint32_t div_u64_by_576div625(uint64_t val)
{
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

@kYc0o kYc0o added the Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) label Jan 30, 2017
@kYc0o
Copy link
Contributor Author

kYc0o commented Jan 30, 2017

Ready?

Copy link
Member

@lebrush lebrush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the #ifs and #else are not matching and there is some dead code. Besides it would be great if you add some empty lines to improve readability.

*/
#if (XTIMER_HZ % 576 == 0)
#if (XTIMER_SHIFT != 0)
#if (XTIMER_HZ % 576 != 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will never run into this, since you first checked for the opposite, right?

#if (XTIMER_HZ % 576 == 0)
#if (XTIMER_HZ % 576 != 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can remove it but I need a way to throw the error if shifting is enabled.

inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) {
return div_u64_by_576div625(ticks) >> XTIMER_SHIFT;
}
#else /* (XTIMER_HZ < 921600ul) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/* (XTIMER_HZ <= 921600ul) */

inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) {
return div_u64_by_576div625(ticks) << XTIMER_SHIFT;
}
#endif /* defined(XTIMER_SHIFT) && (XTIMER_SHIFT != 0) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually /* (XTIMER_HZ > 921600ul) */ or /* (XTIMER_HZ <= 921600ul) */ (depends on the notation you are using)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather the first, and also XTIMER_SHIFT. Will fix.

return div_u64_by_576div625(ticks) << XTIMER_SHIFT;
}
#endif /* defined(XTIMER_SHIFT) && (XTIMER_SHIFT != 0) */
#elif (XTIMER_HZ == 921600ul)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is here expected to be: (XTIMER_SHIFT == 0) && (XTIMER_HZ == 921600ul)? If that's the case then is correct

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what is expected. I tried to reproduce a similar behaviour than for the 1MHz case.

return div_u64_by_576div625(ticks);
}
#endif /* (XTIMER_HZ == 921600ul) */
#elif (XTIMER_SHIFT != 0) /* (XTIMER_HZ % 576 == 0) */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this branch belongs to the #if (XTIMER_HZ % 576 == 0)... then the code will enter the first time you test for #if (XTIMER_SHIFT != 0) and not here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I was trying to solve the issue. Actually I need a way on which we can detect, first, if we're using either 1MHz or 921600Hz clock based timer, then we need to know if the shifting is used, to finally choose the right functions.

The current code will check first if there's shifting activated, then if it's a 1MHz or 921600Hz based clock. The process is repeated to ensure that we can choose 1MHz clocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code will enter here if the clock is not a multiple of 576, for which I need to check again if shifting is used.

@kYc0o
Copy link
Contributor Author

kYc0o commented Jan 31, 2017

@lebrush I added more comments to clarify all those definitions. I still have no idea on how I can simplify them, so if you have suggestions they're welcomed (maybe I'm doing redundant things and I cannot see them by myself).

@kYc0o
Copy link
Contributor Author

kYc0o commented Jan 31, 2017

Some thoughts @kaspar030 ?

@PeterKietzmann PeterKietzmann modified the milestones: Release 2017.01, Release 2017.04 Feb 1, 2017
@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 3, 2017

ping @kaspar030 !

* If it uses shifting, just check if it's not multiple of 576, if so,
* throw an error
*/
#if (XTIMER_HZ % 576 != 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will never be true, as you check above the opposite, or do I miss something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I know, but then how to check this? I need to know if XTIMER_HZ is valid when using shifting, but I'll just remove this line...

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 7, 2017

@lebrush comments addressed.

Copy link
Member

@lebrush lebrush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kYc0o thanks for the heads up! I have some quick comments regarding the comments :-)

I've thought how to factorize the code and it's hard if we want to keep it readable. One possibility is to use some macro magic, despite of readability:

Example:

...
#define PASTER(len,low,high) div_u ## len ## _by ## low ## div ## high
#define EVALUATOR(len,low,high)  PASTER(len,low,high)
...

#if (XTIMER_HZ % 576 == 0)
    #if (XTIMER_SHIFT != 0)
        #define LOW 625
        #define HIGH 576

        #if (XTIMER_HZ > 921600ul)
            #if (XTIMER_HZ != (921600ul << XTIMER_SHIFT))
            #error XTIMER_HZ != (921600ul << XTIMER_SHIFT)
            #endif

            #define USEC_SHIFT(len) DIVIDER(len) << XTIMER_SHIFT
            #define TICKS_SHIFT(len) DIVIDER(len) >> XTIMER_SHIFT
        #else
            #if ((XTIMER_HZ << XTIMER_SHIFT) != 921600ul)
            #error (XTIMER_HZ << XTIMER_SHIFT) != 921600ul
            #endif

            #define USEC_SHIFT(len) DIVIDER(len) >> XTIMER_SHIFT
            #define TICKS_SHIFT(len) DIVIDER(len) << XTIMER_SHIFT
        #endif
...
#define DIVIDER(len) EVALUATOR(len, LOW, HIGH)
...
inline static uint32_t _xtimer_ticks_from_usec(uint32_t usec) {
    return USEC_SHIFT(32); /* i.e. div_u32_by_625div576(usec) << XTIMER_SHIFT; */
}

inline static uint64_t _xtimer_ticks_from_usec64(uint64_t usec) {
    return USEC_SHIFT(64);
}

inline static uint32_t _xtimer_usec_from_ticks(uint32_t ticks) {
    return TICKS_SHIFT(32);
}

inline static uint64_t _xtimer_usec_from_ticks64(uint64_t ticks) {
    return TICKS_SHIFT(64);
}

/*
* If it's not greater, check if it's lower (XTIMER_HZ < 921600ul).
*/
#else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess here /* (XTIMER_HZ <= 921600ul) */ should be enough. Mind the equality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll fix.

* No more shifted multiple of 921600Hz frequencies to check
* (XTIMER_SHIFT != 0)
*/
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: /* (XTIMER_SHIFT != 0) */. I like documentation but I think it's clear enough with a one-liner. In my previous review I didn't mean that you include more comments regarding the code flow, simply that sometimes the one-liner where in the wrong place... :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok no problem, I just wanted to be as clear as possible, even for me. I find this code a bit complicated to understand in itself, so a bit more of documentation won't hurt IMHO.

* Check for the actual frequency without any shifting (921600Hz)
* (XTIMER_SHIFT == 0)
*/
#elif (XTIMER_HZ == 921600ul)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need a special case for that, shifting to any side by 0 (XTIMER_SHIFT should be 0 here). Would give the same result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you're right, I think I can do the same for the 1MHz frequency.

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 10, 2017

I somehow like your suggestion with the macros magic. However, we have an "unofficial" preference to keep macro usage as low as possible, thus very often we use static inline functions instead of macros.

I can try to adapt your proposition with static inline functions to make it "standard", but I'd like to have @gebart opinion on this, since he was the contributor of this code.

@kaspar030
Copy link
Contributor

One possibility is to use some macro magic

I'd strongly oppose this. Please rather try to find a solution without any macros. Most of the checks could be done in C-Code, being syntax checked, and optimized out by the compiler.

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 10, 2017

One possibility is to use some macro magic
I'd strongly oppose this. Please rather try to find a solution without any macros. Most of the checks could be done in C-Code, being syntax checked, and optimized out by the compiler.

That's what I meant when I said I could try to adapt those macros to static in line functions.

@jnohlgard
Copy link
Member

@kYc0o feel free to go ahead with the macro magic -> static inline conversion.

@lebrush
Copy link
Member

lebrush commented Feb 13, 2017

I agree that macro magic makes sometimes code difficult to follow :-)
Another possibility is to create a separate tick_conversion.h for each frequency block (i.e. tick_conversion_921600.h) and include them in the corresponding #if #else blocks.

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 13, 2017

I was trying to convert the ifdefs to inline functions but at the end I was adding more complexity, when why that code is there is to optimise the conversions.

I removed some unnecessary checks, I find now it's a bit more readable and works correctly.

I tested with samr21-xpro and arduino-mega2560 with success. What is missing is a test for cc2538 but xtimer is broken for that platform due to different reasons.

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 14, 2017

For the separate file, IMHO, maybe it would be required if the cases of different frequencies increase. For now I think it's manageable, even if it was hard to get it in a less confusing way.

@kYc0o
Copy link
Contributor Author

kYc0o commented Feb 28, 2017

Ping! Can we maybe get this in for the Hack'n'ACK?

@kYc0o
Copy link
Contributor Author

kYc0o commented Mar 1, 2017

Can I squash to get the CI working?

@kYc0o
Copy link
Contributor Author

kYc0o commented Mar 6, 2017

ping @lebrush @kaspar030

Copy link
Member

@lebrush lebrush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codewise looks good.

@kYc0o kYc0o added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Mar 17, 2017
@kYc0o
Copy link
Contributor Author

kYc0o commented Mar 17, 2017

Well, everything seems good here, just a review from @kaspar030 is missing...

@kYc0o
Copy link
Contributor Author

kYc0o commented Mar 21, 2017

ping @kaspar030

@kYc0o
Copy link
Contributor Author

kYc0o commented Apr 3, 2017

re-ping @kaspar030

@kYc0o
Copy link
Contributor Author

kYc0o commented Apr 18, 2017

@kaspar030 any objections to get this into the release? I have 2 more PRs which are based on this one, so I think they won't make it for the release if we don't merge this first soon.

@smlng
Copy link
Member

smlng commented May 12, 2017

@kaspar030 could you please spare some time to ACK (or/and comment on) this and approve changes done?! I'd rather not dismiss your review, but have your trusted ACK here 😉

@kYc0o
Copy link
Contributor Author

kYc0o commented May 22, 2017

@kaspar030 will you leave this PR open until the xtimer rework is done? in such case we can close it since it won't certainly be compatible with the new xtimer code.

@kaspar030
Copy link
Contributor

kaspar030 commented May 22, 2017

@kaspar030 will you leave this PR open until the xtimer rework is done? in such case we can close it since it won't certainly be compatible with the new xtimer code.

Hm, good question. ;)

By using a 32khz as backend for xtimer (not new in this PR), all code throughout the codebase would need to be checked if it's still working. E.g., are usec values <1/2**15 rounded down to 0?

We need multiple timers edit in the API edit...

@kYc0o
Copy link
Contributor Author

kYc0o commented May 22, 2017

E.g., are usec values <1/2**15 rounded down to 0?

Well, it will depend how much usec you need, since here we're certainly losing accuracy by shifting.

@kYc0o
Copy link
Contributor Author

kYc0o commented Jun 30, 2017

What do we do with this one? It's needed to support xtimer on waspmote-pro...

Copy link
Member

@jnohlgard jnohlgard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind adding more specializations for the xtimer frequencies, but some changes are necessary:

  • Needs rebase
  • Minor comments above
  • Add test cases to unittests/tests-div for the new div.h functions, along with smart choices for the test vector (try to catch rounding errors, errors with large numbers close to the overflow limit, test for numbers near the magic number 10485759996).
  • It may be possible to reduce the very long preprocessor if block in xtimer.h for all different kinds of XTIMER_SHIFT. The special case of XTIMER_SHIFT == 0 is not necessary, a shift of constant literal 0 will be optimized away by the compiler, and worst case it would be a no-op machine instruction by shifting with 0.

* @brief Approximation of (2**l)/d for d=15625, l=12, 32 bits
*/
#define DIV_H_INV_15625_32 0x431bde83ul
#define DIV_H_INV_15625_32 0x431bde83ul
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't matter if you have parentheses or not here, these are just magic numbers and never any complex expressions. As for the letter case, I don't care either way, I tend to prefer lowercase for the suffixes, but I don't see any point in forcing it.

*/
#endif
/*
* Now, check if XTIMER_HZ is a frequency multiple of 1MHz (or 15675, which is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: 15675 -> 15625

#error Unknown hardware timer frequency (XTIMER_HZ), check board.h and/or add an implementation in sys/include/xtimer/tick_conversion.h
#endif
/*
* End of optimisations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to have this comment on the line with the #endif on L275, and related to the if condition. Suggestion:

#endif /* XTIMER_HZ == xxx */

@kYc0o kYc0o removed this from the Release 2017.10 milestone Oct 16, 2017
@kYc0o kYc0o force-pushed the xtimer_diff_freq branch from da37a2f to bf63a79 Compare May 22, 2018 15:53
@kYc0o
Copy link
Contributor Author

kYc0o commented May 22, 2018

Sorry for forgetting this PR since looong time, I was kind of waiting for big changes on xtimer but apparently that won't come soon.

I want to update and if possible merge this PR to support another frequency for the mega-xplained board.

@ZetaR60
Copy link
Contributor

ZetaR60 commented Jun 6, 2018

Some new relevant PRs: #9280, #9283

@kYc0o
Copy link
Contributor Author

kYc0o commented Jun 6, 2018

Yes! I think that will be the way to go for supporting other clock sources in xtimer.

@stale
Copy link

stale bot commented Aug 10, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions.

@stale stale bot added the State: stale State: The issue / PR has no activity for >185 days label Aug 10, 2019
@stale stale bot closed this Sep 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: timers Area: timer subsystems CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR State: stale State: The issue / PR has no activity for >185 days Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XTIMER initialisation for non multiples of 15625Hz

8 participants