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.

TM4C SSI (SPI mode) trouble with lauchpad as a debugger

Other Parts Discussed in Thread: CC1120

I have SPI communications working fine when the firmware runs normally on the TM4C12xx but when I run in debug mode using a TIVA launchpad the code hangs during the first MAP_SSIDataPut() call. Are there any specific debug settings that are required when utilizing an SSI port?

  • Hello Scott,

    No, there should not be anything specific in debug mode, unless the Enable bit in the SSI control registers is not set and the data has filled up in the FIFO.

    Regards
    Amit
  • I replace the MAP_ calls with calls directly to the *.c library and recompiled so I could use the single step functionality of the debugger. Here is what is happening:

    (1) My call to SSIDataPut()
    (2) The second ASSERT results in FaultISR()

    void
    SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
    {
    //
    // Check the arguments.
    //
    ASSERT(_SSIBaseValid(ui32Base));


    //!!!!!!!!!!!!! stepping through each line of code with the debugger
    //!!!!!!!!!!!!! this ASSERT results in FaultISR()

    ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
    SSI_CR0_DSS_M))) == 0);

    //
    // Wait until there is space.
    //
    while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
    {
    }

    //
    // Write the data to the SSI.
    //
    HWREG(ui32Base + SSI_O_DR) = ui32Data;
    }



    // stepping through each line of code with the debugger
    ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) & SSI_CR0_DSS_M))) == 0);

    static void
    FaultISR(void)
    {
    ResetISR();
    //
    // Enter an infinite loop.
    //
    //while(1)
    //{
    //}
    }
  • I replaced the ROM MAP_* calls with calls directly to the *.c library and recompiled so I could use the single step functionality of the debugger. Here is what is happening:

    (1) My call to SSIDataPut()
    (2) The second ASSERT results in FaultISR()

    void
    SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
    {
    //
    // Check the arguments.
    //
    ASSERT(_SSIBaseValid(ui32Base));


    //!!!!!!!!!!!!! stepping through each line of code with the debugger
    //!!!!!!!!!!!!! this ASSERT results in FaultISR()

    ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
    SSI_CR0_DSS_M))) == 0);

    //
    // Wait until there is space.
    //
    while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
    {
    }

    //
    // Write the data to the SSI.
    //
    HWREG(ui32Base + SSI_O_DR) = ui32Data;
    }



    // stepping through each line of code with the debugger
    ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) & SSI_CR0_DSS_M))) == 0);

    static void
    FaultISR(void)
    {
    ResetISR();
    //
    // Enter an infinite loop.
    //
    //while(1)
    //{
    //}
    }
  • //*****************************************************************************
    //
    // This is the code that gets called when the processor receives a fault
    // interrupt. This simply enters an infinite loop, preserving the system state
    // for examination by a debugger.
    // HWREG
    // 0xE000E000
    // HFAULTSTAT
    // MFAULTSTAT
    // BFAULTSTAT
    // UFAULTSTAT
    //*****************************************************************************
    static void
    FaultISR(void)
    {
    ResetISR();
    //
    // Enter an infinite loop.
    //
    //while(1)
    //{
    //}
    }

    Any idea how I might determine the fault condition
  • Hello Scott,

    What are parameters being passed to the SSIDataPut function?

    Regards
    Amit
  • Hello Scott,

    Please see ISSUE#7: Code goes to FaultISR in the following e2e post.

    e2e.ti.com/.../374640

    Regards
    Amit
  • //** Calling function
    bTest = CC1120_Command_Strobe(STROBE_SIDLE_ADDR, &ucStatus);
    //** where STROBE_SIDLE_ADDR = (0x36)



    //============================================================
    // Description:
    // A Command Strobe may be performed at any time (i.e. the CC1120
    // may be in any state). Therefore, a command strobe will perform
    // the necessary wait on chip ready. A command strobe is contained
    // within a 8 bit frame.
    //
    // UCHAR ucStrobeAddress = strobe address (6 bits)
    // UCHAR *pucStatus = location where chip status byte is written
    //
    // Wait on chip ready IS performed as a failure indication.
    //
    // 8 bit xfer:
    // Tx: "0 0 A5 .. A0"
    // Rx: "S7 .. S0"
    // where: A5 .. A0 is the 6 bit register address
    // S7 .. S0 is the read status byte.
    //
    // CC1120 chip status is read on PE2 during strobe address write on PE3.
    //
    // Success returns RSC_TRUE and *pucStatus = CC1120 status.
    // Failure returns RSC_FALSE and *pucStatus = 0x80.
    //============================================================
    BOOL CC1120_Command_Strobe(UCHAR ucStrobe, UCHAR *pucStatus)
    {
    volatile UCHAR ucAddress;
    volatile DWORD dwTemp;

    // turn on chip select
    CC1120_ASSERT_CS;

    if (CC1120_Ready() == RSC_FALSE)
    {
    *pucStatus = 0x80;
    // turn off chip select
    CC1120_DEASSERT_CS;
    return RSC_FALSE;
    }

    // send first byte
    ucAddress = (CC1120_ADDRESS_MASK & ucStrobe);
    ucAddress |= CC1120_WRITE_BYTE;

    //** this #defined as:
    //** #define CC1120_DataPut(a) SSIDataPut(SSI1_BASE, (uint32_t) a)

    CC1120_DataPut(ucAddress);

    // !!WIP 20160719sm test code to identify hang up problem with the debugger
    #if 0
    return RSC_TRUE;
    #endif

    CC1120_WaitOnPut;
    // get status
    CC1120_DataGet(&dwTemp);
    *pucStatus = (UCHAR)(dwTemp & 0xFF);

    // turn off chip select
    CC1120_DEASSERT_CS;

    return RSC_TRUE;
    }

    //** passed parameters are: ui32Base = 0x40009000
    //** ui32Data = 0x00000036

    void
    SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
    {
    //
    // Check the arguments.
    //
    ASSERT(_SSIBaseValid(ui32Base));
    ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
    SSI_CR0_DSS_M))) == 0);

    //
    // Wait until there is space.
    //
    while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
    {
    }

    //
    // Write the data to the SSI.
    //
    HWREG(ui32Base + SSI_O_DR) = ui32Data;
    }
  • 0xE000ED28 = 0x00008200
    0xE000ED38 = 0x40009000
  • Hello Scott

    It looks like either SSI-1 clock is not enabled or it is in reset. Check the RCGCSSI register in system control and it should have the value 0x2 and the register SRSSI must have the value 0x0

    Regards
    Amit
  • RCGCSSI 0x400FE61C = 0x00000002
    SRSSI 0x4000FE51C = 0x00000000
  • #define SPI_RATE (1000000)
    //============================================================
    // Description:
    //
    // Configure (peripheral and pins) and enable SSI1.
    // If successful, return TRUE, otherwise FALSE
    //============================================================
    BOOL SSI1_Init(Void)
    {
    #ifdef RSC_GPSC_MOBILE_CONFIGURATION
    #ifdef TIVAWARE_CONFIGURATION

    UCHAR ucTest;
    UCHAR ucTimeOut;
    volatile DWORD dwSystemClock;

    //===adapted from Tiva Pin Map utility =========================
    // TI Forum author suggested that all peripherals be reset before they are enabled
    MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_SSI1);

    // Enable the GPIO Peripheral used by SSI1.
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    // Enable SSI1
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);

    // Configure Port F GPIO Pins for SSI1 mode.
    // Enable port PF3 for SSI1 SSI1FSS
    MAP_GPIOPinConfigure(GPIO_PF3_SSI1FSS);
    MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_3);
    // Enable port PF2 for SSI1 SSI1CLK
    MAP_GPIOPinConfigure(GPIO_PF2_SSI1CLK);
    MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_2);
    // Enable port PF1 for SSI1 SSI1TX
    MAP_GPIOPinConfigure(GPIO_PF1_SSI1TX);
    MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_1);
    // Enable port PF0 for SSI1 SSI1RX
    // NOTE: this is a protected pin
    // First open the lock and select the bits we want to modify in the GPIO commit register.GPIO_LOCK_KEY
    //HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0x1;
    // Now modify the configuration of the pins that we unlocked.
    MAP_GPIOPinConfigure(GPIO_PF0_SSI1RX);
    MAP_GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0);
    //============================================================

    MAP_SSIDisable(SSI1_BASE);
    // disable SSI1 interrupts
    MAP_SSIIntDisable(SSI1_BASE, (SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR));
    MAP_SSIDMADisable(SSI1_BASE, (SSI_DMA_RX | SSI_DMA_TX));

    // Use the 16MHz PIOSC as the SSI1 clock source.
    MAP_SSIClockSourceSet(SSI1_BASE, SSI_CLOCK_PIOSC);
    dwSystemClock = (DWORD) 16000000;

    MAP_SSIConfigSetExpClk(SSI1_BASE, (uint32_t) dwSystemClock, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, SPI_RATE, 8);

    MAP_SysCtlDelay(10);
    MAP_SSIEnable(SSI1_BASE);

    ucTimeOut = 32;
    // wait on an empty receive buffer
    while (ucTimeOut)
    {
    ucTest = (UCHAR) MAP_SSIDataGetNonBlocking(SSI1_BASE, (uint32_t *) &dwSystemClock);
    if (ucTest == 0)
    {
    // empty
    break;
    }
    ucTimeOut--;
    // delay:
    MAP_SysCtlDelay(1024);
    }

    if (ucTimeOut)
    {
    return RSC_TRUE;
    }
    else
    {
    return RSC_FALSE;
    }

    #endif // TIVAWARE_CONFIGURATION
    #endif // RSC_GPSC_MOBILE_CONFIGURATION
    }
  • Remember that I do not have this problem when I am running normally (i.e. NOT UNDER CONTROL OF THE DEBUGGER)
  • Hello Scott,

    That is strange. Can you step till the point SSIDataPut is called and then check if RCGCSSI is still set as 0x2. if yes, then use the disassembly to see how every CPU instruction is affecting the CPU registers till the Bus fault!

    Regards
    Amit
  • RCGCSS 0x400FE51C remains at 0x00000002 up to entering FaultISR().

    SSIDataPut:
    00014c74: B570 PUSH {R4, R5, R6, LR}
    00014c76: 460C MOV R4, R1
    00014c78: 4605 MOV R5, R0
    580 ASSERT(_SSIBaseValid(ui32Base));
    00014c7a: F001F9B1 BL _SSIBaseValid
    581 ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
    00014c7e: A60C ADD R6, PC, #0x30 $C$SL11

    when stepping through this is the instruction that results in FaultISR()
  • Hello Scott

    And what is the value of the CPU registers just before executing the instruction that causes the bus fault?

    Regards
    Amit
  • Amit,

    I discovered a solution to my problem. I don't understand it completely, perhaps you can help.

    Solution: Had to move SSI1 and 3 from SleepDisable to SleepEnable

    //============================================================
    // Description:
    //
    // Configure SLEEP enable for all MCU peripherals in this project.
    //============================================================
    void Proj_Peripheral_Config_Sleep(void)
    {
    SysCtlPeripheralClockGating(RSC_TRUE);

    //============================================================
    // project peripherals enabled during SLEEP
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_ADC0);

    // not sure about GPIO ports that are not used as GPIO
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOG);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER1);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_TIMER2);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART2);

    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_WDOG0);

    // Necessary in order for code to run on debugger ===========
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI1);
    SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI3);

    //============================================================
    // project peripherals disabled during SLEEP
    //SysCtlPeripheralSleepDisable(SYSCTL_PERIPH_GPIOA);
    //SysCtlPeripheralSleepDisable(SYSCTL_PERIPH_GPIOE);
    //SysCtlPeripheralSleepDisable(SYSCTL_PERIPH_SSI1);
    //SysCtlPeripheralSleepDisable(SYSCTL_PERIPH_SSI3);
    }

  • Hello Scott

    I am not quite sure what you mean by "Had to move SSI1 and 3 from SleepDisable to SleepEnable"

    Regards
    Amit
  • Hi,

    In your SSI1Init() routine I can see these lines:

    MAP_SSIDisable(SSI1_BASE);

    // disable SSI1 interrupts

    Do you further enable SSI1 or it remains disabled, as above line says ? Not quite OK since you continue with configuration after that line.

  • Hello Ptrei,

    SSDisable will not be the cause of a Bus Fault. It shall only make the SSI pins traffic not to be accepted by the controller.

    Regards
    Amit