I'm new to XMOS and it's all little over my head to be honest. What I want to do is:
get 16ch samples from I2S and send them in raw Ethernet (without ip or mac) in TDM fashion in the same interval as received by I2S (44100Hz). to break that down I tried to write the program to send a packet of 100 bytes (all set to zero for testing) each 45us (this is the required packet interval). I'm on the XCore-200 MultiChannel Dev Board. The other Ethernet device wants 100MBit/s HALF_DUPLEX without AUTO_NEGOTIATION. In fact the entire system is send only (XMOS being the transmitter), no packet is ever sent towards the XMOS. I guess in this case the PHY must be set manually to LINK_UP as it will never receive any data to detect the link?! And how can this be set up with HALF_DUPLEX? I tried the following (commented) lines to manually write the register without the DUPLEX bit without any luck. Also the raw MII library doesn't seem to work with the RGMII which is on my DEV board, no?
This program as printed here works using a laptop and in WireShark I can indeed see the packets of 100 bytes each coming in. (The Laptop NIC is MDI-X and always gets correct (and even HALF_DUPLEX) link in contrast to my other device which doesn't link up for any reason). But there is one more problem:
when trying to set the interval to send a packet every 45us I created this line[90]:
Code: Select all
t += packet_period_us * XS1_TIMER_MHZ;
Any help on this (timing, HALF_DUPLEX, PHY, raw MMI/RGMII etc) would be very much appreciate. I'm willing to pay somebody to help me out here with my project idea, as it is very frustrating to me - being a beginner.
This is my application:
Code: Select all
// Copyright (c) 2015-2016, XMOS Ltd, All rights reserved
#include <xs1.h>
#include <platform.h>
#include "ethernet.h"
#include "smi.h"
#include "debug_print.h"
on tile[1]: rgmii_ports_t rgmii_ports = RGMII_PORTS_INITIALIZER; // Fixed RGMII ports on Tile 1
on tile[1]: port p_smi_mdio = XS1_PORT_1C;
on tile[1]: port p_smi_mdc = XS1_PORT_1D;
on tile[1]: port p_eth_reset = XS1_PORT_4A;
// An enum to manage the array of connections from the ethernet component
// to its clients.
enum eth_clients {
ETH_TO_ICMP,
NUM_ETH_CLIENTS
};
enum cfg_clients {
CFG_TO_ICMP,
CFG_TO_PHY_DRIVER,
NUM_CFG_CLIENTS
};
[[combinable]]
void ar8035_phy_driver(client interface smi_if smi,
client interface ethernet_cfg_if eth) {
ethernet_link_state_t link_state = ETHERNET_LINK_DOWN;
ethernet_speed_t link_speed = LINK_100_MBPS_FULL_DUPLEX;
const int phy_reset_delay_ms = 1;
const int link_poll_period_ms = 1000;
const int phy_address = 0x4;
timer tmr;
int t;
tmr :> t;
p_eth_reset <: 0;
delay_milliseconds(phy_reset_delay_ms);
p_eth_reset <: 1;
while (smi_phy_is_powered_down(smi, phy_address));
//trying to manually set HALF_DUPLEX
//uint16_t basic_control = 0;
//basic_control |= 1 << BASIC_CONTROL_100_MBPS_BIT;
//smi.write_reg(phy_address, BASIC_CONTROL_REG, basic_control);
//eth.set_link_state(0, ETHERNET_LINK_UP, basic_control);
smi_configure(smi, phy_address, LINK_100_MBPS_FULL_DUPLEX, SMI_DISABLE_AUTONEG);
while (1) {
select {
case tmr when timerafter(t) :> t:
ethernet_link_state_t new_state = smi_get_link_state(smi, phy_address);
// Read AR8035 status register bits 15:14 to get the current link speed
if (new_state == ETHERNET_LINK_UP) {
link_speed = (ethernet_speed_t)(smi.read_reg(phy_address, 0x11) >> 14) & 3;
}
if (new_state != link_state) {
link_state = new_state;
eth.set_link_state(0, new_state, link_speed);
}
t += link_poll_period_ms * XS1_TIMER_KHZ;
break;
}
}
}
[[combinable]]
void a_server(client ethernet_cfg_if cfg,
client ethernet_rx_if rx,
client ethernet_tx_if tx)
{
const int packet_period_us = 45; //45 uS each packet
timer tmr;
int t;
tmr :> t;
const int len = 100;
unsigned char txbuf[100] = {0};
debug_printf("Test started\n");
while (1)
{
select {
case tmr when timerafter(t) :> t:
tx.send_packet(txbuf, len, ETHERNET_ALL_INTERFACES);
//debug_printf("A packet was sent\n");
t += packet_period_us * XS1_TIMER_MHZ;
break;
}
}
}
int main()
{
ethernet_cfg_if i_cfg[NUM_CFG_CLIENTS];
ethernet_rx_if i_rx[NUM_ETH_CLIENTS];
ethernet_tx_if i_tx[NUM_ETH_CLIENTS];
streaming chan c_rgmii_cfg;
smi_if i_smi;
par {
on tile[1]: rgmii_ethernet_mac(i_rx, NUM_ETH_CLIENTS,
i_tx, NUM_ETH_CLIENTS,
null, null,
c_rgmii_cfg,
rgmii_ports,
ETHERNET_DISABLE_SHAPER);
on tile[1].core[0]: rgmii_ethernet_mac_config(i_cfg, NUM_CFG_CLIENTS, c_rgmii_cfg);
on tile[1].core[0]: ar8035_phy_driver(i_smi, i_cfg[CFG_TO_PHY_DRIVER]);
on tile[1]: smi(i_smi, p_smi_mdio, p_smi_mdc);
on tile[0]: a_server(i_cfg[CFG_TO_ICMP],i_rx[ETH_TO_ICMP], i_tx[ETH_TO_ICMP]);
}
return 0;
}