diff --git a/RP2040_I2C_Registers.py b/RP2040_I2C_Registers.py deleted file mode 100644 index a863473..0000000 --- a/RP2040_I2C_Registers.py +++ /dev/null @@ -1,302 +0,0 @@ -I2C_OFFSET = { - "I2C_IC_CON": 0x00000000, - "I2C_IC_TAR": 0x00000004, - "I2C_IC_SAR": 0x00000008, - "I2C_IC_DATA_CMD": 0x00000010, - "I2C_IC_SS_SCL_HCNT": 0x00000014, - "I2C_IC_SS_SCL_LCNT": 0x00000018, - "I2C_IC_FS_SCL_HCNT": 0x0000001c, - "I2C_IC_FS_SCL_LCNT": 0x00000020, - "I2C_IC_INTR_STAT": 0x0000002c, - "I2C_IC_INTR_MASK": 0x00000030, - "I2C_IC_RAW_INTR_STAT": 0x00000034, - "I2C_IC_RX_TL": 0x00000038, - "I2C_IC_TX_TL": 0x0000003c, - "I2C_IC_CLR_INTR": 0x00000040, - "I2C_IC_CLR_RX_UNDER": 0x00000044, - "I2C_IC_CLR_RX_OVER": 0x00000048, - "I2C_IC_CLR_TX_OVER": 0x0000004c, - "I2C_IC_CLR_RD_REQ": 0x00000050, - "I2C_IC_CLR_TX_ABRT": 0x00000054, - "I2C_IC_CLR_RX_DONE": 0x00000058, - "I2C_IC_CLR_ACTIVITY": 0x0000005c, - "I2C_IC_CLR_STOP_DET": 0x00000060, - "I2C_IC_CLR_START_DET": 0x00000064, - "I2C_IC_CLR_GEN_CALL": 0x00000068, - "I2C_IC_ENABLE": 0x0000006c, - "I2C_IC_STATUS": 0x00000070, - "I2C_IC_TXFLR": 0x00000074, - "I2C_IC_RXFLR": 0x00000078, - "I2C_IC_SDA_HOLD": 0x0000007c, - "I2C_IC_TX_ABRT_SOURCE": 0x00000080, - "I2C_IC_SLV_DATA_NACK_ONLY": 0x00000084, - "I2C_IC_DMA_CR": 0x00000088, - "I2C_IC_DMA_TDLR": 0x0000008c, - "I2C_IC_DMA_RDLR": 0x00000090, - "I2C_IC_SDA_SETUP": 0x00000094, - "I2C_IC_ACK_GENERAL_CALL": 0x00000098, - "I2C_IC_ENABLE_STATUS": 0x0000009c, - "I2C_IC_FS_SPKLEN": 0x000000a0, - "I2C_IC_CLR_RESTART_DET": 0x000000a8, - "I2C_IC_COMP_PARAM_1": 0x000000f4, - "I2C_IC_COMP_VERSION": 0x000000f8, - "I2C_IC_COMP_TYPE": 0x000000fc, -} - - - - -I2C_IC_CON = { - 0x00000400: "STOP_DET_IF_MASTER_ACTIVE", # Master issues the STOP_DET interrupt irrespective of whether... - 0x00000200: "RX_FIFO_FULL_HLD_CTRL", # This bit controls whether DW_apb_i2c should hold the bus when the Rx... - 0x00000100: "TX_EMPTY_CTRL", # This bit controls the generation of the TX_EMPTY interrupt, as described in... - 0x00000080: "STOP_DET_IFADDRESSED", # In slave mode: - 1'b1: issues the STOP_DET interrupt only when it is... - 0x00000040: "IC_SLAVE_DISABLE", # This bit controls whether I2C has its slave disabled, which means once... - 0x00000020: "IC_RESTART_EN", # Determines whether RESTART conditions may be sent when acting as a master. - 0x00000010: "IC_10BITADDR_MASTER", # Controls whether the DW_apb_i2c starts its transfers in 7- or 10-bit... - 0x00000008: "IC_10BITADDR_SLAVE", # When acting as a slave, this bit controls whether the DW_apb_i2c... - 0x00000006: "SPEED", # These bits control at which speed the DW_apb_i2c operates; its setting is relevant... - 0x00000001: "MASTER_MODE", # This bit controls whether the DW_apb_i2c master is enabled. -} - -I2C_IC_TAR = { - 0x00000800: "SPECIAL", # This bit indicates whether software performs a Device-ID or General Call or START... - 0x00000400: "GC_OR_START", # If bit 11 (SPECIAL) is set to 1 and bit 13(Device-ID) is set to 0, then this... - 0x000003FF: "IC_TAR", # This is the target address for any master transaction -} - -I2C_IC_SAR = { - 0x000003FF: "IC_SAR", # The IC_SAR holds the slave address when the I2C is operating as a slave -} - -I2C_IC_DATA_CMD = { - 0x00000800: "FIRST_DATA_BYTE", # Indicates the first data byte received after the address phase for receive... - 0x00000400: "RESTART", # This bit controls whether a RESTART is issued before the byte is sent or received - 0x00000200: "STOP", # This bit controls whether a STOP is issued after the byte is sent or received - 0x00000100: "CMD", # This bit controls whether a read or a write is performed - 0x000000FF: "DAT", # This register contains the data to be transmitted or received on the I2C bus -} - -I2C_IC_SS_SCL_HCNT = { - 0x0000FFFF: "IC_SS_SCL_HCNT", # This register must be set before any I2C bus transaction can take place... -} - -I2C_IC_SS_SCL_LCNT = { - 0x0000FFFF: "IC_SS_SCL_LCNT", # This register must be set before any I2C bus transaction can take place... -} - -I2C_IC_FS_SCL_HCNT = { - 0x0000FFFF: "IC_FS_SCL_HCNT", # This register must be set before any I2C bus transaction can take place... -} - -I2C_IC_FS_SCL_LCNT = { - 0x0000FFFF: "IC_FS_SCL_LCNT", # This register must be set before any I2C bus transaction can take place... -} - -I2C_IC_INTR_STAT = { - 0x00001000: "R_RESTART_DET", # See IC_RAW_INTR_STAT for a detailed description of R_RESTART_DET bit - 0x00000800: "R_GEN_CALL", # See IC_RAW_INTR_STAT for a detailed description of R_GEN_CALL bit - 0x00000400: "R_START_DET", # See IC_RAW_INTR_STAT for a detailed description of R_START_DET bit - 0x00000200: "R_STOP_DET", # See IC_RAW_INTR_STAT for a detailed description of R_STOP_DET bit - 0x00000100: "R_ACTIVITY", # See IC_RAW_INTR_STAT for a detailed description of R_ACTIVITY bit - 0x00000080: "R_RX_DONE", # See IC_RAW_INTR_STAT for a detailed description of R_RX_DONE bit - 0x00000040: "R_TX_ABRT", # See IC_RAW_INTR_STAT for a detailed description of R_TX_ABRT bit - 0x00000020: "R_RD_REQ", # See IC_RAW_INTR_STAT for a detailed description of R_RD_REQ bit - 0x00000010: "R_TX_EMPTY", # See IC_RAW_INTR_STAT for a detailed description of R_TX_EMPTY bit - 0x00000008: "R_TX_OVER", # See IC_RAW_INTR_STAT for a detailed description of R_TX_OVER bit - 0x00000004: "R_RX_FULL", # See IC_RAW_INTR_STAT for a detailed description of R_RX_FULL bit - 0x00000002: "R_RX_OVER", # See IC_RAW_INTR_STAT for a detailed description of R_RX_OVER bit - 0x00000001: "R_RX_UNDER", # See IC_RAW_INTR_STAT for a detailed description of R_RX_UNDER bit -} - -I2C_IC_INTR_MASK = { - 0x00001000: "M_RESTART_DET", # This bit masks the R_RESTART_DET interrupt in IC_INTR_STAT register - 0x00000800: "M_GEN_CALL", # This bit masks the R_GEN_CALL interrupt in IC_INTR_STAT register - 0x00000400: "M_START_DET", # This bit masks the R_START_DET interrupt in IC_INTR_STAT register - 0x00000200: "M_STOP_DET", # This bit masks the R_STOP_DET interrupt in IC_INTR_STAT register - 0x00000100: "M_ACTIVITY", # This bit masks the R_ACTIVITY interrupt in IC_INTR_STAT register - 0x00000080: "M_RX_DONE", # This bit masks the R_RX_DONE interrupt in IC_INTR_STAT register - 0x00000040: "M_TX_ABRT", # This bit masks the R_TX_ABRT interrupt in IC_INTR_STAT register - 0x00000020: "M_RD_REQ", # This bit masks the R_RD_REQ interrupt in IC_INTR_STAT register - 0x00000010: "M_TX_EMPTY", # This bit masks the R_TX_EMPTY interrupt in IC_INTR_STAT register - 0x00000008: "M_TX_OVER", # This bit masks the R_TX_OVER interrupt in IC_INTR_STAT register - 0x00000004: "M_RX_FULL", # This bit masks the R_RX_FULL interrupt in IC_INTR_STAT register - 0x00000002: "M_RX_OVER", # This bit masks the R_RX_OVER interrupt in IC_INTR_STAT register - 0x00000001: "M_RX_UNDER", # This bit masks the R_RX_UNDER interrupt in IC_INTR_STAT register -} - -I2C_IC_RAW_INTR_STAT = { - 0x00001000: "RESTART_DET", # Indicates whether a RESTART condition has occurred on the I2C interface when... - 0x00000800: "GEN_CALL", # Set only when a General Call address is received and it is acknowledged - 0x00000400: "START_DET", # Indicates whether a START or RESTART condition has occurred on the I2C interface... - 0x00000200: "STOP_DET", # Indicates whether a STOP condition has occurred on the I2C interface regardless... - 0x00000100: "ACTIVITY", # This bit captures DW_apb_i2c activity and stays set until it is cleared - 0x00000080: "RX_DONE", # When the DW_apb_i2c is acting as a slave-transmitter, this bit is set to 1 if the... - 0x00000040: "TX_ABRT", # This bit indicates if DW_apb_i2c, as an I2C transmitter, is unable to complete the... - 0x00000020: "RD_REQ", # This bit is set to 1 when DW_apb_i2c is acting as a slave and another I2C master is... - 0x00000010: "TX_EMPTY", # The behavior of the TX_EMPTY interrupt status differs based on the TX_EMPTY_CTRL... - 0x00000008: "TX_OVER", # Set during transmit if the transmit buffer is filled to IC_TX_BUFFER_DEPTH and the... - 0x00000004: "RX_FULL", # Set when the receive buffer reaches or goes above the RX_TL threshold in the... - 0x00000002: "RX_OVER", # Set if the receive buffer is completely filled to IC_RX_BUFFER_DEPTH and an... - 0x00000001: "RX_UNDER", # Set if the processor attempts to read the receive buffer when it is empty by... -} - -I2C_IC_RX_TL = { - 0x000000FF: "RX_TL", # Receive FIFO Threshold Level -} - -I2C_IC_TX_TL = { - 0x000000FF: "TX_TL", # Transmit FIFO Threshold Level -} - -I2C_IC_CLR_INTR = { - 0x00000001: "CLR_INTR", # Read this register to clear the combined interrupt, all individual interrupts,... -} - -I2C_IC_CLR_RX_UNDER = { - 0x00000001: "CLR_RX_UNDER", # Read this register to clear the RX_UNDER interrupt (bit 0) of the... -} - -I2C_IC_CLR_RX_OVER = { - 0x00000001: "CLR_RX_OVER", # Read this register to clear the RX_OVER interrupt (bit 1) of the... -} - -I2C_IC_CLR_TX_OVER = { - 0x00000001: "CLR_TX_OVER", # Read this register to clear the TX_OVER interrupt (bit 3) of the... -} - -I2C_IC_CLR_RD_REQ = { - 0x00000001: "CLR_RD_REQ", # Read this register to clear the RD_REQ interrupt (bit 5) of the... -} - -I2C_IC_CLR_TX_ABRT = { - 0x00000001: "CLR_TX_ABRT", # Read this register to clear the TX_ABRT interrupt (bit 6) of the... -} - -I2C_IC_CLR_RX_DONE = { - 0x00000001: "CLR_RX_DONE", # Read this register to clear the RX_DONE interrupt (bit 7) of the... -} - -I2C_IC_CLR_ACTIVITY = { - 0x00000001: "CLR_ACTIVITY", # Reading this register clears the ACTIVITY interrupt if the I2C is not active anymore -} - -I2C_IC_CLR_STOP_DET = { - 0x00000001: "CLR_STOP_DET", # Read this register to clear the STOP_DET interrupt (bit 9) of the... -} - -I2C_IC_CLR_START_DET = { - 0x00000001: "CLR_START_DET", # Read this register to clear the START_DET interrupt (bit 10) of the... -} - -I2C_IC_CLR_GEN_CALL = { - 0x00000001: "CLR_GEN_CALL", # Read this register to clear the GEN_CALL interrupt (bit 11) of... -} - -I2C_IC_ENABLE = { - 0x00000004: "TX_CMD_BLOCK", # In Master mode: - 1'b1: Blocks the transmission of data on I2C bus even if Tx... - 0x00000002: "ABORT", # When set, the controller initiates the transfer abort - 0x00000001: "ENABLE", # Controls whether the DW_apb_i2c is enabled -} - -I2C_IC_STATUS = { - 0x00000040: "SLV_ACTIVITY", # Slave FSM Activity Status - 0x00000020: "MST_ACTIVITY", # Master FSM Activity Status - 0x00000010: "RFF", # Receive FIFO Completely Full - 0x00000008: "RFNE", # Receive FIFO Not Empty - 0x00000004: "TFE", # Transmit FIFO Completely Empty - 0x00000002: "TFNF", # Transmit FIFO Not Full - 0x00000001: "ACTIVITY", # I2C Activity Status -} - -I2C_IC_TXFLR = { - 0x0000001F: "TXFLR", # Transmit FIFO Level -} - -I2C_IC_RXFLR = { - 0x0000001F: "RXFLR", # Receive FIFO Level -} - -I2C_IC_SDA_HOLD = { - 0x00FF0000: "IC_SDA_RX_HOLD", # Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c... - 0x0000FFFF: "IC_SDA_TX_HOLD", # Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c... -} - -I2C_IC_TX_ABRT_SOURCE = { - 0xFF800000: "TX_FLUSH_CNT", # This field indicates the number of Tx FIFO Data Commands which are flushed... - 0x00010000: "ABRT_USER_ABRT", # This is a master-mode-only bit - 0x00008000: "ABRT_SLVRD_INTX", # 1: When the processor side responds to a slave mode request for data to be... - 0x00004000: "ABRT_SLV_ARBLOST", # This field indicates that a Slave has lost the bus while transmitting... - 0x00002000: "ABRT_SLVFLUSH_TXFIFO", # This field specifies that the Slave has received a read command and... - 0x00001000: "ARB_LOST", # This field specifies that the Master has lost arbitration, or if... - 0x00000800: "ABRT_MASTER_DIS", # This field indicates that the User tries to initiate a Master operation... - 0x00000400: "ABRT_10B_RD_NORSTRT", # This field indicates that the restart is disabled (IC_RESTART_EN bit... - 0x00000200: "ABRT_SBYTE_NORSTRT", # To clear Bit 9, the source of the ABRT_SBYTE_NORSTRT must be fixed... - 0x00000100: "ABRT_HS_NORSTRT", # This field indicates that the restart is disabled (IC_RESTART_EN bit... - 0x00000080: "ABRT_SBYTE_ACKDET", # This field indicates that the Master has sent a START Byte and the START... - 0x00000040: "ABRT_HS_ACKDET", # This field indicates that the Master is in High Speed mode and the High... - 0x00000020: "ABRT_GCALL_READ", # This field indicates that DW_apb_i2c in the master mode has sent a General... - 0x00000010: "ABRT_GCALL_NOACK", # This field indicates that DW_apb_i2c in master mode has sent a General... - 0x00000008: "ABRT_TXDATA_NOACK", # This field indicates the master-mode only bit - 0x00000004: "ABRT_10ADDR2_NOACK", # This field indicates that the Master is in 10-bit address mode and that... - 0x00000002: "ABRT_10ADDR1_NOACK", # This field indicates that the Master is in 10-bit address mode and the... - 0x00000001: "ABRT_7B_ADDR_NOACK", # This field indicates that the Master is in 7-bit addressing mode and... -} - -I2C_IC_SLV_DATA_NACK_ONLY = { - 0x00000001: "NACK", # Generate NACK -} - -I2C_IC_DMA_CR = { - 0x00000002: "TDMAE", # Transmit DMA Enable - 0x00000001: "RDMAE", # Receive DMA Enable -} - -I2C_IC_DMA_TDLR = { - 0x0000000F: "DMATDL", # Transmit Data Level -} - -I2C_IC_DMA_RDLR = { - 0x0000000F: "DMARDL", # Receive Data Level -} - -I2C_IC_SDA_SETUP = { - 0x000000FF: "SDA_SETUP", # SDA Setup -} - -I2C_IC_ACK_GENERAL_CALL = { - 0x00000001: "ACK_GEN_CALL", # ACK General Call -} - -I2C_IC_ENABLE_STATUS = { - 0x00000004: "SLV_RX_DATA_LOST", # Slave Received Data Lost - 0x00000002: "SLV_DISABLED_WHILE_BUSY", # Slave Disabled While Busy (Transmit, Receive) - 0x00000001: "IC_EN", # ic_en Status -} - -I2C_IC_FS_SPKLEN = { - 0x000000FF: "IC_FS_SPKLEN", # I2C SS, FS or FM+ spike suppression limit -} - -I2C_IC_CLR_RESTART_DET = { - 0x00000001: "CLR_RESTART_DET", # Clear RESTART_DET Interrupt Register -} - -I2C_IC_COMP_PARAM_1 = { - 0x00FF0000: "TX_BUFFER_DEPTH", # TX Buffer Depth = 16 - 0x0000FF00: "RX_BUFFER_DEPTH", # RX Buffer Depth = 16 - 0x00000080: "ADD_ENCODED_PARAMS", # Encoded parameters not visible - 0x00000040: "HAS_DMA", # DMA handshaking signals are enabled - 0x00000020: "INTR_IO", # COMBINED Interrupt outputs - 0x00000010: "HC_COUNT_VALUES", # Programmable count values for each mode - 0x0000000C: "MAX_SPEED_MODE", # MAX SPEED MODE = FAST MODE - 0x00000003: "APB_DATA_WIDTH", # APB data bus width is 32 bits -} - -I2C_IC_COMP_VERSION = { - 0xFFFFFFFF: "IC_COMP_VERSION", # IC_COMP_VERSION = 0x3230312a -} - -I2C_IC_COMP_TYPE = { - 0xFFFFFFFF: "IC_COMP_TYPE", # IC_COMP_TYPE = 0x44570140 (Designware Component Type number = 0x44_57_01_40) -} diff --git a/RP2040_Slave.py b/RP2040_Slave.py deleted file mode 100644 index 1067e31..0000000 --- a/RP2040_Slave.py +++ /dev/null @@ -1,306 +0,0 @@ -### i2cSlave.py -from machine import mem32 -from RP2040_I2C_Registers import* - - -class i2c_slave: - """ - RP2040 I2C Slave implementation using direct register access. - - This class implements an I2C slave interface for the RP2040 microcontroller, - allowing it to receive and transmit data as an I2C peripheral device. - """ - - I2C0_BASE = 0x40044000 - I2C1_BASE = 0x40048000 - IO_BANK0_BASE = 0x40014000 - - # Atomic Register Access - mem_rw = 0x0000 # Normal read/write access - mem_xor = 0x1000 # XOR on write - mem_set = 0x2000 # Bitmask set on write - mem_clr = 0x3000 # Bitmask clear on write - - - def get_Bits_Mask(self, bits, register): - """ This function return the bit mask based on bit name """ - bits_to_clear = bits - bit_mask = sum([key for key, value in register.items() if value in bits_to_clear]) - return bit_mask - - def RP2040_Write_32b_i2c_Reg(self, register, data, atr=0): - """ Write RP2040 I2C 32bits register """ - # < Base Addr > | < Atomic Register Access > | < Register > - mem32[self.i2c_base | atr | register] = data - - def RP2040_Set_32b_i2c_Reg(self, register, data): - """ Set bits in RP2040 I2C 32bits register """ - # < Base Addr > | 0x2000 | < Register > - self.RP2040_Write_32b_i2c_Reg(register, data, atr=self.mem_set) - - def RP2040_Clear_32b_i2c_Reg(self, register, data): - """ Clear bits in RP2040 I2C 32bits register """ - # < Base Addr > | 0x3000 | < Register > - self.RP2040_Write_32b_i2c_Reg(register, data, atr=self.mem_clr) - - def RP2040_Read_32b_i2c_Reg(self, offset): - """ Read RP2040 I2C 32bits register """ - return mem32[self.i2c_base | offset] - - def RP2040_Get_32b_i2c_Bits(self, offset, bit_mask): - return mem32[self.i2c_base | offset] & bit_mask - - def __init__(self, i2cID=0, sda=0, scl=1, slaveAddress=0x41, enable_clock_stretch=True): - self.scl = scl - self.sda = sda - self.slaveAddress = slaveAddress - self.i2c_ID = i2cID - if self.i2c_ID == 0: - self.i2c_base = self.I2C0_BASE - else: - self.i2c_base = self.I2C1_BASE - - """ - I2C Slave Mode Intructions - https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf - - """ - - # 1. Disable the DW_apb_i2c by writing a ‘0’ to IC_ENABLE.ENABLE - self.RP2040_Clear_32b_i2c_Reg(I2C_OFFSET["I2C_IC_ENABLE"], - self.get_Bits_Mask("ENABLE", I2C_IC_ENABLE)) - - # 2. Write to the IC_SAR register (bits 9:0) to set the slave address. - # This is the address to which the DW_apb_i2c responds. - self.RP2040_Clear_32b_i2c_Reg(I2C_OFFSET["I2C_IC_SAR"], - self.get_Bits_Mask("IC_SAR", I2C_IC_SAR)) - - self.RP2040_Set_32b_i2c_Reg(I2C_OFFSET["I2C_IC_SAR"], - self.slaveAddress & self.get_Bits_Mask("IC_SAR", I2C_IC_SAR)) - - # 3. Write to the IC_CON register to specify which type of addressing is supported (7-bit or 10-bit by setting bit 3). - # Enable the DW_apb_i2c in slave-only mode by writing a ‘0’ into bit six (IC_SLAVE_DISABLE) and a ‘0’ to bit zero - # (MASTER_MODE). - - # Disable Master mode - self.RP2040_Clear_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CON"], - self.get_Bits_Mask("MASTER_MODE", I2C_IC_CON)) - - # Enable slave mode - self.RP2040_Clear_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CON"], - self.get_Bits_Mask("IC_SLAVE_DISABLE", I2C_IC_CON)) - - # Enable clock strech - if enable_clock_stretch: - self.RP2040_Set_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CON"], - self.get_Bits_Mask("RX_FIFO_FULL_HLD_CTRL", I2C_IC_CON)) - - - # 4. Enable the DW_apb_i2c by writing a ‘1’ to IC_ENABLE.ENABLE. - self.RP2040_Set_32b_i2c_Reg(I2C_OFFSET["I2C_IC_ENABLE"], - self.get_Bits_Mask("IC_ENABLE", I2C_IC_ENABLE)) - - # Reset GPIO0 function - mem32[ self.IO_BANK0_BASE | self.mem_clr | ( 4 + 8 * self.sda) ] = 0x1f - # Set GPIO0 as IC0_SDA function - mem32[ self.IO_BANK0_BASE | self.mem_set | ( 4 + 8 * self.sda) ] = 0x03 - - # Reset GPIO1 function - mem32[ self.IO_BANK0_BASE | self.mem_clr | ( 4 + 8 * self.scl) ] = 0x1f - # Set GPIO1 as IC0_SCL function - mem32[ self.IO_BANK0_BASE | self.mem_set | ( 4 + 8 * self.scl) ] = 3 - - class I2CStateMachine: - I2C_RECEIVE = 0 - I2C_REQUEST = 1 - I2C_FINISH = 2 - I2C_START = 3 - I2C_IDLE = 4 - - - class I2CTransaction: - - def __init__(self, address: int, data_byte: list): - self.address = address - self.data_byte = data_byte - - - - def handle_event(self): - """Optimized event detection by reading interrupt status register once""" - # Read entire interrupt status register in one operation - intr_stat = self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_INTR_STAT"]) - - # Check for restart condition - if intr_stat & self.get_Bits_Mask("R_RESTART_DET", I2C_IC_INTR_STAT): - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_RESTART_DET"]) - # Handle restart logic here - - # Check other conditions using the same intr_stat value - # I2C Master has abort the transactions - if (intr_stat & self.get_Bits_Mask("R_TX_ABRT", I2C_IC_INTR_STAT)): - # Clear int - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_TX_ABRT"]) - return i2c_slave.I2CStateMachine.I2C_FINISH - - # Last byte transmitted by I2C Slave but NACK from I2C Master - if (intr_stat & self.get_Bits_Mask("R_RX_DONE", I2C_IC_INTR_STAT)): - # Clear int - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_RX_DONE"]) - return i2c_slave.I2CStateMachine.I2C_FINISH - - # Start condition detected by I2C Slave - if (intr_stat & self.get_Bits_Mask("R_START_DET", I2C_IC_INTR_STAT)): - # Clear start detection - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_START_DET"]) - return i2c_slave.I2CStateMachine.I2C_START - - # Stop condition detected by I2C Slave - if (intr_stat & self.get_Bits_Mask("R_STOP_DET", I2C_IC_INTR_STAT)): - # Clear stop detection - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_STOP_DET"]) - return i2c_slave.I2CStateMachine.I2C_FINISH - - # Check if RX FIFO is not empty - if (self.RP2040_Get_32b_i2c_Bits(I2C_OFFSET["I2C_IC_STATUS"], - self.get_Bits_Mask("RFNE", I2C_IC_STATUS))): - - return i2c_slave.I2CStateMachine.I2C_RECEIVE - - # Check if Master is requesting data - if (intr_stat & self.get_Bits_Mask("R_RD_REQ", I2C_IC_INTR_STAT)): - - # Shall Wait until transfer is done, timing recommended 10 * fastest SCL clock period - # for 100 Khz = (1/100E3) * 10 = 100 uS - # for 400 Khz = (1/400E3) * 10 = 25 uS - - return i2c_slave.I2CStateMachine.I2C_REQUEST - - # Add at the end - return i2c_slave.I2CStateMachine.I2C_IDLE - - def is_Master_Req_Read(self): - """ Return status if I2C Master is requesting a read sequence """ - - # Check RD_REQ Interrupt bit (master wants to read data from the slave) - status = self.RP2040_Get_32b_i2c_Bits(I2C_OFFSET["I2C_IC_RAW_INTR_STAT"], - self.get_Bits_Mask("RD_REQ", I2C_IC_RAW_INTR_STAT)) - - if status : - return True - return False - - """ - def is_Master_Req_Seq_Write(self): - # Return true if I2C Master is requesting a sequential data writing - - # Check whether is FIRST_DATA_BYTE bit is active in IC_DATA_CMD. - first_data_byte_stat = self.RP2040_Get_32b_i2c_Bits(I2C_OFFSET["I2C_IC_DATA_CMD"], - self.get_Bits_Mask("FIRST_DATA_BYTE", I2C_IC_DATA_CMD)) - - # Check whether is STOP_DET_IFADDRESSED bit is active in IC_CON. - stop_stat = self.RP2040_Get_32b_i2c_Bits(I2C_OFFSET["I2C_IC_CON"], - self.get_Bits_Mask("STOP_DET_IFADDRESSED", I2C_IC_CON)) - - if (stop_stat): - # Clear stop bit int - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_STOP_DET"]) - - # Master sequential write true if FIRST_DATA_BYTE bit is active and no stop condition detected. - if first_data_byte_stat and not(stop_stat): - return True - return False - """ - - def Slave_Write_Data(self, data): - """ Write 8bits of data at destination of I2C Master """ - - # Send data - self.RP2040_Write_32b_i2c_Reg(I2C_OFFSET["I2C_IC_DATA_CMD"], data & - self.get_Bits_Mask("DAT", I2C_IC_DATA_CMD)) - - self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_CLR_RD_REQ"]) - - - def Available(self): - """ Return true if data has been received from I2C Master """ - - # Get RFNE Bit (Receive FIFO Not Empty) - return self.RP2040_Get_32b_i2c_Bits(I2C_OFFSET["I2C_IC_STATUS"], - self.get_Bits_Mask("RFNE", I2C_IC_STATUS)) - - - def Read_Data_Received(self): - """ Return data from I2C Master """ - - return self.RP2040_Read_32b_i2c_Reg(I2C_OFFSET["I2C_IC_DATA_CMD"]) & self.get_Bits_Mask("DAT", I2C_IC_DATA_CMD) - - def deinit(self): - """Disable the I2C slave and release pins""" - # Disable I2C interface - self.RP2040_Clear_32b_i2c_Reg(I2C_OFFSET["I2C_IC_ENABLE"], - self.get_Bits_Mask("ENABLE", I2C_IC_ENABLE)) - - # Reset GPIO pins back to default state - mem32[self.IO_BANK0_BASE | self.mem_clr | (4 + 8 * self.sda)] = 0x1f - mem32[self.IO_BANK0_BASE | self.mem_clr | (4 + 8 * self.scl)] = 0x1f - - -if __name__ == "__main__": - import machine - from machine import mem32 - - def main(): - data_buf = [] - addr = 0x00 - - # Create I2C slave instance - s_i2c = i2c_slave(0, sda=0, scl=1, slaveAddress=0x41, enable_clock_stretch=True) - state = i2c_slave.I2CStateMachine.I2C_IDLE - currentTransaction = i2c_slave.I2CTransaction(addr, data_buf) - - counter = 0 - - print("I2C Slave test") - try: - while True: - state = s_i2c.handle_event() - - if state == s_i2c.I2CStateMachine.I2C_START: - pass - - if state == s_i2c.I2CStateMachine.I2C_RECEIVE: - if currentTransaction.address == 0x00: - # First byte received is the register address - currentTransaction.address = s_i2c.Read_Data_Received() - - # Read all data byte received until RX FIFO is empty - while (s_i2c.Available()): - currentTransaction.data_byte.append(s_i2c.Read_Data_Received()) - # Virtually Increase register address - # s_i2c.I2CTransaction.address += 1 - - if state == s_i2c.I2CStateMachine.I2C_REQUEST: - # Send some dummy data back - while (s_i2c.is_Master_Req_Read()): - counter += 1 - s_i2c.Slave_Write_Data(counter) - - # Virtually Increase register address - # s_i2c.I2CTransaction.address += 1 - print ("Sendind data : ", counter) - - if state == s_i2c.I2CStateMachine.I2C_FINISH: - print ("Register : ", currentTransaction.address ,"Received : ", currentTransaction.data_byte) - - currentTransaction.address = 0x00 - currentTransaction.data_byte = [] - state= s_i2c.I2CStateMachine.I2C_IDLE - - - - except KeyboardInterrupt: - s_i2c.deinit() # Clean up when done - print("I2C slave stopped") - - main() \ No newline at end of file diff --git a/distance.py b/distance.py deleted file mode 100644 index ee712c2..0000000 --- a/distance.py +++ /dev/null @@ -1,84 +0,0 @@ -import machine -import time -from i2c_handler import I2CSlaveHandler, Packet - -class DistanceHandler(I2CSlaveHandler): - """ - I2C handler that responds to master requests by sending distance values - from an HC-SR04 ultrasonic sensor. - """ - - def __init__(self, i2c_id, sda, scl, slave_addr, trig_pin, echo_pin): - super().__init__(i2c_id, sda, scl, slave_addr) - self.trig = machine.Pin(trig_pin, machine.Pin.OUT) - self.echo = machine.Pin(echo_pin, machine.Pin.IN) - - def read_distance_mm(self): - """ - Measure distance using the HC-SR04 sensor. - Returns distance in millimeters as an integer. - """ - # Send a 10us pulse to trigger - self.trig.low() - time.sleep_us(2) - self.trig.high() - time.sleep_us(10) - self.trig.low() - - # Wait for echo high (timeout after 25ms) - timeout = 25000 - start = time.ticks_us() - while not self.echo.value(): - if time.ticks_diff(time.ticks_us(), start) > timeout: - return 0 # sensor error - t1 = time.ticks_us() - while self.echo.value(): - if time.ticks_diff(time.ticks_us(), t1) > timeout: - return 0 # sensor error - t2 = time.ticks_us() - - # Calculate duration and distance - duration = time.ticks_diff(t2, t1) - distance_mm = (duration * 100) // 582 - # HC-SR04: distance (mm) = duration (us) / 5.82 - - # Clamp to 0..65535 - return max(0, min(distance_mm, 65535)) - - def process_request(self): - """ - Called when master requests data. Responds with a packet containing distance. - Packet format: - Byte 0: 0x01 (distance command) - Byte 1: reserved - Byte 2-3: distance (uint16, mm, little-endian) - Byte 4-6: reserved - Byte 7: checksum (xor of bytes 0-6) - """ - #dist = self.read_distance_mm() - dist = 155 - data = [0] * Packet.LENGTH - data[0] = 0x01 # Command: distance - data[2] = dist & 0xFF # Low byte - data[3] = (dist >> 8) & 0xFF # High byte - - # Checksum: XOR of bytes 0-6 - cs = 0 - for b in data[:-1]: - cs ^= b - data[7] = cs - - print(Packet.from_bytes(data)) - return Packet.from_bytes(data) - -def main(): - handler = DistanceHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x41, trig_pin=3, echo_pin=2) - print("Distance handler I2C slave started") - try: - handler.handle() - except KeyboardInterrupt: - handler.deinit() - print("I2C slave stopped") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/i2c_handler.py b/i2c_handler.py deleted file mode 100644 index f3f7698..0000000 --- a/i2c_handler.py +++ /dev/null @@ -1,124 +0,0 @@ -import machine -from RP2040_Slave import i2c_slave - -# === Packet Definition === -class Packet: - """Represents an 8-byte I2C packet.""" - LENGTH = 8 - - def __init__(self, data=None): - if data is None: - data = [0] * self.LENGTH - if len(data) != self.LENGTH: - raise ValueError(f"Packet must be {self.LENGTH} bytes") - self.bytes = data - - @classmethod - def from_bytes(cls, byte_list): - """Create Packet from list of bytes.""" - return cls(byte_list[:cls.LENGTH]) - - def __getitem__(self, idx): - return self.bytes[idx] - - def __setitem__(self, idx, value): - self.bytes[idx] = value - - def __repr__(self): - fields = [f"Byte {i}: 0x{b:02X}" for i, b in enumerate(self.bytes)] - return "\n".join(fields) - - def as_list(self): - return self.bytes - - def is_valid(self): - """Verify checksum (XOR of bytes 0-6 equals byte 7).""" - cs = 0 - for b in self.bytes[:-1]: - cs ^= b - return cs == self.bytes[-1] - -# === I2C Slave Handler === -class I2CSlaveHandler: - def __init__(self, i2c_id, sda, scl, slave_addr): - self.s_i2c = i2c_slave(i2c_id, sda=sda, scl=scl, slaveAddress=slave_addr) - self.packet_buf = [] - self.response_buf = None - self.response_idx = 0 - - def handle(self): - state = self.s_i2c.I2CStateMachine.I2C_IDLE - while True: - state = self.s_i2c.handle_event() - - if state == self.s_i2c.I2CStateMachine.I2C_RECEIVE: - while self.s_i2c.Available(): - byte = self.s_i2c.Read_Data_Received() - self.packet_buf.append(byte) - #print(f"Received byte: 0x{byte:02X}") - - # Only process when full packet is received - if len(self.packet_buf) == Packet.LENGTH: - packet = Packet.from_bytes(self.packet_buf) - print("Received 8-byte packet:") - print(packet) - print("Packet valid:", packet.is_valid()) - self.process_packet(packet) - self.packet_buf = [] # Clear buffer after processing - - if state == self.s_i2c.I2CStateMachine.I2C_FINISH: - if self.packet_buf and len(self.packet_buf) < Packet.LENGTH: - #print(f"Incomplete packet ({len(self.packet_buf)} bytes): {[f'0x{b:02X}' for b in self.packet_buf]}") - print(f"Incomplete packet ({len(self.packet_buf)} bytes): {self.packet_buf}") - self.packet_buf = [] # Clear buffer on incomplete packet - state = self.s_i2c.I2CStateMachine.I2C_IDLE - - if state == self.s_i2c.I2CStateMachine.I2C_REQUEST: - print("Master requested data, sending response packet:") - #self.s_i2c.Slave_Write_Data(self.process_request().as_list()) - # Prepare response buffer if not set - if self.response_buf is None: - self.response_buf = self.process_request().as_list() - self.response_idx = 0 - print("Prepared response packet:", self.response_buf) - - # Send next byte - if self.response_idx < Packet.LENGTH: - self.s_i2c.Slave_Write_Data(self.response_buf[self.response_idx]) - print("write") - self.response_idx += 1 - else: - # Reset response for next transaction - self.response_buf = None - self.response_idx = 0 - - def process_packet(self, packet): - """Override this method to process packets.""" - # Example: Print command/type and target/channel - cmd = packet[0] - target = packet[1] - print(f"Command/Type: 0x{cmd:02X}, Target/Channel: 0x{target:02X}") - # Add custom logic for your robot here - - def process_request(self): - """Override this method to process requests""" - return Packet.from_bytes([0x12, 0, 0, 0, 0, 0, 0, 0]) - - def deinit(self): - self.s_i2c.deinit() - -# === Example usage for RP2040 === -def main(): - # Change slaveAddress as needed for each RP2040 - SLAVE_ADDR = 0x41 - - handler = I2CSlaveHandler(i2c_id=0, sda=0, scl=1, slave_addr=SLAVE_ADDR) - print(f"I2C Slave started at address 0x{SLAVE_ADDR:02X}") - try: - handler.handle() - except KeyboardInterrupt: - handler.deinit() - print("I2C slave stopped") - -if __name__ == "__main__": - main() diff --git a/led.py b/led.py deleted file mode 100644 index 7e67a63..0000000 --- a/led.py +++ /dev/null @@ -1,36 +0,0 @@ -from i2c_handler import I2CSlaveHandler, Packet -import neopixel - -class LedDistanceHandler(I2CSlaveHandler): - def __init__(self, i2c_id, sda, scl, slave_addr): - super().__init__(i2c_id, sda, scl, slave_addr) - self.last_led_color = (0, 0, 0) # RGB tuple - self.np = neopixel.NeoPixel(machine.Pin(23), 1) - - def process_packet(self, packet: Packet): - cmd = packet[0] - # Assume LED color command is 0x10, RGB in bytes 2,3,4 - if cmd == 0x10: # Set LED Color - r = packet[2] - g = packet[3] - b = packet[4] - self.last_led_color = (r, g, b) - print(f"Set LED color to RGB({r},{g},{b})") - # TODO: Set the hardware LED to this color - self.np[0] = self.last_led_color - self.np.write() - else: - print(f"Unknown command 0x{cmd:02X}") - self.response_packet = None - -def main(): - handler = LedDistanceHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x41) - print("LED/Distance handler I2C slave started") - try: - handler.handle() - except KeyboardInterrupt: - handler.deinit() - print("I2C slave stopped") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/usage.py b/usage.py deleted file mode 100644 index f39b27b..0000000 --- a/usage.py +++ /dev/null @@ -1,40 +0,0 @@ -from i2c_handler import I2CSlaveHandler, Packet - -class MyRobotHandler(I2CSlaveHandler): - def process_packet(self, packet: Packet): - """ - Example: Override process_packet to perform actions based on packet command/type. - """ - cmd = packet[0] - target = packet[1] - speed = (packet[2] << 8) | packet[3] - # Convert speed from unsigned to signed if needed - if speed & 0x8000: - speed -= 0x10000 - - print(f"Custom handler: Command 0x{cmd:02X}, Target 0x{target:02X}, Speed {speed}") - - # Example: Perform a motor action for command 0x01 - if cmd == 0x01: # Set Motor Speed - print(f"Setting motor {target} speed to {speed}") - # TODO: Add your motor control code here - - elif cmd == 0xFF: # Emergency Stop - print("Emergency stop received!") - # TODO: Add your emergency stop code here - - else: - print("Unknown command") - -# Usage example -def main(): - handler = MyRobotHandler(i2c_id=0, sda=0, scl=1, slave_addr=0x41) - print("MyRobotHandler I2C slave started") - try: - handler.handle() - except KeyboardInterrupt: - handler.deinit() - print("I2C slave stopped") - -if __name__ == "__main__": - main() \ No newline at end of file