Hi to all, in M-Labs we have come across the lack of compatibility between Legacy firmware and NGFW in terms of configuration data format stored in the EEPROMs. Given a set of data calibrated using Legacy, I'd like to propose a documentation on interpreting the existing data in Legacy format, and convert them to NGFW, possibly done manually or in code with a future PR.
I'm only aware of a similar discussion about documenting NGFW calibration on #107. Please remind me of other threads related to this topic if there's any.
My draft is presented as follows. Please also feel free to point out any mistakes.
Harry's draft
Conversion
Perform conversion to power (in dBm) as required by NGFW.
("EEPROM @n <SYMBOL>" indicates a value for SYMBOL stored at the byte address n, in decimal; Legacy EEPROM is big-endian)
Step 1: Output power transform
Target: <output_power_transform>
Source:
Channel EEPROM @24 <ADC1_SCALE>
Channel EEPROM @20 <ADC1_OFFSET>
Conversion:
- Read 16-bit <ADC1_SCALE> as slope
a, and 16-bit <ADC1_OFFSET> as offset b. Both are unsigned 16-bit integers. They inversely transform a 16-bit ADC raw sample back to power in dBm:
sample = a * power + b ==> power = (sample - b) / a
- Given that ADC sets VDDA = 2500 mV (see
main.rs) and resolution = 12 bits (default value, see stm32f4xx_hal::adc::config::AdcConfig, and STM32 manual RM0090, section 13.13.2 about ADC_CR1), find linear transformation from voltage (in V) to power:
voltage = (sample * 2.5) / ((1 \<\< 12) - 1)
(Note: double check with stm32f4xx_hal::adc::Adc::sample_to_millivolts() implementation)
- ==>
power = (voltage * 4095.0 / 2.5 - b) / a = (4095.0 / 2.5 / a) * voltage + (-b / a)
- Thus, define LT as:
power = c * voltage + d, where
slope: c = 4095.0 / 2.5 / a
offset: d = -b / a
- Instantiate LinearTransform object with c and d.
- Assign the LT object to <output_power_transform>.
Step 2: Output interlock threshold
Target: <output_interlock_threshold>
Source:
Channel EEPROM @18 <DAC2>
Channel EEPROM @30 <HW_INT_SCALE> - see footnote
Channel EEPROM @34 <HW_INT_OFFSET> - see footnote
Conversion:
- Read 16-bit <DAC2>, which is a 12-bit DAC code.
- Convert the code to the correct voltage as f32:
voltage = (code >> 4) / (0x1000) * 2.5
(see Ad5627::set_voltage())
- Convert the <DAC2> voltage, using <output_power_transform>, to the corresponding power as f32 via linear transformation. Currently, NGFW only uses <output_power_transform> to invert a dBm value for setting the DAC.
- Assign the power to <output_interlock_threshold>.
Footnote:
- Legacy uses LT specifically for setting the AD5627 DAC voltage by power, which means this LT is the inverse of NGFW LinearTransform. For this LT on Legacy, 32-bit <HW_INT_SCALE> and <HW_INT_OFFSET> are the slope and offset. Both are float representations in 32-bit, so one must unpack the bytes as f32.
- Currently, NGFW uses only <output_power_transform> to transform the voltage to power when assigning the threshold. Since this LT is vastly different from the LT used by Legacy for accepting user's input, for the same DAC code, the power value stored on NGFW is not necessarily equal to the power accepted by Legacy from the user, and the two shall have no obvious correlation.
- As a result, usage of the values <HW_INT_SCALE> and <HW_INT_OFFSET> on Legacy still remains undiscovered for NGFW.
Step 3: Bias voltage
Target: <bias_voltage>
Source:
Channel EEPROM @28 <BIAS_DAC_VALUE>
Conversion:
- Read 16-bit <BIAS_DAC_VALUE>, which is a 12-bit DAC code.
- Convert the code to the equivalent voltage as f32:
voltage = code / 4096.0 * 3.3
(assume Dac7571::default(); see Dac7571::set_voltage())
- Further convert the voltage to one accepted by
rf_channel::set_bias():
voltage := -1.0 * voltage
(see comment on rf_channel::set_bias())
- Assign the final voltage value to <bias_voltage>.
Footnote:
- Legacy only accepts a DAC7571 DAC code as user's input for setting and storing the bias value, so no conversion is involved. However, NGFW fetches and stores a negated voltage value, and converts it to the bias value with
rf_channel::set_bias().
Step 4: Channel state (optional)
(The Legacy firmware doesn't provide user-facing commands for reading main EEPROM via VCP interface)
Target: <enabled>
Source:
Board EEPROM @30 <POWERCFG_STATUS>
Conversion:
- Read 8-bit <POWERCFG_STATUS>, which is a bitmask where LSB is channel 0.
- Extract the correpsonding bit for the channel.
- Assign the bit as bool to <enabled>.
Step 5: Input power transform
Target: <input_power_transform>
Source:
Channel EEPROM @38 <INPUT_CAL_SCALE>
Channel EEPROM @42 <INPUT_CAL_OFFSET>
Conversion:
- Read 32-bit <INPUT_CAL_SCALE> as slope, and 32-bit <INPUT_CAL_OFFSET> as offset. Both are float representations in 32-bit, so unpack the bytes as f32. They transform a 12-bit ADC raw sample to power in dBm:
power = a * sample + b
- Find linear transformation from voltage to power:
voltage = code / 4096.0 * 3.3
(assume Mcp3221::default(); see Mcp3221::get_voltage())
- ==>
power = a * (voltage * 4096.0 / 3.3) + b
- Thus, define LT as: power = c * voltage + d, where
slope: c = a * 4096.0 / 3.3
offset: d = b
- Instantiate LinearTransform object with the slope and offset.
- Assign the LT object to <input_power_transform>.
Step 6: Reflected power transform
Target: <reflected_power_transform>
Source:
Channel EEPROM @26 <ADC2_SCALE>
Channel EEPROM @22 <ADC2_OFFSET>
Conversion:
- Read 16-bit <ADC2_SCALE> as slope, and 16-bit <ADC2_OFFSET> as offset. Both are unsigned 16-bit integers. They transform 16-bit ADC code to power.
- Find linear transformation from voltage to power, using conversion step 2. for <output_power_transform>.
- Instantiate LinearTransform object with the new slope and offset.
- Assign the LT object to <reflected_power_transform>.
Hi to all, in M-Labs we have come across the lack of compatibility between Legacy firmware and NGFW in terms of configuration data format stored in the EEPROMs. Given a set of data calibrated using Legacy, I'd like to propose a documentation on interpreting the existing data in Legacy format, and convert them to NGFW, possibly done manually or in code with a future PR.
I'm only aware of a similar discussion about documenting NGFW calibration on #107. Please remind me of other threads related to this topic if there's any.
My draft is presented as follows. Please also feel free to point out any mistakes.
Harry's draft
Conversion
Perform conversion to power (in dBm) as required by NGFW.
("EEPROM
@n<SYMBOL>" indicates a value for SYMBOL stored at the byte address n, in decimal; Legacy EEPROM is big-endian)Step 1: Output power transform
Target: <output_power_transform>
Source:
Channel EEPROM
@24<ADC1_SCALE>Channel EEPROM
@20<ADC1_OFFSET>Conversion:
a, and 16-bit <ADC1_OFFSET> as offsetb. Both are unsigned 16-bit integers. They inversely transform a 16-bit ADC raw sample back to power in dBm:sample = a * power + b==>power = (sample - b) / amain.rs) and resolution = 12 bits (default value, seestm32f4xx_hal::adc::config::AdcConfig, and STM32 manual RM0090, section 13.13.2 about ADC_CR1), find linear transformation from voltage (in V) to power:voltage = (sample * 2.5) / ((1 \<\< 12) - 1)(Note: double check with
stm32f4xx_hal::adc::Adc::sample_to_millivolts()implementation)power = (voltage * 4095.0 / 2.5 - b) / a = (4095.0 / 2.5 / a) * voltage + (-b / a)power = c * voltage + d, whereslope:
c = 4095.0 / 2.5 / aoffset:
d = -b / aStep 2: Output interlock threshold
Target: <output_interlock_threshold>
Source:
Channel EEPROM
@18<DAC2>Channel EEPROM
@30<HW_INT_SCALE> - see footnoteChannel EEPROM
@34<HW_INT_OFFSET> - see footnoteConversion:
voltage = (code >> 4) / (0x1000) * 2.5(see
Ad5627::set_voltage())Footnote:
Step 3: Bias voltage
Target: <bias_voltage>
Source:
Channel EEPROM
@28<BIAS_DAC_VALUE>Conversion:
voltage = code / 4096.0 * 3.3(assume
Dac7571::default(); seeDac7571::set_voltage())rf_channel::set_bias():voltage := -1.0 * voltage(see comment on
rf_channel::set_bias())Footnote:
rf_channel::set_bias().Step 4: Channel state (optional)
(The Legacy firmware doesn't provide user-facing commands for reading main EEPROM via VCP interface)
Target: <enabled>
Source:
Board EEPROM
@30<POWERCFG_STATUS>Conversion:
Step 5: Input power transform
Target: <input_power_transform>
Source:
Channel EEPROM
@38<INPUT_CAL_SCALE>Channel EEPROM
@42<INPUT_CAL_OFFSET>Conversion:
power = a * sample + bvoltage = code / 4096.0 * 3.3(assume
Mcp3221::default(); seeMcp3221::get_voltage())power = a * (voltage * 4096.0 / 3.3) + bslope:
c = a * 4096.0 / 3.3offset:
d = bStep 6: Reflected power transform
Target: <reflected_power_transform>
Source:
Channel EEPROM
@26<ADC2_SCALE>Channel EEPROM
@22<ADC2_OFFSET>Conversion: