Active-Pro Debug Port

The ACTIVE-PRO Debug Port

The Active-Pro captures detailed debug information about the execution of firmware, including the graphed values of variables and the exact timings of debug messages as they are executed. The debug information is output from the microprocessors using the firmware routines below using a single line of code to create the Active Debug Port using standard GPIO pins. See the bottom of this page for the active.c and active.h files to include in your firmware projects.

There are 2 types of data captured over the ACTIVE-PRO Debug Port: ACTIVE-PRO Text and ACTIVE-PRO Value (as well as the standard logic and analog inputs).

ACTIVE-PRO Text is character strings and are identical to traditional "printf" output.  They are graphed over time as well as listed vertically.

Each debug text output is created by a simple source code line such as:

ACTIVEText( 2, “Button Pressed” );

or

ACTIVEprintf( 2, “%d”, accum );



ACTIVE-PRO Value is value data that is then graphed versus time for a visual representation of the data.

Each data point on the waveform is created by a simple source code line such as:

ACTIVEValue ( 3, myvariable );

The label on the left of each waveline can also be set from your firmware by calling the ACTIVELabel function. 

ACTIVE Debug Port Protocol

The Active Debug Port Protocol is sent from an embedded processor to the ACTIVE Debugger Pod to transfer the information from the embedded system to the computer for capture and display.

The data is sent from the embedded processor to the ACTIVE Debugger Pod using the ACTIVE Bus, which is available in 2 versions, 1 wire or 2 wire versions.  Each version of the bus sends the same byte stream.

The 1 Wire ACTIVE bus uses an ASYNC serial UART bus signaling with 8 data bits and no parity at any baud rate up to 3MBaud.  Bit alignment is defined by the UART start bit protocol.

The 2 Wire ACTIVE bus uses a SYNC serial bus signaling (CLOCK and DATA lines) with 8 data bits with DATA sampled on the rising edge of the CLOCK rate up to 80M bits per second.  This mode can be created easily using an SPI bus using just the SCK and MOSI signals.  The bit alignment is determined by the fact that every MSBit is a 0.  To sync we detect if the MSBit is a 1, and if it is we skip a bit until it is never a 1.  Once synced, it will remain synced until the 0x7F no longer exists of an MSBit is a 1, and a new sync procedure will be completed.

Code listings below show the use of these 2 modes, and demonstrates 2-wire mode using GPIO as well as a dedicated SPI hardware block.

Active Value Packet Format

The packet format on the Active Bus to send values (as in the ACTIVEValue() routine below) is as follows:


Active Text Packet Format

The packet format on the Active Bus to send debug text (as in the ACTIVEText() or ACTIVEprintf() routines below) is as follows:

Best Practices

Until we can get an ACTIVE Debug Hardware Block built inside every microprocessor, use the following Best Practices while using these critical new debug ports on any of your microprocessors:

Debug Output Speed - Since each call to the debug output takes a small amount of time away from the host processor, it is important to use the fastest method of transfer possible. The fastest mode is 2-wire mode, and if you have a built in SPI hardware block in your MCU even better. The slowest mode is typically the 1-wire mode since it is typically driven by a UART. In this case, use as fast a baud rate as possible since the Active-Pro automatically determines the baud rate and can match your baud rate.

Volume of Debug Messages - To minimize the impact on your host processor and to minimize the capture file size, try to have debug messages only when needed, and make them as brief as possible while not losing the context of the message.

Turn Off Digital Signals- Although you can capture the Digital signals that make up the Active Debug Bus, it is not necessary, and if enabled will consume far more data bandwidth than with them off. So Turn off the Digital Input channels for your Active Busses (and any other hardware decoded busses as well).

Where is the First Debug Output Message? - There is auto signal detection that automatically determines which signal is clock and which is data.   This process takes a whole byte to determine, so it has a 50% chance of misinterpreting the first byte.  To solve this, and capture the very first message, either send the message again, or swap the wires to get the very first message.  Once the Active-Pro determines the correct signal setup (clock and data detection), it will be correct for future captures. 

Using these methods, you can have a powerful debug port into your microprocessor with minimal impact on your application firmware.

ACTIVEValue ( 25, 89815 ); using 2-wire mode with a 33MHz SPI hardware block consumes 6.1usec

ACTIVEText ( 24, “15ed7” ); using 2-wire mode with a 33MHz SPI hardware block consumes 8.3usec


Firmware Routines

The Active-Pro™ captures the debug data from your firmware when you call the following routines.

ACTIVEText ( unsigned char channel, unsigned char * string );

This routine outputs the given text on the Channel specified.

channel = 0 thru 63

string is the \0 terminated string to output.  These can also be special Control Commands (below) to control various features of the host capture software.

Example: ACTIVEText ( 2, "It Happened!");      // Displays "It Happened!" on channel 2 at the current time

 

ACTIVEprintf ( unsigned char channel, unsigned char * printfformatstring, ... );

This routine outputs the printf-like text on the Channel specified. 

channel = 0 thru 63

printfformatstring is the \0 terminated string to use as in the standard C printf routine

... are the parameters that are used by the format string

Example: ACTIVEprintf ( 4, "%d: %d", index, data);      // Displays "23: 15432" on channel 4 if index = 23 and data = 15432

 

ACTIVEValue ( unsigned char channel, signed long value );

This routine outputs the given value on the Channel specified to be graphed over time.

channel = 0 thru 63

value is the value to output on the graph.  value is a signed long and can therefore range from –2,147,483,648 to 2,147,483,647

Example: ACTIVEValue ( 2,  ADCValue );      // Adds a graphed point at the value 123 on channel 2 at the current time if ADCValue = 123

ACTIVELabel( unsigned char channel, unsigned char * string );

This routine sets the label for the Channel specified.

channel = 0 thru 63

string is the \0 terminated string that becomes the new channel label.

Example: ACTIVELabel( 2, "State");      // Changes the Channel 2 label to "State"

Control Commands

These commands are sent using the string parameter in the call to ACTIVE-PROText().

Play Beep:   ACTIVEText( channel, "?cmd=beep");

This command generates an audible BEEP on the computer when it is sent.

channel = 0 thru 7,  ignored

Example: ACTIVEText( 2, "?cmd=beep");      // plays a beep on the computer

 

Stop Capture:   ACTIVEText( channel, "?cmd=stop");

This command stops the capture in progress and displays the trace that has been stored to disk.

channel = 0 thru 7,  ignored

Example: ACTIVEText( 2, "?cmd=stop");      // stops the capture

 

Restart Capture:   ACTIVEText( channel, "?cmd=restart");

This command stops and restarts the capture.  This discards the trace that was previously stored to disk.

channel = 0 thru 7,  ignored

Example: ACTIVEText( 2, "?cmd=restart");      // stops and restarts the capture, discarding the previous trace.

Embedded Firmware

A key component to the Active-Pro™ system is the firmware that runs on your embedded microcontroller.  The microcontroller sends debug information out a pair of general purpose I/O lines (GPIO) whenever you want to see a state, location or variable of your code in real-time operation.  To send out this data you call one of 3 API routines that we provide below. 

The firmware source code below is embedded in your firmware project and provides simple API routines that can be called any time your firmware wants to output information.  Similar to printf(...), you can quickly add single lines of code to output a new set of information at exactly the correct time.

To use this firmware source code, copy the source into your project (either inline or in a new source file).  Then modify the contents between the MAKE YOUR CHANGES comments.  These modifications define how to set the output level of the two GPIO signals as well as other platform specific settings.  See the source code comments below for more details.

Program and Data Usage

The following source code uses the following resources (ROM and RAM) for these various processors and compilers.

             (ROM)    (RAM)
 Processor   Program  Data   Notes
 ----------  -------  ----   -------------------------------------
 Arduino       2132    268   With VARIABLE_ARGUMENT_SUPPORT 
 Arduino        554     14   Without VARIABLE_ARGUMENT_SUPPORT 
 PSoC 5LP      3072    368   With VARIABLE_ARGUMENT_SUPPORT 
 PSoC 5LP       512     19   Without VARIABLE_ARGUMENT_SUPPORT 
 STM EFM32     3152    315   With VARIABLE_ARGUMENT_SUPPORT
 STM EFM32      920      9   Without VARIABLE_ARGUMENT_SUPPORT 
 PIC XC32     15684    628   With VARIABLE_ARGUMENT_SUPPORT
 PIC XC32      2096     16   Without VARIABLE_ARGUMENT_SUPPORT

Source Code in C

The following is the source code to include in your firmware project.  The following code shows how to call the routines from your application. You need to first call ACTIVEInit() at the beginning of your application. You can then place ACTIVEText, ACTIVEValue or ACTIVEprintf() calls wherever you need to output a debug string or value.

#include <Wire.h>
#include "active.h"

#include "SparkFun_BMA400_Arduino_Library.h"

// Create a new sensor object
BMA400 accelerometer;

// I2C address selection
uint8_t i2cAddress = BMA400_I2C_ADDRESS_DEFAULT; // 0x14

void setup()
{
  ACTIVEInit();  // Call this routine to configure any hardware used by the ACTIVE Bus

  ACTIVEText( 0, "Hello World" );   // Debug Text Output

  // Initialize the I2C library
  Wire.begin();

  // Check if sensor is connected and initialize
  while(accelerometer.beginI2C(i2cAddress) != BMA400_OK)
  {
      // Wait a bit to see if connection is established
      delay(1000);
  }
}

void loop()
{
  // Get measurements from the sensor
  accelerometer.getSensorData();

  // Send the values to the Active-Pro Firmware Debugger
  ACTIVEValue( 1, accelerometer.data.accelX * 100);
  ACTIVEValue( 2, accelerometer.data.accelY * 100);
  ACTIVEValue( 3, accelerometer.data.accelZ * 100);
}

Output of the above code showing the ACTIVEText and ACTIVEValue debug outputs


ACTIVE.C

/* =============================================================
ACTIVE-PRO Firmware Debugger
Debug Output Routines 
Provided by activefirmwaretools.com

This file is to be included in your embedded firmware project to 
send debug information to the ACTIVE-PRO Firmware Debugger.

If you have any questions or issues, please email us at
support@activefirmwaretools.com.
===============================================================*/

#define ACTIVE_DEBUG_ON // Comment this line out to remove all ACTIVE Debug output from your project

//===============================================================================================
// MAKE MODIFICATIONS FOR YOUR HARDWARE SETUP BELOW THIS LINE
//===============================================================================================
// CHANGE #1:  Add any includes that you need for the interface to your hardware to the ACTIVE bus
#include "Arduino.h"    // for Arduino Projects
#include "SPI.h"        // for SPI hardware interface

// CHANGE #2:  Modify this routine to set up the interface from this processor to the ACTIVE bus
void ACTIVEInit( void )
{
    // Setup your hardware components for the ACTIVE Debug interface.  Uncomment the mode you want to use or create your own
    // based on the processor you are using.

    // 1-Wire UART Interface
    //  Serial.begin(3000000, SERIAL_8N1, -1, 1);    // Use IO1 as the output signal at 3MBaud, No parity, 8 data bits, 1 stop bit
  
    // 2-wire SPI Interface
    SPI.begin(18, -1, 19);       // Initialize the SPI block and assign pins
    SPI.setFrequency(40000000);  // Set the SPI SCK frequency to 40MHz

    // 2-wire GPIO Interface
    //  pinMode(CLOCK_PIN, OUTPUT);   // Set the CLOCK to an Output (Arduino Style)
    //  pinMode(DATA_PIN, OUTPUT);    // Set the DATA to an Output (Arduino Style)
    //  ACTIVE_CLOCK_SetDriveMode( PIN_DM_STRONG );  // Set the CLOCK to an Output (PSoC Style)
    //  ACTIVE_DATA_SetDriveMode( PIN_DM_STRONG );   // Set the DATA to an Output (PSoC Style)
}

// CHANGE #3:  Modify this routine to send an array of bytes to the the ACTIVE Debug Interface
void SendACTIVEPacket( unsigned char *data, int length )   // This routine is used to send a packet to the ACTIVE Debug Interface
{
    // Send the packet out the wires

    // 2-wire SPI Interface
    SPI.writeBytes( data, length );   // Send the packet directly to the SPI hardware (ESP32 Arduino version)

    // 1-wire UART Interface
    //  Serial.write( data, length );   // Send the packet directly to the UART hardware (ESP32 Arduino version)

    // 2-wire GPIO Interface
    // unsigned char value;
    // while(length--)
    // {
    //     // Send the next byte of data
    //     value = *data++;
    //     // Set the DATA line, and toggle the CLOCK for each bit, MSbit first  (PSoC Style)  
    //     //  Replace the calls here for your calls to set the GPIO output level of the DATA and CLOCK lines.
    //
    //     if (value & 0x80) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x40) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x20) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x10) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x08) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x04) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x02) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    //     if (value & 0x01) ACTIVE_DATA_Write(1); else  ACTIVE_DATA_Write(0); ACTIVE_CLOCK_Write(1); ACTIVE_CLOCK_Write(0);  
    // }

} 
//===============================================================================================
// MAKE MODIFICATIONS FOR YOUR HARDWARE SETUP ABOVE THIS LINE ONLY
//===============================================================================================

//===============================================================================================
// Define the basic Value and Text ACTIVE Message transmit routines
//===============================================================================================
#ifdef ACTIVE_DEBUG_ON

#define MAX_ACTIVE_LENGTH 255 // This defines the maximum length of any debug message
unsigned char ACTIVETxBuffer[MAX_ACTIVE_LENGTH];    // Holds the debug packet as it is being built

void ACTIVEValue( int channel, int value )
{
    int length = 0;
    char done = 0;
    char positive = (value >= 0);
    
    // Assemble the ACTIVE Value Packet

    ACTIVETxBuffer[length++] = 0x7F;           // Every ACTIVE packet starts with a 0x7F
    ACTIVETxBuffer[length++] = channel & 0x3F; // Type and Channel: Bit 7=0, Bit 6=0 Means Value, Bits 5:0 means the channel (0-63)

    while(!done)
    {
        if ((positive && (value >= 32)) || (!positive && (value < -32)))
        {
            ACTIVETxBuffer[length++] = value & 0x3F;
            value = value >> 6;
        }
        else
        {
            ACTIVETxBuffer[length++] =  (value & 0x3F ) | 0x40;
            done = 1;
        }
    }

    // Now actually send the packet to the Active-Pro
    SendACTIVEPacket(ACTIVETxBuffer, length);
}

void ACTIVEText( int channel, char *string )
{
    int length = 0;

    ACTIVETxBuffer[length++] = 0x7F;   // Every ACTIVE packet starts with a 0x7F
    ACTIVETxBuffer[length++] = 0x40 | (channel & 0x3F); // Type and Channel: Bit 7=0, Bit 6=1 Means Text, Bits 5:0 means the channel (0-63)
    
    while(*string)
    {
        if (length >= MAX_ACTIVE_LENGTH-1)
            break;
        ACTIVETxBuffer[length++] = *string & 0x7F;     // Send the ascii characters
        string++;
        
    }
    ACTIVETxBuffer[length++] = 0;     // Send the string termination
        
    // Now actually send the packet to the Active-Pro
    SendACTIVEPacket(ACTIVETxBuffer, length);

}

//===============================================================================================
// Define the printf-like ACTIVE message routine
//===============================================================================================
#include "stdio.h"
#include <stdarg.h>   // va_list, va_start, and va_end
char ACTIVEstr[MAX_ACTIVE_LENGTH];
void ACTIVEprintf( int channel, char *format, ... )
{
    va_list arglist;
    va_start( arglist, format );
    vsprintf( ACTIVEstr, format, arglist );
    va_end( arglist );
    ACTIVEText( channel, ACTIVEstr );
};

#else       // ACTIVE Debug is turned off, so make empty stubs for all routines
void ACTIVEInit( void ) {};
void ACTIVEText( int channel, char *string ) {};
void ACTIVEValue( int channel, int value ) {};
void ACTIVEprintf( int channel, char *format, ... ) {};
#endif

ACTIVE.H

#ifndef ACTIVE_DEBUG_H
#define ACTIVE_DEBUG_H
   
void ACTIVEInit( void );                             // Initialize any hardware needed by the ACTIVE Interface
void ACTIVEValue( int channel, int value );          // Output a Value for this channel
void ACTIVEText( int channel, char *string );        // Output Text for this channel
void ACTIVEprintf( int channel, char *format, ... ); // printf-like function with variable argument list

// Define helpful macros for sending debug command messages
#define ACTIVELabel(channel,string)  ACTIVEText( (channel) , "?cmd=label&label=" string )
#define ACTIVEBeep()  ACTIVEText( 0 , "?cmd=beep" )
#define ACTIVEStop()  ACTIVEText( 0 , "?cmd=stop" )
#define ACTIVERestart()  ACTIVEText( 0 , "?cmd=restart" )

#endif

Source Code in Verilog

//===================================================================================
// Example Use of the Active-Pro Debug Output in the TOP module
//===================================================================================

localparam logic [0:255][15:0] HEXTOA = {
     "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
     "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
     "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
     "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
     "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
     "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
     "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
     "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
     "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
     "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
     "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
     "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
     "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
     "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
     "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
     "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"
     };

module top (
    // Active-Pro output pins
    output ACTIVE_CLOCK,
    output ACTIVE_DATA

    // Other module I/O
    );

    //===================================================================================
    // ACTIVE Debug Output Section
    //===================================================================================
   
    // Active-Pro Debug registers
    reg [63:0][7:0] ACTIVE_MESSAGE; 
    reg [5:0] ACTIVE_CHANNEL; 
    reg ACTIVE_WR;

    ACTIVEPRO myactivepro (
        .RESET(RESET),
        .SYS_CLOCK(SYS_CLOCK),              // Output clock is half this clock
        .ACTIVE_DATA(ACTIVE_DATA),          // Active Debug Port Output Data
        .ACTIVE_CLOCK(ACTIVE_CLOCK),        // Active Debug Port Output Clock
        .ACTIVE_MESSAGE(ACTIVE_MESSAGE),    // 0 (zero) surrounded debug text message
        .ACTIVE_CHANNEL(ACTIVE_CHANNEL),    // Active Debug Port channel to use
        .ACTIVE_WR(ACTIVE_WR)               // Write strobe to send the above message to the above channel
    );

    // Example usage that sends Active Debug Messages
    reg OLD_POWER_ON;
    
    // Output debug messages
    always @(posedge SYS_CLOCK)
    begin
        
        ACTIVE_WR <= 0;
        
        if (POWER_ON != OLD_POWER_ON)
        begin
            OLD_POWER_ON <= POWER_ON;
            
            if (POWER_ON)
                ACTIVE_MESSAGE <= {"\0POWER ON\0"};
            else
                ACTIVE_MESSAGE <= {"\0POWER OFF\0"};
            ACTIVE_CHANNEL <= 2;
            ACTIVE_WR <= 1;
        end
        
        if (SEND_UNSOLICITED_MESSAGE)
        begin
            ACTIVE_MESSAGE <= {"\0Uns Msg:", HEXTOA[UNSOLICITED_MESSAGE], "\0"};
            ACTIVE_CHANNEL <= 4;
            ACTIVE_WR <= 1;
        end

        if (WRITE_STROBE)
        begin
            ACTIVE_MESSAGE <= {"\0WrReg:", HEXTOA[WRITE_REGISTER], " Data:", HEXTOA[WRITE_DATA], "\0"};
            ACTIVE_CHANNEL <= 4;
            ACTIVE_WR <= 1;
        end

        if (KIV_RX_FIFO_RD == 1)        // Done processing a CHSI message.  Tell us what the CMD code is
        begin                           // This happens when we are flushing the command from the FIFO
            ACTIVE_MESSAGE <= {"\0ID ", HEXTOA[KIV_RX_PACKET.bytes[1]], "\0"};
            ACTIVE_CHANNEL <= 1;
            ACTIVE_WR <= 1;
        end
        
        
    end

endmodule


//===================================================================================
// Active-Pro Debug Output Module
//
// This module takes a byte array input that starts and ends with a 0 (zero), 
// computes the length, and clocks out the Active Debug Port packet to send the 
// text message to the requested channel.
//===================================================================================

module ACTIVEPRO (

    // Reset and Clock
    input       RESET,
    input       SYS_CLOCK,               // Output clock is half this clock
    
    // Output - ACTIVE Clock and Data
    output reg  ACTIVE_DATA ,            // Active Debug Port Output Data
    output reg  ACTIVE_CLOCK,            // Active Debug Port Output Clock
    
    // Input - ACTIVE Debug Message
    input [63:0][7:0] ACTIVE_MESSAGE,    // 0 (zero) surrounded debug text message
    input [5:0] ACTIVE_CHANNEL,          // Active Debug Port channel to use
    input  ACTIVE_WR                     // Write strobe to send the above message to the above channel
    
    );
    
    reg [63:0][7:0] ACTIVE_MESSAGE_LATCHED; 
    reg [7:0] MESSAGE_LENGTH;
    
    reg [14:0] state;
    wire clockstate;
    wire [2:0] bitcount;
    wire [7:0] bytecount;
    
    assign clockstate = state[0];
    assign bitcount[2:0] = state[3:1];
    assign bytecount[7:0] = state[11:4];
    
    wire [7:0] FIRST_BYTE;
    assign FIRST_BYTE = 8'h7F;
    wire [7:0] SECOND_BYTE;
    assign SECOND_BYTE = (ACTIVE_CHANNEL & 8'h3F) | 8'h40;
    reg [7:0] clock_divider;
    
    always @ (posedge SYS_CLOCK)
    begin
    
        if (RESET)
        begin
            state <= 0;
            ACTIVE_CLOCK <= 0;
            ACTIVE_DATA <= 0;
        end
        else
        begin

            // Find out the length of this message by counting the bytes until we see a 0
            for (int x = 1; x < 64; x++)  // The first byte is a 0, used to terminate the string on the Active Bus
            begin
              if (ACTIVE_MESSAGE_LATCHED[x] == 8'h0)
                begin
                    MESSAGE_LENGTH <= x + 2;        // Include the 2 header bytes
                    break;
                end
            end
            
            if (state)
            begin
                state <= state + 1;
                
                if (clockstate == 1)   // Send out the bit
                begin
                    ACTIVE_CLOCK <= 0;
                        
                    if (bytecount == 0)
                        ACTIVE_DATA <= FIRST_BYTE[7-bitcount];
                    else if (bytecount == 1)
                        ACTIVE_DATA <= SECOND_BYTE[7-bitcount];
                    else
                        ACTIVE_DATA <= ACTIVE_MESSAGE_LATCHED[MESSAGE_LENGTH - bytecount - 1][7-bitcount];
                end
                else if (clockstate == 0)  ACTIVE_CLOCK <= 1;

                if (bytecount >= MESSAGE_LENGTH) state <= 0;

            end
            else        // Not sending out a message, see if we should send a new one
            begin
                if (ACTIVE_WR) 
                begin
                    state <= 1;     // Start clocking out the data
                    ACTIVE_MESSAGE_LATCHED <= ACTIVE_MESSAGE;
                end
            end
        end
        
    end
endmodule 

Source Code in VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Active_Module is
    Port (
        SYS_CLOCK      : in  std_logic;                      -- system clock
        ACTIVE_MESSAGE : in  std_logic_vector(511 downto 0); -- 64 bytes array (64 * 8 = 512 bits)
        ACTIVE_CHANNEL : in  std_logic_vector(5 downto 0);   -- 6-bit variable
        ACTIVE_WR      : in  std_logic;                      -- single bit variable
        ACTIVE_CLOCK   : out std_logic;                      -- single bit output
        ACTIVE_DATA    : out std_logic                       -- single bit output
    );
end Active_Module;

architecture Behavioral of Active_Module is
    signal total_message_length        : integer := 0;
    signal bit_counter                 : integer := 0;
    signal byte_counter                : integer := 0;
    signal state                       : integer := 0;
    signal active_message_byte_index   : integer := 0;
    signal latched_message             : std_logic_vector(511 downto 0);
    signal first_byte                  : std_logic_vector(7 downto 0);
    signal second_byte                 : std_logic_vector(7 downto 0);
    signal next_byte                   : std_logic_vector(7 downto 0);
begin

    -- Data sending process
    process(SYS_CLOCK)
    begin
        if falling_edge(SYS_CLOCK) then
            if ACTIVE_WR = '1' then
                -- Reset counters and prepare to send data
                byte_counter <= 0;
                bit_counter <= 0;       
                total_message_length <= 0;

                first_byte <= "01111111";
                second_byte <= "01" & ACTIVE_CHANNEL;
                
                -- Calculate total_message_length
                for i in 1 to 63 loop
                    if ACTIVE_MESSAGE((i*8) + 7 downto (i*8)) = "00000000" then
                        total_message_length <= i + 2;     -- Add the header bytes
                        exit;
                    end if;
                end loop;

                -- Store the message to be sent
                latched_message <= ACTIVE_MESSAGE;
                
                state <= 0;

            elsif byte_counter < total_message_length then
            
                if state = 0 then
                    state <= 1;
                    -- Output the next bit
                    ACTIVE_CLOCK <= '0';
                    if byte_counter = 0 then
                        ACTIVE_DATA <= first_byte(7 - bit_counter);
                    elsif byte_counter = 1 then
                        ACTIVE_DATA <= second_byte(7 - bit_counter);
                        active_message_byte_index <= total_message_length - 3;  -- start past the beginning 0
                    else
                        ACTIVE_DATA <= next_byte(7 - bit_counter);
                    end if;


                else
                    ACTIVE_CLOCK <= '1';
                    state <= 0;
                    -- Update the bit and byte counters
                    if bit_counter = 7 then
                        bit_counter <= 0;
                        byte_counter <= byte_counter + 1;
                        active_message_byte_index <= active_message_byte_index - 1;
                        next_byte <= latched_message((active_message_byte_index * 8) + 7 downto (active_message_byte_index * 8));
                    else
                        bit_counter <= bit_counter + 1;
                    end if;                
                end if;
            else
                ACTIVE_CLOCK <= '1';
            end if;
        end if;
    end process;

end Behavioral;

Source Code in Python

# =============================================================
# ACTIVE-PRO Firmware Debugger
# Debug Output Routines 
# Provided by activefirmwaretools.com
#
# This file is to be included in your embedded firmware project to 
# send debug information to the ACTIVE-PRO Firmware Debugger.
#
# If you have any questions or issues, please email us at
# support@activefirmwaretools.com.
# =============================================================

# Define ACTIVE_DEBUG_ON to enable debug output
ACTIVE_DEBUG_ON = True

if ACTIVE_DEBUG_ON:
    import spidev
    import serial

    # Setup your hardware components for the ACTIVE Debug interface
    def ACTIVEInit():
        global spi, uart
        spi = spidev.SpiDev()
        spi.open(0, 0)  # Adjust bus and device as per your setup
        spi.max_speed_hz = 40000000

        uart = serial.Serial()
        uart.baudrate = 3000000
        uart.port = '/dev/ttyS0'  # Adjust as per your setup
        uart.open()

    # Send an array of bytes to the ACTIVE Debug Interface
    def SendACTIVEPacket(data):
        # Send the packet out the wires

        # 2-wire SPI Interface
        spi.xfer2(data)

        # 1-wire UART Interface
        uart.write(bytearray(data))

    MAX_ACTIVE_LENGTH = 255  # This defines the maximum length of any debug message
    ACTIVETxBuffer = bytearray(MAX_ACTIVE_LENGTH)  # Holds the debug packet as it is being built

    def ACTIVEValue(channel, value):
        length = 0
        done = False
        positive = value >= 0

        # Assemble the ACTIVE Value Packet
        ACTIVETxBuffer[length] = 0x7F
        length += 1
        ACTIVETxBuffer[length] = channel & 0x3F  # Type and Channel
        length += 1

        while not done:
            if (positive and value >= 32) or (not positive and value < -32):
                ACTIVETxBuffer[length] = value & 0x3F
                value >>= 6
                length += 1
            else:
                ACTIVETxBuffer[length] = (value & 0x3F) | 0x40
                done = True
                length += 1

        # Now actually send the packet to the Active-Pro
        SendACTIVEPacket(ACTIVETxBuffer[:length])

    def ACTIVEText(channel, string):
        length = 0

        ACTIVETxBuffer[length] = 0x7F
        length += 1
        ACTIVETxBuffer[length] = 0x40 | (channel & 0x3F)
        length += 1

        for char in string:
            if length >= MAX_ACTIVE_LENGTH - 1:
                break
            ACTIVETxBuffer[length] = ord(char) & 0x7F
            length += 1

        ACTIVETxBuffer[length] = 0  # Send the string termination
        length += 1

        # Now actually send the packet to the Active-Pro
        SendACTIVEPacket(ACTIVETxBuffer[:length])

    def ACTIVEprintf(channel, format_string, *args):
        ACTIVEstr = format_string % args
        ACTIVEText(channel, ACTIVEstr)

else:
    # ACTIVE Debug is turned off, so make empty stubs for all routines
    def ACTIVEInit():
        pass

    def ACTIVEText(channel, string):
        pass

    def ACTIVEValue(channel, value):
        pass

    def ACTIVEprintf(channel, format_string, *args):
        pass
Previous
Previous

Packet Presenter

Next
Next

Trace Events to Source Code