The photo shows the completed DSP controller board which allows you to
control the LED array (which we will cover later). The big picture problem is
that there is no "personality" to the Hubo robot, this display will be used to
display facial features on the head.. Solving this partially or completely is important
because knowledge of the Texas Instruments DSP platforms will be gained, as well
as basic knowledge of controls behind the display. This tutorial shows you how
to build the DSP breakout board used in the Hubo Lab and takes approximately 12
hours to complete.
The rest of the tutorial is presented as follows:
To complete this tutorial, you'll need the following items:
| PART DESCRIPTION | VENDOR | PART | PRICE (1999) | QTY | |
| TMS320F2808 | Digikey | 296-18335-ND | $19.50 | 1 | |
| TPS767D301 | Digikey | 296-19002-1-ND | $5.18 | 1 | |
| SN65HVD231 | Digikey | 296-12206-5-ND | $3.04 | 1 | |
| 20MHz Crystal Oscillator | Digikey | XC337TR-ND | $2.77 | 1 | |
| SPST push button switch - reset switch NO contacts 0.3" pin spacing | --- | --- | --- | --- | |
| Assortment of Surface mount components - resisitors, capacitors, LEDs, and beads | --- | --- | --- | --- | |
| PCB Mount mini Molex-style connectors for CAN and Power | --- | --- | --- | --- | |
| Misc Pin headers (0.1 inch and 0.064 inch) | --- | --- | --- | --- | |
--- indicates that these components can be purchased at almost any electronics parts suppliers. Recommendations include Digikey, Jameco, or Mouser.
Click here for a short video clip on removing solder from the DSP using a blade-tip soldering iron.
Click here for another close-up video on removing solder from the DSP.
For new comers, the following is a crash course in soldering surface mount components: Using a small pair of tweezers, hold the component on the board between the pads you want the component to bridge. Clean the tip of the soldering iron, and dip it in the flux to clean it further, This will also allow the solder to ball up at the joint rather than becoming sticky-like. Once you have flux on the tip, add some solder to it, placing a small bead of solder at the tip. Now, take and solder down one side of the component. If all goes well, the solder bridges the gap, and looks smooth and shiny. If not, continue to hold the component, add more flux to the tip of the iron, and re-solder the joint. Once the component solder joint looks good, you can let go of the component with the tweezers, and solder the rest of the component.
Once you feel confident that everything looks good on the side you just worked on, flip the board over and solder the components on the DSP-side of the board. Again, do not place the pin headers on until the very last, for both the pin connectors, jumper headers, and JTAG port. Second to last should go the power and CAN connectors. place all the components on the board, starting with the reset switch, and moving clockwise around the DSP. Note: for the SMT LED's, there will be an indicator to the anode and cathode, usually indicated by a dot (mine is a small green dot in the package) that will indicate the cathode. On my board, the green dot-ed pin goes to to side opposite the + sign (anode).
Once the all the SMT components are soldered on, and looking good, you can now solder on the pin headers. The same technique can be used as when you soldered on the DSP, applying a bead of solder and flux to the iron, and drag the tip along the row. This is a faster way than actually soldering all the pins one by one. It does not matter the sequence of pin headers, all have to go on eventually. Note: if no Molex connectors are available for the CAN, Power and SCI ports, standard 0.1" headers can be used, just watch out for the polarity of the ports. These boards are fragile, they do not have protection for power reversal, or JTAG Port reversal. I have dealt with these issues myself, and they are not fun.
For testing the board, apply power to the power port. I recommend using a current limited power supply, in case something is shorted. When the current is measured, it should be around 60mA for the board (if the DSP is new - without a flashed program), or around 200mA if there is code running on the DSP. When all looks good at this point, connect the DSP to Code Composer Studio, and connect to the chip. If all goes well, CCS will report that the chip is halted, and ready for code upload.
Here is a picture of the DSP all wired up with Power and JTAG:
//###########################################################################
// $ Bryan Kobe
// $ TMS2808, Project template
// $ 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.
// #### GAIN SETTING #########################################################
// Place any gain settings here for control
// #### BOOT TO FLASH ########################################################
#pragma CODE_SECTION(cpu_timer0_isr, "ramfuncs");
// #### DECLARATION OF FUNCTIONS #############################################
// 1. CPU Interrupt Functions
interrupt void cpu_timer0_isr(void);
// 2. GPIO Functions
void Gpio_select(void);
void Pause(unsigned int _counts);
// #### DECLARATION OF VARIABLES #############################################
// These are defined by the linker (see F2808.cmd) For writting FLASH
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;
int counter = 0;
// #### 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();
// 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(;;) { } // add custom code here for execution
}
// 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
counter = CpuTimer0.InterruptCount;
if (counter >= 100 ) {
GpioDataRegs.GPBTOGGLE.bit.GPIO32 = 1; // Toggle the LED at a slow rate
counter = 0;
}
CpuTimer0.InterruptCount=0;
GpioDataRegs.GPBTOGGLE.bit.GPIO32 = 1;
// 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 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
// GPIO13, active low, so set it high: COLUMN 9
GpioCtrlRegs.GPAPUD.bit.GPIO13 = 0; // Enable pullup on GPIO13
GpioDataRegs.GPASET.bit.GPIO13 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 0; // G13/TZ2/CANRXB/SPISOMIB
GpioCtrlRegs.GPADIR.bit.GPIO13 = 1; // 1:output, 0:input
// GPIO14, active low, so set it high: COLUMN 10
GpioCtrlRegs.GPAPUD.bit.GPIO14 = 0; // Enable pullup on GPIO14
GpioDataRegs.GPASET.bit.GPIO14 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 0; // G14/TZ3/SCITXDB/SPICLKB
GpioCtrlRegs.GPADIR.bit.GPIO14 = 1; // 1:output, 0:input
// GPIO15, active low, so set it high: COLUMN 11
GpioCtrlRegs.GPAPUD.bit.GPIO15 = 0; // Enable pullup on GPIO15
GpioDataRegs.GPASET.bit.GPIO15 = 1; // Load output latch
GpioCtrlRegs.GPAMUX1.bit.GPIO15 = 0; // G15/TZ4/SCIRXDB/SPISTEB
GpioCtrlRegs.GPADIR.bit.GPIO15 = 1; // 1:output, 0:input
// GPIO16, active low, so set it high: COLUMN 12
GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0; // Enable pullup on GPIO16
GpioDataRegs.GPASET.bit.GPIO16 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 0; // G16/SPISIMOA/CANTXB/TZ5
GpioCtrlRegs.GPADIR.bit.GPIO16 = 1; // 1:output, 0:input
// GPIO17, active low, so set it high: COLUMN 13
GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pullup on GPIO17
GpioDataRegs.GPASET.bit.GPIO17 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 0; // G17/SPISOMIA/CANRXB/TZ6
GpioCtrlRegs.GPADIR.bit.GPIO17 = 1; // 1:output, 0:input
// GPIO18, active low, so set it high: COLUMN 14
GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pullup on GPIO18
GpioDataRegs.GPASET.bit.GPIO18 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 0; // G18/SPICLKA/SCITXDB
GpioCtrlRegs.GPADIR.bit.GPIO18 = 1; // 1:output, 0:input
// GPIO19, active low, so set it high: COLUMN 15
GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pullup on GPIO19
GpioDataRegs.GPASET.bit.GPIO19 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 0; // G19/SPISTEA/SCIRXDB
GpioCtrlRegs.GPADIR.bit.GPIO19 = 1; // 1:output, 0:input
// GPIO20, active low, so set it high: COLUMN 16
GpioCtrlRegs.GPAPUD.bit.GPIO20 = 0; // Enable pullup on GPIO20
GpioDataRegs.GPASET.bit.GPIO20 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 0; // G20/EQEP1A/SPISIMOC/CANTXB
GpioCtrlRegs.GPADIR.bit.GPIO20 = 1; // 1:output, 0:input
// GPIO21, active low, so set it high: COLUMN 17
GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0; // Enable pullup on GPIO21
GpioDataRegs.GPASET.bit.GPIO21 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 0; // G21/EQEP1B/SPISOMIC/CANRXB
GpioCtrlRegs.GPADIR.bit.GPIO21 = 1; // 1:output, 0:input
// GPIO22, active low, so set it high: COLUMN 18
GpioCtrlRegs.GPAPUD.bit.GPIO22 = 0; // Enable pullup on GPIO22
GpioDataRegs.GPASET.bit.GPIO22 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 0; // G22/EQEP1S/SPICLKC/SCITXDB
GpioCtrlRegs.GPADIR.bit.GPIO22 = 1; // 1:output, 0:input
// GPIO23, active low, so set it high: COLUMN 19
GpioCtrlRegs.GPAPUD.bit.GPIO23 = 0; // Enable pullup on GPIO23
GpioDataRegs.GPASET.bit.GPIO23 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 0; // G23/EQEP1I/SPISTEC/SCIRXDB
GpioCtrlRegs.GPADIR.bit.GPIO23 = 1; // 1:output, 0:input
// GPIO24, active low, so set it high: COLUMN 20
GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0; // Enable pullup on GPIO24
GpioDataRegs.GPASET.bit.GPIO24 = 1; // Load output latch
GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0; // G24/ECAP1/EQEP2S/SPISTEB
GpioCtrlRegs.GPADIR.bit.GPIO24 = 1; // 1:output, 0:input
// 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.
//===========================================================================
Speculating future work, derived from this tutorial, includes building the LED board for the DSP. In the big picture, the problem of building an LED display for the Hubo can be solved with this tutorial.
Click here to email me