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.

ADS1292R: problem with correct data acquisition

Part Number: ADS1292R
Other Parts Discussed in Thread: ADS1292

Tool/software:

Hello  Fellows,
I thinks a have a new problem, that i Think it is a clock communication problem in the SPI.

Maybe, can help me to solve it, under i share some pictures captured during the observation with digital analyzer.

the communication seems out of sync, this way the values not appear well represented. To my comunication I use a SMCLK with 12MHz, derived from the clock system, MCLK with a frequency of 24MHz. By this way  the SPI clock is 500KHz.

can anyone help me?

  • Hello Armando,

    Thank you for your post.

    Please take a look at our Bio-potential FAQ page on E2E for some helpful debug tips with ADS1292R. 500kHz SCLK is not a problem. It's difficult to understand what is being communicated in each frame based on the images provided. I suggest to capture one or two frames only (i.e. during a register read or write) and check the analyzer output.

    Regards,

    Ryan

  • Hi Ryan, 

    Thanks for your quick response, I share with you  the capture of one frame. 

    I have read all FAQ, and change my code to me appear to be a problem of power-up or  comunication timing. Additionally I share the code implemented to communicate with AFE, the device should work with AVDD = 3 V, and DVDD =1.8 V.

    main.c

    #include <msp432.h>
    #include <stdio.h>
    #include <stdbool.h>
    #include "cs.h"
    #include "uart.h"
    #include "spi.h"
    #include "delay.h"
    #include "ads1292r.h"
    
    #define LOW         0x00
    #define HIGH        0x01
    
    uint32_t DCO_FREQ;
    
    uint8_t read_ADS1292R = 0;
    extern uint8_t SPI_TX_BUFF[SPI_TX_BUFF_SIZE];
    extern uint8_t SPI_RXBUFF[SPI_RXBUFF_SIZE], SPI_RX_COUNT, SPI_RX_EXP_COUNT;
    volatile bool ADS1292R_RECEIVED_DATA = false;
    unsigned long uecgTemp = 0;
    signed long secgTemp = 0;
    volatile signed long s32DaqVals[8];
    uint8_t DataPacket[16];
    uint8_t dataLength = 8;
    
    void sendString(char *str);
    void set_uart(void);
    void set_gpio(void);
    void processData(void);
    
    
    void main(void){
        WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
        uint16_t i;
    
        set_gpio();                                     /*INITIALIZE GPIO*/
        clockSystem(FREQ_24_MHz);                       /*INITIALIZE CLOCK SYSTEM*/
    
        set_uart();                                     /*INITIALIZE UART*/
        set_spi();                                      /*INITIALIZE SPI*/
        set_ads1292r();                                 /*INITIALIZE ADS1292R*/
    
    
        /*ENABLE GLOBAL INTERRUPT*/
    
        NVIC->ISER[1] = 1 << ((PORT2_IRQn) & 31);       /*ENABLE PORT2 INTERRUPT IN NVIC MODULE*/
        NVIC->ISER[0] = 1 << ((EUSCIB0_IRQn) & 31);     /*ENABLE EUSCI_B0 INTERRUPT IN NVIC MODULE*/
        __enable_irq();
    
    
        while(1){
    
            /*VERIFY IF PIN IS LOW*/
            while ((P2->IN & BIT3) == 0x00) {
                read_ADS1292R = true;
                //setDeviceOutBytes();
            }
            if(ADS1292R_RECEIVED_DATA == true){
    
            }
        }
    }
    
    

    ads1292.c

    uint8_t SPI_TX_BUFF[SPI_TX_BUFF_SIZE];
    uint8_t SPI_RXBUFF[SPI_RXBUFF_SIZE], SPI_RX_COUNT = 0, SPI_RX_EXP_COUNT = 0;
    long ADS1292_ECG_DATA_BUFFER[6];
    extern uint8_t read_ADS1292R;
    extern volatile bool ADS1292R_RECEIVED_DATA;
    static volatile uint8_t RX_Data = 0;
    
    void set_ads1292r(void) {
        drdy_interruptsADS();
        _delay(1, 's');
        resetADS();
        _delay(100, 'm');
    
        start_disableADS();                             // Set START pin to LOW
        start_enableADS();                              // Set START pin to HIGH
        start_disableADS();                             // Set START pin to LOW
    
        hard_stopADS();
        _delay(10, 'm');
        start_data_convertionCMD();
        soft_stopADS();
        _delay(50, 'm');
    
        /*READ DATA IN CONTINUOUS MODE IS THE DEVICE DEFAULT MODE*/
        /*THE DEVICE GOES TO THIS MODE ON POWER-UP, BY DEFAULT*/
        stop_read_dataContinuous();
        _delay(300, 'm');
        /*INITIATE REGISTERS*/
    
        read_regsADS(0x00);
        register_writeADS(ADS1292_REG_CONFIG1, 0x02);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_CONFIG2, 0xE8);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_LOFF, 0xF0);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_CH1SET, 0x00);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_CH2SET, 0x00);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_RLDSENS, 0xAC);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_LOFFSENS, 0x0F);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_RESP1, 0xEA);
        _delay(10, 'm');
        register_writeADS(ADS1292_REG_RESP2, 0x07);
        _delay(10, 'm');
        start_read_dataContinuous();
        _delay(10, 'm');
      //  start_enableADS();
    
    }
    
    void resetADS(void) {
        P2->OUT |= BIT6;      // Drive reset pin HIGH
        _delay(100, 'm');
        P2->OUT &= ~(BIT6);     // Drive reset pin LOW
        _delay(100, 'm');
        P2->OUT |= BIT6;      // Drive reset pin HIGH
        _delay(100, 'm');      // Hold reset for 17 milliseconds
    }
    
    void drdy_interruptsADS(void) {
        P2->DIR &= ~(BIT3);                             /*SET P2.3 DRDY TO INPUT*/
        P2->OUT &= ~(BIT3);
        P2->REN |=   BIT3;
        P2->SEL0&= ~(BIT3);
        P2->SEL1&= ~(BIT3);
    
        P2->IE  |= BIT3;
        P2->IES &= ~(BIT3);
        P2->IFG &= ~(BIT3);
    
    }
    
    void clock_selectADS(uint8_t clock_in) {
        if (clock_in == 1) {
            P2->OUT |= BIT4;  // Choose internal clock
        } else {
            P2->OUT &= ~(BIT4); // Choose external clock
        }
    }
    
    void start_enableADS(void) {
        P2->OUT |= BIT5;  // Set START pin HIGH
        _delay(20, 'm');  // Wait for 25 microseconds
    }
    
    void start_disableADS(void) {
        P2->OUT &= ~BIT5; // Set START pin LOW
        _delay(20, 'm');  // Wait for 17 microseconds
    }
    
    void chip_enableADS(void) {
        P3->OUT |= BIT0;  // Set CS pin HIGH
    }
    
    void chip_disableADS(void) {
        P3->OUT &= ~BIT0; // Set CS pin LOW
    }
    
    void hard_stopADS(void) {
        P2->OUT &= ~BIT5; // Set START pin LOW
        _delay(35, 'm');  // Wait for 35 milliseconds
    }
    
    void start_data_convertionCMD(void) {
        spi_transmit(START_);
    }
    
    void stop_read_dataContinuous(void) {
        spi_transmit(SDATAC);
    }
    
    void start_read_dataContinuous(void) {
        spi_transmit(RDATAC);
    }
    
    void soft_stopADS(void) {
        spi_transmit(STOP_);
    }
    
    static void spi_transmit(uint8_t data) {
        chip_disableADS();
        _delay(1, 'm');
        chip_enableADS();
        _delay(1, 'm');
        chip_disableADS();
    
        EUSCI_B0->TXBUF = data;
        while (EUSCI_B0->STATW & EUSCI_B_STATW_BBUSY);
    
        _delay(2, 'm');
        chip_enableADS();
    }
    
    static uint8_t spi_receive(void) {
        EUSCI_B0->TXBUF = 0x00; // Send dummy byte to receive data
        while (EUSCI_B0->STATW & EUSCI_B_STATW_BBUSY);
    
        return EUSCI_B0->RXBUF;
    }
    
    void register_writeADS(uint8_t WRITE_ADDRESS, uint8_t DATA) {
        // Apply bit masks based on register address
        switch (WRITE_ADDRESS) {
            case 1:
                DATA &= 0x87;
                break;
            case 2:
                DATA &= 0xFB;
                DATA |= 0x80;
                break;
            case 3:
                DATA &= 0xFD;
                DATA |= 0x10;
                break;
            case 7:
                DATA &= 0x3F;
                break;
            case 8:
                DATA &= 0x5F;
                break;
            case 9:
                DATA |= 0x02;
                break;
            case 10:
                DATA &= 0x87;
                DATA |= 0x01;
                break;
            case 11:
                DATA &= 0x0F;
                break;
            default:
                break;
        }
    
        SPI_TX_BUFF[0] = WRITE_ADDRESS | WREG;
        SPI_TX_BUFF[1] = 0;
        SPI_TX_BUFF[2] = DATA;
    
        chip_disableADS();
        _delay(1, 'm');
        chip_enableADS();
        _delay(1, 'm');
        chip_disableADS();
        _delay(1, 'm');
    
        // Transmit command
        spi_transmit(SPI_TX_BUFF[0]);
        spi_transmit(SPI_TX_BUFF[1]);
        spi_transmit(SPI_TX_BUFF[2]);
    }
    
    uint8_t read_regsADS(uint8_t READ_ADDRESS) {
        SPI_TX_BUFF[0] = READ_ADDRESS | RREG;
        SPI_TX_BUFF[1] = 0;
    
        chip_disableADS();
        _delay(1, 'm');
        chip_enableADS();
        _delay(1, 'm');
        chip_disableADS();
    
        spi_transmit(SPI_TX_BUFF[0]);
        spi_transmit(SPI_TX_BUFF[1]);
        /*RECEIVE THE RESPONSE*/
        uint8_t response = spi_receive();
        /*ENSURE THE CHIP IS ENABLED AFTER  TRANSACTION*/
        chip_enableADS();
    
        return response;
    }
    
    void EUSCIB0_IRQHandler(void) {
        if (EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG) {
            RX_Data = EUSCI_B0->RXBUF;
            if (read_ADS1292R == true) {
                printf("Waiting for 2...\n");
                SPI_RXBUFF[SPI_RX_COUNT++] = RX_Data; // Store data
    
                if (SPI_RX_COUNT > SPI_RX_EXP_COUNT) {
                    SPI_RX_COUNT = 0;
                    ADS1292R_RECEIVED_DATA = true; // Set flag to indicate data received
                    read_ADS1292R = false;
                }
            }
            /* Delay between transmissions for slave to process information */
            _delay(50,'u');
        }
    }
    
    void PORT2_IRQHandler(void) {
        if (P2->IFG & BIT3) {
            P2->IFG &= ~(BIT3); // Clear the interrupt flag
            SPI_RX_COUNT = 0;
    
            EUSCI_B0->TXBUF = 0; // Send dummy byte
            EUSCI_B0->IE |= EUSCI_B_IE_RXIE; // Re-enable RX interrupt
        }
    }
    
    void setDeviceOutBytes(void) {
        SPI_RX_EXP_COUNT = 9; // Set the expected byte count
    }
    

    spi.c

  • Hello Armando,

    The ADS1292 expects CPOL = 0 and CPHA = 1, such that the trailing edge is used to capture the data. Your logic analyzer capture is showing the leading edge as the capture edge. Please check this configuration in your logic analyzer and your controller settings as well.

    Having said that, the first byte in the image above appears to be sending a WREG command to address 0x01, but I cannot see the rest of the frame (i.e. when nCS returns high). Have you been able to successfully write your register configuration and read back the configured settings?

    What's also concerning is the MISO line, which is toggling at a high frequency, much faster than your SCLK. Please check this connection.

    AVDD = 3 V and DVDD = 1.8 V is fine.

    Regards,

    Ryan

  • hello Ryan,
    I made some progress with the help of your colleagues in the microcontrollers forum.
    Now my MISO line seems to be better... however the result of the readings, they are always the same (0xFF)....

  • Hi Armando,

    Is something pulling the MISO line high, either on the PCB or through the MCU?

    Also, note that the WREG command 0x41 0x02 implies you are writing 3 consecutive registers, starting at address 01h. You will need to follow these two bytes with the register data you wish to write to each address, all in the same SPI frame. The data on MISO will not contain conversion results until:

    1. You finish writing the device registers and resume RDATAC mode
    2. Bring START high or send the START command

    Regards,

    Ryan