diff --git a/charon_vna/vna.py b/charon_vna/vna.py index d2d68f0..97d6415 100644 --- a/charon_vna/vna.py +++ b/charon_vna/vna.py @@ -66,6 +66,20 @@ class AD9361Register(IntEnum): AUXDAC2_TX_DELAY = 0x033 +@unique +class AD9361DacVref(IntEnum): + VREF_1V0 = 0b00 + VREF_1V5 = 0b01 + VREF_2V0 = 0b10 + VREF_2V5 = 0b11 + + +@unique +class AD9361DacStepFactor(IntEnum): + FACTOR_2 = 0b0 + FACTOR_1 = 0b1 + + class Charon: FREQUENCY_OFFSET = 1e6 @@ -122,8 +136,8 @@ class Charon: self.ctrl.reg_write(AD9361Register.EXTERNAL_LNA_CONTROL, 0x90) # bit 7: AuxDAC Manual, bit 4: GPO Manual self.ctrl.reg_write(AD9361Register.AUXDAC_ENABLE_CONTROL, 0x3F) self._set_gpo(0b0000) - self._set_dac(value=0, channel=1) - self._set_dac(value=0, channel=2) + self._set_dac_code(value=0, channel=1) + self._set_dac_code(value=0, channel=2) def get_config(self) -> Dict[str, Any]: config = dict() @@ -153,24 +167,24 @@ class Charon: def _set_gpo(self, value: int) -> None: self.ctrl.reg_write(AD9361Register.GPO_FORCE_AND_INIT, (value & 0x0F) << 4) # bits 7-4: GPO3-0 - def _set_dac(self, value: int, channel: Literal[1, 2]): + def _set_dac_voltage(self, voltage: float, channel: Literal[1, 2]): + raise NotImplementedError() + + def _set_dac_code( + self, + value: int, + channel: Literal[1, 2], + vref: AD9361DacVref = AD9361DacVref.VREF_1V0, + step_factor: AD9361DacStepFactor = AD9361DacStepFactor.FACTOR_2, + ) -> None: if channel not in [1, 2]: raise ValueError(f"Invalid channel {channel}. Must be 1 or 2") if value > 0x3FF or value < 0: raise ValueError("Invalid value for 10 bit DAC. Must be between 0 and 0x3FF (inclusive)") - @unique - class Vref(IntEnum): - VREF_1V0 = 0b00 - VREF_1V5 = 0b01 - VREF_2V0 = 0b10 - VREF_2V5 = 0b11 - - @unique - class StepFactor(IntEnum): - FACTOR_2 = 0b0 - FACTOR_1 = 0b1 + vref = AD9361DacVref(vref) + step_factor = AD9361DacStepFactor(step_factor) # https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf # page 13 @@ -185,9 +199,22 @@ class Charon: ) self.ctrl.reg_write( AD9361Register.__getitem__(f"AUXDAC{channel}_CONFIG"), - (value & 0x3) | (Vref.VREF_1V0.value << 2) | (StepFactor.FACTOR_2 << 4), + (value & 0x3) | (vref.value << 2) | (step_factor << 4), ) + def _get_dac_code(self, channel: int) -> Tuple[float, AD9361DacVref, AD9361DacStepFactor]: + word = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_WORD")) + config = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_CONFIG")) + + value = (word << 2) + (config & 0x3) + vref = AD9361DacVref((config >> 2) & 0x3) + step_factor = AD9361DacStepFactor((config >> 4) & 0x1) + + return (value, vref, step_factor) + + def _get_dac_voltage(self) -> float: + raise NotImplementedError() + def set_output_power(self, power: float): pout = xr.DataArray( [-15, -10, -5, 0, 5], @@ -288,6 +315,7 @@ class Charon: ) for ff, freq in enumerate(s.frequency.data): if callback is not None: + # report progress during sweep callback(ff, len(s.frequency)) self.set_output(frequency=freq, power=-5) self.sdr.rx_destroy_buffer() @@ -299,7 +327,9 @@ class Charon: self.sdr.rx_hardwaregain_chan1 = 40 rx = self.sdr.rx() s.loc[dict(frequency=freq)] = np.mean(rx[1] / rx[0]) + if callback is not None: + # mark capture as complete callback(len(s.frequency), len(s.frequency)) return s