Other Parts Discussed in Thread: CCSTUDIO, MSP-EXP430FR5994
Tool/software:
Hello,
I am using the MSP430FR5994 in one of our projects, and everything is working well on the prototype board, except for the SPI bus.
I've tried both to write my own test program as well as using some of the official TI examples, but I can't get it properly working.
What happens is that with both my own as well as the TI code, none of the CLK lines work. CLK stays low, no matter if I enable "CLK inactive high mode". It also doesn't matter if I transmit data or not.
Also, at all times only one of the 4 SIMO lines will transmit the data I am asking them to transmit. The others will stay low.
I haven't tried to interface with the SOMI lines yet, as the MSP is the master and I need a working output first.
Otherwise the MSP430 works as expected, including the UART mode. I am using Spy-By-Wire to debug it through the CCStudio, and looking at the transfers from a debugging side they should work as expected.
Both my code, as well as the TI example code produce the same result on the MSP430FR5994 LaunchPad.
You can find both example codes for interfacing with the SPI attached.
//****************************************************************************** // MSP430FR599x Demo - eUSCI_B1, SPI 4-Wire Master multiple byte RX/TX // // Description: SPI master communicates to SPI slave sending and receiving // 3 different messages of different length. SPI master will enter LPM0 mode // while waiting for the messages to be sent/receiving using SPI interrupt. // SPI Master will initially wait for a port interrupt in LPM0 mode before // starting the SPI communication. // ACLK = NA, MCLK = SMCLK = DCO 16MHz. // // // MSP430FR5994 // ----------------- // /|\ | P1.0|-> Comms LED // | | | // ---|RST P1.4|-> Slave Reset (GPIO) // | | // | P5.0|-> Data Out (UCB1SIMO) // | | // Button ->|P5.5 P5.1|<- Data In (UCB1SOMI) // Button LED <-|P1.1 | // | P5.2|-> Serial Clock Out (UCB1CLK) // | | // | P5.3|-> Slave Chip Select (GPIO) // // Nima Eskandari and Ryan Meredith // Texas Instruments Inc. // January 2018 // Built with CCS V7.0 //****************************************************************************** #include <msp430.h> #include <stdint.h> //****************************************************************************** // Pin Config ****************************************************************** //****************************************************************************** #define SLAVE_CS_OUT P5OUT #define SLAVE_CS_DIR P5DIR #define SLAVE_CS_PIN BIT3 #define SLAVE_RST_OUT P1OUT #define SLAVE_RST_DIR P1DIR #define SLAVE_RST_PIN BIT4 #define BUTTON_DIR P5DIR #define BUTTON_OUT P5OUT #define BUTTON_REN P5REN #define BUTTON_PIN BIT5 #define BUTTON_IES P5IES #define BUTTON_IE P5IE #define BUTTON_IFG P5IFG #define BUTTON_VECTOR PORT5_VECTOR #define BUTTON_LED_OUT P1OUT #define BUTTON_LED_DIR P1DIR #define BUTTON_LED_PIN BIT1 #define COMMS_LED_OUT P1OUT #define COMMS_LED_DIR P1DIR #define COMMS_LED_PIN BIT0 //****************************************************************************** // Example Commands ************************************************************ //****************************************************************************** #define DUMMY 0xFF /* CMD_TYPE_X_SLAVE are example commands the master sends to the slave. * The slave will send example SlaveTypeX buffers in response. * * CMD_TYPE_X_MASTER are example commands the master sends to the slave. * The slave will initialize itself to receive MasterTypeX example buffers. * */ #define CMD_TYPE_0_SLAVE 0 #define CMD_TYPE_1_SLAVE 1 #define CMD_TYPE_2_SLAVE 2 #define CMD_TYPE_0_MASTER 3 #define CMD_TYPE_1_MASTER 4 #define CMD_TYPE_2_MASTER 5 #define TYPE_0_LENGTH 1 #define TYPE_1_LENGTH 2 #define TYPE_2_LENGTH 6 #define MAX_BUFFER_SIZE 20 /* MasterTypeX are example buffers initialized in the master, they will be * sent by the master to the slave. * SlaveTypeX are example buffers initialized in the slave, they will be * sent by the slave to the master. * */ uint8_t MasterType0 [TYPE_0_LENGTH] = {0x11}; uint8_t MasterType1 [TYPE_1_LENGTH] = {8, 9}; uint8_t MasterType2 [TYPE_2_LENGTH] = {'F', '4' , '1' , '9', '2', 'B'}; uint8_t SlaveType2 [TYPE_2_LENGTH] = {0}; uint8_t SlaveType1 [TYPE_1_LENGTH] = {0}; uint8_t SlaveType0 [TYPE_0_LENGTH] = {0}; //****************************************************************************** // General SPI State Machine *************************************************** //****************************************************************************** typedef enum SPI_ModeEnum{ IDLE_MODE, TX_REG_ADDRESS_MODE, RX_REG_ADDRESS_MODE, TX_DATA_MODE, RX_DATA_MODE, TIMEOUT_MODE } SPI_Mode; /* Used to track the state of the software state machine*/ SPI_Mode MasterMode = IDLE_MODE; /* The Register Address/Command to use*/ uint8_t TransmitRegAddr = 0; /* ReceiveBuffer: Buffer used to receive data in the ISR * RXByteCtr: Number of bytes left to receive * ReceiveIndex: The index of the next byte to be received in ReceiveBuffer * TransmitBuffer: Buffer used to transmit data in the ISR * TXByteCtr: Number of bytes left to transfer * TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer * */ 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; /* SPI Write and Read Functions */ /* For slave device, writes the data specified in *reg_data * * reg_addr: The register or command to send to the slave. * Example: CMD_TYPE_0_MASTER * *reg_data: The buffer to write * Example: MasterType0 * count: The length of *reg_data * Example: TYPE_0_LENGTH * */ SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count); /* For slave device, read the data specified in slaves reg_addr. * The received data is available in ReceiveBuffer * * reg_addr: The register or command to send to the slave. * Example: CMD_TYPE_0_SLAVE * count: The length of data to read * Example: TYPE_0_LENGTH * */ SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count); void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count); void SendUCB1Data(uint8_t val); void SendUCB1Data(uint8_t val) { while (!(UCB1IFG & UCTXIFG)); // USCI_B1 TX buffer ready? UCB1TXBUF = val; } 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]; } } SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count) { MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; //Copy register data to TransmitBuffer CopyArray(reg_data, TransmitBuffer, count); TXByteCtr = count; RXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; SLAVE_CS_OUT &= ~(SLAVE_CS_PIN); SendUCB1Data(TransmitRegAddr); __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts SLAVE_CS_OUT |= SLAVE_CS_PIN; return MasterMode; } SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count) { MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; RXByteCtr = count; TXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; SLAVE_CS_OUT &= ~(SLAVE_CS_PIN); SendUCB1Data(TransmitRegAddr); __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts SLAVE_CS_OUT |= SLAVE_CS_PIN; return MasterMode; } //****************************************************************************** // Device Initialization ******************************************************* //****************************************************************************** void initSPI() { //Clock Polarity: The inactive state is high //MSB First, 8-bit, Master, 3-pin mode, Synchronous UCB1CTLW0 = UCSWRST; // **Put state machine in reset** UCB1CTLW0 |= UCCKPL | UCMSB | UCSYNC | UCMST | UCSSEL__SMCLK; // 3-pin, 8-bit SPI Slave UCB1BRW = 0x20; //UCB1MCTLW = 0; UCB1CTLW0 &= ~UCSWRST; // **Initialize USCI state machine** UCB1IE |= UCRXIE; // Enable USCI0 RX interrupt } void initGPIO() { //LEDs COMMS_LED_DIR |= COMMS_LED_PIN; COMMS_LED_OUT &= ~COMMS_LED_PIN; BUTTON_LED_DIR |= BUTTON_LED_PIN; BUTTON_LED_OUT &= ~BUTTON_LED_PIN; // Configure SPI P5SEL0 |= BIT0 | BIT1 | BIT2; SLAVE_RST_DIR |= SLAVE_RST_PIN; SLAVE_RST_OUT |= SLAVE_RST_PIN; SLAVE_CS_DIR |= SLAVE_CS_PIN; SLAVE_CS_OUT |= SLAVE_CS_PIN; //Button to initiate transfer BUTTON_DIR &= ~(BUTTON_PIN); // button input BUTTON_OUT |= BUTTON_PIN; // button pull up BUTTON_REN |= BUTTON_PIN; // button pull up/down resistor enable BUTTON_IES |= BUTTON_PIN; // button Hi/lo edge BUTTON_IE |= BUTTON_PIN; // button interrupt enabled // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; BUTTON_IFG &= ~BUTTON_PIN; // button IFG cleared } 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; // Clock System Setup CSCTL0_H = CSKEY_H; // Unlock CS registers CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz // Set SMCLK = MCLK = DCO, ACLK = VLOCLK CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Per Device Errata set divider to 4 before changing frequency to // prevent out of spec operation from overshoot transient CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz)) __delay_cycles(60); CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers to 1 for 16MHz operation CSCTL0_H = 0; // Lock CS registers } //****************************************************************************** // Main ************************************************************************ // Send and receive three messages containing the example commands ************* //****************************************************************************** int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer initClockTo16MHz(); initGPIO(); initSPI(); while (1) { SendUCB1Data('z'); } return 0; } //****************************************************************************** // SPI Interrupt *************************************************************** //****************************************************************************** #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void) #else #error Compiler not supported! #endif { uint8_t ucb1_rx_val = 0; switch(__even_in_range(UCB1IV, USCI_SPI_UCTXIFG)) { case USCI_NONE: break; case USCI_SPI_UCRXIFG: ucb1_rx_val = UCB1RXBUF; UCB1IFG &= ~UCRXIFG; switch (MasterMode) { case TX_REG_ADDRESS_MODE: if (RXByteCtr) { MasterMode = RX_DATA_MODE; // Need to start receiving now //Send Dummy To Start __delay_cycles(2000000); SendUCB1Data(DUMMY); } else { MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer //Send First SendUCB1Data(TransmitBuffer[TransmitIndex++]); TXByteCtr--; } break; case TX_DATA_MODE: if (TXByteCtr) { SendUCB1Data(TransmitBuffer[TransmitIndex++]); TXByteCtr--; } else { //Done with transmission MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; case RX_DATA_MODE: if (RXByteCtr) { ReceiveBuffer[ReceiveIndex++] = ucb1_rx_val; //Transmit a dummy RXByteCtr--; } if (RXByteCtr == 0) { MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } else { SendUCB1Data(DUMMY); } break; default: __no_operation(); break; } __delay_cycles(1000); break; case USCI_SPI_UCTXIFG: break; default: break; } } //****************************************************************************** // Button Port Interrupt ************************************************************* // Interrupt occurs on button press and initiates the SPI data transfer ******** //****************************************************************************** #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=BUTTON_VECTOR __interrupt void Button_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(BUTTON_VECTOR))) Button_ISR (void) #else #error Compiler not supported! #endif { BUTTON_LED_OUT |= BUTTON_LED_PIN; BUTTON_IFG &= ~BUTTON_PIN; // button IFG cleared BUTTON_IE &= ~BUTTON_PIN; //Initiate __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 }