Hardware:
Custom DA14683 Board
Latest SDK = 1.0.14.1081 (Last updated in 2018)
Situation:
This question applies to any demo, but lets take the BMS demo for an example.
From hw_rf.h, I can see where the tx power levels are defined in this enum:
typedef enum { HW_RF_PWR_LUT_0dbm = 0, /**< TX PWR attenuation 0 dbm */ HW_RF_PWR_LUT_m1dbm = 1, /**< TX PWR attenuation -1 dbm */ HW_RF_PWR_LUT_m2dbm = 2, /**< TX PWR attenuation -2 dbm */ HW_RF_PWR_LUT_m3dbm = 3, /**< TX PWR attenuation -3 dbm */ HW_RF_PWR_LUT_m4dbm = 4, /**< TX PWR attenuation -4 dbm */ } HW_RF_PWR_LUT_SETTING;
From hw_rf.c, I can see the function that sets the TX power level:
void hw_rf_set_tx_power_ble(HW_RF_PWR_LUT_SETTING lut) { RFCU->RF_TX_PWR_BLE_REG = lut; rf_tx_power_luts.tx_power_ble = lut; }
...But the "hw_rf_set_tx_power_ble()" function does not appear to be called anywhere.
...Also none of the enums from "HW_RF_PWR_LUT_SETTING" appear anywhere in the project.
It is unclear where the TX power is being defined. It is also unclear at what point in the power up sequence the TX power is being set.
Questions:
1) Where is the default TX Power level defined? (file and line please)
2) At what point in the BLE radio initialization sequence is the TX power level set? (file and line please)
3) If I wanted to change the BLE radio TX power level, what is the correct sequence of operations to do so? (do I need to power down the radio first?, just stop advertising?, etc)
I think this should be a simple question. It would be great if this didn't take forever to get answered.
Thanks!
Hi Nathan,
According to datasheet :
Radio transceiver- 2.4 GHz CMOS transceiver with integrated balun- 50 matched single wire antenna interface- 0 dBm transmit output power- -94 dBm receiver sensitivity (BLE)- Supply current at VBAT1 (3 V):TX: 3.4 mARX: 3.1 mA (with ideal DC-DC converter)
If you search the code, the hw_rf_set_tx_power_ble() is called in hw_rf_request_recommended_settings() which is called in ad_rf_request_recommended_settings(). Just search into the code in hw_rf.c file.
#ifdef CONFIG_USE_BLE hw_rf_set_tx_power_ble(rf_tx_power_luts.tx_power_ble);#endif
According to hw_rf_tx_power_luts_t struct, rf_tx_power_luts.tx_power_ble = 4.
The hw_rf_set_tx_power_ble() is changing the TX power attenuation setting. Why do you need to change this?
Regards,
PM_Renesas
wow. Did this end up being a NOT simple question or what!
To Answer your question: "Why do you need to change this?"
https://www.agccert.com/news_show/646.html
Because of new FCC rules implemented earlier this year, the TX power needs to be under the new FCC KDB 447498 limits. You guys have not updated your SDK since 2018, well before this new limit was implemented. So I cannot trust the value you have as the default will work now in 2022.
I need to know what TX power is being set during initialization, and make sure nothing is transmitted at a higher power than is allowed. This is why I asked the specific questions I did. I asked where the default power is defined so I can confirm it's not exceeding the new maximum. I asked where the power is set, so I can confirm it's not being set higher than max at some initial stage. I asked how to set the power myself so I can confirm the value I require is being loaded. I don't consider any of this unreasonable.
Regarding the default value for TX power:
The struct that holds the values set by hw_rf_set_tx_power_ble() is indeed in hw_rf.h as follows:
typedef struct __attribute__ ((__packed__)) { uint8_t tx_power_ble: 4; uint8_t tx_power_ftdf: 4; } hw_rf_tx_power_luts_t;
Those “4”s are not values. They are bit fields used to pack both tx_power_ble and tx_power_ftdf into one byte.
The struct rf_tx_power_luts is declared next in that same file:
extern hw_rf_tx_power_luts_t rf_tx_power_luts;
… but it’s tx_power_ble and tx_power_ftdf values are never initialized to anything. (If I’m wrong here, provide file and line please).
The usage is:
void hw_rf_request_recommended_settings(void) { //… hw_rf_set_tx_power_ble(rf_tx_power_luts.tx_power_ble); //… }
Which proceeds to set rf_tx_power_luts.tx_power_ble back to itself:
You commented that "rf_tx_power_luts.tx_power_ble = 4" when it gets run, but you did not specify where that "4" value is coming from or how you determined that “4” was being used. Are you confusing the struct 4 bit bitfield with a value?
NOTE: When I set a debug breakpoint in the hw_rf_set_tx_power_ble() function as called from "hw_rf_request_recommended_settings()" during system power up time, I can see that the value being passed in "lut" = "HW_RF_PWR_LUT_0dbm".
So the mystery continues. Where is the default TX power defined?
Regarding where in the init sequence is the TX power is being set:
Yes, I should have been more clear/specific here. hw_rf_set_tx_power_ble() is indeed called from hw_rf_request_recommended_settings(), which is indeed called from ad_rf_request_recommended_settings().
That is unfortunately not helpful. Take that investigation a few steps further.
ad_rf_request_recommended_settings() is called from rf_init_sdk() and rf_reinit_sdk(). I can see why you stopped where you did because now the trail gets a little less clear. rf_init_sdk() appears to only be called as part of the jump_table.c rom_func_addr_table_var[].
The only relevant use of that jump table I can see is in ble_platform_initialization(), which is called from ad_ble_init(). This is only called from a Macro ADAPTER_INIT_DEP1.
At this point it's unclear what parts of the code are using the ADAPTER_INIT_DEP1 macro.
I hope we can agree that I did enough "file searching" here. This is still a very unsatisfactory answer to my question of, where in the initialization process is the TX power being set?
These are just examples of possible responses that would actually answer my question about "At what point in the BLE radio initialization sequence is the TX power level set?:
a) At some system power up time, even before system_init() is called.
b) When ble_mgr_init() is called.
c) When ble_peripheral_start() is called. (<-- it's this one)
d) When ble_gap_adv_start() is called.
Are any of those correct? If not, please provide the actual answer.
I numbered my previous specific questions. Lets go through them and see what information was provided.
(Partial Answer. See Above. )
(Not Answered. Same Question)
I'll answer one of my questions now. During normal init procedures, the hw_rf_set_tx_power_ble() gets called for the first time from "ble_peripheral_start()".
The other questions still stand:
Answer: hw_rf_set_tx_power_ble() is first called from ble_peripheral_start()
As mentioned in my previous reply and as described in the datasheet, the DA14683 has hardcoded tx power at 0 dBm. This answers all your questions.
The DA14683 has near-field feature that reduces the output power to -20dBm.
Datasheet page 464
https://www.renesas.com/eu/en/document/dst/da14683-datasheet
Note 42: To activate the "Near Field Mode", program address 0x50002230, bits 9:5 with the value 0x0. To stop NFC restore previous bitfield value.
I'm going to have to push back on this. I'm trying to get my project finished and I don't much want to play semantic word games.
As documented above, Your SDK has a function called "hw_rf_set_tx_power_ble()"
The header comment for this function is as follows:
/** * \brief Set TX Power for BLE * This actually sets the index of the RF_TX_PWR_LUT_X_REG to use. * \param [in] lut The TX power attenuation setting * \warning Do not call this function before recommended settings are applied */ void hw_rf_set_tx_power_ble(HW_RF_PWR_LUT_SETTING lut);
From your post above: "The hw_rf_set_tx_power_ble() is changing the TX power attenuation setting."
If you didn't want your users to refer to the "TX Power Attenuator" as "TX Power" then you should not have named your functions "hw_rf_set_tx_power_ble()" and had comments such as "Set TX Power for BLE".
Or....
... Are you trying to say that the "hw_rf_set_tx_power_ble()" function actually doesn't work and has no effect on the TX power (though an attenuator or whatever) coming out of the antenna? If so, why is that function included (and called by other functions in your SDK)?
It would be great if we could get back on track. I will reword my questions to specifically mention the "TX Power Attenuator".
Also once we get back on track here, we can hopefully un-derail the train on the other thread about RF Master TX Power "ATTENUATOR" settings.
1) Where is the default TX Power ATTENUATOR level defined? (file and line please)
(Partial Answer. See Above. ) The rf_tx_power_luts struct is never initialized?
2) At what point in the BLE radio initialization sequence is the TX power ATTENUATOR level set? (file and line please)
3) If I wanted to change the BLE radio TX power ATTENUATOR level, what is the correct sequence of operations to do so? (do I need to power down the radio first?, just stop advertising?, etc)
Did you see my response?
1.
#ifdef CONFIG_USE_BLEhw_rf_set_tx_power_ble(rf_tx_power_luts.tx_power_ble);#endif
rf_tx_power_luts.tx_power_ble = 4 --->> HW_RF_PWR_LUT_m4dbm = 4, /**< TX PWR attenuation -4 dbm */
2. Power down radio and then call hw_rf_set_tx_power_ble()
3. application specific
Yes, I did see your response. Did you read any of my response to your response? I explained exactly why what you said is wrong, in pretty good detail. I'll repost it here. Lets learn together!
Lets start with the hw_rf_tx_power_luts_t struct:
typedef struct __attribute__ ((__packed__)) { uint8_t tx_power_ble: 4; uint8_t tx_power_ftdf: 4; } hw_rf_tx_power_luts_t; extern hw_rf_tx_power_luts_t rf_tx_power_luts;
That is the format for a c bit field: https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm
Those "4"s are not values. You can't assign a value in a c struct definition. Those "4"s are the number of bits for each variable. If you run sizeof(rf_tx_power_luts) you will see that returns 1 byte.
Your statement that "According to hw_rf_tx_power_luts_t struct, rf_tx_power_luts.tx_power_ble = 4. " is both incorrect theoretically (as in you are misunderstanding what the code is doing), and practically when run. As I mentioned, when I debug the code the value that is actually used when the unmodified system calls "hw_rf_set_tx_power_ble()" is 0 = "HW_RF_PWR_LUT_0dbm". Normally I would leave this issue here, but it's super bad form to use an uninitialized variable like this. The "rf_tx_power_luts" is declared but it is never initialized. You would see this if you look through the code I've already posted above or you can check the actual SDK if you don't believe me.
If you think I got this wrong still, go ahead and respond with the file and line number where you think the "rf_tx_power_luts" is initialized with a "4" or "HW_RF_PWR_LUT_m4dbm".
The "ad_rf_request_recommended_settings()" calls "hw_rf_set_recommended_settings()" as follows:
/** * \brief Preferred settings 680 radio * */ void hw_rf_set_recommended_settings(void) { // Preferred Settings File for DCTMON // Device : DA14680AA // Package : All packages, no dependency on package. // Last change date : June 18, 2015 - 18:00:48 // Last change item : Register: RF_KMOD_ALPHA_REG, Field: KMOD_ALPHA_FTDF, Value: 0x10 // File date : June 18, 2015 - 19:16:16 REG_SET_MASKED(DEM, RF_AFC_CTRL_REG, 0x0330, 0x01F5); REG_SET_MASKED(DEM, RF_AGC_CTRL1_REG, 0x007F, 0x950A); REG_SET_MASKED(DEM, RF_AGC_CTRL2_REG, 0x003F, 0x0049); REG_SET_MASKED(DEM, RF_CCA_RSSITH_REG, 0xE000, 0xE708); RFCU_POWER->RF_CNTRL_TIMER_10_REG = 0x0A42; RFCU_POWER->RF_CNTRL_TIMER_11_REG = 0x0A44; REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_12_REG, 0x00FF, 0x0050); RFCU_POWER->RF_CNTRL_TIMER_13_REG = 0x0850; RFCU_POWER->RF_CNTRL_TIMER_14_REG = 0x1858; RFCU_POWER->RF_CNTRL_TIMER_15_REG = 0x0A50; REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_16_REG, 0xFF00, 0x1207); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_1_REG, 0xFF00, 0x0F00); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_21_REG, 0x00FF, 0x0044); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_22_REG, 0x00FF, 0x0040); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_23_REG, 0x00FF, 0x0052); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_2_REG, 0xFF00, 0x0D08); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_3_REG, 0xFF00, 0x0C10); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_5_REG, 0xFF00, 0x0A18); REG_SET_MASKED(RFCU_POWER, RF_CNTRL_TIMER_7_REG, 0xFF00, 0x0A18); RFCU->RF_CP_CTRL_BLE_REG = 0x3535; REG_SET_MASKED(RFCU, RF_CP_CTRL_FTDF_REG, 0x0F0F, 0x7575); REG_SET_MASKED(DEM, RF_DC_OFFSET_CTRL2_REG, 0x0402, 0x05D0); DEM->RF_DC_OFFSET_CTRL3_REG = 0xE9EE; REG_SET_MASKED(RFCU, RF_DIV_IQ_TX_REG, 0x00FF, 0x00A1); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG16_REG, 0x001F, 0x0014); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG23_BLE_REG, 0x03E0, 0x0000); RFCU_POWER->RF_ENABLE_CONFIG42_REG = 0x0210; REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG45_BLE_REG, 0x03E0, 0x0060); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG46_BLE_REG, 0x001F, 0x0015); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG46_FTDF_REG, 0x001F, 0x0015); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG47_BLE_REG, 0x001F, 0x0016); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG47_FTDF_REG, 0x001F, 0x0016); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG48_BLE_REG, 0x001F, 0x0017); REG_SET_MASKED(RFCU_POWER, RF_ENABLE_CONFIG48_FTDF_REG, 0x001F, 0x0017); REG_SET_MASKED(DEM, RF_FTDF_CTRL1_REG, 0xCC00, 0x47C0); REG_SET_MASKED(DEM, RF_FTDF_CTRL4_REG, 0x0500, 0xC6A7); REG_SET_MASKED(DEM, RF_FTDF_LOOP_GAIN_DS_REG, 0x00FF, 0x0000); REG_SET_MASKED(DEM, RF_FTDF_LOOP_GAIN_PD_REG, 0x00FF, 0x0000); REG_SET_MASKED(DEM, RF_FTDF_SIGDET_CTRL_REG, 0x1FFF, 0x0BC3); REG_SET_MASKED(PLLDIG, RF_KMOD_ALPHA_BLE_REG, 0x0FC0, 0x030C); PLLDIG->RF_KMOD_ALPHA_FTDF_REG = 0x000D; REG_SET_MASKED(RFCU, RF_LF_CTRL_REG, 0x0040, 0x0080); RFCU->RF_LF_RES_CTRL_BLE_REG = 0x3434; REG_SET_MASKED(RFCU, RF_LF_RES_CTRL_FTDF_REG, 0x0F0F, 0x7474); RFCU->RF_LO_IQ_TRIM_REG = 0x0001; PLLDIG->RF_MGAIN_CTRL3_REG = 0x0050; REG_SET_MASKED(PLLDIG, RF_MGAIN_CTRL_FTDF_REG, 0xFF00, 0x5000); REG_SET_MASKED(RFCU, RF_MIXER_CTRL1_BLE_REG, 0x000F, 0x0031); REG_SET_MASKED(RFCU, RF_MIXER_CTRL1_FTDF_REG, 0x000F, 0x0031); REG_SET_MASKED(RFCU, RF_OVERRULE_REG, 0x3C00, 0x5800); REG_SET_MASKED(RFCU, RF_REF_OSC_FTDF_REG, 0x7FFF, 0x31EB); REG_SET_MASKED(DEM, RF_RSSI_COMP_CTRL_REG, 0xF000, 0x9777); REG_SET_MASKED(RFCU, RF_SPARE1_BLE_REG, 0x0038, 0x0018); REG_SET_MASKED(RFCU, RF_SPARE1_FTDF_REG, 0x0008, 0x0008); REG_SET_MASKED(PLLDIG, RF_SYNTH_CTRL2_BLE_REG, 0x20C0, 0x304B); REG_SET_MASKED(PLLDIG, RF_SYNTH_CTRL2_FTDF_REG, 0x0040, 0x004B); RFCU->RF_TX_PWR_LUT_5_REG = 0x09FF; REG_SET_MASKED(RFCU, RF_TXDAC_CTRL_REG, 0x0040, 0x0000); }
I'm sure there is something there as well, but most of those registers don't have documentation that makes any sense.
Nathan, will get back on this. Let me check again.
1. The TX power attenuation setting is applied by the hw_rf_set_tx_power_ble() function in hw_rf.c and as you correctly mentioned the aforementioned function takes the HW_RF_PWR_LUT_SETTING enum as an input parameter.
The default parameter that the hw_rf_set_tx_power_ble() is configured is 0, and according to HW_RF_PWR_LUT_SETTING enum means 0dBm:
HW_RF_PWR_LUT_0dbm = 0, /**< TX PWR attenuation 0 dbm */
In file hw_rf.f, in line 107 :
hw_rf_tx_power_luts_t rf_tx_power_luts __RETAINED;
In sdk_defs.h, the __RETAINED stores zero-initialized data retained memory :
#define __RETAINED __attribute__((section("retention_mem_zi"))) // RetRAM0
This means that the rf_tx_power_luts struct is zero-initialized.
2. The hw_rf_set_tx_power_ble() is called in hw_rf_request_recommended_settings(), which is called in ad_rf_request_recommended_settings(). Please search into the SDK to find how the ad_rf_request_recommended_settings() is executed.
---------------------------------------------------------------
******* IGNORE THIS *******
3. I am checking this internally but a possible solution would be to use the __RETAINED_RW attribute which does not zero-initialize the data in the Ret-RAM :
hw_rf_tx_power_luts_t rf_tx_power_luts __RETAINED_RW ;
And then set the rf_tx_power_luts.tx_power_ble item to your preferred value.