MSP432 spi comunication

Thread Starter

biza

Joined Sep 6, 2018
4
I'm trying to communicate between a microcontroller (master) and a front end device (slave), but when I send commands from master to slave, the MISO line is operating faster than the SCLK line, which is configured to work at a frequency of 500 KHz. Is there anyone who had a similar problem and can share the experience with me to try to resolve this.Screenshot 2024-11-06 at 11.16.35.pngScreenshot 2024-11-06 at 11.16.35.png
 

Thread Starter

biza

Joined Sep 6, 2018
4
Nsaspook, thanks for your quick response,
You're right (my fault), my microcontroller is the Texas Instruments MSP432P401R. And at the moment I'm trying to communicate between the master (MSP432P401R) and a slave (ADS1292R). As I mentioned in the previous post, I created a code that interfaces the SPI communication between these two devices. The MSP432P401R sends the correct data on the MOSI line, the SCLK is polling on the correct frequency, as can be seen in the previous post by the shared image of the digital analyzer. But when the slave (MISO), sends the response to the data obtained from the master, I see a much faster response. This should be established, synchronized by the SPI clock.
The clock system works at 24MHz, I configure three clock systems, MCLK, SMCLK and ACLK.
I use SMCLK to configure the SPI clock. Previously, I divide the main clock (MCLK) into two, which results in a 12MHz clock for the SMCLK. After that, using this clock (SMCLK) and in the SPI clock configuration, I divide it into 24, resulting in the SPI clock frequency being 500KHz.
Now let's share the code:
main.c:
void main(void){
    /*STOP WATCH DOG TIMER*/
    WDTCTL = WDTPW | WDTHOLD;
    /*INITIALIZE GPIO PINS*/
    GPIO_INTERFACE_init();
    /*INITIALIZE CLOCK SYSTEM*/
    set_clockSystem(FREQ_24_MHz);
    /*START THE UART*/
    UART_init();
    /*SETUP THE SPI */
    SPI_Initialize_init();
    /*SETUP THE ADS1292R*/
    ADS1292_GInit();
    /*WAIT ONE SECOND*/
    _delay(1,'s');
    /*ENABLE GLOBAL INTERRUPT*/
    __enable_irq();
    /*ENABLE EUSCI_B0 INTERRUPT ON NVIC*/
    NVIC->ISER[0] = 1 << ((EUSCIB0_IRQn) & 31);

    //NVIC->ISER[1] = 1 << ((PORT2_IRQn) & 31);

    while(1){

    }
}
spi.c:
void SPI_Initialize_init(void){
    SPI_Init_Registers();
    Initialize_Port_Registers();
}

void SPI_Init_Registers(void) {
    // Configure pins for EUSCI_B0 SPI (P1.5:SCLK, P1.6:MOSI, P1.7:MISO)

    P1->SEL0 |= BIT5 | BIT6 | BIT7;
    P1->SEL1 &= ~(BIT5 | BIT6 | BIT7);

   // P1->DIR |= BIT5 | BIT6;
    //P1->DIR &=~(BIT7);



    /*STEP 1: PUT THE EUSCI_B0 IN RESET MODE*/
    EUSCI_B0->CTLW0 = EUSCI_B_CTLW0_SWRST;

    /*CONFIGURE EUSCI_B0 FOR SPI MASTER MODE, CLOCK POLARITY/PHASE, BIT RATE, ETC
     *STEP 2: CONFIGURE EUSCI_B0 REGISTER FOR SPI*/

    EUSCI_B0->CTLW0 = EUSCI_B_CTLW0_SWRST           /*KEEP IN RESET*/
                      | EUSCI_B_CTLW0_MST           /*MASTER MODE*/
                      | EUSCI_B_CTLW0_SYNC          /*SYNCHRONOUS MODE*/
                      | EUSCI_B_CTLW0_MODE_0
                      | EUSCI_B_CTLW0_MSB           /*MSB FIRST*/
                      | EUSCI_B_CTLW0_UCSSEL_2      /*USE SMCLK(12MHz IN THIS SETUP)*/
                      | EUSCI_B_CTLW0_CKPW          /*CLOCK POLARITY LOW(CPOL=0)*/
                      | EUSCI_B_CTLW0_CKPH;         /*SET SPI CLOCK PHASE(CPHA=1)*/

    /*STEP 4:SET THE CLOCK DIVIDER TO ARCHIVE THE DESIRE SPI CLOCK FREQUENCY
     * ASSUMING SMCLK=12 AND DESIRED SPI CLOCK = 500KHz*/

    EUSCI_B0->BRW = 24;                             /*DIVIDE BY 24(12MHz/24=500KHz)*/

    /*STEP 5: CONFIGURE 3-PIN SPI MODE*/

    /*RELEASE EUSCI_B0 FROM RESET STATE*/
    EUSCI_B0->CTLW0 &= ~(EUSCI_B_CTLW0_SWRST);

    EUSCI_B0->IE |= EUSCI_B_IE_RXIE0;               /*ENABLE RECEIVE INTERRUPT FOR EUSCI_B0*/

}

void Initialize_Port_Registers(void){
    ADS_CS_PORT->SEL0 &= ~(ADS1292R_CS);
    ADS_CS_PORT->SEL1 &= ~(ADS1292R_CS);
    ADS_CS_PORT->DIR |= ADS1292R_CS;  // Set CS as output
    //ADS_CS_PORT->OUT |= ADS1292R_CS;
}



void SPI_Shutdown(void) {
     EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST; // Reset EUSCI_B0 to shutdown
}

void MSP_ADS_SPI_write_register(uint8_t reg_address, uint8_t data) {
    uint8_t i;

    /*PREPARE DATA FOR TRANSMISSION*/
    masterTxBuffer[0] = (WREG | reg_address);
    masterTxBuffer[1] = 0x00;                       /*NUMBER OF BYTES -1 */
    masterTxBuffer[2] = data;
    /*PULL CS LOW TO BEGIN TRANSACTION*/
    CS_Low();

    /*TRANSMIT BYTES*/
    for (i = 0; i < 3; i++) {
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        EUSCI_B0->TXBUF = masterTxBuffer[i];
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        masterRxBuffer[i] = EUSCI_B0->RXBUF;
    }
    /*PULL CS HIGH TO END TRANSACTION*/
    CS_High();
}

void MSP_ADS_SPI_read_register(uint8_t reg_address, uint8_t* rx_buffer) {
    uint8_t i;
    /*PREPARE DATA FOR TRANSMISSION*/
    masterTxBuffer[0] = (RREG | reg_address);
    masterTxBuffer[1] = 0x00;                       /*NUMBER OF BYTES-1*/
    masterTxBuffer[2] = 0x00;
    /*PULL CS LOW TO BEGIN TRANSACTION*/
    CS_Low();
    // Transmit and receive bytes
    for (i = 0; i < 3; i++) {
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        EUSCI_B0->TXBUF = masterTxBuffer[i];
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        masterRxBuffer[i] = EUSCI_B0->RXBUF;
    }

    // Pull CS high to end transaction
    CS_High();
    // Return the received data byte
    *rx_buffer = masterRxBuffer[2];
}

void MSP_ADS_SPI_write_command(uint8_t command) {

    // Prepare command to send
    masterTxBuffer[0] = command;
    // Pull CS low to begin transaction
    CS_Low();

    // Transmit command byte
    while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
    EUSCI_B0->TXBUF = masterTxBuffer[0];
    while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
    masterRxBuffer[0] = EUSCI_B0->RXBUF;
    // Pull CS high to end transaction
    CS_High();
}

void MSP_ADS_SPI_read_ecg_resp_data(uint32_t* status, uint32_t* channel_1, uint32_t* channel_2) {
    // Prepare dummy bytes to send (9 bytes to receive all data)
    int i;
    for ( i = 0; i < 9; i++) {
        masterTxBuffer[i] = 0x00;
    }

    // Pull CS low to begin transaction
    CS_Low();

    // Transmit dummy bytes and receive data
    for (i = 0; i < 9; i++) {
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        EUSCI_B0->TXBUF = masterTxBuffer[i];
        while (EUSCI_B0->STATW & EUSCI_B_STATW_SPI_BUSY);
        masterRxBuffer[i] = EUSCI_B0->RXBUF;
    }

    // Pull CS high to end transaction
    CS_High();

    // Extract status and channel data
    *status    = (masterRxBuffer[0] << 16) | (masterRxBuffer[1] << 8) | masterRxBuffer[2];
    *channel_1 = (masterRxBuffer[3] << 16) | (masterRxBuffer[4] << 8) | masterRxBuffer[5];
    *channel_2 = (masterRxBuffer[6] << 16) | (masterRxBuffer[7] << 8) | masterRxBuffer[8];
}
ADS1292R.c:
/*CONFIGURATION REGISTERS ADS1292R*/
uint8_t const ADS_REG[][2] = {
    {0x00, 0x73}, // ID
    {0x01, 0x02}, // CONFIG1 - 500 SPS
    {0x02, 0xE0}, // CONFIG2
    {0x03, 0xF0}, // LOFF
    {0x04, 0x00}, // CH1SET
    {0x05, 0x00}, // CH2SET
    {0x06, 0xAC}, // RLD_SENS
    {0x07, 0x0F}, // LOFF_SENS
    {0x08, 0x00}, // LOFF_STAT
    {0x09, 0xEA}, // RESP1
    {0x0A, 0x07}, // RESP2
    {0xFF, 0xFF}  // END OF ARRAY
};
int DELAY_COUNT=3;
int32_t read_data[3];
uint32_t p2_24 = 0;

void CS_Low(void) {
    ADS_CS_PORT->OUT &= ~(ADS1292R_CS);
}

void CS_High(void) {
    ADS_CS_PORT->OUT |= ADS1292R_CS;
}


void initADS1292RDYInterrupt(void) {
    P2->SEL0 &= ~(ADS1292R_DRDY);
    P2->SEL1 &= ~(ADS1292R_DRDY);
    /*CONFIGURE P2.3 INPUT DRDY SIGNAL*/

    P2->DIR &= ~(ADS1292R_DRDY);                     /*P2.3 DIRECTION SET AS INPUT*/
    P2->REN &= ~(ADS1292R_DRDY);                     /*P2.3 ACTIVATING INTERNAL RESISTOR*/
   // P2->OUT |= ADS1292R_DRDY;                       /*DECLARING INTERNAL RESISTOR AS PULL-UP*/
    //P2->IES |= ADS1292R_DRDY;                       /*INTERRUPT EDGE SELECT ON FALLING EDGE (HIGH/LOW)*/

    //P2->IE  |= ADS1292R_DRDY;                       /*INTERRUPT ENABLE P2.3*/
   // P2->IFG &= ~(ADS1292R_DRDY);                    /*CLEAR INTERRUPT FLAG BITS*/
}

bool DRDY_status(void) {
    return !(P2->IN & ADS1292R_DRDY);               /*RETURN TRUE IF P2.3 GOES LOW(0)*/
}

void ADS1292_GInit(void) {
    p2_24 = 1 << 24;
    /*ACTIVATE INTERNAL CLOCK OSCILATOR*/
    initialize_CLK();
    _delay(20,'m');
    /*ADS1292R INIT REGISTERS*/
    ADS_PowerOn_Init();
    _delay(20,'m');
    /*START READ DATA CONTINUOUS MODE*/
    MSP_ADS_SPI_write_command(RDATAC);
}

void ADS_PowerOn_Init(void) {
    /*INITIATE DATA INTERRUPT */
    initADS1292RDYInterrupt();
    //_delay(50,'u');
    /*SEND START COMMAND TO STABILIZE THE DEVICE*/
    MSP_ADS_SPI_write_command(START);
    _delay(20,'u');
    /*SEND STOP COMMAND TO STABILIZE THE DEVICE*/
    MSP_ADS_SPI_write_command(STOP);
    _delay(20,'u');
    /*STOP CONTINUOUS READ MODE*/
    MSP_ADS_SPI_write_command(SDATAC);
    _delay(20,'u');
    ADS_register_read(0x00);
    _delay(20,'m');
    ADS_write_register_configs();
}

void ADS_write_register_configs(void) {
    int i = 1;
    /*WRITE ALL REGISTERS*/
    while (ADS_REG[i][0] != 0xFF) {
        MSP_ADS_SPI_write_register(ADS_REG[i][0], ADS_REG[i][1]);

        i++;
    }
}

unsigned int ADS_register_read(uint8_t reg_address) {
    uint8_t data = 0;
    MSP_ADS_SPI_read_register(reg_address, &data);
    return data;
}

int32_t* ADS_read_ecg_resp_data(void) {
    int i;
    uint32_t data, data_1, data_2;
    MSP_ADS_SPI_read_ecg_resp_data(&data, &data_1, &data_2);

    read_data[0] = data;
    read_data[1] = data_1;
    read_data[2] = data_2;

    for (i = 1; i < 3; i++) {
        read_data[i] &= 0x00FFFFFF;
        if (read_data[i] >= p2_24 / 2) {
            read_data[i] -= p2_24;
        }
    }
    return read_data;
}
/*PORT INTERRUPT FOR DRDY*/
void PORT2_IRQHandler(void){
    if(P2->IFG & ADS1292R_DRDY){
      //  P2->IFG &= ~(ADS1292R_DRDY);
    }
}

/*DATA RDY INTERRUPT*/
void EUSCIB0_IRQHandler(void){
    /*CHECK IF RECEIVE INTERUPT FLAG
     *IS SET IN THE IFG REGISTER */
    if (EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG){
        /*RECIEVE DATA DIRECTLY FROM
         *THE RX_BUFFER */
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG));
        RX_DATA = EUSCI_B0->RXBUF;
        /*ONLY STORE DATA FLAG IS SET*/
        if(ads1292Read == true){
            SPI_RX_BUFF[SPI_RX_COUNT++] = RX_DATA;   /*STORE RESULT DATA ON ARRAY*/
            /*RESULT BUFFER COUNT AND FLAG WHEN
             *ENOUGH DATA HAS BEEN RECEIVEID*/
            if(SPI_RX_COUNT > 8){

                SPI_RX_COUNT = 0;
                ads1292DataReceived = true;
                ads1292Read = false;
            }
        }
        /*IMPLEMENT A OPTIONAL DELAY*/
        _delay(15,'u');
    }
    /*CLEAR THE RECIVE INTERRUPT*/
    EUSCI_B0->IFG &=~(EUSCI_B_IFG_RXIFG);
}
 

nsaspook

Joined Aug 27, 2009
16,259
Looks like some sort of PWM or digital signal is on that pin. I would double check your GPIO pin configuration and check for pin shorts on the PCB (that meets the devices layout bypass capacitor and trace requirements). If you isolate the MISO from slave to master, is the signal source from the controller or the ADC?
 

John P

Joined Oct 14, 2008
2,051
It seems that your slave device is not communicating via an SPI link. If it were, data would be getting clocked by the master's clock line, and instead it's obviously running on some other schedule. I'd give priority to figuring out what communication protocol the slave is actually using, or if that's intended to be communication at all. As you say, " This should be established, synchronized by the SPI clock."

I looked up the ADS1292R here:
https://www.ti.com/product/ADS1292R

and the simplified diagram shows an SPI interface with 3 lines coming in as inputs and one output, which sounds correct. But right next to it is "Clock"--is it possible that the ADS1292R's internal clock is somehow driving the SPI, rather than the master's clock?
 

Thread Starter

biza

Joined Sep 6, 2018
4
Hi @nsaspook, in this microcontroller, we have a possibillity to define primary and secondary task for each configuration pin controller, for this one in focus we define :
P1.5 - SCLK
P1.6 - MOSI
p1.7 - MISO
Soo we define this mcu to run in the primary functions. For certain secondary functions like eUSCI, the I/O direction this controlled by the secondary function itself and not by the PXSEL0 or PXSEL1 register.
What I have made in my code, it was defined my pins with a primary function and release the secondary function. like you can see in the follwing peace of code:

pin functions:
   P1->SEL0 |= BIT5 | BIT6 | BIT7;
   P1->SEL1 &= ~(BIT5 | BIT6 | BIT7);

Answer to your question, "If I isolate the MISO from slave to master, is the signal source from the controller or the ADC" Because the without the p1.7 conected to the device and isolating the MISO pin from the ads1292R connection and analyzing with digital analyser the response from the slave, the line show me a clean response, perfectly synchronized with the SCLK.

@John P,
The communication established between master and slave is an SPI.
It looks like the miso pin is picking up some signal, like the other contributor (@nsaspook) said...
Without this connection (MISO) and observing the reaction on this pin with the digital analyzer, I saw a perfect response synchronized with the clock. Now I'm sure I need to modify this pin, there's something wrong with your configuration, you're doing something different than what I asked for.
 

Attachments

nsaspook

Joined Aug 27, 2009
16,259
I've never used the MSP432P401R so I'm only guessing at what's wrong.
Make sure the SPI master is setup for 4-wire full-duplex mode.

A 4-wire full-duplex connection should be like this.
1733693004570.png

Are you sure P1.7:MISO has a DIR setting of input in your code?
C:
    /*INITIALIZE PORT REGISTERS*/
    // 4. Configure SPI pins: P1.5 (SCLK), P1.6 (MOSI), P1.7 (MISO)
    P1->SEL0 |= (BIT5 | BIT6 | BIT7);   // Select primary module function for P1.5, P1.6, and P1.7
    P1->SEL1 &= ~(BIT5 | BIT6 | BIT7);  // Clear P1SEL1 for those bits to use SPI functionality

    /* set CLK and MOSI as outputs */
    P1->DIR |= (BIT5 | BIT6);
    P1->OUT |= (BIT5 | BIT6);

    /* set MISO as input */
    P1->DIR &= ~(BIT7);
 

Thread Starter

biza

Joined Sep 6, 2018
4
Well, I carried out all your suggestions.
And I did two more tests:
  1. the first, I isolated the P1 wire. 7(miso) from the master and tested with digital analyzer, as you can see in the next photo, there are no glitches or pwm signals, the miso line stays high as you can see (all other pins are connected to the slave, except miso).
Screenshot 2024-12-13 at 20.58.43.png

  1. the second test, was made using the pin of slave connected to the digital analyser to view the signal result, with no connection between the master and slave. The miso wire was left floating, the following image show the signal response.

Screenshot 2024-12-08 at 20.29.03.png
So I don't understand why when I connect the wire to the slave, this line have a stress behaviour, resulting in a faster frequency response.
 
Top