Actions

EmSys

Difference between revisions of "Lab Practicals Using TivaC LaunchPad Board"

From EdWiki

m (On-Chip Peripheral Programming)
m
 
(14 intermediate revisions by the same user not shown)
Line 6: Line 6:
 
   <li class="tab-title">NVIC</li>
 
   <li class="tab-title">NVIC</li>
 
   <li class="tab-title">SysTick</li>
 
   <li class="tab-title">SysTick</li>
 +
  <li class="tab-title">PLL</li>
 
   <li class="tab-title">UART</li>
 
   <li class="tab-title">UART</li>
 
   <li class="tab-title">GPTM</li>
 
   <li class="tab-title">GPTM</li>
Line 16: Line 17:
 
<ul class="tabs" data-tab>
 
<ul class="tabs" data-tab>
 
  <li class="tab-title active">Overview</li>
 
  <li class="tab-title active">Overview</li>
 +
          <li class="tab-title">Init & Config</li>
 
  <li class="tab-title">Blinky</li>
 
  <li class="tab-title">Blinky</li>
 
  <li class="tab-title">SW1 and SW2</li>
 
  <li class="tab-title">SW1 and SW2</li>
Line 22: Line 24:
 
<div class="tabs-content">
 
<div class="tabs-content">
 
  <div class="content active" id="GPIOSubTab1">
 
  <div class="content active" id="GPIOSubTab1">
<p>This is the first panel of the basic tab example. You can place all sorts of content here including a grid.</p>
+
{{EmSys:Programming the GPIO in TM4C123}}
 +
  </div>
 +
  <div class="content" id="GPIOSubTab5">
 +
{{EmSys:TM4C123GXL GPIO Init And Config}}
 
  </div>
 
  </div>
 
  <div class="content" id="GPIOSubTab2">
 
  <div class="content" id="GPIOSubTab2">
<p>This is the second panel of the basic tab example. This is the second panel of the basic tab example.</p>
+
{{EmSys:EK-TM4C123GXL Blinky Program}}
 
  </div>
 
  </div>
 
  <div class="content" id="GPIOSubTab3">
 
  <div class="content" id="GPIOSubTab3">
<p>This is the third panel of the basic tab example. This is the third panel of the basic tab example.</p>
+
{{EmSys:Switch Inputs and LED Outputs in TM4C123}}
 
  </div>
 
  </div>
 
  <div class="content" id="GPIOSubTab4">
 
  <div class="content" id="GPIOSubTab4">
<p>This is the fourth panel of the basic tab example. This is the fourth panel of the basic tab example.</p>
+
== GPIO Tasks ==
 +
# Write a program to light Blue LED when SW1 is pressed, light Green LED when SW2 is pressed, light white LED when both the switches are pressed and light RED LED when none is pressed .
 
  </div>
 
  </div>
 
</div>
 
</div>
Line 37: Line 43:
 
   </div>
 
   </div>
 
   <div class="content" id="NVICTab">
 
   <div class="content" id="NVICTab">
    <p>This is the NVIC panel of the basic tab example. This is the second panel of the basic tab example.</p>
+
<!-- NVIC Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Introduction</a></li>
 +
  <li class="tab-title">GPIO Int</li>
 +
  <li class="tab-title">Sample</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="NVICSubTab1">
 +
{{EmSys:Interrupts in TM4C123GH6PM Launchpad}}
 +
  </div>
 +
  <div class="content" id="NVICSubTab2">
 +
{{EmSys:TM4C123 GPIO Port Interrupt Programming}}
 +
  </div>
 +
  <div class="content" id="NVICSubTab3">
 +
              {{EmSys:Tiva sw1 int source}}
 +
  </div>
 +
  <div class="content" id="NVICSubTab4">
 +
{{EmSys:TM4C123 GPIO Port Interrupt Tasks}}
 +
  </div>
 +
</div>
 +
<!-- NVIC Sub Tabs End Here -->
 
   </div>
 
   </div>
 
   <div class="content" id="SysTickTab">
 
   <div class="content" id="SysTickTab">
    <p>This is the SysTick panel of the basic tab example. This is the second panel of the basic tab example.</p>
+
<!-- SysTick Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Overview</li>
 +
  <li class="tab-title">SysTick Interrupt</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="SysTickSubTab1">
 +
{{EmSys:Using Systick Timer with TM4C123GH6PM Launchpad}}
 +
  </div>
 +
  <div class="content" id="SysTickSubTab2">
 +
{{EmSys:TM4C123 Using SysTick with Interrupt}}
 +
  </div>
 +
  <div class="content" id="SysTickSubTab3">
 +
# We used Software delay in our blinky, read_sw1, and read_sw2 programs. Replace Software Delay with SysTick Timer Delay.
 +
# If we are sure the execution speed of our function is less than ('''2<sup>24</sup>''' bus cycles), we can use this timer to collect timing information with only a modest amount of intrusiveness. Use the SysTick timer to measure the Software Delay functions we used in the earlier programs.
 +
# If we activate the [[EmSys:TM4C123 Using PLL|PLL]] and change the bus clock to 50 MHz (20ns), what is the longest elapsed time we could measure?
 +
  </div>
 +
</div>
 +
<!-- SysTick Sub Tabs Start Here  -->   
 +
  </div>
 +
  <div class="content" id="PLLTab">
 +
<!-- PLL Sub Tabs start Here  -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Using PLL</li>
 +
  <li class="tab-title">Sample</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="PLLSubTab1">
 +
    {{EmSys:TM4C123 Using PLL}}
 +
  </div>
 +
  <div class="content" id="PLLSubTab2">
 +
    {{EmSys:TM4C123GXL PLL Sample Program}}
 +
  </div>
 +
  <div class="content" id="PLLSubTab3">
 +
    # Activate the PLL and change the bus clock to 50 MHz.
 +
  </div>
 +
</div>
 +
<!-- PLL Sub Tabs End Here  -->
 
   </div>
 
   </div>
 
   <div class="content" id="UARTTab">
 
   <div class="content" id="UARTTab">
    <p>This is the UART panel of the basic tab example. This is the third panel of the basic tab example.</p>
+
<!-- UART Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Introduction</li>
 +
  <li class="tab-title">TivaC UART</li>
 +
  <li class="tab-title">UART Int</li>
 +
  <li class="tab-title">Sample</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="UARTSubTab1">
 +
{{EmSys:UART in TM4C123GH6PM Launchpad}}
 +
  </div>
 +
  <div class="content" id="UARTSubTab2">
 +
{{EmSys:TM4C123G Launchpad UART Programming}}
 +
  </div>
 +
  <div class="content" id="UARTSubTab3">
 +
{{EmSys:TM4C123G LaunchPad UART Interrupt Programming}}
 +
  </div>
 +
  <div class="content" id="UARTSubTab4">
 +
{{EmSys:TM4C123G LaunchPad UART Sample Program And Tasks}}
 +
  </div>
 +
  <div class="content" id="UARTSubTab5">
 +
# Write a program to read and write characters (echo) to UART0 Port.
 +
# Write an Echo (read and write) program using other than UART0 (UART1, UART2 ..... UART7)
 +
# UART0 Echo Program showed how UART0 receives data by polling the RXFE status flag. The disadvantage with that program is that it ties down the CPU polling the status flag. Modify it to make it an interrupt driven program.
 +
  </div>
 +
</div>
 +
<!-- UART Sub Tabs Ends Here -->
 
   </div>
 
   </div>
 
   <div class="content" id="GPTMTab">
 
   <div class="content" id="GPTMTab">
    <p>This is the GPTM panel of the basic tab example. This is the fourth panel of the basic tab example.</p>
+
<!-- GPTM Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Overview</li>
 +
  <li class="tab-title">GPIO Pins</li>
 +
  <li class="tab-title">>GPTM Int</li>
 +
          <li class="tab-title">Samples</li>
 +
  <li class="tab-title">Tasks</a></li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="GPTMSubTab1">
 +
{{EmSys:TM4C123 Timer Programming}}
 +
  </div>
 +
  <div class="content" id="GPTMSubTab2">
 +
{{EmSys:TM4C123 Use of GPTM with GPIO Pins}}
 +
  </div>
 +
  <div class="content" id="GPTMSubTab3">
 +
{{EmSys:TM4C123 GPTM Interrupt Programming}}
 +
  </div>
 +
  <div class="content" id="GPTMSubTab4">
 +
              {{EmSys:TM4C123GXL GPTM Sample Programs}}
 +
  </div>
 +
  <div class="content" id="GPTMSubTab5">
 +
              {{EmSys:TivaC GPTM Assignments}}
 +
  </div>
 +
</div>
 +
<!-- GPTM Sub Tabs Start Here -->
 
   </div>
 
   </div>
 
   <div class="content" id="PWMTab">
 
   <div class="content" id="PWMTab">
    <p>This is the PWM panel of the basic tab example. This is the third panel of the basic tab example.</p>
+
<!-- PWM Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Introduction</li>
 +
  <li class="tab-title">TivaC PWM</li>
 +
  <li class="tab-title">Gen Wave</li>
 +
  <li class="tab-title">PWM O/P</li>
 +
  <li class="tab-title">Timer/Counter</li>
 +
  <li class="tab-title">Samples</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="PWMSubTab1">
 +
{{EmSys:TM4C123 PWM Programming}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab2">
 +
{{EmSys:TM4C123 Programming PWM in TI Tiva LaunchPad}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab3">
 +
{{EmSys:TM4C123 Generating Square waves using PWM generators}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab4">
 +
{{EmSys:TM4C123 Enable the PWM output to the output pin}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab5">
 +
{{EmSys:TM4C123 Generating PWM with Microcontroller using Timer/Counter}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab6">
 +
{{EmSys:TM4C123 PWM Examples and Assignment}}
 +
  </div>
 +
  <div class="content" id="PWMSubTab7">
 +
# Write a program to generate programmable pulse-width modulated outputs.
 +
#: Use PWM0A/PB6, PLL
 +
# Using M1PWM7, write a program to create 1-Khz frequency with 50% duty cycle on PF3 pin (green LED). Use System Clock of 16MHz without division. Set the options of PWMGENB register to set the output when reload and clear the output when PWMCMPA match.
 +
# Generate two square waves with 50% duty cycle and 180 degrees out of phase using PWM0/PB6 and PWM1/PB7.
 +
  </div>
 +
</div>
 +
<!-- PWM Sub Tabs End Here -->
 
   </div>
 
   </div>
 
   <div class="content" id="ADCTab">
 
   <div class="content" id="ADCTab">
    <p>This is the ADC panel of the basic tab example. This is the fourth panel of the basic tab example.</p>
+
<!-- ADC Sub Tabs Start Here -->
 +
<ul class="tabs" data-tab>
 +
  <li class="tab-title active">Introduction</li>
 +
  <li class="tab-title">TivaC ADC</li>
 +
  <li class="tab-title">ADC0</li>
 +
  <li class="tab-title">Timer</li>
 +
  <li class="tab-title">Sample</li>
 +
  <li class="tab-title">Tasks</li>
 +
</ul>
 +
<div class="tabs-content">
 +
  <div class="content active" id="ADCSubTab1">
 +
{{EmSys:TM4C123 ADC Programming}}
 +
  </div>
 +
  <div class="content" id="ADCSubTab2">
 +
{{EmSys:ADC Programming with the Tiva TM4C123G}}
 +
  </div>
 +
  <div class="content" id="ADCSubTab3">
 +
{{EmSys:TM4C123 Using ADC0 to convert input from AIN0}}
 +
  </div>
 +
  <div class="content" id="ADCSubTab4">
 +
{{EmSys:TM4C123 Timer Trigger ADC conversion}}
 +
  </div>
 +
  <div class="content" id="ADCSubTab5">
 +
{{EmSys:TM4C123 Temperature sensor}}
 +
  </div>
 +
  <div class="content" id="ADCSubTab6">
 +
# Write software to sample a single channel at a periodic rate
 +
#: Set the maximum sampling rate at 125K samples/sec
 +
# Write software to sample ADC channels 4 and 5 at 1 Khz
 +
#: Channel 4 on the TM4C123 is PD3 and channel 5 is PD2.
 +
  </div>
 +
</div>
 +
<!-- ADC Sub Tabs End Here -->
 
   </div>
 
   </div>
 
</div>
 
</div>

Latest revision as of 08:53, 9 March 2020

On-Chip Peripheral Programming

Programming the GPIO in TM4C123

In this article we are going to write our first program for accessing GPIOs on the EK-TM4C123GXL LaunchPad Board.

Memory Map

The ARM Cortex-M4 has 4GB (Giga bytes) of memory space. It uses memory mapped I/O, which means that the I/O peripheral ports are mapped into the 4GB memory space.

The TI EK-TM4C123GXL LaunchPad uses the TM4C123GH6PM microcontroller, which has 256K bytes (256KB) of on-chip Flash memory for code, 32KB of on-chip SRAM for data, and a large number of on-chip peripherals.

Allocated size Allocated address
Flash 256 KB 0x0000.0000 To 0x0003.FFFF
SRAM 32 KB 0x2000.0000 To 0x2000.7FFF
I/O All the peripherals 0x4000.0000 to 0x400F.FFFF

GPIO & Special Purpose I/O

While memory holds code and data for the CPU to process, the I/O ports are used by the CPU to access input and output devices. In the microcontroller we have two types of I/O :

  • General Purpose I/O (GPIO)
    The GPIO ports are used for interfacing devices such as LEDs, Switches, LCD, Keypad, and so on.
  • Special purpose I/O
    These I/O ports have designated function such as ADC (Analog-to-Digital), Timer, UART, PWM and so on.

TM4C123GH6PM Block Diagram

Tm4c123gh6pm io pins.png

TM4C123GH6PM Micro controller

ARM chip used in TI Tiva LaunchPad is Tiva C series TM4C123GH6PM microcontroller.

Tm4c123gh6pm pin Diagram.png

The pins are designated as:
➢ PA0 - PA7
➢ PB0 - PB7
➢ PC0 - PC7
➢ PD0 - PD7
➢ PE0 - PE5
➢ PF0 – PF4

Port-E and Port-F do not have all the 8 pins implemented.

GPIO APB & AHB Bus

The ARM chips have two buses:

  1. Advanced Peripheral Bus (APB) and
  2. Advanced High-Performance Bus (AHB).

The AHB bus is much faster than APB. The AHB allows one clock cycle access to the peripherals. The APB is slower and its access time is minimum of two clock cycles.

GPIO APB Memory Map

The I/O ports addresses assigned to the Port A - Port F for APB are as follow:

  • GPIO Port A : 0x4000.4000
  • GPIO Port B : 0x4000.5000
  • GPIO Port C : 0x4000.6000
  • GPIO Port D : 0x4000.7000
  • GPIO Port E : 0x4002.4000
  • GPIO Port F : 0x4002.5000

GPIO AHB Memory Map

The Base addresses for the GPIOs of AHB is as follow:

  • GPIO Port A : 0x4005.8000
  • GPIO Port B : 0x4005.9000
  • GPIO Port C : 0x4005.A000
  • GPIO Port D : 0x4005.B000
  • GPIO Port E : 0x4005.C000
  • GPIO Port F : 0x4005.D000

4K bytes of memory space is assigned to each of the GPIO port. Each GPIO has a large number of special function registers (SFR) associated with it and the GPIO DATA register supports bit-banding. The GPIO DATA register is 8-bit wide. With bit-banding, it will need 256 words (4 bytes each, 1 KB total). There are many registers associated with each of the above I/O ports and they have designated addresses in the memory map. The above addresses are the Base addresses meaning that within that base address we have registers associated with that port.

Digital I/O Pads

The TM4C123GH6PM microcontroller contains six ports and thus six of these physical GPIO blocks. Note that not all pins are implemented on every block. Some GPIO pins can function as I/O signals for the on-chip peripheral modules.

Tm4c123gh6pm gpio block diagram.png
Figure: TM4C123GH6PM Micro controller Digital I/O Pads

GPIO Register Map

Name Offset Tivaware Name Description
GPIODATA 0x000 GPIO_PORTn_DATA_R GPIO Data
GPIODIR 0x400 GPIO_PORTn_DIR_R GPIO Direction
GPIOIS 0x404 GPIO_PORTn_IS_R GPIO Interrupt Sense
GPIOIBE 0x408 GPIO_PORTn_IBE_R GPIO Interrupt Both Edges
GPIOIEV 0x40C GPIO_PORTn_IEV_R GPIO Interrupt Event
GPIOIM 0x410 GPIO_PORTn_IM_R GPIO Interrupt Mask
GPIORIS 0x414 GPIO_PORTn_RIS_R GPIO Raw Interrupt Status
GPIOMIS 0x418 GPIO_PORTn_MIS_R GPIO Masked Interrupt Status
GPIOICR 0x41C GPIO_PORTn_ICR_R GPIO Interrupt Clear
GPIOAFSEL 0x420 GPIO_PORTn_AFSEL_R GPIO Alternate Function Select
GPIODR2R 0x500 GPIO_PORTn_DR2R_R GPIO 2-mA Drive Select
GPIODR4R 0x504 GPIO_PORTn_DR4R_R GPIO 4-mA Drive Select
GPIODR8R 0x508 GPIO_PORTn_DR8R_R GPIO 8-mA Drive Select
GPIOODR 0x50C GPIO_PORTn_ODR_R GPIO Open Drain Select
GPIOPUR 0x510 GPIO_PORTn_PUR_R GPIO Pull-Up Select
GPIOPDR 0x514 GPIO_PORTn_PDR_R GPIO Pull-Down Select
GPIOSLR 0x518 GPIO_PORTn_SLR_R GPIO Slew Rate Control Select
GPIODEN 0x51C GPIO_PORTn_DEN_R GPIO Digital Enable
GPIOLOCK 0x520 GPIO_PORTn_LOCK_R GPIO Lock
GPIOCR 0x524 GPIO_PORTn_CR_R GPIO Commit
GPIOAMSEL 0x528 GPIO_PORTn_AMSEL_R GPIO Analog Mode Select
GPIOPCTL 0x52C GPIO_PORTn_PCTL_R GPIO Port Control
where n = A or B or C or D or E or F


Accessing GPIO of this microcontroller includes much more steps as this microcontroller provides a lot of feature in a single board, hence requires lots of configuration.

For accessing and configuring the microcontroller pins, we have to load some values in the registers, associated with that particular pin.

Initialization of an I/O port

To initialize an I/O port for general use:

  1. Activate the clock for the port in the Run Mode Clock Gating Control Register 2 (RCGC2).
  2. Unlock the port (LOCK = 0x4C4F434B). This step is only needed for pins PC0-3, PD7 and PF0 on TM4C123GXL LaunchPad.
  3. Disable the analog function of the pin in the Analog Mode Select register (AMSEL), because we want to use the pin for digital I/O. If this pin is connected to the ADC or analog comparator, its corresponding bit in AMSEL must be set as 1. In our case, this pin is used as digital I/O, so its corresponding bit must be set as 0.
  4. Clear bits in the port control register (PCTL) to select regular digital function. Each GPIO pin needs four bits in its corresponding PCTL register. Not every pin can be configured to every alternative function.
  5. Set its direction register (DIR). A DIR bit of 0 means input, and 1 means output.
  6. Clear bits in the alternate Function Select register (AFSEL).
  7. Enable digital port in the Digital Enable register (DEN).
  • Please note that we need to add a short delay between activating the clock and setting the port registers.
  • PC0-PC3 is used for JTAG connections to the debugger on the LaunchPad. So we’d better do not use these pins normally.

See Also

  1. EK-TM4C123GXL LaunchPad Board
  2. Switch Inputs and LED Outputs in TM4C123

GPIO Initialization and Configuration

The GPIO modules may be accessed via two different memory apertures. The legacy aperture, the Advanced Peripheral Bus (APB), is backwards-compatible with previous devices. The other aperture, the Advanced High-Performance Bus (AHB), offers the same register map but provides better back-to-back access performance than the APB bus. These apertures are mutually exclusive. The aperture enabled for a given GPIO port is controlled by the appropriate bit in the GPIOHBCTL register.

To configure the GPIO pins of a particular port, follow these steps:

  1. Set up the system clock
    Set up the system clock for the specific GPIO Port to enable the clock to drive the port by setting the appropriate bits in the GPIO Run Mode Clock Gating Control (RCGCG2) Register. More ...
  2. Unlock the port
    After enabling the clock some ports are still locked. This step is only needed for pins PC0-3, PD7 and PF0 on TM4C123GXL LaunchPad. More ...
  3. Disable Analog function
    Disable the analog function of the pin in the Analog Mode Select register (AMSEL) More ...
  4. Configure each bit as a GPIO Mode or Alternate Mode
    Optionally you can configure the GPIOAFSEL register to program each bit as a GPIO Mode or Alternate Mode. More ...
  5. Set up the direction for each pin on the GPIO
    Set up the direction for each pin on the GPIO port by programming the GPIODIR register. More ...
  6. Enable GPIO pins as digital I/Os
    To enable GPIO pins as digital I/Os, set the appropriate DEN bit in the GPIODEN register. More ...
  7. Setup the drive strength for each pin
    Optionally, you can setup the drive strength for each pin through the GPIODR2R, GPIODR4R, or GPIODR8R registers. More ...
  8. Configure each pad in the port to have pull-up, pull-down, or open drain function
    Optionally, you can configure each pad in the port to have pull-up, pull-down, or open drain function through the GPIOPUR, GPIOPDR , or GPIOODR register. More ...
  9. Set up the type, event, and mask of the interrupts for each port
    Optionally, you can configure the GPIOIS, GPIOIBE, GPIOEV, and GPIOIM registers to set up the type, event, and mask of the interrupts for each port if interrupts are used for the port. More ...
  10. Lock the configurations of the NMI and JTAG/SWD pins on the GPIO port
    Optionally, you can lock the configurations of the NMI and JTAG/SWD pins on the GPIO port pins by setting the LOCK bits in the GPIOLOCK register. More ...
  11. Read/Write Data Register
    The GPIODATA register is the data register. More ...

EK-TM4C123GXL Blinky Program

  1. /* 
  2. Toggling LEDs using special function registers by their names defined in the TivaWare header file
  3. Runs on TI EK-TM4C123GXl LaunchPad Board
  4. */
  5.  
  6.  
  7. #include <stdint.h>
  8. #include "inc/tm4c123gh6pm.h"
  9.  
  10. void delayMs(int n);
  11.  
  12. int main(void)
  13. {
  14.     SYSCTL_RCGC2_R |= 0x00000020;     /* enable clock to GPIOF at clock gating control register */
  15.  
  16.     GPIO_PORTF_DIR_R = 0x0E;          /* enable the GPIO pins for the LED (PF3, 2, 1) as output */
  17.     GPIO_PORTF_DEN_R = 0x0E;         /* enable the GPIO pins for digital function */
  18.  
  19.     while(1) {
  20.         GPIO_PORTF_DATA_R = 0x0E;     /* turn on all LEDs */
  21.         delayMs(500);
  22.         GPIO_PORTF_DATA_R = 0;        /* turn off all LEDs */
  23.         delayMs(500);
  24.     }
  25. }
  26.  
  27. /* delay n milliseconds (16 MHz CPU clock) */
  28. void delayMs(int n)
  29. {
  30.     int i, j;
  31.     for(i = 0 ; i < n; i++)
  32.         for(j = 0; j < 3180; j++) {}   /* do nothing for 1 ms */
  33. }

See Also

  1. TM4C123GH6PM GPIO Programming
  2. EK-TM4C123GXL LaunchPad Board
  3. Switch Inputs and LED Outputs in TM4C123

Switch Inputs and LED Outputs

There are four ways to interface a switch to the microcontroller as shown in the following Figure:

Interface of a switch to a microcomputer input

We can use either positive or negative logic, and we can use an external resistor or select an internal resistor. Notice the positive logic circuit with external resistor is essentially the same as the positive logic circuit with internal resistance; the difference lies with whether the pull-down resistor is connected externally as a 10 kΩ resistor or internally by setting the corresponding PDR bit during software initialization.

SW1 and SW2 on LaunchPad

SW1 and SW2 on LaunchPad
  • SW1 push-button switch is connected to PF0 pin.
  • SW2 push-button switch is connected to PF4 pin.
  • There is no pull-up resistor connected to SW1 & SW2
  • To use the SW1 and SW2, we need to enable the internal pull-up resistor for PF0 and PF4 pins.

Read SW1 & Display it on the Green LED

To read SW1 and display it on the green LED, the following steps must be taken.

  1. Enable the clock to PortF
  2. Set the Direction register PF4 as input, and PF3 as output
  3. Enable the digital I/O feature of PortF
  4. Enable the pull up resistor option in PUR register since the switch circuit does not have pull-up resistor
  5. Read SW1 on PortF
  6. Invert the value since the switch is active low and the LED is active high
  7. Shift right the switch bit (PF4) to green LED bit(PF3) of the value
  8. Write the value to green LED of PortF
  9. Repeat steps 5 to 8

Source Code

  1. /* Read a switch and write it to the LED */
  2. /* This program reads SW1 of Tiva LaunchPad and writes the inverse of the value to the green
  3.    LED. SW1 is low when pressed (Normally High). LED is ON when high.
  4. */
  5.  
  6. #include <stdint.h>
  7. #include "inc/tm4c123gh6pm.h"
  8.  
  9. int main(void)
  10. {
  11.     unsigned int value;
  12.  
  13.     SYSCTL_RCGC2_R |= 0x00000020;;   /* enable clock to GPIOF */
  14.  
  15.     GPIO_PORTF_DIR_R = 0x08;         /* set PORTF3 pin as output (LED) pin */
  16.                                      /* and PORTF4 as input, SW1 is on PORTF4 */
  17.     GPIO_PORTF_DEN_R = 0x18;         /* set PORTF pins 4-3 as digital pins */
  18.     GPIO_PORTF_PUR_R = 0x10;         /* enable pull up for pin 4 */
  19.  
  20.     While(1) {
  21.         value = GPIO_PORTF_DATA_R;  /* read data from PORTF */
  22.         value = ~value;             /* switch is low active; LED is high active */
  23.         value = value >> 1;         /* shift it right to display on green LED */
  24.         GPIO_PORTF_DATA_R = value;  /* put it on the green LED */
  25.     }
  26. }

Read SW2 and Write it on Red LED

To read SW2 and display it on the Red LED, the program is similar to the previous program except extra steps needed to take care of PortF0 as described below:

  • The SW2 is connected to PortF0 pin, which is shared with NMI (non-maskable interrupt).
  • To prevent accidental write to configuration registers and thus disables NMI, the configuration register bits for PortF0 are normally locked.
  • They may be unlocked by writing a pass code value of 0x4C4F434B to the LOCK Register followed by setting bit 0 of the Commit Register (GPIOCR).


Source Code

  1. /* Read a switch and write it to the LED */
  2. /* This program reads SW2 of Tiva LaunchPad and write the inverse of the value to the red LED.
  3.    SW2 is low when pressed. LED is on when high. */
  4. /* SW2 is connected to PORTF0, which is an NMI pin. */
  5. /* In order to use this pin for any function other than NMI, the pin needs be unlocked first. */
  6.  
  7. #include <stdint.h>
  8. #include "inc/tm4c123gh6pm.h"
  9.  
  10. int main(void)
  11. {
  12.     unsigned int value;
  13.  
  14.     SYSCTL_RCGC2_R |= 0x00000020;       /* enable clock to GPIOF */
  15.  
  16.     GPIO_PORTF_LOCK_R = 0x4C4F434B;     /* unlock commit register */
  17.     GPIO_PORTF_CR_R = 0x01;             /* make PORTF0 configurable */
  18.     GPIO_PORTF_DIR_R = 0x02;            /* set PORTF1 pin as output (LED) pin */
  19.                                         /* and PORTF0 as input, SW2 is on  PORTF0 */
  20.     GPIO_PORTF_DEN_R = 0x03;            /* set PORTF pins 1-0 as digital pins */
  21.     GPIO_PORTF_PUR_R = 0x01;            /* enable pull up for pin 0 */
  22.  
  23.     while(1) {
  24.         value = GPIO_PORTF_DATA_R;      /* read data from PORTF */
  25.         value = ~value;                 /* switch is low active; LED is high active */
  26.         value = value << 1;             /* shift it left to display on red LED */
  27.         GPIO_PORTF_DATA_R = value;      /* put it on red LED */
  28.     }
  29. }

GPIO Tasks

  1. Write a program to light Blue LED when SW1 is pressed, light Green LED when SW2 is pressed, light white LED when both the switches are pressed and light RED LED when none is pressed .

Interrupts in TM4C123GH6PM Launchpad

In this article we are going to deal with GPIO PORTF interrupt that will toggle the on board blue led on rising edge whenever a user switch is pressed. Since the GPIO related initialization has already been discussed in our GPIO section. Here we will look at the initialization rituals for GPIO interrupts only.

As we already know that a micro controller has a built in capability to perform several tasks without waiting for completion of ongoing task. Generally there are two methods by which a peripheral device can receive a service from micro controller, they are:

  1. Polling
  2. Interrupts

In polling method a micro controller continuously monitors the status of a device or a particular condition and waits until the required status or condition is met and then it performs the service, after performing this task it executes the next task. For example, just take a look at our section of UART code you can see that we are continuously monitoring the bit 5 of UART0_FR_R register to ensure that any previous transmission has been completed.

    while((UART0_FR_R & 0x00000010) != 0) {
        ;
    }
    UART0_DR_R = data;

If yes, then transmit the next incoming data, while in interrupt the same thing is serviced by a microcontroller without continuously monitoring the status of a device though it serves when it gets notified by the device by receiving an interrupt signal.

Interrupt service routine (ISR)

For every interrupt there must be a program associated with it. When an interrupt occurs this program is executed to perform certain service for the interrupt. This program is commonly referred to as an interrupt service routine (ISR) or interrupt handler. When an interrupt occurs, the CPU runs the interrupt service routine. Now the question is, how the ISR gets executed? As shown in the Table 7.1, in the ARM CPU there are pins that are associated with hardware interrupts. They are input signals into the CPU. When the signals are triggered, CPU pushes the PC register onto the stack and loads the PC register with the address of the interrupt service routine. This causes the ISR to get executed.

Interrupt Vector Table

Since there is a program (ISR) associated with every interrupt and this program resides in memory (RAM or ROM), there must be a look-up table to hold the addresses of these ISRs. This look-up table is called interrupt vector table. In the ARM, the lowest 1024 bytes (256 * 4 = 1024) of memory space are set aside for the interrupt vector table and must not be used for any other function. Of the 256 interrupts, some are used for software interrupts and some are for hardware IRQ interrupts.

Nested Vectored Interrupt Controller (NVIC)

It is a control unit for a cortex-M4 MCU, It provides the group of programmable registers where all the exceptions and interrupts, including maskable and non-maskable interrupts are handled and preprocessed in a specific sequences.

Nvic in arm cortex.png
Table 7.1: NVIC in ARM Cortex-M
  • Interrupts on the Cortex-M are controlled by the Nested Vectored Interrupt Controller (NVIC).
  • Each exception has an associated 32-bit vector that points to the memory location where the ISR that handles the exception is located.

With CCS IDE, a new project will get a C startup code tm4c123gh6pm_startup_ccs_gcc.c created by the project wizard. For each interrupt, there is a dummy interrupt hander that does not perform any thing and will never return from the handler. The addresses of these interrupt handlers are listed in the interrupt vector table named g_pfnVectors in the file. You need to carefully find the appropriate vector position and replace IntDefaultHandler with the name of your Interrupt handler. The linker will overwrite the interrupt vector table with the new interrupt handler. The interrupt handler is written with a format of a function in C language.

A detailed default vector table can be found at tm4c123gh6pm_startup_ccs_gcc.c file.

Interrupt and Exception assignments in ARM Cortex-M

The NVIC of the ARM Cortex-M has room for the total of 255 interrupts and exceptions. The interrupt numbers are also referred to as INT type (or INT #) in which the type can be from 1 to 255 or 0x01 to 0xFF. The NVIC in ARM Cortex-M assigns the first 15 interrupts for internal use. The memory locations 0 to 3 are used to store the value to be loaded into the stack pointer when the device is coming out of reset. See Table 7.2

Interrupt # Interrupt Memory Location Priority Level
0
Stack Pointer Initial Value 0x00000000
1
Reset 0x00000004 -3 Highest
2
NMI 0x00000008 -2
3
Hard Fault 0x0000000C -1
4
Memory Management Fault 0x00000010 Programmable
5
Bus Fault 0x00000014 Programmable
6
Usage Fault (undefined instructions,
divide by zero, unaligned memory
access, ....)
0x00000018 Programmable
7
Reserved 0x0000001C Programmable
8
Reserved 0x00000020 Programmable
9
Reserved 0x00000024 Programmable
10
Reserved 0x00000028 Programmable
11
SVCall 0x0000002C Programmable
12
Debug Moniter 0x00000030 Programmable
13
Reserved 0x00000034 Programmable
14
PendSV 0x00000038 Programmable
15
SysTick 0x0000003C Programmable
16
IRQ for peripherals 0x00000040 Programmable
17
IRQ for peripherals 0x00000044 Programmable
...
...
...
...
255
IRQ for peripherals 0x000003FC Programmable
Table 7.2: Interrupt Vector Table for ARM Cortex-M.

IRQ Peripheral interrupts

  • An ISR can be launched as a result of an event at the peripheral devices such as timer timeout or analog-to-digital converter (ADC) conversion complete. The largest number of the interrupts in the ARM Cortex-M belong to this category.
  • Notice from Table 7.2 that ARM Cortex-M NVIC has set aside the first 15 interrupts (INT 1 to INT 15) for internal use and exceptions and is not available to chip designer. The Reset, NMI, undefined instructions, and so on are part of this group of exceptions. The rest of the interrupts can be used for peripherals.
  • Many of the INT 16 to INT 255 are used by the chip manufacturer to be assigned to various peripherals such as timers, ADC, Serial COM, external hardware interrupts, and so on. There is no standard in assigning the INT 16 to INT 255 to the peripherals.
  • Each peripheral device has a group of special function registers that must be used to access the device for configuration.
  • For a given peripheral interrupt to take effect, the interrupt for that peripheral must be enabled. The special function registers for that device provide the way to enable the interrupts.

Interrupt Priority for ARM Cortex-M

  • All exceptions and interrupts in the Cortex-M4 system have certain priority levels, either maskable or unmaskable sources.
  • Most maskable interrupts have programmable priority levels, but all Non-Maskable Interrupts (NMIs) have fixed priority levels.
  • When an exception or interrupt occurs, the NVIC performs a comparison between the priority level of current exception or interrupt and the priority level of the new coming exception/interrupt. The current running task will be suspended and the control will be transferred to the service routine of the new coming exception/interrupt if the priority level of the new coming exception/interrupt is higher.
  • In the ARM Cortex-M4 system, the interrupt priority levels are controlled by the Interrupt Priority Registers, as shown in Table 7.3.
  • Each priority register can use 3 bits, 4 bits, or 8 bits to cover all priority levels used in the priority control system.
  • A total of 8 priority levels can be used if 3 bits are used in this register, and 16 priority levels can be obtained if 4 bits are used in this register.
  • Devices within the Tiva family support up to 154 interrupt sources and 8 priority levels, which means that 3 bits are used in the priority register in the TM4C123GH6PM MCU.
  • To activate an interrupt source we need to set its priority and enable that source in the NVIC. This activation is in addition to the arm and enable steps.
    To arm a device means to allow the hardware trigger to interrupt. Conversely, to disarm a device means to shut off or disconnect the hardware trigger from the interrupts
  • Table 7.3 lists some of the interrupt sources available on the TM4C family of micro controllers. Interrupt numbers 0 to 15 contain the faults, software interrupt and SysTick; these interrupts will be handled differently from interrupts 16 and up.
Vector
address
Vector
(Exception)
Number
Interrupt #
(IRQ)
Address
(Priority Register)
Interrupt Source Priority Register
(Tivaware Name)
Priority
Bits
0x00000038
14
-2
0xE000.ED20 PendSV NVIC_SYS_PRI3_R 23 - 21
0x0000003C
15
-1
0xE000.ED20 SysTick NVIC_SYS_PRI3_R 31 - 29
0x00000040
16
0
0xE000.E400 GPIO Port A NVIC_PRI0_R 7 - 5
0x00000044
17
1
0xE000.E400 GPIO Port B NVIC_PRI0_R 15 - 13
0x00000048
18
2
0xE000.E400 GPIO Port C NVIC_PRI0_R 23 - 21
0x0000004C
19
3
0xE000.E400 GPIO Port D NVIC_PRI0_R 31 - 29
0x00000050
20
4
0xE000.E404 GPIO Port E NVIC_PRI1_R 7 - 5
0x00000054
21
5
0xE000.E404 UART0, Rx Tx NVIC_PRI1_R 15 - 13
0x00000058
22
6
0xE000.E404 UART1, Rx Tx NVIC_PRI1_R 23 - 21
0x0000005C
23
7
0xE000.E404 SSI0, Rx Tx NVIC_PRI1_R 31 - 29
0x00000060
24
8
0xE000.E408 I2C0 NVIC_PRI2_R 7 - 5
0x00000064
25
9
0xE000.E408 PWM Fault NVIC_PRI2_R 15 - 13
0x00000068
26
10
0xE000.E408 PWM Gen 0 NVIC_PRI2_R 23 - 21
0x0000006C
27
11
0xE000.E408 PWM Gen 1 NVIC_PRI2_R 31 - 29
0x00000070
28
12
0xE000.E40C PWM0 Gen 2 NVIC_PRI3_R 7 - 5
0x00000074
29
13
0xE000.E40C Quad Encoder 0 NVIC_PRI3_R 15 - 13
0x00000078
30
14
0xE000.E40C ADC Seq 0 NVIC_PRI3_R 23 - 21
0x0000007C
29
15
0xE000.E40C ADC Seq 1 NVIC_PRI3_R 31 - 29
0x00000080
32
16
0xE000.E410 ADC Seq 2 NVIC_PRI4_R 7 - 5
0x00000084
33
17
0xE000.E410 ADC Seq 3 NVIC_PRI4_R 15 - 13
0x00000088
34
18
0xE000.E400 Watchdog NVIC_PRI4_R 23 - 21
0x0000008C
35
19
0xE000.E410 Timer 0A NVIC_PRI4_R 31 - 29
0x00000090
36
20
0xE000.E414 Timer 0B NVIC_PRI5_R 7 - 5
0x00000094
37
21
0xE000.E414 Timer 1A NVIC_PRI5_R 15 - 13
0x00000098
38
22
0xE000.E414 Timer 1B NVIC_PRI5_R 23 - 21
0x0000009C
39
23
0xE000.E414 Timer 2A NVIC_PRI5_R 31 - 29
0x000000A0
40
24
0xE000.E418 Timer 2B NVIC_PRI6_R 7 - 5
0x000000A4
41
25
0xE000.E418 Comp 0 NVIC_PRI6_R 15 - 13
0x000000A8
42
26
0xE000.E418 Comp 1 NVIC_PRI6_R 23 - 21
0x000000AC
43
27
0xE000.E418 Comp 2 NVIC_PRI6_R 31 - 29
0x000000B0
44
28
0xE000.E41C System Control NVIC_PRI7_R 7 - 5
0x000000B4
45
29
0xE000.E41C Flash Control NVIC_PRI7_R 15 - 13
0x000000B8
46
30
0xE000.E41C GPIO Port F NVIC_PRI7_R 23 - 21
0x000000BC
47
31
0xE000.E41C GPIO Port G NVIC_PRI7_R 31 - 29
0x000000C0
48
32
0xE000.E420 GPIO Port H NVIC_PRI8_R 7 - 5
0x000000C4
49
33
0xE000.E420 UART2, Rx Tx NVIC_PRI8_R 15 - 13
0x000000C8
50
34
0xE000.E420 SSI1, Rx Tx NVIC_PRI8_R 23 - -21
0x000000CC
51
35
0xE000.E420 Timer 3A NVIC_PRI8_R 31 - 29
0x000000D0
52
36
0xE000.E424 Timer 3B NVIC_PRI9_R 7 - 5
0x000000D4
53
37
0xE000.E424 I2C1 NVIC_PRI9_R 15 - 13
0x000000D8
54
38
0xE000.E424 Quad Encoder 1 NVIC_PRI9_R 23 - 21
0x000000DC
55
39
0xE000.E424 CAN0 NVIC_PRI9_R 31 - 29
0x000000E0
56
40
0xE000.E428 CAN1 NVIC_PRI10_R 7 - 5
0x000000E4
57
41
0xE000.E428 CAN2 NVIC_PRI10_R 15 - 13
0x000000E8
58
42
0xE000.E428 Ethernet NVIC_PRI10_R 23 - 21
0x000000EC
59
43
0xE000.E428 Hibernate NVIC_PRI10_R 31 - 29
0x000000F0
60
44
0xE000.E42C USB0 NVIC_PRI11_R 7 - 5
0x000000F4
61
45
0xE000.E42C PWM Gen 3 NVIC_PRI11_R 15 - 13
0x000000F8
62
46
0xE000.E42C uDMA Soft Tfr NVIC_PRI11_R 23 - 21
0x000000FC
63
47
0xE000.E42C uDMA Error NVIC_PRI11_R 31 - 29
Table 7.3: The relationship between vectors and NVIC definitions.

The following five conditions must be true for an interrupt to be generated:

  1. Device arm
    Each potential interrupt trigger has a separate arm bit that the software can activate or deactivate. The software will set the arm bits for those devices from which it wishes to accept interrupts, and will deactivate the arm bits within those devices from which interrupts are not to be allowed. In other words it uses the arm bits to individually select which devices will and which devices will not request interrupts.
  2. NVIC enable
    For most devices there is a enable bit in the NVIC that must be set (periodic SysTick interrupts are an exception, having no NVIC enable).
  3. Global enable
    Bit 0 of the special register PRIMASK is the interrupt mask bit, I. If this bit is 1 most interrupts and exceptions are not allowed, which we will define as disabled. If the bit is 0, then interrupts are allowed, which we will define as enabled.
  4. Interrupt priority level must be higher than current level executing
    The BASEPRI register prevents interrupts with lower priority interrupts, but allows higher priority interrupts. For example if the software sets the BASEPRI to 3, then requests with level 0, 1, and 2 can interrupt, while requests at levels 3 and higher will be postponed. The software can also specify the priority level of each interrupt request. If BASEPRI is zero, then the priority feature is disabled and all interrupts are allowed.
  5. Hardware event trigger.
    Hardware triggers are bits in the GPIO_PORTx_RIS_R register that are set on rising or falling edges of digital input pins.

For an interrupt to occur, these five conditions must be simultaneously true but can occur in any order.


GPIO Port Interrupt Programming

Interrupt numbers 16 to 255 are assigned to the peripherals. The INT (IRQ) 46 is assigned to the GPIO Port of F. Although PortF has 8 pins, we have only one interrupt assigned to the entire PortF. In other words, when any of the PortF pins trigger an interrupt, they all go to the same address location in the interrupt vector table. It is the job of our Interrupt Service Routine (ISR or interrupt Handler) to find out which pin caused the interrupt.

Interrupt trigger point

When an input pin is connected to an external device to be used for interrupt, we have 5 choices for trigger point. They are:

  • low-level trigger (active Low level),
  • high-level trigger (active High level),
  • rising-edge trigger (positive-edge going from Low to High),
  • falling-Edge trigger (negative-edge going from High to Low),
  • Both edge (rising and falling) trigger.

Upon Reset, all the interrupts are disabled. To enable any interrupt:

  1. Enable the interrupt for a specific peripheral module.
  2. Enable the interrupts at the NVIC module.
  3. Enable the interrupt globally

GPIO Interrupt Control Registers

GPIO Register Tivaware Name Each Bit Value (Lowest 8-Bit) and Each Pin Function
GPIOIS GPIO_PORTx_IS_R Interrupt sense register
Determines level or edge triggered
0: Detect an edge (edge-sensitive) on the pin,
1: Detect a level (level-sensitive) on the pin.
GPIOIBE GPIO_PORTx_IBE_R 0: Interrupt is controlled by GPIOIEV,
1: Both edges on the corresponding pin trigger an interrupt
GPIOIEV GPIO_PORTx_IEV_R GPIO Interrupt Event Register
Determines the detecting edges or levels.
0: A falling edge or a LOW level,
1: A rising edge or a HIGH level triggers an interrupt
GPIOIM GPIO_PORTx_IM_R GPIO Interrupt Mask Register
Masks (disables) or unmask (enable) an interrupt.
0: Interrupt is masked (disabled),
1: Interrupt is unmasked (enabled).
GPIORIS GPIO_PORTx_IS_R GPIO Raw Interrupt Status Register
Indicates the raw interrupt status for a pin.
0: No interrupt occurred on the pin,
1: An interrupt is occurred on the pin.
For the edge-triggered interrupts,
write a 1 to the pin to clear that interrupt.
For level-triggered interrupt, no action is needed.
GPIOMIS GPIO_PORTx_MIS_R GPIO Masked Interrupt Status Register
Indicates the state of the interrupt.
0: No interrupt occurred or the pin has been masked,
1: An interrupt has been occurred.
GPIOICR GPIO_PORTx_ICR_R GPIO Interrupt Clear Register
Clears an edge-triggered interrupt.
0: No action,
1: The corresponded edge-triggered interrupt is cleared.
Table: The bit values and functions for GPIO interrupt controls.
  • All of these registers are 32-bit, but only lowest 8 bits are used and each bit corresponds to each pin in the selected GPIO Port: bit 0 is for pin 0, bit 1 is for pin 1, and so on. The above table shows the bit values and their functions for these registers.
  • Before any exception or interrupt can be applied to any pin on any GPIO Port, all GPIO pins on selected GPIO Port should be initialized and configured via related GPIO registers.

GPIO Interrupt Control Registers Description

GPIO Interrupt sense register (GPIOIS)

Tm4c gpiois r.png

Bit Bit Name Description
7-0 IS GPIO Interrupt Sense
0: The edge on the corresponding pin is detected (edge-sensitive).
1: The level on the corresponding pin is detected (level-sensitive).

First, we must use GPIO Interrupt Sense (GPIOIS) register to decide the level or edge. Only after using the GPIOIS register we need to indicate which level or edge. To do that, we use the GPIO Interrupt Event (GPIOIEV) to decide low-level, high-level, falling, or rising-edge. The GPIO Interrupt Both Edges (GPIOIBE) register bits overwrite the decision in GPIOIEV. Unless both edge interrupt is desired, the bit in GPIOIBE needs to be cleared.

GPIO Interrupt Event Register (GPIOIEV)

Tm4c gpioiev r.png

GPIOIS
(interrupt sense)
GPIOIEV
(Interrupt Event)
0
0
Falling edge
0
1
Rising edge
1
0
Low level
1
1
High level
Table 7.4: Using GPIOIM and GPIOIEV Registers.
  • Since we need a rising edge triggered interrupt at PF4, so writing 1 to the respective bit field will do the same for us.

GPIO Interrupt Both Edge (GPIOIBE)

Tm4c gpioibe r.png

Bit Bit Name Description
7-0 IBE GPIO Interrupt Both Edges
0: Interrupt generation is controlled by the GPIO Interrupt Event (GPIOIEV) register
1: Both edges on the corresponding pin trigger an interrupt


  • Setting the corresponding bit field enables the interrupts for both edges i.e. rising edge and falling edge but our concern is to enable the interrupts for rising edge only. Making the corresponding bit field i.e. PF4 to 0 will allow us to use this register in conjunction with the GPIOIEV register.

GPIO Interrupt Clear Register (GPIOICR)

Tm4c gpioicr r.png

  • The corresponding bit fields in this register clears the interrupt for the respective pin. To ensure that any previous interrupt has been cleared writing 1 to the respective bit field will clear the interrupt on that pin.
  • It is critical that the interrupt handler clears the interrupt flag before returning from interrupt handler. Otherwise the interrupt appears as if it is still pending and the interrupt handler will be executed again and again forever and the program hangs.

GPIO Interrupt Mask Register (GPIOIM)

Tm4c gpioim r.png

  • We need to enable the interrupt capability of a given peripheral at the module level. This should be done after other configurations of that peripheral are done. In the case of I/O ports, each pin can be used as a source of external hardware interrupt. This is done with the GPIO Interrupt Mask (GPIOIM) register.
  • Notice that, the lower 8 bits of this register is used to enable the interrupt capability of each pin of the I/O port. To enable the interrupts for PF0 and PF4 pins, we will need the following:
GPIO_PORTF_IM_R |= 0x11;  /* unmask interrupt */

GPIO Raw Interrupt Status (GPIORIS)

Tm4c gpioris r.png


Bit Bit Name Description
7-0 RIS GPIO Interrupt Raw Status
0: An interrupt condition has not occurred on the corresponding pin.
1: An interrupt condition has occurred on the corresponding pin.


  • For edge-detect interrupts, this bit is cleared by writing a 1 to the corresponding bit in the GPIOICR register.
  • For a GPIO level-detect interrupt, the bit is cleared when the level is deasserted.

GPIO Masked Interrupt Status (GPIOMIS)

Tm4c gpiomis r.png


Bit Bit Name Description
7-0
MIS
GPIO Masked Interrupt Status
0: An interrupt condition on the corresponding pin is masked or has not occurred.
1: An interrupt condition on the corresponding pin has triggered an interrupt to the interrupt controller.


  • For edge-detect interrupts, this bit is cleared by writing a 1 to the corresponding bit in the GPIOICR register.
  • For a GPIO level-detect interrupt, the bit is cleared when the level is deasserted.

NVIC Interrupt Priority Register

TM4C Interrupt Priority.jpg

Bit/Field Name Description
7:5 INTA Interrupt Priority for Interrupt [4n]
This field holds a priority value, 0-7, for the interrupt with the number [4n], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
15:13 INTB Interrupt Priority for Interrupt [4n+1]
This field holds a priority value, 0-7, for the interrupt with the number [4n+1], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
23:21 INTC Interrupt Priority for Interrupt [4n+2]
This field holds a priority value, 0-7, for the interrupt with the number [4n+2], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
31:29 INTD Interrupt Priority for Interrupt [4n+3]
This field holds a priority value, 0-7, for the interrupt with the number [4n+3], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.


PRIn Register Bit Field Interrupt Source Priority Register Macros
Bits 31:29 Interrupt[IRQ] = Interrupt[4n+3]
NVIC_PRIn_R
Bits 23:21 Interrupt[IRQ] = Interrupt[4n+2]
Bits 15:13 Interrupt[IRQ] = Interrupt[4n+1]
Bits 7:5 Interrupt[IRQ] = Interrupt[4n]
Table 7.5: Priority register bit fields.
  • Table 7.5 represents the priority register bit fields against the interrupt sources. This priority register bit field is 3-bits wide which means that for an interrupt there can be eight priority levels from 000 to 111 and it can be programmed as per the need.
  • n represents the group number of priority registers, for each group n registers NVIC_PRIn can control up to 4 peripheral ranging from 4n to 4n+3.
    To understand this better just take an example, suppose that for an interrupt handler whose IRQ number is 0, in order to satisfy the equation interrupt[4n]=0 the value of n must be zero which corresponds to the NVIC_PRI0_R also this same register can configure the priority levels for 4n to 4n+3 peripherals.
  • In this case the value of n is 0 therefore the same priority level register can be used to configure the interrupts whose IRQ Number are within 4×0 to 4×0+3, which corresponds to the IRQ number 0,1,2,3.
  • In tm4c123gh6pm_startup_ccs_gcc.c file the IRQ number 0 to 3 represents the interrupt handlers for GPIOA to GPIOD respectively. In a program for each interrupt the priority level can be set in the corresponding bit fields.

Table 7.6 shows some of the priority registers on the NVIC. Each register contains an 8-bit priority field for four devices. On the TM4C micro controllers, only the top three bits of the 8-bit field are used. This allows us to specify the interrupt priority level for each device from 0 to 7, with 0 being the highest priority.

Address 31 - 29 23 - 21 15 - 13 7 - 5 Name
0xE000E400 GPIO Port D GPIO Port C GPIO Port B GPIO Port A NVIC_PRI0_R
0xE000E404 SSI0, Rx Tx UART1, Rx Tx UART0, Rx Tx GPIO Port E NVIC_PRI1_R
0xE000E408 PWM Gen 1 PWM Gen 0 PWM Fault I2C0 NVIC_PRI2_R
0xE000E40C ADC Seq 1 ADC Seq 0 Quad Encoder 0 PWM0 Gen 2 NVIC_PRI3_R
0xE000E410 Timer 0A Watchdog ADC Seq 3 ADC Seq 2 NVIC_PRI4_R
0xE000E414 Timer 2A Timer 1B Timer 1A Timer 0B NVIC_PRI5_R
0xE000E418 Comp 2 Comp 1 Comp 0 Timer 2B NVIC_PRI6_R
0xE000E41C GPIO Port G GPIO Port F Flash Control System Control NVIC_PRI7_R
0xE000E420 Timer 3A SSI1, Rx Tx UART2, Rx Tx GPIO Port H NVIC_PRI8_R
0xE000E424 CAN0 Quad Encoder 1 I2C1 Timer 3B NVIC_PRI9_R
0xE000E428 Hibernate Ethernet CAN2 CAN1 NVIC_PRI10_R
0xE000E42C uDMA Error uDMA Soft Tfr PWM Gen 3 USB0 NVIC_PRI11_R
0xE000ED20 SysTick PendSV --- Debug NVIC_SYS_PRI3_R
Table 7.6: Most popular priority registers used in the TM4C123GH6PM NVIC.
  • The interrupt number is loaded into the IPSR register. The servicing of interrupts does not set the I bit in the PRIMASK, so a higher priority interrupt can suspend the execution of a lower priority ISR.
  • If a request of equal or lower priority is generated while an ISR is being executed, that request is postponed until the ISR is completed. In particular, those devices that need prompt service should be given high priority.

Enabling and Disabling an Interrupt

Upon Reset, all the interrupts are disabled. To enable any interrupt we should:

  1. Enable the interrupt for a specific peripheral module.
    This is done with the GPIO Interrupt Mask (GPIOIM) register.
  2. Enable the interrupts at the NVIC module.
  3. Enable the interrupt globally .

Interrupt enabling with all 3 levels

Tm4c123 int enable 3level.png

Figure:Interrupt enabling with all 3 levels


Tm4c gpiom.png

Figure:GPIO Interrupt Mask (GPIOIM)

Interrupt Set Enable Register

It is the interrupt set enable register ranging from NVIC_EN0_R ... NVIC_EN3_R, each ISER register is 32 bit wide that can be used to set the interrupt against the respective IRQ numbers. Each ISER register can be used to enable 32 different types of interrupt sources. For example NVIC_EN0_R is used to enable the interrupt sources whose IRQ numbers are 0-31, similarly the interrupt sources whose IRQ numbers are 32-63 can be enabled by NVIC_EN1_R and so on. The corresponding bit field is required to be set according to the IRQ number of the interrupt sources since each register is 32 bit wide. If the interrupt source whose IRQ number is greater than 31 the corresponding bit number can be calculated by this formula:

bit number = IRQ number - 32(n-1) 

where n=1 for interrupt sources having IRQ number 0-31. Similarly n=2 for interrupt sources having IRQ number 32-63 and so on. For enabling interrupt at PF4 pin writing 1 to the bit field 30 of NVIC_EN0_R will do the same for us, as its IRQ number is 30.

To disable interrupts there are another registers: NVIC_DIS0_R to NVIC_DIS3_R (Interrupt Clear Enable). Writing zeros to the NVIC_EN0_R through NVIC_EN3_R registers has no effect. To disable interrupts we write ones to the corresponding bit in the NVIC_DIS0_R through NVIC_DIS3_R register.

Enable Register 32-Enable Bits Address
0
1
2
3
4
5
6-29
30
31
NVIC_EN0_R PORTA PORTB PORTC PORTD PORTE UART0 ... PORTF PORTG 0xE000E100
NVIC_EN1_R PORTH UART2 SSI1 Timer3A Timer3B I2C1 ... UART6 UART7 0xE000E104
NVIC_EN2_R ... ... ... ... I2C2 I2C3 ... WTimer0A WTimer0B 0xE000E108
NVIC_EN3_R WT1A WT1B WT2A WT2B WT3A WT3B ... GPIOQ2 GPIOQ3 0xE000E10C
Table 7.7: Relationship between each bit on interrupt enable register and related peripheral.

Global interrupt enable/disable

Global interrupt enable/disable allows us with a single instruction to mask all interrupts during the execution of some critical task such as manipulating a common pointer shared by multiple threads. In ARM Cortex M, we do the global enable/disable of interrupts with assembly language instructions of CPSID I (Change processor state-disable interrupts) and CPSIE I (Change processor state-enable interrupts). In C language we use inline assembly language instructions:

void DisableInterrupts(void){__asm ("CPSID  I\n");}
void EnableInterrupts(void){__asm  ("CPSIE  I\n");}

Initialize and Configure GPIO Interrupt Control Registers

To initialize and configure GPIO interrupt controls, one needs to program the GPIOIS, GPIOIBE, GPIOEV, and GPIOIM registers to configure the type, event, and mask of the interrupts for each port. The following steps should be used to do this initialization and configuration process:

  • Configure the GPIOIM register to disable (mask) the undesired pins.
  • Configure the GPIOIS register to indicate the interrupt-triggering type, edge, or level.
  • Configure the GPIOIBE register to indicate if this interrupt is triggered by both edges.
  • Reset the GPIORIS register to 0 to make it ready to set a flag if any interrupt occurred.
  • Configure the GPIOIM register to enable (unmask) the desired pins.

How to configure and set up an interrupt and its handler

Now let’s provide an example to illustrate how to configure and set up an interrupt and its handler based on the above Tables. For example, we want to set up and configure an interrupt for GPIO PortF. Perform the following operations to complete this job:

  1. Find the IRQ number for this interrupt from Table 7.3. The IRQ number for the GPIO PortF is 30.
  2. Based on Table 7.6, obtain the group number of the priority register (n). The IRQ number is 30. In order to make the equation 30 = interrupt[4n + 2] hold, n must be 7. This means that we need to use group 7 priority register NVIC_PRI7_R with bits 23-21 to configure the priority level for the GPIO PortF. Since the IRQ number of this port is 30, we can set the priority level for this port as 5, (101B), in bits 23-21 on the NVIC_PRI7_R. This setup can be written as NVIC_PRI7_R = (NVIC_PRI7_R & 0xFF00FFFF) | 0x00A00000 in the user’s program.
  3. Based on Table 7.7, obtain the bit field in the NVIC Set Enable Register to enable this port. Since the IRQ number of the Port F is 30, the bit 30 in the NVIC_EN0_R register should be set to 1 to enable this port. This setup can be written as NVIC_EN0_R = 0x40000000.
  4. Open tm4c123gh6pm_startup_ccs_gcc.c for editing. This file contains the vector table among other things. Open the file and look for the GPIO PortF vector. You need to carefully find the appropriate vector position and replace IntDefaultHandler with the name of your Interrupt handler.
  5. After going through all these steps an EnableInterrupts() function is called to perform the global interrupt enable function. Note that we have to enable the pull up at PF4 in order to provide high or low input signal.
  6. It is critical that the interrupt handler clears the interrupt flag before returning from interrupt handler. Otherwise the interrupt appears as if it is still pending and the interrupt handler will be executed again and again forever and the program hangs. The PORTF interrupt flag is cleared by writing a 1 to the bit that corresponds to the pin that triggered the interrupt in the GPIO Interrupt Clear Register (GPIOICR). In the case of SW1 (PF4), the interrupt flag is cleared by:
GPIO_PORTF_ICR_R = 0x10;

Note:The ARM Cortex writes are buffered. That means a write does not take effect immediately. It may take many clock cycles before the write to ICR to clear the interrupt flags. When return from interrupt handler and the interrupt flag is still pending, the interrupt handler will be executed again. One way to ensure that interrupt flags are cleared before returning from interrupt handler is to perform a read to force the write to take effect.


sw1_int.c

  1. /* sw1_int.c
  2.  *
  3.  * Runs on EK-TM4C123GXL LaunchPad
  4.  *
  5.  * GPIO PORTF interrupt that will toggle the on board Blue LED
  6.  * on rising edge whenever a user switch (SW1) is pressed.
  7.  *
  8.  */
  9. #include <stdint.h>
  10. #include "inc/tm4c123gh6pm.h"
  11.  
  12. void DisableInterrupts(void);
  13. void EnableInterrupts(void);
  14. void WaitForInterrupt(void);
  15. void GPIOPortF_Init(void);
  16. void GPIOPortF_Handler(void);
  17.  
  18. void GPIOPortF_Init(void)
  19. {
  20.  
  21.     SYSCTL_RCGC2_R |= 0x00000020;   /* 1) activate clock for Port F */
  22.  
  23.     GPIO_PORTF_LOCK_R = 0x4C4F434B; /* 2) unlock GPIO Port F */
  24.     GPIO_PORTF_CR_R = 0x1F;         /* allow changes to PF4-0 */
  25.     GPIO_PORTF_AMSEL_R = 0x00;      /* 3) disable analog on PF */
  26.     GPIO_PORTF_PCTL_R = 0x00000000; /* 4) PCTL GPIO on PF4-0 */
  27.     GPIO_PORTF_DIR_R = 0x0E;        /* 5) PF4,PF0 in, PF3-1 out */
  28.     GPIO_PORTF_AFSEL_R = 0x00;      /* 6) disable alt funct on PF7-0 */
  29.     GPIO_PORTF_PUR_R = 0x11;        /* enable pull-up on PF0 and PF4 */
  30.     GPIO_PORTF_DEN_R = 0x1F;        /* 7) enable digital I/O on PF4-0 */
  31.  
  32.     GPIO_PORTF_IS_R &= ~0x10;       /*  PF4 is edge-sensitive */
  33.     GPIO_PORTF_IBE_R &= ~0x10;      /*  PF4 is not both edges */
  34.     GPIO_PORTF_IEV_R &= ~0x10;      /*  PF4 falling edge event */
  35.     GPIO_PORTF_ICR_R = 0x10;        /*  Clear flag4 */
  36.     GPIO_PORTF_IM_R |= 0x10;        /*  arm interrupt on PF4 */
  37.     NVIC_PRI7_R = (NVIC_PRI7_R & 0xFF1FFFFF) | 0x00A00000; /*  priority 5 */
  38.     NVIC_EN0_R = 0x40000000;        /*  Enable interrupt 30 in NVIC */
  39.  
  40.     EnableInterrupts();             /* Enable global Interrupt flag (I) */
  41. }
  42.  
  43. void GPIOPortF_Handler(void)
  44. {
  45.     volatile int readback;
  46.  
  47.     GPIO_PORTF_ICR_R = 0x10;        /* clear PF4 int */
  48.     GPIO_PORTF_DATA_R ^= (1<<2);    /* toggle Blue LED */
  49.     readback = GPIO_PORTF_ICR_R;    /* a read to force clearing of interrupt flag */
  50.     readback = readback;
  51. }
  52.  
  53. int main(void)
  54. {
  55.     GPIOPortF_Init();               /* initialize GPIO Port F interrupt */
  56.  
  57.     while(1) {
  58.         WaitForInterrupt();
  59.     }
  60. }
  61.  
  62. /*********** DisableInterrupts ***************
  63. *
  64. * disable interrupts
  65. *
  66. * inputs:  none
  67. * outputs: none
  68. */
  69.  
  70. void DisableInterrupts(void)
  71. {
  72.     __asm ("    CPSID  I\n");
  73. }
  74.  
  75. /*********** EnableInterrupts ***************
  76. *
  77. * emable interrupts
  78. *
  79. * inputs:  none
  80. * outputs: none
  81. */
  82.  
  83. void EnableInterrupts(void)
  84. {
  85.     __asm  ("    CPSIE  I\n");
  86. }
  87.  
  88. /*********** WaitForInterrupt ************************
  89. *
  90. * go to low power mode while waiting for the next interrupt
  91. *
  92. * inputs:  none
  93. * outputs: none
  94. */
  95.  
  96. void WaitForInterrupt(void)
  97. {
  98.     __asm  ("    WFI\n");
  99. }

1. Sample program (SW1 Interrupt)

  • Create a CCS Project with "Empty Project"
  • Download sw1_int.c program and Add this file to your project.
  • Open tm4c123gh6pm_startup_ccs_gcc.c for editing and replace IntDefaultHandler with the GPIOPortF_Handler in the GPIO PortF vector position.
  • Build and Debug (Run) the program.
    Run this code and load it into the flash of microcontroller. You will see that the blue LED gets turned on when user switch is pressed first then if it is pressed again it gets turned off.

2. GPIOF interrupt from SW1 and SW2

  • Rewrite sw1_int.c program to distinguish the interrupt pin. Toggle Red LED on PF1 continuously. Upon pressing either SW1 or SW2, the Green or Blue LED will toggle three times. main program toggles Red LED while waiting for interrupt from SW1 or SW2.

3. Interrupt from External Source

  • Write a program to toggle an LED at the same rate as the input frequency by connecting a square wave of 3.3V to a pin of Portx. (You can make it to toggle on positive or negative edge)
    Hint: Configure PORTD6 to trigger interrupt by falling edge. In the interrupt handler, the green LED (PF3) is toggled. The green LED should have half the frequency of the input signal at PORTD6. IRQ3 is assigned to PORTD6.

See Also

  1. EK-TM4C123GXL LaunchPad Board
  2. GPIO Programming



Using Systick Timer with TM4C123GH6PM Launchpad

So far we have learned that how to program general purpose input output(GPIO) of ARM Cortex M-4. But we have not generated the delay in micro controller. In this section we will generate delay using different methods and blink on board LEDs. There are two types of delays that can be generated by our program:

  1. Software delay
  2. Hardware delay

Software delay

This type of delay is nothing but making the controller busy, doing the task which will occupy a certain duration. For example if we want our friend to wait for us then instead of telling him to wait we can simply engage him in other task. But the generated time may or may not be so accurate.

Example: In C code if we can use this for loop for generating a delay of 1 second.

  1.  void delay_1sec(void)
  2.  {
  3.     for( unsigned long i = 0; i <= 3000000; i++ )
  4.         ;
  5.  }

This method doesn’t generate the accurate time delay, but approximate. For generation of accurate delay in microsecond we prefer hardware delay.

Hardware delay

The hardware delay is most precise method to generate delay. In this method we use timer which is the most popular and useful feature of microcontrollers. Generally delay with timer is like waiting a bucket to be empty if we make a small hole to leak its filled liquid more the liquid more time it will take to empty the bucket. In this article, we are going to use a special timer called systick timer. In our micro controller we have six 64 bit and six 32 bit timer excluding systick timer. This timer is very useful and plays very important role in RTOS design. We will see other timers later. In our micro controller, Systick timer is 24 bit wide. For the generation of delay, at first we need to make sure that our controller is working on the clock frequency as we are expecting. This step is required to select the clock source only at external crystal without PLL.

SysTick Timer

SysTick is a simple counter that we can use to create time delays and generate periodic interrupts. It exists on all Cortex-M microcontrollers, so using SysTick means the system will be easy to port to other microcontrollers.

SysTick Timer Internal Structure

As we learned earlier that modifying registers are the key for configuration and desired functionality. Hence systick timer can be used by modifying these registers.

  1. Systick Reload value (STRELOAD)
  2. Systick Control and Status Register (STCTRL)
  3. Systick Current Value (STCURRENT)

Systick Reload Value Register

This register acts like a bucket filled with a liquid that will be empty after some time duration and we will get acknowledgement by a change in flag bit in STCTRL Register. This register is 24 bit wide.
Tm4c systick streload r.png

Since this register is 24 bit wide it can store upto 0xFFFFFF or 16777215. when we load any value into this register and trigger the timer it starts to count down and when the value reaches to 0 it sets the COUNT FLAG. We will see how to reload and check flag bit in the next few steps.

Systick control and Status register

This register is shown in the following figure
Tm4c systick stctl r.png
Bit Name Description
0 Enable Enable
0: the counter is disabled
1: enables SysTick to begin counting Down
1 INTEN Interrupt Enable
0: Interrupt generation is disabled
1: when SysTick counts to 0 an interrupt is generated
2 CLK_SRC Clock Source
0: Precision internal oscillator (PIOSC) divided by 4
1: System clock
16 COUNT Count Flag
0: the SysTick has not counted Down to zero since the last time this bit was read
1: the SysTick has counted Down to Zero
Note: this flag is cleared by reading the STRCTL or writing to STCURRENT Register

We need to set our main clock to system clock by setting CLK_SRC to 1. And we don’t want interrupt method so INTEN bit will be 0. Now we are going to trigger our timer by writing ENABLE bit 1 so writing 0x5 will trigger our timer at the same time it will also set the configuration. Now the loaded value will be started to count down. When the timer gets rollover the bit 16 will set to one. hence we need to monitor 16th bit.

If INTEN=1, when the COUNT flag is set, it causes an interrupt via the NVIC. INTEN is D1 of the STCTRL register.

Systick Register Summary

Address 31-24 23-17 16 15-13 2 1 0 Name
$E000E010 o 0 COUNT 0 CLK_SRC INTEN ENABLE NVIC_ST_CTRL_R
$E000E014 o 24-bit RELOAD value NVIC_ST_RELOAD_R
$E000E018 o 24-bit CURRENT value of SysTick counter NVIC_ST_CURRENT_R

Delay time calculation

Since we are working with external clock i.e. 16 MHz, each pulse generated by the clock source will have:

1/XTAL frequency = 1/(16*10^6) = 62.5ns time period. 

So if we load 253 into the RELOAD register and trigger the counter it will count down with next pulse and will take 62.5ns to change its value from 253 to 252. Hence, In order to generate the delay, we can calculate the approximate value that has to be loaded into this register by the formula-

Reload Value = XTAL*Time delay

one extra clock delay is already included to set the flag for rollover, hence we get one extra clock delay. By subtracting by one will give exact time delay.

Reload Value = (XTAL*Time Delay)-1

Remember that in one shoot, it can only take 0xFFFFFF maximum value. Therefore in one shoot, we can only generate maximum of Time delay

TimeDelay = (ReloadValue+1)/XTAL=16777215+(1/(16*10^6))
TimeDelay = 1.048575937 sec.

Example: For generating 1 sec of delay the value that has to be loaded into the RELOAD Register

Reload Value = (XTAL*Time delay)-1
Reload Value = (16*10^6*1)-1
Reload Value = 15999999

SysTick timer Initialization

There are four steps to initialize the SysTick timer.

  1. Clear the ENABLE (NVIC_ST_CTRL_R) bit to turn off SysTick during initialization.
  2. Set the RELOAD (NVIC_ST_RELOAD_R) register.
  3. Write to the NVIC_ST_CURRENT_R value to clear the counter.
  4. Write the desired mode to the control register, NVIC_ST_CTRL_R.
    • Set the CLK_SRC bit specifying the core clock will be used.
    • We must set CLK_SRC=1 bit specifying the core clock will be used, because CLK_SRC=0 external clock mode is not implemented on the LM3S/TM4C family.
    • Set INTEN (NVIC_ST_CTRL_R) to enable interrupts, but in this first example we clear INTEN so interrupts will not be requested.
    • Set the ENABLE (NVIC_ST_CTRL_R) bit so the counter will run.

When the CURRENT (NVIC_ST_CURRENT_R) value counts down from 1 to 0, the COUNT flag is set. On the next clock, the CURRENT is loaded with the RELOAD value. In this way, the SysTick counter (CURRENT) is continuously decrementing. If the RELOAD value is n, then the SysTick counter operates at modulo n+1 (...n, n-1, n-2 ... 1, 0, n, n-1, ...). In other words, it rolls over every n+1 counts.

The COUNT flag could be configured to trigger an interrupt. However, in this first example interrupts will not be generated.

Source Code

Delay in 62.5ns units

  1. /* delay is in 62.5ns units */
  2. void SysTick_Wait(uint32_t delay)
  3. { 
  4.     NVIC_ST_CTRL_R = 0;            /* (1) disable SysTick during setup */
  5.     NVIC_ST_RELOAD_R = delay-1;    /* (2) number of counts to wait */
  6.     NVIC_ST_CURRENT_R = 0;         /* (3) any value written to CURRENT clears */
  7.     NVIC_ST_CTRL_R |= 0x5;         /* (4) enable SysTick with core clock */
  8.  
  9.     while((NVIC_ST_CTRL_R&0x00010000)==0) {
  10.         ;                          /* wait for COUNT flag */
  11.     }
  12. }


One Second Delay

  1. void One_Second_Delay(void)
  2. {
  3.     NVIC_ST_CTRL_R = 0;            /* disable SysTick during setup */
  4.     NVIC_ST_RELOAD_R = 15999999;    /* Reload Value goes here */
  5.     NVIC_ST_CTRL_R |= 0x5;          /* enable SysTick with core clock */
  6.     while( (NVIC_ST_CTRL_R & (1<<16) ) == 0)
  7.         ;                           /* Monitoring bit 16 to be set */
  8.     NVIC_ST_CTRL_R = 0;             /* Disabling SysTick Timer */
  9. }


See Also

Using SysTick with Interrupt

In the previous article, we used SysTick in a blocking mode. In this article, we will use SysTick with interrupt.

The SysTick interrupt can be used to initiate an action on a periodic basis. This action is performed internally at a fixed rate without external signal. For example, in a given application we can use SysTick to read a sensor every 200 msec. SysTick is used widely for an operating system so that the system software may interrupt the application software periodically (often 10 ms interval) to monitor and control the system operations.

If INTEN=1, when the COUNT flag is set, it causes an interrupt via the NVIC. INTEN is D1 of the STCTRL register. Examining interrupt vector table for ARM Cortex, we see the SysTick is the interrupt #15 assigned to the system itself.

Source Code

  1. /* systick_int.c
  2.  *
  3.  * Toggle the red LED using the SysTick interrupt
  4.  *
  5.  * This program sets up the SysTick to interrupt at 1 Hz.
  6.  * The system clock is running at 16 MHz.
  7.  * 1sec/62.5ns = 16,000,000 for RELOAD register.
  8.  * In the interrupt handler, the red LED is toggled.
  9. */
  10.  
  11. #include <stdint.h>
  12. #include "inc/tm4c123gh6pm.h"
  13.  
  14. void enable_irq(void);
  15.  
  16. int main (void)
  17. {
  18.     /* enable clock to GPIOF at clock gating control register */
  19.     SYSCTL_RCGC2_R |= 0x20;
  20.     /* enable the GPIO pins for the LED (PF3, 2, 1) as output */
  21.     GPIO_PORTF_DIR_R = 0x0E;
  22.     /* enable the GPIO pins for digital function */
  23.     GPIO_PORTF_DEN_R = 0x0E;
  24.  
  25.     /* Configure SysTick */
  26.     NVIC_ST_RELOAD_R = 16000000-1;  /* reload with number of clocks per second */
  27.     NVIC_ST_CTRL_R = 7;             /* enable SysTick interrupt, use system clock */
  28.  
  29.     enable_irq();                   /* global enable interrupt */
  30.  
  31.     while(1) {
  32.         ;
  33.     }
  34. }
  35.  
  36. void SysTick_Handler(void)
  37. {
  38.     GPIO_PORTF_DATA_R ^= 2;         /* toggle the red LED */
  39. }
  40.  
  41. /* global enable interrupts */
  42. void inline enable_irq(void)
  43. {
  44.     __asm  ("    CPSIE  I\n");
  45. }

The above program uses the SysTick to toggle the red LED of PF1 every second. We need the RELOAD value of 16,000,000-1 since 1sec / 62.5nsec = 16,000,000. We assume the CPU clock is 16MHz (1/16MHz=62.5ns). The COUNT flag is raised every 16,000,000 clocks and an interrupt occurs. Then the RELOAD register is loaded with 16,000,000-1 automatically.

Notice the enabling of interrupt in SysTick Control register. Since SysTick is an internal interrupt, the COUNT flag is cleared automatically when the interrupt occurs. Also notice the SysTick is part of INT1-INT15 and not part of IRQ. For this reason we must use the CTLR register to enable it.

Note: Open tm4c123gh6pm_startup_ccs_gcc.c for editing. This file contains the vector table among other things. Open the file and look for the SysTick vector. You need to carefully find the appropriate vector position and replace IntDefaultHandler with the name of your Interrupt handler (SysTick_Handler).

See Also

  1. We used Software delay in our blinky, read_sw1, and read_sw2 programs. Replace Software Delay with SysTick Timer Delay.
  2. If we are sure the execution speed of our function is less than (224 bus cycles), we can use this timer to collect timing information with only a modest amount of intrusiveness. Use the SysTick timer to measure the Software Delay functions we used in the earlier programs.
  3. If we activate the PLL and change the bus clock to 50 MHz (20ns), what is the longest elapsed time we could measure?

Using PLL

TM4C123GH6PM MCU has four different clock sources:

  1. Precision Internal Oscillator (PIOSC) : 16 MHz.
  2. Main Oscillator (MOSC) : It can use an external clock source or an external crystal.
  3. Low-Frequency Internal Oscillator (LFIOSC) : An on-chip internal 30 kHz Oscillator used for Deep-Sleep power-saving modes.
  4. Hibernate RTC Oscillator (RTCOSC) : It can be configured to be the 32.768 KHz external oscillator source from the Hibernation (HIB) module or the HIB Low-Frequency clock source (HIB LFIOSC), which is intended to provide the system with a real-time clock source.


Block Diagram of the main clock tree on the TM4C including the PLL
Figure: Block Diagram


The system clock is generated by a PLL that can be driven by any crystals or oscillators running between 5 and 25 MHz. The output frequency of the PLL is always 400 MHz, and it is independent on the input clock sources.

Two clock sources, Main OSC (MOSC) and Precision Internal osc (PIOSC) 16 MHz, can work as a clock source for the PLL, and this source can be selected via the MUX. Two multiplexers (MUXs) are used to select different clock sources, and two ways can be used to create a system clock to be used by the CPU:

  1. One way is to use the Phase-Locked Loop (PLL) clock generator that needs a clock source as the input source to create this system clock.
  2. Another way is to directly use any one of four clock sources, and this can be selected via a MUX. An easy way is to use Precision Internal OSC (16 MHz) divided by 4 to get a 4-MHz system clock.


When using the PLL, the output frequency of 400 MHz is pre-divided by 2 (becomes 200 MHz) before the user’s divisor is applied. Users can modify this 200-MHz system clock by adding different dividing factors in the SYSDIV in their program to use a lower-frequency system clock. The selected clock source can avoid the SYSDIV and USESYSDIV dividing operations via BYPASS for both MUXs and can be directly sent out as the system clock.

Two registers, Run-Mode Clock Configuration (RCC) register and Run-Mode Clock Configuration 2 (RCC2) register, provide controls for the system clock. The RCC2 register is used to provide additional control parameters that offer additional encodings over the RCC register. These registers control the following clock functionality:

  • Source of clocks in sleep and deep-sleep modes
  • System clock derived from PLL or other clock source
  • Enable or disable the oscillators and PLL
  • Clock divisors
  • Crystal input selection

Run-Mode Clock Configuration

Run-Mode Clock Configuration RCC

Bit
Number
Bit
Name
Bit Function
0 MOSCDIS 0: The main oscillator is enabled
1: The main oscillator is disabled—Default
5-4 OSCSRC Oscillator Source Selection:
0x0: Main Oscillator (MOSC)
0x1: Precision Internal Oscillator (PIOSC)—Default
0x2: Precision Internal Oscillator/4 (PIOSC/4)
0x3: Low-Frequency Internal Oscillator (LFIOSC)
11 BYPASS 0: The system clock uses the PLL output clock divided by the
divisor specified by SYSDIV (bits 26–23 in this register)
1: The system clock uses the OSC source and divided by the
divisor specified by SYSDIV (bits 26–23 in this register)
13 PWRDN 0: The PLL is operating normally
1: The PLL is powered down. Make sure that another clock
source is functioning and that the BYPASS bit is set before
setting this bit
22 USESYSDIV 0: The system clock is used undivided
1: The system clock divider is used for the system clock.
The system clock divider is forced to be used when the PLL is
selected as the source
26-23 SYSDIV System Clock Divisor
Specifies which divisor is used to generate the system clock from
either the PLL output or from the oscillator source, depending on
how the BYPASS bit in this register is configured.
27 ACG 0: The Run-Mode Clock Gating Control (RCGCn) registers are
used when the microcontroller enters a sleep mode
1: The SCGCn or DCGCn registers are used to control the clocks
distributed to the peripherals when the microcontroller is in a
sleep mode.


In the RCC register, the SYSDIV field specifies which divisor is used to generate the system clock from either the PLL output or the oscillator source. When using the PLL, the VCO frequency of 400 MHz is pre-divided by 2 before the divisor is applied.


SYSDIV DIVISOR Frequency
BYPASS=0
Frequency
BYPASS=1
Symbolic Definition
(Tivaware)
0x0 ÷1 Reserved Clock source frequency/1 SYSCTL_SYSDIV_1
0x1 ÷2 Reserved Clock source frequency/2 SYSCTL_SYSDIV_2
0x2 ÷3 66.67 MHz Clock source frequency/3 SYSCTL_SYSDIV_3
0x3 ÷4 50 MHz Clock source frequency/4 SYSCTL_SYSDIV_4
0x4 ÷5 40 MHz Clock source frequency/5 SYSCTL_SYSDIV_5
0x5 ÷6 33.33 MHz Clock source frequency/6 SYSCTL_SYSDIV_6
0x6 ÷7 28.57 MHz Clock source frequency/7 SYSCTL_SYSDIV_7
0x7 ÷8 25 MHz Clock source frequency/8 SYSCTL_SYSDIV_8
0x8 ÷9 22.22 MHz Clock source frequency/9 SYSCTL_SYSDIV_9
0x9 ÷10 20 MHz Clock source frequency/10 SYSCTL_SYSDIV_10
0xA ÷11 18.18 Clock source frequency/11 SYSCTL_SYSDIV_11
0xB ÷12 16.67 MHz Clock source frequency/12 SYSCTL_SYSDIV_12
0xC ÷13 15.38 MHz Clock source frequency/13 SYSCTL_SYSDIV_13
0xD ÷14 14.29 MHz Clock source frequency/14 SYSCTL_SYSDIV_14
0xE ÷15 13.33 MHz Clock source frequency/15 SYSCTL_SYSDIV_15
0xF ÷16 12.5 MHz
Default
Clock source frequency/16 SYSCTL_SYSDIV_16


The XTAL (bits 6-10) field specifies Crystal Frequency and is given in the following table.

XTAL Crystal Freq (MHz) XTAL Crystal Freq (MHz) XTAL Crystal Freq (MHz)
0x4 3.579545 MHz 0xC 6.144 MHz 0x14 14.31818 MHz
0x5 3.6864 MHz 0xD 7.3278 MHz 0x15 16.0 MHz
0x06 4 MHz 0xE 8 MHz 0x16 16.384 MHz
0x7 4.096 MHz 0xF 8.192 MHz 0x17 18.0 MHz
0x8 4.9152 MHz 0x10 10.0 MHz 0x18 20.0 MHz
0x9 5 MHz 0x11 12.0 MHz 0x19 24.0 MHz
0xA 5.12 MHz 0x12 12.288 MHz 0x1A 25.0 MHz
0xB 6 MHz (reset value) 0x13 13.56 MHz others reserved


Run-Mode Clock Configuration 2

Run-Mode Clock Configuration RCC2

Bit
Number
Bit
Name
Bit(s) Function
6-4 OSCSRC2 Oscillator Source 2 (Selects the input source for the OSC)
0x0: MOSC (Main oscillator)
0x1: PIOSC (Precision internal oscillator)
0x2: PIOSC/4 (Precision internal oscillator / 4)
0x3: LFIOSC (Low-frequency internal oscillator)
0x4 - 0x6: Reserved
0x7: 32.768 kHz (32.768-kHz external oscillator)
11 BYPASS2 PLL Bypass 2
0: The system clock is the PLL output clock divided by the divisor specified by SYSDIV2.
1: The system clock is derived from the OSC source and divided by the divisor specified by SYSDIV2.
13 PWRDN2 Power-Down PLL 2
0: The PLL operates normally
1: The PLL is powered down.
22 SYSDIV2LSB Additional LSB for SYSDIV2
When DIV400 is set, this bit becomes the LSB of SYSDIV2. If DIV400 is clear, this bit is not used. This bit can only be set or cleared when DIV400 is set.
28-23 SYSDIV2 System Clock Divisor 2
Specifies which divisor is used to generate the system clock from either the PLL output or the oscillator source. SYSDIV2 is used for the divisor when both the USESYSDIV bit in the RCC register and the USERCC2 bit in this register are set.
30 DIV400 Divide PLL as 400 MHz versus 200 MHz
This bit, along with the SYSDIV2LSB bit, allows additional frequency choices.
0: Use SYSDIV2 as is and apply to 200 MHz predivided PLL output.
1: Append the SYSDIV2LSB bit to the SYSDIV2 field to create a 7 bit divisor using the 400 MHz PLL output.
31 USERCC2 Use RCC2
0: The RCC register fields are used, and the fields in RCC2 are ignored.
1: The RCC2 register fields override the RCC register fields.


The RCC2 provides extend fields and functions compared with the RCC register. The SYSDIV2 field in the RCC2 register is 2 bits wider than the SYSDIV field in the RCC register so that additional larger divisors up to 64 are available to allow a lower system clock frequency to be used to improve the system Deep Sleep power consumption. The following Table shows how the SYSDIV2 encoding affects the system clock frequency, depending on whether the PLL is used (BYPASS2=0) or another clock source is used (BYPASS2=1).


When the RCC2 is used, it will override the functions provided by the RCC register.

SYSDIV2 DIVISOR Frequency
BYPASS2=0
Frequency
BYPASS2=1
Symbolic Definition
(Tivaware)
0x0 ÷1 Reserved Clock source frequency/1 SYSCTL_SYSDIV_1
0x1 ÷2 Reserved Clock source frequency/2 SYSCTL_SYSDIV_2
0x2 ÷3 66.67 MHz Clock source frequency/3 SYSCTL_SYSDIV_3
0x3 ÷4 50 MHz Clock source frequency/4 SYSCTL_SYSDIV_4
0x4 ÷5 40 MHz Clock source frequency/5 SYSCTL_SYSDIV_5
... ... ... .... ...
0x9 ÷10 20 MHz Clock source frequency/10 SYSCTL_SYSDIV_10
... ... ... ... ...
0x3F ÷64 3.125 MHz Clock source frequency/64 SYSCTL_SYSDIV_64

Raw Interrupt Status (RIS)

Raw Interrupt Status (RIS)

Programming the PLL

The Main Oscillator (MOSC) for the TM4C on the evaluation board is 16 MHz. This means the reference clock (Ref Clk) input to the phase/frequency detector will be 16 MHz. For a 16 MHz crystal, we set the XTAL bits to 10101 (0x15). We use RCC2 because it provides more options

  1. Configure the system to use RCC2 (SYSCTL_RCC2_R)for advanced features. If the RCC2 register is being used, the USERCC2 bit must be set and the appropriate RCC2 bit/field is used.
  2. Set BYPASS2 (bit 11), thereby configuring the microcontroller to run off a "raw" clock source and following for the new PLL configuration to be validated before switching the system clock to the PLL.
  3. Specify the crystal frequency in the four XTAL bits. The OSCSRC2 bits are cleared to select the main oscillator as the oscillator clock source.
  4. Clear PWRDN2 (bit 13) to activate the PLL.
  5. Configure and enable the clock divider using the 7-bit SYSDIV2 field. If the 7-bit SYSDIV2 is n, then the clock will be divided by n+1. To get the desired 80 MHz from the 400 MHz PLL, we need to divide by 5. So, we place a 4 into the SYSDIV2 field.
  6. Wait for the PLL to stabilize by waiting for PLLRIS (bit 6) in the SYSCTL_RIS_R to become high.
  7. Connect the PLL by clearing the BYPASS2 bit.


PLL Sample Program

  1. /* Configure the system to get its clock from the PLL */
  2.  
  3. #include <stdint.h>
  4. #include "inc/tm4c123gh6pm.h"
  5.  
  6. #define SYSCTL_RIS_PLLLRIS      0x00000040  /* PLL Lock Raw Interrupt Status */
  7. #define SYSCTL_RCC_XTAL_M       0x000007C0  /* Crystal Value */
  8. #define SYSCTL_RCC_XTAL_6MHZ    0x000002C0  /* 6 MHz Crystal */
  9. #define SYSCTL_RCC_XTAL_8MHZ    0x00000380  /* 8 MHz Crystal */
  10. #define SYSCTL_RCC_XTAL_16MHZ   0x00000540  /* 16 MHz Crystal */
  11. #define SYSCTL_RCC2_USERCC2     0x80000000  /* Use RCC2 */
  12. #define SYSCTL_RCC2_DIV400      0x40000000  /* Divide PLL as 400 MHz vs. 200 MHz */
  13. #define SYSCTL_RCC2_SYSDIV2_M   0x1F800000  /* System Clock Divisor 2 */
  14. #define SYSCTL_RCC2_SYSDIV2LSB  0x00400000  /* Additional LSB for  SYSDIV2 */
  15. #define SYSCTL_RCC2_PWRDN2      0x00002000  /* Power-Down PLL 2 */
  16. #define SYSCTL_RCC2_BYPASS2     0x00000800  /* PLL Bypass 2 */
  17. #define SYSCTL_RCC2_OSCSRC2_M   0x00000070  /* Oscillator Source 2 */
  18. #define SYSCTL_RCC2_OSCSRC2_MO  0x00000000  /* MOSC */
  19.  
  20. #define Bus80MHz     4
  21.  
  22. void PLL_Init(void)
  23. {
  24.   /* 1) configure the system to use RCC2 for advanced features
  25.       such as 400 MHz PLL and non-integer System Clock Divisor */
  26.   SYSCTL_RCC2_R |= SYSCTL_RCC2_USERCC2;
  27.   /* 2) bypass PLL while initializing */
  28.   SYSCTL_RCC2_R |= SYSCTL_RCC2_BYPASS2;
  29.   /* 3) select the crystal value and oscillator source */
  30.   SYSCTL_RCC_R &= ~SYSCTL_RCC_XTAL_M;   	/* clear XTAL field */
  31.   SYSCTL_RCC_R += SYSCTL_RCC_XTAL_16MHZ;	/* configure for 16 MHz crystal */
  32.   SYSCTL_RCC2_R &= ~SYSCTL_RCC2_OSCSRC2_M;	/* clear oscillator source field */
  33.   SYSCTL_RCC2_R += SYSCTL_RCC2_OSCSRC2_MO;	/* configure for main oscillator source */
  34.   /* 4) activate PLL by clearing PWRDN */
  35.   SYSCTL_RCC2_R &= ~SYSCTL_RCC2_PWRDN2;
  36.   /* 5) set the desired system divider and the system divider least significant bit */
  37.   SYSCTL_RCC2_R |= SYSCTL_RCC2_DIV400;  	/* use 400 MHz PLL */
  38.   SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~0x1FC00000)   /* clear system clock divider field */
  39.                   + (Bus80MHz<<22);      	/* configure for 80 MHz clock */
  40.   /* 6) wait for the PLL to lock by polling PLLLRIS */
  41.   while((SYSCTL_RIS_R&SYSCTL_RIS_PLLLRIS)==0){
  42.       ;
  43.   }
  44.   /* 7) enable use of PLL by clearing BYPASS */
  45.   SYSCTL_RCC2_R &= ~SYSCTL_RCC2_BYPASS2;
  46. }
   # Activate the PLL and change the bus clock to 50 MHz.

UART in TM4C123GH6PM Launchpad

A serial port programming is a method of transferring data serially by the means of a few wire, unlike a parallel port which requires many wires for data transfer and limited to a short distance, serial port programming can be used for transferring the data to a larger distance. The advantage of using this serial port is that it is very cheap as compare to the parallel port since it requires a single data line for data transmission making the hardware configuration easy and simple.

Serial data communication uses two methods, asynchronous and synchronous. The synchronous method transfers a block of data (characters) at a time while the asynchronous transfers a single byte at a time.

In this article we are going to use a UART module for serial port communication that uses two pins i.e. RX and TX for data transfer but before proceeding you should have the knowledge of following terms related to the UART.

Half and full-duplex transmission

In data transmission, a duplex transmission is one in which the data can be transmitted and received. This is in contrast to a simplex transmissions such as printers, in which the computer only sends data. Duplex transmissions can be half or full duplex. If data is transmitted one way at a time, it is referred to as half duplex. If the data can go both ways at the same time, it is full duplex. Of course, full duplex requires two wire conductors for the data lines (in addition to ground), one for transmission and one for reception, in order to transfer and receive data simultaneously.

Asynchronous serial communication and data framing

The data coming in at the receiving end of the data line in a serial data transfer is all 0s and 1s; it is difficult to make sense of the data unless the sender and receiver agree on a set of rules, a protocol, on how the data is packed, how many bits constitute a character, and when the data begins and ends.

Start and stop bits

Asynchronous serial data communication is widely used for character-oriented transmissions. In the asynchronous method, each character, such as ASCII characters, is packed between start and stop bits. This is called framing. The start bit is always one bit but the stop bit can be one or two bits. The start bit is always a 0 (low) and the stop bit(s) is 1 (high). For example, look at the following figure where the ASCII character "A", binary 0100 0001, is framed between the start bit and 2 stop bits. Notice that the LSB is sent out first.

Uart framing ascii.png

In the above figure, when there is no data transfer, the signal stays 1 (high), which is referred to as MARK. The 0 (low) is referred to as SPACE. Notice that the transmission begins with a start bit followed by D0, the LSB, then the rest of the bits until the MSB (D7), and finally, the 2 stop bits indicating the end of the character "A".

In asynchronous serial communications, peripheral chips can be programmed for data that is 5, 6, 7, or 8 bits wide. While in older systems ASCII characters were 7-bit, the modern systems usually send non-ASCII 8-bit data. The old Baud code uses 5- or 6-bit characters but they are rarely seen these days even though most of the hardware still supporting them. In some older systems, due to the slowness of the receiving mechanical device, 2 stop bits were used to give the device sufficient time to organize itself before transmission of the next byte. However, in modern PCs the use of 1 stop bit is common. Assuming that we are transferring a text file of ASCII characters using 1 stop bit, we have a total of 10 bits for each character since 8 bits are for the ASCII code, and 1 and 2 bits are for start and stop bits, respectively. Therefore, for each 8-bit character there are an extra 2 bits, or 25% overhead. (2/8x100=25%)

Parity bit

In some systems in order to maintain data integrity, the parity bit of the character byte is included in the data frame. This means that for each character (7- or 8-bit, depending on the system) we have a single parity bit in addition to start and stop bits. The parity bit may be odd or even. In the case of an odd-parity the number of data bits, including the parity bit, has an odd number of 1s. Similarly, in an even-parity the total number of bits, including the parity bit, is even. For example, the ASCII character "A", binary 0100 0001, has 0 for the even-parity bit. UART chips allow programming of the parity bit for odd-, even-, and no-parity options, as we will see in the next section. If a system requires the parity, the parity bit is transmitted after the MSB, and is followed by the stop bit.

Data transfer rate

The rate of data transfer in serial data communication is stated in bps (bits per second). Another widely used terminology for bps is Baud rate. However, the baud and bps rates are not necessarily equal. This is due to the fact that baud rate is defined as number of signal changes per second. In modems, it is possible for each signal to transfer multiple bits of data. As far as the conductor wire is concerned, the baud rate and bps are the same.

Baud Rate

The baud rate is defined as the rate of data transfer in serial communication, we can choose the desired baud rate for our data transmission as specified in the data sheet, later we will show you how to select this baud rate for our micro-controller.

RS232 and other serial I/O standards

To allow compatibility among data communication equipment made by various manufacturers, an interfacing standard called RS232 was set by the Electronics Industries Association (EIA) in 1960.

Today, RS232 is the most widely used serial I/O interfacing standard. However, since the standard was set long before the advent of the TTL logic family, the input and output voltage levels are not TTL compatible. In the RS232 at the receiver, a 1 is represented by –3 to –25 V, while the 0 bit is +3 to +25 V, making –3 to +3 undefined.

For this reason, to connect any RS232 to a TTL-level chip (microprocessor or UART) we must use voltage converters such as MAX232 or MAX233 to convert the TTL logic levels to the RS232 voltage level, and vice versa. MAX232 and MAX233 IC chips are commonly referred to as line drivers.

Uart max232 2to uc.png

RS232 pins

The table below provides the pins and their labels for the RS232, commonly referred to as the DB-9 connector.

Uart db9 con.png
Pin Description
1 Data carrier detect (DCD)
2 Received data (RxD)
3 Transmitted data (TxD)
4 Data terminal ready (DTR)
5 Signal ground (GND)
6 Data set ready (DSR)
7 Request to send (RTS)
8 Clear to send (CTS)
9 Ring indicator (RI)

Data communication classification

Current terminology classifies data communication equipment as DTE (data terminal equipment) or DCE (data communication equipment). DTE refers to terminals and computers that send and receive data, while DCE refers to communication equipment, such as modems, that is responsible for transferring the data. Notice that all the RS232 pin function definitions of from the above table are from the DTE point of view.

The simplest connection between two PCs (DTE and DTE) requires a minimum of three pins, TxD, RxD, and ground. Notice that the connection between two DTE devices, such as two PCs, requires pins 2 and 3 to be interchanged. In looking at the following figure, keep in mind that the RS232 signal definitions are from the point of view of DTE.

Uart dte dce and dce dce con.png
Figure: DTE-DCE and DTE-DTE Connections

RS232 handshaking signals

To ensure fast and reliable data transmission between two devices, the data transfer must be coordinated. Some of the pins of the RS-232 are used for handshaking signals. They are described below. Due to the fact that in serial data communication the receiving device may have no room for the data there must be a way to inform the sender to stop sending data. So some of these handshaking lines may be used for flow control tool

  • DTR (data terminal ready)
    When the terminal (or a PC COM port) is turned on, after going through a self-test, it sends out signal DTR to indicate that it is ready for communication. If there is something wrong with the COM port, this signal will not be activated. This is an active-low signal and can be used to inform the modem that the computer is alive and kicking. This is an output pin from DTE (PC COM port) and an input to the modem.
  • DSR (data set ready)
    When a DCE (modem) is turned on and has gone through the self-test, it asserts DSR to indicate that it is ready to communicate. Therefore, it is an output from the modem (DCE) and an input to the PC (DTE). This is an active-low signal. If for any reason the modem cannot make a connection to the telephone, this signal remains inactive, indicating to the PC (or terminal) that it cannot accept or send data.
  • RTS (request to send)
    When the DTE device (such as a PC) has a byte to transmit, it asserts RTS to signal the modem that it has a byte of data to transmit. RTS is an active-low output from the DTE and an input to the modem.
  • CTS (clear to send)
    In response to RTS, when the modem has room for storing the data it is to receive, it sends out signal CTS to the DTE (PC) to indicate that it can receive the data now. This input signal to the DTE is used by the DTE to start transmission.
  • CD (carrier detect, or DCD, data carrier detect)
    The modem asserts signal DCD to inform the DTE (PC) that a valid carrier has been detected and that contact between it and the other modem is established. Therefore, DCD is an output from the modem and an input to the PC (DTE).
  • RI (ring indicator)
    An output from the modem (DCE) and an input to a PC (DTE) indicates that the telephone is ringing. It goes on and off in synchronization with the ringing sound. Of the six handshake signals, this is the least often used, due to the fact that modems take care of answering the phone. However, if in a given system the PC is in charge of answering the phone, this signal can be used.

From the above description, PC and modem communication can be summarized as follows:
While signals DTR and DSR are used by the PC and modem, respectively, to indicate that they are alive and well, it is RTS and CTS that actually control the flow of data. When the PC wants to send data it asserts RTS, and in response, if the modem is ready (has room) to accept the data, it sends back CTS. If, for lack of room, the modem does not activate CTS, the PC will deassert DTR and try again. RTS and CTS are also referred to as hardware control flow signals.

Uart null modem con.png
Figure: Null Modem Connection with Flow Control Signals


EK-TM4C123GXL Launchpad UART Programming

Many of the TI ARM chips come with up to eight on-chip UART ports. They are designated as UART0 - UART7. In the EK-TM4C123GXL LaunchPad board, the UART0 port is connected to the ICDI (In-Circuit Debug Interface), which is connected to a USB connector. This ICDI USB connection contains three distinct functions:

  1. Programming (downloading) using LM Flash Programming software
  2. Debugging using JTAG (Stellaris In-Circuit Debug Interface)
  3. To use as a virtual COM port

Virtual COM Port

  • When the USB cable connects the EK-TM4C123GXL LaunchPad board, the device driver at the host PC establishes a virtual connection between the PC and the UART0 of the TM4C123GH6PM micro controller.
  • On the EK-TM4C123GXL LaunchPad, the connection appears as UART0 (PA0-PA1).
  • On the host PC, it appears as a COM (/dev/ttyACM0) port and will work with communication software on the PC such as a terminal emulator (gtkterm, PuTTY, minicom, etc).
  • It is called a virtual connection because there is no need for an additional cable to make this connection.

UART Base Addresses

TI TM4C123GH6PM micro controller can have up to 8 UART ports. They are designated as UART0 to UART7. The following shows their Base addresses in the memory map

  • UART0 base: 0x4000.C000
  • UART1 base: 0x4000.D000
  • UART2 base: 0x4000.E000
  • UART3 base: 0x4000.F000
  • UART4 base: 0x4001.0000
  • UART5 base: 0x4001.1000
  • UART6 base: 0x4001.2000
  • UART7 base: 0x4001.3000

UART Register Map

Name Offset Tivaware Name Description
UARTDIR 0x000 UARTn_DR_R UART Data
UARTRSR
USRTECR
0x004 UARTn_RSR_R
UARTn_ECR_R
UART Receive Status
UARTError Clear
UARTFR 0x018 UARTn_FR_R UART Flag
UARTILPR 0x020 UARTn_ILPR_R UART IrDA Low-Power Register
UARTIBRD 0x024 UARTn_IBRD_R UART Integer Baud-Rate Divisor
UARTFBRD 0x028 UARTn_FBRD_R UART Fractional Baud-Rate Divisor
UARTLCRH 0x02C UARTn_LCRH_R UART Line Control
UARTCTL 0x030 UARTn_CTL_R UART Control
UARTIFLS 0x034 UARTn_IFLS_R UART Interrupt FIFO Level Select
UARTIM 0x038 UARTn_IM_R UART Interrupt Mask
UARTRIS 0x03C UARTn_RIS_R UART Raw Interrupt Status
UARTMIS 0x040 UARTn_MIS_R UART Masked Interrupt Status
UARTICR 0x044 UARTn_ICR_R UART Interrupt Clear
UARTDMACTL 0x048 UARTn_DMACTL_R UART DMA Control
UART9BITADDR 0x0A4 UARTn_9BITADDR_R UART 9-Bit Self Address
UART9BITAMASK 0x0A8 UARTn_9BITAMASK_R UART DMA Control
UARTPP 0xFC0 UARTn_PP_R UART Peripheral Properties
UARTCC 0xFC8 UARTn_CC_R UART Clock Configuration
where n = 0 to 7

UART Registers Setup

There are many special function registers associated with each of the above UARTs. We will be using the UART0 as an example since a virtual connection is available on the TI Tiva LaunchPad.

Baudrate Generator (UARTIBRD)

Two registers are used to set the baud rate:

  • They are UART Integer Baud-Rate Divisor (UARTIBRD) and UART Fractional Baud-Rate Divisor (UARTFBRD).
  • Of the 32-bit of the UARTIBRD, only lower 16 bits are used and of the 32-bit of the UARTFBRD, only the lower 6 bits are used.
  • That gives us total of 22 bits (16 bits integer + 6 bits of fraction).
  • To reduce the rate of error and use the standard baud rate, we should use both of the above divisor registers when we program the baud rate.


Tm4c uartibrd r.png

Baudrate Generator (UARTFBRD)

Tm4c uartfbrd r.png

Baudrate Calculation

The baud rate can be calculated using the following formula:

Desired Baud Rate = SysClk/(16 — ClkDiv)

where the SysCLK is the working system clock connected to the UART and ClkDiv is the values we load into divisor registers. The system clock fed to the CPU can come from XTAL, PLL, or an internal RC. For TI Tiva LaunchPad, the default system clock is 16 MHz. So we can rearrange the above formula as:

Desired Baud Rate = 16MHz/(16 - ClkDiv) = 1MHz/ClkDiv

The ClkDiv value gives us both the integer and fractional values needed for the UARTIBRD and UARTFBRD registers. While the integer portion of the divisor is easy to calculate using a simple calculator, the calculation of the fraction part requires some mathematical manipulation. One way would be, to multiply the fraction by 64 and round it by adding 0.5 to it.

Baudrate Calculation Example

Assume SysCLK Frequency = 16MHz. Find the values for the divisor registers of UARTIBRD and UARTFBRD for the following standard baud rates:

(a) 4800 (b) 9600 (c) 57,600 (d) 115,200

By default, 16 MHz System Clock is divided by 16 before it is fed to the UART.
Therefore, we have 16MHz/16 = 1MHz and ClkDiv = 1MHz.

(a) 1MHz/4800 = 208.3333, UARTIBRD = 208 and UARTFBRD = (0.3333 * 64) + 0.5 = 21.8312 = 21
(b) 1MHz/9600 = 104.166666, UARTIBRD = 104 and UARTFBRD = (0.16666 * 64) + 0.5 = 11
(c) 1MHz/57600 = 17.361, UARTIBRD = 17 and UARTFBRD = (0.361* 64) + 0.5 = 23
(d) 1MHz/115200 = 8.680,UARTIBRD = 8 and UARTFBRD = (0.680 * 64) + 0.5 = 44

In the above Example, it must be noted that default clock is divide-by-16. We can change it to divide-by-8 by setting to 1 the HSE bit of the UART Control (UARTCTL) register.

UART Control (UARTCTL)

The next important register in UART is the control register. It is a 32-bit register and many of the bits are unused. For us the most important bits are RXE, TXE, HSE, and UARTEN.

Tm4c uartctl r.png
  • UARTEN (D0) UART enable
    This allows one to enable or disable the UART. During the initialization we must disable it while modifying some of the UART registers.
  • HSE (D5) High Speed enable
    For the baud rate divisor, by default the system clock is divided by 16 before it is fed to the UART. We can change it to divide-by-8 by setting the HSE = 1 to run higher Baud rate with a low system clock frequency.
  • RXE (D8) Receive enable
    We must enable this bit to receive data.
  • TXE (D9) Transmit Enable
    We must enable this bit to transmit data.
  • The other bits of this register are used for MODEM signals such as CTS (clear to send), RTS (request to send), parity bit, and so on.

UART Line Control (UARTLCRH)

Tm4c uartlcrh r.png

This is the register we use to set the number of bits per character (data length) in a frame and number of stop bits among other things.

  • STP2 (D3) stop bit2:
    The stop bit can be 1 or 2. The default is 1 stop bit at the end of each frame. If the receiving device is slow, we can use 2 stop bits by making the STP2 = 1.
  • WLEN (D6 -D5) Word Length
    The number of bits per character data in each frame can be 5, 6, 7, or 8. Generally, we use 8 bits for each character data frame. Notice that default is 5 bits and we must change it to 8 bits as shown below:
D6 D5
0 0 5 bits
0 1 6 bits
1 0 7 bits
1 1 8 bits
  • FEN (D4) FIFO enable
    TI Tiva UART has an internal 16-byte FIFO (first in first out) buffer to store data for transmission. There is also another 16-byte FIFO buffer to save all the received bytes. By enabling FEN bit, we can write up to 16 bytes of data block into its transmission FIFO buffer and let it transfer one byte at a time.
  • The programmer may set up a threshold for the UART to notify the CPU when the level of the FIFO passes the threshold.
  • There is also a 16 byte FIFO for the receiver to buffer the incoming data.
  • Upon Reset, the default for FIFO buffer size is 1 byte (character mode).

UART Data (UARTDR)

Tm4c uartdr r.png

To transmit a byte of data we must place it in UART Data register. Although it is a 32-bit register, only the lower 8 bits (D0 - D7) are used. It must be noted that "A write to this register initiates a transmission from the UART." In the same way, the received byte is placed in this register and must be retrieved by reading it before it is lost. For transmit, only the lower 8 bits are used. For the receive, the lower 8 bits holds the received byte and other extra 4 bits of D8 - D11 are used for error detection such as framing error, parity error, and so on. There is another register called UARTRSR/UARTRCR (UART Receive Status Error/Error Clear) that can be used to check the source of error.

UART Flag Register (UARTFR)

Tm4c uartfr r.png
  • TXFE (D7) TX FIFO empty
    When we write a byte to Data register to be transmitted, the byte is placed in transmission FIFO buffer. When the transmitter is not busy, it loads one byte from the FIFO buffer and the FIFO becomes empty and the TXFE is raised. The transmitter then frames the byte and sends it out via TxD pin bit-by-bit serially.
  • RXFF (D6) RX FIFO full
    When a byte of data is received, this byte is placed in Data register and RXFF (RX FIFO full) flag bit is raised. In other words, when RXFF is HIGH, it means a byte has been received.
  • TXFF (D5) TX FIFOI full
    When we write a byte to Data register to be transmitted, the byte is placed in transmission FIFO buffer. When the transmitter is not busy, it loads one byte from the FIFO buffer and the FIFO is not full anymore and the TXFF is lowered. The transmitter then frames the byte and sends it out via TxD pin bit by bit serially. This is essentially the opposite of TXFE flag bit when FIFO buffer is disabled. We can monitor TXFF flag and upon going LOW we can write another byte to the Data register while the last byte is being transmitted.
  • RXFE (D4) RX FIFO empty
    The received byte of data comes in serially into a Receive buffer (first bit coming in is the start bit, 8-bit data, and stop bit). After the last bit (stop bit) has been received by the receiver, the UART circuitry discards the start and stop bits and delivers a byte of data to the Data register and lowers the RXFE bit (RX FIFO empty). This is essentially the opposite of RXFF flag bit. We can monitor RXFE flag and upon going LOW (buffer not empty) we should read (retrieve) the data from Data register.
  • Busy (D3)
    When a byte is written to the Data register the Busy flag goes High. While UART busy transmitting data this bit remains high until the stop bit is gone. Upon transmission of the last bit (stop bit), it goes low indicating the transmission is completed. This is only used when it is essential to complete the transmission before starting the next task.

Enabling Clock to UART (RCGCUART)

Tm4c rcgcuart r.png

The RCGCUART register is used to enable the clock to the UART. In this register, there is a bit for each of the UART0 to UART7 modules. If a given UART is not used, we should disable the clock to it to save power. To use UART0, we set to high the D0 of this register.

The GPIO pins used for UART (TxD & RxD)

In addition to the UART registers setup, we must also configure the I/O pins used for UART for their alternate functions. In the case of UART, we need to set up GPIO pins for the alternate functions of TxD and RxD signals. In the previous examples, we used GPIO as simple I/O. We showed the minimum configuration for each port as Digital I/O and providing the Clock to it. When GPIO pins are used for their alternate peripheral functions such as UART, Timer, and ADC, we need to configure five more registers. They are PORTx Run Mode Clock Gating Control, PORTx Digital Enable, PORTx ADC Mode Selection, PORTx Alternate Selection and PORTx Port Control registers.

GPIOAMSEL (GPIO Analog Mode Select)

Tm4c gpioamsel r.png

The TI ARM comes with on-chip ADC (analog to digital converter). Assume a given pins can be used for both ADC and UART and we want to use it for UART. In this case, we must isolate the ADC function since it is not used for analog operation. This is done with GPIOAMSEL (GPIO Analog Mode Selection). Although each port has its own PORTxAMSEL register, not all the pins of each port has ADC capability. Upon Reset, the PORTxAMSEL register has all 0s which means ADC function for the pin, if there is one, is disabled.

GPIO Alternate Function Select (GPIOAFSEL)

Tm4c gpioafsel r.png

In addition to Digital I/O and Clock enable, we must also configure the alternate function select register. Upon Reset, the GPIO pins are configured for simple I/O. To use the alternate function (e.g. UART) of given pin of a given Port, there are two steps to be taken. First we must set the corresponding bits in the alternate function select HIGH. In the case of UART0, PA0 and PA1 pins are used for RxD and TxD signals, respectively. Therefore, we must set both of them high in order to be used for the alternate functions of RxD and TxD. A one in the alternate function select register tells the port pin to perform a function other than simple I/O. GPIO Alternate Function Select Register (GPIOAFSEL) needs to work with the GPIO Port Control Register (GPIOPCTL) together to determine the operational mode and related peripheral functions for the selected GPIO pins.

GPIOPCTL Register

Tm4c gpiopctl r.png

The alternate function is selected by the Port Control Register. Each 32-bit GPIOPCTL register defines the alternate function for the eight pins of that port, 4 bits for each pin. If we wished to specify PA5-2 as SSI0, we would set Port A PCTL bits 23-16 to 0x2222 like this:

GPIO_PORTA_PCTL_R = (GPIO_PORTA_PCTL_R & 0xFF0000FF) + 0x00222200;

For most of the pins, UART function select number is 1. The only exceptions are PC4 and PC5. PC4 and PC5 may be used for either UART4 or UART1. When they are used for UART4, the select number is 1. When they are used for UART1, the select number is 2.

More information on GPIO Alternate functions is available here.


UART Interrupt Programming

Examining the UARTIM (UART Interrupt Mask) register, we see bit 4 allows us to enable the receive interrupt. If the receive interrupt for UART is enabled, when a byte is received, the receive flag is directed to NVIC and that causes the interrupt handler associated with the UART to be executed. In the UART handler we must read the received byte and clear the interrupt flag.

UART Interrupt Mask Register

Tm4c uartim r.png

bit Name Description
1 CTSIM UART Clear to Send Modem Interrupt Mask
1: An interrupt is sent to the interrupt controller when the CTSRIS bit in the UARTRIS register is set.
0: The CTSRIS interrupt is suppressed and not sent to the interrupt controller.
4 RXIM UART Receive Interrupt Mask
1: An interrupt is sent to the interrupt controller when the RXRIS bit in the UARTRIS register is set.
0: The RXRIS interrupt is suppressed and not sent to the interrupt controller.
5 TXIM UART Transmit Interrupt Mask
1: An interrupt is sent to the interrupt controller when the TXRIS bit in the UARTRIS register is set.
0: The TXRIS interrupt is suppressed and not sent to the interrupt controller.
6 RTIM UART Receive Time-Out Interrupt Mask
1: An interrupt is sent to the interrupt controller when the RTRIS bit in the UARTRIS register is set
0: The RTRIS interrupt is suppressed and not sent to the interrupt controller.
7 FEIM UART Framing Error Interrupt Mask
1: An interrupt is sent to the interrupt controller when the RTRIS bit in the UARTRIS register is set.
0: The FERIS interrupt is suppressed and not sent to the interrupt controller.
8 PEIM UART Parity Error Interrupt Mask
1: An interrupt is sent to the interrupt controller when the PERIS bit in the UARTRIS register is set.
0: The PERIS interrupt is suppressed and not sent to the interrupt controller.
9 BEIM UART Break Error Interrupt Mask
1: An interrupt is sent to the interrupt controller when the BERIS bit in the UARTRIS register is set.
0: The BERIS interrupt is suppressed and not sent to the interrupt controller.
10 OEIM UART Overrun Error Interrupt Mask
1: An interrupt is sent to the interrupt controller when the OERIS bit in the UARTRIS register is set.
0: The OERIS interrupt is suppressed and not sent to the interrupt controller.
12 9BITIM 9-Bit Mode Interrupt Mask
1: An interrupt is sent to the interrupt controller when the 9BITRIS bit in the UARTRIS register is set.
0: The 9BITRIS interrupt is suppressed and not sent to the interrupt controller.

UART Masked Interrupt Status (UARTMIS)

Tm4c uartmis r.png

bit Name Value Description
1 CTSMIS UART Clear to Send Modem Masked Interrupt Status
1: An unmasked interrupt was signaled due to Clear to Send.
0: An interrupt has not occurred or is masked.
4 RXMIS UART Receive Masked Interrupt Status
1: An unmasked interrupt was signaled due to passing through the specified receive FIFO level.
0: An interrupt has not occurred or is masked.
5 TXMIS UART Transmit Masked Interrupt Status
1: An unmasked interrupt was signaled due to passing through the specified transmit FIFO level (if the EOT bit is clear) or due to the transmission of the last data bit (if the EOT bit is set).
0: An interrupt has not occurred or is masked.
6 RTMIS UART Receive Time-Out Masked Interrupt Status
1: An unmasked interrupt was signaled due to a receive time out.
0: An interrupt has not occurred or is masked.
7 FEMIS UART Framing Error Masked Interrupt Status
1: An unmasked interrupt was signaled due to a framing error.
0: An interrupt has not occurred or is masked.
8 PEMIS UART Parity Error Masked Interrupt Status
1: An unmasked interrupt was signaled due to a parity error.
0: An interrupt has not occurred or is masked.
9 BEMIS UART Break Error Masked Interrupt Status
1: An unmasked interrupt was signaled due to a break error.
0: An interrupt has not occurred or is masked.
10 OEMIS UART Overrun Error Masked Interrupt Status
1: An unmasked interrupt was signaled due to an overrun error.
0: An interrupt has not occurred or is masked.
12 9BITMIS 9-Bit Mode Masked Interrupt Status
1: An unmasked interrupt was signaled due to a receive address match.
0: An interrupt has not occurred or is masked.

UART Raw Interrupt Status (UARTRIS)

Tm4c uartris r.png

bit Name Description
1 CTSRIS UART Clear to Send Modem Raw Interrupt Status
1: Clear to Send used for software flow control.
0: No interrupt
4 RXRIS UART Receive Raw Interrupt Status
1: The receive FIFO level has passed through the condition defined in the UARTIFLS register.
0: No interrupt
5 TXRIS UART Transmit Raw Interrupt Status
1: If the EOT bit in the UARTCTL register is clear, the transmit FIFO level has passed through the condition defined in the UARTIFLS register.
If the EOT bit is set, the last bit of all transmitted data and flags has left the serializer.
0: No interrupt
6 RTRIS UART Receive Time-Out Raw Interrupt Status
1: A receive time out has occurred.
0: No interrupt
7 FERIS UART Framing Error Raw Interrupt Status
1: A framing error has occurred.
0: No Interrupt
8 PERIS UART Parity Error Raw Interrupt Status
1: A parity error has occurred.
0: No Interrupt.
9 BERIS UART Break Error Raw Interrupt Status
1: A break error has occurred.
0: No Interrupt.
10 OERIS UART Overrun Error Raw Interrupt Status
1: An overrun error has occurred.
0: No Interrupt.
12 9BITRIS 9-Bit Mode Raw Interrupt Status
1: A receive address match has occurred.
0: No Interrupt.

UART Interrupt Clear (UARTICR)

Tm4c uarticr r.png

bit Name Description
1 CTSMIC UART Clear to Send Modem Interrupt Clear
Writing a 1 to this bit clears the CTSRIS bit in the UARTRIS register and the CTSMIS bit in the UARTMIS register.
This bit is implemented only on UART1 and is reserved for UART0 and UART2.
4 RXIC Receive Interrupt Clear
Writing a 1 to this bit clears the RXRIS bit in the UARTRIS register and the RXMIS bit in the UARTMIS register.
5 TXIC Transmit Interrupt Clear
Writing a 1 to this bit clears the TXRIS bit in the UARTRIS register and the TXMIS bit in the UARTMIS register.
6 RTIC Receive Time-Out Interrupt Clear
Writing a 1 to this bit clears the RTRIS bit in the UARTRIS register and the RTMIS bit in the UARTMIS register.
7 FEIC Framing Error Interrupt Clear
Writing a 1 to this bit clears the FERIS bit in the UARTRIS register and the FEMIS bit in the UARTMIS register.
8 RTIC Parity Error Interrupt Clear
Writing a 1 to this bit clears the PERIS bit in the UARTRIS register and the PEMIS bit in the UARTMIS register.
9 BEIC Break Error Interrupt Clear
Writing a 1 to this bit clears the BERIS bit in the UARTRIS register and the BEMIS bit in the UARTMIS register.
10 OEIC Overrun Error Interrupt Clear
Writing a 1 to this bit clears the OERIS bit in the UARTRIS register and the OEMIS bit in the UARTMIS register.
12 9BITIC 9-Bit Mode Interrupt Clear
Writing a 1 to this bit clears the 9BITRIS bit in the UARTRIS register and the 9BITMIS bit in the UARTMIS register.



TM4C123G LaunchPad UART Tasks

Steps for transmitting & Receiving data

Here are the steps to configure the UART0 to transmit/recive a byte of data for TI Tiva TM4C123GH6PM on the LaunchPad:

  1. Provide clock to UART0 by writing a 1 to RCGCUART (SYSCTL_RCGCUART_R) register.
  2. Provide clock to PORTA by writing a 1 to RCGCGPIO (SYSCTL_RCGCGPIO_R) register.
  3. Disable the UART0 by writing 0 to UARTCTL (UART0_CTL_R) register of UART0.
  4. Write the integer portion of the Baud rate to the UARTIBRD (UART0_IBRD_R) register of UART0.
  5. Write the fractional portion of the Baud rate to the UARTFBRD (UART0_FBRD_R) register of UART0.
  6. Configure the line control value for 1 stop bit, no FIFO, no interrupt, no parity, and 8-bit data size. That gives us 0x60 for the UARTLCRH (UART0_LCRH_R) register of UART0.
  7. Set UARTEN bit in UARTCTL (UART0_CTL_R) register to enable the UART0.
    Set TxE and RxE bits in UARTCTL register to enable the transmitter and receiver of UART0.
  8. Make PA0 and PA1 pins to be used as Digital I/O (GPIO_PORTA_DEN_R).
  9. Select the alternate functions of PA0 (RxD) and PA1 (TxD) pins using the GPIOAFSEL (GPIO_PORTA_AFSEL_R).
  10. Configure PA0 and PA1 pins for UART function (GPIO_PORTA_PCTL_R).
  11. Disable analog functionality on PortA0-1 (GPIO_PORTA_AMSEL_R)
  12. Monitor the RXFE flag bit in UART Flag register (UART0_FR_R) and when it goes LOW (buffer not empty), read the received byte from Data register (UART0_DR_R) and save it.
  13. Monitor the TXFF flag bit in UART Flag register (UART0_FR_R) and when it goes LOW (buffer not full), write received byte to Data register (UART0_DR_R) to be transmitted.

Before starting the UART echo program, we need a serial communication software in order to receive/transmit the data at the PC end, we can use putty software for this purpose, you can download it from here.

So just install it and run putty software, now click on "serial", it will show COM1 in "serial line" and 9600 baud in the "speed" fields.

Putty hyper terminal 1.png

In order to get the COM Port Number of connected launchpad, launch device manager (PC), click on ports, “Stellaris Virtual Serial Port” will appear and so its COM Port number in brackets, here you will find the COM port number, in our case it is COM3. Just go to the putty and enter this COM port and select the speed as 115200.

Putty hyper terminal 2.png

  1. Write a program to read and write characters (echo) to UART0 Port.
  2. Write an Echo (read and write) program using other than UART0 (UART1, UART2 ..... UART7)
  3. UART0 Echo Program showed how UART0 receives data by polling the RXFE status flag. The disadvantage with that program is that it ties down the CPU polling the status flag. Modify it to make it an interrupt driven program.

Programming General-Purpose Timer Module (GPTM)

In TI Tiva micro controllers, the timers are called General-Purpose Timer Module (GPTM). The General-Purpose Timer Module (GPTM) contains six 16/32-bit GPTM blocks and six 32/64-bit Wide GPTM blocks. In otherwords, there are 12 Timer Blocks in the TI Tiva TM4C123G, 6 of them are 16/32-bit timers and the other 6 are 32/64-bit. Each 16/32-bit GPTM block can provide two 16-bit (half-width) timers/counters that are referred to as Timer A and Timer B. These timers/counters can be further configured to operate independently as timers or event counters, or concatenated together to operate as one 32-bit (full-width) timer or one 32-bit Real-Time Clock (RTC).

Similarly, each 32/64-bit Wide GPTM block provides two 32-bit timers, also called Timer A and Timer B, and they can be concatenated together to form a 64-bit timer. Timers can also be used to trigger μDMA transfers. All timers have interrupt controls and separate interrupt vectors as well as separate interrupt handlers.


Tm4c gptm blkdiagram.png
Figure: GPTM Module Block Diagram


The 16/32-bit timer blocks are designated as Timer 0, Timer 1, ..., and Timer 5. The following shows the base addresses for the 16/32-bit Timer blocks:

  • 16/32-bit Timer 0 base: 0x4003.0000
  • 16/32-bit Timer 1 base: 0x4003.1000
  • 16/32-bit Timer 2 base: 0x4003.2000
  • 16/32-bit Timer 3 base: 0x4003.3000
  • 16/32-bit Timer 4 base: 0x4003.4000
  • 16/32-bit Timer 5 base: 0x4003.5000
  • 32/64-bit Wide Timer 0: 0x4003.6000
  • 32/64-bit Wide Timer 1: 0x4003.7000
  • 32/64-bit Wide Timer 2: 0x4004.C000
  • 32/64-bit Wide Timer 3: 0x4004.D000
  • 32/64-bit Wide Timer 4: 0x4004.E000
  • 32/64-bit Wide Timer 5: 0x4004.F000

Timer A and Timer B

Each of the Timer blocks contains two timers. They are called Timer A and Timer B. These two timers A and B can work independent of each other as two 16-bit timers or together as one single 32-bit timer. TimerA and TimerB each contains a counter. When the clock is fed to them, they keep counting up/down. We can read their contents as they count and we can load a new value in them. We will examine TimerA and give some examples. The discussion about TimerA also applies equally to TimerB. First, we must remember that, we need to enable the clock to the Timers before they can be used. This is done with the RCGCTimer register.

RCGCTimer

RCGCTimer
Figure 8.1: RCGCTimer
Bit Name Description
0 R0 Timer0 clock control (0: clock disabled, 1: clock enabled)
1 R1 Timer1 clock control (0: clock disabled, 1: clock enabled)
2 R2 Timer2 clock control (0: clock disabled, 1: clock enabled)
3 R3 Timer3 clock control (0: clock disabled, 1: clock enabled)
4 R4 Timer4 clock control (0: clock disabled, 1: clock enabled)
5 R5 Timer5 clock control (0: clock disabled, 1: clock enabled)
Table 8.1: RCGCTimer (Timer Run Mode Clock Gating Control)


The RCGCTIMER is part of the System Control registers. We must enable the clock to Timer0 - Timer5 before we can use them. Notice, in RCGCTIMER registers, bit R0 is for Timer0 block, bit R1 is for Timer1 block, and so on.

Timers Register Map

Name Offset Tivaware Name Description
GPTMCFG 0x000 TIMERn_CFG_R GPTM Configuration
GPTMTAMR 0x004 TIMERn_TAMR_R GPTM Timer A Mode
GPTMTBMR 0x008 TIMERn_TBMR_R GPTM Timer B Mode
GPTMCTL 0x00C TIMERn_CTL_R GPTM Control
GPTMSYNC 0x010 TIMERn_SYNC_R GPTM Synchronize
GPTMIMR 0x018 TIMERn_IMR_R GPTM Interrupt Mask
GPTMRIS 0x01C TIMERn_RIS_R GPTM Raw Interrupt Status
GPTMMIS 0x020 TIMERn_MIS_R GPTM Masked Interrupt Status
GPTMICR 0x024 TIMERn_ICR_R GPTM Interrupt Clear
GPTMTAILR 0x028 TIMERn_TAILR_R GPTM Timer A Interval Load
GPTMTBILR 0x02C TIMERn_TBILR_R GPTM Timer B Interval Load
GPTMTAMATCHR 0x030 TIMERn_TAMATCHR_R GPTM Timer A Match
GPTMTBMATCHR 0x034 TIMERn_TBMATCHR_R GPTM Timer B Match
GPTMTAPR 0x038 TIMERn_TAPR_R GPTM Timer A Prescale
GPTMTBPR 0x03C TIMERn_TBPR_R GPTM Timer B Prescale
GPTMTAPMR 0x040 TIMERn_TAPMR_R GPTM TimerA Prescale Match
GPTMTBPMR 0x044 TIMERn_TBPMR_R GPTM TimerB Prescale Match
GPTMTAR 0x048 TIMERn_TAR_R GPTM Timer A
GPTMTBR 0x4C TIMERn_TBR_R GPTM Timer B
GPTMTAV 0x050 TIMERn_TAV_R GPTM Timer A Value
GPTMTBV 0x054 TIMERn_TBV_R GPTM Timer B Value
GPTMRTCPD 0x058 TIMERn_RTCPD_R GPTM RTC Predivide
GPTMTAPS 0x05C TIMERn_TAPS_R GPTM Timer A Prescale Snapshot
GPTMTBPS 0x060 TIMERn_TBPS_R GPTM Timer B Prescale Snapshot
GPTMTAPV 0x064 TIMERn_TAPV_R GPTM Timer A Prescale Value
GPTMTBPV 0x068 TIMERn_TBPV_R GPTM Timer B Prescale Value
Where n = 0 to 5


Each GPTM block is composed of different control and status registers and these control and status registers can be divided into six groups based on their functions. We only discuss those registers used for the TimerA since the same registers are used for the TimerB. These registers can be divided into the following groups:

  • TimerA Control Register group
  • TimerA Status Register group
  • Timers A and B Interrupt and Configuration Register group
  • External Controls group

TimerA Control Register Group

Eight registers are used to configure and control the operations of the Timer A:

  1. GPTM Configuration Register (GPTMCFG)
  2. GPTM Control Register (GPTMCTL)
  3. GPTM Timer A Mode Register (GPTMTAMR)
  4. GPTM Timer A Interval Load Register (GPTMTAILR)
  5. GPTM Timer A Match Register (GPTMTAMATCHR)
  6. GPTM Timer A Prescale Register (GPTMTAPR)
  7. GPTM Timer A Prescale Match Register (GPTMTAPMR)
  8. GPTM Timer A Prescale Snapshot Register (GPTMTAPS)

GPTM Control Register (GPTMCTL)

Tm4c123 gptmctl.png
Figure 8.2: GPTM Control Register (GPTMCTL)


Bit(s) Name Description
0 TAEN Timer A Enable
0: disabled
1: enabled
1 TASTALL Timer A Stall (useful while debugging)
0: Timer A continues counting if the CPU is halted by the debugger,
1: Timer A Stalls (stops counting) while the CPU is halted by the debugger.
2 & 3 TAEVENT Timer A Event Mode
0: positive edge
1: negative edge
2: reserved
3: both edges
4 RTCEN RTC Stall Enable (useful while debugging)
0: RTC Stalls (stops counting) while the CPU is halted by the debugger
1: RTC continues counting if the CPU is halted by the debugger.
5 TAOTE Timer A Output Trigger Enable
0: ADC trigger disabled
1: ADC trigger enabled
6 TAPWML GPTM Timer A PWM Output Level
0: Output is unaffected
1: Output is inverted
8 TBEN GPTM Timer B Enable
0: Timer B is disabled
1: Timer B is enabled.
9 TBSTALL GPTM Timer B Stall Enable
0: Timer B continues counting while the processor is halted by the debugger
1: Timer B freezes counting while the processor is halted by the debug
11 & 10 TBEVENT GPTM Timer B Event Mode
0x0: Positive going edge
0x1: Negative going edge
0x3: Both edges
0x2: Reserved.
13 TBOTE GPTM Timer B Output Trigger Enable
0: The output Timer B ADC trigger is disabled
1: The output Timer B ADC trigger is enabled.
14 TBPWML GPTM Timer B PWM Output Level
0: Output is unaffected
1: Output is inverted.
31:15 Reserved Reserved
Table 8.2: GPTM Control Register

Note:

  • During the initialization of the Timers we must disable them. Modifying the configurations of a running timer may cause unpredictable results.
  • We use bit D0 of GPTMCTL (GPTM Control) register to disable or enable the TimerA.

GPTM Configuration Register (GPTMCFG)

To configure TimerA as 16- or 32-bit, we must use GPTMCFG (GPTM Configuration) register. Bits D2, D1, and D0 are used to select either 16- or 32-bit option. To use the 16-bit option we need to have D2:D1:D0=0x4. As mentioned above, in 16-bit mode, TimerA and TimerB make two separate timers which work independently.


Tm4c123 gptmcfg.png

D2:D1:D0 Mode
000 32-bit Mode
001 RTC Counter
100 16-bit Mode
Table 8.3: GPTM Configuration Register

TimerA Mode selection register (GPTMTAMR)

The mode selection such as periodic, count up/down selection for TimerA is done with GPTM TimerA Mode (GPTMTAMR) register.


Tm4c123 gptmtamr.png


Bit(s) Name Description
0 & 1 TAMR Timer A Mode
2 TACMR Timer A Capture Mode (0: Edge Count, 1: Edge Time)
3 TAAMS Timer A Alternate Mode Select (0: Capture or Compare Mode, 1: PWM Mode)
4 TACDIR Timer A Count Direction (0: Count Down, 1: Count Up)
5 TAMIE Timer A Match Interrupt Enable (0: the match interrupt is disabled, 1: enabled)
6 TAWOT Timer A Wait-On-Trigger (0: It begins counting when enabled, 1: waits for trigger)
7 TASNAPS Timer A Snap-Shot Mode (0: Snap Shot is disabled)
8 TAILD Timer A Interval Load Write
9 TAPWMIE Timer A PWM Interrupt Enable (0: Capture Event Interrupt is Disabled, 1: Enabled)
10 TAMRSU Timer A Match Register Update
11 TAPLO Timer A PWM Legacy Operation
Table 8.4: GPTMTAMR (GPTM Timer A Mode)


The mode selection is done with D1:D0 bits of GPTMTAMR, as shown below:

Mode D1 D0 Mode Name
0 0 0 Reserved
1 0 1 One-Shot Mode
2 1 0 Periodic Mode
3 1 1 Capture Mode
Table 8.5: TAMR Bits of GPTMTAMR

The direction Count is done with D4 (TACDIR). Upon Reset, the default is down counter. By making D4=1, TimerA counts up.

GPTM Timer n Interval Load (GPTMTnILR)

When the timer is counting down (the timer counts down if the TACDIR bit of the GPTMTAMR register is 0), the timer counter begins counting from GPTMTnILR (GPTMTAILR / GPTMTBILR) and goes down until it reaches zero. Then, the timer counter is reloaded with the value from GPTMTnILR and the TnTORIS flag of the GPTMRIS register is set.

The role of gptmtnr.png
Figure 8.3: The role of GPTMTnR

When the timer is counting up, the timer counter begins counting from 0 and goes up until it reaches the GPTMTnILR value. Then, the timer counter is cleared to zero and the TnTORIS flag of the GPTMRIS register is set.

Upon reset, all bits of the GPTMTnILR register are initialized to 1s which makes the biggest value and has no effect on the timer counting. But the software can change the value of GPTMTnILR. The smaller values for the register leads the timer timeout faster and the TnTORIS flag sets sooner. In other words, changes of delay can be made by setting the GPTMTnILR register and monitoring the TnTORIS flag.

Timer A Status Register Group

Three registers are used to monitor and detect the status of the Timer A:

  • GPTM Timer A Register (GPTMTAR)
  • GPTM Timer A Value Register (GPTMTAV)
  • GPTM Timer A Prescale Value Register (GPTMTAPV).

GPTMTnV (GPTM Timer Value)

GPTMTAV and GPTMTBV are two 16-bit up/down counter registers. When a timer is in 16-bit mode, they work as 2 separate counters. When the timer is in 32-bit mode, they are cascaded to form a 32-bit counter. When read, this register shows the current, free-running value of Timer A in all modes. When written, the value written into this register is loaded into the GPTMTAR register on the next clock cycle.

Note: In 16-bit mode, only the lower 16-bits of the GPTMTAV register can be written with a new value. Writes to the prescaler bits have no effect.

GPTM TimerA Match Register (GPTMTAMATCHR)

The GPTM Timer A Match (GPTMTAMATCHR) register can be used to load a match value, and this value can be compared with the current timer value stored in the GPTM Timer A (GPTMTAR ) register to trigger a matching interrupt or set a flag to indicate that a time value matching has occurred if both values are equal. The GPTM Timer B has the similar registers and functions.

When TimerA keeps counting it is compared with the contents of this register. Whenever the contents of free-running TimerA counter and TimerA Match register are equal, the TAMRIS Flag goes up indicating there is a match. The D4 of GPTMRIS register belongs to this flag.

Note: Although the TimerA Match is a 32-bit register, only the lower 16 bits are used in the 16-bit configuration selection.

Tm4c123 tnr tnmatchr tnmris.png
Figure 8.1: The Relation Between TnR, TnMATCHR, and TnMRIS

GPTM Timer A Register (GPTMTAR)

  • This is a 32-bit register and all 32 bits are used to indicate the current value of the 16-bit free-running counter of the Timer A. This register shows the current value of the Timer A counter in all cases except for Input Edge Count and Input Edge Time modes.
  • In the Input Edge Count mode, this register contains the number of edges that have occurred. In the Input Edge Time mode, this register contains the time at which the last edge event took place.
  • In the 16-bit Input Edge Count, Input Edge Time, and PWM modes, bits 15:0 contain the value of the counter and bits 23:16 contain the value of the prescaler, which is the upper 8 bits of the count. Bits 31:24 always read as 0.
  • When a 16/32-bit GPTM is configured to one of the 32-bit modes, GPTMTAR works as a 32-bit register with the upper 16 bits corresponding to the contents of the GPTMTBR register.
  • To read the value of the prescaler in 16-bit One-Shot and Periodic modes, read bits [23:16] in the GPTMTAV register. To read the value of the prescalar in periodic snapshot mode, read the Timer A Prescale Snapshot (GPTMTAPS) register.

GPTM Raw Interrupt Status Register (GPTMRIS)

Tm4c gptmris r.png


This 32-bit register only used the lower 16 bits to monitor and set a raw or internal interrupt if a GPTM-related raw interrupt occurred. These bits are set whether or not the interrupt is masked in the GPTMIMR register. However, whether these set raw interrupts can be sent to the interrupt controller to be further processed, it depends on whether the corresponding bits on the GPTMIMR register are set (enabled) or not (disabled). Only for those bits that have been set on the GPTMIMR register, they can be sent to the NVIC. The bit field and functions for this register are similar to those in the GPTMIMR register. If a GPTM-related raw interrupt is generated, the corresponding bit on this register is set to 1. Each bit can be cleared by writing a 1 to its corresponding bit in GPTMICR register.


Bit Name Description
0 TATORIS Timer A Time-out Raw interrupt (0: not occurred, 1: occurred)
1 CAMRIS Timer A Capture Mode Match Raw Interrupt (0: not occurred, 1: occurred)
2 CAERIS Timer A Capture Mode Event Raw Interrupt (0: not occurred, 1: occurred)
3 RTCRIS RTC Raw Interrupt(0: not occurred, 1: occurred)
4 TAMRIS Timer A Match Raw Interrupt
8 TBTORIS Timer B Time-out Raw interrupt (0: not occurred, 1: occurred)
9 CBMRIS Timer B Capture Mode Match Raw Interrupt (0: not occurred, 1: occurred)
10 CBERIS Timer B Capture Mode Event Raw Interrupt (0: not occurred, 1: occurred)
11 TBMRIS Timer B Match Raw Interrupt
16 WUERIS 32/64-Bit Wide GPTM Write Update Error Raw Interrupt Status

Periodic mode vs. one shot mode

The timer can be in 4 different modes including the periodic and one shot modes. In periodic mode the timer continues counting after each timeout. But in one shot mode, the timer stops counting after timeout is reached. For example, when it is in up counting and one shot modes, it counts from 0 to GPTMTnILR and then goes to zero just once and then the TnEN bit of GPTMCTL is cleared causing the timer to stop.


Tm4c123 timer oneshot mode.png

Figure 8.4: Counting in One Shot Mode

Each timer module has:

  • A clock enable bit, SYSCTL_RCGCTIMER_R
  • A control register, TIMERn_CTL_R
  • A configuration register, TIMERn_CFG_R
  • A mode register, TIMERn_TAMR_R
  • A 32-bit reload register, TIMERn_TAILR_R
  • A resolution (prescale) register, TIMERn_TAPR_R
  • An interrupt clear register, TIMERn_ICR_R
  • An interrupt arm bit, TIMERn_IM_R
  • A flag bit, TIMERn_RIS_R

( where n = 0 to 5)

Initialization and Configuration for One-Shot/Periodic Timer Mode

Perform the following operational steps to complete the initialization and configuration process for this mode:

  1. Disable the selected timer by clearing the TnEN bit in the GPTMCTL register (TIMERn_CTL_R).
  2. Initialize the GPTMCFG register to set up timer(s) as 16/32-bit timers (TIMERn_CFG_R).
  3. Configure the TnMR field in the GPTMTnMR (TIMERn_TAMR_R) register by writing
    • 0x1 for one-shot mode.
    • 0x2 for periodic mode.
  4. Optionally configure the TnSNAPS, TnWOT, TnMTE, and TnCDIR bits in the GPTMTnMR (TIMERn_TAMR_R) register to select whether to capture the value of the free-running timer at timeout, use an external trigger to start counting, configure an additional trigger or interrupt, and count-up or count-down operational mode.
  5. Load the start value (time up value) into the GPTMTnILR (TIMERn_TAILR_R) and the GPTMTnPR (TIMERn_TAPR_R, if prescaler is used) registers for the count-down (count-up) operations.
  6. If interrupts are required, set the appropriate bits in the GPTMIMR (TIMERn_IMR_R) register to enable the selected interrupt source.
  7. After these initializations and configurations done, set the TnEN bit in the GPTMCTL (TIMERn_CTL_R) register to enable the timer and start counting.
  8. If no interrupt is used, one can poll the GPTMRIS (TIMERn_RIS_R) register to check the appropriate bits and wait for the time event to occur. If an interrupt is used, put appropriate codes inside the interrupt handler to process the interrupt. In both cases, the status flags are cleared by writing a 1 to the appropriate bit of the GPTMICR (TIMERn_ICR_R) register.


In One-Shot mode, the timer stops counting after the timeout event. If the timer is configured as a periodic mode, the timer reloads the start value (time up value) and continues counting after the timeout event.

Prescaler register for Timer A

In the above example, the largest time delay that we can create is:

65535 × (1 / 16MHz) = 65535 × 62.5 nsec = 4.096 msec.

One way to create a longer time delay is to use the prescaler register. TimerA in 16-bit mode has an 8-bit prescaler register whose value can go from 0x00 to 0xFF. The 8-bit prescaler extends the 16-bit timer to 24-bit. The prescaler register allows system frequency to be divided by a value between 1 and 256 before it is fed to the TimerA. Note the prescaler can yield proper division only when the timer is configured as a down counter. As shown in Figure 8.5, the clock is divided by GPTMTnPR + 1.


Tm4c123 gptm prescalar.png
Figure 8.5: Prescalar


For CPU Freq=16MHz calculate the largest delay size using

  1. 16-bit TimerA without prescaler and
  2. 16-bit TimerA with prescaler.

Solution:
1/16MHz = 62.5 nsec is period of clock pulses fed to CPU.

  1. 65,536 x 62.5 nsec = 4.096 msec for TimerA 16-bit option .
  2. 65,536 x 256 x 62.5ns = 1.0485 second for TimerA 16-bit option with the Prescaler.

Use of Timers with the I/O Pins

If the timers are only used for the timing-base or timing-up indications, one does not need to use these Capture/Compare pins (CCP) since these pins are mainly connected to the external signals to detect the number of events that have occurred or the time period events that have been experienced.

In the previous session, we showed how to use timers to generate time delay. In this lab session, we will examine the use of timers with the I/O pins. There are five modes for each timer block. They are :

  1. One-shot/Periodic mode,
  2. Real-time clock mode,
  3. Input edge-time mode,
  4. Input edge-count mode and
  5. Pulse Width Modulation (PWM).

TimerA and TimerB CCP pins

There are TimerA and TimerB for each of the Timer block 0 to 5. There are one or two designated pins for each of the TimerA and TimerB. For example, TimerA of Timer block 4 is connected internally to pin PC0 of PortC and TimerB of Timer block 4 is connected to pin PC1 of PortC. Notice, TimerA pins are also called CCP0 and TimerB pins are called CCP1. Some of the timers have option to be connected to one of the two pins. For example, TimerA of Timer1 (T1CCP0) can use PB0 or PF2 pins. Table 9.1 shows the pin designations for 16/32-bit Timer block 0 to 5.


TimerA Pins TimerB Pins
Timer0 T0CCP0 PB6 or PF0 T0CCP1 PB7 or PF1
Timer1 T1CCP0 PB4 or PF2 T1CCP1 PB5 or PF3
Timer2 T2CCP0 PB0 or PF4 T2CCP1 PB1
Timer3 T3CCP0 PB2 T3CCP1 PB3
Timer4 T4CCP0 PC0 T4CCP1 PC1
Timer5 T5CCP0 PC2 T5CCP1 PC3
Table 9.1: The Pin Designation for 16/32 bit Timer Block 0 to 5

General-Purpose Timers CCP pins distributions

Timer Pin I/O pin Pin Function
T0CCP0 PB6 16/32-Bit Timer 0 Capture/Compare/PWM 0
PF0
T0CCP1 PB7 16/32-Bit Timer 0 Capture/Compare/PWM 1
PF1
T1CCP0 PB4 16/32-Bit Timer 1 Capture/Compare/PWM 0
PF2
T1CCP1 PB5 16/32-Bit Timer 1 Capture/Compare/PWM 1
PF3
T2CCP0 PB0 16/32-Bit Timer 2 Capture/Compare/PWM 0
PF4
T2CCP1 PB1 16/32-Bit Timer 2 Capture/Compare/PWM 1
T3CCP0 PB2 16/32-Bit Timer 3 Capture/Compare/PWM 0
T3CCP1 PB3 16/32-Bit Timer 3 Capture/Compare/PWM 1
T4CCP0 PC0 16/32-Bit Timer 4 Capture/Compare/PWM 0
T4CCP1 PC1 16/32-Bit Timer 4 Capture/Compare/PWM 1
T5CCP0 PC2 16/32-Bit Timer 5 Capture/Compare/PWM 0
T5CCP1 PC3 16/32-Bit Timer 5 Capture/Compare/PWM 1
WT0CCP0 PC4 32/64-Bit Wide Timer 0 Capture/Compare/PWM 0
WT0CCP1 PC5 32/64-Bit Wide Timer 0 Capture/Compare/PWM 1
WT1CCP0 PC6 32/64-Bit Wide Timer 1 Capture/Compare/PWM 0
WT1CCP1 PC7 32/64-Bit Wide Timer 1 Capture/Compare/PWM 1
WT2CCP0 PD0 32/64-Bit Wide Timer 2 Capture/Compare/PWM 0
WT2CCP1 PD1 32/64-Bit Wide Timer 2 Capture/Compare/PWM 1
WT3CCP0 PD2 32/64-Bit Wide Timer 3 Capture/Compare/PWM 0
WT3CCP1 PD3 32/64-Bit Wide Timer 3 Capture/Compare/PWM 1
WT4CCP0 PD4 32/64-Bit Wide Timer 4 Capture/Compare/PWM 0
WT4CCP1 PD5 32/64-Bit Wide Timer 4 Capture/Compare/PWM 1
WT5CCP0 PD6 32/64-Bit Wide Timer 5 Capture/Compare/PWM 0
WT5CCP1 PD7 32/64-Bit Wide Timer 5 Capture/Compare/PWM 1
Table 9.2: General-Purpose Timers signals and GPIO pins distributions.

Selecting alternate function for Timers pin

Upon Reset, the GPIOAFSEL register has all 0s meaning the I/O pins are used as simple I/O. To use an alternate function, we first must set the bit in the AFSEL register to 1 for that pin. For example, for the PB6, we need to write 0x40 to GPIO_PORTB_AFSL_R register. After that, the GPIOPCTL register must be configured for the desired function. To do that, we need to use the information in Table 23-5 (Page No.1351) of TI Tiva TM4C123GH6PM data sheet or refer here.

Table 9.2 provides the summary for the Timers pins.

Timer Pin I/O pin How to use peripheral function on the pin
T0CCP0 PB6 GPIO_PORTB_AFSEL_R = 0x40
PF0 GPIO_PORTF_AFSEL_R = 0x01
T0CCP1 PB7 GPIO_PORTB_AFSEL_R = 0x80
PF1 GPIO_PORTF_AFSEL_R = 0x02
T1CCP0 PB4 GPIO_PORTB_AFSEL_R = 0x10
PF2 GPIO_PORTF_AFSEL_R = 0x04
T1CCP1 PB5 GPIO_PORTB_AFSEL_R = 0x20
PF3 GPIO_PORTF_AFSEL_R = 0x08
T2CCP0 PB0 GPIO_PORTB_AFSEL_R = 0x40
PF4 GPIO_PORTF_AFSEL_R = 0x10
T2CCP1 PB1 GPIO_PORTB_AFSEL_R = 0x02
T3CCP0 PB2 GPIO_PORTB_AFSEL_R = 0x04
T3CCP1 PB3 GPIO_PORTB_AFSEL_R = 0x08
T4CCP0 PC0 GPIO_PORTC_AFSEL_R = 0x01
T4CCP1 PC1 GPIO_PORTC_AFSEL_R = 0x02
T5CCP0 PC2 GPIO_PORTC_AFSEL_R = 0x04
T5CCP1 PC3 GPIO_PORTC_AFSEL_R = 0x08
WT0CCP0 PC4 GPIO_PORTC_AFSEL_R = 0x10
WT0CCP1 PC5 GPIO_PORTC_AFSEL_R = 0x20
WT1CCP0 PC6 GPIO_PORTC_AFSEL_R = 0x40
WT1CCP1 PC7 GPIO_PORTC_AFSEL_R = 0x80
WT2CCP0 PD0 GPIO_PORTD_AFSEL_R = 0x01
WT2CCP1 PD1 GPIO_PORTD_AFSEL_R = 0x02
WT3CCP0 PD2 GPIO_PORTD_AFSEL_R = 0x04
WT3CCP1 PD3 GPIO_PORTD_AFSEL_R = 0x04
WT4CCP0 PD4 GPIO_PORTD_AFSEL_R = 0x10
WT4CCP1 PD5 GPIO_PORTD_AFSEL_R = 0x20
WT5CCP0 PD6 GPIO_PORTD_AFSEL_R = 0x40
WT5CCP1 PD7 GPIO_PORTD_AFSEL_R = 0x80
Table 9.3: Timers Alternate Pin Assignments


Timer Pin I/O pin How to select the timer function on the pin
T0CCP0 PB6 GPIO_PORTB_PCTL_R = 0x0700.0000
PF0 GPIO_PORTF_PCTL_R = 0x0000.0007
T0CCP1 PB7 GPIO_PORTB_PCTL_R = 0x7000.0000
PF1 GPIO_PORTF_PCTL_R = 0x0000.0070
T1CCP0 PB4 GPIO_PORTB_PCTL_R = 0x0007.0000
PF2 GPIO_PORTF_PCTL_R = 0x0000.0700
T1CCP1 PB5 GPIO_PORTB_PCTL_R = 0x0070.0000
PF3 GPIO_PORTF_PCTL_R = 0x0000.7000
T2CCP0 PB0 GPIO_PORTB_PCTL_R = 0x0000.0007
PF4 GPIO_PORTF_PCTL_R = 0x0007.0000
T2CCP1 PB1 GPIO_PORTB_PCTL_R = 0x0000.0070
T3CCP0 PB2 GPIO_PORTB_PCTL_R = 0x0000.0700
T3CCP1 PB3 GPIO_PORTB_PCTL_R = 0x0000.7000
T4CCP0 PC0 GPIO_PORTC_PCTL_R = 0x0000.0007
T4CCP1 PC1 GPIO_PORTC_PCTL_R = 0x0000.0070
T5CCP0 PC2 GPIO_PORTC_PCTL_R = 0x0000.0700
T5CCP1 PC3 GPIO_PORTC_PCTL_R = 0x0000.7000
WT0CCP0 PC4 GPIO_PORTC_PCTL_R = 0x0007.0000
WT0CCP1 PC5 GPIO_PORTC_PCTL_R = 0x0070.0000
WT1CCP0 PC6 GPIO_PORTC_PCTL_R = 0x0700.0000
WT1CCP1 PC7 GPIO_PORTC_PCTL_R = 0x7000.0000
WT2CCP0 PD0 GPIO_PORTD_PCTL_R = 0x0000.0007
WT2CCP1 PD1 GPIO_PORTD_PCTL_R = 0x0000.0070
WT3CCP0 PD2 GPIO_PORTD_PCTL_R = 0x0000.0700
WT3CCP1 PD3 GPIO_PORTD_PCTL_R = 0x0000.7000
WT4CCP0 PD4 GPIO_PORTD_PCTL_R = 0x0007.0000
WT4CCP1 PD5 GPIO_PORTD_PCTL_R = 0x0070.0000
WT5CCP0 PD6 GPIO_PORTD_PCTL_R = 0x0700.0000
WT5CCP1 PD7 GPIO_PORTD_PCTL_R = 0x7000.0000
Table 9.4: Timers pin assignment using GPIO_PCTL


Example 9.1: Write the code to provide the T0CCP1 function on PF1.
Solution: The I/O pin is used as a peripheral function pin by setting the AFSEL register of PORTF and the desired peripheral function is selected by setting the PCTL register of PORTF:

GPIO_PORTF_AFSEL_R |= 0x02;
GPIO_PORTF_PCTL_R = 0x00000070;

Some Implementations on GPTM Modules

Timer system is a complex system with many different components and functions. We only discuss some very popular and important implementations. These include:

  • Using timer capture functions to detect the number of input edges.
  • Using timer detecting functions to measure the period for periodic signals.
  • Using timer control functions to generate PWM signals to control motors.

Using Timer for input edge-time capturing

Input edge-time capture mode

In input edge-time mode, an I/O pin is used to capture the signal transition events. When an event occurs, the content of the timer counter is captured in another register while the counter keeps counting. The program can then read the counter value when the event occurs at a slightly later time.

To configure the timer to input edge time mode the TnMR and TnCMR bits of GPTMTnMR should be set to capture edge-time mode (TnMR = 3 and TnCMR = 1). See Table 8.5. In this mode, the timer counter value is stored in the GPTMTnR register whenever the input pin is triggered by an external event. See Figure 9.1

Input Edge Time Capturing
Figure 9.1: Input Edge Time Capturing


The timer can be configured to capture on the falling edge, rising edge, or both. To determine the type of edge that is captured, the TnEVENT bits of the GPTMCTL register should be initialized. See Table 8.4

Timer counting in input edge time mode

In edge time mode GPTMTnV and the optional prescaler are combined to make a 24-bit or 48-bit timer. The timer is 24-bit when 16-bit timers are used. The timer is 48-bit when 32-bit timers are used.

In up counting mode, the GPTMTnV and GPTMTnPV registers are initialized with 0s and they count up until they reach to GPTMTnILR and GPTMTnPR, respectively. Then, they are reset to 0s again.

Tm4c counting in input edge time mode.png
Figure 9.2: Counting in Input Edge-Time Mode


In down counting mode, the GPTMTnV and GPTMTnPV registers are initialized with GPTMTnILR and GPTMTnPR, respectively and they count down until they reach 0. Then, they are reloaded with GPTMTnILR and GPTMTnPR, again. Notice that capturing has no effect on counting and the timer continues counting when the capturing event takes place.

Initialization and Configuration for Input Edge-Time Mode

Perform the following operational steps to complete the initialization and configuration process for this mode (n = A or B):

  1. Disable the selected timer by clearing the TnEN bit in the GPTMCTL register.
  2. Initialize the GPTMCFG register by writing 0x4 to setup all timers as 16-bit default timers.
  3. Configure the TnMR and TnCMR fields in the GPTMTnMR register by writing:
    • TnMR = 0x3 for capture mode.
    • TnCMR = 0x1 for edge time mode.
    • Select a count direction by programming the TnCDIR bit (0=count-down; 1=count-up).
  4. Configure the event type (positive-going, negative-going, or both) that the timer captures by writing the TnEVENT field of the GPTMCTL register.
  5. If a prescaler is to be used, write the prescale value to the GPTMTnPR register.
  6. Load the timer start value into the GPTMTnILR register.
  7. If interrupts are required, set the CnEIM bit in the GPTMIMR register.
  8. After these initializations and configurations are done, set the TnEN bit in the GPTMCTL register to enable the timer and begin waiting for edge events.
  9. If no interrupt is used, one can poll the CnERIS bit in the GPTMRIS register to wait for the edge event to occur. If interrupt is used, put appropriate codes inside the interrupt handler to process the interrupt. In both cases, the status flags are cleared by writing a 1 to the CnECIR bit on the GPTMICR register. The time at which the event happened can be obtained by reading the GPTMTnR register.

In the Input Edge Timing mode, the timer continues running after an edge event has been detected, but the timer interval can be changed at any time by writing the GPTMTnILR register and clearing the TnILD bit in the GPTMTnMR register. The change takes effect at the next cycle after the write taking placing.

Using Timer As a Counter

As shown in Table 8.4, a timer works as a counter when the TAMR bits of the GPTMTnMR are configured to capture mode and the TACMR bit is cleared. In this situation, the timer counts whenever the input pin is triggered. See Figure 9.3. The pin can be configured to count on the falling edge, rising edge, or both. To determine the type of edge that is counted, the TnEVENT bits of the GPTMCTL register should be initialized. See Table 8.3 and Table 8.4.

Tm4c counter diagram.png
Figure 9.3: Counter Diagram

Timer counting in input edge count mode

In this mode GPTMTnV and the prescaler are combined to make a 24-bit or 48-bit timer. The timer is 24-bit when TimerA and TimerB are used separately. Otherwise, they make a 48-bit timer.

In up counting mode, the GPTMTnV and GPTMTnPV registers are initialized with 0s and they count up until they reach to GPTMTnMATCHR and GPTMTnPMR, respectively. Then, they are reloaded with 0s again. See Figure 9.4.

Tm4c counting in input edge count mode.png
Figure 9.4: Counting in the Input Edge-Count Mode


Note: The value of GPTMTnPR and GPTMTnILR must be greater than the value of GPTMTnPMR and GPTMTnMATCHR.

In down counting, the GPTMTnV and GPTMTnPV registers are initialized with GPTMTnILR and GPTMTnPR, respectively and they count down until they reach to TnMATCHR and TnPMR, respectively. Then, they are reloaded with GPTMTnILR and GPTMTnPR and the CnMRIS flag of the GPTMRIS register is set. As a result, in cases that a task must be done after a specific number of events, the registers should be initialized so that (TnPR:TnILR – TnPMR:TnMATCHR = number of events to be counted); and then the CnMRIS flag is monitored to be set.

Initialization and Configuration for Input Edge-Count Mode

Perform the following operational steps to complete the initialization and configuration process for this mode (n = A or B):

  1. Disable the selected timer by clearing the TnEN bit in the GPTMCTL register.
  2. Initialize the GPTMCFG register by writing 0x4 to setup all timers as 16-bit default timers.
  3. Configure the TnMR and TnCMR fields in the GPTMTnMR register by writing:
    • TnMR = 0x3 for capture mode.
    • TnCMR = 0x0 for edge count mode.
  4. Configure the event type (positive-going, negative-going or both) that the timer captures by writing the TnEVENT field of the GPTMCTL register.
  5. Configure the following registers according to count direction:
  6. In count-down mode, the GPTMTnMATCHR and GPTMTnPMR registers are configured so that the difference between the value in the GPTMTnILR and GPTMTnPR registers and the GPTMTnMATCHR and GPTMTnPMR registers equals the number of edge events that must be counted. Make sure that the value in the GPTMTnILR and GPTMTnPR registers is greater than the value in the GPTMTnMATCHR and GPTMTnPMR registers.
  7. In count-up mode, the timer counts from 0x0 to the value in the GPTMTnMATCHR and GPTMTnPMR registers. Note that when executing a count-up, the value of the GPTMTnPR and GPTMTnILR must be greater than the value of GPTMTnPMR and GPTMTnMATCHR registers.
  8. If interrupts are required, set the CnMIM bit in the GPTMIMR register.
  9. After these initializations and configurations done, set the TnEN bit in the GPTMCTL register to enable the timer and begin waiting for edge events.
  10. If no interrupt is used, one can poll the CnMRIS bit in the GPTMRIS register to wait for the edge event to be occurred. If interrupt is used, put appropriate codes inside the interrupt handler to process the interrupt. In both cases, the status flags are cleared by writing a 1 to the CnMCIR bit on the GPTMICR register.

When counting down in the Input Edge-Count Mode, the timer stops after the programmed number of edge events has been detected. To re-enable the timer, ensure that the TnEN bit is cleared and repeat steps 4 through 8.

PWM Mode

  • When working in this mode, each timer can be configured as a 24- or 48-bit count-down counter to generate PWM output signals. At start, the timer loads the start values stored in the GPTMTAILR and GPTMTAPR registers (if prescaler is used) and begins its count-down actions. When gets 0, the timer reloads the start value and begin the next cycle.
  • The period and frequency of the PWM signal is controlled by the start values setup in the GPTMTAILR and GPTMTAPR registers, and the pulse width is controlled by the values set in the GPTMTAMATCHR and GPTMTAPMR registers (if prescaler is used). The PWM pulse is generated (outputs High) when the timer is at its start value and terminated (outputs Low) when the timer equals to the terminate values stored in the GPTMTAMATCHR and GPTMTAPMR registers.
  • The timer can generate three types of interrupt: rising edge, falling edge, and both. The event is configured by the TAEVENT field of the GPTMCTL register, and the interrupt is enabled by setting the TAPWMIE bit in the GPTMTAMR register.
  • In this mode, the GPTMTAR and GPTMTAV registers always have the same value, as do the GPTMTAPS and the GPTMTAPV registers.


The operational sequence of using the Timer A to generate a PWM signal is as follows:

  1. The start values are loaded into the GPTMTAILR and GPTMTAPR registers, and the terminate values are loaded into the GPTMTAMATCHR and GPTMTAPMR registers. The period and duty cycle of the PWM signal are determined based on these values.
  2. The PWM mode is enabled with the GPTMTAMR register by setting the TAAMS bit to 1, the TACMR bit to 0, and the TAMR field to 0x2.
  3. The timer is enabled and starts its count-down operation by setting the TAEN bit in the GPTMCTL register to 1. The counter begins counting down until it reaches the 0 state. Then it reloads the start values and continues for the next cycle until disabled by software clearing the TAEN bit in the GPTMCTL register. Alternatively, if the TAWOT bit is set in the GPTMTAMR register, once the TAEN bit is set, the timer waits for a trigger to begin counting.
  4. As the timer starts counting from its start values, the PWM pulse is generated with outputting High. During the counting-down process, when the value in the timer is equal to the terminate values set in the GPTMTAMATCHR and GPTMTAPMR registers, the pulse of the PWM signal is terminated with outputting Low.
  5. The output level of the PWM signal can be controlled by the software, it means that the software has the capability of inverting the output PWM signal by setting the TAPWML bit in the GPTMCTL register.

Timer Interrupt Programming

In the previous article, we showed how to program the timers. In those programming examples, we used polling to see if a timeout event occurred. In this section, we give interrupt-based version of those programs. Examine the earlier programs, we could run those programs only one at a time since we have to monitor the timer flag continuously. By using interrupt, we can run several of timer programs all at the same. To do that, we need to enable the timer interrupts using the GPTMIMR (GPTM Interrupt Mask) register.

Timers A and B Interrupt and Configuration Register Group

Six registers are used to control and handle interrupts of the Timers A and B:

  • GPTM Interrupt Mask Register (GPTMIMR)
  • GPTM Raw Interrupt Status Register (GPTMRIS)
  • GPTM Masked Interrupt Status Register (GPTMMIS)
  • GPTM Interrupt Clear Register (GPTMICR)
  • GPTM Synchronize Register (GPTMSYNC)
  • GPTM Peripheral Properties Register (GPTMPP)

GPTM Interrupt Mask Register (GPTMIMR)

Tm4c gptm imr.png


Bit Name Description
0 TATOIM Timer A Time-out Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
1 CAMIM Timer A Capture Mode Match Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
2 CAEIM Timer A Capture Mode Event Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
3 RTCIM RTC Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
4 TAMIM Timer A Match Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
8 TBTOIM Timer B Time-out Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
9 CBMIM Timer B Capture Mode Match Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
10 CBEIM Timer B Capture Mode Event Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
11 TBMIM Timer B Match Interrupt Mask (0: interrupt is disabled, 1: interrupt is enabled)
16 WUEIM 32/64-Bit Wide GPTM Write Update Error Interrupt Mask (0: disabled, 1: enabled)
Table 10.1: GPTM Interrupt Mask (GPTMIMR)


IRQ21 is assigned to Timer1A and IRQ23 to Timer2A. The following will enable these timers in NVIC:

NVIC_EN0_R |= 0x00200000;   /* enable IRQ21  */
NVIC_EN0_R |= 0x00800000;   /* enable IRQ23 */

GPTM Raw Interrupt Status Register (GPTMRIS)

Tm4c gptmris r.png


This 32-bit register only used the lower 10 bits to monitor and set a raw or internal interrupt if a GPTM-related raw interrupt occurred. These bits are set whether or not the interrupt is masked in the GPTMIMR register. However, whether these set raw interrupts can be sent to the interrupt controller to be further processed, it depends on whether the corresponding bits on the GPTMIMR register are set (enabled) or not (disabled). Only for those bits that have been set on the GPTMIMR register, they can be sent to the NVIC. The bit field and functions for this register are similar to those in the GPTMIMR register. If a GPTM-related raw interrupt is generated, the corresponding bit on this register is set to 1. Each bit can be cleared by writing a 1 to its corresponding bit in GPTMICR register.


Bit Name Description
0 TATORIS Timer A Time-out Raw interrupt (0: not occurred, 1: occurred)
1 CAMRIS Timer A Capture Mode Match Raw Interrupt (0: not occurred, 1: occurred)
2 CAERIS Timer A Capture Mode Event Raw Interrupt (0: not occurred, 1: occurred)
3 RTCRIS RTC Raw Interrupt(0: not occurred, 1: occurred)
4 TAMRIS Timer A Match Raw Interrupt
8 TBTORIS Timer B Time-out Raw interrupt (0: not occurred, 1: occurred)
9 CBMRIS Timer B Capture Mode Match Raw Interrupt (0: not occurred, 1: occurred)
10 CBERIS Timer B Capture Mode Event Raw Interrupt (0: not occurred, 1: occurred)
11 TBMRIS Timer B Match Raw Interrupt
16 WUERIS 32/64-Bit Wide GPTM Write Update Error Raw Interrupt Status

GPTM Masked Interrupt Status Register (GPTMMIS)

Tm4c gptmmis r.png

Similar to the GPTMIMR register, this 32-bit register only used the lower 10 bits to monitor and make a responded interrupt if a GPTM related interrupt is occurred and has been responded. The bit field and functions for this register is similar to those in the GPTMIMR register. A value of 1 on a bit in this register indicates that the corresponding interrupt has occurred and has received a response. All bits are cleared by writing a 1 to the corresponding bit in GPTMICR register.

GPTM Interrupt Clear Register (GPTMICR)

Tm4c gptmicr r.png

Similar to GPTMIMR register, this 32-bit register only used the lower 10 bits to clear related responded interrupts if the GPTM-related interrupts have received a response and have been processed. This register is used to clear the status bits in the GPTMRIS and GPTMMIS registers. Writing a 1 to a bit clears the corresponding bit in the GPTMRIS and GPTMMIS registers. All processed or responded interrupts must be cleared by using this register. Otherwise the responded interrupt cannot be generated again in the future if it is not cleared. The bit field and functions for this register is similar to those in the GPTMIMR register.

1. Build a General Purpose Timer Project

Use GPTM block 0 Timer A (Timer0A) as a 16-bit count-down counter to periodically generate a timeout interrupt to turn on three LEDs, PF3∼PF1, via GPIO Port F. The input clock to the timer is the 16 MHz system clock, and the period to be counted in the Timer0A counter is 65.536 ms.

To perform this periodic interrupt for each 65.536 ms, one needs to:

  1. Enable and clock the Timer0A for GPTM Block 0.
  2. Enable and clock the GPIO Port F.
  3. Disable the Timer0A module before any configuration can be performed.
  4. Configure the Timer0A to work as a 16-bit count-down periodic counter.
  5. Load 65535 (65536 – 1) into the GPTMTAILR register as the start value since we want to get the maximum period of time, which is 65.536 ms, for each period.
  6. Load 15 (16 – 1) into the GPTMTAPR register as a prescale value. After this 16 MHz system clock is divided by this prescaler (16), the working clock for this counter is 1 MHz with a 1-μs period.
  7. Clear any previous timeout interrupt for Timer0A by writing 1 to an appropriate bit in the GPTMICR register.
  8. Enable Timer0A timeout interrupt by writing 1 to an appropriate bit in the GPTMIMR register.
  9. Use NVIC_PRI4_R (Bit 31 - 29 ) to set the interrupt priority level as 3 for the Timer0A.
  10. Use NVIC_EN0_R (IRQ19) to enable the timeout interrupt for the Timer0A.
  11. Enable the Timer0A module after these configuration and the Timer0A begins to count.
  12. Use EnableInterrupts() function to globally enable all interrupts.
  13. Use an infinitive while() loop to wait for any interrupt coming.

In addition to the main program, one also needs to build the Timer0A interrupt handler:

  1. Clear the timeout interrupt for Timer0A by writing 1 to an appropriate bit in the GPTMICR register to enable it to be generated in the future.
  2. Turn on the related LED via GPIO Port F.

2. Use Timer1A and Timer2A timeout events to trigger interrupts

  • Configure Timer1A to timeout once every second. In the interrupt handler, toggle the red LED.
  • Configure Timer2A to timeout at 10 Hz. In the interrupt handler, toggle the green LED.

3. Measure pulse width using interrupts with a precision of 24 bits and a resolution of 12.5 ns

  • The pulse width measurement is performed from rising edge to falling edge.
  • The resolution is 12.5 ns, determined by the system bus clock.
  • The range is about 25 ns to 209ms with no overflow checking.

Hints:

  • The digital-level input signal is connected to two input capture pins, CCP0 and CCP1.
  • The bus clock is selected to be 80 MHz so the measurement resolution will be 12.5 ns.
  • The rising edge time will be measured by Timer0B without the need of an interrupt and the falling edge interrupts will be handled by Timer0A.
  • The pulse width is calculated as the difference in TIMER0_TBR_R - TIMER0_TAR_R latch values.


Tm4c measuring pulse width.png

4. Measure the period of a square wave input signal

Hint: To measure the period of a signal we must measure the time between two falling or rising edges.

Tm4c measuring square wave.png
Figure 10.5: Measuring Period and Pulse Width

5. Generate PWM

  • Generate an output PWM with a 1-ms period and a 66% duty cycle (TAPWML = 0) assuming a 50 MHz input clock. The duty cycle could be 33% if the TAPWML = 1.
    Hint:
    1. The start value is GPTMTAILR = 0xC350 and the match value in GPTMTAMATCHR is 0x411A.
    2. Use PLL
    3. Use Timer A
Task timer pwm.png

Pulse-Width Modulation — What is it?

The good definition of Pulse-Width Modulation (PWM) is already in the name itself. It means modulating/varying the width of the pulse only, not the frequency. In the digital control system, PWM is used to control the amount of power sent to a device.

The speed of the motor depends on three factors: (a) load, (b) voltage, and (c) current. For a given fixed load we can maintain a steady speed by using a method called pulse width modulation (PWM). By varying (modulating) the width of the pulse applied to the DC motor we can increase or decrease the amount of power provided to the motor, thereby increasing or decreasing the motor speed. Notice that, although the voltage has a fixed amplitude, it has a variable duty cycle. That means the wider the pulse, the higher the speed.

The ability to control the speed of the DC motor using PWM is one reason that DC motors are preferable over AC motors. AC motor speed is dictated by the AC frequency of the voltage applied to the motor and the frequency is generally fixed. As a result, we cannot control the speed of the AC motor when the load is increased.

Principle

A PWM signal consists of two main components that define its behavior: a duty cycle and a frequency.

Pwm dutycycle principle.png
  • Duty Cycle
    The duty cycle describes the amount of time the signal is in a high (ON) state as a percentage of the total time it takes to complete one cycle. A lower duty cycle corresponds to lower power, because the power is OFF for most of the time. Duty cycle is expressed in percent, 100% duty cycle would be fully ON as same as setting the signal to Vcc (high); 0% duty cycle would be the same as grounding the signal.
  • Frequency
    The frequency determines how fast the PWM completes a cycle, ie. 100Hz would be 100 cycles per second. In another words, it shows how fast the PWM switches between high and low states. In the digital system, PWM is the method to produce variable voltage using digital means. Typically, digital system only has two output voltages, the high (5V, 3.3V … etc.) or low (0V).

Types of PWM

There are a couple of types of PWM, and it can be classified in different ways. There are two kinds of PWM signals: Symmetric and Asymmetric.

Symmetric PWM

  • The pulses of a symmetric PWM signal are always symmetric with respect to the center of each PWM period.
  • Symmetric PWM are often used for three-phase AC induction and brushless DC motors, due to the lower harmonic distortion that is generated on phase currents in comparsion to asymmetric PWM methods.

Asymmetric PWM

  • The pulses of an asymmetric PWM signal always have the same side aligned with one end of each PWM period.
  • Asymmetric PWM can be used for stepper motors and other variable-reluctance motors.

Classifying PWM Signal by Signal-Alignment

The PWM signal can be classified by signal-alignment in four different types:

Pwm symmetric asymmetric.png
  1. Center-aligned PWM:
    • Symmetric PWM
    • Center-aligned PWMs are most often used in AC motor control to maintain phase alignment
  2. Left-aligned PWM
    • Asymmetric PWM
    • Left-aligned PWMs are used for most general-purpose PWM uses
  3. Right-aligned PWM
    • Asymmetric PWM
    • Right-aligned PWMs are typically only used in special cases that require alignment opposite of left-aligned PWMs
  4. Dual-edge PWM
    • Dual-edged PWMs are optimized for power conversion where phase alignment must be adjusted

PWM Modules in the TM4C123GH6PM MCU System

The TM4C123GH6PM MCU contains two PWM modules, PWM0 and PWM1. Each module has four PWM generator blocks and a control block, and each generator block can create two PWM output signals, therefore a total of 16 PWM output signals can be generated by these two modules. The control block determines the polarity of the PWM signals, and it also determines which signals are passed through to the output pins.

Following are the basic facts about the PWM features of TI Tiva LaunchPad:

  • There are two PWM modules, PWM0 and PWM1.
  • Each PWM module has four Generators.
  • Each Generator has a Counter (Timer).
  • Each Generator has two Compare registers CMPA and CMPB.
  • Each Generator has two output pins, which means there are a total of 8 PWM pins per module.
  • The Counter of the Generator can be programmed to count-up or count-up/down.
  • As the Counter counts , it may change the output pin when the counter value matches the:
    1. Compare register(s),
    2. reaches zero, or is
    3. reloaded.

The options for output pin change are:

  1. toggle,
  2. driven LOW, or
  3. driven HIGH.


Tm4c pwm module.png
Figure 14.1: PWM Module

The PWM Generator Block

In the TM4C123GH6PM MCU system, each PWM generator block is composed of two components:

  1. One 16-bit Counter or Timer and
  2. Two PWM Comparators, cmpA and cmpB.

The counter provides a timing base for two comparators, and it is mainly used to perform count-down or count-up/down functions to provide a comparison source for two comparators.

The PWM Counter (Timer)

The 16-bit counter or timer in each PWM generator runs in one of two modes, Count-Down mode or Count-Up/Down mode:

  • In Count-Down mode, the timer counts from the LOAD value to 0, and then it goes back to the LOAD value and continues to perform the counting down.
  • In Count-Up/Down mode, the timer counts from 0 up to the LOAD value and then counts down back to 0, back up to the LOAD value, and so on. Generally, Count-Down mode is used for generating left-aligned or right-aligned PWM signals, and the Count-Up/Down mode is used to generate center-aligned PWM signals.

The timers output three signals that can be used in the PWM generation process:

  1. The direction signal.
    This signal is always LOW in Count-Down mode, but alternates between LOW and HIGH in Count-Up/Down mode.
  2. A single-clock-cycle-width High pulse when the counter gets zero.
  3. A single-clock-cycle-width High pulse when the counter is equal to the LOAD value.

The PWM Comparators

Each PWM generator has two comparators that monitor the value of the counter and output a single-clock-cycle-width HIGH when either comparator’s value is equal to the counting value in the counter. These outputs are labeled cmpA and cmpB. In the Count-Up/Down mode, these comparators match both when counting up and when counting down and thus are qualified by the counter direction signal. If either comparator match-value is greater than the counter load value, that comparator never outputs a High pulse.

Tm4c pwm count up down modes a.png
(a) PWM Count-Down Mode


Tm4c pwm count up down modes b.png
(b) PWM Count-Up/Down Mode


Figure 14.2: PWM Count-Down and Count Up/Down modes

Figure 14.2(a) shows the behavior of the counter and the relationship of these pulses when the counter is in Count-Down mode.
Figure 14.2(b) shows the behavior of the counter and the relationship of these pulses when the counter is in Count-Up/Down mode.

The PWM Output Signals Generator

Each PWM generator uses the load, zero, cmpA, and cmpB pulses and the dir signal to generate two internal PWM signals, pwmA and pwmB, as shown in Figure 14.3.

In Count-Down mode, four events can affect these signals: zero, load, match A down, and match B down. In Count-Up/Down mode, six events can affect these signals: zero, load, match A down, match A up, match B down, and match B up. The match A or match B events are ignored when they coincide with the zero or load events. If the match A and match B events coincide, the first signal, pwmA, is generated based only on the match A event, and the second signal, pwmB, is generated based only on the match B event.

Each event can affect each output PWM signal by programming to make the output to be:

  • Left alone (ignoring the event)
  • Toggled
  • Driven Low or High

These actions can be used to generate a pair of PWM signals of various positions and duty cycles, which do or do not overlap. Figure 14.3 shows the use of Count-Up/Down mode to generate a pair of center-aligned, overlapped PWM signals that have different duty cycles. The pwmA and pwmB signals shown in this figure are before they have passed through the dead-band generator.

Tm4c pwm count up down output.png
Figure 14.3: An example of using the count-up/down mode to generate PWM outputs.


In Figure 14.3, the first PWM generator is set to output High on match A up (COMPA), output Low on match A down (COMPA), and ignore the other four events. The second PWM generator is set to output High on match B up (COMPB ), output Low on match B down (COMPB), and ignore the other four events. Changing the value of comparator A (COMPA) changes the duty cycle of the pwmA signal, and changing the value of comparator B (COMPB) changes the duty cycle of the pwmB signal.

In addition to normal PWM outputs, these two PWM output signals can be combined together to form a so-called Dead-Band output to drive a half-H bridge circuit for some motors.

The Dead-Band Generator

The pwmA and pwmB signals generated by each PWM generator can be passed to the dead-band generator. If the dead-band generator is disabled, these PWM signals can be passed through to the pwmA’ and pwmB’ signals without any modification. If the dead-band generator is enabled, the pwmB signal is ignored and only the pwmA signal is used to generate two PWM signals, pwmA’ and pwmB’.

The first output PWM signal, pwmA’, is the pwmA signal with the rising edge delayed by a programmable amount. The second output PWM signal, pwmB’, is just the inversion of the pwmA signal with a programmable delay added between the falling edge of the pwmA signal and the rising edge of the pwmB’ signal, as shown in Figure 14.4.

The resulting signals are therefore suitable for driving a half-H bridge, with the dead-band delays preventing shoot-through current from damaging the power electronics. These resulting pwmA’ and pwmB’ signals will be transmitted to the output control block.

Tm4c pwm dead generator.png
Figure 14.4: PWM Dead-Band Generator.


Programming PWM in TI Tiva LaunchPad

PWM Clock source

The Clock source to the PWM module in TI Tiva LaunchPad is enabled via R1 or R0 bits of RCGCPWM register. The RCGCPWM register is part of the System Control registers and located at the physical address of 0x400F.E000 with offset 0x640. See Figure 15.21.

Tm4c rcgcpwm r.png
Figure 15.21: RCGCPWM Register


We enable the clock source to PWM0 module with SYSCTL_RCGCPWM_R |= 1; and to PWM1 module with SYSCTL_RCGCPWM_R |= 2;

SYSCTL_RCGCPWM_R |= 1;  /* enable clock source to PWM0 module */
SYSCTL_RCGCPWM_R |= 2;  /* enable clock source to PWM1 module */

Run-Mode Clock Configuration (RCC)

This register is used to pre-divide the system clock before feeding it to the PWM modules. The clock source to the PWM module may come directly from the system clock or after going through a divider. See Figures 15.22 and 15.23.

Tm4c rcc r.png
bit Name Description
19-17 PWMDIV PWM Unit Clock: The System Clock is divided by 2PWMDIV-1 when the USEPWMDIV bit is set one.
PWMDIV value 0 1 2 3 4 5 6 7
Division Clk/2 Clk/4 Clk/8 Clk/16 Clk/32 Clk/64 Clk/64 Clk/64
20 USEPWMDIV Enable PWM Clock Divisor (Use PWM clock Divisor)
0: The PWM clock divider is by passed.
1: The PWM clock divider is used as the PWM clock source.
Figure 15.22: Run-Mode Clock Configuration (RCC)


Tm4c Clock sources to pwm.png
Figure 15.23: Clock Sources to PWM


The D20 bit (USEPWMDIV) of RCC register allows us to make this selection. With Bit D20 = 1, we have the choices of dividing the system clock by 2, 4, 8, 16, 32, and 64 (default) before it is fed to the PWM modules. The D19-D17 bits of RCC register determines the value of the divisor. Notice that the default is divide by 64 if the pre-divider is enabled by D20 bit.

Example:
Find the value of bit 20-17(PWMDIV) of the RCC register for PWM Module clock frequencies of (a) 8MHz, (b) 2MHz, (c) 1MHz, and (d) 250KHz. Assume the system clock frequency is 16MHz.

Solution:
With D20 = 1, we have the following:
(a) D19-D17 = 000 gives us 16MHz/2=8MHz for PWM Module Frequency.
(b) D19-D17 = 010 gives us 16MHz/8=2MHz for PWM Module Frequency.
(c) D19-D17 = 011 gives us 16MHz/16=1MHz for PWM Module Frequency.
(d) D19-D17 = 111 gives us 16MHz/64=250KHz for PWM Module Frequency (default).

Enabling PWMx Generator (Counter)

In TI Tiva LaunchPad, we have two PWM modules PWM0 and PWM1. Each PWM module has four Generators (Counters) as shown in Figure 14.1. Figure 15.24 shows the simplified structure of a Generator.

Tm4c pwm generator diagram.png
Figure 15.24: A PWM Generator (Counter) and PWMa and PWMb Output


We use PWMxCTL (PWMx Control) register to enable the Generator (Counter). Notice that we use the terms Counter and Generator interchangeably since there is one Counter per Generator and all the programming of the Generator surrounds the Counter. Also notice that we have a PWMxCTL for each Generator. See Figure 15.25.

Tm4c pwmnctl r.png
Figure 15.25: PWMxCTL Register


The most important bit of the PWMxCTL is D0 (Enable). This bit is used to start or stop the Counter. The next important bit is D1 (MODE). The counter has two modes:

  1. Count Down: counts down from the load value until it reaches 0. Upon reaching zero, the load value is placed in the counter and the countdown starts again. This is the default option.
  2. Count Up-Down: counts up from 0 until it reaches the load value. After reaching the load value, it turns around and counts down to 0 and upon reaching 0 it repeats the process. See Figure 15-26.
Tm4c pwm updown down counter.png
Figure 15.26: Up/down and down-counter


In both modes, the load value is in a register called LOAD (PWMxLOAD) register. Notice that we must disable a given Generator (Counter) before the initialization. After the initialization is done, we must enable it to start counting.

Table 15-21 shows the offset address for Control register of PWM0 Module. We also have four Control registers for PWM1 Module. The offset addresses are the same except the Base address for the PWM1 module is different, as we mentioned earlier.


Register Offset
PWM0_0_CTL (Control for Counter0) 0x040
PWM0_1_CTL (Control for Counter1) 0x080
PWM0_2_CTL (Control for Counter2) 0x0C0
PWM0_3_CTL (Control for Counter3) 0x100
Table 15.21: The Offset Addresses of PWMCTL Registers in TI TIVA

The LOAD register

To set the maximum value for the Counter, we have to load register called PWMxLOAD. Since each of PWM0 and PWM1 has four Generators (Counters), we also have four PWMxLOAD registers. The PWMxLOAD register is 16-bit wide and it determines the maximum count and hence the PWM output frequency.

Figure 15.27 shows the LOAD registers of PWM0 Module. We also have four LOAD registers for PWM1 Module. The offset addresses are the same except the base address for the PWM1 module is different, as we mentioned earlier.

Tm4c pwmnload r.png


Register Offset
PWM0_0_LOAD 0x050
PWM0_1_LOAD 0x090
PWM0_2_LOAD 0x0D0
PWM0_3_LOAD 0x110
Figure 15.27: PWMxLOAD Register

Reading the Current Counter Value

The current value of the Counter (Generator) can be read from the PWMxCOUNT register. As the Counter (Generator) counts up or counts down, we can read the value of this register at any time. Notice, this is a Read-Only (RO) register. Since the Counter is 16-bit, the PWMxCOUNT gives us the current value of the counter which can be between 0 to 0xFFFF. We can set a maximum value for the Counter using the LOAD register. Figure 15.28 shows the Current Count registers of PWMn Module.

Tm4c pwmncount r.png


Register Offset
PWM0_0_COUNT 0x054
PWM0_1_COUNT 0x094
PWM0_2_COUNT 0x0D4
PWM0_3_COUNT 0x114
Figure 15.28: PWMxCOUNT (Current Counter)

We also have four Current Count registers for PWM1 Module. The offset addresses are the same except the Base address for the PWM1 module is different, as we mentioned earlier.

Compare A and Compare B

Figure 15-29 shows the offset addresses for CompareA registers of PWM0 Module. We also have four CompareA registers for PWM1 Module. The offset addresses are the same except the Base address for the PWM1 module is different, as we mentioned earlier.

Tm4c pwmncmpa r.png


Register Offset
PWM0_0_CMPA 0x058
PWM0_1_CMPA 0x098
PWM0_2_CMPA 0x0D8
PWM0_3_CMPA 0x118
Figure 15.29: PWMxCMPA

Figure 15-30 shows the offset addresses for CompareB registers of PWM0 Module. We also have four CompareB registers for PWM1 Module. The offset addresses are the same except the Base address for the PWM1 module is different, as we mentioned earlier.

Tm4c pwmncmpb r.png


Register Offset
PWM0_0_CMPB 0x05C
PWM0_1_CMPB 0x09C
PWM0_2_CMPB 0x0DC
PWM0_3_CMPB 0x11C
Figure 15.30: PWMxCMPB

PWM generators

Tm4c pwmngena r.png
Tm4c pwmngenb r.png

ACTCMPBD: Action when the counter matches comparator B while counting down
ACTCMPBU: Action when the counter matches comparator B while counting up
ACTCMPAD: Action when the counter matches comparator A while counting down
ACTCMPAU: Action when the counter matches comparator A while counting up
ACTLOAD: Action when the counter is reloaded
ACTZERO: Action when the counter reaches zero


For each of the above events the following actions can be choosen:


Value Description
0x00 Do nothing
0x01 Invert pwmA
0x02 Drive pwmA Low
0x03 Drive pwmA High
Figure 15.31: PWMxGENA and PWMxGENB registers

Figure 15.32 shows the offset addresses for GeneratorA and GeneratorB Control registers of PWM0 Module. We also have four GeneratorA and GeneratorB Control registers for PWM1 Module. The offset addresses are the same except the Base address for the PWM1 module is different.


Register Offset Resgister Offset
PWM0_0_GENA 0X060 PWM0_0_GENB 0X064
PWM0_1_GENA 0X0A0 PWM0_1_GENB 0X0A4
PWM0_2_GENA 0X0E0 PWM0_2_2GENB 0X0E4
PWM0_3_GENA 0X120 PWM0_3_GENB 0X124
Figure 15.32: PWMxGENA and PWMxGENB Offset


Generating Square waves using PWM generators

In TI Tiva LaunchPad, each of the Generator has two Compare registers. They are called PWMxCMPA (PWMx Compare A) and PWMxCMPB (PWMx Compare B). As the Counter counts down (or up), its value is compared with the PWMxCMPx register and upon a match, a PWM output pin will do one of the following:

  1. do nothing,
  2. toggle,
  3. driven HIGH,
  4. driven LOW

These output actions are not limited to the compare register, you may choose one of these actions when the counter reaches zero and when the counter reloads. The selections of these actions are made in the PWM generator (PWMxGENx) register. Each register is associated with an output pin and has six actions you may specify:

  1. action when the counter matches comparator B while counting down.
  2. action when the counter matches comparator B while counting up.
  3. action when the counter matches comparator A while counting down.
  4. action when the counter matches comparator A while counting up.
  5. action when the counter is reloaded.
  6. action when the counter reaches zero.


Tm4c pwm events in ti tiva.png
Figure 15.41: PWM Events in TI TIVA

These options allow us to generate some elaborate output waveforms. Each wave generator has 2 outputs: PwmA and PwmB; Using PWMxGENA and PWMxGENB registers the action of the outputs are chosen as was shown in Figure 15-24. The details of PWMxGENx register is shown in Figure 15.31. Each event may cause an action specified by two bits.

Generating periodic square wave using down counting mode

For now, we will start with a simple periodic square wave. To do that, a PWMxGENx register is configured so that the output is driven high when the counter is reloaded and the output is driven low when the counter matches a comparator register while counting down. See Figure 15-42.

Tm4c pwm gen countdown cmpa.png
Figure 15.42: PWM generation using count-down mode and ComparatorA

The PWM Output Frequency in Count Down mode

To calculate the value for the PWMxLOAD register for a desired PWM output frequency, we divide the period of the desired PWM output by the period of the PWM module clock. Examples 15.41 and 15.42 show how to calculate the LOAD register value.

Example 15.41: Assume the PWM3 Module clock frequency is 8MHz. Find the value of the PWM3LOAD register if we want the PWM3 output Frequency of (a) 5KHz, (b) 10KHz, and (c) 25KHz.  

Solution: The clock period for PWM3 Module is 1/8MHz = 0.125µs (micro second).
(a) The PWM3 output period is 1/5KHz = 200µs. Now, PWM3LOAD = 200µs/0.125µs = 1600 or 0x640.
(b) The PWM3 output period is 1/10KHz=100µs. Now, PWM3LOAD = 100µs/0.125µs = 800 or 0x320.
(c) The PWM3 output period is 1/25KHz=40µs. Now, PWM3LOAD = 40µs/0.125µs = 320 or 0x140.

Example 15.42:In a given PWM application, we need the PWM output frequency of 60Hz. Using the PWM Module frequencies of Example 15.41, find out the value of the PWMxLOAD register.

Solution: The period for the PWM output is 1/60Hz = 16.6ms
In Example 15.41, we have the following cases:
(a) The PWM Module clock period is 1/8MHz=0.125µs(micro second). PWM×LOAD=16.6ms/0.125µs = 132,800. This is not acceptable since it is larger than 65535, the maximum value the PWM×LOAD register can hold.
(b) The PWM Module clock period is 1/2MHz = 0.5 µs. PWM×LOAD = 16.6ms/0.5 µs = 33,333.
(c) The PWM Module clock period is 1/1MHz = 1 µs. PWM×LOAD = 16.6ms/1µs = 16,600.
(d) The PWM Module clock period is 1/250KHz = 4 µs. PWM×LOAD = 16.6ms/4µs = 4,150.

The PWM output duty cycle in Count Down mode

In this configuration, the duty cycle (the percentage of the time the output is high) is determined by the ratio between PWMxCMPx and PWMxLOAD registers and is shown below:

PWMxCMPx = (100% - DutyCycle%) x PWMxLOAD

Example 15.43: Assume the PWM0 Module System clock frequency is 16MHz. Find the value of the PWMxLOAD and PWMxCMPA registers for the following PWM output frequencies and duty cycles: (a) 1KHz with 25%, (b) 5KHz with 60%, (c) 20KHz with 80%, and (d) 2KHz of 50%.

Solution: The System Clock period for PWM0 Module is 1/16MHz = 62.5ns (nano sec).
(a) The PWM output period is 1 / 1KHz = 1msec. Now, PWM0LOAD = 1ms / 62.5ns = 16000
PWMxCMPA = (100% – Duty Cycle) × PWMxLOAD = (100% – 25%) × 16000 = 75% × 16000 = 12000
(b) The PWM output period is 1/5KHz = 0.2msec. Now, PWM0LOAD = 2ms / 62.5ns = 3200
PWMxCMPA = (100% – Duty Cycle) × PWMxLOAD = (100% – 60%) × 3200 = 40% × 3200 = 1280
(c) The PWM output period is 1/20KHz = 0.05msec. Now, PWM0LOAD = 0.05ms / 62.5ns = 800
PWMxCMPA = (100% – Duty Cycle) × PWMxLOAD = (100% – 80%) × 800 = 20% × 800 = 160
(d) The PWM output period is 1/2KHz = 0.5msec. Now, PWM0LOAD = 0.5ms / 62.5ns = 8000
PWMxCMPA = (100% – Duty Cycle) × PWMxLOAD = (100% – 50%) × 8000 = 50% × 8000 = 4000


Enable the PWM output to the output pin

To provide an easy way to turn off the PWM output, each PWM generator has an enable register PWMENABLE. Since many of the PWM registers are shared, this allows us to disable a given PWM signal from going to the output pin without disturbing the rest of the PWMs. The lower 8 bits of the PWMENABLE register are used for enabling or disabling the PWM0 to PWM7. When the bit is enabled, the signal generated by the PWM generator is connected to the output pin. When the bit is disabled, there will be no output but the PWM generator still runs without any change.

There are total of 8 PWM pins supported by each PWM module. The PWM pins for each of PWM module are designated as PWM0, PWM1, PWM2, ..., PWM7 as shown in Figure 14.1.

We use PWM0_ENABLE_R and PWM1_ENABLE_R to control the outputs of PWM0 and PWM1, respectively. The offset addresses are the same except the base address is different, as we mentioned earlier. See Figure 16.1.

Tm4c pwmenable r.png


bit Name Description
0 PWM0EN MnPWM0 Output Enable
0: The MnPWM0 signal has zero value.
1: The generated pwm signal is passed to the MnPWM0 pin.
1 PWM1EN MnPWM1 Output Enable
0: The MnPWMx signal has zero value.
1: The generated pwm signal is passed to the MnPWM1 pin
Figure 16.1: PWMENABLE

The role of the PWMENABLE register is shown in the PWM Output Control part of Figure 16.1.

Selecting alternate function for PWMx pin

Upon reset, the GPIOAFSEL register has all 0s meaning the I/O pins are used as simple I/O. To use the alternate function, we first must set to 1 the bit in the AFSEL register for that pin. For example, for the PB6, we need to write 0x40 (01000000 in binary) to GPIO_PORTB_AFSL register. See Tables 16.1 and 16.2. After that, the GPIOPCTL register must be configured for the desired function, as shown in Tables 16.1 and 16.2. The alternate functions for each I/O pin are listed in Table 23-5 of TI Tiva LaunchPad manual. Tables 16.1 through 16.2 provide the summary for the M0PWMx and M1PWMx pins. See Example 16.1.


M0PWMx PIN Value for GPIOAFSL register Value for GPIOPCTL register
M0PWM0 PB6 GPIO_PORTB_AFSEL_R = 0x40  GPIO_PORTB_PCTL_R=0x04000000
M0PWM1 PB7 GPIO_PORTB_AFSEL_R = 0x80 GPIO_PORTB_PCTL_R=0x40000000
M0PWM2 PB4 GPIO_PORTB_AFSEL_R = 0x10 GPIO_PORTB_PCTL_R=0x00040000
M0PWM3 PB5 GPIO_PORTB_AFSEL_R = 0x20 GPIO_PORTB_PCTL_R=0x00400000
M0PWM4 PE4 GPIO_PORTE_AFSEL_R = 0x10 GPIO_PORTE_PCTL_R=0x00040000
M0PWM5 PE5 GPIO_PORTE_AFSEL_R = 0x20 GPIO_PORTE_PCTL_R=0x00400000
M0PWM6 PC4 GPIO_PORTC_AFSEL_R = 0x10 GPIO_PORTC_PCTL_R=0x00040000
PD0 GPIO_PORTD_AFSEL_R = 0x01 GPIO_PORTD_PCTL_R=0x00000004
M0PWM7 PC5 GPIO_PORTC_AFSEL_R = 0x20 GPIO_PORTC_PCTL_R=0x00400000
PD1 GPIO_PORTD_AFSEL_R = 0x02 GPIO_PORTD_PCTL_R=0x00000040
Table 16.1: Module 0 (M0) PWM GPIOAFSL and GPIOPCTL pin assignment


M1PWMx PIN GPIOAFSL register Value for GPIOPCTL
M1PWM0 PD0 GPIO_PORTD_AFSEL_R = 0x01 GPIO_PORTD_PCTL_R= 0x00000005
M1PWM1 PD1 GPIO_PORTD_AFSEL_R = 0x02 GPIO_PORTD_PCTL_R=0x00000050
M1PWM2 PA6 GPIO_PORTA_AFSEL_R = 0x40 GPIO_PORTA_PCTL_R=0x05000000
PE4 GPIO_PORTE_AFSEL_R = 0x10 GPIO_PORTE_PCTL_R=0x00050000
M1PWM3 PA7 GPIO_PORTA_AFSEL_R = 0x80 GPIO_PORTA_PCTL_R=0x50000000
PE5 GPIO_PORTE_AFSEL_R = 0x20 GPIO_PORTE_PCTL_R=0x00500000
M1PWM4 PF0 GPIO_PORTF_AFSEL_R = 0x01 GPIO_PORTF_PCTL_R=0x00000005
M1PWM5 PF1 GPIO_PORTF_AFSEL_R = 0x02 GPIO_PORTF_PCTL_R=0x00000050
M1PWM6 PF2 GPIO_PORTF_AFSEL_R = 0x04 GPIO_PORTF_PCTL_R=0x00000500
M1PWM7 PF3 GPIO_PORTF_AFSEL_R = 0x08 GPIO_PORTF_PCTL_R=0x00005000
Table 16.2: Module 1 (M1) PWM GPIOAFSL and GPIOPCTL pin assignment


Example: Show how to select the alternative function for (a) M0PWM0, (b) M0PWM1, and (c) M1PWM2 pins.

Solution:

(a) From Tables 16.1 and 16.2, we see M0PWM0 is the alternate function for pin PB6.
GPIO_PORTB_AFSEL_R |= 0x40;  /* PB6 alternative function for M0PWM0 */
GPIO_PORTB_PCTL_R &= ~0x0F000000; /* clear alternate function for PB6 */
GPIO_PORTB_PCTL_R |= 0x04000000; /* clear alternate function of PB6 for M0PWM0 */

(b) From Table 16.1 and 16.2, we see M0PWM1 is the alternate function for pin PB7. 
GPIO_PORTB_AFSEL_R |= 0x80;  /* PB7 alternative function for M0PWM1 */
GPIO_PORTB_PCTL_R &= ~0xF0000000; /* clear alternate function for PB7 */
GPIO_PORTB_PCTL |= 0x40000000; /* clear alternate function of PB7 for M0PWM1 */

(c) From Table 16.3 and 16.4, we see M1PWM2 is the alternate function for pin PE4.
GPIO_PORTE_AFSEL_R |=  0x10;  /* PE4 alternative function for M1PWM2 */
GPIO_PORTE_PCTL_R &= ~0x000F0000; /* clear alternate function for PE4 */
GPIO_PORTE_PCTL_R |= 0x00040000; /* clear alternate function of PE4 for M1PWM2 */


Generating PWM with Microcontroller using Timer/Counter

The basic idea to generate PWM signal is using a counter (or timer), a CMP (compare) value, and a digital output pin. The counter continuously counts to up or down, and is compared with CMP value. The digital output (PWM) will be changed when the counter matches the CMP value, or when counter resets. It can be implemented by software or hardware. Most of microcontrollers already have hardware modules that can generate PWM signal after initialize the registers.

Tm4c123 pwm genertor blk.png

PWM Timer

The PWM timer in the microcontroller runs in one of two modes: Count-Down mode or Count-Up/Down mode.

In Count-Down mode, the timer counts from the Period (LOAD) value to zero, goes back to the Period (LOAD) value, and continues counting down. In Count-Up/Dow mode, the timer counts from zero up to the Period (LOAD) value, back down to zer, back up to the Period (LOAD) value, and so on. Generally, Count-Down mode is used for generating left- or right-aligned PWM signals, while the Count-Up/Down mode is used for generating center-aligned PWM signals.

Center-Aligned PWM

A center-aligned PWM implements the PWM differently from all of the other modes. The PWM timer is configured counting-up and -down mode. The counter starts at zero and count up to the Period (LOAD) vlaue, and when the Period (LOAD) value is reached, the counter starts counting back down to zero. In this mode, the Period (LOAD) value is actually half of the period of the final PWM output.

  • A single compare (CMP) value, which ciontains the duty cycle value, is constantly compared with the PWM timer (COUNTER) value. When the timer (COUNTER) value is less than the CMP value, the PWM output signal is deasserted.
  • When the timer (COUNTER) value exceeds or equal to the CMP value, the PWM output signal is asserted. When the timer (COUNTER) value reaches the Period (LOAD) value, the timer starts counting down to zero.
  • When the timer (COUNTER) value is less than or equal to the CMP value, the PWM output signal is deasserted, and the process repeats.
Pwm center aligned.gif

Left-Aligned PWM

To create the Left-Aligned PWM, a PWM timer counts downward from a specified maxmimum value, called Period (LOAD) value, to zero. When the timer counts to zero, the Period (LOAD) value will be reloaded to the timer and continue to count down..

  • When the timer (COUNTER) value is greater than the CMP value, the PWM output signal is asserted.
  • When the timer (COUNTER) value is less than or equal to the CMP value, the PWM output signal is deasserted.
  • When the timer counts to zero, the timer will reload the value from Period (LOAD) value.
Pwm left aligned.gif

Right-Aligned PWM

To create the Right-Aligned PWM, the PWM timer still runs on counting-down mode

  • When the timer (COUNTER) value is greater than the CMP value, the PWM output signal is deasserted.
  • When the timer (COUNTER) value is less than or equal to the CMP value, the PWM output signal is asserted.
  • When the timer counts to zero, the timer will reload the value from Period (LOAD) value, and the process repeats.
Pwm right aligned.gif

Dual-Edge PWM

A dual-edge PWM uses two different aligned PWM, one is right-aligned and another is left-aligned. Those two PWMs are connected to an AND gate, the output is the dual-edge PWM signal.

Dual edge pwm.gif


PWM Examples

Configuring GPIO pin for PWM

In using PWM, we must configure the GPIO pins for PWM output. In this regard, it is same as all other peripherals. The steps are as follows:

  1. Enable the clock to GPIO pin by using RCGCGPIO.
  2. Set the GPIOAFSEL (GPIO alternate function) for PWM output pins.
  3. Enable digital pins in the GPIODEN (GPIO Digital enable) register.
  4. Assign the PWM signals to specific pins using GPIOCTL register (See Tables 16.1 through 16.4).

Configuring PWM generator to create pulses

After the GPIO configuration, we need to take the following steps to configure the PWM:

  1. Disable the generator using PWM×CTL register.
  2. Configure PWM×GENA (or PWM×GENB).
  3. Load the value into PWM×LOAD register to set the desired output frequency.
  4. Load the value into PWM×CMPA (or PWMxCMPB) register to set the desired duty cycle.
  5. Start the PWM generator using PWMxCTL.
  6. Configure PWM×ENABLE register to direct the PWMx to output pin.

Source Code

  1. /* Use PWM to control LED intensity */
  2.  
  3. /* In the infinite loop, the value of CMPA register is decremented
  4.  * by 100 every 20 ms. The decreasing CMPA value causes the duty cycle
  5.  * to lengthen.
  6. */
  7.  
  8. #include <stdint.h>
  9. #include "inc/tm4c123gh6pm.h"
  10.  
  11. void delayMs(int n);
  12.  
  13. int main(void)
  14. {
  15.     int x = 15999;
  16.  
  17.     /* Enable Peripheral Clocks */
  18.     SYSCTL_RCGCPWM_R |= 2;       /* enable clock to PWM1 */
  19.     SYSCTL_RCGCGPIO_R |= 0x20;   /* enable clock to PORTF */
  20.     SYSCTL_RCC_R &= ~0x00100000; /* no pre-divide for PWM clock */
  21.  
  22.     /* Enable port PF3 for PWM1 M1PWM7 */
  23.     GPIO_PORTF_AFSEL_R = 8;      /* PF3 uses alternate function */
  24.     GPIO_PORTF_PCTL_R &= ~0x0000F000; /* make PF3 PWM output pin */
  25.     GPIO_PORTF_PCTL_R |= 0x00005000;
  26.     GPIO_PORTF_DEN_R |= 8;       /* pin digital */
  27.  
  28.     PWM1_3_CTL_R = 0;            /* stop counter */
  29.     PWM1_3_GENB_R = 0x0000008C;  /* M1PWM7 output set when reload, */
  30.                                  /* clear when match PWMCMPA */
  31.     PWM1_3_LOAD_R = 16000;       /* set load value for 1kHz (16MHz/16000) */
  32.     PWM1_3_CMPA_R = 15999;       /* set duty cycle to min */
  33.     PWM1_3_CTL_R = 1;            /* start timer */
  34.     PWM1_ENABLE_R = 0x80;        /* start PWM1 ch7 */
  35.  
  36.     for(;;) {
  37.         x = x - 100;
  38.  
  39.         if (x <= 0)
  40.             x = 16000;
  41.  
  42.         PWM1_3_CMPA_R = x;
  43.  
  44.         delayMs(20);
  45.     }
  46. }
  47.  
  48.  
  49. /* delay n milliseconds (16 MHz CPU clock) */
  50. void delayMs(int n)
  51. {
  52.     int i, j;
  53.  
  54.     for(i = 0 ; i < n; i++)
  55.         for(j = 0; j < 3180; j++)
  56.             {}  /* do nothing for 1 ms */
  57. }


  1. Write a program to generate programmable pulse-width modulated outputs.
    Use PWM0A/PB6, PLL
  2. Using M1PWM7, write a program to create 1-Khz frequency with 50% duty cycle on PF3 pin (green LED). Use System Clock of 16MHz without division. Set the options of PWMGENB register to set the output when reload and clear the output when PWMCMPA match.
  3. Generate two square waves with 50% duty cycle and 180 degrees out of phase using PWM0/PB6 and PWM1/PB7.

ADC devices

Analog-to-digital converters are among the most widely used devices for data acquisition. Digital computers use binary (discrete) values, but in the physical world everything is analog (continuous). Temperature, pressure (wind or liquid), humidity, and velocity are a few examples of physical quantities that we deal with every day.

A physical quantity is converted to electrical (voltage, current) signals using a device called a transducer. Transducers used to generate electrical outputs are also referred to as sensors. Sensors for temperature, velocity, pressure, light, and many other natural physical quantities produce an output that is voltage (or current).

Therefore, we need an analog-to-digital (ADC) converter to translate the analog signals to digital numbers so that the micro controller can read and process the numbers.

Mc sensor via adc.png
Figure 11.1: Microcontroller Connection to Sensor via ADC


8bit adc block diagram.png
Figure 11.2: An 8-bit ADC Block Diagram


Major characteristics of the ADC

Resolution

The ADC has n-bit resolution, where n can be 8, 10, 12, 16, or even 24 bits. Higher-resolution ADCs provide a smaller step size, where step size is the smallest change that can be discerned by an ADC. Some widely used resolutions for ADCs are shown in Table 11.1. Although the resolution of an ADC chip is decided at the time of its design and cannot be changed, we can control the step size with the help of what is called Vref.

n-bit Number of steps Step size
8 256 5V/256 = 19.53 mV
10 1024 5V/1024 = 4.88 mV
12 4096 5V/4096 = 1.2 mV
16 65,536 5V/65,536 = 0.076 mV
Note: Vref = 5V
Table 11.1: Resolution versus Step Size for ADC (Vref = 5V)

Vref

Vref is an input voltage used for the reference voltage. The voltage connected to this pin, along with the resolution of the ADC chip, determine the step size. For an 8-bit ADC, the step size is Vref / 256 because it is an 8-bit ADC, and 2 to the power of 8 gives us 256 steps. See Table 11.1.

  • If the analog input range needs to be 0 to 4 volts, Vref is connected to 4 volts. That gives 4 V / 256 = 15.62 mV for the step size of an 8-bit ADC.
  • If we need a step size of 10 mV for an 8-bit ADC, then Vref = 2.56 V, because 2.56 V / 256 = 10 mV.
  • For the 10-bit ADC, if the Vref = 5V, then the step size is 4.88 mV as shown in Table 11.1. Tables 11.2 and 11.3 show the relationship between the Vref and step size for the 8- and 10-bit ADCs, respectively.
  • In some applications, we need the differential reference voltage where Vref =  Vref (+) – Vref (–). Often the Vref (–) pin is connected to ground and the Vref (+) pin is used as the Vref.
Vref (V) Vin Range (V) Step Size (mV)
5.00 0 to 5 5 / 256 = 19.53
4.00 0 to 4 4 / 256 = 15.62
3.00 0 to 3 3 / 256 = 11.71
2.56 0 to 2.56 2.56 / 256 = 10
2.00 0 to 2 2 / 256 = 7.81
1.28 0 to 1.28 1.28 / 256 = 5
1.00 0 to 1 1 / 256 = 3.90
Note: In an 8-bit ADC, step size is Vref/256
Table 11.2: Vref Relation to Vin Range for an 8-bit ADC


Vref (V) Vin Range (V) Step Size (mV)
5.00 0 to 5 5 / 1024 = 4.88
4.96 0 to 4.096 4.096 / 1024 = 4
3.00 0 to 3 3 / 1024 = 2.93
2.56 0 to 2.56 2.56 / 1024 = 2.5
2.00 0 to 2 2 / 1024 = 2
1.28 0 to 1.28 1.28 / 1024 = 1.25
1.024 0 to 1.024 1.024 / 1024 = 1
Note: Vref Relation to Vin Range for an 10-bit ADC
Table 11.3: Vref Relation to Vin Range for an 10-bit ADC

Conversion time

Conversion time is defined as the time it takes the ADC to convert the analog input to a digital number. The conversion time is dictated by the clock source connected to the ADC in addition to the method used for data conversion and technology used in the fabrication of the ADC.

Digital data output

In an 8-bit ADC we have an 8-bit digital data output of D0–D7, while in the 10-bit ADC the data output is D0–D9. To calculate the output voltage, we use the following formula:

DOUT = VIN / Step size

where Dout = digital data output (in decimal), Vin = analog input voltage, and step size (resolution) is the smallest change, which is Vref/256 for an 8-bit ADC.

Parallel versus Serial ADC

The ADC chips are either parallel or serial. In parallel ADC, we have 8 or more pins dedicated to bringing out the binary data, but in serial ADC we have only one pin for data out. The D0–D7 data pins of the 8-bit ADC provide an 8-bit parallel data path between the ADC chip and the CPU. In the case of the 16-bit parallel ADC chip, we need 16 pins for the data path.

In order to save pins, many 12- and 16-bit ADCs use pins D0–D7 to send out the upper and lower bytes of the binary data. In recent years, for many applications where space is a critical issue, using such a large number of pins for data is not feasible. For this reason, serial devices such as the serial ADC are becoming widely used. While the serial ADCs use fewer pins and their smaller packages take much less space on the printed circuit board, more CPU time is needed to get the converted data from the ADC because the CPU must get data one bit at a time, instead of in one single read operation as with the parallel ADC.

Analog input channels

Many data acquisition applications need more than one analog input for ADC. For this reason, we see ADC chips with 2, 4, 8, or even 16 channels on a single chip. Multiplexing of analog inputs is widely used allowing us to monitor multiple quantities such as temperature, pressure, flow, and so on. Nowadays, some ARM microcontroller chips come with 16-channel on-chip ADC.

Start conversion and end-of-conversion signals

For the conversion to be controlled by the CPU, there are needs for start conversion (SC) and end-of-conversion (EOC) signals. When SC is activated, the ADC starts converting the analog input value of Vin to a digital number. The amount of time it takes to convert varies depending on the conversion method. When the data conversion is complete, the end-of-conversion signal notifies the CPU that the converted data is ready to be picked up.


ADC Modules in the TM4C123GH6PM MCU System

The TM4C123GH6PM microcontroller contains two identical Analog-to-Digital Converter modules. These two modules, ADC0 and ADC1, provide 12-bit conversion precision and share the same 12 analog input channels. Each ADC module operates independently and can therefore execute different sample sequences, sample any of the analog input channels at any time, and generate different interrupts and triggers.

These two ADC modules provide the following features:

  • 12 shared analog input channels
  • 12-bit precision ADC
  • Single-ended and differential-input configurations
  • On-chip internal temperature sensor
  • Maximum sample rate of one million samples/second (MSPS)
  • Optional phase shift in sample time programmable
  • Four programmable sample conversion sequencers from one to eight entries long, with corresponding conversion result FIFOs
  • Five flexible trigger controls
    • Software Trigger Controller (default)
    • Timers
    • Analog Comparators
    • PWM
    • GPIO
  • Hardware averaging of up to 64 samples
  • 2 Analog Comparators

ADC Programming with the Tiva TM4C123G

To program these two modules, ADC0 and ADC1, we need to understand some of the major registers. Figure 11.21 shows a simplified block diagram of a Tiva ADC module.

Tm4c adc module.png
Figure 11.21: Simplified Block Diagram of a TI ADC Module

Enabling Clock to ADC

First thing we need to do is to enable the clock to the ADC0 or ADC1. Bit 0 and bit 1 of RCGCADC register are used to enable the clock to ADC0 and ADC1 modules, respectively. The RCGCADC is part of the System Control register and is located at base address of 0x400F.E000 with offset 0x638. That means, the RCGCADC is located at physical address of 0x400FE638 (0x400FE000 + 0x638 = 0x400FE638) in memory map. See Figure 11.22.

Tm4c rcgcadc r.png


bit Name Description
0 R0 0: ADC Module 0 is disabled, 1: Enable and provide a clock to ADC module 0
1 R1 0: ADC Module 1 is disabled, 1: Enable and provide a clock to ADC module 1
Figure 11.22: ADC Run Mode Clock Gating Control (RCGCADC)

The Sample Sequencer

The Sample Sequencer is a part of the ADC module that moves the conversion result of the ADC to one of the FIFOs. There are 4 Sample Sequencers. They are called SS3, SS2, SS1, and SS0. Each one of them is associated with a FIFO. The FIFOs have different sizes so the sample sequencers have different lengths of sequences. The longest sequence has 8 samples and the shortest has only one. Table 11.10 shows the relation between the sample sequencers and FIFO sizes.

Sequencer Number of
Samples
Depth of FIFO
SS0 8 8
SS1 4 4
SS2 4 4
SS3 1 1
Table 11.10: Samples and FIFO Depth of Sequencers

We will use the SS3 with a single sample. We use ADCACTSS (ADC Active Sample Sequencer) to enable the SS3. When bit 3 (ASEN3) is set to 1 the SS3 is enabled. We must disable the SS3 before configuring the sample sequencer so that no erroneous events occur during initialization. After the initialization is done, we must enable it to use it.

Tm4c adcactss r.png
Figure 11.23: ADC Active Sample Sequencer (ADCACTSS)
Bit Name Description
16 BUSY ADC Busy
0: ADC is idle, 1: ADC is busy
3 ASEN3 ADC SS3 Enable
0: Sample Sequencer 3 is disabled, 1: Sample Sequencer 3 is enabled.
2 ASEN2 ADC SS2 Enable
0: Sample Sequencer 2 is disabled, 1: Sample Sequencer 2 is enabled.
1 ASEN1 ADC SS1 Enable
0: Sample Sequencer 1 is disabled, 1: Sample Sequencer 1 is enabled.
0 ASEN0 ADC SS0 Enable
0: Sample Sequencer 0 is disabled, 1: Sample Sequencer 0 is enabled.

Start Conversion trigger options

There are many start-conversion (trigger) options. Among them are using Timer, PWM, Analog Comparator, External signal from GPIO, and Software. The selection of Trigger for SS3 is done via the bits 15-12 of ADCEMUX register. The default is Software and that is what we use in this section.

Tm4c adcemux r.png
Figure 11.24: ADC Event Multiplexer Select (ADCEMUX)

EMx bits select the trigger source for Sample Sequencer x. By default the field is 0x0 which means the ADC conversion begins when the SSn bit of the ADCPSSI register is set by software. The following table shows the available choices for trigger.

EMx Value Trigger source
0x0 Processor (default)
0x1 Analog Comparator 0
0x2 Analog Comparator 1
0x3 reserved
0x4 External (GPIO Pins)
0x5 Timer
0x6 PWM Generator 0
0x7 PWM Generator 1
0x8 PWM Generator 2
0x9 PWM Generator 3
0xF Always (continuously sample)
Table 11.11: ADC Event Multiplexer Select (ADCEMUX)

After we select the software option bit (which is the default) in the ADCEMUX, we must use bit D3 of ADCPSSI register to start a conversion every time we want a new reading from the ADC input channel.

Tm4c adcpssi r.png
SSx Value Trigger source
0 No Effect
1 Begin sampling on sample sequence x
Figure 11.25: ADC Processor Sample Sequence Initiate (ADCPSSI)

Notice that we can trigger the SS3 option only if we have enabled the SS3 in the ADCACTSS register.

Choosing Vin input channel

The channel selection is done through the ADCSSMUXn (n=0, 1, 2, 3) registers. For the SS3, the ADCSSMUX3 is used. Since SS3 only handles single conversion, bits 3 – 0 are used to specify the analog channel to be converted. The number of available channels in the TI Tiva TM4C123G varies among the family members. In the case of TI Tiva TM4C123GH6PM, there are 12 channels. They are designated as AIN0 (analog input 0) to AIN11 (analog input 11). Their designated pins are shown in Table 11.12.

Pin
Name
Description Pin Pin
Number
AIN0 ADC input 0 PE3 6
AIN1 ADC input 1 PE2 7
AIN2 ADC input 2 PE1 8
AIN3 ADC input 3 PE0 9
AIN4 ADC input 4 PD3 64
AIN5 ADC input 5 PD2 63
AIN6 ADC input 6 PD1 62
AIN7 ADC input 7 PD0 61
AIN8 ADC input 8 PE5 60
AIN9 ADC input 9 PE4 59
AIN10 ADC input 10 PB4 58
AIN11 ADC input 11 PB5 57
Table 11.12: Analog input pin assignment in TI Tiva TMC123GH6PM


Tm4c adcssmux3 r.png
bit Name Desription
0-3 MUX0 Sample Input Select
Figure 11.26: ADC Sample Sequence Input Multiplexer Select 3 (ADCSSMUX3)

Polling or interrupt

The end-of-conversion is indicated by a flag bit in the ADCRIS (ADC Raw Interrupt) register. Upon the completion of conversion for the SS3, the D3 bit (INR3) flag goes high. By polling this flag, we know if the conversion is complete and we can read the value in ADCSSFIFO3 register. We can also use an interrupt to inform us that the conversion is complete but that will require us to set up the interrupt mask ADCIM. By default, the interrupts are not enabled.

Tm4c adcris r.png


bit Name Discription
0 INR0 SSO Raw Interrupt Status
0:An interrupt has not occured
1: A sample has completed conversion and respective ADCSSCTL0
len bit is set, enabling a raw interrupt.
Note: This bit is cleared by writing a 1 to the IN0 bit in the ADCISC register.
1 INR1 SS1 Raw Interrupt Status
2 INR2 SS2 Raw Interrupt Status
3 INR3 SS3 Raw Interrupt Status
16 INRDC Digital Comparator Raw Interrupt Status
0: All bits in the ADCDCISC register are clear.
1: At least one bit in the ADCDCISC register is set,
meaning that a digital comparator interrupt has occurred.
Figure 11.27: ADC Raw Interrupt Status (ADCRIS)

ADC Data result

Upon the completion of conversion, the binary result is placed in the ADCSSFIFOn register. Since we are using SS3, we need to read the result from ADCSSFIFO3 register. This is 32-bit register but only the lower 12 bits are used.

Tm4c adcssfifon.png
bit Name Description
0-11 DATA Conversion Result Data
Figure 11.28: ADC Sample Sequence Result FIFO 3 (ADCSSFIFO3)

Clearing end-of-conversion flag

After reading the data from the ADCSSFIFOx register, we must clear the INR3 flag bit in ADCRIS register so that we may detect another conversion complete. The raw interrupt flag in ADCRIS is cleared by writing to ADCISC (ADC Interrupt Status and Clear) register. By writing a 1 to bit 3 (IN3 bit) of ADCISC, the interrupt flag is cleared and we can do another conversion again.

Tm4c adcisc r.png
bit Name Description
0-3 INx SSx Interrupt Status and Clear
0: No Interrupt has occurred or the interrupt is masked
1: A sample has completed conversion (the INRx bit in the ADCRIS register is set)
and the MASKx bit in the ADCIM register is set, providing an interrupt to the
interrupt controller.
Note: This bit is cleared by writing a 1. Clearing the bit also clears the INRx bit in
the ADCRIS register.
16
to
19
DCINSSx Digital Comparator Interrupt Status on SSx
0:No Interrupt has occurred or the interrupt is masked
1: Both the INRDC bit in the ADCRIS register and the DCONSSx bit in the ADCIM
register are set providing an interrupt to the interrupt controller.
Note: This bit is cleared by writing a 1. Clearing the bit also clears the INRDC
bit in the ADCRIS register.
Figure 11.29: ADC Interrupt Status and Clear (ADCISC)

Differential versus Single-Ended

In some applications, our interest is in the differences between two analog signal voltages (the differential voltages). Rather than converting two channels and calculate the differences between them, the Tiva TM4C123G has the option of converting the differential voltages of two analog channels. The bit 0 of ADCSSCTL3 (ADC Sample sequence Control 3) register allows us to enable the differential option. Upon Reset, the default is the single-ended input. The pairing of the analog inputs for differential is hardwired. Table 11.13 shows the pairing of the ADC input channels for differential option.

Differential Pair Analog Inputs
0 0 and 1
1 2 and 3
2 4 and 5
3 6 and 7
4 8 and 9
5 10 and 11
Table 11.13: ADC channel pairing for differential

The other bits in ADCSSCTL3 register are bit 1 (END0), bit 2 (IE0), and bit 3 (TS) bits. On some of the ADC inputs, we have an internal temperature sensor embedded into the chip. Making bit 3 = 1, reads the temperature sensor value inside the chip itself. Since we are using one sample in the SSE3, we must enable the bit 1 (END0) to let ADC know that first sample is the only sample and there is no sample coming after that. Bit 2 (IE0) is the Interrupt enable. It causes the raw interrupt flag to set when this sample conversion is completed. However, in order to redirect the end-of-conversion to the NVIC interrupt controller, we must also enable the bit in ADCIM register, as we will see soon. It must be noted, even if we do not want to use interrupt, we must still set IE0 = 1, in order to post the raw interrupt flag for polling the conversion complete.

Tm4c adcssctl3 r.png
bit Name Description
0 D0 Sample Differential Input Select
0: The analog inputs are not differentially sampled
1: The analog inputs are differentially sampled. The corresponding
ADCSSMUX nibble must be set to the pair number "i", where the
paired inputs are 2i and 2i+1.
Note: Because the temperature sensor doesn't have a differential option
this bit must not be set when the TS0 bit is set.
1 END0 End of Sequence:
This bit must be set before initiating a single sample sequence.
0: Sampling and conversion continues
1: This is the end of the sequence.
2 IE0 Sample Interrupt Enable
0: The raw interrupt is not asserted to the interrupt controller
1: The raw interrupt signal (INR0 bit) is asserted at the end of this sample's
conversion. If the MASK0 bit in the ADCIM register is set, the interrupt is
promoted to the interrupt controller.
It is legal to have multiple samples with in a sequence generate interrupts.
3 TS0 1st Sample Temperature Sensor Select
0: The input pin specified by the ADCSSMUXn register is read during the
first sample of the sample sequence.
1: The temperature sensor is read during the first sample
sequence.
Table 11.14: ADC Sample Sequence Control 3 (ADCSSCTL3)

Masking interrupt for SS3

Since we are using polling for the end-of-conversion, we must mask the interrupt option for the SS3 to prevent it from interrupting us via NVIC. This is done with bit 3 of ADCIM (ADC Interrupt Mask) register. Upon Reset, the default for the bit 3 (MASK3) is 0. With the MASK3 = 0, it disables the interrupt and we will leave it like that. However, if we like to handle end-of-conversion by interrupt, we need to set this bit to 1 and write an interrupt handler to read the conversion result.

Tm4c adcim r.png
bit Name Description
0-3 MASKx SSx Interrupt Mask
0: The Status of Sample Sequencer x doesn't affect the SSx Interrupt Status.
1. The raw interrupt signal from Sample Sequencer x (ADCRIS register INRx bit)
is sent to the interrupt controller.
16
to
19
DCONSSx Digital Comparator Interrupt on SSx
0: The status of the digital comparators doesn't affect the SSx interrupt status.
1: The raw Interrupt signal from digital comparators (INRDC bit in the ADCRIS
register) is sent to the interrupt controller on the SSx interrupt line.
Figure 11.30: ADC Interrupt Mask (ADCIM)

Vref in Tiva LaunchPad

In the TI ARM Tiva chip series, the pin for Vref (+) is called VDDA (VDD analog) and Vref (-) pin is called GNDA (Ground Analog). In the TI Tiva LaunchPad, the VDDA pin is connected to 3.3V, the same supply voltage as the digital part of the chip.

Even if we connect the VDDA to a separate power source other than the VDD of the chip, it cannot go beyond the VDD voltage. With Vref=3.3V, we have the step size of 3.3V / 4096 = 0.8057 mV since the ADC resolution is 12 bits.

Operational Procedure for ADC

Each ADC module contains four sample sequencers, SS0 - SS3. Each sample can be obtained from different input sources (different channels). These sample sequencers are under the control of some control registers in the Control/Status block. The operational procedure of each ADC module includes:

  1. Each ADC module must be clocked by configuring the ADC Clock Configuration (ADCCC) register before it works since all ADC modules share the same clock source to facilitate the synchronization of data samples between conversion units.
  2. Before the ADC can start its conversion, the sample sequencers must be configured by related registers in each sample sequencer block, such as ADC Sample Sequence Input Multiplexer Select n (ADCSSMUXn) and ADC Sample Sequence Control n (ADCSSCTLn) registers.
  3. Then the sample sequencers must be enabled by configuring the ADC Active Sample Sequencer (ADCACTSS) register. If multiple triggering events were used, the ADC Sample Sequencer Priority (ADCSSPRI) register must also be configured.
  4. The trigger source or trigger event must be determined by configuring the ADC Event Multiplexer Select (ADCEMUX) register, and the sampling process must be initiated by setting up the ADC Processor Sample Sequence Initiate (ADCPSSI) register.
  5. Optionally, one can use the ADC Peripheral Property (ADCPP) register to set up the resolution, include the temperature sensor, and set the ADC sample rate. Generally, you do not need to touch this register and only use the default settings of this register.
  6. The ADC Trigger Source Select (ADCTSSEL) register is used to select a PWM generator as the trigger source when the PWM generator is used.
  7. After the analog input channel and sample property have been determined by ADCSSMUXn, ADCSSCTLn registers, the ADC conversion starts. After the ADC conversion is complete, the conversion results can be obtained from the ADC Sample Sequence Result FIFO (ADCSSFIFOn) registers.
  8. If interrupts are used for any ADC conversion, some registers in the Interrupt Control block should also be configured.

The Hardware Averager is used to make the ADC conversion results smoother by averaging some continuous samples. The Digital Comparator is used to compare the ADC conversion results with some predefined values to monitor and control the external signals.


Using ADC0 to convert input from AIN0

Configuring GPIO for ADC input

In using ADC, we must also configure the GPIO pins to allow the connection of an analog signal through the input pin. In this regard, it is the same as all other peripherals. The steps are as follows:

  1. Enable the clock to GPIO pin by using RCGCGPIO.
  2. Set the GPIOAFSEL (GPIO alternate function) bit for ADC input pin to 1.
  3. Configure AINx signal to be used as analog input by clearing the bit in the GPIODEN (GPIO Digital enable) register.
  4. Disable the Analog isolation circuit for ADC input pins by writing a 1 to the GPIOAMSEL register.

Configuring ADC and reading ADC channel

After the GPIO configuration, we need to take the following steps to configure the ADC for Sample Sequencer 3 (SS3):

  1. Enable the clock to ADC0 or ADC1 modules using RCGCADC register of System Registers.
    The SYSCTL_RCGCADC_R |= 3 will enable the clock to both ADC0 and ADC1 modules. For ADC0 module use SYSCTL_RCGCADC_R |= 1
  2. Disable the Sample Sequencer using the ADCACTSS register before changing the configuration of the sequencer.
    ADC0_ACTSS_R &= ~8 disables the SS3.
  3. Choose the software trigger using the ADCEMUX register.
    Use ADC0_EMUX_R &= ~0xF000 for software trigger.
  4. Select the ADC input channel using the ADCSSMUXn register. In the case of SS3 we use the ADCSSMUX3.
    For example, The ADC0_SSMUX3_R = 0 selects AIN0 channel on pin PE3.
  5. Select the single-ended option, one-conversion per sample, and raw interrupt bit for end-of-conversion using the ADCSSCTL3 register.
    Use ADC0_SSCTL3_R |= 6 for single-ended, one-conversion, and raw interrupt.
  6. Enable the Sample Sequencer SS3 using ADCACTSS register.
    ADC0_ACTSS_R |= 8 enables the SS3.
  7. Use ADCPSSI register to start a new conversion.
    Use ADC0_PSSI_R |= 8 to start a conversion by Sample Sequencer 3.
  8. Keep monitoring the end-of-conversion INR3 flag in ADCRIS (ADC0_RIS_R) register.
  9. When the INR3 goes HIGH, read the ADC result from the ADCSSFIFO3 (ADC0_SSFIFO3_R) and save it.
  10. After reading the ADC result in step 9, clear the INR3 flag in ADCRIS register to allow for the next conversion.
    To clear INR3 flag, write to ADCICS register with ADC0_ISC_R = 8.
  11. Repeat steps 7 through 10 for the next conversion.


Tm4c adc prog1 connection.png
Figure 11.31: ADC Connection for the following Program

Source Code

  1. /* A to D conversion
  2.  *
  3.  * This program converts the analog input from AIN0 (J3.9 of LaunchPad)
  4.  * using sample sequencer 3 and software trigger continuously.
  5.  *
  6.  * Note: AIN0 channel is on PE3 pin.
  7.  *
  8.  */
  9.  
  10. #include <stdint.h>
  11. #include "inc/tm4c123gh6pm.h"
  12.  
  13. int main(void)
  14. {
  15.     volatile int result;
  16.  
  17.     /* enable clocks */
  18.     SYSCTL_RCGCGPIO_R |= 0x10; /* enable clock to PE (AIN0 is on PE3) */
  19.     SYSCTL_RCGCADC_R |= 1;     /* enable clock to ADC0 */
  20.  
  21.     /* initialize PE3 for AIN0 input  */
  22.     GPIO_PORTE_AFSEL_R |= 8;   /* enable alternate function */
  23.     GPIO_PORTE_DEN_R &= ~8;    /* disable digital function */
  24.     GPIO_PORTE_AMSEL_R |= 8;   /* enable analog function */
  25.  
  26.     /* initialize ADC0 */
  27.     ADC0_ACTSS_R &= ~8;        /* disable SS3 during configuration */
  28.     ADC0_EMUX_R &= ~0xF000;    /* software trigger conversion */
  29.     ADC0_SSMUX3_R = 0;         /* get input from channel 0 */
  30.     ADC0_SSCTL3_R |= 6;        /* take one sample at a time, set flag at 1st sample */
  31.     ADC0_ACTSS_R |= 8;         /* enable ADC0 sequencer 3 */
  32.  
  33.     while(1) {
  34.         ADC0_PSSI_R |= 8;      /* start a conversion sequence 3 */
  35.         while((ADC0_RIS_R & 8) == 0)
  36.             ;                  /* wait for conversion complete */
  37.         result = ADC0_SSFIFO3_R; /* read conversion result */
  38.         ADC0_ISC_R = 8;        /* clear completion flag */
  39.     }
  40. }

Note

  • Short 3 & 4 of J7 on the EduARM4 Trainer Board
  • To change the input voltage to the ADC, Vary the RV2 potentiometer.


Timer Trigger ADC conversion

For digital signal processing, not only the precision of the ADC conversion result is important, the precision of the time that the analog input is sampled is also important. Using software trigger conversion does not yield precision timing especially when there are other software tasks running at the same time. One way of getting precision sampling timing interval is to use the timer to trigger the conversion. To do so:

  1. Configure the ADC to use timer trigger
    The four bits of ADCEMUX register for the sample sequencer used should be loaded with the value of 5 for timer trigger.
  2. Configure a timer to generate periodic timeout
    The periodic timer function is covered here.
  3. Connect timer to ADC trigger.
    To connect the timer to ADC trigger, the TAOTE or TBOTE bit of the GPTMCTL should be set to 1.

The most accurate sampling method is timer-triggered sampling (EM3=0x5). On the TM4C123, the MUX fields are 4 bits wide, allowing us to specify channels 0 to 11. The following are the steps to configure the ADC to sample a single channel at a periodic rate:

  1. Enable the ADC clock in the SYSCTL_RCGCADC_R register.
  2. Bits 3 – 0 of the ADC0_PC_R register specify the maximum sampling rate of the ADC. Set the maximum sampling rate at 125 kHz. This will require less power and produce a longer sampling time, creating a more accurate conversion.
  3. Set the priority of each of the four sequencers. Use just one sequencer, so the priorities are irrelevant, except for the fact that no two sequencers should have the same priority. The default configuration has Sample Sequencer 0 with the highest priority, and Sample Sequencer 3 as the lowest priority.
  4. Configure the timer to run at the desired sampling frequency. Enable the Timer0 clock by setting bit 0 of the SYSCTL_RCGCTIMER_R register. First set bit 5 of the TIMER0_CTL_R register to activate TAOTE, which is the Timer A output trigger enable. Secondly, do not arm any Timer0 interrupts. The rate at which the timer rolls over determines the sampling frequency. Let prescale be the value loaded into TIMER0_TAPR_R, and let period be the value loaded into TIMER0_TAILR_R. If the period of the bus clock frequency is t, then the ADC sampling period will be t *(prescale + 1)*(period + 1). The fastest sampling rate is determined by the speed of the processor handling the ADC interrupts and by the speed of the main program consuming the data from the FIFO. If the bus clock is 80 MHz, the slowest possible sampling rate for this example is 80MHz/232, which is about 0.018 Hz, which is every 55.56 seconds.
  5. Before configuring the sequencer, we need to disable it. To disable sequencer 3, we write a 0 to bit 3 (ASEN3) in the ADC0_ACTSS_R register. Disabling the sequencer during programming prevents erroneous execution if a trigger event were to occur during the configuration process.
  6. Configure the trigger event for the sample sequencer in the ADC0_EMUX_R register. For this example, we write a 0101 to bits 15–12 (EM3) specifying timer trigger mode for sequencer 3.
  7. For each sample in the sample sequence, configure the corresponding input source in the ADC0_SSMUXn register. In this example, we write the channel number (0, 1, 2, or 3) to bits 3–0 in the ADC0_SSMUX3_R register.
  8. For each sample in the sample sequence, Configure the sample control bits in the corresponding nibble in the ADC0_SSCTLn register. When programming the last nibble, ensure that the END bit is set. Failure to set the END bit causes unpredictable behavior. Sequencer 3 has only one sample, so we write a 0110 to the ADC0_SSCTL3_R register. Bit 3 is the TS0 bit, which we clear because we are not measuring temperature. Bit 2 is the IE0 bit, which we set because we want to request an interrupt when the sample is complete. Bit 1 is the END0 bit, which is set because this is the last (and only) sample in the sequence. Bit 0 is the D0 bit, which we clear because we do not wish to use differential mode.
  9. If interrupts are to be used, write a 1 to the corresponding mask bit in the ADC0_IM_R register. We want an interrupt to occur when the conversion is complete (set bit 3, MASK3).
  10. We enable the sample sequencer logic by writing a 1 to the corresponding ASENn. To enable sequencer 3, we write a 1 to bit 3 (ASEN3) in the ADC0_ACTSS_R register.
  11. The priority of the ADC0 sequencer 3 interrupts are in bits 13–15 of the NVIC_PRI4_R register.
  12. Since we are requesting interrupts, we need to enable interrupts in the NVIC. ADC sequencer 3 interrupts are enabled by setting bit 17 in the NVIC_EN0_R register.
  13. Lastly, we must enable interrupts in the PRIMASK register.

The timer starts the conversion at a regular rate. Bit 3 (INR3) in the ADC0_RIS_R register will be set when the conversion is done. This bit is armed and enabled for interrupting, so conversion complete will trigger an interrupt. The IN3 bit in the ADC0_ISC_R register triggers the interrupt. The ISR acknowledges the interrupt by writing a 1 to bit 3 (IN3). The 12-bit result is read from the ADC0_SSFIFO3_R register.


Temperature sensor

There is an internal temperature sensor embedded into the TI ARM Tiva chip. This gives us the temperature inside the ARM chip itself. The temperature sensor does not have any separate enable control, because it also contains the band-gap reference and must always be enabled. The reference is also supplied to other analog modules, not just the ADC. In addition, the temperature sensor has a second power-down input in the 3.3V domain which provides control by the Hibernation module.

The internal temperature sensor converts a temperature measurement into a voltage. This voltage value, VTSENS, is given by the following equation (where TEMP is the temperature in °C):

VTSENS = 2.7 - ((TEMP + 55)/75)

The temperature sensor reading can be sampled in a sample sequencer by setting the TSn bit in the ADCSSCTLn register. The temperature reading from the temperature sensor can also be given as a function of the ADC value. The following formula calculates temperature (TEMP in °C) based on the ADC reading that is an ADC_output given as an unsigned decimal number from 0 to 4095 and the maximum ADC voltage range (Vref(+) Vref(–)):

Temp = 147.5 – ((75 × Vref(+) – Vref(–)) × ADC_output)) / 4096

Since the Vref = 3.3 V in TI Tiva Launchpad, we have:

Temp = 147.5 – ((75 × 3.3V) × ADC_output) / 4096
Temp = 147.5 – (247.5 × ADC_output) / 4096

Example: Find the temperature inside the ARM chip for the TI Tiva Launchpad if the reading of ADC output is = 0x7D0.
Solution: The 0x7D0 is 2000 in decimal. Now, we have

Temp = 147.5 – (247.5x2000) / 4096 = 147.5 – 120.85 = 26.6 Celsius

Source Code

  1. /* Convert on-chip temperature
  2.  *
  3.  * Runs on TM4C123 LaunchPad
  4.  *
  5.  * This program converts the on-chip temperature sensor output using
  6.  * sample sequencer 3 and timer trigger at 1 Hz.
  7.  *
  8. */
  9.  
  10. #include <stdint.h>
  11. #include "inc/tm4c123gh6pm.h"
  12.  
  13. int main(void)
  14. {
  15.     volatile int temperature;
  16.  
  17.     /* enable clocks */
  18.     SYSCTL_RCGCADC_R |= 1;       /* enable clock to ADC0 */
  19.     SYSCTL_RCGCWTIMER_R |= 1;    /* enable clock to WTimer Block 0 */
  20.  
  21.     /* initialize ADC0 */
  22.     ADC0_ACTSS_R &= ~8;          /* disable SS3 during configuration */
  23.     ADC0_EMUX_R &= ~0xF000;
  24.     ADC0_EMUX_R |= 0x5000;       /* timer trigger conversion seq 0 */
  25.     ADC0_SSMUX3_R = 0;           /* get input from channel 0 */
  26.     ADC0_SSCTL3_R |= 0x0E;       /* take chip temperature, set flag at 1st sample */
  27.     ADC0_ACTSS_R |= 8;           /* enable ADC0 sequencer 3 */
  28.  
  29.     /* initialize wtimer 0 to trigger ADC at 1 sample/sec */
  30.     WTIMER0_CTL_R = 0;           /* disable WTimer before initialization */
  31.     WTIMER0_CFG_R = 0x04;        /* 32-bit option */
  32.     WTIMER0_TAMR_R = 0x02;       /* periodic mode and down-counter */
  33.     WTIMER0_TAILR_R = 16000000;  /* WTimer A interval load value reg (1 s) */
  34.     WTIMER0_CTL_R |= 0x20;       /* timer triggers ADC */
  35.     WTIMER0_CTL_R |= 0x01;       /* enable WTimer A after initialization */
  36.  
  37.     while(1) {
  38.         while((ADC0_RIS_R & 8) == 0)
  39.             ;                    /* wait for conversion complete */
  40.         temperature = 147 - (247 * ADC0_SSFIFO3_R) / 4096;
  41.         ADC0_ISC_R = 8;          /* clear completion flag */
  42.     }
  43. }


  1. Write software to sample a single channel at a periodic rate
    Set the maximum sampling rate at 125K samples/sec
  2. Write software to sample ADC channels 4 and 5 at 1 Khz
    Channel 4 on the TM4C123 is PD3 and channel 5 is PD2.