15.11.2011
Komunikacja sieciowa z wykorzystaniem mikrokontrolerów Freescale Kinetis
Przykładowy kod źródłowy implementujący wszystkie wymienione wyżej punkty przedstawiono w listingu:
/* Buffer Descriptor Format */ #ifdef ENHANCED_BD typedef struct { uint16_t status; /* control and status */ uint16_t length; /* transfer length */ uint8_t *data; /* buffer address */ uint32_t ebd_status; uint16_t length_proto_type; uint16_t payload_checksum; uint32_t bdu; uint32_t timestamp; uint32_t reserverd_word1; uint32_t reserverd_word2; } NBUF; #else typedef struct { uint16_t status; /* control and status */ uint16_t length; /* transfer length */ uint8_t *data; /* buffer address */ } NBUF; #endif /* ENHANCED_BD */ static void enet_init() { int usData; const unsigned portCHAR ucMACAddress[6] = { configMAC_ADDR0, configMAC_ADDR1,configMAC_ADDR2,configMAC_ADDR3,configMAC_ADDR4,configMAC_ADDR5 }; /* Enable the ENET clock. */ SIM_SCGC2 |= SIM_SCGC2_ENET_MASK; /*FSL: allow concurrent access to MPU controller. Example: ENET uDMA to SRAM, otherwise bus error*/ MPU_CESR = 0; prvInitialiseENETBuffers(); /* Set the Reset bit and clear the Enable bit */ ENET_ECR = ENET_ECR_RESET_MASK; /* Wait at least 8 clock cycles */ for( usData = 0; usData < 10; usData++ ) { asm( "NOP" ); } /*FSL: start MII interface*/ mii_init(0, periph_clk_khz/1000/*MHz*/); //enet_interrupt_routine set_irq_priority (76, 6); enable_irq(76);//ENET xmit interrupt //enet_interrupt_routine set_irq_priority (77, 6); enable_irq(77);//ENET rx interrupt //enet_interrupt_routine set_irq_priority (78, 6); enable_irq(78);//ENET error and misc interrupts /* * Make sure the external interface signals are enabled */ PORTB_PCR0 = PORT_PCR_MUX(4);//GPIO;//RMII0_MDIO/MII0_MDIO PORTB_PCR1 = PORT_PCR_MUX(4);//GPIO;//RMII0_MDC/MII0_MDC #if configUSE_MII_MODE PORTA_PCR14 = PORT_PCR_MUX(4);//RMII0_CRS_DV/MII0_RXDV PORTA_PCR5 = PORT_PCR_MUX(4);//RMII0_RXER/MII0_RXER PORTA_PCR12 = PORT_PCR_MUX(4);//RMII0_RXD1/MII0_RXD1 PORTA_PCR13 = PORT_PCR_MUX(4);//RMII0_RXD0/MII0_RXD0 PORTA_PCR15 = PORT_PCR_MUX(4);//RMII0_TXEN/MII0_TXEN PORTA_PCR16 = PORT_PCR_MUX(4);//RMII0_TXD0/MII0_TXD0 PORTA_PCR17 = PORT_PCR_MUX(4);//RMII0_TXD1/MII0_TXD1 PORTA_PCR11 = PORT_PCR_MUX(4);//MII0_RXCLK PORTA_PCR25 = PORT_PCR_MUX(4);//MII0_TXCLK PORTA_PCR9 = PORT_PCR_MUX(4);//MII0_RXD3 PORTA_PCR10 = PORT_PCR_MUX(4);//MII0_RXD2 PORTA_PCR28 = PORT_PCR_MUX(4);//MII0_TXER PORTA_PCR24 = PORT_PCR_MUX(4);//MII0_TXD2 PORTA_PCR26 = PORT_PCR_MUX(4);//MII0_TXD3 PORTA_PCR27 = PORT_PCR_MUX(4);//MII0_CRS PORTA_PCR29 = PORT_PCR_MUX(4);//MII0_COL #else PORTA_PCR14 = PORT_PCR_MUX(4);//RMII0_CRS_DV/MII0_RXDV PORTA_PCR5 = PORT_PCR_MUX(4);//RMII0_RXER/MII0_RXER PORTA_PCR12 = PORT_PCR_MUX(4);//RMII0_RXD1/MII0_RXD1 PORTA_PCR13 = PORT_PCR_MUX(4);//RMII0_RXD0/MII0_RXD0 PORTA_PCR15 = PORT_PCR_MUX(4);//RMII0_TXEN/MII0_TXEN PORTA_PCR16 = PORT_PCR_MUX(4);//RMII0_TXD0/MII0_TXD0 PORTA_PCR17 = PORT_PCR_MUX(4);//RMII0_TXD1/MII0_TXD1 #endif /* Can we talk to the PHY? */ do { RTOS_DELAY( netifLINK_DELAY ); usData = 0xffff; mii_read( 0, configPHY_ADDRESS, PHY_PHYIDR1, &usData ); } while( usData == 0xffff ); /* Start auto negotiate. */ mii_write( 0, configPHY_ADDRESS, PHY_BMCR, ( PHY_BMCR_AN_RESTART | PHY_BMCR_AN_ENABLE ) ); /* Wait for auto negotiate to complete. */ do { RTOS_DELAY( netifLINK_DELAY ); mii_read( 0, configPHY_ADDRESS, PHY_BMSR, &usData ); } while( !( usData & PHY_BMSR_AN_COMPLETE ) ); /* When we get here we have a link - find out what has been negotiated. */ usData = 0; mii_read( 0, configPHY_ADDRESS, PHY_STATUS, &usData ); /* Clear the Individual and Group Address Hash registers */ ENET_IALR = 0; ENET_IAUR = 0; ENET_GALR = 0; ENET_GAUR = 0; /* Set the Physical Address for the selected ENET */ enet_set_address( 0, ucMACAddress ); #if configUSE_MII_MODE /* Various mode/status setup. */ ENET_RCR = ENET_RCR_MAX_FL(configENET_RX_BUFFER_SIZE) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK; #else ENET_RCR = ENET_RCR_MAX_FL(configENET_RX_BUFFER_SIZE) | ENET_RCR_MII_MODE_MASK | ENET_RCR_CRCFWD_MASK | ENET_RCR_RMII_MODE_MASK; #endif /*FSL: clear rx/tx control registers*/ ENET_TCR = 0; /* Setup half or full duplex. */ if( usData & PHY_DUPLEX_STATUS ) { /*Full duplex*/ ENET_RCR &= (unsigned portLONG)~ENET_RCR_DRT_MASK; ENET_TCR |= ENET_TCR_FDEN_MASK; } else { /*half duplex*/ ENET_RCR |= ENET_RCR_DRT_MASK; ENET_TCR &= (unsigned portLONG)~ENET_TCR_FDEN_MASK; } /* Setup speed */ if( usData & PHY_SPEED_STATUS ) { /*10Mbps*/ ENET_RCR |= ENET_RCR_RMII_10T_MASK; } #if( configUSE_PROMISCUOUS_MODE == 1 ) { ENET_RCR |= ENET_RCR_PROM_MASK; } #endif #ifdef ENHANCED_BD ENET_ECR = ENET_ECR_EN1588_MASK; #else ENET_ECR = 0; #endif /* Set Rx Buffer Size */ ENET_MRBR = (unsigned portSHORT) configENET_RX_BUFFER_SIZE; /* Point to the start of the circular Rx buffer descriptor queue */ ENET_RDSR = ( unsigned portLONG ) &( xENETRxDescriptors[ 0 ] ); /* Point to the start of the circular Tx buffer descriptor queue */ ENET_TDSR = ( unsigned portLONG ) xENETTxDescriptors; /* Clear all ENET interrupt events */ ENET_EIR = ( unsigned portLONG ) -1; /* Enable interrupts */ ENET_EIMR = ENET_EIR_TXF_MASK | ENET_EIMR_RXF_MASK | ENET_EIMR_RXB_MASK | ENET_EIMR_UN_MASK | ENET_EIMR_RL_MASK | ENET_EIMR_LC_MASK | ENET_EIMR_BABT_MASK | ENET_EIMR_BABR_MASK | ENET_EIMR_EBERR_MASK; /* Create the task that handles the MAC ENET RX */ /* RTOS + TCP/IP stack dependent */ /* Enable the MAC itself. */ ENET_ECR |= ENET_ECR_ETHEREN_MASK; /* Indicate that there have been empty receive buffers produced */ ENET_RDAR = ENET_RDAR_RDAR_MASK; } static void prvInitialiseENETBuffers( void ) { unsigned portBASE_TYPE ux; unsigned char *pcBufPointer; pcBufPointer = &( xENETTxDescriptors_unaligned[ 0 ] ); while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) { pcBufPointer++; } xENETTxDescriptors = ( NBUF * ) pcBufPointer; pcBufPointer = &( xENETRxDescriptors_unaligned[ 0 ] ); while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) { pcBufPointer++; } xENETRxDescriptors = ( NBUF * ) pcBufPointer; /* Setup the buffers and descriptors. */ pcBufPointer = &( ucENETTxBuffers[ 0 ] ); while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) { pcBufPointer++; } for( ux = 0; ux < configNUM_ENET_TX_BUFFERS; ux++ ) { xENETTxDescriptors[ ux ].status = TX_BD_TC; #ifdef NBUF_LITTLE_ENDIAN xENETTxDescriptors[ ux ].data = (uint8_t *)__REV((uint32_t)pcBufPointer); #else xENETTxDescriptors[ ux ].data = pcBufPointer; #endif pcBufPointer += configENET_TX_BUFFER_SIZE; xENETTxDescriptors[ ux ].length = 0; #ifdef ENHANCED_BD xENETTxDescriptors[ ux ].ebd_status = TX_BD_IINS | TX_BD_PINS; #endif } pcBufPointer = &( ucENETRxBuffers[ 0 ] ); while( ( ( unsigned long ) pcBufPointer & 0x0fUL ) != 0 ) { pcBufPointer++; } for( ux = 0; ux < configNUM_ENET_RX_BUFFERS; ux++ ) { xENETRxDescriptors[ ux ].status = RX_BD_E; xENETRxDescriptors[ ux ].length = 0; #ifdef NBUF_LITTLE_ENDIAN xENETRxDescriptors[ ux ].data = (uint8_t *)__REV((uint32_t)pcBufPointer); #else xENETRxDescriptors[ ux ].data = pcBufPointer; #endif pcBufPointer += configENET_RX_BUFFER_SIZE; #ifdef ENHANCED_BD xENETRxDescriptors[ ux ].bdu = 0x00000000; xENETRxDescriptors[ ux ].ebd_status = RX_BD_INT; #endif } /* Set the wrap bit in the last descriptors to form a ring. */ xENETTxDescriptors[ configNUM_ENET_TX_BUFFERS - 1 ].status |= TX_BD_W; xENETRxDescriptors[ configNUM_ENET_RX_BUFFERS - 1 ].status |= RX_BD_W; uxNextRxBuffer = 0; uxNextTxBuffer = 0; }