Skip to content

Enable new HAL us_ticker API on fast model MPS2 platform #7175

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

Merged
merged 5 commits into from
Jun 20, 2018

Conversation

jamesbeyond
Copy link
Contributor

Description

Fast Model targets didn't implement the new HAL us_ticker API.

This PR is about modify fast models ticker implementation to match with recently merged HAL ticker branch #7009

Pull request type

[x] Fix
[ ] Refactor
[ ] New target
[ ] Feature
[ ] Breaking change

CC @mprse @c1728p9 @bulislaw

@0xc0170 0xc0170 requested a review from a team June 8, 2018 11:02
0xc0170
0xc0170 previously approved these changes Jun 8, 2018
Copy link
Contributor

@0xc0170 0xc0170 left a comment

Choose a reason for hiding this comment

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

LGTM but from the code changes, us ticker and drivers changes do not seem to be related , or are they?

How the PRESCALE Msk is related to enablement? I would do two commits, one in the driver and then in HAL implementation

@@ -270,7 +270,7 @@ typedef struct {
#define CMSDK_DUALTIMER1_CTRL_INTEN_Msk (0x1ul << CMSDK_DUALTIMER1_CTRL_INTEN_Pos) /* CMSDK_DUALTIMER1 CTRL_INTEN: CTRL Int Enable Mask */

#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos 2 /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Position */
#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Msk (0x3ul << CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos) /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Mask */
#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Msk (0x1ul << CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos) /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Mask */
Copy link
Contributor

Choose a reason for hiding this comment

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

In the review comment , I was referring to this line. I can see it is needed for us ticker but still looks like 2 step action . Editing sdk (for whatever reason - wrong definitions, updating to the latest or something that is not clear from this commit) and second updating us ticker implementation based on the SDK update (header files 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.

OK, I kind of agree it is may treat as 2 step action.
I would revert the changes about SDK, which mostly about comments not accurate.
I'll raise a separate PR if required.

Copy link
Member

@ithinuel ithinuel left a comment

Choose a reason for hiding this comment

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

Can you provide some clarification on these points please ?

@@ -270,7 +270,7 @@ typedef struct {
#define CMSDK_DUALTIMER1_CTRL_INTEN_Msk (0x1ul << CMSDK_DUALTIMER1_CTRL_INTEN_Pos) /* CMSDK_DUALTIMER1 CTRL_INTEN: CTRL Int Enable Mask */

#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos 2 /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Position */
#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Msk (0x3ul << CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos) /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Mask */
#define CMSDK_DUALTIMER1_CTRL_PRESCALE_Msk (0x1ul << CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos) /* CMSDK_DUALTIMER1 CTRL_PRESCALE: CTRL PRESCALE Mask */
Copy link
Member

Choose a reason for hiding this comment

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

This reduces the field size from 2 bits to 1.
What are doing the bits in position 3 and 4 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

bit 4 is an undefined bit, bit 3 is another prescale bit, maybe I should keep the SDK definition as it was. Anyway, I will revert it based on Martin's comments. I will raise another PR to change SDK.

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, if the field is 2 bits wide this mask should stay at 0x3ul.
To set the value in the register you should write

US_TICKER_TIMER1->TimerControl &= ~CMSDK_DUALTIMER1_CTRL_PRESCALE_Msk;
US_TICKER_TIMER1->TimerControl |= 0x1 << CMSDK_DUALTIMER1_CTRL_PRESCALE_Pos; // you can replace 0x1 by any value in [0..3]

US_TICKER_TIMER2->TimerControl |= 0x80; // enable counter
US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_MODE_Msk; // set TIMER2 periodic mode

US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_ONESHOOT_Msk; // set TIMER2 one-shot mode
Copy link
Member

Choose a reason for hiding this comment

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

CMSDK_DUALTIMER2_CTRL_ONESHOOT_Msk should probably be CMSDK_DUALTIMER2_CTRL_ONESHOT_Msk

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 a typo in SDK, will change that


US_TICKER_TIMER1->TimerControl |= 0x80; // enable counter
US_TICKER_TIMER2->TimerControl |= 0x80; // enable counter
US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_MODE_Msk; // set TIMER2 periodic mode
Copy link
Member

Choose a reason for hiding this comment

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

Is configuring the US_TICKER_TIMER2 as periodic & one-shot intended ? It sound a bit opposite.

Copy link
Member

Choose a reason for hiding this comment

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

@jamesbeyond explained that periodic actually means that the timer will come back to the TimerLoad value when it reaches 0 after triggering an interrupt else the mode is said free running.
One-shot means that the timer will get disabled after reaching 0 and/or triggering the interrupt.

US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_ONESHOOT_Msk; // set TIMER2 one-shot mode

US_TICKER_TIMER1->TimerControl |= CMSDK_DUALTIMER1_CTRL_EN_Msk; // enable TIMER1 counter
US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_EN_Msk; // enable TIMER2 counter
Copy link
Contributor

@mprse mprse Jun 8, 2018

Choose a reason for hiding this comment

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

According to the ticker requirements interrupts should be disabled after init, so I suggest to disable US_TICKER_TIMER2 (I assume that it is used to generating interrupts) and disable interrupts instead of enabling them:
NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);

Copy link
Contributor

Choose a reason for hiding this comment

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

Ticker interrupts are now disabled, but I think there is no need to enable TIMER2 here. It should be enabled while setting the interrupt.

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 interrupts and counters ticking controlled by different bits.
Since the interrupts control bit is off. and let the TIMER2 ticking going not having any bad impacts to the HAL ticker behavior in the current implementation.
I can set TIMER2 to NOT ticking by default, reduce the ambiguity.

us_ticker_inited = 1;
}

void us_ticker_free(void)
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't have requirements for us_ticker_free but I think it should also disable ticker interrupt.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}

uint32_t us_ticker_read()
{
uint32_t return_value = 0;
if (!us_ticker_inited) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This code is redundant and should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -61,12 +87,10 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
us_ticker_init();
Copy link
Contributor

Choose a reason for hiding this comment

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

This code is redundant and should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So you mean it is not necessary to check the flag, we just need to call us_ticker_init() directly?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I was thinking about entire block. Upper layer handles initialization, so it will call init only once on first ticker usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can see HAL API claimed that as undefined behavior, I will remove the function of checking flags

US_TICKER_TIMER1->TimerLoad = (delta) * 25; //initialise the timer value
US_TICKER_TIMER1->TimerControl |= 0x80; //enable timer
uint32_t delta = timestamp - us_ticker_read();
US_TICKER_TIMER2->TimerLoad = delta; // Set TIMER2 load value
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we safety change timer value while timer is running?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also consider case when delta is equal to 0. Will interrupt be fired?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the current implementation, if 0 is set, interrupt will be fired.
I didn't find clear definition HAL API what happen if current_time is set to interrupt. but seems This line indicates a interrupt will need to be fired

US_TICKER_TIMER1->TimerControl &= 0xDF;
US_TICKER_TIMER2->TimerControl &= 0xDF;

US_TICKER_TIMER2->TimerControl &= ~CMSDK_DUALTIMER2_CTRL_INTEN_Msk;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also disable ticker interrupt, not only TIMER2:
NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

NVIC_DisableIRQ() added

@jamesbeyond
Copy link
Contributor Author

Hi all, the code had been changed based on your comments, please review again @0xc0170 @ithinuel @mprse

int us_ticker_inited = 0;

void us_ticker_init(void)
{
if (us_ticker_inited) {
us_ticker_disable_interrupt();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this what targets do? I dont recall seeing it before. init should disable interrupt , but in this case, why only if it was already initialized?

why us_ticker_inited variable is not static?

Copy link
Contributor

Choose a reason for hiding this comment

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

Code implements the following ticker requirement:

* * The function ticker_init allows the ticker to keep counting and disables the ticker interrupt - Verified by test ::ticker_init_test

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, calling us_ticker_disable_interrupt() on an uninitialized ticker is an undefined behavior in HAL
I re-checked, upper level dirvers are not use this variable, it can be staticed, good catch.


US_TICKER_TIMER1->TimerControl |= 0x80; // enable counter
US_TICKER_TIMER2->TimerControl |= 0x80; // enable counter
US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_MODE_Msk; // set TIMER2 periodic mode
Copy link
Contributor

Choose a reason for hiding this comment

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

If periodic mode means that counter after reaching 0 is reloaded and continue counting, then it looks like this mode should be used for TIMER1 which is dedicated to count elapsed time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I previously mentioned in Wilfried's comment:
Based on SSE-200 TRM
the timer can be set in 2 main modes:
Free-running mode: which not triggers interrupts, and wraps counter form the MAX.
Periodic mode: generates interrupts when it reaches 0, and reload from TIMERLOAD value.

So this case, we use TIMER1 in the free-running mode for monitoring time eclipsing, and TIME2 in periodic mode, and reset TIMERLOAD when we set the interrupt.

maybe I should be put these as comments in the code, seem just reading from the mode name, it is a bit misleading.

Copy link
Contributor

@mprse mprse left a comment

Choose a reason for hiding this comment

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

Minor changes requested.

uint32_t delta = timestamp - us_ticker_read();
US_TICKER_TIMER2->TimerControl &= ~CMSDK_DUALTIMER2_CTRL_EN_Msk; // disable TIMER2
US_TICKER_TIMER2->TimerLoad = delta; // Set TIMER2 load value
US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_INTEN_Msk; // enable TIMER2 interrupt
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to enable timer interrupts only if they are disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So you mean calling NVIC_EnableIRQ() before Enable TIMER2 counter?

Copy link
Contributor

Choose a reason for hiding this comment

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

Something like:

if (US_TICKER_TIMER2->TimerControl & CMSDK_DUALTIMER2_CTRL_INTEN_Msk== 0) {
    US_TICKER_TIMER2->TimerControl |= CMSDK_DUALTIMER2_CTRL_INTEN_Msk;
    NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So is there any particular reasons for this?
what are the drawbacks for setting interrupt regardless of the current status?

I was thinking about the case where an interrupt been set, but not timeout yet, another interrupt got set again. Or where NVIC got enabled for the TIMER_IRQ, but TimerControl interrupts BIT was not set.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was just thinking about optimisation (increase performance). NVIC_EnableIRQ() doesn't need to be called every time the interrupt is set.

Copy link
Member

Choose a reason for hiding this comment

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

A write only operation would be probably faster than a "read/check" or "read/check/write".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think there is no guarantee that CMSDK_DUALTIMER2_CTRL_INTERUPT bit and NVIC_EnableIRQ() are in the same states (outside this driver code), so set NVIC_EnableIRQ() regardless CMSDK_DUALTIMER2_CTRL_INTERUPT would be "safer"?

Copy link
Contributor

@mprse mprse Jun 18, 2018

Choose a reason for hiding this comment

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

A write only operation would be probably faster than a "read/check" or "read/check/write".

This is only suggestion and I didn't checked that. Maybe you are right, but please note there is an extra call to NVIC_EnableIRQ() function. Additionally there is no point to do things which are already done. This function might be called very often when we have Ticker objects with small periods (us).

@jamesbeyond
Copy link
Contributor Author

Hi @mprse, your first two comments were addressed and waiting for your feedback on the third one.

Copy link
Contributor

@mprse mprse left a comment

Choose a reason for hiding this comment

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

Looks good!

@cmonr
Copy link
Contributor

cmonr commented Jun 19, 2018

@ithinuel @0xc0170 All good with the changes?

@0xc0170
Copy link
Contributor

0xc0170 commented Jun 20, 2018

/morph build

@mbed-ci
Copy link

mbed-ci commented Jun 20, 2018

Build : SUCCESS

Build number : 2400
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/7175/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented Jun 20, 2018

@mbed-ci
Copy link

mbed-ci commented Jun 20, 2018

@cmonr cmonr merged commit c4113ae into ARMmbed:master Jun 20, 2018
@0xc0170 0xc0170 removed the needs: CI label Jun 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants