Tool/software: TI C/C++ Compiler
I have seen a strange behavior I somply don't understand:
I have worked with the Delfino controllers and really enjoyed the struct mechanism to access registers and bits within the peripherals and I thought I would try the same for 6748 DSP.
So I made a header file with structs to define the GPIO registers and bits based on the way it is done for the 2000 series. See file.
Also I made a little test file to see how it works. See file.
And now comes the strange stuff:
When I single step the "GPIOPinWrite( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), 1 );" and the "GpioBanks.B6_7.SET.bit.SETA6 = 1;" lines, I got two very different results when counting the clock pulses in Timer 2.
For the TI call (GPIOPinWrite) the number of clock pulses are around 25 to 30 and when I test the struct the number of pulses is 3 to 5. Looks like a huge improvement: 5 times faster when using the struct way.
Great, let's try it in real time without the debugger: Now it turns out the TI call is faster (~40%?) than the struct way. Bummer. I looked at the actual pin, GPIO 6,6, on a scope.
But how come it seems faster when using the debugger as compared to the free run?
Any good explanation?
Thanks,
Claus Knudsen
//CODE
/* * main.c */ #include "psc.h" #include "soc_C6748.h" #include "gpio.h" #include "pll_regs.h" #include "timer.h" #include "C6000GPIOStruct.h" #define GPIO_PIN_NUMBER(BANK,PINNR) (BANK * 16 + PINNR + 1) void TestGPIO_STRUCT (void); void ConfigandStartTimer_2( void ); int main(void) { PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE); PINMUX14 = 0x00000080; // set pin to GPIO(6,6) GPIODirModeSet( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), GPIO_DIR_OUTPUT ); ConfigandStartTimer_2(); while (1) { TestGPIO_STRUCT(); } } #pragma DATA_SECTION(GpioBanks , "GPIO_REG"); volatile struct GPIO_BANKS_0_8 GpioBanks; void TestGPIO_STRUCT (void) { GPIOPinWrite( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), 1 ); // step GPIOPinWrite( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), 0 ); // step // Use the struct two times in order to distinguish between the TI call and the struct GpioBanks.B6_7.SET.bit.SETA6 = 1; GpioBanks.B6_7.CLR.bit.CLRA6 = 1; GpioBanks.B6_7.SET.bit.SETA6 = 1; GpioBanks.B6_7.CLR.bit.CLRA6 = 1; } void ConfigandStartTimer_2( void ) { TimerConfigure( SOC_TMR_2_REGS, TMR_CFG_64BIT_CLK_INT); TimerPeriodSet( SOC_TMR_2_REGS, TMR_TIMER12, 0xFFFFFFFF ); TimerPeriodSet( SOC_TMR_2_REGS, TMR_TIMER34, 0xFFFFFFFF ); TimerEnable( SOC_TMR_2_REGS, TMR_TIMER12, TMR_ENABLE_CONT); }
// STRUCT
/*
* main.c
*/
#include "psc.h"
#include "soc_C6748.h"
#include "gpio.h"
#include "pll_regs.h"
#include "timer.h"
#include "C6000GPIOStruct.h"
#define GPIO_PIN_NUMBER(BANK,PINNR) (BANK * 16 + PINNR + 1)
void TestGPIO_STRUCT (void);
void ConfigandStartTimer_2( void );
int main(void) {
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
PINMUX14 = 0x00000080; // set pin to GPIO(6,6)
GPIODirModeSet( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), GPIO_DIR_OUTPUT );
ConfigandStartTimer_2();
while (1)
{
TestGPIO_STRUCT();
}
}
#pragma DATA_SECTION(GpioBanks , "GPIO_REG");
volatile struct GPIO_BANKS_0_8 GpioBanks;
void TestGPIO_STRUCT (void)
{
GPIOPinWrite( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), 1 ); // step
GPIOPinWrite( SOC_GPIO_0_REGS, GPIO_PIN_NUMBER(6,6), 0 ); // step
// Use the struct two times in order to distinguish between the TI call and the struct
GpioBanks.B6_7.SET.bit.SETA6 = 1;
GpioBanks.B6_7.CLR.bit.CLRA6 = 1;
GpioBanks.B6_7.SET.bit.SETA6 = 1;
GpioBanks.B6_7.CLR.bit.CLRA6 = 1;
}
void ConfigandStartTimer_2( void )
{
TimerConfigure( SOC_TMR_2_REGS, TMR_CFG_64BIT_CLK_INT);
TimerPeriodSet( SOC_TMR_2_REGS, TMR_TIMER12, 0xFFFFFFFF );
TimerPeriodSet( SOC_TMR_2_REGS, TMR_TIMER34, 0xFFFFFFFF );
TimerEnable( SOC_TMR_2_REGS, TMR_TIMER12, TMR_ENABLE_CONT);
}
// Linker CMD file
// ============================================================================
// Linker Command File for Linking c674 DSP Programs
//
// These linker options are for command line linking only. For IDE linking,
// you should set your linker options in Project Properties.
// -c Link Using C Conventions
// -stack 0x1000 Software Stack Size
// -heap 0x1000 Heap Area Size
// ===========================================================================
-stack 0x3000
//-heap 0x2000
// ============================================================================
// Specify the System Memory Map
// ============================================================================
MEMORY
{
L1P: o = 0x11E00000 l = 0x00008000
L1D: o = 0x11F00000 l = 0x00008000
L2: o = 0x11800000 l = 0x00040000
SHARED_RAM: o = 0xC0000000 l = 0x00100000
DDR2: o = 0xC0100000 l = 0x07F00000
EMIFA2 o = 0x60000000 l = 0x02000000
GPIOMEM o = 0x01E26010 l = 0xC8
}
// ============================================================================
// Specify the Sections Allocation into Memory
// ============================================================================
SECTIONS
{
.cinit > L2 // Initialization Tables
.pinit > SHARED_RAM//DDR2
.init_array > L2 //
.binit > L2 // Boot Tables
.const > SHARED_RAM //DDR2//L2 // Constant Data. was L2, now DDR2 with fpga code
.switch > L2 // Jump Tables
.text > L2// DDR2 // Executable Code
.text:_c_int00: align=1024 > L2 // Entrypoint
GROUP (NEARDP_DATA) // group near data
{
.neardata
.rodata
.bss // note: removed fill = 0
} > L2
.far: fill = 0x0, load > L2 // Far Global & Static Variables
.fardata > L2 // Was L2. Far RW Data
.stack > L2 // Software System Stack
.sysmem > L2 // Dynamic Memory Allocation Area
.heap > DDR2
{
. += 0x01000000;
}
.cio > L2 // C I/O Buffer
.vecs > L2 // Interrupt Vectors
FPGASection > EMIFA2
DDR2Funcs > DDR2
SharedRAMFuncs > SHARED_RAM
LEVEL2 > L2
FASTMEM: fill = 0x0 > L1D
FASTPROG > L1P
GPIO_REG > GPIOMEM
}