Skip to content

drivers: add imx7d pwm driver #8794

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 6 commits into from
Jul 17, 2018

Conversation

diegosueiro
Copy link
Contributor

This pull request is to add PWM driver for mcimx7_m4 arch and colibri_imx7d_m4 board.

The implementation was tested on the colibri_imx7d_m4 board by compiling and running the samples/basic/blink_led and tests/drivers/pwm/pwm_api/ applications (PWM characteristics were verified using a Saleae Logic Analyzer) using the PWM_1 interface.

@codecov-io
Copy link

codecov-io commented Jul 7, 2018

Codecov Report

Merging #8794 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #8794   +/-   ##
=======================================
  Coverage   52.25%   52.25%           
=======================================
  Files         196      196           
  Lines       24802    24802           
  Branches     5155     5155           
=======================================
  Hits        12961    12961           
  Misses       9762     9762           
  Partials     2079     2079

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5b8e4ae...9896fbd. Read the comment docs.

Copy link
Contributor

@dbkinder dbkinder left a comment

Choose a reason for hiding this comment

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

+1 for doc changes

Copy link
Member

@MaureenHelm MaureenHelm left a comment

Choose a reason for hiding this comment

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

Please update samples/basic/blink_led/sample.yaml and tests/drivers/pwm/pwm_api/testcase.yaml to include the colibri board. This will ensure that we build the driver in CI

} else {
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1);
do {
k_busy_wait(500);
Copy link
Member

Choose a reason for hiding this comment

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

Do we have to busy-wait? Can we k_sleep instead?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would put 500 along with PWM_PWMSWR_LOOP define, so the values are written close together.

k_busy_wait(500);
cr = PWM_PWMCR_REG(base);
} while ((PWM_PWMCR_SWR(cr)) &&
(wait_count++ < PWM_PWMSWR_LOOP));
Copy link
Member

Choose a reason for hiding this comment

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

PWM_PWMSWR_LOOP should be a Kconfig option

* Description : Get clock frequency applys to the PWM module
*
*END**************************************************************************/
uint32_t get_pwm_clock_freq(PWM_Type *base)
Copy link
Member

Choose a reason for hiding this comment

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

I can see why you did this, but I still want to avoid modifying ext/ files. Can you implement in soc.c instead?

Copy link
Contributor Author

@diegosueiro diegosueiro Jul 16, 2018

Choose a reason for hiding this comment

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

@MaureenHelm,

The clock_freq.c came originally from "FreeRTOS_BSP_1.0.1_iMX7D/examples/imx7d_val_m4/clock_freq.c" and I put it inside "ext/hal/nxp/imx/devices/MCIMX7D/" path following yours and @stanislav-poboril suggestion.

What should I do in this case? Move all get_pwm_clock_freq related stuff to "arch/arm/soc/nxp_imx/mcimx7_m4/" folder?

Should I have to isolate the changes for "ext/hal/nxp/imx/drivers/ccm_imx7d.h" in another header with other enums inside the "arch/arm/soc/nxp_imx/mcimx7_m4/" folder as well?

Copy link
Collaborator

@stanislav-poboril stanislav-poboril Jul 16, 2018

Choose a reason for hiding this comment

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

The clock_freq.c should stay in the ext folder, unmodified. The get_pwm_clock_freq() function and related changes should be either moved to soc.c (or similar soc related location) or Zephyr has a mechanism for this which is probably preferred but would require a little more effort - see drivers/clock_control/ folder and the file clock_control_mcux_ccm.c.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MaureenHelm and @stanislav-poboril ,

This should be addressed now.

Copy link
Member

Choose a reason for hiding this comment

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

Just to be clear, did you write get_pwm_clock_freq() yourself following the pattern from clock_freq.c, or did you copy the function from somewhere? I assumed the former in my previous comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MaureenHelm,

Yes, I wrote the function by myself following the same pattern from the other functions.

@MaureenHelm MaureenHelm added area: PWM Pulse Width Modulation platform: NXP NXP labels Jul 10, 2018
@diegosueiro
Copy link
Contributor Author

@MaureenHelm,

I found some issues with the pwm_api test related to asserts in the i.MX UART Driver. This PR depends on the PR #8938.

return -EINVAL;
}

duty_cycle = 100 * pulse_cycles / period_cycles;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The duty_cycle variable is used for logging only. Maybe the formula can be written directly in the logging statement. But compiler would probably optimize it anyway if log not used.

Copy link
Member

Choose a reason for hiding this comment

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

Another reason to move the formula is to avoid a compiler warning when you build with logging turned off.

struct imx_pwm_data *data = DEV_DATA(dev);
u8_t duty_cycle;
unsigned int period_ms;
bool enable = imx_pwm_is_enabled(base);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would rename to enabled or is_enabled. At the end of the function, PWM should be enabled anyway (unless there is an error in parameters etc).

} else {
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1);
do {
k_busy_wait(500);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would put 500 along with PWM_PWMSWR_LOOP define, so the values are written close together.

if (period_cycles > 2) {
period_cycles -= 2;
} else {
period_cycles = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the period_cycles < 2, should the function return error?


if (data->period_cycles != period_cycles) {
data->period_cycles = period_cycles;
PWM_PWMPR_REG(base) = period_cycles;
Copy link
Collaborator

Choose a reason for hiding this comment

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

If there are still some data in the sample register FIFO, say 1-3, could this happen:

  • We change the period to another value.
  • Samples in the FIFO were meant to be output with the previous period value.
  • But they will be output with the new period value, it may even be shorter than the sample value.

This is probably not very usual to change the period and I know the hardware does not allow to handle it better, though (unless we maintain our own fifo with both the cycle and period and set the HW FIFO low watermark to 1 and change the period in interrupt at the last moment).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@stanislav-poboril ,

Maybe in the "if (enable)" block it can wait for a full cycle if there is still 1,2,3 or 4 words of data in the FIFO. I think this way it will only configure a new period cycle if the FIFO is empty.
What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The best would be to try it. But then it could be perhaps too late to set the new period - there could be delays between stream of output with different cycles, which means FIFO would be emptied and the last cycle would repeat once more before changing the period.

I think the peripheral was created with the following use case in mind where period is set once and then the FIFO is filled ahead of time to keep it from underflowing (or let it underflow and repeat the same cycle until stopped or changing the cycle).

My previous comment would be probably relevant in a scenario, where the exact number of cycles has to be output (some sort of audio output?), but then I think it probably does not makes a sense to change the period duration.

Well I am not sure at the end if we should do anything about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps we can leave as is (I used the same approach as the Linux kernel driver) for now and add a comment in the source code about this specific scenario that is not covered?

@MaureenHelm,
What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I handled a similar case in pwm_mcux_ftm.c by logging a warning. You can do the same here for now.

SYS_LOG_WRN("Changing period cycles from %d to %d"

return -EINVAL;
}

duty_cycle = 100 * pulse_cycles / period_cycles;
Copy link
Member

Choose a reason for hiding this comment

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

Another reason to move the formula is to avoid a compiler warning when you build with logging turned off.


if (data->period_cycles != period_cycles) {
data->period_cycles = period_cycles;
PWM_PWMPR_REG(base) = period_cycles;
Copy link
Member

Choose a reason for hiding this comment

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

I handled a similar case in pwm_mcux_ftm.c by logging a warning. You can do the same here for now.

SYS_LOG_WRN("Changing period cycles from %d to %d"

def_bool y

config PWM_2
def_bool n
Copy link
Member

Choose a reason for hiding this comment

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

The def_bool n are redundant. I think all but PWM_1 should be removed.

@ulfalizer Will you please confirm?

@diegosueiro diegosueiro force-pushed the imx7d_pwm branch 3 times, most recently from 7eb88c0 to 276a17f Compare July 17, 2018 05:45
@diegosueiro
Copy link
Contributor Author

@MaureenHelm and @stanislav-poboril ,

All comments should be addressed now.

} else {
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1);
do {
k_sleep(1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I didn't realize before that the k_busy_wait(500) is 500 microseconds, vs k_sleep(1) is one millisecond, but due to the default quantum is 10 milliseconds in Zephyr/ARM, it will sleep 10 milliseconds or more (unless kernel parameters are changed, you have maybe changed the system tick to 1 ms). Is this ok?

Copy link
Member

@MaureenHelm MaureenHelm left a comment

Choose a reason for hiding this comment

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

Just two small nits

k_sleep(1);
cr = PWM_PWMCR_REG(base);
} while ((PWM_PWMCR_SWR(cr)) &&
(wait_count++ < CONFIG_PWM_PWMSWR_LOOP));
Copy link
Member

Choose a reason for hiding this comment

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

This should be ++wait_count

(wait_count++ < CONFIG_PWM_PWMSWR_LOOP));

if (PWM_PWMCR_SWR(cr))
SYS_LOG_WRN("software reset timeout\n");
Copy link
Member

Choose a reason for hiding this comment

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

Need to wrap in braces

This patch adds the get_pwm_clock_freq function to be used by the
i.MX PWM driver.

Signed-off-by: Diego Sueiro <[email protected]>
Adds the PWM shim driver for i.MX

Signed-off-by: Diego Sueiro <[email protected]>
Adds definitions, devicetree entries and clock controller
configurations for PWM peripheral.

Signed-off-by: Diego Sueiro <[email protected]>
Adds configurations and pinmux to support PWM on colibri_imx7d_m4

Signed-off-by: Diego Sueiro <[email protected]>
Adds the appropriated configuration for colibri_imx7d_m4 board in
blink_led sample app.

Signed-off-by: Diego Sueiro <[email protected]>
Adds the appropriated configuration for colibri_imx7d_m4 board in
pwm_api tests.

Signed-off-by: Diego Sueiro <[email protected]>
@MaureenHelm MaureenHelm merged commit 5d1b57f into zephyrproject-rtos:master Jul 17, 2018
@diegosueiro diegosueiro deleted the imx7d_pwm branch July 19, 2018 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: PWM Pulse Width Modulation platform: NXP NXP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants