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.

Reading multiple channels from ADC_DOUT over non_streaming SPI protocol (LMP90080, ScanMode3, DRDYB disabled)

Other Parts Discussed in Thread: LMP90080, LMP90100

Can someone help me understand the sequence of events (with code/pseudo-code examples) to achieve this?  I have successfully implemented SPI comms and can write/read configuration settings to the appropriate registers and I am now ready to read actual ADC values but I require a few more details on the functionality of the LMP90080 - specifically how the ADC_DOUT registers gets populated.  I've got the channels configured as below:

#define TI_LMP90100_CH_SCAN_REG_VALUE                  (0xD8)             /* ScanMode3, LAST_CH=CH3, FIRST_CH=CH0 */  //was 0xF0
#define TI_LMP90100_CH0_INPUTCN_REG_VALUE              (0x81)             /* enable sensor diagnostics, default ref, vinp 0 vinn 1 */
#define TI_LMP90100_CH0_CONFIG_REG_VALUE               (0x77)             /* CH0 Configuration: 214.65 SPS, Gain=8 (FGA off), buffer in signal path*/
#define TI_LMP90100_CH1_INPUTCN_REG_VALUE              (0x93)             /* enable sensor diagnostics, default ref, vinp 2 vinn 3 */
#define TI_LMP90100_CH1_CONFIG_REG_VALUE               (0x77)             /* CH1 config: 214.65 SPS, Gain=8 (FGA off), buffer in signal path */
#define TI_LMP90100_CH2_INPUTCN_REG_VALUE              (0xA5)             /* enable sensor diagnostics, default ref, vinp 4 vinn 5 */
#define TI_LMP90100_CH2_CONFIG_REG_VALUE               (0x77)             /* 214.65 SPS, Gain=8 (FGA off), buffer in signal path */
#define TI_LMP90100_CH3_INPUTCN_REG_VALUE              (0xB7)             /* enable sensor diagnostics, default ref, vinp 6 vinn 7 */
#define TI_LMP90100_CH3_CONFIG_REG_VALUE               (0x77)             /* 214.65 SPS, Gain=8 (FGA off), buffer in signal path */

And my circuit is wired up as follows:

Channel

Positive Input

Negative Input

Variable

0

VIN0

VIN1

RTD1_Exc

1

VIN2

VIN3

RTD1_Sig

2

VIN4

VIN5

RTD2_Sig

3

VIN6

VIN7

RTD2_Exc

Question is this: how do I know/control what channel is being read from ADC_DOUT in a given transaction given that I'm not using the streaming read/write protocol and I've disabled DRDYB?  I've reviewed the manual and the afe firmware considerations documents in detail and the only clue I can find is that I may need to monitor the SAMPLED_CH bits in the SENDIAG_FLAGS register to determine what channel I will be getting when I read from ADC_DOUT.  Please let me know if this interpretation is correct and, if so, what the behavior will be after ADC_DOUT has been read (for example, will SAMPLED_CH automatically increment through CH0->CH1->CH2->CH3->CH0->CH1, etc)?  If this is incorrect, what is the proper way to handle this?  Is there a mechanism for the firmware to configure which channel's data goes into ADC_DOUT?

Thanks in advance,

Tony

  • Hi Tony,

    You are correct. The best way to determine which channel the data that you read applies to is to also read SENDIAG_FLAGS register. The channel information is in bits 2:0. This is the reason that this register was placed in series with the ADC_DOUT registers, so that you can read all four registers at one time.

    When you are in Mode3 the part does sample the channels as you have written. This is also shown in Figure 57 in the datasheet.

    There is sample code available in the MSP430 Interface to LMP90100 Code Library available on the Tools and Software tab of the LMP90100 web page.

    Mike
  • Thank you for your fast response, Mike. I have reviewed the LMP90100 demo code but it doesn't appear to do what I'm attempting to do (read multiple channels in non-streaming mode). It appears as though SAMPLED_CH changes every time I read from it so I still don't know at any given time what to expect to get from ADC_DOUT. Is my only option to do this in the streaming mode (I assume this is what you mean when you say "read all four registers at one time"). Is it not possible read SAMPLED_CH, then ADC_DOUTH, then ADC_DOUTL as individual discrete steps (i.e. 3 independent 8-bit SPI transfers)? Cause by the time I read ADC_DOUTH & ADC_DOUTL, SAMPLED_CH may have changed already...

    Thanks again,
    Tony

  • HI Tony,


    What about using the Controlled Streaming mode?  See section 9.5.5 in the datasheet.  In this mode you set up that you are going to stream more than 3 bytes, the address to start and how many bytes.  It will start at the first byte, read out the number of bytes specified, and then wrap around to the first byte and do it again.  As long as CS is low it will continue to do this.


    Mike

  • Thank you again for the suggestion.  I wanted to walk before I ran ;)  However, based on your suggestion to just "try to run", I've been wrestling with the Controlled streaming mode and references the code examples, particularly demo-app06 to prototype my code.  Despite the fact that I can read back register values properly in a single transaction, I do not seem to get anything back from the chip once I enter the Controlled Streaming mode (see screenshot). 

    The code I'm using is provided below, note that the test read of SPI_STREAMCN back works properly (0x83), but after I go into Controlled streaming mode with continuous PCS , I do not get response back from the chip.  STRM_RANGE is 3 so I am expecting 4 registers back (0x18-0x1B), all of which come back 0.  I have an RTD simulator hooked up pumping in 100 degF into pins 2 & 3 (vinp0 & vinn1), so a response of 0 from all of these registers is unexpected.  Can you take a look at my screenshot/code and let me know what I'm doing wrong?

    #define TI_LMP90100_SPI_STREAMCN_REG_VALUE             (0x83)             /* SPI Controlled Streaming mode, Stream Range = 1 */
    #define TI_LMP90100_CH_SCAN_REG_VALUE                  (0x80)             /* ScanMode2, LAST_CH=CH0, FIRST_CH=CH0 */  //was 0xF0
    #define TI_LMP90100_CH0_INPUTCN_REG_VALUE              (0x81)             /* enable sensor diagnostics, default ref, vinp 0 vinn 1 */
    #define TI_LMP90100_CH0_CONFIG_REG_VALUE               (0x77)             /* CH0 Configuration: 214.65 SPS, Gain=8 (FGA off), buffer in signal path*/



        /// Program SPI_STREAMCN
        URA   = (TI_LMP90100_SPI_STREAMCN_REG & LMP90100_URA_MASK) >> 4;          ///< Extract upper register address
        SPI1_PUSHR = (SPI_PUSHR_TXDATA(LMP90100_INSTRUCTION_BYTE1_WRITE << 8 | URA) | ///< Transmit Instruction 1 Byte & UAB simultaneously
                 SPI_PUSHR_PCS(SPI_CHIP_SEL(0)));                               ///< Assert the PCS signal
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr_reg = (uint8_t)SPI1_POPR;                                                         ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        LRA   = TI_LMP90100_SPI_STREAMCN_REG & LMP90100_LRA_MASK;                  ///< Extract lower register address
        SPI1_PUSHR = ((SPI_PUSHR_TXDATA(((LMP90100_WRITE_BIT|LMP90100_SIZE_1B|LRA)<<8) | TI_LMP90100_SPI_STREAMCN_REG_VALUE)) | ///< Transmit Instruction 2 Byte & data byte to write
                  SPI_PUSHR_PCS(SPI_CHIP_SEL(0)));                             ///< Assert the PCS signal
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr_reg = (uint8_t)SPI1_POPR;                                                         ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        // Test - read SPI_STREAMCN back
        SPI1_PUSHR = (SPI_PUSHR_TXDATA(((LMP90100_READ_BIT|LMP90100_SIZE_1B|LRA)<<8)|(0xFF)) | ///< Transmit Instruction 2 Byte & dummy byte to write
                 SPI_PUSHR_PCS(SPI_CHIP_SEL(0)));                                ///< Assert the PCS signal
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr_reg = (uint8_t)SPI1_POPR;                                                         ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag

        
        
        /// Read addrs 0x18 - 0x1B in controlled stream
        URA   = (TI_LMP90100_ADC_DONE_REG & LMP90100_URA_MASK) >> 4;            ///< Extract upper register address
        SPI1_PUSHR = (SPI_PUSHR_TXDATA(LMP90100_INSTRUCTION_BYTE1_WRITE << 8 | URA) | ///< Transmit Instruction 1 Byte & UAB simultaneously
                 SPI_PUSHR_PCS(SPI_CHIP_SEL(0)));                             ///< Assert the PCS signal
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr_reg = (uint8_t)SPI1_POPR;                                                         ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        LRA   = TI_LMP90100_ADC_DONE_REG & LMP90100_LRA_MASK;                   ///< Extract lower register address
        SPI1_PUSHR = (SPI_PUSHR_TXDATA(((LMP90100_READ_BIT|LMP90100_SIZE_3B|LRA)<<8)|(0xFF)) | ///< Transmit Instruction 2 Byte & dummy byte to write
                (SPI_PUSHR_PCS(SPI_CHIP_SEL(0))) |                             ///< Select which PCS signals are to be asserted for the transfer
                 SPI_PUSHR_CONT_MASK);                                        ///< Keep PCS asserted between transfers when reading TI ADC in streaming mode
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr1 = (uint8_t)SPI1_POPR;   //0x18                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr2 = (uint8_t)SPI1_POPR;   //0x19                                                       ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr3 = (uint8_t)SPI1_POPR;   //0x1A                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr4 = (uint8_t)SPI1_POPR;   //0x1B                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr1 = (uint8_t)SPI1_POPR;   //0x18                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr2 = (uint8_t)SPI1_POPR;   //0x19                                                       ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr3 = (uint8_t)SPI1_POPR;   //0x1A                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr4 = (uint8_t)SPI1_POPR;   //0x1B                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr1 = (uint8_t)SPI1_POPR;   //0x18                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr2 = (uint8_t)SPI1_POPR;   //0x19                                                       ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr3 = (uint8_t)SPI1_POPR;   //0x1A                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag
        
        while (!(SPI1_SR & SPI_SR_TCF_MASK)) {}                                      ///< Wait for all bits in the frame to be shifted out
        popr4 = (uint8_t)SPI1_POPR;   //0x1B                                                      ///< Read the incoming byte (decrements RXCTR)
        SPI1_SR = SPI_SR_TCF_MASK;                                                   ///< Clear Transfer Complete flag

  • Ok so the issue above is I needed dummy writes in order read.  Once I put those in, I'm now getting responses back from the chip.  However, it appears as though I'm get 0x2 (modulator overranged) for the OFLO_FLAGS bitfield within the SENDIAG_FLAGS register.  After measuring voltages, it doesn't make sense that I would be getting this.  I also reduced the RTD temp down to 32 degF which means my VIN now measures 0.574 V.  My Vref is tied to 5V, but measures at 4.5 and my Gain is set to 8 (FGA Off) in the CH0 config register (#define TI_LMP90100_CH0_CONFIG_REG_VALUE  (0x77)).

    So 0.574V is not greater than 1.2*VREF/Gain (0.675).  Since 0.574 is not greater than 0.675, which is OFLO_FLAGS set to 0x2 every time I read from it?

  • Hi Anthony,

    Can you decrease the gain and see if you still have the overrange problem?

    Thanks,

    Mike

  • Decreasing the gain does solve the issue...so presumably I'm hitting the threshold transiently? I will hook up a scope to VIN and take analog measurements over time to confirm/deny this. Once this overrange trips, does it latch?
  • Hi Anthony,

    The datasheet is a little unclear about when the overrange is shown. Section 9.4.2.3.4 seems to indicate that it happens when the input is over VREF/Gain and Table 27 says that you can go up to 1.2*VREF/Gain. It would probably be best to stay under VREF/Gain.
    The overrange bit does not latch, so if the input is overrange it will indicate that, but if the next reading is not overrange it will change to show that the input is not overrange.

    Mike
  • Ok thank you for that clarification - perhaps this should discrepancy should be addressed in a future rev to that document.  Regardless, I'm now reading 3 channels in stream mode, but when I read them in a tight loop, I get the same channel data (SENDIAG_FLAGS register is always the same).  If I manually step through my code (i.e. slow down the looping), I get all the channels (SENDIAG_FLAGS register changes each time I come back around to read it again).  Given that my chip select remains asserted during the entire stream, Is there some sort of delay I need to enforce between successive channel reads?

  • Hi Anthony,

    It could possibly be a timing issue.  For example, if your sampling rate is very slow, say at 1.6775sps and you were reading very fast, you would only read the value of the one conversion.  There is the other possibility that the reading rate and the sample rate is set up so they always sync, channel 1 is converted, a reading is done, channel 2 is converted, channel 3 is converted, channel 1 is converted and the next reading is done.  

    You can set up the part so that you are always reading the DRDYB pin, and when it changes do a reading of the ADC registers.  This way you always get a reading when there is new data in the ADC registers.

    Mike

     

  • Hi Mike,

    Thank you again for your support. My ODR is maxed at 214.65 SPS, so i'm assuming I'm in the second case where I'm likely synched in an unfortunate way. Even worse, my application has explicitly speced that we disable DRDYB because it needs to leverage all the GPIOs (we are actually using multiple LMP90080's to handle all the I/O).

    What other mechanisms do I have to control this behavior? I need to be able to consistently read conversions for 4 channels (CH0-3) in some sort of predictable manner without the use of DRDYB.
  • Hi Anthony,

    You can use the DRDYB function two other ways.

    One is by setting up the DRDYB on the SDO pin. This is set up in the SPI_HANDSHAKECN register. See sections 9.5.1.6.1 and 9.5.1.6.2.

    The other way is through software. The DRDYB info is in the ADC_DONE register. You can read this register (at a higher rate than the ADC sampling) and when it indicates that a conversion is available read the ADC registers. Then go back to reading the ADC_DONE register until it indicates a new conversion is available and so on.

    Mike
  • Ok great - I think using ADC_DONE programmatically is the best option for us.  Can you describe (possibly in pseudo-code) how I might do this given that I've already entered Controlled Streaming Mode?  Would I just always read, for example, 4 registers (0x18-0x1B) and only save the results if ADC_DONE != 0XFF?

  • of course, even with this approach, there is still no guarantee that I will be able to catch each channel in a predictable manner. E.g., isn't it possible that I'll could read 0x18-0x1B and get valid data for CH0, then next time I come around to read again still end up getting CH0 data? I need a way to get CH0, then CH1, then CH2, then CH3 without use of DRDYB (only ADC_DONE)...
  • To better demonstrate my point, here is a loop where I would expect to take 100 readings, 25 for each channel (CH0-3). However, even using ADC_DONE, there is no guarantee that I will get 25 readings for each channel. I may actually just get 100 readings from only one of the four channels.  What I really need is an ADC_DONE flag for each channel or some other similar mechanism that would allow me to read valid data from all 4 channels as quickly as possible and then exit my routine to give the processor time to do other tasks.  Furthermore, the definition of ADC_DONE is unclear. I cannot tell from its description under what conditions is gets set (or when it gets set to 0xFF). Is it "set" when any conversion data is ready (e.g. CH0) or only when all conversion data is ready (e.g. CH0-3, per CH_SCAN)? I would like to try this approach but will need some more info to get there. Thanks again for your support.

    for (int ii=0; ii<100; ii++) {
    popr1[ii] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[ii] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[ii] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[ii] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

    if (popr1[ii] != 0xFF) { // Conversion ready!

    switch (popr2[ii] & CHAN_MASK) {
    case 0:
    CH0 = ((popr3[ii]<<8)|popr4[ii]);
    break;
    case 1:
    CH1 = ((popr3[ii]<<8)|popr4[ii]);
    break;
    case 2:
    CH2 = ((popr3[ii]<<8)|popr4[ii]);
    break;
    case 3:
    CH3 = ((popr3[ii]<<8)|popr4[ii]);
    break;
    default:
    break;
    }
    }
    }

  • Hi Anthony,

    The LMP90080 has only one converter that is shared by all the channels.  When data is available it is only for one channel.  For example if the data for ch1 has been put in the ADC_DOUT registers it is available until the ch2 input is converted and the data put in the ADC_DOUT registers.  The data for ch1 is overwritten even if it hasn't been read out.  

    When new data is put in the ADC_DOUT register the ADC_DONE register is set to a value between 0x00 - 0xFE.  At this point two things can happen: 1 - the data is read from the ADC_DOUT register and the value in the ADC_DONE register will change to 0xFF to show that new data is not available (it is considered old since it has been read), or 2 - the data is not read from the ADC_DOUT register, new data from the next converted channel is put in the ADC_DOUT register and the ADC_DONE register is again set to a value between 0x00 - 0xFE.  This will happen if the data is read or not.  You need to read data at a rate that is faster then the rate the ADC is converting or you will lose data.

    As an example, if you have 4 channels and they are each sampling at at rate of 1sps (not an available rate for the LMP90080, but it makes the example easier), there will be new conversion data in the ADC_DOUT register every 1 second.  To get all the available data you will need to read data at a rate that is faster than 1x per second.

    Start the ADC converting and then make the first reading after 1sec.  You would make a reading of registers 0x18 - 0x1B.  Look at the data in register 0x18.  If it is between 0x00 - 0xFE then the data in registers 0x1A and 0x1B is good data.  Look at the data in register 0x19 to see what channel this data is for. 

    Wait 0.9sec, and then read registers 0x18 - 0x1B again.  Take a look at the data in register 0x18.  In this example it would be 0xFF since it is not new data and it has already been read.  Wait another 0.9sec and again read registers 0x18 - 0x1B.  By this time ch2 will have been converted and the data available.  Register 0x18 will show a value between 0x00 - 0xFE.  Read register 0x19 to determine what channel the data is for (ch2 in this case).  Continue on like this. 

    Mike

  • Thank you Mike for that detailed description - that is very helpful.  Sometimes, I am getting readings from unexpected channels.  For example, even though I think I've set CH_SCAN_REG to only convert CH0-CH3, sometimes the SENDIAG_FLAGS register indicates results from a different channel (e.g. 0x3d would correspond to CH5 which I would never expect to get).  Can you confirm I have the correct values set for this scenario:

    #define TI_LMP90100_SPI_STREAMCN_REG_VALUE (0x83) /* SPI Controlled Streaming mode, Stream Range = 3 */

    #define TI_LMP90100_CH_SCAN_REG_VALUE (0xD8) /* ScanMode3, LAST_CH=CH3, FIRST_CH=CH0 */

    It also looks like my stream range is only 3.  For the example code below, my results are as follows (note that popr2 and popr4 are identical which leads to believe I have stream size of 3 addrs, not 4):

    popr1 = [0x0, 0x0, 0x0, 0x0] //ADC_DONE

    popr2 = [0x3D, 0x87, 0xff, 0x3D] // SENDIAG_FLAGS (note that none of these are from CH0-3?!)

    popr3 = [0xFF, 0xFF, 0xFF, 0xFF] // garbage

    popr4 = [0x3D, 0x87, 0xff, 0x3D] // looks same as popr2?!  section 9.5.1.3 says it will stream STRM_RANGE + 1 addrs...

     

    for (int jj=0; jj<1000000; jj++) {} // busy wait between successive channel reads
    popr1[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

    for (int jj=0; jj<1000000; jj++) {} // busy wait between successive channel reads
    popr1[1] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[1] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[1] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[1] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

    for (int jj=0; jj<1000000; jj++) {} // busy wait between successive channel reads
    popr1[2] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[2] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[2] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[2] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

    for (int jj=0; jj<1000000; jj++) {} // busy wait between successive channel reads
    popr1[3] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[3] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[3] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[3] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

    Also, do I need to deassert CSB after each stream of 4 addrs or is it ok to leave CSB asserted throughout the process above?

  • Hi Anthony,

    It may be best to simplify a little and see if it can read the register correctly one time.  After you have set up the registers of the LMP90100, do one reading of the registers 0x18 to 0x1B.  Did you get the values that you are expecting?  If not we need to figure out what is not set up correctly in the registers. 

    One other thing I noticed as I was going through the datasheet is that there is a repeat read time on the ADC_OUT registers of 72us.  The reads of these registers need to be spaced out by at least 72us.  (See page 46 in the datasheet.)  If you are doing a continuous read of these registers it will read it a lot faster than that.  That would mean you would have to do something like a continuous read of only ADC_DONE until it say that there is new data, then do a continuous read of registers 0x19 to 0x1B then go back to continuously reading ADC_DONE until new data is available and so on.


    Mike

  • Agreed.  I do not get expected results on the first read.  Notice from my example above, the very first read is for channel 5 even though I've setup CH_SCAN to stream CH0-3.  I would never expect to get a reading from channel 5 in this case.  This thread should contain the pertinent register settings, can you double them for correctness please?

    Yes I did notice that note about 72us as well.  Should be ok in this case as I am waiting an exorbitant amount of time between streams (notice the jj counter above).  Besides, I'm not sure how to just read ADC_DONE when my stream size is 4 registers - wouldn't I always have to read 4 registers in this case?

    I've dumbed it down to one read of one channel with stream size of 4 and I do not get expected results (see below):

    #define TI_LMP90100_SPI_STREAMCN_REG_VALUE (0x83) /* SPI Controlled Streaming mode, Stream Range = 3 */

    #define TI_LMP90100_CH_SCAN_REG_VALUE (0x92) /* ScanMode2, LAST_CH=CH1, FIRST_CH=CH1 */

    /// Program SPI_STREAMCN - can this go in init?
    URA = (TI_LMP90100_SPI_STREAMCN_REG & LMP90100_URA_MASK) >> 4; ///< Extract upper register address
    pushr = (SPI_PUSHR_TXDATA(LMP90100_INSTRUCTION_BYTE1_WRITE << 8 | URA) | ///< Transmit Instruction 1 Byte & UAB simultaneously
    SPI_PUSHR_PCS(SPI_CHIP_SEL(PCS))); ///< Assert the PCS signal
    popr = (uint8_t)spi_rw(SPI1, pushr); ///< Read the incoming byte

    LRA = TI_LMP90100_SPI_STREAMCN_REG & LMP90100_LRA_MASK; ///< Extract lower register address
    pushr = ((SPI_PUSHR_TXDATA(((LMP90100_WRITE_BIT|LMP90100_SIZE_1B|LRA)<<8) | TI_LMP90100_SPI_STREAMCN_REG_VALUE)) | ///< Transmit Instruction 2 Byte & data byte to write
    SPI_PUSHR_PCS(SPI_CHIP_SEL(PCS))); ///< Assert the PCS signal
    popr = (uint8_t)spi_rw(SPI1, pushr); ///< Read the incoming byte

    /// Read specified address(es) in Controlled Streaming Mode
    URA = (TI_LMP90100_ADC_DONE_REG & LMP90100_URA_MASK) >> 4; ///< Extract upper register address
    pushr = (SPI_PUSHR_TXDATA(LMP90100_INSTRUCTION_BYTE1_WRITE << 8 | URA) | ///< Transmit Instruction 1 Byte & UAB simultaneously
    SPI_PUSHR_PCS(SPI_CHIP_SEL(PCS))); ///< Assert the PCS signal
    popr = (uint8_t)spi_rw(SPI1, pushr); ///< Read the incoming byte

    LRA = TI_LMP90100_ADC_DONE_REG & LMP90100_LRA_MASK; ///< Extract lower register address
    pushr = (SPI_PUSHR_TXDATA(((LMP90100_READ_BIT|LMP90100_SIZE_3B|LRA)<<8)|(0xFF)) | ///< Transmit Instruction 2 Byte & dummy byte to write
    (SPI_PUSHR_PCS(SPI_CHIP_SEL(PCS))) | ///< Select which PCS signals are to be asserted for the transfer
    SPI_PUSHR_CONT_MASK); ///< Keep PCS asserted between transfers when reading TI ADC in streaming mode

    popr1[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x18 - ADC_DONE
    popr2[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x19 - SENDIAG_FLAGS
    popr3[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1A - ADC_DOUTH
    popr4[0] = (uint8_t)spi_rw(SPI1, pushr); ///< 0x1B - ADC_DOUTL

     

     

    i get popr1[0] = 0x0 (this is ok, conversion ready)

    popr2[0] = 0x3d (this is not expected,indicates conversion on channel 5 when I only expect conversions from CH1 per TI_LMP90100_CH_SCAN_REG_VALUE)

    popr3[0] = 0xff (this is not expected)

    popr4[0] = 0x3d (this is not expected, looks like another popr2?!)

     

    If you look closely at the results, it looks like popr1[0] is ADC_DONE, popr2[0] is SENDIAG_FLAGS (but indicates unexpected channel conversion).  But then it looks like I popr3[0] is another ADC_DONE (conversion not ready) and popr4[0] is another popr2 (same value).  It's almost as if my stream size is 2...

  • Ok, so I think I now understand why I was getting popr3=popr1 and popr4=popr2: I am setup for 16 bit frames, not 8!  So, for me, popr1 would contain both 0x18 and 0x19 and popr2 would contain both 0x1A and 0x1B.

    With that, I've refined the code that reads the conversions also taking into account the 72 us repeat read limit for the ADC_DOUT register (see snippet below).  Does this look proper based on everything we've discussed?

    Also, I need clarification on exactly what the CH_SCAN register controls on the chip.  Specifically are conversions only occurring for channels FIRST_CH through LAST_CH?  For example, if I set CH_SCAN to 0xD8 (ScanMode3, LAST_CH=CH3, FIRST_CH=CH0), would ADC_DOUT ever contain results from a conversion on say CH 5?

    for (int ii=0; ii<100; ii++) {

      popr1[ii] = spi_rw(SPI1, pushr); // 16 bit frame => popr1 contains ADC_DONE & SENDIAG_FLAGS (0x18 - 0x19)

      CHAN = (popr1[ii]>>8) & 0x7;

      if ((popr1[ii] & 0xFF) != 0xFF) { // Conversion ready!

         popr2[ii] = spi_rw(SPI1, pushr); // 16 bit frame => popr2 contains ADC_DOUT (0x1A - 0x1B)

         ADCH = popr2[ii] & ADC_OUTH_SHIFT;

         ADCL = popr2[ii]>>8;

      }

    }

  • I was looking closer at your response above and am wondering if what you suggest in the second paragraph is feasible. In order to stream (or change stream conditions), 4 transactions must take place: SPI_STREAMCN URA & LRA followed by the stream start address URA & LRA. So I can start just streaming 1 register at first (ADC_DONE), but then when it indicates conversion results are ready, it seems to me that there is no guarantee that by the time I tell the chip to then stream 3 addresses starting at 0x19 (4 "transactions") that ADC_DOUT will still contain the correct conversion results by the time I read it. I am running at the fastest possible rate of 214.65 SPS. Am I missing something in your suggestions or is there perhaps some other way to predictably get the conversion results out in a tight loop?
  • Hi Anthony,

    In answer to your question two posts above, if you have it set up to start with CH0 and end with CH3, you will not get a conversion for CH5.

    To get all the conversion results out it is best to set up your URA and when you know a conversion result is available by monitoring the data ready signal, you do Transaction 2 of Figure 73 only. You do not need to do Transaction 1 because you have already set up the URA. When the next conversion result is ready, do a Transaction 2 again.

    Mike