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.

EK-TM4C123GXL: Trouble Executing Code through Interrupts

Part Number: EK-TM4C123GXL


My project was to create a automatic plant waterer.  I have some sensors(soil moisture sensor, DHT22 air temp and humidity sensor, and others that are working fine).  Here is my first issue.

So I have this DHT22 air temperature and humidity sensor.  The way it works is that the microcontroller sends a constant high signal to the single serial port.  The sensor is told to send data for air temp and humidity when that GPIO output pin sending the high signal goes low for at least 1ms.  After 1ms (or more) that GPIO pin switches to input in order to be ready to read the signal from the serial port.  In general, if the HIGH signal coming from the sensor lasts longer than 50us, it is a '1' bit, and if it lasts less than 50us it is a '0' bit value.  I slowly built a code up from scratch by making use of a timer, a bunch of loops, and variables.  I was able to simulate my code fine when I used it in the main but when using it in a UART interrupt it acts crazy as hell.  I used UART outputs to watch the values and see how their changing, and I see my bit values jump to crazy high numbers in the 10's of thousands.  Mind you these values are assigned during a conditional statement and can only become 1 or 0.  When this happens it screws with my bit conversions to get the actual values of the air temp and humidity.  So, if anyone has any idea why this is happening, please help me out.  This was for a class project and unfortunately it didn't get turned in fully complete, but I have put so much time into it I want to see this thing properly functioning. 

Another minor issue I have is using sysctldelay in one of my timer interrupt handlers it.  This interrupt is used to periodically check the soil moisture conditions by calling another ADC interrupt that is connected to the soil moisture sensor.  If it is below a certain value i want it to run an output that triggers the pump for 15 sec, so i tried to use sysctldelay for this.  However anytime sysctldelay is in the interrupt, everything appears to work except for the call to the ADC interrupt to retrieve the value.  Then when I magically remove it, the interrupt runs fine. 

So there are all my issues with this project, so far.  I really have a lot of plans to build on this but I really need to figure out these crazy issues first.  Thank you! 

I just posted my entire code.  The section where the issues occur with the bit values being calculated to crazy high numbers occurs in the UARIntHandler and the section with the sysctldelay issues is at the Timer0A_Handler.  


#include <stdint.h>
#include <math.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/interrupt.h"
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"


#define BLUE_MASK 0x04

uint32_t ui32ADC0Value[1];		//store sample from ADC0 SS3
uint32_t ui32ADC1Value[1];   //store sample from ADC1 SS3
volatile uint32_t Photoresistor;	//Photoresistor
volatile uint32_t Soil_Moisture;	//Soil Moisture
volatile unsigned long Timer_Value;

uint32_t Letter;


volatile unsigned long timerValue, timeConverted, count, timeInMicro, timeInMicroPrevious, timeMicroLoop;
volatile int digit[32], soil_moisture_percentage, photoresistor_percentage;
volatile double humidity, temperature, temperatureCelsius, humidityRelative, temperatureFahrenheit;
//*****************************************************************************
void
PortFunctionInit(void)
{
	  // Enable Peripherals
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
 
	
		GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

	
    // Enable pin PE3 and PE2 for ADC AIN0 and ADC AIN1 respectively
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
	
		// Enable pin PE4 and PE5 for GPIOInput
		GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_3);
	  GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_2);
	
   	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0x1;
		
	  //
    // Enable pin PF1, PF2, PF3, PE4, and PE5 for GPIOOutput (LEDs)
    //
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
		GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_4);
    GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_5);
		

    //
    // Enable pin PE4, PE5, & PF0 for GPIOInput
    //
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_0);


		// Enable pull-up on PF0
	  GPIO_PORTF_PUR_R |= 0x01; 
	  		
		
}

//Globally enable interrupts 
void IntGlobalEnable(void)
{
    __asm("    cpsie   i\n");
}

void UART_init(void)
{
		//Enable Peripherals
		SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

		// Configure Pins 
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
	  GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	
    //UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,										//don't need
    //(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));		//don't need
		UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTStdioConfig(0, 115200, 16000000);

    IntMasterEnable(); //enable processor interrupts
    IntEnable(INT_UART0); //enable the UART interrupt
		UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT); //only enable RX and TX interrupts
		//code one line above will need to change to switch # in setup_rvmdk.S

}

//ADC0 initializaiton
void ADC0_Init(void)
{
	
		SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); // configure the system clock to be 40MHz
		SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);					  //activate the clock of ADC0
		SysCtlDelay(2);	//insert a few cycles after enabling the peripheral to allow the clock to be fully activated.

		ADCSequenceDisable(ADC0_BASE, 2); 				//disable ADC0 before the configuration is complete
		ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PROCESSOR, 1);   // will use ADC0, SS1, processor-trigger, priority 0
		//ADCSequenceStepConfigure(ADC0_BASE, 2,0,ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 2,0,ADC_CTL_CH1|ADC_CTL_IE|ADC_CTL_END);	
	
		IntPrioritySet(INT_ADC0SS2, 0x01);  	 	// configure ADC0 SS3 interrupt priority as 0
		IntEnable(INT_ADC0SS2);    			// enable interrupt 33 in NVIC (ADC0 SS3)
		ADCIntEnableEx(ADC0_BASE, ADC_INT_SS2);     	// arm interrupt of ADC0 SS3
		ADCSequenceEnable(ADC0_BASE, 2);		// enable ADC0
}

void ADC1_Init(void)
{
		SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); // configure the system clock to be 40MHz
		SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);					  //activate the clock of ADC0
		SysCtlDelay(2);	//insert a few cycles after enabling the peripheral to allow the clock to be fully activated.

		ADCSequenceDisable(ADC1_BASE, 3); 				//disable ADC0 before the configuration is complete
		ADCSequenceConfigure(ADC1_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);   // will use ADC0, SS1, processor-trigger, priority 0
  	ADCSequenceStepConfigure(ADC1_BASE,3,0,ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END); 
	
		IntPrioritySet(INT_ADC1SS3, 0x02);    	 	// configure ADC0 SS3 interrupt priority as 0
		IntEnable(INT_ADC1SS3);    			// enable interrupt 33 in NVIC (ADC0 SS3)
		ADCIntEnableEx(ADC1_BASE, ADC_INT_SS3);     	// arm interrupt of ADC0 SS3
		ADCSequenceEnable(ADC1_BASE, 3);	  	// enable ADC0
	
}


void UARTIntHandler(void){
	
    uint32_t ui32Status;		
	
    ui32Status = UARTIntStatus(UART0_BASE, true); //get interrupt status
		
	
		 while(UARTCharsAvail(UART0_BASE)) //loop while there are chars
    {
			//UARTprintf("Temperature: %d F \n \n \r ", temperatureFahrenheit); // print temperature(F) value to UART			

			Letter = UARTCharGetNonBlocking(UART0_BASE);
			
			if(Letter == 'R')
			{
				///// INITIATE CALL TO SENSOR FOR DATA //////
				GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, 0x00);  // PE3 Output Low (wake up signal to sensor)
				SysCtlDelay(288000);  // hold low input for 2ms
				GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_4);  // PE3 Switch to GPIO Input to recieve data from sensor
				////// END OF DATA REQUEST //////

				GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0xff);  // red LED ON (Pink light helps indicate state)
		
				/////////////// START COUNT OF HIGH SIGNAL INPUT STATE BIT VALUES ///////////////////////
				for (int i=0; i<=31; i=i)
				{
					GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0xff);  // green led turns on (white light helps indicate state)	
			
			
					//////////////////// ENTER LOW SIGNAL INPUT STATE ///////////////////
					if(GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_4)==0x00)  // PE3 input is Low
					{
						TimerDisable(TIMER1_BASE, TIMER_A);
						GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);  // green led turns off (pink light helps indicate state)

						timerValue = TimerValueGet(TIMER1_BASE, TIMER_A);  // get value of timer, assign to timerValue
						timeConverted = timerValue/40000000;  // convert timerValue to show time in seconds
						timeInMicro = timerValue/40;  // convert timerValue to show time in micro seconds
					

						timeMicroLoop = timeInMicro - timeInMicroPrevious;	// how long timer was on during last high signal input 
				
					
					
				
						if(timeMicroLoop < 500000)   // if greater than 1/2 a second
						{
								digit[i] = 0;  // bit value for loop is 0
						}
		
						else
						{ 
								digit[i] = 1;  // bit value for loop is 1
						}
				
						timeInMicroPrevious = timeInMicro;  // used to find time in next high signal loop cycle
				
//				//*************** UART OUTPUTS FOR DEBUGGING *****************//
				UARTprintf("Total Timer Time(s): %d \n \r ", timeConverted);
				UARTprintf("Total Timer Time(us): %d \n \r ", timeInMicro);
				UARTprintf("Time of loop(us): %d \n \r ", timeMicroLoop);
				UARTprintf("Digit %d (us): %d \n \n \r ", i, digit[i]);
				
						i++;  // advance for loop to find next time high input time
				
						while(GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_4)==0x00 && i < 32)  // Loop While PE3 is Low until i = 32 so code doesn't get stuck when sensor sends low output after finishing data transmission
							{                                                                                                                                                                                                                                                                                                                                                                                                                                      		
							}
					
				
					}
					/////////////////// EXIT LOW SIGNAL INPUT STATE///////////////////

						TimerEnable(TIMER1_BASE, TIMER_A);  // start loop back up when signal is no longer low, and now high
			
				}
				////////////EXIT COUNT OF HIGH SIGNAL BIT VALUES FROM SENSOR//////////
				
				TimerDisable(TIMER1_BASE, TIMER_A);  // no more high signals are expected, stop timer from counting up
		
		
				///////////////////CACULATION OF HUMIDITY AND TEMPERATURE BASED ON DIGIT VALUES FROM SENSOR////////////////////////
		
				humidity = 0;  
				temperature = 0;
				for(int e=0; e<16; e++)  // for loop to turn binary values of the first 16 bits to decimal that represent humidity value
				{
					humidity = humidity + (digit[e]*(pow(2,e)));
				}
				for(int e=16; e<32; e++)  // for loop to turn binary values of the last 16 bits to decimal that represent temperature value
				{
					temperature = temperature+ (digit[e]*(pow(2,(e-16))));		
				}
		
				temperatureCelsius = ((120*temperature)/65535) - 40;  // calculations to convert decimal into temperature in range of -40C to 80C
				temperatureFahrenheit = ((temperatureCelsius*9)/5) + 32;  //convert celsius value to fahrenheit
				humidityRelative = (100*humidity)/65535;	// calculation to convert decimal of humidity to value of 0%-100%
				//////////////////END OF CALCULATIONS FOR HUMIDITY AND TEMPERATURE VALUES////////////////////////
			//	UARTprintf("Humidity: %d%%\n \n \r ", humidity);   // print humidity value to UART
			//	UARTprintf("Temperature: %d F \n \n \r ", temperature); // print temperature(F) value to UART		
				//////////////UART OUTPUTS DISPLAYING CURRENT SENSOR READINGS/////////////////////
				UARTprintf("Humidity: %d%%\n \n \r", humidityRelative);   // print humidity value to UART
				UARTprintf("Temperature: %d F \n \n \r", temperatureFahrenheit); // print temperature(F) value to UART			
				UARTIntClear(UART0_BASE, ui32Status); //clear the asserted interrupts
				ADCProcessorTrigger(ADC0_BASE, 2); // initialize the ADC1 sequence 
				ADCProcessorTrigger(ADC1_BASE, 3); // initialize the ADC0 sequence
				GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);  // red LED ON (Pink light helps indicate state)
			}
		
			
			
			
		}
}

void ADC0_Handler(void)
{
		ADCIntClear(ADC0_BASE, 2);
		ADCSequenceDataGet(ADC0_BASE, 2, ui32ADC0Value);  // Gets ADC0 value
		Photoresistor = ui32ADC0Value[0];		  // give value for photoresistor
		photoresistor_percentage = ((Photoresistor-60)*100);
		photoresistor_percentage = (photoresistor_percentage/4025) - 100;
		photoresistor_percentage = photoresistor_percentage * (-1); // give value for soil moisure variable
		if(photoresistor_percentage < 0)
		{
			photoresistor_percentage = 0;
		}
		if (photoresistor_percentage > 100)
		{
			photoresistor_percentage = 100;
		}
		UARTprintf("Light Exposure: %d%% \n\r",photoresistor_percentage);

}

void ADC1_Handler(void)
{
		ADCIntClear(ADC1_BASE, 3);
		ADCSequenceDataGet(ADC1_BASE, 3, ui32ADC1Value);  // Gets ADC0 value
		Soil_Moisture = ui32ADC1Value[0];	
		soil_moisture_percentage = ((Soil_Moisture-2100)*100);
		soil_moisture_percentage = (soil_moisture_percentage/1755) - 100;
		soil_moisture_percentage = soil_moisture_percentage * (-1); // give value for soil moisure variable
		if(soil_moisture_percentage < 0)
		{
			soil_moisture_percentage = 0;
		}
		if (soil_moisture_percentage > 100)
		{
			soil_moisture_percentage = 100;
		}
		UARTprintf("Soil Moisture: %d%% \n\r",soil_moisture_percentage);

}

void Timer0A_Handler(void)
{
		TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);		//acknowledge flag for Timer0A timeout
		ADCProcessorTrigger(ADC1_BASE, 3); // initialize the ADC1 sequence
   	//UARTprintf("Soil Moisture: %d%% \n\n\r",soil_moisture_percentage);
			if(soil_moisture_percentage < 30)  //when soil moisture is less than 30% water plant
		{
		   UARTprintf("Pump waters plant for 15 seconds \n \n \r");
			 GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_5, 0xff);  // PE3 Output Low (wake up signal to sensor)

	     //SysCtlDelay(40000000); // runs for 5 secs to save time during demo, change to 600000000 for 15s	
			 // pumps flow is 1.2gpm, at 15s 0.3 gallons of water will be used to water plant
		}
		else
		{
			 GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_5, 0x00);  // PE5 Output low to keep pump off
		}
		
		
}

void Timer1A_init()
{
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ); // configure the system clock to be 40MHz
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
	TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC_UP);
	TimerLoadSet(TIMER1_BASE, TIMER_A, 0xffffffff);
}
void Timer0A_Init(unsigned long period)
{   
  // Enable Peripheral Clocks 
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
  TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); 		// configure for 32-bit timer mode
  TimerLoadSet(TIMER0_BASE, TIMER_A, period -1);        	//reload value
  IntPrioritySet(INT_TIMER0A, 3);  	 			// configure Timer0A interrupt priority as 0
  IntEnable(INT_TIMER0A);    					// enable interrupt 19 in NVIC (Timer0A)
  TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);       	// arm timeout interrupt
  TimerEnable(TIMER0_BASE, TIMER_A);      			// enable timer0A
}


int main(void)
{
	unsigned long period = 400000000; // set to 10s to save time during demo, will use 90s in real world application
 	PortFunctionInit();
	UART_init();  // UART Interrupt Initializations
	ADC1_Init();  // ADC1 Interrupt Initializations
	ADC0_Init();	// ADC0 Interrupt Initializations
	Timer0A_Init(period);  // Timer0A Interrupt initializations
	Timer1A_init();  // Timer1A Initializations
	IntMasterEnable(); //enable processor interrupts



	GPIO_PORTF_DATA_R |= 0x04;
	timeMicroLoop=0;
	timeInMicroPrevious=0;
  GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0xff);  // Blue LED on (helps indicate state)
	timeInMicroPrevious=0;

	while(1)
	{
		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00); // green LED off
		GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00); // red LED off
		GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_4); // Set PE3 to Output type
		GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, 0xff);  // PE3 Output High (will be set to low when ready for request signal to DHT22)	

	}
	
}


  • I am sorry that you were not able to get your project to work. Unfortunately debugging your project is beyond what I may do to help you. What I suggest is that you should not put such time consuming tasks into your interrupt routines. The interrupt routines should be short, in and out, routines. When you are in an interrupt routine, you block other interrupts from happening. (The TM4C devices do support nested interrupts, but that is not what you are doing here, and not what you need.) Your interrupt routine should set a flag for an operation that is then completed in the main loop.