Polulu Sensor Library Issue

Hello, recently I bought the QTR-1RC from Pololu. I am using a Teensy 3.1 to read the data. This uses an arduino addon called teensyduino, which allows me to do the programming in arduino. Anyways, I hooked it up and I kept getting 0’s for my data. So I thought this was very weird and did A LOT of debugging. I was testing everything, and everything seemed fine. Eventually, I called Pololu and the guy suggested I try making a basic program myself. Well, low and behold, I started to get better numbers. I did some digging and I found the issue in Pololu’s code I believe. Here are a couple of things that I suggest they change in their library for QTRSensors.

Line 432: (The pinMode and digitalWrite lines should be switched.)

sensor_values[i] = _maxValue; digitalWrite(_pins[i], HIGH); // make sensor line an output pinMode(_pins[i], OUTPUT); // drive sensor line high

Line 445:

unsigned long startTime = micros(); while (micros() - startTime < _maxValue) { unsigned int time = micros() - startTime; for (i = 0; i < _numSensors; i++) { if (digitalRead(_pins[i]) == LOW && time < sensor_values[i]) sensor_values[i] = time; } }
I would recommend changing to:

unsigned int time; do { time = micros() - startTime; for (i = 0; i < _numSensors; i++) { if (digitalRead(_pins[i]) == LOW && time < sensor_values[i]) sensor_values[i] = time; } } while( time < _maxValue);

The original code would call micros() and subtract the startTime twice. Once for the while loop, and then once again to set the time. I’m sure the compiler can catch that, but the second method seems more efficient.

Thank you.


The order of the digitalWrite() and pinMode() calls in the portion you quote is intentional, though it looks like the comments are misaligned and should be swapped: it configures the state of the output prior to enabling the pin as an output, avoiding a brief period of driving the pin low. If changing the orders of those two calls makes the program go from non-functional to functional, that would be an indication of a bug in the teensyduino implementation (e.g., maybe their implementation of pinMode() is clearing the PORT bit in addition to changing the data direction bit). It is okay to change the order of those calls if that is what it takes to get it working on your Teensy.

As for your second suggestion, I don’t think the improvement is very significant, but I agree that your version is a little nicer; do you want to submit a pull request on GitHub? By the way, this isn’t something the compiler can catch and optimize away because the return value of micros() might be different in the two places it’s called.

- Ben

Thanks for the response Ben. When I was first reading through the source code and noticed that, I thought that maybe it was intentional as well. So I went to the Arduino website and researched digitalWrite.

If you take a look here: http://arduino.cc/en/Reference/digitalWrite

[quote]If the pin has been configured as an OUTPUT with pinMode(), its voltage will be set to the corresponding value: 5V (or 3.3V on 3.3V boards) for HIGH, 0V (ground) for LOW.

If the pin is configured as an INPUT, digitalWrite() will enable (HIGH) or disable (LOW) the internal pullup on the input pin. It is recommended to set the pinMode() to INPUT_PULLUP to enable the internal pull-up resistor. See the digital pins tutorial for more information. [/quote]

This suggests that the digitalWrite command should be written after the pinMode is set to OUTPUT. Otherwise, it will just enable/disable the internal pullup on the input pin.

Also, I took a look at the github and noticed that there was a bug reported from March of 2014. I decided to post the issue here because it is more likely it will receive a response. Would you suggest I post a bug report anyways?

If you look at what those functions are doing to the AVR registers, you’ll see that it’s okay to call them in what seems to be the “wrong” order if you are just going by the Arduino function names. The pinMode() function configures the data direction register (DDRx), which determines if a pin is an input or output. The digitalWrite() function configures the PORT register, which determines the pin output value or default input value. When the pin is set as an input (i.e., the DDRx bit is zero) and the PORT bit is one, it is an input with the internal pull-up enabled. If you then set the DDRx bit to one while leaving the PORT bit high, the pin becomes a driving-high output. That is what happens if you call digitalWrite(pin, HIGH) before calling pinMode(pin, OUTPUT), and this is the behavior we want.

If you take our library code and only change the order of those two functions, does it go from non-working to working in your setup?

Edit: Oh, I just realized you’re using a Teensy 3.1, which is not based on an AVR. I do not know the details of how the I/O registers work on your board’s microcontroller, but everything I said about how the pinMode() and digitalWrite() functions work on an Arduino likely does not apply to the teensyduino implementation, and it is totally conceivable that the order of those calls matters for you. Can you confirm it works with the function order switched?

- Ben


I just ran into this issue again, using the Teensy 3.5. Swapping the digitalWrite and pinMode lines as addison mentions solves the problem. And the swapped lines still work as expected on the Uno as well. FWIW.