Welcome to the Embedded Systems Programming course. My name is Miro Samek and in this lesson I'll introduce you to arrays and basic pointer arithmetic in C. You will learn how to apply these concepts to take advantage of the more advanced features of the Stellaris GPIO DATA registers, which I hope will answer some questions asked in the comments to this video course posted on YouTube. As usual, let's start with making a copy of the previous "lesson6" project and renaming it to "lesson7". If you are just joining the course, you can download the previous projects from state-machine.com/quickstart. Get inside the new "lesson7" directory and double-click on the workspace file to open the IAR toolset. If you don't have the IAR toolset, go back to "lesson0". So, this is the program you created in "lesson6". Let's clean it up a bit and step into the debugger. As you can see, this program uses read-modify-write sequences to change the value of individual bits of the GPIO register without disturbing the other bits. For example, to set bit-1 controlling the red-LED, the program first reads the current value of the GPIOF DATA register with the LDR instruction. Next it uses the bit-wise OR to set the bit-1, and finally it writes the modified value back with the STR instruction. The read-modify-write sequence is necessary, because all the GPIO bits are co-located in a single byte, with a single address. But imagine that each bit could be accessed separately through its own unique address. Or better yet, every possible combination of GPIO bits would have its own unique address. Then a single, atomic write operation to this particular address would change the selected bits without disturbing any other GPIO bits. In this lesson, I will show you how the Stellaris GPIO hardware allows you to do exactly this, so that you can replace the typical read-modify-write sequence with a single and atomic write operation. But before I explain HOW to do this, I think it's interesting to understand WHY bother. After all, the read-modify-write sequence is fast enough for most cases. Well, it turns out that it is not so much about the speed in this case, but rather to give you the ability to manipulate the individual GPIO bits truly independently; from any part of your code, including from interrupts. Now, I realize that I haven't talked about interrupts yet, and I promise I will, because it is a fascinating subject, especially in embedded systems. But just for now let me only say that interrupts are a hardware-supported mechanism for a processor to abruptly change the flow of control in your program. When an interrupt occurs, a special hardware in the processor changes the value of the program counter register so that the processor suddenly starts executing a different piece of code called the interrupt service routine or ISR, which is typically quite short. When the ISR ends, the processor resumes the execution of the original code as though nothing happened. The interesting case is when the ISR changes some GPIO bits. If the interrupt happens to come in the middle of the read-modify-write cycle, after the main code reads the GPIO register, but before it writes the modified value back, any changes to the GPIO bits made in the interrupt service routine will get lost. This is because the main code will still use the previous value of the GPIO register, before the interrupt happened. This is the inherent problem with the read-modify-write sequence. So that's the main reason why the designers of the Stellaris GPIO hardware devised a way to avoid the read-modify-write sequence and replace it with a single and atomic write operation. Here is how it works. The GPIO bits are connected to the CPU with the bunch of wires called a bus. Each bit is connected to both a dedicated data line and a dedicated address line as well. The bit can be changed only when the connected address line is 1, otherwise the bit is unaffected, regardless of the value of the attached data line. For example, to isolate the three GPIO bits connected to the LEDs, you need to write to the address ending with 0000111000 binary. Please note that the two lowest-order address lines A0 and A1 are not used, because the hardware requires all addresses to be divisible by 4. The data you write determine the state of the pins. For example, you can light up the red-LED, extinguish the blue-LED and light-up the green-LED, all in a single write operation. I hope it is becoming clear that this hardware design requires many registers with unique addresses, because not only each GPIO bit has its own address-- for this you would need only 8 registers. Each combination of bits has its own address in this scheme. To cover all possible bit combinations of 8 GPIO bits, the Stellaris GPIO provides 256 32-bit DATA registers starting with the address 0x40025000. So far in the previous lessons, you have been using only the last of these registers called GPIO_PORTF_DATA_R corresponding to the offset 1111111100 binary, which is 0x3FC hex. This register obviously didn't isolate any bits, and enabled all 8 GPIO bits to be changed with data lines. In this lesson we will use the other registers. So, now the question is how to access all those GPIO registers in C. One way is to hard-code the address directly, with the brute-force approach you learned in lesson 3. For example, to isolate only the bit-1 corresponding to the red-LED, you could manually compute the address by starting with the base address from the datasheet and adding to it the LED_RED bit left-shifted by two to skip the two unused address bits. You need to cast the synthesized address to a pointer and de-reference the pointer. Remembering that this address isolates just a single bit, it matters only what you write to this particular bit, and it is irrelevant what you write to the other bits. For the sake of demonstration, let's write 1 to the LED_RED bit and 0 to all the other bits. Let's check if this code compiles by pressing F7. Now it is of course interesting to test this on the Launchpad board. As you can see, the read-modify-write sequence is simplified to just the STR instruction to the address in R2, which is the GPIO base address plus the offset 8. When you step through the code, you see that the red-LED lights up, and the other LEDs stay unchanged, proving that the code does exactly what you wanted. So the code works, but is not very elegant. You can improve it significantly by applying the concept of an array. An array is a group of variables of the same type, occupying consecutive memory locations, such as the group of 256 identical GPIO DATA registers. In C you can declare an array by adding the number of elements in square brackets to a variable. For example, this is an array of two counters, each being a volatile integer. You can even initialize the whole array at once, by using the array initializer, like this. Now, you can use the array elements as normal variables by referring to the elements by their numbers. The number in the brackets is called the array index and the first element of an array in C has always 0. The second is 1 and so on. Let's compile by pressing F7 to see if the compiler accepts the syntax. Arrays in C are closely related to pointers. The C compiler treats an array as a pointer, which points to the beginning of the array. To get a pointer to an element with index i, you simply need to add i to the array pointer. So instead of counter[1] you can write *(counter + 1). This is an example of a simple pointer arithmetic. The correspondence between arrays and pointers goes both ways, because every pointer can also be viewed as an array. For example, the standard LM4F header file defines the pointer GPIO_PORTF_DATA_BITS_R. This pointer can be used to access all 256 GPIO DATA registers as an array. So, for instance to access only the LED_RED bit, you can index into GPIO_PORTF_DATA_BITS_R like this... which is exactly equivalent to using the following pointer arithmetic... Let's step into the debugger to see how these three options compare. As you can see, all three implementation options write to the same address stored in the R4 register, So this little experiment shows that indeed all the three alternatives are equivalent and generate the exact same machine code. Going back to the source code, let me point out the very important difference between address arithmetic and pointer arithmetic. In the first case, you perform address arithmetic first and only then you cast the raw address to the unsigned long pointer. In this case, you had to left-shift the LED_RED value by two bits, to take into account the size of the GPIO register, which is 4-byte wide. In the second case, you use pointer arithmetic, because GPIO_PORTF_DATA_BITS_R is a pointer to unsigned long. In pointer arithmetic you don't need to scale the offset by the size of the element, because this is done automatically for you. This must be so, because of the equivalence between pointer arithmetic and array indexing. Of all these thee options, I think that array indexing looks the cleanest, so I am going to leave this one and comment out the others. Now, let's use the array indexing technique to clear the red-LED. As you remember from the wiring diagram, this requires writing 0 to the LED_RED bit position. Finally, I use the array indexing consistently for setting the blue-LED bit in the beginning. So, this is the final program that uses the fast and interrupt-safe technique for manipulating GPIO bits. Let's test this program on the Launchpad board... First, let's run full speed and watch the LEDs. As you can see the program works as before. When you break into the code, you can see that clearing the red-LED bit takes only one STR instruction to the GPIO address in R0. So, your program is about as good as it gets, except that, as it turns out, the Stellaris LM4F microcontroller can do even better. As you can find out in the Datasheet, the microcontroller has not one, but two peripheral busses. Advanced Peripheral Bus (APB) and Advanced High-Performance Bus (AHB). The GPIO ports are connected to both. The APB bus is the default and this is what you've been using so far. But APB is older and slower than AHB, and is kept only for backwards compatibility. So in the remaining minute of this lesson, I will show you how to switch to the faster and better AHB. First, you need to find in the Datasheet how to switch GPIO from the default APB to AHB. In the system control section, you find the GPIOHBCTL register, which does exactly this. You note that PortF is controlled by bit number 5. Next, you go to the LM4F header file and look for the GPIOHBCTL register. You copy the register name and set bit 5 in it. Finally, you need to change all GPIO addresses from the APB address range, which is called APB aperture in the Datasheet, to the AHB aperture. You search again the LM4F header file for GPIO_PORTF and you find a set of registers with the _AHB suffix. So, you need to add this suffix to all the GPIO_PORTF registers in your program. Let's test this final version on the Launchpad board... This concludes this lesson about arrays and pointer arithmetic in C. Now you are an expert in Stellaris GPIO, so congratulations! In the next lesson, I'll talk about C functions! If you like this channel, please subscribe to stay tuned. You can also visit state-machine.com/quickstart for the class notes and project file downloads. --- Course web-page: http://www.state-machine.com/quickstart YouTube playlist of the course: http://www.youtube.com/playlist?list=PLPW8O6W-1chwyTzI3BHwBLbGQoPFxPAPM