raw rgmii and timers

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
leutholl
Member++
Posts: 19
Joined: Wed Feb 04, 2015 11:41 pm

raw rgmii and timers

Post by leutholl »

Hi

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;
when packet_period_us is higher than around 300 then I see the packet in correct timing intervals in WireShark. But I must keep the 45us and when the multiplier is lower than around 300 every packet is sent every 1uS and I can't set the timing as I wanted to do (setting the multiplier to 45us).

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;
}


User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Hi.

Change:

Code: Select all

[[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"); // comment out
  t += packet_period_us * XS1_TIMER_MHZ;
  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;
    }
  }
}
to:

Code: Select all

[[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;
  unsigned t;  // changed from int
  const int len = 100;
  unsigned char txbuf[100] = {0};

  debug_printf("Test started\n"); 

  tmr :> t;
  
  t += packet_period_us * XS1_TIMER_MHZ;
  
  while (1)
  {
    select {
    case tmr when timerafter(t) :> void:
      t += packet_period_us * XS1_TIMER_MHZ;
      tx.send_packet(txbuf, len, ETHERNET_ALL_INTERFACES);
      //debug_printf("A packet was sent\n");
      break;
    }
  }
}
review:
http://www.xmos.com/support/examples/AN10045

See the details on last paragraph.
I'm willing to pay somebody to help me
Please post your results.

If the result is positive then,

a) can share banking details for a deposit of unmarked bills in small denominations or
b) you can forward a high five
leutholl
Member++
Posts: 19
Joined: Wed Feb 04, 2015 11:41 pm

Post by leutholl »

Thank you so much. I pm'ed you!
Post Reply