SPI CS Pin Only Working When Grounded

Hi,

I'm currently trying to operate a MAX86141 sensor (datasheet found here) with an nRF 5340 development kit using SPI communication. I haven't used SPI before, but I've been going through examples and trying to get it operating correctly. Currently, I am simply trying to read the part ID, which should be achieved by reading the register 0xFF, which should then return the value of 0x25 according to the datasheet. The issue I'm running into is that when I run my code (shown below) I receive back a value of 0x00, or occasionally 0xFF or 0x7F. If I, however, connect the  CS pin of my sensor to ground, I get back the correct reading of 0x25. I know that SPI communication shouldn't have the CS pin connected to ground, however, so this clearly isn't how it should be operating. When I use an oscilloscope to check the CS pin's output from the nRF5340dk, it seems to go high and low as expected, but it still doesn't seem to operate correctly when interfacing with the sensor. Any help with this would be appreciated!

Here's the code I'm using for the moment: (note that a lot of the pins defined upfront aren't being used yet, but I decided to leave them in for this post in case they're somehow interfering in a way I'm not familiar with)

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <ncs_version.h>


#define WRITE_EN 0x00
#define READ_EN 0xFF

#define REG_INT_STAT_1         0x00      //Interrupt Status 1
#define REG_INT_STAT_2         0x01      //Interrupt Status 2
#define REG_INT_EN_1           0x02      //Interrupt Enable 1
#define REG_INT_EN_2           0x03      //Interrupt Enable 2
#define REG_FIFO_WR_PTR        0x04      //FIFO Buffer Write Pointer
#define REG_FIFO_RD_PTR        0x05      //FIFO Buffer Read Pointer
#define REG_OVF_COUNTER        0x06      //Over Flow Counter
#define REG_FIFO_DATA_COUNT    0x07      //FIFO Data Counter
#define REG_FIFO_DATA          0x08      //FIFO Data Register

#define REG_FIFO_CONFIG_1      0x09      //FIFO Configuration 1
#define REG_FIFO_CONFIG_2      0x0A      //FIFO Configuration 2
#define REG_MODE_CONFIG        0x0D      //System Control

//Photoplethysmogram (PPG) registers
#define REG_PPG_SYNC_CTRL      0x10      //PPG Sync Control
#define REG_PPG_CONFIG_1       0x11      //PPG Configuration Settings Group 1
#define REG_PPG_CONFIG_2       0x12      //PPG Configuration Settings Group 2
#define REG_PPG_CONFIG_3       0x13      //PPG Configuration Settings Group 3

#define REG_PROX_INTR_THRESH   0x14      //Prox Interrupt Threshold
#define REG_PD_BIAS            0x15      //Photo Diode Bias
#define REG_PICKET_FENCE       0x16      //Picket Fence Settings

#define REG_LED_SEQ_1          0x20      //LED Sequence 1
#define REG_LED_SEQ_2          0x21      //LED Sequence 2
#define REG_LED_SEQ_3          0x22      //LED Sequence 3

#define REG_LED1_PA            0x23      //LED 1 Pulse Amplitude
#define REG_LED2_PA            0x24     //LED 2 Pulse Amplitude
#define REG_LED3_PA            0x25      //LED 3 Pulse Amplitude
#define REG_LED4_PA            0x26      //LED 4 Pulse Amplitude
#define REG_LED5_PA            0x27      //LED 5 Pulse Amplitude
#define REG_LED6_PA            0x28      //LED 6 Pulse Amplitude
#define REG_LED_PILOT_PA       0x29      //LED Pilot Pulse Amplitude
#define REG_LED_RANGE_1        0x2A      //LED Amplitude Range 1
#define REG_LED_RANGE_2        0x2B      //LED Amplitude Range 2

//Hi resolution DAC settings for each LED.
#define REG_S1_HI_RES_DAC1     0x2C
#define REG_S2_HI_RES_DAC1     0x2D
#define REG_S3_HI_RES_DAC1     0x2E
#define REG_S4_HI_RES_DAC1     0x2F
#define REG_S5_HI_RES_DAC1     0x30
#define REG_S6_HI_RES_DAC1     0x31

#define REG_S1_HI_RES_DAC2     0x32
#define REG_S2_HI_RES_DAC2     0x33
#define REG_S3_HI_RES_DAC2     0x34
#define REG_S4_HI_RES_DAC2     0x35
#define REG_S5_HI_RES_DAC2     0x36
#define REG_S6_HI_RES_DAC2     0x37

//Die-temp registers
#define REG_TEMP_CONFIG        0x40
#define REG_TEMP_INTR          0x41
#define REG_TEMP_FRAC          0x42

//SHA256 registers
#define REG_SHA_CMD            0xF0
#define REG_SHA_CONFIG         0xF1

//Memory registers
#define REG_MEM_CTRL           0xF2
#define REG_MEM_IDX            0xF3
#define REG_MEM_DATA           0xF4
#define REG_PART_ID            0xFF

#define SIZE 					20
#define FIFO_SAMPLES 			128

#define RESET_REG       0x00
#define READ_CMD        0x07

static const struct spi_config spi_cfg = {
    .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
             SPI_MODE_CPOL | SPI_MODE_CPHA,
    .frequency = 125000,
    .slave = 0,
};

#define SPI1_NODE       DT_NODELABEL(my_spi_master)
static const struct device *spi_dev = DEVICE_DT_GET(SPI1_NODE);

#define MY_GPIO1 DT_NODELABEL(gpio1)    //CS
#define GPIO_1_CS       12
const struct device *gpio1_dev = DEVICE_DT_GET(MY_GPIO1);

void spi_test_send(uint8_t reg, uint8_t size)
{
    int err;
    uint8_t tx_buffer[1];
    
    tx_buffer[0] = size | reg;
    static uint8_t rx_buffer[2];
    
    for (int i=0; i<sizeof(tx_buffer);i++)
    {
        rx_buffer[i] = 0x00;
    }

    const struct spi_buf tx_buf = {
        .buf = tx_buffer,
        .len = sizeof(tx_buffer)
    };
    const struct spi_buf_set tx = {
        .buffers = &tx_buf,
        .count = 1
    };

    struct spi_buf rx_buf = {
        .buf = rx_buffer,
        .len = size,
    };
    const struct spi_buf_set rx = {
        .buffers = &rx_buf,
        .count = 1
    };
    
    gpio_pin_set(gpio1_dev, GPIO_1_CS, 0);
    //k_sleep(K_MSEC(2000));
    err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    gpio_pin_set(gpio1_dev, GPIO_1_CS, 1);
    
    if (err) {
        printk("SPI error: %d\n", err);
    } else {
        printk("\r\nTX sent: ");
        printk("0x%02x", tx_buffer[0]);
        
        printk("\r\nRX recv 1: ");
        printk("0x%02x", rx_buffer[0]);
        printk("\r\n");
    }   
}

void main(void)
{
    gpio_pin_configure(gpio1_dev, GPIO_1_CS, GPIO_OUTPUT);
    gpio_pin_set(gpio1_dev, GPIO_1_CS, 1);
    
    while(1){
    spi_test_send(WRITE_EN, REG_PART_ID);
    k_sleep(K_MSEC(1000));
    }
}

Thanks in advance!

Parents
  • "Read mode operations will access the requested data on the 16th SCLK rising edge, and present the MSB of the requested data on the following SCLK falling edge"

    24-bits, 3 bytes, are required for this 1-byte read transaction (CS to ground is a red herring, causing the MAX86141 to "see" 3 bytes).

        static uint8_t rx_buffer[2];
    change to
        static uint8_t rx_buffer[3];
    
    Response is in rx_buffer[2] not rx_buffer[0]

    As noted, the result is in rx_buffer[2], ie the 3rd byte not the first rx byte.

    Using Mode 3 probably works fine; maybe also try Mode 0:

    // Mode 3
        .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
                 SPI_MODE_CPOL | SPI_MODE_CPHA,
        .frequency = 125000,
    
    // Mode 0
        .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB,
        .frequency = 125000,

Reply Children
No Data
Related