Academic Company Events NI Developer Zone Support Solutions Products & Services Contact NI MyNI

LabVIEW Embedded for ARM Porting Guide - Chapter 5: Integrating the Real-Time Agent

0 ratings | 0.00 out of 5
Print

Overview

The 32-bit RISC ARM processor architecture developed by ARM Limited is widely used across many embedded designs due to its low price, low power consumption, and wide variety of peripherals for many of the major silicon vendors. Today, the ARM family accounts for more than 75 percent of all 32-bit RISC CPUs. You can use the NI LabVIEW Embedded Module for ARM Microcontrollers for programming ARM microcontrollers with the RTX embedded operating system.

This document offers a general outline for targeting LabVIEW code to any custom ARM target. It is the fifth document in a five-part series that demonstrates the steps you need to take to port LabVIEW code to the Phytec LPC3180 ARM9 microcontroller. For additional information, read these chapters:

Chapter 1: Introduction

Chapter 2: Integration of LabVIEW and Keil Toolchains

Chapter 3: Implementing Elemental I/O

Chapter 4: Porting the RTX Real-Time Kernel

Chapter 5: Integrating the Real-Time Agent

When debugging embedded applications, many times it is not practical to halt a program to view or modify memory contents. By adding the Real-Time Agent to your application, you can view and modify your target memory “on the fly” without stopping your program. The Real-Time Agent is a small code module you can add to your ARM applications that allows your program to communicate back to the µVision Debugger using the ULINK2 USB-JTAG adapter. Adding this module to ARM applications also allows real-time front panel debugging with LabVIEW.

To determine if Real-Time Agent support has already been developed for your target, open the \Keil\ARM\RT Agent\RTX folder to see if your particular ARM target is listed. Open the provided RTX_Config.c file for your target in the appropriate directory and ensure that the Real-Time Agent configuration options defined in section 5.3 are already implemented. If your target does not already have Real-Time Agent support, follow the guide below to incorporate this feature in your target.

The Real-Time Agent offers enhanced debugging capabilities including:

  • Memory read/write during program execution
  • Terminal emulation
  • Serial debug output

For more information on the Real-Time Agent, see the ULINK2 User’s Guide.

Modify the Project Source Files to Add Real-Time Agent Support

The Real-Time Agent feature is easy to add to your application. This section explains how to add and configure these files and verify that they are working properly. Continue with the chapter to make the necessary modifications to the project you created in chapter 4.

Modify the Device Startup File (LPC3000.s) to Support an External DAbt Handler

  • Comment out the following line from the startup file:
    • DAbt_Handler    B       DAbt_Handler
  • Add the following line to the startup file:
    • EXTERN     DAbt_Handler
  • Save LPC3000.s.

Modify RTX_Config.c to Add the Real-Time Agent Configuration Options

  • Add the following code to the RTX User Configuration section:

// <e0>Real-Time Agent

// <i>Enable Real-Time Agent to obtain run-time debug information.

#ifndef __RTA_ENABLED

 #define __RTA_ENABLED          1

#endif

 

// <o0>Output Buffer Size (bytes) <i>If you are experiencing buffer overruns, increase the buffer size.

// <i>Default: 256

//    <256=>256

//    <512=>512

//    <1024=>1024

//    <2048=>2048

#ifndef __RTA_OUT_SIZE_BYTES

 #define __RTA_OUT_SIZE_BYTES  1024

#endif

#define __RTA_OUT_SIZE         (__RTA_OUT_SIZE_BYTES / 4)

 

// <o>  Invalid Memory Pattern <0x0-0xFFFFFFFF>

// <i>  This pattern is shown at inaccessible locations in the memory window at run-time.

// <i>  Default: 0xCCCCCCCC

#ifndef __RTA_NO_MEM_FLAG

 #define __RTA_NO_MEM_FLAG     0xCCCCCCCC

#endif

 

// <e0>Enable Real-Time Agent Terminal

//   <o1.0>Echo Characters Automatically<i>Echoes back characters typed in the serial window

//          <i>Default: Off

//   <o2.0>Block on Write<i>Waits for serial buffer to have available space to send data.

//          <i>This option must be disabled to run without the debugger.

//          <i>Default: On

//  </e>

#ifndef __RTA_TERM_SUPPORT

 #define __RTA_TERM_SUPPORT   1

#endif

 

/* Echo characters back to the serial window automatically */

#ifndef __RTA_TERM_ECHO

 #define __RTA_TERM_ECHO       0

#endif

 

/* Blocking writes - write  blocks when output buffer full*/

#ifndef __RTA_TERM_W_BLOCKING

 #define __RTA_TERM_W_BLOCKING 1

#endif

 

// <o0.0>Task switch monitoring (RTX Kernel only)

// =============================

// <i> Enable Real-Time Agent task switch monitoring.

#ifndef __RTA_RTX_TASK_SWITCHING

 #define __RTA_RTX_TASK_SWITCHING     1

#endif

 

// </e>

 

// <e0>I/O Retargeting

// <i>Enable I/O retargeting

#ifndef __IO_RETARGET_ENABLED

 #define __IO_RETARGET_ENABLED  1

#endif

 

/* Possible stream sources/destinations */

#define __IO_RETARGET_STREAM_NONE           0

#define __IO_RETARGET_STREAM_RTA            1

#define __IO_RETARGET_STREAM_COM_0          2

#define __IO_RETARGET_STREAM_COM_1          3

 

// <o0>STDIO Routing (for printf(), scanf(), etc) <i>Select the route for standard input/output, and standard error

//   <0=> None

//   <1=> Real-Time Agent

//   <3=> COM Port 1

#ifndef __IO_RETARGET_STDIO_ROUTE

 #define __IO_RETARGET_STDIO_ROUTE          1

#endif

 

 

// <o0.0>External file operations (eg RTL Flash File System)

// <i>Enable if __fopen(), __fclose(), __write(), __read(), __setfpos(), __flushbuf() and __get_flen() are defined

#ifndef __IO_RETARGET_FOPEN_ETC_ENABLED

 #define __IO_RETARGET_FOPEN_ETC_ENABLED    0

#endif

 

// </e>

 

// <<< end of configuration section >>>

 

/* Terminal Emulator input buffer size (must be a power of 2)

     This should be modified based on the amount of

     data being sent, and the speed of the JTAG. A faster

     JTAG and/or greater amount of data would require a

     larger buffer size. */

#ifndef __RTA_TERM_IN_SIZE

 #define __RTA_TERM_IN_SIZE    16

#endif

 

// Override the RTA_Config.c hardware type

#define RTA_HW_LPC21xx        1

#define RTA_HW_LPC23xx        2

#define RTA_HW_STR91x         3

#define RTA_HW_AT91SAM7Sx     4

#define RTA_HW_POLLED         99

#define RTA_HW_CUSTOM         100

 

#ifndef __RTA_HW_TYPE

 #define __RTA_HW_TYPE          RTA_HW_POLLED

#endif

 

  • Add the following code after the Global Variables section

#if ((__RTA_ENABLED) && (__RTA_RTX_TASK_SWITCHING))

 #include "rt_agent_rtx.h"

#endif

 

  • Add the following code to the end of RTX_Config.c

#include <RT_Agent.c>

void rt_init (void) {

  RTA_Init ();

}

 

Configure the Real-Time Agent for "Polled Mode"

For the LPC3180, the Real-Time Agent is used in polled mode. In polled mode, a timer interrupt decides when to send and receive data via the Real-Time Agent. To operate the Real-Time Agent in polled mode, you must:

  • Periodically call the RTA_tx_word_ext() and RTA_rx_word_ext() functions from a regular timer interrupt in your application code.
  • Implement the void RTA_irq_enable_ext(void) and void RTA_irq_disable_ext(void) functions. These functions should disable and enable the timer interrupt setup in the step above.

To periodically call the RTA_tx_word_ext() and RTA_rx_word_ex() functions, the HSTimer is configured to interrupt every 1 ms. Recall that the HSTimer is also used for the RTX system timer tick. The HSTimer is capable of firing an interrupt on three different match registers. Match 0 is used to fire an interrupt every 1,000 ticks and then reset the counter. Therefore, to call the Real-Time Agent interrupt, Match Register 1 is used to interrupt on the 500th tick, but Match 1 does not reset the counter. This happens only when the system timer tick interrupt fires. Therefore, the two interrupts fire alternately every 0.500 ms.

Configure the HSTimer to Periodically Call the RTA Functions

  • In the section of code directly after the RTX User Configuration section, add the following definition:
    • #define OS_TRV1         ((((1ULL*OS_CLOCK*500))/1000000ULL)-1ULL)
    • This define is used to signal the HSTimer to interrupt on every 500th tick.
  • Add the following code to the end of the OS_TINIT() function right before the last line that states HSTIM_CTRL |= (1 << 0)
    • HSTIM_INT |= (1 << 1);       /*  Clear Int1 Stat */ \

    • HSTIM_MCTRL |= (1 << 3);     /*  Enable Int on M1*/ \

    • HSTIM_MATCH1 = OS_TRV1;      /*  Setup Match Val */ \

    • This code configures the HSTimer to interrupt on Match 1 every 500th tick.

Implement the RTA_irq_enable_ext(void) and RTA_irq_disable_ext(void) Functions

  • Add the following code to the Global Functions section:

Void RTA_irq_enable_ext (void) {

   MIC_ER |= OS_TIM_;    //Enable Timer 0 Interrupt

}

Void RTA_irq_disable_ext (void) {

   MIC_ER &= ~(OS_TIM_); //Disable Timer 0 Interrupt

}

Modify the System IRQ Handler to Take the Correct Interrupt

  • Add the RTA interrupt function, irq_sys_handler(void), to the Global Functions section and modify the IRQ_Handler(void) function code so that it matches the following:

__irq void irq_sys_handler (void) {

   RTA_rx_word_ext();                 ; Call RTA Polled Mode function

   RTA_tx_word_ext();                 ; Call RTA Polled Mode function

   HSTIM_INT |= (1<<1);               ; Clear Match 1 Interrupt

}

__asm void IRQ_Handler(void) {

   PRESERVE8

   ARM

 

   STMDB  SP!,{R0}                   ; Save Work Register

   LDR    R0,=__cpp(0x40038000)      ; Get Address of HSTIM_INT register

   LDR    R0,[R0]                    ; Read HSTIM_INT register

 

   TST    R0,#0x00000002             ; Check for Match 1 interrupt

   LDMIA  SP!,{R0}                   ; Restore Work Register

   LDRNE  PC,=__cpp(os_clock_interrupt) ; RTX OS Clock IRQ Handler

   LDR    PC,=__cpp(irq_sys_handler) ; RTA IRQ Handler

}

 

  • Save RTX_Config.c.

Verify that the Real-Time Agent Works

  • Build the target by selecting either the Build Target icon  on the build toolbar or the Project»Build target on the main menu bar.
  • Download the code into flash memory by selecting either the Download to Flash Memory icon  on the build toolbar or Flash»Download in the main menu bar.
  • Click on the debugger icon  on the μVision 3 toolbar.
  • Click on the Run icon , and the program runs.
  • If you have successfully configured the Real-Time Agent, the execution of the program flashes the LEDs (D400, D401, D402, and D403) on the Carrier Board and the following message appears on the µVision status bar:


[+] Enlarge Image

Conclusion: Porting to Another ARM Microcontroller

The NI LabVIEW Embedded Module for ARM Microcontrollers provides a complete solution for porting LabVIEW software to any ARM microcontroller that supports the RTX Real-Time Kernel. If you choose an ARM that already has RTX and Real-Time Agent support, the move is relatively straightforward. First, follow chapter 2 to create the target in LabVIEW and to integrate the Keil toolchain. Then, create elemental I/O nodes that access the correct memory-mapped registers on the new device using the Elemental I/O Wizard. If the chosen ARM does not already have RTX support, you must complete some additional work to port and configure the OS and add the Real-Time Agent module as shown in chapters 4 and 5. For more information, see http://www.ni.com/arm.

0 ratings | 0.00 out of 5
Print

Reader Comments | Submit a comment »

 

Legal
This tutorial (this "tutorial") was developed by National Instruments ("NI"). Although technical support of this tutorial may be made available by National Instruments, the content in this tutorial may not be completely tested and verified, and NI does not guarantee its quality in any way or that NI will continue to support this content with each new revision of related products and drivers. THIS TUTORIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND AND SUBJECT TO CERTAIN RESTRICTIONS AS MORE SPECIFICALLY SET FORTH IN NI.COM'S TERMS OF USE (http://ni.com/legal/termsofuse/unitedstates/us/).