你好、
我想动态配置 l2 查找表,如何配置?
不使用 ECT 工具,如何配置 l2 查找表?
有例子吗?
此致敬礼
阿特金森
您好 @PavelL
"在您的代码中,条目[3]中缺少移位值,条目[3]、条目[4]和条目[5]中缺少或错放了括号。"
我已经实现了与 python 代码相同的功能,抱歉,我不确定在哪里缺少了括号和移位值。请您提供对齐的代码,这样可能会更清楚,抱歉漏掉了括号和移位
。如果您能提供准确的 entry[3]、entry[4]、entry[5],会更有帮助,也更清楚。
你好@Atkinson、
在您的代码中,输入条目[3]中缺少移位值,输入条目[3]、输入条目[4]和输入条目[5]中缺少或错位了括号。
为了验证您的 L2 查找配置,您可以考虑将条目设置为静态条目,而不是动态条目,这有助于区分问题是出在条目格式上,还是出在动态更新机制上。
另外,请注意,Python 脚本中的"漂亮表格" 仅用于格式化命令窗口中的输出,并不影响功能或寄存器配置。
顺祝商祺!
帕维尔
你好@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 = 0xffffffffffffffff;
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;
常量 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>>
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;
}
我改变了与 Python 脚本类似的实现方式。如果发现任何错误,请将修改内容发送给我
Python 脚本
" 写完之后,尝试发送一个符合条目的 mac/VLAN/Port 标准的帧,然后观察该帧是否根据 DESTPORTS 字段进行转发 "
正如你提到的那样, 我正在尝试用这种方式发送但看不到这种反射
我看不到我的参赛 作品是否得到反映?
还有其他需要设置的东西吗?
在 Python 脚本中,在将 controll2entry 的寄存器值写入 L2_ADDRESS_CTL
之后 , 有几行代码可以在 " prettytable " 中添加一个条目,我们是否
也需要 这样做?
你好@Atkinson、
在条目[3]、条目[4]和条目[5]中存在缺失的移位值和不完整的表达式。这可能导致寄存器值不正确。我建议将你的逻辑与 Python 引用脚本进行比较,后者正确构造了 L2 条目。
写入后,尝试发送一个符合该条目 MAC/VLAN/ 端口条件的帧,并观察它是否根据 DESTPORTS 字段转发。
顺祝商祺!
帕维尔
你好@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 = 0xffffffffffffffff;
const uint32_t VLANID = 0;
const uint32_t VLANID_MASK = 0xffffff;
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;
常量 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)>>
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;
}
这是我修改后的代码实现
,你能否验证一下这个实现是否会带来动态入口。因此,我试着回读寄存器的值来调试寄存器是否被写入,我可以看到寄存器被写入了值,但我不确定是否创建了enrty?
此外,L2 查找表的动态条目也没有得到反映?
,那么我如何验证 L2 查找表是否已创建?
你好@Atkinson、
1.位移语法 (<< ,>> )
您代码中的一些位移运算符似乎被替换成了 HTML 实体,如<< 和>>。这种情况通常发生在将代码复制到网络平台时。总之,请直接在代码中进行检查。
#define L2_CTRL_VALID_BIT (1U<< 31)
应为:
#define L2_CTRL_VALID_BIT (1U<< 31)
2.条目问题
在 CreateL2Entry() 函数中,尤其是在条目[3]、条目[4]和条目[5]中,存在一些语法错误和缺失的移位值。这可能导致寄存器写入不完整或无效。
例如
我建议将您的实现与 Python 参考脚本进行比较,后者正确构造了 L2 条目的所有六个 32 位单词。
顺祝商祺!
帕维尔
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. 该表每个条目由六个 32 位寄存器组成。您可以在 Python 脚本的调试输出中看到这种结构。"
因此,我遇到了这样一个问题:我试图将数据写入需要在 L2 查找表中创建动态条目的地址,但却没有创建动态条目。
#define L2_ENTRY0_ADDR 0x00000023
#define L2_ENTRY1_ADDR 0x00000024
#define L2_ENTRY2_ADDR 0x00000025
#defineL2_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 = 0xFFFFF;
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)>>
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];
// 第 1 步:创建条目
ret = CreateL2Entry(entry);
if (ret != E_OK) return ret;
// 第 2 步:等待 VALID 位清零
do {
ret = spi_read_reg(L2_CTRL_ADDR,&ctrlReg);
if (ret != E_OK) return ret;
} while (ctrlReg& L2_CTRL_VALID_BIT);
// 第 3 步:将条目数据写入寄存器
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) 返回 ret;
ret = spi_write_reg(L2_ENTRY5_ADDR, entry[5]); if (ret != E_OK) 返回 ret;
//步骤 4:设置控制寄存器以触发信号写入
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;
}
你能否检查一次,是否存在任何问题,因为它没有为 L2 查找表创建动态条目?
你好@Atkinson、
1。是的,主机工具最初是为 SJA1110-EVM 板开发的。我个人使用这些带有调试打印的脚本来验证我对寄存器访问的理解。虽然您不能在 S32G-VNP-RDB2 平台上直接运行它们,但由于 S32G 通过 SPI 访问 SJA1110,因此可以调整底层逻辑。
2.如果您正在为 S32G 平台寻找 SPI 读/写实现方案,您有两个主要选择:
3.如果我没理解错的话,你指的是 UM11107 表 1182 中描述的 L2 查找表。该表每个条目由 6 个 32 位寄存器组成。您可以从 Python 脚本的调试输出中看到这种结构。
顺祝商祺!
帕维尔
你好@PavelL
我有一些问题
1.)l2_write_lookup_table.py 的这份 Debug 打印件取自 SJA1110 EVM 板的实现不是来自 S32G-VNP RDB 板吗?而且我们无法直接在 S32G-VNP-RDB32 板中实现 l2_write_lookup_table.py
2.) 你能向我提供用于与上述代码集成的 SPI_read 和 SPI_Write 的代码吗?
因为在 S32G 中通过 SPI_Read 和 SPI_write 执行写入操作时,无法看到动态条目被添加。
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 };
// 将芯片选择拉低
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 Register address to#define L2_ENTRY0_ADDR 0x00000023
but still I am not able to identify which I am trying to add table getting reflected when I transmit the message
你好@Atkinson、
你的代码看起来不错。但是,如果您想通过 SPI 访问动态表,则入口地址不含 FF,并右移 2。
因此,#define L2_ENTRY0_ADDR0xFF00008c应该是 #define L2_ENTRY0_ADDR0x00000023
但这取决于你的例程spi_write_reg 的实际作用。
以下是 write_l2_lookup_table.py 的输出结果,包括我的调试打印(tx/rx 指的是通过示波器或逻辑分析仪在 SPI 线路上看到的数据):
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 查找表项 (SW1)
关于 FAE 申请,FAE 不在我的升级路径中。贵公司已指派 FAE,因此您可以直接联系 FAE。
顺祝商祺!
帕维尔
你好@PavelL
#define L2_ENTRY0_ADDR 0xFF00008c
#define L2_ENTRY1_ADDR 0xFF000090
#define L2_ENTRY2_ADDR 0xFF000094
#define L2_ENTRY3_ADDR 0xFF000098
#define L2_ENTRY4_ADDR0xFF00009C
#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 = 0xFFFFF;
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)>>
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) 返回 ret;
ret = spi_write_reg(L2_ENTRY5_ADDR, entry[5]); if (ret != E_OK) 返回 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;
}
这是目前创建动态条目的实现方法,你能否与 FAE 相互验证一下这种实现方法是否正确 !!
还需要做其他修改吗?
你好@Atkinson、
您的问题的答案与您的应用程序用例有关。
您可以在任何地方创建动态条目,也可以在 S32G 或 SJA1110 中创建:
这里有如何向 SJA1110 的开关芯写入动态入口的示例:
问候、
帕维尔
你好@PavelL
1.)
2.)If via SJA1110 switch whether reading and write 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!!
你好@Atkinson、
很抱歉,由于我目前工作繁忙,回复迟了。
我知道这乍看起来可能并不简单,但实际上这个概念非常简单。
最终的寄存器地址取决于访问方法--是通过 AHB 在内部访问 M7 内核,还是通过 SPI_AP 接口从外部访问。基本地址因接入点而异。
寄存器地址使用 UM11107 表 2 中提供的基地址计算。例如,对于交换机子系统,SPI_AP 访问的基地址为0x00000000 ,AHB 访问的基地址为0xFF000000 。
在这种情况下,通过 AHB 访问寄存器0x8C (DYN_BE_LKP_ENTRY0)时,寄存器会变成0xFF00008C 。
现在,可能会让人感到困惑的地方来了:SDK 驱动程序定义了以下内容:
你好 @PavelL 你 能不能给我读写
地址名称访问RESET描述
8Ch DYN_BE_LKP_
ENTRY0
R/W 0h
(fffffFeh)
8ch 之前的完整地址会是什么基址?
比如它会有 0x3fc0008c 所以在这个动态入口表中我们会有完整的地址你能不能给我
8Ch DYN_BE_LKP_
ENTRY0
R/W 0h
(fffffFEH)
90h DYN_BE_LKP_
ENTRY1
R/W 0h
94h DYN_BE_LKP_
ENTRY2
R/W 0h
98h DYN_BE_LKP_
R/W 0h
9 8h DYN_BE_LKP_ ENTRY3 R/W 0h 9Ch DYN_BE_LKP_
ENTRY4
R/W 0h
a0h a0h dyn_BE_LKP_
ENTRY5
R/W 0h
a4H DYN_BE_LKP_ A4H DYN_BE_LKP_CTRL R/W 0h
(ff800000h)
你好@Atkinson、
我不知道有任何支持文件——这是常识,与设备无关。我向 Copilot 咨询了这个问题,应该可以修改 sja11xx_ftdi4232.py 以使用 DSPI5 而不是 FTDI。
顺祝商祺!
帕维尔
你好 @PavelL
要在 S32G-VNP-RDB2 或 RDB3 板上使用这个脚本,需要修改 FTDI 层才能在 S32G 处理器上通过 DSPI5 进行通信。
有什么证明文件吗?
你好@Atkinson、
问题 1:" 那么,既然 Linux 电路板支持包已预安装在 SD 卡上... 它会自动启用动态配置吗?"
A1:不,电路板支持包包含 DSA 驱动程序,该驱动程序支持动态配置,但它不会在所有用例中自动启用。
问题 2:"通过动态使用 write_l2_lookup.py(python evm 主机工具)配置 L2 查找条目,该过程是否保持不变?对于 S32G-VNP-RDB 板,它将更改 "
A2:创建和上传动态条目的大致流程保持不变,如 UM11107 和 AN12925 中所述。
但是,write_l2_lookup_table.py 脚本使用 FTDI 驱动程序通过 USB 访问 SJA1110-EVM。
要在 S32G-VNP-RDB2 或 RDB3 板上使用此脚本,需要修改 FTDI 层,以便在 S32G 处理器上通过 DSPI5 进行通信。
问题 3:" 是否有可能连接笔记本电脑 & S32G-VNP_RDB32 板创建动态条目?"
A3:是的,这是可能的。您可以自由开发运行在 Linux 上的定制软件,通过 SPI 或以太网处理自己的协议,配置动态条目。
问题 4:"还有一件事,SJA1110_SDK_1.0.2 是否是实施 RTM1.0.0 所需的主要内容?"
答 4: 不是,建议使用最新版本的 SJA1110 SDK 1.0.2,以保证兼容性和稳定性。
如需进一步支持,请联系您的 FAE 或通过https://support.nxp.com/s/?language=en_US 提交报告。
感谢您的理解。
顺祝商祺!
帕维尔
你好@PavelL
因此,如果 SD 卡插入 S32G-VNP-RDB 板,Linux 电路板支持包会预先安装在 SD 卡上。那么SD卡中存在的电路板支持包是否会自动启用动态配置
通过动态使用 write_l2_lookup.py(python evm 主机工具)配置 L2 查找条目时,进程是否保持不变?对于 S32G-VNP-RDB 板来说,情况将会发生变化
如果流程保持不变我们如何连接笔记本电脑 & rdb32Board 在通过笔记本电脑和 SJA1110 EVM 板连接时它将使用 USB 接口进行连接,这将有助于对其进行配置动态输入那么对于 S32G-VNP-RDB32 板来说,接口会是什么样子?
是否有可能连接笔记本电脑 & S32G-VNP_RDB32 板创建动态条目?
还有,SJA1110_SDK_1.0.2 是否是实施 RTM1.0.0 所需的主要内容?
你好@Atkinson、
Linux 电路板支持包已经预装在 S32G-VNP-RDB3 板附带的 SD 卡上,因此在这方面无需采取任何其他措施。
我假设你已经成功启动了板(如果你在之前的消息中已经提到了这一点,很抱歉)。
电路板支持包 包含 SJA1110 DSA 驱动程序,该驱动程序提供了一系列有用的功能,包括支持动态 L2 查询表配置。
DSA 驱动程序默认已启用。
随着这个案例演变成一个多功能域话题,我已经联系了你的FAE,讨论我们应该如何进一步发展。
顺祝商祺!
帕维尔
你好 @PavelL
我目前正在尝试在 S32G-VNP-RDB32 中实现它 — SJA1110 Switch
目前,我自己没有任何固件需要使用
哪个 Linux 电路板支持包可能需要完成全部更改
你好@Atkinson、
如果你打算在 S32G-VNP-RDB3 板上这样做,情况就会发生重大变化。你会在板上运行 Linux 电路板支持包,还是打算使用自己的固件?
顺祝商祺!
帕维尔
你好 @PavelL
3.SPI_HAP(主机访问协议)
主机工具中的 write_l2_lookup_table.py 脚本演示了如何通过 SPI 动态配置 L2 表。任何外部 MCU 或主机处理器都可以使用这种方法。如有需要,也可将该脚本中的逻辑移植到内部 M7 内核上直接运行。
我希望通过 write_l2_lookup_table.py 配置一个条目
通过我们在 write_l2_lookup_table.py 文件中编写的配置将如何移至 RDB32 板 ,
从笔记本电脑到 RDB32 板 需要做 什么接口?
我们可以通过什么通信机制将二级查询条目传递给设备(RDB32 板) 你
能给我一个程序或者我可以在哪里找到实施程序
你好@Atkinson、
是的,你说得对,系统启动时,静态配置会自动从外部闪存加载。
让我来详细说明一下动态配置的概念。
动态配置的任务可分为两个部分:
有三种接口可用于此目的:
顺祝商祺!
帕维尔
Hi@PavelL
3. SPI_HAP(主机访问协议)
主机工具中的 write_l2_lookup_table.py 脚本演示了如何通过 SPI 动态配置 L2 表。任何外部 MCU 或主机处理器都可以使用这种方法。如有需要,也可将该脚本中的逻辑移植到内部 M7 内核上直接运行。
我希望通过 write_l2_lookup_table.py 配置一个条目
通过我们在 write_l2_lookup_table.py 文件中编写的配置将如何移至 RDB32 板,从笔记本电脑到 RDB32板 需要做
什么接口?
我们可以通过什么通信机制将二级查询条目传递给设备(RDB32 板)你
能给我一个程序或者我可以在哪里找到实施程序
您好@PavelL
正如您所提到的,我想动态地配置 switch_core 配置
当系统启动时,我们在外设中配置的静态配置会被加载
我正在寻找一种方法来配置表项,这些表项是在静态中配置的,需要通过动态来配置。
在这两种情况下,通常有三种方法可以动态更新交换机配置:
如果这些都是唯一可能的方法,那么按照我提供的代码进行配置是可行还是不可行?
,这里提到的三个过程与 ECT& write_l2_lookup_table.py 是否相同?
你好@Atkinson、
能否请您说明使用动态 L2 查找表的用例?
就我个人而言,我会考虑在两种典型情况下使用动态条目:
在这两种情况下,通常有三种方法可以动态更新交换机配置:
您的用例属于这些类别之一,还是您的目标有所不同?
顺祝商祺!
帕维尔
您好@PavelL
正如您所提到的,我尝试加入代码
您能否确认我需要在哪里放置代码,这将有助于我们创建条目
您在之前的信息中提到有两种方法可以通过使用 ECT(以太网配置工具)和 SPI_HAP
所以这些工具和文件需要在运行时进行处理,对吗?
我分享的代码是我试图在不使用这些工具的情况下实现的
我想创建一个动态 L2 查找条目,这样做可以吗?
Atkinson Regards
你好@Atkinson、
很抱歉由于公共假期而延迟回复。
感谢您分享代码。我快速浏览了一下,乍一看似乎与 AN12925 第 5.1.3.2 章中概述的原则一致写入 L2 查找表项。我还注意到,sja1110.h 中的 #define 语句似乎被重复使用了,这是标准做法。
但请注意,深入的自定义代码审查超出了我们免费在线支持的范围。此外,调用此函数的时间和上下文高度特定应用,可能会因您的系统架构和要求而异。
顺祝商祺!
帕维尔
你好@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] )<<
// 准备 L2 查找条目字段
uint32_t entry[WORD_COUNT] = {0};
条目 [0] = ((5 & 0xF) << 24) | (1 << 11); // SrcPort, DestPorts 1 & 2
条目 [1] = (uint32_t)(mac64 & 0xFFFFFFFF);
条目 [2] = (uint32_t)((mac64 >> 32) & 0xFFFF);
条目 [2] |= (3 << 16); // VLAN ID = 3
条目 [3] = 0; // 可选的掩码
条目 [4] = 0;
条目 [5] = (8 << 4) | (1 << 10); // CB_SID_IN = 8, CB_ON_DA = 1
// 等待直到前一个操作完成
status = wait_for_valid_clear(swt);
if (status != STATUS_SUCCESS) return status;
// 将 L2 输入数据写入寄存器
status = SWITCH_DRV_Write(swt,WORD_COUNT,DYN_BE_LKP_ENTRY0,entry);
if (status != STATUS_SUCCESS) return status;
// 构造控制寄存器值
uint32_t ctrl = DYN_BE_LKP_CTRL_VALID_MASK |
DYN_BE_LKP_CTRL_RDWRSET_MASK |
(HOSTCMD_WRITE<< DYN_BE_LKP_CTRL_HOSTCMD_SHIFT);
//触发信号写入
状态 = switch_drv_Write (swt, 1, DYN_BE_LKP_CTRL, & ctrl); if (status!
= STATUS_SUCCESS) 返回状态;
// 等待操作完成
return wait_for_valid_clear(swt);
}
这段代码是否可用于生成动态条目?
如果这段代码正确,需要在何处调用该函数?
Atkinson Regards
你好@PavelL
#include
#include
// 根据 SoC 映射定义寄存器地址
#define DYN_BE_LKP_ENTRY0 0x000 // 替换为实际地址
#define DYN_BE_LKP_ENTRY1 0x004
#defineDYN_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 地址
uint16_t vlan_id = 3;
uint8_t dest_port = 3; // 端口 3
uint16_t dest_ports_mask = (1<< dest_port);
uint16_t index = 5;
// === 第 1 步:等待上一步操作完成 ===
while (read_register(DYN_BE_LKP_CTRL)& ETHSW_DYN_BE_LKP_CTRL_bValid_MASK);
// === 第 2 步:准备输入字段 ===
uint32_t mac_lo = (uint32_t)(mac& 0xFFFFFFFF); // 低 32 位
uint32_t mac_hi = (uint32_t)((mac>> 32)& 0xFFFF); // 高 16 位
uint32_t entry0 = ethsw_dyn_be_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_BE_LKP_ENTRY1_UVENTRY_62__31_ (mac_lo);uint32_t entry2 = ethsw_dyn_BE_BE_LK_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 & 0xFFF));uint32_t entry4 = ethfff sw_dyn_be_lkp_entry4_uventry_158__127_ (0x00000000);//
可选标志/保留的
uint32_t 条目5 = ethsw_dyn_be_lkp_entry5_uventry_190__159_(索引);
// === 第 3 步:将条目写入 DYN 寄存器 ===
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);
//=== 步骤 4:通过控制寄存器触发写入 ===
uint32_t ctrl_val = 0; ctrl_val |= ethsw_dyn_be_ctrl_bvalid (1); ctrl_val |= ethsw_dyn_be_be_ctrl_bw
rdb (1);//写入操作 ctrl_val |= ethsw_dyn_be_be_be__lkp_ctrl_uvHostCommand (0b011);//主机写入 ctrl_val |= ethsw_dyn_be_lkp_ctrl_bvalident
ry (1);//有效输入
write_register(DYN_BE_LKP_CTRL, ctrl_val);
// === 第 5 步:等待操作完成 ===
while (read_register(DYN_BE_LKP_CTRL)& ETHSW_DYN_BE_LKP_CTRL_bValid_MASK);
// === 第 6 步:检查错误 ===
uint32_t status = read_register(DYN_BE_LKP_CTRL);
if (status& ETHSW_DYN_BE_LKP_CTRL_bError_MASK) {
// 处理错误
// 你可以根据需要打印或记录
}
}
我是否可以插入这段代码,将数据动态写入 L2 查找表
我应该在哪里插入这段代码进行测试?
期待您的回复
Atkinson
你好@PavelL
在通过 SPI_HAP 进行配置的方法中
在哪里可以找到 write_l2_lookup_table.py?
如何通过 SPI_HAP 进行通信?设备启动后的时间以前
在静态配置期间,我们已经通过每个索引配置了每个数据?
那么,如果最初配置的是静态数据,是否就可以连接?
您能分享一下 write_l2_lookup_table.py 吗?
当从哪里(需要连接哪个端口才能传递数据)运行这个脚本时,脚本将轮询数据?
Atkinson
你好@Atkinson、
动态配置的方法取决于您的使用情况--可以由内部 M7 内核执行,也可以通过 SPI 从外部执行。下面是一份可能的解决方案清单:
1.ECT(以太网控制工具)
通过外部以太网(UDP)帧进行动态配置。M7 核心上运行的内部固件接收配置并将其应用到交换机核心。
2.修改后的 ECT
ECT 源代码可进行调整,以接受任何以太网帧格式(不仅仅是 UDP)。这样就可以集成到定制协议或系统中。内部逻辑保持不变--M7 内核执行实际的寄存器更新。
3.SPI_HAP(主机访问协议)
主机工具中的 write_l2_lookup_table.py 脚本演示了如何通过 SPI 动态配置 L2 表。任何外部 MCU 或主处理器都可以使用这种方法。如果需要,该脚本中的逻辑也可以移植到 M7 内核上直接运行。
上述所有方法都遵循 AN12925 第 5.1.3.2 节所述的相同原则。寄存器级别的流程是相同的,包括轮询控制寄存器、写入条目寄存器以及通过控制寄存器触发信号更新。
顺祝商祺!
帕维尔