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