XC-2 AVB Ethernet Endpoints

Technical discussions related to any XMOS development kit or reference design. Eg XK-1A, sliceKIT, etc.
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

XC-2 AVB Ethernet Endpoints

Post by Manust »

First of all Happy New Year ;-)

I'm working on XC-2 based AVB Ethernet Endpoints. Therefore i developed an external PCB using the CS2300CP and a Cirrus DAC and ADC.
I also wanted to test the attero avb windows demo tool so i thought i could just change the XR-AVB-LC Code to be used with die XC-2 Board. The Code is Compiled with legacy mode set to 1.
Changes to the code are quite marginal. The Channel count is set to 4/4 and the Threads are moved to the fitting core.

So starting the debugger delivers following Uart Outputs:

Code: Select all

\227INFO: avb1722_talker: Started..
Using dynamic ip
INFO: AVB1722_EthernetRx : Started..
PTP Role: Master
PTP Role: Slave
PTP sync locked
dhcp: 192.168.2.93
from the ethernet part it seems fine ;-)

The Problem now is that the I2S Part isn't working. Particularly the SYNC output for the external PLL Chip CS2300CP is constantly low which is resulting in no MCLK present. The I2S Ports are also low, guess because there is no MCLK.
Communication over I2C with the PLL is working.

Is there any known issue when using the Code on a G4 device?

I guess im not allowed to post my main file here, am i right?


Thanks for any of your help

Greetings Manuel


User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Post by Andy »

Hi Manust,

Firstly, can you check that the configuration of the port named PORT_SYNC_OUT in your XN file corresponds to your hardware. Is it attached to the correct port number and on the correct core in your XN file?

On your hardware, are the I2S pins and PORT_SYNC_OUT pin attached to ports all on the same core? (The software assumes so).

Make sure that the thread that generates these signals is running on the core that the IO is connected. The expansion headers are connected to cores 1, 2 and 3, so you might need to change the 'on stdcore[0]' from 0 to 1, 2, or 3 depending on what header your hardware is attached:

Code: Select all

		// AVB - Audio
		on stdcore[0]: {
			init_media_input_fifos(ififos, ififo_data, AVB_NUM_MEDIA_INPUTS);
			configure_clock_src(b_mclk, p_aud_mclk);
			start_clock(b_mclk);
			par
			{
				audio_gen_CS2300CP_clock(p_fs, clk_ctl[0]);

				i2s_master (b_mclk,
						b_bclk,
						p_aud_bclk,
						p_aud_lrclk,
						p_aud_dout,
						AVB_NUM_MEDIA_OUTPUTS,
						p_aud_din,
						AVB_NUM_MEDIA_INPUTS,
						MASTER_TO_WORDCLOCK_RATIO,
						c_samples_to_codec,
						ififos,
						media_ctl[0],
						0);
			}
		}
It's fine for you to post your AVB code here on XCore - it's all open source.
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

I am using the standard XN File of the XC-2 Board and just defined the ports in the main xc file.

I ran a test program to check if the pins are correct they worked fine there.
The hardware is attached to the ports of Core 1

It's all a bit messy but there's a lot time pressure for that prototype...
so here it is:

Code: Select all

#include <platform.h>
#include <print.h>
#include <assert.h>
#include <xccompat.h>
#include <stdio.h>
#include <string.h>
#include "xtcp_client.h"
#include "uip_server.h"
#include "audio_i2s.h"
#include "xlog_server.h"
#include "i2c.h"
#include "avb.h"
#include "audio_clock_CS2300CP.h"
#include "audio_codec_CS42448.h"
#include "simple_printf.h"
#include "media_fifo.h"
#include "mdns.h"
#include "control_api_server.h"
#include "osc.h"
#include "demo_stream_manager.h"

#define PORT_SYNC_OUT XS1_PORT_1A
#define PORT_MCLK XS1_PORT_1B
#define PORT_SCLK XS1_PORT_1C
#define PORT_LRCLK XS1_PORT_1D
#define PORT_SDATA_OUT0 XS1_PORT_1E
#define PORT_SDATA_OUT1 XS1_PORT_1F
#define PORT_SDATA_IN0 XS1_PORT_1G
#define PORT_SDATA_IN1 XS1_PORT_1H

#define PORT_I2C_SCL XS1_PORT_1G
#define PORT_I2C_SDA XS1_PORT_1H
#define PORT_LEDS XS1_PORT_4A


// this is the sample rate, the frequency of the word clock
#define SAMPLE_RATE 48000

// This is the number of master clocks in a word clock
#define MASTER_TO_WORDCLOCK_RATIO 512

// Set the period inbetween periodic processing to 50us based
// on the Xcore 100Mhz timer.
#define PERIODIC_POLL_TIME 5000

// Timeout for debouncing buttons
#define BUTTON_TIMEOUT_PERIOD (20000000)

// Commands sent from the GPIO to the main demo app
enum gpio_cmd {
	STREAM_SEL, CHAN_SEL, REMOTE_SEL
};

// Note that this port must be at least declared to ensure it
// drives the mute low
on stdcore[2]: out port p_mute_led_remote = XS1_PORT_4B; // mute, led remote;
on stdcore[2]: out port p_chan_leds = PORT_LEDS;

on stdcore[2]: in port p_buttons = XS1_PORT_4C;

void demo(chanend tcp_svr, chanend c_rx, chanend c_tx, chanend c_gpio_ctl);

void ptp_server_and_gpio(chanend c_rx, chanend c_tx, chanend ptp_link[],
		int num_ptp, enum ptp_server_type server_type, chanend c);

//***** Ethernet Configuration ****
on stdcore[2]: port otp_data = XS1_PORT_32B; // OTP_DATA_PORT
on stdcore[2]: out port otp_addr = XS1_PORT_16C; // OTP_ADDR_PORT
on stdcore[2]: port otp_ctrl = XS1_PORT_16D; // OTP_CTRL_PORT

on stdcore[2]: mii_interface_t mii = {
		XS1_CLKBLK_1,
		XS1_CLKBLK_2,
		PORT_ETH_RXCLK,
		PORT_ETH_RXER,
		PORT_ETH_RXD,
		PORT_ETH_RXDV,
		PORT_ETH_TXCLK,
		PORT_ETH_TXEN,
		PORT_ETH_TXD
};

on stdcore[2]: clock clk_smi = XS1_CLKBLK_5;

on stdcore[2]: smi_interface_t smi = { PORT_ETH_RST_N_MDIO, PORT_ETH_MDC, 1 };

on stdcore[2]: struct r_i2c r_i2c = { PORT_I2C_SCL, PORT_I2C_SDA };

//***** AVB audio ports ****
on stdcore[1]: out port p_fs = PORT_SYNC_OUT;
on stdcore[1]: clock b_mclk = XS1_CLKBLK_1;
on stdcore[1]: clock b_bclk = XS1_CLKBLK_2;
on stdcore[1]: in port p_aud_mclk = PORT_MCLK;
on stdcore[1]: buffered out port:32 p_aud_bclk = PORT_SCLK;
on stdcore[1]: out buffered port:32 p_aud_lrclk = PORT_LRCLK;
on stdcore[1]: out buffered port:32 p_aud_dout[2] = {
		PORT_SDATA_OUT0,
		PORT_SDATA_OUT1
};

on stdcore[1]: in buffered port:32 p_aud_din[2] = {
		PORT_SDATA_IN0,
		PORT_SDATA_IN1,
};

on stdcore[0]: port p_uart_tx = PORT_UART_TX;

media_input_fifo_data_t ififo_data[AVB_NUM_MEDIA_INPUTS];
media_input_fifo_t ififos[AVB_NUM_MEDIA_INPUTS];

media_output_fifo_data_t ofifo_data[AVB_NUM_MEDIA_OUTPUTS];
media_output_fifo_t ofifos[AVB_NUM_MEDIA_OUTPUTS];




int main(void) {
	// ethernet tx channels
	chan tx_link[5];
	chan rx_link[4];
	chan connect_status;

	//ptp channels
	chan ptp_link[3];

	// avb unit control
	chan listener_ctl[AVB_NUM_LISTENER_UNITS];
	chan buf_ctl[AVB_NUM_LISTENER_UNITS];
	chan talker_ctl[AVB_NUM_TALKER_UNITS];

	// media control
	chan media_ctl[AVB_NUM_MEDIA_UNITS];
	chan clk_ctl[AVB_NUM_MEDIA_CLOCKS];
	chan media_clock_ctl;

	// audio channels
	streaming
	chan c_samples_to_codec;

	// tcp/ip channels
	chan xtcp[1];

	// control channel from the GPIO buttons
	chan c_gpio_ctl;

	par
	{
		// AVB - Ethernet
		on stdcore[2]:
		{
			int mac_address[2];
			ethernet_getmac_otp(otp_data,
                                            otp_addr,
                                            otp_ctrl,
                                            (mac_address, char[]));
			phy_init(clk_smi, null,
					smi,
					mii);

			ethernet_server(mii, mac_address,
					rx_link, 4,
					tx_link, 5,
					smi, connect_status);
		}

		// TCP/IP stack
		on stdcore[2]:
		{
			uip_server(rx_link[1],
                                   tx_link[2],
                                   xtcp, 1,
                                   null,
                                   connect_status);
		}

		// AVB - PTP
		on stdcore[2]:
		{
			// We need to initiate the PLL from core 1, so do it here before
			// launching  the main function of the thread
			audio_clock_CS2300CP_init(r_i2c, MASTER_TO_WORDCLOCK_RATIO);

			ptp_server_and_gpio(rx_link[0], tx_link[0], ptp_link, 3,
					PTP_GRANDMASTER_CAPABLE,
					c_gpio_ctl);
		}

		on stdcore[2]:
		{
			media_clock_server(media_clock_ctl,
					ptp_link[1],
					buf_ctl,
					1,
					clk_ctl,
					1);
		}

		// AVB - Audio
		on stdcore[1]: {
			init_media_input_fifos(ififos, ififo_data, AVB_NUM_MEDIA_INPUTS);
			configure_clock_src(b_mclk, p_aud_mclk);
			start_clock(b_mclk);
			par
			{
				audio_gen_CS2300CP_clock(p_fs, clk_ctl[0]);

				i2s_master (b_mclk,
						b_bclk,
						p_aud_bclk,
						p_aud_lrclk,
						p_aud_dout,
						AVB_NUM_MEDIA_OUTPUTS,
						p_aud_din,
						AVB_NUM_MEDIA_INPUTS,
						MASTER_TO_WORDCLOCK_RATIO,
						c_samples_to_codec,
						ififos,
						media_ctl[0],
						0);
			}
		}

		// AVB Talker - must be on the same core as the audio interface
		on stdcore[1]: avb_1722_talker(ptp_link[0],
				tx_link[1],
				talker_ctl[0],
				AVB_NUM_SOURCES);

		// AVB Listener
		on stdcore[1]: avb_1722_listener(rx_link[3],
				tx_link[3],
				buf_ctl[0],
				listener_ctl[0],
				AVB_NUM_SINKS);

		on stdcore[1]:
		{	init_media_output_fifos(ofifos, ofifo_data, AVB_NUM_MEDIA_OUTPUTS);
			media_output_fifo_to_xc_channel_split_lr(media_ctl[1],
					c_samples_to_codec,
					0, // clk_ctl index
					ofifos,
					AVB_NUM_MEDIA_OUTPUTS);
		}

		// Xlog server
		on stdcore[0]:
		{
			xlog_server_uart(p_uart_tx);
		}

		// Application threads
		on stdcore[1]:
		{
			// First initialize avb higher level protocols
			avb_init(media_ctl, listener_ctl, talker_ctl, media_clock_ctl, rx_link[2], tx_link[4], ptp_link[2]);

			demo(xtcp[0], rx_link[2], tx_link[4], c_gpio_ctl);
		}
	}

	return 0;
}

void ptp_server_and_gpio(chanend c_rx, chanend c_tx, chanend ptp_link[],
		int num_ptp, enum ptp_server_type server_type, chanend c) {

	static unsigned buttons_active = 1;
	static unsigned buttons_timeout;
	static unsigned remote = 0;
	static unsigned selected_chan = 0;

	unsigned button_val;
	timer tmr;
    p_mute_led_remote <: ~(remote << 1) | 1;
	p_chan_leds <: ~(1 << selected_chan);
	p_buttons :> button_val;

	ptp_server_init(c_rx, c_tx, server_type);

	while (1) {
		select
		{
			do_ptp_server(c_rx, c_tx, ptp_link, num_ptp);

			case buttons_active =>
			p_buttons when pinsneq(button_val) :> unsigned new_button_val:
			if ((button_val & 0x1) == 1 &&
					(new_button_val & 0x1) == 0) {
				c <: STREAM_SEL;
				buttons_active = 0;
			}
			if ((button_val & 0x2) == 2 &&
					(new_button_val & 0x2) == 0) {
				remote = 1-remote;
				p_mute_led_remote <: ~(remote << 1) | 1;

				/* Currently we do not do anything with the remote select
				 mode. So there is no need to signal the demo thread. */
				//c <: REMOTE_SEL;
				//c <: remote;
				buttons_active = 0;
			}
			if ((button_val & 0x4) == 4 &&
					(new_button_val & 0x4) == 0) {
				selected_chan++;
				if (selected_chan > 3)
				selected_chan = 0;
				p_chan_leds <: ~(1 << selected_chan);
				c <: CHAN_SEL;
				c <: selected_chan;
				buttons_active = 0;
			}
			if (!buttons_active) {
				tmr :> buttons_timeout;
				buttons_timeout += BUTTON_TIMEOUT_PERIOD;
			}
			button_val = new_button_val;
			break;
			case !buttons_active => tmr when timerafter(buttons_timeout) :> void:
			buttons_active = 1;
			p_buttons :> button_val;
			break;

		}
	}
}

/** The main application control thread **/
void demo(chanend tcp_svr, chanend c_rx, chanend c_tx, chanend c_gpio_ctl) {

	timer tmr;
	int avb_status = 0;
	int map[8];
	unsigned char macaddr[6];
	int selected_chan = 0;
	unsigned change_stream = 1;
	unsigned timeout;

	// Set AVB to be in "legacy" mode
	avb_set_legacy_mode(1);

	// Initialize Zeroconf
	mdns_init(tcp_svr);

	// Register all the zeroconf names
	mdns_register_canonical_name("xmos_attero_endpoint");
	mdns_register_service("XMOS/Attero AVB", "_attero-cfg._udp",
			ATTERO_CFG_PORT, "");

	// Initialize the control api server
	c_api_server_init(tcp_svr);

	// Initialize the media clock (a ptp derived clock)
	//printstr("Media clock: LOCAL\n");
	//set_device_media_clock_type(0, MEDIA_FIFO_DERIVED);
	set_device_media_clock_type(0, LOCAL_CLOCK);
	//set_device_media_clock_type(0, PTP_DERIVED);
	set_device_media_clock_rate(0, SAMPLE_RATE);
	set_device_media_clock_state(0, DEVICE_MEDIA_CLOCK_STATE_ENABLED);

	// Configure the source stream
	set_avb_source_name(0, "8 channel stream out");

	set_avb_source_channels(0, 8);
	for (int i = 0; i < 8; i++)
		map[i] = i;
	set_avb_source_map(0, map, 8);
	set_avb_source_format(0, AVB_SOURCE_FORMAT_MBLA_24BIT, SAMPLE_RATE);
	set_avb_source_sync(0, 0); // use the media_clock defined above

	// Main loop
	tmr	:> timeout;
	while (1) {
		unsigned char tmp;
		xtcp_connection_t conn;
		unsigned int streamId[2];
		unsigned int nbytes;
		unsigned int buf[(MAX_AVB_CONTROL_PACKET_SIZE+1)>>2];
		int already_seen;

		select
		{
			// Receive any incoming AVB packets (802.1Qat, 1722_MAAP)
			case avb_get_control_packet(c_rx, buf, nbytes):

			// Process AVB control packet if it is one
			avb_status = avb_process_control_packet(buf, nbytes, c_tx);
			switch (avb_status)
			{
				case AVB_SRP_TALKER_ROUTE_FAILED:
				avb_srp_get_failed_stream(streamId);
				// handle a routing failure here
				break;
				case AVB_SRP_LISTENER_ROUTE_FAILED:
				avb_srp_get_failed_stream(streamId);
				// handle a routing failure here
				break;
				case AVB_MAAP_ADDRESSES_LOST:
				// oh dear, someone else is using our multicast address
				for (int i=0;i<AVB_NUM_SOURCES;i++)
				set_avb_source_state(i, AVB_SOURCE_STATE_DISABLED);

				// request a different address
				avb_1722_maap_request_addresses(AVB_NUM_SOURCES, null);
				break;
				default:
				break;
			}

			// add any special control packet handling here
			break;

			// Process TCP/IP events
			case xtcp_event(tcp_svr, conn):
			if (conn.event == XTCP_IFUP) {
				avb_start();

				// Request a multicast addresses for stream transmission
				avb_1722_maap_request_addresses(AVB_NUM_SOURCES, null);
			}

			{
				mdns_event res;
				res = mdns_xtcp_handler(tcp_svr, conn);
				if (res & mdns_entry_lost)
				{
					printstr("Media clock: FIFO\n");
					set_device_media_clock_type(0, MEDIA_FIFO_DERIVED);
				}
			}

			c_api_xtcp_handler(tcp_svr, conn);

			// add any special tcp/ip packet handling here
			break;

			// Receive any events from user button presses
			case c_gpio_ctl :> int cmd:
			switch (cmd)
			{
				case STREAM_SEL:
				change_stream = 1;
				break;
				case CHAN_SEL:
				{
					enum avb_sink_state_t cur_state;

					c_gpio_ctl :> selected_chan;
					get_avb_sink_state(0, cur_state);
					set_avb_sink_state(0, AVB_SINK_STATE_DISABLED);
					for (int j=0;j<8;j++)
					map[j] = (j+selected_chan*2) & 0x7;
					set_avb_sink_map(0, map, 8);
					if (cur_state != AVB_SINK_STATE_DISABLED)
					set_avb_sink_state(0, AVB_SINK_STATE_POTENTIAL);
				}
				break;
			}
			break;

			// Periodic processing
			case tmr when timerafter(timeout) :> void:
			timeout += PERIODIC_POLL_TIME;

			do {
			avb_status = avb_periodic();
			switch (avb_status)
			{
				case AVB_MAAP_ADDRESSES_RESERVED:
				for(int i=0;i<AVB_NUM_SOURCES;i++) {
					avb_1722_maap_get_offset_address(macaddr, i);
					// activate the source
					set_avb_source_dest(i, macaddr, 6);
					set_avb_source_state(i, AVB_SOURCE_STATE_POTENTIAL);
				}
				break;
			}
			} while (avb_status != AVB_NO_STATUS);

			// Call the stream manager to check for new streams/manage
			// what is being listened to
			demo_manage_listener_stream(change_stream, selected_chan);

			break;
		}
	}
}
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Post by Andy »

Can you try updating your demo() function with the latest code here:

https://github.com/xcore/sw_avb/blob/ma ... vb_demo.xc

You'll notice that the number 8 (the number of channels) is hard coded in several places in the version of the code you've ported. The latest version above uses the correct channel num defines from avb_conf.h.
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

Ah ok thanks thats good to know :)

after updating the demo function with the code you provided i'm getting these messages:

Code: Select all

\227Using dynamic ip
INFO: AVB1722_EthernetRx : Started..
PTP Role: Master
Found 229700119D0000
.Mapping 229700119D0000 ---> 0
There is still no Clock out on Sync Pin and nothing on the I2S Ports.
Watching the Sync Pin with the scope shows it's being high for a few ms and then constantly going to low.

By the way:
The Attero Tech Demo Tool is also finding nothing when i click on Discover Endpoints.
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

New Update:

I replaced the PTP Server function with the new one and now the Slave seems to work.
Correct MCLK BCLK LRCLK are present on the Outputs. ;)

On the Board thats setting itself als PTP Master there is still no Output.
Debugging that one shows the following ET_LOAD_STORE error und suspends:

Image


could that also be a problem with the "older" listener module?
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

After preparing another project with an l1 usb audio interface for a presentation i finally found some time to work on the avb problem again.

But still its very frustrating :?

I tried nearly everything i could imagine but i stell get on the device that's setting itself as a master the following errors when debugging it:

Image


The error seems to be in the listener unit when i guess the fifos are initialized?
I hoped i don't have to alter the modules from xmos...


Does anybody have a clue or an idea for this error?

Thanks a lot
Manuel


below is my application code:

Code: Select all

#include <platform.h>
#include <print.h>
#include <assert.h>
#include <xccompat.h>
#include <stdio.h>
#include <string.h>
#include "xtcp_client.h"
#include "uip_server.h"
#include "audio_i2s.h"
#include "xlog_server.h"
#include "i2c.h"
#include "avb.h"
#include "audio_clock_CS2300CP.h"
//#include "audio_codec_CS42448.h"
#include "simple_printf.h"
#include "media_fifo.h"
#include "mdns.h"
#include "control_api_server.h"
#include "osc.h"
#include "demo_stream_manager.h"

#define PORT_SYNC_OUT XS1_PORT_1A
#define PORT_MCLK XS1_PORT_1B
#define PORT_SCLK XS1_PORT_1C
#define PORT_LRCLK XS1_PORT_1D
#define PORT_SDATA_OUT0 XS1_PORT_1E
#define PORT_SDATA_OUT1 XS1_PORT_1F
#define PORT_SDATA_IN0 XS1_PORT_1G
#define PORT_SDATA_IN1 XS1_PORT_1H

#define PORT_I2C_SCL XS1_PORT_1G
#define PORT_I2C_SDA XS1_PORT_1H
#define PORT_LEDS XS1_PORT_4A


// this is the sample rate, the frequency of the word clock
#define SAMPLE_RATE 48000

// This is the number of master clocks in a word clock
#define MASTER_TO_WORDCLOCK_RATIO 512

// Set the period inbetween periodic processing to 50us based
// on the Xcore 100Mhz timer.
#define PERIODIC_POLL_TIME 5000

// Timeout for debouncing buttons
#define BUTTON_TIMEOUT_PERIOD (20000000)

// Commands sent from the GPIO to the main demo app
enum gpio_cmd {
	STREAM_SEL, CHAN_SEL, REMOTE_SEL
};

// Note that this port must be at least declared to ensure it
// drives the mute low
on stdcore[2]: out port p_mute_led_remote = XS1_PORT_4B; // mute, led remote;
on stdcore[2]: out port p_chan_leds = PORT_LEDS;

on stdcore[2]: in port p_buttons = XS1_PORT_4C;

void demo(chanend tcp_svr, chanend c_rx, chanend c_tx, chanend c_gpio_ctl);

void ptp_server_and_gpio(chanend c_rx, chanend c_tx, chanend ptp_link[],
		int num_ptp, enum ptp_server_type server_type, chanend c);

//***** Ethernet Configuration ****
on stdcore[2]: port otp_data = XS1_PORT_32B; // OTP_DATA_PORT
on stdcore[2]: out port otp_addr = XS1_PORT_16C; // OTP_ADDR_PORT
on stdcore[2]: port otp_ctrl = XS1_PORT_16D; // OTP_CTRL_PORT

on stdcore[2]: mii_interface_t mii = {
		XS1_CLKBLK_1,
		XS1_CLKBLK_2,
		PORT_ETH_RXCLK,
		PORT_ETH_RXER,
		PORT_ETH_RXD,
		PORT_ETH_RXDV,
		PORT_ETH_TXCLK,
		PORT_ETH_TXEN,
		PORT_ETH_TXD
};

on stdcore[2]: clock clk_smi = XS1_CLKBLK_5;

on stdcore[2]: smi_interface_t smi = { PORT_ETH_RST_N_MDIO, PORT_ETH_MDC, 1 };

on stdcore[2]: struct r_i2c r_i2c = { PORT_I2C_SCL, PORT_I2C_SDA };

//***** AVB audio ports ****
on stdcore[1]: out port p_fs = PORT_SYNC_OUT;
on stdcore[1]: clock b_mclk = XS1_CLKBLK_1;
on stdcore[1]: clock b_bclk = XS1_CLKBLK_2;
on stdcore[1]: in port p_aud_mclk = PORT_MCLK;
on stdcore[1]: buffered out port:32 p_aud_bclk = PORT_SCLK;
on stdcore[1]: out buffered port:32 p_aud_lrclk = PORT_LRCLK;
on stdcore[1]: out buffered port:32 p_aud_dout[2] = {
		PORT_SDATA_OUT0,
		PORT_SDATA_OUT1
};

on stdcore[1]: in buffered port:32 p_aud_din[2] = {
		PORT_SDATA_IN0,
		PORT_SDATA_IN1,
};

on stdcore[0]: port p_uart_tx = PORT_UART_TX;

media_input_fifo_data_t ififo_data[AVB_NUM_MEDIA_INPUTS];
media_input_fifo_t ififos[AVB_NUM_MEDIA_INPUTS];

media_output_fifo_data_t ofifo_data[AVB_NUM_MEDIA_OUTPUTS];
media_output_fifo_t ofifos[AVB_NUM_MEDIA_OUTPUTS];




int main(void) {
	// ethernet tx channels
	chan tx_link[5];
	chan rx_link[4];
	chan connect_status;

	//ptp channels
	chan ptp_link[3];

	// avb unit control
	chan listener_ctl[AVB_NUM_LISTENER_UNITS];
	chan buf_ctl[AVB_NUM_LISTENER_UNITS];
	chan talker_ctl[AVB_NUM_TALKER_UNITS];

	// media control
	chan media_ctl[AVB_NUM_MEDIA_UNITS];
	chan clk_ctl[AVB_NUM_MEDIA_CLOCKS];
	chan media_clock_ctl;

	// audio channels
	streaming
	chan c_samples_to_codec;

	// tcp/ip channels
	chan xtcp[1];

	// control channel from the GPIO buttons
	chan c_gpio_ctl;

	par
	{
		// AVB - Ethernet
		on stdcore[2]:
		{
			int mac_address[2];
			ethernet_getmac_otp(otp_data,
                                            otp_addr,
                                            otp_ctrl,
                                            (mac_address, char[]));
			phy_init(clk_smi, null,
					smi,
					mii);

			ethernet_server(mii, mac_address,
					rx_link, 4,
					tx_link, 5,
					smi, connect_status);
		}

		// TCP/IP stack
		on stdcore[2]:
		{
			uip_server(rx_link[1],
                                   tx_link[2],
                                   xtcp, 1,
                                   null,
                                   connect_status);
		}

		// AVB - PTP
		on stdcore[2]:
		{
			// We need to initiate the PLL from core 1, so do it here before
			// launching  the main function of the thread
			audio_clock_CS2300CP_init(r_i2c, MASTER_TO_WORDCLOCK_RATIO);

			ptp_server_and_gpio(rx_link[0], tx_link[0], ptp_link, 3,
					PTP_GRANDMASTER_CAPABLE,
					c_gpio_ctl);

		}

		on stdcore[2]:
		{
			media_clock_server(media_clock_ctl,
					ptp_link[1],
					buf_ctl,
					1,
					clk_ctl,
					1);
		}

		// AVB - Audio
		on stdcore[1]: {
			init_media_input_fifos(ififos, ififo_data, AVB_NUM_MEDIA_INPUTS);
			configure_clock_src(b_mclk, p_aud_mclk);
			start_clock(b_mclk);
			par
			{
				audio_gen_CS2300CP_clock(p_fs, clk_ctl[0]);

				i2s_master (b_mclk,
						b_bclk,
						p_aud_bclk,
						p_aud_lrclk,
						p_aud_dout,
						AVB_NUM_MEDIA_OUTPUTS,
						p_aud_din,
						AVB_NUM_MEDIA_INPUTS,
						MASTER_TO_WORDCLOCK_RATIO,
						c_samples_to_codec,
						ififos,
						media_ctl[0],
						0);
			}
		}

		// AVB Talker - must be on the same core as the audio interface
		on stdcore[1]: avb_1722_talker(ptp_link[0],
				tx_link[1],
				talker_ctl[0],
				AVB_NUM_SOURCES);

		// AVB Listener
		on stdcore[1]: avb_1722_listener(rx_link[3],
				tx_link[3],
				buf_ctl[0],
				listener_ctl[0],
				AVB_NUM_SINKS);

		on stdcore[1]:
		{	init_media_output_fifos(ofifos, ofifo_data, AVB_NUM_MEDIA_OUTPUTS);
			media_output_fifo_to_xc_channel_split_lr(media_ctl[1],
					c_samples_to_codec,
					0, // clk_ctl index
					ofifos,
					AVB_NUM_MEDIA_OUTPUTS);
		}

		// Xlog server
		on stdcore[0]:
		{
			xlog_server_uart(p_uart_tx);
		}

		// Application threads
		on stdcore[0]:
		{
			// First initialize avb higher level protocols
			avb_init(media_ctl, listener_ctl, talker_ctl, media_clock_ctl, rx_link[2], tx_link[4], ptp_link[2]);

			demo(xtcp[0], rx_link[2], tx_link[4], c_gpio_ctl);
		}
	}

	return 0;
}

void ptp_server_and_gpio(chanend c_rx, chanend c_tx, chanend ptp_link[],
		int num_ptp, enum ptp_server_type server_type, chanend c) {

	static unsigned buttons_active = 1;
	static unsigned buttons_timeout;
	static unsigned remote = 0;
	static unsigned selected_chan = 0;

	unsigned button_val;
	timer tmr;
	p_mute_led_remote	<: ~(remote << 1) | 1;
	p_chan_leds <: ~(1 << selected_chan);
	p_buttons :> button_val;

	ptp_server_init(c_rx, c_tx, server_type);

	while (1) {
		select
		{
			do_ptp_server(c_rx, c_tx, ptp_link, num_ptp);

			case buttons_active =>
			p_buttons when pinsneq(button_val) :> unsigned new_button_val:
			if ((button_val & 0x1) == 1 &&
					(new_button_val & 0x1) == 0) {
				c <: STREAM_SEL;
				buttons_active = 0;
			}
			if ((button_val & 0x2) == 2 &&
					(new_button_val & 0x2) == 0) {
				remote = 1-remote;
				p_mute_led_remote <: ~(remote << 1) | 1;

				/* Currently we do not do anything with the remote select
				 mode. So there is no need to signal the demo thread. */
				//c <: REMOTE_SEL;
				//c <: remote;
				buttons_active = 0;
			}
			if ((button_val & 0x4) == 4 &&
					(new_button_val & 0x4) == 0) {
				selected_chan++;
				if (selected_chan > 3)
				selected_chan = 0;
				p_chan_leds <: ~(1 << selected_chan);
				c <: CHAN_SEL;
				c <: selected_chan;
				buttons_active = 0;
			}
			if (!buttons_active) {
				tmr :> buttons_timeout;
				buttons_timeout += BUTTON_TIMEOUT_PERIOD;
			}
			button_val = new_button_val;
			break;
			case !buttons_active => tmr when timerafter(buttons_timeout) :> void:
			buttons_active = 1;
			p_buttons :> button_val;
			break;

		}
	}
}

/** The main application control thread **/
void demo(chanend tcp_svr, chanend c_rx, chanend c_tx, chanend c_gpio_ctl) {

	timer tmr;
	int avb_status = 0;
	int map[AVB_NUM_MEDIA_INPUTS];
	unsigned char macaddr[6];
	int selected_chan = 0;
	unsigned change_stream = 1;
	unsigned timeout;

	// Set AVB to be in "legacy" mode
	avb_set_legacy_mode(1);

	// Initialize Zeroconf
	mdns_init(tcp_svr);

	// Register all the zeroconf names
	mdns_register_canonical_name("xmos_attero_endpoint");
	mdns_register_service("XMOS/Attero AVB", "_attero-cfg._udp",
			ATTERO_CFG_PORT, "");

	// Initialize the control api server
	c_api_server_init(tcp_svr);

	// Initialize the media clock (a ptp derived clock)
	//printstr("Media clock: LOCAL\n");
	//set_device_media_clock_type(0, MEDIA_FIFO_DERIVED);
	set_device_media_clock_type(0, LOCAL_CLOCK);
	//set_device_media_clock_type(0, PTP_DERIVED);
	set_device_media_clock_rate(0, SAMPLE_RATE);
	set_device_media_clock_state(0, DEVICE_MEDIA_CLOCK_STATE_ENABLED);

	// Configure the source stream
	set_avb_source_name(0, "multi channel stream out");

	set_avb_source_channels(0, AVB_NUM_MEDIA_INPUTS);
	for (int i = 0; i < AVB_NUM_MEDIA_INPUTS; i++)
		map[i] = i;
	set_avb_source_map(0, map, AVB_NUM_MEDIA_INPUTS);
	set_avb_source_format(0, AVB_SOURCE_FORMAT_MBLA_24BIT, SAMPLE_RATE);
	set_avb_source_sync(0, 0); // use the media_clock defined above

	// Main loop
	tmr	:> timeout;
	while (1) {
		unsigned char tmp;
		xtcp_connection_t conn;
		unsigned int streamId[2];
		unsigned int nbytes;
		unsigned int buf[(MAX_AVB_CONTROL_PACKET_SIZE+1)>>2];
		int already_seen;

		select
		{
			// Receive any incoming AVB packets (802.1Qat, 1722_MAAP)
			case avb_get_control_packet(c_rx, buf, nbytes):

			// Process AVB control packet if it is one
			avb_status = avb_process_control_packet(buf, nbytes, c_tx);
			switch (avb_status)
			{
				case AVB_SRP_TALKER_ROUTE_FAILED:
				avb_srp_get_failed_stream(streamId);
				// handle a routing failure here
				break;
				case AVB_SRP_LISTENER_ROUTE_FAILED:
				avb_srp_get_failed_stream(streamId);
				// handle a routing failure here
				break;
				case AVB_MAAP_ADDRESSES_LOST:
				// oh dear, someone else is using our multicast address
				for (int i=0;i<AVB_NUM_SOURCES;i++)
				set_avb_source_state(i, AVB_SOURCE_STATE_DISABLED);

				// request a different address
				avb_1722_maap_request_addresses(AVB_NUM_SOURCES, null);
				break;
				default:
				break;
			}

			// add any special control packet handling here
			break;

			// Process TCP/IP events
			case xtcp_event(tcp_svr, conn):
			{
				if (conn.event == XTCP_IFUP)
				{
					avb_start();

					// Request a multicast addresses for stream transmission
					avb_1722_maap_request_addresses(AVB_NUM_SOURCES, null);
				}
				else if (conn.event == XTCP_IFDOWN)
				{
					for(int i=0; i<AVB_NUM_SOURCES; i++)
					{
						set_avb_source_state(i, AVB_SOURCE_STATE_DISABLED);
					}
				}

				{
					mdns_event res;
					res = mdns_xtcp_handler(tcp_svr, conn);
					if (res & mdns_entry_lost)
					{
						printstr("Media clock: FIFO\n");
						set_device_media_clock_type(0, MEDIA_FIFO_DERIVED);
					}
				}

				c_api_xtcp_handler(tcp_svr, conn);

				// add any special tcp/ip packet handling here
			}
			break;

			// Receive any events from user button presses
			case c_gpio_ctl :> int cmd:
			{
				switch (cmd)
				{
					case STREAM_SEL:
					change_stream = 1;
					break;
					case CHAN_SEL:
					{
						enum avb_sink_state_t cur_state;

						c_gpio_ctl :> selected_chan;
						get_avb_sink_state(0, cur_state);
						set_avb_sink_state(0, AVB_SINK_STATE_DISABLED);
						for (int j=0;j<AVB_NUM_MEDIA_INPUTS;j++)
						map[j] = (j+selected_chan*2) & 0x7;
						set_avb_sink_map(0, map, AVB_NUM_MEDIA_INPUTS);
						if (cur_state != AVB_SINK_STATE_DISABLED)
						set_avb_sink_state(0, AVB_SINK_STATE_POTENTIAL);
					}
					break;
				}
			}
			break;

			// Periodic processing
			case tmr when timerafter(timeout) :> void:
			timeout += PERIODIC_POLL_TIME;

			do
			{
				avb_status = avb_periodic();
				switch (avb_status)
				{
					case AVB_MAAP_ADDRESSES_RESERVED:
					for(int i=0;i<AVB_NUM_SOURCES;i++) {
						avb_1722_maap_get_offset_address(macaddr, i);
						// activate the source
						set_avb_source_dest(i, macaddr, 6);
						set_avb_source_state(i, AVB_SOURCE_STATE_POTENTIAL);
					}
					break;
				}
			}while (avb_status != AVB_NO_STATUS);

			// Call the stream manager to check for new streams/manage
			// what is being listened to
			demo_manage_listener_stream(change_stream, selected_chan);

			break;
		}
	}
}


User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Post by Andy »

Hi Manust,

Can you print s.num_channels after it is received on the channel? It should equal 2 but if it's not it will access an invalid array index and crash.
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

Outputting this value gives "8" there seems to be the problem.
I'm checking now why this happens...
User avatar
Manust
Member++
Posts: 19
Joined: Tue Mar 29, 2011 3:56 pm

Post by Manust »

Good Morning!

I finally decided for the moment to switch to 8 channels and now the endpoints seem to work, didn't had a scope at home but debug informations showed "stream on" so i guess they are "coupling".
So it seems the "8" channels are still hardcode somewhere else :S

Then i wanted to test the attero config tool but it isn't able to find the endpoints.
Is there a check for the use processor so it only works with the LC-Board?


Thanks

Greetings,
Manuel