Other Parts Discussed in Thread: CAPTIVATE-FR2676
The Goal
Having an issue with getting this processor to act appropriately as an SPI slave. Basically, the goal is to make this MCU into a transceiver that gets sent a request from the master, then responds accordingly depending on the request.
The Problem
But when I try to transmit to the master, I get intermittent and erroneous results. Either the wrong bytes will be sent entirely, or the timing will be off, or the order that the bytes are sent to the master gets out of sync, etc.
What I've Tried:
- I've quadruple-checked my wiring.
- Made sure my SPI mode settings (clock polarity, phase, LSB/MSB, etc) are correct on both MCU's.
- Tried every clock speed I could think of on the master.
- Scoured the MSP430FR4xx and MSP430FR2xx family user guide and MSP430FR2676 datasheet.
- Tried both using the DriverLibrary & also tried writing directly to registers.
My code is based on the example code TI provides which is shown below. At the moment all I am trying to get working is: slave receives 3 bytes from the master, then slave responds with 3 bytes accordingly. Any help getting this to work is much appreciated.
Note: I am using the CAPTIVATE-FR2676 dev board as the slave. and a simple Arduino as master.
//******************************************************************************
// MSP430FR2676x Demo - eUSCI_A0, SPI 4-Wire Slave multiple byte RX/TX
//
// Description: SPI master communicates to SPI slave sending and receiving
// 3 different messages of different length. SPI slave will enter LPM0
// while waiting for the messages to be sent/receiving using SPI interrupt.
// ACLK = NA, MCLK = SMCLK = DCO 16MHz.
//
//
// MSP430FR2676
// -----------------
// | |
// | |
// | P5.2|<- Data In (UCA0SIMO)
// | |
// | P5.1|-> Data Out (UCA0SOMI)
// | |
// | P5.0|<- Serial Clock In (UCA0CLK)
// | |
// | P4.7|<- Master's GPIO (UCA0STE)
//
//******************************************************************************
#include <msp430.h>
#include <stdint.h>
#include <stdbool.h>
#include "Board.h"
#include "driverlib.h"
//******************************************************************************
// Pin Config ******************************************************************
//******************************************************************************
#define LED_OUT P5OUT
#define LED_DIR P5DIR
#define LED0_PIN BIT7
//******************************************************************************
// General SPI State Machine ***************************************************
//******************************************************************************
typedef enum SPI_ModeEnum{
IDLE_MODE,
RX_PREAMBLE_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
TIMEOUT_MODE
} SPI_Mode;
/* Used to track the state of the software state machine*/
SPI_Mode SlaveMode = RX_PREAMBLE_MODE;
#define MAX_BUFFER_SIZE 20
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
uint8_t ReceiveNumBytes = 0;
uint8_t ReceiveRW = 0;
uint8_t ReceiveRegAddr = 0;
uint8_t ReceiveHeader = 0;
uint8_t frame = 0;
static const uint8_t RX = 1;
static const uint8_t TX = 2;
uint8_t AckByteCtr = 0;
uint8_t RegisterMap[0xFF];
void SendUCA0Data(uint8_t val);
void SPI_Slave_ProcessCMD(uint8_t regaddr, uint8_t header);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count, uint8_t startAddr);
void initSPI();
void initSystem();
void initClockTo16MHz();
void SendUCA0Data(uint8_t val)
{
while (!(UCA0IFG & UCTXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = val;
}
void SPI_Slave_ProcessCMD(uint8_t regaddr, uint8_t header)
{
ReceiveIndex = 0;
TransmitIndex = 0;
RXByteCtr = 0;
TXByteCtr = 0;
ReceiveRegAddr = regaddr;
ReceiveRW = (header & 0b10000000) >> 7;
ReceiveNumBytes = (header & 0b01111111);
if(frame == RX)
{
SlaveMode = RX_DATA_MODE;
RXByteCtr = ReceiveNumBytes;
}
else if(frame == TX)
{
SlaveMode = TX_DATA_MODE;
TXByteCtr = ReceiveNumBytes;
CopyArray(RegisterMap, TransmitBuffer, ReceiveNumBytes, ReceiveRegAddr);
SendUCA0Data(header);
SendUCA0Data(ReceiveRegAddr);
}
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count, uint8_t startAddr)
{
unsigned int copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex+startAddr];
}
}
//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************
void initSPI()
{
SYSCFG3|=USCIA0RMP; //Set the SPI remapping source
P5SEL0 |= BIT0 | BIT1 | BIT2; // set SPI MOSI, MISO, & CLK pins as second function
//Initialize slave to LSB first, clock polarity of 0, clock phase of 1 and 4 wire SPI
EUSCI_A_SPI_initSlaveParam param = {0};
param.msbFirst = EUSCI_A_SPI_MSB_FIRST;
param.clockPhase = EUSCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
param.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
param.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW; //UCMODE_2
EUSCI_A_SPI_initSlave(EUSCI_A0_BASE, ¶m);
//Enable SPI Module
EUSCI_A_SPI_enable(EUSCI_A0_BASE);
//Clear receive interrupt flag
EUSCI_A_SPI_clearInterrupt(EUSCI_A0_BASE, EUSCI_A_SPI_RECEIVE_INTERRUPT);
//Enable Receive interrupt
EUSCI_A_SPI_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_SPI_RECEIVE_INTERRUPT);
}
void initSystem()
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
initClockTo16MHz();
//Stop watchdog timer
WDT_A_hold(WDT_A_BASE);
// Configure Pins for XIN
//Set P2.0 and P2.1 as Module Function Input.
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN1 + GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION);
// Configure SPI Pins for UCA0CLK, UCA0TXD/UCA0SIMO and UCA0RXD/UCA0SOMI
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN0 + GPIO_PIN1 + GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);
// Disable the GPIO power-on default high-impedance mode to activate previously configured port settings
PMM_unlockLPM5();
initSPI();
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
}
void initClockTo16MHz()
{
// Configure one FRAM waitstate as required by the device datasheet for MCLK
// operation beyond 8MHz _before_ configuring the clock system.
FRCTL0 = FRCTLPW | NWAITS_1;
__bis_SR_register(SCG0); // disable FLL
CSCTL3 |= SELREF__REFOCLK; // Set REFO as FLL reference source
CSCTL0 = 0; // clear DCO and MOD registers
CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first
CSCTL1 |= DCORSEL_5; // Set DCO = 16MHz
CSCTL2 = FLLD_0 + 487; // set to fDCOCLKDIV = (FLLN + 1)*(fFLLREFCLK/n)
// = (487 + 1)*(32.768 kHz/1)
// = 16 MHz
__delay_cycles(3);
__bic_SR_register(SCG0); // enable FLL
while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // FLL locked
}
//******************************************************************************
// Main ************************************************************************
// Enters LPM0 and waits for SPI interrupts. The data sent from the master is *
// then interpreted and the device will respond accordingly *
//******************************************************************************
void main(void)
{
initSystem();
__no_operation();
RegisterMap[128] = 1;
}
//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
uint8_t uca0_rx_val = 0;
switch(__even_in_range(UCA0IV, USCI_SPI_UCTXIFG))
{
case USCI_NONE: break;
case USCI_SPI_UCRXIFG:
uca0_rx_val = UCA0RXBUF;
UCA0IFG &= ~UCRXIFG;
switch (SlaveMode)
{
case (RX_PREAMBLE_MODE):
frame = RX;
if(AckByteCtr == 0)
{
ReceiveHeader = uca0_rx_val;
AckByteCtr = 1;
}
else if(AckByteCtr == 1)
{
ReceiveRegAddr = uca0_rx_val;
SPI_Slave_ProcessCMD(ReceiveRegAddr, ReceiveHeader);
AckByteCtr = 0;
}
break;
case (RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++] = uca0_rx_val;
RXByteCtr--;
if (RXByteCtr == 0)
{
frame = TX;
SPI_Slave_ProcessCMD(ReceiveRegAddr, ReceiveHeader);
}
break;
case (TX_DATA_MODE):
if (TXByteCtr > 0)
{
SendUCA0Data(1);//TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
}
if (TXByteCtr == 0)
{
//Done Transmitting MSG
SlaveMode = RX_PREAMBLE_MODE;
}
break;
default:
__no_operation();
break;
}
break;
case USCI_SPI_UCTXIFG:
break;
default: break;
}
}

