From 285c657a51fad4929a2623616505e37a032108c0 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 7 Nov 2013 09:17:46 -0600 Subject: SAMA5 PWM: PWM driver is now functional --- nuttx/ChangeLog | 3 + nuttx/arch/arm/src/sama5/sam_pwm.c | 90 +++++++++++++++------- nuttx/configs/sama5d3x-ek/README.txt | 81 ++++++++++++-------- nuttx/configs/sama5d3x-ek/include/board.h | 122 ++++++++++++++++++++---------- 4 files changed, 195 insertions(+), 101 deletions(-) diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 54b4b816c..eefa4cbc2 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -5979,3 +5979,6 @@ no errors (2013-11-6). * configs/sama5d3x-ek: Add support for the PWM test for the SAMA5D3x-EK board (2013-11-6). + * arch/arm/src/sama5/sam_pwm.c and .h: SAMA5 PWM driver is now + function (2013-11-7). + diff --git a/nuttx/arch/arm/src/sama5/sam_pwm.c b/nuttx/arch/arm/src/sama5/sam_pwm.c index fe0ea8a2e..5d389a221 100644 --- a/nuttx/arch/arm/src/sama5/sam_pwm.c +++ b/nuttx/arch/arm/src/sama5/sam_pwm.c @@ -471,7 +471,7 @@ struct sam_pwm_s /* Register access */ #ifdef CONFIG_SAMA5_PWM_REGDEBUG -static bool pwm_checkreg(FAR struct sam_dev_s *chan, bool wr, uint32_t regval, +static bool pwm_checkreg(FAR struct sam_pwm_s *chan, bool wr, uint32_t regval, uintptr_t regaddr); #else # define pwm_checkreg(chan,wr,regval,regaddr) (false) @@ -693,7 +693,7 @@ static struct sam_pwm_chan_s g_pwm_chan3 = ****************************************************************************/ #ifdef CONFIG_SAMA5_PWM_REGDEBUG -static bool pwm_checkreg(struct sam_pwm_chan_s *pwm, bool wr, uint32_t regval, +static bool pwm_checkreg(FAR struct sam_pwm_s *pwm, bool wr, uint32_t regval, uintptr_t regaddr) { if (wr == pwm->wr && /* Same kind of access? */ @@ -747,26 +747,40 @@ static bool pwm_checkreg(struct sam_pwm_chan_s *pwm, bool wr, uint32_t regval, static uint32_t pwm_getreg(struct sam_pwm_chan_s *chan, int offset) { +#ifdef PWM_SINGLE uintptr_t regaddr; uint32_t regval; -#ifdef PWM_SINGLE regaddr = SAM_PWMC_VBASE + offset; + regval = getreg32(regaddr); + +#ifdef CONFIG_SAMA5_PWM_REGDEBUG + if (pwm_checkreg(&g_pwm, false, regval, regaddr)) + { + lldbg("%08x->%08x\n", regaddr, regval); + } +#endif + + return regval; + #else struct sam_pwm_chan_s *pwm = chan->pwm; - regaddr = pwm->base + offset; -#endif + uintptr_t regaddr; + uint32_t regval; - regval = getreg32(regaddr); + regaddr = pwm->base + offset; + regval = getreg32(regaddr); #ifdef CONFIG_SAMA5_PWM_REGDEBUG - if (pwm_checkreg(chan->pwm, false, regval, regaddr)) + if (pwm_checkreg(pwm, false, regval, regaddr)) { lldbg("%08x->%08x\n", regaddr, regval); } #endif return regval; + +#endif } /**************************************************************************** @@ -793,7 +807,11 @@ static uint32_t pwm_chan_getreg(struct sam_pwm_chan_s *chan, int offset) regval = getreg32(regaddr); #ifdef CONFIG_SAMA5_PWM_REGDEBUG +#ifdef PWM_SINGLE + if (pwm_checkreg(&g_pwm, false, regval, regaddr)) +#else if (pwm_checkreg(chan->pwm, false, regval, regaddr)) +#endif { lldbg("%08x->%08x\n", regaddr, regval); } @@ -817,25 +835,35 @@ static uint32_t pwm_chan_getreg(struct sam_pwm_chan_s *chan, int offset) * ****************************************************************************/ -static void pwm_putreg(struct sam_pwm_chan_s *chan, int offset, uint32_t regval) +static void pwm_putreg(struct sam_pwm_chan_s *chan, int offset, + uint32_t regval) { - uintptr_t regaddr; - #ifdef PWM_SINGLE - regaddr = SAM_PWMC_VBASE + offset; + uintptr_t regaddr = SAM_PWMC_VBASE + offset; + +#ifdef CONFIG_SAMA5_PWM_REGDEBUG + if (pwm_checkreg(&g_pwm, true, regval, regaddr)) + { + lldbg("%08x<-%08x\n", regaddr, regval); + } +#endif + + putreg32(regval, regaddr); + #else struct sam_pwm_chan_s *pwm = chan->pwm; - regaddr = pwm->base + offset; -#endif + uintptr_t regaddr = pwm->base + offset; #ifdef CONFIG_SAMA5_PWM_REGDEBUG - if (pwm_checkreg(chan->pwm, true, regval, regaddr)) + if (pwm_checkreg(pwm, true, regval, regaddr)) { lldbg("%08x<-%08x\n", regaddr, regval); } #endif putreg32(regval, regaddr); + +#endif } /**************************************************************************** @@ -853,12 +881,17 @@ static void pwm_putreg(struct sam_pwm_chan_s *chan, int offset, uint32_t regval) * ****************************************************************************/ -static void pwm_chan_putreg(struct sam_pwm_chan_s *chan, int offset, uint32_t regval) +static void pwm_chan_putreg(struct sam_pwm_chan_s *chan, int offset, + uint32_t regval) { uintptr_t regaddr = chan->base + offset; #ifdef CONFIG_SAMA5_PWM_REGDEBUG +#ifdef PWM_SINGLE + if (pwm_checkreg(&g_pwm, true, regval, regaddr)) +#else if (pwm_checkreg(chan->pwm, true, regval, regaddr)) +#endif { lldbg("%08x<-%08x\n", regaddr, regval); } @@ -885,57 +918,57 @@ static void pwm_chan_putreg(struct sam_pwm_chan_s *chan, int offset, uint32_t re static void pwm_dumpregs(struct sam_pwm_chan_s *chan, FAR const char *msg) { pwmvdbg("PWM: %s\n", msg); - pwmvdbg(" CLK: %04x SR: %04x IMR1: %04x ISR1: %04x\n", + pwmvdbg(" CLK: %08x SR: %08x IMR1: %08x ISR1: %08x\n", pwm_getreg(chan, SAM_PWM_CLK_OFFSET), pwm_getreg(chan, SAM_PWM_SR_OFFSET), pwm_getreg(chan, SAM_PWM_IMR1_OFFSET), pwm_getreg(chan, SAM_PWM_ISR1_OFFSET)); - pwmvdbg(" SCM: %04x SCUC: %04x SCUP: %04x IMR2: %04x\n", + pwmvdbg(" SCM: %08x SCUC: %08x SCUP: %08x IMR2: %08x\n", pwm_getreg(chan, SAM_PWM_SCM_OFFSET), pwm_getreg(chan, SAM_PWM_SCUC_OFFSET), pwm_getreg(chan, SAM_PWM_SCUP_OFFSET), pwm_getreg(chan, SAM_PWM_IMR2_OFFSET)); - pwmvdbg(" ISR2: %04x OOV: %04x OS: %04x FMR: %04x\n", + pwmvdbg(" ISR2: %08x OOV: %08x OS: %08x FMR: %08x\n", pwm_getreg(chan, SAM_PWM_ISR2_OFFSET), pwm_getreg(chan, SAM_PWM_OOV_OFFSET), pwm_getreg(chan, SAM_PWM_OS_OFFSET), pwm_getreg(chan, SAM_PWM_FMR_OFFSET)); - pwmvdbg(" FSR: %04x FPV: %04x FPE: %04x ELMR0: %04x\n", + pwmvdbg(" FSR: %08x FPV: %08x FPE: %08x ELMR0: %08x\n", pwm_getreg(chan, SAM_PWM_FSR_OFFSET), pwm_getreg(chan, SAM_PWM_FPV_OFFSET), pwm_getreg(chan, SAM_PWM_FPE_OFFSET), pwm_getreg(chan, SAM_PWM_ELMR0_OFFSET)); - pwmvdbg(" ELMR1: %04x SMMR: %04x WPSR: %04x\n", + pwmvdbg(" ELMR1: %08x SMMR: %08x WPSR: %08x\n", pwm_getreg(chan, SAM_PWM_ELMR1_OFFSET), pwm_getreg(chan, SAM_PWM_SMMR_OFFSET), pwm_getreg(chan, SAM_PWM_WPSR_OFFSET)); - pwmvdbg(" CMPV0: %04x CMPM0: %04x CMPV1: %04x CMPM1: %04x\n", + pwmvdbg(" CMPV0: %08x CMPM0: %08x CMPV1: %08x CMPM1: %08x\n", pwm_getreg(chan, SAM_PWM_CMPV0_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM0_OFFSET), pwm_getreg(chan, SAM_PWM_CMPV1_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM1_OFFSET)); - pwmvdbg(" CMPV2: %04x CMPM2: %04x CMPV3: %04x CMPM3: %04x\n", + pwmvdbg(" CMPV2: %08x CMPM2: %08x CMPV3: %08x CMPM3: %08x\n", pwm_getreg(chan, SAM_PWM_CMPV2_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM2_OFFSET), pwm_getreg(chan, SAM_PWM_CMPV3_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM3_OFFSET)); - pwmvdbg(" CMPV4: %04x CMPM4: %04x CMPV5: %04x CMPM5: %04x\n", + pwmvdbg(" CMPV4: %08x CMPM4: %08x CMPV5: %08x CMPM5: %08x\n", pwm_getreg(chan, SAM_PWM_CMPV4_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM4_OFFSET), pwm_getreg(chan, SAM_PWM_CMPV5_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM5_OFFSET)); - pwmvdbg(" CMPV6: %04x CMPM6: %04x CMPV7: %04x CMPM7: %04x\n", + pwmvdbg(" CMPV6: %08x CMPM6: %08x CMPV7: %08x CMPM7: %08x\n", pwm_getreg(chan, SAM_PWM_CMPV6_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM6_OFFSET), pwm_getreg(chan, SAM_PWM_CMPV7_OFFSET), pwm_getreg(chan, SAM_PWM_CMPM7_OFFSET)); pwmvdbg("Channel %d: %s\n", chan->channel, msg); - pwmvdbg(" CMR: %04x CDTY: %04x CPRD: %04x CCNT: %04x\n", + pwmvdbg(" CMR: %08x CDTY: %08x CPRD: %08x CCNT: %08x\n", pwm_chan_getreg(chan, SAM_PWM_CMR_OFFSET), pwm_chan_getreg(chan, SAM_PWM_CDTY_OFFSET), pwm_chan_getreg(chan, SAM_PWM_CPRD_OFFSET), pwm_chan_getreg(chan, SAM_PWM_CCNT_OFFSET)); - pwmvdbg(" CT: %04x\n", + pwmvdbg(" CT: %08x\n", pwm_chan_getreg(chan, SAM_PWM_DT_OFFSET)); } #endif @@ -1118,7 +1151,7 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, * the CPRDUPD) register. */ - cprd = (info->frequency + (fsrc >> 1)) / fsrc; + cprd = (fsrc + (info->frequency >> 1)) / info->frequency; pwm_chan_putreg(chan, SAM_PWM_CPRD_OFFSET, cprd); /* Set the PWM duty. Since the PWM is disabled, we can write directly @@ -1128,12 +1161,13 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev, regval = b16toi(info->duty * cprd + b16HALF); if (regval > cprd) { - /* Rounding could cause the duty value to exceed CPRD */ + /* Rounding up could cause the duty value to exceed CPRD (?) */ regval = cprd; } pwm_chan_putreg(chan, SAM_PWM_CDTY_OFFSET, regval); + pwmvdbg("Fsrc=%d cprd=%d cdty=%d\n", fsrc, cprd, regval); /* Enable the channel */ diff --git a/nuttx/configs/sama5d3x-ek/README.txt b/nuttx/configs/sama5d3x-ek/README.txt index 04c1ea381..076676683 100644 --- a/nuttx/configs/sama5d3x-ek/README.txt +++ b/nuttx/configs/sama5d3x-ek/README.txt @@ -852,44 +852,48 @@ SAMA5 PWM Support Where x=0..3. Care must be taken because all PWM output pins conflict with some other - usage of the pin by other devices: - - -----+---+---+----+-------------------- - PWM PIN PER PIO CONFLICTS - -----+---+---+----+-------------------- - PWM0 FI B PC28 SPI1, ISI - H B PB0 GMAC - B PA20 LCDC, ISI - L B PB1 GMAC - B PA21 LCDC, ISI - -----+---+---+----+-------------------- - PWM1 FI B PC31 HDMI - H B PB4 GMAC - B PA22 LCDC, ISI - L B PB5 GMAC - B PE31 ISI, HDMI - B PA23 LCDC, ISI - -----+---+---+----+-------------------- - PWM2 FI B PC29 UART0, ISI, HDMI - H C PD5 HSMCI0 - B PB8 GMAC - L C PD6 HSMCI0 - B PB9 GMAC - -----+---+---+----+-------------------- - PWM3 FI C PD16 SPI0, Audio - H C PD7 HSMCI0 - B PB12 GMAC - L C PD8 HSMCI0 - B PB13 GMAC + usage of the pin by other devices. Furthermore, many of these pins have + not been brought out to an external connector: + + -----+---+---+----+------+---------------- + PWM PIN PER PIO I/O CONFLICTS + -----+---+---+----+------+---------------- + PWM0 FI B PC28 J2.30 SPI1, ISI + H B PB0 --- GMAC + B PA20 J1.14 LCDC, ISI + L B PB1 --- GMAC + B PA21 J1.16 LCDC, ISI + -----+---+---+----+------+---------------- + PWM1 FI B PC31 J2.36 HDMI + H B PB4 --- GMAC + B PA22 J1.18 LCDC, ISI + L B PB5 --- GMAC + B PE31 J3.20 ISI, HDMI + B PA23 J1.20 LCDC, ISI + -----+---+---+----+------+---------------- + PWM2 FI B PC29 J2.29 UART0, ISI, HDMI + H C PD5 --- HSMCI0 + B PB8 --- GMAC + L C PD6 --- HSMCI0 + B PB9 --- GMAC + -----+---+---+----+------+---------------- + PWM3 FI C PD16 --- SPI0, Audio + H C PD7 --- HSMCI0 + B PB12 J3.7 GMAC + L C PD8 --- HSMCI0 + B PB13 --- GMAC -----+---+---+----+-------------------- + See configs/sama5d3x-ek/include/board.h for all of the default PWM + pin selections. I used PWM channel 0, pins PA20 and PA21 for testing. + Clocking is addressed in the next paragraph. PWM Clock Configuration ----------------------- PWM Channels can be clocked from either a coarsely divided divided down MCK or from a custom frequency from PWM CLKA and/or CLKB. If you want - to use CLKA or CLKB, you must enable and configuratino them. + to use CLKA or CLKB, you must enable and configure them. System Type -> PWM Configuration CONFIG_SAMA5_PWM_CLKA=y @@ -901,7 +905,7 @@ SAMA5 PWM Support for that channel: System Type -> PWM Configuration - CONFIG_SAMA5_PWM_CHANx_CLKA=y : Pick one of MCK, CLKA, or CLKB + CONFIG_SAMA5_PWM_CHANx_CLKA=y : Pick one of MCK, CLKA, or CLKB (only) CONFIG_SAMA5_PWM_CHANx_CLKB=y CONFIG_SAMA5_PWM_CHANx_MCK=y CONFIG_SAMA5_PWM_CHANx_MCKDIV=128 : If MCK is selected, then the MCK divider must @@ -921,6 +925,21 @@ SAMA5 PWM Support CONFIG_EXAMPLES_PWM_DEVPATH="/dev/pwm0" CONFIG_EXAMPLES_PWM_FREQUENCY=100 + Usage of the example is straightforward: + + nsh> pwm -h + Usage: pwm [OPTIONS] + + Arguments are "sticky". For example, once the PWM frequency is + specified, that frequency will be re-used until it is changed. + + "sticky" OPTIONS include: + [-p devpath] selects the PWM device. Default: /dev/pwm0 Current: /dev/pwm0 + [-f frequency] selects the pulse frequency. Default: 100 Hz Current: 100 Hz + [-d duty] selects the pulse duty as a percentage. Default: 50 % Current: 50 % + [-t duration] is the duration of the pulse train in seconds. Default: 5 Current: 5 + [-h] shows this message and exits + OV2640 Camera interface ======================= diff --git a/nuttx/configs/sama5d3x-ek/include/board.h b/nuttx/configs/sama5d3x-ek/include/board.h index 59d184906..8cb83570e 100644 --- a/nuttx/configs/sama5d3x-ek/include/board.h +++ b/nuttx/configs/sama5d3x-ek/include/board.h @@ -178,56 +178,88 @@ /* PWM. There are no dedicated PWM output pins available to the user for PWM * testing. Care must be taken because all PWM output pins conflict with some other - * usage of the pin by other devices: - * - * -----+---+---+----+-------------------- - * PWM PIN PER PIO CONFLICTS - * -----+---+---+----+-------------------- - * PWM0 FI B PC28 SPI1, ISI - * H B PB0 GMAC - * B PA20 LCDC, ISI - * L B PB1 GMAC - * B PA21 LCDC, ISI - * -----+---+---+----+-------------------- - * PWM1 FI B PC31 HDMI - * H B PB4 GMAC - * B PA22 LCDC, ISI - * L B PB5 GMAC - * B PE31 ISI, HDMI - * B PA23 LCDC, ISI - * -----+---+---+----+-------------------- - * PWM2 FI B PC29 UART0, ISI, HDMI - * H C PD5 HSMCI0 - * B PB8 GMAC - * L C PD6 HSMCI0 - * B PB9 GMAC - * -----+---+---+----+-------------------- - * PWM3 FI C PD16 SPI0, Audio - * H C PD7 HSMCI0 - * B PB12 GMAC - * L C PD8 HSMCI0 - * B PB13 GMAC - * -----+---+---+----+-------------------- + * usage of the pin by other devices. Furthermore, many of these pins have not been + * brought out to an external connector: + * + * -----+---+---+----+------+---------------- + * PWM PIN PER PIO I/O CONFLICTS + * -----+---+---+----+------+---------------- + * PWM0 FI B PC28 J2.30 SPI1, ISI + * H B PB0 --- GMAC + * B PA20 J1.14 LCDC, ISI + * L B PB1 --- GMAC + * B PA21 J1.16 LCDC, ISI + * -----+---+---+----+------+---------------- + * PWM1 FI B PC31 J2.36 HDMI + * H B PB4 --- GMAC + * B PA22 J1.18 LCDC, ISI + * L B PB5 --- GMAC + * B PE31 J3.20 ISI, HDMI + * B PA23 J1.20 LCDC, ISI + * -----+---+---+----+------+---------------- + * PWM2 FI B PC29 J2.29 UART0, ISI, HDMI + * H C PD5 --- HSMCI0 + * B PB8 --- GMAC + * L C PD6 --- HSMCI0 + * B PB9 --- GMAC + * -----+---+---+----+------+---------------- + * PWM3 FI C PD16 --- SPI0, Audio + * H C PD7 --- HSMCI0 + * B PB12 J3.7 GMAC + * L C PD8 --- HSMCI0 + * B PB13 --- GMAC + * -----+---+---+----+------+---------------- */ -#if !defined(CONFIG_SAMA5_GMAC) +/* PWM channel 0: + * + * PA20 and PA21 can be used if the LCDC or ISI are not selected. These outputs are + * available on J1, pins 14 and 16, respectively. + * + * If the GMAC is not selected, then PB0 and PB1 could also be used. However, + * these pins are not available at the I/O expansion connectors. + */ + +#if !defined(CONFIG_SAMA5_LCDC) && !defined(CONFIG_SAMA5_ISI) +# define PIO_PWM0_H PIO_PWM0_H_2 +# define PIO_PWM0_L PIO_PWM0_L_2 +#elif !defined(CONFIG_SAMA5_GMAC) # define PIO_PWM0_H PIO_PWM0_H_1 # define PIO_PWM0_L PIO_PWM0_L_1 -#elif !defined(CONFIG_SAMA5_LCDC) && !defined(CONFIG_SAMA5_ISI) -# define PIO_PWM0_H PIO_PWM0_H_2 -# define PIO_PWM0_L PIO_PWM0_L_3 #endif -#if !defined(CONFIG_SAMA5_GMAC) -# define PIO_PWM1_H PIO_PWM1_H_1 -# define PIO_PWM1_L PIO_PWM1_L_1 -#elif !defined(CONFIG_SAMA5_LCDC) && !defined(CONFIG_SAMA5_ISI) +/* PWM channel 1: + * + * PA22 and PA23 can be used if the LCDC or ISI are not selected. These outputs are + * available on J1, pins 18 and 20, respectively. + * + * PE31 can be used if the ISI is not selected (and the HDMI is not being used). + * That signal is available at J3 pin 20. + * + * If the GMAC is not selected, then PB4 and PB5 could also be used. However, + * these pins are not available at the I/O expansion connectors. + */ + +#if !defined(CONFIG_SAMA5_LCDC) && !defined(CONFIG_SAMA5_ISI) # define PIO_PWM1_H PIO_PWM1_H_2 +#elif !defined(CONFIG_SAMA5_GMAC) +# define PIO_PWM1_H PIO_PWM1_H_1 +#endif + +#if !defined(CONFIG_SAMA5_LCDC) && !defined(CONFIG_SAMA5_ISI) # define PIO_PWM1_L PIO_PWM1_L_3 #elif !defined(CONFIG_SAMA5_ISI) # define PIO_PWM1_L PIO_PWM1_L_2 +#elif !defined(CONFIG_SAMA5_GMAC) +# define PIO_PWM1_L PIO_PWM1_L_1 #endif +/* PWM channel 2: + * + * None of the output pin options are available at any of the I/O expansion + * connectors for PWM channel 2 + */ + #if !defined(CONFIG_SAMA5_HSMCI0) # define PIO_PWM2_H PIO_PWM2_H_1 # define PIO_PWM2_L PIO_PWM2_L_1 @@ -236,12 +268,18 @@ # define PIO_PWM2_L PIO_PWM2_L_2 #endif -#if !defined(CONFIG_SAMA5_HSMCI0) -# define PIO_PWM3_H PIO_PWM3_H_1 -# define PIO_PWM3_L PIO_PWM3_L_1 -#elif !defined(CONFIG_SAMA5_GMAC) +/* PWM channel 3: + * + * If the GMAC is not selected, then PB12 can used and is available at J3 pin 7. + * None of the other output pins are accessible at the I/O expansion connectors. + */ + +#if !defined(CONFIG_SAMA5_GMAC) # define PIO_PWM3_H PIO_PWM3_H_2 # define PIO_PWM3_L PIO_PWM3_L_2 +#elif !defined(CONFIG_SAMA5_HSMCI0) +# define PIO_PWM3_H PIO_PWM3_H_1 +# define PIO_PWM3_L PIO_PWM3_L_1 #endif /************************************************************************************ -- cgit v1.2.3