[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