This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294 CRC completion interrupt on Software DMA channel does not appear

Other Parts Discussed in Thread: TM4C1294NCPDT, SEGGER

DEVICE: TM4C1294NCPDT Silicon Rev3.

DMA channel 6 has been mapped to software (encoding 0x05), and after being started using DMASWREQ, sends a 16 byte sequence to the CRC module. The computed answer is correct, the DMA finishes correctly but no end of software DMA interrupt is generated. The interrupt handler is never called. IRQ44 has been enabled and if I 'manually' provoke the interrupt handler by loading the SWTRIG with software DMA interrupt number 44 the handler is called and it executes as expected.

There's no mention in the Errata for anything related. And the data sheet confirms that the end of CRC DMA should generate an interrupt.

So I was wanting to check a couple of things before posting code:
1) That the end of DMA to the CRC module interrupt is possible, the data sheet suggests it is.
2) As the interrupt was software instigated that the end of transfer interrupt does actually appear on Software DMA channel 44.

  • Hello Pete

    Can you please share the UDMA Configuration Code for Interrupt, the startup vector file?

    Regards
    Amit
  • project_file.zip

    Hello Amit,

    I've attached the BIN file as the vector table is in it. And you mentioned the BIN file being good.

    I also remember you saying that problems were much easier to investigate if they occur within 10mS of start up. So I've stripped down the application to only leave code that exhibits the problem. Total length is now 433 machine cycles. Clock rate is launchpad default.

    A bit of info that may help Amit - a brief guide to program flow......

    From RESET

    Vector table left at default position.

    SUBROUTINE:Initialise GPIO module (full reset and wait for module to be available, enables PF1 & PF2 for scope triggers)

    SUBROUTINE:Initialise CRC module (full reset and wait for module to be available, then basic CRC module configuration)

    SUBROUTINE:Initialise DMA module (full reset and wait for module to be available, enables DMA module and programs DMA control table base address)

    SUBROUTINE:Setup of DMA CH6 to load CRC, Sets DMA channel to software only, channel mapping, priority,enables primary structure, burst only.

    Copies ROM based test pattern to be CRCed of 16No 0xFF to RAM buffer.

    Clears any CH44 pending IRQ

    Enables CH44 IRQ

    SUBROUTINE:Send data to CRC (Zeros CRC seed, Sets up source and end pointers for DMA, Sets up control word mode=AUTO, enables DMA CH6, generates DMA start request)

    END OF CODE.

    If the uDMA handler is ever entered it sets pin PF2 high. I assume it's a sequencing problem, but have run out of datasheet information I think.

  • Hello Pete

    Would be needing the data on clock source as well?

    Regards
    Amit
  • Hello Amit,
    The clock source is the 25Mhz main oscillator. The PLL is not used. Anything in the way of clock source selection is the device power-on default. Is that what you mean?


    EDITED TO ADD: Just realised that in the code uploaded it will still be on PIOSC from reset as the original PLL enabling code was removed in the strip down. So it'll be on PIOSC.

  • Hello Pete

    Even better. PIOSC as clock source is preferred for such cases. Also you mentioned ROM based data pattern. Do you mean data patterns in Flash?

    Regards
    Amit
  • Sorry, yes, I meant Flash, not ROM.

    The 16 byte (all 0xFF) data pattern is intially in Flash and the application copies it to RAM prior to transfer to the CRC module, as the DMA won't DMA from Flash.

  • Hi Pete,

    Several @ my tech firm very much liked this posting.   Perhaps your thread can serve as a good model for others - we believe it very well qualifies, due to:

    • 7:02 an opening narrative clearly describes your program's objective - along w/a detailed description of where it stutters.   So far beyond the (usual) "Hey - my Tiva "Does NOT Work!"  (Period - the End!)   Staff/I believe that Amit's human - being bombarded w/"failing" code blurbs all day - cannot be fun.   The narrative makes your post far more understandable - and vastly more compelling.
    • 9:00 here you made the time/effort to clearly list the program's goals & execution sequence.  Again great.   At my firm we enforce just such a rule - if we don't make the time/effort to clarify our objective - we have reduced our chances for success - and "guaranteed" that our time expenditure will increase!

    Amit's beyond busy - if & when he "comes up for air" - staff/I would love to know if he was as impressed w/your posting as were we.   Well done, Pete...

  • Hello cb,
    I do try to summarise the problem in the least space, with the least ambiguity, and with the smallest code footprint that demonstrates the problem, as others have to look at it and that will aid them to do so. I also try to title the thread and add tags specifically relevant to that which others may search on in the future. To make them as machine searchable as possible.

    After all, we are now in a world where, in the blink of an eye, if you get your search right, and the material is available with sufficient keywords present, that a problem could be answered straight away. And often is. Unfortunately this one persists despite extensive datasheet reading, and (and you might need to sit down before reading this cb) even a read through the latest Tivaware. But a relevant example I couldn't find. Nor could I find a previous related forum post.

    I was thinking the other day, having read some of those 'hey my thingy doesn't work' posts that the forum could do with a simple template that a poster could fill out that establishes the basics from the word go. Even things so basic as:
    1) Complete device part number.
    2) Silicon rev.
    3) Clock source.
    4) Have you read Errata yes/no
  • Yes Pete - you are "Preaching to the chorus!"

    More than Two years past I produced such a, "Guidelines for Forum Postings." Amit was kind enough to apply "sticky status" and over 1,000 "hits" (and many replies) ensued.

    Forum management was not convinced - and, "Tiva does NOT Work" echoes loudly (and too often) across this fruited plain.   (staff/I "hold our ears - and sometimes, stomachs...")   Can you say, NIH, Pete?

  • Preaching to the ones that appreciate such methods yes. I wasn't on this forum 2 years back so didn't appreciate that. That said I should read the stickies.
    I was meaning that the 'form' should be presented without choice for a new forum post and not just be a sticky. Sounds like you've already had a go at that too.
  • Indeed - that was "precisely" my suggestion - No choice - "Read, Understand & Comply" w/directions. (Has long worked well on PBS' "home repair show" - can (only) improve things here. Alas - forum Mgmt. (clearly) "knows best." (maybe...)

    After a reasonable period my post "lost" its adhesive quality - and quickly rotated off "Page 1" into dreaded, "Forum oblivion."   (along w/several thousand, "Tiva don't Work!" unguided postings)

  • Hello Pete,

    I checked the binary file and the issue is with the use of channel 6 for software transfer. Only channel 30 is dedicated for "true" software initiated transfers. If using any other channel the peripheral has to signal the dma done interrupt.

    Also you had mentioned that "as the DMA won't DMA from Flash." The DMA can read from the Flash for which the Internal memory registers need to be configured.

    Regards
    Amit
  • Dear Amit,

     Thankyou for that, it works wonderfully. Again something you can't tell from the datasheet, you look at the channel table and think you have free rein. I'd picked channel 6 to raise its priority. Now the CRC scheduling works and I can see precisely how it slots in with the other running DMA channels I don't need to raise it, in fact I need to demote it now, so something else slower starts before it and then the controller fills in as it arbitrates. For some tasks, the real power of this device is not in the CPU, it's in the DMA controller.

    Discussion of the DMA_done signal appears every so often on forum posts going back quite a way. Be great to see more info on this in any revised datasheet. I know it's an inner module signal but it comes into play every so often in explanations of the workings. And in the CRC module you don't have peripheral DMA specific flags like many of the other modules have.

    Thankyou for the tip on DMAing from flash. I'd seen this fault in practice and then come across a post way back of one of the TI employees I think mentioning that it had to be from RAM, so I'd not looked any further on that one.

    Pete

  • Hello Pete

    When DMA needs to access the flash there are 3 registers that need to be setup. These are the internal memory register FLASHDMASZ and FLASHDMAST at 0x400FDFD0 and 0x400FDFD4 and the FLASHPP register for setting the DFA bit. Onc these are setup a DMA access to Flash will not generate a Bus Fault. Note that this is only read access that is allowed to the flash from the DMA.

    Regards
    Amit
  • Hello Amit,

     Ah yes, these are obvious when you look for them, but in currently having mixed fixed and variable data I'd just copied the whole lot to RAM first. The ability to DMA will be useful for future packet building. Thankyou for that.

  • Hello Pete,

    Knowing the size of fixed and variable data that is stored on the on-chip flash should not be difficult?

    Regards
    Amit
  • Hi Amit,
    Not sure what you meant by that, but currently the packets being sent were partially fixed data, partially computed data and the rest was variable. This works well for the current process. So I'd just copied the fixed data into RAM and gather DMA derives the rest. But to be able to DMA from flash would is very useful for things like, say, fixed pattern generation from DACs where the header can be combined with table based pre-programmed patterns and DMA will sew it all together.
    Pete
  • Hello Pete

    Sounds like Memory Scatter Gather implementation.

    Regards
    Amit
  • Hi Amit,
    It would be if it was purely internal, but it is actually Peripheral Gather DMA as it generates SPI packets. Peripheral Gather has proved so flexible that there was no need to use another process to setup the data to be transmitted first, then DMA it out.
  • Hello Pete,

    I think Peripheral Scatter Gather can achieve the same. Let me see if I have a code base which shows how to mix memory and peripheral transfers.

    Regards
    Amit
  • Hi Amit,
    Reading various old posts about DMA it would seem that the different modes can be mixed. Bit I've never tried it yet. I would guess that the mode is mixed on the alternate tasklist 'stack'.
    When I was troubleshooting I found one method, in ScatterGather DMA with alternate modes, was to initally set the primary mode to AUTO and then run it. The DMA doesn't happen but it loads the alternate task into the control structure and then quits. It's an easy way to verify that the first alternate task loads correctly. You can check whichever of the tasks you need to by modifying the primary XFERSIZE in steps of 4.
    One thing I did find, was that in memory ScatterGather you seem to have to set the last task to AUTO so it self completes, but Peripheral scatterGather works only if the mode is set to 0x07 for all the alternate tasks. Set it to AUTO and it misses the last task.
  • Hello Pete

    The Scatter Gather is seldom used due to the complicated method (though explanation makes it sound simple). There can be different task type in the alternate structure but then not all options converge.

    Anyways my search of code base turned empty. So guess, I need to create the code and your use case seems interesting to make a pseduo use case for Peripheral Scatter Gather with memory transfers,

    Regards
    Amit
  • Hello Amit,

     You mentioned earlier in the thread that there were 3 registers needing to be setup to be able to DMA direct from flash. "FLASHDMASZ and FLASHDMAST at 0x400FDFD0 and 0x400FDFD4 and the FLASHPP register for setting the DFA bit." I thought I'd update the application to DMA straight from flash, but it doesn't work.

    FLASHDMASZ and FLASHDMAST, because the flash to DMA from is in the first 2KB of space are both zero at reset anyway, but I set them up regardless.

    FLASHPP containing the DFA bit is read-only going by the datasheet. I assume DFA status is the result of protection checking for DMA access in the address space setup with FLASHDMASZ and FLASHDMAST? The datasheet also says that DFA needs to be '1' before FLASHDMASZ can be programmed. DFA appears to always be '1'.

    Is there something else that needs to be setup for DMAing direct from flash?

    I also note MEM#13 in the errata. EEPROM is not used, but how do I disable the EEPROM to test it?

    What I see is expected behaviour DMAing from RAM to SSI1, but spurious data when sending from flash. The only difference in the two sets of code is a single pointer.

    I can upload you a test program for a launchpad if need be.

  • Hello Pete

    Performing the following operations allows me to transfer data between the Flash and Peripheral.

       HWREG(FLASH_PP) |= FLASH_PP_DFA;

       HWREG(FLASH_DMASZ) = 0x4000;

       HWREG(FLASH_DMAST) = 0x0;

    Attached is a reference code.

    //*****************************************************************************
    //
    // sdram.c - Example demonstrating how to configure the EPI bus in SDRAM
    //           mode.
    //
    // Copyright (c) 2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    //   Redistribution and use in source and binary forms, with or without
    //   modification, are permitted provided that the following conditions
    //   are met:
    //
    //   Redistributions of source code must retain the above copyright
    //   notice, this list of conditions and the following disclaimer.
    //
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the
    //   documentation and/or other materials provided with the
    //   distribution.
    //
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "inc/hw_uart.h"
    #include "inc/hw_flash.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    // The control table used by the uDMA controller.  This table must be aligned
    // to a 1024 byte boundary.
    //
    //*****************************************************************************
    #if defined(ewarm)
    #pragma data_alignment=1024
    uint8_t pui8ControlTable[1024];
    #elif defined(ccs)
    #pragma DATA_ALIGN(pui8ControlTable, 1024)
    uint8_t pui8ControlTable[1024];
    #else
    uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
    #endif
    
    //*****************************************************************************
    //
    // A global variable to indicate that the UDMA operation is complete.
    //
    //*****************************************************************************
    volatile bool g_bEPITransferComplete;
    volatile uint32_t g_ui32SysClock;
    
    const uint8_t g_pc[34] = "This is a string of 34 characters";
    
    void
    UDMAErrorIntHandler(void)
    {
    	uDMAErrorStatusClear();
    }
    
    void
    UART0IntHandler(void)
    {
    
    	UARTDMADisable(UART0_BASE, UART_DMA_TX);
        UARTIntClear(UART0_BASE, UART_INT_DMATX);
    
    }
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
        //
        // Enable GPIO port A which is used for UART0 pins.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Configure the pin muxing for UART0 functions on port A0 and A1.
        // This step is not necessary if your part does not support pin muxing.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
    
        //
        // Enable UART0 so that we can configure the clock.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_SYSTEM);
    
        //
        // Select the alternate (UART) function for these pins.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, g_ui32SysClock);
    
        //
        // Enable the UART Interrupts
        //
        UARTIntEnable(UART0_BASE, UART_INT_DMATX);
        IntEnable(INT_UART0);
    }
    
    //*****************************************************************************
    //
    // Configure EPI0 in SDRAM mode.  The EPI memory space is setup using an a
    // simple C array.  This example shows how to read and write to an SDRAM using
    // the EPI bus in SDRAM mode and uDMA to transfer the data.
    //
    //*****************************************************************************
    int
    main(void)
    {
        //
        // Set the clocking to run at 120MHz from the PLL.
        // TODO: Update this call to set the system clock frequency your
        // application requires.
        //
        g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                                          SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // Set up the serial console to use for displaying messages.  This is
        // just for this example program and is not needed for EPI operation.
        //
        InitConsole();
    
        //
        // Set up Flash Access for DMA
        //
        HWREG(FLASH_PP) |= FLASH_PP_DFA;
        HWREG(FLASH_DMASZ) = 0x4000;
        HWREG(FLASH_DMAST) = 0x0;
    
        //
        // Now Configure the UDMA Controller to read data from SDRAM
        // NBRFIFO and then transfer it to the Write Buffer
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    
        //
        // Enable the uDMA controller error interrupt.  This interrupt will occur
        // if there is a bus error during a transfer.
        //
        IntEnable(INT_UDMAERR);
    
        //
        // Enable the uDMA controller.
        //
        uDMAEnable();
    
        //
        // Point at the control table to use for channel control structures.
        //
        uDMAControlBaseSet(pui8ControlTable);
    
        //
        // Assign the UDMA Channel for EPI RX DMA Request
        //
        uDMAChannelAssign(UDMA_CH9_UART0TX);
    
        //
        // Configure the USE BURST Feature for the channel
        //
        uDMAChannelAttributeEnable(UDMA_CH9_UART0TX, UDMA_ATTR_USEBURST);
    
        //
        // Configure the control parameters for the EPI RX.  The uDMA EPI RX
        // channel is used to transfer a block of data from the NBRFIFO to a buffer
        // in SDRAM. The data size is 32 bits.  The source address is not
        // incremented as it is coming from a FIFO. The destination increment is
        // incremented by 32 bits as it is SDRAM address space.  The
        // arbitration size is set to 8, which matches the EPI RDFIFO threshold
        //
        uDMAChannelControlSet(UDMA_CH9_UART0TX | UDMA_PRI_SELECT,
                                  UDMA_SIZE_8 | UDMA_SRC_INC_8 |
                                  UDMA_DST_INC_NONE |
                                  UDMA_ARB_1);
    
    
        uDMAChannelTransferSet(UDMA_CH9_UART0TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC,
    							   (void *)(&g_pc[0]),
    							   (void *)(UART0_BASE + UART_O_DR),
                                   sizeof(g_pc));
    
        //
        // Now the uDMA EPI RX channel is primed to start a transfer. As soon as
        // the EPIRPSTD0 register is written with a count value, it will read the
        // SDRAM and put the data in the read FIFO. When threshold has been reached
        // the EPI shall generate a DMA Request to read.
        //
        uDMAChannelEnable(UDMA_CH9_UART0TX);
    
    	UARTDMAEnable(UART0_BASE, UART_DMA_TX);
    
        //
        // Wait in while loop at the end...
        //
        while(1)
        {
        }
    }
    

    Regards

    Amit

  • Hello Amit,
    Thankyou for the information but it has had no effect. The data from flash is only partially transmitted, and the data from RAM is correctly transmitted.

    I used your settings of:

    FLASHDMASZ= 0x4000 (if my workings are correct this will set a flash region size of 80002 KB and thus easily cover the first part of the default flash range)
    FLASHDMAST= 0x0    (start flash region accessible to DMA at address zero)

    I have also tried setting the DFA bit in FLASHPP before updating FLASH_DMASZ & FLASH_DMAST and:
    a) it is already set from reset. I tried setting it again anyway, but it had no effect,

    b) the datasheet says that the DFA bit is read only, although the wording on page 649 may conflict this. ie "Note that the DFA bit must be set in the FLASHPP register before [SIZE in FLASH_DMASZ] can be programmed."

    c) trying to clear the bit doesn't do anything, suggesting that it is indeed read only.

    The settings in FLASH_DMASZ and FLASH_DMAST do actually have an effect - if the Flash start & region size settings are correct I get the first 3 bytes out of the 16 it should send transmitted out of SSI1 and these are correct. 3 out of 16 suggests the XFERSIZE in the DMA setup is incorrect but it's not. All DMA settings except the source end pointer are used to DMA the same data from RAM after its copied from flash and this works fine, all 16 bytes are correct.

    If I set the flash start address incorrectly in FLASH_DMAST to be in the 2KB block after the block in which the data to be DMAed is, then the SSI1 only transmits a single blank byte.  

  • Hello Pete,

    Is the DMA Table in SRAM?

    Regards
    Amit
  • Yes it is. And it's aligned to a 1K boundary. It starts at 0x20000000. The original gather DMA that had a problem was re-written into a standard single DMA running in basic mode in order to troubleshoot it, but it made no difference to the outcome.
  • Hello Pete,

    And when the SSI stops transmitting, what does the DMA Channel Table in SRAM show the value of the channel registers and the what does SSI address map show the value of the registers as?

    Regards
    Amit
  • SSI1 TX is on DMA CH11. After the 3bytes have been sent and the SSI TX has finished the channel words are:

    Address     Content          Notes

    0x200000B0  0x000006B7       Source end pointer. This is correct for the last byte that should be sent

    0x200000B4  0x40009008       Destination pointer. SSI TX register

    0x200000B8  0xC000C000       Control word after SSITX finished

    0xC000.C000 = 1100.0000.0000.0000..1100.0000.0000.0000

    DSTINC          31:30           Not incremental

    DSTSIZE         29:28           8bit

    SRCINC          27:26           8bit

    SRCSIZE         25:24           8bit

    reserved        23:22           00

    DSTPROT0        21              0

    reserved        20:19           00

    SRCPROT0        18              0

    ARBSIZE         17:14           0011 = 3 = 8 transfers to match FIFO

    XFERSIZE        13:4            00.0000.0000 = 0

    NXTUSEBURST     3               0

    XFERMODE        2:0             000 = 0 = stopped.

    I have previously tried changing the address alignment of the data in flash just to see if it did make a difference, but it did not.

    The above control word started as 0xC000C0F1

    The SSI1 registers after the TX ends are as follows:

  • Hello Pete,

    The configuration seems correct (except that SSIDMACTL is all 0 which I think is because the Software is clearing the bits on DONE). The transmit FIFO is also empty. I may have to create a small test code to see if configuring it as shown in the images leads to 3 or 16 transfer.

    Regards
    Amit
  • Amit,
    I have a simple version of this if it's any use to you? It's not quite reduced to a bare minimum code but it's not far off. The target is, as usual, a EK1294 launchpad and the code takes one of 2 paths (DMA from RAM, or DMA from flash) depending on whether User_switch1 is held down at reset. The only difference between the 2 flows is that it skips updating the DMA pointer depending on the switch position.
    Let me know if you want the BIN and a description.
  • By way of comparison, here's exactly the same code but user_switch1 is held down which means the DMA happens from RAM (source end pointer is '0x2000040F') . The SSI1TX is successful and the DMA CH11 control word ends the same at '0xC000C000'. However there's a difference in the SSI1 registers, shown here:

  • Hello Pete

    I ran the same use case for both Flash and SRAM and it does not complete for either of them. May be there is something different in the interrupt handler and/or the configuration on your side and on my bench. Can you please send the Interrupt Handler code?

    Regards
    Amit
  • Hello Amit,

      That's interesting. Amit, there's no interrupts active, anywhere. In the original code that had the problem there were interrupts active, and I used the handler to figure out what was causing the original fault. I shall explain......

    The investigation began when I was wondering why the byte stream being sent out of SSI TX, using a 5 task gather DMA on CH11, was being partially corrupted mid-stream. It turned out that the CRC DMA on CH30, when it completed, caused the next SSI1 FIFOs worth of data to be sent out of SSI TX (on DMA CH11) to be ended early. The SSI1 TX DMA then carried on to correctly complete the bit stream. Turning off the CRC DMA removed the problem. The DMA driven CRC computation was correct. The SSI TX stream was only missing what looked to be the later bytes of one FIFO's worth of data.

    However it only corrupted SSI TX data at SSI1 clock speeds exceeding about 1.25Mhz (1Mhz was always okay, 2Mhz would always corrupt), this was while running off the PLL at 120Mhz. So I also removed the PLL as a factor and went back to the internal 16Mhz system clock. I could reproduce the problem at various clock speeds. I could also get the system to work if I scheduled the CRC DMA to happen and complete before the SSI TX occurred, but this is no use in the final system as it needs to calculate CRC concurrently.

    The original code had interrupts active, and it was that that give me  hand to figure out what was corrupting the SSI1 TX DMA by setting a port bit in the handler. Interrupts were the first thing to be turned off and the SSI1 corruption problem remained, although the system could no longer inject the CRC computation into the SSI TX stream.

    I think that if I discover the current problem it may answer this one too.

  • Hello Pete

    I have attached my test code (have a look at it so that I can confirm that it is close to your code)

    //*****************************************************************************
    //
    // sdram.c - Example demonstrating how to configure the EPI bus in SDRAM
    //           mode.
    //
    // Copyright (c) 2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    //   Redistribution and use in source and binary forms, with or without
    //   modification, are permitted provided that the following conditions
    //   are met:
    //
    //   Redistributions of source code must retain the above copyright
    //   notice, this list of conditions and the following disclaimer.
    //
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the
    //   documentation and/or other materials provided with the
    //   distribution.
    //
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "inc/hw_ssi.h"
    #include "inc/hw_flash.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/ssi.h"
    #include "driverlib/udma.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    // The control table used by the uDMA controller.  This table must be aligned
    // to a 1024 byte boundary.
    //
    //*****************************************************************************
    #if defined(ewarm)
    #pragma data_alignment=1024
    uint8_t pui8ControlTable[1024];
    #elif defined(ccs)
    #pragma DATA_ALIGN(pui8ControlTable, 1024)
    uint8_t pui8ControlTable[1024];
    #else
    uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
    #endif
    
    //*****************************************************************************
    //
    // A global variable to indicate that the UDMA operation is complete.
    //
    //*****************************************************************************
    volatile bool g_bEPITransferComplete;
    volatile uint32_t g_ui32SysClock=16000000;
    
    const uint8_t g_pc[16] = "ABCD1234EFEF5678";
    
    void
    UDMAErrorIntHandler(void)
    {
    	while(1);
    }
    
    void
    SSI1IntHandler(void)
    {
    
    	SSIDMADisable(SSI1_BASE, SSI_DMA_TX);
        SSIIntClear(SSI1_BASE, SSI_DMATX);
    
    }
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
        //
        // Enable GPIO port A which is used for UART0 pins.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
        //
        // Enable UART0 so that we can configure the clock.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    
        //
        // Configure the pin muxing for UART0 functions on port A0 and A1.
        // This step is not necessary if your part does not support pin muxing.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinConfigure(GPIO_PB5_SSI1CLK);
        GPIOPinConfigure(GPIO_PB4_SSI1FSS);
        GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
        GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
    
        GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5);
        GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    
        SSIConfigSetExpClk(SSI1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
        		SSI_MODE_MASTER, 3750000, 8);
    
        SSIEnable(SSI1_BASE);
    
        //
        // Enable the UART Interrupts
        //
        SSIIntEnable(SSI1_BASE, SSI_DMATX);
        IntEnable(INT_SSI1);
    }
    
    //*****************************************************************************
    //
    // Configure EPI0 in SDRAM mode.  The EPI memory space is setup using an a
    // simple C array.  This example shows how to read and write to an SDRAM using
    // the EPI bus in SDRAM mode and uDMA to transfer the data.
    //
    //*****************************************************************************
    int
    main(void)
    {
    	uint32_t ui32DummyByte;
        //
        // Set the clocking to run at 120MHz from the PLL.
        // TODO: Update this call to set the system clock frequency your
        // application requires.
        //
        //g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
        //                                  SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // Set up the serial console to use for displaying messages.  This is
        // just for this example program and is not needed for EPI operation.
        //
        InitConsole();
    
        //
        // Set up Flash Access for DMA
        //
        HWREG(FLASH_PP) |= FLASH_PP_DFA;
        HWREG(FLASH_DMASZ) = 0x4000;
        HWREG(FLASH_DMAST) = 0x0;
    
        //
        // Now Configure the UDMA Controller to read data from SDRAM
        // NBRFIFO and then transfer it to the Write Buffer
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    
        //
        // Enable the uDMA controller error interrupt.  This interrupt will occur
        // if there is a bus error during a transfer.
        //
        IntEnable(INT_UDMAERR);
    
        //
        // Enable the uDMA controller.
        //
        uDMAEnable();
    
        //
        // Point at the control table to use for channel control structures.
        //
        uDMAControlBaseSet(pui8ControlTable);
    
        //
        // Assign the UDMA Channel for EPI RX DMA Request
        //
        uDMAChannelAssign(UDMA_CH11_SSI1TX);
    
        //
        // Configure the USE BURST Feature for the channel
        //
        uDMAChannelAttributeEnable(UDMA_CH11_SSI1TX, UDMA_ATTR_USEBURST);
    
        //
        // Configure the control parameters for the EPI RX.  The uDMA EPI RX
        // channel is used to transfer a block of data from the NBRFIFO to a buffer
        // in SDRAM. The data size is 32 bits.  The source address is not
        // incremented as it is coming from a FIFO. The destination increment is
        // incremented by 32 bits as it is SDRAM address space.  The
        // arbitration size is set to 8, which matches the EPI RDFIFO threshold
        //
        uDMAChannelControlSet(UDMA_CH11_SSI1TX | UDMA_PRI_SELECT,
                                  UDMA_SIZE_8 | UDMA_SRC_INC_8 |
                                  UDMA_DST_INC_NONE |
                                  UDMA_ARB_8);
    
    
        uDMAChannelTransferSet(UDMA_CH11_SSI1TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC,
    							   (void *)(&g_pc[0]),
    							   (void *)(SSI1_BASE + SSI_O_DR),
                                   sizeof(g_pc));
    
        //
        // Now the uDMA EPI RX channel is primed to start a transfer. As soon as
        // the EPIRPSTD0 register is written with a count value, it will read the
        // SDRAM and put the data in the read FIFO. When threshold has been reached
        // the EPI shall generate a DMA Request to read.
        //
        uDMAChannelEnable(UDMA_CH11_SSI1TX);
    
    	SSIDMAEnable(SSI1_BASE, SSI_DMA_TX);
    
        //
        // Wait in while loop at the end...
        //
        while(1)
        {
        	SSIDataGet(SSI1_BASE,&ui32DummyByte);
        }
    }
    

    Regards

    Amit

  • Hello Pete

    Finally got it to work. 2 changes had to be made

    1. UDMA_CH11_SSI1TX changed to UDMA_CH25_SSI1TX: I think it is the same errata as on TM4C123 for uDMA Channel Mapping
    2. UDMA_ARB_8 changed to UDMA_ARB_4: The SSI FIFO is 8 deep and generates a DMA request when 4 locations are empty.

    Regards
    Amit
  • Hello Amit,

    I've just converted my test program so it will run the SSI1 TX from either DMA Ch11 or Ch25. Both do the same thing and the problem is still there.

    I then changed it so that ARBSIZE could be either 4bytes or 8bytes, as you found in your code, and all 4 combinations of channel number and ARBSIZE could be tried. This is also didn't make any difference. I'll now try these combinations in the original application as a double check.

    Changing ARBSIZE from 8bytes to 4bytes is contrary to what you've previously recommended, and actually changing from 4 to 8 fixed a previous problem here:

    However an ARBSIZE of 4 is recommended in the TM4C1294 datasheet, as you say due to the FIFO trigger level. ??!?

    Your code is not the same as mine as mine is in assembler.

    Here is my test code but with the 4 variations as you found worked at your end, for a EK1294XL launchpad, one pair of images does the DMA from CH25, the other pair from CH11. Each then has ARBSIZE 4 or 8bytes in size.

    On reset you'll see the partial packet out of SSI1 TX as its DMAed from flash.

    PE4 is SSI1 MOSI

    PB5 is SSI1 CLK

    PB4 is in GPIO mode and used for 'manually' setting and resetting the SPI CS signal due to SPI signalling constraints

    PE5 is SSI1 MISO

    Clock source is the internal clock, PLL is not used.

    Hold launchpad user_switch1 down while reseting and you'll see the correct data packet out of SSI1TX, which is DMAed from RAM.

    The correct SSI1 TX packet is:  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F.

    DMA_SSITX_troubleshooting_images.zip

    Please let me know if you need a description for them.

  • Amit,
    Are you refering to DMA#01 in the TM4C123 errata here?
  • Hello Pete

    Did you reset the DMA controller before reconfiguration?

    Regards,
    Amit
  • In the test code there's only 1 configuration of both the DMA and the SSI1. The DMA controller is initialised like this, and in this order:

    Disable DMA module
    Reset the DMA module
    Enable DMA module
    Delay 3 system clocks after enabling the DMA module clock
    Wait for the DMA module to complete its initialisation
    Enable DMA controller
    Program DMA control table base address
  • Hello Pete

    Thanks for the bin files, I will try the same tomorrow. In the meantime, you can check using my reference CCS project (attached)

    ektm4c129_flash2ssi_udma.zip

    Regards

    Amit

  • Hello Amit,
    Your suggestion of changing the ARBSIZE to 4bytes appears to have fixed the problem. So some of the DMA tasks work well with ARBSIZE=8bytes (as we've investigated previously) and some work well with ARBSIZE=4bytes (as per the actual datasheet). If you do find out why the DMA from flash wasn't working it'd be interesting to know. I never got that to work but it's a minor issue to me, DMA from RAM is the important bit.

    For the record this was the setup and the issue seen, and what cured it -
    The DMA channel setup:

    CH11 SSI1 TX, Mode Gather 0x06
    CH24 SSI1 RX, Mode Basic 0x01
    CH30 CRC module, Mode Auto 0x02

    All 3 channels DMA to/from RAM.

    Clock source: PLL 120MHz.

    DMA channel Sequencing:
    DMA CH24 enabled 1st. Immediately after that DMA CH11 is enabled. CRC DMA on CH30 is enabled last shortly afterwards.

    If ARBSIZE for DMA CH11 gather (alternate task, not the primary) is set to 0x03 (ie 8bytes), SSI1 TX transmits:
    Task1 (1byte). Okay
    Task2 (128bytes) Fails. First 12 bytes are correct, then 4bytes missing, then it continues and completes correctly.
    Task3 (2bytes). Okay
    Task4 (4bytes). Okay
    Task5 (2bytes). Okay

    When DMA CH30 for the CRC completes, the next FIFO load for DMA CH11 seems to be truncated.

    The byte count at which the SSITX fails I don't think is significant, as I can move it about by changing the scheduling of CH30.
    Turning off DMA CH30 for the CRC stops the SSI1TX corruption. There is a completion IRQ for this channel but removing it, and indeed all IRQs, doesn't make a difference to the corruption of SSI1TX.

    When, ARBSIZE for DMA CH11 gather (alternate task, not the primary) is set to 0x02 (ie 4bytes), SSI1 TX transmits okay for all bytes with DMA CH30 active.

    The only thing being changed between working and non-working version is ARBSIZE which is set up once and then stored into each CH11 task control word, as the task list is constructed.

    The CCS setup wasn't much use I'm afraid. v6 doesn't support the Segger Jlink, and the onboard USB has been disabled as it's not as reliable as the Jlink. I have CCS v5.5 still, but it was faster to solve the issue at hand than to set that up properly and learn how to use it. Unfortunately CCS is slow and and somewhat unstable at times too.