Subversion Repositories Code-Repo

Rev

Rev 254 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
253 Kevin 1
#include "defines.h"
2
#include "ETHERNET.h"
3
 
4
static ETH_DATA *eth_data;
5
 
6
/* Function to convert from virtual address to physical address
7
    See 3.4.1 in reference manual for explanation */
8
uint32_t VA_TO_PA(uint32_t ptr) {
9
    uint32_t ret = ptr & 0x1FFFFFFF;
10
    return ret;
11
}
12
 
13
void ETH_Init(ETH_DATA *data, void(*tx_callback)(void), void(*rx_callback)(void)) {
14
    // Save a pointer to the descriptor tables
15
    eth_data = data;
16
    eth_data->tx_callback = tx_callback;
17
    eth_data->rx_callback = rx_callback;
18
 
19
    // Bring the PHY reset line high to initialize the PHY
20
    PHY_RESET_TRIS = 0;
21
    PHY_RESET_LAT = 0;
22
    Delay_US(100);
23
    PHY_RESET_LAT = 1;
24
 
25
    INTDisableInterrupts();
26
 
27
    // Initialize the I/O lines (dont actually need this)
28
    ETH_MDC_TRIS = 0;
29
    ETH_MDIO_TRIS = 1;
30
    ETH_TXEN_TRIS = 0;
31
    ETH_TXD0_TRIS = 0;
32
    ETH_TXD1_TRIS = 0;
33
    ETH_RXCLK_TRIS = 1;
34
    ETH_RXDV_TRIS = 1;
35
    ETH_RXD0_TRIS = 1;
36
    ETH_RXD1_TRIS = 1;
37
    ETH_RXERR_TRIS = 1;
38
 
39
    eth_data->TX_descriptor_index = 0;
40
    eth_data->RX_descriptor_index = 0;
41
 
42
    // Initialize values in the descriptor tables
43
    uint8_t i;
44
    for (i = 0; i < ETH_TX_DESCRIPTOR_COUNT; i++) {
45
        // Set the NPV values for each descriptor (linear list)
46
        eth_data->TX_ED_table.descriptor[i].NPV = 0;
47
 
48
        // Set the EOWN values for each descriptor
49
        eth_data->TX_ED_table.descriptor[i].EOWN = 0;
50
 
51
        // Assign a data buffer to each descriptor
52
        eth_data->TX_ED_table.descriptor[i].BUFFER_ADDR = VA_TO_PA((uint32_t)eth_data->TX_ED_buffer[i]);
53
    }
54
    for (i = 0; i < ETH_RX_DESCRIPTOR_COUNT; i++) {
55
        // Set the NPV values for each descriptor (linear list)
56
        eth_data->RX_ED_table.descriptor[i].NPV = 0;
57
 
58
        // Set the EOWN values for each descriptor
59
        eth_data->RX_ED_table.descriptor[i].EOWN = 1;
60
 
61
        // Assign a data buffer to each descriptor
62
        eth_data->RX_ED_table.descriptor[i].BUFFER_ADDR = VA_TO_PA((uint32_t)eth_data->RX_ED_buffer[i]);
63
    }
64
 
65
    // On the last descriptor, save the address to the beginning of the list
66
    eth_data->TX_ED_table.descriptor[ETH_TX_DESCRIPTOR_COUNT-1].NPV = 1;
67
    eth_data->RX_ED_table.descriptor[ETH_RX_DESCRIPTOR_COUNT-1].NPV = 1;
68
 
69
    // Set the last RX descriptor EOWN to software, thus using list configuration
70
//    eth_data->TX_ED_table.descriptor[ETH_TX_DESCRIPTOR_COUNT-1].EOWN = 0;
71
//    eth_data->RX_ED_table.descriptor[ETH_RX_DESCRIPTOR_COUNT-1].EOWN = 0;
72
 
73
    // Loop the end of the descriptor table to the beginning (ring configuration)
74
    eth_data->TX_ED_table.next_ED = VA_TO_PA((uint32_t)eth_data->TX_ED_table.descriptor);
75
    eth_data->RX_ED_table.next_ED = VA_TO_PA((uint32_t)eth_data->RX_ED_table.descriptor);
76
 
77
    // Save the head of the table to the corresponding ETH register
78
    ETHTXST = VA_TO_PA((uint32_t)eth_data->TX_ED_table.descriptor);
79
    ETHRXST = VA_TO_PA((uint32_t)eth_data->RX_ED_table.descriptor);
80
 
81
 
82
    // Ethernet Initialization Sequence: see section 35.4.10 in the PIC32 Family Reference Manual
83
 
84
    // Part 1. Ethernet Controller Initialization
85
    IEC1bits.ETHIE = 0;     // Disable ethernet interrupts
86
    ETHCON1bits.ON = 0;     // Disable the ethernet module
87
    ETHCON1bits.TXRTS = 0;  // Stop transmit logic
88
    ETHCON1bits.RXEN = 0;   // Stop receive logic
89
    ETHCON1bits.AUTOFC = 0;
90
    ETHCON1bits.MANFC = 0;
91
    while (ETHSTATbits.ETHBUSY);
92
    IFS1bits.ETHIF = 0;     // Clear interrupt flags
93
    ETHIENCLR = 0xFFFF;     // Clear the ETHIEN register (interrupt enable)
94
 
95
    // Part 2. MAC Init
96
    EMAC1CFG1bits.SOFTRESET = 1;    // Put the MACMII in reset
97
    EMAC1CFG1bits.SOFTRESET = 0;
98
        // Default I/O configuration, RMII operating mode
99
    EMAC1SUPPbits.RESETRMII = 1;    // Reset the MAC RMII module
100
    EMAC1MCFGbits.RESETMGMT = 1;    // Reset the MII management module
101
    EMAC1MCFGbits.RESETMGMT = 0;    
102
    EMAC1MCFGbits.CLKSEL = 0x8;     // Set the MIIM PHY clock to SYSCLK/40
103
    while(EMAC1MINDbits.MIIMBUSY);
104
 
105
    // Part 3. PHY Init
106
        // Contrary to the ref manual, the ETH module needs to be enabled for the MIIM to work
107
 
108
    ETHCON1bits.ON = 1;     // Enable the ethernet module
109
 
110
    uint16_t value;
111
    // Reset the PHY chip
112
    ETH_PHY_Write(PHY_ADDRESS, 0x0, 0x8000);
113
    do {
114
        value = ETH_PHY_Read(PHY_ADDRESS, 0x0);
115
    } while (value & 0x8000 != 0);
116
 
117
    // Delay to wait for the link to be established
118
    Delay_MS(5000);
119
 
120
    // Wait for auto-negotiation to finish
121
    do {
122
        value = ETH_PHY_Read(PHY_ADDRESS, 0x1F); // Acquire link status
123
    } while (value & 0x1000 == 0);
124
 
125
    ETHCON1bits.ON = 0;     // Disable the ethernet module before changing other settings
126
 
127
    // Part 4. MAC Configuration
128
    EMAC1CFG1bits.RXENABLE = 1;     // Enable the MAC receiving of frames
129
    EMAC1CFG1bits.TXPAUSE = 1;      // Enable PAUSE flow control frames
130
    EMAC1CFG1bits.RXPAUSE = 1;      // Enable processing of PAUSE control frames
131
    EMAC1CFG2bits.AUTOPAD = 0;      // No auto-detection for VLAN padding
132
    EMAC1CFG2bits.VLANPAD = 0;      // MAC does not perform padding of short frames
133
    EMAC1CFG2bits.PADENABLE = 1;    // Pad all short frames
134
    EMAC1CFG2bits.CRCENABLE = 1;    // Append a CRC to every frame
135
    EMAC1CFG2bits.HUGEFRM = 1;      // Allow frames of any length
136
    EMAC1CFG2bits.LENGTHCK = 0;     // Check the frame lengths to the length/type field
137
    if ((value & 0x14) || (value & 0x18)) {
138
        EMAC1CFG2bits.FULLDPLX = 1; // Operate in full-duplex mode
139
        EMAC1IPGT = 0x15;           // Back-to-back interpacket gap @ 0.96us/9.6us
140
//        LED1_LAT = 1;
141
    } else {
142
        EMAC1CFG2bits.FULLDPLX = 0; // Operate in half-duplex mode
143
        EMAC1IPGT = 0x12;           // Back-to-back interpacket gap @ 0.96us/9.6us
144
//        LED2_LAT = 1;
145
    }
146
    if ((value & 0x08) || (value & 0x18)) {
147
        EMAC1SUPPbits.SPEEDRMII = 1;    // 100Mbps mode
148
//        LED3_LAT = 1;
149
    } else {
150
        EMAC1SUPPbits.SPEEDRMII = 0;    // 10Mbps mode
151
//        LED4_LAT = 1;
152
    }
153
    EMAC1IPGRbits.NB2BIPKTGP1 = 0xC;    // Set some other delay gap values
154
    EMAC1IPGRbits.NB2BIPKTGP2 = 0x12;
155
    EMAC1CLRTbits.CWINDOW = 0x37;       // Set collision window to count of frame bytes
156
    EMAC1CLRTbits.RETX = 0xF;           // Set number of retransmission attempts
157
    EMAC1MAXF = 0x7F4;                  // Set the maximum frame length to 2046 bits
158
    // Default MAC address is 00-04-A3-1A-4C-FC
159
    // Set MAC address to 00-18-3E-00-D7-EB
160
    EMAC1SA0 = 0xEBD7;
161
    EMAC1SA1 = 0x003E;
162
    EMAC1SA2 = 0x1800;
163
 
164
    // Part 5. Ethernet Controller Initialization cont.
165
        // Flow control is off by default!
166
    ETHRXFCbits.HTEN = 0;       // Disable hash table filtering
167
    ETHRXFCbits.MPEN = 0;       // Disable magic packet filtering
168
    ETHRXFCbits.PMMODE = 0;     // Disable pattern matching
169
    ETHRXFCbits.CRCERREN = 0;   // Disable CRC error collection filtering
170
    ETHRXFCbits.CRCOKEN = 0;    // Disable CRC filtering
171
    ETHRXFCbits.RUNTERREN = 0;  // Disable runt error collection filtering
172
    ETHRXFCbits.RUNTEN = 0;     // Disable runt filtering
173
    ETHRXFCbits.UCEN = 1;       // Enable unicast filtering
174
    ETHRXFCbits.NOTMEEN = 0;    // Disable acceptance of packets to other destinations
175
    ETHRXFCbits.MCEN = 0;       // Disable multicast filtering
176
    ETHRXFCbits.BCEN = 0;       // Disable broadcast filtering
177
 
178
    ETHCON2bits.RXBUF_SZ = 0x7F;    // Set RX data buffer size to 2032 bytes
179
 
180
    EMAC1SUPPbits.RESETRMII = 0;    // Bring the RMII module out of reset
181
    ETHCON1bits.ON = 1;             // Enable the ethernet module
182
 
183
    ETHCON1bits.RXEN = 1;       // Start receive logic
184
 
185
    ETHIENbits.TXBUSEIE = 1;    // Enable interrupt on transmit BVCI bus error
186
    ETHIENbits.RXBUSEIE = 1;    // Enable interrupt on receive BVCI bus error
187
//    ETHIENbits.RXDONEIE = 1;    // Enable interrupt on packet received
188
    ETHIENbits.PKTPENDIE = 1;   // Enable interrupt on packet pending
189
//    ETHIENbits.RXACTIE = 1;
190
    ETHIENbits.TXDONEIE = 1;    // Enable interrupt on packet sent
191
    ETHIENbits.TXABORTIE = 1;   // Enable interrupt on packet send aborted
192
 
193
    IPC12bits.ETHIP = 1;        // Set interrupt priority to 1
194
    IPC12bits.ETHIS = 1;        // Set intererupt sub-priority to 1
195
    IEC1bits.ETHIE = 1;         // Enable ethernet interrupts
196
 
197
    INTEnableInterrupts();
198
}
199
 
254 Kevin 200
/* Reads from the specified register on the PHY chip */
253 Kevin 201
uint16_t ETH_PHY_Read(uint8_t address, uint8_t reg) {
202
    EMAC1MADR = reg | (address << 8);
203
    EMAC1MCMDbits.READ = 1;
204
    Nop();Nop();Nop();
205
    while (EMAC1MINDbits.MIIMBUSY);
206
    EMAC1MCMDbits.READ = 0;
207
    return EMAC1MRDD;
208
}
209
 
254 Kevin 210
/* Write to the specified register on the PHY chip */
253 Kevin 211
void ETH_PHY_Write(uint8_t address, uint8_t reg, uint16_t value) {
212
    EMAC1MADR = reg | (address << 8);
213
    EMAC1MWTD = value;
214
    Nop();Nop();Nop();
215
    while (EMAC1MINDbits.MIIMBUSY);
216
}
217
 
254 Kevin 218
/* Queries the number of pending packets */
253 Kevin 219
uint8_t ETH_Recv_Queue(void) {
220
    return ETHSTATbits.BUFCNT;
221
}
222
 
223
/* Function to read a single packet (<2014 bytes) */
224
uint8_t ETH_Read_Packet(uint8_t *buffer, uint16_t *length) {
225
    uint16_t i, j;
226
    uint16_t size;
227
    uint8_t descriptor_index = eth_data->RX_descriptor_index;
228
 
229
    // Look for the first descriptor where EOWN is cleared and SOP/EOP is set
230
    for (i = 0; i < ETH_RX_DESCRIPTOR_COUNT; i++) {
231
        if ((eth_data->RX_ED_table.descriptor[descriptor_index].EOWN == 0) &&
232
                (eth_data->RX_ED_table.descriptor[descriptor_index].SOP == 1) &&
233
                (eth_data->RX_ED_table.descriptor[descriptor_index].EOP == 1)) {
234
 
254 Kevin 235
            // Read the packet data values into the buffer
253 Kevin 236
            size = eth_data->RX_ED_table.descriptor[descriptor_index].BYTE_COUNT - 18;
237
            *length = size;
238
            for (j = 0; j < size - 18; j++) {
239
                buffer[j] = eth_data->RX_ED_buffer[descriptor_index][j+14];
240
            }
254 Kevin 241
 
242
            // Reset the descriptors
253 Kevin 243
            eth_data->RX_ED_table.descriptor[descriptor_index].SOP = 0;
244
            eth_data->RX_ED_table.descriptor[descriptor_index].EOP = 0;
245
            eth_data->RX_ED_table.descriptor[descriptor_index].EOWN = 1;
246
 
247
            eth_data->RX_descriptor_index = (descriptor_index == ETH_RX_DESCRIPTOR_COUNT - 1) ? 0 : descriptor_index + 1;
248
 
249
            ETHCON1bits.BUFCDEC = 1;
250
 
251
            return 0;
252
 
253
        } else {
254
            descriptor_index = (descriptor_index == ETH_RX_DESCRIPTOR_COUNT - 1) ? 0 : descriptor_index + 1;
255
        }
256
    }
257
 
258
    return 1;
259
}
260
 
261
/* Function to send a single packet (<2018 bytes) */
262
uint8_t ETH_Write_Packet(ETH_MAC_ADDRESS dest, ETH_MAC_ADDRESS src, uint16_t length, uint8_t *buffer) {
263
    uint16_t i;
264
    uint16_t write_index = 0;
265
    uint16_t read_index = 0;
266
    uint16_t descriptor_index = eth_data->TX_descriptor_index;
267
 
268
    // Do a quick sanity check to ensure that we have enough memory to send the message
269
    if (length > ETH_TX_ED_BUFFER_SIZE - 14)
270
        return 1;
271
 
272
    // Fill the descriptor
273
    eth_data->TX_ED_table.descriptor[descriptor_index].TSV.registers[0] = 0;
274
    eth_data->TX_ED_table.descriptor[descriptor_index].TSV.registers[1] = 0;
275
    eth_data->TX_ED_table.descriptor[descriptor_index].EOWN = 1;
276
    eth_data->TX_ED_table.descriptor[descriptor_index].SOP = 1;
277
    eth_data->TX_ED_table.descriptor[descriptor_index].EOP = 1;
278
 
279
    for (i = 0; i < 6; i++) {
280
        eth_data->TX_ED_buffer[descriptor_index][write_index] = dest.bytes[i];
281
        write_index++;
282
    }
283
    for (i = 0; i < 6; i++) {
284
        eth_data->TX_ED_buffer[descriptor_index][write_index] = src.bytes[i];
285
        write_index++;
286
    }
287
    eth_data->TX_ED_buffer[descriptor_index][write_index] = length >> 8;
288
    eth_data->TX_ED_buffer[descriptor_index][write_index+1] = length;
289
    write_index += 2;
290
 
291
 
292
    eth_data->TX_ED_table.descriptor[descriptor_index].BYTE_COUNT = length + 14;
293
 
294
    for (i = 0; i < length; i++) {
295
        eth_data->TX_ED_buffer[descriptor_index][write_index] = buffer[read_index];
296
        write_index++;
297
        read_index++;
298
    }
299
 
300
    // Wait for any previous transmits to finish before sending
301
    while (ETHSTATbits.TXBUSY);
302
    ETHCON1bits.TXRTS = 1;
303
    while (ETHSTATbits.TXBUSY);
304
 
305
    eth_data->TX_descriptor_index = (descriptor_index == ETH_TX_DESCRIPTOR_COUNT - 1) ? 0 : descriptor_index + 1;
306
 
307
    return 0;
308
}
309
 
310
void __ISR(_ETH_VECTOR, ipl1) __ETH_Interrupt_Handler(void) {
311
    uint32_t value = ETHIRQ;
312
    if (ETHIRQbits.TXBUSE) {
313
 
314
        ETHIRQbits.TXBUSE = 0;
315
    }
316
    if (ETHIRQbits.RXBUSE) {
317
 
318
        ETHIRQbits.RXBUSE = 0;
319
    }
320
//    if (ETHIRQbits.RXDONE) {
321
//        ETHIRQbits.RXDONE = 0;
322
//    }
323
    if (ETHIRQbits.PKTPEND) {
324
        if (eth_data->rx_callback != NULL)
325
            (*eth_data->rx_callback)();
326
        ETHIRQbits.PKTPEND = 0;
327
    }
328
    if (ETHIRQbits.TXDONE) {
329
        if (eth_data->tx_callback != NULL)
330
            (*eth_data->tx_callback)();
331
        ETHIRQbits.TXDONE = 0;
332
    }
333
    if (ETHIRQbits.TXABORT) {
334
 
335
        ETHIRQbits.TXABORT = 0;
336
    }
337
    if (ETHIRQbits.RXBUFNA) {
338
        // This is a serious error!
339
 
340
        ETHIRQbits.RXBUFNA = 0;
341
    }
342
    if (ETHIRQbits.RXOVFLW) {
343
        // This is a serious error!
344
 
345
        ETHIRQbits.RXOVFLW = 0;
346
    }
347
 
348
    IFS1bits.ETHIF = 0;
349
}