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");
}