教学大纲
------------
介绍代码调试器使用环境,以及如何调试SimpleLink LaunchPad。
准备阶段
------------
**软件**
* **[Code Composer Studio v8.3.0](https://processors.wiki.ti.com/index.php/Download_CCS)** 或更高版本。
* 与您使用的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 平台](https://www.ti.com/wireless-connectivity/simplelink-solutions/overview/overview.html) 和 [SimpleLink SDK](https://www.ti.com/wireless-connectivity/simplelink-solutions/overview/software.html)
* 关于 [RTOS](https://dev.ti.com/tirex/content/simplelink_academy_cc2640r2sdk_1_14_02_04/modules/rtos_concepts/rtos_concepts.html) 和 [TI-RTOS](https://dev.ti.com/tirex/content/simplelink_academy_cc2640r2sdk_1_14_02_04/modules/tirtos_basics/tirtos_basics.html)
Lab 1: 导入, 编辑, 运行项目
---------------
这个教程将通过导入**SimpleLink SDK**的一个范例项目, 更改部分代码, 加载到**SimpleLink LaunchPad**运行。
### 导入项目
1. 用USB连接器连接SimpleLink LaunchPad和电脑
2. 打开 **Code Composer Studio**
3. 菜单栏,选择: **View → Resource Explorer**
{{b 你可以使用 **Resource Explorer** 浏览使用文档,资料库和一些项目范例。}}
4. 在**Resource Explorer**主页面, 选择**Working Offline**, 下载并安装与您使用的LaunchPad对应的最新版本的SimpleLink SDK. 假如您正在使用**CC1310** LaunchPad, 您需要下载并安装**SimpleLink CC13X0 SDK**。 如果需要, 您也可以同时下载 **SimpleLink Academy**(中文版)
![Download and install SimpleLink SDK](.\images\CCSv8_simplelink_workshop_01_00.PNG)
打开 左侧的 **Software** 文件夹, 标有绿色箭头的 **SimpleLink (YourDeviceFamily) SDK -v:(X.X.X.X)** 表示其已经下载完毕
{{b **注意:** 只需点击右上角的 **Home** 键即可返回 **Resource Explorer** 主页面}}
{{y **注意:** 如果没有选择安装 **SimpleLink Academy**, 箭头是灰色的}}
5. 点击 **Resource Explorer** 页面左上角的 **Select a Device or Board **, 输入您的 **SimpleLink LaunchPad** 型号.
6. 在文件夹列表里选择 **Software → SimpleLink (YourDeviceFamily) SDK – v:(X.X.X.X) → Examples → Development Tools → (YourLaunchPad) → TI Drivers → empty → TI-RTOS → CCS Compiler → empty**, 选择 **Import to IDE**.
{{b **Resource Explorer** 还包含许多未下载其他资源, 您可以下载并运行。}}
{{y **注意:** 使用**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灯闪烁。
![Importing example project to IDE](.\images\CCSv8_simplelink_workshop_01_01.PNG)
7. 这时 **Project Explorer** 应该出现了两个项目: *empty* 和 *tirtos kernel configuration*. *empty* 依赖于 *tirtos* 项目(包含TI-RTOS的设置)。 如果您需要更多相关资料,您可以查找 [SimpleLink MCU SDK User's Guide](https://dev.ti.com/tirex/content/simplelink_cc13x0_sdk_1_40_00_10/docs/simplelink_mcu_sdk/Users_Guide.html#ti-rtos-kernel)。
如果您的Project Explorer里面有很多项目, 双击*empty* (项目名称), 令其显示active状态
8. 您可以使用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()* 方程初始化所需驱动, 其他的方程的定义。
9. 在上方菜单, 选择 **Run → Debug**。 触发保存源文件,建立项目,开始调试模式,连接CCS和目标板,加载程序。(第一次运行时,设置TI-RTOS项目可能会需要几分钟)
* 右上角的按钮可以切换 **调试** 和 **编辑** 界面。
* **调试** 模式时, 点击左上角的 **Resume**或者 **Run** 来开始运行程序。
* 现在LaunchPad上的LED以0.5 Hz的频率闪烁。
* 您可以随时 **Suspend** (中断) 和 **Resume** (继续) 程序。
![CCS shortcuts](.\images\CCSv8_simplelink_workshop_01_02_c.PNG)
10. **Terminate** (终止) 程序, 返回编辑界面。
### 更改程序
目前程序只能让LaunchPad上的LED以0.5 Hz的频率闪烁。 现在我们来更改代码来控制闪烁频率。
* 初始程序时, **LED0** 以 1 Hz频率闪烁
* 按下 **GPIO_Button0**, **LED0** 闪烁频率双倍, 最大32 Hz
* 按下 **GPIO_Button1**, **LED0** 闪烁频率减半, 最小1 Hz
* 每次按下**GPIO_Button0** 或 **GPIO_Button1**,**LED1** 的状态都会改变
[[b 注意:
一些LaunchPad没有 **LED1**。 运行前可以通过查看 **Board.html** 或 **Board.h**确定。 (例如在**CC3220S/CC3220SF** LaunchPad的**Board.h** 里,可以看到**Board_GPIO_LED0**, **Board_GPIO_LED1**, 和 **Board_GPIO_LED2** 指向相同LED)
此情况下, 唯一影响的是您将观察不到 **LED1** 的变化。
]]
1. * 打开**empty.c**,**mainThread()**, 变量`time`为1,在 **mainThread()** 用来设置LED0开关的延迟。
* 将下方代码复制到**empty.c**的include语句下方,确保是全局变量。
* 主循环语句使用的 **sleep(seconds)** 变成了 **usleep(useconds)**,所以LED0初始值变成500000 (useconds)。
* 将`time` 改成更详细的名字 `led0_on_off_useconds`。
``` cpp
/* Board_GPIO_LED0 on and off time in microseconds */
uint32_t led0_on_off_useconds = 500000;
```
2. 更改 mainThread() 的主循环语句。
``` cpp
while (1) {
usleep(led0_on_off_useconds);
GPIO_toggle(Board_GPIO_LED0);
}
```
{{y **关于 usleep():** *usleep(useconds)* 方程只能接受小于1000000无符号整数,否则会出现溢出}}
3. 在**mainThread()**, 调整设置 **LED0** 和 **LED1**的初始值。
``` cpp
/* 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);
```
4. 定义每次按下**Button0** 或 **Button1**触发的方程。 根据按钮改变 **LED0** 的频率和 **LED1** 的状态。 同时设置边界,防止溢出。
[[b 注意:
这些方程应该被放在mainThread()上面.
]]
``` cpp
/*
* ======== 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);
}
```
5. 最后, 一些代码要被加到 **mainThread()** 的 **LED configuring/initialization** 和 **main loop** 之间。
``` cpp
/* 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);
```
[[b 注意:
你可以在 **SimpleLink SDK → Examples → Development Tools → (YourLaunchPad) → TI Drivers** 找到很有用的代码。 同时也有一些简单利用ADC,GPI0 interrupts,timer,PWM等硬件的项目。
]]
[[+d 完整版的 **empty.c** 如下(展开)
``` cpp
/*
* 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
#include
#include
/* Driver Header files */
#include
// #include
// #include
// #include
// #include
// #include
/* 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.中的值,更好的了解程序运行。这在调试中尤为重要。
[[b 软件中断点和硬件中断点
**硬件中断点** 常用于 **Flash**, 每个目标板可以使用的数量有限。 **软件中断点** 常用于 **RAM**, 使用数量几乎不受限制。 更多相关信息可以在[这里找到](https://processors.wiki.ti.com/index.php/How_Do_Breakpoints_Work)。
]]
1. 如果您的SimpleLink LaunchPad正在运行。 请确保您正在 **Debug**(调试)界面并 **Suspend**(暂停)程序。 如果不是, 选择 **Run → Debug** 运行程序。
2. 点击 **View → Breakpoints** 打开 **Breakpoints view**。
3. 在**CCS Debug**界面,打开**empty.c**,找到**gpioButtonFxn1()**,双击本行左边缘。当代码运行到这一行时,程序会暂停。CCS会根据情况自动选择软件中断点或者硬件中断点。
![Inserting a breakpoint](.\images\CCSv8_simplelink_workshop_02_00.PNG)
4. 点击 **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** 确保变量值随时更新。
![Continuous refresh](.\images\CCSv8_simplelink_workshop_02_01.PNG)
5. 注意每当程序暂停时,中断代码旁边都会出现蓝色箭头。点击 **Run → Step Into** 或 **Run → Step Over**。代码将逐行运行下棋。 **Step**直到 **led0_on_off_useconds**的值被改变。 这时 **Expressions** 中的值也将改变。 点击 **Run → Resume** 继续运行程序。
* **Step into** 执行下一行代码。 包括进入下一个方程。
* **Step over** 执行本方程内的下一行代码。 不会进入下一个方程。
* **Step return** 跳出本方程。
6. 在 **Breakpoints** 界面移除中断点。或者双击中断点代码左侧蓝色标志。
### Watchpoints(观察点)
观察点是中断点的一种,用来追踪观察某个地址储存的值。
1. 如果您的SimpleLink LaunchPad正在运行。 请确保您正在 **Debug**(调试)界面并 **Suspend**(暂停)程序。 如果不是, 选择 **Run → Debug** 运行程序。
2. 在**Breakpoints** 界面,点击**New (down arrow) → Hardware Watchpoint**,**Location** 一栏填写`led0_on_off_useconds`,**Memory** 一栏填写 **Write**,点击 **OK**。 一旦 `led0_on_off_useconds` 的值被更改,程序就会暂停。
![New hardware watchpoint](.\images\CCSv8_simplelink_workshop_02_02.PNG)
3. 点击 **Run → Resume**运行程序, 按板子上的对应键测试程序: 每次`led0_on_off_useconds`的值被更改,观察点就会暂停程序。
4. 在**Breakpoints** 界面,鼠标右击已经添加的**hardware watchpoint**,选择 **Breakpoint Properties...** 更改设置。展开**Type**,**With Data**设置为**Yes**,**Data Value**设置为**15625**,点击**Apply and Close**。当**led0_on_off_useconds**的值变为**15625**时,程序将会暂停。 运行程序,将**LED0**闪烁频率调至最大(15625), 观察程序是否暂停。
5. 移除中断点。
### Profile Clock(分析器时钟)
分析器时钟用来测量运行时间,多用于测量代码中某两行之间的运行时间。
1. 如果您的SimpleLink LaunchPad正在运行。 请确保您正在 **Debug**(调试)界面并 **Suspend**(暂停)程序。 如果不是, 选择 **Run → Debug** 运行程序。
2. 点击 **Run → Clock → Enable**。一个时钟的标志将会在CCS右下方角落出现。
![Profile clock icon](.\images\CCSv8_simplelink_workshop_02_03.PNG)
3. 双击测试代码段头尾行左侧。**Breakpoints**界面将会出现两个中断点。
![Adding two breakpoints](.\images\CCSv8_simplelink_workshop_02_04.PNG)
4. 点击 **Run → Resume** 运行程序。
* 按几次板子上的 **Button0**。 这不会使程序暂停。
* 按几次板子上的 **Button1**。 这会触发中断点,使程序暂停。注意到此时右下角的时钟右边显示了一个很大的数字。这是从程序开始运行到现在的**clock cycle**。双击时钟图标,清零记录。
* 点击**Run → Resume**。程序会继续运行至第二个中断点并暂停。此时右下角时钟图标右侧的数字大约在100至200之间。 (代码段运行时间)
5. 移除中断点。
### Disassembly View反汇编展示
1. 如果您的SimpleLink LaunchPad正在运行。 请确保您正在 **Debug**(调试)界面并 **Suspend**(暂停)程序。 如果不是, 选择 **Run → Debug** 运行程序。
2. 点击 **View → Disassembly** 打开 **Disassembly** 界面。默认打开档期那运行代码反汇编语言。程序计数器的地址被蓝色箭头指示。
{{b 您可以通过更改 **location box**中的地址查看不同位置的反汇编语言。例如**0x2600** 或 **main**。}}
3. 点击 **Disassembly** 中的 **Show Source**展示源代码和反汇编语言。
![Disassembly view with show source](.\images\CCSv8_simplelink_workshop_02_05.PNG)
### Other Views(其他调试功能)
#### Registers View(寄存器)
The **Registers view**用来展示和编辑外设寄存器上的值。
#### Modules View(模块试图)
The **Modules view** 允许浏览已加载的调试符号。这在不以项目为单位的调试中尤为重要。
### Loading Symbols for Flashed Program(加载符号)
如果一个程序已经被加载至目标板, 如果您不想重复加载。 您可以使用CCS的加载符号功能只加载程序符号。
1. 如果您的SimpleLink LaunchPad正在运行或处在**Debug View**(调试界面)。 请 **Terminate**(中止)程序。
2. 点击 **Run → Debug Configurations...** 更改调试设置。 这些信息将被设为未来每次运行的默认值(除非更改)。
3. 选择 **empty**项目,点击右侧的 **Program**按钮。在 **Loading Options** 下方选择 **Load symbols only**。 点击 **Apply**。点击**Debug**。
调试器将开始运行,连接目标板,只加载程序的符号。(没有代码被加载)
![Debug configurations](.\images\CCSv8_simplelink_workshop_02_06.PNG)
4. 注意此时程序计数器将指向代码的开端而不是 *main()* 的开端。 您需要选择 **Run → Go Main** 或者选择 **Run → Restart**。
5. 点击 **Run → Resume** 运行程序。
6. 点击 **Run → Terminate** 中止运行(您可以选择再次打开**Debug Configurations**,将**Loading options** 改回 **Load program**)。
###总结
Lab 1讲解了如何在**Code Composer Studio**中导入并运行项目。 Lab 2讲解了如何在**Code Composer Studio**中调试代码。