No data coming from ADS1298 after connecting the SPI with nRF52833.

Hi, I am working on a project where ECG data can be send wirelessly. For that I am using ADS1298 and nRF52833. I am very new to it. I have connected the nRF52833 SPI lines with the ADS1298. For power, since the DRDY was not falling when I used the power from nRF52833, I am using the MMB0 board by the ADS1298 ECG FE itself. Still I am not getting any output. I am not sure what I am not getting right. I can see the DRDY going low and coming back, the CS and SCLK are all working but there is no output from DOUT(MISO). What could be reasons? I saw some old queries about the issue and they are mentioning about the timing of CS. How to check that? I have also provided the code that I am using. 

#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_spi.h"
#include "nrf_drv_gpiote.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "app_error.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define PIN_SPI_SCK     36
#define PIN_SPI_MOSI    34
#define PIN_SPI_MISO    33
#define PIN_SPI_CS      35
#define PIN_DRDY        37
#define PIN_START       38
#define PIN_RESET       39

// -------------------- SPI and ADS constants --------------------
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);

#define ADS_FRAME_BYTES 27   // 3 status + 8 * 3 bytes

// ADS1298 commands
#define CMD_WAKEUP   0x02
#define CMD_STANDBY  0x04
#define CMD_RESET    0x06
#define CMD_START    0x08
#define CMD_STOP     0x0A
#define CMD_RDATAC   0x10
#define CMD_SDATAC   0x11
#define CMD_RDATA    0x12

// -------------------- globals --------------------
static volatile bool drdy_flag = false;

// -------------------- low-level helpers --------------------
// Manual CS control (we will initialize SPI with ss_pin = NOT_USED)
static inline void cs_low(void)  { nrf_gpio_pin_clear(PIN_SPI_CS); }
static inline void cs_high(void) { nrf_gpio_pin_set(PIN_SPI_CS);  }

// send a single-command (CS low, send byte, CS high)
static void ads_cmd(uint8_t cmd)
{
    cs_low();
    ret_code_t rc = nrf_drv_spi_transfer(&spi, &cmd, 1, NULL, 0);
    APP_ERROR_CHECK(rc);
    cs_high();
    nrf_delay_us(2);
}

// write single register (WREG reg, count=0)
static void ads_write_reg(uint8_t reg, uint8_t val)
{
    uint8_t buf[3];
    buf[0] = 0x40 | (reg & 0x1F); // WREG
    buf[1] = 0x00;                // write 1 register (N-1)
    buf[2] = val;

    cs_low();
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, buf, 3, NULL, 0));
    cs_high();
    nrf_delay_us(2);
}

// read single register (RREG reg, count=0)
static uint8_t ads_read_reg(uint8_t reg)
{
    uint8_t hdr[2];
    uint8_t val = 0;
    hdr[0] = 0x20 | (reg & 0x1F); // RREG
    hdr[1] = 0x00;                // read 1

    cs_low();
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, hdr, 2, NULL, 0));
    nrf_delay_us(2);
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, NULL, 0, &val, 1));
    cs_high();
    return val;
}

// -------------------- DRDY handler --------------------
static void drdy_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    (void)pin; (void)action;
    drdy_flag = true; // signal main loop to read frame
}

static void drdy_init(void)
{
    if (!nrf_drv_gpiote_is_init()) APP_ERROR_CHECK(nrf_drv_gpiote_init());
    nrf_drv_gpiote_in_config_t in_cfg = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); // falling edge
    in_cfg.pull = NRF_GPIO_PIN_PULLUP;
    APP_ERROR_CHECK(nrf_drv_gpiote_in_init(PIN_DRDY, &in_cfg, drdy_handler));
    nrf_drv_gpiote_in_event_enable(PIN_DRDY, true);
}

// -------------------- ADS1298 init sequence --------------------
static void ads1298_init_sequence(bool test_mode)
{
    // Ensure chip not in RDATAC (stop continuous read so registers writable)
    ads_cmd(CMD_SDATAC);
    nrf_delay_ms(2);

    // Disable lead-off detection (LOFF)
    ads_write_reg(0x04, 0x00); // LOFF
    ads_write_reg(0x0F, 0x00); // LOFF_SENSP
    ads_write_reg(0x10, 0x00); // LOFF_SENSN
    ads_write_reg(0x11, 0x00); // LOFF_FLIP
    // Optionally LOFF_STATP/LOFF_STATN etc left default

    // CONFIG registers
    // CONFIG1: set 500 SPS, HR mode if you want
    // Use 0x86 was used earlier by you (HR mode, 500SPS). If needed use 0x02 (regular mode, 500SPS).
    ads_write_reg(0x01, 0x86); // CONFIG1 = 0x86 (HR, 500 SPS)

    if (test_mode) {
        // CONFIG2: enable internal test signal
        // 0xD3 is a common value used earlier: bits to enable test and internal signal type
        ads_write_reg(0x02, 0xD3);
    } else {
        ads_write_reg(0x02, 0x10); // CONFIG2 normal
    }

    ads_write_reg(0x03, 0xDC); // CONFIG3 typical (ref buffer on etc)

    // Enable channels: CH1..CH8
    // 0x00 = normal electrode input enabled
    // If test_mode, route CH1 to test input (0x05)
    for (uint8_t ch = 0; ch < 8; ++ch) {
        uint8_t addr = 0x05 + ch;
        if (test_mode && ch == 0) {
            ads_write_reg(addr, 0x05); // CH1 test signal
        } else {
            ads_write_reg(addr, 0x00); // normal electrode input, not power-down
        }
    }

    // Done: restart continuous read and start conversions
    ads_cmd(CMD_RDATAC);
    nrf_delay_ms(1);
    ads_cmd(CMD_START);
    nrf_delay_ms(1);
}

// -------------------- Frame read helper --------------------
static inline int32_t s24_to_s32(const uint8_t *b)
{
    int32_t v = ((int32_t)b[0] << 16) | ((int32_t)b[1] << 8) | ((int32_t)b[2]);
    if (v & 0x00800000) v |= 0xFF000000; // sign extend
    return v;
}

// -------------------- Main --------------------
int main(void)
{
    // Init logging
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("ADS1298 nRF52833 example starting...");
    NRF_LOG_FLUSH();

    // Configure control GPIOs
    nrf_gpio_cfg_output(PIN_SPI_CS);
    nrf_gpio_cfg_output(PIN_START);
    nrf_gpio_cfg_output(PIN_RESET);
#ifdef PIN_PWDN
    nrf_gpio_cfg_output(PIN_PWDN);
    nrf_gpio_pin_set(PIN_PWDN); // enable device
#endif

    // Idle states
    nrf_gpio_pin_set(PIN_SPI_CS);   // CS high (inactive)
    nrf_gpio_pin_set(PIN_START);    // START high (enable conversions)
    nrf_gpio_pin_set(PIN_RESET);    // keep reset high initially

    // Reset pulse
    nrf_gpio_pin_clear(PIN_RESET);
    nrf_delay_ms(5);
    nrf_gpio_pin_set(PIN_RESET);
    nrf_delay_ms(20);

    // Init SPI (manual CS)
    nrf_drv_spi_config_t spi_cfg = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_cfg.ss_pin = NRF_DRV_SPI_PIN_NOT_USED;
    spi_cfg.sck_pin = PIN_SPI_SCK;
    spi_cfg.mosi_pin = PIN_SPI_MOSI;
    spi_cfg.miso_pin = PIN_SPI_MISO;
    spi_cfg.frequency = NRF_DRV_SPI_FREQ_1M; // you can lower to 125k for debugging
    spi_cfg.mode = NRF_DRV_SPI_MODE_1;
    spi_cfg.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_cfg, NULL, NULL));

    // Setup DRDY interrupt
    drdy_init();

    // Quick ID check: stop RDATAC and read ID register
    ads_cmd(CMD_SDATAC);
    nrf_delay_ms(2);
    uint8_t id = ads_read_reg(0x00);
    NRF_LOG_INFO("ADS1298 ID = 0x%02X", id);
    NRF_LOG_FLUSH();

    // Choose mode here: true = internal test signal; false = ECG electrode mode
    bool test_mode = true; // <-- change as needed

    if ((id & 0xF0) == 0x90 || id != 0x00) {
        NRF_LOG_INFO("ADS seems present, configuring...");
        ads_init_sequence(test_mode);
    } else {
        NRF_LOG_ERROR("ADS not responding. Check power, PWDN, CLKSEL, reset, wiring.");
    }

    // Buffers for frame read
    uint8_t tx[ADS_FRAME_BYTES];
    uint8_t rx[ADS_FRAME_BYTES];

    // main loop: wait for drdy_flag and read a frame
    while (1) {
        if (drdy_flag) {
            drdy_flag = false;

            // Perform full-frame SPI transfer (CS manual)
            for (size_t i=0;i<ADS_FRAME_BYTES;i++) tx[i] = 0xFF; // dummy bytes to clock out data

            cs_low();
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx, ADS_FRAME_BYTES, rx, ADS_FRAME_BYTES));
            cs_high();

            // Parse channels: status bytes are rx[0..2], channels start at rx[3]
            int32_t ch[8];
            for (int i = 0; i < 8; ++i) {
                ch[i] = s24_to_s32(&rx[3 + i*3]);
            }

            // Log channels (coarse)
            NRF_LOG_INFO("CH: %d,%d,%d,%d,%d,%d,%d,%d",
                (int)ch[0], (int)ch[1], (int)ch[2], (int)ch[3],
                (int)ch[4], (int)ch[5], (int)ch[6], (int)ch[7]);
            NRF_LOG_FLUSH();
        }
        
        __WFE();
    }
}
  

Parents Reply Children
No Data
Related