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.

RTOS: [K2H] Undefined instruction exception when using DRV GPIO interrupt directly

Tool/software: TI-RTOS

Hello,

I'm experimenting with using the DRV library directly for bare metal applications instead of using the SYS/BIOS on the keystone 2 K2H evaluation kit processor, with the PDK. I took one of the examples that supported bare metal -- a blinky project that used gpio interrupts -- and tested it. 

With sys/bios everything works fine. However, as soon as I switch over to its bare metal version, when the gpio interrupt occurs the program hangs as it gets stuck in the undefined instruction region. The example was said to support bare metal, so I didn't do much to modify the example. The example works just fine bare metal without interrupts -- I tested it by simply commenting out the lines that enabled said interrupt -- but is there more extensive modifications I have to make in order to get gpio interrupts working with this example, such as implementing a peripheral ISR table myself or something?

The code is below.

/**
 *  \file   main.c
 *
 *  \brief  Example application main file. This application will toggle the led.
 *          The led toggling will be done inside an callback function, which
 *          will be called by Interrupt Service Routine. Interrupts are
 *          triggered manually and no external source is used to trigger
 *          interrupts.
 *
 */

/*
 * Copyright (C) 2014 - 2016 Texas Instruments Incorporated - http://www.ti.com/
 *
 * 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.
 *
 */

#define BARE_METAL I put this define in
#ifndef BARE_METAL
/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>
#endif

/* BIOS Header files */
//#include <ti/sysbios/BIOS.h>
#//include <ti/sysbios/knl/Task.h>

#include <stdio.h>

#include <ti/csl/csl_sem.h>
#include <ti/csl/csl_semAux.h>

/* TI-RTOS Header files */
#include <ti/drv/gpio/GPIO.h>
#include <ti/drv/gpio/soc/GPIO_soc.h>

#include "ti/drv/gpio/test/led_blink/src/GPIO_log.h"
#include "ti/drv/gpio/test/led_blink/src/GPIO_board.h"

/**********************************************************************
 ************************** Macros ************************************
 **********************************************************************/
#if defined(SOC_AM572x) || defined (SOC_AM571x)
#if defined (__TI_ARM_V7M4__)
#define DELAY_VALUE       (0x6FFFFFU) /* Update Delay as it is not sufficent for M4 core */
#else
#define DELAY_VALUE       (0x6FFFFFU)
#endif
#else
#define DELAY_VALUE       (0x6FFFFFU)
#endif

/**********************************************************************
 ************************** Internal functions ************************
 **********************************************************************/

/* Delay function */
void AppDelay(unsigned int delayVal);

/* Callback function */
void AppGpioCallbackFxn(void);

#if defined(idkAM572x) || defined(idkAM571x)
/* GPIO clock and pinmux configurations */
extern void AppGPIOInit(void);
#endif

#if defined(idkAM572x)
extern void GPIOApp_UpdateBoardInfo(void);
extern void GPIOAppUpdateConfig(uint32_t *gpioBaseAddr, uint32_t *gpioPin);
#endif

/*
 *  ======== Board_initGPIO ========
 */
static void Board_initGPIO(void)
{
    Board_initCfg boardCfg;
    GPIO_v0_HwAttrs gpio_cfg;

    // Get the default SPI init configurations
    GPIO_socGetInitCfg(GPIO_LED0_PORT_NUM, &gpio_cfg);

    // Modify the default GPIO configurations if necessary

    // Set the default GPIO init configurations
    GPIO_socSetInitCfg(GPIO_LED0_PORT_NUM, &gpio_cfg);

    boardCfg = BOARD_INIT_PINMUX_CONFIG;
    Board_init(boardCfg);

#if defined(idkAM572x)
    GPIOApp_UpdateBoardInfo();
#endif
}

/**********************************************************************
 ************************** Global Variables **************************
 **********************************************************************/
volatile uint32_t gpio_intr_triggered = 0;
uint32_t gpioBaseAddr;
uint32_t gpioPin;

/*
 *  ======== test function ========
 */
#ifndef BARE_METAL
void gpio_test(UArg arg0, UArg arg1)
{
#else
void main()
{
    Board_initGPIO();
#endif
    uint32_t testOutput = 1;

    /* GPIO initialization */
    GPIO_init();

    /* Set the callback function */
    GPIO_setCallback(USER_LED0, AppGpioCallbackFxn);

    /* Enable GPIO interrupt on the specific gpio pin */
    GPIO_enableInt(USER_LED0);

    /* Write high to gpio pin to control LED1 */
    GPIO_write((USER_LED1), GPIO_PIN_VAL_HIGH);
    AppDelay(DELAY_VALUE);

    //GPIO_log("\n GPIO Led Blink Application \n");

    while(1)
    {
        GPIO_toggle(USER_LED0);
        AppDelay(DELAY_VALUE);
        if (testOutput)
        {
            //GPIO_log("\n All tests have passed \n");
            testOutput = 0;
        }
    }
#endif
    //Task_exit();
}

#ifndef BARE_METAL
/*
 *  ======== main ========
 */
int main(void)
{
    /* Call board init functions */
    Board_initGPIO();

    /* Start BIOS */
    BIOS_start();
    return (0);
}
#endif

/*
 *  ======== AppDelay ========
 */
void AppDelay(unsigned int delayVal)
{
    while(delayVal)
    {
        delayVal--;
    }
}

/*
 *  ======== Callback function ========
 */
int i = 0;
void AppGpioCallbackFxn(void)
{
    /* Toggle LED1 */
    i += 1;
    GPIO_toggle(USER_LED1);
    AppDelay(DELAY_VALUE);
    gpio_intr_triggered = 1;
    //System_printf("Blink: %d\n", i);
    //System_flush();
}

Using the followng load script and startup files:

/****************************************************************************/
/*  66AK2Gxx.lds                                                            */
/*  Copyright (c) 2016  Texas Instruments Incorporated                      */
/*  Author: Rafael de Souza                                                 */
/*                                                                          */
/*    Description: This file is a sample linker command file that can be    */
/*                 used for linking programs built with the GCC compiler    */
/*                 and running the resulting .out file on a 66AK2Gxx device.*/
/*                 Use it as a guideline.  You will want to                 */
/*                 change the memory layout to match your specific          */
/*                 target system.  You may want to change the allocation    */
/*                 scheme according to the size of your program.            */
/*                                                                          */
/****************************************************************************/

MEMORY
{

    MSMC_SRAM :  o = 0x0C000000,  l = 0x00100000  /* 1MB MSMC Shared SRAM */
    DDR0      :  o = 0x80000000,  l = 0x80000000  /* 2GB external DDR0 */

}

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory region DDR0.
 * It references following symbols, which must be defined in code:
 *   Entry : Entry of reset handler
 * 
 * It defines following symbols, which code can use without definition:
 *   __exidx_start
 *   __exidx_end
 *   __etext
 *   __data_start__
 *   __preinit_array_start
 *   __preinit_array_end
 *   __init_array_start
 *   __init_array_end
 *   __fini_array_start
 *   __fini_array_end
 *   __data_end__
 *   __bss_start__
 *   __bss_end__
 *   __end__
 *   end
 *   __HeapLimit
 *   __HeapBase        - To be compatible with Linaro's semihosting support 
 *   __StackLimit
 *   __StackTop
 *   __StackBase    - To be compatible with Linaro's semihosting support 
 *   __stack
 */
ENTRY(Entry)

SECTIONS
{
    .rsthand :
    {
        . = ALIGN(0x10000);
        KEEP(*(.isr_vector))
        *startup_ARMCA15.o (.text)
    } > MSMC_SRAM
    
    . = ALIGN(4);
    .text :
    {
        *(.text*)

        KEEP(*(.init))
        KEEP(*(.fini))

        /* .ctors */
        *crtbegin.o(.ctors)
        *crtbegin?.o(.ctors)
        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
        *(SORT(.ctors.*))
        *(.ctors)

        /* .dtors */
         *crtbegin.o(.dtors)
         *crtbegin?.o(.dtors)
         *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
         *(SORT(.dtors.*))
         *(.dtors)

        *(.rodata*)

        KEEP(*(.eh_frame*))
    } > MSMC_SRAM

    .ARM.extab : 
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > MSMC_SRAM

    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > MSMC_SRAM
    __exidx_end = .;

        
    .data :
    {
        . = ALIGN(4);
        __data_start__ = .;
        *(vtable)
        *(.data*)

        . = ALIGN(4);
        /* preinit data */
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP(*(.preinit_array))
        PROVIDE_HIDDEN (__preinit_array_end = .);

        . = ALIGN(4);
        /* init data */
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);


        . = ALIGN(4);
        /* finit data */
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP(*(SORT(.fini_array.*)))
        KEEP(*(.fini_array))
        PROVIDE_HIDDEN (__fini_array_end = .);

        . = ALIGN(4);
        /* All data end */
        __data_end__ = .;

    } > MSMC_SRAM

    .bss :
    {
        . = ALIGN(4);
        __bss_start__ = .;
        *(.bss*)
        *(COMMON)
        __bss_end__ = .;
    } > MSMC_SRAM
    
    .heap (NOLOAD):
    {
        /* The line below can be used to FILL the memory with a known value and
         * debug any stack overruns. For this to work, the specifier (NOLOAD) above 
         * must be removed at the expense of an increase in the output binary size */
        FILL(0xDEADBEEF)
        . = ALIGN(4);
        __end__ = .;
        end = __end__;
        /* The line below created to be compatible with Linaro's semihosting support */
        __HeapBase = __end__; 
        *(.heap*)
        . = . + HEAPSIZE;
        __HeapLimit = .; 
    } > MSMC_SRAM

    /* .stack section doesn't contain any symbols. It is only
     * used for linker to calculate size of stack sections, and assign
     * values to stack symbols later */
    .stack (NOLOAD):
    {
        /* The line below can be used to FILL the memory with a known value and
         * debug any stack overruns. For this to work, the specifier (NOLOAD) above 
         * must be removed at the expense of an increase in the output binary size */
        FILL(0xBAD0BAD0)
        . = ALIGN(4);
        __StackLimit = . ;
        *(.stack*)
        . = . + STACKSIZE;
        __StackTop = . ;
        /* The line below created to be compatible with Linaro's semihosting support */
        __StackBase = . ;
    } > MSMC_SRAM
    PROVIDE(__stack = __StackTop);

}
/**************************************************************************/
@******************************************************************************
@
@ startup_ARMCA15.S - Init code routine for Cortex A15 cores and Linaro baremetal
@
@******************************************************************************
@
@ Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
@  (Rafael de Souza - 2015) initial Cortex A15 version, based on Cortex A8
@
@
@  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.
@
@******************************************************************************

@****************************** Global Symbols*******************************
        .global Entry
        .global __stack
        .global __bss_start__
        .global __bss_end__
        .global start_boot

@************************ Internal Definitions ******************************
@
@ to set the mode bits in CPSR for different modes
@
        .set  MODE_USR, 0x10
        .set  MODE_FIQ, 0x11
        .set  MODE_IRQ, 0x12
        .set  MODE_SVC, 0x13
        .set  MODE_ABT, 0x17
        .set  MODE_UND, 0x1B
        .set  MODE_SYS, 0x1F

        .equ  I_F_BIT, 0xC0

@**************************** Code Section ***********************************
        .text

@
@ This code is assembled for ARM instructions
@
        .code 32

@******************************************************************************
@
@******************************************************************************
@
@ The reset handler sets up the stack pointers for all the modes. The FIQ and
@ IRQ shall be disabled during this. Then clears the BSS section, enters the
@ main function.

Entry:
@
@ The stack for all the modes (Abort, FIQ, etc.) is set by
@ the runtime support library.
@

@
@ Set up the Vector Base Address Regsiter
@
		LDR   r0, = __isr_vector
		MCR   p15, 0, r0, c12, c0, 0     @ Write VBAR Register

.if __ARM_PCS_VFP == 1
@
@ Enable NEON extensions and the VFP. Must be done before entering user mode.
@
        MRC   p15, #0, r3, c1, c0, #2    @ Read CPACR
		ORR   r3, r3, #0x00F00000        @ Enable access to CP10 and CP11
		MCR   p15, #0, r3, c1, c0, #2    @ Write CPACR
		MOV   r3, #0
      	MOV   r0,#0x40000000
        //FMXR  FPEXC,r0                   @ Set FPEXC bit 30 to enable VFP
		MCR   p15, #0, r3, c7, c5, #4    @ flush prefetch buffer because of FMXR above
.endif

.if USERMODE == 1
@
@ Change to user mode. It allows for a stack smaller than 64kB.
@
        MSR   cpsr_c, #MODE_USR|I_F_BIT  @ change to user mode
.endif

@
@ The BSS section is cleared by the runtime support library
@

@
@ Enter the main function.
@ The symbol _start is the entry point for the runtime support library
@


Enter_BootLoader:
         LDR   r10, = _start              @ Get the address of _start
         MOV   lr,pc                     @ Dummy return
         BX    r10                       @ Branch to main
         SUB   pc, pc, #0x08             @ looping

@
@ Set the Stack space here
@
    .section .stack
    .align 4
    .globl  __StackBase
    .globl  __StackLimit
__StackLimit:
@    .space   0x400			@ the stack size is set by the linker script
    .size  __StackLimit, . - __StackLimit
__StackBase:
    .size  __StackBase, . - __StackBase

@
@ Set the Heap space here
@
    .section .heap
    .align 4
    .globl  __HeapBase
    .globl  __HeapLimit
__HeapBase:
@    .space   0x400			@ the heap size is set by the linker script
    .size  __HeapBase, . - __HeapBase
__HeapLimit:
    .size  __HeapLimit, . - __HeapLimit

@
@ Set the Interrupt vector table here
@

    .section .isr_vector
    .align 4
    .globl  __isr_vector
__isr_vector:
        LDR   pc, [pc,#24]       @ 0x00 Reset
        LDR   pc, [pc,#-8]       @ 0x04 Undefined Instruction
        LDR   pc, [pc,#24]       @ 0x08 Supervisor Call
        LDR   pc, [pc,#-8]       @ 0x0C Prefetch Abort
        LDR   pc, [pc,#-8]       @ 0x10 Data Abort
        LDR   pc, [pc,#-8]       @ 0x14 Not used
        LDR   pc, [pc,#-8]       @ 0x18 IRQ interrupt
        LDR   pc, [pc,#-8]       @ 0x1C FIQ interrupt
        .long  Entry
        .long  0
        .long  SVC_Handler
        .long  0
        .long  0
        .long  0
        .long  0
        .long  0

    /* External interrupts */
        .long  Default_Handler

        .size  __isr_vector, . - __isr_vector

/*    Macro to define default handlers. Default handler
 *    will be weak symbol and just dead loops. They can be
 *    overwritten by other handlers */
        .macro  def_default_handler    handler_name
        .align 1
        .thumb_func
        .type  \handler_name, %function
\handler_name :
        B    .
        .size  \handler_name, . - \handler_name
        .endm

        def_default_handler  NMI_Handler
        def_default_handler  HardFault_Handler
        def_default_handler  SVC_Handler
        def_default_handler  PendSV_Handler
        def_default_handler  SysTick_Handler
        def_default_handler  Default_Handler

       .weak  DEF_IRQHandler
       .set  DEF_IRQHandler, Default_Handler

@
@ End of the file
@
       .end

  • Hi,

    Which Processor SDK RTOS version are you using?

    Best Regards,
    Yordan
  • Drue,

    We don`t have too many bare-metal examples for this device as we expect most user to use a quad A15 and eigth core DSP device with an OS rather than using bare-metal programming. However, we test the drivers in both TI RTOS environment and in bare-metal environment on other devices which are lower power and smaller subset of the the K2H device.

    For examples, you can refer to the bare-metal GPIO examples for K2G device that is provided in the diagnostic package which you can find here:
    pdk_k2hk_4_0_9\packages\ti\board\diag\led

    The key to configuring interrupts with GPIO LLD driver in bare-metal environment is to link to the no-OS version of OSAL instead of the TI RTOS version. Your code can remain the same but make sure during the build step that the correct version of OSAL is picked up. If your configuration script has the following code, change "tirtos" to "nonos"

    var osType = "tirtos";
    var Osal = xdc.loadPackage('ti.osal');
    Osal.Settings.osType = osType;

    Let us know if you are still running into issues.

    Regards,
    Rahul