教学大纲
介绍代码调试器使用环境,以及如何调试SimpleLink LaunchPad。
准备阶段
软件
- Code Composer Studio v8.3.0 或更高版本。
- 与您使用的LaunchPad相对应最新版本的SimpleLink SDK。
硬件
- 任意有SimpleLink SDK 支持的 SimpleLink LaunchPad, 包括:
- CC1310 LaunchPad (LAUNCHXL-CC1310)
- CC1350 LaunchPad (LAUNCHXL-CC1350)
- CC1312R LaunchPad (LAUNCHXL-CC1312R1)
- CC1352R LaunchPad (LAUNCHXL-CC1352R1)
- MSP432P401R LaunchPad (MSP-EXP432P401R)
- MSP432P4111 LaunchPad (MSP-EXP432P4111)
- MSP432E401Y LaunchPad (MSP-EXP432E401Y)
- CC26X2R LaunchPad (LAUNCHXL-CC26X2R1)
- CC2640R2 LaunchPad (LAUNCHXL-CC2640R2)
- CC3220S LaunchPad (CC3220S-LAUNCHXL)
- CC3220SF LaunchPad (CC3220SF-LAUNCHXL)
建议阅读
- 关于 SimpleLink MCU 平台 和 SimpleLink SDK
- 关于 RTOS 和 TI-RTOS
Lab 1: 导入, 编辑, 运行项目
这个教程将通过导入SimpleLink SDK的一个范例项目, 更改部分代码, 加载到SimpleLink LaunchPad运行。
导入项目
用USB连接器连接SimpleLink LaunchPad和电脑
打开 Code Composer Studio
菜单栏,选择: View → Resource Explorer
你可以使用 Resource Explorer 浏览使用文档,资料库和一些项目范例。
在Resource Explorer主页面, 选择Working Offline, 下载并安装与您使用的LaunchPad对应的最新版本的SimpleLink SDK. 假如您正在使用CC1310 LaunchPad, 您需要下载并安装SimpleLink CC13X0 SDK。 如果需要, 您也可以同时下载 SimpleLink Academy(中文版)
打开 左侧的 Software 文件夹, 标有绿色箭头的 SimpleLink (YourDeviceFamily) SDK -v:(X.X.X.X) 表示其已经下载完毕
注意: 只需点击右上角的 Home 键即可返回 Resource Explorer 主页面
注意: 如果没有选择安装 SimpleLink Academy, 箭头是灰色的
点击 Resource Explorer 页面左上角的 Select a Device or Board , 输入您的 SimpleLink LaunchPad 型号.
在文件夹列表里选择 Software → SimpleLink (YourDeviceFamily) SDK – v:(X.X.X.X) → Examples → Development Tools → (YourLaunchPad) → TI Drivers → empty → TI-RTOS → CCS Compiler → empty, 选择 Import to IDE.
Resource Explorer 还包含许多未下载其他资源, 您可以下载并运行。
注意: 使用CCSv8.3.0导入项目时, 即使用户已经安装了 v3.51, CCS可能会报错: 需要XDCtools v3.50.999或者更高版本。解决办法是下载XDCtools 原来匹配SDK的版本(例如 XDCtools v3.50.08.24 和 SimpleLink CC2640R2 SDK v2.30.00.28), 这些在CCSv9得到了修复。
名为 empty 的项目是一个 简单的 TI-RTOS 项目, 使连接的LaunchPad上的LED灯闪烁。
这时 Project Explorer 应该出现了两个项目: empty 和 tirtos kernel configuration. empty 依赖于 tirtos 项目(包含TI-RTOS的设置)。 如果您需要更多相关资料,您可以查找 SimpleLink MCU SDK User's Guide。
如果您的Project Explorer里面有很多项目, 双击empty (项目名称), 令其显示active状态
您可以使用Project Explorer浏览empty的所有文件. 包括Board.html, Board.h, empty.c, 和 main_tirtos.c等等
- Board.html: LaunchPad结构图,按钮及LED位置,有关设置等等。
- Board.h: 头文件,包含一些定义,例如 Board_GPIO_LED1,方便代码的便携性。
- main_tirtos.c: main() 方程所在文件。
- empty.c: mainThread() 方程初始化所需驱动, 其他的方程的定义。
在上方菜单, 选择 Run → Debug。 触发保存源文件,建立项目,开始调试模式,连接CCS和目标板,加载程序。(第一次运行时,设置TI-RTOS项目可能会需要几分钟)
- 右上角的按钮可以切换 调试 和 编辑 界面。
- 调试 模式时, 点击左上角的 Resume或者 Run 来开始运行程序。
- 现在LaunchPad上的LED以0.5 Hz的频率闪烁。
- 您可以随时 Suspend (中断) 和 Resume (继续) 程序。
Terminate (终止) 程序, 返回编辑界面。
更改程序
目前程序只能让LaunchPad上的LED以0.5 Hz的频率闪烁。 现在我们来更改代码来控制闪烁频率。
- 初始程序时, LED0 以 1 Hz频率闪烁
- 按下 GPIO_Button0, LED0 闪烁频率双倍, 最大32 Hz
- 按下 GPIO_Button1, LED0 闪烁频率减半, 最小1 Hz
每次按下GPIO_Button0 或 GPIO_Button1,LED1 的状态都会改变
注意:
一些LaunchPad没有 LED1。 运行前可以通过查看 Board.html 或 Board.h确定。 (例如在CC3220S/CC3220SF LaunchPad的Board.h 里,可以看到Board_GPIO_LED0, Board_GPIO_LED1, 和 Board_GPIO_LED2 指向相同LED)
此情况下, 唯一影响的是您将观察不到 LED1 的变化。
- 打开empty.c,mainThread(), 变量
time
为1,在 mainThread() 用来设置LED0开关的延迟。 - 将下方代码复制到empty.c的include语句下方,确保是全局变量。
- 主循环语句使用的 sleep(seconds) 变成了 usleep(useconds),所以LED0初始值变成500000 (useconds)。
- 将
time
改成更详细的名字led0_on_off_useconds
。
/* Board_GPIO_LED0 on and off time in microseconds */ uint32_t led0_on_off_useconds = 500000;
- 打开empty.c,mainThread(), 变量
更改 mainThread() 的主循环语句。
while (1) { usleep(led0_on_off_useconds); GPIO_toggle(Board_GPIO_LED0); }
关于 usleep(): usleep(useconds) 方程只能接受小于1000000无符号整数,否则会出现溢出
在mainThread(), 调整设置 LED0 和 LED1的初始值。
/* Configure the LED pins */ GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); /* Initialize LED states to ON */ GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
定义每次按下Button0 或 Button1触发的方程。 根据按钮改变 LED0 的频率和 LED1 的状态。 同时设置边界,防止溢出。
注意:
这些方程应该被放在mainThread()上面.
/* * ======== gpioButtonFxn0 ======== * Callback function for the GPIO interrupt on Board_GPIO_BUTTON0. */ void gpioButtonFxn0(uint_least8_t index) { /* Double LED0 frequency, and toggle LED1 */ if(led0_on_off_useconds >= 31250) { /* LED0 frequency currently <= 16 Hz; can double */ led0_on_off_useconds /= 2; } else { /* limit LED0 frequency to 32 Hz max */ led0_on_off_useconds = 15625; } GPIO_toggle(Board_GPIO_LED1); } /* * ======== gpioButtonFxn1 ======== * Callback function for the GPIO interrupt on Board_GPIO_BUTTON1. */ void gpioButtonFxn1(uint_least8_t index) { /* Halve LED0 frequency, and toggle LED1 */ if(led0_on_off_useconds <= 250000) { /* LED0 frequency currently >= 2 Hz; can halve */ led0_on_off_useconds *= 2; } else { /* limit LED0 frequency to 1 Hz min */ led0_on_off_useconds = 500000; } GPIO_toggle(Board_GPIO_LED1); }
最后, 一些代码要被加到 mainThread() 的 LED configuring/initialization 和 main loop 之间。
/* Configure the board Pushbuttons as interrupts */ GPIO_setConfig(Board_GPIO_BUTTON0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); /* Install Button callbacks */ GPIO_setCallback(Board_GPIO_BUTTON0, gpioButtonFxn0); GPIO_setCallback(Board_GPIO_BUTTON1, gpioButtonFxn1); /* Enable interrupts */ GPIO_enableInt(Board_GPIO_BUTTON0); GPIO_enableInt(Board_GPIO_BUTTON1);
注意:
你可以在 SimpleLink SDK → Examples → Development Tools → (YourLaunchPad) → TI Drivers 找到很有用的代码。 同时也有一些简单利用ADC,GPI0 interrupts,timer,PWM等硬件的项目。
/*
* Copyright (c) 2015-2017, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ======== empty.c ========
*/
/* For usleep() */
#include <unistd.h>
#include <stdint.h>
#include <stddef.h>
/* Driver Header files */
#include <ti/drivers/GPIO.h>
// #include <ti/drivers/I2C.h>
// #include <ti/drivers/SDSPI.h>
// #include <ti/drivers/SPI.h>
// #include <ti/drivers/UART.h>
// #include <ti/drivers/Watchdog.h>
/* Board Header file */
#include "Board.h"
/* Board_GPIO_LED0 on and off time in microseconds */
uint32_t led0_on_off_useconds = 500000;
/*
* ======== gpioButtonFxn0 ========
* Callback function for the GPIO interrupt on Board_GPIO_BUTTON0.
*/
void gpioButtonFxn0(uint_least8_t index)
{
/* Double LED0 frequency, and toggle LED1 */
if(led0_on_off_useconds >= 31250) { /* LED0 frequency currently <= 16 Hz; can double */
led0_on_off_useconds /= 2;
}
else { /* limit LED0 frequency to 32 Hz max */
led0_on_off_useconds = 15625;
}
GPIO_toggle(Board_GPIO_LED1);
}
/*
* ======== gpioButtonFxn1 ========
* Callback function for the GPIO interrupt on Board_GPIO_BUTTON1.
*/
void gpioButtonFxn1(uint_least8_t index)
{
/* Halve LED0 frequency, and toggle LED1 */
if(led0_on_off_useconds <= 250000) { /* LED0 frequency currently >= 2 Hz; can halve */
led0_on_off_useconds *= 2;
}
else { /* limit LED0 frequency to 1 Hz min */
led0_on_off_useconds = 500000;
}
GPIO_toggle(Board_GPIO_LED1);
}
/*
* ======== mainThread ========
*/
void *mainThread(void *arg0)
{
/* Call driver init functions */
GPIO_init();
// I2C_init();
// SDSPI_init();
// SPI_init();
// UART_init();
// Watchdog_init();
/* Configure the LED pins */
GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
/* Initialize LED states to ON */
GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
/* Configure the board Pushbuttons as interrupts */
GPIO_setConfig(Board_GPIO_BUTTON0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
/* Install Button callbacks */
GPIO_setCallback(Board_GPIO_BUTTON0, gpioButtonFxn0);
GPIO_setCallback(Board_GPIO_BUTTON1, gpioButtonFxn1);
/* Enable interrupts */
GPIO_enableInt(Board_GPIO_BUTTON0);
GPIO_enableInt(Board_GPIO_BUTTON1);
while (1) {
usleep(led0_on_off_useconds);
GPIO_toggle(Board_GPIO_LED0);
}
}
点击 Run → Debug 然后 Resume 运行程序。 测试程序是否正确运行。(按键并观察 LED0 闪烁频率及 LED1 状态。)
Lab 2: 基本调试概念
这部分教程将使用更改后的 empty.c。具体将被讲解的内容:
- Breakpoints
- Watchpoints
- Profile Clock
- Disassembly View
- Other Views
- Loading Symbols Only to Debug Flashed Program
Breakpoints(中断点)
中断点是标记某处的代码,使运行中断的点。一旦中断, 我们可以观察registers/memory/etc.中的值,更好的了解程序运行。这在调试中尤为重要。
软件中断点和硬件中断点
硬件中断点 常用于 Flash, 每个目标板可以使用的数量有限。 软件中断点 常用于 RAM, 使用数量几乎不受限制。 更多相关信息可以在这里找到。
如果您的SimpleLink LaunchPad正在运行。 请确保您正在 Debug(调试)界面并 Suspend(暂停)程序。 如果不是, 选择 Run → Debug 运行程序。
点击 View → Breakpoints 打开 Breakpoints view。
在CCS Debug界面,打开empty.c,找到gpioButtonFxn1(),双击本行左边缘。当代码运行到这一行时,程序会暂停。CCS会根据情况自动选择软件中断点或者硬件中断点。
点击 Run → Resume 继续程序运行。按几次板子上的 Button0,直到 LED0 以最高频率32 Hz闪烁。 注意此时程序继续运行。 按下 Button1,程序中断。
- 把鼠标放置在 empty.c 中的 led0_on_off_useconds 附近。 因为中断发生在方程运行之前, 所以显示此变量当前的值依然为15625(32 Hz)。
- 您也可以通过 Watch Expressions 追踪变量的值。 点击 View → Expressions。 在 Expressions 中, 点击 Add a new expression, 添加
led0_on_off_useconds
和500000/led0_on_off_useconds
。 最后,点击 Continuous Refresh 确保变量值随时更新。
注意每当程序暂停时,中断代码旁边都会出现蓝色箭头。点击 Run → Step Into 或 Run → Step Over。代码将逐行运行下棋。 Step直到 led0_on_off_useconds的值被改变。 这时 Expressions 中的值也将改变。 点击 Run → Resume 继续运行程序。
- Step into 执行下一行代码。 包括进入下一个方程。
- Step over 执行本方程内的下一行代码。 不会进入下一个方程。
- Step return 跳出本方程。
在 Breakpoints 界面移除中断点。或者双击中断点代码左侧蓝色标志。
Watchpoints(观察点)
观察点是中断点的一种,用来追踪观察某个地址储存的值。
如果您的SimpleLink LaunchPad正在运行。 请确保您正在 Debug(调试)界面并 Suspend(暂停)程序。 如果不是, 选择 Run → Debug 运行程序。
在Breakpoints 界面,点击New (down arrow) → Hardware Watchpoint,Location 一栏填写
led0_on_off_useconds
,Memory 一栏填写 Write,点击 OK。 一旦led0_on_off_useconds
的值被更改,程序就会暂停。点击 Run → Resume运行程序, 按板子上的对应键测试程序: 每次
led0_on_off_useconds
的值被更改,观察点就会暂停程序。在Breakpoints 界面,鼠标右击已经添加的hardware watchpoint,选择 Breakpoint Properties... 更改设置。展开Type,With Data设置为Yes,Data Value设置为15625,点击Apply and Close。当led0_on_off_useconds的值变为15625时,程序将会暂停。 运行程序,将LED0闪烁频率调至最大(15625), 观察程序是否暂停。
移除中断点。
Profile Clock(分析器时钟)
分析器时钟用来测量运行时间,多用于测量代码中某两行之间的运行时间。
如果您的SimpleLink LaunchPad正在运行。 请确保您正在 Debug(调试)界面并 Suspend(暂停)程序。 如果不是, 选择 Run → Debug 运行程序。
点击 Run → Clock → Enable。一个时钟的标志将会在CCS右下方角落出现。
双击测试代码段头尾行左侧。Breakpoints界面将会出现两个中断点。
点击 Run → Resume 运行程序。
- 按几次板子上的 Button0。 这不会使程序暂停。
- 按几次板子上的 Button1。 这会触发中断点,使程序暂停。注意到此时右下角的时钟右边显示了一个很大的数字。这是从程序开始运行到现在的clock cycle。双击时钟图标,清零记录。
- 点击Run → Resume。程序会继续运行至第二个中断点并暂停。此时右下角时钟图标右侧的数字大约在100至200之间。 (代码段运行时间)
移除中断点。
Disassembly View反汇编展示
如果您的SimpleLink LaunchPad正在运行。 请确保您正在 Debug(调试)界面并 Suspend(暂停)程序。 如果不是, 选择 Run → Debug 运行程序。
点击 View → Disassembly 打开 Disassembly 界面。默认打开档期那运行代码反汇编语言。程序计数器的地址被蓝色箭头指示。
您可以通过更改 location box中的地址查看不同位置的反汇编语言。例如0x2600 或 main。
点击 Disassembly 中的 Show Source展示源代码和反汇编语言。
Other Views(其他调试功能)
Registers View(寄存器)
The Registers view用来展示和编辑外设寄存器上的值。
Modules View(模块试图)
The Modules view 允许浏览已加载的调试符号。这在不以项目为单位的调试中尤为重要。
Loading Symbols for Flashed Program(加载符号)
如果一个程序已经被加载至目标板, 如果您不想重复加载。 您可以使用CCS的加载符号功能只加载程序符号。
如果您的SimpleLink LaunchPad正在运行或处在Debug View(调试界面)。 请 Terminate(中止)程序。
点击 Run → Debug Configurations... 更改调试设置。 这些信息将被设为未来每次运行的默认值(除非更改)。
选择 empty项目,点击右侧的 Program按钮。在 Loading Options 下方选择 Load symbols only。 点击 Apply。点击Debug。
调试器将开始运行,连接目标板,只加载程序的符号。(没有代码被加载)
注意此时程序计数器将指向代码的开端而不是 main() 的开端。 您需要选择 Run → Go Main 或者选择 Run → Restart。
点击 Run → Resume 运行程序。
点击 Run → Terminate 中止运行(您可以选择再次打开Debug Configurations,将Loading options 改回 Load program)。
总结
Lab 1讲解了如何在Code Composer Studio中导入并运行项目。 Lab 2讲解了如何在Code Composer Studio中调试代码。