This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Problem with SPI communication read/write for MS5540C.

Hello to all,

I am using nRF52840 DK with SDK15.0 and SES. To communicate with MS5540C I have used SPI master sample example but getting some incorrect results.

Almost 4 days I have spend to analyse this issue but still get same problem. I want to send the following commands to sensor:

Conversion start for pressure measurement (D1): 0Fh & 40h
Conversion start for temperature measurement (D2): 0Fh & 20h
Read calibration word 1 (W1): 1Dh & 50h
Read calibration word 2 (W2): 1Dh & 60h
Read calibration word 3 (W3): 1Dh & 90h
Read calibration word 4 (W4): 1Dh & A0h
Reset sequence command: 15h & 55h & 40h 

I am able to read word1-4 but not confirm is this correct result or Not and problem getting for read D1 and D2 continuously getting FF FF value. 

Will you please review my below program snippet and is it correct?

static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
static volatile bool start_measurement = false;
/* Configure MS5540C Sensor Register frame & Sequence */
static uint8_t       reset_seq[] = { 0x15, 0x55, 0x40 };     /**< TX buffer. */
static uint8_t       address_word1[] = { 0x1D, 0x50, 0x00, 0x00 };       /**< TX buffer. */
static uint8_t       address_word2[] = { 0x1D, 0x60, 0x00, 0x00 };       /**< TX buffer. */
static uint8_t       address_word3[] = { 0x1D, 0x90, 0x00, 0x00 };       /**< TX buffer. */
static uint8_t       address_word4[] = { 0x1D, 0xA0, 0x00, 0x00 };       /**< TX buffer. */
static uint8_t       address_pressure[] = { 0x0F, 0x40, 0x00, 0x00 };    /**< TX buffer. */
static uint8_t       address_temp[] = { 0x0F, 0x20, 0x00, 0x00 };        /**< TX buffer. */
static uint8_t       m_rx_buf[sizeof(address_word1)];    /**< RX buffer. */
static uint8_t       p_rx_buff[sizeof(address_pressure)];    /**< RX buffer. */
//static uint8_t start = 0x1D;
//static uint8_t add_word1 = 0x50;
static const uint8_t m_length = sizeof(m_rx_buf);

/* Declair coefficients factor of MS5540C sensor */
static long c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
unsigned int sensor_val = 0;

/**
 * @brief SPI user event handler.
 * @param event
 */
void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context) {
  spi_xfer_done = true;
  NRF_LOG_DEBUG("Transfer completed.");
  if (m_rx_buf[0] != 0) {
    NRF_LOG_INFO(" Received:");
    NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
    NRF_LOG_HEXDUMP_INFO(m_rx_buf2, strlen((const char *)m_rx_buf2));
  }
}

void wait_for_spi_event() {
  while (!spi_xfer_done) {
    idle_state_handle();
  }
}

/**
 * Initialized SPI driver and their pin configurations
 */
void spi_init() {
  nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
//  spi_config.ss_pin = SPI_SS_PIN; /* Vibzer PCB Pin: 25*/
  spi_config.miso_pin = SPI_MISO_PIN; /* Vibzer PCB Pin: 27*/
  spi_config.mosi_pin = SPI_MOSI_PIN; /* Vibzer PCB Pin: 26*/
  spi_config.sck_pin = SPI_SCK_PIN; /* Vibzer PCB Pin: 28*/
  spi_config.mode    = NRF_DRV_SPI_MODE_0;
  spi_config.frequency    = NRF_SPI_FREQ_500K;
  spi_config.bit_order    = NRF_SPI_BIT_ORDER_MSB_FIRST;
  APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}

/**
 * reset sensor module and send sequence.
 */
void reset_sensor() {
  NRF_LOG_INFO("Reset Sensor");
  spi_xfer_done = false;
  APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, reset_seq, sizeof(reset_seq), NULL, 0));
  wait_for_spi_event();
  NRF_LOG_FLUSH();
}

/**
 * brief function Read calibration data (factory calibrated) from PROM of MS5540C
 * by sending specific address.
 */
unsigned int read_cal_word(const uint8_t *address) {
  spi_xfer_done = false;
  unsigned int word = 0;
  uint8_t dummy_byte = 0x00;
  memset(m_rx_buf, 0, m_length);
  memset(m_rx_buf2, 0, sizeof(m_rx_buf2));
//  NRF_LOG_INFO("m_length: %d", m_length)
//  NRF_LOG_INFO("address: %s", (uint32_t)address);
  reset_sensor(); /*Before read calibration word need to reset sensor module*/
  APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, address, sizeof(address), m_rx_buf, sizeof(m_rx_buf)));
  nrf_delay_ms(200);
  wait_for_spi_event();
  NRF_LOG_FLUSH();
  APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &dummy_byte, sizeof(dummy_byte), m_rx_buf2, sizeof(m_rx_buf2)));
  wait_for_spi_event();
  nrf_delay_ms(200);
  NRF_LOG_INFO("RX Buff_byte1:%X byte2:%X", m_rx_buf[2], m_rx_buf[3]);
  word = (m_rx_buf[2] << 8) | m_rx_buf[3]; /*Combine received 2 bytes from sensor*/
//  NRF_LOG_DEBUG("Return Calibration word = %u", word);
  return word;
}

/**
 * brief function for sensor initialized to read factory calibrated data from PROM of MS5540C
 */
void sensor_init() {
  unsigned int word1 = 0; /*Calibration Word 1 */
  unsigned int word2 = 0; /*Calibration Word 2 */
  unsigned int word3 = 0; /*Calibration Word 3 */
  unsigned int word4 = 0; /*Calibration Word 4 */
  
  /* Read Calibration Word 1 */
  word1 = read_cal_word(address_word1);
  NRF_LOG_DEBUG("Calibration Word 1: %u", word1);
  nrf_delay_ms(200);
  /* Read Calibration Word 2 */
  word2 = read_cal_word(address_word2);
  NRF_LOG_DEBUG("Calibration Word 2: %u", word2);
  nrf_delay_ms(200);
  /* Read Calibration Word 3 */
  word3 = read_cal_word(address_word3);
  NRF_LOG_DEBUG("Calibration Word 3: %u", word3);
  nrf_delay_ms(200);
  /* Read Calibration Word 4 */
  word4 = read_cal_word(address_word4);
  NRF_LOG_DEBUG("Calibration Word 4: %u", word4);
  nrf_delay_ms(200);
  /*Do some bitshifting to extract the calibration factors*/
   /*Convert calibration data into coefficients*/
  c1 = (word1 >> 1);
  c2 = ((word3 & 0x3F) << 6) | (word4 & 0x3F);
  c3 = (word4 >> 6);
  c4 = (word3 >> 6);
  c5 = (word2 >> 6) | ((word1 & 0x1) << 10);
  c6 = word2 & 0x3F;
  NRF_LOG_INFO("coefficients- C1: %u C2:%u C3:%u C4:%u C5:%u C6:%u", c1,c2,c3,c4,c5,c6);
}

/**
 * brief function for read pressure value
 */
void read_sensor_val() {
  unsigned int dp_val = 0;
  unsigned int dt_val = 0;
  static uint32_t level = 0;
  /* Read compensated digital pressure value */
  dp_val = read_cal_word(address_pressure);
  NRF_LOG_DEBUG("compensated pressure value: %u", dp_val);
  nrf_delay_ms(200); /* wait for conversion end */
  /* Read compensated digital temperature value*/
  dt_val = read_cal_word(address_temp);
  nrf_delay_ms(200); /* wait for conversion end */
  NRF_LOG_DEBUG("compensated temperature value: %u", dt_val);
}  

The compensate pressure and temperature value getting 65535. Where the coefficients c1-c6 values getting but not sure whether is correct or not.

I am stuck here and getting difficult to understand for debugging. Because we don't have logic analyzer or CRO to check SPI signals.

Will you please provide your suggestion in program or other solution for the same. For your reference I have attached sensor datasheet ms5540c.pdf

Looking forward your response..

Thanks.....

Vishal

  • Thanks for your great explanation. Now I have modified my program snippet here is below:

    unsigned int read_cal_word(const uint8_t *address, const uint8_t add_len) {
      word = 0;
      memset(m_rx_buf, 0, m_length);
      reset_sensor(); /*Before read calibration word need to reset sensor module*/
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, address, add_len, m_rx_buf, sizeof(m_rx_buf)));
      wait_for_spi_event();
      NRF_LOG_FLUSH();
      NRF_LOG_INFO("RX Buff_byte1:%X byte2:%X", m_rx_buf[2], m_rx_buf[3]);
      word = (m_rx_buf[2] << 8) | m_rx_buf[3]; /*Combine received 2 bytes from sensor*/
    //  NRF_LOG_DEBUG("Return Calibration word = %u", word);
      return word;
    }
    
    \\ Below function use for read D1 and D2
    unsigned int read_sensor_value(const bool check_add) {
      sensor_val = 0;
      static uint8_t       add_pressure[] = { 0x0F, 0x40 }; // D1 command
      static uint8_t       add_temp[] = { 0x0F, 0x20 }; // D2 command       
      uint8_t dummy_byte = 0x00;
      memset(m_rx_buf, 0, m_length);
      reset_sensor(); /*Before read calibration word need to reset sensor module*/
      spi_xfer_done = false;
      if (check_add == true) { /*Check here address of read sensor value*/
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, add_pressure, sizeof(add_pressure), NULL, 0));
      } else {
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, add_temp, sizeof(add_temp), NULL, 0));
      }
      nrf_delay_ms(200);
      wait_for_spi_event();
      NRF_LOG_FLUSH();
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &dummy_byte, sizeof(dummy_byte), m_rx_buf, sizeof(m_rx_buf)));
      nrf_delay_ms(200);
      wait_for_spi_event();
      NRF_LOG_FLUSH();
      sensor_val = (m_rx_buf[1] << 8) | m_rx_buf[2];
      NRF_LOG_DEBUG("Sensor value MSB:%X LSB:%X return:[%u]", m_rx_buf[1], m_rx_buf[2], sensor_val);
      return sensor_val;
    }

    But problem is the value of D1= 58048 and D2= 63552 which is out of range of max value of sensor.

    Here is my Logs:

    <info> app: Level Detector started.
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  FE                     |.       
    <info> app: RX Buff_byte1:D7 byte2:9C
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  FE 01 9F 8C            |....    
    <info> app: RX Buff_byte1:9F byte2:8C
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  FE                     |.       
    <info> app: RX Buff_byte1:C6 byte2:2E
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  FE 01 DA 5D            |...]    
    <info> app: RX Buff_byte1:DA byte2:5D
    <info> app: coefficients- C1: 27598 C2:2973 C3:873 C4:792 C5:638 C6:12
    <info> app: Wake up sensor
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  21 E3 40               |!.@     
    <info> app: Sensor value MSB:E3 LSB:40 return:[58176]
    <info> app: compensated pressure value [D1]: 58176
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  3D F9 40               |=.@     
    <info> app: Sensor value MSB:F9 LSB:40 return:[63808]
    <info> app: compensated temperature value [D2]: 63808
    <info> app: Compensated pressure in mbar: -669
    <info> app: Water level: 0cm
    <info> app: Real Temperature in C: 208
    <info> app: Wake up sensor
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  21 E2 C0               |!..     
    <info> app: Sensor value MSB:E2 LSB:C0 return:[58048]
    <info> app: compensated pressure value [D1]: 58048
    <info> app: Reset Sensor
    <info> app:  Received:
    <info> app:  3D F8 40               |=.@     
    <info> app: Sensor value MSB:F8 LSB:40 return:[63552]
    <info> app: compensated temperature value [D2]: 63552
    <info> app: Compensated pressure in mbar: -1069
    <info> app: Water level: 0cm
    <info> app: Real Temperature in C: 207

    How I know the measured value is corrected, because the temperature is not getting correct.

    Thanks....

  • First I would not wait for the spi event, or use such a long delay, since the 33mSec conversion starts while the spi transfer is finishing up.

    Change:
      nrf_delay_ms(200);
      wait_for_spi_event();
    To:
      nrf_delay_ms(33 and a bit more); // 33 mSec conversion time
      wait_for_low_DOUT();             // DOUT goes low when data ready
    or just:
      wait_for_falling_edge_on_DOUT(); // DOUT goes low when data ready

    Next the SPI transfer is already in progress, so I would suggest the first 2 bytes of received data are the bytes making up the 16-bit value in D1 (say), not the 2nd and 3rd bytes. For there to be no issues with Tx presenting unwanted '1's while reading out Rx, which could cause erroneous operation, I would be inclined to make the transfer specifically send '0' on Tx while reading in the 2 Rx bytes

    // Ensure trailing Tx bits are all '0'
    spi_config.orc = 0x00;

  • One last thing, the more I look at the timing diagrams (not as clear as I would like) the more I see CPHA 1 and CPOL 0 to match the sensor timing. In the Nordic encoding this is NRF_DRV_SPI_MODE_1, ie. not Mode_0:

      spi_config.mode = NRF_DRV_SPI_MODE_1; // CPOL = 0, CPHA = 1

  • Hi, 

    If I change delay 200ms to 35ms then sensor is not getting correct value. If I add 200ms delay then it should fine and working and got corrected value of D1 and D2.

    What I need to do in wait_for_low_DOUT(); and wait_for_falling_edge_on_DOUT(); functions.

    Currently my program is working with added 200ms delay but is this good way.

    Thanks....

  • Hi Vishal

    The wait_for_low_DOUT(); and wait_for_falling_edge_on_DOUT Hugh is describing should be very similar to your wait_for_spi_event(); I believe. Instead of the while loop waiting for the SPI transfer to be done, you should set it to wait for D OUT to go low. You should probably set the delay to a bit more than 35ms as well. Could you try with a 40-50 ms delay to see if that's successful?

    Best regards,

    Simon

Related