SYS/BIOS for the 28x

From Texas Instruments Wiki
Jump to: navigation, search


Sysbios image.png
This page summarizes device-specific features, and implementation details of SYS/BIOS for 28x devices, which are 32-bit microcontrollers designed for real-time control applications.

Important: Significant enhancements were made in SYS/BIOS 6.32 to support 28x devices. We recommend that you use SYS/BIOS 6.32.01 or a later version with 28x devices.

General Considerations for Using SYS/BIOS with 28x

This page shows most SYS/BIOS configuration settings using *.cfg source code snippets. You can also configure 28x applications using the XGCONF Graphical Configuration Tool. For example, when you open the tool, you see the Welcome screen. You can click the System Overview button to see a block diagram of the available SYS/BIOS modules. Modules used by your application have a green checkmark. Notice the modules circled in red in the following figure; they have configuration settings that are specific to 28x devices.

Bios 28x sys overview.png

If you click the Device Support button at the top of the XGCONF page, you see a list of SYS/BIOS modules that apply to the 28x. You can click those links to see a configuration page for each module.

28x bios config.png

Note that some 28x devices do not have enough memory to run SYS/BIOS applications. See the release notes in your SYS/BIOS installation for a detailed, up-to-date list of supported devices (here is a recent list).

Concerto img.jpg
If you are using a Concerto device, this page describes how to use SYS/BIOS with the 28x part of the Concerto. See SYS/BIOS for Stellaris for a description of using SYS/BIOS with the M3 part of the Concerto. For information about inter-processor communication on the Concerto, see the IPC User's Guide.

Building ROM based SYS/BIOS Applications

SYS/BIOS has been flashed into the ROM in TMS320F2837X devices. If you are using a device belonging to this family, you can build a ROM based SYS/BIOS application. Please read the SYS/BIOS for TMS320F2837X ROM wiki page.

Booting SYS/BIOS Application on 28x

This section summarizes the bootstrap sequence for SYS/BIOS. It begins with a review of the boot sequence without SYS/BIOS. This description includes some 28x-specific items, but the general flow of the boot sequence applies to all the device families supported by SYS/BIOS.

Normal Boot Sequence without SYS/BIOS

The picture below summarizes the typical device boot sequence to main(), without SYS/BIOS. The next section will describe SYS/BIOS additions to this sequence. The source files mentioned in this section can be found in the rtssrc.zip file that typically resides in this directory: {CCS Install Directory}\tools\compiler\c2000\lib

Normal boot.jpg

When the device is released from reset, the reset vector initiates C runtime initialization at the _c_int00() entry point (in the file boot.asm, which branches to boot28.inc). The first step to initialize the device is to initialize the system stack pointer. This same stack is used during initial booting, as well as in and after main(). The size of the system stack defaults to 1K words, but can be overridden via the "-stack_size" or "-stack" linker option (defined via CCS project Build Properties->Tool Settings->C2000 Linker->Basic Options).

After the stack pointer is initialized, the boot28.inc file sets various status bits and then processes the global variable initialization records (the “cinit” records) to initialize global variables. After processing these records, boot28.inc traverses the table of .pinit functions (if any are defined), and calls each function. These .pinit functions are typically C++ constructor functions, but can be used for other purposes as well.

Once the table of .pinit functions has been processed, boot28.inc calls your main() function. If there are arguments to pass to main() (depending upon the application build options), the args_main() function is used to call main(). At this point, the C runtime environment has been fully initialized, and the application can begin its intended purpose.

Boot Sequence with SYS/BIOS

The picture below shows additions to the boot sequence when using SYS/BIOS. The dark blue boxes indicate hook mechanisms into the normal boot flow. The green boxes indicate the additional control points that result, and allow calling of SYS/BIOS-defined, as well as user-defined functions, at progressive stages of the boot flow. The red numeric bubbles are used to reference the description below.

Note that this section mentions source files that are modified versions of those provided with TI's C2000 compiler (which were mentioned in the previous section). The modified files referenced here are delivered with XDCtools, and can be found at this location: {XDCtools Install Dir}\packages\ti\targets\rts2800

In particular, the boot_cg.asm file in the {XDCtools Install Dir}\packages\ti\targets\rts2800 directory controls the boot process, and is a modified version of the boot28.inc file in the rtssrc.zip file in the {CCS Install Directory}\tools\compiler\c2000\lib directory.

Boot sequence updated.jpg

1. Startup_reset() refers to a hook mechanism added to boot.asm to allow a table of functions (see '1a' below) to be called immediately after the stack pointer has been initialized. Since only the stack pointer is initialized at this point, these functions must not reference any global variables, because global variables have not been initialized yet, and their locations will be overwritten later in the boot sequence.

1a. For 28x devices, SYS/BIOS installs a configurable Startup reset function called ti_catalog_c2800_init_Boot_init(), which is provided by XDCtools. Depending on your configuration of the ti.catalog.c2800.init.Boot module, this function performs the following actions:
  • Disables the watchdog timer
  • Configures the PLL
  • Sets the CPU frequency to the one you have configured
  • For eZdsp283xx boards only, configures the XINTF external memory interface
You can configure what the Startup reset function does using the C28x Boot module. First, in XGCONF select the Boot module from the SYS/BIOS System Overview page:
Bios 28x startup.png
You will see the configuration page for the 28x Boot module.
28x boot config.png
Watchdog timer: By default, the watchdog timer is enabled, meaning that if the system hangs long enough for the watchdog timer's 8-bit counter to reach its maximum value, a system reset is triggered. To prevent this, you can check the "Disable the watchdog timer" box in XGCONF or use the following configuration statements:
var Boot = xdc.useModule('ti.catalog.c2800.init.Boot');
Boot.disableWatchdog = true;
Boot from Flash: If you want to be able to boot this application from Flash, check the "Enable boot from FLASH" box in XGCONF or use the following configuration statements:
var Boot = xdc.useModule('ti.catalog.c2800.init.Boot');
Boot.bootFromFlash = true;
If you configure your application to boot from Flash, a long branch (LB) to the c_int00 entry point will be placed at the BEGIN section address defined in the linker command file.
PLL configuration: The phase-locked loop (PLL) on 28x devices is used to maintain correct clocking rates. The reference guides linked to in the System Control and Interrupts Reference Guides for C28x topic describe the PLL registers in more detail.
Note: On 280x and 281x devices, XDCtools and SYS/BIOS do not configure the PLL. The PLL is in its default state--bypassed but not turned off--after your application finished booting. If you want to modify the configuration of the PLL on these devices, you can add a Reset function as described at this end of this step (2).
By default, XDCtools automatically enables the PLL for your 2802x, 2803x, 2806x, 282xx, 283xx, or 2834x device. If you want to override the default PLL configuration, you can check the "Configure the PLL" box in XGCONF and set values for the following parameters:
  • PLL input clock (OSCCLK) frequency (MHz) sets the frequency of the oscillator clock (OSCCLK) input to the PLL. On some devices (for example, the TMS320C28346) this corresponds to the frequency of an external crystal or clock input. On others (for example, the TMS320F28069) this corresponds to the frequency of an internal oscillator which is the default OSCCLK coming out of reset.
  • PLL Control Register - DIV specifies the PLL clocking ratio value. This value is the actual value written to the DIV bits in the PLL Control Register (PLLCR[DIV]). This value controls whether the PLL is bypassed or not and sets the PLL clocking ratio when it is not bypassed. The default value is 10.
  • PLL Status Register - DIVSEL specifies the PLL divide select value. This value is the actual value written to the DIVSEL bits in the PLL Status Register (PLLSTS[DIVSEL]). The default value is 2. To divide by 4, use a value of 0 or 1.
  • Limp mode abort function specifies a function to be called if the Boot module finds the device operating in Limp mode (that is, if the OSCCLK input is missing). The default function provided by XDCtools does an ESTOP0 and then enters an infinite loop.
  • Frequency shows the resulting PLL frequency in Hz based on your current configuration. The calculation is Boot.pllOSCCLK * Boot.pllcrDIV * 1000000) / divider, where divider is 2 if Boot.pllstsDIVSEL is 2 and 4 if Boot.pllstsDIVSEL is 0 or 1.
For example, the following configuration statements configure the PLL to a slower rate.
var Boot = xdc.useModule('ti.catalog.c2800.init.Boot');
Boot.configurePll = true;
Boot.pllOSCCLK = 8;
Boot.pllcrDIV = 2;
Boot.pllstsDIVSEL = 0;
User-defined reset functions: If you want to add your own functions to the table of early reset functions, you can do so by adding statements like the following to your application configuration file:
Reset = xdc.useModule('xdc.runtime.Reset');
Reset.fxns[Reset.fxns.length++] = '&myResetFxn';

2. After the table of Startup reset functions has been processed, booting continues in _c_int00(). The boot_cg.asm file in the {XDCtools Install Dir}\packages\ti\targets\rts2800 directory controls the boot process. The .cinit records are processed to initialize global variables.

3. After .cinit records have been processed, additional SYS/BIOS and user-defined initialization functions can be called via the Startup_exec() hook mechanism, which XDCtools adds to the boot_cg.asm file. Since global variables have been initialized, these functions have much more freedom in what they can do, compared to the early reset functions described in 1 and 1a above. One thing that they must not do is to enable global interrupts, because that would allow interrupts to fire before the bootstrap sequence is completed. The startup functions are partitioned into three categories: first functions, module initialization functions, and last functions.

3a. First functions execute before module initialization or last functions. First functions are referenced in a table, and each function in the table is called before proceeding to the module initialization functions. SYS/BIOS typically provides one first function: a function that initializes the system stack with a "watermark" value; this allows checking of the stack later, for depth of use, and overflow.
If you want to add your own first function to be called at this stage, you can do so by adding statements like the following to your application configuration file (*.cfg):
var Startup = xdc.useModule('xdc.runtime.Startup');
Startup.firstFxns[Startup.firstFxns.length++] = '&myFirstFxn';
3b. Module initialization functions are used to initialize the SYS/BIOS or other modules that have been configured into the application. A typical use for these functions is to initialize statically-configured instances of module objects. For example, if the application configuration file statically created two semaphores, the Semaphore module will initialize the corresponding data structures at this stage of boot. Note that this stage only applies to module initialization; it cannot be hooked into for application-level initialization purposes.
3c. The last functions will be invoked after all regular SYS/BIOS module initialization functions have executed. At this stage, SYS/BIOS will typically insert a function to start the Timestamp counter (if it is enabled in the application configuration).
If you want to add your own last functions to be called at this state, you can add statements like the following to the application configuration file:
var Startup = xdc.useModule('xdc.runtime.Startup');
Startup.lastFxns[Startup.lastFxns.length++] = '&myLastFxn';

4. After all last functions have been executed, control returns back to the boot_cg.asm file, which then invokes any .pinit functions that have been defined. After this, boot_cg.asm calls main().

Once in main() the C runtime has been fully initialized, and SYS/BIOS modules have been initialized. But SYS/BIOS has not "started up" yet; this will happen at the end of main(), when BIOS_start() is called. Before that point, the application can do many things, like creating new threads and performing application-specific initialization. Two things that the application must not do at this point are:

  • Do a global interrupt enable (i.e., set GIE=1)
  • Call a SYS/BIOS API that blocks execution waiting for some condition.

These types of calls must wait until after BIOS_start() is invoked. See each SYS/BIOS module's API descriptions for a list of valid API calling contexts.

5. As the last phase of the startup process, BIOS_start() must be called at the end of main(). Note that once SYS/BIOS is "started up", control will never return back to main(). The steps performed within the BIOS_start() startup process are:

5a. Execute any user-defined startup functions. If you want to define a function that is called at this stage, you can add code like the following to your application configuration script:
var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.addUserStartupFunction('&myBiosStartFxn');
5b. Enable servicing of hardware interrupts. Any interrupts that are fully enabled can now be triggered.
5c. Initialize any Timers that have been configured for the application. If individual timers are configured to "auto start", start them now.
5d. If enabled within the application configuration, enable the Software Interrupt (Swi) scheduler. If any Swis are ready to run (i.e., they have been "posted"), they will preempt the startup sequence at this point, and control returns here when no Swis are ready to run.
5e. If enabled within the application configuration, enable the Task scheduler. If any user-defined Tasks are ready to run they will run at this point. When none are ready, the Idle Task runs.
5f. If execution reaches this point (because Tasks are not enabled in the application configuration), any configured Idle functions will be run in a continuous loop.

Handling 28x Interrupts with SYS/BIOS

SYS/BIOS provides the same basic hardware interrupt functionality on 28x devices as it does on other devices. In addition, it provides the ability to configure and use the Peripheral Interrupt Expansion (PIE) block and the zero-latency interrupts supported by 28x devices. The general ti.sysbios.hal.Hwi module is implemented and extended with device-specific functionality by the ti.sysbios.family.c28.Hwi module.

If you want to use only the generic Hwi module run-time APIs and static configuration settings to manage hardware interrupts in your 28x application, you should use the ti.sysbios.hal.Hwi module. To use this module, include the following in your code:

  • C code: #include <ti/sysbios/hal/Hwi.h>
  • Configuration script: var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');

Alternately, you can use the 28x-specific versions of the run-time APIs and static configuration settings provided by the ti.sysbios.family.c28.Hwi module. These include some additional features for 28x only. To use this module, include the following in your code:

  • C code: #include <ti/sysbios/family/c28/Hwi.h>
  • Configuration script: var Hwi = xdc.useModule('ti.sysbios.family.c28.Hwi');

PIE Interrupts

The 28x Peripheral Interrupt Expansion (PIE) block multiplexes numerous interrupt sources into a smaller set of interrupt inputs. The interrupts are grouped into blocks of eight and each group is fed into one of 12 CPU interrupt lines (INT1 to INT12). Each of the 96 interrupts is supported by its own vector stored in a dedicated RAM block that serves as a PIE interrupt vector table. The reference guides linked to in the System Control and Interrupts Reference Guides for C28x topic describe the PIE block in more detail.

The vector is automatically fetched by the CPU when servicing the interrupt. It takes nine CPU clock cycles to fetch the vector and save critical CPU registers. Therefore, 28x CPUs can respond quickly to interrupt events. Each individual interrupt can be enabled/disabled within the PIE block.

You use the same Hwi_create() API and Hwi.create() static configuration method to create Hwi objects for the 32 core interrupt lines (INT1 to INT12) and for individual PIE interrupts. Interrupt numbers 0-32 apply to the core interrupt lines (INT1 to INT12), and numbers 32-127 apply to individual PIE interrupts.

The relationship between the numbers corresponding to PIE interrupts and their groups (CPU interrupt) is as follows:

 PIEGROUPNUM = [(PIENUM - 32) / 8] + 1

The following table shows the mapping between the PIENUM (interrupt ID) and the PIE groups. INTX.Y is the interrupt number for the PIE interrupt belonging to group X and group-specific id Y. For example, in PIE group 2, interrupt 3 would be INT2.3 with an interrupt ID of 42.

INTX.1 INTX.2 INTX.3 INTX.4 INTX.5 INTX.6 INTX.7 INTX.8
INT1.Y 32 33 34 35 36 37 38 39
INT2.Y 40 41 42 43 44 45 46 47
INT3.Y 48 49 50 51 52 53 54 55
INT4.Y 56 57 58 59 60 61 62 63
INT5.Y 64 65 66 67 68 69 70 71
INT6.Y 72 73 74 75 76 77 78 79
INT7.Y 80 81 82 83 84 85 86 87
INT8.Y 88 89 90 91 92 93 94 95
INT9.Y 96 97 98 99 100 101 102 103
INT10.Y 104 105 106 107 108 109 110 111
INT11.Y 112 113 114 115 116 117 118 119
INT12.Y 120 121 122 123 124 125 126 127

For example, the following configuration code plugs the function 'myHwi' into the vector table for PIE group 5, interrupt 1. As the above table shows, this corresponds to interrupt ID 64:

var Hwi = xdc.useModule('ti.sysbios.family.c28.Hwi');
/* PIE group 5, interrupt 1 */
var interruptNum = 64;
var hwiParams = new Hwi.Params();
hwiParams.arg = interruptNum;
hwiParams.enableAck = true;
hwiParams.maskSetting = Hwi.MaskingOption_BITMASK;
hwiParams.disableMask = 0x0;
hwiParams.restoreMask = 0x0;
hwiParams.enableAck = true;
Hwi.create(interruptNum, "&myHwi", hwiParams);

In addition to creating Hwi objects to service PIE interrupts, you can use the following APIs from the ti.sysbios.family.c28.Hwi module to manage PIE interrupt handling at run-time:

  • Hwi_disablePIEIER() disables interrupts in the specified PIE group using a bitmask.
  • Hwi_enablePIEIER() enables interrupts in the specified PIE group using a bitmask.
  • Hwi_restorePIEIER() restores interrupts in the specified PIE group to the settings they had before the previous call to Hwi_disablePIEIER() or Hwi_enablePIEIER().

Similar APIs--Hwi_disableIER(), Hwi_enableIER(), and Hwi_restoreIER()--can be used to disable, enable, and restore the core interrupt lines (INT1 to INT12) at run-time.

The Hwi_clearInterrupt() API can be used to clear an interrupt's pending status. For 28x devices this function clears a PIEIFR bit if the interrupt number is a PIE interrupt number. It clears an IFR bit if this is an interrupt number between 1 and 14.

The following additional configuration parameters are provided for configuring 28x interrupts:

  • Hwi.enableAck enables automatic clearing of the CPU acknowledge bit for PIE interrupts by the SYS/BIOS interrupt dispatcher. This must be done before further interrupts from that block can occur. By default, SYS/BIOS does this for you. See Plugging Interrupts for Use Outside the SYS/BIOS Interrupt Dispatcher for more about clearing this bit.
  • Hwi.disableMask defines which IER bits are disabled prior to invoking an ISR function. This mask is used only if the SYS/BIOS interrupt dispatcher is set to support nested hardware interrupts (the default, set by the Hwi.dispatcherAutoNestingSupport property) and you set the maskSetting parameter for a Hwi object to MaskingOption_BITMASK. Bits in this mask set to 1 correspond to IER bits that will be cleared prior to invoking the ISR.
  • Hwi.restoreMask defines which IER bits are restored to their previous setting upon returning from an ISR function. This mask is used only if the SYS/BIOS interrupt dispatcher is set to support nested hardware interrupts (the default, set by the Hwi.dispatcherAutoNestingSupport property) and you set the maskSetting parameter for a Hwi object to MaskingOption_BITMASK. Bits in this mask set to 1 correspond to IER bits that will be restored.

28x hwi instance new.png

Minimal Latency Interrupts

You can pass a bitmask to the Hwi.zeroLatencyIERMask property to identify interrupts that should never be disabled. The advantage to doing this is that such interrupts will have minimal interrupt-to-ISR execution time. (Though the property name is named "zero latency", the latency is actually minimized, but not zero.) The disadvantage to using this setting is that when SYS/BIOS disables or enabling interrupts, extra work is required to avoid making changes to such interrupts.

For example, the following configuration code sets INT5 and the PIE group 5 multiplexed to INT5 to provide minimal latency:

var Hwi = xdc.useModule('ti.sysbios.family.c28.Hwi');
Hwi.zeroLatencyIERMask = 0x0010;

Bit 0 in the IER mask corresponds to INT1 and PIE group 1. Bit 1 corresponds to INT2 and PIE group 2, and so on through INT12. Bits 12-16 are used for other purposes, and should not be set in the zeroLatencyIERMask. In the previous example, a mask of 0x0010 sets bit 4, which corresponds to INT5.

By default, the Hwi.zeroLatencyIERMask property is shown as a decimal value in XGCONF:

28x hwi zero lat.png

Note that all the interrupts in the PIE group whose bit is set in the zeroLatencyIERMask will be treated as zero latency interrupts.

Note: We recommend that you use the zeroLatencyIERMask only if all interrupts in the groups execute non-SYS/BIOS interrupt handlers. This feature is best used only in applications that demand very low latency.

CPU interrupts specified in this mask (which corresponds to the 16-bit IER register) are not disabled by the Hwi_disable() call and are generally left enabled except when explicitly disabled using Hwi_disableIER() or Hwi_disablePIEIER().

If you use zero latency mode for any interrupt, the code used to disable, enable, and restore interrupts in SYS/BIOS will be slower. This is because the code needs to set individual bits in the IER register rather than setting the INTM bit. It is important to be aware of the performance tradeoff associated with using zero latency interrupts before using this feature.

Plugging Interrupts for Use Outside the SYS/BIOS Interrupt Dispatcher

To consolidate code that performs register saving and restoration for each interrupt, SYS/BIOS provides an interrupt dispatcher that automatically performs these actions for an interrupt routine. Use of the Hwi dispatcher allows ISR functions to be written in C. In addition to preserving the interrupted thread's context, the SYS/BIOS Hwi dispatcher orchestrates the following actions:

  • Disables SYS/BIOS Swi and Task scheduling during interrupt processing
  • Automatically manages nested interrupts on a per-interrupt basis.
  • Invokes any configured "begin" Hwi Hook functions.
  • Runs the Hwi function.
  • Invokes any configured "end" Hwi Hook functions.
  • Invokes Swi and Task schedulers after interrupt processing to perform any Swi and Task operations resulting from actions within the Hwi function.

By default, all Hwi interrupts created statically or dynamically with SYS/BIOS are routed to the interrupt dispatcher.

If you have some interrupts that you do not want serviced by the SYS/BIOS interrupt dispatcher, you should create them using the Hwi_plug() run-time API. Such ISR functions are directly plugged into the vector table. Hwi_plug() can only be used for ISR functions that do not call any SYS/BIOS APIs. If you are using Hwi_plug(), you should also be aware of potential timing and resource access issues between ISRs that are and are not managed by the SYS/BIOS interrupt dispatcher.

If you use Hwi_plug() for any PIE interrupts, your application must clear the CPU acknowledge bit manually for the respective PIE block before further interrupts from that block can occur. The SYS/BIOS interrupt dispatcher normally takes care of this. (This differs from DSP/BIOS 5, in which the application had to acknowledge the interrupt.) If your application contains legacy code with HWI instances created with the legacy-support ti.bios.HWI module, the HWI function must also clear the CPU acknowledge bit manually before returning.

28x Hardware Interrupt Priority Limitations

There are two limitations to parameters in the Hwi.Params structure used when you create a Hwi object on 28x devices:

  • params.priority: The priority parameter for the Hwi.Params structure passed to Hwi_create() is ignored for 28x devices. The 28x devices do not support modifications to the hardware interrupt priorities. Hardware interrupts are automatically prioritized by the C28x hardware. Interrupts that typically require higher priority are assigned to lower-numbered interrupt groups and will thus be serviced with a higher priority by default. The Interrupt Nesting on C28x topic describes this in more detail, and also explains how to disable higher-priority interrupts temporarily in order modify the effective priorities of interrupts via software at run-time. If your interrupt functions use SYS/BIOS APIs, however, you should use the Hwi APIs to disable and enable interrupts, rather than setting registers directly.
  • params.maskSetting: With the 28x Hwi module implementation, the maskSetting parameter for Hwi instances supports all options except MaskingOption_LOWER. If you set this parameter to MaskingOption_LOWER in the configuration, a build warning will be issued. Whether you set this parameter to MaskingOption_LOWER in the configuration or in C code, only this interrupt will be disabled when masking occurs, as if you had specified MaskingOption_SELF. The maskSetting is used when Hwi_reconfig() is called to reconfigure a dispatched interrupt.

28x Timer Management with SYS/BIOS

The 28x devices have three 32-bit timers--Timer 0 through Timer 2. By default, SYS/BIOS uses two of these timers, one for the Clock module and one for the Timestamp module. Typically, the timers used by SYS/BIOS are Timer 0 and Timer 1, but if your application uses a timer for its own processing, SYS/BIOS will use Timer 2 if necessary.

Timestamp

You can control which 28x timers used by SYS/BIOS by configuring the ti.sysbios.family.c28.TimestampProvider module. By default, SYS/BIOS uses the first two available timers for the Clock and Timestamp modules. You can specify that the Timestamp module should use, for example, Timer 2 with the following configuration code:

var TimestampProvider = xdc.useModule('ti.sysbios.family.c28.TimestampProvider');
TimestampProvider.timerId = 2;

The following configuration code causes the Timestamp module to use the same 28x timer as the Clock module:

var TimestampProvider = xdc.useModule('ti.sysbios.family.c28.TimestampProvider');
TimestampProvider.useClockTimer = true;

Sharing the Clock timer leaves more timers available for other uses, but makes the Timestamp APIs less efficient. If you use the Clock timer for timestamps, the timestamp is calculated as: (Clock ticks) x (tick period) + (current timer count) As a result, the maximum value of the timestamp is limited to 2^32 x (Clock tick period).

If you use a separate timer for the timestamp (the default behavior), the maximum value of the timestamp is 2^64 and the multiplication operation is not required in order to retrieve the value.

You can also configure the 28x TimestampProvider module in XGCONF:

28x timestamp config.png

For Concerto devices, you should use the ti.sysbios.family.[c28|arm].f28m35x.TimestampProvider modules, which access the shared timestamp counter that can be read by either the 28x or M3 core.

Timer

Internally, the 28x timers count downward from "period" to 0; however, the Timer_getCount() API subtracts the timer counter value from the period so that it counts upward instead of downward.

The ti.sysbios.family.c28.Timer module configuration lets you specify a mask to identify the CPU timers that are available for use by the Timer module. By default, this mask is set to 7 (111 in binary), which means that Timers 0, 1, and 2 are available. Timers used by SYS/BIOS need not be omitted from this mask, but if your application uses a specific 28x timer, you should omit the bit for that timer from this mask.

28x timer config.png

If you create an instance of the device-specific ti.sysbios.family.c28.Timer module (rather than an instance of the generic ti.sysbios.hal.Timer module), you can also configure the 28x parameters circled below:

28x timer instance.png

The Timer Id parameter specifies which 28x CPU timer should be used for this instance. If you choose ANY, the first available timer is used. Remember that 28x devices have 3 timers and SYS/BIOS uses 2 by default.

The Prescale factor parameter sets the length of a timer tick using the 28x device's 16-bit prescaler. If a prescale factor of 10 is specified, a timer tick will occur every 11 cycles. If this timer is used as a counter, the prescale factor determines the period between counts. Otherwise, the prescale factor can be used to achieve longer timer periods; with a prescale specified, the actual period is period * prescale+1

The 28x Timer module provides the following APIs to access the prescaler:

  • Timer_getPrescale() Returns the prescale configuration setting.
  • Timer_getPrescaleCount() returns the current counter value for the prescaler
  • Timer_setPrescale() Sets the prescale configuration to a new value. This has the effect of changing the timer's actual period.

The Free run and Soft stop parameters let you specify how a timer behaves at a software breakpoint, like those you can set in Code Composer Studio. If the "free" flag is set to 1, the timer will continue to run normally when the program halts at a software breakpoint; the value of the "soft" flag doesn't matter if "free" is set to 1. If "free" is 0 and "soft" is 1, the timer will run down to 0 and then stop. When "free" is 0 and "soft" is 0 (the default), the timer halts at software breakpoints.

For example, the following configuration code creates a 28x Timer with a period of 2000 microseconds and a prescale value of 999. As a result, the Timer ticks every 1000 cycles (prescale+1) and the actual period for running the myTimerFxn() function is 2,000,000 microseconds (2 seconds). When a software breakpoint occurs in Code Composer Studio, this Timer will continue to run.

var ti_sysbios_family_c28_Timer = xdc.useModule('ti.sysbios.family.c28.Timer');
var my28xTimerParams = new ti_sysbios_family_c28_Timer.Params();
my28xTimerParams.instance.name = "my28xTimer";
my28xTimerParams.period = 2000;
my28xTimerParams.prescale = 999;
my28xTimerParams.emulationModeInit.free = 1;
my28xTimerParams.emulationModeInit.soft = 0;
Program.global.my28xTimer = ti_sysbios_family_c28_Timer.create(null, "&myTimerFxn", my28xTimerParams);

As with other device-specific Timer modules, you can also specify the creation parameters for the Hwi object to be triggered by this timer interrupt.

28x Memory Management with SYS/BIOS

Remember that sizes on 28x devices are measured in 16-bit words. The Minimum Addressable Data Unit (MADU) is 16 bits.

Because the amount of memory available on 28x devices is relatively small, reducing the amount of memory used by applications is likely to be important. You may encounter errors when you build an application if the application footprint is too large to fit in RAM. See the "Minimizing the Application Footprint" appendix of the SYS/BIOS User's Guide (SPRUEX3) for a number of ways to reduce the amount of memory used by SYS/BIOS. In addition, you may want to customize the memory map provided by your RTSC platform.

Since the 28x RAM is limited, you may want to consider running the application from Flash memory and copying only critical sections to RAM for faster execution. See the instructions above for details about running SYS/BIOS applications from Flash.

The System stack and all Task stacks must be located within Page 0 in memory, which has a memory address of 0 to 0xffff. An error is raised if a Task stack is placed in some other memory location. By default, Task stacks are placed in the .ebss:taskStackSection section, which is on Page 0. This section is a subsection of .ebss to allow SYS/BIOS to be used with the CCS-supplied linker .cmd files for the 28x devices.

The .taskStackSection contains the stacks for statically created tasks. The size of the .taskStackSection is calculated as (Task.defaultStackSize * number of static tasks) + system heap size.

To reduce the size of this section, you can do the following:

  1. By default, the Task.defaultStackSize is 256 (0x100) 16-bit words. You can configure this value to be somewhat smaller in the Task module parameter settings.
  2. Minimize number of tasks in your application.
  3. Minimize the size of the heap for dynamic allocations (HeapMem.heapMemParams.size) or eliminate all dynamic memory allocation by configuring objects statically.

As you decrease heap and stack sizes, you'll need to watch for "out of memory" errors from heaps and overrunning your stacks. The ROV tool can be helpful in monitoring stack and heap usage.

Training

The "Intro to TI-RTOS Kernel Workshop" is now available. Follow the link below to find out more. The TI-RTOS Kernel Workshop covers the SYS/BIOS operating system available for all TI embedded processors - C28x, MSP430, Tiva-C, C6000 and AM335x (Cortex A-8). You can take a LIVE workshop (scheduled at various sites around the U.S.) or download/stream the videos of each chapter online and watch at your own pace. All of the labs, solutions, powerpoint slides, student guides, installation instructions, lab procedures, etc., are all available to you. The workshop labs run on all MCU platforms and the C6000. Check it out...

Intro to TI-RTOS Kernel Workshop