Altera_Forum
Honored Contributor
15 years agoStream-to-memory SGDMA does not write last QWord during a transfer
Hi all!
I am trying to perform a very simple transfer from an Avalon-ST bus to a memory. For this, I use the Stream-to-memory SGDMA. I make up a descriptor chain that contains only 1 descriptor. Descriptor and destination data buffer are statically allocated (declared as variables). I took care to set the destination data buffer to a 64-bit boundary address. Here is the software: --- Quote Start --- # include <stdio.h> # include <errno.h> # include <string.h> // Headers for accessing and configuring SGDMA devices and descriptors # include <altera_avalon_sgdma.h> # include <altera_avalon_sgdma_descriptor.h> # include <altera_avalon_sgdma_regs.h> // Copied from altera_avalon_tse.h # define IORD_ALTERA_SGDMA_DESC_STATUS(base) (((IORD(base, 0x7)) >> 16) & 0xFF) # define IORD_ALTERA_SGDMA_DESC_WRITE_ADDR(base) (IORD(base, 0x2) & 0xFFFFFFFF) # define IORD_ALTERA_SGDMA_DESC_ACTUAL_BYTES_TRANSFERRED(base) (IORD(base, 0x7) & 0xFFFF) # define BUFFER_SIZE 4096 alt_u8 buffer[BUFFER_SIZE + 7]; alt_sgdma_descriptor descriptor; void SGDMA_isr(void * context) { // Read SGDMA status fprintf(stdout, "SGDMA status: 0x%02X\n", IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_BASE)); // Read descriptor status fprintf(stdout, "descriptor status: 0x%02X\n", IORD_ALTERA_SGDMA_DESC_STATUS(&descriptor)); // Read write address fprintf(stdout, "write address: 0x%08X\n", IORD_ALTERA_SGDMA_DESC_WRITE_ADDR(&descriptor)); // Read actual bytes transfered fprintf(stdout, "actual bytes transfered: %i\n", IORD_ALTERA_SGDMA_DESC_ACTUAL_BYTES_TRANSFERRED(&descriptor)); } int main(int argc, char ** argv) { alt_u8 * aligned_buffer = (alt_u8 *) (8 * ((((alt_u32) buffer) + 7) / 8)); alt_sgdma_dev * SGDMA_device; alt_u8 error_code; // Open SGDMA device SGDMA_device = alt_avalon_sgdma_open(SGDMA_NAME); if (SGDMA_device == NULL ) { fprintf(stderr, "ERROR: Cannot open '%s' SGDMA device (error code %d: %s)\n", SGDMA_NAME, errno, strerror(errno)); return -1; } // Register callback alt_avalon_sgdma_register_callback( SGDMA_device, (alt_avalon_sgdma_callback) &SGDMA_isr, (ALTERA_AVALON_SGDMA_CONTROL_IE_ERROR_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK), NULL[/INDENT][/INDENT][/INDENT][/INDENT] ); // Build descriptor chain alt_avalon_sgdma_construct_stream_to_mem_desc(&descriptor, NULL, (alt_u32 *) aligned_buffer, 0, 0); // Start SGDMA error_code = -alt_avalon_sgdma_do_async_transfer(SGDMA_device, &descriptor); if (error_code) { fprintf(stderr, "ERROR: Cannot start SGDMA device (error code %d: %s)\n", error_code, strerror(error_code)); return -1; } // Infinite loop while (1); fprintf(stderr, "ERROR: This code should never be executed\n"); return 0;[/INDENT] } --- Quote End --- This system suffers from several things: - It only receives 1 packet from the Avalon-ST bus since SGDMA is not restarted in ISR - I do some printf in the ISR - I use global variables so that they are accessible from both main and the ISR instead of using a context but this is no problem since I am still in the process of debugging. When I run the system and send a packet through the Avalon-ST, I get the following traces: --- Quote Start --- nios2-terminal: connected to hardware target using JTAG UART on cable nios2-terminal: "USB-Blaster [USB 6-1.2]", device 1, instance 0 nios2-terminal: (Use the IDE stop button or Ctrl-C to terminate) SGDMA status: 0x0E descriptor status: 0x80 write address: 0x0800F2A8 actual bytes transfered: 40 --- Quote End --- which is normal : - bits active in SGDMA status correspond to EOP_ENCOUNTERED, DESCRIPTOR_COMPLETED and CHAIN_COMPLETED - bit active in descriptor status corresponds to TERMINATED_BY_EOP - actual_bytes transfered = 40 is the correct size of the packet I sent on the Avalon-ST bus Unfortunatly, when I dump the destination data buffer, I see that the last 8-byte word of the packet was not written. So I use signaltap and looked at the SGDMA signals. Here are the waves (http://img8.imageshack.us/img8/396/sgdmahwbug.png): http://img8.imageshack.us/img8/396/sgdmahwbug.png As can be seen, after each valid 8-byte word on the Avalon-ST bus, the SGDMA performs a write on its DMA interface with the corresponding data (except bytes have been reordered) and byte-enable = "11111111". Address starts from 0x0800F2A8 (which I checked to be the address of the destination data buffer) and then is incrmented by 8 after each write. After the last word of the packet is received, ready is deasserted because the SGDMA has some work to do, starting with updating the descriptor status. So on cycle 28, the SGDMA performs a write on its descriptor interface, at address 0x0800F2A4 (which I checked to be the address of the descriptor "control", "status" and "actual_bytes_transferred" fields). So we have status = 0x80 and actual_bytes_transferrede = 0x0028 = 40, which is correct. The problem is that when the SGDMA writes the last word of the packet (cycle 21), that was flagged with EOP, the signal byte-enable is not set to "11111111" as for the previous words, it remains at "00000000". That's why the last word is not written into the memory. This looks like a bug in the SGDMA to me, because I think i did everything right, plus the SGDMA itself thinks it has transfered 40 bytes since it sets actual_bytes_tranferred to 40. Has anyone been confronted to this? Is it due to the fact that there are cycles with valid = 0 in the middle of the packet ? Has it been corrected? Am I wrong? Thanks a lot! - Julien