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.