[PATCH] Subject: Add original BBBIO PWM driver to BBB BSP

punit vara punitvara at gmail.com
Wed Jun 22 07:02:07 UTC 2016


Hi all,

In next patch I will apply changes for working code as well as will
add licence information to pwm.c file. Right now I added URL to
commit. Should I go ahead for further changes ?

Thanks,
Punit Vara

On Wed, Jun 22, 2016 at 12:26 PM, Punit Vara <punitvara at gmail.com> wrote:
>         This patch perform following things:
>         - adds original BBBIO PWM code as it is.
>         - not added to Makefile otherwise it will break build
>         - adds required registers
>         - adds declarations to BSP_HEADERS
>
>         This code is added from
>         https://github.com/VegetableAvenger/BBBIOlib/blob/master/BBBio_lib/BBBiolib_PWMSS.c
> ---
>  c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h |  46 +++
>  c/src/lib/libbsp/arm/beagle/pwm/pwm.c         | 407 ++++++++++++++++++++++++++
>  c/src/lib/libcpu/arm/shared/include/am335x.h  |  11 +-
>  3 files changed, 463 insertions(+), 1 deletion(-)
>  create mode 100644 c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h
>  create mode 100644 c/src/lib/libbsp/arm/beagle/pwm/pwm.c
>
> diff --git a/c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h b/c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h
> new file mode 100644
> index 0000000..bd70385
> --- /dev/null
> +++ b/c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h
> @@ -0,0 +1,46 @@
> +/**
> + * @file
> + *
> + * @ingroup arm_beagle
> + *
> + * @brief BeagleBone Black BSP definitions.
> + */
> +
> +/**
> + * Copyright (c) 2016 Punit Vara <punitvara at gmail.com>
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.org/license/LICENSE.
> + */
> +
> +#ifndef LIBBSP_ARM_BEAGLE_BBB_PWM_H
> +#define LIBBSP_ARM_BEAGLE_BBB_PWM_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +/**
> + * @brief  BeagleBone Black PWM functions.
> + */
> +#define BBBIO_PWMSS_COUNT       3
> +#define BBBIO_PWMSS0           0
> +#define BBBIO_PWMSS1           1
> +#define BBBIO_PWMSS2           2
> +
> +/**
> + * @brief  BeagleBone Black PWM API.
> + */
> +int BBBIO_PWMSS_Setting(unsigned int PWMID , float HZ ,float dutyA ,float dutyB);
> +int BBBIO_PWM_Init();
> +void BBBIO_PWM_Release();
> +int BBBIO_PWMSS_Status(unsigned int PWMID);
> +void BBBIO_ehrPWM_Enable(unsigned int PWMSS_ID);
> +void BBBIO_ehrPWM_Disable(unsigned int PWMSS_ID);
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* LIBBSP_ARM_BEAGLE_BBB_PWM_H */
> diff --git a/c/src/lib/libbsp/arm/beagle/pwm/pwm.c b/c/src/lib/libbsp/arm/beagle/pwm/pwm.c
> new file mode 100644
> index 0000000..f65ff89
> --- /dev/null
> +++ b/c/src/lib/libbsp/arm/beagle/pwm/pwm.c
> @@ -0,0 +1,407 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <time.h>
> +#include "BBBiolib.h"
> +/*-----------------------------------------------------------------------------------------------*/
> +/*
> + * PWMSS Registers
> + *
> + * @Source : AM335x Technical Reference Manual ,page 1991
> + *           Table 15-5. PWMSS REGISTERS
> + *
> +*/
> +
> +#define PWMSS0_MMAP_ADDR       0x48300000
> +#define PWMSS1_MMAP_ADDR       0x48302000
> +#define PWMSS2_MMAP_ADDR       0x48304000
> +#define PWMSS_MMAP_LEN         0x1000
> +
> +#define PWMSS_IDVER    0x0
> +#define PWMSS_SYSCONFIG        0x4
> +#define PWMSS_CLKCONFIG        0x8
> +#define PWMSS_CLKSTATUS        0xC
> +
> +/* EPWM Registers
> + *
> + * @Source : AM335x Technical Reference Manual ,page 2084
> + *           Table 15-58. EPWM REGISTERS
> + *
> +*/
> +#define EPWM_TBCTL     0x0
> +#define EPWM_TBSTS     0x2
> +#define EPWM_TBPHSHR   0x4
> +#define EPWM_TBPHS     0x6
> +#define EPWM_TBCNT     0x8
> +#define EPWM_TBPRD     0xA
> +#define EPWM_CMPCTL    0xE
> +#define EPWM_CMPAHR    0x10
> +#define EPWM_CMPA      0x12
> +#define EPWM_CMPB      0x14
> +#define EPWM_AQCTLA    0x16
> +#define EPWM_AQCTLB    0x18
> +#define EPWM_AQSFRC    0x1A
> +#define EPWM_AQCSFRC   0x1C
> +#define EPWM_DBCTL     0x1E
> +#define EPWM_DBRED     0x20
> +#define EPWM_DBFED     0x22
> +/*-----------------------------------------------------------------------------------------------*/
> +extern int memh;
> +extern volatile unsigned int *CM_ptr;  /*c ontrol module */
> +volatile unsigned int *cm_per_addr;
> +
> +
> +const unsigned int PWMSS_AddressOffset[]={PWMSS0_MMAP_ADDR,
> +                                         PWMSS1_MMAP_ADDR,
> +                                         PWMSS2_MMAP_ADDR};
> +volatile unsigned int *pwmss_ptr[3]     ={NULL, NULL, NULL} ;
> +volatile unsigned int *epwm_ptr[3]      ={NULL, NULL, NULL} ;
> +volatile unsigned int *ecap_ptr[3]      ={NULL, NULL, NULL} ;
> +volatile unsigned int *eqep_ptr[3]      ={NULL, NULL, NULL} ;
> +
> +#define TBCTL_CTRMODE_UP        0x0
> +#define TBCTL_CTRMODE_DOWN      0x1
> +#define TBCTL_CTRMODE_UPDOWN    0x2
> +#define TBCTL_CTRMODE_FREEZE    0x3
> +/* ----------------------------------------------------------------------------------------------- */
> +/* PWMSS Timebase clock check
> + *     check the timenase clock enable or not
> + *
> + *     @param PWMSS_ID :  PWM sumsystem ID (BBBIO_PWMSS0 ,BBBIO_PWMSS1, BBBIO_PWMSS2)
> + *
> + *     @return : 0 for disable timebase clock , 1 for enable for timebase clock
> + */
> +static int PWMSS_TB_clock_check(unsigned int PWMSS_ID)
> +{
> +       volatile unsigned int* reg;
> +       unsigned int reg_value ;
> +
> +       /* Control module check */
> +       reg =(void *)CM_ptr + BBBIO_PWMSS_CTRL;
> +       reg_value = *reg ;
> +
> +       return (reg_value & (1 << PWMSS_ID)) ;
> +}
> +
> +/* ----------------------------------------------------------------------------------------------- */
> +/* PWM subsystem system control
> + *     enable or disable module clock
> + *
> + *     @param PWMSS_ID :  PWM sumsystem ID (BBBIO_PWMSS0 ,BBBIO_PWMSS1, BBBIO_PWMSS2).
> + *     @param enable : 0 for disable , else for enable .
> + *
> + *     @return : 1 for success ,  0 for error
> + */
> +static int PWMSS_module_ctrl(unsigned int PWMSS_ID, int enable)
> +{
> +       volatile unsigned int *reg = NULL;
> +       unsigned int module_set[] = {BBBIO_PWMSS0, BBBIO_PWMSS1, BBBIO_PWMSS2};
> +       unsigned int module_clk_set[] = {BBBIO_CM_PER_EPWMSS0_CLKCTRL, BBBIO_CM_PER_EPWMSS1_CLKCTRL, BBBIO_CM_PER_EPWMSS2_CLKCTRL};
> +       int ret = 1;
> +
> +       reg = (void*)cm_per_addr + module_clk_set[PWMSS_ID];
> +       if(enable) {
> +               if(PWMSS_TB_clock_check(module_set[PWMSS_ID])) {
> +                       /* Enable module clock */
> +                       *reg = 0x2;     /* Module enable and fully functional */
> +                       return ret;
> +               }
> +#ifdef BBBIO_LIB_DBG
> +               else {
> +                       printf("PWMSS_module_ctrl : PWMSS-%d timebase clock disable in Control Module\n", PWMSS_ID);
> +               }
> +#endif
> +               ret = 0 ;
> +       }
> +       *reg = 0x3 << 16;       /* Module is disabled and cannot be accessed */
> +       return ret;
> +}
> +
> +/* ----------------------------------------------------------------------------------------------- */
> +/* PWM init
> + *     iolib_init will run this function automatically
> + *
> + *      @return         : 1 for success , 0 for failed
> + */
> +
> +int BBBIO_PWM_Init()
> +{
> +       int i = 0;
> +
> +       if (memh == 0) {
> +#ifdef BBBIO_LIB_DBG
> +               printf("BBBIO_PWM_Init: memory not mapped?\n");
> +#endif
> +               return 0;
> +       }
> +
> +       /* Create Memory map */
> +       for (i = 0 ; i < 3 ; i ++) {
> +               pwmss_ptr[i] = mmap(0, PWMSS_MMAP_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, memh, PWMSS_AddressOffset[i]);
> +               if(pwmss_ptr[i] == MAP_FAILED) {
> +#ifdef BBBIO_LIB_DBG
> +                       printf("BBBIO_PWM_Init: PWMSS %d mmap failure!\n", i);
> +#endif
> +                       goto INIT_ERROR ;
> +               }
> +               ecap_ptr[i] = (void *)pwmss_ptr[i] + 0x100 ;
> +               eqep_ptr[i] = (void *)pwmss_ptr[i] + 0x180 ;
> +               epwm_ptr[i] = (void *)pwmss_ptr[i] + 0x200 ;
> +
> +               if(!PWMSS_module_ctrl(i, 1)) {
> +#ifdef BBBIO_LIB_DBG
> +                       printf("BBBIO_PWM_Init: PWMSS %d clock  failure!\n", i);
> +#endif
> +                       goto INIT_ERROR ;
> +               }
> +       }
> +       return 1;
> +
> +INIT_ERROR :
> +       BBBIO_PWM_Release();
> +       return 0;
> +}
> +
> +/* ----------------------------------------------------------------------------------------------- */
> +void BBBIO_PWM_Release()
> +{
> +       int i = 0;
> +       for(i = 0 ; i < 3 ; i ++) {
> +               if(pwmss_ptr[i] != NULL) {
> +                       munmap((void *)pwmss_ptr[i], PWMSS_MMAP_LEN);
> +                       pwmss_ptr[i] = NULL;
> +                       ecap_ptr[i] = NULL;
> +                       eqep_ptr[i] = NULL;
> +                       epwm_ptr[i] = NULL;
> +               }
> +       }
> +}
> +
> +/* ----------------------------------------------------------------------------------------------- */
> +/* PWMSS status (no effect now)
> + *     set pluse rgument of epwm module
> + *
> + *      @param PWMID    : EPWMSS number , 0~3
> + *
> + *      @return         : 1 for success , 0 for failed
> + */
> +int BBBIO_PWMSS_Status(unsigned int PWMID)
> +{
> +       int param_error = 1;
> +       volatile unsigned int* reg;
> +       unsigned int reg_value ;
> +
> +       if (memh == 0)
> +            param_error = 0;
> +
> +       if (PWMID > 2)          /* if input is not EPWMSS 0~ WPEMSS 2 */
> +            param_error = 0;
> +
> +       if (param_error == 0) {
> +#ifdef BBBIO_LIB_DBG
> +               printf("BBBIO_PWM_Status: parameter error!\n");
> +#endif
> +               return 0;
> +       }
> +
> +       reg =(void *)CM_ptr + BBBIO_PWMSS_CTRL;
> +
> +       reg_value = *reg >> PWMID & 0x01 ;
> +       if(reg_value == 0) {
> +               printf("PWMSS [%d] Timebase clock Disable , Control Module [pwmss_ctrl register]\n", PWMID);
> +       }
> +       else {
> +               reg=(void *)pwmss_ptr[PWMID] + PWMSS_CLKSTATUS;
> +               reg_value = *reg ;
> +
> +               printf("PWMSS [%d] :\tCLKSTOP_ACK %d , CLK_EN_ACK %d , CLKSTOP_ACK %d , CLK_EN_ACK %d , CLKSTOP_ACK %d , CLK_EN_ACK %d\n",
> +                       PWMID ,
> +                       reg_value >>9 & 0x1 ,
> +                       reg_value >>8 & 0x1 ,
> +                       reg_value >>5 & 0x1 ,
> +                       reg_value >>4 & 0x1 ,
> +                       reg_value >>1 & 0x1 ,
> +                       reg_value >>0 & 0x1 );
> +       }
> +       return 1 ;
> +}
> +/* ----------------------------------------------------------------------------------------------- */
> +/* PWMSS setting
> + *     set pluse rgument of epwm module
> + *
> + *      @param PWMID    : EPWMSS number , 0~2
> + *      @param HZ      : pluse HZ
> + *      @param dutyA    : Duty Cycle in ePWM A
> + *      @param dutyB    : Duty Cycle in ePWM B
> + *
> + *      @return         : 1 for success , 0 for failed
> + *
> + *      @example        :  BBBIO_PWMSS_Setting(0 , 50.0f , 50.0f , 25.0f);     // Generate 50HZ pwm in PWM0 ,
> + *                                                                             // duty cycle is 50% for ePWM0A , 25% for ePWM0B
> + *
> + *     @Note :
> + *             find an number nearst 65535 for TBPRD , to improve duty precision,
> + *
> + *             Using big TBPRD can increase the range of CMPA and CMPB ,
> + *             and it means we can get better precision on duty cycle.
> + *
> + *             EX : 20.25% duty cycle
> + *                  on TBPRD = 62500 , CMPA = 12656.25 ( .25 rejection) , real duty : 20.2496% (12656 /62500)
> + *                  on TBPRD = 6250  , CMPA = 1265.625 ( .625 rejection), real duty : 20.24%   (1265 6250)
> + *                  on TBPRD = 500   , CMPA = 101.25   ( .25 rejection) , real duty : 20.2%    (101/500)
> + *
> + *             Divisor = CLKDIV * HSPCLKDIV
> + *                             1 TBPRD : 10 ns (default)
> + *                     65535 TBPRD : 655350 ns
> + *                     65535 TBPRD : 655350 * Divisor ns  = X TBPRD : Cyclens
> + *
> + *             accrooding to that , we must find a Divisor value , let X nearest 65535 .
> + *             so , Divisor must  Nearest Cyclens/655350
> +*/
> +
> +int BBBIO_PWMSS_Setting(unsigned int PWMID , float HZ ,float dutyA ,float dutyB)
> +{
> +       int param_error = 1;
> +       volatile unsigned short* reg16 ;
> +        if (memh == 0)
> +            param_error = 0;
> +        if (PWMID > 2)              // if input is not EPWMSS 0~ WPEMSS 2
> +            param_error = 0;
> +       if (HZ < 0 )
> +           param_error = 0;
> +       if(dutyA < 0.0f || dutyA > 100.0f || dutyB < 0.0f || dutyB > 100.0f)
> +           param_error = 0;
> +
> +        if (param_error == 0) {
> +#ifdef BBBIO_LIB_DBG
> +               printf("BBBIO_PWMSS_Setting: parameter error!\n");
> +#endif
> +               return 0;
> +        }
> +
> +       dutyA /= 100.0f ;
> +       dutyB /= 100.0f ;
> +
> +       /* compute neccessary TBPRD */
> +       float Cyclens =0.0f ;
> +       float Divisor =0;
> +       int i , j ;
> +       const float CLKDIV_div[] = {1.0 ,2.0 ,4.0 ,8.0 ,16.0 ,32.0 , 64.0 , 128.0};
> +       const float HSPCLKDIV_div[] ={1.0 ,2.0 ,4.0 ,6.0 ,8.0 ,10.0 , 12.0 , 14.0};
> +       int NearCLKDIV =7;
> +       int NearHSPCLKDIV =7;
> +       int NearTBPRD =0;
> +
> +       Cyclens = 1000000000.0f / HZ ; /* 10^9 / HZ , comput time per cycle (ns) */
> +
> +
> +       Divisor =  (Cyclens / 655350.0f) ;      /* am335x provide (128*14) divider , and per TBPRD means 10 ns when divider /1 ,
> +                                                * and max TBPRD is 65535 , so , the max cycle is 128*14* 65535 *10ns
> +                                                */
> +#ifdef BBBIO_LIB_DBG
> +       printf("Cyclens %f , Divisor %f\n", Cyclens, Divisor);
> +#endif
> +
> +       if(Divisor > (128 * 14)) {
> +#ifdef BBBIO_LIB_DBG
> +               printf("BBBIO_PWMSS_Setting : Can't generate %f HZ \n", HZ);
> +#endif
> +               return 0;
> +       }
> +       else {
> +               /* using Exhaustive Attack metho */
> +               for(i = 0 ; i < 8 ; i ++) {
> +                       for(j = 0 ; j < 8 ; j ++) {
> +                               if((CLKDIV_div[i] * HSPCLKDIV_div[j]) < (CLKDIV_div[NearCLKDIV] * HSPCLKDIV_div[NearHSPCLKDIV]) &&
> +                                 ((CLKDIV_div[i] * HSPCLKDIV_div[j]) > Divisor)) {
> +                                       NearCLKDIV = i ;
> +                                       NearHSPCLKDIV = j ;
> +                               }
> +                       }
> +               }
> +#ifdef BBBIO_LIB_DBG
> +               printf("nearest CLKDIV %f , HSPCLKDIV %f\n" ,CLKDIV_div[NearCLKDIV] ,HSPCLKDIV_div[NearHSPCLKDIV]);
> +#endif
> +               NearTBPRD = (Cyclens / (10.0 *CLKDIV_div[NearCLKDIV] *HSPCLKDIV_div[NearHSPCLKDIV])) ;
> +
> +#ifdef BBBIO_LIB_DBG
> +               printf("nearest TBPRD %d, %f %f\n ",NearTBPRD,NearTBPRD * dutyA, NearTBPRD * dutyB);
> +#endif
> +
> +               /* setting clock diver and freeze time base */
> +               reg16=(void*)epwm_ptr[PWMID] +EPWM_TBCTL;
> +               *reg16 = TBCTL_CTRMODE_FREEZE | (NearCLKDIV << 10) | (NearHSPCLKDIV << 7);
> +
> +               /*  setting duty A and duty B */
> +               reg16=(void*)epwm_ptr[PWMID] +EPWM_CMPB;
> +               *reg16 =(unsigned short)((float)NearTBPRD * dutyB);
> +
> +               reg16=(void*)epwm_ptr[PWMID] +EPWM_CMPA;
> +               *reg16 =(unsigned short)((float)NearTBPRD * dutyA);
> +
> +               reg16=(void*)epwm_ptr[PWMID] +EPWM_TBPRD;
> +               *reg16 =(unsigned short)NearTBPRD;
> +
> +               /* reset time base counter */
> +               reg16 = (void *)epwm_ptr[PWMID] + EPWM_TBCNT;
> +               *reg16 = 0;
> +       }
> +       return 1;
> +}
> +/* ----------------------------------------------------------------------------------------------- */
> +/* Enable/Disable ehrPWM module
> + *      @param PWMID    : PWMSS number , 0~2
> + *
> + *      @return         : void
> + *
> + *      @example        : BBBIO_PWMSS_Enable(0) ;// Enable PWMSS 0
> + */
> +
> +void BBBIO_ehrPWM_Enable(unsigned int PWMSS_ID)
> +{
> +       volatile unsigned short *reg16 ;
> +
> +       reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLA;
> +       *reg16 = 0x2 | ( 0x3 << 4) ;
> +
> +       reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLB;
> +       *reg16 = 0x2 | ( 0x3 << 8) ;
> +
> +       reg16 = (void *)epwm_ptr[PWMSS_ID] + EPWM_TBCNT;
> +       *reg16 = 0;
> +
> +        reg16=(void *)epwm_ptr[PWMSS_ID] + EPWM_TBCTL;
> +       *reg16 &= ~0x3;
> +}
> +
> +void BBBIO_ehrPWM_Disable(unsigned int PWMSS_ID)
> +{
> +       volatile unsigned short *reg16 ;
> +        reg16=(void *)epwm_ptr[PWMSS_ID] + EPWM_TBCTL;
> +        *reg16 |= 0x3;
> +
> +       reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLA;
> +       *reg16 = 0x1 | ( 0x3 << 4) ;
> +
> +       reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLB;
> +       *reg16 = 0x1 | ( 0x3 << 8) ;
> +
> +       reg16 = (void *)epwm_ptr[PWMSS_ID] + EPWM_TBCNT;
> +       *reg16 = 0;
> +}
> +//--------------------------------------------------------
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> diff --git a/c/src/lib/libcpu/arm/shared/include/am335x.h b/c/src/lib/libcpu/arm/shared/include/am335x.h
> index 2009cef..2ba5a98 100644
> --- a/c/src/lib/libcpu/arm/shared/include/am335x.h
> +++ b/c/src/lib/libcpu/arm/shared/include/am335x.h
> @@ -467,4 +467,13 @@
>  #define AM335X_CONF_EXT_WAKEUP 0xA00
>  #define AM335X_CONF_RTC_KALDO_ENN 0xA04
>  #define AM335X_CONF_USB0_DRVVBUS 0xA1C
> -#define AM335X_CONF_USB1_DRVVBUS 0xA34
> \ No newline at end of file
> +#define AM335X_CONF_USB1_DRVVBUS 0xA34
> +
> +/* Registers for PWM Subsystem */
> +#define BBBIO_PWMSS_CTRL               (0x664)
> +#define BBBIO_CM_PER_EPWMSS0_CLKCTRL    (0xD4)
> +#define BBBIO_CM_PER_EPWMSS1_CLKCTRL    (0xCC)
> +#define BBBIO_CM_PER_EPWMSS2_CLKCTRL    (0xD8)
> +#define BBBIO_CONTROL_MODULE           (0x44e10000)
> +#define BBBIO_CM_PER_ADDR              (0x44e00000)
> +#define PWMSS_CLKSTATUS                        (0xC)
> --
> 2.7.1
>



More information about the devel mailing list