Всем привет!
Возникла проблема при работе с модулем TSE и нет никаких предположений в какую сторону копать. Очень надеюсь на вашу помощь!
Я пытаюсь при помощи NIOS и модуля TSE выплюнуть тестовую посылку в Ethernet. За основу взял проект vadimuzzz. В main_memory я при помощи Nios записываю 10 тестовых слов, которые и хочу передать в одной посылке через Ethernet.
TSE настроен на работу по интерфейсу RGMII. Mac Options модуля можно увидеть на фото ниже. Запустить пытаюсь на чипе KSZ9031.
Я считываю все данные из descriptor_memory при помощи SGDMA_tx и передаю их на модуль UDP. Этот модуль формирует на выходе посылку и передает ее на модуль TSE, который в свою очередь никак на это не реагирует.
Очень прошу вашей помощи! Тырните носом в мою ошибку или подскажите в каком направлении ее искать.
Скрин QSYS системы и листинг программы для NIOS:
Нажмите для просмотра прикрепленного файлаКод
#include <altera_avalon_sgdma.h>
#include <altera_avalon_sgdma_descriptor.h>
#include <altera_avalon_sgdma_regs.h>
#include <udp_tx_offload_regs.h>
#include "system.h"
#include <altera_avalon_tse.h>
#include "sys/alt_stdio.h"
#include "sys/alt_irq.h"
#include <stdio.h>
#include <unistd.h>
/*
* -----------------------------------------------------------------------------------------------------------------------------------------
*/
struct mac_struct
{
/* EXAMPLE
* 00-1C-23-17-4A-CB
* mac_hi = 0x17231c00
* mac_lo = 0x0000CB4a
* */
unsigned int mac_hi;
unsigned int mac_lo;
};
typedef union
{
struct mac_struct mac_addr;
unsigned char mac_arr[6];
} mac_addr_t;
typedef union
{
unsigned int addr;
unsigned char ad_arr[4];
} ip4_addr_t;
mac_addr_t MY_MAC_ADDR;
ip4_addr_t MY_IP_ADDR;
// Create sgdma transmit and receive devices
alt_sgdma_dev * sgdma_tx_dev;
alt_sgdma_dev * sgdma_rx_dev;
// Allocate descriptors in the descriptor_memory (onchip memory)
alt_sgdma_descriptor tx_descriptor __attribute__ (( section ( ".descriptor_memory" )));
alt_sgdma_descriptor tx_descriptor_end __attribute__ (( section ( ".descriptor_memory" )));
/*
* -----------------------------------------------------------------------------------------------------------------------------------------
*/
void TSE_init1(void)
{
alt_u32 /*t,*1=0,*/t2=0;
int status=0;
#define PHY 0x4
/* PHY and other board peripherial initialization */
IOWR_ALTERA_TSEMAC_MDIO_ADDR0(TSE_MAC_BASE,PHY);
alt_printf("TSE_MAC_REV:%x\n", IORD_ALTERA_TSEMAC_REV(TSE_MAC_BASE));
alt_printf("PHY_ID1:%x\n", IORD_ALTERA_TSEMAC_MDIO(TSE_MAC_BASE, 0, ALTERA_TSEMAC_PHY_ADDR_PHY_ID1));
alt_printf("PHY_ID2:%x\n", IORD_ALTERA_TSEMAC_MDIO(TSE_MAC_BASE, 0, ALTERA_TSEMAC_PHY_ADDR_PHY_ID2));
do
{
t2=IORD_ALTERA_TSEMAC_MDIO(TSE_MAC_BASE,0,ALTERA_TSEMAC_PHY_ADDR_STATUS);
}
while((t2&0x04)==0);//wait for link-up
/* Get the Rx and Tx SGDMA addresses */
sgdma_tx_dev = alt_avalon_sgdma_open("/dev/sgdma_tx");
sgdma_rx_dev = alt_avalon_sgdma_open("/dev/sgdma_rx");
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_TX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_TX_BASE, 0x0);
/* reset the mac */
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_MAC_BASE , ALTERA_TSEMAC_CMD_SW_RESET_MSK /*| ALTERA_TSEMAC_CMD_TX_ENA_MSK | ALTERA_TSEMAC_CMD_RX_ENA_MSK*/);
while(IORD_ALTERA_TSEMAC_CMD_CONFIG(TSE_MAC_BASE) & ALTERA_TSEMAC_CMD_SW_RESET_MSK)
{
}
/* Initialize MAC registers */
IOWR_ALTERA_TSEMAC_FRM_LENGTH(TSE_MAC_BASE, ALTERA_TSE_MAC_MAX_FRAME_LENGTH);
IOWR_ALTERA_TSEMAC_RX_ALMOST_EMPTY(TSE_MAC_BASE, 8);
IOWR_ALTERA_TSEMAC_RX_ALMOST_FULL(TSE_MAC_BASE, 8);
IOWR_ALTERA_TSEMAC_TX_ALMOST_EMPTY(TSE_MAC_BASE, 8);
IOWR_ALTERA_TSEMAC_TX_ALMOST_FULL(TSE_MAC_BASE, 3);
IOWR_ALTERA_TSEMAC_TX_SECTION_EMPTY(TSE_MAC_BASE, 240); //1024/4;
IOWR_ALTERA_TSEMAC_TX_SECTION_FULL(TSE_MAC_BASE, 16); //32/4; // start transmit when there are 48 bytes
IOWR_ALTERA_TSEMAC_RX_SECTION_EMPTY(TSE_MAC_BASE, 240); //4000/4);
IOWR_ALTERA_TSEMAC_RX_SECTION_FULL(TSE_MAC_BASE, 16);
IOWR_ALTERA_TSEMAC_TX_CMD_STAT(TSE_MAC_BASE,0);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_MAC_BASE,ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK);
IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_MAC_BASE,0);
IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_MAC_BASE, ALTERA_TSEMAC_CMD_TX_ENA_MSK | ALTERA_TSEMAC_CMD_RX_ENA_MSK | /*ALTERA_TSEMAC_CMD_TX_ADDR_INS_MSK |*/ ALTERA_TSEMAC_CMD_RX_ERR_DISC_MSK | ALTERA_TSEMAC_CMD_PAD_EN_MSK | ALTERA_TSEMAC_CMD_CRC_FWD_MSK);
IOWR_ALTERA_TSEMAC_MAC_0(TSE_MAC_BASE, MY_MAC_ADDR.mac_addr.mac_hi);
IOWR_ALTERA_TSEMAC_MAC_1(TSE_MAC_BASE, MY_MAC_ADDR.mac_addr.mac_lo);
}
int UDP_init()
{
int status=0;
UDP_TX_OFFLOAD_WR_CSR(UDP_TX_OFFLOAD_0_BASE, 0x1);
UDP_TX_OFFLOAD_WR_MAC_DST_HI(UDP_TX_OFFLOAD_0_BASE, 0x2819BEC8);
UDP_TX_OFFLOAD_WR_MAC_DST_LO(UDP_TX_OFFLOAD_0_BASE, 0x0000179B);
UDP_TX_OFFLOAD_WR_MAC_SRC_HI(UDP_TX_OFFLOAD_0_BASE, MY_MAC_ADDR.mac_addr.mac_hi);
UDP_TX_OFFLOAD_WR_MAC_SRC_LO(UDP_TX_OFFLOAD_0_BASE, MY_MAC_ADDR.mac_addr.mac_lo);
UDP_TX_OFFLOAD_WR_IP_SRC(UDP_TX_OFFLOAD_0_BASE, MY_IP_ADDR.ad_arr);
UDP_TX_OFFLOAD_WR_IP_DST(UDP_TX_OFFLOAD_0_BASE, 0x0100A8C0);
UDP_TX_OFFLOAD_WR_UDP_PORTS(UDP_TX_OFFLOAD_0_BASE, 0xE000);
UDP_TX_OFFLOAD_WR_IP_HDR_HI(UDP_TX_OFFLOAD_0_BASE, 0x0);
UDP_TX_OFFLOAD_WR_IP_HDR_LO(UDP_TX_OFFLOAD_0_BASE, 0x00004011/*0x0200FF11*/);
UDP_TX_OFFLOAD_WR_AUX_CONFIG(UDP_TX_OFFLOAD_0_BASE, 0x0800);
return status;
}
void add_phy_to_profile()
{
/* supported PHY definition */
/* ------------------------------ */
/* KSZ9031 */
/* ------------------------------ */
enum {
KSZ9031_OUI = 0x10A1,
KSZ9031_MODEL = 0x22,
KSZ9031_REV = 0x02
};
alt_tse_phy_profile KSZ9031 = {
"KSZ9031", /* Micrel KSZ9031 */
KSZ9031_OUI, /* OUI */
KSZ9031_MODEL, /* Vender Model Number */
KSZ9031_REV, /* Model Revision Number */
0x1F, /* Location of Status Register */
5, /* Location of Speed Status */
3, /* Location of Duplex Status */
0 /* Location of Link Status */
/*&KSZ9031_phy_cfg,*/ /* function pointer to configure Micrel KSZ8893M */
/*&KSZ9031_link_status_read*/ /* Function pointer to read from PHY specific status register */
};
/* add supported PHY to profile */
alt_tse_phy_add_profile(&KSZ9031);
}
int main(void)
{
alt_putstr("Start Work!\n");
/* MAC ADDRESS
* 00-07-AB-F0-0D-BA
* IP ADDRESS
* 192.168.0.3*/
MY_MAC_ADDR.mac_addr.mac_hi = 0xF0AB0700;
MY_MAC_ADDR.mac_addr.mac_lo = 0x0000BA0D;
MY_IP_ADDR.ad_arr[3] = 192;
MY_IP_ADDR.ad_arr[2] = 168;
MY_IP_ADDR.ad_arr[1] = 0;
MY_IP_ADDR.ad_arr[0] = 3;
unsigned int i;
unsigned int* adr;
unsigned int test_data;
adr = (unsigned int*) MAIN_MEMORY_BASE;
test_data = 0xFF00AA64;
adr = (unsigned int*) MAIN_MEMORY_BASE;
for(i = 0; i < 10; i += 1)
{
*adr = test_data;
adr += 1;
test_data += 1;
}
// Открываем SGDMA
sgdma_tx_dev = alt_avalon_sgdma_open(SGDMA_TX_NAME);
if (sgdma_tx_dev == NULL) {
alt_printf ("Error: could not open scatter-gather dma transmit device\n");
return -1;
} else alt_printf ("Opened scatter-gather dma transmit device\n");
alt_tse_phy_init();
add_phy_to_profile();
TSE_init1();
UDP_init();
UDP_TX_OFFLOAD_WR_PACKET_LEN(UDP_TX_OFFLOAD_0_BASE, 10);
alt_u32 *uncached_packet_payload;
uncached_packet_payload = (alt_u32*)alt_remap_cached ((volatile void*) MAIN_MEMORY_BASE, 4);
adr = (unsigned int*) MAIN_MEMORY_BASE;
alt_avalon_sgdma_construct_mem_to_stream_desc(
&tx_descriptor, // descriptor I want to work with
&tx_descriptor_end, // pointer to "next"
uncached_packet_payload,
40,
0,
1,
1,
0);
int timeout;
timeout = 0;
while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_TX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) )
{
if(timeout++ == ALTERA_TSE_SGDMA_BUSY_TIME_OUT_CNT)
{
alt_printf("tse_mac_raw_send: WARNING - TX SGDMA Timeout\n");
return -22; // avoid being stuck here
}
}
IOWR_ALTERA_AVALON_SGDMA_CONTROL (SGDMA_TX_BASE, 0);
IOWR_ALTERA_AVALON_SGDMA_STATUS (SGDMA_TX_BASE, 0xFF);
// Set up non-blocking transfer of sgdma transmit descriptor
alt_avalon_sgdma_do_async_transfer( sgdma_tx_dev, &tx_descriptor);
/* Event loop never exits. */
while (1);
return 0;
}