From 6dc5c03fad3ddd51423d21b5d60d24b62bb653e9 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Mon, 4 Jul 2016 15:02:05 -0300 Subject: Beaglebone: Add original BBBIO PWM driver This patch adds the PWM driver code for the Beaglebone Black from BBBIO: https://github.com/VegetableAvenger/BBBIOlib/blob/master/BBBio_lib/BBBiolib_PWMSS.c This commit is for tracking purposes only; the next commit will adapt the code for RTEMS. --- c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h | 41 +++ c/src/lib/libbsp/arm/beagle/pwm/pwm.c | 407 ++++++++++++++++++++++++++ 2 files changed, 448 insertions(+) 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 (limited to 'c/src/lib/libbsp/arm/beagle') 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 0000000000..761eae2b37 --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/include/bbb-pwm.h @@ -0,0 +1,41 @@ +#ifndef LIBBSP_ARM_BEAGLE_BBB_PWM_H +#define LIBBSP_ARM_BEAGLE_BBB_PWM_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief BeagleBone Black PWM Macros. + */ +#define BBBIO_PWMSS_COUNT 3 +#define BBBIO_PWMSS0 0 +#define BBBIO_PWMSS1 1 +#define BBBIO_PWMSS2 2 + +#define MUXMODE0 0 +#define MUXMODE1 1 +#define MUXMODE2 2 +#define MUXMODE3 3 +#define MUXMODE4 4 +#define MUXMODE5 5 +#define MUXMODE6 6 +#define MUXMODE7 7 + +#define EPWM_GROUP1 1 +#define EPWM_GROUP2 2 +#define EPWM_GROUP0 0 + +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 0000000000..7586a82381 --- /dev/null +++ b/c/src/lib/libbsp/arm/beagle/pwm/pwm.c @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include +#include +#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; +} +//-------------------------------------------------------- + + + + + + + + + + + + -- cgit v1.2.3