Part Number: MSP430F5529
Hello,
I am trying to connect Raspberry pi 3 B + with the MSP430f5529 (launchpad) using SPI communication but I seem to encounter an error I can't get around.
The SPI communication is a 3 wire connection with the Raspberry being the master and the MSP the slave. I have made sure that all the SPI parameters are OK (clock polarity and phase, etc...). The program consists simply in the raspberry sending a command (TX_CMD) in order to make the MSP read a sensor (not implemented yet, simulated as an array being modified) and then send back 4096 bytes (maximum supported by Raspberry buffer).
The problem is that the MSP sends twice the first byte to transmit (after receiving the TX_CMD), so the last byte is not sent. I have also seen that when I increase the SPI CLK frequency, more than just the first byte is sent twice. I thought it might be the SYS clock not being able to keep up with the SPI interrupt frequency, but after increasing the MCLK speed to 20MHz I stilll have the same error. The program runs fine for low frequencies, but are too low for an SPI communication (around 120KHz).
I don't usually post in forums, if any info is required just ask. I leave the code here:
#include <msp430.h>
#include <stdint.h>
#include <stdbool.h>
#define SLAVE_CS_IN P2IN
#define SLAVE_CS_DIR P2DIR
#define SLAVE_CS_PIN BIT0
#define IT_CMD 11
#define TX_CMD 22
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];
}
}
//INIT FUNCTIONS
void initGPIO()
{
//LEDs
P1OUT = 0x00; // P1 setup for LED & reset output
P1DIR |= BIT0 + BIT5;
P4DIR |= BIT7;
P4OUT &= ~(BIT7);
//SPI Pins
P3SEL |= BIT3 + BIT4; // P3.3,4 option select
P2SEL |= BIT7; // P2.7 option select
/*
P2SEL |= BIT2; //PARA MIRAR LA FRECUENCIA DEL SMCLK EN EL PIN 2.2
P2DIR |= BIT2;
*/
}
void initSPI()
{
//Clock Polarity: The inactive state is high
//MSB First, 8-bit, Master, 3-pin mode, Synchronous
UCA0CTL1 = UCSWRST; // **Put state machine in reset**
UCA0CTL0 |= UCMSB + UCSYNC;// +UCCKPH; // 3-pin, 8-bit SPI Slave
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI0 RX interrupt
SLAVE_CS_DIR &= ~(SLAVE_CS_PIN);
}
void initClockTo16MHz()
{
UCSCTL3 |= SELREF_2; // Set DCO FLL reference = REFO
UCSCTL4 |= SELA_2; // Set ACLK = REFO
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_6; //DCORSEL_5; // Select DCO range 16MHz operation
UCSCTL2 = FLLD_0 + 762;//487; // Set DCO Multiplier for 16MHz
// (N + 1) * FLLRef = Fdco
// (487 + 1) * 32768 = 16MHz
// Set FLL Div = fDCOCLK
__bic_SR_register(SCG0); // Enable the FLL control loop
// Worst-case settling time for the DCO when the DCO range bits have been
// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
// UG for optimization.
// 32 x 32 x 16 MHz / 32,768 Hz = 500000 = MCLK cycles for DCO to settle
__delay_cycles(500000);//
// Loop until XT1,XT2 & DCO fault flag is cleared
do
{
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
SFRIFG1 &= ~OFIFG; // Clear fault flags
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
}
uint16_t setVCoreUp(uint8_t level){
uint32_t PMMRIE_backup, SVSMHCTL_backup, SVSMLCTL_backup;
//The code flow for increasing the Vcore has been altered to work around
//the erratum FLASH37.
//Please refer to the Errata sheet to know if a specific device is affected
//DO NOT ALTER THIS FUNCTION
//Open PMM registers for write access
PMMCTL0_H = 0xA5;
//Disable dedicated Interrupts
//Backup all registers
PMMRIE_backup = PMMRIE;
PMMRIE &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE |
SVSLPE | SVMHVLRIE | SVMHIE |
SVSMHDLYIE | SVMLVLRIE | SVMLIE |
SVSMLDLYIE
);
SVSMHCTL_backup = SVSMHCTL;
SVSMLCTL_backup = SVSMLCTL;
//Clear flags
PMMIFG = 0;
//Set SVM highside to new level and check if a VCore increase is possible
SVSMHCTL = SVMHE | SVSHE | (SVSMHRRL0 * level);
//Wait until SVM highside is settled
while((PMMIFG & SVSMHDLYIFG) == 0)
{
;
}
//Clear flag
PMMIFG &= ~SVSMHDLYIFG;
//Check if a VCore increase is possible
if((PMMIFG & SVMHIFG) == SVMHIFG)
{
//-> Vcc is too low for a Vcore increase
//recover the previous settings
PMMIFG &= ~SVSMHDLYIFG;
SVSMHCTL = SVSMHCTL_backup;
//Wait until SVM highside is settled
while((PMMIFG & SVSMHDLYIFG) == 0)
{
;
}
//Clear all Flags
PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
SVMLVLRIFG | SVMLIFG |
SVSMLDLYIFG
);
//Restore PMM interrupt enable register
PMMRIE = PMMRIE_backup;
//Lock PMM registers for write access
PMMCTL0_H = 0x00;
//return: voltage not set
return false;
}
//Set also SVS highside to new level
//Vcc is high enough for a Vcore increase
SVSMHCTL |= (SVSHRVL0 * level);
//Wait until SVM highside is settled
while((PMMIFG & SVSMHDLYIFG) == 0)
{
;
}
//Clear flag
PMMIFG &= ~SVSMHDLYIFG;
//Set VCore to new level
PMMCTL0_L = PMMCOREV0 * level;
//Set SVM, SVS low side to new level
SVSMLCTL = SVMLE | (SVSMLRRL0 * level) |
SVSLE | (SVSLRVL0 * level);
//Wait until SVM, SVS low side is settled
while((PMMIFG & SVSMLDLYIFG) == 0)
{
;
}
//Clear flag
PMMIFG &= ~SVSMLDLYIFG;
//SVS, SVM core and high side are now set to protect for the new core level
//Restore Low side settings
//Clear all other bits _except_ level settings
SVSMLCTL &= (SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 +
SVSMLRRL1 + SVSMLRRL2
);
//Clear level settings in the backup register,keep all other bits
SVSMLCTL_backup &=
~(SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 + SVSMLRRL1 + SVSMLRRL2);
//Restore low-side SVS monitor settings
SVSMLCTL |= SVSMLCTL_backup;
//Restore High side settings
//Clear all other bits except level settings
SVSMHCTL &= (SVSHRVL0 + SVSHRVL1 +
SVSMHRRL0 + SVSMHRRL1 +
SVSMHRRL2
);
//Clear level settings in the backup register,keep all other bits
SVSMHCTL_backup &=
~(SVSHRVL0 + SVSHRVL1 + SVSMHRRL0 + SVSMHRRL1 + SVSMHRRL2);
//Restore backup
SVSMHCTL |= SVSMHCTL_backup;
//Wait until high side, low side settled
while(((PMMIFG & SVSMLDLYIFG) == 0) &&
((PMMIFG & SVSMHDLYIFG) == 0))
{
;
}
//Clear all Flags
PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |
SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG
);
//Restore PMM interrupt enable register
PMMRIE = PMMRIE_backup;
//Lock PMM registers for write access
PMMCTL0_H = 0x00;
return true;
}
bool increaseVCoreToLevel2()
{
uint8_t level = 3;//2;
uint8_t actlevel;
bool status = true;
//Set Mask for Max. level
level &= PMMCOREV_3;
//Get actual VCore
actlevel = PMMCTL0 & PMMCOREV_3;
//step by step increase or decrease
while((level != actlevel) && (status == true))
{
if(level > actlevel)
{
status = setVCoreUp(++actlevel);
}
else{
status = setVCoreUp(--actlevel);
}
}
return (status);
}
void SendUCA0Data(uint8_t val)
{
//while (!(UCA0IFG & UCTXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = val;
}
/**
* main.c
*/
typedef enum SPI_ModeEnum{
IDLE_MODE,
SET_IT_MODE,
TX_MODE,
} SPI_Mode;
uint8_t SlaveMode = IDLE_MODE;
uint8_t TxBuff[4096] = {0};
uint8_t *txptr;
uint8_t RXCounter = 0; //To receive the integration time (2 bytes)
uint16_t TXCounter = 4096;
volatile uint16_t TXIndex = 0;
uint16_t integration_time = 2096;
uint8_t debug = 1;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
increaseVCoreToLevel2();
initClockTo16MHz();
initGPIO();
initSPI();
//txptr = TxBuff; //Init the txpointer to the correc position
__bis_SR_register(GIE);
while (1){
if(SlaveMode == TX_MODE && TXIndex == 0){
//SensorRead();
TxBuff[0] = 27;
TxBuff[1] = 28;
TxBuff[2] = 29;
TxBuff[3] = debug;
TxBuff[4095] = 32;
debug++;
//UCA0TXBUF = *txptr++;
//SendUCA0Data(TxBuff[TXIndex++]);
UCA0TXBUF = TxBuff[TXIndex++];
}
}
return 0;
}
//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
uint8_t uca0_rx_val = 0;
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 -RX interrupt
uca0_rx_val = UCA0RXBUF;
switch (SlaveMode)
{
case (IDLE_MODE):
if (uca0_rx_val == IT_CMD) {
RXCounter = 0;
SlaveMode = SET_IT_MODE;
UCA0TXBUF = 99;
}
else if (uca0_rx_val == TX_CMD) {SlaveMode = TX_MODE;}
break;
case (SET_IT_MODE):
integration_time |= uca0_rx_val<<(RXCounter*8);
RXCounter++;
if (RXCounter >= 2) {
SlaveMode = IDLE_MODE;
}
UCA0TXBUF = 99;
break;
case (TX_MODE):
TXCounter--;
if(TXCounter<1){
UCA0TXBUF = 86;
//txptr = TxBuff; //reset pointer
TXCounter = 4096;
TXIndex = 0;
SlaveMode = IDLE_MODE;
break;
}
if (TXIndex > 0){
//UCA0TXBUF = *txptr++;
//SendUCA0Data(TxBuff[TXIndex++]);
UCA0TXBUF = TxBuff[TXIndex++];
}
else {UCA0TXBUF = 11;}
break;
default:
UCA0TXBUF = 77;
__no_operation();
break;
}
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}
//END OF THE CODE
Correct at 180KHz:
First byte twice at 500KHz:
More bytes repeated at 3MHz:
Thanks in advance.