Ethernet Shield code

This commit is contained in:
Andreas Mieke 2018-04-03 22:50:13 +02:00
parent 496209fb46
commit f3d70e65a8
7 changed files with 1158 additions and 2 deletions

115
Mieke/SW/ETH/main.c Normal file
View file

@ -0,0 +1,115 @@
/*
Ethernet shield test program
Copyright (C) 2018 Andreas Mieke
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "stm32f10x.h"
#include "stm32f10x_usart.h" // Keil::Device:StdPeriph Drivers:USART
#include "w5100.h"
#include "socket.h"
#include "string.h"
#define BUFFLEN 256
// Socket (TCP) with ID 1
SOCKET tcp = 1;
uint8_t buffer[BUFFLEN] = {0};
uint8_t len = 0;
void USART_SendString(USART_TypeDef *USARTx, uint8_t *str)
{
// Send a string character by character over UART
while(*str) {
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
USART_SendData(USARTx, *str++);
}
}
int main() {
// Enable USART 1 and GPIOA clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// Create gpio strct and set default values
GPIO_InitTypeDef gpio;
GPIO_StructInit(&gpio);
// Set PA9 to alternate function push pull (TxD)
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOA, &gpio);
// Set PA10 to input floating (RxD)
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &gpio);
// Set up USART1
USART_InitTypeDef usart;
USART_StructInit(&usart);
USART_Init(USART1, &usart);
// Set up USART1 clocks
USART_ClockInitTypeDef usartclock;
USART_ClockStructInit(&usartclock);
USART_ClockInit(USART1, &usartclock);
// Enable USART1
USART_Cmd(USART1, ENABLE);
// Initzialize Ethernet module
ETH_init();
// Set gateway IP
uint8_t gid[4] = {192, 168, 10, 1};
// Set subnet mask
uint8_t sma[4] = {255, 255, 255, 0};
// Set MAC address (unused testing address space)
uint8_t mac[6] = {0x1E, 0x8E, 0xA8, 0x88, 0x1C, 0xAA};
// Set source IP (IP of the Ethernet module)
uint8_t sip[4] = {192, 168, 10, 2};
// Transmit all these values to the module
ETH_set_gateway_IP(gid);
ETH_set_subnet_mask(sma);
ETH_set_mac(mac);
ETH_set_IP(sip);
// Try to create a TCP socket on port 80 as long as it does not work
do {
ETH_socket(tcp, ETH_SMR_TCP, 80, 0);
} while (ETH_socket_status(tcp) != ETH_SSR_INIT);
// Wait for the socket to finish creating
while(!ETH_listen(tcp));
// Endless loop
do {
// Wait for data to be available
while(ETH_recv_available(tcp) == 0);
// Receive data
buffer[ETH_recv(tcp, buffer, BUFFLEN)] = 0;
// Send data to USART
USART_SendString(USART1, buffer);
// Send string over tcp
ETH_send(tcp, "Hallo, Welt!", 12);
} while (1);
}

391
Mieke/SW/ETH/socket.c Normal file
View file

@ -0,0 +1,391 @@
/*
Ethernet shield test program
Copyright (C) 2018 Andreas Mieke
Copyright (C) 2010 Arduino LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "socket.h"
// Check if address is a net addres 0.0.0.0
#define is_net_addr(addr) ((addr[0] == 0x00) && \
(addr[1] == 0x00) && \
(addr[2] == 0x00) && \
(addr[3] == 0x00))
// Check if address is broadcast address 255.255.255.255
#define is_broadcast_addr(addr) ((addr[0] == 0xFF) && \
(addr[1] == 0xFF) && \
(addr[2] == 0xFF) && \
(addr[3] == 0xFF))
// Check if port is valid (not 0)
#define is_valid_port(port) (port != 0x00)
static uint16_t local_port;
uint8_t ETH_socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
{
// Check if protocol is supported
if ((protocol == ETH_SMR_TCP) || (protocol == ETH_SMR_UDP) || (protocol == ETH_SMR_IPRAW) || (protocol == ETH_SMR_MACRAW) || (protocol == ETH_SMR_PPPoE))
{
// Close socket, if open
ETH_close(s);
// Set the mode register to the protocol, plus eventual flags
ETH_writeSnMR(s, protocol | flag);
if (port != 0) {
// If port is not 0 (0 on client mode) write port to the port register
ETH_writeSnPORT(s, port);
}
else {
// Write a random port to the port register (for client mode)
local_port++;
ETH_writeSnPORT(s, local_port);
}
// Execute the open socket command
ETH_exec_socket_cmd(s, ETH_SCR_OPEN);
return 1;
}
return 0;
}
uint8_t ETH_socket_status(SOCKET s)
{
// Read the status register and return it
uint8_t tmp = ETH_readSnSR(s);
return tmp;
}
void ETH_close(SOCKET s)
{
// Execute close socket and disable interrupts
ETH_exec_socket_cmd(s, ETH_SCR_CLOSE);
ETH_writeSnIR(s, 0xFF);
}
uint8_t ETH_connect(SOCKET s, uint8_t * addr, uint16_t port)
{
// Check if port and address is valid
if (is_net_addr(addr) || is_broadcast_addr(addr) || !is_valid_port(port))
return 0;
// Write IP to destination register
ETH_writeSnDIPR(s, addr);
// Write port to destination register
ETH_writeSnDPORT(s, port);
// Execute connect
ETH_exec_socket_cmd(s, ETH_SCR_CONNECT);
return 1;
}
void ETH_disconnect(SOCKET s)
{
// Execute disconnect
ETH_exec_socket_cmd(s, ETH_SCR_DISCON);
}
uint8_t ETH_listen(SOCKET s)
{
// If state is not initzialized, return
if (ETH_readSnSR(s) != ETH_SSR_INIT) {
return 0;
}
// Execute the listen command
ETH_exec_socket_cmd(s, ETH_SCR_LISTEN);
return 1;
}
uint16_t ETH_send(SOCKET s, const uint8_t * buf, uint16_t len)
{
uint8_t status=0;
uint16_t ret=0;
uint16_t freesize=0;
// If data is bigger then Tx memory, split it
if (len > ETH_SSIZE)
ret = ETH_SSIZE;
else
ret = len;
do
{
// Write data to Tx memory
freesize = ETH_get_TX_free_size(s);
status = ETH_readSnSR(s);
if ((status != ETH_SSR_ESTABLISHED) && (status != ETH_SSR_CLOSE_WAIT))
{
ret = 0;
break;
}
}
while (freesize < ret);
// Start data processing and execute send command
ETH_send_data_processing(s, (uint8_t *)buf, ret);
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
// Check interrupt if everything is okay
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK )
{
// If socket is closed set the state locally right
if (ETH_readSnSR(s) == ETH_SSR_CLOSED )
{
ETH_close(s);
return 0;
}
}
// Mark interrupt as handled
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
return ret;
}
int16_t ETH_recv(SOCKET s, uint8_t * buf, int16_t len)
{
// Check remaining size
int16_t ret = ETH_get_RX_received_size(s);
if (ret == 0)
{
// Read status
uint8_t status = ETH_readSnSR(s);
// If status is wrong, return 0 read bytes
if (status == ETH_SSR_LISTEN || status == ETH_SSR_CLOSED || status == ETH_SSR_CLOSE_WAIT)
{
ret = 0;
}
else
{
// Return -1 if there is nothing to read
ret = -1;
}
}
// If there is more to read then we have space, just read to the supplied limit
else if (ret > len)
{
ret = len;
}
// If there is data to read and we have space, beginn processing and reading
if (ret > 0)
{
ETH_recv_data_processing(s, buf, ret, 0x00);
ETH_exec_socket_cmd(s, ETH_SCR_RECV);
}
return ret;
}
int16_t ETH_recv_available(SOCKET s)
{
// Check if data is available to read
return ETH_get_RX_received_size(s);
}
uint16_t ETH_peek(SOCKET s, uint8_t *buf)
{
// Receive one byte
ETH_recv_data_processing(s, buf, 1, 1);
return 1;
}
uint16_t ETH_sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
{
uint16_t ret=0;
// If write size is bigger then memory, limit to memory
if (len > ETH_SSIZE) ret = ETH_SSIZE;
else ret = len;
// Check if address and port is right
if (is_net_addr(addr) || !is_valid_port(port) || ret == 0) {
ret = 0;
}
else
{
// Set address and port to send to
ETH_writeSnDIPR(s, addr);
ETH_writeSnDPORT(s, port);
// Process data and send it
ETH_send_data_processing(s, (uint8_t *)buf, ret);
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
// Wait for the data to be sent
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
{
// If time out reset send and timout interrupts
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
{
ETH_writeSnIR(s, (ETH_SIR_SEND_OK | ETH_SIR_TIMEOUT));
return 0;
}
}
// Reset send ok interrupt
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
}
return ret;
}
uint16_t ETH_recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)
{
uint8_t head[8];
uint16_t data_len=0;
uint16_t ptr=0;
// Check if there is something to receive
if (len > 0)
{
// Get the receive pointer
ptr = ETH_readSnRX_RD(s);
// Handle receiving according to socket type
switch (ETH_readSnMR(s) & 0x07)
{
case ETH_SMR_UDP :
ETH_read_data(s, ptr, head, 0x08);
ptr += 8;
addr[0] = head[0];
addr[1] = head[1];
addr[2] = head[2];
addr[3] = head[3];
*port = head[4];
*port = (*port << 8) + head[5];
data_len = head[6];
data_len = (data_len << 8) + head[7];
ETH_read_data(s, ptr, buf, data_len);
ptr += data_len;
ETH_writeSnRX_RD(s, ptr);
break;
case ETH_SMR_IPRAW :
ETH_read_data(s, ptr, head, 0x06);
ptr += 6;
addr[0] = head[0];
addr[1] = head[1];
addr[2] = head[2];
addr[3] = head[3];
data_len = head[4];
data_len = (data_len << 8) + head[5];
ETH_read_data(s, ptr, buf, data_len);
ptr += data_len;
ETH_writeSnRX_RD(s, ptr);
break;
case ETH_SMR_MACRAW:
ETH_read_data(s, ptr, head, 2);
ptr+=2;
data_len = head[0];
data_len = (data_len<<8) + head[1] - 2;
ETH_read_data(s, ptr, buf, data_len);
ptr += data_len;
ETH_writeSnRX_RD(s, ptr);
break;
default :
break;
}
ETH_exec_socket_cmd(s, ETH_SCR_RECV);
}
return data_len;
}
void ETH_flush(SOCKET s)
{
// TODO
}
uint16_t ETH_igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
{
uint16_t ret=0;
if (len > ETH_SSIZE)
ret = ETH_SSIZE;
else
ret = len;
if (ret == 0)
return 0;
// Process and send IGMP data
ETH_send_data_processing(s, (uint8_t *)buf, ret);
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
// Wairt for data to be sent or timeout
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
{
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
{
ETH_close(s);
return 0;
}
}
// Reset interrupt
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
return ret;
}
int ETH_start_UDP(SOCKET s, uint8_t* addr, uint16_t port)
{
// Check if address and port are valid
if (is_net_addr(addr) || !is_valid_port(port))
{
return 0;
}
else
{
// Write IP and port
ETH_writeSnDIPR(s, addr);
ETH_writeSnDPORT(s, port);
return 1;
}
}
uint16_t ETH_buffer_data(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
{
uint16_t ret = 0;
if (len > ETH_get_TX_free_size(s))
{
ret = ETH_get_TX_free_size(s);
}
else
{
ret = len;
}
ETH_send_data_processing_offset(s, offset, buf, ret);
return ret;
}
int ETH_send_UDP(SOCKET s)
{
ETH_exec_socket_cmd(s, ETH_SCR_SEND);
while ((ETH_readSnIR(s) & ETH_SIR_SEND_OK) != ETH_SIR_SEND_OK)
{
if (ETH_readSnIR(s) & ETH_SIR_TIMEOUT)
{
ETH_writeSnIR(s, (ETH_SIR_SEND_OK | ETH_SIR_TIMEOUT));
return 0;
}
}
ETH_writeSnIR(s, ETH_SIR_SEND_OK);
return 1;
}

45
Mieke/SW/ETH/socket.h Normal file
View file

@ -0,0 +1,45 @@
/*
Ethernet shield test program
Copyright (C) 2018 Andreas Mieke
Copyright (C) 2010 Arduino LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __SOCKET_H
#define __SOCKET_H
#include "w5100.h"
uint8_t ETH_socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag);
uint8_t ETH_socket_status(SOCKET s);
void ETH_close(SOCKET s);
uint8_t ETH_connect(SOCKET s, uint8_t * addr, uint16_t port);
void ETH_disconnect(SOCKET s);
uint8_t ETH_listen(SOCKET s);
uint16_t ETH_send(SOCKET s, const uint8_t * buf, uint16_t len);
int16_t ETH_recv(SOCKET s, uint8_t * buf, int16_t len);
int16_t ETH_recv_available(SOCKET s);
uint16_t ETH_peek(SOCKET s, uint8_t *buf);
uint16_t ETH_sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port);
uint16_t ETH_recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port);
void ETH_flush(SOCKET s);
uint16_t ETH_igmpsend(SOCKET s, const uint8_t * buf, uint16_t len);
int ETH_start_UDP(SOCKET s, uint8_t* addr, uint16_t port);
uint16_t ETH_buffer_data(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len);
int ETH_send_UDP(SOCKET s);
#endif

256
Mieke/SW/ETH/w5100.c Normal file
View file

@ -0,0 +1,256 @@
/*
Ethernet shield test program
Copyright (C) 2018 Andreas Mieke
Copyright (C) 2010 Arduino LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "w5100.h"
uint16_t ETH_SBASE[ETH_SOCKETS]; // Tx buffer base address
uint16_t ETH_RBASE[ETH_SOCKETS]; // Rx buffer base address
#define TX_RX_MAX_BUF_SIZE 2048
#define TX_BUF 0x1100
#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
#define ETH_TXBUF_BASE 0x4000
#define ETH_RXBUF_BASE 0x6000
void SPI_SetSS(void)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
}
void SPI_ResetSS(void)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET);
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
}
uint8_t SPI_WriteRead(uint8_t write)
{
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI1->DR = write;
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return SPI1->DR;
}
void ETH_init(void)
{
// Port init stuff
// PA5 -> SCK
// PA6 -> MISO
// PA7 -> MOSI
// PC8 -> /SS
// Set RCC Registers for GPIOA/C
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
// Init gpio structure to default values
GPIO_InitTypeDef gpio;
GPIO_StructInit(&gpio);
// Set PA5 to alternate function PushPull
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &gpio);
// Set PA7 to alternate function push pull
gpio.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &gpio);
// Set PC8 to push pull
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOC, &gpio);
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
// Set PA6 to input floating
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &gpio);
// Init SPI engine
// Init struct to default values
SPI_InitTypeDef spi;
SPI_StructInit(&spi);
// We are master
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_NSS = SPI_NSS_Soft;
//spi.SPI_CPHA = SPI_CPHA_2Edge;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
// Write the registers
SPI_Init(SPI1, &spi);
// Enable SPI1
SPI_Cmd(SPI1, ENABLE);
for(uint16_t i = 0; i < 65535; i++);
ETH_writeMR(ETH_MR_RST);
ETH_writeRMSR(0x55);
ETH_writeTMSR(0x55);
for (int i=0; i<MAX_SOCK_NUM; i++) {
ETH_SBASE[i] = ETH_TXBUF_BASE + ETH_SSIZE * i;
ETH_RBASE[i] = ETH_RXBUF_BASE + ETH_RSIZE * i;
}
}
uint8_t ETH_write_8(uint16_t addr, uint8_t data)
{
SPI_SetSS();
SPI_WriteRead(0xF0);
SPI_WriteRead(addr >> 8);
SPI_WriteRead(addr & 0xFF);
SPI_WriteRead(data);
SPI_ResetSS();
return 8;
}
uint16_t ETH_write_n(uint16_t addr, const uint8_t *buf, uint16_t len)
{
for (uint16_t i = 0; i < len; i++) {
SPI_SetSS();
SPI_WriteRead(0xF0);
SPI_WriteRead(addr >> 8);
SPI_WriteRead(addr & 0xFF);
addr++;
SPI_WriteRead(buf[i]);
SPI_ResetSS();
}
return len;
}
uint8_t ETH_read_8(uint16_t addr)
{
uint8_t data;
SPI_SetSS();
SPI_WriteRead(0x0F);
SPI_WriteRead(addr >> 8);
SPI_WriteRead(addr & 0xFF);
data = SPI_WriteRead(0x00);
SPI_ResetSS();
return data;
}
uint16_t ETH_read_n(uint16_t addr, uint8_t *buf, uint16_t len)
{
for (uint16_t i = 0; i < len; i++) {
SPI_SetSS();
SPI_WriteRead(0x0F);
SPI_WriteRead(addr >> 8);
SPI_WriteRead(addr & 0xFF);
addr++;
buf[i] = SPI_WriteRead(0x00);
SPI_ResetSS();
}
return len;
}
uint16_t ETH_get_TX_free_size(SOCKET s)
{
uint16_t val=0, val1=0;
do {
val1 = ETH_readSnTX_FSR(s);
if (val1 != 0)
val = ETH_readSnTX_FSR(s);
}
while (val != val1);
return val;
}
uint16_t ETH_get_RX_received_size(SOCKET s)
{
uint16_t val=0,val1=0;
do {
val1 = ETH_readSnRX_RSR(s);
if (val1 != 0)
val = ETH_readSnRX_RSR(s);
}
while (val != val1);
return val;
}
void ETH_read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len)
{
uint16_t size;
uint16_t src_mask;
uint16_t src_ptr;
src_mask = src & ETH_RMASK;
src_ptr = ETH_RBASE[s] + src_mask;
if( (src_mask + len) > ETH_RSIZE )
{
size = ETH_RSIZE - src_mask;
ETH_read_n(src_ptr, (uint8_t *)dst, size);
dst += size;
ETH_read_n(ETH_RBASE[s], (uint8_t *) dst, len - size);
}
else
ETH_read_n(src_ptr, (uint8_t *) dst, len);
}
void ETH_send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
{
ETH_send_data_processing_offset(s, 0, data, len);
}
void ETH_send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
{
uint16_t ptr = ETH_readSnTX_WR(s);
ptr += data_offset;
uint16_t offset = ptr & ETH_SMASK;
uint16_t dstAddr = offset + ETH_SBASE[s];
if (offset + len > ETH_SSIZE)
{
uint16_t size = ETH_SSIZE - offset;
ETH_write_n(dstAddr, data, size);
ETH_write_n(ETH_SBASE[s], data + size, len - size);
}
else {
ETH_write_n(dstAddr, data, len);
}
ptr += len;
ETH_writeSnTX_WR(s, ptr);
}
void ETH_recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
{
uint16_t ptr;
ptr = ETH_readSnRX_RD(s);
ETH_read_data(s, ptr, data, len);
if (!peek)
{
ptr += len;
ETH_writeSnRX_RD(s, ptr);
}
}
void ETH_exec_socket_cmd(SOCKET s, uint8_t cmd)
{
ETH_writeSnCR(s, cmd);
while(ETH_readSnCR(s)) {
// Wait for command to be executed
}
}

302
Mieke/SW/ETH/w5100.h Normal file
View file

@ -0,0 +1,302 @@
/*
Ethernet shield test program
Copyright (C) 2018 Andreas Mieke
Copyright (C) 2010 Arduino LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __W5100_H
#define __W5100_H
#include "stm32f10x.h" // Device header
#include "stm32f10x_rcc.h" // Keil::Device:StdPeriph Drivers:RCC
#include "stm32f10x_gpio.h" // Keil::Device:StdPeriph Drivers:GPIO
#include "stm32f10x_spi.h" // Keil::Device:StdPeriph Drivers:SPI
#define MAX_SOCK_NUM 4
typedef uint8_t SOCKET;
enum {
ETH_MR_RST = 0x80,
ETH_MR_PB = 0x10,
ETH_MR_PPPoE = 0x08,
ETH_MR_AI = 0x02,
ETH_MR_IND = 0x01
};
enum {
ETH_IR_CONFLICT = 0x80,
ETH_IR_UNREACH = 0x40,
ETH_IR_PPPoE = 0x20,
ETH_IR_S3_INT = 0x08,
ETH_IR_S2_INT = 0x04,
ETH_IR_S1_INT = 0x02,
ETH_IR_S0_INT = 0x01
};
enum {
ETH_IMR_IR7 = 0x80,
ETH_IMR_IR6 = 0x40,
ETH_IMR_IR5 = 0x20,
ETH_IMR_IR3 = 0x08,
ETH_IMR_IR2 = 0x04,
ETH_IMR_IR1 = 0x02,
ETH_IMR_IR0 = 0x01
};
enum {
ETH_SMR_MULTI = 0x80,
ETH_SMR_ND = 0x20,
ETH_SMR_CLOSED = 0x00,
ETH_SMR_TCP = 0x01,
ETH_SMR_UDP = 0x02,
ETH_SMR_IPRAW = 0x03,
ETH_SMR_MACRAW = 0x04,
ETH_SMR_PPPoE = 0x05
};
enum {
ETH_SCR_OPEN = 0x01,
ETH_SCR_LISTEN = 0x02,
ETH_SCR_CONNECT = 0x04,
ETH_SCR_DISCON = 0x08,
ETH_SCR_CLOSE = 0x10,
ETH_SCR_SEND = 0x20,
ETH_SCR_SEND_MAC = 0x21,
ETH_SCR_SEND_KEEP = 0x22,
ETH_SCR_RECV = 0x40
};
enum {
ETH_SIR_SEND_OK = 0x10,
ETH_SIR_TIMEOUT = 0x08,
ETH_SIR_RECV = 0x04,
ETH_SIR_DISCON = 0x02,
ETH_SIR_CON = 0x01
};
enum {
ETH_SSR_CLOSED = 0x00,
ETH_SSR_INIT = 0x12, // Actually 13, Cortex doesn't seem to register the LSB
ETH_SSR_LISTEN = 0x14,
ETH_SSR_SYNSENT = 0x15,
ETH_SSR_SYNRECV = 0x16,
ETH_SSR_ESTABLISHED = 0x17,
ETH_SSR_FIN_WAIT = 0x18,
ETH_SSR_CLOSING = 0x1A,
ETH_SSR_TIME_WAIT = 0x1B,
ETH_SSR_CLOSE_WAIT = 0x1C,
ETH_SSR_LAST_ACK = 0x1D,
ETH_SSR_UDP = 0x22,
ETH_SSR_IPRAW = 0x32,
ETH_SSR_MACRAW = 0x42,
ETH_SSR_PPPoE = 0x5F
};
enum {
ETH_SPROTO_IP = 0,
ETH_SPROTO_ICMP = 1,
ETH_SPROTO_IGMP = 2,
ETH_SPROTO_GGP = 3,
ETH_SPROTO_TCP = 6,
ETH_SPROTO_PUP = 12,
ETH_SPROTO_UDP = 17,
ETH_SPROTO_IDP = 22,
ETH_SPROTO_ND = 77,
ETH_SPROTO_RAW = 255
};
void ETH_init(void);
void ETH_read_data(SOCKET s, volatile uint16_t src, volatile uint8_t * dst, uint16_t len);
void ETH_send_data_processing(SOCKET s, const uint8_t *data, uint16_t len);
void ETH_send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len);
void ETH_recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek);
inline void ETH_set_gateway_IP(uint8_t *addr);
inline void ETH_get_gateway_IP(uint8_t *addr);
inline void ETH_set_subnet_mask(uint8_t *addr);
inline void ETH_get_subnet_mask(uint8_t *addr);
inline void ETH_set_mac(uint8_t * addr);
inline void ETH_get_mac(uint8_t * addr);
inline void ETH_set_IP(uint8_t * addr);
inline void ETH_get_IP(uint8_t * addr);
inline void ETH_set_retransmission_time(uint16_t timeout);
inline void ETH_set_retransmission_count(uint8_t retry);
inline void ETH_exec_socket_cmd(SOCKET s, uint8_t cmd);
uint16_t ETH_get_TX_free_size(SOCKET s);
uint16_t ETH_get_RX_received_size(SOCKET s);
uint8_t ETH_write_8(uint16_t addr, uint8_t data);
uint16_t ETH_write_n(uint16_t addr, const uint8_t *buf, uint16_t len);
uint8_t ETH_read_8(uint16_t addr);
uint16_t ETH_read_n(uint16_t addr, uint8_t *buf, uint16_t len);
#define __GP_REGISTER8(name, address) \
static inline void ETH_write##name(uint8_t _data) { \
ETH_write_8(address, _data); \
} \
static inline uint8_t ETH_read##name() { \
return ETH_read_8(address); \
}
#define __GP_REGISTER16(name, address) \
static void ETH_write##name(uint16_t _data) { \
ETH_write_8(address, _data >> 8); \
ETH_write_8(address+1, _data & 0xFF); \
} \
static uint16_t ETH_read##name() { \
uint16_t res = ETH_read_8(address); \
res = (res << 8) + ETH_read_8(address + 1); \
return res; \
}
#define __GP_REGISTER_N(name, address, size) \
static uint16_t ETH_write##name(uint8_t *_buff) { \
return ETH_write_n(address, _buff, size); \
} \
static uint16_t ETH_read##name(uint8_t *_buff) { \
return ETH_read_n(address, _buff, size); \
}
__GP_REGISTER8 (MR, 0x0000); // Mode
__GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address
__GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address
__GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address
__GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address
__GP_REGISTER8 (IR, 0x0015); // Interrupt
__GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask
__GP_REGISTER16(RTR, 0x0017); // Timeout address
__GP_REGISTER8 (RCR, 0x0019); // Retry count
__GP_REGISTER8 (RMSR, 0x001A); // Receive memory size
__GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size
__GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode
__GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer
__GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number
__GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode
__GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode
#undef __GP_REGISTER8
#undef __GP_REGISTER16
#undef __GP_REGISTER_N
static inline uint8_t ETH_sock_read_8(SOCKET _s, uint16_t _addr);
static inline uint8_t ETH_sock_write_8(SOCKET _s, uint16_t _addr, uint8_t _data);
static inline uint16_t ETH_sock_read_n(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
static inline uint16_t ETH_sock_write_n(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
static const uint16_t ETH_CH_BASE = 0x0400;
static const uint16_t ETH_CH_SIZE = 0x0100;
#define __SOCKET_REGISTER8(name, address) \
static inline void ETH_write##name(SOCKET _s, uint8_t _data) { \
ETH_sock_write_8(_s, address, _data); \
} \
static inline uint8_t ETH_read##name(SOCKET _s) { \
return ETH_sock_read_8(_s, address); \
}
#define __SOCKET_REGISTER16(name, address) \
static void ETH_write##name(SOCKET _s, uint16_t _data) { \
ETH_sock_write_8(_s, address, _data >> 8); \
ETH_sock_write_8(_s, address+1, _data & 0xFF); \
} \
static uint16_t ETH_read##name(SOCKET _s) { \
uint16_t res = ETH_sock_read_8(_s, address); \
uint16_t res2 = ETH_sock_read_8(_s,address + 1); \
res = res << 8; \
res2 = res2 & 0xFF; \
res = res | res2; \
return res; \
}
#define __SOCKET_REGISTER_N(name, address, size) \
static uint16_t ETH_write##name(SOCKET _s, uint8_t *_buff) { \
return ETH_sock_write_n(_s, address, _buff, size); \
} \
static uint16_t ETH_read##name(SOCKET _s, uint8_t *_buff) { \
return ETH_sock_read_n(_s, address, _buff, size); \
}
__SOCKET_REGISTER8(SnMR, 0x0000) // Mode
__SOCKET_REGISTER8(SnCR, 0x0001) // Command
__SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt
__SOCKET_REGISTER8(SnSR, 0x0003) // Status
__SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port
__SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr
__SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr
__SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port
__SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size
__SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode
__SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS
__SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL
__SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size
__SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer
__SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer
__SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size
__SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer
__SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?)
#undef __SOCKET_REGISTER8
#undef __SOCKET_REGISTER16
#undef __SOCKET_REGISTER_N
static const int ETH_SOCKETS = 4;
static const uint16_t ETH_SMASK = 0x07FF; // Tx buffer MASK
static const uint16_t ETH_RMASK = 0x07FF; // Rx buffer MASK
static const uint16_t ETH_SSIZE = 2048; // Max Tx buffer size
static const uint16_t ETH_RSIZE = 2048; // Max Rx buffer size
extern uint16_t ETH_SBASE[ETH_SOCKETS]; // Tx buffer base address
extern uint16_t ETH_RBASE[ETH_SOCKETS]; // Rx buffer base address
uint8_t ETH_sock_read_8(SOCKET s, uint16_t addr)
{
return ETH_read_8(ETH_CH_BASE + s * ETH_CH_SIZE + addr);
}
uint8_t ETH_sock_write_8(SOCKET s, uint16_t addr, uint8_t data)
{
return ETH_write_8(ETH_CH_BASE + s * ETH_CH_SIZE + addr, data);
}
uint16_t ETH_sock_read_n(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len)
{
return ETH_read_n(ETH_CH_BASE + s * ETH_CH_SIZE + addr, buf, len);
}
uint16_t ETH_sock_write_n(SOCKET s, uint16_t addr, uint8_t *buf, uint16_t len)
{
return ETH_write_n(ETH_CH_BASE + s * ETH_CH_SIZE + addr, buf, len);
}
void ETH_set_gateway_IP(uint8_t *addr) { ETH_writeGAR(addr); }
void ETH_get_gateway_IP(uint8_t *addr) { ETH_readGAR(addr); }
void ETH_set_subnet_mask(uint8_t *addr) { ETH_writeSUBR(addr); }
void ETH_get_subnet_mask(uint8_t *addr) { ETH_readSUBR(addr); }
void ETH_set_mac(uint8_t * addr) { ETH_writeSHAR(addr); }
void ETH_get_mac(uint8_t * addr) { ETH_readSHAR(addr); }
void ETH_set_IP(uint8_t * addr) { ETH_writeSIPR(addr); }
void ETH_get_IP(uint8_t * addr) { ETH_readSIPR(addr); }
void ETH_set_retransmission_time(uint16_t timeout) { ETH_writeRTR(timeout); }
void ETH_set_retransmission_count(uint8_t retry) { ETH_writeRCR(retry); }
#endif

View file

@ -84,3 +84,28 @@ Der Piezo Test gibt einen ton auf eben diesem aus.
\subsubsection{display.c} \subsubsection{display.c}
Um das Display zu testen, wird mehrmals der Screen gelöscht und in einer anderen Farbe gezeichnet. Dieser Befehl sollte auch ohne extra Test-Programm, unabhänging von dem zur Zeit geflashten Programm, auf dem Display funktionieren. Um das Display zu testen, wird mehrmals der Screen gelöscht und in einer anderen Farbe gezeichnet. Dieser Befehl sollte auch ohne extra Test-Programm, unabhänging von dem zur Zeit geflashten Programm, auf dem Display funktionieren.
\lstinputlisting[language={[ANSI]C}, caption=Tests: Display Implementation, label=lst:sw-mt-displayc]{Mieke/SW/MT/display.c} \lstinputlisting[language={[ANSI]C}, caption=Tests: Display Implementation, label=lst:sw-mt-displayc]{Mieke/SW/MT/display.c}
\subsection{Ethernet}
Ein Ziel dieser Diplomarbeit war es eine Library für das Arduino Ethernet Shield (Version 1.0) zu entwickeln, dies ist bis dato nicht 100\%ig gelungen, da die SPI Peripherie des \gls{cpu} Probleme bereitet und in manchen Situationen das \gls{LSb} ignoriert. Zum Beispiel, wenn der Ethernet Controller den Status \texttt{0x13} sendet, beinhaltet das Datenregister nur \texttt{0x12}, das \gls{LSb} ist also immer \texttt{0}. Das derzeitige Hauptaugenmerk liegt beim \gls{Debugging} dieses Fehlers. Eine mögliche Lösung wäre das SPI Interface selbst zu implementieren, und nicht die vorhandene Peripherieeinheit zu verwenden. Der nun folgende Programmcode ist deshalb keine Library, sondern ein eigenständiges Test-Programm, welches noch nicht 100\% funktioniert.
\subsubsection{main.c}
Das Hauptpgrogramm initsialisiert das Ethernet Modul und setzt die entsprechenden IP- und MAC-Adressen, danach wird ein TCP Server auf Port 80 gestartet, und übermittelte Pakete über UART ausgegeben.
\lstinputlisting[language={[ANSI]C}, caption=Ethernet: Hauptpgrogramm, label=lst:sw-eth-mainc]{Mieke/SW/ETH/main.c}
\subsubsection{socket.c}
In \texttt{socket.c} wird eine Socket API, welche der POSIX Socket API ähnlich ist, zur Verfügung gestellt. Das Headerfile \texttt{socket.h} enthält hierbei nur die Funktionsdeklarationen. Anders als bei der POSIX Socket API, muss hier jeder Socket manuell eine ID \textbf{vor} dem Erstellen erhalten. Diese ID muss zwischen 1 und 4 liegen, und repräsentiert die 4 Sockets (Register und Speicher), welche am Ethernet-Controller vorhanden sind.
Der Code wurde größtenteils von der entsprechenden Arduino Library \cite{arduino:ethernet} übernommen und auf C adaptiert.
\lstinputlisting[language={[ANSI]C}, caption=Ethernet: Socket API, label=lst:sw-eth-socketc]{Mieke/SW/ETH/socket.c}
\subsubsection{w5100.h}
Der Ethernet Controller selbst ist ein W5100 \cite{arduino:ethernetchip}. Dieses Headerfile enthält sämtliche Funktionsdeklarationen für diesen Controller, aber auch structs und enums welche die verschiedenen Register und Memory Bereiche spezifizieren.
Der Code wurde größtenteils von der entsprechenden Arduino Library \cite{arduino:ethernet} übernommen und auf C adaptiert.
\lstinputlisting[language={[ANSI]C}, caption=Ethernet: W5100 Header, label=lst:sw-eth-w5100h]{Mieke/SW/ETH/w5100.h}
\subsubsection{w5100.c}
Der Ethernet Controller selbst ist ein W5100 \cite{arduino:ethernetchip}. Diese Implementation enthält sämtliche Funktionen für diesen Controller.
Der Code wurde größtenteils von der entsprechenden Arduino Library \cite{arduino:ethernet} übernommen und auf C adaptiert.
\lstinputlisting[language={[ANSI]C}, caption=Ethernet: W5100 Implementation, label=lst:sw-eth-w5100c]{Mieke/SW/ETH/w5100.c}

View file

@ -358,3 +358,25 @@
url = "https://www.onsemi.com/pub/Collateral/NCP5623-D.PDF", url = "https://www.onsemi.com/pub/Collateral/NCP5623-D.PDF",
urldate = "2018-03-18" urldate = "2018-03-18"
} }
@misc{ arduino:ethernet,
author = {Tinitigan, Dino},
title = {Arduino Ethernet Library},
year = {2016},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/arduino/Arduino/tree/master/libraries/Ethernet/src/utility},
commit = {0873b36aa53590e2ace81a3b0535ead7c668bcbb},
urldate = "2018-04-03"
}
@manual{ arduino:ethernetchip,
organization = "{WIZnet Co., Inc.}",
title = "W5100 Datasheet",
number = "W5100",
year = "2008",
month = "1",
note = "Version 1.1.6",
url = "https://www.sparkfun.com/datasheets/DevTools/Arduino/W5100_Datasheet_v1_1_6.pdf",
urldate = "2018-04-03"
}