Professional Documents
Culture Documents
C Review
1. Overview
In this lesson, we will start writing program in C language. C programs provide some abstraction level that is
not available with assembly language. For example, when you write a C function, you don’t need to know
exactly what general purpose registers to use, or to keep track of the return addresses, or to maintain the stack
memory, etc. However, in order communicate with various peripherals and devices of the microcontroller, we
will need to directly access registers of these peripherals and devices. And since these registers are mapped into
the system memory address space, we will need to use C pointers extensively.
2. Review of C Pointer
The pointer data type corresponds to a memory address. A pointer variable is designated with a *. For example,
int x = 1, y = 5, z = 8, *ptr;
*ptr indicates that ptr is a pointer (i.e., a memory address) and it points to a location with the int data type. x, y,
and z are integer variables.
A conceptual diagram of the memory space after the compilation is shown in the figure below. An arrow is
used to indicate a pointer variable. Note that the arrow points to nowhere (i.e. null) because it is unassigned
initially. Variable x is assigned to locations 0x1000 to 0x1003 (4-byte integer); variable y is assigned to
locations 0x100C to 0x100F; and variable z is assigned to 0x1020 to 0x1023 as shown in the figure.
Address
PTR NULL
0x1000 X
?
0x100C Y
0x1020 Z
The & operator returns the address of a variable and is known as the address-of operator. For example,
ptr = &x ;
For the statement above, the address of x is assigned to ptr. The result is
1
Address
PTR NULL
0x1000 X
0x100C Y
0x1020 Z
The * operator returns the content pointed by the pointer and is known as the dereference operator. For
example,
y = *ptr ;
*ptr = z;
For the “y = *ptr” statement above, the content pointed by ptr is assigned to y. For the “*ptr = z” statement, the
value of z is stored to the location pointed by ptr. The result is
Address
PTR NULL
0x1000 X
0x100C Y
0x1020 Z
The memory addresses assigned to the registers of the I/O devices can be thought of as values of pointers. So,
we can use pointer operators to directly manipulate these registers. For example, address of the PINSEL4
register is 0x4002C010. We can define a pointer to point to this register as:
2
volatile unsigned int* PINSEL4_ptr = (unsigned int *) 0x4002C010;
The keyword volatile instructs the compiler that the value of the object may be modified without processor
interaction and thus optimizations should not be performed. When some level of optimization is done, the
pointer may be optimized away (removed).
To make your code more readable, you may want to use symbolic constants to replace the hard numbers by
using the #define directive. For example, we can define a pointer to point to PINSEL4 register as
Bit Manipulation:
We can use the bitwise operators to manipulate a bit or a group of bits in a data object with a mask operand. For
example,
Question: What will be the results of a0, a1, a2 and a3 after the following statements are executed?
3
a0 = 0b11010011 invert bits 6 and 5 of data
5. Example: EINT0 Interrupt
Write a C code to setup EINT0 interrupt. Keep a count of the number of interrupt occurrences.
/*----------------------------------------------------------------------------
Lesson 13: C review (low level access): set up EINT0 interrupt
*---------------------------------------------------------------------------*/
#include "LPC17xx.h" // Device header
void EINT0_IRQHandler(void);
void EINT0_Init(void);
int EINT0_Interrupt_count; // variable stored at address 0x10000000
/*----------------------------------------------------------------------------
Main: Initialize
*---------------------------------------------------------------------------*/
int main (void) {
4
/*----------------------------------------------------------------------------
EINT0_Init: set up EINT0 to request interrup on falling edge
*---------------------------------------------------------------------------*/
void EINT0_Init(void)
{
// ------------------- Step 1 -------------------------------------------
//Setup pin to be EINT0 in PINSEL4 register (0x4002C010)
PINSEL4_value = *(PINSEL4_ptr); // read current value of PINSEL4
PINSEL4_value |= 0x00100000; // set bit 20
PINSEL4_value &= 0xffdfffff; // clear bit 21
*(PINSEL4_ptr) = PINSEL4_value; // write back to PINSEL4
return;
}
/*----------------------------------------------------------------------------
EINT0_IRQHandler: EINT0 ISR (Step 5) --> keep a count
*---------------------------------------------------------------------------*/
void EINT0_IRQHandler(void){
return;
}
5
Exercise: Write a program to verify the example above.
6. References
[1]. Joseph Yiu, The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors, Elsevier, 3rd ed, 2014.
[2]. Jonathan Valvano, Introduction to ARM Cortex-M Microcontroller, 4nd ed, 2013.
[3]. ARMv7-M Architecture Reference Manual, ARM Limited, 2010.
[4]. LPC17xx User manual, NXP Semiconductors, 2010.
[5]. Cortex-M3 Technical Reference Manual, ARM Limited, 2010.