Lab Manual ENGG3640 F22
Lab Manual ENGG3640 F22
References:
[1] Arm Assembly Language Fundamentals and Techniques, by William Hohl and Christopher
Hinds
[2] ARM Compiler V5.05u2
[3] uVision Assembler User Guide
[4] uVision Compiler User Guide
[5] NXP, K60 Family Product Brief
[6] NXP, K60 Sub-Family Data Sheet
[7] NXP, K60 Sub-Family Reference Manual
[8] NXP, TWR-K60D100M Tower Module, User’s Manual
SAFETY
Lab safety presentation by the lab instructor and teaching assistant (TA).
GROUP SETUP
The TAs will form groups and the lab instructor will distribute the equipment.
NXP(FREESCALE) SYSTEM
The TWR‐K60D100M is a Tower Controller Module compatible with the NXP (Freescale) Tower
System. It can function as a stand‐alone, low‐cost platform for evaluating the Kinetis K10, K20, and
K60 microcontroller (MCU) devices. The TWR‐K60D100M features the Kinetis K60 low‐power
microcontroller based on the ARM Cortex-M4 architecture with a USB 2.0 full‐speed OTG controller
and 10/100 Mbps Ethernet MAC. The TWR‐K60D100M is available as a stand‐alone product or as a
kit (TWR‐K60D100M‐KIT) with the Tower Elevator Modules (TWR‐ELEV) and the Tower Serial
Module (TWR‐SER). The TWR‐K60D100M can also be combined with other Freescale Tower
peripheral modules to create development platforms for a wide variety of applications. Figure 20
provides an overview of the NXP (Freescale) Tower System.
The TWR-K60D100M Tower system contains the TWR-K60D100M Tower MCU module shown in
Figure 2 below. Also, check the TWR-K60D100M Tower Module User’s Manual posted on the
University of Guelph Courselink system and online information at https://www.nxp.com/.
K60DN512 Microcontroller
The TWR-K60D100M module features the MK60DN512VMD10 microcontroller. The K60
microcontroller family is part of the Kinetis portfolio of devices built around an ARM Cortex-M4 core.
Refer to the K60 Family Product Brief and the K60 Family Reference Manual for comprehensive
information on the microcontroller devices. The key features are listed here:
• 32-bit ARM Cortex-M4 core with DSP instructions
• 144 MAPBGA, 13mm × 13 mm, 1.0mm pitch package
• 1.71V-3.6V operating voltage input range
• 512 Kbytes of program flash, 128 Kbytes of static RAM
• External bus interface
• Power management controller with 10 different power modes
• Multi-purpose clock generator with PLL and FLL operation modes
• 16-bit SAR ADC, 12-bit DAC
• High-speed analog comparator with 6-bit DAC
• Programmable voltage reference
• USB full-speed/low-speed OTG/Host/Device controller with device charge detect
• 10/100 Mbps Ethernet MAC
• SPI, I2C (w/SMBUS support), UART (w/ISO7816 or IrDA), CAN, I2S
• SD Host Controller (SDHC)
• GPIO with pin interrupt support, DMA request capability, digital glitch filtering
• Capacitive touch sensing inputs (TSI)
• Debug interfaces: JTAG, cJTAG, SWD
• Trace: TPIU, FPB, DWT, ITM, ETM, ETB
For further information please check the “K60 Sub-Family Reference Manual” from Freescale (posted
on ENGG3640 Courselink).
Then you plug the board again and continue with the update. After updating the firmware, unplug the
board again and remove the jumper from the JM60 Boot connector. Then, replug the board and
continue with the lab development.
To ensure everything works well, start the Keil uVision 5, if not yet started, and run an example. Click
Project >> Open Project, navigate to Demo.uvproj project, and open it.
The terminal should work, and you should be able to communicate with the program and run the demo,
as shown below.
Your labtemplateea.uvprojx uVisoin final project structure should look like the structure shown in
figure below after you expend all the group folders:
Open a PuTTY terminal and set it to the right COMx port with serial communication and speed
115200.
Build (F7) the project, then load it into the board and verify that it executes as required. When
loading, it might ask to select the device target. Choose the K60DN512M10 device:
To run the project on the board, press the Reset button, and the LED D7 should lit. Then pressing the
switch button SW1 should turn the LED off; then, pressing again, the LED should turn on.
Step 3. Rebuild your project and run it. First, make sure that your PuTTY terminal is active. Your
PuTTY terminal should display the following after resetting and pressing the SW1 (inner switch).
Step 2. Delete the embedded assembly addition within your main.c program and make the following
additions before and after the int main (void) line, as shown in the figure below.
Step 3. Within your while loop in the main, make the additions shown in the figure below.
Step 4. Start your PuTTY terminal if not started. Then, rebuild the project, load it into the board and
run it. Your terminal window should appear like in the figure below.
If we don’t want the functionality of the GPIO in our main function, we can build a clean main.c that
just calls the strcopy assembly function. Keep the scropy.s file the same. Please note that you can just
rebuild the files you change in the project to save time.
NOTE: If you change a file in your project, you do not need to rebuild the entire project. Instead, you
can use build target, and only the files that have been updated will be recompiled and linked.
Figure: main.c
3) Create a new item as an assembly language target that you include in the source group. You can
call this file mymain.s or pseudo_main.s or any other name you like. This file will be your main
working file for your assembly language implementation. The content of the main asm file is
shown in Figure: mymain.s. Ensure that for the DATA area, srcstr and dststr are labels, and
Figure: mymain.s
4) Rebuild all target files for this project and download the project to the board. Please note that
you don’t need to rebuild all files next time you make some changes. Instead, you can use build,
and only files that have been modified will be recompiled.
5) The terminal PuTTY should display the following. However, you will most likely have only the
first two lines displayed. Note: If you right-click on the terminal header, a set of actions and
commands you can perform on the terminal are shown. You can reset the terminal if needed.
1) For the Lab Report sample and organization, please see the Appendix.
2) The mymain.s program from the example above contains an intentional code error. Debug the
mymain.s program and have it display all four rows as shown in the PuTTY figure above.
Explain the program error in the Lab 1 report.
3) Your Lab 1 report should show the content of the addresses where your code and data are
loaded. Also, what hexadecimal addresses do “srcstr” and “dststr” data fields have? Present
your answer in the report.
4) At what hexadecimal addresses are your main.c function and mymain.s function located? Why
are the address regions for mymain.s much different than for the data? After all, the code and
data are present in the same program.
5) Study ENGG3640 week 1 and week 2 lecture notes. Specifically, for this lab requirement, study
the topic of “Program Loops,” slides 87 to 93. Using the template assembly develop a program
that counts by 10 seconds and displays the seconds repeatedly, wrapping after 60 s (10s, 20s, …
60s, 10s, 20s, …), displaying the seconds approximately 10 seconds apart. Use the loop delay
method to implement this program. To implement the delay, you are required to use a delay
loop. Identify the processor speed in MHz from the board data specifications and show your
calculations for the counter and the loop delay. Present the complete delay program and the
loop delay calculations in your Lab 1 report.
6) Answer all the questions completely in your lab report and explain your program
implementation in your report. For example, describe the time delay routine and how you can
obtain higher time delay precision with your implementation.
Lab 2 builds on Lab 1 and teaches more assembly language concepts by implementing a Reverse Polish
Notation (RPN) calculator. Specifically, in this lab, you will define and use the stack and the functions
such as debug_getchar() and debug_putchar(). In addition, you will use ASCII code representation of
numbers and integer representation, converting numbers from ASCII to integer and from integer to
ASCII. Below are the definitions for console communication that you can use from
fsl_debug_console.h. So far, we have used in Lab1 PRINTF, and here in this lab, we will use PRINTF,
PUTCHAR, and GETCHAR.
To understand how these functions (PRINTF, SCANF, PUTCHAR, GETCHAR) are implemented, you
need to examine the fsl_debug_console.c file.
IMPORTANT NOTE: As you develop your assembly program for this course, you might encounter a
memory fault problem. I understand that the memory fault exception is sometimes set when you
program a peripheral device such as ADC0 (Analog to Digital Converter) or a DAC0 (Digital to
Analog converter) and attempt to write the control registers before you have enabled the corresponding
clock gate control bit in the System Integration Module (SIM). The system sets this memory fault
exception because you are trying to write a memory location associated with one of the control
registers of a peripheral device. Still, since your clock is not enabled to the peripheral device, the
memory location you intend to write will not be updated, and the system generates the fault to let you
know that your value was not, in fact, written in the memory. Therefore, always initialize first the SIM
registers and then the corresponding peripheral control registers.
In ASCII representation, the numbers are stored as a string of ASCII characters. For example, the string
0123456789 is stored as 0x30 0x31 0x32 … 0x39. Also, to delimitate the end of the string, you can use
the null-terminated string method where the last character of the string is 0x00. In our implementation,
we will delimitate the end of an argument and an operator by typing enter (that will generate a carriage
return ASCII character).
Note that R13 (the main stack pointer register) is set to 0x20010000, the top memory address of the
IRAM1 memory area specified in the Target 1 project options (shown in the figure below). Likewise,
the SP (stack pointer) register is initialized to this value. You can use this setting, or you can define
your own stack region within the RAM area.
The evaluation of the RPN calculator is simple if you implement a stack. First, each argument is
pushed on the stack. Then, when an operator is encountered, you pop two arguments from the stack and
perform the required operation, and next, you store the result back on the stack, and so on.
For our calculator in Lab 2, we will separate each argument and operation by a carriage return (CR)
ASCII character generated by pressing return on your keyboard after each argument. The ASCII code
for CR is 0x0D. So, for example, if you type on your keyboard 1234Enter, your generated ASCII string
that you will store in the memory will be the following 5 bytes: 0x31 0x32 0x33 0x34 0x0D.
So, how should our calculator work when using the RPN method? For example, if we want to calculate
the expression shown on row 4 of our table above, we will need to type the following:
30
50
+
40
60
+
*
=
The result displayed should be: 8000
Also, if you prefer, you could separate the arguments and the operators by spaces (0x20), and then you
will have:
30 50 + 40 60 + * =
8000
How will the stack method work for this example and how will you implement the calculator?
Step 1:
Your program must wait for characters and test for arguments and operators. We receive each character
and store them in a string in memory. When one argument is received, it must be converted from the
ASCII representation into integer representation. Then we push the integer value on the stack. In our
example, our first argument is 30, so our stack will be:
top
30
Bottom
Step 2:
Receive the following argument and push it on the stack. Now the stack will be:
Step 3:
When received, each character will be tested for operators such as +, -, *, and /, and the best practice
would be to do this in Step 1. When you encounter an operator, you will pop two arguments from the
stack, perform the operation, and then push the result on the stack again. At this step, in our example,
we encounter +, and we will pop from the stack 50 into a register (register_argument_1 = 50), then 30
into another register (register_argument_2 = 30); we will add the two registers and obtain 80
(register_result = 80). After this operation, we will push the result onto the stack. Now, our stack will
be:
top
80
bottom
Step 4:
Receive the following argument that, for our example, is 40. Push this argument onto the stack:
top
40
80
Bottom
Step 5:
Receive the following argument that is now entered as 60. Push this argument onto the stack:
top
60
40
80
Bottom
Step 6:
Receive the + operator. Pop the top two arguments in order (60, 40) from the stack and place them in
registers. Perform the addition and then store the result 100 onto the stack:
top
100
80
Bottom
Step 7:
Receive the * operator. Pop the top two arguments in order (100, 80) from the stack and place them in
registers. Then, perform the multiplication operation and store the result on the stack.
top
8000
Bottom
Step 9:
Jump to the start again (Step 1).
1. Prepare a demo of your calculator program that can perform at least the following integer
arithmetic operation (+, -, *, /).
2. Prepare a lab report detailing the implementation and the use of the stack.
3. Present a block diagram of your program in your report with detailed explanations of the use of
the stack.
4. Present a block diagram of your calculator and explain your subroutines.
5. Trace the stack for an example that uses your program and show the results in your report. The
stack trace should show the contents of the stack and the SP register values for the example.
Example of conversion from binary to decimal. The conversion from binary to ASCII decimal can
be done by using the division by 10 algorithm.
Assembly implementation algorithm:
1. If the number is greater than 10, divide the number to be converted by 10, and preserve the
quotient and the remainder in some registers.
2. The first remainder is the least significant digit of the conversion. In order to get the ASCII
value, you must add 0x30 to the digit value and store the result as a byte.
3. Next, if the quotient is greater than 10, divide the quotient by 10, and get a new quotient and a
new remainder. This new remainder will be the second digit of the conversion.
4. Step 4. Continue until the quotient is less than 10.
Lab 3 builds on Labs 1 and 2 and teaches more assembly language concepts. Specifically, in this lab,
you will learn how to develop an interrupt handler routine in assembly.
IMPORTANT NOTE: As you develop your assembly program for this course, you might encounter a
memory fault problem. I understand that the memory fault exception is sometimes set when you
program a peripheral device such as ADC0 (Analog to Digital Converter) or a DAC0 (Digital to
Analog converter) and attempt to write the control registers before you have enabled the corresponding
clock gate control bit in the System Integration Module (SIM). The reason the system sets this memory
fault exception is that you are trying to write a memory location associated with one of the control
registers of a peripheral device. Still, since your clock is not enabled to the peripheral device, the
memory location will not be updated, and the system generates the fault to let you know that your value
was not, in fact, written in the memory. Therefore, always initialize first the SIM registers and then the
corresponding peripheral control registers.
• Really if you try to write to a READONLY section, you will get a memory fault exception.
When you get a memory fault exception, ensure that your program data is declared as a
READWRITE section.
EXCEPTION HANDLERS
Handlers are program routines. The processor handles exceptions using:
• Interrupt Service Routines (ISRs) – these routines handle the IRQ interrupts
• Fault Handlers – these are fault exception routines for: HardFault, MemManage fault,
UsageFault, and BusFault.
• System Handlers – these are fault exception routines for: NMI, PendSV, SVCall, SysTick.
The exception handlers are executed by the use of the vector table. The vector table contains the reset
value of the stack pointer, and the start addresses (exception vectors) for all exception handlers. The
figure below shows the order of the exception vectors in the vector table.
Note that the least-significant bit of each vector must be 1, indicating that the exception handler is
Thumb code.
Note that a lower priority number indicates a higher priority level. There are configurable priorities in
software for all exceptions except Reset, HardFault, and NMI. For example, assigning a higher priority
value to the IRQ[0] and a lower priority value to the IRQ[1] (See pages 4-7) means that IRQ[1] has
higher priority than IRQ[0].
In order to increase priority control in a system with interrupts, the NVIC supports priority grouping by
dividing each interrupt priority register entry into two fields:
• Upper field defining the group priority
• Lower field defining the sub-priority within the group.
Note that only the group priority determines the preemption of interrupt exceptions.
CMSIS functions enable software portability between different Cortex-M profile processors. The table
below gives functions to access NVIC registers when using CMSIS.
For a better description of the NVIC registers and their bit usage, check Chapter 4 in “Cortex M4
Devices.pdf”.
LAB 3 Development
Note that the vector address for the “low power timer” is 0x0000_0194; the vector number is 101, and
the IRQ number is 85 (i.e., 0x55) (See pp. 78 in K60 SFRM document (Section 3.2.2).
For this lab, you should reference the lptmr_example project from the MDK. Specifically, you can
consult the fsl_lptmr_driver.h (C:\Freescale\KSDK_1.2.0\platform\drivers\inc\fsl_lptmr_driver.h),
fsl_lptmr_driver.c (C:\Freescale\KSDK_1.2.0\platform\drivers\src\lptmr\fsl_lptmr_driver.c ), and
fsl_lptmr_hal.h (C:\Freescale\KSDK_1.2.0\platform\hal\inc\fsl_lptmr_hal.h) files.
Note that the hardware_init.c file within this project should be appropriate for your application.
However, it looks like they are placed in different locations.
IN MK60D10. H FILE WE HAVE :
▪ Line 259: LPTMR0_IRQn = 85, /**< Low power timer interrupt */
▪ Lines 11306-11449 the LPTMR peripheral access layer is defined.
▪ #define LPTMR0_BASE (0x40040000u) // this is the base address (See pp 1089 in the K60
Sub Family Reference Manual.pdf (K60SFRM)
▪ Line 19107: #define LPTMR0_BASE (0x40040000u)
▪ Line 19108: #define LPTimer_IRQHandler LPTMR0_IRQHandler
Also, the K60 Sub Family Reference Manual (K60SFRM) document describes the Low-Power Timer
(LPTMR) in Chapter 42.
LAB3 REQUIREMENTS
Please consult the Lab3 Requirement Notes below before attempting to implement the laboratory.
Requirement 1: Using the LPTMR0 timer, implement a hardware interrupt-based project in C that
counts on the terminal every 5 to 10 seconds from 0s to 60s. You can choose any second value greater
than 5 and smaller than 10. Do not use a callback function as the lptmr_example uses. Setup your
lptmr0 interrupt routine such that it does the counting. You can print a short message in your main ()
routine such as: 0, 10s, 20s, …, 60s. Note that you need to activate the NVIC for the proper interrupt
channel and initialize the timer to generate the hardware interrupts. Also, it would be best if you
cleared the lptmr interrupt flag.
Requirement 2: Using the C project developed at lab Requirement 1, perform changes such that your
lptmr IRQ service routine is entirely implemented in assembly. Your routine should perform the
clearing of the interrupt flag and keep track of the number of interrupts by incrementing a counter that
later you print as a value in seconds in the main loop. It is important to show how you generate the
appropriate address in the interrupt vector table in the assembly, clear the interrupt flag, and return
from the interrupt. For example, to calculate the aliased memory location of a bit within a control
register, you can use the following formula:
Bit-band alias = bit-band-aliased base + (byte offset × 32) + (bit number × 4).
For example, for your LPTMR0_CSR register bit TCF we will have:
Bit-band alias = 0x42000000 + [(0x40040000 – 0x40000000) × 32] + (7 × 4) = 0x4200001C.
Requirement 3: Using the C project developed at lab Requirement 1 and the things you learned at
Requirement 2, perform changes such that your LPTMR0 setup and the hardware interrupt service
routing are all implemented in assembly language. Explain all your LPTMR0 timer programming steps.
Requirement 4: Prepare your repot and demo. The report should clearly explain how the interrupt
system works for the K60 microcontroller, and you should present clear code examples of how the
interrupts are initialized and set.
Requirement 2 Notes
Note 1: To implement the lptmr0 IRQ handler, you must understand how to clear or set a bit in a
peripheral device control register. In our case, we need to clear the Timer Compare Flag (TCF) in the
Low Power Timer Control Status Register (LPTMR0_CSR) register (See pp. 1089 in the K60 Sub
Family Reference Manual). The CSR register for LPTMR0 is at the Address: 4004_0000h base + 0h
offset = 4004_0000h. One way to do this is by writing a 0x01 in the corresponding location within the
Aliased to peripheral bridge (AIPS-Lite) and general-purpose input/output (GPIO) bitband memory
(See pp. 169 – 171 in the K60 Sub Family Reference Manual to understand the writing in this memory.
Another way is to perform a logical AND operation with that location (well, you need to first load it
into a register due to RISC architecture design for ARM) and clear that bit. However, by debugging the
C code project from Requirement 1, you can step through the assembly code generated by the C code,
and you can learn how you can do the writing in this memory. Also, you can view the status of the
control register when you debug by opening the LPTMR0 system viewer window (in the debug session
go to View >> System Viewer >> LPTMR0). Below is a screenshot from my C lab implementation for
Requirement 1. Note in the figure below the bits content of the CSR register as I show a screenshot
from my debug session going through the interrupt handler routine. To trace through the assembly
language, you need to click in the assembly language window and highlight an instruction; then, you
can step through. Please remember that when you are using interrupts, your debugging is more
complex since the interrupting device might do its work at a different rate while you are stepping
through the program.
Note 2: The next important thing is understanding how the interrupts work for the Cortex M4 devices.
This mechanism is described in Section 2.3 of the Cortex M4 Devices manual. Specifically, it is
important to understand how exception entry occurs, and exception exit occurs (See pp. 2-26 to 2-28 in
the Cortex M4 Devices manual). The processor automatically stacks its state on exception entry and
unstacks this state on exception exit with no instruction overhead.
Exception Entry:
• Exception entry occurs when there is a pending exception with sufficient priority and either one
of the following is true:
o The processor is in thread mode
o The new exception is of a higher priority than the exception being currently handled.
• In the general case when the processor takes an exception, the processor pushes information
onto the current stack. This operation is referred to as stacking, and the structure of eight data
words stacked is referred to as stack frame. The content of the stack frame depends on the
processor mode.
• The stack frame includes the return address which is the address of the next instruction in the
interrupted program. This value is restored to the PC at exception return so that the interrupted
program can resume.
• In parallel with the stacking operation, the processor performs a vector fetch that reads the
exception handler start address from the vector table (See startup_MK60D10.s for the default
handler vector table).
• When the stacking is complete, the processor starts executing the exception handler. At the
same time, the processor writes an EXC_RETURN value to the LR (link register that is register
r14). This code value indicates which stack pointer corresponds to the stack frame and what
operation mode the processor was in before the entry occurred. See the value stored in LR in the
figure above (0xFFFFFFE9) as I entered by C interrupt handler.
Exception Return:
• Exception return occurs when the processor is in the handler mode and executes one of the
following instructions to load the EXC_RETURN value to the PC:
o An LDM or POP instruction to load the PC
o An LDR instruction with the PC as the destination
o A BX instruction using any register
• Note that EXC_RETURN value is the value loaded into the LR on exception entry. In this case
as you build your assembly IRQ handler you will need to save this value on the stack and when
Requirement 3Notes
Note 1. To implement Requirement 3, you must understand how to program the LPTMR0 control
registers. For a description of the LPTMR registers, review Chapter 42 in the K60 Sub Family
Reference Manual. If you follow the C implementation that you developed at Requirement 1 or the
lptmr driver example, you will see that there are three important steps in programming the LPTMR
module:
• Initialize the LPTMR0
• Set the timer’s period
• Start the timer
If you go into the debug mode with your C implementation and step through the assembly, you will
learn how to write your main assembly program to initialize the timer. Below are some screenshots
from my debugging session through my C Lab 3 project.
Screenshot1: The program here has a breakpoint before the LPTMR is initialized. Watch the LPTMR0
register values!
Screenshot2: The program here has a breakpoint after the LPTMR is initialized and before the timer’s
period is set. Watch the LPTMR0 register values!
Screenshot3: The program here has a breakpoint after the LPTMR is initialized and after the timer’s
period is set. Watch the LPTMR0 register values!
Note 2. Important here is how to enable the NVIC and the interrupts. For this requirement, you can use
the CMSIS function: NVIC_EnableIRQ(IRQn_Type IRQn), where the IRQn is the IRQ number (i.e.,
85 or 0x55 for lptmr0). These NVIC functions are found in the core_cm4.h file. In order to use these
functions, you should use INT_SYS_EnableIRQ and INT_SYS_DisableIRQ instead, which are found
in the fsl_interrupt_manager.h file. I have called these functions in my implementation similar to the
my_fprint function built in Lab 1. However, I recommend you directly program the NVIC register for
this IRQ. I have programmed directly the NVIC_ISER2 register in order to enable the IRQ 85. Each
NVIC_ISERn register has 32 bits; the IRQ number corresponds to the bit position starting with
NVIC_ISER0 (0 to 31), then NVIC_ISER1 (32 to 63), etc.
• Table 4-2 NVIC register summary, gives the register addresses.
• NVIC_ISER2 has the address: 0xE000E108.
• You need to write a 0x00200000 value in this register to activate IRQ 85.
I have implemented my Lab 3 example all in assembly, and I have managed to write NVIC registers,
and the LPTM0 registers in assembly. My main function in main.c file source follows the basic
structure that I have introduced in Lab 1:
In Labs 1, 2, and 3, we learned programming in ARM assembly and how to use interrupts. The main
objective of Lab 4 is to teach the students how to use the GPIO functionality to control LEDs and the
seven-segments display and use timers such as PIT to generate interrupts. You can implement this lab
in C or assembly.
IMPORTANT NOTE: As you develop your assembly program for this course, you might encounter a
memory fault problem. I understand that the memory fault exception is sometimes set when you
program a peripheral device such as ADC0 (Analog to Digital Converter) or a DAC0 (Digital to
Analog converter) and attempt to write the control registers before you have enabled the corresponding
clock gate control bit in the System Integration Module (SIM). The reason the system sets this memory
fault exception is that you are trying to write a memory location associated with one of the control
registers of a peripheral device. Still, since your clock is not enabled to the peripheral device, the
memory location will not be updated, and the system generates the fault to let you know that your value
was not, in fact, written in the memory. Therefore, always initialize first the SIM registers and then the
corresponding peripheral control registers.
LAB 4 Development
The project reference for this lab is gpio_example.uvprojx found in
C:\Freescale\KSDK_1.2.0\examples\twrk60d100m\driver_examples\gpio\mdk folder and the lecture
notes related to LEDs and 7-segments display interfaces. So, load this project, rebuild it, and test that it
runs on your station. Another project you can study to understand the GPIO functionality is the Blinky
project found at: C:\Keil_v5\ARM\Boards\Freescale\TWR-K60D100M\Blinky\Blinky.uvprojx.
The following explains the main characteristics of the Blinky.uvprojx project. Note that the project
Blinky is a simple project that you can efficiently study. However, it does not support the use of the
PuTTY terminal.
Working with gpio_example.uvprojx you need to note that the fsl_gpio_driver.c, fsl_gpio_irq.c files
are found in: C:\Freescale\KSDK_1.2.0\platform\drivers\src\gpio\fsl_gpio_driver.c and the
fsl_gpio_hal.c is found in: C:\Freescale\KSDK_1.2.0\platform\hal\src\gpio\fsl_gpio_hal.c. These files
have all the GPIO register functionalities used in the example.
GPIO
Note that all references here are made to the “K60 Sub Family Reference Manual.pdf” available from
nxp.com or ENGG3640 CourseLink system.
The key to understanding the example programs we have is understanding the interfaces and their
registers. The MK60D10.h header file describes all data types that reflect the interface registers.
In Lab 4 Requirement 1, you are required to run a simple GPIO example that blinks 3 LEDs. The
program is straightforward, but you must understand the interface and how to use the header file. We
need to know that the port pins can be multiplexed for different functions (See Chapter 10: Signal
Multiplexing and Signal Description), and some pre-programming steps must be taken before we can
read or write a port pin. To successfully program the GPIO, you need to do the following steps:
LAB4 REQUIREMENTS
Step 2. I first used a large PIT interrupt period (about 2 seconds), so I could easily verify what I was
displaying, and then I reduced the scanning time to 5 ms when I reached the last step.
Step 3. Disconnect the K60 board from the USB. Connect the break-out box to the primary connector
of your K60 board. Connect the board back and download your program and go step by step through
your program. See that you can measure the right signals on the connector pins that will be wired to the
PCB board. Here you can either use the oscilloscope or a voltmeter. Make sure you set the voltmeter to
measure volts. Keep in mind that the output voltage levels for our digital values for the K60 board are
0V for 0 logic and about 3.1 V for the 1 logic. Here the ground terminal of your scope or meter must be
connected to a ground pin on the board. For example, you can use pin 81 from the primary connector
(check the TWRK60 User Manual to verify that GND is outputted to pin 81 on the primary connector).
The measuring probe of the oscilloscope or multimeter can be connected to the break-out box where
you output the port signals and verify that the values are 0 logic or 1 logic as required.
Step 3. Disconnect the USB from your K60 board. Next, build your PCB circuit (See Figure below,
where I present the working system for my Lab 4). As shown, you can similarly arrange your PCB with
the transistors, resistors, and the 7-segments device.
Step 4. VERY IMPORTANT!!! Now you should be ready to power your circuit.
• Do not place any power wires from your power supply on the breadboard. Instead, turn the
power supply ON and make sure that your output is regulated to 0V.
• Turn off the power supply. First, check that you have proper wires to connect the power supply
outputs to the breadboard; your power wires should have an end with a pin plugged into the
breadboard. Next, connect the plus (+) terminal of the power supply to one of the plus (+) lines
(which is marked with red) on your breadboard. Note that all the pins on the top + line of your
breadboard will carry the power voltage (if you are connected to the top line). Then connect the
COM output from your power equipment to one of the minuses (-) lines (marked with blue) on
your breadboard.
• After you connect the outputs of the power supply equipment to your breadboard, it is essential
to run a wire from a ground pin (GND) from your primary connector, specifically, from the
break-out box, to the minus (-) line on your breadboard. I used Pin 81 from the primary
connector as my common ground connection between the K60 board and the breadboard. If you
don’t make this common ground connection, your circuit will not work. Also, when you have
separate circuits that need to work together and are powered from different power sources, they
MUST have a common ground (K60 gets its Vdd from the PC through the USB cable, and the
breadboard gets its Vdd power from the power equipment).
Step 5. Verify your wiring and the circuit again and reconnect the USB cable to the K60 board.
Download the program and turn ON the power supply device. Slowly regulate the power output of your
device to reach 5V (not more than 5V). Run the program by pressing the reset button and watch your
display work. If not working, you will need to debug your program and verify the voltage levels that
come to the display.
OBJECTIVES
Lab 5 main objective is to teach the students the ADC and DAC interfaces using the K60
microcontrollers and the use of timers to control the ADC module. In this lab, you will finalize the
voltmeter design started in Lab 4 and use the DAC module to output the signal measured by the ADC
to an oscilloscope.
IMPORTANT NOTE: As you develop your assembly program for this lab, you might encounter a
memory fault problem. I understand that the memory fault exception is sometimes set when you
program a peripheral device such as ADC0 (Analog to Digital Converter) or a DAC0 (Digital to
Analog converter) and attempt to write the control registers before you have enabled the corresponding
clock gate control bit in the System Integration Module (SIM). The system sets this memory fault
exception because you are trying to write a memory location associated with one of the control
registers of a peripheral device. Still, since your clock is not enabled to the peripheral device, the
memory location will not be updated, and the system generates the fault to let you know that your value
was not, in fact, written in the memory. Therefore, always initialize first the SIM registers and then the
corresponding peripheral control registers.
LAB 5 Development
The lab references are Chapter 35 Analog-to-Digital Converter (ADC), Chapter 37 Digital-to-Analog
converter (DAC), and Chapter 39 Programmable Delay Block (PDB) in the K60 SFRM documentation.
INTRODUCTION
The MK60DN512VMD10 microcontroller that is part of the TWR-K60D100M base board has various
on-chip interfaces, and complex applications can be developed.
ADC Initialization
The reference manual describes the initialization procedure that needs to be followed before using the
ADC. Here I present the primary initialization sequence from the manual. Please consult the manual for
further explanations.
The figure below shows the block diagram of the DAC module found on pp 904 in the reference
manual. Study further the functionality and the programming of the DAC module.
Requirement 1: Interfaces Demos. For implementing the lab requirements please also consult the
LAB 5 Implementation Notes section that follows the requirements sections.
1. Run the example project adc16_example.uvprojx found in the directory:
C:\Freescale\KSDK_1.2.0\examples\twrk60d100m\driver_examples\adc16\. Rebuild the project
and download it to your board. Analyze the application and understand how the ADC works
and how it was programmed.
2. Run the example project dac_example.uvprojx found in the directory:
C:\Freescale\KSDK_1.2.0\examples\twrk60d100m\driver_examples\dac\. Rebuild the project
and download it to your board. Analyze the application and understand how the DAC works
and how it was programmed.
The ADC module has a selectable asynchronous hardware conversion trigger, ADHWT, that is enabled
when SC2[ADTRG] is set and a hardware trigger select event, ADHWTSn (in our case would be Ch 0
trigger), has occurred. However, you must start the PDB0 trigger before receiving the ADHWT signal.
The channel and status fields selected for conversion depend on the active trigger select signal:
ADHWTSA active selects SC1A, and ADHWTSn active selects SC1n.
Figure below shows my setup for the working DC voltmeter as per Requirement 3.
Note: My implementation works decently and reproduces the input signal from the function generator
up to 1.7 kHz. However, you can see the delay of the conversion input >> ADC0 >> DAC0 when you
perform the MATH function on the oscilloscope. Also, you can see that the edges of my output signal
when a square waveform is inputted are not that good.
REQUIREMENT 2 — Implementation
1. Design a system that uses the FTM module to control a 5V DC motor. The implementation
should use a 5V DC motor and one FTM channel to control the DC motor circuit. The PWM
signal's duty cycle should be controlled through your PuTTY by entering a percentage value
such as 20%, etc., or you could use the potentiometer from the TWR-K60D100M board to
control the duty cycle. The potentiometer line is connected to the ADC1_DM1 signal that is
connected to the K2 pin of the microcontroller. As you change the percentage value or the
potentiometer, you should be able to observe the DC motor speed changing. Also, the PWM
signal should be plotted on the oscilloscope to show how the signal changes dynamically. For
the programming of the FTM channel, you can use the example presented in the Appendix of
this lab (See also ENGG3640 lecture notes).
2. Verify the DC motor circuit you have built, show the circuit to the TA before you power it, and
then connect it to the controller.
3. Plot on the scope the PWM signals controlling your motor and demonstrate the changing of the
duty cycle signal as you enter different values from the PuTTY
REQUIREMENT 3 — Demo and Report
Demo all your implementation to the TA. Be ready to answer any theoretical and practical questions
related to the implementation. Prepare a good report that presents all the programs you experimented
with in this lab. Explain the implementations and back your implementations with screenshots showing
results and calculations for your timers etc.
Specifically, for this report, you should clearly present how you programmed your FTM module. Then,
analyze the results, explain the lab application in detail, and justify your design.
If you write your Lab code in ARM assembly, your main.c could be just a few lines as shown below:
…
int main(void)
{
// Init hardware.
CLOCK_SYS_EnablePortClock(PORTA_IDX);
CLOCK_SYS_EnablePortClock(PORTD_IDX);
CLOCK_SYS_EnablePortClock(PORTE_IDX);
/* Init board clock */
BOARD_ClockInit();
dbg_uart_init();
//call asmmain where we initialize lptmr
asmmain();
}
Note: For more information about programming the FTM and controlling a DC motor please follow the
examples presented in the ENGG*3640 lectures (Lectures Weeks 9-10).
APPENDIX
Lab Report Organization Example
The following is a general outline that you can use for your lab reports. However, this outline is not
mandatory; you can enhance it or tailor it to suit your goals.
1. Introduction
1.1 Lab description (problem definition)
1.2 System requirement (tools, equipment etc.)
2. Background
2.1 Short overview of the background related to the programming tools and/or the components and
devices used (depending on the lab). For example, if you use the oscilloscope, you should talk a bit
about it, what you use it for, etc. Same, if you use, for example, a transistor such as a 2N2222 or 7-
segments display, you should briefly discuss their characteristics.
3. Implementation
3.1 Present a top-down functional implementation of the lab.
3.1.1 Software implementation.
3.1.2 Hardware implementation.
3.2 Present specific implementation details answering the Lab Requirements. Highlight all the Lab
Requirement points. You should have them as subsections:
3.2.1 Lab Requirement 1
3.2.2 Lab Requirement 2, etc.
3.3 Simulation results – show any simulation results and oscilloscope graphs and display plots from
your experiments.
4. Conclusions – briefly describe your conclusions highlighting the challenges and the achievements of
your Lab experiments.