Dynamic configuration in sja1110 Hi, I would like to configure l2 lookup table dynamically how can I configure it ? Without using ECT tool how can I configure the l2 lookup table ? Any examples? Regards Atkinson Re: Dynamic configuration in sja1110 Hi @PavelL "In your code, there are missing shift values in entry[3], and missing or misplaced brackets in entry[3], entry[4], and entry[5]." I have implemented it as same as the python code sorry i am nots sure where i am missing the brackets and shift values. can you kindly provide me the aligned code which might be more clear sorry for missing out the brackets and shift It would be more helpful and clear if you provide me the exact entry[3],entry[4], entry[5] Re: Dynamic configuration in sja1110 Hello @Atkinson ,
In your code, there are missing shift values in entry[3], and missing or misplaced brackets in entry[3], entry[4], and entry[5].
To verify your L2 lookup configuration, you may consider setting the entry as a static one instead of dynamic — this can help isolate whether the issue is with the entry format or the dynamic update mechanism.
Also, please note that the "pretty tables" in the Python script are used only for formatting output in the command window — they do not affect the functionality or register configuration.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL int WriteL2LookupEntry(int cs) { const uint32_t DESTPORTS = 0x004; const uint32_t INDEX = 2; const uint64_t MACADDR = 0x112233445566; const uint64_t MACADDR_MASK = 0xffffffffffff; const uint32_t VLANID = 0; const uint32_t VLANID_MASK = 0x0; const uint32_t IOTAG = 0; const uint32_t IOTAG_MASK = 0; const uint32_t SRCPORT = 0x6; const uint32_t SRCPORT_MASK = 0xF; const uint32_t ENFPORT = 0; const uint32_t RETAG = 0; const uint32_t MIRROR = 0; const uint32_t TAKETS = 0; const uint32_t MIRR_VLAN = 0xFFF; const uint32_t TRAPTOHOST = 0; const uint32_t CBSIDIN = 0x3F; const uint32_t CBENONDA = 0; const uint32_t VLIDX = 0xFFF; const uint32_t SA_POLICE = 0; const uint32_t DA_POLICE = 0; uint32_t L2_OFFSET = 0x23; uint32_t L2CTRL_OFFSET = 0x29; const uint32_t SWREG_BASE = 0x00000000; const uint32_t VALID = 1U; const uint32_t RDWRSET = 1U; const uint32_t VALIDENT = 1U; const uint32_t HOSTCMD = 3U; const uint32_t MGMTROUTE = 0U; const uint32_t LOCKED = 1U; const uint32_t ERROR = 0U; uint32_t L2_ADDRESS = SWREG_BASE + L2_OFFSET; uint32_t L2_ADDRESS_CTL = SWREG_BASE + L2CTRL_OFFSET; uint32_t l2Entry[ADDRESS_RANGE] = {0}; l2Entry[0] = (((INDEX & 0x03ff) << (1 % 32)) + ((ENFPORT & 1) << (11 % 32)) + ((DESTPORTS & 0x7FF) << (12 % 32)) + ((SRCPORT & 0xF) << (23 % 32)) + ((MACADDR & 0x1F) << (27 % 32))); l2Entry[1] = (((MACADDR >> 5) & 0xFFFFFFFF)); l2Entry[2] = ((((MACADDR >> 37) & 0x7FF) << (64 % 32)) + ((VLANID & 0xFFF) << (75 % 32)) + ((IOTAG & 1) << (87 % 32)) + ((MACADDR_MASK & 0xFF) << (88 % 32))); l2Entry[3] = (((MACADDR_MASK >> 😎 & 0xFFFFFFFF)); l2Entry[4] = (((MACADDR_MASK >> 40) & 0xFF << (128 % 32)) + ((VLANID_MASK & 0xfff) << (136 % 32)) + ((IOTAG_MASK & 1) << (148 % 32)) + ((SRCPORT_MASK & 0xF) << (149 % 32)) + ((RETAG & 0x1) << (153 % 32)) + ((MIRROR & 0x1) << (154 % 32)) + ((TAKETS & 0x1) << (155 % 32)) + ((MIRR_VLAN & 0xF) << (156 % 32))); l2Entry[5] = (((MIRR_VLAN >> 4) & 0xFF << (160 % 32)) + ((TRAPTOHOST & 0x1) << (168 % 32)) + ((CBSIDIN & 0x3F) << (169 % 32)) + ((CBENONDA & 0x1) << (175 % 32)) + ((VLIDX & 0xFFF) << (177 % 32)) + ((SA_POLICE & 0x1) << (189 % 32)) + ((DA_POLICE & 0x1) << (190 % 32))); uint32_t status = 0; do { Std_ReturnType ret = spi_read_reg(L2_ADDRESS_CTL, &status); if (ret != E_OK) { return -1; } } while ((status >> VALID_BIT_SHIFT) & 1U); for (int i = 0; i < ADDRESS_RANGE; i++) { Std_ReturnType ret = spi_write_reg(L2_ADDRESS + i, l2Entry[i]); if (ret != E_OK) { return -2; } uint32_t readBack = 0; ret = spi_read_reg(L2_ADDRESS + i, &readBack); if (ret != E_OK || readBack != l2Entry[i]) { return -3; } } uint32_t controlL2Entry = 0; controlL2Entry = ((VALID << 31) + (RDWRSET << 30) + (ERROR << 29) + (LOCKED << 28) + (VALIDENT << 27) + (MGMTROUTE << 26) + (HOSTCMD << 23)); Std_ReturnType ret = spi_write_reg(L2_ADDRESS_CTL, controlL2Entry); if (ret != E_OK) { return -4; } do { ret = spi_read_reg(L2_ADDRESS_CTL, &status); if (ret != E_OK) { return -5; } } while ((status >> VALID_BIT_SHIFT) & 1U); return 0; } I have changed the implementation similar to Python script. if you found any errors can you send me the changes please Python script # Write Control platform.spi_write(L2_ADDRESS_CTL, controlL2Entry, cs) table = prettytable.PrettyTable( ("INDEX", "DESTPORTS", "MACADDR", "VLANID", "ENFPORT", "IOTAG")) entry = ( str(INDEX), '{0:11b}'.format(DESTPORTS), mac_to_str(MACADDR), str(VLANID), str(ENFPORT), str(IOTAG)) table.add_row(entry) print(table.get_string()) "After writing, try sending a frame that matches the MAC/VLAN/port criteria of the entry and observe whether it is forwarded according to the DESTPORTS field" I am trying to send in this way as you mentioned but this reflection is not seen I am unable to see my entry is getting reflected ? is there any other things need to be setted up ?? In Python script after writing the register value for controll2entry into L2_ADDRESS_CTL there were few lines of code which does adding a entry into "prettytable" Do we need to this also same and whether we have provision to do this ?? Re: Dynamic configuration in sja1110 Hello @Atkinson ,
There are missing shift values and incomplete expressions in entry[3], entry[4], and entry[5]. These may result in incorrect register values. I recommend comparing your logic against the Python reference script, which constructs the L2 entry correctly.
After writing, try sending a frame that matches the MAC/VLAN/port criteria of the entry and observe whether it is forwarded according to the DESTPORTS field.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL int WriteL2LookupEntry(int cs) { const uint32_t DESTPORTS = 0x002; const uint32_t INDEX = 8; const uint64_t MACADDR = 0x661122334455; const uint64_t MACADDR_MASK = 0xffffffffffff; const uint32_t VLANID = 0; const uint32_t VLANID_MASK = 0xfff; const uint32_t IOTAG = 0; const uint32_t IOTAG_MASK = 0; const uint32_t SRCPORT = 0x5; const uint32_t SRCPORT_MASK = 0xF; const uint32_t ENFPORT = 0; const uint32_t RETAG = 0; const uint32_t MIRROR = 0; const uint32_t TAKETS = 0; const uint32_t MIRR_VLAN = 0xFFF; const uint32_t TRAPTOHOST = 0; const uint32_t CBSIDIN = 0x3F; const uint32_t CBENONDA = 0; const uint32_t VLIDX = 0xFFF; const uint32_t SA_POLICE = 0; const uint32_t DA_POLICE = 0; uint32_t L2_OFFSET = 0x23; uint32_t L2CTRL_OFFSET = 0x29; const uint32_t SWREG_BASE = 0x00000000; const uint32_t VALID = 1U; const uint32_t RDWRSET = 1U; const uint32_t VALIDENT = 1U; const uint32_t HOSTCMD = 3U; const uint32_t MGMTROUTE = 0U; const uint32_t LOCKED = 1U; const uint32_t ERROR = 0U; uint32_t L2_ADDRESS = SWREG_BASE + L2_OFFSET; uint32_t L2_ADDRESS_CTL = SWREG_BASE + L2CTRL_OFFSET; uint32_t l2Entry[ADDRESS_RANGE] = {0}; l2Entry[0] = ((INDEX & 0x03FF) << 1) | ((ENFPORT & 0x1) << 11) | ((DESTPORTS & 0x7FF) << 12) | ((SRCPORT & 0xF) << 23) | ((uint32_t)(MACADDR & 0x1F) << 27); l2Entry[1] = (uint32_t)((MACADDR >> 5) & 0xFFFFFFFF); l2Entry[2] = (uint32_t)(((MACADDR >> 37) & 0x7FF) << 0) | ((VLANID & 0xFFF) << 11) | ((IOTAG & 0x1) << 23) | ((uint32_t)(MACADDR_MASK & 0xFF) << 24); l2Entry[3] = (uint32_t)((MACADDR_MASK >> 😎 & 0xFFFFFFFF); l2Entry[4] = ((uint32_t)((MACADDR_MASK >> 40) & 0xFF) << 0) | ((VLANID_MASK & 0xFFF) << 😎 | ((IOTAG_MASK & 0x1) << 20) | ((SRCPORT_MASK & 0xF) << 21) | ((RETAG & 0x1) << 25) | ((MIRROR & 0x1) << 26) | ((TAKETS & 0x1) << 27) | ((MIRR_VLAN & 0xF) << 28); l2Entry[5] = (((MIRR_VLAN >> 4) & 0xFF) << 0) | ((TRAPTOHOST & 0x1) << 😎 | ((CBSIDIN & 0x3F) << 9) | ((CBENONDA & 0x1) << 15) | ((VLIDX & 0xFFF) << 17) | ((SA_POLICE & 0x1) << 29) | ((DA_POLICE & 0x1) << 30); uint32_t status = 0; do { Std_ReturnType ret = spi_read_reg(L2_ADDRESS_CTL, &status); if (ret != E_OK) { return -1; } } while ((status >> VALID_BIT_SHIFT) & 1U); for (int i = 0; i < ADDRESS_RANGE; i++) { Std_ReturnType ret = spi_write_reg(L2_ADDRESS + i, l2Entry[i]); if (ret != E_OK) { return -2; } uint32_t readBack = 0; ret = spi_read_reg(L2_ADDRESS + i, &readBack); if (ret != E_OK || readBack != l2Entry[i]) { return -3; } } uint32_t controlL2Entry = 0; controlL2Entry |= (VALID << VALID_BIT_SHIFT); controlL2Entry |= (RDWRSET << RDWRSET_BIT_SHIFT); controlL2Entry |= (ERROR << ERROR_BIT_SHIFT); controlL2Entry |= (LOCKED << LOCKED_BIT_SHIFT); controlL2Entry |= (VALIDENT << VALIDENT_BIT_SHIFT); controlL2Entry |= (MGMTROUTE << MGMTROUTE_BIT_SHIFT); controlL2Entry |= (HOSTCMD << HOSTCMD_BIT_SHIFT); Std_ReturnType ret = spi_write_reg(L2_ADDRESS_CTL, controlL2Entry); if (ret != E_OK) { return -4; } do { ret = spi_read_reg(L2_ADDRESS_CTL, &status); if (ret != E_OK) { return -5; } } while ((status >> VALID_BIT_SHIFT) & 1U); return 0; } This is my revised code implementation can you verify once this implementation will bring a Dynamic Entry. so i tried debugging it by readingback the register value whether the values are getting written into the register i could able to see the values are written into the register but i am not sure whether the enrty is created or not ? and also the reflection of Dynamic entry of L2 lookup table is not getting reflected ? so how can i verify the L2 lookup table enrty is created ? Re: Dynamic configuration in sja1110 Hello @Atkinson ,
1. Bit Shift Syntax (<<, >>) It appears that some of the bit shift operators in your code were replaced with HTML entities like << and >>. This typically happens when code is copied into web-based platforms. Anyway, please check it directly in your code.
#define L2_CTRL_VALID_BIT (1U << 31)
should be: #define L2_CTRL_VALID_BIT (1U << 31)
2. Entry Issue There are several syntax errors and missing shift values in the CreateL2Entry() function, particularly in entry[3], entry[4], and entry[5]. These may result in incomplete or invalid register writes.
e.g.
((TRAPTOHOST & 0x1) << |
I recommend comparing your implementation against the Python reference script, which correctly constructs all six 32-bit words of the L2 entry.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL 3.)I have changed the Register address to #define L2_ENTRY0_ADDR 0x00000023 but still i am not able to identify the table which i am trying to add getting reflected when i transmit the message "If I understand correctly, you're referring to the L2 Lookup Table described in Table 1182 of UM11107. This table consists of six 32-bit registers per entry. You can see this structure reflected in the debug output from the Python script." So i am facing up with the issue in a way where i am trying to write the data into address which need to create a Dynamic Entry in L2 lookup table but its not creating a Dynamic Entry #define L2_ENTRY0_ADDR 0x00000023 #define L2_ENTRY1_ADDR 0x00000024 #define L2_ENTRY2_ADDR 0x00000025 #define L2_ENTRY3_ADDR 0x00000026 #define L2_ENTRY4_ADDR 0x00000027 #define L2_ENTRY5_ADDR 0x00000028 #define L2_CTRL_ADDR 0x00000029 #define L2_CTRL_VALID_BIT (1U << 31) #define L2_CTRL_WR_RDB_BIT (1U << 30) #define L2_CTRL_VALIDENTRY_BIT (1U << 28) #define L2_CTRL_HOSTCMD_SHIFT 23 #define L2_CTRL_HOSTCMD_WRITE (0b011U << L2_CTRL_HOSTCMD_SHIFT) Std_ReturnType CreateL2Entry(uint32_t entry[6]) { uint16_t INDEX = 11; uint64_t MACADDR = 0x661122334455; uint64_t MACADDR_MASK = 0xFFFFFFFFFFFF; uint16_t VLANID = 3; uint16_t VLANID_MASK = 0xFFF; uint8_t IOTAG = 0; uint8_t IOTAG_MASK = 0; uint8_t SRCPORT = 5; uint8_t SRCPORT_MASK = 0xF; uint8_t DESTPORTS = 0x02; uint8_t ENFPORT = 1; uint8_t RETAG = 0; uint8_t MIRROR = 0; uint8_t TAKETS = 0; uint16_t MIRR_VLAN = 0xFFF; uint8_t TRAPTOHOST = 0; uint8_t CBSIDIN = 0x3F; uint8_t CBENONDA = 0; uint16_t VLIDX = 0xFFF; uint8_t SA_POLICE = 0; uint8_t DA_POLICE = 0; entry[0] = ((INDEX & 0x03FF) << 1) | ((ENFPORT & 0x1) << 11) | ((DESTPORTS & 0x7FF) << 12) | ((SRCPORT & 0xF) << 23) | ((MACADDR & 0x1F) << 27); entry[1] = (uint32_t)((MACADDR >> 5) & 0xFFFFFFFF); entry[2] = (((MACADDR >> 37) & 0x7FF) << 0) | ((VLANID & 0xFFF) << 11) | ((IOTAG & 0x1) << 23) | ((MACADDR_MASK & 0xFF) << 24); entry[3] = (uint32_t)((MACADDR_MASK >> 😎 & 0xFFFFFFFF); entry[4] = (((MACADDR_MASK >> 40) & 0xFF) << 0) | ((VLANID_MASK & 0xFFF) << 😎 | ((IOTAG_MASK & 0x1) << 20) | ((SRCPORT_MASK & 0xF) << 21) | ((RETAG & 0x1) << 25) | ((MIRROR & 0x1) << 26) | ((TAKETS & 0x1) << 27) | ((MIRR_VLAN & 0xF) << 28); entry[5] = (((MIRR_VLAN >> 4) & 0xFF) << 0) | ((TRAPTOHOST & 0x1) << 😎 | ((CBSIDIN & 0x3F) << 9) | ((CBENONDA & 0x1) << 15) | ((VLIDX & 0xFFF) << 17) | ((SA_POLICE & 0x1) << 29) | ((DA_POLICE & 0x1) << 30); return E_OK; } Std_ReturnType WriteL2LookupEntry(uint8_t swt) { if (swt > 0) return E_NOT_OK; Std_ReturnType ret; uint32_t ctrlReg = 0; uint32_t entry[6]; // Step 1: Create the entry ret = CreateL2Entry(entry); if (ret != E_OK) return ret; // Step 2: Wait for VALID bit to clear do { ret = spi_read_reg(L2_CTRL_ADDR, &ctrlReg); if (ret != E_OK) return ret; } while (ctrlReg & L2_CTRL_VALID_BIT); // Step 3: Write entry data to registers ret = spi_write_reg(L2_ENTRY0_ADDR, entry[0]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY1_ADDR, entry[1]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY2_ADDR, entry[2]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY3_ADDR, entry[3]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY4_ADDR, entry[4]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY5_ADDR, entry[5]); if (ret != E_OK) return ret; // Step 4: Set control register to trigger write uint32_t ctrlValue = (1U << 31) | (1U << 30) | (1U << 28) | (1U << 27) | (3U << 23); ret = spi_write_reg(L2_CTRL_ADDR, ctrlValue); if (ret != E_OK) return ret; do { ret = spi_read_reg(L2_CTRL_ADDR, &ctrlReg); if (ret != E_OK) return ret; } while (ctrlReg & L2_CTRL_VALID_BIT); return E_OK; } can you check once whether any issues is there because its not creating Dynamic Entry for the L2 lookup Table ? Re: Dynamic configuration in sja1110 Hello @Atkinson ,
1. Yes, the host tools were originally developed for the SJA1110-EVM board. I personally use these scripts with debug prints to verify my understanding of register access. While you cannot run them directly on the S32G-VNP-RDB2 platform, the underlying logic can be adapted, since the S32G accesses the SJA1110 via SPI.
2. If you're looking for SPI read/write implementations for the S32G platform, you have two main options:
Refer to the SPI examples provided in the S32G RTD 4.0.0 package.
Alternatively, I recommend posting a dedicated question on the NXP S32G Community Forum, where the S32G support team can assist you further. I focus primarily on Automotive Ethernet topics, with limited overlap into platform-specific drivers.
3. If I understand correctly, you're referring to the L2 Lookup Table described in Table 1182 of UM11107. This table consists of six 32-bit registers per entry. You can see this structure reflected in the debug output from the Python script.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL I am having some certain questions 1.) This Debug print of l2_write_lookup_table.py was taken from SJA1110 EVM Board Implementation ryt its not from S32G-VNP RDB Board? and we can't implement l2_write_lookup_table.py in S32G-VNP-RDB32 Board directly 2.)can you provide me the code of SPI_read and Spi_write for integrating with the above code? because in through the implementation in S32G writing it via SPI_Read and SPI_write is doing the operation but unable to see the Dynamic Entry getting added Std_ReturnType spi_read_reg(uint32_t regAddress, uint32_t* regValue) { Std_ReturnType ret; uint32_t TxChBuf[65] = {0}; uint32_t RxChBuf[65] = {0}; uint16_t regCount = 1; Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 0U); ret = getSpiAPCommand(false, regAddress, regCount, TxChBuf, regValue); if (ret != E_OK) { Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 1U); return ret; } ret=Spi_SetupEB(5u, (uint8_t*)TxChBuf, (uint8_t*)RxChBuf, 8u); if (ret == E_OK) { ret=Spi_SyncTransmit(SpiConf_SpiSequence_SpiSequence_sja); if (ret == E_OK) { *regValue = RxChBuf[1]; } } Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 1U); return ret; } Std_ReturnType spi_write_reg(uint32_t regAddress, uint32_t regValue) { Std_ReturnType ret; uint32_t TxChBuf[65] = {0}; uint32_t RxChBuf[65] = {0}; uint16_t regCount = 1; uint32_t regValArray[1] = { regValue }; // Pull chip select LOW Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 0U); ret = getSpiAPCommand(true, regAddress, regCount, TxChBuf, regValArray); if (ret != E_OK) { Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 1U); return ret; } ret=Spi_SetupEB(5u, (uint8_t*)TxChBuf, (uint8_t*)RxChBuf, 8u); if (ret == E_OK) { ret=Spi_SyncTransmit(SpiConf_SpiSequence_SpiSequence_sja); } Siul2_Dio_Ip_WritePin(SPI_MCU_ES1_CS_AP_PORT, SPI_MCU_ES1_CS_AP_PIN, 1U); return ret; } Correct me if i am wrong !! 3.)I have changed the Register address to #define L2_ENTRY0_ADDR 0x00000023 but still i am not able to identify the table which i am trying to add getting reflected when i transmit the message Re: Dynamic configuration in sja1110 Hello @Atkinson ,
your code looks good. However, if you want to access dynamic tables by SPI, the entry addresses are without FF and shifted right by 2. As I already mentioned in some of my previous post.
So, #define L2_ENTRY0_ADDR 0xFF00008c should be #define L2_ENTRY0_ADDR 0x00000023
But it depends, what your routine spi_write_reg actually does.
Here is output of the write_l2_lookup_table.py , incl. my debug prints (tx/rx refers to data what would be seen on SPI wires by oscilloscope or by logic analyzer):
DBG spi_tx: ['0x02000290', '0xAABBCCDD'] DBG spi_rx: ['0x02000290', '0x00000000'] DBG spi_read 0x0029 -> 0x00000000 DBG spi_write 0x0023 <- 0x37FFFA00 DBG spi_tx: ['0x80000230', '0x37FFFA00'] DBG spi_write 0x0024 <- 0x119A22AB DBG spi_tx: ['0x80000240', '0x119A22AB'] DBG spi_write 0x0025 <- 0xFF807089 DBG spi_tx: ['0x80000250', '0xFF807089'] DBG spi_write 0x0026 <- 0xFFFFFFFF DBG spi_tx: ['0x80000260', '0xFFFFFFFF'] DBG spi_write 0x0027 <- 0xF1FFFFFF DBG spi_tx: ['0x80000270', '0xF1FFFFFF'] DBG spi_write 0x0028 <- 0x1FFE7EFF DBG spi_tx: ['0x80000280', '0x1FFE7EFF'] DBG spi_write 0x0029 <- 0xD9800000 DBG spi_tx: ['0x80000290', '0xD9800000'] +-------+-------------+-------------------+--------+---------+-------+ | INDEX | DESTPORTS | MACADDR | VLANID | ENFPORT | IOTAG | +-------+-------------+-------------------+--------+---------+-------+ | 256 | 11111111111 | 11:22:33:44:55:66 | 14 | 1 | 1 | +-------+-------------+-------------------+--------+---------+-------+ L2 Lookup Table Entry Written (SW1)
Regarding the FAE request, FAE is not on my escalation path. Your company has assigned FAE, so you can contact FAE directly.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL #define L2_ENTRY0_ADDR 0xFF00008c #define L2_ENTRY1_ADDR 0xFF000090 #define L2_ENTRY2_ADDR 0xFF000094 #define L2_ENTRY3_ADDR 0xFF000098 #define L2_ENTRY4_ADDR 0xFF00009C #define L2_ENTRY5_ADDR 0xFF0000A0 #define L2_CTRL_ADDR 0xFF0000A4 Std_ReturnType CreateL2Entry(uint32_t entry[6]) { uint16_t INDEX = 11; uint64_t MACADDR = 0x661122334455; uint64_t MACADDR_MASK = 0xFFFFFFFFFFFF; uint16_t VLANID = 3; uint16_t VLANID_MASK = 0xFFF; uint8_t IOTAG = 0; uint8_t IOTAG_MASK = 0; uint8_t SRCPORT = 5; uint8_t SRCPORT_MASK = 0xF; uint8_t DESTPORTS = 0x02; uint8_t ENFPORT = 1; uint8_t RETAG = 0; uint8_t MIRROR = 0; uint8_t TAKETS = 0; uint16_t MIRR_VLAN = 0xFFF; uint8_t TRAPTOHOST = 0; uint8_t CBSIDIN = 0x3F; uint8_t CBENONDA = 0; uint16_t VLIDX = 0xFFF; uint8_t SA_POLICE = 0; uint8_t DA_POLICE = 0; entry[0] = ((INDEX & 0x03FF) << 1) | ((ENFPORT & 0x1) << 11) | ((DESTPORTS & 0x7FF) << 12) | ((SRCPORT & 0xF) << 23) | ((MACADDR & 0x1F) << 27); entry[1] = (uint32_t)((MACADDR >> 5) & 0xFFFFFFFF); entry[2] = (((MACADDR >> 37) & 0x7FF) << 0) | ((VLANID & 0xFFF) << 11) | ((IOTAG & 0x1) << 23) | ((MACADDR_MASK & 0xFF) << 24); entry[3] = (uint32_t)((MACADDR_MASK >> 😎 & 0xFFFFFFFF); entry[4] = (((MACADDR_MASK >> 40) & 0xFF) << 0) | ((VLANID_MASK & 0xFFF) << 😎 | ((IOTAG_MASK & 0x1) << 20) | ((SRCPORT_MASK & 0xF) << 21) | ((RETAG & 0x1) << 25) | ((MIRROR & 0x1) << 26) | ((TAKETS & 0x1) << 27) | ((MIRR_VLAN & 0xF) << 28); entry[5] = (((MIRR_VLAN >> 4) & 0xFF) << 0) | ((TRAPTOHOST & 0x1) << 😎 | ((CBSIDIN & 0x3F) << 9) | ((CBENONDA & 0x1) << 15) | ((VLIDX & 0xFFF) << 17) | ((SA_POLICE & 0x1) << 29) | ((DA_POLICE & 0x1) << 30); return E_OK; } Std_ReturnType WriteL2LookupEntry(uint8_t swt) { if (swt > 0) return E_NOT_OK; Std_ReturnType ret; uint32_t ctrlReg = 0; uint32_t entry[6]; ret = CreateL2Entry(entry); if (ret != E_OK) return ret; do { ret = spi_read_reg(L2_CTRL_ADDR, &ctrlReg); if (ret != E_OK) return ret; } while (ctrlReg & (1U << 31)); ret = spi_write_reg(L2_ENTRY0_ADDR, entry[0]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY1_ADDR, entry[1]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY2_ADDR, entry[2]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY3_ADDR, entry[3]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY4_ADDR, entry[4]); if (ret != E_OK) return ret; ret = spi_write_reg(L2_ENTRY5_ADDR, entry[5]); if (ret != E_OK) return ret; uint32_t ctrlValue = (1U << 31) | (1U << 30) | (1U << 28) | (1U << 27) | (3U << 23); ret = spi_write_reg(L2_CTRL_ADDR, ctrlValue); if (ret != E_OK) return ret; do { ret = spi_read_reg(L2_CTRL_ADDR, &ctrlReg); if (ret != E_OK) return ret; } while (ctrlReg & (1U << 31)); return E_OK; } This was the current implementation for Creating a Dynamic Entry can you cross verify with FAE whether this implementation is correct !! Any other changes need to be done Re: Dynamic configuration in sja1110 Hello @Atkinson ,
Answers to your question are related to your application use case.
You can create a dynamic entry absolutely anywhere, also in S32G or in SJA1110:
transfer the entry in any supported way to the S32G and write it to SJA1110 via SPI, or via Ethernet
or, transfer the entry to the SJA1110 via Ethernet and use internal AHB access
or, send a custom trigger event (GPIO, Ethernet frame, ...) to the SJA1110, create a dynamic entry there and write the entry via AHB access
or, ....
or, ....
There are examples how to write dynamic entry to the switchcore of SJA1110:
via SPI - python script write_l2_lookup_table.py
via AHB - source code of ECT server
Bets regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL 1.) So this change of accessing the register for Dynamic configuration need to be done in S32G or SJA1110 switch ? 2.)if via SJA1110 switch whether reading and writing the register by SPI need to be performed and where this implementation need to be carried in between SWITCH_DRV? 3.) where we can create our Dynamic entry so that it will get append in switch More Explanation would be great help!! Re: Dynamic configuration in sja1110 Hello @Atkinson ,
I apologize for late response caused my current workload.
I understand it might not seem straightforward at first, but the concept is actually quite simple.
The final register address depends on the access method - whether you're accessing it internally via the M7 core over AHB, or externally via the SPI_AP interface. The base addresses differ depending on the access point.
The register address is calculated using the base address provided in Table 2 of UM11107. For example, for the switch subsystem, the base address is 0x00000000 for SPI_AP access and 0xFF000000 for AHB access.
In your case, the register 0x8C (DYN_BE_LKP_ENTRY0) becomes 0xFF00008C when accessed via AHB.
Now, here’s where it might get confusing: the SDK driver defines the following:
#define SJA1110_L2_ART_LE_ADDR (0x3fc00023) /**< Address of the l2ArtLockedEntry register *
The SWITCH_DRV_Write routine shifts the address left by 2 bits (<< 2) for internal (AHB) access. For SPI transfers (used in cascaded switch setups), no shift is applied. So, 0x3fc00023 << 2 results in 0xFF00008C.
I hope that with the explanation above, it makes sense now.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL can you give me the complete address for Reading and writing Address Name Access Reset Description 8Ch DYN_BE_LKP_ ENTRY0 R/W 0h (FFFFFFFEh) before 8ch what would be the base address? like for example it will have 0x3fc0008c so for this dynamic entry table we will have a complete address can you give me the complete address for 8Ch DYN_BE_LKP_ ENTRY0 R/W 0h (FFFFFFFEh) 90h DYN_BE_LKP_ ENTRY1 R/W 0h 94h DYN_BE_LKP_ ENTRY2 R/W 0h 98h DYN_BE_LKP_ ENTRY3 R/W 0h 9Ch DYN_BE_LKP_ ENTRY4 R/W 0h A0h DYN_BE_LKP_ ENTRY5 R/W 0h A4h DYN_BE_LKP_CTRL R/W 0h (FF800000h) Re: Dynamic configuration in sja1110 Hello @Atkinson ,
I'm not aware of any supporting documents - that's a general knowledge, device independent. I have consulted this topic with Copilot and it should be possible to modify sja11xx_ftdi4232.py to use DSPI5 instead of FTDI.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL To use this script with the S32G-VNP-RDB2 or RDB3 board, the FTDI layer would need to be modified to communicate via DSPI5 on the S32G processor. How to do that? is there any supporting documents? Re: Dynamic configuration in sja1110 Hello @Atkinson ,
Q1: "So since the Linux BSP is pre-installed on the SD Card... will it enable dynamic configuration automatically?" A1: No, the BSP includes the DSA driver, which supports dynamic configuration, but it is not automatically enabled for all use cases.
Q2: "For configuring the L2 lookup entry via Dynamically using the write_l2_lookup.py (python evm host tools) whether that process remains same ?or for S32G-VNP-RDB board it will change" A2: The general flow for creating and uploading a dynamic entry remains the same, as described in UM11107 and AN12925. However, the write_l2_lookup_table.py script uses the FTDI driver to access the SJA1110-EVM via USB. To use this script with the S32G-VNP-RDB2 or RDB3 board, the FTDI layer would need to be modified to communicate via DSPI5 on the S32G processor.
Q3: "Whether it is possible to interface Laptop & S32G-VNP_RDB32 board creating a Dynamic entry?" A3: Yes, it is possible. You are free to develop custom software running on Linux to handle your own protocol over SPI or Ethernet to configure dynamic entries.
Q4: "and one more thing whether SJA1110_SDK_1.0.2 is a main thing needed for implementing RTM1.0.0 would that be fine?" A4: No, it is recommended to use the latest version of SJA1110 SDK 1.0.2 for compatibility and stability.
For further support, please contact your FAE or submit a ticket via https://support.nxp.com/s/?language=en_US. Thank you for your understanding.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL So since the Linux BSP is pre-installed on the SD Card if the SD card is getting inserted into the S32G-VNP-RDB board. so whether the BSP which present in SD card which will be enabling Dynamic configuration automatically For configuring the L2 lookup entry via Dynamically using the write_l2_lookup.py (python evm host tools) whether that process remains same ?or for S32G-VNP-RDB board it will change If the Process remains same how can we interface laptop & RDB32Board when interfacing it via Laptop and SJA1110 EVM board it will be connected using USB interface which will help to configure it Dynamic entry So in the case of S32G-VNP-RDB32 Board How the interface will be? Whether it is possible to interface Laptop & S32G-VNP_RDB32 board creating a Dynamic entry? and one more thing whether SJA1110_SDK_1.0.2 is a main thing needed for implementing RTM1.0.0 would that be fine ? Re: Dynamic configuration in sja1110 Hello @Atkinson ,
The Linux BSP is already pre-installed on the SD card delivered with the S32G-VNP-RDB3 board, so no additional action is required in that regard.
I assume you have successfully brought up the board (apologies if you already mentioned this in previous messages).
The BSP includes the SJA1110 DSA driver, which provides a range of useful features — including support for dynamic L2 lookup table configuration. The DSA driver is enabled by default.
As this case has evolved into a multi-domain topic, I’ve reached out to your FAE to discuss how we should proceed further.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL I am currently trying to implement it in S32G-VNP-RDB32 -- SJA1110 Switch currently, I don't have any firmware on my own Which Linux BSP need to be utilized What might be the complete changes need to be done Re: Dynamic configuration in sja1110 Hello @Atkinson ,
If you're planning to do this from the S32G-VNP-RDB3 board, that changes things significantly. Will you be running the Linux BSP on the board, or do you plan to use your own firmware?
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL 3. SPI_HAP (Host Access Protocol) The write_l2_lookup_table.py script from the host tools demonstrates how to configure the L2 table dynamically via SPI. This approach can be used by any external MCU or host processor. The logic from this script can also be ported to run directly on the internal M7 core if needed. I am looking to configure an entry via write_l2_lookup_table.py via how the configuration which we written in write_l2_lookup_table.py file will be moving to the RDB32 Board what interface need to be done from laptop to RDB32Board? what are the communication mechanism through which we can pass our l2 lookup entry to the device (RDB32 Board) can you give me a procedure or where i can find the procedure for implementation Re: Dynamic configuration in sja1110 Hello @Atkinson ,
Yes, you're right — when the system boots, the static configuration is automatically loaded from external flash.
Let me clarify the concept of dynamic configuration in more detail.
The task of dynamic configuration can be split into two parts:
Assembling a valid entry — see UM11107, chapter 5.6 "Dynamic configuration"
Writing this entry to the switch — see AN12925, chapter 5.1.3.2 "Writing an L2 Lookup Table Entry"
There are three interfaces that can be used for this:
AHB — via the internal M7 core. SDK support is available, and the ECT server source code can serve as a starting point.
SPI_HAP — the host processor assembles a valid entry and writes it to the switch. This is what write_l2_lookup_table.py does.
Ethernet — the host processor sends a user-defined message (UDP, TCP, etc.), which is processed by the internal M7 core. The M7 decodes the message, assembles a valid entry, and writes it to the switch — so we’re effectively back to point 1. This is how ECT works internally.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hi @PavelL 3. SPI_HAP (Host Access Protocol) The write_l2_lookup_table.py script from the host tools demonstrates how to configure the L2 table dynamically via SPI. This approach can be used by any external MCU or host processor. The logic from this script can also be ported to run directly on the internal M7 core if needed. I am looking to configure an entry via write_l2_lookup_table.py via how the configuration which we written in write_l2_lookup_table.py file will be moving to the RDB32 Board what interface need to be done from laptop to RDB32Board? what are the communication mechanism through which we can pass our l2 lookup entry to the device (RDB32 Board) can you give me a procedure or where i can find the procedure for implementation Re: Dynamic configuration in sja1110 Hello @PavelL As you mentioned I would like to configure the switch_core configuration Dynamically When a System boots the static configuration which we configured in peripherals is getting loaded I am looking in a way to configure the Table entry which are configured in Static needs to be configured it via, Dynamically. In either case, there are generally three ways to update the switch configuration dynamically: From the internal M7 core From the host processor via SPI_HAP From the host processor via Ethernet so you are saying these are the only ways of updating the system dynamically ? if these are the only possible way, then configuring it in as a code which i provided will work or will not work ? and also the three process which mentioned here is it same as the ECT & write_l2_lookup_table.py? or these are different one !! Re: Dynamic configuration in sja1110 Hello @Atkinson ,
Could you please clarify your use case for using a dynamic L2 lookup table?
Personally, I would consider using dynamic entries in two typical scenarios:
When you want to maintain a common switch configuration across multiple devices and then "personalize" each switch dynamically after power-up.
When you need to modify the switch configuration at runtime based on application-specific requirements.
In either case, there are generally three ways to update the switch configuration dynamically:
From the internal M7 core
From the host processor via SPI_HAP
From the host processor via Ethernet
Does your use case fall into one of these categories, or are you aiming for something different?
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hello @PavelL As you mentioned it i tried incorporating the code can you confirm where do i need to place the code which will help us in creating the entry Earlier Message you have mentioned there were Two Methods via doing it using ECT (Ethernet configuration Tool) and SPI_HAP so these tools and files are needed to process on run -time ryt ?? The code which i shared is which i am trying to implement it without these tools I am looking to create a Dynamic L2 Lookup Entry whether it is fine to do ?? Regards Atkinson Re: Dynamic configuration in sja1110 Hello @Atkinson ,
I apologize for the delayed response due to public holidays.
Thank you for sharing your code. I had a quick look, and at first glance, it appears to align with the principles outlined in AN12925, chapter 5.1.3.2 Writing a L2 Lookup table entry. I also noticed that the #define statements seem to be reused from SJA1110.h, which is standard practice.
Please note, however, that an in-depth custom code review goes beyond the scope of our complimentary online support. Additionally, the timing and context in which this function should be called are highly application-specific and may vary depending on your system architecture and requirements.
Best regards,
Pavel Re: Dynamic configuration in sja1110 Hello @PavelL static status_t wait_for_valid_clear(uint8_t swt) { status_t status; uint32_t ctrl = 0; do { status = SWITCH_DRV_Read(swt, 1, DYN_BE_LKP_CTRL, &ctrl); if (status != STATUS_SUCCESS) return status; } while (ctrl & DYN_BE_LKP_CTRL_VALID_MASK); if (ctrl & DYN_BE_LKP_CTRL_ERROR_MASK) return STATUS_ERROR; return STATUS_SUCCESS; } status_t SJA1110_AddL2LookupEntry_Dynamic(uint8_t swt) { status_t status; // MAC = 66:11:22:33:44:55 uint8_t mac[6] = {0x66, 0x11, 0x22, 0x33, 0x44, 0x55}; uint64_t mac64 = ((uint64_t)mac[0] << 40) | ((uint64_t)mac[1] << 32) | ((uint64_t)mac[2] << 24) | ((uint64_t)mac[3] << 16) | ((uint64_t)mac[4] << 😎 | (uint64_t)mac[5]; // Prepare L2 lookup entry fields uint32_t entry[WORD_COUNT] = {0}; entry[0] = ((5 & 0xF) << 24) | (1 << 11); // SrcPort, DestPorts 1 & 2 entry[1] = (uint32_t)(mac64 & 0xFFFFFFFF); entry[2] = (uint32_t)((mac64 >> 32) & 0xFFFF); entry[2] |= (3 << 16); // VLAN ID = 3 entry[3] = 0; // Optional masks entry[4] = 0; entry[5] = (8 << 4) | (1 << 10); // CB_SID_IN = 8, CB_ON_DA = 1 // Wait until previous operation completes status = wait_for_valid_clear(swt); if (status != STATUS_SUCCESS) return status; // Write L2 entry data to registers status = SWITCH_DRV_Write(swt, WORD_COUNT, DYN_BE_LKP_ENTRY0, entry); if (status != STATUS_SUCCESS) return status; // Construct control register value uint32_t ctrl = DYN_BE_LKP_CTRL_VALID_MASK | DYN_BE_LKP_CTRL_RDWRSET_MASK | (HOSTCMD_WRITE << DYN_BE_LKP_CTRL_HOSTCMD_SHIFT); // Trigger write status = SWITCH_DRV_Write(swt, 1, DYN_BE_LKP_CTRL, &ctrl); if (status != STATUS_SUCCESS) return status; // Wait for operation to complete return wait_for_valid_clear(swt); } Whether this code can be utilized for generating a Dynamic entry ? if this code is correct, where the function needs to be called?? Regards Atkinson Re: Dynamic configuration in sja1110 Hi @PavelL #include #include // Define register addresses as per your SoC mapping #define DYN_BE_LKP_ENTRY0 0x000 // Replace with actual address #define DYN_BE_LKP_ENTRY1 0x004 #define DYN_BE_LKP_ENTRY2 0x008 #define DYN_BE_LKP_ENTRY3 0x00C #define DYN_BE_LKP_ENTRY4 0x010 #define DYN_BE_LKP_ENTRY5 0x014 #define DYN_BE_LKP_CTRL 0x018 void insert_l2_unicast_entry(void) { // === INPUTS === uint64_t mac = 0x021122334455ULL; // MAC address uint16_t vlan_id = 3; uint8_t dest_port = 3; // Port 3 uint16_t dest_ports_mask = (1 << dest_port); uint16_t index = 5; // === STEP 1: Wait for previous operation to complete === while (read_register(DYN_BE_LKP_CTRL) & ETHSW_DYN_BE_LKP_CTRL_bValid_MASK); // === STEP 2: Prepare entry fields === uint32_t mac_lo = (uint32_t)(mac & 0xFFFFFFFF); // Lower 32 bits uint32_t mac_hi = (uint32_t)((mac >> 32) & 0xFFFF); // Upper 16 bits uint32_t entry0 = ETHSW_DYN_BE_LKP_ENTRY0_uvEntry_30__0_(0x00000000); uint32_t entry1 = ETHSW_DYN_BE_LKP_ENTRY1_uvEntry_62__31_(mac_lo); uint32_t entry2 = ETHSW_DYN_BE_LKP_ENTRY2_uvEntry_94__63_(mac_hi); uint32_t entry3 = ETHSW_DYN_BE_LKP_ENTRY3_uvEntry_126__95_( ((vlan_id & 0xFFF) << 16) | (dest_ports_mask & 0xFFFF)); uint32_t entry4 = ETHSW_DYN_BE_LKP_ENTRY4_uvEntry_158__127_(0x00000000); // optional flags/reserved uint32_t entry5 = ETHSW_DYN_BE_LKP_ENTRY5_uvEntry_190__159_(index); // === STEP 3: Write entries to DYN registers === write_register(DYN_BE_LKP_ENTRY0, entry0); write_register(DYN_BE_LKP_ENTRY1, entry1); write_register(DYN_BE_LKP_ENTRY2, entry2); write_register(DYN_BE_LKP_ENTRY3, entry3); write_register(DYN_BE_LKP_ENTRY4, entry4); write_register(DYN_BE_LKP_ENTRY5, entry5); // === STEP 4: Trigger WRITE via control register === uint32_t ctrl_val = 0; ctrl_val |= ETHSW_DYN_BE_LKP_CTRL_bValid(1); ctrl_val |= ETHSW_DYN_BE_LKP_CTRL_bWrRdB(1); // Write operation ctrl_val |= ETHSW_DYN_BE_LKP_CTRL_uvHostCommand(0b011); // Host write ctrl_val |= ETHSW_DYN_BE_LKP_CTRL_bValidEntry(1); // Valid entry write_register(DYN_BE_LKP_CTRL, ctrl_val); // === STEP 5: Wait for operation to complete === while (read_register(DYN_BE_LKP_CTRL) & ETHSW_DYN_BE_LKP_CTRL_bValid_MASK); // === STEP 6: Check for error === uint32_t status = read_register(DYN_BE_LKP_CTRL); if (status & ETHSW_DYN_BE_LKP_CTRL_bError_MASK) { // Handle the error // You can print or log this as needed } } whether can i insert this code for Dynamically Writing the data to L2 Lookup Table Where should i insert this code to test ? Looking forward for your reply Regards Atkinson Re: Dynamic configuration in sja1110 Hi @PavelL In the Method of configuring via SPI_HAP where can i find the write_l2_lookup_table.py? How this needs to be communicated via SPI_HAP? when after the device bootup In Previously during the static configuration, we have configured it each data via each index? so whether data if static initially configured is fine or none of the static configuration its shouldn't be connected? whether this write_l2_lookup_table.py can you share it? when running this script from where (which port it need to be connected to pass the data) the script will be polling the data? Regards Atkinson Re: Dynamic configuration in sja1110 Hello @Atkinson ,
The method of dynamic configuration depends on your use case — it can be performed either by the internal M7 core or externally via SPI. Below is a list of possible solutions:
1. ECT (Ethernet Control Tool) Dynamic configuration via external Ethernet (UDP) frames. The internal firmware running on the M7 core receives the configuration and applies it to the switch core.
2. Modified ECT The ECT source code can be adapted to accept any Ethernet frame format (not just UDP). This allows integration into custom protocols or systems. The internal logic remains the same — the M7 core performs the actual register updates.
3. SPI_HAP (Host Access Protocol) The write_l2_lookup_table.py script from the host tools demonstrates how to configure the L2 table dynamically via SPI. This approach can be used by any external MCU or host processor. The logic from this script can also be ported to run directly on the internal M7 core if needed.
All of the above methods follow the same principle described in AN12925, section 5.1.3.2. The register-level flow is identical and includes polling the control register, writing to the entry registers, and triggering the update via the control register.
Best regards,
Pavel
記事全体を表示