Forum Discussion
TSE and scatter-gather dma problem
hi, everyone
I am recently trying to connect nios II to computor through ethernet , I separately connected a memory to stream scatter gather DMA to TSE's transmit and a stream to memory scatter gather DMA to TSE's receive . But when I sent a packet through scatter gather DMA, the output of TSE was nothing , also ,when I send packet from computor to NIOS, the receiving DMA got nothing. I had tried connect the memory to stream DMA to stream to memory DMA, it worked OK. Please give me some advice ,thanks. https://www.alteraforum.com/forum/attachment.php?attachmentid=5665 when I runned the code below , I checked ouput signals of TSE through signaltap II,but nothing happened# include "sys/alt_stdio.h"# include "altera_avalon_sgdma_regs.h"# include "altera_avalon_sgdma.h"# include "altera_avalon_sgdma_descriptor.h"
/* These will gate the data checking near the end of main */
volatile alt_u8 tx_done = 0;
volatile alt_u8 rx_done = 0;
void tx_callback_function(void * context)
{
tx_done++; /* main will be polling for this value being 1 */
}
void rx_callback_function(void * context)
{
rx_done++; /* main will be polling for this value being 1 */
}
unsigned int * mac_rev = (unsigned int *)TRIPLE_SPEED_ETHERNET_BASE;
unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C);
unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200);
unsigned int * mac_phy_reg_17 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200+ 17*4);
char rx_buf;
char tx_buf;
int i;
void init_phy()
{
* mac_phy_addr = 1;
* mac_phy_reg_addr_base = * mac_phy_reg_addr_base | 0x8000;
//*mac_phy_reg_addr_base = *mac_phy_reg_addr_base | 0x1000;
}
int main()
{
init_phy();
alt_printf("control register is %x\n", *mac_phy_reg_17);
alt_sgdma_dev * pSink = alt_avalon_sgdma_open(HITIC_SINK_NAME);
if(pSink == NULL)
{
alt_putstr("open sink error!\n");
}
alt_sgdma_dev * pSource = alt_avalon_sgdma_open(HITIC_SOURCE_NAME);
if(pSource == NULL)
{
alt_putstr("open source error!\n");
}
/**************************************************************
* Register the ISRs that will get called when each (full) *
* transfer completes *
************************************************************/
alt_avalon_sgdma_register_callback(pSource, &tx_callback_function,
(ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK),
NULL);
alt_avalon_sgdma_register_callback(pSink, &rx_callback_function,
(ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK),
NULL);
/**************************************************************/
alt_sgdma_descriptor sinkDesc, sourceDesc;
alt_sgdma_descriptor nextSinkDesc, nextSourceDesc;
nextSinkDesc.control = 0;
nextSinkDesc.control = 0;
alt_avalon_sgdma_construct_stream_to_mem_desc(&sinkDesc, &nextSinkDesc,
(alt_u32 *)rx_buf, 100, 0);
alt_avalon_sgdma_construct_mem_to_stream_desc(&sourceDesc, &nextSourceDesc,
(alt_u32 *)tx_buf, 100, 0, 0, 0, 0);
for(i = 0; i < 6; i ++)
{
tx_buf=0xff;
}
for(i = 6; i < 12; i ++)
{
tx_buf=0x11;
}
tx_buf = 0;
tx_buf = 100;
// while(1)
// {
// alt_avalon_sgdma_do_async_transfer(pSource, &sourceDesc);
// while(tx_done == 0) {}
// alt_putstr("The transmit SGDMA has completed\n");
// tx_done = 0;
// for(i = 0; i < 10000000; i++);
// }
while(1)
{
alt_avalon_sgdma_do_async_transfer(pSink, &sinkDesc);
while(rx_done == 0) {}
alt_putstr("The receive SGDMA has completed\n");
rx_done = 0;
}
16 Replies
- Altera_Forum
Honored Contributor
Transmit should always work. CHeck with signal tap both the avalon stream interface and the PHY side signals, to check where the transfer is stopped.
For reception you should configure the MAC with a MAC address, or set it in promiscuous mode, or most of the packets will be filtered and never transmitted to the DMA. You should also check if the PHY needs any initialization. Is there any reason why you don't use an OS with a tcp/ip stack? - Altera_Forum
Honored Contributor
I can only use the on chip mem ,so I have not enough space to run os, an I alse need not to use a tcp/ip.
I just found that only when I unchecked the Aligned packet headers to 32-bit boundary and check SG DMA's Allow unaligned transfers ,I could send data to computor. When received data from computor , after the first packet TSE's start of packet signal always high and sink in ready was always low. The first packet 's data also was not correctly all . what's the problem maybe, please give me some advice ,thanks. - Altera_Forum
Honored Contributor
if the sink ready signal is low it means that the DMA can't receive more data. Check all the signals around the DMA to verify that it got its descriptor and isn't stuck in a memory operation.
- Altera_Forum
Honored Contributor
I have got the problem ,and it works OK now. there are three problem :
1. I didn't initial the TSE properly ,command_config needed to configure and enable sending and receiving . 2. I used the asynchronous transfer of sgdma, I find the synchronized transfer works OK, but the asynchronous transfer would encounter some error after just less ten transfers. I don't know why . 3. If I checked the Align packet headers to 32-bit boundaries in sopc builder ,It did not work at all. For the problems above ,would you give me some advices, thanks sincerely hjh - Altera_Forum
Honored Contributor
2) it depends on your code. When using asynchronous transfers you must be very careful with synchronization, you mustn't modify the descriptor before the transfer is finished.
3) it should work also without the alignment. Just check that you are sending a correct Ethernet packet when you don't use the alignment (i.e. without the two padding bytes before the Ethernet header). - Altera_Forum
Honored Contributor
Hello, hujianhua (http://www.alteraforum.com/forum/member.php?u=35796)
First of all I tryied to use TSE with InterNich tcp/ip stack (SSS example). And I found that tse_mac_init was called somewhere inside alt_iniche_init() and netmain(): I can see link, speed and other information in console, and all works fine. But I do not really need OS + tcp/ip stack using for some reasons. So I tryied to use TSE and SGDMA in the same way as you did. I unchecked the Aligned packet headers to 32-bit boundary and checked SGDMA's Allow unaligned transfers in SOPC builder. When I runned code you posted above, nothing happened. I tryied to use async and sync transmitt also... I didn't see any TSE output (trying to observe mdio_out signal of tse with SignaltapII). The only message in console was "Control register is ffff". Is it correct value? How can I configure command_config to enable send/receive of TSE? - Altera_Forum
Honored Contributor
--- Quote Start --- Hello, hujianhua (http://www.alteraforum.com/forum/member.php?u=35796) First of all I tryied to use TSE with InterNich tcp/ip stack (SSS example). And I found that tse_mac_init was called somewhere inside alt_iniche_init() and netmain(): I can see link, speed and other information in console, and all works fine. But I do not really need OS + tcp/ip stack using for some reasons. So I tryied to use TSE and SGDMA in the same way as you did. I unchecked the Aligned packet headers to 32-bit boundary and checked SGDMA's Allow unaligned transfers in SOPC builder. When I runned code you posted above, nothing happened. I tryied to use async and sync transmitt also... I didn't see any TSE output (trying to observe mdio_out signal of tse with SignaltapII). The only message in console was "Control register is ffff". Is it correct value? How can I configure command_config to enable send/receive of TSE? --- Quote End --- hi, Forester, I configured the TSE as : unsigned int * mac_addr0 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x00C); unsigned int * mac_addr1 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x0010); unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C); unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200); unsigned int * mac_command_configure = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x008); * mac_addr0 = 0x17231c00;//the mac address * mac_addr1 = 0x0000cb4a;//the mac address * mac_command_configure = *mac_command_configure | 0x2000; //reset TSE for(i = 0; i < 10000000; i++); * mac_command_configure = *mac_command_configure | 0x00800233;//configure use the configure above can enable the TSE trans, you can look up the detail information from Triple speed ehternet user guide. you can contact me by [email protected] - Altera_Forum
Honored Contributor
unsigned int * mac_rev = (unsigned int *)TRIPLE_SPEED_ETHERNET_BASE;
unsigned int * mac_command_configure = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x008); unsigned int * mac_addr0 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x00C); unsigned int * mac_addr1 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x0010); unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C); unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200); unsigned int * mac_phy_reg_17 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200+ 17*4); * mac_addr0 = 0x17231c00; * mac_addr1 = 0x0000cb4a; * mac_command_configure = *mac_command_configure | 0x2000; //reset TSE for(i = 0; i < 10000000; i++); * mac_command_configure = *mac_command_configure | 0x00800233; - Altera_Forum
Honored Contributor
Hello,
Here is test code: /* These will gate the data checking near the end of main */ volatile alt_u8 tx_done = 0; volatile alt_u8 rx_done = 0; void tx_callback_function(void * context) { tx_done++; /* main will be polling for this value being 1 */ } void rx_callback_function(void * context) { rx_done++; /* main will be polling for this value being 1 */ } // Base configuration register unsigned int * mac_addr0 = (unsigned int *)(TSE_BASE + 0x00C); // mac0 unsigned int * mac_addr1 = (unsigned int *)(TSE_BASE + 0x010); // mac1 // mdio_addr0 register unsigned int * mac_phy_addr = (unsigned int *)(TSE_BASE + 0x03C); // Command configuration register unsigned int * mac_command_configure = (unsigned int *)(TSE_BASE + 0x008); // MDIO Space 0 (map to PHY device 0) unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TSE_BASE + 0x200); // ( PHY = DP8384I ) // PHY basic mode control register unsigned int * mac_phy_reg_0 = (unsigned int *)(TSE_BASE + 0x200); // PHY mode status register unsigned int * mac_phy_reg_1 = (unsigned int *)(TSE_BASE + 0x200 + 1 * 4); // PHY status register unsigned int * mac_phy_reg_10 = (unsigned int *)(TSE_BASE + 0x200 + 10 * 4); // PHY control register unsigned int * mac_phy_reg_19 = (unsigned int *)(TSE_BASE + 0x200 + 19 * 4); char rx_buf[1800]; char tx_buf[1800]; void init_phy() { # define PHY_RESET 0x8000 # define PHY_AUTONEG_ENA 0x1000 long i; *mac_phy_addr = 0x01; // associate MAC with with PHY addr = 0x01 *mac_phy_reg_0 = *mac_phy_reg_0 | PHY_AUTONEG_ENA; # define AUTO_MDIX 0x8000 *mac_phy_reg_19 = *mac_phy_reg_19 | AUTO_MDIX; } void init_tse() { *mac_addr0 = 0x17231c00; // set MAC = *mac_addr1 = 0x0000cb4a; // 00-1c-23-17-4a-cb # define TX_ENA 0x00000001 # define RX_ENA 0x00000002 # define PROMIS_EN 0x00000010 # define PAD_EN 0x00000020 # define TX_ADDR_INS 0x00000200 # define SW_RESET 0x00002000 # define CTR_FRM_ENA 0x00800000 *mac_command_configure = *mac_command_configure | SW_RESET; // Reset while ( *mac_command_configure & SW_RESET ) // wait for reset complete alt_putstr("reset in progress\n"); *mac_command_configure = *mac_command_configure | PROMIS_EN; *mac_command_configure = *mac_command_configure | PAD_EN; *mac_command_configure = *mac_command_configure | TX_ADDR_INS; *mac_command_configure = *mac_command_configure | CTR_FRM_ENA; *mac_command_configure = *mac_command_configure | RX_ENA; *mac_command_configure = *mac_command_configure | TX_ENA; } int main() { int i; init_tse(); alt_printf("command_cfg register is %x\n", *mac_command_configure); init_phy(); for(i = 0; i < 10000000; i++); alt_printf("PHY mode status is %x\n", *mac_phy_reg_1); alt_printf("PHY status is %x\n", *mac_phy_reg_10); alt_printf("PHY control is %x\n", *mac_phy_reg_19); alt_sgdma_dev * pSink = alt_avalon_sgdma_open(SGDMA_RX_NAME); if(pSink == NULL) alt_putstr("open sink error!\n"); else alt_putstr("sink was opened\n"); alt_sgdma_dev * pSource = alt_avalon_sgdma_open(SGDMA_TX_NAME); if(pSource == NULL) alt_putstr("open source error!\n"); else alt_putstr("source was opened\n"); /************************************************************** * Register the ISRs that will get called when each (full) * * transfer completes * ************************************************************/ alt_avalon_sgdma_register_callback(pSource, &tx_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); alt_avalon_sgdma_register_callback(pSink, &rx_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); /**************************************************************/ alt_sgdma_descriptor sinkDesc, sourceDesc; alt_sgdma_descriptor nextSinkDesc, nextSourceDesc; nextSinkDesc.control = 0; nextSourceDesc.control = 0; alt_avalon_sgdma_construct_stream_to_mem_desc(&sinkDesc, &nextSinkDesc, (alt_u32 *)rx_buf, 100, 0); alt_avalon_sgdma_construct_mem_to_stream_desc(&sourceDesc, &nextSourceDesc, (alt_u32 *)tx_buf, 100, 0, 0, 0, 0); for(i = 0; i < 6; i ++) { tx_buf = 0xff;}
for(i = 6; i < 12; i ++)
{
tx_buf = 0x11; } tx_buf[12] = 0; tx_buf[13] = 100; while(1) { //alt_avalon_sgdma_do_async_transfer(pSource, &sourceDesc); alt_avalon_sgdma_do_sync_transfer(pSource, &sourceDesc); while(tx_done == 0) {} alt_putstr("The transmit SGDMA has completed\n"); tx_done = 0; } } As a result, I see only command_cfg register is 800233 PHY mode status is 7869 PHY status is 0 PHY control is 0 sink was opened source was opened and nothing is transmitted via tse. Is it important, tse or phy is inited earlier?
- Altera_Forum
Honored Contributor
Does the Nios CPU have a data cache? If yes, then it is possible that the values you set aren't written to the TSE, but just in the data cache instead. You can try and disable the data cache, use some IOWR/IORD macros to write the TSE registers, use uncached pointers (set bit 31 in the address) or flush the data cache once you are done configuring the TSE, and invalidating it before reading the PHY registers.