Whitney Knitter
Published © GPL3+

Automated Control of SP701 Over LAN using lwIP

This project shows how to use an lwIP server on the SP701 to be able to send it commands/data on a local area network (LAN).

IntermediateFull instructions provided1 hour1,256
Automated Control of SP701 Over LAN using lwIP

Things used in this project

Hardware components

Spartan-7 SP701 FPGA Evaluation Kit
AMD Spartan-7 SP701 FPGA Evaluation Kit
×1
Ethernet Cable, Cat6a
Ethernet Cable, Cat6a
×1

Software apps and online services

Vitis Unified Software Platform
AMD Vitis Unified Software Platform

Story

Read more

Schematics

UG1319 SP701 Evaluation Board User Guide

Code

main.c

C/C++
#include <stdio.h>

#include "led_8bits.h"
#include "xparameters.h"

#include "netif/xadapter.h"

#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif

#include "lwip/tcp.h"
#include "xil_cache.h"

#if LWIP_IPV6==1
#include "lwip/ip.h"
#else
#if LWIP_DHCP==1
#include "lwip/dhcp.h"
#endif
#endif

/* defined by each RAW mode application */
void print_app_header();
int start_application();
int transfer_data();
void tcp_fasttmr(void);
void tcp_slowtmr(void);

/* missing declaration in lwIP */
void lwip_init();

#if LWIP_IPV6==0
#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif
#endif

extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
static struct netif server_netif;
struct netif *echo_netif;

#if LWIP_IPV6==1
void print_ip6(char *msg, ip_addr_t *ip)
{
	print(msg);
	xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
			IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK8(&ip->u_addr.ip6));

}
#else
void
print_ip(char *msg, ip_addr_t *ip)
{
	print(msg);
	xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
			ip4_addr3(ip), ip4_addr4(ip));
}

void
print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{

	print_ip("Board IP: ", ip);
	print_ip("Netmask : ", mask);
	print_ip("Gateway : ", gw);
}
#endif

#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
int ProgramSi5324(void);
int ProgramSfpPhy(void);
#endif
#endif

#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endif

int main()
{
#if LWIP_IPV6==0
	ip_addr_t ipaddr, netmask, gw;

#endif
	/* the mac address of the board. this should be unique per board */
	unsigned char mac_ethernet_address[] =
	{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

	echo_netif = &server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
	ProgramSi5324();
	ProgramSfpPhy();
#endif
#endif

/* Define this board specific macro in order perform PHY reset on ZCU102 */
#ifdef XPS_BOARD_ZCU102
	if(IicPhyReset()) {
		xil_printf("Error performing PHY reset \n\r");
		return -1;
	}
#endif

	init_platform();
	Configure_led_8bits_ctrl();

	xil_printf("Hello SP701!\n\r");

#if LWIP_IPV6==0
#if LWIP_DHCP==1
    ipaddr.addr = 0;
	gw.addr = 0;
	netmask.addr = 0;
#else
	/* initialize IP addresses to be used */
	IP4_ADDR(&ipaddr,  192, 168,   1, 10);
	IP4_ADDR(&netmask, 255, 255, 255,  0);
	IP4_ADDR(&gw,      192, 168,   1,  1);
#endif
#endif
	print_app_header();

	lwip_init();

#if (LWIP_IPV6 == 0)
	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, &ipaddr, &netmask,
						&gw, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
#else
	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
	echo_netif->ip6_autoconfig_enabled = 1;

	netif_create_ip6_linklocal_address(echo_netif, 1);
	netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);

	print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);

#endif
	netif_set_default(echo_netif);

	/* now enable interrupts */
	platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(echo_netif);

#if (LWIP_IPV6 == 0)
#if (LWIP_DHCP==1)
	/* Create a new DHCP client for this interface.
	 * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
	 * the predefined regular intervals after starting the client.
	 */
	dhcp_start(echo_netif);
	dhcp_timoutcntr = 24;

	while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
		xemacif_input(echo_netif);

	if (dhcp_timoutcntr <= 0) {
		if ((echo_netif->ip_addr.addr) == 0) {
			xil_printf("DHCP Timeout\r\n");
			xil_printf("Configuring default IP of 192.168.1.10\r\n");
			IP4_ADDR(&(echo_netif->ip_addr),  192, 168,   1, 10);
			IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);
			IP4_ADDR(&(echo_netif->gw),      192, 168,   1,  1);
		}
	}

	ipaddr.addr = echo_netif->ip_addr.addr;
	gw.addr = echo_netif->gw.addr;
	netmask.addr = echo_netif->netmask.addr;
#endif

	print_ip_settings(&ipaddr, &netmask, &gw);

#endif
	/* start the application (web server, rxtest, txtest, etc..) */
	start_application();

	/* receive and process packets */
	while (1) {
		if (TcpFastTmrFlag) {
			tcp_fasttmr();
			TcpFastTmrFlag = 0;
		}
		if (TcpSlowTmrFlag) {
			tcp_slowtmr();
			TcpSlowTmrFlag = 0;
		}
		xemacif_input(echo_netif);
		transfer_data();
	}

	/* never reached */
	cleanup_platform();

	return 0;
}

echo.c

C/C++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "led_8bits.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#if defined (__arm__) || defined (__aarch64__)
#include "xil_printf.h"
#endif

char command[32]; // 32 byte buffer length in python

char LED0_on_command[]  = "LED0 on";
char LED1_on_command[]  = "LED1 on";
char LED2_on_command[]  = "LED2 on";
char LED3_on_command[]  = "LED3 on";
char LED4_on_command[]  = "LED4 on";
char LED5_on_command[]  = "LED5 on";
char LED6_on_command[]  = "LED6 on";
char LED7_on_command[]  = "LED7 on";

char LED0_off_command[] = "LED0 off";
char LED1_off_command[] = "LED1 off";
char LED2_off_command[] = "LED2 off";
char LED3_off_command[] = "LED3 off";
char LED4_off_command[] = "LED4 off";
char LED5_off_command[] = "LED5 off";
char LED6_off_command[] = "LED6 off";
char LED7_off_command[] = "LED7 off";

char all_LEDs_on_command[]  = "All LEDs on";
char all_LEDs_off_command[] = "All LEDs off";

int transfer_data() {
	return 0;
}

void print_app_header()
{
#if (LWIP_IPV6==0)
	xil_printf("\n\r\n\r-----lwIP TCP echo server ------\n\r");
#else
	xil_printf("\n\r\n\r-----lwIPv6 TCP echo server ------\n\r");
#endif
	xil_printf("TCP packets sent to port 6001 will be echoed back\n\r");
}

err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
                               struct pbuf *p, err_t err)
{
	/* do not read the packet if we are not in ESTABLISHED state */
	if (!p) {
		tcp_close(tpcb);
		tcp_recv(tpcb, NULL);
		return ERR_OK;
	}

	/* indicate that the packet has been received */
	tcp_recved(tpcb, p->len);
	strncpy(command, p->payload, p->len);
	command[p->len] = 0;

	xil_printf("command = %s\n\r", command);

	if (strcmp(command, LED0_on_command) == 0 ) {
		xil_printf("LED0 on\n\r");
		set_LED(0, 1);
	} else if (strcmp(command, LED0_off_command) == 0 ) {
		xil_printf("LED0 off\n\r");
		set_LED(0, 0);
	} else if (strcmp(command, LED1_on_command) == 0 ) {
		xil_printf("LED1 on\n\r");
		set_LED(1, 1);
	} else if (strcmp(command, LED1_off_command) == 0 ) {
		xil_printf("LED1 off\n\r");
		set_LED(1, 0);
	} else if (strcmp(command, LED2_on_command) == 0 ) {
		xil_printf("LED2 on\n\r");
		set_LED(2, 1);
	} else if (strcmp(command, LED2_off_command) == 0 ) {
		xil_printf("LED2 off\n\r");
		set_LED(2, 0);
	} else if (strcmp(command, LED3_on_command) == 0 ) {
		xil_printf("LED3 on\n\r");
		set_LED(3, 1);
	} else if (strcmp(command, LED3_off_command) == 0 ) {
		xil_printf("LED3 off\n\r");
		set_LED(3, 0);
	} else if (strcmp(command, LED4_on_command) == 0 ) {
		xil_printf("LED4 on\n\r");
		set_LED(4, 1);
	} else if (strcmp(command, LED4_off_command) == 0 ) {
		xil_printf("LED4 off\n\r");
		set_LED(4, 0);
	} else if (strcmp(command, LED5_on_command) == 0 ) {
		xil_printf("LED5 on\n\r");
		set_LED(5, 1);
	} else if (strcmp(command, LED5_off_command) == 0 ) {
		xil_printf("LED5 off\n\r");
		set_LED(5, 0);
	} else if (strcmp(command, LED6_on_command) == 0 ) {
		xil_printf("LED6 on\n\r");
		set_LED(6, 1);
	} else if (strcmp(command, LED6_off_command) == 0 ) {
		xil_printf("LED6 off\n\r");
		set_LED(6, 0);
	} else if (strcmp(command, LED7_on_command) == 0 ) {
		xil_printf("LED7 on\n\r");
		set_LED(7, 1);
	} else if (strcmp(command, LED7_off_command) == 0 ) {
		xil_printf("LED7 off\n\r");
		set_LED(7, 0);
	} else if (strcmp(command, all_LEDs_on_command) == 0 ) {
		xil_printf("All LEDs on\n\r");
		assert_LEDs();
	} else if (strcmp(command, all_LEDs_off_command) == 0 ) {
		xil_printf("All LEDs off\n\r");
		clear_LEDs();
	} else {
		xil_printf("unrecognized command\n\r");
	}

	/* echo back the payload */
	/* in this case, we assume that the payload is < TCP_SND_BUF */
	if (tcp_sndbuf(tpcb) > p->len) {
		err = tcp_write(tpcb, p->payload, p->len, 1);
	} else
		xil_printf("no space in tcp_sndbuf\n\r");

	/* free the received pbuf */
	pbuf_free(p);

	/* clear command char value */
	memset(command, 0, 32);

	return ERR_OK;
}

err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	static int connection = 1;

	/* set the receive callback for this connection */
	tcp_recv(newpcb, recv_callback);

	/* just use an integer number indicating the connection id as the
	   callback argument */
	tcp_arg(newpcb, (void*)(UINTPTR)connection);

	/* increment for subsequent accepted connections */
	connection++;

	return ERR_OK;
}


int start_application()
{
	struct tcp_pcb *pcb;
	err_t err;
	unsigned port = 7;

	/* create new TCP PCB structure */
	pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
	if (!pcb) {
		xil_printf("Error creating PCB. Out of Memory\n\r");
		return -1;
	}

	/* bind to specified @port */
	err = tcp_bind(pcb, IP_ANY_TYPE, port);
	if (err != ERR_OK) {
		xil_printf("Unable to bind to port %d: err = %d\n\r", port, err);
		return -2;
	}

	/* we do not need any arguments to callback functions */
	tcp_arg(pcb, NULL);

	/* listen for connections */
	pcb = tcp_listen(pcb);
	if (!pcb) {
		xil_printf("Out of memory while tcp_listen\n\r");
		return -3;
	}

	/* specify callback to use for incoming connections */
	tcp_accept(pcb, accept_callback);

	xil_printf("TCP echo server started @ port %d\n\r", port);

	return 0;
}

led_8bits.c

C/C++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "xgpio.h"
#include "led_8bits.h"
#include "xil_assert.h"
#include "xparameters.h"
#include "xil_exception.h"

static XGpio led_8bits_ctrl_Ptr;
XGpio_Config *led_8bits_ctrl_Config_Ptr;

int status;

int Configure_led_8bits_ctrl()
{
	led_8bits_ctrl_Config_Ptr = XGpio_LookupConfig(led_8bits_ctrl_DeviceID);

	status = XGpio_CfgInitialize(&led_8bits_ctrl_Ptr, led_8bits_ctrl_Config_Ptr, led_8bits_ctrl_Config_Ptr->BaseAddress);

	if(status != XST_SUCCESS)
	{
		xil_printf("Failed to Initialize led_8bits GPIO Interface\n\r");
		return XST_FAILURE;
	}

	// Set all bits to be outputs
	XGpio_SetDataDirection(&led_8bits_ctrl_Ptr, 1, 0);

	return XST_SUCCESS;
}


int set_LED(int LED_num, int logic_level){

	u32 LED_mask;

	switch (LED_num){
	case 0:
		LED_mask = LED0;
		break;
	case 1:
		LED_mask = LED1;
		break;
	case 2:
		LED_mask = LED2;
		break;
	case 3:
		LED_mask = LED3;
		break;
	case 4:
		LED_mask = LED4;
		break;
	case 5:
		LED_mask = LED5;
		break;
	case 6:
		LED_mask = LED6;
		break;
	case 7:
		LED_mask = LED7;
		break;
	default:
		LED_mask = ALL_LEDS;
		break;
	}

	if (logic_level == 0){
		// set LED low
		XGpio_DiscreteClear(&led_8bits_ctrl_Ptr, 1, LED_mask);
	} else {
		// set LED high
		XGpio_DiscreteSet(&led_8bits_ctrl_Ptr, 1, LED_mask);
	}

	return XST_SUCCESS;

}

int clear_LEDs(){

	u32 LED_mask;
	LED_mask = ALL_LEDS;

	XGpio_DiscreteClear(&led_8bits_ctrl_Ptr, 1, LED_mask);

	return XST_SUCCESS;
}

int assert_LEDs(){

	u32 LED_mask;
	LED_mask = ALL_LEDS;

	XGpio_DiscreteSet(&led_8bits_ctrl_Ptr, 1, LED_mask);

	return XST_SUCCESS;

}

led_8bits.h

C Header File
#ifndef __LED_8BITS_H_
#define __LED_8BITS_H_

int Configure_led_8bits_ctrl();
int set_LED(int LED_num, int logic_level);
int clear_LEDs();
int assert_LEDs();

#define led_8bits_ctrl_DeviceID    XPAR_AXI_GPIO_1_DEVICE_ID
#define LED0                       0x00000001
#define LED1                       0x00000002
#define LED2                       0x00000004
#define LED3                       0x00000008
#define LED4                       0x00000010
#define LED5                       0x00000020
#define LED6                       0x00000040
#define LED7                       0x00000080
#define ALL_LEDS                   0x000000ff

#endif /* LED_8BITS_H_ */

led_blink_echo_client.py

Python
import socket
import time
import sys

def echo_packet(lwIP_socket, message):
	message_byte = message.encode()
	
	lwIP_socket.sendall(message_byte)
	
	bytes_buffer_size = 32	
	bytes_received = 0
	bytes_total = len(message)
	
	while bytes_received < bytes_total:
		message_recvd = lwIP_socket.recv(bytes_buffer_size)
		bytes_received += len(message_recvd)
		print(message_recvd)

print('Create a socket on the host PC client.')
lwIP_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print('Connect to the socket of the lwIP server listening on the SP701.')
lwIP_server_address = ('192.168.1.10', 7)
lwIP_socket.connect(lwIP_server_address)

try:
	message = 'All LEDs off'	
	echo_packet(lwIP_socket, message)		
	time.sleep(0.5)	
		
	message = 'LED0 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED1 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED2 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED3 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED4 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED5 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED6 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED7 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED0 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED1 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED2 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED3 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)

	message = 'LED4 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED5 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED6 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED7 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)
		
finally: 
	print('Closing the socket from the host PC client side...')
	lwIP_socket.close()

Credits

Whitney Knitter

Whitney Knitter

169 projects • 1700 followers
All thoughts/opinions are my own and do not reflect those of any company/entity I currently/previously associate with.

Comments