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.

AM3358: Unable to write PWM registers

Part Number: AM3358
Other Parts Discussed in Thread: SYSCONFIG,

Hello,

I have been unable to write the TBPRD and CMPA registers for PWM1. The following statements are true:

The PBPRD register is fixed at 0x0 and cannot be written.

The TBCNT register is verified rd/wr and is also verified to count-up as configured when initialized with a non-zero value i.e. 0x1 for instance.

The TBCNT register will count-up to 0xFFFF then roll over to 0x0 and stop there.

Register CMPB is verified rd/wr.

The SHDWBFULL bit accurately reflects a write to CMPB.

Register CMPA is verified NOT writable.

The SHDWAFULL bit does not reflect a write to CMPA.

Below is a debug listing of the relevant running code, with the relevant register contents.

    -> **** IMU_10DOF::fire TBCNT = f501h
    -> **** IMU_10DOF::fire TBPRD =    0h
    -> **** IMU_10DOF::fire TBCTL = d030h
    -> **** IMU_10DOF::fire CMPCTL =  200h
    -> **** IMU_10DOF::fire CM_PER_EPWMSS0_CLKCTRL 2
    -> **** IMU_10DOF::fire CM_PER_EPWMSS1_CLKCTRL 2
    -> **** IMU_10DOF::fire CM_PER_EPWMSS2_CLKCTRL 2
    -> **** IMU_10DOF::fire PWMSS_IDVER     47400001h
    -> **** IMU_10DOF::fire PWMSS_SYSCONFIG        ch
    -> **** IMU_10DOF::fire PWMSS_CLKCONFIG      111h
    -> **** IMU_10DOF::fire PWMSS_CLKSTATUS      111h
    -> **** IMU_10DOF::fire setting TBPRD reg to 7800h
    -> **** IMU_10DOF::fire TBPRD = 0h
    -> **** IMU_10DOF::fire setting TBCNT reg to 1h
    -> **** IMU_10DOF::fire TBCNT =    3h
    -> **** IMU_10DOF::fire spinning for 400 1GHz clocks
    -> **** IMU_10DOF::fire TBCNT = 2b
    -> **** IMU_10DOF::fire TBCTL = d030
    -> **** IMU_10DOF::fire TBPRD = 0h
    -> **** IMU_10DOF::epwm_wr_cmp writing CMPA (servo_data[7]) = 19bh
    -> **** IMU_10DOF::epwm_wr_cmp writing CMPB (servo_data[9]) = 174h
    -> **** IMU_10DOF::epwm_wr_cmp CMPA = 0h
    -> **** IMU_10DOF::epwm_wr_cmp CMPB = 174h
    -> **** IMU_10DOF::epwm_wr_cmp writing CMPA = 1234h
    -> **** IMU_10DOF::epwm_wr_cmp CMPA = 0h
    -> **** IMU_10DOF::fire CMPCTL =  200h
    -> **** IMU_10DOF::fire verifying TBCNT is counting up
    -> **** IMU_10DOF::fire TBCNT = e6
    -> **** IMU_10DOF::fire TBCNT = ef
    -> **** IMU_10DOF::fire TBCNT = f8
    -> **** IMU_10DOF::fire TBCNT = 101
    -> **** IMU_10DOF::fire TBCNT = 10a
    -> **** IMU_10DOF::fire TBCNT = 114
    -> **** IMU_10DOF::fire TBCNT = 11d
    -> **** IMU_10DOF::fire TBCNT = 126
    -> **** IMU_10DOF::fire TBCNT = 12f
    -> **** IMU_10DOF::fire TBCNT = 138
    -> **** IMU_10DOF::fire TBCNT = 141


  • Hi,

    What software is this?
  • Custom user space application on Linux-Xenomai. I have developed several custom peripheral interfaces, including simple GPIO, I2C via PRU's and ARM-PRU communications via RAM, functional for over a year now. Recently I desired to implement on chip PWM functionality. I have quite a substantial comprehension of the AM3358 internals, but am afraid that the current functionality has stumped me. I expect that there is usually something quite small that I have missed, but I can't explain the discrepancy in writing some but not all the PWMSS registers, in particular TBPRD and CMPA. Perhaps there are other discrepancies but I have not made the time to W/R the entire reg file.

  • In the TBPRD register field descriptions I see:

    "Shadowing of this register is enabled and disabled by the TBCTL[PRDLD] bit. By default this register is shadowed.
    (a) If TBCTL[PRDLD] = 0, then the shadow is enabled and any write or read will automatically go to the shadow register. In this case, the active register will be loaded from the shadow register when the time-base counter equals zero.
    (b) If TBCTL[PRDLD] = 1, then the shadow is disabled and any write or read will go directly to the active register, that is the register actively controlling the hardware.
    (c) The active and shadow registers share the same memory map address."

    Same for CMPA register:

    "By default this register is shadowed.
    (a) If CMPCTL[SHDWAMODE] = 0, then the shadow is enabled and any write or read will automatically go to the shadow register. In this case, the CMPCTL[LOADAMODE] bit field determines which event will load the active register from the shadow register.
    (b) Before a write, the CMPCTL[SHDWAFULL] bit can be read to determine if the shadow register is currently full.
    (c) If CMPCTL[SHDWAMODE] = 1, then the shadow register is disabled and any write or read will go directly to the active register, that is the register actively controlling the hardware.
    (d) In either mode, the active and shadow registers share the same memory map address."
  • Biser,

    Thank you for your response, however I have been well aware of the above restated requirements after having read and re-read the TRM several tens of times. Attention to such requirements do not appear to have any bearing on the current, apparently inexplicable hardware behaviour. The debug fragments below indicate the erroneous behavior of CMPA and TBPRD regs. I have verified that neither of these registers permit ever being written regardless of their SHADOW mode.

        -> **** IMU_10DOF::fire CMPCTL =    0h
        -> **** IMU_10DOF::fire writing servo_data to PWM1 Ch A/B
        -> **** IMU_10DOF::epwm_wr_cmp writing CMPA (servo_data[7]) = 1a3h
        -> **** IMU_10DOF::epwm_wr_cmp writing CMPB (servo_data[9]) = 169h
        -> **** IMU_10DOF::fire SHDWxFULL bits 8,9 should be 1's, i.e. CMPCTL = 030xh

        Notice how the SHDWAFULL bit is NOT updated in the CMPCTL register. This is yet another symptom.


        -> **** IMU_10DOF::fire CMPCTL =  200h
        -> **** IMU_10DOF::epwm_wr_cmp CMPA = 0h
        -> **** IMU_10DOF::epwm_wr_cmp CMPB = 169h
        -> **** IMU_10DOF::epwm_wr_cmp writing CMPA = 1234h
        -> **** IMU_10DOF::epwm_wr_cmp CMPA = 0h
        -> **** IMU_10DOF::fire CMPCTL =  200h

        -> **** IMU_10DOF::fire setting TBPRD reg to 7fffh
        -> **** IMU_10DOF::fire TBPRD = 0h

    Also, I have reviewed the following threads in meticulous detail:

    https://e2e.ti.com/support/arm/sitara_arm/f/791/t/294909#pi316653=2

    As per in the above thread, I have also looked at the CONTROL_MODULE pwmss_ctrl register which reads 7h, and which is correct.

    https://e2e.ti.com/support/embedded/starterware/f/790/t/408065

    https://android.googlesource.com/kernel/lk/+/upstream-master/platform/am335x/ti/drivers/ehrpwm.c

    It now appears with absolutely certainty, that the TBPRD and CMPA registers are exhibiting erroneous behaviour.

    QUESTION:

    Is there any errata posted for PWMSS_IDVER = 47400001h ???

  • Is anyone at TI tracking this or am I the owner of a solitary voice in an ephemeral void, perpetually on the event horizon of a massive object invisible to all?

  • I recently ran into a problem using PWM1. I am not working with LINUX, so I'm not sure if this could be the same root-cause for you, but is PWM1 configured and enabled? In the Sys/Bios environment provided for the chip, PWM1 was not configured: only 0 and 2. I had to modify my code to complete the chip setup not done by the TI driver/example code. This addressed my problem.

    Are you able to view the PWM1 registers via the register or memory viewer, or does the data all show up as "??????"

    - Tim
  • Timothy,
    The Linux-Xenomai user space environment, as I am using it currently, is functionally equivalent to bare bones register level. I rd/wr the AM3358 registers directly and do not depend upon any pre-existing Linux device drivers whatsoever. As far as I have determined, the TBPRD and CMPA registers are not writable. After writing them, their contents are read as 0, always. Also the CMPA register SHDWAFULL bit is NOT updated in the CMPCTL register after writing CMPA. Writing CMPB register however does appears to reflect correctly in the HDWBFULL bit of the CMPCTL register.

    I am currently running the same testbench on PWM2 and as of now the results are identical as for PWM1.


    By the way, the PWMSS version in my chip is PWMSS_IDVER = 47400001h. What version are you working with?

  • Further verification indicates that register AQCTLA is also NOT writable.
    The verified non-writable registers are currently TBPRD , CMPA and AQCTLA. Well now there unfolds a coincidence!
  • Hi Brendan,

    The PWM registers are 16-bit wide (rather than the standard 32-bit). Make sure that you're only access that size when writing/reading the CMPA and TBPRD registers.

    Regards,
    Melissa
  • On careful review of the code, I have certainly NOT been overwriting 16-bit registers.
    The problem persists.
    The verified non-writable registers are currently TBPRD , CMPA and AQCTLA.
  • Faulty cross domain register clocks perhaps on AM3358 on my Serial# BBG115080120 ?

    What is peculiar to TBPRD , CMPA and AQCTLA ?

  • Hi Brendan,

    Are you able to write to CMPCTL?  I see that you’re accessing this register in the debug listing, but I can’t tell if you’re reading or writing.

    There shouldn’t be anything peculiar to TBPRD, CMPA, and AQCTLA, aside from their offset not falling on the typical 32-bit boundary (i.e. their offsets are Ah, 12h, 16h instead of the typical Ch, 10h, 14h, 18h). The CMPCTL register (Eh offset) falls into this same pattern, which is why I’m curious if you can write to this register.

    Your issue sounds very similar to something I’ve experienced with the eCAP peripheral, which also has 16-bit wide registers. I wasn’t able to write to the ECCTL2 [CAP_APWM], and the root cause was the 16-bit register size.

    Regards,

    Melissa

  • I can rd/wr CMPCTL just fine.

    Let me be clear. I am performing a RMW operation on 16-bit registers thus upper 16-bits of a 32-bit write transaction do NOT overwrite the next higher address reg.

  • Melissa,
    Of the EPWM registers, there are 3 registers NOT requiring a read-modify-write (RMW) transaction. These are TBPRD, TZSEL and PCCTL. The others ALL require, one of the following prototype 32-bit RMW transaction:

    Absolute (non bit-field preserving) data write:
    reg32 = (reg32 & 0xFFFF0000) | data16

    Bit field preserving, bit set:
    reg32 = (reg32 & (0xFFFF0000 | ~data16)) | data16

    With regards to your previous problem with register bit field, bit ECCTL2 [CAP_APWM], I am certain that you have since determined that the above prototype RMW solutions resolve your 16-bit bit field write problem. Indeed, of the ECAP registers, there are 5 that require a RMW transaction. These are of course the following:

    28h ECCTL1
    2Ah ECCTL2
    2Ch ECEINT
    2Eh ECFLG
    30h ECCLR

    The apparently erroneous write behaviour I am describing with the specific EPWM registers TBPRD, CMPA, and AQCTLA, is not the same. Using the RMW transactions outlined above, these registers are NOT writable. A read after write does not reflect the data written. Furthermore a write to any of these registers is not reflected in any change in observable operational functionality of the EPWM module.
  • Brendan,

    Thanks for the extra background. Let me consult with some colleagues and get back with you.

    Also, I didn't previously mention, but yesterday I tried reproducing your issue by manually writing the settings I saw in your debug list to registers in CCS. I was able to successfully write to the TBPRD and CMPA registers.

    Regards,
    Melissa
  • Melissa,
    Although I am sure that the AM3358 in your possession may be operating correctly, what I have been suggesting, is that the device in my possession does NOT appear to be operating according to the specification. I must admit to often making inadvertent and sometimes even foolish coding mistakes. In this particular case, as hard as I have tried to prove both myself and my test bench in error, I simply have been unable to do so.
  • Brendan,

    I’ve discussed this with a colleague, and below are his comments/suggestions:

    First off, TI does not have a background with Linux and Xenomai in terms of support. We will not be able to fully support if there are issues discovered with such a setup. Since we know that both OS’s run simultaneously, have you disabled any conflicts here between Linux and the Xemomai kernel for this peripheral?

    Also, have you tried to accessing the desired registers with a prebuilt TI SDK on TI EVM to make sure the interface works as expected first? After doing that, then moved back to the Linux/Xenomai to continue debug.

    It might also be worth disabling all the CMPB functions in your code.  This would simplify the environment, so you can focus on getting CMPA working.  

    Regards,

    Melissa

  • Melissa,
    Below are the results of yet another approach; a simple (non RMW operation) 32-bit write to reg CMPB (offset 14h). The upper 16-bits of the data is filled with the proposed value to be written to reg AQCTLA (offset 16h).

    -> **** IMU_10DOF::fire performing ((AQCTLA << 0x10) | CMPB) 32-bit write test
    -> **** IMU_10DOF::fire CMPB = 169h
    -> **** IMU_10DOF::fire proposed value of AQCTLA = (AQ_SET << ZRO | AQ_CLEAR << CAD) = 42h
    -> **** IMU_10DOF::fire simple 32-bit writing ((AQCTLA << 0x10) | CMPB) = 00420169h
    -> **** IMU_10DOF::fire CMPB = 169h
    -> **** IMU_10DOF::fire AQCTLA = 0h
    -> **** IMU_10DOF::fire AQCTLA = 04020000h
    -> **** IMU_10DOF::fire CBD = 0
    -> **** IMU_10DOF::fire CBU = 0
    -> **** IMU_10DOF::fire CAD = 0
    -> **** IMU_10DOF::fire CBU = 0
    -> **** IMU_10DOF::fire PRD = 0
    -> **** IMU_10DOF::fire ZRO = 0
    -> **** IMU_10DOF::fire AQCTLB = 00000402h
    -> **** IMU_10DOF::fire CBD = 1
    -> **** IMU_10DOF::fire CBU = 0
    -> **** IMU_10DOF::fire CAD = 0
    -> **** IMU_10DOF::fire CBU = 0
    -> **** IMU_10DOF::fire PRD = 0
    -> **** IMU_10DOF::fire ZRO = 2

    As can be seen from the above, the value in reg CMPB is retained correctly but once again nothing is written to reg AQCTLA.
    Also as my application is running on Linux-Xenomai, the DTS file contains the pinmux associations for pins ehrpwm0A, ehrpwm0B, ehrpwm1A, ehrpwm1B, ehrpwm2A and ehrpwm2B. If I complied the DTB file with incorrect associations I would receive a Kernel Panic. If I attempt to write the pinmux regs from user space I will receive a Segmentation Fault as I assume the pinmux regs address space is locked to ring0 in Kernel space. I have verified that the pinmux associations in the DTB file are indeed correct. As you can see, I have been through the code rather comprehensively and cannot find any flaws. Also I have not yet mentioned that the ehrpwm1A and ehrpwm2A pins are both stuck LOW as per the oscilloscope. The ehrpwm1B and ehrpwm2B pins are however both stuck HIGH. I have not yet tested ehrpwm0 but would not expect any different behaviour.

  • Melissa,
    I do not now, now have I ever owned a TI EVM platform. As per Linux-Xenomai conflicts; I have never witnessed anything like this before. The code I am executing in this particular environment test bench is real simple stuff. I perform a great deal of very sophisticated code on this platform and until now everything works logically and according to the book. I can also tell you that the AM3358 ADC peripheral is not TRM compliant. I was forced to hack that thing but alas it can be coaxed to fulfill its obligations. This EHRPWM peripheral appears flawed in my chip and by extension possibly others as well. You might want to check errata of other reported failures of BBG boards or AM3358's in general. My BBG board's serial# is BBG115080120. I am sure that I cannot possibly be the only person having this problem, or since what can happen will happen, perhaps I am! Who knows.

    I understand that TI can't support every environment. I'm not asking for support, only for individuals who know how to think.

  • Brendan,

    Just for kicks, can you try changing your "reg32" accesses to "reg16"?

    Regards,
    Melissa
  • To: Development community in general.

    Melissa,
    We are all developers striving for a successful outcome. Please find the solution below.

    /*
    * Note: Argument "reg" must be even number
    */
    void IMU_10DOF::wr_16bit(long unsigned int* addr_ptr, int reg, uint16_t data)
    {
    if(reg%4==0) // on even 32-bit word boundry, RMW
    *get_mem(addr_ptr, reg) = (*get_mem(addr_ptr, reg) & 0xFFFF0000) | data;
    else if(reg%2==0) // not on even 32-bit word boundry, but on even 16-bit word boundry
    // use lower 32-bit word boundry, RMW by saving the lower 16-bit reg and rwiting data to upper 16-bits
    *get_mem(addr_ptr, reg-2) = (*get_mem(addr_ptr, reg-2) & 0x0000FFFF) | (data << 0x10);
    }
  • Brendan,

    Thanks for sharing your solution.  Glad the issue is now resolved.

    Regards,

    Melissa

  • Melissa,

                Thank you for your cooperation in this matter.

    Brendan