Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SGDMA
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
RuSTA
Изучил эту ветку вдоль и поперек, но так и не смог настроить SGDMA в нужном мне режиме, т.е. смена по кругу дескрипторов и закрепленных за ними буферов.

Переменные
Код
volatile alt_sgdma_descriptor *SGDMARxDscrTab = (alt_sgdma_descriptor*)(DESCRIPTORS_ETH_BASE);
volatile alt_sgdma_descriptor *SGDMATxDscrTab = (alt_sgdma_descriptor*)(DESCRIPTORS_ETH_BASE+ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE*4);

volatile alt_sgdma_descriptor *SGDMARxDescToSet;
volatile alt_sgdma_descriptor *SGDMATxDescToSet;


Настройка TSE и SGDMA.
Код
int MAC_init(void){
    uint32_t errCount=0;
    uint32_t *cached_packet_payload;
    uint16_t temp;

    /* Set phy address at marvell 88E11111*/
    IOWR_ALTERA_TSEMAC_MDIO_ADDR0(TSE_BASE,PHY_ADDR);
    printf("Initialization MAC and PHY.\n");
    /* Wait while the bit of status register is wake up */
    do{
        errCount++;
        temp = IORD_ALTERA_TSEMAC_MDIO(TSE_BASE,0,ALTERA_TSEMAC_PHY_ADDR_STATUS);
        if(errCount>=0xFFFF0){
            printf("\nError read status\n");
            return 2;
        }
    }while(!(temp&PHY_LINK_UP)||(temp==0xFFFF));

    errCount = 0;
    /* Open scatter-gather DMA for receiver and transmitter */
    sgdma_rx_dev = alt_avalon_sgdma_open(SGDMA_RX_NAME);
    sgdma_tx_dev = alt_avalon_sgdma_open(SGDMA_TX_NAME);

    if(ALT_ERRNO==ENODEV)
        printf("Error opening sgdma rx or/and tx.\n");
    /* Soft reset sgdma rx    */
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_CONTROL_SOFTWARERESET_MSK);
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,0x00);
    /* Software reset MAC altera and enable rx and tx */
    IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_SW_RESET_MSK|
            ALTERA_TSEMAC_CMD_RX_ENA_MSK|
            ALTERA_TSEMAC_CMD_TX_ENA_MSK);
    while(IORD_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE)&ALTERA_TSEMAC_CMD_SW_RESET_MSK);
    /* Configure MAC    */
    IOWR_ALTERA_TSEMAC_FRM_LENGTH(TSE_BASE,ALTERA_TSE_MAC_MAX_FRAME_LENGTH);
    IOWR_ALTERA_TSEMAC_RX_ALMOST_EMPTY(TSE_BASE,8);
    IOWR_ALTERA_TSEMAC_RX_ALMOST_FULL(TSE_BASE,8);
    IOWR_ALTERA_TSEMAC_RX_SECTION_EMPTY(TSE_BASE,TSETHERNET_RECEIVE_FIFO_DEPTH-16);
    IOWR_ALTERA_TSEMAC_RX_SECTION_FULL(TSE_BASE,16);
    IOWR_ALTERA_TSEMAC_TX_ALMOST_EMPTY(TSE_BASE,8);
    IOWR_ALTERA_TSEMAC_TX_ALMOST_FULL(TSE_BASE,3);
    IOWR_ALTERA_TSEMAC_TX_SECTION_EMPTY(TSE_BASE,TSETHERNET_TRANSMIT_FIFO_DEPTH-16);
    IOWR_ALTERA_TSEMAC_TX_SECTION_FULL(TSE_BASE,16);
    IOWR_ALTERA_TSEMAC_TX_CMD_STAT(TSE_BASE,0);
    IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,ALTERA_TSEMAC_RX_CMD_STAT_RXSHIFT16_MSK);
    IOWR_ALTERA_TSEMAC_RX_CMD_STAT(TSE_BASE,0);
    IOWR_ALTERA_TSEMAC_CMD_CONFIG(TSE_BASE,ALTERA_TSEMAC_CMD_RX_ENA_MSK|ALTERA_TSEMAC_CMD_TX_ENA_MSK|
            ALTERA_TSEMAC_CMD_TX_ADDR_INS_MSK|ALTERA_TSEMAC_CMD_PAD_EN_MSK|
            ALTERA_TSEMAC_CMD_RX_ERR_DISC_MSK|
            ALTERA_TSEMAC_CMD_ETH_SPEED_MSK);
    IOWR_ALTERA_TSEMAC_MAC_0(TSE_BASE,(mac_addr[1]<<8|mac_addr[2]<<16|mac_addr[3]<<24|mac_addr[0])&0xFFFFFFFF);
    IOWR_ALTERA_TSEMAC_MAC_1(TSE_BASE,(mac_addr[5]<<8|mac_addr[4] & 0xFFFF));

    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE,IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE)|ALTERA_AVALON_SGDMA_CONTROL_PARK_MSK);

    /* Registering callback function for receiving */
    alt_avalon_sgdma_register_callback(sgdma_rx_dev,(alt_avalon_sgdma_callback)&tse_sgdmaRx_isr,(uint16_t)ALTERA_TSE_SGDMA_INTR_MASK,sgdma_rx_dev);
    /* Reforming non-cached memory to cached */

    alt_avalon_sgdma_rx_reg_chain((alt_sgdma_descriptor*)SGDMARxDscrTab,(alt_u8*)Rx_Buff,4);
    alt_avalon_sgdma_tx_reg_chain((alt_sgdma_descriptor*)SGDMATxDscrTab,(alt_u8*)Tx_Buff,2);

    while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);

    SGDMARxDescToSet->control |= ALTERA_AVALON_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
    alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev,(alt_sgdma_descriptor*)SGDMARxDscrTab);
    printf("Pointer to SGDMA->CONTROL: %x\n",IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_RX_BASE));
    sem=0;
    return SUCCESS;
}

void alt_avalon_sgdma_rx_reg_chain(alt_sgdma_descriptor *sgdma_table,alt_u8 *RxBuff,alt_u32 length_table){
    uint32_t i = 0;
    alt_sgdma_descriptor *SGDMARxDesc;
    while((((alt_u32)sgdma_table) % ALTERA_AVALON_SGDMA_DESCRIPTOR_SIZE) != 0){
        sgdma_table++;  // slide the pointer until 32 byte boundary is found
    }
    /* Set the DMARxDescToGet pointer with the first one of the DMARxDescTab list */
    SGDMARxDescToSet = sgdma_table;
    /* Fill each DMARxDesc descriptor with the right values */
    for(i=0; i < length_table; i++){
        /* Get the pointer on the ith member of the Rx Desc list */
        SGDMARxDesc = sgdma_table+i;
        /* Set Own bit of the Rx descriptor Status */
        //SGDMARxDesc->Status = ETH_DMARxDesc_OWN;

        /* Set Buffer1 size and Second Address Chained bit */
        //SGDMARxDesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)ETH_RX_BUF_SIZE;
        /* Set Buffer1 address pointer */
        SGDMARxDesc->write_addr = i==0?(uint32_t*)(RxBuff):(uint32_t*)(RxBuff+i*1524);

        /* Initialize the next descriptor with the Next Descriptor Polling Enable */
        if(i < (length_table-1)){
            /* Set next descriptor address register with next descriptor base address */
            SGDMARxDesc->next = (uint32_t*)(sgdma_table+i+1);
        }
        else{
            /* For last descriptor, set next descriptor address register equal to the first descriptor base address */
            SGDMARxDesc->next = (uint32_t*)(sgdma_table);
        }
        alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDesc),
                        (alt_sgdma_descriptor*)SGDMARxDesc->next,SGDMARxDesc->write_addr,0,0);
        while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) );
        printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARxDesc,SGDMARxDesc->next,SGDMARxDesc->write_addr);
    }
}


Обработка прерывания
Код
#define DEBUGE    1
int tse_sgdmaRx_isr(void * context, alt_u32 irqnum){
    alt_u32 t2=0;
    alt_u32 *uncached_packet_payload;

    t2=IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE);

    alt_sgdma_descriptor *SGDMARx_OWEN = (alt_sgdma_descriptor *)IORD_ALTERA_AVALON_SGDMA_NEXT_DESC_POINTER(SGDMA_RX_BASE);
    //SGDMARxDescToSet = (alt_sgdma_descriptor*)(SGDMARxDescToSet->next);

    if (t2 & (ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK|
            ALTERA_AVALON_SGDMA_STATUS_DESC_COMPLETED_MSK)){
        p_counter++;
        //alt_printf("Packet counter:%x\n",p_counter);
        IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_RX_BASE,ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK);
        t2=IORD_ALTERA_TSE_SGDMA_DESC_STATUS((alt_sgdma_descriptor *)SGDMARxDescToSet);
        /*check status and handle packet*/
        if((t2&(ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK | ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK |
                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK |
                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK |ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK |
                ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK ) ) == 0){

            t2=IORD_16DIRECT((alt_sgdma_descriptor *)SGDMARxDescToSet->actual_bytes_transferred, 0)-2;
        }
        else{
            alt_printf("RX descriptor reported error. Packet dropped\n");
        }
    }
    /*alt_avalon_sgdma_construct_stream_to_mem_desc((alt_sgdma_descriptor*)(SGDMARxDescToSet),
            (alt_sgdma_descriptor*)SGDMARxDescToSet->next,SGDMARxDescToSet->write_addr,0,0);
    while(IORD_ALTERA_AVALON_SGDMA_STATUS(TSE_BASE)&ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK);

    t2=alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, (alt_sgdma_descriptor *)SGDMARxDescToSet);*/


#ifdef DEBUGE

    printf("Frame coming\n");
    printf("Pointer to Desc: %p Pointer to next: %p RX buffer: %p\n",SGDMARx_OWEN,SGDMARx_OWEN->next,SGDMARx_OWEN->write_addr);
    for(t2=0;t2<10;t2++){
        printf("%x ",SGDMARx_OWEN->write_addr[t2]);
    }
    printf("\n");
#endif

    eth_filter((eth_frame_t*)SGDMARx_OWEN->write_addr);
    printf("\n");
    return 0;
}


Как видно из обработчика прерывания, повторно запуска alt_avalon_sgdma_do_async_transfer нет. Но данные продолжают приниматься, но все время в один и тот же буфер с тем же дескриптором.
doom13
Первое, что бросается в глаза, цепочка дескрипторов у Вас зациклена, а для последнего дескриптора в цепи указатель next должен быть ноль, чтоб Sg-DMA понял, что обработал все буферы. После обработки дескриптора Sg-DMA сбрасывает в нём флаги (не помню точно какой), если даже расположение буферов и не меняется, то для того, чтоб данный дескриптор опять подсунуть Sg-DMA, надо обновить в нём флаги.
Если не смотрели, можете глянуть эту тему, там и пример есть по работе Sg-DMA совместно с TSE (при запуске Ethernet на нём и учился).
RuSTA
Ну мне и хотелось сделать цикличным дескрипторы. Только вот не выходит.
gosu-art
У меня была такая же проблема. ну никак не зацикливались. что только не пробовал. решил вопрос так http://electronix.ru/forum/index.php?s=&am...t&p=1115476 Если нашли другое решение- отпишитесь, интересно 1111493779.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.