Part 3 : GPIO : ARM Assembly : Line Follower : TI-RSLK

About: Have enjoyed a mostly fun ride in an electronics and software career. Also enjoy latin dancing.

Hello. This is the next installment where we continue using ARM assembly (instead of a higher-level language). The inspiration for this Instructable is Lab 6 of the Texas Instruments Robotics System Learning Kit, or TI-RSLK.

We'll be using the microcontroller from the kit, the MSP432 LaunchPad development board, but perhaps you'll find something useful to extract from this Instructable even if you are not using the LaunchPad, or following the T.I. curriculum.

We began with an Instructable introducing ARM Assembly, the development environment, and how to make a project.

The next Instructable on ARM Assembly introduced how to interact with input/output (GPIO).

Then we expanded our knowledge, and introduced functions, controlling LEDs and switches.

Now with this Instructable, we can use what we've learned to do something more fun, more useful: detect a line.

This can help us later on when we build a line-follower robot.

In the curriculum, most of the programming is done in C or C++, but it is helpful to become familiar with assembly, before we start depending on higher-level languages, and libraries.

Step 1: The Hardware

I don't want to rehash the hardware in detail, as there are already sources, but we'll add explanations where needed.

For this Instructable, we'll be using the Reflectance Sensor Arrray from Pololu, since it comes as part of the TI-RSLK (the robot kit). It is the one used in the course, and in Lab 6 of the curriculum.

If you don't have that, you can use any IR detector (or series of them) that outputs a digital signal, HIGH or LOW, for presence and absence.

The array sensor is best because it can help detect whether we are right at the center of the line, or off to one side. Plus, as we'll see later, it can help us detect the robot's angle with respect to the line.

The reflectance array has detectors very close next to each other. That means we should get multiple detection signals, depending of course on the thickness of the line.

If so, then if the robot is not directly inline with the line, then it should return an output that the line is wider than it should be (because we're at an angle).

For a better explanation of the above, take a look at the Lab 6 document.

For help in wiring / connecting the sensor to the MSP432 LaunchPad development board, here are some helpful instructions.

I have also added the same(similar?) pdf instructions to this Step.

If you carefully read the Pololu documents, they explain the reason for the "3.3V bypass", that you'll want to jumper if you're using 3.3V instead of 5V.

Since we are not yet building the robot but instead we are just learning about ARM assembly and also how to interact with pieces (subsystems) of the robot, we don't have to follow the above instructions to the letter.

For now, connecting the line sensor array just boils/reduces down to the following:

  • connect 3.3V and GND from the MSP432 board to the sensor array.
  • connect a port pin (I suggest P5.3) from the MSP432 to the LED enable pin on the line sensor array. That pin on the sensor is between 3.3V and GND.
  • connect all eight pins/bits of a single port (I suggest P7.0 through P7.7) to the eight pins of the sensor array labeled "1" through "8". These are the lines that will go HIGH or LOW depending on what they sense.

As you can see in the images of this step, and in the video, I did not attach the sensor to the robot chassis, because I wanted ease of programming, debugging, testing, learning.

So with everything connected, we are ready to get into the software.

Step 2: Line Following

The reflectance array sensor is pretty nifty because it can help out in at least two ways.

  • Determine is the robot centered on line or drifting off to one side.
  • Is the robot aligned in the direction of the line, or is it at an angle.

Each of the detectors of the array essentially provide one bit of information, either HIGH or LOW.

The idea is to combine all those bits into a single number or single bit-pattern, and use that pattern to make decisions (in order to move correctly).

Step 3: Before We Can Really Get Started....

.. we need to learn something new about ARM assembly programming. And I don't just mean another instruction. Those tend to be minor.

Up to now we have not used the "stack" in our programs.

We have relied on using most of the core cpu registers globally across different subroutines.

The one thing we did do was to save and restore the LR (link register) address for one function - the one that called several other functions. (I use "function" and "subroutine" interchangeably here).

What we've been doing isn't good. What if we want to nest other functions? What if we have more than one level of nesting?

In previous examples, we chose to use register R6 as the storage for the LR or return address. But if we want to do further/deeper nesting, we can not continue to change the value of R6. We would have to pick yet another register. And another. And then it becomes burdensome to keep track of which core cpu register holds which LR to restore to which function.

So now we take a look at the "stack".

Step 4: The Stack

Here is some reading material explaining the stack.

I'm a bigger proponent of a couple of ideas:

  • only as much theory as required, go for the practical quickly
  • learn as needed, focus on actually doing something and not just purposeless exercises or examples.

There is plenty of ARM and MSP432 documentation online that talks about the stack, so not going to rehash all that. I'm also going to keep the usage of the stack here to a bare minimum - saving the return address (the Link Register).

Essentially, we only need to instructions:

PUSH {register list}

POP{register list}

Or, in our case, specifically:

PUSH {LR}

POP {LR}

So, an assembly function/subroutine would look like so:

funcLabel:	.asmfunc


	PUSH{LR}	;this should probably be one of the first instructions on entry.
	; do more code here..
	; blah .. blah... blah...

	; ok, we're done with function, ready to return back up to calling function
	POP{LR}		;this restores the correct return address back to calling
			; function.


	BX LR		; return

	.endasmfunc

The video goes through a live example of several nested functions.

Step 5: The Software

The attached file labeled "MSP432_Chapter..." has a lot of good information about the ports of the MSP432, and from that document we get the following ports, registers, addresses, etc. It's a bit dated, however. However, I didn't see the detailed addresses listed for Port 5 and up. (only "alternate functions"). But it's still useful.

We're going to be using two Ports. P5, P7, P1, and P2.

P5.3 (a single bit) output will be to control the IR LED-enable on the sensor. We're using P5.3 because it's an exposed pin on the same header as the other MSP432 connections going to the sensor array.

P7.0 through P7.7 will be the eight inputs that collect the data from the sensor; what it "sees".

P1.0 is the single red LED and we could use that to give us some indications of the data.

P2.0, P2.1, P2.2 is the RGB LED and we can use that as well, with its different color possibilities, to give us indication of the sensor data.

If you've gone through the previous Instructables related to all this, then you already know how to set up the program.

Just have declaration section for the ports and bits, etc.

You'll have a "main" section.

There should be a loop, where we continuously read the data from P7, make decision of that data, and light up the two LEDs accordingly.

Here again are the Port Register addresses:

  • GPIO P1 : 0x4000 4C00 + 0 (even addresses)
  • GPIO P2 : 0x4000 4C00 + 1 (odd addresses)
  • GPIO P3 : 0x4000 4C00 + 20 (even addresses)
  • GPIO P4 : 0x4000 4C00 + 21 (odd addresses)
  • GPIO P5 : 0x4000 4C00 + 40 (even addresses)
  • GPIO P6 : 0x4000 4C00 + 41 (odd addresses)
  • GPIO P7 : 0x4000 4C00 + 60 (even addresses)
  • GPIO P8 : 0x4000 4C00 + 61 (odd addresses)
  • GPIO P9 : 0x4000 4C00 + 80 (even addresses)
  • GPIO P10 : 0x4000 4C00 + 81 (odd addresses)

What's in bold is what we'll be using for this Instructable.

Program Steps To Read IR Detectors

The following is psuedo-code for writing the program in C, but it is still useful, and we'll follow it pretty closely in the assembly version of the program.

main program
0) Initialize //ports while(1) { 1) Set P5.3 high (turn on IR LED) 2) Make P7.0 an output, and set it high (charging the capacitor) 3) Wait 10 us, Clock_Delay1us(10); 4) Make P7.0 an input 5) Run this loop 10,000 times a) Read P7.0 (converts voltage on P7.0 into binary) b) Output binary to P1.0 (allows you to see binary in real time) 6) Set P5.3 low (turn off IR LED, saving power) 7) Wait 10 ms, Clock_Delay1ms(10); } // repeat (back to while() )

Step 6: Let's Improve the Code

The purpose or use of the Pololu IR LED array is to detect a line, and to know if the robot (future) is directly centered on the line, or off to one side. Also, since the line has a certain thickness, if the sensor array is directly perpendicular to the line, N number of sensors will have a different reading than the rest, whereas if the IR LED array is at some angle (not perpendicular), then N+1 or N+2 IR LED/detector pairs should now give a different reading.

Thus, depending on how many sensors indicate the presence of the line, we should know if we're centered, and if we're angled or not.

For this final experiment, let's just see if we can get the red LED and the RGB LED to give us more information about what the sensor array is telling us.

The video goes into all the details. The final code is also attached.

This completes the series of ARM Assembly related to GPIO. We hope to return with more ARM Assembly at a later time.

Thank you.

Share

    Recommendations

    • Make it Glow Contest 2018

      Make it Glow Contest 2018
    • Optics Contest

      Optics Contest
    • Plastics Contest

      Plastics Contest

    Discussions