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.

MSP430F5529 Interrupts causing Ultrasonic sensor pulseIn to return zero

Other Parts Discussed in Thread: ENERGIA

Hi there. In my application I'm using uart interrupts on both A0 and A1, and when a certain character is received I want to access the ultrasonic sensor and take a reading to see if there is an object in the way of my robot or not. There are a few issues that I've been having. The first is that the micros() function doesn't work, so I've taken to making my own delays by using a volatile integer and burning clock cycles that way. The main issue that I'm having (and the reason for this question) is that no matter what I do, the pulseIn() does not work. I've pasted the relevant code below. Note that the sensors.cpp file was originally made in Energia, then imported into code composer so that it could be integrated with the main.c file.

So this is how my code works. In main.c, U1 will receive an 'I' as an interrupt. In this case, I will call the function fwd(). In the fwd() function, I call the function detectUltraFwd(), which is in sensors.cpp. (It's labeled fwd because later there will be a second ultrasonic sensor for the reverse direction). detectUltraFwd() calls detectUltrasonic(int trig, int echo), where "trig" and "echo" are the specific pins where the ultrasonic sensor is connected to the msp. (Note again, this file came from Energia, so it's a little different than a standard code composer c file).

The problem arrives at the line with the pulseIn() function. According to the function, 0 is returned when there was no measured pulse within the specified timeout. I've tried timeout values varying from 100us to 1s, the maximum value for the function, to no avail. This function always returns 0 and I don't know why. I'm not sure if it's even possible to take a single sample using an ultrasonic sensor. I've tried having the detectUltrasonic() function loop a few times in case just the initial reading was zero, but that wasn't it. The conclusion that I've come to is that it has something to do with micros() not working. Since I'm using interrupts, calling micros() will return 0. (Which is why I'm using the volatile integers to pass time. And yes, I am well aware that I need to play around with the timing to get it close enough to the values I want.)

Any insight / help with this matter would be appreciated. My initial searches did not show a resolution to this issue.

main.c

#include <msp430.h>
#include <string.h>
#include <stdlib.h>
#include "motors.h" // my file used for motor control
#include "sensors.h" // my file used for sensor control

int sensingDist=46; //cm

int main(void)
{
	WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

	// initialize A0 uart for communication
	P3SEL = BIT3+BIT4;                        // P3.4,5 = USCI_A0 TXD/RXD
	UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
	UCA0CTL1 |= UCSSEL_2;                     // SMCLK
	UCA0BR0 = 9;                              // 1MHz 115200 (see User's Guide)
	UCA0BR1 = 0;                              // 1MHz 115200
	UCA0MCTL |= UCBRS_1 + UCBRF_0;   // Modln UCBRSx=0, UCBRFx=0, over sampling
	UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
	UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

	// initialize A1 uart for communication
	P4SEL |= BIT4+BIT5;                       // P4.4,5 = USCI_A1 TXD/RXD
	UCA1CTL1 |= UCSWRST;                      // **Put state machine in reset**
	UCA1CTL1 |= UCSSEL_2;                     // SMCLK
	UCA1BR0 = 9;                              // 1MHz 115200 (see User's Guide)
	UCA1BR1 = 0;                              // 1MHz 115200
	UCA1MCTL |= UCBRS_1 + UCBRF_0;   // Modln UCBRSx=0, UCBRFx=0,
	UCA1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
	UCA1IE |= UCRXIE;                         // Enable USCI_A1 RX interrupt

	// Set the pinout for the motor controller.
	setup(); // see motors.h

	P1DIR |= 0x01; // set blue led as output 1.0
	P4DIR |= 0x80; // set green led as output 4.7
	P4OUT |= 0x80; // turn on green led
	P1OUT &= ~0x01; // turn off blue led

	__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0, interrupts enabled
	__no_operation();                         // For debugger
}

// lots of irrelevant code was removed, including the A0 interrupt. 

// USCI_A1 interrupt -- bluetooth module (or terminal if debugging)
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A1_VECTOR))) USCI_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(UCA1IV)
  {
	case 0:break; // no interrupt
 	case 2: // RXIFG - received a character!

		if('I' == UCA1RXBUF)
		 {
 			// Move forward
 			fwd();
		 }
 		break;
	case 4: break; // TXIFG - sending a character
	 default: break;
  }
}

void fwd()
{

        // Check to see if there's an object in the way
	int dist = detectUltraFwd();
	if(dist > sensingDist) // if the returned distance is greater than sensingDist, we can freely move forward.
	{
		forward(rotateSpeedFB, rotateLengthFB); // see motors.h - tells the robot to move forward.
	}
	else // otherwise the ultrasonic sensor has detected an object in the way. blink the blue led a couple times as an indication.
	{
 		toggleBlue();
		volatile int c = 0;
		for(c=0; c<10000; c++);
		toggleBlue();
		for(c=0; c<10000; c++);
		toggleBlue();
		for(c=0; c<10000; c++);
		toggleBlue();
		for(c=0; c<10000; c++);
		toggleBlue();
	}
}

sensors.cpp

#include "Energia.h"
#include "sensors.h"

const int ultraTrigFwd = P3_5;
const int ultraEchoFwd = P3_6;

int detectUltraFwd()
{
	return detectUltrasonic(ultraTrigFwd, ultraEchoFwd);
}


//ultrasonic function
int detectUltrasonic(int trig, int echo)
{
	long duration, cm;

	 // set pin as output
	 pinMode(trig, OUTPUT);
	// set it low & wait 2us - in order to get a clean signal.
	digitalWrite(trig, LOW);
	senswait(3);
	// Then set it high for 5 us - i.e. begin taking the measurement.
	digitalWrite(trig, HIGH);
	senswait(10);
	digitalWrite(trig, LOW); // now stop taking the measurement



	//setting up input pin, and receiving the duration in microseconds
	pinMode(echo, INPUT);
	duration  = pulseIn(echo, HIGH, 1000); // *** THIS RIGHT HERE ALWAYS RETURNS ZERO ***

	cm = microSecondsToCentimeter(duration);

	return cm;
}


long microSecondsToCentimeter(long microseconds)
{
	//The speed of sound is 340 m/s or 29 microseconds per centimeter.
	//Convert speed
	return microseconds/29/2;
}

// This function is being used since micros() will always return zero. So I'm burning clock cycles this way.
void senswait(int delay)
{
	for(int i=0; i<delay; i++) {
		volatile unsigned int x;
		x = 5000;
		do x--;
		while(x !=0);
	}
}

Also, no, this is not my complete code, so there might be missing declarations etc. that I forgot to paste in. I'm pretty sure I've got almost everything, but just an fyi.

Thank you in advance for your help.

  • Are you sure that there actually is a pulse? How?
  • While testing I put an infinite loop within the detectUltrasonic function. When that happens, you can hear the sensor clicking as it is turned on and off. I then reduced the infinite loop to a loop that counted to 5 before returning, with pauses in between each iteration of sending and estimating the pulse, and you can still hear it clicking. So I know that it's definitely on and trying.
  • First, using a for loop for a delay isn't reliable. you don't know how the compiler compiles it. And it might be even optimized away totally (putting volatile on a local variable is futile, as the compiler knows for sure whether a local variable can't be volatile).
    If you want to burn CPU cycles, use __delay_cycles() or use a timer (that's what timers are designed for).

    Now your code talks about waiting 2µs and 5µs.
    if I look at your code and assume that senswait(10) would indeed give a 5µs delay, then your CPU must run with whopping 30GHz.
    (simplified: 3 CPU cycles per count for 5000 counts and this 10 times means 150000 CPU cycles in 5µs = 30.000 cycles per µs = 30GHz CPU clock.)

    Even if you wanted a ms delay, you're still far off. And in just 1ms, you'd have 34cm signal way.
    With the delay you have, you might be able to detect whether the moon is there or not. But any signal reflection from within the ultrasonic sensor range has long dissipated when your delay is over.
    The call to senswait() alone, without parameters, without any code inside, will take 6µs@1MHz

    The last time I've someone was asking for help with an ultrasonic detector, we worked out a mechanism using the timer PWM to generate the activation pulse and the capturing the return signal. With a precision of single timer ticks. And always the latest value captured in the background, while the main code was doing something else.
    This is a microcontroller, no PC. You don't have to do everything in software. Use the hardware. It's there to be used.

**Attention** This is a public forum