/** ************************************************************************** * @file at32_emac.c * @version v2.0.4 * @date 2021-12-31 * @brief emac config program ************************************************************************** * Copyright notice & Disclaimer * * The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer. * * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * ************************************************************************** */ /* includes ------------------------------------------------------------------*/ #include "at32_emac.h" #include "SystemDelayInterface.h" /** @addtogroup AT32F437_periph_examples * @{ */ /** @addtogroup 437_EMAC_tcp_server * @{ */ /** * @brief enable emac clock and gpio clock * @param none * @retval success or error */ error_status emac_system_init(void) { error_status status; emac_nvic_configuration(); /* emac periph clock enable */ crm_periph_clock_enable(CRM_EMAC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_EMACTX_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_EMACRX_PERIPH_CLOCK, TRUE); emac_pins_configuration(); status = emac_layer2_configuration(); return status; } error_status emac_system_init_eth(void) { nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); error_status status = emac_system_init(); return status; } /** * @brief configures emac irq channel. * @param none * @retval none */ void emac_nvic_configuration(void) { nvic_irq_enable(EMAC_IRQn, 1, 0); NVIC_SetPriority((IRQn_Type)EMAC_IRQn, 0); } /** * @brief configures emac required pins. * @param none * @retval none */ void emac_pins_configuration(void) { gpio_init_type gpio_init_struct = {0}; /* emac pins clock enable */ crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOG_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOH_PERIPH_CLOCK, TRUE); /* pa2 -> mdio */ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_11); gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pins = GPIO_PINS_2; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOA, &gpio_init_struct); /* pc1 -> mdc */ gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE1, GPIO_MUX_11); gpio_init_struct.gpio_pins = GPIO_PINS_1; gpio_init(GPIOC, &gpio_init_struct); #ifdef MII_MODE /* pg13 -> tx_d0 pg14 -> tx_d1 pc2 -> tx_d2 pb8 -> tx_d3 pb11 -> tx_en pc3 -> tx_clk */ gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE13, GPIO_MUX_11); // pg13 -> tx_d0 gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE14, GPIO_MUX_11); // pg14 -> tx_d1 gpio_init_struct.gpio_pins = GPIO_PINS_13 | GPIO_PINS_14; gpio_init(GPIOG, &gpio_init_struct); gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE2, GPIO_MUX_11); // pc2 -> tx_d2 gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE3, GPIO_MUX_11); // pc3 -> tx_clk gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3; gpio_init(GPIOC, &gpio_init_struct); gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE8, GPIO_MUX_11); // pb8 -> tx_d3 gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE11, GPIO_MUX_11); // pb11 -> tx_en gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_11; gpio_init(GPIOB, &gpio_init_struct); /* pa7 -> rx_dv pc4 -> rx_d0 pc5 -> rx_d1 pb0 -> rx_d2 pb1 -> rx_d3 */ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE7, GPIO_MUX_11); // pa7 -> rx_dv gpio_init_struct.gpio_pins = GPIO_PINS_7; gpio_init(GPIOA, &gpio_init_struct); gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE4, GPIO_MUX_11); // pc4 -> rx_d0 gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE5, GPIO_MUX_11); // pc5 -> rx_d1 gpio_init_struct.gpio_pins = GPIO_PINS_4 | GPIO_PINS_5; gpio_init(GPIOC, &gpio_init_struct); gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE0, GPIO_MUX_11); // pb0 -> rx_d2 gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE1, GPIO_MUX_11); // pb1 -> rx_d3 gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1; gpio_init(GPIOB, &gpio_init_struct); /* pa1 -> rx_clk pa0 -> crs pa3 -> col pb10 -> rx_er */ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE1, GPIO_MUX_11); // pa1 -> rx_clk gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE0, GPIO_MUX_11); // pa0 -> crs gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_11); // pa3 -> col gpio_init_struct.gpio_pins = GPIO_PINS_1 | GPIO_PINS_0 | GPIO_PINS_3; gpio_init(GPIOA, &gpio_init_struct); gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE10, GPIO_MUX_11); // pb10 -> rx_er gpio_init_struct.gpio_pins = GPIO_PINS_10; gpio_init(GPIOB, &gpio_init_struct); #endif /* MII_MODE */ #ifdef RMII_MODE /* pb12 -> tx_d0 pb13 -> tx_d1 pb11 -> tx_en */ gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE11, GPIO_MUX_11); gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE13, GPIO_MUX_11); gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE14, GPIO_MUX_11); gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_13 | GPIO_PINS_14; gpio_init(GPIOG, &gpio_init_struct); /* pd8 -> rx_dv pd9 -> rx_d0 pd10 -> rx_d1 */ gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE8, GPIO_MUX_11); gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE9, GPIO_MUX_11); gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE10, GPIO_MUX_11); gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init(GPIOD, &gpio_init_struct); #endif /* RMII_MODE */ /* pa1 -> ref_clk */ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE1, GPIO_MUX_11); gpio_init_struct.gpio_pins = GPIO_PINS_1; gpio_init(GPIOA, &gpio_init_struct); #if !CRYSTAL_ON_PHY gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE8, GPIO_MUX_0); gpio_init_struct.gpio_pins = GPIO_PINS_8; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init(GPIOA, &gpio_init_struct); #endif } /** * @brief configures emac layer2 * @param none * @retval error or success */ error_status emac_layer2_configuration(void) { emac_control_config_type mac_control_para; emac_dma_config_type dma_control_para; crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE); #ifdef MII_MODE scfg_emac_interface_set(SCFG_EMAC_SELECT_MII); #elif defined RMII_MODE scfg_emac_interface_set(SCFG_EMAC_SELECT_RMII); #endif // crm_clock_out1_set(CRM_CLKOUT1_PLL); // crm_clkout_div_set(CRM_CLKOUT_INDEX_1, CRM_CLKOUT_DIV1_5, CRM_CLKOUT_DIV2_2); crm_clock_out1_set(CRM_CLKOUT1_HEXT); crm_clkout_div_set(CRM_CLKOUT_INDEX_1, CRM_CLKOUT_DIV1_1, CRM_CLKOUT_DIV2_1); /* reset phy */ reset_phy(); /* reset emac ahb bus */ emac_reset(); /* software reset emac dma */ emac_dma_software_reset_set(); while(emac_dma_software_reset_get() == SET); emac_control_para_init(&mac_control_para); // mac_control_para.duplex_mode = EMAC_FULL_DUPLEX; // mac_control_para.fast_ethernet_speed = EMAC_SPEED_10MBPS; /* mac_control_para.auto_nego = EMAC_AUTO_NEGOTIATION_OFF; mac_control_para.fast_ethernet_speed = EMAC_SPEED_100MBPS; mac_control_para.duplex_mode = EMAC_FULL_DUPLEX; */ //mac_control_para.auto_nego = EMAC_AUTO_NEGOTIATION_OFF; //mac_control_para.fast_ethernet_speed = PHY_FULL_DUPLEX_100MBPS_BIT; //mac_control_para.duplex_mode = EMAC_FULL_DUPLEX; // mac_control_para.auto_nego = EMAC_AUTO_NEGOTIATION_ON; mac_control_para.auto_nego = EMAC_AUTO_NEGOTIATION_OFF; mac_control_para.fast_ethernet_speed = EMAC_SPEED_100MBPS; mac_control_para.duplex_mode = EMAC_FULL_DUPLEX; if(emac_phy_init(&mac_control_para) == ERROR) { return ERROR; } emac_dma_para_init(&dma_control_para); dma_control_para.rsf_enable = TRUE; dma_control_para.tsf_enable = TRUE; dma_control_para.osf_enable = TRUE; dma_control_para.aab_enable = TRUE; dma_control_para.usp_enable = TRUE; dma_control_para.fb_enable = TRUE; dma_control_para.flush_rx_disable = TRUE; dma_control_para.rx_dma_pal = EMAC_DMA_PBL_32; dma_control_para.tx_dma_pal = EMAC_DMA_PBL_32; dma_control_para.priority_ratio = EMAC_DMA_2_RX_1_TX; emac_dma_config(&dma_control_para); // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_NORMAL_SUMMARY, TRUE); // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX, TRUE); // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX, TRUE); /*!< transmit interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX_STOP, TRUE); /*!< transmit process stopped interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX_UNAVAILABLE, TRUE); /*!< transmit buffer unavailable interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX_JABBER, TRUE); /*!< transmit jabber timeout interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX_OVERFLOW, TRUE); /*!< receive overflow interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX_UNDERFLOW, TRUE); /*!< transmit underflow interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX, TRUE); /*!< receive interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX_UNAVAILABLE, TRUE); /*!< receive buffer unavailable interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX_STOP, TRUE); /*!< receive process stopped interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX_TIMEOUT, TRUE); /*!< receive watchdog timeout interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_TX_EARLY, TRUE); /*!< early transmit interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_FATAL_BUS_ERROR, TRUE); /*!< fatal bus error interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_RX_EARLY, TRUE); /*!< early receive interrupt */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_ABNORMAL_SUMMARY, TRUE); /*!< abnormal interrupt summary */ // emac_dma_interrupt_enable(EMAC_DMA_INTERRUPT_NORMAL_SUMMARY, TRUE); /*!< normal interrupt summary */ return SUCCESS; } /** * @brief reset layer 1 * @param none * @retval none */ void static reset_phy(void) { gpio_init_type gpio_init_struct = {0}; crm_periph_clock_enable(CRM_GPIOG_PERIPH_CLOCK, TRUE); gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pins = GPIO_PINS_12; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOG, &gpio_init_struct); gpio_bits_reset(GPIOG, GPIO_PINS_12); SystemDelayMs(2); // delay_ms(2); gpio_bits_set(GPIOG, GPIO_PINS_12); SystemDelayMs(2); // delay_ms(2); /* gpio_init_type gpio_init_struct = {0}; crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOG_PERIPH_CLOCK, TRUE); gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pins = GPIO_PINS_15; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOE, &gpio_init_struct); gpio_init_struct.gpio_pins = GPIO_PINS_15; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOG, &gpio_init_struct); gpio_bits_reset(GPIOG, GPIO_PINS_15); gpio_bits_reset(GPIOE, GPIO_PINS_15); SystemDelayMs(2); // delay_ms(2); gpio_bits_set(GPIOE, GPIO_PINS_15); SystemDelayMs(2); // delay_ms(2); */ } /** * @brief reset phy register * @param none * @retval SUCCESS or ERROR */ error_status emac_phy_register_reset(void) { uint16_t data = 0; uint32_t timeout = 0; uint32_t i = 0; if(emac_phy_register_write(PHY_ADDRESS, PHY_CONTROL_REG, PHY_RESET_BIT) == ERROR) { return ERROR; } for(i = 0; i < 0x000FFFFF; i++); do { timeout++; if(emac_phy_register_read(PHY_ADDRESS, PHY_CONTROL_REG, &data) == ERROR) { return ERROR; } } while((data & PHY_RESET_BIT) && (timeout < PHY_TIMEOUT)); for(i = 0; i < 0x00FFFFF; i++); if(timeout == PHY_TIMEOUT) { return ERROR; } return SUCCESS; } /** * @brief set mac speed related parameters * @param nego: auto negotiation on or off. * this parameter can be one of the following values: * - EMAC_AUTO_NEGOTIATION_OFF * - EMAC_AUTO_NEGOTIATION_ON. * @param mode: half-duplex or full-duplex. * this parameter can be one of the following values: * - EMAC_HALF_DUPLEX * - EMAC_FULL_DUPLEX. * @param speed: 10 mbps or 100 mbps * this parameter can be one of the following values: * - EMAC_SPEED_10MBPS * - EMAC_SPEED_100MBPS. * @retval none */ error_status emac_speed_config(emac_auto_negotiation_type nego, emac_duplex_type mode, emac_speed_type speed) { uint16_t data = 0; uint32_t timeout = 0; if(nego == EMAC_AUTO_NEGOTIATION_ON) { do { timeout++; if(emac_phy_register_read(PHY_ADDRESS, PHY_STATUS_REG, &data) == ERROR) { return ERROR; } } while(!(data & PHY_LINKED_STATUS_BIT) && (timeout < PHY_TIMEOUT)); if(timeout == PHY_TIMEOUT) { return ERROR; } timeout = 0; if(emac_phy_register_write(PHY_ADDRESS, PHY_CONTROL_REG, PHY_AUTO_NEGOTIATION_BIT) == ERROR) { return ERROR; } do { timeout++; if(emac_phy_register_read(PHY_ADDRESS, PHY_STATUS_REG, &data) == ERROR) { return ERROR; } } while(!(data & PHY_NEGO_COMPLETE_BIT) && (timeout < PHY_TIMEOUT)); if(timeout == PHY_TIMEOUT) { return ERROR; } // if(emac_phy_register_read(PHY_ADDRESS, PHY_SPECIFIED_CS_REG, &data) == ERROR) // { // return ERROR; // } if (emac_phy_register_read(PHY_ADDRESS, PHY_AUTO_NEG_REG, &data) == ERROR) { return ERROR; } #ifdef DM9162 if(data & PHY_FULL_DUPLEX_100MBPS_BIT) { emac_fast_speed_set(EMAC_SPEED_100MBPS); emac_duplex_mode_set(EMAC_FULL_DUPLEX); } else if(data & PHY_HALF_DUPLEX_100MBPS_BIT) { emac_fast_speed_set(EMAC_SPEED_100MBPS); emac_duplex_mode_set(EMAC_HALF_DUPLEX); } else if(data & PHY_FULL_DUPLEX_10MBPS_BIT) { emac_fast_speed_set(EMAC_SPEED_10MBPS); emac_duplex_mode_set(EMAC_FULL_DUPLEX); } else if(data & PHY_HALF_DUPLEX_10MBPS_BIT) { emac_fast_speed_set(EMAC_SPEED_10MBPS); emac_duplex_mode_set(EMAC_HALF_DUPLEX); } #else if(data & PHY_DUPLEX_MODE) { emac_duplex_mode_set(EMAC_FULL_DUPLEX); } else { emac_duplex_mode_set(EMAC_HALF_DUPLEX); } if(data & PHY_SPEED_MODE) { emac_fast_speed_set(EMAC_SPEED_10MBPS); } else { emac_fast_speed_set(EMAC_SPEED_100MBPS); } #endif } else { if(emac_phy_register_write(PHY_ADDRESS, PHY_CONTROL_REG, (uint16_t)((mode << 8) | (speed << 13))) == ERROR) { return ERROR; } if(speed == EMAC_SPEED_100MBPS) { emac_fast_speed_set(EMAC_SPEED_100MBPS); } else { emac_fast_speed_set(EMAC_SPEED_10MBPS); } if(mode == EMAC_FULL_DUPLEX) { emac_duplex_mode_set(EMAC_FULL_DUPLEX); } else { emac_duplex_mode_set(EMAC_HALF_DUPLEX); } } return SUCCESS; } /** * @brief initialize emac phy * @param none * @retval SUCCESS or ERROR */ error_status emac_phy_init(emac_control_config_type *control_para) { emac_clock_range_set(); if(emac_phy_register_reset() == ERROR) { return ERROR; } if(emac_speed_config(control_para->auto_nego, control_para->duplex_mode, control_para->fast_ethernet_speed) == ERROR) { return ERROR; } emac_control_config(control_para); return SUCCESS; } /** * @} */ /** * @} */