Tutorial 1 : Blink
Basics
In this tutorial we will be dealing with the basic idea of GPIOs and how to configure them so as to light the on Board tri-color LED on the Stellaris LaunchPad. There are 6 General Purpose Input Output ports namely PA,PB,PC,PD,PE and PF. Each of the ports are capable of bit banding which can be used to configure each pin of any port in whatever way we wish to. A Newbie can think of bit banding as masking the corresponding pins that we wish to configure, so that the value that we send into the port will only affect the masked pins.
For. example if i am masking 6th pin of PORTA and then I send a value into the PORTA, the value will affect only the value of PIN6. This is what effectively bit banding do.
Now lets talk about the GPIOs. GPIO are General Purpose Input Output registers which available to the user to configure. These are connected to the external output pins of the Stellaris LaunchPad. These have an output voltage typically of 3.3V but it depends largely on the VBat. The maximum Current rating of each pin is around 40mA. The Tri-color LED on the Stellaris LaunchPad is made up of three LEDs namely RED GREEN and BLUE.When we look into the schematic of the LaunchPad, we see that the red LED is connected to the PF1, Blue LED is connected to the PF2 and Green LED is connected to PF3.
For. example if i am masking 6th pin of PORTA and then I send a value into the PORTA, the value will affect only the value of PIN6. This is what effectively bit banding do.
Now lets talk about the GPIOs. GPIO are General Purpose Input Output registers which available to the user to configure. These are connected to the external output pins of the Stellaris LaunchPad. These have an output voltage typically of 3.3V but it depends largely on the VBat. The maximum Current rating of each pin is around 40mA. The Tri-color LED on the Stellaris LaunchPad is made up of three LEDs namely RED GREEN and BLUE.When we look into the schematic of the LaunchPad, we see that the red LED is connected to the PF1, Blue LED is connected to the PF2 and Green LED is connected to PF3.
Step1 - Set up System Clock
In the Stellaris LaunchPad, there is an external main oscillator of 16MHz frequency. This is the Oscillator of our interest. If we check in the datasheet,
we can see that this External Main Oscillator is fed into the Phase Loop Lock(PLL) to generate a clock of 400 MHz. This clock is divided by 2 in the
hardware itself to generate a 200 MHz clock. This is then fed into the SYSDIV which is user configurable to generate the required system clock
frequency.Now, if we check in the datasheet, it is evident that the maximum system clock frequency that can be delivered to the LM4F120H5QR CPU is 80 MHz. This is the reason why SYSDIV is important to us.
In any code for this uC the firs line is supposed to set the clock frequency. Now let us see how to configure the clock frequency using the StellarisWare
DriverLib functions. The "SysCtlClockSet()" function can be used to set the clock frequency. The code snippet given below shows how to configure the
system clock to 40MHz.
we can see that this External Main Oscillator is fed into the Phase Loop Lock(PLL) to generate a clock of 400 MHz. This clock is divided by 2 in the
hardware itself to generate a 200 MHz clock. This is then fed into the SYSDIV which is user configurable to generate the required system clock
frequency.Now, if we check in the datasheet, it is evident that the maximum system clock frequency that can be delivered to the LM4F120H5QR CPU is 80 MHz. This is the reason why SYSDIV is important to us.
In any code for this uC the firs line is supposed to set the clock frequency. Now let us see how to configure the clock frequency using the StellarisWare
DriverLib functions. The "SysCtlClockSet()" function can be used to set the clock frequency. The code snippet given below shows how to configure the
system clock to 40MHz.
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
We need to generate a system clock of 40 MHz. We know that the input clock frequency after system prescale is 200 MHz. Now we need to prescale this by 5 which is done my the macro : SYSCTL_SYSDIV_5. There are many more prescales available which you are free to use. But make sure that the generated system clock frequency is less than 80 MHz.
SYSCTL_USE_PLL - this macro is used to specify that we are using the PLL to generate the 400 MHz clock frequency.
SYSCTL_XTAL_16MHz - This says to the uC that we give the input to the PLL from an external crystal(XTAL) of frequency 16 MHz.
SYSCTL_OSC_MAIN - This denotes that we are using an external main oscillator ( Again represents the 16 MHz crystal ).
Now we know that all these are to be done together, and that is the reason why we logically OR all the macros.
##NOTE - Generally inside a function whose name starts with SysCtl, the macro names will start with "SYSCTL_". This will help you in selecting the correct macro most of the time.
SYSCTL_USE_PLL - this macro is used to specify that we are using the PLL to generate the 400 MHz clock frequency.
SYSCTL_XTAL_16MHz - This says to the uC that we give the input to the PLL from an external crystal(XTAL) of frequency 16 MHz.
SYSCTL_OSC_MAIN - This denotes that we are using an external main oscillator ( Again represents the 16 MHz crystal ).
Now we know that all these are to be done together, and that is the reason why we logically OR all the macros.
##NOTE - Generally inside a function whose name starts with SysCtl, the macro names will start with "SYSCTL_". This will help you in selecting the correct macro most of the time.
Step 2 - Enable the GPIO
When an LM4F120h5QR uC is powered up, all the peripherals are disabled by default. Therefore we have to mention in our code, the GPIO ports that we need to enable. In our case, we know that all the 3 LEDs are in the PORTF. Therefore it is only required to enable the GPIO PORTF. By enabling a GPIO PORT, we mean that we enable the system clock to that peripheral so that the peripheral will work properly. This is done using the "SysCtlPeripheralEnable()" function as shown below.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
The above given statement is self explainatory. Now let us consider that we want to enable PORTA. this can be done as ginen below :
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
Step 3 - Setting The Data direction
This is an important step in using the GPIO. Setting the Data direction means nothing but to say the controller whether the GPIO PIN is an Input/output pin.
If this step is not performed properly, the GPIO may not work as we wish. The pins are configured by bit banding, which means that each pin to be configured must be mentioned separately when we configure the port. The function that we use to set a pin as input is "GPIOPinTypeGPIOInput()", whereas, the one used to set a pin as output is "GPIOPinTypeGPIOOutput()". Both the functions are having two parameters. The first one refers to the PORT that we want to configure. The second one refers to the pins that we want to configure. In case we want to configure more than one pin in the same port at a time, we will have to
logically OR each of the pin macros.
Eg. Consider that we want to
configure the PIN 6 of GPIO PORT F as output. This can be done as shown below :
If this step is not performed properly, the GPIO may not work as we wish. The pins are configured by bit banding, which means that each pin to be configured must be mentioned separately when we configure the port. The function that we use to set a pin as input is "GPIOPinTypeGPIOInput()", whereas, the one used to set a pin as output is "GPIOPinTypeGPIOOutput()". Both the functions are having two parameters. The first one refers to the PORT that we want to configure. The second one refers to the pins that we want to configure. In case we want to configure more than one pin in the same port at a time, we will have to
logically OR each of the pin macros.
Eg. Consider that we want to
configure the PIN 6 of GPIO PORT F as output. This can be done as shown below :
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_6);
Let us take another example. Consider that we want to configure the PIN5 and 7 of PORTA and PIN3 of PORTB also as input. This can be done as shown below :
GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_5|GPIO_PIN_7);
GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_3);
Step 4 - Writing data into the GPIO
This is the last step. We use the function called "GPIOPinWrite()" to write data to the bitbanded pins. The function has three parameters. The first one refers to the PORT that we want to configure. The second one refers to the pins that we want to configure. In case we want to configure more than one pin in the same port at a time, we will have to logically OR each of the pin macros. The third parameter is the value to be transferred to the pins. Eg. consider we want to set PIN3 of any port as high. So the data must be 0b00001000 in binary representation which in decimals can be written as 16. Now if the second parameter only contain GPIO_PIN_3, then even if we send 0b11111111 to the PORT, the value of PIN 3 will only be altered. This is due to bit banding. This means that in this case a value of 255 and 16 have the same effect.
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 2); //Lights the RED LED
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4); //Lights the BLUE LED
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 8); //Lights the GREEN LED
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 14); //Lights the ALL LEDs
Step 5 - Delay loop
Delay can be created by using the "SysCtlDelay()" function. The parameter to be provided inside the function specifies the number of loops it has to wait.
From the Stellaris API it is evident that the microcontrolleer takes 3 clock cycles to run a single delay loop. Therefore we create the delay getting the system clock frequency using the function "SysCtlClockGet()", dividing the value by 3 and then multiplying the result by the delay required in seconds.
The function provided below will do the job for us.
From the Stellaris API it is evident that the microcontrolleer takes 3 clock cycles to run a single delay loop. Therefore we create the delay getting the system clock frequency using the function "SysCtlClockGet()", dividing the value by 3 and then multiplying the result by the delay required in seconds.
The function provided below will do the job for us.
void delay_ms(int del) //generates delay in milliseconds
{
del = (SysCtlClockGet()/3.0)*del/1000.0;
SysCtlDelay(del);
}
Winding Up
The final code is given below. Hopes that the code will be clear and easy enough to understand.
main.c | |
File Size: | 1 kb |
File Type: | c |
/*
* Stellaris LAUNCHPAD LM4F120H5QR
* C++ code to blink the tri colour led
*/
#include <inc/hw_types.h>
#include <inc/hw_memmap.h>
#include <driverlib/gpio.h>
#include <driverlib/sysctl.h>
void delay_ms(int del)
{
del = (SysCtlClockGet()/3.0)*del/1000.0;
SysCtlDelay(del);
}
int main(void)
{
/*
* The System clock is run using a 16 Mhz crystal connected to the main oscillator pins of the microcontroller
* This generates a internal clock signal of 400 Mhz using the PLL
* The signal is prescaled by the system by 2
* Now we are defining a prescale of 5 in addition to make the clock frequency 40MHz
* The system clock frequency must be less than or equal to 80MHz
*/
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
/*
* Enabling the system clock for GPIO PORT F
* We must do this for every peripheral that we use
*/
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
while(1)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 2);
delay_ms(1000); // 1 second delay
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0); //explicitly turning off the led
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4);
delay_ms(1000);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 8);
delay_ms(1000);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
}
}