This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Beagle Bone Black, PRU not able to initialize PWMSS0 or PWMSS1.

PRU 1 is not able to get ehrpwm module(s) to initialize or function.

I followed the USE CASE 15.28 on page 2261 of TRM (spruh731.pdf). The initialization procedure in Table 15-20 on page 2262.

Here is the Initialization code:


    PWMSS0.EPWM_TBPRD = 600;
    PWMSS0.EPWM_TBPHS = 0;
    PWMSS0.EPWM_TBCNT = 0;
    PWMSS0.EPWM_TBCTL = 0x30;
    PWMSS0.EPWM_CMPA = 350;
    PWMSS0.EPWM_CMPB = 200;
    PWMSS0.EPWM_CMPCTL = 0x0;
    PWMSS0.EPWM_AQCTLA = 0x12;
    PWMSS0.EPWM_AQCTLB = 0x102;

    PWMSS1.EPWM_TBPRD = 600;
    PWMSS1.EPWM_TBPHS = 0;
    PWMSS1.EPWM_TBCNT = 0;
    PWMSS1.EPWM_TBCTL = 0x30;
    PWMSS1.EPWM_CMPA = 350;
    PWMSS1.EPWM_CMPB = 200;
    PWMSS1.EPWM_CMPCTL = 0x0;
    PWMSS1.EPWM_AQCTLA = 0x12;
    PWMSS1.EPWM_AQCTLB = 0x102;

Here is my Device Tree:

        pinctrl-single,pins = <
            0x1a0 (PIN_INPUT_PULLDOWN | MUX_MODE1)      // eQEP0A       P9-42  
            0x1a4 (PIN_INPUT_PULLDOWN | MUX_MODE1)      // eQEP0B       P9-27  
            0x1a8 (PIN_INPUT_PULLDOWN | MUX_MODE1)      // eQEP0index   P9-41  
            0x1ac (PIN_INPUT_PULLDOWN | MUX_MODE1)      // eQEP0Strobe  P9-25   
            0x048 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)     // ehrpwm1A     P9-14 PWM        
//
            0x0d0 (PIN_INPUT_PULLDOWN | MUX_MODE2)      // eQEP1A       P8-35
            0x0d4 (PIN_INPUT_PULLDOWN | MUX_MODE2)      // eQEP1B       P8-33 
            0x0d8 (PIN_INPUT_PULLDOWN | MUX_MODE2)      // eQEP1index   P8-31 
            0x0dC (PIN_INPUT_PULLDOWN | MUX_MODE2)      // eQEP1Strobe  P8-32 
            0x04c (PIN_OUTPUT_PULLDOWN | MUX_MODE6)     // ehrpwm1B     P9-16  PWM
//            
            0x030 (PIN_INPUT_PULLDOWN | MUX_MODE4)      // eQEP2A         P8-12  
            0x034 (PIN_INPUT_PULLDOWN | MUX_MODE4)      // eQEP2B         P8-11 
            0x038 (PIN_INPUT_PULLDOWN | MUX_MODE4)      // eQEP2index     P8-16 
            0x03c (PIN_INPUT_PULLDOWN | MUX_MODE4)      // eQEP2Strobe    P8-15 
            0x154 (PIN_INPUT_PULLDOWN | MUX_MODE3)      // ehrpwm0B       P9-21 PWM
/

Whats missing?

Regards,

Mike

  • Not LINUX, I need to use the PRU to control the eQEP perpherals

    check this link:     http://processors.wiki.ti.com/index.php/PRU_Training:_PRU_PID_Motor_Demo

    Need to use the PRU's in a five motor PID loop control. The above referenced demo initializes and  uses the eQEP, I need to access the ehrpwm modules in the eQEP.

    Here is  my complete eQEP & ehrpwm initialization:


        // allow external memory reads
        CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

        /* ***************************************************************
         * eQEP0
         */
        while (!(CM_PER_EPWMSS0 & 0x2)) {
            CM_PER_EPWMSS0 |= 0x2;
        }

        PWMSS0.EQEP_QDECCTL = 0x00;

        /* Enable unit timer
         * Enable capture latch on unit time out
         * Enable quadrature position counter
         * Enable software loading of position counter
         * Reset position counter on unit time event to gauge RPM
         */
        PWMSS0.EQEP_QEPCTL = 0x308E;

        /* Set prescalers for EQEP Capture timer and UPEVNT */
        /* Note: EQEP Capture unit must be disabled before changing prescalar */
        PWMSS0.EQEP_QCAPCTL = 0x0073;

        /* Enable EQEP Capture */
        PWMSS0.EQEP_QCAPCTL |= 0x8000;

        /* Enable unit time out interupt */
        PWMSS0.EQEP_QEINT |= 0x0800;

        /* Clear encoder count */
        PWMSS0.EQEP_QPOSCNT_bit.QPOSCNT = 0x00000000;

        /* Set max encoder count */
        PWMSS0.EQEP_QPOSMAX_bit.QPOSMAX = UINT_MAX;

        /* Clear timer */
        PWMSS0.EQEP_QUTMR_bit.QUTMR = 0x00000000;

        /* Set unit timer period count */
        /*  QUPRD = Period * 100MHz */
        PWMSS0.EQEP_QUPRD_bit.QUPRD = 0x007FFFFF; // (~1/12s) @ 100MHz

        /* Clear all interrupt bits */
        PWMSS0.EQEP_QCLR = 0xFFFF;

        // from AM335x Sitara Processors, TRF Table 15-20 pg. 2262
        // initialization for Figure 15-28 pg. 2261
        PWMSS0.EPWM_TBPRD = 600;    //Period = 601 TBCLK counts
        PWMSS0.EPWM_TBPHS = 0;        //Clear Phase Register to 0
        PWMSS0.EPWM_TBCNT = 0;        //Clear TB counter
        PWMSS0.EPWM_TBCTL = 0x30;    // Phase loading disabled, TBCLK = SYSCLK
        PWMSS0.EPWM_CMPA = 350;        // Compare A = 350 TBCLK counts
        PWMSS0.EPWM_CMPB = 200;        // Compare B = 200 TBCLK counts
        PWMSS0.EPWM_CMPCTL = 0x0;    // Load A on CTR = 0, Load B on CTR = 0
        PWMSS0.EPWM_AQCTLA = 0x12;
        PWMSS0.EPWM_AQCTLB = 0x102;

        /* ****************************************************************
         * eQEP1
         */
        while (!(CM_PER_EPWMSS1 & 0x2)) {
            CM_PER_EPWMSS1 |= 0x2;
        }

        PWMSS1.EQEP_QDECCTL = 0x00;

        /* Enable unit timer
         * Enable capture latch on unit time out
         * Enable quadrature position counter
         * Enable software loading of position counter
         * Reset position counter on unit time event to gauge RPM
         */
        PWMSS1.EQEP_QEPCTL = 0x308E;

        // Set prescalers for EQEP Capture timer and UPEVNT
        // Note: EQEP Capture unit must be disabled before changing prescalar
        PWMSS1.EQEP_QCAPCTL = 0x0073;

        // Enable EQEP Capture
        PWMSS1.EQEP_QCAPCTL |= 0x8000;

        // Enable unit time out interupt
        PWMSS1.EQEP_QEINT |= 0x0800;

        // Clear encoder count
        PWMSS1.EQEP_QPOSCNT_bit.QPOSCNT = 0x00000000;

        // Set max encoder count
        PWMSS1.EQEP_QPOSMAX_bit.QPOSMAX = UINT_MAX;

        // Clear timer
        PWMSS1.EQEP_QUTMR_bit.QUTMR = 0x00000000;

        // Set unit timer period count
        //  QUPRD = Period * 100MHz
        PWMSS1.EQEP_QUPRD_bit.QUPRD = 0x007FFFFF; // (~1/12s) @ 100MHz

        // Clear all interrupt bits
        PWMSS1.EQEP_QCLR = 0xFFFF;

        PWMSS1.EPWM_TBPRD = 600;
        PWMSS1.EPWM_TBPHS = 0;
        PWMSS1.EPWM_TBCNT = 0;
        PWMSS1.EPWM_TBCTL = 0x30;
        PWMSS1.EPWM_CMPA = 350;
        PWMSS1.EPWM_CMPB = 200;
        PWMSS1.EPWM_CMPCTL = 0x0;
        PWMSS1.EPWM_AQCTLA = 0x12;
        PWMSS1.EPWM_AQCTLB = 0x102;


        /*
         * eQEP2
         */
        while (!(CM_PER_EPWMSS1 & 0x2)) {
            CM_PER_EPWMSS2 |= 0x2;
        }

        PWMSS2.EQEP_QDECCTL = 0x00;

        /* Enable unit timer
         * Enable capture latch on unit time out
         * Enable quadrature position counter
         * Enable software loading of position counter
         * Reset position counter on unit time event to gauge RPM
         */
        PWMSS2.EQEP_QEPCTL = 0x308E;

        // Set prescalers for EQEP Capture timer and UPEVNT
        // Note: EQEP Capture unit must be disabled before changing prescalar
        PWMSS2.EQEP_QCAPCTL = 0x0073;

        // Enable EQEP Capture
        PWMSS2.EQEP_QCAPCTL |= 0x8000;

        // Enable unit time out interupt
        PWMSS2.EQEP_QEINT |= 0x0800;

        // Clear encoder count
        PWMSS2.EQEP_QPOSCNT_bit.QPOSCNT = 0x00000000;

        // Set max encoder count
        PWMSS2.EQEP_QPOSMAX_bit.QPOSMAX = UINT_MAX;

        // Clear timer
        PWMSS2.EQEP_QUTMR_bit.QUTMR = 0x00000000;

        // Set unit timer period count
        //  QUPRD = Period * 100MHz
        PWMSS2.EQEP_QUPRD_bit.QUPRD = 0x007FFFFF; // (~1/12s) @ 100MHz

        // Clear all interrupt bits
        PWMSS2.EQEP_QCLR = 0xFFFF;

    // not in use ,
    //    PWMSS2.EPWM_TBPRD = 600;
    //    PWMSS2.EPWM_TBPHS = 0;
    //    PWMSS2.EPWM_TBCNT = 0;
    //    PWMSS2.EPWM_TBCTL = 0x30;
    //    PWMSS2.EPWM_CMPA = 350;
    //    PWMSS2.EPWM_CMPB = 200;
    //    PWMSS2.EPWM_CMPCTL = 0x0;
    //    PWMSS2.EPWM_AQCTLA = 0x12;
    //    PWMSS2.EPWM_AQCTLB = 0x102;
    //

    Please read TRM pg 2261 & 2262

    Regards,

    Mike

  • Michael Brainerd said:
        while (!(CM_PER_EPWMSS0 & 0x2)) {
            CM_PER_EPWMSS0 |= 0x2;
        }

    You should simply write

    CM_PER_EPWMSS0 = 2;

    Everything except the lowest two bits are read-only, so there's no need for a read-modify-write.  Also, the proper field to poll is the IDLEST field (bits 17:16).

    Michael Brainerd said:

        /*
         * eQEP2
    Here is  my complete eQEP & ehrpwm initialization:


         */
        while (!(CM_PER_EPWMSS1 & 0x2)) {
            CM_PER_EPWMSS2 |= 0x2;
        }[/quote]

    Looks like you have a copy/paste error here.  You have a mix of PWMSS1 and PWMSS2.

    What do you see when you look at the PWM registers?  Are the values you programmed there as expected?  Do timers appear to be running?  Do you get interrupts (if expected)?

  • This code is from your DEMO.

    while (!(CM_PER_EPWMSS0 & 0x2)) {
    CM_PER_EPWMSS0 |= 0x2;
    }

    PLEASE LOOK AT THIS DEMO OF YOURS....
    processors.wiki.ti.com/.../PRU_Training:_PRU_PID_Motor_Demo

    This is my base application, except instead of PRU eCAP pwm generation I need to use the PWMSS ehrpwm modules.

    This I fixed, still no PWM.

    while (!(CM_PER_EPWMSS1 & 0x2)) {
    CM_PER_EPWMSS2 |= 0x2;
    }

    I have put togather a test app using PWMSS1 running on JTAG debugger.

    Here is the source:

    void initEqepPWM(void)
    {

    // allow external memory reads
    CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

    share_buff.enc_rpm[1] = 0;

    /* ****************************************************************
    * eQEP1
    */
    CM_PER_EPWMSS1 = 2;

    PWMSS1.EQEP_QDECCTL = 0x00;

    /* Enable unit timer
    * Enable capture latch on unit time out
    * Enable quadrature position counter
    * Enable software loading of position counter
    * Reset position counter on unit time event to gauge RPM
    */
    PWMSS1.EQEP_QEPCTL = 0x308E;

    // Set prescalers for EQEP Capture timer and UPEVNT
    // Note: EQEP Capture unit must be disabled before changing prescalar
    PWMSS1.EQEP_QCAPCTL = 0x0073;

    // Enable EQEP Capture
    PWMSS1.EQEP_QCAPCTL |= 0x8000;

    // Enable unit time out interupt
    PWMSS1.EQEP_QEINT |= 0x0800;

    // Clear encoder count
    PWMSS1.EQEP_QPOSCNT_bit.QPOSCNT = 0x00000000;

    // Set max encoder count
    PWMSS1.EQEP_QPOSMAX_bit.QPOSMAX = UINT_MAX;

    // Clear timer
    PWMSS1.EQEP_QUTMR_bit.QUTMR = 0x00000000;

    // Set unit timer period count
    // QUPRD = Period * 100MHz
    PWMSS1.EQEP_QUPRD_bit.QUPRD = 0x007FFFFF; // (~1/12s) @ 100MHz

    // Clear all interrupt bits
    PWMSS1.EQEP_QCLR = 0xFFFF;

    share_buff.pwm_out[AZIMUTH] = DUTY_CYCLE_2;
    share_buff.pwm_out[ELEVATION] = DUTY_CYCLE_2;

    PWMSS1.EPWM_TBPRD = PERIOD_CYCLES;
    PWMSS1.EPWM_TBPHS = 0;
    PWMSS1.EPWM_TBCNT = 0;
    PWMSS1.EPWM_TBCTL = 0x30;
    PWMSS1.EPWM_CMPA = share_buff.pwm_out[AZIMUTH];
    PWMSS1.EPWM_CMPB = share_buff.pwm_out[ELEVATION]; // elevation
    PWMSS1.EPWM_CMPCTL = 0x0;
    PWMSS1.EPWM_AQCTLA = 0x12;
    PWMSS1.EPWM_AQCTLB = 0x102;

    uint32_t temp[10];

    temp[0] = PWMSS1.EPWM_TBPRD;
    temp[1] = PWMSS1.EPWM_TBPHS;
    temp[2] = PWMSS1.EPWM_TBCNT;
    temp[3] = PWMSS1.EPWM_TBCTL;
    temp[4] = PWMSS1.EPWM_CMPA;
    temp[5] = PWMSS1.EPWM_CMPB;
    temp[6] = PWMSS1.EPWM_CMPCTL;
    temp[7] = PWMSS1.EPWM_AQCTLA;
    temp[8] = PWMSS1.EPWM_AQCTLB;

    // this indicates that the registers are set properly according to the TRM.

    for ( ;; ) {

    __delay_cycles(150);

    // just a trap to look at signals with oscilloscope
    if (PWMSS1.EQEP_QPOSCNT_bit.QPOSCNT > 15) {
    temp[9] = PWMSS1.EQEP_QPOSCNT_bit.QPOSCNT;
    __delay_cycles(10);
    }

    }
    }

    Here is my GEL file for this test.

    //---------------------------------
    // Gel file for AM335x BBB PRU CAPE
    // rev 1.1


    menuitem "PRU_CAPE"

    /* AM335x specific mux bit defines */

    #define AM335X_SLEWCTRL_FAST (0 << 6)
    #define AM335X_SLEWCTRL_SLOW (1 << 6)
    #define AM335X_INPUT_EN (1 << 5)
    #define AM335X_PULL_UP (1 << 4)
    /* bit 3: 0 - enable, 1 - disable for pull enable */
    #define AM335X_PULL_DISA (1 << 3)

    #define AM335X_PIN_OUTPUT (0)
    #define AM335X_PIN_OUTPUT_PULLUP (AM335X_PULL_UP)
    #define AM335X_PIN_INPUT (AM335X_INPUT_EN | AM335X_PULL_DISA)
    #define AM335X_PIN_INPUT_PULLUP (AM335X_INPUT_EN | AM335X_PULL_UP)
    #define AM335X_PIN_INPUT_PULLDOWN (AM335X_INPUT_EN)

    hotmenu PRU_Cape_Init()
    {
    PRU_PINMUX_Config();
    PRU_PRCM_Enable();
    PRU_ICSS_Reset();
    }

    hotmenu PRU_PINMUX_Config()
    {

    GEL_TextOut("****** PRU Cape PINMUX is being configured ***** \n","Output",1,1,1);


    //**********************************************************
    // 8 bit latch
    //**********************************************************

    *((unsigned int*) 0x44e108a0) = AM335X_PIN_OUTPUT | 5; //adr0
    *((unsigned int*) 0x44e108a4) = AM335X_PIN_OUTPUT | 5; //adr1
    *((unsigned int*) 0x44e108a8) = AM335X_PIN_OUTPUT | 5; //adr2
    *((unsigned int*) 0x44e108ac) = AM335X_PIN_OUTPUT | 5; //data 0
    *((unsigned int*) 0x44e108b0) = AM335X_PIN_OUTPUT | 5; //data 1
    *((unsigned int*) 0x44e108b4) = AM335X_PIN_OUTPUT | 5; //data 2
    *((unsigned int*) 0x44e108b8) = AM335X_PIN_OUTPUT | 5; //data 3
    *((unsigned int*) 0x44e108bc) = AM335X_PIN_OUTPUT | 5; //enable
    *((unsigned int*) 0x44e108e0) = AM335X_PIN_OUTPUT | 5; //reset

    *((unsigned int*) 0x44e108d0) = AM335X_PIN_INPUT | 2; // eQEP1A
    *((unsigned int*) 0x44e108d4) = AM335X_PIN_INPUT | 2; // eQEP1B
    *((unsigned int*) 0x44e108d8) = AM335X_PIN_INPUT | 2; // eQEP1-index
    *((unsigned int*) 0x44e108dc) = AM335X_PIN_INPUT | 2; // eQEP1-Strobe

    *((unsigned int*) 0x44e1084c) = AM335X_PIN_OUTPUT | 6; // ehrpwm1B


    }


    hotmenu PRU_PRCM_Enable()
    {

    GEL_TextOut("\t****** Enabling PRU-ICSS clock ****** \n","Output",1,1,1);

    *((unsigned int*) 0x44E000E8 ) |= 0x02; // enabling the pru-icss module taking it out of idle

    //CSS_Reset();

    }

    hotmenu PRU_ICSS_Reset()
    {

    GEL_TextOut("*\t***** Reseting the PRU-ICSS ******\n","Output",1,1,1);

    *((unsigned int*) 0x44E00C00 ) |= 0x2;
    *((unsigned int*) 0x44E00C00 ) &= 0xFFFFFFFD;

    }

    hotmenu PRU0_Pause()
    {
    GEL_TextOut("*\t***** Halting PRU 0 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a322000) = 0x0;

    }

    hotmenu PRU1_Pause()
    {
    GEL_TextOut("*\t***** Halting PRU 1 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a324000) = 0x0;

    }

    hotmenu PRU0_1_Pause()
    {
    GEL_TextOut("*\t***** Halting PRU 0 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a322000) = 0x0;

    GEL_TextOut("*\t***** Halting PRU 1 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a324000) = 0x0;

    }

    hotmenu PRU0_Start()
    {
    GEL_TextOut("*\t***** Starting PRU 0 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a322000) = 0x2;

    }

    hotmenu PRU1_Start()
    {
    GEL_TextOut("*\t***** Starting PRU 1 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a324000) = 0x2;

    }

    hotmenu PRU0_1_Start()
    {
    GEL_TextOut("*\t***** Starting PRU 0 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a322000) = 0x2;

    GEL_TextOut("*\t***** Starting PRU 1 ******\n","Output",1,1,1);
    *((unsigned int*) 0x4a324000) = 0x2;

    }

    hotmenu ENABLE_ECAP_LOOP()
    {

    //**********************************************************
    // PRU input
    //**********************************************************

    // J4 pin 2 = pr1_pru0_gpi15 (GPMC_AD15 - mode 6)
    *((unsigned int*) 0x44e1083C) = AM335X_PIN_INPUT | 6; //mode 6

    //**********************************************************
    // ECAP_PWM output
    //**********************************************************

    // J4 pin 1 = pr1_ecap0_in_pwm0_out (ECAP0_IN_PWM0_OUT - mode 3)
    *((unsigned int*) 0x44e10964) = AM335X_PIN_INPUT | 3; //mode 7
    }

    According to the TRM this should all work.

    Any Ideas?

    Regards,
    MIke