教学大纲

介绍代码调试器使用环境,以及如何调试SimpleLink LaunchPad。

准备阶段

软件

硬件

  • 任意有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)

建议阅读

Lab 1: 导入, 编辑, 运行项目

这个教程将通过导入SimpleLink SDK的一个范例项目, 更改部分代码, 加载到SimpleLink LaunchPad运行。

导入项目

  1. 用USB连接器连接SimpleLink LaunchPad和电脑

  2. 打开 Code Composer Studio

  3. 菜单栏,选择: View → Resource Explorer

    你可以使用 Resource Explorer 浏览使用文档,资料库和一些项目范例。

  4. 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, 箭头是灰色的

  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.

    Resource Explorer 还包含许多未下载其他资源, 您可以下载并运行。

    注意: 使用CCSv8.3.0导入项目时, 即使用户已经安装了 v3.51, CCS可能会报错: 需要XDCtools v3.50.999或者更高版本。解决办法是下载XDCtools 原来匹配SDK的版本(例如 XDCtools v3.50.08.24SimpleLink CC2640R2 SDK v2.30.00.28), 这些在CCSv9得到了修复。

    名为 empty 的项目是一个 简单的 TI-RTOS 项目, 使连接的LaunchPad上的LED灯闪烁。

  7. 这时 Project Explorer 应该出现了两个项目: emptytirtos kernel configuration. empty 依赖于 tirtos 项目(包含TI-RTOS的设置)。 如果您需要更多相关资料,您可以查找 SimpleLink MCU SDK User's Guide

    如果您的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 (继续) 程序。
  10. Terminate (终止) 程序, 返回编辑界面。

更改程序

目前程序只能让LaunchPad上的LED以0.5 Hz的频率闪烁。 现在我们来更改代码来控制闪烁频率。

  • 初始程序时, LED0 以 1 Hz频率闪烁
  • 按下 GPIO_Button0LED0 闪烁频率双倍, 最大32 Hz
  • 按下 GPIO_Button1LED0 闪烁频率减半, 最小1 Hz
  • 每次按下GPIO_Button0GPIO_Button1LED1 的状态都会改变

    注意:

    一些LaunchPad没有 LED1。 运行前可以通过查看 Board.htmlBoard.h确定。 (例如在CC3220S/CC3220SF LaunchPad的Board.h 里,可以看到Board_GPIO_LED0Board_GPIO_LED1, 和 Board_GPIO_LED2 指向相同LED)

    此情况下, 唯一影响的是您将观察不到 LED1 的变化。

    • 打开empty.cmainThread(), 变量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;
    
  • 更改 mainThread() 的主循环语句。

    while (1) {
        usleep(led0_on_off_useconds);
        GPIO_toggle(Board_GPIO_LED0);
    }
    

    关于 usleep(): usleep(useconds) 方程只能接受小于1000000无符号整数,否则会出现溢出

  • mainThread(), 调整设置 LED0LED1的初始值。

    /* 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);
    
  • 定义每次按下Button0Button1触发的方程。 根据按钮改变 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/initializationmain 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, 使用数量几乎不受限制。 更多相关信息可以在这里找到

  1. 如果您的SimpleLink LaunchPad正在运行。 请确保您正在 Debug(调试)界面并 Suspend(暂停)程序。 如果不是, 选择 Run → Debug 运行程序。

  2. 点击 View → Breakpoints 打开 Breakpoints view

  3. CCS Debug界面,打开empty.c,找到gpioButtonFxn1(),双击本行左边缘。当代码运行到这一行时,程序会暂停。CCS会根据情况自动选择软件中断点或者硬件中断点。

  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_useconds500000/led0_on_off_useconds。 最后,点击 Continuous Refresh 确保变量值随时更新。
  5. 注意每当程序暂停时,中断代码旁边都会出现蓝色箭头。点击 Run → Step IntoRun → 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 WatchpointLocation 一栏填写led0_on_off_usecondsMemory 一栏填写 Write,点击 OK。 一旦 led0_on_off_useconds 的值被更改,程序就会暂停。

  3. 点击 Run → Resume运行程序, 按板子上的对应键测试程序: 每次led0_on_off_useconds的值被更改,观察点就会暂停程序。

  4. Breakpoints 界面,鼠标右击已经添加的hardware watchpoint,选择 Breakpoint Properties... 更改设置。展开TypeWith Data设置为YesData 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右下方角落出现。

  3. 双击测试代码段头尾行左侧。Breakpoints界面将会出现两个中断点。

  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 界面。默认打开档期那运行代码反汇编语言。程序计数器的地址被蓝色箭头指示。

    您可以通过更改 location box中的地址查看不同位置的反汇编语言。例如0x2600main

  3. 点击 Disassembly 中的 Show Source展示源代码和反汇编语言。

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

    调试器将开始运行,连接目标板,只加载程序的符号。(没有代码被加载)

  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中调试代码。