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.
Part Number: MSP432P401R
Tool/software: Code Composer Studio
Hello,
In my current setup I am using an STM32F4 discovery board as SPI master and an MSP432P401R (Launchpad) as SPI Slave.
I tried working with some example code from each. Upon startup, the SPI master sends the sequence 0x5678 to the slave. It seems I get the initial 0x56, but not the 0x78 (in fact the code does not seem to enter the ISR, though the master seems to think it is sending it.
Here is the MSP432 slave code (using Code Composer Studio):
-------------
/* --COPYRIGHT--,BSD * Copyright (c) 2017, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ /******************************************************************************* * MSP432 SPI - 3-wire Slave Incremented Data * * SPI slave talks to SPI master using 3-wire mode. Data is received * from master and data from slave is then transmitted back to master. * USCI RX ISR is used to handle communication, CPU normally in LPM0. * Prior to initial data exchange, master pulses slaves RST for complete * reset. * * Note that in this example, EUSCIB0 is used for the SPI port. If the user * wants to use EUSCIA for SPI operation, they are able to with the same APIs * with the EUSCI_AX parameters. * * Use with the master version of the code example * * MSP432P401 * ----------------- * | | * | | * | | * | P1.6|<- Data In (UCB0SIMO) * | | * | P1.7|-> Data Out (UCB0SOMI) * | | * | P1.5|<- Serial Clock In (UCB0CLK) * *******************************************************************************/ /* DriverLib Includes */ #include <ti/devices/msp432p4xx/driverlib/driverlib.h> /* Statics */ //static volatile uint8_t transmitData = 0x01, receiveData = 0x00; static volatile uint8_t transmitData = 0x01; static volatile uint8_t receiveData[2] = {0,0}; static volatile uint8_t receiveDataCount = 0x00; static volatile uint8_t receiveDataCmdLength = 0x02; static volatile uint16_t receiveDataCmd = 0x5678; /* SPI Slave Configuration Parameter */ const eUSCI_SPI_SlaveConfig spiSlaveConfig = { EUSCI_B_SPI_MSB_FIRST, // MSB First EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT, // Phase EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Normal Polarity EUSCI_B_SPI_3PIN // 3wire mode }; int main(void) { /* Stop watchdog timer */ WDT_A_holdTimer(); /* Selecting P1.5 P1.6 and P1.7 in SPI mode */ GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION); /* Initialize slave to MSB first, inactive high clock polarity and * 3 wire SPI */ SPI_initSlave(EUSCI_B0_BASE, &spiSlaveConfig); /* Enable the SPI module */ SPI_enableModule(EUSCI_B0_BASE); /* Enable Receive interrupt */ SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT); Interrupt_enableSleepOnIsrExit(); Interrupt_enableInterrupt(INT_EUSCIB0); Interrupt_enableMaster(); PCM_gotoLPM0(); } //****************************************************************************** // //This is the EUSCI_B0 interrupt vector service routine. // //****************************************************************************** void EUSCIB0_IRQHandler(void) { uint32_t status; status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE); SPI_clearInterruptFlag(EUSCI_B0_BASE, status); if(status & EUSCI_B_SPI_RECEIVE_INTERRUPT) { //Receive data from master receiveData[receiveDataCount++] = SPI_receiveData(EUSCI_B0_BASE); } if (receiveDataCount == receiveDataCmdLength) { receiveDataCount = 0; } }
-------------
Hi Stefan,
Yes, I have set up a breakpoint in the SPI interrupt handler. I see that the first byte goes into the SPI hardware RxBuffer and also gets loaded into my receive buffer. However, the SPI interrupt does not seem to be entered again.
I am waiting on receiving a logic analyzer to probe the traces to see if there is any insight there.
Best,
Mehdi
> the SPI master sends the sequence 0x5678 to the slave.
How is SPICR1:DFF set in the Master? The USCI doesn't know about 16-bit frames, and would instead see two bytes in rapid succession.
My suspicion is that your slave is being overrun, though in that case you'd see the second byte (0x78?) in RXBUF.
[Edit: In the absence of a scope, try slowing your SPI clock Way Way down.]
So I have attached a screenshot of the SPI communication. It seems that both 0x78 and 0x56 do get sent by the master. The protocol is to send the MSB first.
I run the setup as follows:
Thanks for the suggestion Bruce. How high would I need to increase the clock? I tried the following (I put this piece of code, and am still running into the same error:
--------
/* Setting DCO to 12MHz */ CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);
--------
I also tried increasing to 24 MHz, and then even 48 MHz. Am I increasing the DCO improperly?
I put this code on a Launchpad, and drove it with an FR2311 master which sent 1 byte with 8MHz SPI clock every 7usec. I added something to wiggle P1.0 in the ISR.
At 3MHz, my scope measured 132us; at 12MHz 21us; at 24MHz 10us, still too long. (Keep in mind I wasn't measuring the ISR entry/exit.) Optimization had no visible effect, meaning most of the time was spent in the library functions.
I replaced the ISR with this, and at 12MHz the scope measured 3.4us; at 24MHz 2us. I didn't see overruns at 24MHz. The results at 12MHz were ambiguous. (You should try it with your test case.)
void EUSCIB0_IRQHandler(void) { uint32_t status; P1OUT |= BIT0; #if 1 if (EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0) { receiveData[receiveDataCount++] = EUSCI_B0->RXBUF; } #else status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE); SPI_clearInterruptFlag(EUSCI_B0_BASE, status); if(status & EUSCI_B_SPI_RECEIVE_INTERRUPT) { //Receive data from master receiveData[receiveDataCount++] = SPI_receiveData(EUSCI_B0_BASE); } #endif if (receiveDataCount == receiveDataCmdLength) { receiveDataCount = 0; } P1OUT &= ~BIT0; }
So interestingly, this did work. I put a breakpoint on the "receiveDataCount = 0" line. So my question is why doesn't the sample provided by TI work? Is it that the main clock of the master SPI device is too fast for the original ISR as provided by TI?
Do you think this has anything to do with low power modes?
Actually, running this multiple times. I notice that sometimes the MSP432 does not receive the bytes properly. For example, look at the screenshot:
I'm supposing(?) that you started with spi_3wire_incrementing_data.
In that, the master side transmits from an ISR which has a structure similar to that in the slave, and probably has a similar run time. I suspect this introduces inter-byte pauses that allow both ends time to run.
LPM0 is a fairly light sleep, and enterLPM0() is not much more than a WFI. I don't suspect LPMs being a problem here.
[Edit: DMA can speed up the flow, though it may or may not fit well with your protocol.]
"I'm supposing(?) that you started with spi_3wire_incrementing_data. "
So I'm not sure exactly what you mean by this.
Regarding the SPI master device, it is actually an STM32F4 Discovery board, where I am running an SPI master example. The master does not initiate SPI communication until I press a button on the board. I make sure both codes are running before doing this.
Yeah, I tried temporarily removing the LPM0 line and did not see a difference in behavior.
Any insight as to why I do not always get the same behavior (refer to the screenshot in my previous post). Sometimes I get 0x56 and 0x78, but other times these become 0x2B and 0x3C.
Could this have to do with improper reads as a result of clock speeds?
So I just noticed this message on my console:
CORTEX_M4_0: Flash Programmer: Reading device TLV failed.
CORTEX_M4_0: Error initializing flash programming: Your XMS432P401R material is no longer supported. We recommend you moving to production-quality MSP432P401R/M silicon by ordering samples at www.ti.com/product/MSP432P401R.
Hi Bruce,
Thanks for your reply. I'll be a little more specific about the problem I ran into. So after receiving the 0x56 and 0x78 initialization bytes, I set the slave MSP432 to transfer the first acknowledgement byte back to the master, disable the RX interrupt, enable the transmit interrupt. I can see that the interrupt enable register correspond to this: the IE for RX is 0, the IE for TX is 1. However, the next time my code enters the interrupt, the code enters the if condition for the RX interrupt, because the RXIFG is set high (in fact upon inspection it was high when I disabled the interrupt enable bit).
Here is the code:
-----------
/* --COPYRIGHT--,BSD * Copyright (c) 2017, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --/COPYRIGHT--*/ /******************************************************************************* * MSP432 SPI - 3-wire Slave Incremented Data * * SPI slave talks to SPI master using 3-wire mode. Data is received * from master and data from slave is then transmitted back to master. * USCI RX ISR is used to handle communication, CPU normally in LPM0. * Prior to initial data exchange, master pulses slaves RST for complete * reset. * * Note that in this example, EUSCIB0 is used for the SPI port. If the user * wants to use EUSCIA for SPI operation, they are able to with the same APIs * with the EUSCI_AX parameters. * * Use with the master version of the code example * * MSP432P401 * ----------------- * | | * | | * | | * | P1.6|<- Data In (UCB0SIMO) * | | * | P1.7|-> Data Out (UCB0SOMI) * | | * | P1.5|<- Serial Clock In (UCB0CLK) * *******************************************************************************/ /* DriverLib Includes */ #include <ti/devices/msp432p4xx/driverlib/driverlib.h> #define RECEIVE 0 #define TRANSMIT 1 /* Statics */ //static volatile uint8_t transmitData = 0x01, receiveData = 0x00; static volatile uint8_t state = RECEIVE; static volatile uint8_t transmitDataCount = 0x00; static volatile uint8_t transmitDataInit[2] = {0xD5,0xE5}; static volatile uint8_t receiveData[2] = {0,0}; static volatile uint8_t receiveDataCount = 0x00; static volatile uint8_t receiveDataCmdLength = 0x02; static volatile uint16_t receiveDataCmd = 0x5678; /* SPI Slave Configuration Parameter */ const eUSCI_SPI_SlaveConfig spiSlaveConfig = { EUSCI_B_SPI_MSB_FIRST, // MSB First EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT, // Phase EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Normal Polarity EUSCI_B_SPI_3PIN // 3wire mode }; int main(void) { /* Stop watchdog timer */ WDT_A_holdTimer(); /* Setting DCO to 24MHz */ CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24); /* Selecting P1.5 P1.6 and P1.7 in SPI mode */ GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION); /* Initialize slave to MSB first, inactive high clock polarity and * 3 wire SPI */ SPI_initSlave(EUSCI_B0_BASE, &spiSlaveConfig); /* Enable the SPI module */ SPI_enableModule(EUSCI_B0_BASE); /* Enable Receive interrupt */ SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT); /* Disable Transmit interrupt */ SPI_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT); Interrupt_enableSleepOnIsrExit(); Interrupt_enableInterrupt(INT_EUSCIB0); Interrupt_enableMaster(); PCM_gotoLPM0(); } void EUSCIB0_IRQHandler(void) { uint32_t status; P1OUT |= BIT0; #if 1 if (EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0) { receiveData[receiveDataCount++] = EUSCI_B0->RXBUF; } else if(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0) { /* USCI_B0 TX buffer ready? */ while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT))); // Transmit data to master SPI_transmitData(EUSCI_B0_BASE, transmitDataInit[transmitDataCount]); transmitDataCount++; if (transmitDataCount >= 2) { transmitDataCount = 0; SPI_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT); // Disable Transmit interrupt SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT); // Enable Receive Interrupt } } #else status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE); SPI_clearInterruptFlag(EUSCI_B0_BASE, status); if(status & EUSCI_B_SPI_RECEIVE_INTERRUPT) { //Receive data from master receiveData[receiveDataCount++] = SPI_receiveData(EUSCI_B0_BASE); } #endif if (receiveDataCount == receiveDataCmdLength) { receiveDataCount = 0; // USCI_B0 TX buffer ready? while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT))); // Transmit data to master SPI_transmitData(EUSCI_B0_BASE, transmitDataInit[transmitDataCount]); transmitDataCount++; // Enable Transmit interrupt SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT); // Disable Receive interrupt SPI_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_SPI_RECEIVE_INTERRUPT); } P1OUT &= ~BIT0; }
-----------
So a few questions:
As a point of reference, I set a breakpoint on the master code after sending the acknowledgement bytes, preventing it from transmitting anything on the MOSI line.
Best,
Mehdi
**Attention** This is a public forum