cancel
Showing results for 
Search instead for 
Did you mean: 

Question about LL CRS initialization generated by MX (USB L4+ or G4)

Nikita91
Lead II

Cube MX generate the following code:

LL_CRS_SetSyncDivider(LL_CRS_SYNC_DIV_1);
LL_CRS_SetSyncPolarity(LL_CRS_SYNC_POLARITY_RISING);
LL_CRS_SetSyncSignalSource(LL_CRS_SYNC_SOURCE_USB);
LL_CRS_SetReloadCounter(__LL_CRS_CALC_CALCULATE_RELOADVALUE(48000000,1000));
LL_CRS_SetFreqErrorLimit(34);
LL_CRS_SetHSI48SmoothTrimming(64);

In this code the CRS clock is not initialized and the CRS is not enabled. I can't find these actions elsewhere in the code.

If HAL is used, the CRS clock is started and the CRS is enabled

So I use this code

LL_APB1_GRP1_EnableClock (LL_APB1_GRP1_PERIPH_CRS) ;
 
LL_CRS_SetSyncDivider(LL_CRS_SYNC_DIV_1);
LL_CRS_SetSyncPolarity(LL_CRS_SYNC_POLARITY_RISING);
LL_CRS_SetSyncSignalSource(LL_CRS_SYNC_SOURCE_USB);
LL_CRS_SetReloadCounter(__LL_CRS_CALC_CALCULATE_RELOADVALUE(48000000,1000));
LL_CRS_SetFreqErrorLimit(34);
LL_CRS_SetHSI48SmoothTrimming(64);
 
LL_CRS_EnableAutoTrimming () ;
LL_CRS_EnableFreqErrorCounter () ;

Is this what CubeMX should generate?

Tested with G431 and L4R5

3 REPLIES 3
Piranha
Chief II

That bloatware initializes things that doesn't need it, because those are the default values anyway, and takes 30+ instructions. And here is a normal code with 3 instructions:

CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN;

Or even better... 2 instructions:

CRS->CR = _VAL2FLD(CRS_CR_TRIM, 64) | CRS_CR_AUTOTRIMEN | CRS_CR_CEN;

In what alternate reality is a CubeMX generated code and endless fighting with it's stupidities better, faster or easier in any way than just writing a simple single line of code?

Nikita91
Lead II

@Piranha​ This is not the code I am using but the one generated by MX. My code is much more compact.

In this MX generated code it seems to me that essential settings are missing, and therefore that the CRS does not work. I added LL statements only to be consistent with the generated code.

I did not know _VAL2FLD and I thank you for this elegant trick👍

I hope you saw the _FLD2VAL() also. In addition I can share some related macros from my own collection:

#define REG_MOD_FIELD(rReg, xFld, xVal)    ( (rReg) = ((uint32_t)(rReg) & ~xFld##_Msk) | (((uint32_t)(xVal) << xFld##_Pos) & xFld##_Msk) )
 
#define REG_MOD_BITS(rReg, fClr, fSet, iPos)    ( (rReg) = ((uint32_t)(rReg) & ~((uint32_t)(fClr) << (iPos))) | ((uint32_t)(fSet) << (iPos)) )