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.

Problem receiving data in SPI comunication on the MSP432P401R

Other Parts Discussed in Thread: ADS1292R, ADS1292, ADS1292RECG-FE

Hello guys,

I'm trying to integrate a digital analog front end (ADS1292R) with the MSP432P401 development board, but I'm having some problems with receiving the data, because through the interrupts I check what is sent by the slave board. In analyzing the data, I verify that it responds to a command that identifies the read register. But right away I send a command to perform the slave chip identification and it only gives me 0's. I'm suspicious that I made a bad integration of SPI communication. As this is a prototype and I needed a quick analysis of this problem I resorted to development with driverlib, which is not my strong point. Then I need someone with more knowledge to give me some tips on what could be wrong. Enclosed I send the produced code

.adsInterface.zip

Thanks in advance

  • Hi Armando,

    There is quite a bit of code to sort through to understand all that is happening.  The only thing that catches my eye is I see a couple of 10usec delays that appear after a function call that performs the SPI operation.  Is it possible that this delay is too short and the SPI is not finished transmitting data when the ADS1292 chip select is disabled?

  • Hi Dennis, 

    Thanks for your response. I already changed the delay value, but I didn't get any change. I reviewed all the connections between the bord and the launch pad and everything is correctly connected.

    In step-by-step debub mode I was checking the variables as well as the commands sent to the slave device, but I don't get a response through the SPI. It would be supposed when transmitting the information after the interruption in the variable Rx_data it should receive a hexadecimal value 0x73, which would be the value that confirms the chip ID, but instead I only receive 0's.

  • Hi Armando,

    Can you capture on an oscilloscope or logic probe a SPI transaction that does work and one that does not?

  • SPI_RW() relies on EUSCI_SPI_TRANSMIT_INTERRUPT (TXIFG) to decide whether the byte has been sent, but the EUSCI's double buffering means that the byte has only started at that moment. With BRW=12, it won't be complete for another 8*12=96 CPU clocks, so you'll fetch RX_data too early. 

    Try replacing the second SPI_getInterruptStatus() check with something like:

    > while (SPI_isBusy(EUSCI_B0_BASE)) /*EMPTY*/;   // Wait for buffered byte to finish

  • Hello Dennis , 

    This is the signal I got with a logic analyser

  • In the first trace, the ENABLE (I assume this is /CS) isn't asserted.

    The second trace shows only the first two bytes (which look correct), but not the third byte which would have the RREG response in it. Can you maybe "squeeze" the trace a bit more?

  • Hello Bruce, 

    This is the entire trace with first three bytes but just the first two bytes have values...

  • Because you never actually read the data.

    uint8_t SPI_RW(uint8_t TXData){
          while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_TRANSMIT_INTERRUPT)));
    
          SPI_transmitData(EUSCI_B0_BASE, TXData);
    
          while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_TRANSMIT_INTERRUPT)));
    
          return Rx_data;
    }
    

    Rx_data is a global which you never put data from RXBUF into. You should be waiting on RXIFG after sending the data. Note also that if you only use SPI_RW(), then the initial check of TXIFG will always be true and doesn't need to be done. Something like this. (Note that I do not use driver lib so the details are a guess on my part.)

    uint8_t SPI_RW(uint8_t TXData){
              SPI_transmitData(EUSCI_B0_BASE, TXData);
    
          while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_RECEIVE_INTERRUPT)));
    
          return SPI_receviceData(EUSCI_B0_BASE);
    }
    

  • David  Schultz

    thanks for joining this discussion. I replaced the code snippet I had with what you suggested, but the code locks in:

    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_RECEIVE_INTERRUPT)));

    this way the program does not pass from there

  • I hesitate to disagree with David, but in this case the RXIFG is absorbed by the ISR (which also captures Rx_data), and even if it gets caught it will be the wrong RXIFG. I (still) recommend waiting for the SPI to go idle (see above). [I actually recommend not using interrupts at all, but that would be a bigger change.]

    What's more significant than the fact that /CS is being de-asserted too early (implying reading RX_Data too early) is that there's no evidence of an RREG response -- at minimum the 0x8C bits should be 0. [Ref data sheet (SBAS502B) p. 39]. Are you fairly certain of the power-up/reset sequence?

    [Edit: Based on this trace, you should be reading 0xFF, but you reported that you're reading 0x00. Maybe check your wiring?]

  • Bruce  I preserved the suggested code snippet, getting the code as follows:

    uint8_t SPI_RW(uint8_t TXData){
          while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_TRANSMIT_INTERRUPT)));
          SPI_transmitData(EUSCI_B0_BASE, TXData);
          while (SPI_isBusy(EUSCI_B0_BASE));
          return Rx_data;
    }

    I would like not to use interrupts, but unfortunately I do not have the knowledge to carry out such a procedure, so I chose interrupts. On the other hand, the CS part I think I can control by staying in low just before the data transmission, the data sequence according to the diagram is as follows. what I think I managed to do the sequence correctly

    Sorry, I forgot to update your "Rx_data" status, now the return value is 255 , by my count it should be 115.
    Thanks in advance
  • I didn't look far enough in the code to see an ISR. Silly me to assume if transmit was polled then so was receive.

    The ISR should be deleted as it is an abomination. Worst is sending serial data (a long operation) from within an ISR.

  • That is odd. Usually people say that interrupts are too complex to use.

    A polled version of SPI_RW() is a lot easier and you know that the data returned is what was received while sending that particular byte.

  • How is the CLKSEL pin set? I don't see any code that generates an (external) clock, so I suppose it's =1?

  • Bruce McKenney47378, 

    On the ADS1292R protocentral board, on the CLK I added a 10KOhm resistor connected to 3.3V, which activates the internal oscillator on the board causing it to oscillate at 512Khz , this it's = 1

  • The flowchart indicates that DRDY should oscillate at 512/256=2kHz once the clock starts. Have you been able to observe this? The device doesn't seem to provide a lot of  feedback, so you should look for any signs of life.

    ---------------------

    As David says, it's actually simpler, faster, and more reliable to use spin-loops rather than interrupts for short transactions on a fast SPI. I offer this from time to time on the Forum:

    uint8_t spix(uint8_t c)
    {
      while (!(UCB0IFG & UCTXIFG)) /*EMPTY*/;
      UCB0TXBUF = c;
      while (!(UCB0IFG & UCRXIFG)) /*EMPTY*/;
      c = UCB0RXBUF;
      return(c);
    }

    Each Tx byte gets back a corresponding Rx byte; if that Rx byte isn't interesting you can throw it away. It (deliberately) avoids filling the Tx pipeline, and so avoids Rx overruns. When it returns, the SPI is idle, so (if appropriate) you can de-assert /CS. As David points out, the first line is optional (if you promise to use only this function to drive the SPI).

  • Bruce  Thanks for your answer,

    I have change the function SPI_RW(), and in  the last while the program stop, s waiting to.

    receive the response from the RX, but it is not returned additionally added a wire to check the status of the DRDY I don't see any change

  • Did you remove this line?

    >  SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_RECEIVE_INTERRUPT);

    As I mentioned earlier, the ISR will "absorb" the Rx interrupt if it's enabled, but the spin loop form makes the ISR unnecessary.

  • Hello Bruce, 

    I see some progress, answering to your question, yes, a read on google a while about polling after that i have made some changes to implement a new life to the code. Soo on the SPI implementation (spi_init()) I have remove some lines of code, like:

     >SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_RECEIVE_INTERRUPT);

     >Interrupt_enableInterrupt(INT_EUSCIB0);

      >MAP_Interrupt_enableMaster();

    After that I have run the code and the digital analyser and watch the signs and I have  repaired the first byte sent is 0x11, previously before the new code changes I never see this byte.

    On the MSO line, I don't receive qualquer dado, I am start show some doubts that this protocentral board is broken

  • It (still) looks like the ENABLE is being de-asserted before the final byte is sent. Can you show what SPI_RW  and ADS1292R_REG look like now? Are you using only SPI_RW to drive the SPI? (I saw a few other functions in there.)

    I still wonder about not seeing DRDY wiggle, at least up to when you send the SDATAC. 

  • The SPI_RW() looks like :

    uint8_t SPI_RW(uint8_t TXData){
        
           while(!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG));
            EUSCI_B0->TXBUF = TXData;
            while(!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG));
            return (TXData);
    }

    Yes in this moment I have put the interrupt sideway, and I use the SPI_SW to drive all SPI performance. 

    The ADS1292R_REG is in the same way i sent you.

    uint8_t ADS1292R_REG(uint8_t cmd, uint8_t data){
        GPIO_setOutputLowOnPin(ADS1292R_CS_PORT,ADS1292R_CS_PIN);
        delay_us(10);
        ADS1292R_SPI_RW(cmd);
        ADS1292R_SPI_RW(0x00);
        if((cmd & 0x20)==0x20){
            ADS1292R_SPI_RW(0x00);
        }else{
            ADS1292R_SPI_RW(data);
        }
        delay_us(10);
        GPIO_setOutputHighOnPin(ADS1292R_CS_PORT,ADS1292R_CS_PIN);
        return Rx_data;
    }
    

  • > return (TXData);

    This should look more like:

    > Rx_data = EUSCI_B0->RXBUF;  // Capture data and clear RXIFG
    > return (Rx_data);

    Rx_data doesn't really need to be global, but for the callers' logic.

  • Hello Bruce,

    More news , I been working with code and debug step by step, I have made some upgrades like monitorize the START and DRDY pin's.

    Soo when start the program the START pin goes high but the DRDY and the MISO does not have changes. The DRDY is normal because only after the chip ID read and the data be equal to 0x73 is that the code is executed, after that the DRDY should change the signal based in each transition. Step by step the problem seems to be solving, but the MISO pin still without response, this is the new transmission...

  • OK, it looks like the SPI is OK, what's left is that the ADS1292 doesn't seem to be starting up.

    According to the flow chart [Data Sheet (SBAS502B) Fig 63, which you pasted above], the DRDY toggle should start as soon as the (internal) clock starts, about 8ms after you set START=1 (in ADS1292R_Init, long before you read the ID). This seems to fit with RDATAC behavior. Then you're supposed to set PWDN=1 (early in ADS1292R_PowerOnInit()).

    However, this seems to conflict with with Fig 62, which suggests that PWDN=1 should happen immediately at power-up. This actually seems reasonable, since PWDN=0 holds the device in reset, which would keep it from toggling DRDY. Try changing the last line of ADS1292R_Init to:

    >      GPIO_setOutputHighOnPin(ADS1292R_PWDN_PORT,ADS1292R_PWDN_PIN); // Out of Reset per DS Fig 62 (disagrees with Fig 63]

    >      delay_ms(8+200);   // 8ms from DS Table 17 plus a large amount of slop

    [Edit: Also, what board are you using? Is it the ADS1292RECG-FE? I'm thinking schematics might be useful.]

  • yes, trough the diagram seem the spi is Ok. you are correct in your suggestion, and i will made some changes.

    I've been looking for references to the figures you've been telling me and I've come to the conclusion that the bibliography you're using is already out of date, as there is already a new version (SBAS502C – DECEMBER 2011 – REVISED APRIL 2020) .No my friend I am not using the ADS1292RECG-FE. It is a protocentral board ADS1292R, in atachment I add the schemma...

    7750.pc_ads1292r_brk_v3.pdf

  • That's why I include the document version number. It appears the relevant references in Rev C are Figs 44 and 72, and Table 29.

    Did you try what I suggested?

    The Data Converters Forum has an FAQ which points to:

    https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/775288/faq-ads129x-how-do-i-verify-that-my-ads129x-device-is-still-functional/2868597#2868597

    It mentions raising START but not (explicitly) PWDN. Maybe they expect a pullup there?

  • Yes  I have tried the thing you have suggested but does not bring any new to the previous code we have upgradedd. I have integrate the function ADS1292R_Work() after "power down high" and before "start pin low" inside on ADS1292R_PowerOnInit()...

    void ADS1292R_Work(void){
        MAP_GPIO_setAsInputPin(ADS1292R_ADC_RDY_PORT, ADS1292R_ADC_RDY_PIN);
        MAP_GPIO_setAsInputPinWithPullUpResistor(ADS1292R_ADC_RDY_PORT, ADS1292R_ADC_RDY_PIN);
        MAP_GPIO_interruptEdgeSelect(ADS1292R_ADC_RDY_PORT,ADS1292R_ADC_RDY_PIN, GPIO_HIGH_TO_LOW_TRANSITION);
        MAP_GPIO_clearInterruptFlag(ADS1292R_ADC_RDY_PORT, ADS1292R_ADC_RDY_PIN);
        MAP_GPIO_enableInterrupt(ADS1292R_ADC_RDY_PORT, ADS1292R_ADC_RDY_PIN);
        MAP_Interrupt_enableInterrupt(INT_PORT4);
    }

    do you suggest implement a pull Up resistor in the Start PIN? 10K?

  • Try changing the last line of ADS1292R_Init to:

    >      GPIO_setOutputHighOnPin(ADS1292R_PWDN_PORT,ADS1292R_PWDN_PIN); // Out of Reset per DS Fig 72 (disagrees with Fig 44]

    >      delay_ms(8+200);   // 8ms from DS Table 29 plus a large amount of slop

    Putting a pullup on PWDN probably doesn't help you since you're driving it (low) as an output. 

    The thing I noticed about that checklist I linked is that the Data Converter people also consider it important to see the DRDY toggle (step 5).

  • Well at last I  have checked the FAQ posted in Data Converters Forum and for the ADS1292R:

    Vcap1 = AVSS + 1.2V=> Vcap1 = 0 + 1.2 = 1.2V

    Vcap2 = AVDD +1.9V=> Vcap2 = 3.32 + 1.9 = 5.22V 

    but verifiing localy in the board the values the Vcap1= 1.09V and the  Vcap2 = 2.54V. On the step 3  says "Enable the internal master clock or provide an external master clock per the data sheet specifications". How you enable the internal clock if the code does not pass the part where it requires the CHIP ID. Maybe is in fault some connection, only CLK and GPIO pins  does not are conected, this is the unique explanation to the internal oscilator not run. we already look everything, the last thing we don't try it was the CLK and GPIO pins, the question is how we activate the internal oscilator, without run the code,becouse if you dont configurate the code correctly the oscilator will never work!!..

  • According to step 3 in the startup flowchart [DS Fig 44, posted above] you start the internal clock by setting CLKSEL=1. Is CLKSEL=1?

    This happens long before you can read the ID register. 

  • Hi Armando,

    We haven’t heard from you for a couple of days now, so I’m assuming you were able to resolve your issue.
    I'll change the status of this posting to RESOLVED, but if this isn’t the case, please click the "This did NOT resolve my issue" button and reply to this thread with more information.
    If this thread locks, please click the "Ask a related question" button and in the new thread describe the current status of your issue and any additional details you may have to assist us in helping to solve your issues.