Subversion Repositories Code-Repo

Rev

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

Rev Author Line No. Line
255 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
263 Kevin 118
    // Something needs to be done about this. 5s is WAY too long to wait
255 Kevin 119
    Delay_MS(5000);
120
 
121
    // Wait for auto-negotiation to finish
122
    do {
123
        value = ETH_PHY_Read(PHY_ADDRESS, 0x1F); // Acquire link status
124
    } while (value & 0x1000 == 0);
125
 
126
    ETHCON1bits.ON = 0;     // Disable the ethernet module before changing other settings
127
 
128
    // Part 4. MAC Configuration
129
    EMAC1CFG1bits.RXENABLE = 1;     // Enable the MAC receiving of frames
130
    EMAC1CFG1bits.TXPAUSE = 1;      // Enable PAUSE flow control frames
131
    EMAC1CFG1bits.RXPAUSE = 1;      // Enable processing of PAUSE control frames
132
    EMAC1CFG2bits.AUTOPAD = 0;      // No auto-detection for VLAN padding
133
    EMAC1CFG2bits.VLANPAD = 0;      // MAC does not perform padding of short frames
134
    EMAC1CFG2bits.PADENABLE = 1;    // Pad all short frames
135
    EMAC1CFG2bits.CRCENABLE = 1;    // Append a CRC to every frame
136
    EMAC1CFG2bits.HUGEFRM = 1;      // Allow frames of any length
137
    EMAC1CFG2bits.LENGTHCK = 0;     // Check the frame lengths to the length/type field
138
    if ((value & 0x14) || (value & 0x18)) {
139
        EMAC1CFG2bits.FULLDPLX = 1; // Operate in full-duplex mode
140
        EMAC1IPGT = 0x15;           // Back-to-back interpacket gap @ 0.96us/9.6us
141
//        LED1_LAT = 1;
142
    } else {
143
        EMAC1CFG2bits.FULLDPLX = 0; // Operate in half-duplex mode
144
        EMAC1IPGT = 0x12;           // Back-to-back interpacket gap @ 0.96us/9.6us
145
//        LED2_LAT = 1;
146
    }
147
    if ((value & 0x08) || (value & 0x18)) {
148
        EMAC1SUPPbits.SPEEDRMII = 1;    // 100Mbps mode
149
//        LED3_LAT = 1;
150
    } else {
151
        EMAC1SUPPbits.SPEEDRMII = 0;    // 10Mbps mode
152
//        LED4_LAT = 1;
153
    }
154
    EMAC1IPGRbits.NB2BIPKTGP1 = 0xC;    // Set some other delay gap values
155
    EMAC1IPGRbits.NB2BIPKTGP2 = 0x12;
156
    EMAC1CLRTbits.CWINDOW = 0x37;       // Set collision window to count of frame bytes
157
    EMAC1CLRTbits.RETX = 0xF;           // Set number of retransmission attempts
158
    EMAC1MAXF = 0x7F4;                  // Set the maximum frame length to 2046 bits
159
    // Default MAC address is 00-04-A3-1A-4C-FC
160
    // Set MAC address to 00-18-3E-00-D7-EB
161
    EMAC1SA0 = 0xEBD7;
162
    EMAC1SA1 = 0x003E;
163
    EMAC1SA2 = 0x1800;
164
 
165
    // Part 5. Ethernet Controller Initialization cont.
166
        // Flow control is off by default!
167
    ETHRXFCbits.HTEN = 0;       // Disable hash table filtering
168
    ETHRXFCbits.MPEN = 0;       // Disable magic packet filtering
169
    ETHRXFCbits.PMMODE = 0;     // Disable pattern matching
170
    ETHRXFCbits.CRCERREN = 0;   // Disable CRC error collection filtering
171
    ETHRXFCbits.CRCOKEN = 0;    // Disable CRC filtering
172
    ETHRXFCbits.RUNTERREN = 0;  // Disable runt error collection filtering
173
    ETHRXFCbits.RUNTEN = 0;     // Disable runt filtering
174
    ETHRXFCbits.UCEN = 1;       // Enable unicast filtering
175
    ETHRXFCbits.NOTMEEN = 0;    // Disable acceptance of packets to other destinations
176
    ETHRXFCbits.MCEN = 0;       // Disable multicast filtering
177
    ETHRXFCbits.BCEN = 0;       // Disable broadcast filtering
178
 
179
    ETHCON2bits.RXBUF_SZ = 0x7F;    // Set RX data buffer size to 2032 bytes
180
 
181
    ETHIENbits.TXBUSEIE = 1;    // Enable interrupt on transmit BVCI bus error
182
    ETHIENbits.RXBUSEIE = 1;    // Enable interrupt on receive BVCI bus error
261 Kevin 183
    ETHIENbits.RXDONEIE = 1;    // Enable interrupt on packet received
184
//    ETHIENbits.PKTPENDIE = 1;   // Enable interrupt on packet pending
255 Kevin 185
//    ETHIENbits.RXACTIE = 1;
186
    ETHIENbits.TXDONEIE = 1;    // Enable interrupt on packet sent
187
    ETHIENbits.TXABORTIE = 1;   // Enable interrupt on packet send aborted
188
 
261 Kevin 189
    IPC12bits.ETHIP = 1;        // Set interrupt priority to 2
190
    IPC12bits.ETHIS = 1;        // Set intererupt sub-priority to 2
255 Kevin 191
    IEC1bits.ETHIE = 1;         // Enable ethernet interrupts
192
 
193
    EMAC1SUPPbits.RESETRMII = 0;    // Bring the RMII module out of reset
194
    ETHCON1bits.RXEN = 1;       // Start receive logic
195
    ETHCON1bits.ON = 1;             // Enable the ethernet module
196
 
197
    INTEnableInterrupts();
198
}
199
 
200
/* Reads from the specified register on the PHY chip */
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
 
210
/* Write to the specified register on the PHY chip */
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
 
218
/* Queries the number of pending packets */
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
 
235
            // Read the packet data values into the buffer
236
            size = eth_data->RX_ED_table.descriptor[descriptor_index].BYTE_COUNT - 18;
261 Kevin 237
            for (j = 0; j < size; j++) {
255 Kevin 238
                buffer[j] = eth_data->RX_ED_buffer[descriptor_index][j+14];
239
            }
261 Kevin 240
            *length = size;
255 Kevin 241
 
242
            // Reset the descriptors
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) {
261 Kevin 311
//    uint32_t value = ETHIRQ;
255 Kevin 312
    if (ETHIRQbits.TXBUSE) {
263 Kevin 313
        // TX bus error, something -should- be done
268 Kevin 314
        Reset_Board(BOARD_MODE_ETHERNET);
255 Kevin 315
        ETHIRQbits.TXBUSE = 0;
316
    }
317
    if (ETHIRQbits.RXBUSE) {
263 Kevin 318
        // RX bus error, something -should- be done
268 Kevin 319
        Reset_Board(BOARD_MODE_ETHERNET);
255 Kevin 320
        ETHIRQbits.RXBUSE = 0;
321
    }
261 Kevin 322
    if (ETHIRQbits.RXDONE) {
263 Kevin 323
        // Call the previously saved function
255 Kevin 324
        if (eth_data->rx_callback != NULL)
325
            (*eth_data->rx_callback)();
261 Kevin 326
        ETHIRQbits.RXDONE = 0;
255 Kevin 327
    }
261 Kevin 328
//    if (ETHIRQbits.PKTPEND) {
329
//
330
//        ETHIRQbits.PKTPEND = 0;
331
//    }
255 Kevin 332
    if (ETHIRQbits.TXDONE) {
263 Kevin 333
        // Call the previously saved function
255 Kevin 334
        if (eth_data->tx_callback != NULL)
335
            (*eth_data->tx_callback)();
336
        ETHIRQbits.TXDONE = 0;
337
    }
338
    if (ETHIRQbits.TXABORT) {
263 Kevin 339
        // TX aborted, do we care?
255 Kevin 340
        ETHIRQbits.TXABORT = 0;
341
    }
342
    if (ETHIRQbits.RXBUFNA) {
343
        // This is a serious error!
263 Kevin 344
        // TODO: handle this
268 Kevin 345
        Reset_Board(BOARD_MODE_ETHERNET);
255 Kevin 346
        ETHIRQbits.RXBUFNA = 0;
347
    }
348
    if (ETHIRQbits.RXOVFLW) {
349
        // This is a serious error!
263 Kevin 350
        // TODO: handle this
268 Kevin 351
        Reset_Board(BOARD_MODE_ETHERNET);
255 Kevin 352
        ETHIRQbits.RXOVFLW = 0;
353
    }
354
 
355
    IFS1bits.ETHIF = 0;
356
}