SAM V71 XDMAC : Circular buffering? One doc error, Problems with End of Block Interrupt (Handler Lock-up) when using a linked list

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So first thing,

V71 Manual page 517 states :

 • BLEN: Channel x Block Length The length of the block is (BLEN+1) microblocks.

This is incorrect - the value you need to program in the register is BLEN - 1. I have tested this over and over with different values and it's BLEN - 1. i.e: 

mbr_bc = XDMAC_CBC_BLEN(value); where your number of microblocks per block - 1 is the value.

 

Problem 2 : Trying to circular buffer and using the 2 Blocks consisting of 2 microblocks each (4 uBlocks), and 2 descriptors in a linked list. The linked list is of the form LLView3, so that I can actually use a descriptor which defines the BLEN each time. Linked list LIE is not enabled, because a circular list never ends. BIE is enabled so that I can get a "half-interrupt" after the first 2 uBlocks (Block 1), and a complete interrupt after the second the last 2 uBlocks (Block 2), and start all over. 

 

The first time through, the interrupt is entered, only two uBlocks are written, and when debugging, sometimes I see the third uBlock if the interrupt wasn't triggered fast enough - it completes the transfer. The problem is that after this, the BIS status bit remains permanently set as long as the DMA channel is engaged. Hardware is not clearing Block Interrupt Status bit when the interrupt is exits, it's a read-only bit, and it essentially hangs in the Handler until the channel is disengaged. I have proven this by setting breakpoints on a simple short loop in the main body of code, and they're never hit until the channel is turned off. I had to set the interrupt priority of my switch to be higher than the DMA transfer so that it would actually turn off the DMA channel. 

 

Here is the code if anyone can shed some light on what setting I might need to adjust... 

    pmc_enable_periph_clk(ID_XDMAC);

 

    /* Initialize channel config */
    xdmac_channel_cfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN //Synchronize with peripheral (Bi-directional)
    | XDMAC_CC_MBSIZE_SINGLE    //Memory Burst is single 
    | XDMAC_CC_DSYNC_PER2MEM    //Peripheral to Memory
    | XDMAC_CC_CSIZE_CHK_1        //Channel x Chunk size... 1 Data Transferred? 
    | XDMAC_CC_DWIDTH_HALFWORD  //16-bit transfer per transfer
    | XDMAC_CC_SIF_AHB_IF1        //bus 
    | XDMAC_CC_DIF_AHB_IF0        //bus
    | XDMAC_CC_SAM_FIXED_AM        //Source fixed Address (The peripheral)
    | XDMAC_CC_DAM_INCREMENTED_AM //Destination Address Increments by DWIDTH Setting
    //| XDMAC_CC_DAM_UBS_AM //<-- SUBSTITUTE TO SEE IF IT UPDATES BOUNDARIES
    | XDMAC_CC_PERID(33);        //Peripheral ID #

    //xdmac_channel_cfg.mbr_bc = XDMAC_CBC_BLEN(3);
    xdmac_configure_transfer(XDMAC, XDMA_CH_SSC_RX, &xdmac_channel_cfg);
    

    /* Initialize linked list descriptor */
    src = &AudioRxBuffer[0];
    
    for(i = 0; i < TOTAL_BLOCKS; i++) {

        linklist_read[i].mbr_ubc = XDMAC_UBC_NVIEW_NDV3
        | XDMAC_UBC_NDE_FETCH_EN | XDMAC_UBC_NSEN_UPDATED | XDMAC_UBC_NDEN_UPDATED | //Added NDEN...
         XDMAC_CUBC_UBLEN(MICROBLOCK_LEN);

        linklist_read[i].mbr_sa  = (uint32_t)&(SSC->SSC_RHR);
        linklist_read[i].mbr_da = (uint32_t)(src);
        linklist_read[i].mbr_bc = XDMAC_CBC_BLEN(1); //Number of blocks -1....
        //linklist_read[i].mbr_dus = MICROBLOCK_LEN;
        linklist_read[i].mbr_cfg = XDMAC_CC_TYPE_PER_TRAN //Synchronize with peripheral (Bi-directional)
        | XDMAC_CC_MBSIZE_SINGLE    //Memory Burst is single
        | XDMAC_CC_DSYNC_PER2MEM    //Peripheral to Memory
        | XDMAC_CC_CSIZE_CHK_1        //Channel x Chunk size... 1 Data Transferred?
        | XDMAC_CC_DWIDTH_HALFWORD  //16-bit transfer per transfer
        | XDMAC_CC_SIF_AHB_IF1        //bus
        | XDMAC_CC_DIF_AHB_IF0        //bus
        | XDMAC_CC_SAM_FIXED_AM        //Source fixed Address (The peripheral)
        | XDMAC_CC_DAM_INCREMENTED_AM //Destination Address Increments by DWIDTH Setting
        //| XDMAC_CC_DAM_UBS_AM //<-- SUBSTITUTE TO SEE IF IT UPDATES BOUNDARIES
        | XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_SSC_RX);        //Peripheral ID #
        
        if ( i == (TOTAL_BLOCKS - 1)) {
            linklist_read[i].mbr_nda = (uint32_t)&linklist_read[0];
            } else {
            linklist_read[i].mbr_nda = (uint32_t)&linklist_read[i + 1];
        }

        src += MICROBLOCK_LEN * 2; //THIS WAS JUST MICOROBLOCK LEN ---> CAN I FORCE THE ADRESS TO INCREASE?
    } //SET XDMAC
    //XDMAC_CBC_BLEN(value) ((XDMAC_CBC_BLEN_Msk & ((value) << XDMAC_CBC_BLEN_Pos)))
    //THe channel is XDMA_CH_SSC_RX ....
    xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_SSC_RX, XDMAC_CNDC_NDVIEW_NDV3 |
    XDMAC_CNDC_NDE_DSCR_FETCH_EN | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED);

    xdmac_channel_set_descriptor_addr(XDMAC, XDMA_CH_SSC_RX, (uint32_t)(&linklist_read[0]), 0);
    xdmac_enable_interrupt(XDMAC, XDMA_CH_SSC_RX);
    xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_SSC_RX, XDMAC_CIE_BIE); //changed Flag from XDMAC_CIE_LIE to CIE_BIE

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The bit won't clear unless you read the interrupt status register. 

 

uint32_t dma_status;

 

dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_SSC_RX);

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes your right about the typo it should be BLEN-1