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.

LM4F120 - Timer seems to break SSI



I have some working code that dumps a sine wave out to a DAC via SSI.  Right now I use a system tick timer to detect elapsed time to figure out what value to output next.

I'm converting this to output on a fixed interval based on a pre-calc'd table.  This is a small step in my overall project, so it's important that I be able to output to SSI at a fixed interval.

If I modify my code to enable a timer (I've tried both Timer 1a and TImer 2a), the calls to SSIDataPut (and PutNonBlocking) immediately dump me into the fault ISR.  If I comment out the enabling of the timer, everything works fine again.  Is there some conflict between SSI0 and Timer1a and Timer2a?

Am I doing something silly?  I can comment out all SSIDataPut calls and validate via breakpoint that my timer interrupt handler is actually being called, so it definitely appears to be some sort of negative interaction between ssi and timers.  (note: I removed some commented code relating to pulsing the on board LED, so ignore the unused variables)

unsigned long COLOR_RED[3] = {0xFF, 0, 0};
unsigned long COLOR_GREEN[3] = {0, 0xFF, 0};
unsigned long COLOR_BLUE[3] = {0, 0, 0xFF};

void delayMS(int ms) {
    ROM_SysCtlDelay( (ROM_SysCtlClockGet()/(3*1000))*ms );
}

#define SYSTICKS_PER_SECOND     1000000
static unsigned long g_ulTicks = 0;
void
SysTickHandler(void)
{
    g_ulTicks++;
}


#define SAMPLE_RATE 20000
#define NUM_SAMPLES 2048
unsigned short g_freq = 440;
unsigned short g_outputBuffer[NUM_SAMPLES];
volatile unsigned char g_advanceOutput = 0;
volatile unsigned short g_outputIndex = 0;

//output
void
Timer1AIntHandler(void)
{
	ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
	//g_advanceOutput = 1;
}

void
InitOutputTimer()
{
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
	ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
	ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, ROM_SysCtlClockGet() / (SAMPLE_RATE - 1));
	ROM_IntEnable(INT_TIMER1A);
	ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
	ROM_TimerEnable(TIMER1_BASE, TIMER_A);
}

void
PopulateDebugBuffer()
{
	unsigned short i = 0;
	for(i=0; i < NUM_SAMPLES; i++)
	{
		g_outputBuffer[i] = (0.5 * sin(2 * 3.14159 * g_freq * i  / SAMPLE_RATE) * 2047) + 2048;
	}
}

int
main(void)
{
    volatile unsigned long ulLoop;


    ROM_FPUEnable();
    ROM_FPULazyStackingEnable();

    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                       SYSCTL_OSC_MAIN);
                       
    //
    // Initialize the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioInit(0);

    UARTprintf("Hello, world!\n");
    
    // init ssi
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH2_SSI0);
    ROM_GPIOPinConfigure(GPIO_PA5_SSI0TX);
    ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    ROM_GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    ROM_GPIOPinConfigure(GPIO_PA4_SSI0RX);

    ROM_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
                       GPIO_PIN_2);

    ROM_SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_1,
    		SSI_MODE_MASTER, 20000000, 16);

    ROM_SSIEnable(SSI0_BASE);

    ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / SYSTICKS_PER_SECOND);
    ROM_SysTickIntEnable();
    ROM_SysTickEnable();

    float intensity = 0;
    float increment = 0.1;
    unsigned long * color = (ROM_SysCtlClockGet() == 80000000 ? COLOR_BLUE : COLOR_RED);

    unsigned short spiData = 0;
    unsigned short spiSine = 0;
    short spiIncrement = 400;

    PopulateDebugBuffer();
    InitOutputTimer(); // !!!! If I comment out this line, everything works.  If I leave it uncommented i breaks

    while(1)
    {
        spiSine = (0.5 * sin(2 * 3.14159 * 440 * g_ulTicks  / SYSTICKS_PER_SECOND) * 2047) + 2048;

        ROM_SSIDataPut(SSI0_BASE, 0x4000 | spiSine);

        delayMS(1);

        intensity += increment;
        if((intensity >= 1.0) || (intensity <= 0))
        {
        	increment *= -1;
        }

        spiData += spiIncrement;
        if((spiData >= 4000) || (spiData <= 0))
        {
        	spiIncrement *= -1;
        }
    }
}

  • Looking quickly - I don't see your error.  Might this be (yet another) case of, "Default Stack too small?"

    Suggest that you start there - myself (likely others) may review further tomorrow...

    Note that I like your use of multiple/different timers in the attempt to isolate/diagnose.  Might you switch to a different SSI Port (I know that it won't "connect" w/your DAC) to further isolate any possible, "peripherals in conflict?"

    [edit] Now find the (unusual) "ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH2_SSI0);

    I don't recall that "PERIPH2" w/in normal/customary SSI parameters...

    [edit2] now find "PERIPH2" w/in sysctl.h - had never encountered it in the past...  Don't know what's intended w/that "2" part - but my "find" has cooled w/its appearance w/in sysctl.c...

  •  

    cb1_mobile said:
    Looking quickly - I don't see your error.  Might this be (yet another) case of, "Default Stack too small?"

    It resemble my beginner trouble, and I was measuring stack depth on timer too.... :(

      Which IDE are you using and if CCS where you set up stack size?

  • CCS.  I'm using a modified Hello example and it looks like the stack size is 512 (Project Properties, ARM Linker, Basic Options)

  •  That property is the last one setting the stack and fooling me, try increase to 2048 and see if your trouble come away, other fault causes are non initialized port or wrong mode, when you write or use get hardware fault..

     Try stack then try isolate line where fault isr fire.

  • Hello Rob,

    Can you tell us the value of the NVIC_FAULTSTAT and NVIC_FAULTADDR regiter at address 0xE000ED28 and 0xE000ED38?

    Regards

    Amit

  • Amit - once again you've "outclassed" your humble, "riff-raff" brigade.

    But do note - you've attacked a fully legitimate MCU issue here - well detailed "but for those key Fault Registers!  Now there does exist an App Note describing, "How to find/debug MCU Faults" - but note that it is NOT, "Front - Central" enough that poster, Roberto & this reporter could quickly/easily find and pull it up!

    That document especially - and many others (I can think of at least 5-8 more) would immensely speed, ease, and enhance the development efforts of your active/motivated MCU user community.

    But they're scattered or don't fully exist yet - are they not?   No crystal clear index guides and eases our search.  (there just has not been time to create such an index - nor enhance that specific document - and create needed others!")  

    But there has been much time "carved" for RTC basics, and nano-pulse (impossible) generation - and 24 bit ADC by a neophyte...  Is something, "out of whack, here?"  

    Amit - how many here are likely to employ an external, 24 bit ADC?  You yourself reported upon the complexity of a similar, 16 bit ADC.  (our group - after a struggle - got one of your 18 bit devices to (mostly) work...)  Thus - if practically no one here will use a 24 bit ADC - how then do we justify an "18 post - back/forth - exchange?"  What is the value in satisfying one lone poster - clearly unlikely to drive that project to successful completion?

    There's just one Amit, yet - the complex uDMA - better insight into MCU Fault Handling - new/improved, multi-bit SSI (to name a quick few); are not each/every one of these "sacrificed at the altar" of the (unlikely) 24 bit ADC? Why is that?  Does it make any sense?  To whom?

  • NVIC_FAULTSTAT 0x00008200

    NVIC_FAULTADDR 0x4000800C

  • Hello Rob,

    Thanks for the info and the code post. I was able to complete the code import for CCS and get the issue replicated with a slight difference

    While the FAULTSTAT matched indicating a Bus Fault and Imprecise Error, the Fault Address never showed up as SSI but some junk address. I then checked the code optimization options and saw it was set to 2. Switching code optimization OFF, allowed the code to work. Could you try the same as well?

    How to change code optimization?

    Right Click your CCS Project and then Show Build Settings -> Build -> ARM Compiler -> Optimization

    I would continue looking into why it is not working with code optimization ON (any setting).

    Also looking at the code and the use of SYSCTL_PERIPH2_SSI0, it looks you are using StellarisWare SW package and not TIVAWare Software package and since you are using LM4F device there is an errata on SRAM where

    "Non-word-aligned write to SRAM can cause incorrect value to be loaded" and this is sensitive to code optimization and compiler. Could you be running into the same?

    Regards

    Amit

  • Hi,

    My observations related to the code posted:

    -) missing IntMasterEnable() call 

    -) not sure if startup_ccs.c file was modified (i. e the interrupt handler for timer T1 was declared and inserted into interrupt vectors;

    -) some problems with sample calculations - need to review the expressions - take into account the calculations are in fp and the real data to feed the DAC should be unsigned integer. What is sent to SSI seems useless or-ed with 0x4000, although an offset of 0x2048 is already present.

    Petrei

  • Hi,

    Why do you use "SYSCTL_PERIPH2_SSI0" instead simply SYSCTL_PERIPH_SSI0

    Petrei

  • Hello Petrei

    The SYSCTL_PERIPH2_SSI0 is a define in the older StellarisWare SW Releases. In TIVAWare it got replaced with SYSCTL_PERIPH_SSI0 and the former define was deprecated

    Regards

    Amit

  • Disabling Optimization doesn't fix things on my end. I still get the same faultstat and faultaddr.

    I'm using stellarisware 9453 in CCS 5.2.1.00018.

    I have a later tivaware driverlib but when I first tried it I think I got a missing compiler error or something so I went back to the driverlib for the lm4f120 instead of the newer tiva c stuff.

    For completeness, here are my includes:

    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "utils/uartstdio.h"
    #include "drivers/rgb.h"
    #include "driverlib/ssi.h"
    #include "driverlib/timer.h"
    #include "inc/hw_ints.h"
    #include "math.h"
    

    I have the stellarisware and stellarisware/boards/ek-lm4f120xl folders added as linker include sources to resolve some of those as well as the standard ccsv5/tools/compiler/tms470_4.9.5/include folder.

    I don't think I'm hitting that errata issue as the writing that the driverlib does for inserting into the tx fifo appears to be word aligned anyway (and optimization didn't fix it).

    I had another post here that describes my hardware setup more: http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/345163.aspx

  • Hello Rob,

    Can you send across the CCS Project, so that all files can be checked and seen as to why the SSI is giving a bus fault? I have StellarisWare (though a newer version) which would be used.

    Regards

    Amit

  • Rob P said:
    Here you go.

     Hi Rob, I see you are using RGB driver, my last program on LM4F120 was a punched tape emulator reading from SD card, My intenction was to use RGB driver to report smooth status of program but I ended removing that code and simply setting RED GREEN BLUE LED on or off, that RGB was forever the cause of fault. try remove and see if this can also cure your code.

     Another issue causing fault was multiple call of peripheral enable, fault appear not immediately but after some more cycle.

  • @ Roberto,

    Your mention of, "multiple calls" to, "SysCtlPeripheralEnable()" escaped my note.  (pardon - I've not read poster's code)

    Trying to discern why a peripheral would be regularly enabled/disabled - unless one took excessive time to service - and it was desired to, "lock it out."  That said - if regularly enabling - and then "too quickly" making a call to that same peripheral - it may not (yet) be ready to handle that call!   And - fault results.

    Cure is to provide some minimum delay time after "each/every" call to, "SysCtlPeripheralEnable()" when that same peripheral is to be immediately accessed.

  • Hello Rob,

    Thanks for the code. I was able to replicate the issue and understand why it was not working.

    There are two sets of register for clock enabling in LM4F and TM4C123. The first set is the RCGC0-2 (called legacy) and the second set is RCGCperipheral.

    When the Legacy register bit is updated, the RCGCperipheral set is also updated but not the other way around. The SSI clock enable happens through the RCGCperipheral set and allows the configuration to happen. The the timer is enabled which happens through the legacy register set. The Timer clock enable register is RCGC1 which has SSI-0 also in it and this bit is clear. Updating the timer enable bit causes the SSI0 bit (which is clear) to be written back. The HW sees this as an update and clears the RCGCperipheral bit. As a result when SSIDataPut is called there is a Bus fault.

    The data sheet also mentions this as a note in the RCGC legacy section.

    So the solution to this is to use the Timer's RCGCperipheral Register to enable the clock using SYSCTL_PERIPH2_TIMER0.

    Regards

    Amit

  • Woot.  That worked.  Thanks!

    How complex is it to update to a later CCS and use Tivaware instead of stellarisware?  Since those PERIPH2 things go away I'm guessing this problem would be gone as well.

    I may stick with what I have for now since it's working, but I did have that thought.

    Thanks again.

  • Hello Rob

    Looking at the code you sent, I would consider it to be 5-10 minutes to update. Simple would be to use an example code from TIVAWare (preferably w/o interrupt) and then copy the main section of your code.

    Regards

    Amit

  • @ Amit,

    Good job - note that such detail "beat" poster, Roberto & this reporter!  Note that poster Petrei also was befuddled by the sudden appearance of this, "SYSCTL_PERIPH2" parameter.  (in that case - offender was SSI0)

    It's just great that you're here to, "diagnose, detect, and correct such new and unexpected, design "hiccups." 

    It is distressing that - once again - the MCU manual appears, "not especially effective" in signaling this new requirement!  As you say, "The data sheet also mentions this as a note in the RCGC legacy section." but this is a rather drastic change from the past - and will surely catch many!  (some - with long tenure here)

    Might both this unexpected, new encoding - and the past, always troubling "NMI-default" both benefit immensely from "front of the MCU Manual" highlighting and extended mention?  Yes - the alert exists (w/in the mice-type) but has that proven as effective as it should?   (many here would state, No!... to especially include this reporter...)

    Not to beat (too badly) an already dead/dying horse - but your time focused on the detection, alerting and correction of such clear MCU issues is so much more valuable than, "24 bit ADC operation while that ADC sits unpowered!"  Mon Dieu!  Sacre bleu!

    Suspect that you surely agree - and we hope that you can more appropriately target "real MCU" issues - not the "lost in space" largely irrelevant, "sideshows..."

    Thanks much for this day's MCU focus - would be wonderful if that critical resource can continue...

  • cb1- said:

    Your mention of, "multiple calls" to, "SysCtlPeripheralEnable()" escaped my note.  (pardon - I've not read poster's code)

     Hi CB1, this is from I learn first time, SysCtlPer..(gpioA),  was called one time from Main and another time from SD card init, if both call where in place fault happen at first port access.

     When searching for fault I completely dissected code one line at time...

     Clearly was only fixed on IDE dissection double stack set :( One week of deep pain!