[PATCH 1/2] Subject: Add original BBBIO PWM driver to BBB BSP
Punit Vara
punitvara at gmail.com
Sun Jun 26 05:25:50 UTC 2016
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 | 41 +++
c/src/lib/libbsp/arm/beagle/pwm/pwm.c | 395 ++++++++++++++++++++++++++
2 files changed, 436 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
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..64eb4c0
--- /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 0000000..5cb3b4c
--- /dev/null
+++ b/c/src/lib/libbsp/arm/beagle/pwm/pwm.c
@@ -0,0 +1,395 @@
+#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;
+}
+//--------------------------------------------------------
--
2.7.1
More information about the devel
mailing list