Skip to content

Commit 63f2fe9

Browse files
mstasiaknordickartben
authored andcommitted
soc: nordic: nrf54l: Clean up internal capacitance calculations.
Code responsible for internal capacitor values containted leftover workarounds in the calculations after PS update. Removed redundant conversions and cleaned up both code and comments to align both LFXO and HFXO calculation. Signed-off-by: Michał Stasiak <michal.stasiak@nordicsemi.no>
1 parent e163b2c commit 63f2fe9

File tree

1 file changed

+32
-39
lines changed

1 file changed

+32
-39
lines changed

soc/nordic/nrf54l/soc.c

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include <zephyr/devicetree.h>
1919
#include <zephyr/kernel.h>
20-
#include <zephyr/devicetree.h>
2120
#include <zephyr/init.h>
2221
#include <zephyr/logging/log.h>
2322
#include <zephyr/cache.h>
@@ -50,46 +49,43 @@ static inline void power_and_clock_configuration(void)
5049
*/
5150
#if DT_ENUM_HAS_VALUE(LFXO_NODE, load_capacitors, internal)
5251
uint32_t xosc32ktrim = NRF_FICR->XOSC32KTRIM;
53-
54-
uint32_t offset_k =
55-
(xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk) >> FICR_XOSC32KTRIM_OFFSET_Pos;
56-
52+
/* The SLOPE field is in the two's complement form, hence this special
53+
* handling. Ideally, it would result in just one SBFX instruction for
54+
* extracting the slope value, at least gcc is capable of producing such
55+
* output, but since the compiler apparently tries first to optimize
56+
* additions and subtractions, it generates slightly less than optimal
57+
* code.
58+
*/
5759
uint32_t slope_field_k =
5860
(xosc32ktrim & FICR_XOSC32KTRIM_SLOPE_Msk) >> FICR_XOSC32KTRIM_SLOPE_Pos;
5961
uint32_t slope_mask_k = FICR_XOSC32KTRIM_SLOPE_Msk >> FICR_XOSC32KTRIM_SLOPE_Pos;
6062
uint32_t slope_sign_k = (slope_mask_k - (slope_mask_k >> 1));
6163
int32_t slope_k = (int32_t)(slope_field_k ^ slope_sign_k) - (int32_t)slope_sign_k;
62-
64+
uint32_t offset_k =
65+
(xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk) >> FICR_XOSC32KTRIM_OFFSET_Pos;
6366
/* As specified in the nRF54L15 PS:
6467
* CAPVALUE = round( (2*CAPACITANCE - 12) * (FICR->XOSC32KTRIM.SLOPE + 0.765625 * 2^9)/(2^9)
6568
* + FICR->XOSC32KTRIM.OFFSET/(2^6) );
6669
* where CAPACITANCE is the desired capacitor value in pF, holding any
6770
* value between 4 pF and 18 pF in 0.5 pF steps.
6871
*/
6972

70-
/* Encoding of desired capacitance (single ended) to value required for INTCAP core
71-
* calculation: (CAP_VAL - 4 pF)* 0.5
72-
* That translate to ((CAP_VAL_FEMTO_F - 4000fF) * 2UL) / 1000UL
73-
*
74-
* NOTE: The desired capacitance value is used in encoded from in INTCAP calculation formula
75-
* That is different than in case of HFXO.
76-
*/
77-
uint32_t cap_val_encoded = (((DT_PROP(LFXO_NODE, load_capacitance_femtofarad) - 4000UL)
78-
* 2UL) / 1000UL);
73+
uint32_t lfxo_intcap_femto_f = DT_PROP(LFXO_NODE, load_capacitance_femtofarad);
7974

8075
/* Calculation of INTCAP code before rounding. Min that calculations here are done on
8176
* values multiplied by 2^9, e.g. 0.765625 * 2^9 = 392.
8277
* offset_k should be divided by 2^6, but to add it to value shifted by 2^9 we have to
83-
* multiply it be 2^3.
78+
* multiply it be 2^3. Capacitance value passed to the formula is in femto Farads to
79+
* avoid floating point data type. Hence, offset_k needs to be multiplied by 1000.
8480
*/
85-
uint32_t mid_val = (2UL * cap_val_encoded - 12UL) * (uint32_t)(slope_k + 392UL)
86-
+ (offset_k << 3UL);
81+
uint32_t lfxo_intcap_mid_val = (2UL * lfxo_intcap_femto_f - 12000UL)
82+
* (uint32_t)(slope_k + 392UL) + (offset_k << 3UL) * 1000UL;
8783

88-
/* Get integer part of the INTCAP code */
89-
uint32_t lfxo_intcap = mid_val >> 9UL;
84+
/* Get integer part of the INTCAP by dividing by 2^9 and convert to pico Farads. */
85+
uint32_t lfxo_intcap = lfxo_intcap_mid_val / 512000UL;
9086

91-
/* Round based on fractional part */
92-
if ((mid_val & BIT_MASK(9)) > (BIT_MASK(9) / 2)) {
87+
/* Round based on fractional part. */
88+
if (lfxo_intcap_mid_val % 512000UL >= 256000UL) {
9389
lfxo_intcap++;
9490
}
9591

@@ -107,11 +103,11 @@ static inline void power_and_clock_configuration(void)
107103
* additions and subtractions, it generates slightly less than optimal
108104
* code.
109105
*/
110-
uint32_t slope_field =
106+
uint32_t slope_field_m =
111107
(xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk) >> FICR_XOSC32MTRIM_SLOPE_Pos;
112-
uint32_t slope_mask = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos;
113-
uint32_t slope_sign = (slope_mask - (slope_mask >> 1));
114-
int32_t slope_m = (int32_t)(slope_field ^ slope_sign) - (int32_t)slope_sign;
108+
uint32_t slope_mask_m = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos;
109+
uint32_t slope_sign_m = (slope_mask_m - (slope_mask_m >> 1));
110+
int32_t slope_m = (int32_t)(slope_field_m ^ slope_sign_m) - (int32_t)slope_sign_m;
115111
uint32_t offset_m =
116112
(xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk) >> FICR_XOSC32MTRIM_OFFSET_Pos;
117113
/* As specified in the nRF54L15 PS:
@@ -121,22 +117,19 @@ static inline void power_and_clock_configuration(void)
121117
* holding any value between 4.0 pF and 17.0 pF in 0.25 pF steps.
122118
*/
123119

124-
/* NOTE 1: Requested HFXO internal capacitance in femto Faradas is used directly in formula
125-
* to calculate INTCAP code. That is different than in case of LFXO.
126-
*
127-
* NOTE 2: PS formula uses piko Farads, the implementation of the formula uses femto Farads
128-
* to avoid use of floating point data type.
129-
*/
130-
uint32_t cap_val_femto_f = DT_PROP(HFXO_NODE, load_capacitance_femtofarad);
120+
uint32_t hfxo_intcap_femto_f = DT_PROP(HFXO_NODE, load_capacitance_femtofarad);
131121

132-
uint32_t mid_val_intcap = (((cap_val_femto_f - 5500UL) * (uint32_t)(slope_m + 791UL))
133-
+ (offset_m << 2UL) * 1000UL) >> 8UL;
122+
/* Capacitance value passed to the formula is in femto Farads to
123+
* avoid floating point data type. Hence, offset_m needs to be multiplied by 1000.
124+
*/
125+
uint32_t hfxo_intcap_mid_val = (((hfxo_intcap_femto_f - 5500UL)
126+
* (uint32_t)(slope_m + 791UL)) + (offset_m << 2UL) * 1000UL) >> 8UL;
134127

135-
/* Convert the calculated value to piko Farads */
136-
uint32_t hfxo_intcap = mid_val_intcap / 1000;
128+
/* Convert the calculated value to piko Farads. */
129+
uint32_t hfxo_intcap = hfxo_intcap_mid_val / 1000;
137130

138-
/* Round based on fractional part */
139-
if (mid_val_intcap % 1000 >= 500) {
131+
/* Round based on fractional part. */
132+
if (hfxo_intcap_mid_val % 1000 >= 500) {
140133
hfxo_intcap++;
141134
}
142135

0 commit comments

Comments
 (0)