Lab 1
Introduction
Github
You will be using the IU enterprise github installation. This is a version control system that has a rich set of features for developers. Your team will be creating a single private repository called digitalsystems.
- one team member should create a new repository at https://github.iu.edu named digitalsystems.
- Create the repository as private.
- Initialize it with a README.
- Use the "Admin" toolbar menu to access the properties for the repository.
- Add your partner as a collaborator. Additionally add the following instructors as collaborators to allow for evaluation of your source code. They will receive notification when you add them as a collaborator.
- Clone your repository. Swap yourusername with the correct information for your repository.
git clone git@github.iu.edu:yourusername/digitalsystems.git
Code Template
You should now have a directory in your storage space called digitalsystems. The next step will involve initializing this space with date from a code template. This template provides a build framework and an initial starting point for your course code base.
- Copy the template code from /l/arm2/resources to your digitalsystems directory. Adjust the path to your digital systems directory.
cp /l/arm2/resources/digitalsystems.tgz /path/to/digitalsystems
- Untar the template into the digitalsystems directory.
bhimebau@silo:~/forge/digitalsystems] $ tar zxvf digitalsystems.tgz
- This framework contains a directory for lab1 along with an area to keep your driver code. In this lab you will write drivers for the leds and the F3 board button.
- remove the digitalsystems.tgz file.
rm digitalsystems.tgz
- add the code to your repository.
git add *
git commit -m "initial commit of the code template"
git push origin master
- You should navigate to the web address for your repository and confirm that the code has been updated.
- For more information about git, Scott Chacon has an excellent reference posted at Pro Git.
Initial Code Build
You are almost ready to build the template. You will just need to update your path and then make the code.
- Path: Assuming that your are using a bash shell, you will need to add the following to your .bashrc file.
export PATH=/l/arm2/codesourcery/bin:$PATH
- Building the code: Enter the lab1 directory and make the code.
[bhimebau@silo:~/forge/digitalsystems] $ cd lab1/
[bhimebau@silo:~/forge/digitalsystems/lab1] $ make
- The final output of this process is lab1.elf. Confirm that this file was created.
[bhimebau@silo:~/forge/digitalsystems/lab1] $ ls
ds_led.d ds_led.o lab1.elf main.c main.d main.o Makefile startup_stm32f30x.o stm32f30x_gpio.d stm32f30x_gpio.o stm32f30x_rcc.d stm32f30x_rcc.o system_stm32f30x.d system_stm32f30x.o
[bhimebau@silo:~/forge/digitalsystems/lab1] $
Downloading to the Board
There are a couple of ways to download your code to the flash on the F3 board. This example will describe the simpler process using a utility called st-flash.
- Confirm that your board's usb connector is plugged into the machine. The F3 board has two USB connections. The one labeled USB-ST-Link is the one that you need to connect.
- Downloading: the st-flash utility will copy a binary file to the STM32F3 flash through the stlink debugger channel. A utility called objcopy will be used to create the binary file that we need for downloading. This entire process is included when you run the following make command.
bhimebau@osprey:~/forge/digitalsystems/lab1$ make download
- Congratulations you have just created your first build and downloaded it to the board. You will not see much with this build because we still need to add functionality to this code. Currently the code initializes and then sits in an infinite loop.
LED
This section will focus on lighting one of the LEDs on the board.
- Determining the correct port and pin for the LEDs: We will use schematic to locate the LEDs. See page 4 which includes a compass rose that illustrates the leds along with the associated port mapping.
- Let's target the north facing red led. This led is on port E at pin 9 (PE9). Notice that all of the leds are attached to Port E. Additionally, note that the port pins run through the leds to ground. This indicates that a one on the pin will cause the led to light.
- ST Libraries: ST has developed a set of libraries that simplifies the interface to the peripherals in the STM32F3. The source code for these libraries is located at:
/l/arm2/STM32F3-Discovery_FW_V1.1.0/Libraries/STM32F30x_StdPeriph_Driver
This code is documented using the Doxygen documentation tool. The documentation for the libraries is posted at http://www.cs.indiana.edu/~bhimebau/f3lib/html/.
- We are going to want to specifically focus on the GPIO_Init function in the stm32f30x_gpio.c file. This function takes a GPIO port and an initialization structure as inputs. The structure allows us to configure the parameter for one or many pins on the same port simultaneously. For now, add this structure initialization to your main() in main.c of the lab1 directory.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- If you would like to extend this function to configure more than pin 9, you can "or" in additional pins to the GPIO_InitStructure.GPIO_Pin member.
- Now that we have the structure defined, we need to call the GPIO_Init function to apply this structure to the specific pin on port E. However, prior to doing this, recall that we need to enable the clock for this port. We do this using a call to the Reset and Clock Control (RCC) peripheral.
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
- Once the clock is enabled, we can go ahead with the port configuration.
GPIO_Init(GPIOE, &GPIO_InitStructure);
- PE9 is now configured as an output. To write a one to the pin, you need to write to GPIOE's bit set register.
GPIOE->BSRR = GPIO_Pin_9;
- If we were interested in turning the LED off, we could use the reset register.
GPIOE->BRR = GPIO_Pin_9;
- You main() function should look something like the following:
int main(void) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIOE->BSRR = GPIO_Pin_9;
while (1);
}
- Building: Run make on the lab1 directory.
bhimebau@osprey:~/forge/digitalsystems/lab1$ make
- Error: You should receive an error similar to the following:
/home/bhimebau/forge/digitalsystems/lab1/main.c:49: undefined reference to `RCC_AHBPeriphClockCmd'
/home/bhimebau/forge/digitalsystems/lab1/main.c:51: undefined reference to `GPIO_Init'
This is telling you that the linker tried to resolve the symbols and ran into a couple of problems. This is because we need to specifically tell the compiler to build the RCC and GPIO drivers. To correct the issue, we need to add the driver object files to the build objects in the Makefile:
OBJS= $(STARTUP) main.o ds_led.o stm32f30x_rcc.o stm32f30x_gpio.o
- When we run make again the code should build cleanly. We can go ahead and download it to see if we get the expected result on the red led.
make download
- If all went well, the top red led should be constantly on.
Button:
The F3 board includes a user input button. The user input button is blue while the system reset is the black button. We are going to track the status of the user button on the red led.
- Initialize the input pin: Review page 4 of the schematic to identify the port and pin for the USER & WAKE-UP button.
- Don't forget to enable the clock the port that includes the button.
- Setup the structure to initialize the pin as an input. You will need to set the GPIO_Mode. You will not need to set GPIO_OType or GPIO_Speed. For an input you might need to set GPIO_PuPd_NOPULL. However, since the button circuitry already pulls the pin to a stable state, adding an internal pull-up or pull-down is not needed in this case.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
- Reading the pin: You can read the state of the input bit using GPIO_ReadInputDataBit. This function takes a port and a pin as input and returns the status Bit_SET or Bit_RESET.
- Use an if block to link the button state to the red led state. When the button is SET (pressed), turn on the LED using:
GPIOE->BSRR = GPIO_Pin_9;
When the button is RESET (released), turn off the red LED using:
GPIOE->BRR = GPIO_Pin_9;
- Congratulations, you have written you first I/O driven program for the board! Next we are going to rearrange the code and extend it to include the other 7 LEDs.
Assignment:
As the programs in the course grow, the initialization code will expand as well. It will be helpful if we encapsulate the initialization and helper functions in other files. In this assignment, you are going to be moving the led setup and low level driving code from the main() function and into the digitalsystems/driver/src/ds_led.c driver file.
- In the digitalsystems/driver/src/ds_led.c there are stubs of the functions that you need to write. You will need to move and extend the led initialization code that is currently in your main function.
void ds_led_init(void) {
// initialize the port and pins for the 8 leds
}
void ds_led_on(int led) {
// enable the led specified by led parameter
// led = 0-7 representing the 8 leds
}
void ds_led_off(int led) {
// disable the led specified by led parameter
// led = 0-7 representing the 8 leds
}
void ds_led_all_on(void) {
// turn on all 8 leds
}
void ds_led_all_off(void) {
// turn off all 8 leds
}
- Write and test these 5 functions to ensure that all of the functions work properly.
- Delay function: In main.c of lab1, you will notice that there is a function called delay. This function runs through a look to create a delay. You are going to use this function to create pause between lighting each of the leds in sequence. You can adjust i to set the length of the delay.
void delay(void) {
int i = 2000000;
while (i-- > 0) {
asm("nop"); /* This stops it optimising code out */
}
}
- Sequenced led output: Utilize your led control functions to sequentially light each led. Pressing the user button will pause the sequence. The sequence should start with all leds off and and then end with all leds on. With exception of the all leds on state, only one led should be on at a time. The sequence should proceed around the circuit in a clockwise direction. The speed the sequence operates is up to you. However, it should be possible to visually identify each individual led state.
To implement the pause, think about where your program spends most of it's time when considering where to install the button polling.
What to Turn in:
This assignment is due by midnight on 1/17. At midnight, your AI will pull the current state of your repository to review your code. In the following lab session, you will be asked to demonstrate your solution. Independently, you will also write a lab report describing in approximately 300 words or less the following:
- Description of issues that you encountered in developing your solution.
- Information that was needed to complete the lab but was not included.
You will turn in this lab report in the oncourse assignments section.