Quantcast
Channel: Forums - Recent Threads
Viewing all articles
Browse latest Browse all 262198

MSP430F5529: SPI communication sending bytes twice

$
0
0

Part Number:MSP430F5529

Hello,

I am trying to connect Raspberry pi 3 B + with the MSP430f5529 (launchpad) using SPI communication but I seem to encounter an error I can't get around.

The SPI communication is a 3 wire connection with the Raspberry being the master and the MSP the slave. I have made sure that all the SPI parameters are OK (clock polarity and phase, etc...). The program consists simply in the raspberry sending a command (TX_CMD) in order to make the MSP read a sensor (not implemented yet, simulated as an array being modified) and then send back 4096 bytes (maximum supported by Raspberry buffer).

The problem is that the MSP sends twice the first byte to transmit (after receiving the TX_CMD), so the last byte is not sent. I have also seen that when I increase the SPI CLK frequency, more than just the first byte is sent twice. I thought it might be the SYS clock not being able to keep up with the SPI interrupt frequency, but after increasing the MCLK speed to 20MHz I stilll have the same error. The program runs fine for low frequencies, but are too low for an SPI communication (around 120KHz).

I don't usually post in forums, if any info is required just ask. I leave the code here:

#include <msp430.h> 
#include <stdint.h>
#include <stdbool.h>



#define SLAVE_CS_IN     P2IN
#define SLAVE_CS_DIR    P2DIR
#define SLAVE_CS_PIN    BIT0


#define IT_CMD 11
#define TX_CMD 22


void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
    uint8_t copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
        dest[copyIndex] = source[copyIndex];
    }
}

//INIT FUNCTIONS
void initGPIO()
{
  //LEDs
  P1OUT = 0x00;                             // P1 setup for LED & reset output
  P1DIR |= BIT0 + BIT5;

  P4DIR |= BIT7;
  P4OUT &= ~(BIT7);

  //SPI Pins
  P3SEL |= BIT3 + BIT4;                     // P3.3,4 option select
  P2SEL |= BIT7;                            // P2.7 option select

  /*
  P2SEL |= BIT2;        //PARA MIRAR LA FRECUENCIA DEL SMCLK EN EL PIN 2.2
  P2DIR |=   BIT2;
  */
}

void initSPI()
{
  //Clock Polarity: The inactive state is high
  //MSB First, 8-bit, Master, 3-pin mode, Synchronous
  UCA0CTL1 = UCSWRST;                       // **Put state machine in reset**
  UCA0CTL0 |=  UCMSB + UCSYNC;// +UCCKPH;      // 3-pin, 8-bit SPI Slave
  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA0IE |= UCRXIE;                          // Enable USCI0 RX interrupt

  SLAVE_CS_DIR &= ~(SLAVE_CS_PIN);

}

void initClockTo16MHz()
{
    UCSCTL3 |= SELREF_2;                      // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
    __bis_SR_register(SCG0);                  // Disable the FLL control loop
    UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx
    UCSCTL1 = DCORSEL_6; //DCORSEL_5;                      // Select DCO range 16MHz operation
    UCSCTL2 = FLLD_0 + 762;//487;                   // Set DCO Multiplier for 16MHz
                                              // (N + 1) * FLLRef = Fdco
                                              // (487 + 1) * 32768 = 16MHz
                                              // Set FLL Div = fDCOCLK
    __bic_SR_register(SCG0);                  // Enable the FLL control loop

    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
    // UG for optimization.
    // 32 x 32 x 16 MHz / 32,768 Hz = 500000 = MCLK cycles for DCO to settle
    __delay_cycles(500000);//
    // Loop until XT1,XT2 & DCO fault flag is cleared
    do
    {
        UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
        SFRIFG1 &= ~OFIFG;                          // Clear fault flags
    }while (SFRIFG1&OFIFG);                         // Test oscillator fault flag
}

uint16_t setVCoreUp(uint8_t level){
    uint32_t PMMRIE_backup, SVSMHCTL_backup, SVSMLCTL_backup;

    //The code flow for increasing the Vcore has been altered to work around
    //the erratum FLASH37.
    //Please refer to the Errata sheet to know if a specific device is affected
    //DO NOT ALTER THIS FUNCTION

    //Open PMM registers for write access
    PMMCTL0_H = 0xA5;

    //Disable dedicated Interrupts
    //Backup all registers
    PMMRIE_backup = PMMRIE;
    PMMRIE &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE |
                SVSLPE | SVMHVLRIE | SVMHIE |
                SVSMHDLYIE | SVMLVLRIE | SVMLIE |
                SVSMLDLYIE
                );
    SVSMHCTL_backup = SVSMHCTL;
    SVSMLCTL_backup = SVSMLCTL;

    //Clear flags
    PMMIFG = 0;

    //Set SVM highside to new level and check if a VCore increase is possible
    SVSMHCTL = SVMHE | SVSHE | (SVSMHRRL0 * level);

    //Wait until SVM highside is settled
    while((PMMIFG & SVSMHDLYIFG) == 0)
    {
        ;
    }

    //Clear flag
    PMMIFG &= ~SVSMHDLYIFG;

    //Check if a VCore increase is possible
    if((PMMIFG & SVMHIFG) == SVMHIFG)
    {
        //-> Vcc is too low for a Vcore increase
        //recover the previous settings
        PMMIFG &= ~SVSMHDLYIFG;
        SVSMHCTL = SVSMHCTL_backup;

        //Wait until SVM highside is settled
        while((PMMIFG & SVSMHDLYIFG) == 0)
        {
            ;
        }

        //Clear all Flags
        PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
                     SVMLVLRIFG | SVMLIFG |
                     SVSMLDLYIFG
                     );

        //Restore PMM interrupt enable register
        PMMRIE = PMMRIE_backup;
        //Lock PMM registers for write access
        PMMCTL0_H = 0x00;
        //return: voltage not set
        return false;
    }

    //Set also SVS highside to new level
    //Vcc is high enough for a Vcore increase
    SVSMHCTL |= (SVSHRVL0 * level);

    //Wait until SVM highside is settled
    while((PMMIFG & SVSMHDLYIFG) == 0)
    {
        ;
    }

    //Clear flag
    PMMIFG &= ~SVSMHDLYIFG;

    //Set VCore to new level
    PMMCTL0_L = PMMCOREV0 * level;

    //Set SVM, SVS low side to new level
    SVSMLCTL = SVMLE | (SVSMLRRL0 * level) |
               SVSLE | (SVSLRVL0 * level);

    //Wait until SVM, SVS low side is settled
    while((PMMIFG & SVSMLDLYIFG) == 0)
    {
        ;
    }

    //Clear flag
    PMMIFG &= ~SVSMLDLYIFG;
    //SVS, SVM core and high side are now set to protect for the new core level

    //Restore Low side settings
    //Clear all other bits _except_ level settings
    SVSMLCTL &= (SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 +
                 SVSMLRRL1 + SVSMLRRL2
                 );

    //Clear level settings in the backup register,keep all other bits
    SVSMLCTL_backup &=
        ~(SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 + SVSMLRRL1 + SVSMLRRL2);

    //Restore low-side SVS monitor settings
    SVSMLCTL |= SVSMLCTL_backup;

    //Restore High side settings
    //Clear all other bits except level settings
    SVSMHCTL &= (SVSHRVL0 + SVSHRVL1 +
                 SVSMHRRL0 + SVSMHRRL1 +
                 SVSMHRRL2
                 );

    //Clear level settings in the backup register,keep all other bits
    SVSMHCTL_backup &=
        ~(SVSHRVL0 + SVSHRVL1 + SVSMHRRL0 + SVSMHRRL1 + SVSMHRRL2);

    //Restore backup
    SVSMHCTL |= SVSMHCTL_backup;

    //Wait until high side, low side settled
    while(((PMMIFG & SVSMLDLYIFG) == 0) &&
          ((PMMIFG & SVSMHDLYIFG) == 0))
    {
        ;
    }

    //Clear all Flags
    PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
                SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG
                );

    //Restore PMM interrupt enable register
    PMMRIE = PMMRIE_backup;

    //Lock PMM registers for write access
    PMMCTL0_H = 0x00;

    return true;
}

bool increaseVCoreToLevel2()
{
    uint8_t level = 3;//2;
    uint8_t actlevel;
    bool status = true;

    //Set Mask for Max. level
    level &= PMMCOREV_3;

    //Get actual VCore
    actlevel = PMMCTL0 & PMMCOREV_3;

    //step by step increase or decrease
    while((level != actlevel) && (status == true))
    {
        if(level > actlevel)
        {
            status = setVCoreUp(++actlevel);
        }
        else{
            status = setVCoreUp(--actlevel);
        }
    }

    return (status);
}

void SendUCA0Data(uint8_t val)
{
    //while (!(UCA0IFG & UCTXIFG));              // USCI_A0 TX buffer ready?
    UCA0TXBUF = val;
}
/**
 * main.c
 */
typedef enum SPI_ModeEnum{
    IDLE_MODE,
    SET_IT_MODE,
    TX_MODE,
} SPI_Mode;

uint8_t SlaveMode = IDLE_MODE;
uint8_t TxBuff[4096] = {0};
uint8_t *txptr;
uint8_t RXCounter = 0;  //To receive the integration time (2 bytes)
uint16_t TXCounter = 4096;
volatile uint16_t TXIndex = 0;
uint16_t integration_time = 2096;

uint8_t debug = 1;

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer
	
    increaseVCoreToLevel2();
    initClockTo16MHz();
    initGPIO();
    initSPI();

    //txptr = TxBuff;             //Init the txpointer to the correc position

    __bis_SR_register(GIE);
    while (1){
        if(SlaveMode == TX_MODE && TXIndex == 0){
            //SensorRead();
            TxBuff[0] = 27;
            TxBuff[1] = 28;
            TxBuff[2] = 29;
            TxBuff[3] = debug;
            TxBuff[4095] = 32;
            debug++;
            //UCA0TXBUF = *txptr++;
            //SendUCA0Data(TxBuff[TXIndex++]);
            UCA0TXBUF = TxBuff[TXIndex++];

        }
    }
	return 0;
}

//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************



#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  uint8_t uca0_rx_val = 0;
  switch(__even_in_range(UCA0IV,4))
  {
    case 0:break;                             // Vector 0 - no interrupt
    case 2:                                   // Vector 2 -RX interrupt
        uca0_rx_val = UCA0RXBUF;
        switch (SlaveMode)
        {
              case (IDLE_MODE):
                  if (uca0_rx_val == IT_CMD) {
                      RXCounter = 0;
                      SlaveMode = SET_IT_MODE;
                      UCA0TXBUF = 99;
                  }
                  else if (uca0_rx_val == TX_CMD) {SlaveMode = TX_MODE;}
                  break;
              case (SET_IT_MODE):

                  integration_time |= uca0_rx_val<<(RXCounter*8);
                  RXCounter++;

                  if (RXCounter >= 2) {
                      SlaveMode = IDLE_MODE;
                  }
                  UCA0TXBUF = 99;

                  break;
              case (TX_MODE):
                  TXCounter--;
                  if(TXCounter<1){
                      UCA0TXBUF = 86;
                      //txptr = TxBuff;           //reset pointer
                      TXCounter = 4096;
                      TXIndex = 0;
                      SlaveMode = IDLE_MODE;
                      break;
                  }
                  if (TXIndex > 0){
                      //UCA0TXBUF = *txptr++;
                      //SendUCA0Data(TxBuff[TXIndex++]);
                      UCA0TXBUF = TxBuff[TXIndex++];
                  }
                  else {UCA0TXBUF = 11;}
                  break;
              default:
                  UCA0TXBUF = 77;
                  __no_operation();
                  break;
        }

        break;
    case 4:break;                             // Vector 4 - TXIFG
    default: break;
  }
}

//END OF THE CODE

Correct at 180KHz:

First byte twice at 500KHz:

More bytes repeated at 3MHz:

Thanks in advance.


Viewing all articles
Browse latest Browse all 262198

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>