Browse Source

define all SPI/register addresses in cc1101/addresses.py

Fabian Peter Hammerle 3 years ago
parent
commit
c0c56aeb8d
3 changed files with 158 additions and 63 deletions
  1. 2 0
      .gitignore
  2. 62 63
      cc1101/__init__.py
  3. 94 0
      cc1101/addresses.py

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.*.swp
+__pycache__/

+ 62 - 63
cc1101/__init__.py

@@ -5,6 +5,13 @@ import typing
 
 import spidev
 
+from cc1101.addresses import (
+    StrobeAddress,
+    ConfigurationRegisterAddress,
+    StatusRegisterAddress,
+    FIFORegisterAddress,
+)
+
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -29,39 +36,6 @@ class CC1101:
     _READ_SINGLE_BYTE = 0x80
     _READ_BURST = 0xC0
 
-    class _SPIAddress(enum.IntEnum):
-        # see "Table 45: SPI Address Space"
-        # > The configuration registers on the CC1101 are
-        # > located on SPI addresses from 0x00 to 0x2E.
-        PKTLEN = 0x06
-        FREQ2 = 0x0D
-        FREQ1 = 0x0E
-        FREQ0 = 0x0F
-        MDMCFG4 = 0x10
-        MDMCFG3 = 0x11
-        MDMCFG2 = 0x12
-        MCSM0 = 0x18
-        # > For register addresses in the range 0x30-0x3D,
-        # > the burst bit is used to select between
-        # > status registers when burst bit is one, and
-        # > between command strobes when burst bit is
-        # > zero. [...]
-        # > Because of this, burst access is not available
-        # > for status registers and they must be accessed
-        # > one at a time. The status registers can only be
-        # > read.
-        SRES = 0x30
-        STX = 0x35
-        SFTX = 0x3B
-        PARTNUM = 0x30
-        VERSION = 0x31
-        MARCSTATE = 0x35
-        # see "10.5 FIFO Access"
-        # > When the R/W-bit is zero, the TX FIFO is
-        # > accessed, and the RX FIFO is accessed when
-        # > the R/W-bit is one.
-        TXFIFO = 0x3F
-
     class ModulationFormat(enum.IntEnum):
         """
         MDMCFG2.MOD_FORMAT
@@ -108,25 +82,40 @@ class CC1101:
             chip_status & 0b1111,
         )
 
-    def _read_single_byte(self, register: _SPIAddress) -> int:
+    def _read_single_byte(
+        self, register: typing.Union[ConfigurationRegisterAddress, FIFORegisterAddress]
+    ) -> int:
         response = self._spi.xfer([register | self._READ_SINGLE_BYTE, 0])
         assert len(response) == 2, response
         self._log_chip_status_byte(response[0])
         return response[1]
 
-    def _read_burst(self, start_register: _SPIAddress, length: int) -> typing.List[int]:
+    def _read_burst(
+        self,
+        start_register: typing.Union[ConfigurationRegisterAddress, FIFORegisterAddress],
+        length: int,
+    ) -> typing.List[int]:
         response = self._spi.xfer([start_register | self._READ_BURST] + [0] * length)
         assert len(response) == length + 1, response
         self._log_chip_status_byte(response[0])
         return response[1:]
 
-    def _read_status_register(self, register: _SPIAddress) -> int:
-        _LOGGER.debug("reading status register 0x%02x", register)
-        values = self._read_burst(start_register=register, length=1)
-        assert len(values) == 1, values
-        return values[0]
+    def _read_status_register(self, register: StatusRegisterAddress) -> int:
+        # > For register addresses in the range 0x30-0x3D,
+        # > the burst bit is used to select between
+        # > status registers when burst bit is one, and
+        # > between command strobes when burst bit is
+        # > zero. [...]
+        # > Because of this, burst access is not available
+        # > for status registers and they must be accessed
+        # > one at a time. The status registers can only be
+        # > read.
+        response = self._spi.xfer([register | self._READ_BURST, 0])
+        assert len(response) == 2, response
+        self._log_chip_status_byte(response[0])
+        return response[1]
 
-    def _command_strobe(self, register: _SPIAddress) -> None:
+    def _command_strobe(self, register: StrobeAddress) -> None:
         # see "10.4 Command Strobes"
         _LOGGER.debug("sending command strobe 0x%02x", register)
         response = self._spi.xfer([register | self._WRITE_SINGLE_BYTE])
@@ -134,7 +123,9 @@ class CC1101:
         self._log_chip_status_byte(response[0])
 
     def _write_burst(
-        self, start_register: _SPIAddress, values: typing.List[int]
+        self,
+        start_register: typing.Union[ConfigurationRegisterAddress, FIFORegisterAddress],
+        values: typing.List[int],
     ) -> None:
         _LOGGER.debug(
             "writing burst: start_register=0x%02x values=%s", start_register, values
@@ -145,28 +136,32 @@ class CC1101:
         assert all(v == 0x0F for v in response[1:]), response  # TODO why?
 
     def _reset(self) -> None:
-        self._command_strobe(self._SPIAddress.SRES)
+        self._command_strobe(StrobeAddress.SRES)
 
     def _get_symbol_rate_exponent(self) -> int:
         """
         MDMCFG4.DRATE_E
         """
-        return self._read_single_byte(self._SPIAddress.MDMCFG4) & 0b00001111
+        return self._read_single_byte(ConfigurationRegisterAddress.MDMCFG4) & 0b00001111
 
     def _set_symbol_rate_exponent(self, exponent: int):
-        mdmcfg4 = self._read_single_byte(self._SPIAddress.MDMCFG4)
+        mdmcfg4 = self._read_single_byte(ConfigurationRegisterAddress.MDMCFG4)
         mdmcfg4 &= 0b11110000
         mdmcfg4 |= exponent
-        self._write_burst(start_register=self._SPIAddress.MDMCFG4, values=[mdmcfg4])
+        self._write_burst(
+            start_register=ConfigurationRegisterAddress.MDMCFG4, values=[mdmcfg4]
+        )
 
     def _get_symbol_rate_mantissa(self) -> int:
         """
         MDMCFG3.DRATE_M
         """
-        return self._read_single_byte(self._SPIAddress.MDMCFG3)
+        return self._read_single_byte(ConfigurationRegisterAddress.MDMCFG3)
 
-    def _set_symbol_rate_mantissa(self, mantissa: int) -> int:
-        self._write_burst(start_register=self._SPIAddress.MDMCFG3, values=[mantissa])
+    def _set_symbol_rate_mantissa(self, mantissa: int) -> None:
+        self._write_burst(
+            start_register=ConfigurationRegisterAddress.MDMCFG3, values=[mantissa]
+        )
 
     @classmethod
     def _symbol_rate_floating_point_to_real(cls, mantissa: int, exponent: int) -> float:
@@ -208,28 +203,28 @@ class CC1101:
         self._set_symbol_rate_exponent(exponent)
 
     def get_modulation_format(self) -> ModulationFormat:
-        mdmcfg2 = self._read_single_byte(self._SPIAddress.MDMCFG2)
+        mdmcfg2 = self._read_single_byte(ConfigurationRegisterAddress.MDMCFG2)
         return self.ModulationFormat((mdmcfg2 >> 4) & 0b111)
 
     def _set_modulation_format(self, modulation_format: ModulationFormat) -> None:
-        mdmcfg2 = self._read_single_byte(self._SPIAddress.MDMCFG2)
+        mdmcfg2 = self._read_single_byte(ConfigurationRegisterAddress.MDMCFG2)
         mdmcfg2 &= ~(modulation_format << 4)
         mdmcfg2 |= modulation_format << 4
-        self._write_burst(self._SPIAddress.MDMCFG2, [mdmcfg2])
+        self._write_burst(ConfigurationRegisterAddress.MDMCFG2, [mdmcfg2])
 
     def __enter__(self) -> "CC1101":
         # https://docs.python.org/3/reference/datamodel.html#object.__enter__
         self._spi.open(0, 0)
         self._spi.max_speed_hz = 55700  # empirical
         self._reset()
-        partnum = self._read_status_register(self._SPIAddress.PARTNUM)
+        partnum = self._read_status_register(StatusRegisterAddress.PARTNUM)
         if partnum != self._SUPPORTED_PARTNUM:
             raise ValueError(
                 "unexpected chip part number {} (expected: {})".format(
                     partnum, self._SUPPORTED_PARTNUM
                 )
             )
-        version = self._read_status_register(self._SPIAddress.VERSION)
+        version = self._read_status_register(StatusRegisterAddress.VERSION)
         if version != self._SUPPORTED_VERSION:
             raise ValueError(
                 "unexpected chip version number {} (expected: {})".format(
@@ -243,7 +238,7 @@ class CC1101:
         # 3:2 PO_TIMEOUT: default
         # 1 PIN_CTRL_EN: default
         # 0 XOSC_FORCE_ON: default
-        self._write_burst(self._SPIAddress.MCSM0, [0b010100])
+        self._write_burst(ConfigurationRegisterAddress.MCSM0, [0b010100])
         marcstate = self.get_main_radio_control_state_machine_state()
         if marcstate != self.MainRadioControlStateMachineState.IDLE:
             raise ValueError("expected marcstate idle (actual: {})".format(marcstate))
@@ -258,7 +253,7 @@ class CC1101:
         self
     ) -> MainRadioControlStateMachineState:
         return self.MainRadioControlStateMachineState(
-            self._read_status_register(self._SPIAddress.MARCSTATE)
+            self._read_status_register(StatusRegisterAddress.MARCSTATE)
         )
 
     def get_marc_state(self) -> MainRadioControlStateMachineState:
@@ -285,10 +280,14 @@ class CC1101:
     def _get_base_frequency_control_word(self) -> typing.List[int]:
         # > The base or start frequency is set by the 24 bitfrequency
         # > word located in the FREQ2, FREQ1, FREQ0 registers.
-        return self._read_burst(start_register=self._SPIAddress.FREQ2, length=3)
+        return self._read_burst(
+            start_register=ConfigurationRegisterAddress.FREQ2, length=3
+        )
 
     def _set_base_frequency_control_word(self, control_word: typing.List[int]) -> None:
-        self._write_burst(start_register=self._SPIAddress.FREQ2, values=control_word)
+        self._write_burst(
+            start_register=ConfigurationRegisterAddress.FREQ2, values=control_word
+        )
 
     def get_base_frequency_hertz(self) -> float:
         return self._frequency_control_word_to_hertz(
@@ -313,12 +312,12 @@ class CC1101:
         packet length in fixed packet length mode,
         maximum packet length in variable packet length mode.
         """
-        return self._read_burst(start_register=self._SPIAddress.PKTLEN, length=1)[0]
+        return self._read_single_byte(ConfigurationRegisterAddress.PKTLEN)
 
-    def _flush_tx_fifo_buffer(self) -> str:
+    def _flush_tx_fifo_buffer(self) -> None:
         # > Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states.
         _LOGGER.debug("flushing tx fifo buffer")
-        self._command_strobe(self._SPIAddress.SFTX)
+        self._command_strobe(StrobeAddress.SFTX)
 
     def transmit(self, payload: typing.List[int]) -> None:
         # see "15.2 Packet Format"
@@ -345,6 +344,6 @@ class CC1101:
                 + "\npayload: {}".format(payload)
             )
         self._flush_tx_fifo_buffer()
-        self._write_burst(self._SPIAddress.TXFIFO, payload)
+        self._write_burst(FIFORegisterAddress.TX, payload)
         _LOGGER.info("transmitting %s", payload)
-        self._command_strobe(self._SPIAddress.STX)
+        self._command_strobe(StrobeAddress.STX)

+ 94 - 0
cc1101/addresses.py

@@ -0,0 +1,94 @@
+import enum
+
+
+class StrobeAddress(enum.IntEnum):
+    # see "Table 42: Command Strobes"
+    SRES = 0x30
+    SFSTXON = 0x31
+    SXOFF = 0x32
+    SCAL = 0x33
+    SRX = 0x34
+    STX = 0x35
+    SIDLE = 0x36
+    SWOR = 0x38
+    SPWD = 0x39
+    SFRX = 0x3A
+    SFTX = 0x3B
+    SWORRST = 0x3C
+    SNOP = 0x3D
+
+
+class ConfigurationRegisterAddress(enum.IntEnum):
+    # see "Table 43: Configuration Registers Overview"
+    IOCFG2 = 0x00  # GDO2 output pin configuration
+    IOCFG1 = 0x01  # GDO1 output pin configuration
+    IOCFG0 = 0x02  # GDO0 output pin configuration
+    FIFOTHR = 0x03  # RX FIFO and TX FIFO thresholds
+    SYNC1 = 0x04  # Sync word, high byte
+    SYNC0 = 0x05  # Sync word, low byte
+    PKTLEN = 0x06  # Packet length
+    PKTCTRL1 = 0x07  # Packet automation control
+    PKTCTRL0 = 0x08  # Packet automation control
+    ADDR = 0x09  # Device address
+    CHANNR = 0x0A  # Channel number
+    FSCTRL1 = 0x0B  # Frequency synthesizer control
+    FSCTRL0 = 0x0C  # Frequency synthesizer control
+    FREQ2 = 0x0D  # Frequency control word, high byte
+    FREQ1 = 0x0E  # Frequency control word, middle byte
+    FREQ0 = 0x0F  # Frequency control word, low byte
+    MDMCFG4 = 0x10  # Modem configuration
+    MDMCFG3 = 0x11  # Modem configuration
+    MDMCFG2 = 0x12  # Modem configuration
+    MDMCFG1 = 0x13  # Modem configuration
+    MDMCFG0 = 0x14  # Modem configuration
+    DEVIATN = 0x15  # Modem deviation setting
+    MCSM2 = 0x16  # Main Radio Control State Machine configuration
+    MCSM1 = 0x17  # Main Radio Control State Machine configuration
+    MCSM0 = 0x18  # Main Radio Control State Machine configuration
+    FOCCFG = 0x19  # Frequency Offset Compensation configuration
+    BSCFG = 0x1A  # Bit Synchronization configuration
+    AGCTRL2 = 0x1B  # AGC control
+    AGCTRL1 = 0x1C  # AGC control
+    AGCTRL0 = 0x1D  # AGC control
+    WOREVT1 = 0x1E  # High byte Event 0 timeout
+    WOREVT0 = 0x1F  # Low byte Event 0 timeout
+    WORCTRL = 0x20  # Wake On Radio control
+    FREND1 = 0x21  # Front end RX configuration
+    FREND0 = 0x22  # Front end TX configuration
+    FSCAL3 = 0x23  # Frequency synthesizer calibration
+    FSCAL2 = 0x24  # Frequency synthesizer calibration
+    FSCAL1 = 0x25  # Frequency synthesizer calibration
+    FSCAL0 = 0x26  # Frequency synthesizer calibration
+    RCCTRL1 = 0x27  # RC oscillator configuration
+    RCCTRL0 = 0x28  # RC oscillator configuration
+    FSTEST = 0x29  # Frequency synthesizer calibration control
+    PTEST = 0x2A  # Production test
+    AGCTEST = 0x2B  # AGC test
+    TEST2 = 0x2C  # Various test settings
+    TEST1 = 0x2D  # Various test settings
+    TEST0 = 0x2E  # Various test settings
+
+
+class StatusRegisterAddress(enum.IntEnum):
+    # see "Table 44: Status Registers Overview"
+    PARTNUM = 0x30  # Part number for CC1101
+    VERSION = 0x31  # Current version number
+    FREQEST = 0x32  # Frequency Offset Estimate
+    LQI = 0x33  # Demodulator estimate for Link Quality
+    RSSI = 0x34  # Received signal strength indication
+    MARCSTATE = 0x35  # Control state machine state
+    WORTIME1 = 0x36  # High byte of WOR timer
+    WORTIME0 = 0x37  # Low byte of WOR timer
+    PKTSTATUS = 0x38  # Current GDOx status and packet status
+    VCO_VC_DAC = 0x39  # Current setting from PLL calibration module
+    TXBYTES = 0x3A  # Underflow and number of bytes in the TX FIFO
+    RXBYTES = 0x3B  # Overflow and number of bytes in the RX FIFO
+    RCCTRL1_STATUS = 0x3C  # Last RC oscillator calibration result
+    RCCTRL0_STATUS = 0x3D  # Last RC oscillator calibration result
+
+
+class FIFORegisterAddress(enum.IntEnum):
+    # see "10.5 FIFO Access"
+    # > When the R/W-bit is zero, the TX FIFO is accessed,
+    # > and the RX FIFO is accessed when the R/W-bit is one.
+    TX = RX = 0x3F