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.

I get "No source available for "0xfffffff8" " while accessing interrupt handler first time

Other Parts Discussed in Thread: TM4C123GH6PM

Hi,

I get "No source available for "0xfffffff8" " while accessing interrupt handler first time (I assume that this is what is going on...)

I copied from Lab4 in the Workshop examples the definition of the timer interrupt and its handler to my code in order to modify it and adapt to my needs. Lab 4 works perfect and my code seems to fail at first access to the interrupt handler. I do not know what is going on and no clue on how to continue. See my code below.

Any help will be highly appreciated.

Thanks in advance

Joan S. 

// ***** 0. Documentation Section **********************************************************
// the GPIOB module for PB0 and PB1 to control motor direction in L298 and EV3 motor.
// QEI is used to monitor motor encoder
// PF is needed to read SW1 and SW2 in the LaunchPad board
// If SW1 is presed, the PWM is increased by 1% in one direction.
// If SW2 then is increased 1% in the other direction.
// At counter = 100 --> Motor stopped
// At counter = 0 --> Motor at maximum velocity direction 1
// At counter = 200 --> Motor at maximum velocity direction 2
// PINS:
// PD0 PWM
// PB0, PB1 Motor direction
// PF0, PF4 Buttons SW1 and SW2 in LaunchPad
// PA0, PA1 UART
// PD3,PD6,PD7(need to unblock it!!!) QEI: IDX0, PhA0, PhB0

// ***** 1. Pre-processor Directives Section ***********************************************
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "utils/tm4c123gh6pm.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/debug.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_gpio.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h" //C:/ti/TivaWare_C_Series-2.1.2.111/
#include "utils/UART.h"
#include "driverlib/qei.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"

// ***** 2. Global Declarations Section *****

// FUNCTION PROTOTYPES: Each subroutine defined


// VARIABLES
#define PWM_FREQUENCY 60//55

//Define several variable to use during PWM config
volatile uint32_t ui32Load=0;
volatile uint32_t ui32PWMClock=0;
volatile uint32_t ui8Adjust=0;
volatile uint32_t ui32AdjustVal=0;
volatile uint32_t uit32_SWX_state=0x00;
volatile uint32_t counter=100;
volatile uint32_t position=0;
signed char direction=0;
char position_char[10];
volatile uint32_t desired_position=180;
volatile uint8_t PWM_percent=10;
volatile ui32Period;

// ***** 3. Subroutines Section *****
void EnablePWM(void){
// The PWM module is clocked by the system clock through a divider, and that divider has a range
// of 2 to 64. By setting the divider to 64, it will run the PWM clock at 625 kHz.
SysCtlPWMClockSet(SYSCTL_PWMDIV_64);
// We need to enable the PWM1 and GPIOD modules (for the PWM output on PD0) and
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
// Port D pin 0 (PD0) must be configured as a PWM output pin for module 1, PWM generator
// 0 (check out the schematic).
GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
GPIOPinConfigure(GPIO_PD0_M1PWM0);
//----------------------------PWM Config----------------------------------------------
// Calculate reload value i.e the period of the PMW we wish to generate
ui32PWMClock = SysCtlClockGet() / 64; //Frequency unit
ui32Load = (ui32PWMClock / PWM_FREQUENCY) - 1; //Number ticks of the PWM clock units
// Configure PWM to mode count down
PWMGenConfigure(PWM1_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN);
//Define period of PWM signal (Reload value)
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, ui32Load);
//PWM Pulse width, i.e the tyme on. ui8Adjust is controling width in %.
//ui8Adjust = 5; //ui8Adjust defined from 0 to 100
//ui32AdjustVal=(ui8Adjust) * ui32Load/100; //Calculate the number of ticks for PWM signala width @ PWM_FREQUENCY
//PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui32AdjustVal);
//This function enables or disables the selected PWM outputs. --> Why is needed??
PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, true);
//Enable the counter, i,e enable the PWM
//PWMGenEnable(PWM1_BASE, PWM_GEN_0);
}

void ConfigPortB(void){
//Configure PB0 and PB1 to control motor direction
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// Port B pins 0 and 1 need to be outputs
GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1);
}

void ConfigPortF(void){
//Configure PF0 and PF4 to use SW1 and SW2 buttons in LaunchPad
//PF0 need to be unlocked by writing in LOCK adn CR registers, otherwise it can not be configured
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
// Port F pin 0 is input to read SW2
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE,GPIO_PIN_0|GPIO_PIN_4);
//In GPIODirModeSet (pag 254 TivaWare documentation), says that protected pins such as PF0 need to be unlocked manually
//by direct register writting.
// Unlock register GPIOLOCK to allow write in GPIOCR.
GPIO_PORTF_LOCK_R = 0x4C4F434B;
// Allow write in GPIOPUR by
GPIO_PORTF_CR_R = 0x1;
// Configure pull up in PF0
GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_0,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
}

void ConfigureUART(void){
// Enable the GPIO Peripheral used by the UART. This is used to debug by sending diferent states to Putty
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

// Enable UART0
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

// Configure GPIO Pins for UART mode.
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

// Use the internal 16MHz oscillator as the UART clock source.
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

// Initialize the UART for console I/O.
UARTStdioConfig(0, 115200, 16000000);
}

uint32_t Update_counter(uint32_t initial_counter){
// Function updates counter as function of SW1 and SW2 buttons in LaunchPad
// In Update_PWM counter is used to determine direction and PWM%.
volatile uint32_t updated_counter = initial_counter;
//Read the SW1 and SW2 state
uit32_SWX_state = GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_0|GPIO_PIN_4);
//Update counter by:
//If SW2(PF0) is pressed and counter is smaller than 200 then increase counter.
if (uit32_SWX_state==0x10 & counter < 200){
updated_counter = initial_counter + 1;
}
//If SW2(PF0) is pressed and counter is equal to 200, counter is equal to 200.
else if (uit32_SWX_state==0x10 & counter == 200){
updated_counter = 200;
}
//If SW1(PF4) is pressed and counter is larger than 0 then decrease counter.
else if (uit32_SWX_state==0x01 & counter > 0){
updated_counter = initial_counter - 1;
}
//If SW1(PF4) is pressed and counter is equal to 0 then counter is equal to 0.
else if (uit32_SWX_state==0x01 & counter == 0){
updated_counter = 0;
}
return updated_counter;
}

void Update_PWM(uint32_t counter){
//The function set the PWM % and direction as a function of counter as:
//if counter == 100 then disable PWM
if (counter == 100){
PWMGenDisable(PWM1_BASE, PWM_GEN_0);
}
// counter is different than 100
else{
//if counter > 100 then (PWM value = counter -100) and rotation +
if (counter > 100){
ui8Adjust = counter - 100; //ui8Adjust defined from 0 to 100
GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1,0x01);
//GPIOPinWrite(GPIO_PORTB_BASE,(GPIO_PIN_0|GPIO_PIN_1),(GPIO_PIN_0));
}
//if counter < 100 then (PWM value = 100 - counter and rotation -
else if (counter < 100){
ui8Adjust = 100 - counter; //ui8Adjust defined from 0 to 100
GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1,0x02);
//GPIOPinWrite(GPIO_PORTB_BASE,(GPIO_PIN_0|GPIO_PIN_1),(GPIO_PIN_1));
}
//load PWM value
ui32AdjustVal=(ui8Adjust) * ui32Load/100; //Calculate the number of ticks for PWM signala width @ PWM_FREQUENCY
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui32AdjustVal);
//enable PWM
PWMGenEnable(PWM1_BASE, PWM_GEN_0);
}
}

void ConfigureQEI(void){

// The following example shows how to configure the Quadrature Encoder module to read back an
// absolute position:
// 1. Enable the QEI clock using the RCGCQEI register in the System Control module (see page 355).
//
// Enable the QEI0 peripheral
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0);
//
// Wait for the QEI0 module to be ready.
//
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_QEI0)){}

// 2. Enable the clock to the appropriate GPIO module via the RCGCGPIO register in the System
// Control module (see page 340).
//PortD needs to be enabled.In this example GPIOD is already enabled in Config PWM
//SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

//ATENTION!!! PD7 needs to be unlocked!!!!!! This need to be do
// Unlock register GPIOLOCK to allow write in GPIOCR.
GPIO_PORTD_LOCK_R = 0x4C4F434B;
// Allow write in GPIOPUR by writing 1 in Pin 7
GPIO_PORTD_CR_R = 0x80;

// 3. In the GPIO module, enable the appropriate pins for their alternate function using the
// GPIOAFSEL register. To determine which GPIOs to configure, see Table 23-4 on page 1344.
GPIOPinTypeQEI(GPIO_PORTD_BASE,GPIO_PIN_3|GPIO_PIN_6|GPIO_PIN_7);

// 4. Configure the PMCn fields in the GPIOPCTL register to assign the QEI signals to the appropriate
// pins (see page 688 and Table 23-5 on page 1351). Seen pin_map.h for PD3, PD6 and PD7 QEI codes
GPIOPinConfigure(GPIO_PD3_IDX0);
GPIOPinConfigure(GPIO_PD6_PHA0);
GPIOPinConfigure(GPIO_PD7_PHB0);

// 5. Configure the quadrature encoder to capture edges on both signals and maintain an absolute
// position by resetting on index pulses. A 1000-line encoder with four edges per line, results in
// 4000 pulses per revolution; therefore, set the maximum position to 3999 (0xF9F) as the count
// is zero-based.
// -Write the QEICTL register with the value of 0x0000.0018.
// -Write the QEIMAXPOS register with the value of 0x0000.0F9F.

//
// Configure the quadrature encoder to capture edges on both signals and
// maintain an absolute position by resetting on index pulses. Using a
// 1000 line encoder at four edges per line, there are 4000 pulses per
// revolution; therefore set the maximum position to 3999 as the count
// is zero based.
//
QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_RESET_IDX |QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 359);
//QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_RESET_IDX | QEI_CONFIG_CLOCK_DIR | QEI_CONFIG_NO_SWAP), 360);//Aquest funciona pero no detecta canvis de direccio
//QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 360);

// 6. Enable the quadrature encoder by setting bit 0 of the QEICTL register.
// Note: Once the QEI module has been enabled by setting the ENABLE bit in the QEICTL
// register, it cannot be disabled. The only way to clear the ENABLE bit is to reset the
// module using the Quadrature Encoder Interface Software Reset (SRQEI) register.
QEIEnable(QEI0_BASE);

// 7. Delay until the encoder position is required.
// 8. Read the encoder position by reading the QEI Position (QEIPOS) register value.
// Note: If the application requires the quadrature encoder to have a specific initial position, this
// value must be programmed in the QEIPOS register after the quadrature encoder has been
// enabled by setting the ENABLE bit in the QEICTL register.

}

void Configure_SYSTIC_Timer_and_interrupt(void){

//Configure timer
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

//Interrupt frequency 1Hz
ui32Period = 20; //SysCtlClockGet();
TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period -1); //-1 is because timer fires at 0!

//Interrupt enable
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
IntMasterEnable();

//Timer enable
TimerEnable(TIMER0_BASE, TIMER_A);

}

// ***** 4. Main Section **********************************************************************
int main(void) {
//Let’s run the CPU at 80MHz.
//SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN| SYSCTL_XTAL_16MHZ);//This configure 40MHz
SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); //This configure 80MHz
EnablePWM();
ConfigPortB();
ConfigPortF();
ConfigureUART();
ConfigureQEI();


//Make sure PWM is disabled
PWMGenDisable(PWM1_BASE, PWM_GEN_0);
//GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0|GPIO_PIN_1,0x01);
QEIPositionSet(QEI0_BASE,0);

//Set desired PWM velocity and set pulse
PWM_percent = 20;
ui32AdjustVal=(PWM_percent) * ui32Load/100; //Calculate the number of ticks for PWM signala width @ PWM_FREQUENCY
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui32AdjustVal);
PWMGenEnable(PWM1_BASE, PWM_GEN_0);

//Set desired direction
desired_position=180;

//Configure timer interrupt and set up
Configure_SYSTIC_Timer_and_interrupt();


while (1) {

//Update counter to know PWM % and direction
counter = Update_counter(counter);

//Update PWM to set PWM% and direction
Update_PWM(counter);

//Delay of ?? seconds
SysCtlDelay(SysCtlClockGet() / 10 / 3);

//SysCtlDelay(1481); //This gives a delay of 44444 cycles de rellotge aprox. 0,5 ms. Ara tots els tics del encode a maxim velocity shan de poder veure.
//position = QEIPositionGet(QEI0_BASE);
//direction = QEIDirectionGet(QEI0_BASE);


//******Debug features*************************************************************************
//Watch value in Putty
//UART_OutUDec(QEIPositionGet(QEI0_BASE));


}
}

void Timer0IntHandler(void)
{
// Acknowledge the timer interrupt
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
// Out string to
// UART_OutString("In the handler");


}

  • Hello Joan

    Please do not paste the entire code (it makes the post long and absolutely incomprehensible). You may want to attach the code in the future (on the bottom right corner of the reply page is "Use rich formatting", which gives you the option to attach files).

    Now if we suspect the issue is the interrupt handler.

    void Timer0IntHandler(void)
    {
    // Acknowledge the timer interrupt
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    // Out string to
    // UART_OutString("In the handler");
    }

    It would be simpler to have a timer only example first to see how the CPU behave when timer interrupt is fired. Can you simplify the code for a timer interrupt handler only.

    Regards
    Amit
  • Joan Sans said:
    I get "No source available for "0xfffffff8" " while accessing interrupt handler first time (I assume that this is what is going on...)

    I copied from Lab4 in the Workshop examples the definition of the timer interrupt and its handler to my code in order to modify it and adapt to my needs. Lab 4 works perfect and my code seems to fail at first access to the interrupt handler. I do not know what is going on and no clue on how to continue. See my code below.

    In your project did you modify the g_pfnVectors array in the the startup_ccs.c source file to add the Timer0IntHandler?

    Where the g_pfnVectors array sets the interrupt vector table in flash.

    If not, when a timer interrupt occurs the IntDefaultHandler() will be called, instead of the the project Timer0IntHandler().

    [An alternative to modifying the g_pfnVectors array is to call IntRegister() which copies the interrupt vector table from flash to RAM and then adds an interrupt handler to the RAM based vector table]

  • Hi Amit,

    Thanks for your answer and sorry for the mess. Next time I will follow your advice to use "Use rich formatting".

    Actually the reply from Chester Gillon has helped me to solve the issue.

    Regards

    Joan S.
  • Hi Chester,

    Thanks you indicated me the right way to solve the issue. I did not modified the g_pfnVectors array. I did some time ago LAb4 and i did not remember this point.

    Regards

    Joan S.