NOTE: TI renamed Stellaris LM4F232H5QD to Tiva C Series TM4C123GH6PGE - Both these part numbers refer to the same chip. StellarisWare is now superseded by/renamed to TivaWare 2.0. The LM4F232 USB+CAN Evaluation Kit is now rebranded as Tiva™ C Series TM4C123G USB+CAN Development Kit. This blog post refers to the old StellarisWare (SW-LM3S-9107(Stellarisware).exe) and old CodeComposer Studio (CCS5.2.1.00018_win32) and the old part numbers for the microcontroller chip and the evaluation kit.
The Texas Instruments Stellaris LM4F232H5QD Evaluation Board is supplied with uart_echo project (C:\StellarisWare\boards\ek-lm4f232\uart_echo) which shows how to use UART0. The UART0 appears on the computer as a virtual serial port. The PA0/PA1 pins which act as the TX/RX pins of UART0 are connected to the computer via the on board In-Circuit Interface.
If we want to use UART1 instead of UART0, the code must be modified accordingly.
A special point worth noting is that UART1's TX/RX signals can be made available on 2 pairs of pins: PC4/PC5 or PB0/PB1. We need to tell the microcontroller which of the pairs to use explicitly.
To use UART1, you will need a USB-to-Serial board like the one based on FT232RL available from Sparkfun. You can hook up the board to the Evaluation Kit as shown:
The following steps will not only show you the code for accessing UART1 but also show you how to create and configure a new CodeComposer Project. You will need a Windows PC - I used Windows 7 32bit edition.
The Texas Instruments Stellaris LM4F232H5QD Evaluation Board is supplied with uart_echo project (C:\StellarisWare\boards\ek-lm4f232\uart_echo) which shows how to use UART0. The UART0 appears on the computer as a virtual serial port. The PA0/PA1 pins which act as the TX/RX pins of UART0 are connected to the computer via the on board In-Circuit Interface.
If we want to use UART1 instead of UART0, the code must be modified accordingly.
A special point worth noting is that UART1's TX/RX signals can be made available on 2 pairs of pins: PC4/PC5 or PB0/PB1. We need to tell the microcontroller which of the pairs to use explicitly.
To use UART1, you will need a USB-to-Serial board like the one based on FT232RL available from Sparkfun. You can hook up the board to the Evaluation Kit as shown:
PC4 of LM4F232H5QD is connected to TX-O of FT232 PC5 of LM4F232H5QD is connected to RX-I of FT232 |
- Install Code Composer Studio from the Disc supplied with the kit. When asked for the Processor Support, select "Stellaris Cortex M MCUs". Leave all other options at default.
- Install StellarisWare. It will be installed to C:\StellarisWare
- Connect the LM4F232H5QD Evaluation Board to the Computer. Use the USB ICD miniUSB connector on the evaluation board.
- Windows won't be able to locate the drivers for the same. You will have to manually specify the location for the driver. The drivers can be found at: "C:\ti\ccsv5\ccs_base\emulation\drivers\stellaris\icdi"
- You will have to perform the driver installation process three times as the USB device enumerates as three separate devices. Use the Windows device manager to do this:
- Connect the FT232 board to the computer and install the driver for it. Use HyperTerminal/ Bray's Terminal/TeraTerm or PuTTY to open the corresponding COM Port at 115200 8-N-1. We will use it shortly.
- Start CodeComposer Studio. A new workspace will be created.
- Select File>New>CCS Project to create a new project with the following settings:
- Project name: uart1_echo
- Family: ARM
- Variant: Cortex M | Stellaris LM4F232H5QD
- Connection: Stellaris In-Circuit Debug Interface
- Template: Empty Project (with main.c)
- Replace the content of main.c with the following lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
#include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/debug.h" #include "driverlib/fpu.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "driverlib/rom.h" #include "grlib/grlib.h" #include "drivers/cfal96x64x16.h" #ifdef DEBUG void __error__(char *pcFilename, unsigned long ulLine) { } #endif void UARTIntHandler(void) { unsigned long ulStatus; // Get the interrrupt status. ulStatus = ROM_UARTIntStatus(UART1_BASE, true); // Clear the asserted interrupts. ROM_UARTIntClear(UART1_BASE, ulStatus); // Loop while there are characters in the receive FIFO. while (ROM_UARTCharsAvail(UART1_BASE)) { // Read the next character from the UART and write it back to the UART. ROM_UARTCharPutNonBlocking(UART1_BASE, ROM_UARTCharGetNonBlocking(UART1_BASE)); } } // Send a string to the UART. void UARTSend(const unsigned char *pucBuffer, unsigned long ulCount) { // Loop while there are more characters to send. while (ulCount--) { // Write the next character to the UART. ROM_UARTCharPutNonBlocking(UART1_BASE, *pucBuffer++); } } // This example demonstrates how to send a string of data to the UART. int main(void) { tRectangle sRect; tContext sContext; // Enable lazy stacking for interrupt handlers. This allows floating-point // instructions to be used within interrupt handlers, but at the expense of // extra stack usage. ROM_FPULazyStackingEnable(); // Set the clocking to run directly from the crystal. ROM_SysCtlClockSet( SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Initialize the display driver. CFAL96x64x16Init(); // Initialize the graphics context. GrContextInit(&sContext, &g_sCFAL96x64x16); // Fill the top part of the screen with blue to create the banner. sRect.sXMin = 0; sRect.sYMin = 0; sRect.sXMax = GrContextDpyWidthGet(&sContext) - 1; sRect.sYMax = 9; GrContextForegroundSet(&sContext, ClrDarkBlue); GrRectFill(&sContext, &sRect); // Change foreground for white text. GrContextForegroundSet(&sContext, ClrWhite); // Put the application name in the middle of the banner. GrContextFontSet(&sContext, g_pFontFixed6x8); GrStringDrawCentered(&sContext, "uart-echo", -1, GrContextDpyWidthGet(&sContext) / 2, 4, 0); // Initialize the display and write some instructions. GrStringDrawCentered(&sContext, "Connect a", -1, GrContextDpyWidthGet(&sContext) / 2, 20, false); GrStringDrawCentered(&sContext, "terminal", -1, GrContextDpyWidthGet(&sContext) / 2, 30, false); GrStringDrawCentered(&sContext, "to UART1.", -1, GrContextDpyWidthGet(&sContext) / 2, 40, false); GrStringDrawCentered(&sContext, "115000,N,8,1", -1, GrContextDpyWidthGet(&sContext) / 2, 50, false); // Enable the peripherals used by this example. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); // Enable processor interrupts. ROM_IntMasterEnable(); // Set GPIO C4 and C5 as UART pins. ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5); // Extra setting for UART1 // Because UART1 can be routed to either PC4/PC5 or PB0/PB1 // So you have to select where to route it to ROM_GPIOPinConfigure(GPIO_PC4_U1RX); ROM_GPIOPinConfigure(GPIO_PC5_U1TX); // Configure the UART for 115,200, 8-N-1 operation. ROM_UARTConfigSetExpClk(UART1_BASE, ROM_SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); // Enable the UART interrupt. ROM_IntEnable(INT_UART1); ROM_UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT); // Prompt for text to be entered. UARTSend((unsigned char *) "Enter text: ", 12); // Loop forever echoing data through the UART. while (1) { } }
ROM_GPIOPinConfigure(GPIO_PC4_U1RX);
ROM_GPIOPinConfigure(GPIO_PC5_U1TX);
These are for telling the microcontroller that we want to use PC4/PC5 for UART1 instead PB0/PB1 - Replace the contents for lm4f232h5qd.cmd with the following lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
--retain=g_pfnVectors /* The following command line options are set as part of the CCS project. */ /* If you are building using the command line, or for some reason want to */ /* define them here, you can uncomment and modify these lines as needed. */ /* If you are using CCS for building, it is probably better to make any such */ /* modifications in your CCS project and leave this file alone. */ /* */ /* --heap_size=0 */ /* --stack_size=256 */ /* --library=rtsv7M3_T_le_eabi.lib */ /* The starting address of the application. Normally the interrupt vectors */ /* must be located at the beginning of the application. */ #define APP_BASE 0x00000000 #define RAM_BASE 0x20000000 /* System memory map */ MEMORY { /* Application stored in and executes from internal flash */ FLASH (RX) : origin = APP_BASE, length = 0x00040000 /* Application uses internal RAM for data */ SRAM (RWX) : origin = 0x20000000, length = 0x00008000 } /* Section allocation in memory */ SECTIONS { .intvecs: > APP_BASE .text : > FLASH .const : > FLASH .cinit : > FLASH .pinit : > FLASH .init_array : > FLASH .vtable : > RAM_BASE .data : > SRAM .bss : > SRAM .sysmem : > SRAM .stack : > SRAM } __STACK_TOP = __stack + 512;
- Right click the project "uart1_echo" (in Project Explorer view) and select New>Source File and create a file named "startup_ccs.c"
- Replace the content of startup_ccs.c with the following lines of code. This file contains the interrupt vector table. Note that we have moved the UART Interrupt Function from vector location of UART0 to that of UART1 .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
//***************************************************************************** // Forward declaration of the default fault handlers. //***************************************************************************** void ResetISR(void); static void NmiSR(void); static void FaultISR(void); static void IntDefaultHandler(void); //***************************************************************************** // External declaration for the reset handler that is to be called when the // processor is started //***************************************************************************** extern void _c_int00(void); //***************************************************************************** // Linker variable that marks the top of the stack. //***************************************************************************** extern unsigned long __STACK_TOP; //***************************************************************************** // External declaration for the interrupt handler used by the application. //***************************************************************************** extern void UARTIntHandler(void); //***************************************************************************** // The vector table. Note that the proper constructs must be placed on this to // ensure that it ends up at physical address 0x0000.0000 or at the start of // the program if located at a start address other than 0. //***************************************************************************** #pragma DATA_SECTION(g_pfnVectors, ".intvecs") void (* const g_pfnVectors[])(void) = { (void (*)(void))((unsigned long)&__STACK_TOP), // The initial stack pointer ResetISR,// The reset handler NmiSR,// The NMI handler FaultISR,// The hard fault handler IntDefaultHandler,// The MPU fault handler IntDefaultHandler,// The bus fault handler IntDefaultHandler,// The usage fault handler 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved IntDefaultHandler,// SVCall handler IntDefaultHandler,// Debug monitor handler 0,// Reserved IntDefaultHandler,// The PendSV handler IntDefaultHandler,// The SysTick handler IntDefaultHandler,// GPIO Port A IntDefaultHandler,// GPIO Port B IntDefaultHandler,// GPIO Port C IntDefaultHandler,// GPIO Port D IntDefaultHandler,// GPIO Port E IntDefaultHandler,// UART0 Rx and Tx UARTIntHandler,// UART1 Rx and Tx IntDefaultHandler,// SSI0 Rx and Tx IntDefaultHandler,// I2C0 Master and Slave IntDefaultHandler,// PWM Fault IntDefaultHandler,// PWM Generator 0 IntDefaultHandler,// PWM Generator 1 IntDefaultHandler,// PWM Generator 2 IntDefaultHandler,// Quadrature Encoder 0 IntDefaultHandler,// ADC Sequence 0 IntDefaultHandler,// ADC Sequence 1 IntDefaultHandler,// ADC Sequence 2 IntDefaultHandler,// ADC Sequence 3 IntDefaultHandler,// Watchdog timer IntDefaultHandler,// Timer 0 subtimer A IntDefaultHandler,// Timer 0 subtimer B IntDefaultHandler,// Timer 1 subtimer A IntDefaultHandler,// Timer 1 subtimer B IntDefaultHandler,// Timer 2 subtimer A IntDefaultHandler,// Timer 2 subtimer B IntDefaultHandler,// Analog Comparator 0 IntDefaultHandler,// Analog Comparator 1 IntDefaultHandler,// Analog Comparator 2 IntDefaultHandler,// System Control (PLL, OSC, BO) IntDefaultHandler,// FLASH Control IntDefaultHandler,// GPIO Port F IntDefaultHandler,// GPIO Port G IntDefaultHandler,// GPIO Port H IntDefaultHandler,// UART2 Rx and Tx IntDefaultHandler,// SSI1 Rx and Tx IntDefaultHandler,// Timer 3 subtimer A IntDefaultHandler,// Timer 3 subtimer B IntDefaultHandler,// I2C1 Master and Slave IntDefaultHandler,// Quadrature Encoder 1 IntDefaultHandler,// CAN0 IntDefaultHandler,// CAN1 IntDefaultHandler,// CAN2 IntDefaultHandler,// Ethernet IntDefaultHandler,// Hibernate IntDefaultHandler,// USB0 IntDefaultHandler,// PWM Generator 3 IntDefaultHandler,// uDMA Software Transfer IntDefaultHandler,// uDMA Error IntDefaultHandler,// ADC1 Sequence 0 IntDefaultHandler,// ADC1 Sequence 1 IntDefaultHandler,// ADC1 Sequence 2 IntDefaultHandler,// ADC1 Sequence 3 IntDefaultHandler,// I2S0 IntDefaultHandler,// External Bus Interface 0 IntDefaultHandler,// GPIO Port J IntDefaultHandler,// GPIO Port K IntDefaultHandler,// GPIO Port L IntDefaultHandler,// SSI2 Rx and Tx IntDefaultHandler,// SSI3 Rx and Tx IntDefaultHandler,// UART3 Rx and Tx IntDefaultHandler,// UART4 Rx and Tx IntDefaultHandler,// UART5 Rx and Tx IntDefaultHandler,// UART6 Rx and Tx IntDefaultHandler,// UART7 Rx and Tx 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved IntDefaultHandler,// I2C2 Master and Slave IntDefaultHandler,// I2C3 Master and Slave IntDefaultHandler,// Timer 4 subtimer A IntDefaultHandler,// Timer 4 subtimer B 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved 0,// Reserved IntDefaultHandler,// Timer 5 subtimer A IntDefaultHandler,// Timer 5 subtimer B IntDefaultHandler,// Wide Timer 0 subtimer A IntDefaultHandler,// Wide Timer 0 subtimer B IntDefaultHandler,// Wide Timer 1 subtimer A IntDefaultHandler,// Wide Timer 1 subtimer B IntDefaultHandler,// Wide Timer 2 subtimer A IntDefaultHandler,// Wide Timer 2 subtimer B IntDefaultHandler,// Wide Timer 3 subtimer A IntDefaultHandler,// Wide Timer 3 subtimer B IntDefaultHandler,// Wide Timer 4 subtimer A IntDefaultHandler,// Wide Timer 4 subtimer B IntDefaultHandler,// Wide Timer 5 subtimer A IntDefaultHandler,// Wide Timer 5 subtimer B IntDefaultHandler,// FPU IntDefaultHandler,// PECI 0 IntDefaultHandler,// LPC 0 IntDefaultHandler,// I2C4 Master and Slave IntDefaultHandler,// I2C5 Master and Slave IntDefaultHandler,// GPIO Port M IntDefaultHandler,// GPIO Port N IntDefaultHandler,// Quadrature Encoder 2 IntDefaultHandler,// Fan 0 0,// Reserved IntDefaultHandler,// GPIO Port P (Summary or P0) IntDefaultHandler,// GPIO Port P1 IntDefaultHandler,// GPIO Port P2 IntDefaultHandler,// GPIO Port P3 IntDefaultHandler,// GPIO Port P4 IntDefaultHandler,// GPIO Port P5 IntDefaultHandler,// GPIO Port P6 IntDefaultHandler,// GPIO Port P7 IntDefaultHandler,// GPIO Port Q (Summary or Q0) IntDefaultHandler,// GPIO Port Q1 IntDefaultHandler,// GPIO Port Q2 IntDefaultHandler,// GPIO Port Q3 IntDefaultHandler,// GPIO Port Q4 IntDefaultHandler,// GPIO Port Q5 IntDefaultHandler,// GPIO Port Q6 IntDefaultHandler,// GPIO Port Q7 IntDefaultHandler,// GPIO Port R IntDefaultHandler,// GPIO Port S IntDefaultHandler,// PWM 1 Generator 0 IntDefaultHandler,// PWM 1 Generator 1 IntDefaultHandler,// PWM 1 Generator 2 IntDefaultHandler,// PWM 1 Generator 3 IntDefaultHandler// PWM 1 Fault }; //***************************************************************************** // // This is the code that gets called when the processor first starts execution // following a reset event. Only the absolutely necessary set is performed, // after which the application supplied entry() routine is called. Any fancy // actions (such as making decisions based on the reset cause register, and // resetting the bits in that register) are left solely in the hands of the // application. // //***************************************************************************** void ResetISR(void) { // Jump to the CCS C initialization routine. This will enable the // floating-point unit as well, so that does not need to be done here. __asm(" .global _c_int00\n" " b.w _c_int00"); } //***************************************************************************** // // This is the code that gets called when the processor receives a NMI. This // simply enters an infinite loop, preserving the system state for examination // by a debugger. // //***************************************************************************** static void NmiSR(void) { // Enter an infinite loop. while (1) { } } //***************************************************************************** // // This is the code that gets called when the processor receives a fault // interrupt. This simply enters an infinite loop, preserving the system state // for examination by a debugger. // //***************************************************************************** static void FaultISR(void) { // Enter an infinite loop. while (1) { } } //***************************************************************************** // // This is the code that gets called when the processor receives an unexpected // interrupt. This simply enters an infinite loop, preserving the system state // for examination by a debugger. // //***************************************************************************** static void IntDefaultHandler(void) { // Go into an infinite loop. while (1) { } }
- Now we need to perform some project settings. Right click on the "uart1_echo" project and select "Project Properties" and perform the following configurations:
- Build>ARM Compiler>Include Options. Add the following two paths to the "#include search path":
"C:\StellarisWare"
"C:\StellarisWare\boards\ek-lm4f232" - Build>ARM Linker>File Search Paths Options. Add the following three paths to the "Include Library File" (in this order):
"libc.a"
"C:\StellarisWare\grlib\ccs-cm4f\Debug\grlib-cm4f.lib"
"C:\StellarisWare\driverlib\ccs-cm4f\Debug\driverlib-cm4f.lib" - Build>ARM Compiler>Advanced Options>Predefined symbols. Add the following 3 lines to Pre-define NAME (in this order):
ccs="ccs"
PART_LM4F232H5QD
TARGET_IS_BLIZZARD_RA1 - ARM Compiler>Advanced Options>Language Options: Enable Support for GCC Extensions.
- ARM Compiler>Advanced Options>Assembler Options: Use unified assembly language must be checked.
- ARM Compiler>Advanced Options>Runtime Model Options: Place each function in separate subsection must be "on"
- ARM Linker>Basic Options: C System Stack size must be set to 512 bytes.
- Right click the project "uart1_echo" (in Project Explorer view) and select New>Folder and create a folder named "drivers"
- Right click on this newly created "drivers" folder and select "Import"
- Select "General>File System"
- Browse to C:\StellarisWare\boards\ek-lm4f232\drivers
- Check only the box next to cfal96x64x16.c
- Click Advanced and tick "Create links in workspace"
- Click Finish
- Right click the project and select Build
- After the build is done, right click the project and select Debug As>Code Composer Debug Session
- Press F8 on your keyboard to begin executing the program on the Eval board.
- Switch to the serial terminal, you will be able to type the characters there which will be echoed back to you.
Comments
Post a Comment