This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28020: How to reduce code size in example programs

Part Number: TMS320F28020
Other Parts Discussed in Thread: TMS320F28021

Hi All,

I'm quickly running out of memory on a TMS320F28020 project after adding code for only two of the several peripherals that will be needed. The project is a port from an ATMEGA328PB-MU processor written in C/C++.  The Atmega part has 32kBytes Flash, 1kByte EEPROM, and 2kBytes SRAM, and its memory isn't maxed out even with all the modules implemented and working.

Here's the C2000 scenario:

I2C Implementation:

1. Starting with "Example_2802xI2c_eeprom.c" bitfield code downloaded from the "Resource Explorer"

2. on a LaunchPadXL TMS320F2802x

3. in CCS ver. 10.4.0.00006

4. with Compiler ver. TI v21.6.0LTS

5. I added a switch statement along with a small amount of related code, and it has pretty much maxed out memory.

//###########################################################################
//
// FILE:    Example_2802xI2c_eeprom.c
//
// TITLE:   f2802x I2C EEPROM Example
//
// ASSUMPTIONS:
//
//    This program requires the f2802x header files.
//
//    This program requires an external I2C EEPROM connected to
//    the I2C bus at address 0x50.
//
//    As supplied, this project is configured for "boot to SARAM"
//    operation.  The 2802x Boot Mode table is shown below.
//    For information on configuring the boot mode of an eZdsp,
//    please refer to the documentation included with the eZdsp,
//
//    $Boot_Table
//    While an emulator is connected to your device, the TRSTn pin = 1,
//    which sets the device into EMU_BOOT boot mode. In this mode, the
//    peripheral boot modes are as follows:
//
//      Boot Mode:   EMU_KEY        EMU_BMODE
//                   (0xD00)         (0xD01)
//      ---------------------------------------
//      Wait         !=0x55AA        X
//      I/O          0x55AA          0x0000
//      SCI          0x55AA          0x0001
//      Wait         0x55AA          0x0002
//      Get_Mode     0x55AA          0x0003
//      SPI          0x55AA          0x0004
//      I2C          0x55AA          0x0005
//      OTP          0x55AA          0x0006
//      Wait         0x55AA          0x0007
//      Wait         0x55AA          0x0008
//      SARAM        0x55AA          0x000A   <-- "Boot to SARAM"
//      Flash        0x55AA          0x000B
//      Wait         0x55AA          Other
//
//   Write EMU_KEY to 0xD00 and EMU_BMODE to 0xD01 via the debugger
//   according to the Boot Mode Table above. Build/Load project,
//   Reset the device, and Run example
//
//   $End_Boot_Table
//
// DESCRIPTION:
//
//    This program will write 1-14 words to EEPROM and read them back.
//    The data written and the EEPROM address written to are contained
//    in the message structure, I2cMsgOut1. The data read back will be
//    contained in the message structure I2cMsgIn1.
//
//    This program will work with the on-board I2C EEPROM supplied on
//    the F2802x eZdsp.
//
//
//###########################################################################
// $TI Release: F2802x Support Library v3.05.00.00 $
// $Release Date: 10-19-2021 $
// $Copyright:
// Copyright (C) 2009-2021 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//   Redistributions of source code must retain the above copyright 
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the 
//   documentation and/or other materials provided with the   
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################

//
// Included Files
//
#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

//
// Note: I2C Macros used in this example can be found in the
// f2802x_I2C_defines.h file
//

//
// Function Prototypes
//
void   I2CA_Init(void);
uint16_t I2CA_WriteData(struct I2CMSG *msg);
__interrupt void i2c_int1a_isr(void);
void pass(void);
void fail(void);

//
// Defines
//
#define I2C_SLAVE_ADDR        0x50
#define I2C_NUMBYTES          2
#define I2C_EEPROM_HIGH_ADDR  0x00
#define I2C_EEPROM_LOW_ADDR   0x30

//
// Globals
//
struct I2CMSG I2cMsgOut1=
{
    I2C_MSGSTAT_SEND_WITHSTOP,
    I2C_SLAVE_ADDR,
    I2C_NUMBYTES,
    I2C_EEPROM_HIGH_ADDR,
    I2C_EEPROM_LOW_ADDR,

    //
    // Msg Byte 1
    //
    0x12,

    //
    // Msg Byte 2
    //
    0x34
};

struct I2CMSG I2cMsgIn1=
{
    I2C_MSGSTAT_SEND_NOSTOP,
    I2C_SLAVE_ADDR,
    I2C_NUMBYTES,
    I2C_EEPROM_HIGH_ADDR,
    I2C_EEPROM_LOW_ADDR
};

uint16_t				delayCounter		= 0;
volatile unsigned int	volumeCommand[40];
volatile int			redSwitchCurrent	= 0;
volatile int			redSwitchPrevious	= 0;
volatile int			greenSwitchCurrent	= 0;
volatile int			greenSwitchPrevious	= 0;
volatile int			transmitStringFlag	= 0;


//
// Used in interrupts
//
struct I2CMSG *CurrentMsgPtr;               
uint16_t PassCount;
uint16_t FailCount;

volatile uint16_t	idleCounter1;
volatile uint16_t	idleCounter2;
volatile uint16_t	tempByte = 0;

// vv Tim's code vv
//PARSING PORTION
/*****************************************************************************
 *
 *****************************************************************************/
enum Command
{
    NONE, QET, RET, SRC, QRC, QMS, IVI, DVI, SVI, QVI, SRS, QPW, SVO, IVO, DVO, QVO, SLD, SOS
} ;


/*****************************************************************************
 *
 *****************************************************************************/
struct CommandMessage
{

    enum Command cmd;
    short value1;
    short value2;
};
// ^^ Tim's code ^^

void TransmitString(int numBytes);

struct CommandMessage cm;	// This works


//
// Main
//
void main(void)
{
    uint16_t Error;
    uint16_t i;

    //
    // WARNING: Always ensure you call memcpy before running any functions from
    // RAM InitSysCtrl includes a call to a RAM based function and without a 
    // call to memcpy first, the processor will go "into the weeds"
#ifdef _FLASH
    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
#endif

//    CurrentMsgPtr = &I2cMsgOut1;

    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the f2802x_SysCtrl.c file.
    //
    InitSysCtrl();

    //
    // Step 2. Initialize GPIO:
    // This example function is found in the f2802x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    //
    //InitGpio();
    
    //
    // Setup only the GP I/O only for I2C functionality
    //
    InitI2CGpio();

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

    //
    // Initialize 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 f2802x_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 f2802x_DefaultIsr.c.
    // This function is found in f2802x_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
    PieVectTable.I2CINT1A = &i2c_int1a_isr;
    EDIS;      // This is needed to disable write to EALLOW protected registers

    //
    // Step 4. Initialize all the Device Peripherals
    //
    I2CA_Init();                    // I2C-A only

    //
    // Step 5. User specific code
    //

    //
    // Clear Counters
    //
    PassCount = 0;
    FailCount = 0;

    //
    // Clear incoming message buffer
    //
    for (i = 0; i < (I2C_MAX_BUFFER_SIZE - 2); i++)
    {
//        I2cMsgIn1.MsgBuffer[i] = 0x0000;
    }

    //
    // Enable interrupts required for this example
    //

    //
    // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1
    //
    PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

    //
    //  Init GPIOs (rdv)
    //

    EALLOW;
    GpioCtrlRegs.GPAMUX1.bit.GPIO4  = 0;    // 0 configures GPIO4 as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO4   = 0;    // 0 makes it an input
    GpioCtrlRegs.GPAPUD.bit.GPIO4   = 0;    // 0 enables pull-up

    GpioCtrlRegs.GPAMUX1.bit.GPIO5  = 0;    // 0 configures GPIO5 as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO5   = 0;    // 0 makes it an input
    GpioCtrlRegs.GPAPUD.bit.GPIO5   = 0;    // 0 enables pull-up

    GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 0;    // 0 configures GPIO19 as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO19  = 1;    // 1 makes it an output
    GpioCtrlRegs.GPAPUD.bit.GPIO19  = 0;    // 0 enables pull-up
    EDIS;

//    GpioDataRegs.GPASET.bit.GPIO19 = 1;
    GpioDataRegs.GPACLEAR.bit.GPIO19 = 1;


    //
    // Enable CPU INT8 which is connected to PIE group 8
    //
    IER |= M_INT8;
    EINT;

    //
    // Application loop
    //

    //
    // Temp debug vars
    //

    volumeCommand[0] = 0xfe;
    volumeCommand[1] = 0x51;
    volumeCommand[2] = 0xfe;
    volumeCommand[3] = 0x45;
    volumeCommand[4] = 0x00;

    volumeCommand[21] = 0xfe;
    volumeCommand[22] = 0x45;
    volumeCommand[23] = 0x40;

	cm.cmd	= 0;
	cm.value1 = 0;
	cm.value2 = 0;

    for(;;)
    {

	    if(delayCounter++ > 1)
	    {
		    delayCounter = 0;
		    redSwitchCurrent = GpioDataRegs.GPADAT.bit.GPIO4;	// Get switch states
		    greenSwitchCurrent = GpioDataRegs.GPADAT.bit.GPIO5;

			   if(redSwitchCurrent != redSwitchPrevious)			// Compare to previous state
			   {
				   if(!redSwitchCurrent & redSwitchPrevious){	// If the button change is from a press, not release...

					   transmitStringFlag = 1;

					   cm.cmd++;

					   if(cm.cmd > SOS)						// Increment to next command
					   {
						   cm.cmd = NONE;						// Roll to first command
					   }
				   }
				   redSwitchPrevious = redSwitchCurrent;		// Update previous state to current
			   }

			   if(greenSwitchCurrent != greenSwitchPrevious)			// Compare to previous state
			   {
				   if(!greenSwitchCurrent & greenSwitchPrevious){	// If the button change is from a press, not release...

					   transmitStringFlag = 1;

					   cm.cmd--;

					   if(cm.cmd <= NONE)						// Increment to next command
					   {
						   cm.cmd = SOS;						// Roll to first command
					   }
				   }
				   greenSwitchPrevious = greenSwitchCurrent;		// Update previous state to current
			   }

		   if(transmitStringFlag)
		   {
			   switch(cm.cmd)
			   {
				   case NONE:	// 0
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "     NONE       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QET:	// 1
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QET       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case RET:	// 2
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      RET       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SRC:	// 3
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SRC       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QRC:	// 4
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QRC       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QMS:	// 5
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QMS       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case IVI:	// 6
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      IVI       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case DVI:	// 7
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      DVI       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SVI:	// 8
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SVI       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QVI:	// 9
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QVI       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SRS:	// 10
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SRS       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QPW:	// 11
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QPW       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SVO:	// 12
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SVO       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case IVO:	// 13
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      IVO       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case DVO:	// 14
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      DVO       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case QVO:	// 15
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      QVO       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SLD:	// 16
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SLD       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   case SOS:	// 17
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "      SOS       ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"**Bottom  line**.  ");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
				   default:	// Anything else
				   {
					   short numBytes = 40;
					   strcpy(volumeCommand+5, "    Command     ");
									   //   1234567890123456
					   strcpy(volumeCommand+24,"was out of range");
									   //   1234567890123456
					   volumeCommand[21] = 0xfe;
					   TransmitString(numBytes);
					   transmitStringFlag = 0;
				   }
				   break;
			   }
		   }
	    }
    }
}
//
// I2CA_Init -
//
void
I2CA_Init(void)
{
    // Initialize I2C
    I2caRegs.I2CMDR.bit.IRS         = 0;	// SEE BELOW - Put I2C module in reset while making changes


    //
    // Own Address Register
    //								// Bit   15: READ ONLY - Reserved
    I2caRegs.I2COAR                 = 0x26;	// Own address = 0x28

    	    	    	    	    	    	    	    	    	// Bits 7-15: Reserved
    //
    // I2C Interrupt Enable Register
    //								// Bits 7-15: READ ONLY - Reserved
    I2caRegs.I2CIER.bit.AAS         = 0;	// Bit	 6: 1 = Addressed as slave interrupt request enabled
    I2caRegs.I2CIER.bit.SCD         = 0;	// Bit     5: 1 = Stop condition detected interrupt request enabled
    I2caRegs.I2CIER.bit.XRDY        = 0;	// Bit     4: 1 = Transmit data ready interrupt request disabled
    I2caRegs.I2CIER.bit.RRDY        = 0;	// Bit     3: 1 = W1C - Receive data ready interrupt request enabled
    I2caRegs.I2CIER.bit.ARDY        = 0;	// Bit     2: 1 = Master Only - Register access ready interrupt request enabled
    I2caRegs.I2CIER.bit.NACK        = 0;	// Bit     1: 0 = W1C - No-ack interrupt request disabled
    I2caRegs.I2CIER.bit.ARBL        = 0;	// Bit     0: 0 = W1C - Arbitration lost interrupt request disabled


    //
    // I2C Status Register
    //								// Bit   15: READ ONLY - Reserved
    I2caRegs.I2CSTR.bit.SDIR        = 1;	// Bit   14: W1C - Slave direction bit 0 = not addressed as slave transmitter
    I2caRegs.I2CSTR.bit.NACKSNT     = 1;	// Bit   13: W1C - NACK sent bit 0 = NACK not sent
    I2caRegs.I2CSTR.bit.BB          = 0;	// Bit   12: Bus Busy bit 0 = bus free
    I2caRegs.I2CSTR.bit.RSFULL      = 0;	// Bit   11: 1 = receive shift register overrun condition detected
    I2caRegs.I2CSTR.bit.XSMT        = 0;	// Bit   10: 0 = transmit shift register underflow detected (empty)
    I2caRegs.I2CSTR.bit.AAS         = 0;	// Bit    9: 1 = I2C module recognized its own slave address
    I2caRegs.I2CSTR.bit.AD0         = 0;	// Bit    8: 1 = address of all zeros (general call) was detected
    	    	    	    	    	    	    	    	    	// Bits 6-7: READ ONLY - Reserved
    I2caRegs.I2CSTR.bit.SCD         = 1;	// Bit    5: W1C - 1 = stop condition was detected
    I2caRegs.I2CSTR.bit.XRDY        = 1;	// Bit    4: 1 = Ready for more transmit data to go in I2CDXR
    I2caRegs.I2CSTR.bit.RRDY        = 1;	// Bit    3: W1C - Receive data ready int flag 1 = data is in I2CDRR
    I2caRegs.I2CSTR.bit.ARDY        = 1;	// Bit    2: Master Only - Register access ready int flag
    I2caRegs.I2CSTR.bit.NACK        = 1;	// Bit    1: W1C - 1 = NACK received
    I2caRegs.I2CSTR.bit.ARBL        = 1;	// Bit    0: W1C - 1 = arbitration lost


    //
    // I2C Clock Prescale Register
    //
    // Setup I2C data rate
    I2caRegs.I2CPSC.bit.IPSC        = 5;	// Prescaler value 60mHz SYSCLK / 6 = 10mHz (5+1=6)


    //
    // I2C Clock high-time and low-time Registers
    //
    // 10mHz / 200 = 50kHz for comm's with 2x16 debugging display
    I2caRegs.I2CCLKL                =  129;	// 129 + 5 = 136
    I2caRegs.I2CCLKH                =   61;	//  61 + 5 =  66


    //
    // Data Count Register
    //
    I2caRegs.I2CCNT                 = 1;	// Bits 0-15: Set data count (ignored in RM mode)
									// Is changed to actual number of bytes to transfer when in
									// transmit mode.
    //
    // Slave Address Register
    //   	    	    	    	    	    	    	     // Bits 10-15: READ ONLY - Reserved
    I2caRegs.I2CSAR                 = 0x28;	// Bits   0-9: Address to which data will be transmitted (Master only)


    //
    // I2C Mode Register
    //   	    	    	    	    	    	    	     // Bits 14-15:  READ ONLY - Reserved
    I2caRegs.I2CMDR.bit.NACKMOD     = 0;	// Bit   15: NACK mode
    I2caRegs.I2CMDR.bit.FREE        = 0;	// Bit   14: For debugging: 0 = I2C halts during interrupts
//    I2caRegs.I2CMDR.bit.STT         = 0;	// Bit   13: Master only - Start bit Can't be written when IRS=0
    	    	    	    	    	    	    	    	    	// Bit   12: Reserved
//    I2caRegs.I2CMDR.bit.STP         = 0;	// Bit   11: Master only - Stop bit Can't be written when IRS=0
    I2caRegs.I2CMDR.bit.MST         = 1;	// Bit   10: Remains 0 for slave mode.  1 = Master mode
    I2caRegs.I2CMDR.bit.TRX         = 1;	// Bit    9: 0 = Receive mode, 1 = Transmit mode
    I2caRegs.I2CMDR.bit.XA          = 0;	// Bit    8: 0 = 7 bit address mode
    I2caRegs.I2CMDR.bit.RM          = 1;	// Bit    7: 1 = repeat mode
    I2caRegs.I2CMDR.bit.DLB         = 0;	// Bit    6: 0 = Digital loopback mode disabled
//    I2caRegs.I2CMDR.bit.IRS         = 1;	// Bit    5: I2C module is re-enabled after making changes
    I2caRegs.I2CMDR.bit.STB         = 0;	// Bit    4: Master only - Start Byte mode
    I2caRegs.I2CMDR.bit.FDF         = 0;	// Bit    3: Keep at 0. Free data format mode
    I2caRegs.I2CMDR.bit.BC          = 0;	// Bits 0-2: Set bit count to 8 bits (0 = 8)


    //
    // I2C Extended Mode Register
    //   	    	    	    	    	    	    	     // Bits 1-15: READ ONLY - Reserved
    I2caRegs.I2CEMDR.bit.BCM         = 0;	// Bit     0: Backwards compatibility mode


    //
    // Transmit FIFO Register
    //   	    	    	    	    	    	    	     // Bits 14-15:  READ ONLY - Reserved
    	    	    	    	    	    	    	    	     // Bit 15: Reserved
    I2caRegs.I2CFFTX.bit.I2CFFEN    = 0;	// Bit    14: 1 = Enable transmit & receive FIFOs
    I2caRegs.I2CFFTX.bit.TXFFRST    = 0;	// Bit    13: 1 = Take transmit FIFO out of reset
//    I2caRegs.I2CFFTX.bit.TXFFST     = 0;	// Bits 8-12: READ ONLY - How many bytes are in the transmit FIFO
//    I2caRegs.I2CFFTX.bit.TXFFINT    = 0;	// Bit     7: READ ONLY - 1 = interrupt occurred
    I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1;	// Bit     6: W1C - Clears transmit interrupt flag (do again after irs = 1)
    I2caRegs.I2CFFTX.bit.TXFFIENA   = 0;	// Bit     5: 0 = Disable transmit FIFO interrupt
    I2caRegs.I2CFFTX.bit.TXFFIL     = 0;	// Bits  0-4: Set the transmit FIFO interrupt Threshold


    //
    // Receive FIFO Register
    //   	    	    	   	    	    	    	     // Bits 14-15:  READ ONLY - Reserved
    I2caRegs.I2CFFRX.bit.RXFFRST    = 0;	// Bit     13: 1 = enable receive FIFO operation
//    I2caRegs.I2CFFRX.bit.RXFFST     = 0;	// BitS  8-12: READ ONLY - Bytes in receive FIFO
//    I2caRegs.I2CFFRX.bit.RXFFINT    = 0;	// Bit      7: READ ONLY - Receive interrupt flag 1 = int
    I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1;	// Bit      6: Write 1 to clear receive int flag
    I2caRegs.I2CFFRX.bit.RXFFIENA   = 0;	// Bit      5: 1 = receive interrupt is enabled
    I2caRegs.I2CFFRX.bit.RXFFIL     = 0;	// Bits   0-4: Set the receive FIFO interrupt level


    // Clean up and exit
    I2caRegs.I2CMDR.bit.IRS         = 1;	// SEE ABOVE - I2C module is re-enabled after making changes

    I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1;	// SEE ABOVE - Clears transmit interrupt flag
    I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1;	// SEE ABOVE - Clears receive interrupt flag

    return;
}

//
// Transmit String -
//
void
TransmitString(int numBytes)
{
	uint16_t i;
	uint16_t i2;

	// wait for STOP condition
	while (I2caRegs.I2CMDR.bit.STP != 0); //bus is not occupied

	// generate START condition
	I2caRegs.I2CMDR.bit.STT = 1;// resets once the START condition is issued

	for(i = 0; i < numBytes; i++){
		idleCounter1 = 0;
		while(!I2caRegs.I2CSTR.bit.XRDY)
		{
			if(idleCounter1++ >= 60000)		// 30,000 ~ 12.6ms
										// When the master read happens before data is ready (after the master sends a write)
											// XRDY is never satisfied.  This algorithm senses this condition and after a time
											// (~12.6ms) reads the I2CDRR to clear the I2C bus condition.
											// Extending this delay makes the data transfer more robust, but at the expense of
											// extending the GMS trip response (during this delay).
											//
											//
											// This is to help unstick the bus when too many writes are issued
			{                               // by master w/o reading. It must be long enough to allow master

				idleCounter1 = 0;           // enough time to download bytes normally.
				tempByte = I2caRegs.I2CDRR; // It must be short enough to allow quick end to CPU hogging

				// The following resets I2C xmit buffer in case master doesn't pull all data
				I2caRegs.I2CMDR.bit.IRS         = 0;    // Put I2C module in reset while making changes
				I2caRegs.I2CCNT                 = 0;    // Set data count to 0 clears xmit buffer
				I2caRegs.I2CMDR.bit.IRS         = 1;    // I2C module is re-enabled after making changes
			}
		}

	    // wait for XRDY flag to transmit data
//	    while (I2caRegs.I2CSTR.bit.XRDY != 1);//wait for the XRDY (transmit mode ready) bit of the status register, which means that the data transmit register is ready to accept new data.

	    I2caRegs.I2CDXR = volumeCommand[i];  // Loads a value into the data xmit buffer, starting the xmit process

//		I2caRegs.I2CMDR.all = 0x6E20;

	    for(i2=0; i2<2500; i2++)
	    {
			// Do nothing, just wait
	    }
    }

    // snd stop condition here
    I2caRegs.I2CMDR.bit.STP = 1;
/*
    idleCounter2 = 0;
    while(I2caRegs.I2CSTR.bit.BB)
    {
        if(idleCounter2++ >= 1000)    // This is to help unstick the bus when xmit buffer empties
        {
            idleCounter2 = 0;
            I2caRegs.I2CDXR = 0xdb;
        }
    }
*/
    I2caRegs.I2CMDR.all = 0x06a0;	// Resets the I2C mode register
}

uint16_t I2CA_WriteData(struct I2CMSG *msg)
{
	    uint16_t i;
	    uint16_t i2;

    // wait for STOP condition
    while (I2caRegs.I2CMDR.bit.STP != 0); //bus is not occupied

    // generate START condition
    I2caRegs.I2CMDR.bit.STT = 1;// resets once the START condition is issued

    for(i = 0; i < 40; i++){
        idleCounter1 = 0;
        while(!I2caRegs.I2CSTR.bit.XRDY)
        {
            if(idleCounter1++ >= 60000)		// 30,000 ~ 12.6ms
            								// When the master read happens before data is ready (after the master sends a write)
											// XRDY is never satisfied.  This algorithm senses this condition and after a time
											// (~12.6ms) reads the I2CDRR to clear the I2C bus condition.
											// Extending this delay makes the data transfer more robust, but at the expense of
											// extending the GMS trip response (during this delay).
											//
											//
											// This is to help unstick the bus when too many writes are issued
            {                               // by master w/o reading. It must be long enough to allow master

                idleCounter1 = 0;           // enough time to download bytes normally.
                tempByte = I2caRegs.I2CDRR; // It must be short enough to allow quick end to CPU hogging

                // The following resets I2C xmit buffer in case master doesn't pull all data
                I2caRegs.I2CMDR.bit.IRS         = 0;    // Put I2C module in reset while making changes
                I2caRegs.I2CCNT                 = 0;    // Set data count to 0 clears xmit buffer
                I2caRegs.I2CMDR.bit.IRS         = 1;    // I2C module is re-enabled after making changes
            }
        }

	    // wait for XRDY flag to transmit data
//	    while (I2caRegs.I2CSTR.bit.XRDY != 1);//wait for the XRDY (transmit mode ready) bit of the status register, which means that the data transmit register is ready to accept new data.

	    // generate START condition
//	    I2caRegs.I2CMDR.bit.STT = 1;// resets once the START condition is issued

	    I2caRegs.I2CDXR = volumeCommand[i];  // Loads a value into the data xmit buffer, starting the xmit process

//		I2caRegs.I2CMDR.all = 0x6E20;

	    for(i2=0; i2<2500; i2++) {
			// Do nothing, just wait
	    }
    }

    // snd stop condition here
    I2caRegs.I2CMDR.bit.STP = 1;

    idleCounter2 = 0;
    while(I2caRegs.I2CSTR.bit.BB)
    {
        if(idleCounter2++ >= 1000)    // This is to help unstick the bus when xmit buffer empties
        {
            idleCounter2 = 0;
            I2caRegs.I2CDXR = 0xdb;
        }
    }

    I2caRegs.I2CMDR.all = 0x06a0;	// Resets the I2C mode register


    return I2C_SUCCESS;
}

//
// i2c_int1a_isr - I2C-A
//
__interrupt void
i2c_int1a_isr(void)
{
	    uint16_t IntSource, i;

	    //
	    // Read interrupt source
	    //
	    IntSource = I2caRegs.I2CISRC.all;

	    //
	    // Interrupt source = stop condition detected
	    //
	    if(IntSource == I2C_SCD_ISRC)
	    {
	        //
	        // If completed message was writing data, reset msg to inactive state
	        //
	        if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
	        {
	            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
	        }
	        else
	        {
	            //
	            // If a message receives a NACK during the address setup portion
	            // of the EEPROM read, the code further below included in the
	            // register access ready interrupt source code will generate a stop
	            // condition. After the stop condition is received (here), set the
	            // message status to try again. User may want to limit the number
	            // of retries before generating an error.
	            //
	            if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
	            {
	                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
	            }

	            //
	            // If completed message was reading EEPROM data, reset msg to
	            // inactive state and read data from FIFO.
	            //
	            else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
	            {
	                CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
	                for(i=0; i < I2C_NUMBYTES; i++)
	                {
	                    CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
	                }

	                //
	                // Check received data
	                //
	                for(i=0; i < I2C_NUMBYTES; i++)
	                {
	                    if(I2cMsgIn1.MsgBuffer[i] == I2cMsgOut1.MsgBuffer[i])
	                    {
	                        PassCount++;
	                    }
	                    else
	                    {
	                        FailCount++;
	                    }
	                }

	                if(PassCount == I2C_NUMBYTES)
	                {
	                    pass();
	                }

	                else
	                {
	                    fail();
	                }
	            }
	        }
	    }

	    //
	    // Interrupt source = Register Access Ready
	    // This interrupt is used to determine when the EEPROM address setup
	    // portion of the read data communication is complete. Since no stop bit is
	    // commanded, this flag tells us when the message has been sent instead of
	    // the SCD flag. If a NACK is received, clear the NACK bit and command a
	    // stop. Otherwise, move on to the read data portion of the communication.
	    //
	    else if(IntSource == I2C_ARDY_ISRC)
	    {
	        if(I2caRegs.I2CSTR.bit.NACK == 1)
	        {
	            I2caRegs.I2CMDR.bit.STP = 1;
	            I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
	        }
	        else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
	        {
	            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
	        }
	    }

	    else
	    {
	        //
	        // Generate some error due to invalid interrupt source
	        //
	        __asm("   ESTOP0");
	    }

	    //
	    // Enable future I2C (PIE Group 8) interrupts
	    //
	    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

//
// pass -
//
void
pass()
{
    __asm("   ESTOP0");
    for(;;);
}

//
// fail -
//
void
fail()
{
    __asm("   ESTOP0");
    for(;;);
}


//
// End of File
//

SCIA Implementation:

1. Running "Example_2802xScia_FFDLB.c" Bitfield code downloaded from the "Resource Explorer"

2. on a LaunchPadXL TMS320F2802x

3. in CCS ver. 10.4.0.00006

4. with Compiler ver. TI v21.6.0LTS

I'm not able to get these two modules to run together, because of insufficient memory.  I will still need to add functionality for:

1. ADC

2. GPIO

3. Flash memory IO

4. User interface

Questions:

1. The Atmega part is an 8-bit processor, whereas the 28020 is 32-bit.  Was it wrong to assume what fit into 32kbytes of memory on the 8-bit part would fit in 32kbytes on a 32-bit part?

2. Can a significant amount of the example code be eliminated, while maintaining the ability for simple I2C and SCIA communications?  With I2C, the 28020 is the master, and the slave doesn't respond with data (ACK only).

3. I can switch to a TMS320F28021 for 64k, but will that be enough?

I would appreciate insight from anyone who can help.

Thanks,
robin

  • Hi Robin,

    We are forwarding your query to the expert. Please expect response in a day.

  • Robin ,

    Can you share the error that you are observing w.r.t allocation of memory? 

    What compiler version are you using and what is the optimization level that is configured for the compiler?

    Best Regards

    Siddharth

  • Hi Siddharth,

    Thanks for your response.

    I'm using the TI compiler version 21.6.0.LTS:

     No code optimization currently set:

    Here's an image of the compile error:

    Here's the memory allocation:

    As a temporary work-around, I decreased the stack from its default of 512 to 272.  That allowed me to test the code, but if I try to add any more code, I'll run into another error.  I still have a lot of code to add, so I'll have to trim down example code severely to get all of it to fit.  I can reuse variables and use more efficient algorithms, but I was hoping to just glean example code in order to produce working firmware quickly.

    Thoughts?

    Thanks,
    robin

  • Not sure why images didn't come through in my reply.  Here they are again:

    I'm using the TI compiler version 21.6.0.LTS:

    No code optimization currently set:



    Here's an image of the compile error:



    Here's the memory allocation:

  • Robin ,

    From the error message, looks like  the sections allocated to RAMM1 section are not able to fit in the memory. 

    You can update the linker command file to check which sections are allocated to RAMM1 and move them to a bigger section.

    You can even allocate to two sections by specifying - RAMM0 | RAMM1 in the linker command file

    Best Regards

    Siddharth 

  • Hi Siddharth,

    The linker command file hadn't assigned the upper 0x400 bytes of RAML0, so I assigned them to Page 1.  Then specified RAML0 | RAMM1 for those sections that were previously targeting RAMM1.  Now the code builds and runs properly, but I'm still needing help in understanding if my code will ultimately fit in this part.

    Question #1:

    My I2C needs are simple.  I have to send I2C commands to a peripheral chip.  Speed is not critical.  The peripheral doesn't have the ability to respond (other than ACK).  What's the best approach to minimizing code to perform this function.  The example code I started with seems unnecessarily large.  Is there an example of a minimalistic approach to I2C comm's?

    Question #2:

    Same question for my serial communications needs.  I started with an SCIA example, but I would like to have a bare-bones solution.

    Question #3:

    Can I leave some code in flash memory, and run it from there?

    My need is to better understand how to best utilize the memory space available, while producing code that is reduced to a bare minimum of features.  Do you have any suggestions or can you point to any other app notes that will help me to understand this two fold approach?

    Thanks,
    robin

  • Robin,

    Its better to have your code run from Flash, this will avoid having to load the code to RAM each time after a power on reset. 

    To minimize the code, one approach will be to use only the driverlib APIs that are needed in your code. You can use a preprocessor directive to include only such functions and recompile the driverlib library .  This is assuming that you are using the driverlib based approach.

    You can refer to the following link 

    https://software-dl.ti.com/C2000/docs/optimization_guide/phase3/optimization_levels.html

    Best Regards

    Siddharth

  • Its better to have your code run from Flash, this will avoid having to load the code to RAM each time after a power on reset. 

    Based on your comment, I added FLASH to the linker command file, and assigned .econst to it.  Then I was able to reassign all of RAML0 to Page 0.  So, this is working, and I can expand as much of my new code into FLASH as is possible/necessary.

    To minimize the code, one approach will be to use only the driverlib APIs that are needed in your code.
    assuming that you are using the driverlib based approach.

    I was only able to find a bitfield example of I2C code, so I'm not using the driverlib approach.  Are you able to point me to some I2C example code using the driverlib approach?  Can I implement this approach without having example code to start with?

    You can use a preprocessor directive to include only such functions and recompile the driverlib library

    Can you expand on that?  Is there a document demonstrating the use of the preprocessor directive?  Also, how to recompile the driverlib library?

    Thanks,
    robin

  • Robin , 

    Looks like there is no driverlib example for I2C for TMS320F28020 device. You can continue with the bitfield approach. 

    You can load the code to Flash and also use the compiler options to optimize the code. 

    Best Regards

    Siddharth