This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

DTM Example Firmware Bug ?

Hi I'm setting up a firmware based on the DTM example to perform certification tests.

In the DTM example firmware I see that there is a VENDOR_SPECIFIC command option to use combined with the LE_TRANSMITTER_TEST command. The VENDOR_SPECIFIC command option has other sub-commands and I'm interested in the SET_TX_POWER one.

In the main.c code there is the uart packet parsing:

static uint32_t dtm_cmd_put(uint16_t command)
{
  dtm_cmd_t      command_code = (command >> 14) & 0x03;
  dtm_freq_t     freq         = (command >> 8) & 0x3F;
  uint32_t       length       = (command >> 2) & 0x3F;
  dtm_pkt_type_t payload      = command & 0x03;

  // Check for Vendor Specific payload.
  if (payload == 0x03) 
  {
    payload = DTM_PKT_VENDORSPECIFIC;
  }
  return dtm_cmd(command_code, freq, length, payload);
}

In the

dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)

function there this call:

dtm_vendor_specific_pkt(length, freq);

and the function is defined as

dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)

so, for VENDOR_SPECIFIC commands, the length field becomes the vendor_cmd and the freq field becomes the vendor_option (the type dtm_freq_t is defined as an uint32_t).

For the SET_TX_POWER command there is a call to

dtm_set_txpower(vendor_option)

and the function is like this:

bool dtm_set_txpower(uint32_t new_tx_power)
{
  // radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
  int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);

  if (m_state > STATE_IDLE)
  {
    // radio must be idle to change the tx power
    return false;
  }

  if ((new_power8 > 4) || (new_power8 < -40))
  {
    // Parameter outside valid range: nRF radio is restricted to the range -40 dBm to +4 dBm
    return false;
  }

  if (new_tx_power & 0x03) 
  {
    // Parameter error: The nRF51 radio requires settings that are a multiple of 4.
    return false;
  }
  m_tx_power = new_tx_power;

  return true;
}

My question is: how the freq value (that for the SET_TX_POWER command is the new_tx_power value), can be a negative value?

freq is initially set as:

freq = (command >> 8) & 0x3F;

so freq is a 6-bit value ( 00bbbbbb )

An int8_t is a byte where the msb is the sign bit ( sbbbbbbb ), so the conversion in the function dtm_set_txpower(...) that is

int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);

in my opinion, never gets a negative value for new_power8.

  • Yes, there were couple of bugs in Vendor Specific DTM commands (used by Nordic for Tx Power settings), there were even some Q&S on this forum and it use to be listed in known issues of particular SDK releases...

  • FormerMember
    0 FormerMember

    SDK 12.0.0 and later supports negative TX power:

    /**@brief Function for configuring the output power for transmitter test.
          This function may be called directly, or through dtm_cmd() specifying
          DTM_PKT_VENDORSPECIFIC as payload, SET_TX_POWER as length, and the dBm value as frequency.
    */
    bool dtm_set_txpower(uint32_t new_tx_power)
    {
    // radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
    int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);
    
    // The two most significant bits are not sent in the 6 bit field of the DTM command.
    // These two bits are 1's if and only if the tx_power is a negative number.
    // All valid negative values have the fourth most significant bit as 1.
    // All valid positive values have the fourth most significant bit as 0.
    // By checking this bit, the two most significant bits can be determined.
    new_power8 = (new_power8 & 0x30) != 0 ? (new_power8 | 0xC0) : new_power8;
    
    if (m_state > STATE_IDLE)
    {
        // radio must be idle to change the tx power
        return false;
    }
    
    m_tx_power = new_power8;
    
    return true;
    

    }

Related