#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; } //--------------------------------------------------------