lab description - keil tools

21
Lab Description – Lab1 (Project lab1_hello_world) Objective Objective of this lab is to get familiar with Cortex M3, the evaluation/development kit, and the ARM/Keil tools set. We will write a simple program that toggles the LED connected to the GPIO port. The LED is on different pins for different boards: EK-LM3S811 - Port C, Pin 5 EK-LM3S3748 - Port F, Pin 0 EK-LM3S8962 - Port F, Pin 0 EK-LM3S 9B90/92- Port D, Pin 0 DK-LM3S9B96 - Port F, Pin 3 System Diagram Example (EK-LM3S8962) GPIO Port A Pin 0 Pin 7 GPIO Port F Pin 0 Pin 7 ... GPIO Port G Pin 0 Pin 7 LM3S8962 CPU Toggle Procedure 1. Get familiar with the directory structure used by all labs. The StellarisWare folder contains all of the software you need to run code on your board. The sub-folders for the four labs of this workshop are located in StellarisWare/boards/<board_name> , and start with the numbers 01 … 04. In the document folder (docs) you can find documentation about the processor, the evaluation kit and the peripheral driver library. The driverlib folder contains the source files of peripheral driver library (which is used to access all peripherals) while the inc folder contains the associated header files. 2. Start Keil uVision by clicking on the icon on your desktop, or from the Start Menu. Get familiar with the different icons and menus.

Upload: gnurt-neyugn

Post on 12-Apr-2015

53 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lab Description - Keil Tools

Lab Description – Lab1 (Project lab1_hello_world) Objective Objective of this lab is to get familiar with Cortex M3, the evaluation/development kit, and the ARM/Keil tools set. We will write a simple program that toggles the LED connected to the GPIO port. The LED is on different pins for different boards: EK-LM3S811 - Port C, Pin 5 EK-LM3S3748 - Port F, Pin 0 EK-LM3S8962 - Port F, Pin 0 EK-LM3S 9B90/92- Port D, Pin 0 DK-LM3S9B96 - Port F, Pin 3 System Diagram Example (EK-LM3S8962)

GP

IO

Por

t APin 0

Pin 7

GP

IO

Por

t F

Pin 0

Pin 7

...G

PIO

P

ort G

Pin 0

Pin 7

LM3S8962

CPU Toggle

Procedure

1. Get familiar with the directory structure used by all labs. The StellarisWare folder contains all of the software you need to run code on your board. The sub-folders for the four labs of this workshop are located in StellarisWare/boards/<board_name> , and start with the numbers 01 … 04. In the document folder (docs) you can find documentation about the processor, the evaluation kit and the peripheral driver library. The driverlib folder contains the source files of peripheral driver library (which is used to access all peripherals) while the inc folder contains the associated header files.

2. Start Keil uVision by clicking on the icon on your desktop, or from the Start Menu. Get familiar with the different icons and menus.

Page 2: Lab Description - Keil Tools

3. Each board directory contains a project file for your specific board. To open the project, select Project Open Project… and browse to the .Uv2 file in your board’s directory. In this lab, the project name is lab1_hello_world.Uv2.

4. Get familiar with the source code structure. We use three types of files in this project:

- C Source Files These is the program code that we write

- Library Files Libraries are collections of pre-compiled routines that can be re-used. In our case, we use the peripheral library (driverlib.lib) to access all peripherals.

In our labs we will only modify C source files, but you should familiarize yourself also with the structure of the linker command file.

5. Double-click on hello_world.c to open the main source file. Check its content. The tasks you should perform are marked as TO DO.

6. Your first task is to write an instruction that enables the GPIO peripheral connected to the LED. Remember that the GPIO peripheral is organized into different blocks (A…G) with each block containing 8 pins. Each block can be enabled and disabled separately by the system control module. Check the description of the system control module in the peripheral driver library documentation to determine which instruction enables a peripheral. Task: Enable GPIO Block (block letter depends on your board, see above) Hint: Use SYSCTL_PERIPH_GPIOx as parameter (example: SYSCTL_PERIPH_GPIOF)

7. Next, we need to set the pin type of the pin as GPIO output. Check the GPIO chapter of the peripheral library documentation on how this could be achieved. The correct instruction takes two parameters – the base address of the module and the pin which is selected. The base addresses are defined in the included hw_memmap.h file which you can find in the /inc folder. The GPIO-specific definitions can be found in the included gpio.h file which you can find in the /driverlib folder. Study these files to get an idea of the parameter naming. Task: Set the pin type of GPIO pin as GPIO output Hint: Use GPIO_PORTx_BASE and GPIO_PIN_n as arguments (example: GPIO_PORTF_BASE and GPIO_PIN_0)

8. In the main loop, we want to switch the GPIO pin ON and OFF. We do this by setting it to 0xff and 0x0 respectively. We use 0xff instead of 1 because the

Page 3: Lab Description - Keil Tools

GPIO module uses address masking to write pins. Using 0xff may appear to set all pins, but the address masking feature only passes the “1” to the appropriate pin. Use the GPIO chapter of the documentation to determine how to write to a pin (or several pins). The right instruction will use three parameters – the base address of the module, the selected pin(s) and the value to which this pin is set. Task: Set the output pin to ‘1’ and ‘0’ respectively at the indicated locations. Hint: Use GPIO_PORTX_BASE for the base address and GPIO_PIN_n for the selected pin (example: GPIO_PORTF_BASE and GPIO_PIN_0). Use 0xff as value if you want to set the pin and 0x0 to clear the pin.

9. Our program should now be (hopefully) complete. We can build it now by selecting Project Rebuild all target files. Check in the Build window if there were any errors. If so, then correct them and rebuild.

10. Connect the board to the PC via USB. USB is used both for powering the

board and for debugging.

11. Download the program onto the board by using Flash Download. To launch the debugger, select Debug Start/Stop Debug Session, and the program execution should be stopped at the application entry point.

12. Run the program using Debug Run. If the Status LED blinks then you have completed the basic part of this lab.

Advanced Part (Optional)

13. If you have some time to spare then do the following. Check the startup_rvmdk.S file to understand the structure of the interrupt vector table and how the stack is initialized.

14. Use the register window to determine the function of the different registers.

15. Check the value of the stack pointer and try to find out what has been pushed onto the stack.

16. Check the project build options (Project Options) and try to understand the different fields in there.

17. Use the watch window to check the values of variables

Page 4: Lab Description - Keil Tools

Lab Description – Lab2 (Project lab2_timers) Objective Objective of this lab is to get familiar with how to do interrupt handling on Cortex M3. We will again write a simple program that toggles the LED connected to GPIO, but this time we will use a timer interrupt to do so. System Diagram Example (EK-LM3S8962)

GP

IO

Por

t A

Pin 0

Pin 7

GP

IO

Por

t F

Pin 0

Pin 7

...G

PIO

P

ort G

Pin 0

Pin 7

LM3S8962T

IME

R

A CPUInterrupt ISR

Procedure

1. Open the project lab2_timers.Uv2 from the 02 timers directory, and open the timers.c file and check for your tasks.

2. We will start with the interrupt service routine for Timer0, sub-timer A. Remember that each timer consists of two 16-Bit sub-timers named TimerA and TimerB. They can either be used individually or connected together to form one 32-Bit timer named Timer A. The interrupt service routine for Timer0, sub-timer A is named Timer0IntHandler() and will get called whenever this timer expires. As first step in the interrupt handling process we clear the Timer0, sub-timerA interrupt. This should be done early in the interrupt handling process. Check the Timer chapter of the peripheral documentation to determine how to clear an interrupt. The correct instruction takes two parameters – the base address of the timer module (which is timer 0) and the interrupt to be cleared (which is a timeout of sub-timer A). Task: Clear the Timer0 time-out interrupt Hint: Use TIMER0_BASE and TIMER_TIMA_TIMEOUT as parameters

3. In the interrupt service routine we want to toggle the state of the GPIO pin connected to the LED. To do so, we first need to read the state of this pin. We

Page 5: Lab Description - Keil Tools

will store the state of the pin in a variable named ulPinStatus, toggle the bit corresponding to LED and write the result back. Check the documentation of the GPIO module to determine how you can read the status of a GPIO pin. The right instruction will use two parameters – the base address of the module and the selected pin(s) and give the value to which this pin is set back as result. Task: Read the pin state into variable ulPinStatus Hint: Use GPIO_PORTx_BASE for the base address and GPIO_PIN_n for the selected pin (example: GPIO_PORTF_BASE and GPIO_PIN_0)

4. The status of the GPIO pin is contained in the corresponding bit of ulPinStatus. Task: Toggle this bit, e.g. by using the XOR (^) operator or by using an if / then statement.

5. Finally, we need to write back the updated status. You can reuse the same instruction you used in lab 1.

6. Next, we need to setup Timer0 as 32-Bit periodic timer. This will combine its sub-timers A and B into one timer and ensure that it automatically restarts after it expires. Check in the timer chapter of the documentation how to configure a timer as 32-Bit periodic timer. The right function should take two parameters – base address and operating mode. Task: Configure Timer0 as 32-Bit periodic timer Hint: Use TIMER0_BASE and TIMER_CFG_32_BIT_PER as arguments.

7. Next, we need to enable Timer0 to trigger an interrupt upon the time-out of its sub-timerA. Check the Timer chapter of the documentation on how to do so. The right function should take two parameters – base address and interrupt type. Task: Configure Timer0 to trigger an interrupt upon time-out of Sub-timerA. Hint: Use TIMER0_BASE and TIMER_TIMA_TIMEOUT as parameters.

8. Now, we need enable the Timer0, Sub-timerA interrupt in the nested interrupt vector controller (NVIC). Check the Interrupt Controller chapter of the documentation on how to do so. The right instruction takes the selected interrupt as its only parameter. Task: Enable the Timer0, Sub-timerA interrupt in the (NVIC) Hint: Use INT_TIMER0A as parameter.

Page 6: Lab Description - Keil Tools

9. Now the timer is fully configured and we can enable it. Check the documentation on how to enable a timer. The right instruction takes two parameters – base address and sub-timer identifier. Task: Enable Timer0A Hint: Use TIMER0_BASE and TIMER_A as parameters.

10. Finally, we need to globally enable interrupts. Check the interrupt controller chapter on how to enable interrupt handling (master enable). Task: Enable interrupts globally

11. Your source code should now be complete. Build, download and test as with the previous lab.

Lab2 - Advanced Part (Optional) Objective Toggle the blink rate of the LED using the user push button. The push button is on different pins on different boards: EK-LM3S811 - Port C, Pin 4 EK-LM3S3748 - Port B, Pin 7 EK-LM3S8962 - Port F, Pin 1 EK-LM3S 9B90/92- Port B, Pin 4 DK-LM3S9B96 - Port J, Pin 7

Page 7: Lab Description - Keil Tools

System Diagram Example (EK-LM3S8962)

GP

IO

Por

t A

Pin 0

Pin 7

GP

IO

Por

t F

Pin 0

Pin 7

...G

PIO

P

ort G

Pin 0

Pin 7

LM3S8962

TIM

ER

A CPU

Interrupt ISRPin 1

InterruptBlink Rate

Procedure

12. Change the blink rate by modifying the load value of Timer0A, recompile and check the effect.

13. Now, we want to change between fast and slow blinking by pressing the user push button (also called SELECT on some boards). To do so, you need to configure the push button such that it will generate an interrupt when it is pressed. Firstly, you need to configure this pin as an input. You also need to configure the pad to drive a weak pull-up (2mA, WPU) so that you can detect when the push button is pressed.

14. Next, you need to setup the pin such that it detects a falling edge and generates an interrupt based on that. You then need to enable this interrupt in the GPIO module. You also need to enable the interrupt in the NVIC.

15. Write an interrupt service routine for this GPIO interrupt that toggles the Timer0 interrupt rate between low and high.

16. Write the entry point of this interrupt service routine into the right location of the interrupt vector table. Note that you will have to add a reference to this function into the source file containing the interrupt handler. This is because the interrupt handler itself is in a different source file. Now you should be ready to try your program.

Page 8: Lab Description - Keil Tools

Lab Description – Lab3 (Project lab3_adc_display) Objective Objective of this lab is to get familiar with two key peripherals on our board – the ADC converter and the display. We will use the periodic interrupts generated by our timer to trigger an ADC capture. Once we get the result of this capture, we will write it to the display. NOTE: Not all boards have a peripheral connected to the ADC pins, so the conversion values may be floating. In some cases, the board will have a potentiometer connected to the ADC channel used in this lab. System Diagram Example (EK-LM3S8962)

Inpu

t M

UX

ADC0

Pin 0

SSI

LM3S8962

TIM

ER

A CPUInterrupt Toggle

ADC

Trig

ger Interrupt

DisplayUpdate

ADC3

Measure

GP

IOPo

rt F

V

Procedure

1. Open the project lab3_adc_display.Uv2 from the 03 adc_display directory, and open the adc_display.c file and check for your tasks.

2. We will first modify our Timer ISR such that it triggers an ADC capture using ADC Sample Sequencer 0. Check the description of the ADC on how the processor can trigger a sequencer to sample an input. The right instruction takes two inputs – the base address of the ADC and the number of the sequencer that should be triggered. Task: Generate a processor trigger to ADC Sample Sequencer 0. Hint: Use ADC0_BASE and 0 as parameters.

3. Next, we modify the interrupt service routine of ADC Sample Sequencer 0. It will get called whenever this sequencer generates an interrupt. The correct instruction takes two parameters – the base address of the ADC module (which is ADC0) and the number of the sequencer whose interrupt should be cleared (which is SS0).

Page 9: Lab Description - Keil Tools

Task: Clear the ADC interrupt in the ADC module. Check the ADC chapter of the documentation on how to do so. Hint: Use ADC0_BASE and 0 as parameters.

4. Next, we need to read the sample data from the result buffer of sample sequencer 0. Check the ADC chapter of the documentation on how to get sequencer data. The right instruction takes three parameters - base address, sequencer number and a pointer to the data buffer.

5. Task: Retrieve one sample from Sample Sequencer 0 and store this into a scalar variable named adc0_value. Hint: Use ADC0_BASE, 0 and & ulADC0_value as parameters.

6. We provided the code for how to transform the data into a string and display it

on the LCD. Study this to understand how this is done.

7. Next, we need to setup the ADC in the main() routine. Check in the ADC documentation on how to configure a sequence. The right instruction takes four parameters – base address, sequencer number (we will use sequencer 0), trigger type (we will use processor trigger) and priority (we will use the highest one – 0). Task: Setup sample sequencer 0 to be triggered by the processor and to have high priority (0). Hint: Use ADC0_BASE , 0 , ADC_TRIGGER_PROCESSOR and 0 as parameters.

8. Next, we need to configure the first (and only) entry of the sequencer. Each

such entry – a so-called Sequencer Step – will trigger one sample acquisition based on the parameters of this entry. Check the documentation on how to configure a sequencer step. The right instruction takes four parameters – base address, sequencer number, step number and an OR combination of control parameters. Task: Write an entry into sample sequencer 0 that configures step 0 in sequencer 0 to acquire one sample from channel 0 and generate an interrupt. This entry shall be marked as the last one of the sequence. Hint: Use ADC0_BASE, 0, 0 and ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END as parameters. (If using the DK-LM3S9B96, use ADC_CTL_CH10 instead of ADC_CTL_CH0).

9. We now can enable Sample Sequencer 0.

Task: Enable sample sequencer 0. Check the documentation on how to enable a sequencer. The right instruction uses two parameters – base address and sequencer number. Hint: Use ADC0_BASE and 0 as paramters.

10. Your source code should now be complete. Build and download it, then check

if the ADC0 values are displayed correctly. You can (carefully) touch the ADC0 input to introduce noise resulting in

Page 10: Lab Description - Keil Tools

higher input voltages. You can also short the ADC0 input against GND and +3.3V (this should result in full scale output = 1023). Please do not use +5V or +15V unless you are keen to see some smoke ☺ This completes the basic part of this lab.

Lab3 - Advanced Part (Optional) Objective Use the LEFT/RIGHT buttons to switch between ADC channels on your board. NOTE: The EK-LM3S811, EK-LM3S9B90/92 and the DK-LM3S9B96 do not have the extra buttons needed for this part of the lab. Button locations: EK-LM3S3748 – LEFT = Port B, Pin 5, RIGHT = Port B, Pin 6 EK-LM3S8962 – LEFT = Port E, Pin 3, RIGHT = Port E, Pin 2 System Diagram Example (EK-LM3S8962)

Inpu

t M

UX

ADC0

Pin 0

SS

I

LM3S8962

TIM

ER

A CPU

Interrupt Toggle

ADC

Trig

ger Interrupt

DisplayUpdate

ADC3

Measure

GPI

OP

ort F

V

Pin 1

SpeedInterruptSpeed

GP

IOP

ort E

Pin 2Pin 3

CH+ CH-

Cha

nnel

Interrupt

Channel

Procedure

11. Configure the LEFT and RIGHT direction buttons as inputs and generate an interrupt whenever they are pressed (same procedure as in the advanced part of Lab2).

12. Use the generated interrupt to modify the channel number, e.g. increase when the RIGHT button is pressed and decrease when the LEFT button is pressed.

13. You can also measure the temperature of the device by configuring the ADC to measure the voltage supplied by the temperature sensor instead of an input channel.

Page 11: Lab Description - Keil Tools

You can convert the measurement value into Celsius using the following formula: T (in *C) = (59960 - (ADC temp sensor reading * 100)) / 356

Lab Description – Lab4 (Project lab4_webserver_uip) Objective Objective of this lab is to demonstrate on how our Stellaris processor can serve as a web server based on the uIP (MicroIP) open software stack. This allows remote computers to check the ADC value over the internet. NOTE: This lab is currently only supported on the EK-LM3S8962. System Diagram

Inpu

t M

UX

ADC0

Pin 0

SS

I

LM3S8962

TIM

ER

A CPU

Interrupt Toggle

ADC

Trig

ger

Interrupt

DisplayUpdate

ADC3

Measure

GP

IOP

ort F

V

Eth

erne

t

Respond

Req

uest

PCEthernet

Procedure

1. Open the project lab4_webserver_uip.ewp from the 04 webserver_uip directory. Try to understand the structure of this project (we know – it is complex…).

2. The function of this program is to return the ADC data in response to an external internet webpage request. The external server (your PC) will issue an HTPP GET request for a website. Our board will then reply with a stream of HTML data. This data HTML data will be sent in two parts:

- The first - static - part (page_buffer_part1[]) holding most of the web page

- The second - dynamic - part (page_buffer_part2[]) holding the ADC value and some comment after that

We will modify part 2 whenever the ADC has new samples; part 1 will always remain the same. Both buffers can be found in the source code file httpd.c

Page 12: Lab Description - Keil Tools

which is located in the uIP (StellarisWare/third_party/uip-1.0/uip) folder. Whenever we receive a web page update request from the PC, we will send the first buffer, wait for an acknowledge from the PC and then send the second buffer. Using two buffers makes it simpler to determine where to write the ADC data into the buffer (otherwise you would need to count a lot of letters…). Study the HTML data to understand the structure and content of the webpage. A list of common HTML elements can be found in Appendix A.

3. Check the content of the first buffer. It contains the HTTP response with the

embedded HTML code that represents the actual web page. During this lab, we will only modify the HTML part.

4. Check the HTML part and note the structure with the division into HTML section (which includes also the second buffer), header and body.

5. Your first task will be to set the title of the webpage in the header section. Check in Appendix A on how this is done. Task: Introduce the right HTML statement (with a name of your choice) for setting the web page title into the HTML header.

6. Your next task will be to update the dynamic buffer (page_buffer_part2) with the currently selected ADC channel and latest captured ADC value in the ADC interrupt service routine. Check the structure of the dynamic buffer. This is defined in the HTTP demon (service) routine httpd.c which can be found in the uIP (Third Party) folder since it is part of the uIP stack.

7. We want to display “CHn: xxxx” where n stands for the currently selected channel and xxxx for the four-digit ADC value. Some additional information follows after that which we will leave the same. So the channel number is at offset two characters (‘C’, ‘H’) from the start of the buffer while the ADC data starts at an offset of five (‘C’, ‘H’, ‘0|1|2|3’, ‘:’ and a white space).

8. We will update the dynamic buffer whenever we receive a new ADC value. Therefore we will perform this update in the ADC SS0 interrupt service routine (ADC0IntHandler). As first step, we first need to clear out any previous data. We do this by writing spaces (‘ ‘) at the appropriate locations. This is important if you write a shorter string (a smaller value) over a longer string (a bigger value). If you don’t clear the buffer then the last digit(s) of the old value might remain there. This overwriting can easiest be done using a for() loop starting from the right location in the buffer.

Page 13: Lab Description - Keil Tools

Task: Overwrite old buffer data with white spaces

9. Next, we will write the channel number into the right location. The channel number is stored into the variable adc0Channel. This needs to be converted into a character (‘0’, ‘1’, ‘2’ or ‘3’) and written into the right location of the buffer. There are several ways of doing this – either by checking individually if the value is 0, 1, 2 or 3 and writing the appropriate string or by remembering that ‘0’ equals ASCII code 48, ‘1’ equals 49 and so on. Task: Write the current channel number into the right location of the dynamic webpage buffer.

10. Now, we will convert the captured value (adc0_value) into a string and write it to the appropriate location of the dynamic buffer (page_buffer_part2). Remember to use the right offset - see above. There are (at least) two different ways of doing this:

– Do another conversion of adc0_value into page_buffer_part2 using the usprintf function, or

– Reuse the already converted string (adc0_string) and copy it character by character using a for() loop.

Task: Choose one approach and write the string-converted ADC data into the dynamic page buffer.

11. If you used the usprintf() function to convert the string then we need to remove the string termination character (0x0) from the buffer. Otherwise this will show up as strange character on the webpage. Task: Make sure that no string termination character has been placed into the dynamic buffer.

12. Finally, we need to define if our board will use a static (pre-defined) or a dynamic (DHCP-assigned) IP address. If you connect the board directly to the lab PC then you need to use a static IP address since there is no DHCP server in the system. In this case make sure that the definition #define USE_STATIC_IP is not commented out. If you connect the board to a router / switch then the board will obtain its IP address automatically. In this case make sure that the definition #define USE_STATIC_IP is either commented out by using two slashes (//) in front of it or deleted altogether.

13. Build and download the program. Connect the Ethernet cable between your board and your PC. Run the program. On the display you should see the IP address of your board.

Page 14: Lab Description - Keil Tools

14. If the board is connected directly to the PC then you need to modify the TCP/IP protocol settings on your PC to give it an IP address within the same subnet as the board. To do so, open the Network Connection dialog on the PC (this is usually under Start Settings Network Connections) and select the correct LAN connection (you normally see only one LAN as active). Double-click on that and select Properties. You should see the left dialog below:

There, select Internet Protocol and press Properties. Select “Use the following IP address”. Set an address in the same subnet as the one used by the board (e.g. use 169.254.19.62 when the board uses 169.254.19.63). Make sure that the subnet is configured such that the last number is zero (e.g. 255.255.0.0). Then click OK on both dialogs.

15. Start a web browser on your PC and type the IP address shown on the board into the address bar. Check the generated web page. Every time you press “Refresh” on the browser you should be able to see how the ADC value updates.

Page 15: Lab Description - Keil Tools

Appendix A – Common HTML Elements

Header Elements (Part of the HTML Header)

<title>My Webpage Title</title> <meta Metatext />

Heading Elements (Differently-sized Text)

<h1>Largest Heading</h1> <h2> . . . </h2> <h3> . . . </h3> <h4> . . . </h4> <h5> . . . </h5> <h6>Smallest Heading</h6>

Text Elements

<p>This is a paragraph</p> <br> (line break) <hr> (horizontal rule / horizontal line)

Physical Styles

<b>This text is bold</b> <i>This text is italic</i>

Links and Image Elements

<a href="http://www.ti.com/">This is a Link</a>

Unordered list

<ul> <li>First item</li> <li>Next item</li> </ul>

Ordered list

<ol> <li>First item</li> <li>Next item</li> </ol>

Page 16: Lab Description - Keil Tools

Lab Solution – Lab1

1. Your first task is to write an instruction that enables the Block of the GPIO peripheral. Remember that the GPIO peripheral is organized into different blocks (A…G) with each block containing 8 pins. Each block can be enabled and disabled separately by the system control module. Check the description of the system control module in the peripheral driver library documentation to determine which instruction enables a peripheral. Task: Enable GPIO Block F Hint: Use SYSCTL_PERIPH_GPIOF as parameter Solution: SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOx);

2. Next, we need to set the pin type of GPIO Block F, pin 0 as GPIO output. Check the GPIO chapter of the peripheral library documentation on how this could be achieved. The correct instruction takes two parameters – the base address of the module and the pin which is selected. The base addresses are defined in the included hw_memmap.h file which you can find in the /inc folder. The GPIO-specific definitions can be found in the included gpio.h file which you can find in the /driverlib folder. Study these files to get an idea of the parameter naming. Task: Set the pin type of GPIO Block F, pin 0 as GPIO output Hint: Use GPIO_PORTF_BASE and GPIO_PIN_0 as arguments Solution: GPIOPinTypeGPIOOutput(GPIO_PORTx_BASE, GPIO_PIN_n);

3. In the main loop, we want to switch the GPIO pin ON and OFF. We do this by setting it to 0xff and 0x0 respectively. Use the GPIO chapter of the documentation to determine how to write to a pin (or several pins). The right instruction will use three parameters – the base address of the module, the selected pin(s) and the value to which this pin is set. Task: Set the output pin to ‘1’ and ‘0’ respectively at the indicated locations. Hint: Use GPIO_PORTx_BASE for the base address and GPIO_PIN_n for the selected pin. Use 0xff as value if you want to set the pin and 0x0 to clear the pin. Solution: GPIOPinWrite(GPIO_PORTx_BASE, GPIO_PIN_n, 0xff);

Page 17: Lab Description - Keil Tools

Lab Solution – Lab2

1. We will start with the interrupt service routine for Timer0, sub-timer A. Remember that each timer consists of two 16-Bit sub-timers named TimerA and TimerB. They can either be used individually or connected together to form one 32-Bit timer named Timer A. The interrupt service routine for Timer0, sub-timer A is named Timer0IntHandler() and will get called whenever this timer expires. As first step in the interrupt handling process we clear the Timer0, sub-timerA interrupt. This should be done early in the interrupt handling process. Check the Timer chapter of the peripheral documentation to determine how to clear an interrupt. The correct instruction takes two parameters – the base address of the timer module (which is timer 0) and the interrupt to be cleared (which is a timeout of sub-timer A). Task: Clear the Timer0 time-out interrupt Hint: Use TIMER0_BASE and TIMER_TIMA_TIMEOUT as parameters Solution: TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

2. In the interrupt service routine we want to toggle the state of the GPIO pin. To do so, we first need to read the state of this pin. We will store the state of the pin in a variable named ulPinStatus, toggle the Bit corresponding to the LEDand write the result back. Check the documentation of the GPIO module to determine how you can read the status of a GPIO pin. The right instruction will use two parameters – the base address of the module and the selected pin(s) and give the value to which this pin is set back as result. Task: Read the pin state into variable pin_status Hint: Use GPIO_PORTx_BASE for the base address and GPIO_PIN_n for the selected pin. Solution: ulPinStatus = GPIOPinRead(GPIO_PORTx_BASE, GPIO_PIN_n);

3. The status of the pin is contained in ulPinStatus. Task: Toggle this bit, e.g. by using the XOR (^) operator or by using an if / then statement. Solution: pinStatus ^= GPIO_PIN_n;

4. Finally, we need to write back the updated status. You can reuse the same instruction you used in lab 1. Solution: GPIOPinWrite(GPIO_PORTx_BASE, GPIO_PIN_n, ulPinStatus);

Page 18: Lab Description - Keil Tools

5. Next, we need to setup Timer0 as 32-Bit periodic timer. This will combine its sub-timers A and B into one timer and ensure that it automatically restarts after it expires.

6. Check in the timer chapter of the documentation how to configure a timer as 32-Bit periodic timer. The right function should take two parameters – base address and operating mode. Task: Configure Timer0 as 32-Bit periodic timer Hint: Use TIMER0_BASE and TIMER_CFG_32_BIT_PER as arguments Solution: TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);

7. Next, we need to enable Timer0 to trigger an interrupt upon the time-out of its sub-timerA. Check the Timer chapter of the documentation on how to do so. The right function should take two parameters – base address and interrupt type. Task: Configure Timer0 to trigger an interrupt upon time-out of Sub-timerA Hint: Use TIMER0_BASE and TIMER_TIMA_TIMEOUT as parameters Solution: TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

8. Now, we need enable the Timer0, Sub-timerA interrupt in the nested interrupt vector controller (NVIC). Check the Interrupt Controller chapter of the documentation on how to do so. The right instruction takes the selected interrupt as its only parameter. Task: Enable the Timer0, Sub-timerA interrupt in the (NVIC) Hint: Use INT_TIMER0A as parameter Solution: IntEnable(INT_TIMER0A);

9. Now the timer is fully configured and we can enable it. Check the documentation on how to enable a timer. The right instruction takes two parameters – base address and sub-timer identifier. Task: Enable Timer0A Hint: Use TIMER0_BASE and TIMER_A as parameters. Solution: TimerEnable(TIMER0_BASE, TIMER_A);

10. Finally, we need to globally enable interrupts. Check the interrupt controller chapter on how to enable interrupt handling (master enable). Task: Enable interrupts globally Solution: IntMasterEnable();

Page 19: Lab Description - Keil Tools

Lab Solution – Lab3

1. We will first modify our Timer ISR such that it triggers an ADC capture using ADC Sample Sequencer 0. Check the description of the ADC on how the processor can trigger a sequencer to sample an input. The right instruction takes two inputs – the base address of the ADC and the number of the sequencer that should be triggered. Task: Generate a processor trigger to ADC Sample Sequencer 0. Hint: Use ADC0_BASE and 0 as parameters. Solution: ADCProcessorTrigger(ADC0_BASE, 0);

2. Next, we modify the interrupt service routine of ADC Sample Sequencer 0. It will get called whenever this sequencer generates an interrupt. The correct instruction takes two parameters – the base address of the ADC module (which is ADC0) and the number of the sequencer whose interrupt should be cleared (which is SS0). Task: Clear the ADC interrupt in the ADC module. Check the ADC chapter of the documentation on how to do so. Hint: Use ADC0_BASE and 0 as parameters. Solution: ADCIntClear(ADC0_BASE, 0);

3. Next, we need to read the sample data from the result buffer of sample sequencer 0. Check the ADC chapter of the documentation on how to get sequencer data. The right instruction takes three parameters - base address, sequencer number and a pointer to the data buffer. Task: Retrieve one sample from Sample Sequencer 0 and store this into a scalar variable named adc0_value Hint: Use ADC0_BASE , 0 and &adc0_value as parameters Solution: ADCSequenceDataGet(ADC0_BASE, 0, &adc0Value);

4. Next, we need to setup the ADC in the main() routine. Check in the ADC

documentation on how to configure a sequence. The right instruction takes four parameters – base address, sequencer number (we will use sequencer 0), trigger type (we will use processor trigger) and priority (we will use the highest one – 0). Task: Setup sample sequencer 0 to be triggered by the processor and to have high priority (0). Hint: Use ADC0_BASE , 0 , ADC_TRIGGER_PROCESSOR and 0 as parameters. Solution: ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

Page 20: Lab Description - Keil Tools

5. Next, we need to configure the first (and only) entry of the sequencer. Each such entry – a so-called Sequencer Step – will trigger one sample acquisition based on the parameters of this entry. Check the documentation on how to configure a sequencer step. The right instruction takes four parameters – base address, sequencer number, step number and an OR combination of control parameters. Task: Write an entry into sample sequencer 0 that configures step 0 in sequencer 0 to acquire one sample from channel 0 and generate an interrupt. This entry shall be marked as the last one of the sequence. Hint: Use ADC0_BASE, 0, 0 and ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END as parameters. Solution: ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END );

NOTE: DK-LM3S9B96 should use ADC_CTL_CH10

6. We now can enable Sample Sequencer 0.

Task: Enable sample sequencer 0. Check the documentation on how to enable a sequencer. The right instruction uses two parameters – base address and sequencer number. Hint: Use ADC0_BASE and 0 as parameters. Solution: ADCSequenceEnable(ADC0_BASE, 0);

Lab Solution – Lab4

1. Your first task will be to set the title of the webpage in the header section. Check in Appendix A on how this is done. Task: Introduce the right HTML statement (with a name of your choice) for setting the web page title into the HTML header. Solution: "<title>Welcome to the ADC web server!</title>"

2. We will update the dynamic buffer whenever we receive a new ADC value. Therefore we will perform this update in the ADC SS0 interrupt service routine (ADC0IntHandler). As first step, we first need to clear out any previous data. We do this by writing spaces (‘ ‘) at the appropriate locations. This is important if you write a shorter string (a smaller value) over a longer string (a bigger value). If you don’t clear the buffer then the last digit(s) of the old value might remain there. This overwriting can easiest be done using a for() loop starting from the right location in the buffer. Task: Overwrite old buffer data with white spaces Solution: for (i=0;i<5;i++) {page_buffer_part2[i+5]=' ';}

Page 21: Lab Description - Keil Tools

3. Next, we will write the channel number into the right location. The channel number is stored into the variable adc0Channel. This needs to be converted into a character (‘0’, ‘1’, ‘2’ or ‘3’) and written into the right location of the buffer. There are several ways of doing this – either by checking individually if the value is 0, 1, 2 or 3 and writing the appropriate string or by remembering that ‘0’ equals ASCII code 48, ‘1’ equals 49 and so on. Task: Write the current channel number into the right location of the dynamic webpage buffer Solution: page_buffer_part2[2] = adc0Channel+48;

4. Now, we will convert the captured value (adc0_value) into a string and write it to the appropriate location of the dynamic buffer (page_buffer_part2). Remember to use the right offset - see above. Task: Choose one approach and write the string-converted ADC data into the dynamic page buffer. Solution: usprintf(&page_buffer_part2[5], "%d", adc0_value);

5. If you used the usprintf() function to convert the string then we need to remove the string termination character (0x0) from the buffer. Otherwise this will show up as strange character on the webpage. Task: Make sure that no string termination character has been placed into the dynamic buffer Solution: for (i=0;i<5;i++) {

if (page_buffer_part2[i+5] == 0) {

page_buffer_part2[i+5] = ' '; } }