Hubo LED Display Tutorial Series:

Tutorial 3: Software Running on the DSP

Keywords: LED Array, TMS320F2808, Texas Instruments DSP, Hubo KHR-4, Hubo, Hubo Lab

The photo shows what the software (TI Code Composer Studio 3.1) looks like.  This software allows you to develop and download the code for the F28xx series DSP's. Solving this partially or completely is important because without the IDE for the DSP, the Hubo LED display is pretty much pointless.  This tutorial shows you how to open the project file, and download the source code of the DSP and takes approximately 1-2 hours to complete depending on your current skill level.


Motivation and Audience

This tutorial's motivation is to download and flash the firmware (program code) onto the DSP F2808 board. Readers of this tutorial assumes the reader has the following background and interests:

The rest of the tutorial is presented as follows:

Parts List and Sources

To complete this tutorial, you'll need the following items:

TABLE 1: Parts needed to build (fill in the blank)

PART DESCRIPTION

VENDOR

PART

PRICE (1999)

QTY

Texas Instruments Code Composer Studio 3.1 for C2400 devices

Texas Instruments

---

License varies, but ~$1000

1

**Note: Code Composer Studio does not have to be purchased per-device.  It usually is a per computer or per-organization license.

Construction

This section gives step-by-step instructions along with photos to complete the programming of the DSP firmware for the Hubo LED Display.  Most of this tutorial talk about the software running in the DSP during operation. 

Step 1 - Opening the Project File in Code Composer Studio 3.1

    The first item to do before you start with Code Composer Studio is to download my project file.  Click here to download.  This folder (zipped) contains all the necessary programs to flash the DSP in the F2808 board (that you may have built in my earlier tutorial).  From now on, I will refer to TI Code Composer Studio as CCS to keep the writing simple.  Once you download the project folder, and unzip it to a easily accessible location (like My Documents), open CCS.  If all goes well, and there are no issues starting the IDE (If you encounter any problems with the JTAG Emulation, or setup, this is beyond the scope of this document and will not be covered.  There are MANY emulators available to communicate with the TI DSP's), navigate to Project > Open.  In the pop-up window, navigate to your unzipped folder, and select the *.pjt file for opening.  If you are using my file, this will be HuboDisplay_v100.pjt.  The project will not be open and seen on the left in the browser navigation tree.

    Once the project opens, you should see something similar to this:

To navigate to the main program, go to Source > HuboDisplay_v100.c.  This is the place where all the programming magic happens!

 

Step 2 - Connecting the DSP to CCS

    In this section, I will cover connecting the DSP to Code Composer Studio.  Because of the many different emulators available for the TMS320F2808 DSP, I will be focusing on (and only supporting the Xds510PP Emulator from Spectrum Digital Inc. This screenshot shows my setup configuration for the Parallel Port Emulator:

   

** Note: A key point to address is the setting of the port type (EPP vs. SPP4 vs. SPP).  It does not matter which you use, just make sure that the BIOS and the configuration utility are set to the same type.

    At this point, CCS should know what DSP's are configured to the system, so it is then possible to connect through the JTAG Port.  The parallel port emulator draws its power from the DSP board through the header (5v.), so the DSP has to be powered before you intend to connect to the DSP.  Once powered up, and in CCS, press the hotkey ALT + C, or navigate to Debug >Connect.  See screenshot below:

If the connection is successful, you will then see a window pop up with a bunch of hex number addresses in it, with an arrow pointing to one of the numbers.  This indicates that the JTAG Emulator was successful in connecting with the DSP, and the DSP is halted (no code is running).  See below for a picture:

 

 

Step 3 - Using the DSP Flash utility for CCS

    The flash utility for Code Composer Studio is an after-market add-on.  This allows for easy integration of simple downloading, with a powerful front end for DSP configuration.  I will only be using the Execute Operation button.  When you click this button, all the compiled code is gathered automatically by the utility, and is written into the flash on the microcontroller. 

Below is a screenshot of the flash utility.  As you can see, it has a wide range of functionality, but to keep it simple, we will be using the "Execute Operation" button to flash the code to the DSP.

 

Step 4 - Running the Code on the DSP

    After the download completes successfully, you can now close the window.  With the JTAG still connected, simply click the "Run" button on the far left of CCS.  This will use the JTAG, and command the DSP to run as if it would without the JTAG (no single-stepping or function-stepping).  For information on hoe to single step through your own code, consult the user manual for Code Composer Studio.  For more information, there is also a large TI forums and information database free to use.

If all went well, the DSP should now be running and the display is working!

Programming

    If you wish to dive further into the control code, the main program file is below (HuboDisplay_v100.c).  The code is pretty much self explanatory using the comments.  Not all lines are commented, but the main parts have explanations on how they work, and why they are needed.


To be compiled with Code Composer Studio 3.1 for C2400
Note: download HuboDisplay_v100.pjt file rather than cutting and pasting the main code from below. This only shows the Main program, the project includes support files for the main program. For a copy of the main program, click here (for the HuboDisplay_v100.c file)
//###########################################################################
// $ Bryan Kobe
// $ TMS2808, Hubo2 LED Display for the Head Visor
// $ Release Date: February 23, 2008 $
//###########################################################################

//###########################################################################
// Updated 
// 1. Nothing yet. First Release 
//###########################################################################

#include <stdio.h>
#include "DSP280x_Device.h" // DSP280x Headerfile Include File
#include "DSP280x_Examples.h" // DSP280x Examples Include File

// #### PARAMETER SETTING ####################################################
// Place parameter variables here for setting program.
#define BoardNo 0x50 // This is the CAN address that the PC talks to.
#define NameInfo 0x01 

// #### GAIN SETTING #########################################################
// Place any gain settings here for control


// #### BOOT TO FLASH ########################################################
#pragma CODE_SECTION(cpu_timer0_isr, "ramfuncs");
// #pragma CODE_SECTION(can_isr, "ramfuncs");

// #### DECLARATION OF FUNCTIONS #############################################
// 1. CPU Interrupt Functions
interrupt void cpu_timer0_isr(void);

// 2. GPIO Functions
void Gpio_select(void);
void SetGPIOPins(unsigned long leds);
void ClearAllPins(void);
void Pause(unsigned int _counts);

// #### DECLARATION OF VARIABLES #############################################
int lineactive = 0;

// The led_data array sets the bits for each row of the display. 
// Row 1 = 0x10------, Row 2 = 0x20------, and so on...
// Write to this variable array to light up the LED's 
// LSB = left most LED (4th Quadrant cartesian coordinates, so TOP LEFT LED = row 1, column 1)
// Note: The MSByte is only used to indicate line number, no control is used with the MSByte
// To CLEAR the display, write: {0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000};
unsigned long led_data[] = {0x10080001,0x20040002,0x30020004,0x40010008,0x50000000};

struct ECAN_REGS ECanaShadow_main;
struct ECAN_MBOXES ECanMboxShadow;

// These are defined by the linker (see F2808.cmd) For writting FLASH
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
// End of Declaration of Variables

// #### MAIN CONTROL PROGRAM ################################################
void main(void)
{
// Step 1. Initialize System Control
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP280x_SysCtrl.c file.
InitSysCtrl();

// Step 2. Initalize GPIO
// This example function is found in the DSP280x_Gpio.c file and
// illustrates how to set the GPIO to it's default state for the program
Gpio_select();

// Step 3. Clear all interrupts and initialize PIE vector table
// Disable CPU interrupts 
DINT;

// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared. 
// This function is found in the DSP280x_PieCtrl.c file.
InitPieCtrl();

// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt 
// Service Routines (ISR). 
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP280x_DefaultIsr.c.
// This function is found in DSP280x_PieVect.c.
InitPieVectTable();

// Initialize the CAN bus and set parameters
InitECana();
// Receiving MBOX0 
ECanMboxShadow.MBOX0.MSGID.bit.AAM = 0; // auto answer mode off
ECanMboxShadow.MBOX0.MSGID.bit.AME = 0; // accpetance mask enable
ECanMboxShadow.MBOX0.MSGID.bit.IDE = 0; // the message to be received must have a standard id when AMI=0
ECanMboxShadow.MBOX0.MSGID.bit.STDMSGID = 0x01;
ECanaMboxes.MBOX0.MSGID.all = ECanMboxShadow.MBOX0.MSGID.all; // Standard Identifier, Acceptance mask disable
// Receiving MBOX0

// Configure Mailbox under test as a Transmit mailbox

ECanaShadow_main.CANMD.all = ECanaRegs.CANMD.all; 
ECanaShadow_main.CANMD.bit.MD0 = 1; // Mailbox 0 : receiving mailbox
ECanaShadow_main.CANMD.bit.MD1 = 0; // Mailbox 1 : transmit mailbox
ECanaShadow_main.CANMD.bit.MD2 = 1; // Mailbox 2 : receiving mailbox
ECanaShadow_main.CANMD.bit.MD3 = 0; // Mailbox 3 : transmit mailbox
ECanaRegs.CANMD.all = ECanaShadow_main.CANMD.all; 

// Enable Mailboxes
ECanaShadow_main.CANME.all = ECanaRegs.CANME.all; 
ECanaShadow_main.CANME.bit.ME0 = 1;
ECanaShadow_main.CANME.bit.ME1 = 1;
ECanaShadow_main.CANME.bit.ME2 = 1;
ECanaShadow_main.CANME.bit.ME3 = 1;
ECanaRegs.CANME.all = ECanaShadow_main.CANME.all;

// Setting up Global Interrupt Mask Register
EALLOW;
ECanaShadow_main.CANGIM.all = ECanaRegs.CANGIM.all; 
ECanaShadow_main.CANGIM.bit.MTOM = 0; 
ECanaShadow_main.CANGIM.bit.TCOM = 0;
ECanaShadow_main.CANGIM.bit.AAIM = 0;
ECanaShadow_main.CANGIM.bit.WDIM = 0;
ECanaShadow_main.CANGIM.bit.WUIM = 0;
ECanaShadow_main.CANGIM.bit.RMLIM = 0;
ECanaShadow_main.CANGIM.bit.BOIM = 0;
ECanaShadow_main.CANGIM.bit.EPIM = 0;
ECanaShadow_main.CANGIM.bit.WLIM = 0;
ECanaShadow_main.CANGIM.bit.GIL = 0; // All global interrupts are mapped to the ECAN0INT interrupt line
ECanaShadow_main.CANGIM.bit.I1EN = 0;
ECanaShadow_main.CANGIM.bit.I0EN = 1;
ECanaRegs.CANGIM.all = ECanaShadow_main.CANGIM.all; 
EDIS;

ECanaShadow_main.CANOPC.all = ECanaRegs.CANOPC.all;
ECanaShadow_main.CANOPC.all = 0x00000000;
ECanaRegs.CANOPC.all = ECanaShadow_main.CANOPC.all;


EALLOW;
ECanaRegs.CANMIM.all = 0x00000005; // Mailbox Interrupt Mask. MBOX0, MBOX2 : mailbox interrupt is enabled
ECanaShadow_main.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow_main.CANMC.bit.DBO = 1; // Data Byte Order : the data is received or transmitted least significant byte first 
ECanaRegs.CANMC.all = ECanaShadow_main.CANMC.all;
EDIS;
ECanaRegs.CANMIL.all = 0x00000000; // Mailbox Interrupt Level: All mailboxes' interrupts are generated 
// on interrupt line 0 
// End of CAN initialization

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file. 
EALLOW; // This is needed to write to EALLOW protected registers

// CPU Timer Interrupt
PieVectTable.TINT0 = &cpu_timer0_isr;

EDIS; // This is needed to disable write to EALLOW protected registers


// Step 4. Initialize all the Device Peripherals
// This function is found in DSP280x_InitPeripherals.c
InitCpuTimers();

// Configure CPU-Timer 0 to interrupt at given time period
ConfigCpuTimer(&CpuTimer0, 100, 1000); // 1kHz : 1000, 100Hz : 10000
StartCpuTimer0();

// Step 5. User specific code, enable interrupts
// Copy time critical code and Flash setup code to RAM

// The RamfuncsLoadStart, RamfuncsLoadEnd, and RamfuncsRunStart
// symbols are created by the linker. Refer to the F2808.cmd file. 

// Copy the Flash API functions to SARAM
MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);

// Call Flash Initialization to setup flash waitstates
// This function must reside in RAM
InitFlash();

// Enable CPU INT1 which is connected to CPU-Timer 0:
IER |= M_INT1; // Enable CPU INT
IER |= M_INT9; // Enable PIE Group 9 for SCIB

// Enable TINT0 in the PIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // cpu interrupt
PieCtrlRegs.PIEIER9.bit.INTx3 = 1; // PIE Group 9, INT3 // SCIB_RX
PieCtrlRegs.PIEIER9.bit.INTx4 = 1; // PIE Group 9, INT3 // SCIB_TX

// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM 

// Step 6. IDLE loop. Just sit and loop (or place control code here for CAN Communication

for(;;) { // Demonstration Program this only shows preset graphics - take out for your own code!
// Displaying Text - Hubo 2
led_data[0] = 393477;
led_data[1] = 532741;
led_data[2] = 283479;
led_data[3] = 152917;
led_data[4] = 926501;
Pause(20000);
// Displaying Text - by :
led_data[0] = 162;
led_data[1] = 162;
led_data[2] = 1222;
led_data[3] = 138;
led_data[4] = 1126;
Pause(10000);
// Displaying Text - Bryan
led_data[0] = 1283;
led_data[1] = 9477;
led_data[2] = 218659;
led_data[3] = 357461;
led_data[4] = 348947;
Pause(20000);
// Happy Eyes
led_data[0] = 0x10000000;
led_data[1] = 0x2003000C;
led_data[2] = 0x300C8013;
led_data[3] = 0x40000000;
led_data[4] = 0x50000000;
Pause(20000);
// Regular Eyes
led_data[0] = 0x10000000;
led_data[1] = 0x20020004;
led_data[2] = 0x3007000E;
led_data[3] = 0x40020004;
led_data[4] = 0x50000000;
Pause(20000);
// Angry Eyes
led_data[0] = 0x10080001;
led_data[1] = 0x20040002;
led_data[2] = 0x30020004;
led_data[3] = 0x40010008;
led_data[4] = 0x50000000;
Pause(20000);

// To write data to the display (turning on and off the LED's), write data into the led_data[] array
// Line 1 corresponds to led_data[0], line 2 = led_data[1], etc. 
// The ISR takes care of writing the data to the outputs, only wirte to these variables in the Main() loop! 


/* This example CAN code is taken from the IMU sontrol code. Refer to it for more information on CAN
switch(ECanaRegs.CANGIF0.bit.MIV0) {
// Hubo TX_Byte = 0x Byte7 Byte7 ... Byte0
// MDL.byte = 0x BYTE0 BYTE1 BYTE2 BYTE3 when DBO=1
// MDH.byte = 0x BYTE4 BYTE5 BYTE6 BYTE7 when DBO=1
case 0:
if(ECanaMboxes.MBOX0.MDL.byte.BYTE3 == BoardNo &&
ECanaMboxes.MBOX0.MDL.byte.BYTE2 == NameInfo)
{ 
SendCAN(0x00000000, 0x00000100, GYRO_NAME_RXDF); // send data for CAN check
//bCAN_check = 1;
}
ECanaRegs.CANRMP.all = 0x00000001;
break;

case 2:
//if(ECanaMboxes.MBOX2.MDL.byte.BYTE3 == 0x00 &&
// bCAN_check == 1 &&
// (bSCIA_check == 1 || bSCIB_check == 1))
if(ECanaMboxes.MBOX2.MDL.byte.BYTE3 == 0x00)
{
GpioDataRegs.GPBTOGGLE.bit.GPIO33 = 1;
inc_roll_can=(Uint32)(inc_roll_avg_MA);
inc_pitch_can=(Uint32)(inc_pitch_avg_MA);

SendCAN((inc_roll_can & 0x0000FFFF)+((inc_pitch_can & 0x0000FFFF)<<16), (GyroA_rate & 0x0000FFFF)+((GyroC_rate & 0x0000FFFF)<<16), GYRO_VALUE_RXDF); 
}
ECanaRegs.CANRMP.all = 0x00000004;
break;
} */

}
} 
// End of main

// #### LIST OF USED FUNCTIONS ################################################
interrupt void cpu_timer0_isr(void)
{
// Put the Flash into sleep
FlashRegs.FPWR.bit.PWR = FLASH_SLEEP; 

GpioDataRegs.GPASET.bit.GPIO31 = 1; // SET led - for check time for interrupt processing

CpuTimer0.InterruptCount++; // 1 count = 1ms
ClearAllPins();


CpuTimer0.InterruptCount=0;
GpioDataRegs.GPBTOGGLE.bit.GPIO32 = 1;

// Every time the CPU Timer interrupts, the SWITCH statement causes a line change, 
// and writiing the next variable to the display.
switch (lineactive) {
case 0:
// Set the Line 1 transistor HIGH
GpioDataRegs.GPASET.bit.GPIO0 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
break;
case 1:
// Set the Line 2 transistor HIGH
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
GpioDataRegs.GPASET.bit.GPIO1 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
break;
case 2:
// Set the Line 3 transistor HIGH
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
GpioDataRegs.GPASET.bit.GPIO2 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
break;
case 3:
// Set the Line 4 transistor HIGH
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioDataRegs.GPASET.bit.GPIO3 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
break;
case 4:
// Set the Line 5 transistor HIGH
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1;
GpioDataRegs.GPASET.bit.GPIO4 = 1;
break;
case 5:
lineactive = 0;
break;
}

SetGPIOPins(led_data[lineactive]);

lineactive++;

if (lineactive > 4) lineactive = 0;

// Acknowledge this interrupt to receive more interrupts from group 1
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

GpioDataRegs.GPACLEAR.bit.GPIO31 = 1; // CLEAR led - for check time of interrupt processing
}

void SetGPIOPins(unsigned long leds) {
// Column 1
if ((leds & 0x000001) == 0x000001) {
GpioDataRegs.GPACLEAR.bit.GPIO5 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO5 = 1;

// Column 2
if ((leds & 0x000002) == 0x000002) {
GpioDataRegs.GPACLEAR.bit.GPIO6 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO6 = 1;

// Column 3
if ((leds & 0x000004) == 0x000004) {
GpioDataRegs.GPACLEAR.bit.GPIO7 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO7 = 1;

// Column 4
if ((leds & 0x000008) == 0x000008) {
GpioDataRegs.GPACLEAR.bit.GPIO8 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO8 = 1;

// Column 5
if ((leds & 0x000010) == 0x000010) {
GpioDataRegs.GPACLEAR.bit.GPIO9 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO9 = 1;

// Column 6
if ((leds & 0x000020) == 0x000020) {
GpioDataRegs.GPACLEAR.bit.GPIO10 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO10 = 1;

// Column 7
if ((leds & 0x000040) == 0x000040) {
GpioDataRegs.GPACLEAR.bit.GPIO11 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO11 = 1;

// Column 8
if ((leds & 0x000080) == 0x000080) {
GpioDataRegs.GPACLEAR.bit.GPIO12 = 1;
}
else GpioDataRegs.GPASET.bit.GPIO12 = 1;

// For sake of scrolling through this tutorial, I deleted the next 12 columns, but you can see the concept...
// For a more complete look, download wither the project file, or the HuboDisplay_v100.c file.

}

void ClearAllPins(void) {
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1;
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1;
GpioDataRegs.GPASET.bit.GPIO5 = 1;
GpioDataRegs.GPASET.bit.GPIO6 = 1;
GpioDataRegs.GPASET.bit.GPIO7 = 1;
GpioDataRegs.GPASET.bit.GPIO8 = 1;
GpioDataRegs.GPASET.bit.GPIO9 = 1;
GpioDataRegs.GPASET.bit.GPIO10 = 1;
GpioDataRegs.GPASET.bit.GPIO11 = 1;
GpioDataRegs.GPASET.bit.GPIO12 = 1;
GpioDataRegs.GPASET.bit.GPIO13 = 1;
GpioDataRegs.GPASET.bit.GPIO14 = 1;
GpioDataRegs.GPASET.bit.GPIO15 = 1;
GpioDataRegs.GPASET.bit.GPIO16 = 1;
GpioDataRegs.GPASET.bit.GPIO17 = 1;
GpioDataRegs.GPASET.bit.GPIO18 = 1;
GpioDataRegs.GPASET.bit.GPIO19 = 1;
GpioDataRegs.GPASET.bit.GPIO20 = 1;
GpioDataRegs.GPASET.bit.GPIO21 = 1;
GpioDataRegs.GPASET.bit.GPIO22 = 1;
GpioDataRegs.GPASET.bit.GPIO23 = 1;
GpioDataRegs.GPASET.bit.GPIO24 = 1;

}

void Gpio_select(void)
{
EALLOW;

// GPIO0, active high, so set it low: ROW 1
GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // Enable pullup on GPIO0
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // G0/EPWM1A
GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // 1:output, 0:input

// GPIO1, active high, so set it low: ROW 2
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1; // Enable pullup on GPIO1
GpioDataRegs.GPACLEAR.bit.GPIO1 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 0; // G1/EPWM1B/SPISIMOD
GpioCtrlRegs.GPADIR.bit.GPIO1 = 1; // 1:output, 0:input

// GPIO2, active high, so set it low: ROW 3
GpioCtrlRegs.GPAPUD.bit.GPIO2 = 1; // Enable pullup on GPIO2
GpioDataRegs.GPACLEAR.bit.GPIO2 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0; // G2/EPWM2A
GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; // 1:output, 0:input

// GPIO3, active high, so set it low: ROW 4
GpioCtrlRegs.GPAPUD.bit.GPIO3 = 1; // Enable pullup on GPIO3
GpioDataRegs.GPACLEAR.bit.GPIO3 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 0; // G3/EPWM2B/SPISOMID
GpioCtrlRegs.GPADIR.bit.GPIO3 = 1; // 1:output, 0:input

// GPIO4, active high, so set it low: ROW 5
GpioCtrlRegs.GPAPUD.bit.GPIO4 = 1; // Enable pullup on GPIO4
GpioDataRegs.GPACLEAR.bit.GPIO4 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0; // G4/EPWM3A
GpioCtrlRegs.GPADIR.bit.GPIO4 = 1; // 1:output, 0:input

// GPIO5, active low, so set it high: COLUMN 1
GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; // Enable pullup on GPIO5
GpioDataRegs.GPASET.bit.GPIO5 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 0; // G5/EPWM3B/SPICLKD/ECAP1
GpioCtrlRegs.GPADIR.bit.GPIO5 = 1; // 1:output, 0:input

// GPIO6, active low, so set it high: COLUMN 2
GpioCtrlRegs.GPAPUD.bit.GPIO6 = 0; // Enable pullup on GPIO6
GpioDataRegs.GPASET.bit.GPIO6 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 0; // G6/EPWM4A
GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; // 1:output, 0:input

// GPIO7, active low, so set it high: COLUMN 3
GpioCtrlRegs.GPAPUD.bit.GPIO7 = 0; // Enable pullup on GPIO7
GpioDataRegs.GPASET.bit.GPIO7 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO7 = 0; // G7/EPWM4B/SPISTED/ECAP2
GpioCtrlRegs.GPADIR.bit.GPIO7 = 1; // 1:output, 0:input

// GPIO8, active low, so set it high: COLUMN 4
GpioCtrlRegs.GPAPUD.bit.GPIO8 = 0; // Enable pullup on GPIO8
GpioDataRegs.GPASET.bit.GPIO8 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO8 = 0; // G8/EPWM5A/CANTXB/ADCSOCAO
GpioCtrlRegs.GPADIR.bit.GPIO8 = 1; // 1:output, 0:input

// GPIO9, active low, so set it high: COLUMN 5
GpioCtrlRegs.GPAPUD.bit.GPIO9 = 0; // Enable pullup on GPIO9
GpioDataRegs.GPASET.bit.GPIO9 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO9 = 0; // G9/EPWM5B/SCITXDB/ECAP3
GpioCtrlRegs.GPADIR.bit.GPIO9 = 1; // 1:output, 0:input

// GPIO10, active low, so set it high: COLUMN 6
GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0; // Enable pullup on GPIO10
GpioDataRegs.GPASET.bit.GPIO10 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 0; // G10/EPWM6A/CANRXB/ADCSOCBO
GpioCtrlRegs.GPADIR.bit.GPIO10 = 1; // 1:output, 0:input

// GPIO11, active low, so set it high: COLUMN 7
GpioCtrlRegs.GPAPUD.bit.GPIO11 = 0; // Enable pullup on GPIO11
GpioDataRegs.GPASET.bit.GPIO11 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 0; // G11/EPWM6B/SCIRXB/ECAP4
GpioCtrlRegs.GPADIR.bit.GPIO11 = 1; // 1:output, 0:input

// GPIO12, active low, so set it high: COLUMN 8
GpioCtrlRegs.GPAPUD.bit.GPIO12 = 0; // Enable pullup on GPIO12
GpioDataRegs.GPASET.bit.GPIO12 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 0; // G12/TZ1/CANTXB/SPISIMOB
GpioCtrlRegs.GPADIR.bit.GPIO12 = 1; // 1:output, 0:input
// For sake of scrolling through this tutorial, I deleted the next pin definitions, but you can see the concept...
// For a more complete look, download wither the project file, or the HuboDisplay_v100.c file.
// GPIO32, set it low: LED 1
GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0; // Enable pullup on GPIO32
GpioDataRegs.GPBSET.bit.GPIO32 = 1; // Load output latch
GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0; // G32/SDAA/EPWMSYNCI/ADCSOCAO
GpioCtrlRegs.GPBDIR.bit.GPIO32 = 1; // 1:output, 0:input

// GPIO33, set it low: LED 2
GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0; // Enable pullup on GPIO33
GpioDataRegs.GPBSET.bit.GPIO33 = 1; // Load output latch
GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 0; // G33/SCLA/EPWMSYNCO/ADCSOCBO
GpioCtrlRegs.GPBDIR.bit.GPIO33 = 1; // 1:output, 0:input

EDIS; 
}

void Pause(unsigned int _counts) {
short i;
short j;

for(i=0; i < 1000; i++) 
{
for(j=0; j < _counts; j++)
{}
}
}

//===========================================================================
// End of file.
//===========================================================================


 

Final Words

This tutorial's objective was to program the DSP board for the Hubo LED Display visor project. Speculating future work, derived from this tutorial, includes developing code for operation on the hubo CAN bus. In the big picture, the problem of creating an LED Display for the Hubo KHR-4 and programming the display can be solved with this tutorial (Following the three tutorial series).

Click here to email me