TI开发笔记

[TOC]

SYS/BIOS

  • The Ethernet Media Access Controller (EMAC) module provides an efficient interface between the device core processor and the networked community.

  • The EMAC controls the flow of packet data from the processor to the PHY. The MDIO module controls PHY configuration and status monitoring.

  • Both the EMAC and the MDIO modules interface to the DSP through a custom interface that allows efficient data transmission and reception.

  • This custom interface is referred to as the EMAC control module, and is considered integral to the EMAC/MDIO peripheral.

  • The EMAC control, EMAC, and MDIO modules all have control registers. These registers are memory mapped into device memory space via the device configuration bus.【EMAC控制器、EMAC、MDIO模块都有控制寄存器,寄存器地址通过设备控制总线写入设备内存空间。】

  • 【Descriptor 不存储任何缓冲数据,仅仅作为数据描述包而存在。主要结构为pNext、pBuffer、Buffer Offset、Buffer Length、Flags和Packet Length。其中,pBuffer是指向数据包Packet的指针存储块。】

Preparation

IDE Installation

SETUP

CONFIGURATIONS

Project

开发及编译环境

  1. CSS安装
  2. TI编译工具安装
  3. SYS/BIOS安装
  4. BIOS-MCSDK软件包安装
  5. BIOS-MCSDK软件包补丁安装
  6. XDC-Tools安装
  7. pdk_C6657软件包
安装流程 备注
CCS安装 CCS工程操作本体软件
TI编译工具安装 TI某型号设备编译软件,一定要确保是否安装,没有的话无法生成工程文件
SYS/BIOS安装 SYS/BIOS RTOS系统(可能安装BIOS_MCSDK时自带)
BIOS-MCSDK软件包安装 安装时会生成 ndk_2_21_01_38,需要删除,不删除会导致后面无法安装其他软件包
BIOS-MCSDK软件包补丁安装 必须安装,否则会出错
XDC-Tools安装 装CSS的时候就已经能自带XDC-Tools了,也可以单独更新版本
pdk_C6657软件包 安装BIOS_MCSDK时自带

注意:

  • 部分SDK、组件包可能会线下兼容,但是版本包带不带特殊标识,如XDCTOOLS个别版本带 _core 的,可能会导致不兼容gr platform。
  • 组件包安装完毕之后需要在 CCS 的 Products and Repositories 中进行挂载和选择。

工程生成、导入与重编

工程的生成、导入与重编主要是针对他人写的代码,未针对我的硬件生成对应的工程文件,因而需要按照我的编译环境和硬件生成对应的工程文件,进而应用到我的硬件上。

工程生成

通过执行命令行工具 pdksetupenv.batpdkProjectCreate.bat 在对应的工程文件包生成工程文件夹 project

注意事项:

命令行工具中设置了一些关于路径的变量,如果安装了更新版本的软件包则因进入命令行文件对相应的文件路径进行修改。 如下,XDC-TOOLS 可能因为版本问题而导致 XDC_INSTALL_PATH 变量出错,各变量也应一一对照安装路径的文件夹名称进行审核。

pdksetupenv.bat 文件下的变量设置:

1
2
set MCSDK_INSTALL_PATH=D:\TexasInstruments\
set XDC_INSTALL_PATH=%MCSDK_INSTALL_PATH%\xdctools_3_25_06_96

pdkProjectCreate.bat 文件下的变量设置如下:

1
2
3
4
5
6
7
8
9
10
11
@REM 需修改成实际安装路径
set CCS_INSTALL_PATH="D:\ti\ccsv7"

@REM 以下各文件版本需要根据当前最新使用的软件包版本来调整
set CGT_VERSION=8.3.8
set XDC_VERSION=3.32.2.25_core
set BIOS_VERSION=6.33.06.50
set IPC_VERSION=1.24.03.32
set EDMA_VERSION=02.11.05.02
set NDK_VERSION=2.21.02.43
set PDK_VERSION=1.1.2.6

在以上文件都设置好以后,还需要进入CCS,点击 WINDOWS -> PREFERENCES -> CODE COMPOSER STUDIO -> PRODUCTS , 在 INSTALLED PRODUCTS 面板下找到已安装的软件包,如果未找到,点击 INSTALL , 选择 /ti 路径进行软件包安装。

如未挂载软件包,可能会出现错误提示如:!ERROR: Unknown product-type ID 'com.ti.sdo.edma3'!

找到示例文件,在示例文件的 /src/ 文件夹下,按住 shift键 并 点击鼠标右键,选择 在此处打开Powershell窗口 ,输入绝对路径和文件名称并按回车运行,如下:

1
2
D:\ti\pdk_C6657_1_1_2_6\packages\ti\drv\pdksetupenv.bat
D:\ti\pdk_C6657_1_1_2_6\packages\ti\drv\pdkProjectCreate.bat

成功时结果如下示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PDK_SHORT_NAME: I:\03.TexasInstruments_Workspace\tl-led-flash\src
*****************************************************************************
Detecting UnitTest Projects in PDK and importing them in the workspace "I:\03.TexasInstruments_Workspace\tl-led-flash\src\project"
找不到文件
*****************************************************************************
Detecting Example Projects in PDK and importing them in the workspace "I:\03.TexasInstruments_Workspace\tl-led-flash\src\project"
找不到文件
*****************************************************************************
Detecting TL Projects and importing them in the workspace "I:\03.TexasInstruments_Workspace\tl-led-flash\src\project"
Detected Example Project: tl-led-flash

--------------------------------------------------------------------------------
Creating project 'tl-led-flash'...


Done!
Copying macros.ini
已复制 1 个文件。

遇到关于 的问题

D:\ti\ccsv7\tools\compiler\ti-cgt-c6000_8.2.2\lib

XDC/STD

DETAILS

In addition to the interfaces specified below, this package also supplies a C/C++ header, std.h that facilitates the creation of portable sources. This header defines a set of "base" types that enable the creation of C-code that is portable between any two targets. C source code that relies exclusively on these types is portable to all targets and platforms. Where appropriate, the types defined below are related to the types defined in the library headers prescribed by the C99 standard (ISO/IEC 9899:1999).

Why not simply use the C99 types? Having a unique set of names provides a layer of insulation between a portable code base and a particular compiler; e.g., even if a compiler does not support the C99 types or defines them inappropriately for a particular device, it is possible to use the compiler without changing the code base. Thus, the developer is not forced to choose the lesser of two evils: waiting for a change to the compiler or forking the code base for a particular compiler device combination.

There are several situations where a small separate set of portable types can help the maintainability of a code base.

  • not all of the types described in the C99 standard are required to be defined by conformant implementations nor is it possible for all devices to implement some of the types specified (e.g., int8_t is not implemented on C54 devices); so it is difficult to identify non-portable source code.
  • not all compilers provide C99 type support; if XDC supplies the type definition and the compiler is updated to include C99 types, a compilation error will occur if the source includes the C99 headers.
  • not all compiler and device combinations are conformant; even high quality compilers may not properly define the types for each device supported by compiler.

USAGE

1
#include <xdc/std.h>

To compile sources that include xdc/std.h, two symbols must be defined before including this header:

  • xdc_target_types__

    the package qualified path of the target's standard types header; e.g., ti/targets/std.h. This value is specified in the target's stdInclude config parameter; see xdc.bld.ITarget.stdInclude

  • xdc_target_name__

    the target's module name without the package prefix; e.g., C64 rather than ti.targets.C64.

For example, to compile sources for the ti.targets.C64 target using TI's cl6x compiler, the following command line is sufficient:

1
cl6x -Dxdc_target_types__=ti/targets/std.h -Dxdc_target_name__=C64

Each of the type names below has an equivalent "long name"; i.e., a name that has an "xdc_" prefix. For example, the type Bool can also be written as "xdc_Bool". Long names exist to avoid conflicts with names defined or used by existing code bases.

In the event that one of the short type names below conflicts with another type name (that can not be changed), it is possble to disable the short names by defining the symbol xdc__nolocalnames before including xdc/std.h.

1
2
#define xdc__nolocalnames
#include <xdc/std.h>

STANDARD TYPES

This header may be included multiple times and defines the following target-dependent types:

  • Bool

    this type is large enough to hold the values 0 or 1. The constants TRUE and FALSE are of this type; see below.

  • String

    this type is defined to be a char * and exists to allow code to distinguish between pointers to buffers of raw data and '\0' terminated strings.

  • CString

    this type is defined to be a const char * and exists to allow code to distinguish between pointers to a modifiable '\0' terminated sequence of characters (i.e., a String) and one that is not modifiable (e.g., a literal string such as "hello world\n").

  • Intn, where n = 8, 16, or 32

    signed integer type that is large enough to hold n bits; the actual target type may by be larger than n. This type is equivalent to one of the C99 types int_leastn_t or int_fastn_t; see Section 7.18.

  • UIntn, where n = 8, 16, or 32

    unsigned integer type that is large enough to hold n bits; the actual target type may by be larger than n. This type is equivalent to one of the C99 types uint_leastn_t or uint_fastn_t; see ISO/IEC 9899:1999 Section 7.18.

  • Bitsn, where n = 8, 16, or 32

    unsigned integer type that is precisely n bits. Not all targets support all values of n; if the target does not support an exact size the corresponding type is not defined. This type is equivalent to the corresponding C99 type uintn_t; see ISO/IEC 9899:1999 Section 7.18.

  • Fxn

    this type is a pointer to code; it can hold a pointer to any function.

  • Ptr

    this type is a pointer to data; it can hold a pointer to any data structure.

  • IArg

    this integer type is large enough to hold a Fxn, Ptr, or Int.

  • UArg

    this unsigned integer type is large enough to hold a Fxn, Ptr, or Int.

  • LLong

    this long integer type is large enough to hold a Long and is defined as a 'long long' type on targets that support this type; otherwise, it is simply a Long. Note that C99 requires the long long type to be at least 64-bits wide (See ISO/IEC 9899:1999 Section 5.2.4.2.1). But some compilers do not support 64-bit integral types and some don't support the long long even though they do support 64-bit integral types. Since these variations limit the portability of valid C sources, the LLong type is always defined, is always at least as wide as the Long type, and is at least 64-bits wide for targets that support 64-bit integral types.

  • ULLong

    this unsigned long integer type is large enough to hold a ULong and is defined as a 'unsigned long long' type on targets that support this type; otherwise, it is simply a ULong.

The xdc/std.h header also defines the following aliases for the base C types. These aliases exist so that C sources can consistently follow a naming convention in which all type names are written in camel-case.

  • Char and UChar

    aliases for char and unsigned char, respectively

  • Short and UShort

    aliases for short and unsigned short, respectively

  • Int and UInt

    aliases for int and unsigned int, respectively

  • Long and ULong

    aliases for long and unsigned long, respectively

  • Double and LDouble

    aliases for double and long double, respectively

  • SizeT

    alias for size_t

  • VaList

    alias for va_list

The types above are defined for all targets. Some targets can support the following additional types. Since these types are not always supported by a target, these types should only be used when no other type sufficies.

  • Bitsn, where n = 8, 16, or 32

    this unsigned integer type is precisely n-bits wide. This type is equivalent to the optional C99 type uintn_t; see ISO/IEC 9899:1999 Section 7.18.1.1. This type is defined if and only if the preprocessor macro xdc__BITSn__ is defined.

64 BIT TYPES

Although the C99 standard requires support for 64-bit types, not all compiler/device combinations can usefully support them. As a result, the 64-bit types described here may not be defined for all targets. For each type there is a corresponding pre-processor macro which is defined if and only if the type is supported.

  • Int64

    signed integer type that is large enough to hold 64 bits; the actual target type may by be wider than 64 bits. This type is equivalent to one of the C99 types int_least64_t or int_fast64_t; see Section 7.18. This type is defined if and only if the preprocessor macro xdc__INT64__ is defined.

  • UInt64

    unsigned integer type that is large enough to hold n bits; the actual target type may by be wider than 64 bits. This type is equivalent to one of the C99 types uint_least64_t or uint_fast64_t; see ISO/IEC 9899:1999 Section 7.18. This type is defined if and only if the preprocessor macro xdc__INT64__ is defined.

  • Bits64

    unsigned integer type that is precisely 64 bits wide. If the target does not support an exact 64-bit size, this type is not defined. This type is equivalent to the corresponding C99 type uint64_t; see ISO/IEC 9899:1999 Section 7.18. This type is defined if and only if the preprocessor macro xdc__BITS64__ is defined.

The table below is from Log_print6() in the XDC/RUNTIME/LOG.H.

However, because the declared type of the arguments is IArg, all pointer arguments must be cast to an IArg type.IArg is an integral type large enough to hold any pointer or an int. So, casting a pointer to an IArg does not cause any loss of information and C's normal integer conversions make the cast unnecessary for integral arguments.

The format string can use the following conversion characters. However, it is important to recall that all arguments referenced by these conversion characters have been converted to an IArg prior to conversion; so, the use of "length modifiers" should be avoided.

Conversion Character Description
%c Character
%d Signed integer
%u Unsigned integer
%x Unsigned hexadecimal integer
%o Unsigned octal integer
%s Character string
%p Pointer
%f Single precision floating point (float)

usertype.h 中的定义:

1
2
3
4
5
6
typedef char           INT8;
typedef short INT16;
typedef int INT32;
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;

SYS/BIOS RTOS

我们依赖操作系统来提供底层和中间件的服务,如让设备启动,处理基本IO口,允许多个程序并行运行,为多个正在运行的程序分配内存和磁盘空间,以及通过USB和以太网口等通讯堆栈来实现更多复杂的IO口通讯。

RTOS的优点

  • 模块化设计,线程的使用使各任务得到最大化独立;
  • 提供模块及接口以方便地驱动外设;
  • 代码可移植性/脱离于内核处理器;

线程

  • 线程是一组存储在存储器的代码,一旦寄存器被正确初始化,CPU就会执行这些代码。
  • 定义和管理任何需要被操作的内容
    • 包括程序指针、堆栈和寄存器等值
    • 这些被统称“上下文”【每个线程都会被定义上下文,包括程序计数器堆栈关键寄存器的信息】
    • 会有一系列的线程需要在指定时间被执行,RTOS会按一定标准在指定时间选择线程执行。
  • 线程可以使任何类型的,SYS/BIOS定义了四种线程类型(优先级降序排列):
    • 硬件中断
    • 软件中断
    • 任务
    • 空闲
  • 各线程有 隐式的(implicity) 和 显示的(explicity)(可能有)优先级
    • 隐式的优先级由线程类型决定
    • 显式的优先级由软件编程者决定
  • 允许抢占(或者上下文切换)
    • 基于优先级的调度管理机制保证了最高优先级的线程能够在第一时间被执行
  • 线程之间的交互
    • 阻断
    • 通信
    • 同步

TIMER and CLOCK

  • 定时器模块 TIMER

  • 管理定时器外设

  • 提供虚拟的目标/设备概念

    • 【通过操作定时器模块而不是硬件外设,开发人员能够更轻松更直观地管理定时器,且在多个不同TI芯片中移植式,代码更具可移植性】
    • 【对于SYS/BIOS而言,可以产生无限数量的定时器】
  • 时钟模块 CLOCK

    • 管理BIOS的“心脏节拍“
    • 在指定时间触发功能(单次或周期性)
    • 使用定时器模块或者应用层模块的“节拍”来处理输入事件
    • 【时钟模块所在的层位于定时器之上】
    • 【时钟模块可以通过定时器模块将系统中的外部事件引入作为输入事件,或者使用定时器模块产生的周期性节拍,基于这些输入事件,时钟模块可以产生软件中断,或者时钟模块还能提供一种服务,以便一次性或者周期性地触发任意数量的不同函数】
    • 【时钟实例中包含了对两个时间段的定义,第一个时间段的定义称为超时时间量,它定义了时钟实例的启动和首次触发相关函数的时间量,通常会在应用程序中,通过显示的调用时钟来启动一个时钟实例,如果创建时钟实例时,标志为TRUE,则实例会在创建后立即启动;第二个时间段的定义标志了相关函数首次调用和后续调用之间持续时间量;对于一次性的时钟实例,只需定义超时时间量,持续时间量将为0;相关函数都是由时钟实例的中断来调用的,这意味着必须在同一线程中启动或停止时钟,而不能在其他线程中任意启动或停止时钟】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 启动/停止时钟实例,仅能通过时钟SWI调用
Clock_start()
Clock_stop()

// 启动/停止定时器底层产生时间节拍
// 【`时钟停止启动` 和 `时钟节拍停止`,用来为驱动时钟模块提供底层定时器】
Clock_tickStart()
Clock_tickStop()

// 修改停止的时钟实例
// 【设置 `时钟周期`、`超时`、`功能` 函数,用于修改时钟实例的参数】
Clock_setPeriod()
Clock_setTimeout()
Clock_setfunc()

// 允许修改时钟实例的参数,基于新的定时器频率
// 当CPU的频率发生变化时,可以通过此函数对时钟进行重新配置
Clock_tickReconfig()
  • 时间戳模块
    • 为代码的基准测试提供便捷的时间戳服务
    • 允许时间戳记录RTA日志
1
2
3
4
5
6
7
8
9
10
11
12
/*前两个变量的类型由时钟模块定义*/
Clock_Params clockParams; //用于容纳所有的时钟实例参数
Task_Handle myClock; //用于存储将要创建的时钟实例的句柄
Error_block eb; //错误块变量,若创建失败可以获取失败原因的信息

Clock_Params_init(&clockParams); //时钟实例初始化参数,已默认值填充参数结构
/*下两句分别更新与默认值不同的参数*/
clockParams.period = 4; //Every 4 Clock ticks
ClockParams.startFlag = TRUE; //Start immediately
Error_init(&eb); //错误块变量,若创建失败可以获取失败原因的信息

myClock = Clock_create((Clock_FuncPtr)clockHandler,4,&clockParams,&eb); //三参数,时钟实例创建,并返回句柄给myClock

在XGCONF中配置时钟参数:

NAME VALUE
tickSource tickSource_TIMER :选择定时器(周期性调用Clock_tick); tickSource_User:选择外部中断触发调用Clock_tick;tickSource_NULL:没有时钟API,没有超时【由信号量写入的调用不能具有超时值】
timerId 【用于指定芯片实际使用的定时器外设】-1:默认定时器
swiPiority 【时钟模块是由底层定时器模块触发软件中断来调用的,因此其SWI的优先级可以设置】默认值 15
tickPeriod 【系统节拍的周期】默认值 1000 usec

时钟实例化参数:

NAME VALUE
clockFxn [Creat Args]【需要被调用的实例函数在clockfxn字段中】
timeout [Creat Args]【从时钟开始运行到相关函数被首次调用的初始时间值】
startFlag [Params]【将指定时钟是在BIOS的调度程序开始运行时立即启动,还是由应用程序调用时钟的启动API】true:立即启动;false:调用;Clock_start() :后启动
period [Params]【在首次调用函数后,需要确定后续函数调用的间隔】0:单次调用;
arg [Params] argument to clockFxn【用户可以将静态变量传递给相关函数,这样做可以将多个时钟实例共同使用单一函数,由于每个实例都可以向被调用的函数传递一个不同的值,因此在实现函数时可以根据调用到的时钟采取不同的操作】

HWI and Idle

嵌入式硬件中断的原理:前台/后台调度(主要由低优先级任务、无线循环任务和ISR构成,复杂性较低,存在不足)

  • 应用程序循环处理由硬件中断服务程序职位的标志位
  • ISR抢断主循环,执行中断服务【ISR 被称为前台进程】

SYS/BIOS在BIOS之上实行 Idle loop + Hwi + main() 的方式:

  • 空闲循环是优先级最低的无限循环(并不代表优先级不重要),所执行的是一系列静态配置的后台程序
  • 典型应用:用户界面,内置的系统测试,测量,以及低功耗模式
  • 被最高优先级线程抢断/从被抢断的地方恢复运行
  • ISR以HWI线程的方式运行,任意HWI都能抢断空闲循环

后台空闲循环(线程)

The background Idle Loop is the thread with the lowest priority of all. It runs in a loop when the CPU is not busy running another thread.

  • When tasks are enabled, the Idle Loop is implemented as the only task running at priority 0.

  • When tasks are disabled, the Idle Loop is fallen into after the application's "main()" function is called.(空闲循环会在应用程序main()函数被调用后陷入?)

HWI的中断及恢复流程(中断调度流程):

  1. 屏蔽任务调度【HWI是被视为隐式的较高优先级线程,因此不希望所有目前最高优先级的线程抢断HWI线程,如果应用程序没有启用任务模块,该段启动任务调度的程序将被优化出中断调度程序,以便确保中断调度程序能够高效执行】
  2. 转向ISR堆栈(如果没有指向该堆栈)【如果当前指针指向任务堆栈,则此时会切换到中断堆栈】
  3. 保存中断返回地址【中断调度程序将存储该指针,以防用户使用IRP的API来检索该返回地址,如果不需要使用该API则被优化】
  4. 屏蔽SWI调度【如任务模块一样未被开启,则自动优化出中断调度程序】
  5. 调用HWI挂钩启动函数【附加挂钩函数】
  6. 如果允许自动嵌套:允许全局中断【有更高优先级的硬件中断来临时,打开中断屏蔽,使能全局中断】
  7. 调用ISR服务程序【真正的硬件中断程序开始执行】
  8. 屏蔽全局中断
  9. 调用HWI挂钩结束函数
  10. 运行SWI调度
  11. 切换回任务堆栈
  12. 运行任务调度

SYS/BIOS中断管理的优势:

  1. 降低代码量
  2. 提供中断堆栈,降低任务堆栈大小
  3. 管理中断嵌套
  4. 在ISR任务中禁止调度中断
  5. 运行由ISR程序递交的SWI程序
  6. 管理任务抢断
  7. 提供监测
  8. 灵活性:仍然允许不执行中断调度

注意: HWI不需要使用编译器认可的中断关键字!SYS/BIOS的中断调度会自动保存堆栈相关数据,如果使用会导致灾难性的运行故障发生!

1
2
3
4
5
6
7
Hwi_Params hwiParams;              //硬件中断参数结构体实例
Hwi_Handle hwi0; //硬件中断句柄
Error_block eb;

Hwi_Params_init(&hwiParams); //参数初始化
hwiParams.arg = 5; //更新参数
hwi0 = Hwi_create(id,hwiFunc,&hwiParams,&eb); //四参数,前两个未知

SWI

  • 一般伴随着硬件中断的发生而发生,以便最灵活地处理中断事务

  • 优先级共16级:0-15

  • 寄存器的保护/恢复由SYS/BIOS系统自动处理

  • 单堆栈模式:增加优先级将增加堆栈的开销

  • 【与任务的处理方式不同,SWI在单个堆栈上运行,同时兼具优点与局限性,能使SWI以非常低的内存消耗来运行,但也不允许他们被挂起(即SWI必须运行到结束)】

  • 【SWI通常由HWI调用,系统产生了一个外设的中断,从而触发了HWI线程,而HWI处理的都是需要紧急实时响应的事务,HWI线程需要尽可能快速处理完毕,并且处理HWI时会屏蔽其他中断,因此为了让HWI处理尽可能少的操作,一些不太需要紧急实时处理的任务会放到SWI中处理。】

  • 【因此当HWI将中断发布到SWI时,SWI会立即处理】

  • 【HWI通常是突发而紧急的,SWI通常较为灵活、常态而平稳】

  • 【HWI通常以微秒计时,SWI通常以毫秒计时】

  • 【HWI和SWI都只会运行一次,不管该线程在运行前被发布了多少次】

  • 【具有相同优先级的两个SWI线程不会抢占对方,会以FIFO的方式先后运行两个线程,即使第二个线程已经被发布,但直到第一个线程运行完毕,第二个线程都在持续等待】

  • 【如果使用ISR来发布更高优先级的SWI,或者说在使用ISR时发布SWI,则可能使得SWI立即抢占ISR的线程,造成数据丢失,BIOS更推荐使用HWI来发布SWI】

  • 【同一个SWI线程不论在运行前被发布了多少次,都只会运行一次】

API Allows you to :
Swi_inc() 知道SWI在运行前被发布了多少次——N:自加计数
Swi_dec() 需要发布N次SWI,才能运行SWI——N:自减计数
Swi_or() 在发布发出一个有用的信号——签名
Swi_andn() 只有在所需要的发布都已经发布后才会发布
Bitmask Counter Not Used
无条件发布 Swi_or() Swi_inc() Swi_post()
仅在触发值为0时发布 Swi_andn() Swi_dec()
  • If trigger value is needed by the Swi, use Swi_getTrigger() which returns the value of the trigger when the Swi function starts running.
  • After each posting, the trigger is reset to the initial condition specified in the Swi object.
1
2
3
4
5
6
7
8
9
10
Swi_Params swiParams;
Swi_Handle mySwi;
Error_Block eb; //创建错误块结构体实例

Swi_Params_init(&swiParams);
swiParams.priority = 15;

Error_init(&eb); //初始化错误块结构体

mySwi = Swi_create(swiFunc, &swiParams, &eb); //三参数

Task

SYS/BIOS-TASK

任务创建函数原型Task_create(Task_FuncPtr, Const*, Error_Block*)

注意:要与 TaskCreate(void*(), char*, int, uint, UINT32, UINT32, UINT32); 做区分。

1
2
3
Task_create(Task_FuncPtr fxn,
const Task_Params *params,
Error_Block *eb);

示例

1
2
3
4
5
6
7
Task_Params taskParams;

// Create task with priority 15
Task_Params_init(&taskParams);
taskParams.stackSize = 512;
taskParams.priority = 15;
Task_create((Task_FuncPtr)myFxn, &taskParams, &eb);

任务特性

  • 任务调度使用更先进的调度技术
    • 每个任务在创建时都会设立独立堆栈,任务访问共享资源时可能会因为等待而被挂起
    • 任务会被其他更高优先级的线程打断(SWI、HWI),HWI 及 SWI不可挂起(SWI是需要退出和返回);
  • 任务的数量、状态及优先级都可以在程序执行时动态改变
  • 【两个任务可以调用同一函数(主要该函数是可以重入?的函数),即该函数在执行完毕之前可被安全地二次调用,任务在调用函数时可携带参数,使函数知晓是被哪个实例调用】

任务间时间切片。

任务在正常情况下是个看似 “无限循环” 的进程,只有在整个系统停止后才会结束;但在未被挂起的情况下,任务在被CPU分时间调度的过程中,任务会重新从头开始运行,即不会停留在上一次的位置。任务看似一次被执行就一直被无限调度,实际上是在时间分片中快速切换。

任务与Semaphore。

在使用Semaphore作为同步方式的任务调度中,如果一个任务等级较高,且 Semaphore_pend() 时,设置了第二个参数为 BIOS_NO_WAIT ,即该任务会被立即循环执行。如果参数设置为 BIOS_WAIT_FOREVER ,则该程序将会一直等待,直到它的信号量被post出来。

原文:A timeout value of BIOS_WAIT_FOREVER causes the task to wait indefinitely for its semaphore to be posted. A timeout value of BIOS_NO_WAIT causes Semaphore_pend to return immediately.

注意:互相形成依赖的任务(如嵌套)不要用同一个信号量,会发生冲突、堆栈溢出或死锁等现象。尽量一个任务关联一个信号量。

注意:如果有堆栈溢出,应优先检查task和semaphore的初始化情况。

Functions explaination
Task_construct (Task_Struct *structP, Task_FuncPtr fxn, const Task_Params *params, Error_Block *eb); // Initialize a new instance object inside the provided structure
在提供的结构中创建一个新的实体对象
Task_create(Task_FuncPtr fxn, const Task_Params *params, Error_Block *eb); // Allocate and initialize a new instance object and return its handle
开辟内存并初始化一个新的实体对象并返回其句柄
Task_delete(Task_Handle *handleP); // Finalize and free this previously allocated instance object, setting the referenced handle to NULL
终结一个已存在的实体对象,并释放内存,设置其句柄为空
Task_destruct(Task_Struct *structP); // Finalize the instance object inside the provided structure
在提供的结构中创建一个新的实体对象
Task_disable(); // Disable the task scheduler
使任务(列表)功能关闭
Task_exit(); // 5Terminate execution of the current task
终结现在正在运行的任务
Task_getEnv(Task_Handle handle); // Get task environment pointer
获取任务环境指针
Task_getIdleTask(); // returns a handle to idle task object
返回一个句柄给空闲任务对象
Task_getMode(Task_Handle handle); // Retrieve the Mode of a task
获取任务的句柄
Task_getPri(Task_Handle handle); // Get task priority
获取任务的优先级
Task_Params_init(Task_Params *params); // Initialize this config-params structure with supplier-specified defaults before instance creation
在实例创建前使用指定默认值初始化配置参数结构
Task_restore(UInt key); // Restore Task scheduling state储存任务调度状态
Task_self(); // Returns a handle to the currently executing Task object
返回一个句柄给当前执行中的任务对象
Task_selfMacro(); // Returns a handle to the currently executing Task object
返回一个句柄给当前执行中的任务对象
Task_setEnv(Task_Handle handle, Ptr env); // Set task environment
设置任务环境
Task_setHookContext(Task_Handle handle, Int id, Ptr hookContext); // Set hook instance's context for a task
为任务设置hook实例的
Task_setPri(Task_Handle handle, Int newpri); // Set a task's priority
设置任务优先级
Task_sleep(UInt nticks); // Delay execution of the current task
延迟当前任务的执行时间
Task_stat(Task_Handle handle, Task_Stat *statbuf); // Retrieve the status of a task
获取任务状态
Task_yield(); // Yield processor to equal priority task
在两个相同等级的任务间切换处理器使用权
同等级任务切换函数
任务测试
priority task_yield() ISR Post Sem 任务内任务 是否执行
更高 存在 存在
相同 存在 存在

Table 3-1. Comparison of Thread Characteristics

Characteristic Hwi Swi Task Idle
Priority Highest 2nd Highest 2nd lowest Lowest
Number of priority levels family/device-specific Up to 32; Periodic functions run at the priority of the Clock Swi. Up to 32; This includes 1 for the Idle Loop. 1
Can yield and pend No, runs to completion except for preemption No, runs to completion except for preemption Yes Should not pend. Pending would disable all registered Idle threads.
Execution states Inactive, ready, running Inactive, ready, running Ready, running, blocked, terminated Ready, running
Thread scheduler disabled by Hwi_disable() Swi_disable() Task_disable() Program exit
Posted or made ready to run by Interrupt occurs Swi_post() , Swi_andn() , Swi_dec() , Swi_inc() , Swi_or() Task_create() and various task synchronization mechanisms (Event, Semaphore, Mailbox) main() exits and no other thread is currently running
Stack used System stack (1 per program) System stack (1 per program) Task stack (1 per program) Task stack used by default
Context saved when preempts other thread
Context saved when blocked
share data with thread via
Synchronize with thread via
Function hooks
Static creation
Dynamic creation
Dynamically change priority
Implicit logging
Implicit statistics

OSIF-TASK

<osif.h> 文件提供系统级接口函数,与SYS/BIOS提供的相似任务函数具有不一样的函数定义。所有任务相关函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 以下功能可能需要被链接或移植
_extern void TaskBlock(HANDLE h);
_extern HANDLE TaskCreate( void(*pFun)(), char *Name, int Priority, uint StackSize,
UINT32 Arg1, UINT32 Arg2, UINT32 Arg3 );
_extern void TaskDestroy( HANDLE h );
_extern void TaskExit();
_extern HANDLE TaskGetEnv( HANDLE h, int Slot );
_extern int TaskGetPri(HANDLE h);
_extern HANDLE TaskSelf();
_extern void TaskSetEnv( HANDLE h, int Slot, HANDLE hEnv );
_extern int TaskSetPri(HANDLE h, int priority);
_extern void TaskSleep(UINT32 delay);
_extern void TaskYield();

任务创建函数 TaskCreate(void*(), char*, int, uint, UINT32, UINT32, UINT32);

1
2
_extern HANDLE TaskCreate( void(*pFun)(), char *Name, int Priority, uint StackSize,
UINT32 Arg1, UINT32 Arg2, UINT32 Arg3 );

TaskCreate(); 的使用方式如下:

1
( void ) TaskCreate ( TCP_Perform_Server , "TCPBenchmarkRX" , OS_TASKPRIHIGH , 0x1400 , 0 , 0 , 0 );

关于任务优先级Priority的定义存在同一头文件中,具体如下:

1
2
3
4
5
6
7
8
9
10
// Equates used in code
#define DBG_PRINT_LEVEL (_oscfg.DbgPrintLevel)
#define DBG_ABORT_LEVEL (_oscfg.DbgAbortLevel)
#define OS_TASKPRILOW (_oscfg.TaskPriLow)
#define OS_TASKPRINORM (_oscfg.TaskPriNorm)
#define OS_TASKPRIHIGH (_oscfg.TaskPriHigh)
#define OS_TASKPRIKERN (_oscfg.TaskPriKern)
#define OS_TASKSTKLOW (_oscfg.TaskStkLow)
#define OS_TASKSTKNORM (_oscfg.TaskStkNorm)
#define OS_TASKSTKHIGH (_oscfg.TaskStkHigh)

以下出自 <spru523h.pdf> Chapter 3.3 Creating a Task

The process of creating a sockets application begins with the creation of a SYS/BIOS Task thread. You can use XGCONF to statically configure Tasks or use the standard SYS/BIOS API or the provided Task abstraction to dynamically create Tasks. For example, the following C code creates a basic Task:

1
2
3
4
5
6
7
8
9
10
11
12
Task_Params taskParams;
Task_Handle hMyTask;
Error_Block eb;
Error_init(&eb);

Task_Params_init(&taskParams);
taskParams.stackSize = 4096;
taskParams.priority = 5; /* Create a Task with priority 5 */
hMyTask = Task_create((Task_FuncPtr)entrypoint, &taskParams, &eb);
if (hMyTask == NULL) {
System_abort("Task create failed");
}

The same Task can be created via the TaskCreate() function in the Task abstraction API. The abstracted function is a little more restrictive. It creates a Task thread with exactly 3 parameters (they do not all have to be used). For example, the following call would create a Task similar to that shown above:

hMyTask = TaskCreate( entrypoint, "TaskName", OS_TASKPRINORM, stacksize, arg1, arg2, arg3 );

In both cases, hMyTask is a handle to a SYS/BIOS Task thread.

Synchronization

SYS/BIOS内的同步类型分为 进程同步核同步 ;同步方式共5种:Semaphore(信号量) / Event(事件) / Gate(门) / Mailbox(邮箱) / Queue(队列)

Semaphore

信号量可分为 互斥型计数型 两种。

互斥型信号量

也称为为互斥量、二进制型信号量。可以理解为只能维护资源数量为1的二值计数信号量(值为0或1),但是互斥信号量又不同于计数信号量,因为它还具有 优先级继承 的机制。

优先级继承机制是RTOS中为了避免出现 优先级翻转 问题而做的处理方式。简单来说就是如果低优先级持有互斥信号量那么高优先级任务想访问互斥量就会失败而挂起等待互斥量被释放,此时反而是低优先级任务在运行,这就出现了优先级翻转。为了避免该情况RTOS处理方式是把正在持有互斥量运行的低优先级任务的优先级提高到与等待访问互斥资源的高优先级任务同等优先级,这就是优先级继承。等互斥量被释放后RTOS会将该任务恢复到之前的低优先级。

特性:

  • 信号量是指系统当前可用资源的数值,当资源超过1时,为 计数型信号量 ;当资源仅为1和0时,为 二进制型信号量;因为资源总为1及以上,因此不论是计数型还是二进制型,可用的信号量始终≥0。

  • 信号量用于标识和实现任务的 挂起发布

    • 发布 指任务正在处于结束状态,Semaphore_post() 将使信号量递增
    • 挂起 指任务正在处于运行状态,Semaphore_pend() 将使信号量递减
    • 使用 Semaphore_pend() 以使用资源,使用 Semaphore_post() 以离开资源
  • 计数型信号量用来进行多任务管理

    • 多任务信号量的初始值将为可同时进行任务的最大值
    • 当达到最大可运行任务量时,信号量值为0,即信号阻塞
  • 当信号量为0时,即系统资源被占满,如果此时出现最高优先级任务,系统将抢断低优先级任务从而使高优先级任务进行工作

任务与调用任务

在调用任务时,不需要特意调高被调用任务的等级。

在被调用任务的等级等于本任务时,使用Semaphore_post(); 并使用 task_yeild(); ,即可顺利将任务切换到被调用任务。(如下 SEM-1 示)

在被调用任务的等级低于本任务时,使用 Semaphore_post(); 并使用 task_sleep(); ,即可让低等级任务在本任务休眠期间执行。(如下 SEM-2 示)

SEM-1

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
void task_core0TCPService(UArg a0, UArg a1) {                                      //Core0执行TCP信息接收任务
short rx_length = 1;

while(1){
Semaphore_pend( sem0_TcpReceive, BIOS_WAIT_FOREVER );
TcpReceive(ReceiveBuffer, RECEIVEBUFFER_SIZE);

//...
if(rx_length > 0){
if(ReceiveBufferTemp[0]==0xf5){
switch(ReceiveBufferTemp[2]){
case 0x01:
if(ReceiveBufferTemp[3] == 0x01){
Semaphore_post(sem0_ad); //post同等级任务的信号量
Task_yield(); //调用任务切换函数
}
//...
default:
//...
break;
}
}
}
//...
}
}

void task_core0AdcRead(UArg a0, UArg a1)
{
int i = 0;
while(1){
Semaphore_pend(sem0_ad,BIOS_WAIT_FOREVER);
while(ADC_Cnt <= ADC_MICROSECOND){
//...
}
}
}

Int main()
{
Task_Handle task; //创建空任务句柄
Task_Params param; //创建空任务参数
Error_Block eb; //创建空错误块
Error_init(&eb); //初始化错误块参数
Task_Params_init(&param); //初始化任务参数
uart_init(); //串口初始化
uart_set_baudrate(115200); //设置波特率

if(CSL_chipReadDNUM() == 0)
{
SemInit_Core0(); //配置semaphore,sem0_ad,sem0_da
FanLed_Init(); //点亮LED3,开启FAN
Sgmii_Init(); //外设初始化
ADS8568_Init(); //INT6
DAC8565_Init(); //INT7
Timer3_Init(); //INT4

task = Task_create(task_core0Init, &param, &eb);
TaskSuccess(&task,"任务创建失败:task_core0Init\n");

param.priority=10;
task = Task_create(task_core0TCPService, &param, &eb);
TaskSuccess(&task,"任务创建失败:task_core0TCPListenAndReceive!\n");

param.priority = 10;
task = Task_create(task_core0AdcRead, &param, &eb); //读取AD任务
TaskSuccess(&task,"任务创建失败:task_core0AdcRead\n");
}
BIOS_start();
return(0);
}


SEM-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Void lowPriTask(UArg arg0, UArg arg1)
{
for(;;){
Semaphore_pend(mySem, BIOS_WAIT_FOREVER); //挂起任务
resource += 1; //do work on locked resource
Semaphore_post(mySem);
}
}

Void hiPriTask(UArg arg0, UArg arg1)
{
for(;;){
Semaphore_pend(mySem, BIOS_WAIT_FOREVER);
resource += 1; //do work on locked resource
Semaphore_post(mySem);
Task_sleep(5); //allow low pri taks to work
}
}

任务与信号量之间的关系?

  • 任务的顺利执行,需要经过 任务新建信号量新建信号量阻塞信号量发布 四个流程。任务不是在被发布后就立即执行的,他需要等待信号量的到来。

  • 先pend后post,即任务执行必须由对应的信号量进行排队(阻塞)和准备(发布),如果其中任何一个步骤缺省都无法执行任务。

  • pend要在该任务被执行时使用,放置在任务最开始的一句话中;post可以放置在别的任务或 IRS 中断里,由别的任务或函数来启动本任务。

  • 信号量使用须统一为计数型或二进制型?

Event

NDK

EMAC

EMAC驱动程序提供了一个定义良好的API层,允许应用程序使用EMAC外设来控制从处理器到PHY的数据包数据流,并使用MDIO模块来控制PHY配置和状态监控。

EMAC驱动程序的设计要求如下:

  • 每个核支持多个EMAC端口(如果设备上可用)。
  • 每个核支持多个通道/MAC地址。
  • 支持多个内核在同一个EMAC端口上使用不同的通道。
  • 驱动程序是独立于操作系统的,通过OSAL操作系统层暴露所有的操作系统callout。
  • EMAC示例测试应用程序提供了标准配置,并演示了可度量的基准测试。

EMAC驱动程序的架构图如下:

img

1.EMAC设备驱动程序

设备驱动程序公开了一组定义良好的API,应用层使用它通过EMAC外围设备发送和接收数据包,并通过MDIO外围设备配置和监视PHY。驱动程序还公开了一组定义良好的操作系统抽象API,用于确保驱动程序是操作系统独立的和可移植的。EMAC驱动程序对所有EMAC MMR访问使用CSL EMAC功能层。

2.应用程序代码

这是EMAC驱动程序的用户,它与驱动程序的接口是通过定义良好的API集实现的。应用程序用户使用EMAC驱动程序API通过EMAC外围设备发送和接收数据包。

3.操作系统抽象层

EMAC LLD是独立于操作系统的,并通过这个层公开所有的操作系统调出。

4.CSL功能层

EMAC驱动程序使用CSL EMAC功能层通过访问MMR来对设备IP进行编程。

5.注册层

寄存器层是由IP所有者生成的IP块内存映射寄存器。EMAC驱动程序不直接访问MMR寄存器,而是使用EMAC CSL功能层实现这个目的。

SOCKET

在C++/MFC中有Window Socket,作为TCP/UDP数据传输的接口工具。

在C#/WPF中也有Socket,作用同上。

在C++/TI.SYSBIOS的NDK套件中也有Socket作为沟通套接的工具。

TI.SYSBIOS的NDK套件中,常用的函数如下:

NDK_accept()

Accept a connection on a socket

SOCKET NDK_accept(SOCKET s, struct sockaddr *pName, int *plen);

NDK_bind()

Bind a name to a socket

int NDK_bind(SOCKET s, struct sockaddr *pName, int len);

NDK_connect()

Initiate a connection on a socket

int NDK_connect(SOCKET s, struct sockaddr *pName, int len);

NDK_getpeername()

Return name (address) of connected peer

int NDK_getpeername(SOCKET s, struct sockaddr *pName, int *plen);

NDK_getsockname()

Return the local name (address) of the socket

int NDK_getsockname(SOCKET s, struct sockaddr *pName, int *plen);

NDK_getsockopt()

Get the value of a socket option

int NDK_getsockopt(SOCKET s, int level, int op, void *pbuf, int *pbufsize);

NDK_listen()

Listen for connection requests on a socket

int NDK_listen(SOCKET s, int maxcon);

NDK_recv()

Receive data from a socket

int NDK_recv(SOCKET s, void *pbuf, int size, int flags);

NDK_recvfrom()

Receive data from a socket with the senders name (address)

int NDK_recvfrom(SOCKET s, void *pbuf, int size, int flags, struct sockaddr *pName, int *plen);

NDK_send()

Send data to a connected socket

int NDK_send(SOCKET s, void *pbuf, int size, int flags);

NDK_sendto()

Send data to a specified destination on an unconnected socket

int NDK_sendto(SOCKET s, void *pbuf, int size, int flags, struct sockaddr *pName, int len);

NDK_setsockopt()

Set the value of a socket option

int NDK_setsockopt(SOCKET s, int level, int op, void *pbuf, int bufsize);

NDK_shutdown()

Close one half of a socket connection

int NDK_shutdown(SOCKET s, int how)

NDK_socket()

Create a socket

SOCKET NDK_socket(int domain, int type, int protocol);

NDK_socketpair()

Create socket pair. Redundant; see Section 3.5, Full Duplex Pipes Programming Interface.

The domain parameter specifies a communications domain within which communication will take place; 域参数指定通信将在其中发生的通信域;

Terminology

EMAC

Ethernet Media Access Controller

MDIO

Management Data Input/Output

PHY

Physical Layer

Purpose of the Peripheral

The EMAC module is used on the device to move data between the device and another host connected to the same network, in compliance with the Ethernet protocol.

PLL

Phase-Locked Loop 锁相环

锁相环路 是一种反馈控制电路,简称锁相环。

锁相环 的特点是:利用外部输入的参考信号控制环路内部振荡信号的频率和相位。因锁相环可以实现输出信号频率对输入信号频率的自动跟踪,所以锁相环通常用于闭环跟踪电路。

锁相环在工作的过程中,当输出信号的频率与输入信号的频率相等时,输出电压与输入电压保持固定的相位差值,即输出电压与输入电压的相位被锁住,这就是锁相环名称的由来。

锁相环通常由鉴相器(PD,Phase Detector)、环路滤波器(LF,Loop Filter)和 压控振荡器(VCO,Voltage Controlled Oscillator)三部分组成。

MII

以太网媒体接口有:MII、RMII、SMII、GMII

Media Independent Interface

称为 介质无关接口媒体独立接口,它是 IEEE-802.3 定义的以太网行业标准。

  • 它包括一个 数据接口 和一个 MACPHY 之间的管理接口。数据接口 包括分别用于 发送器接收器 的两条独立信道,每条信道都有自己的 数据、时钟 和 控制信号 。MII数据接口总共需要16个信号。
  • 管理接口是个双信号接口:一个是时钟信号,另一个是数据信号。通过管理接口,上层能监视和控制PHY。
  • MII标准接口用于连接 Fast Ethernet MAC-blockPHY。表明在不对MAC硬件重新设计或替换的情况下,任何类型的PHY设备都可以正常工作。
  • 在其他速率下工作的与MII等效的接口有:AUI(10M 以太网)、GMII(Gigabyte 以太网)和XAUI(10-Gigabit 以太网)。
  • MII支持10兆和100兆的操作,一个接口由14根线组成,它的支持还是比较灵活的,但是有一个缺点是因为它一个端口用的信号线太多,如果一个8端口的交换机要用到112根线,16端口就要用到224根线,到32端口的话就要用到448根线,一般按照这个接口做交换机,是不太现实的,所以现代的交换机的制作都会用到由MII简化而来的标准,如 RMIISMIIGMII 等。
    • RMII(Reduced MII)是简化的MII接口,在数据的收发上它比MII接口少了一倍的信号线,所以它一般要求是50兆的总线时钟。RMII一般用在多端口的交换机,它不是每个端口安排收、发两个时钟,而是所有的数据端口公用一个时钟用于所有端口的收发,这里就节省了不少的端口数目。RMII的一个端口要求7个数据线,比MII少了一倍,所以交换机能够接入多一倍数据的端口。和MII一样,RMII支持10兆和100兆的总线接口速度。
    • SMII(Serial MII)是由思科提出的一种媒体接口,它有比RMII更少的信号线数目,S表示串行的意思。因为它只用一根信号线传送发送数据,一根信号线传输接受数据,所以在时钟上为了满足100的需求,它的时钟频率很高,达到了125兆,为什么用125兆,是因为数据线里面会传送一些控制信息。SMII一个端口仅用4根信号线完成100信号的传输,比起RMII差不多又少了一倍的信号线。SMII在工业界的支持力度是很高的。同理,所有端口的数据收发都公用同一个外部的125M时钟。
    • GMII(Gigabyte MII)是千兆网的MII接口,这个也有相应的RGMII接口,表示简化了的GMII接口。

MII (Management interface)只有两条信号线。

SGMII

Serial Gigabit Media Independent Interface

SerDes

ESD

Electrostatic discharge

STATS

SOP

Start of Packet, the first fragment of packet

EOP

End of Packet, the last fragment of packet

EOQ

end-of-queue

LSB

least-significant bit

HDP

head descriptor pointer

DMA

TXnHDP

Transmit Channel n DMA Head Descriptor Pointer Register

RXnHDP

Receive Channel n DMA Head Descriptor Pointer Register

Swi

Software Interrupt

Hwi

Hardware Interrupt

ISR

中断服务程序

C99

C99 (以前称为C9X )是ISO / IEC 9899:1999的非正式名称,在1999年推出,被ANSI于2000年3月采用。它是C编程语言标准的过去版本。 它扩展了以前的版本( C90 ),增加了语言和标准库的新功能,并帮助实现更好地利用可用的计算机硬件,如IEEE 754-1985浮点运算和编译器技术,最主要的增强在数值处理上。 2011年发布的C编程语言标准的C11版本取代了C99。

C99是在C89/90的基础上发展起来的,增加了基本数据类型、关键字和一些系统函数等。

C99有一部分是对于增加了宽字符集,还加入了一些库函数,是继C89标准之后的第二个C语言官方标准。第一个C++语言官方标准C++98标准,就是基于C89编写的,因此C99标准新增的语法特性在C++的编译器中就或多或少地支持了,而完全或几乎完全支持C99标准的主流编译器有:GCC 、Clang 、Intel C++ Compiler 等。另外,Visual Studio 2013也部分支持了C99语法特征 。

C99标准的草案是免费的 [6]

初始化列表

初始化列表是用于初始化一组(结构体)内存位置的值列表。

例如,假设已经声明了以下 Date 结构体:

1
struct Date{int day, month, year;};

定义和初始化 Date 变量的方式是:先指定变量名,后接赋值运算符和初始化列表,如下所示:

1
Date birthday = {23, 8, 1983};

该声明定义 birthday 是一个 Date 结构体的变量,大括号内的值按顺序分配给其成员。

也可以仅初始化结构体变量的部分成员。例如,如果仅知道要存储的生日是8月23日, 但不知道年份,则可以按以下方式定义和初始化变量:

1
Date birthday = {23,8};

这里只有 day 和 month 成员被初始化,year 成员未初始化。但是,如果某个结构成员未被初始化,则所有跟在它后面的成员都需要保留为未初始化。使用初始化列表时,C++ 不提供跳过成员的方法。以下语句试图跳过 month 成员的初始化。这是不合法的。

1
Date birthday = {23,1983}; //非法

还有一点很重要,不能在结构体声明中初始化结构体成员,因为结构体声明只是创建一个新的数据类型,还不存在这种类型的变量。因为结构体声明只声明一个结构体“看起来是什么样子的”,所以不会在内存中创建成员变量。只有通过定义该结构体类型的变量来实例化结构体,才有地方存储初始值。

构造函数

虽然初始化列表易于使用,但它有两个缺点:

  1. 如果有某个成员未被初始化,那么在这种情况下,跟随在该成员后面的成员都不能初始化。
  2. 如果结构体包括任何诸如字符串之类的对象,那么在许多编译器上它都将无法运行。

在这些情况下,可以使用构造函数来初始化结构体成员变量,这和初始化类成员变量是相同的。与类构造函数一样,结构体的构造函数必须是与结构体名称相同的公共成员函数,并且没有返回类型。因为默认情况下,所有结构体成员都是公开的,所以不需要使用关键字 public。

以下是一个名为 Employee 的结构体的声明语句,它包含一个具有两参数的构造函数,以便在创建一个 Employee 变量而不向其传递任何参数时,提供默认值:

1
2
3
4
5
6
7
8
9
10
11
12
struct Employee
{
string name; // 员工姓名
int vacationDays, // 允许的年假
daysUsed; //已使用的年假天数
Employee (string n ="",int d = 0) // 构造函数
{
name = n;
vacationDays = 10;
daysUsed = d;
}
};

Const in C++

  1. const与#define

    两者都可以用来定义常量,但是const定义时,定义了常量的类型,所以更精确一些。

    #define只是简单的文本替换,除了可以定义常量外,还可以用来定义一些简单的函数,有点类似内联函数(Inline)。

    const和define定义的常量可以放在头文件里面。(小注:可以多次声明,但只能定义一次)

  2. const与指针和引用

    • const与指针

      1
      2
      3
      4
      int me;
      const int* p1 = &me;//p1可变,*p1不可变,此时不能用*p1来修改,但是p1可以转向
      int* const p2 = &me;//p2不可变,*p2可变,此时允许*p2来修改其值,但是p2不能转向。
      const int* const p3 = &me;//p3不可变,*p3也不可变,此时既不能用*p3来修改其值,也不能转向
    • 指针和引用的区别很简单,就是引用更简洁,更安全。因为引用声明时必须初始化。 引用更接近const指针,一旦与某个变量关联,就将一直效忠于他。

    • const指针可以接受const和非const地址,但是非const指针只能接受非const地址。所以const指针的能力更强一些,所以尽量多用const指针,这是一种习惯。

  3. const与函数

  • 由于2.3,所以经常把函数的形参类型设为const,而且多为const 引用。但是这里有一个限制,不能把不是左值的地址传递给引用。(左值包括变量,数组元素,结构成员,引用,被解除引用的指针等)。 形参是const类型的,说明该函数将不会修改其值,该函数便为const函数。

  • const与类成员函数。先看看下面这段代码:

    1
    2
    const Stock land = Stock("hyd");
    land.show();

    land 是常量,但是类成员函数show()无法保证不修改land,所以编译器将拒绝执行该段代码。除非你能保证show像const函数一样,但这需要另外一种语法,即:

    1
    2
    void show() const; //声明
    void Stock::show() const{} //定义

内联函数

Inline Functions

超级循环

ANC

IPC

Inter-Processor Communication

内部处理器通信

NDK

Network Development Kit

网络开发套件

GPIO

General Purpose Input/Output

通用型之输入输出的简称,功能类似8051的P0—P3,其接脚可以供使用者由程控自由使用,PIN脚依现实考量可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),如当clk generator, chip select等。

既然一个引脚可以用于输入、输出或其他特殊功能,那么一定有寄存器用来选择这些功能。对于输入,一定可以通过读取某个寄存器来确定引脚电位的高低;对于输出,一定可以通过写入某个寄存器来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。

EMIFA

SRIO

高速串行IO口

Hyperlink

超链接

JTAG

Warm reset

软复位

LLD

Low Level Driver

HAL

Hardware Adaption Layer硬件适应层

IGMP

Internet Group Management Protocol

Internet Group Management Protocol (IGMP) is designed to help routers in routing IP multicast traffic. Each router can have multiple ports, and it is inefficient for the router to replicate every IP multicast packet out of each active port. Using the IGMP protocol, the multicast router is able to keep track of which IP multicast addresses need to be routed to each individual port. This allows the router to limit IP multicast transmission to only those ports that require the multicast traffic. IGMP 是用来帮助路由器路由IP组播流量的。每个路由器可以有多个端口,并且路由器从每个活动端口复制每个IP组播包是低效的。使用IGMP协议,组播路由器能够跟踪哪些IP组播地址需要被路由到每个单独的端口。这允许路由器将IP组播传输限制为仅需要组播流量的端口。

The IGMP protocol assumes a client/server relationship between endpoints. The IGMP server is run by the multicast router to get IP multicast information about all the client on each of its individual ports. The IGMP client is only concerned with communicating its own multicast requirements to the local IGMP server, so that it will get the IP multicast packets that it requires. IGMP协议假定端点之间存在客户端/服务器关系。IGMP服务器由组播路由器运行,以获得关于每个单独端口上的所有客户端的IP组播信息。IGMP客户端只关心把它自己的组播要求传达给本地IGMP服务器,这样它就会得到它所需要的IP组播包。

Vocabulary

  1. granularity n. 间隔尺寸,[岩] 粒度

    the quality of being composed of relatively large particles

  2. be patched with 用**修补

    patched /pætʃt/

    adj. 打补丁的 v. 打补丁;遮盖(视力好的眼)促进弱视眼看;(用补丁对程序)改错(patch 的过去式和过去分词)

  3. an entire contiguous Ethernet packet 一个完整连续的以太网包

  4. byte-aligned memory address 字节内存地址

    aligned [əˈlaɪnd]

    1. 结盟;支持;使成一直线;校准;安放,排列;使一致(align 的过去式和过去分词)
  5. prior [ˈpraɪər] adj. (时间、顺序等)先前的;优先的

  6. indicate vt. 表明;指出;预示;象征

  7. prologue /prəʊlɒg/ n. 开场白

  8. auxiliary definitions 辅助定义

    auxiliary [ɔːɡˈzɪliəri]

    adj. 辅助的;副的;附加的;(发动机、设备等)备用的

  9. static inline 静态内联

  10. volatile unsigned int

    volatile [ˈvɒlətaɪl]

    adj. [化学] 挥发性的;不稳定的;爆炸性的;反复无常的

    1. 挥发物;有翅的动物
  11. heap n. 信号量

  12. explicity and implicity 显性和隐性

    explicitly [ɪkˈsplɪsɪtli]

    adv. 明确地;明白地

    implicitly [ɪmˈplɪsɪtli]

    adv. 含蓄地;暗中地

  13. assertion check 断言检查

    assertion [əˈsɜːʃn]

    1. 断言,声明;主张,要求;坚持;认定

    assert

    internal asserts

  14. wrapper function 包装函数

  15. name mangling (函数)命名重整

    mangle /mæŋgl/

    vt. 乱砍、损坏

    The process of encoding the signature into the link name is referred to as name mangling. 对链接名称解码签名的过程被称为命名重整。

    Since function overloading is accomplished through name mangling, function overloading has limitations for functions that are called from the configuration. 由于函数重载是通过命名重整完成的,因此函数重载对从配置中调用的函数有限制。

  16. periodic /periɒdik/ adj. 周期的

    period n. 周期

  17. instantiation of clock 时钟实例化

  18. advancing the connected timer by one second 将连接的时钟向前推进1秒

    advance at different rates 以不同的速率前进

  19. the attached clock 附带的时钟

  20. results in an accurate clock 产生了(导致、致使)一个精确的时钟

  21. constructor n. 构造函数;构造器;建造者

  22. destructor n. 析构函数

  23. millenium n. 千年;千禧年

  24. leap year 闰年

  25. millisecond [ˈmɪlisekənd] n. 毫秒;千分之一秒

    microsecond 微秒

  26. semaphore [ˈseməfɔːr] n. 信号标,旗语;臂板信号装置 v. 打旗语,发信号

  27. diagnostics n. 诊断学(用作单数)

  28. declaration /,deklə'reiʃən/ n. (纳税品等的)申报;宣布;公告;申诉书;声明;

  29. prefix n. 前缀 vt. 加前缀;将某事物加在前面

  30. assembly source 汇编源代码

    assembly code 汇编码

  31. toggle split editor 切换分屏编辑器

    toggle [ˈtɒɡl]

    1. 拴扣;切换键,开关;套索钉

    2. 切换;拴牢,系紧

    split [splɪt]

    vt. 分离;使分离;劈开;离开;分解
    1. 离开;被劈开;断绝关系
    1. 劈开;裂缝 adj. 劈开的

    toggle full screen 切换全屏幕

    toggle funciton

  32. perspective n. 观点;远景;透视图 adj. 透视的

    customize perspective

  33. energia [e'nə:dʒiə] n. (Energia) 能源(火箭名)

    energia sketch 能源草图?

  34. specifications for benchmark tests 基准测试规范

    specification

    ​ a detailed description of design criteria for a piece of work

    ​ n. 规范

    benchmark

    ​ a standard by which something can be measured or judged

    ​ n. 参考标准,基准

  35. target-specific functions 目标特定的功能

    device-specific functions 设备特定的功能

  36. implementation of the IGateProvider interface IGateProvider 接口的实现

    implement

    ​ apply in a manner consistent with its purpose or design

    ​ v. 实现

  37. fixed-size buffers 固定大小缓冲

    fixed

    ​ adj. 固定的

    variable-sized buffers 可变大小缓冲

  38. dynamic memory allocation and deallocation 动态内存分配和回收

  39. reentrant versions 可重入版本

    SYS/BIOS provides reentrant versions of malloc() and free() that internally use the xdc.runtime.

    SYS/BIOS为内部使用XDC.RUNTIME的 malloc() 和 free() 提供了可重入版本。

  40. formal parameter 形式参数

    C++ allows you to specify default values for formal parameters within the function declaration.

    C++允许你在函数声明中指定形参的默认值。

  41. invoke the class member function 调用类成员函数

    By writing a wrapper function which accepts a class instance as a parameter, you can invoke the class member function from within the wrapper. 通过编写以类实例作为参数的包装函数,你可以在包装函数中调用其类成员函数。

  42. context of a software interrupt 软件中断的上下文

    Memory allocation APIs such as Memory_alloc() and Memory_calloc() cannot be called from within the context of a software interrupt.内存分配接口如A和B不能够在软件中断的上下文中被调用。

  43. initial commit message 初始提交消息

    commit [kəˈmɪt]

    ​ vt. 犯罪;把...交托给;指派…作战;使…承担义务;(公开地)表示意见

    ​ vi. 忠于(某个人、机构等);承诺

    amend last commit 修改上一次提交(的数据)

  44. stage changed (确认)暂存(数据)已变化

  45. device endianness 设备字节顺序

  46. preempt 抢占

    All Clock functions run at the same Swi priority, so one Clock function cannot preempt another. 所有的时钟函数都运行在相同的SWI优先级,所以一个时钟函数不能抢占另一个时钟函数。

  47. terminate /ˈtɜːmɪneɪt/ vi./vt. 使终止;使结束;解雇

  48. Event Combiner 事件组合器

  49. optimal isolation 最佳隔离???

    As previously stated, the stack has been designed for optimal isolation, and so that it may seamlessly plug in to varying run-time environments.

  50. octet /ɔk'tet/ 八重、八位(计算机语境下,基本与byte同意)

  51. configuration entry 配置条目

  52. is independent of 独立于……;相对于……独立

  53. Parsing CGI Form Data 解析CGI结构的数据

    parse /'pɑːz/ v.理解,从语法上分析

Reference

www.digoboy.com