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.

msp430 spi communication

Other Parts Discussed in Thread: CC2500

Dear all

I'm trying to speed up communication through the spi interface between a msp430 and the CC2500.

I'm performing a burst write access on the CC2500_TXFIFO with the following code.

    CSn_PxOUT &= ~CSn_PIN;                                                        // CC2500 CS enable
    while (SPI_USCIB0_PxIN&SPI_USCIB0_SOMI);                    // Wait for CC2500 ready

    IFG2 &= ~UCB0RXIFG;

                      // Send the address of the register to be written (burst mode selected

    UCB0TXBUF = TI_CC2500_TXFIFO | TI_CC2500_WRITE_BURST;                                                                                            
    while (!(IFG2&UCB0RXIFG));                                                      // Wait for TX to finish
   
    // send the size of the buffer to be sent (CC2500 used in variable packet lenght transmission mode)
    IFG2 &= ~UCB0RXIFG;
    UCB0TXBUF = size;                            // Send buffer size
    while (!(IFG2&UCB0RXIFG));            // Wait for TX to finish
    IFG2 &= ~UCB0RXIFG;

 for (i = 0; i < count; i++)
    {
      IFG2 &= ~UCB0RXIFG;
      UCB0TXBUF = buffer[i];                      // Send data
      while (!(IFG2&UCB0RXIFG));            // Wait for TX to finish
    }

With a 1MHz clock I guess I can complete the buffer transfer within count*8/1MHz [sec]. However, it is not what happens. I checked waveforms with a mixed signal oscilloscope and I noticed that there are dead times of about 28[us] between each 8bit transfer.

The question is: is it everything working as it should? I guess it doesn't because Figure 8 at page 20 of the CC2500 datasheet shows the timing diagram for different allowed register access types. In particular, the timing diagram for the burst access doesnt show any delay between consecutive data tranfers.

Any suggestion wil be welcome.

Thanks in advance

Gian

  • Just took quick look at the code I wrote some months ago (or should I say: I copied into my project from a TI sample [:$]).

    The big difference is: The SPI send loop waits for the TXIFG and not for the RXIFG. Here is the code from my app (F4618 project):

    for (i = 0; i < count; i++)
        {
          U0TXBUF = buffer[i];                  // Send data
          while (!(IFG1&UTXIFG0));              // Wait for TX to finish
        }

    I guess that the 28µs is caused by waiting for the RXIFG. But I would not worry to much about that: When using SPI, sending slower than allowed is rarely a problem...

    Regards,
    Johannes

     

  • As reported in the MSP430 datasheet

    "A set transmit interrupt flag, UCxTXIFG, indicates that data has moved from
    UCxTXBUF to the TX shift register and UCxTXBUF is ready for new data. It
    does not indicate RX/TX completion."

    So, if you want to be sure that transmission is completed correctly, you have to check the UCxRXIFG.

    I know that if you go slower everything works fine but the problem is that I want to go faster.

    To better understand why, here is a brief description of my application. I have two EZ430 Development Kits.  I want to sample and convert data (continuosly) with the integrated ADC of the MSP430.   I also want to send these data with the CC2500 to the target board which is in charge of sending received data to a PC. The maximum sampling frequency without any data lost is currently 8KHz, but I need to sample at a minimum of 20KHz.

  • "A set transmit interrupt flag, UCxTXIFG, indicates that data has moved from
    UCxTXBUF to the TX shift register and UCxTXBUF is ready for new data. It
    does not indicate RX/TX completion."

    That is exactly the point why you should use the TXIFG flag: It is possible to fill the buffer with a new byte while the USCI is still shifting out the bits. This way, you can avoid a gap between the bytes. If you want to be sure that transmission is complete, you can wait the RXIFG (or BUSY flag in Status register) to make sure that the burst transfer is complete. That is exactly what the TI code does (I should have copied 2 more line into my last post):

        for (i = 0; i < count; i++)
        {
          U0TXBUF = buffer[i];                  // Send data
          while (!(IFG1&UTXIFG0));              // Wait for TX to finish
        }
        IFG1 &= ~URXIFG0;
        while(!(IFG1&URXIFG0));

    Hope this helps,
    Johannes

  • I already tried to do what you suggest, but nothing changes. The gap between consecutives tranfers remains: after 8 cycles the SMCLK stops clocking and restart after around 24us.

  • SMCLK stops?? This would mean that the CPU is going into LPM between sending bytes... or did you mean the SPI clock? Anyway, 28µs is quite a long time and it can't be fully explained by the time the CPU needs to run the loop and load another byte into the TXBUFFER (at least if CPU speed is above 1MHz). Maybe the CPU is executung an IRQ while running the loop? What happens if you disable the IRQs before entering the send loop?
    Regards,
    Johannes

  • Actually the SPI clock (derived from the SMCLK) stops for sure, but I can't tell you if the SMCLK stops as well. I disable all IRQs as following:

    IE1 &= 0x00;

    IE2 &= 0x00;

    (Guess it's enough!)

    And nothing changes.Anyway, the USCIB0 interrupt had already been disabled since in IE2 register both UCB0TXIE and UCB0RXIE bits were reset.

    One more thing. I speed up the SPI clock source untill 4MHz and, strange thing, the dead time is still of about 24us.

    Regards

    Gian

     

  • The easiest way to disable every interrupt is clearing the GIE flag (you can use _DINT(); for that is you are using IAR). For example the timer interrupts might still be active even if you clear IE1/IE2. But now I am nearly running out of ideas... maybe one last question before I give up: Do you find the gap between EVERY byte or only some of the bytes?

  • Even if GIE are disabled I got the gap after EACH byte transfer.

    I can't undestand why this happens.

    Regards

    Gian

  • Last thing to check is now: Did you (accidently) configure the USCI in 4 wire SPI mode and STE temporary blocks the transfers? Maybe you should post the USCI initialization code here... and maybe someone else has an idea? I am out now... have never seen this before, too.
    Regards,
    Johannes

     

  • Hi Johannes

    Here is the SPI initialization

    void SPISetup(void)
    {
      // Slaves are hereafter disabled. The system have multiple slaves which can be individually selected
      //CC2500 nCS==1
      CSn_PxDIR |= CSn_PIN;
      CSn_PxOUT |= CSn_PIN;            
      // DAC_nCS==1
      DAC_CSn_PxDIR |= DAC_CSn_PIN;
      DAC_CSn_PxOUT |= DAC_CSn_PIN;          

      //MUX_nCS==1
      MUX_CSn_PxDIR |= MUX_CSn_PIN;
      MUX_CSn_PxOUT |= MUX_CSn_PIN;
      //STIM_POWER_nSHDN==0;
      STIM_POWER_SUPPLY_nSHDN_PxDIR |= STIM_POWER_SUPPLY_nSHDN_PIN;
      STIM_POWER_SUPPLY_nSHDN_PxOUT &= ~STIM_POWER_SUPPLY_nSHDN_PIN;
     
    // USCIB0 module initialization
      UCB0CTL0 = UC_CK_POL_LOW + UC_MSB_FIRST + UC_MST_MODE + UC_3pin_SPI + UC_SYNC_MODE;
    // initialize MSB transmission first, master mode, 3pin SPI mode, Sync mode.
     
      UCB0CTL1 = UC_SMCLK_SOURCE_SEL;   //SMCLK mode select
      UCB0BR0 = 0x02;                   //The clock frequency is scaled by UCB0BR0 + UCB0BR1*256
      UCB0BR1 = 0x00;
     
      // NOTE: the SPI interface is clocked at 4 MHz;
     
      SPI_USCIB0_PxSEL |= SPI_USCIB0_UCLK | SPI_USCIB0_SOMI | SPI_USCIB0_SIMO;
          // 3-pin SPI option
      SPI_USCIB0_PxDIR |= SPI_USCIB0_SIMO | SPI_USCIB0_UCLK;
          // SPI TX output direction
     
      UCB0CTL1 &= ~UC_USCI_MOD_DIS;       // disable software reset. USCI module reset released for operation
    }

    While the following is the porcedure for the burst access:

    void SPIWriteBurstReg(char addr, char *buffer, char count)
    {
        unsigned int i;

        CSn_PxOUT &= ~CSn_PIN;                    // /CS enable
        while (SPI_USCIB0_PxIN&SPI_USCIB0_SOMI);  // Wait for CC2500 ready
        IFG2 &= ~UCB0RXIFG;
        UCB0TXBUF = addr | TI_CC2500_WRITE_BURST; // Send the address of the register to be written
        while (!(IFG2&UCB0RXIFG));                // Wait for TX to finish
        for (i = 0; i < count; i++)
        {
          IFG2 &= ~UCB0RXIFG;
          UCB0TXBUF = buffer[i];                // Send data
          while (!(IFG2&UCB0RXIFG));            // Wait for TX to finish
        }
        CSn_PxOUT |= CSn_PIN;       // /CS disable
    }

    Regards

    Gian

  • The configuration of the USCI should only be changed when the USCI is held in reset state. With UCB0CTL1 = UC_SMCLK_SOURCE_SEL; you release the USCI for operation by accidently clearing the UCSWRST (UC_USCI_MOD_DIS) bit and afterwards you change the bit rate. Maybe that is the problem?
    So simply change the line into UCB0CTL1 |= UC_SMCLK_SOURCE_SEL; and let's see what happens... 
    In case you initilize the USCI several times, than you should make sure, that the USCI is always in reset before you write to a register.

    Regards,
    Johannes

  • Even if the reset should be released only after setup is completed, that's not the problem. I corrected the code as you suggest, but nothing changes.

    I'm really getting crazy with this!

    Gian

  • I have finally almost fixed the problem by speeding up the MCLK (it's not a real solution but it works pretty well at the cost of more power consumption). Infact the "dead times" are mainly due to the for cycle which is used to move packets on the TXbuffer.

    Thanks Johannes for your patience

    Gian

**Attention** This is a public forum