Tool/software:
Description: The EPWM_tbTimebaseClkCfg
function from epwm.c does not always calculate the optimal combination of hspClkDiv
and lspClkDiv
from the allowed values. This can result in suboptimal performance or incorrect configuration of the EPWM module.
Expected Behavior: The function should select the optimal combination of hspClkDiv
and lspClkDiv
from the allowed values:
hspClkDiv
: 1, 2, 4, 6, 8, 10, 12, 14lspClkDiv
: 1, 2, 4, 8, 16, 32, 64, 128Actual Behavior: The function does not always select the optimal combination, leading to potential issues in the EPWM module configuration.
Example:
moduleClk
= 25,000,000 HztbClk
= 25,000,000 / 128 = 195,312.5 HzclkDiv
= 128Optimal Values:
hspClkDiv
= 1lspClkDiv
= 128Actual Values (according to current behavior):
hspClkDiv
and lspClkDiv
due to the current logic. For example, it could set:
hspClkDiv
= 14 (maximum allowed value)lspClkDiv
= 8 (derived from 128 / 14
)moduleClk/128, as the user expects, but moduleClk/112
Actual clkDiv
:
clkDiv
= 14 * 8 = 112 (which is not equal to the expected clkDiv
of 128)Proposal:
Environment:
Additional Information: The issue seems to arise from the logic used to determine the values of hspClkDiv
and lspClkDiv
. A more robust approach is needed to ensure the optimal combination is always selected.
Hi Angel, thanks for your detailed information and proposed fix. Allow me some time to take a look and discuss it internally.
Paula
Hi Angel, thanks again for your feedback. FYI, I created an internal ticket to follow this up with our developers.
Paula
Hi Paula:
Would the timeframe for this be AM64x MCU+ SDK V11?
We should also inquire thru Nick Saulnier/Bin Liu that the EPWM drivers for the AM64x Linux SDKs be likewise checked and supported for same.
thanks
Jim
Meanwhile, we created an own C++ implementation of the required function. Probably something similar in C is what you would be implmenting:
static constexpr std::array<uint32_t, 8> m_lspVal {1, 2, 4, 8, 16, 32, 64, 128}; static constexpr std::array<uint32_t, 8> m_hspVal {1, 2, 4, 6, 8, 10, 12, 14}; float PwmSourceGroup::setOptimalDividers(uint32_t sourceFreq, uint32_t tbFreq) { int32_t targetDiv = sourceFreq/tbFreq; int8_t bestLsIdx = -1, bestHsIdx = -1; int32_t bestDiff = std::numeric_limits<int>::max(); for (uint8_t lsIdx = 0; lsIdx < m_lspVal.size(); lsIdx++) { for (uint8_t hsIdx = 0; hsIdx < m_hspVal.size(); hsIdx++) { int32_t div = m_lspVal[lsIdx]*m_hspVal[hsIdx]; auto cDiff = std::abs(div - targetDiv); if (cDiff < bestDiff) { bestDiff = cDiff; bestLsIdx = lsIdx; bestHsIdx = hsIdx; } if (cDiff == 0) { //No better diff to achieve break; } } } #define PWMSS_EPWM_OFFSET (0x0U) uint32_t regVal = HW_RD_REG16((m_pwmUnitBaseAddress + PWMSS_EPWM_OFFSET) + PWMSS_EPWM_TBCTL); HW_SET_FIELD32(regVal, PWMSS_EPWM_TBCTL_CLKDIV, bestLsIdx); HW_SET_FIELD32(regVal, PWMSS_EPWM_TBCTL_HSPCLKDIV, bestHsIdx); HW_WR_REG16(((m_pwmUnitBaseAddress + PWMSS_EPWM_OFFSET) + PWMSS_EPWM_TBCTL), (uint16_t)regVal); return ((float)sourceFreq/(m_lspVal[bestLsIdx]*m_hspVal[bestHsIdx])); }
Hi Jim, I will update here when it gets added to MCU+SDK pipeline. To be honest I think EPWM's Linux driver works OK, and it doesn't have the issue mentioned by Angel, at least last time I tested it, scalers seem to be selected ok, and frequencies (even low frequencies) worked as expected. But, please let us know if you face any issues as my tests was a small few-samples frequencies test
thank you,
Paula