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.

CCS/TMS320F28335: Sending commands using SCI and getting framing error (FE)

Part Number: TMS320F28335
Other Parts Discussed in Thread: CONTROLSUITE

Tool/software: Code Composer Studio

Hello everyone,

I'm using a C2000 F28335 (R2.2) control card with a docking station and coding with Code Composer 6.2.0.00050. I need to send commands to a motor using RS232 (SCI).

The motor is correctly linked to the F28335 :

- its Rx to Tx pin of the card and its Tx to Rx pin of the card,

- powered by an external power supply (+24V).

To begin my project, I've used the SCI loopback example and it perfectly worked. But with my program I'm getting Framing Error (FE) bit set to 1 after the first sent command. Maybe I'm missing something and/or I did it wrong. Could you please help me ?

My objective is to activate the motor, then to ask 60 RPM (I'm also using a LED to see if the FE bit is set) :

1st command : EN [CR] (enable motor)

2nd command : V60 [CR] ( asking 60 RPM)

3st command (inside the for loop) : POS [CR] (requesting actual position)

Here is my code :

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

#define CPU_FREQ 	 150E6
#define LSPCLK_FREQ  CPU_FREQ/4

// Prototype statements for functions found within this file.
__interrupt void cpu_timer0_isr(void);

void scia_init(void);
void scia_fifo_init(void);
void scia_xmit(int a);

void scib_init(void);
void scib_fifo_init(void);
void scib_xmit(int a);

void error();

void scia_msg(char *msg);

// Global counts used in this example
Uint16 LoopCount;
Uint16 ErrorCount;
char dataToRead[10];

void main(void)
{
	// unsigned char SendChar;
	unsigned char ReceivedChar;
	char *msg;
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
	InitSysCtrl();

// Step 2. Initialize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio();  // Skipped for this example
	InitSciaGpio();
	InitScibGpio();

// 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 DSP2833x_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 DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
   InitPieVectTable();

   // Enable CPU and PIE interrupts
   // This example function is found in the DSP2833x_PieCtrl.c file.
   EnableInterrupts();

// Step 4. Initialize all the Device Peripherals to a known state:
// This function is found in DSP2833x_InitPeripherals.c
// InitPeripherals(); skip this for SCI tests

// Step 5. User specific functions, Reassign vectors (optional), Enable Interrupts:

   LoopCount = 0;
   ErrorCount = 0;

   scia_fifo_init();	   // Initialize the SCI FIFO
   scia_init();  // Initialize SCI

   scib_fifo_init();	   // Initialize the SCI FIFO
   scib_init();  // Initialize SCI

   unsigned char charP = 0x50;
   unsigned char charO = 0x4F;
   unsigned char charS = 0x53;
   unsigned char charE = 0x45;
   unsigned char charN = 0x4E;
   unsigned char charI = 0x49;
   unsigned char charD = 0x44;
   unsigned char charCR = 0x0D;

   int statePosRead = 0;

// 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.TINT0 = &cpu_timer0_isr;
   EDIS;    // This is needed to disable write to EALLOW protected registers

// Step 4. Initialize the Device Peripheral. This function can be
//         found in DSP2833x_CpuTimers.c
   InitCpuTimers();   // For this example, only initialize the Cpu Timers

   ConfigCpuTimer(&CpuTimer0, 150, 50000);

// To ensure precise timing, use write-only instructions to write to the entire register. Therefore, if any
// of the configuration bits are changed in ConfigCpuTimer and InitCpuTimers (in DSP2833x_CpuTimers.h), the
// below settings must also be updated.

   CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0


// Configure GPIO58 as a GPIO output pin
   EALLOW;
   GpioCtrlRegs.GPBMUX2.bit.GPIO58 = 0;
   GpioCtrlRegs.GPBDIR.bit.GPIO58 = 1;
   EDIS;

// Enable CPU INT1 which is connected to CPU-Timer 0:
   IER |= M_INT1;

// Enable TINT0 in the PIE: Group 1 interrupt 7
   PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

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

   // EN CR
   scib_xmit(charE);
   scib_xmit(charN);
   scib_xmit(charCR);

   while (ScibRegs.SCIFFTX.bit.TXFFST != 0) {}

   // V60 CR
   scib_xmit(0x56);
   scib_xmit(0x39);
   scib_xmit(charCR);

   DELAY_US(10000);

   for(;;)
   {
	   scib_xmit(charP);
	   scib_xmit(charO);
	   scib_xmit(charS);
	   scib_xmit(charCR);

	   DELAY_US(10000);

	   while (ScibRegs.SCIFFRX.bit.RXFFST == 0) {}
	   int cptRead = ScibRegs.SCIFFRX.bit.RXFFST;
	   int i = 0;
	   //char *dataToRead = malloc(cptRead*sizeof(char));
	   //char dataToRead[cptRead];

	   for(i=0;i<cptRead;i++)
	   {
		   dataToRead[i] = ScibRegs.SCIRXBUF.all;
		   DELAY_US(1000);
	   }

      msg = "\r\nReceived position : \n\0";
      scia_msg(msg);
      scia_xmit(dataToRead[0]);

      LoopCount++;
   }
}


__interrupt void cpu_timer0_isr(void)
{
   if (ScibRegs.SCIRXST.bit.FE == 1){
   CpuTimer0.InterruptCount++;
   GpioDataRegs.GPBTOGGLE.bit.GPIO58 = 1; // Toggle GPIO58 if FE bit is set
   }
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

void error()
{
      ErrorCount++;
}

void scia_init()
{
    // Note: Clocks were turned on to the SCIA peripheral
    // in the InitSysCtrl() function
 	SciaRegs.SCICCR.all =0x0007;   // 1 stop bit,  No loopback
                                   // No parity,8 char bits,
                                   // async mode, idle-line protocol
	SciaRegs.SCICTL1.all =0x0003;  // enable TX, RX, internal SCICLK,
                                   // Disable RX ERR, SLEEP, TXWAKE
	SciaRegs.SCICTL2.all =0x0003;
	SciaRegs.SCICTL2.bit.TXINTENA =1;
	SciaRegs.SCICTL2.bit.RXBKINTENA =1;
    SciaRegs.SCIHBAUD    =0x0001; // BRR = 487 => Baud = 9600
    SciaRegs.SCILBAUD    =0x00E7;
	SciaRegs.SCICTL1.all =0x0023;     // Relinquish SCI from Reset
}

// Transmit a character from the SCI'
void scia_xmit(int a)
{
	while (SciaRegs.SCICTL2.bit.TXRDY == 0) {}
	SciaRegs.SCITXBUF=a;
}

void scia_msg(char * msg)
{
    int i;
    i = 0;
    while(msg[i] != '\0')
    {
        scia_xmit(msg[i]);
        i++;
    }
}

// Initialize the SCI FIFO
void scia_fifo_init()
{
    SciaRegs.SCIFFTX.all=0xE040;
    SciaRegs.SCIFFRX.all=0x204f;
    SciaRegs.SCIFFCT.all=0x0;
}

void scib_init()
{
    // Note: Clocks were turned on to the SCIB peripheral
    // in the InitSysCtrl() function
 	ScibRegs.SCICCR.all =0x0007;   // 1 stop bit,  No loopback
                                   // No parity,8 char bits,
                                   // async mode, idle-line protocol
	ScibRegs.SCICTL1.all =0x0003;  // enable TX, RX, internal SCICLK,
                                   // Disable RX ERR, SLEEP, TXWAKE
	ScibRegs.SCICTL2.all =0x0003;
	ScibRegs.SCICTL2.bit.TXINTENA =1;
	ScibRegs.SCICTL2.bit.RXBKINTENA =1;
    ScibRegs.SCIHBAUD    =0x0001; // BRR = 487 => Baud = 9600
    ScibRegs.SCILBAUD    =0x00E7;
	ScibRegs.SCICTL1.all =0x0023;     // Relinquish SCI from Reset
}

// Transmit a character from the SCI'
void scib_xmit(int a)
{
	while (ScibRegs.SCICTL2.bit.TXRDY == 0) {}
	ScibRegs.SCITXBUF=a;
}

// Initialize the SCI FIFO
void scib_fifo_init()
{
    ScibRegs.SCIFFTX.all=0xE040;
    ScibRegs.SCIFFRX.all=0x204f;
    ScibRegs.SCIFFCT.all=0x0;
}

//===========================================================================
// No more.
//===========================================================================

Thanks for your help !

  • Hi,

    Does the frame error occur when you send a command or when you receive a response?

    It is my understanding that it should occur when data is received. You should make sure that the number of data bits, parity bits, and stop bits are the same between the device and the motor. If they are not expecting the same format, then it could cause a frame error response.

    Hope this helps.
    sal
  • Hi Sal,

    Thank you for considering my problem.

    The motor is expecting this format :

    - 8 bits length,

    - no parity,

    - 1 stop bit.

    The baud rate is 9600.

    So I've set the SCI_b like this :

    SPICCR = 0x07 (8 bits length, no parity, 1 stop bit, no loopback, idle line mode protocol as the protocol used is RS232).

    SCIHBAUD = 0x01;

    SCILBAUD = 0x07; (BRR = 487 => with LSPCLK = 37.5 MHz the SCI baud is 9600).

    Using the debug mode (step by step) I see that the Frame Error occurs when i send the first char of V60 command. Also I see that the FIFO receive register has 2 words at the exact same moment FE is set.

    The motor came with a demo card and a software. I can reproduce the exact same commands and see the terminal transmitted and received messages. With the motor's software the commands are correctly executed by the motor.

    I've updated my commands in order to be exactly in the same conditions as the software's ones :

       // EN CR
       scib_xmit(charE);
       scib_xmit(charN);
       scib_xmit(charCR);
    
       // V60 CR
       scib_xmit(0x56);
       scib_xmit(0x36); // 6
       scib_xmit(0x30); // 0
       scib_xmit(charCR);
  • The SCI is clocked off of the Low Speed Peripheral Clock which is divided down from the SYSCLK.'

    Do you know if your SYSCLK and LSPCLK is what you are expecting?

    Regards,
    sal
  • Hi Sal,

    The crystal clock is 30MHz on the F28335. All the following parameters are defined in the controlSUITE file "DSP2833x_Examples.h" :

    - PLLCR value is 10,

    - PLLSTS value is 2.

    So I should have : SYSCLKOUT = (OSSCLK*PLLCR)/PLLSTS = (30*10)/2 = 150 MHz.

    The CPU_RATE (instruction cycle) is properly defined at 6.667 ns.

    Also I have :

        SysCtrlRegs.HISPCP.all = 0x0001;
        SysCtrlRegs.LOSPCP.all = 0x0002 // => div' by 4;

    Then LSPCLK = SYSCLKOUT/4= 150/4 = 37.5 MHz.

    On the clock parameters side I think everything is OK =/

  • I am not sure what the issue is here right now.

    Can you try disconnecting the motor and enabling loopback? Just to make sure the SCI is configured properly and working?

    The next thing to do would be to hook up an oscilloscope or communication analyzer to see what is being sent and received on the SCI communication lines.

    sal
  • Thank you for all your answers Sal,

    After enabling loopback on SCI_b and modifying the scib_xmit function like this :

    // Transmit a character from the SCI'
    void scib_xmit(int a)
    {
    	while (ScibRegs.SCICTL2.bit.TXRDY == 0) {}
    	ScibRegs.SCITXBUF=a;
    	while (ScibRegs.SCIFFRX.bit.RXFFST == 0) {}
    	scia_xmit(ScibRegs.SCIRXBUF.all);
    }

    I can perfectly see the messages EN -> V60 -> POS (loop) on puTTy (9600 baud).

    I'll try to find a communication analyser and I'll get back to you. We're also going to contact the motor supplier.

  • Great. Glad that is working. It appears the MCU would be working properly then.

    Maybe the motor is expecting something different. Let me know what you find.

    Regards,
    sal
  • Hi Sal,

    I think that we did a huge mistake... Can you confirm us that the SCI uses the bit levels 0V (state 0) and +Vcc (or +Vdd ?) (state 1) ? Because that's what we see on the oscilloscope... SCI uses TTL or CMOS logic ?

    In this case I think we can't communicate with our motor which is using the RS232 logic :
    - state 0 : +3V to +15V
    - state 1 : -3V to -15V

    The solution would be to use a MAX 232 hardware interface in order to convert the logic levels ?

    Many thanks,
  • Hi,

    Yes, state 0 is 0V and state 1 is 3.3V.

    Regards,
    sal