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.

SPI communication between CC2480 and the MSP430f47196 device

Other Parts Discussed in Thread: MSP430F47196

Hi,

I have a problem with the SPI communication between CC2480 and the MSP430f47196 device.

When I send a sys_Version request, I get only 0xFF value from the CC2480. I checked different clock settings, MRDY/ SRDY signals and the configuration of my MSP430 Board and I didn't find an issue.

My hardware clock frequency is 8MHz and it is supplied with 3.3V

The CC2480 software is a modification of the Ti Zigbee software:



/* *****************************Main Zigbee CC2480***************************************/


#include  <msp430x471x6.h>

#include "cc2480.h"
#include "cc2480_rpc_spi.h"


#define SRDY 16;
#define MRDY 32;
#define SS 8;
#define Reset 8;
#define CFG0_CFG1 6;

void Turn_On_Interrupts(void)
{
  __enable_interrupt();
}

void Turn_Off_Interrupts(void)
{
  __disable_interrupt();
}

void Config_IO_MCU_Ports(void)
{
    P1OUT &=~ 255;
    P2OUT &=~ 255;
    
    

    P1DIR &=~ SRDY;
    P1REN |= SRDY;
    
   
    P2DIR |= SS;
    P2OUT |= SS;
    P2SEL |= SS;
  
    
    P1DIR |= MRDY;
    P1OUT |= MRDY;
    
  /*********** Przytrzymanie ukladu CC2480 w stanie Reset**************/

    
    P1DIR |= Reset;
    P1OUT &=~ Reset;
  
    
    P1DIR |= CFG0_CFG1;
    P1OUT |= CFG0_CFG1;
 
      /* P4.0 is a DO to control Cfg0 (Slave Configuration Switch 0.)
    * - Set high configures slave to use 32-kHz crystal installed and used.
    * - Set low configures slave to use internal oscillator.
    * P4.1 is a DO to control Cfg1 (Slave Configuration Switch 1.)
    * - Set high configures slave to use SPI transport.
    * - Set low configures slave to use UART transport.
    */
 
}

void Config_MCU_CLK(void)
{
    unsigned int i;
   
    FLL_CTL1 |= SELM1 + SELS;            
    FLL_CTL1 &=~ (XT2OFF + SELM0);
    
    do
   {
    IFG1 &= ~OFIFG;                           // Clear OSCFault flag
    for (i = 0x47FF; i > 0; i--);             // Time for flag to set
    }
    while ((IFG1 & OFIFG));                   // OSCFault flag still set?

}

void Config_SPI_Register(void)
{
    /* Clear MRDY and Disable SPI interface */
    ZACCEL_SPI_END();
    /* Set optional CCZACC configuration pins */
    ZACCEL_CFG0_OPIN(1);
    ZACCEL_CFG1_OPIN(1);
    
    UCA1CTL1 |= UCSWRST;
    UCA1BR0 = 1;
    UCA1BR1 = 0;
    UCA1CTL0  = UCMST + UCSYNC + UCMODE_0 + UCMSB; // UCCKPH + UCMSB + UCMST + UCSYNC
    UCA1CTL1 |= UCSSEL_2;
   
    P1SEL |= 64;
    P1OUT |= 64;
    
    P1SEL |= 128;  
    P1OUT |= 128;
     
    P2SEL |= 1;
    P2OUT |= 1;
       
    UCA1CTL1 &= ~UCSWRST;
}

void CC2480_Radio_Reset()
{
    unsigned char Temp;
    
    ZACCEL_RESET();
    
    while(ZACCEL_SRDY_IN() != 0);
      
    ZACCEL_MRDY_SET(); 
    ZACCEL_MRDY_CLR();
    
}

void WaitUs(unsigned int usec)
{
     // The least we can wait is 3 usec:
     // ~1 usec for call, 1 for first compare and 1 for return
     while(usec > 3)       // 2 cycles for compare
     {                     // 2 cycles for jump
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        asm("NOP");       // 1 cycles for nop
        usec -= 2;        // 1 cycles for optimized decrement
      }                   // 4 cycles for returning;
}

void WaitMs(unsigned int msec)
{
      while(msec-- > 0)
    {
          WaitUs(1000);
    }                        
    
}

void main (void)
{
  static unsigned int chipId;

  WDTCTL = WDTPW + WDTHOLD;
 
  Turn_Off_Interrupts();
  Config_IO_MCU_Ports();
  Config_MCU_CLK();
  Config_SPI_Register();
  CC2480_Radio_Reset();
  Turn_On_Interrupts();
  //WaitMs(200);
  //chipId = cc2480HardReset();
  chipId = cc2480GetChipId();
  for(;;);
}


/******************** CC2480.c**********************/


/***********************************************************************************
  Filename:     cc2480.c

  Description:  This file implements basic functions for accessing CC2480

***********************************************************************************/

/***********************************************************************************
* INCLUDES
*/
#include "cc2480.h"


/***********************************************************************************
* CONSTANTS AND DEFINES
*/


/***********************************************************************************
* GLOBAL VARIABLES
*/
unsigned int BUILD_UINT16(loByte, hiByte)
{
  unsigned int temp;
 
  temp = ((unsigned int)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8)));

  return temp;
}

void ZACCEL_CFG0_OPIN(unsigned char val)
{
   if(val)
     {
        P1OUT |= 4;
     }else
        {
          P1DIR &=~ 4;
        }
}

void ZACCEL_CFG1_OPIN(unsigned char val)
{
   if(val)
     {
        P1OUT |= 2;
     }else
        {
          P1DIR &=~ 2;
        }
}


void ZACCEL_SPI_BEGIN(void)
{
  ZACCEL_MRDY_SET();
  ZACCEL_CSN_EN();
  WaitMs(20);
}

void ZACCEL_SPI_END(void)
{
  ZACCEL_MRDY_CLR();
  ZACCEL_CSN_DIS();
}

void ZACCEL_RESET(void)                  
{
  volatile unsigned int i;
  ZACCEL_RESET_SET();
  while (--i) { asm("NOP"); };
  ZACCEL_RESET_CLR();
}

unsigned int ZACCEL_SRDY_IN(void)
{
  unsigned int temp;
 
  temp = (P1IN & 16)/16;
 
  return(temp);
}
/***********************************************************************************
* @fn      cc2480HardReset
*
* @brief   Hardware reset of chip (Hard Reset)
*
* @param   none
*
* @return  uint16 - System Reset Indication ID
*/
unsigned int cc2480HardReset(void)
{
    unsigned char  rtrnCmdId;
    unsigned char  rtrnCmdType;

    /* Reset CC2480 */
    ZACCEL_RESET();

     /* Wait for SRDY to go low */
    while (ZACCEL_SRDY_IN() != 0);

    /* Get SYS_RESET_IND from CC2480 */
    cc2480RpcPoll(hostMsgBuf);

    /* Extract the command ID of the response */
    rtrnCmdType = hostMsgBuf[1];
    rtrnCmdId   = hostMsgBuf[2];

    return (BUILD_UINT16( rtrnCmdId, rtrnCmdType ));   //// Tutaj sprawdzic
}


/***********************************************************************************
* @fn      cc2480SoftReset
*
* @brief   Software reset chip (Soft Reset)
*
* @param   none
*
* @return  uint16 - System Reset Indication ID
*/
unsigned int cc2480SoftReset(void)
{
    unsigned char *pBuf = hostMsgBuf;
    unsigned char  rtrnCmdId;
    unsigned char  rtrnCmdType;

    /* Construct the SYS_RESET_REQ command issued by the application processor */
    *(pBuf+RPC_POS_LEN)   = 0x01;
    *(pBuf+RPC_POS_CMD0)  = RPC_CMDSUBSYS_SYS | RPC_CMD_AREQ;
    *(pBuf+RPC_POS_CMD1)  = CMDID_SYS_RESET_REQ;
    *(pBuf+RPC_POS_PARAM) = 0x00;

    /* Send Soft Reset over SPI bus */
    cc2480Rpc(hostMsgBuf);

    /* Extract the command ID of the response */
    rtrnCmdType = hostMsgBuf[1];
    rtrnCmdId   = hostMsgBuf[2];

    return (BUILD_UINT16( rtrnCmdId, rtrnCmdType )); // Tutaj sprawdzic !!!!!!!!!!!
}


/***********************************************************************************
* @fn      cc2480GetChipId
*
* @brief   Get chip id
*
* @param   none
*
* @return  uint8 - The chip ID
*/
unsigned char cc2480GetChipId(void)
{
    unsigned char *pBuf = hostMsgBuf;

    *(pBuf+RPC_POS_LEN) = 0;
    *(pBuf+RPC_POS_CMD0) = RPC_CMDSUBSYS_SYS | RPC_CMD_SREQ;
    *(pBuf+RPC_POS_CMD1) = CMDID_SYS_VERSION;

    cc2480Rpc(hostMsgBuf);

    return (hostMsgBuf[4]);
}


/***********************************************************************************
* @fn      cc2480GetIEEEAddress
*
* @brief   Get IEEE address
*
* @param   uint8' buffer - where to write the IEEE Address
*
* @return  uint8 - 0
*/
unsigned char cc2480GetIEEEAddress(unsigned char* buffer)
{
    unsigned char *pBuf = hostMsgBuf;
    unsigned char i;

    *(pBuf+RPC_POS_LEN) = 0x01;
    *(pBuf+RPC_POS_CMD0) = RPC_CMDSUBSYS_SAPI | RPC_CMD_SREQ;
    *(pBuf+RPC_POS_CMD1) = CMDID_ZB_GET_DEVICE_INFO;

    /* Parameter 1: Device IEEE address */
    *(pBuf+RPC_POS_PARAM) = 0x01;

    cc2480Rpc(hostMsgBuf);

    /* Write the IEEE address to the specified buffer */
    for (i = 0; i < 8; i++) {
        buffer[i] = hostMsgBuf[4 + i];
    }

    return 0;
}


/***********************************************************************************
* @fn      cc2480Write
*
* @brief   Write to TX buffer; Read RX buffer
*
* @param   uint8* data   - buffer to write and read
*          uint8  length - number of bytes
*
* @return  uint8  - Always 0
*/

void ZACCEL_SPI_TX(unsigned char x)
{
  //UC1IFG &= ~UCA1RXIFG;
  while (!(UC1IFG & UCA1TXIFG));
  //while (UCA1STAT & UCBUSY);
  UCA1TXBUF = x;
}

void ZACCEL_SPI_WAIT_RXRDY(void)
{
   // while (UCA1STAT & UCBUSY);
   while (!(UC1IFG & UCA1RXIFG));
}

unsigned char ZACCEL_SPI_RX()
{
  return UCA1RXBUF;
}
inline unsigned char ZACCEL_SPI_TXRX(unsigned char x)
{
    ZACCEL_SPI_TX(x);
    ZACCEL_SPI_WAIT_RXRDY();
    return ZACCEL_SPI_RX();
}

unsigned char cc2480Write(unsigned char *data, unsigned char length)
{
    while(length--) {
        ZACCEL_SPI_TX(*data);
        ZACCEL_SPI_WAIT_RXRDY();
        *data = ZACCEL_SPI_RX();
        data++;
    }
    return(0);
}


/***********************************************************************************
* @fn      cc2480Read
*
* @brief   Read RX buffer
*
* @param   uint8* data   - data buffer. This must be allocated by caller.
*          uint8  length - number of bytes
*
* @return  uint8  - Always 0
*/
unsigned char cc2480Read(unsigned char *data, unsigned char length)
{
    while (length--) {
        ZACCEL_SPI_TX(0x00);
        ZACCEL_SPI_WAIT_RXRDY();
        *data = ZACCEL_SPI_RX();
        data++;
    }
    return(0);
}

/***********************************************************************************
    Filename:     rpc_spi_cc2480.c

    Description:  RPC SPI master implementation for MSP430

************************************************************************************/


/***********************************************************************************
* INCLUDES
*/

#include "cc2480.h"
#include "cc2480_rpc_spi.h"


/***********************************************************************************
* CONSTANTS AND DEFINES
*/
#define CC2480_PACKET_OVERHEAD_SIZE 3


/***********************************************************************************
* TYPEDEFS
*/


/***********************************************************************************
* LOCAL VARIABLES
*/


/***********************************************************************************
* GLOBAL VARIABLES
*/
unsigned char hostMsgBuf[RPC_MAX_BUF];


/***********************************************************************************
* LOCAL FUNCTIONS
*/
static unsigned char rpcSpiAREQ(unsigned char *pBuf);
static unsigned char rpcSpiSREQ(unsigned char *pBuf);



/**************************************************************************************************
 * @fn          cc2480Rpc
 *
 * @brief       This function effects the requested RPC transaction across the configured medium.
 *
 * input parameters
 *
 * @param       pBuf - Pointer to the RPC buffer.
 *
 * output parameters
 *
 * None.
 *
 * @return      TRUE if RPC transaction with slave succeeded; FALSE otherwise.
 **************************************************************************************************
 */
unsigned char cc2480Rpc(unsigned char *pBuf)
{
  unsigned char rtrn = 0;

  if (RPC_CMD_SREQ == (*(pBuf+RPC_POS_CMD0) & (RPC_CMD_SREQ | RPC_CMD_AREQ)))
  {
    if (rpcSpiSREQ(pBuf))
    {
      rtrn = 1;
    }
  }
  else
  {
    rtrn = rpcSpiAREQ(pBuf);
  }
  return rtrn;
}


/**************************************************************************************************
 * @fn          cc2480RpcPoll
 *
 * @brief       This function polls the NP slave according to the RPC protocol for POLL.
 *
 * input parameters
 *
 * @param       pBuf - Pointer to the buffer to Tx a POLL across the SPI and then receive the AREQ.
 *
 * output parameters
 *
 * @param       pBuf - Pointer to the buffer to Tx a POLL across the SPI and then receive the AREQ.
 *
 * @return      TRUE if RPC transaction with slave succeeded; FALSE otherwise.
 **************************************************************************************************
 */
unsigned char cc2480RpcPoll(unsigned char *pBuf)
{

  *(pBuf+RPC_POS_LEN)  = 0;                /* POLL command has zero data bytes. */
  *(pBuf+RPC_POS_CMD0) = RPC_CMD_POLL;     /* POLL command MSB. */
  *(pBuf+RPC_POS_CMD1) = 0;                /* POLL command LSB. */

  return rpcSpiSREQ(pBuf);
}


/**************************************************************************************************
 * @fn          spiAREQ
 *
 * @brief       This function effects an asynchronous transaction with the NP slave
 *              according to the RPC protocol for the AREQ.
 *
 * input parameters
 *
 * @param       pBuf - Pointer to the buffer to Tx across the SPI.
 *
 * output parameters
 *
 * None.
 *
 * @return      TRUE if RPC transaction with slave succeeded; FALSE otherwise.
 **************************************************************************************************
 */
static unsigned char rpcSpiAREQ(unsigned char *pBuf)
{

  ZACCEL_SPI_BEGIN();

  while (ZACCEL_SRDY_IN() != 0);

  cc2480Write(pBuf,(*pBuf+CC2480_PACKET_OVERHEAD_SIZE));

  /* Wait for the slave to signal that it is ready. */
  while (ZACCEL_SRDY_IN() == 0);

  ZACCEL_SPI_END();

  return RPC_SUCCESS;
}


/**************************************************************************************************
 * @fn          rpcSpiSREQ
 *
 * @brief       This function effects a synchronous transaction with the NP slave
 *              according to the RPC protocol for the SREQ.
 *
 * input parameters
 *
 * @param       pBuf - Pointer to the buffer to Tx across the SPI.
 *
 * output parameters
 *
 * @param       pBuf - Pointer to the data received across the SPI.
 *
 * @return      TRUE if RPC transaction with slave succeeded; FALSE otherwise.
 **************************************************************************************************
 */
static unsigned char rpcSpiSREQ(unsigned char *pBuf)
{
    volatile unsigned int abort = 0;

    ZACCEL_SPI_BEGIN();

    /* Slave aborts a stuck RPC transaction by resetting, so it will come up with SRDY active low
     * in order to report the reset message. Therefore, the host can never get stuck here.
     */
    while (ZACCEL_SRDY_IN() != 0);
    
    cc2480Write(pBuf,(*pBuf+CC2480_PACKET_OVERHEAD_SIZE));

  /* Now setup the POLL command in the buffer which has just been transmitted and which will now
   * be used to receive the SRSP.
   */

    *(pBuf+RPC_POS_LEN) = 0;                  /* POLL command has zero data bytes. */
    *(pBuf+RPC_POS_CMD0) = RPC_CMD_POLL;     /* POLL command MSB. */
    *(pBuf+RPC_POS_CMD1) = 0;                /* POLL command LSB. */

    /* Wait for the slave to signal that it is ready. */
   while (ZACCEL_SRDY_IN() == 0);

    // Send POLL cmd
    cc2480Write(pBuf,CC2480_PACKET_OVERHEAD_SIZE);

  // Receive the rest of the slave's message if it is longer than the POLL.
  if (*pBuf != 0)
  {
    cc2480Write(pBuf+CC2480_PACKET_OVERHEAD_SIZE, *pBuf);
  }

   ZACCEL_SPI_END();

   return 1;
}




Thanks a lot for your help and your time



Marcin Barowski