Mega2560 to EthernetShield SPI in avr-c

Hello!

I tried programming the Arduino board directly in C (without arduino libraries) and now got stuck
on trying to initialize the Ethernet Shield with SPI.
After digging the W5100 datasheet, I came to this nice article Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller | ermicroblog
and there is an example wiznetping.c which is exactly what I need, however it does not work with
my devices and I can't figure out correct pins and procedure to init SPI.

The code in example is not for mega256 and it uses PORTB pins as SPI, the reference here
SPI - Arduino Reference says that "On the Arduino Mega, this is 50 (MISO), 51 (MOSI), 52 (SCK), and 53 (SS)."
but these pins aren't even connected to the shield.

Ethernet examples from IDE fork fine, and I tried to unroll the included series of Ethernet.h w5100.h SPI.h and the file
mega/pins_arduino.h also defines them this way

static const uint8_t SS   = 53;
static const uint8_t MOSI = 51;
static const uint8_t MISO = 50;
static const uint8_t SCK  = 52;

Can anyone help me to initialize the EthernetShield from Mega2560, or point me if I am conceptually wrong.
Thank you!

The latest Ethernet shields pick up the SPI signals from the ICSP pins on the host board, though I believe earlier versions did not and therefore were not "mega compatible". There doesn't seem to be any mention of this on the ethernet shield page at Ethernet - Arduino Reference, in fact it shows the SPI signals are on pins 50-53 (which they are) but doesn't say they aren't used from there. This does mean you can't stack and ethernet shield on top of a shield that doesn't pass through the ICSP pins (like the mega proto board for example :0 Bit of a design oversight there I think :astonished: ).

You should be able to pull out the w5100 initialisation code from the arduino ethernet library. I was looking at it last evening, and once you get past the clever macro code that defines all the register access functions it seems quite straight forward.

HTH, PeterO

I have finally managed to bring it to a pingable state!
So in case someone else wants to try this at home...
I took SPI read/write functions from the Integrating Wiznet W5100, WIZ811MJ network module with Atmel AVR Microcontroller | ermicroblog mentioned above,
and the init part is what I gather from the library files.
The way I compiled upload this is :

avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega2560 -c -o $1.o $1.c
avr-gcc -mmcu=atmega2560 $1.o -o $1
avr-objcopy -O ihex -R .eeprom $1 $1.hex
avrdude -F -V -c arduino -p m2560 -c avrispmkII  -P /dev/ttyACM0  -U flash:w:$1.hex
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>


#define SPI_PORT PORTB
#define SPI_DDR  DDRB
#define SPI_CS   PORTB4

#define MAX_SOCK_NUM 4
#define TXBUF_BASE 0x4000
#define RXBUF_BASE 0x6000


// Wiznet W5100 Op Code

#define WIZNET_WRITE_OPCODE 0xF0
#define WIZNET_READ_OPCODE 0x0F

// Wiznet W5100 Register Addresses
#define MR   0x0000   // Mode Register
#define GAR  0x0001   // Gateway Address: 0x0001 to 0x0004
#define SUBR 0x0005   // Subnet mask Address: 0x0005 to 0x0008
#define SAR  0x0009   // Source Hardware Address (MAC): 0x0009 to 0x000E
#define SIPR 0x000F   // Source IP Address: 0x000F to 0x0012
#define RMSR 0x001A   // RX Memory Size Register
#define TMSR 0x001B   // TX Memory Size Register

void SPI_Write(unsigned int addr,unsigned char data)
{
  // Activate the CS pin
  SPI_PORT &= ~(1<<SPI_CS);

  // Start Wiznet W5100 Write OpCode transmission
  SPDR = WIZNET_WRITE_OPCODE;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));

  // Start Wiznet W5100 Address High Bytes transmission
  SPDR = (addr & 0xFF00) >> 8;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));

  // Start Wiznet W5100 Address Low Bytes transmission
  SPDR = addr & 0x00FF;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));   

  // Start Data transmission
  SPDR = data;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));

  // CS pin is not active
  SPI_PORT |= (1<<SPI_CS);
}

unsigned char SPI_Read(unsigned int addr)
{
  // Activate the CS pin
  SPI_PORT &= ~(1<<SPI_CS);

  // Start Wiznet W5100 Read OpCode transmission
  SPDR = WIZNET_READ_OPCODE;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));

  // Start Wiznet W5100 Address High Bytes transmission
  SPDR = (addr & 0xFF00) >> 8;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));

  // Start Wiznet W5100 Address Low Bytes transmission
  SPDR = addr & 0x00FF;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));   

  // Send Dummy transmission for reading the data
  SPDR = 0x00;

  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)));  

  // CS pin is not active
  SPI_PORT |= (1<<SPI_CS);

  return(SPDR);
}

 unsigned char mac_addr[] = {0x00,0x16,0x36,0xDE,0x58,0xF7};
 unsigned char ip_addr[] = {192,168,88,10};
 unsigned char sub_mask[] = {255,255,255,0};
 unsigned char gtw_addr[] = {192,168,88,1};

int main(){


  SPI_DDR = (1<<PORTB2)|(1<<PORTB1)|(1<<PORTB0);

  // CS pin is not active
  SPI_PORT |= (1<<SPI_CS);

  // Enable SPI, Master Mode 0, set the clock rate fck/2
  SPCR = (1<<SPE)|(1<<MSTR);
  SPSR |= (1<<SPI2X);

  
  
  DDRB  |=  _BV(4);
  SPI_Write(MR,0b10000000);  
  SPI_Write(TMSR,0x55);
  SPI_Write(RMSR,0x55);
  
  static const uint16_t SSIZE = 2048; // Max Tx buffer size
  static const uint16_t RSIZE = 2048; // Max Rx buffer size
  
  uint16_t SBASE[4]; // Tx buffer base address
  uint16_t RBASE[4];
  
    SBASE[0] = TXBUF_BASE + SSIZE * 0;
    RBASE[0] = RXBUF_BASE + RSIZE * 0;
    
    SBASE[1] = TXBUF_BASE + SSIZE * 1;
    RBASE[1] = RXBUF_BASE + RSIZE * 1;

    SBASE[2] = TXBUF_BASE + SSIZE * 2;
    RBASE[2] = RXBUF_BASE + RSIZE * 2;

    SBASE[3] = TXBUF_BASE + SSIZE * 3;
    RBASE[3] = RXBUF_BASE + RSIZE * 3;

  SPI_Write(SIPR + 0,ip_addr[0]);
  SPI_Write(SIPR + 1,ip_addr[1]);
  SPI_Write(SIPR + 2,ip_addr[2]);
  SPI_Write(SIPR + 3,ip_addr[3]);
  
  SPI_Write(SUBR + 0,sub_mask[0]);
  SPI_Write(SUBR + 1,sub_mask[1]);
  SPI_Write(SUBR + 2,sub_mask[2]);
  SPI_Write(SUBR + 3,sub_mask[3]);
  
  SPI_Write(SAR + 0,mac_addr[0]);
  SPI_Write(SAR + 1,mac_addr[1]);
  SPI_Write(SAR + 2,mac_addr[2]);
  SPI_Write(SAR + 3,mac_addr[3]);
  SPI_Write(SAR + 4,mac_addr[4]);
  SPI_Write(SAR + 5,mac_addr[5]);
  
  SPI_Write(GAR + 0,gtw_addr[0]);
  SPI_Write(GAR + 1,gtw_addr[1]);
  SPI_Write(GAR + 2,gtw_addr[2]);
  SPI_Write(GAR + 3,gtw_addr[3]);




return 0;
}