• Re: Using the Arduino Ethernet shield with AMICUS18 (Part3)

    Hi,
    In todays post I'll try to cover the basic input and output routines I use to communicate with the W5100.

    The W5100 can communicate with the main controller either over a parallel data bus featuring 14 adress lines, 8 data lines and a couple of control lines or it can use a serial interface, SPI. On the Ethernet shield the W5100 is setup to use the SPI interface which is fortunate because we simply don't have enough I/O lines on the AMICUS18.

    Every transaction to and from the W5100, when using SPI, requires 4 bytes. First an OP code telling the W5100 if we're doing a read or a write operation, then two bytes containing the adress we are writing or reading and finally the actual data. When writing to the W5100 WE put the data in the forth byte, when reading from the W5100 IT puts the data in the forth byte - basically. So for each transaction we pull the Chip Select line of the W5100, send 4 bytes and release the Chip Select line (pull high). Here's the code for my read and write subroutines:

    Code:
    WizAdress           VAR WORD       ' Adress in the W5100 to be read or written
    WizData             VAR BYTE       ' Data to be written or data read from the W5100
    WizResponse         VAR BYTE[4]    ' Respose to the four bytes in each SPI transaction. Should be 0,1,2,3 or 0,1,2,data
     
    W5100_Select        VAR PortB.5    ' Chip select line of W5100 connected to RB.5
    W5100_Select = 1
     
    '******************************************************************************************
    Read_W5100:
        WizResponse[0] = SSPBUF         ' Dummy read 
     
        W5100_Select = 0                ' Select W5100
     
        SSPBUF = W5100_READ_OP          ' Send OP code for read operation
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[0] = SSPBUF         ' Store result, should be 0
     
        SSPBUF = WizAdress.HighByte     ' Send high byte of adress
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[1] = SSPBUF         ' Store result, should be 1
        SSPBUF = WizAdress.LowByte      ' Send low byte of adress
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[2] = SSPBUF         ' Store result, should be 2
     
        SSPBUF = 0                      ' Send data
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[3] = SSPBUF         ' Store result, will be the actual data read at the specified adress
     
        WizData = WizResponse[3]        ' Copy databyte from array to WizData.
        W5100_Select = 1                ' Deselect the W5100
    RETURN
    '******************************************************************************************
     
    '******************************************************************************************
    Write_W5100:
        WizResponse[0] = SSPBUF         ' Dummy read.
     
        W5100_Select = 0                ' Pull chip select line low to select W5100
     
        SSPBUF = W5100_WRITE_OP         ' Send OP code for write operation
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[0] = SSPBUF         ' Store result, should be 0
     
        SSPBUF = WizAdress.HighByte     ' Send high byte of adress
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[1] = SSPBUF         ' Store result, should be 1
     
        SSPBUF = WizAdress.LowByte      ' Send low byte of adress
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[2] = SSPBUF         ' Store result, should be 2
     
        SSPBUF = WizData                ' Send the data byte
        While SSPSTAT.0 = 0 : WEND      ' Wait for operation to complete
        WizResponse[3] = SSPBUF         ' Store the result, should be 3
     
        W5100_Select = 1                ' Deselect the W5100
     
    RETURN
    '******************************************************************************************
    I've declared two variables of specific interest here, WizAdress and WizData. WizAdress is the adress in the W5100 we want to access and WizData is, in the case of a write operation, the data we want to write to that adress OR, in the case of a read operation, the data read FROM that adress. In the W5100_defs.pbp file attached to an earlier post the OP-codes for read and write operation as well as the names and adresses of all the registers are defined. Looking at the datasheet for the W5100 we can see that setting bit 7 of the Mode register will perform a reset of the device after which bit 7 is automatically cleared again. Doing this with help from the above subroutines is as simple as:
    Code:
    WizAdress = W5100_Mode : WizData = %10000000 : GOSUB Write_W5100
    In a similar manner we can read, for example, the interrupt register at location $0015 and output its content over the USART like this:
    Code:
    WizAdress = W5100_IR : GOSUB Read_W5100
    HSEROUT ["The status of the Interrupt register is: ", BIN8 WizData, 13]
    As ilustrated here, when writing TO the W5100 WE put the data in the WizData variable and when reading FROM the W5100 we GET the data in the WizData variable.


    To get the Ethernet shield to respond to a Ping all we need to do is set its MAC-adress, IP-adress and NetMask. Doing that is just a series of write operations:

    Code:
    SetUp:
        HSEROUT["W5100_Init",13]
     
        'Send Reset command to W5100.
        WizAdress = W5100_Mode  : WizData = 128 : Gosub Write_W5100
     
        ' Set MAC-adress, see sticker on the back of the Ethernet shield. 
        WizAdress = W5100_SHAR0 : WizData = $05 : GOSUB Write_W5100
        WizAdress = W5100_SHAR1 : WizData = $06 : GOSUB Write_W5100
        WizAdress = W5100_SHAR2 : WizData = $07 : GOSUB Write_W5100
        WizAdress = W5100_SHAR3 : WizData = $08 : GOSUB Write_W5100
        WizAdress = W5100_SHAR4 : WizData = $09 : GOSUB Write_W5100
        WizAdress = W5100_SHAR5 : WizData = $0A : GOSUB Write_W5100
     
        'Set IP adress of W5100    
        WizAdress = W5100_SIPR0 : WizData = 192 : GOSUB Write_W5100
        WizAdress = W5100_SIPR1 : WizData = 168 : GOSUB Write_W5100
        WizAdress = W5100_SIPR2 : WizData = 1   : GOSUB Write_W5100
        WizAdress = W5100_SIPR3 : WizData = 50  : GOSUB Write_W5100
        'Set net-mask
        WizAdress = W5100_SUBR0 : WizData = 255 : GOSUB Write_W5100
        WizAdress = W5100_SUBR1 : WizData = 255 : GOSUB Write_W5100    
        WizAdress = W5100_SUBR2 : WizData = 255 : GOSUB Write_W5100
        WizAdress = W5100_SUBR3 : WizData = 0   : GOSUB Write_W5100
        HSEROUT ["Basic setup done",13]
     
    Main:
    @ NOP
    GOTO MAIN

    (Sorry about the Swedish screenshot but you'll get the idea...it works...)

    Without the HSEROUT statements we're looking at a just above 400 bytes (out of the 18F25K20's 16k) worth of program memory. Granted, only being able to respond to a ping isn't really worth much from a practical standpoint but it IS a start.


    Finally a word or two about the WizResponse array. When using SPI, data is shifted in and out of the PIC at the same time. Basically as one bit goes out at the "low end" of the MSSP modules shift register one bit goes at the "high end" so after 8 clock cycles the byte we loaded into SSPBUF have been exchanged with a byte from the W5100.

    When writing data to the W5100 it responds with 0, 1, 2, 3 for the four bytes it receives and I'm storing this response in the array WizResponse in order to potentionally use it to verify that the operation was successfull. When reading from the W5100 it responds with 0, 1, 2 and then the actual data in the 4th byte so all I'm doing is copying the data from the 4th byte of the array to the WizData variable before returning from the subroutine.

    /Henrik.
    This article was originally published in forum thread: Using the Arduino Ethernet shield with AMICUS18 (Joint forum project?) started by HenrikOlsson View original post