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.

ADS1299 RDATAC mode setup problem.

Other Parts Discussed in Thread: ADS1299, MSP430F5510

Hi Everyone,

I am using MSP430F5510 SPI to control ADS1299, set it in RDATAC mode, read data and send through USB to PC.

After setup ADS1299 I can only test DRDY signal and I can not test sclk(0) and somi(DVdd). So I doubt that I made some mistake on setup part

Below I list part of my code for the ADS1299 setup.

Thank you for the help.

int TX_START[2] = {8,16}; // the order is: start->rdatac

int TX_WREG[28]= {17,65,24,212,192,228,0,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,15,0,0,0,0,0};
// 17 is opcode for SDATAC, 65 is the memory address for CONFIG1 (Starts writing registers at that point)
//and 24 is (n-1) number of registers to be written (so we are writing 25 registers, starting at CONFIG1)
//212(0xD4 for 1k sps, disable osc output and standart mode), 192(0xC0 for config2),
//228(0xE4) for conifg3 get externally biasref
//7(gain = 1 for all 8 chs), 15(0x0F for GPIO set)

void power_up(void)
{
uint8_t i;

// ADS1299 power up*************************************************************************//

GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET high
__delay_cycles(4000000);//1 second delay
// RESET pulse
GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET low
__delay_cycles(100);//at least two cycles delay
GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET high
//Wait for slave to initialize
__delay_cycles(100); // at least 18clk delay
// Finish power up **************************************************************************//

// Send opcode to program configration register
GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);//ensable /CS0

for (i=0; i<28; i++)
{
//USCI_A1 TX buffer ready?
while(!USCI_A_SPI_getInterruptStatus(USCI_A1_BASE,
USCI_A_SPI_TRANSMIT_INTERRUPT));

//Transmit Data to slave
USCI_A_SPI_transmitData(USCI_A1_BASE, TX_WREG[i]);
__delay_cycles(32);//must wait for at least 4clk between two opcode
}

GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
}

void send_spi_start(void)
// 1. This command sends RREG opcode to the ADS1299 to read register values
{
uint8_t i;

GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);//ensable /CS0

for (i=0; i<2; i++)
{
//USCI_A1 TX buffer ready?
while(!USCI_A_SPI_getInterruptStatus(USCI_A1_BASE,
USCI_A_SPI_TRANSMIT_INTERRUPT));

//Transmit Data to slave
USCI_A_SPI_transmitData(USCI_A1_BASE, TX_START[i]);
__delay_cycles(32);//must wait for at least 4clk between two opcode
}

//GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
}

void send_spi_rdatac (void)
{
uint8_t i;

// Initialize variables //
stop=0;

// Send start opcode
send_spi_start();

// Start RDATAC loop //
while(!stop)
{
// // step 1 - wait for DRDY0

while (!GPIO_getInputPinValue( GPIO_PORT_P1, GPIO_PIN1));

// // step 2 - Read from ADS0
GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0); //enable ADS1299_0

for(i=0; i<27; i++)
{
DOUT[i] = USCI_A_SPI_receiveData(USCI_A1_BASE);
//DOUT[i] = DOUT[i]+0x21;
}

//Send data
USBCDC_sendDataInBackground(DOUT,27,CDC0_INTFNUM,1); 

}

  • Hey Jerry,

    Can you send over a schematic as well as scope captures of the part in the communications that is not working properly?

    Regards,
    Brian Pisani
  • Hi, Brian,

    Please see the schematic in the attachment and for the scope capture I am not quite clear about your meaning. I put my whole code in the attachment too.

    In the schematic there are two ADS1299 and  I just use one. D_EEG16K.schMainBrd_02I.sch

    Thank you for your help.

    //******************************************************************************
    //   MSP430F5510:  RDATACV2.0
    //
    //   Description:  Demonstrates simple sending data continuouly using ADS1299_0
    //
    //   Problem:
    //
    //   Jerry.
    //   08/16/16
    //******************************************************************************
    
    #include <string.h>
    
    #include "driverlib.h"
    
    #include "USB_config/descriptors.h"
    #include "USB_API/USB_Common/device.h"
    #include "USB_API/USB_Common/usb.h"                 // USB-specific functions
    #include "USB_API/USB_CDC_API/UsbCdc.h"
    #include "USB_app/usbConstructs.h"
    
    #include "hal.h"
    
    // SPI init
    void MySPIinit (void);
    void send_spi_rdatac(void);
    void power_up(void);
    void send_spi_start(void);
    uint8_t CheckIfUSBStop(void);
    
    // Global variables
    #define SPICLK 1000000 // first set 500000 and change to 8000000
    
    // Global flags set by events
    volatile uint8_t bCDCDataReceived_event = FALSE; // Indicates data has been rx'ed
                                                  // without an open rx operation
    #define MAX_STR_LENGTH 64
    
    // Holds the new addition to the string
    char pieceOfString[MAX_STR_LENGTH] = "";
    
    // Holds the outgoing string
    char outString[MAX_STR_LENGTH] = "";
    
    uint8_t returnValue = 0x00;
    uint8_t stamp0=0, stamp1=0, stamp2=0;
    
    // 1datapackage(57bytes) = counter(3) + data1(3+24) + data2(3+24);
    #define DATA_LENGTH 30
    
    //DATA to PC through USB
    uint8_t DOUT[DATA_LENGTH];
    
    char TxString,RxString;
    int stop,dummy;
    
    int TX_START[2] = {8,16}; // the order is: start->rdatac
    
    int TX_WREG[28]= {17,65,24,212,192,228,0,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,15,0,0,0,0,0};
    // 17 is opcode for SDATAC, 65 is the memory address for CONFIG1 (Starts writing registers at that point)
    //and 24 is (n-1) number of registers to be written (so we are writing 25 registers, starting at CONFIG1)
    //212(0xD4 for 1k sps, disable osc output and standart mode), 192(0xC0 for config2),
    //228(0xE4) for conifg3 get externally biasref
    //7(gain = 1 for all 8 chs), 15(0x0F for GPIO set)
    
    /***************************************
     * ======== main ========
     ***************************************/
    void main (void)
    {
        WDT_A_hold(WDT_A_BASE); // Stop watchdog timer
    
        __disable_interrupt();               // Disable global interrupts
        // Minumum Vcore setting required for the USB API is PMM_CORE_LEVEL_2 .
        PMM_setVCore(PMM_CORE_LEVEL_2);
        USBHAL_initPorts();           // Config GPIOS for low-power (output low)
        USBHAL_initClocks(8000000);   // Config clocks. MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
        MySPIinit();          // Init the SPI
        __enable_interrupt();  // Enable interrupts globally. and this is very important
    
        USB_setup(TRUE, TRUE); // Init USB & events; if a host is present, connect
    
        //P1.1 for /DRDY0
        GPIO_setAsInputPinWithPullUpResistor( GPIO_PORT_P1, GPIO_PIN1 );  // setup as input
    
        power_up();
    
    	 while (1)
    	{
    		// Check the USB state and directly main loop accordingly
    		 switch (USB_getConnectionState())
    		{
    			case ST_ENUM_ACTIVE:
    				// If true, some data is in the buffer; begin receiving a cmd
    				if (bCDCDataReceived_event)
    				{
    					// Add bytes in USB buffer to the string
    					USBCDC_receiveDataInBuffer((uint8_t*)pieceOfString,
    						MAX_STR_LENGTH,
    						CDC0_INTFNUM); // Get the next piece of the string
    
    					//******************************************************************************************************************
    					// Compare to string #1, and respond
    					if (!(strcmp(pieceOfString, "s")))
    					{
    						send_spi_rdatac();
    					}
    					bCDCDataReceived_event = FALSE;
    					//******************************************************************************************************************
    				}
    				break;
    
    			case ST_PHYS_DISCONNECTED:
    			case ST_ENUM_SUSPENDED:
    			case ST_PHYS_CONNECTED_NOENUM_SUSP:
    				__bis_SR_register(LPM3_bits + GIE);
    				_NOP();
    				break;
    			case ST_ENUM_IN_PROGRESS:
    			default:;
    		}
    	}  // while(1)
    } // main()
    
    void send_spi_start(void)
    // 1. This command sends RREG opcode to the ADS1299 to read register values
    {
    	uint8_t i;
    
    	GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);//ensable /CS0
    	//GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN2); //disable /CS1
    
    	for (i=0; i<2; i++)
    	{
    		//USCI_A1 TX buffer ready?
    		while(!USCI_A_SPI_getInterruptStatus(USCI_A1_BASE,
    				USCI_A_SPI_TRANSMIT_INTERRUPT));
    
    		//Transmit Data to slave
    		USCI_A_SPI_transmitData(USCI_A1_BASE, TX_START[i]);
    		__delay_cycles(32);//must wait for at least 4clk between two opcode
    	}
    
    	GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
    }
    
    void send_spi_rdatac (void)
    {
    	uint8_t i;
    
    	// Initialize variables //
        stop=0;
    
        // Send start opcode
        send_spi_start();
    
    	// Start RDATAC loop //
    	while(!stop)
    	{
    		//  step 1 - wait for DRDY0
    		while (!GPIO_getInputPinValue( GPIO_PORT_P1, GPIO_PIN1));
    		//  step 2 - Read from ADS0
    		//  step 2.1 - enable CS0
    		GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0); //enable ADS1299_0
    
    		for(i=0; i<27; i++)
    		{
    			DOUT[i+3] = USCI_A_SPI_receiveData(USCI_A1_BASE);
    			//DOUT[i+3] = DOUT[i+3]+0x21;
    		}
    
    		//If Counter is Enabled, add the time stamp; Counter is always first 3 bytes
    		DOUT[0]=stamp0;
    		DOUT[1]=stamp1;
    		DOUT[2]=stamp2;
    		//If counter increment data
    		if(stamp2==255)
    		{
    			if(stamp1==255)
    			{
    				stamp0++;
    			}
    			stamp1++;
    		}
    		stamp2++;
    		//Send data
    		USBCDC_sendDataInBackground(DOUT,30,CDC0_INTFNUM,1); // 30 = 3bytes counter +3bytes status + 24bytes data
    
    		//check stop cmd
    		if (CheckIfUSBStop())
    		{
    			stop = 1;
    			//Send_SPI_SDATAC();
    		}
    
    		GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
    	} // End of RDATAC [while(!stop)] Loop
    }
    
    uint8_t CheckIfUSBStop(void)
    {
    	if (!USBCDC_receiveDataInBuffer((uint8_t*)pieceOfString,1,0)) // Get the next piece of the string)
    	{
    		return (!strcmp(pieceOfString, "p"));
    	}
    	return 0;
    }
    
    /* ADS1299 Power up */
    void power_up(void)
    {
    	uint8_t i;
    
    	GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
    
    	// ADS1299 power up*************************************************************************//
    	GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET high
    	__delay_cycles(4000000);//1 second delay
    	// RESET pulse
    	GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET low
    	__delay_cycles(100);//at least two cycles delay
    	GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); // /RESET high
    	//Wait for slave to initialize
    	__delay_cycles(100); // at least 18clk delay
    	// Finish power up **************************************************************************//
    
    	// Send opcode to program configration register
    	GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);//ensable /CS0
    	GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN2); //disable /CS1
    
    	for (i=0; i<28; i++)
    	{
    		//USCI_A1 TX buffer ready?
    		while(!USCI_A_SPI_getInterruptStatus(USCI_A1_BASE,
    				USCI_A_SPI_TRANSMIT_INTERRUPT));
    
    		//Transmit Data to slave
    		USCI_A_SPI_transmitData(USCI_A1_BASE, TX_WREG[i]);
    		__delay_cycles(32);//must wait for at least 4clk between two opcode
    	}
    
    	GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); //disable /CS0
    }
    
    /* SPI init*/
    void MySPIinit(void)
    {
    	GPIO_setAsPeripheralModuleFunctionInputPin(
    		  GPIO_PORT_P4,
    		  GPIO_PIN0 + GPIO_PIN4 + GPIO_PIN5
    		  );
    
    	//Initialize Master
    	USCI_A_SPI_initMasterParam param = {0};
    	param.selectClockSource = USCI_A_SPI_CLOCKSOURCE_SMCLK;
    	param.clockSourceFrequency = UCS_getSMCLK();
    	param.desiredSpiClock = SPICLK;
    	param.msbFirst = USCI_A_SPI_MSB_FIRST;
    	param.clockPhase = USCI_A_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
    	param.clockPolarity = USCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
    	returnValue = USCI_A_SPI_initMaster(USCI_A1_BASE, &param);
    
    	if(STATUS_FAIL == returnValue)
    	{
    		return;
    	}
    
    	//Enable SPI module
    	USCI_A_SPI_enable(USCI_A1_BASE);
    
    	//Wait for slave to init
    	__delay_cycles(100);
    
    	//Initialize and Setup DMA Channel 0
    	/*
    	 * Configure DMA channel 0
    	 * Configure channel for single transfer
    	 * DMA transfers will be disabled and interrupt flag will be set after every
    	 *   1 transfer
    	 * Use DMA Trigger Source 21 (UCA1TXIFG)
    	 * Transfer Byte-to-byte
    	 * Trigger transfer on signal held high
    	 */
    	DMA_initParam param0 = {0};
    	param0.channelSelect = DMA_CHANNEL_0;
    	param0.transferModeSelect = DMA_TRANSFER_SINGLE;
    	param0.transferSize = 1;
    	param0.triggerSourceSelect = DMA_TRIGGERSOURCE_21;
    	param0.transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE;
    	param0.triggerTypeSelect = DMA_TRIGGER_HIGH;
    	DMA_init(&param0);
    	/*
    	 * Configure DMA channel 0
    	 * Use TxString as source
    	 * Increment source address after every transfer
    	 */
    	DMA_setSrcAddress(DMA_CHANNEL_0,
    					  (uint32_t)&TxString,
    					  DMA_DIRECTION_INCREMENT);
    	/*
    	 * Configure DMA channel 0
    	 * Use SPI TX Buffer as destination
    	 * Don't move the destination address after every transfer
    	 */
    	DMA_setDstAddress(DMA_CHANNEL_0,
    					  USCI_A_SPI_getTransmitBufferAddressForDMA(USCI_A1_BASE),
    					  DMA_DIRECTION_UNCHANGED);
    
    	//Initialize and Setup DMA Channel 1
    	/*
    	 * Configure DMA channel 1
    	 * Configure channel for single transfer
    	 * DMA transfers will be disabled and interrupt flag will be set after every
    	 *   1 transfer
    	 * Use DMA Trigger Source 20 (UCA1RXIFG)
    	 * Transfer Byte-to-byte
    	 * Trigger transfer on signal held high
    	 */
    
    	DMA_initParam param1 = {0};
    	param1.channelSelect = DMA_CHANNEL_1;
    	param1.transferModeSelect = DMA_TRANSFER_SINGLE;
    	param1.transferSize = 1;
    	param1.triggerSourceSelect = DMA_TRIGGERSOURCE_20;
    	param1.transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE;
    	param1.triggerTypeSelect = DMA_TRIGGER_HIGH;
    	DMA_init(&param1);
    
    	/*
    	 * Configure DMA channel 1
    	 * Use SPI RX Buffer as source
    	 * Don't move the source address after every transfer
    	 */
    	DMA_setSrcAddress(DMA_CHANNEL_1,
    					  USCI_A_SPI_getReceiveBufferAddressForDMA(USCI_A1_BASE),
    					  DMA_DIRECTION_UNCHANGED);
    	/*
    	 * Configure DMA channel 1
    	 * Use RxString as destination
    	 * Increment destination address after every transfer
    	 */
    	DMA_setDstAddress(DMA_CHANNEL_1,
    					  (uint32_t)&RxString,
    					  DMA_DIRECTION_INCREMENT);
    
    	//Clear TxString && RxString
    	TxString = RxString = 0;
    }
    
    /*
     * ======== UNMI_ISR ========
     */
    #if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
    #pragma vector = UNMI_VECTOR
    __interrupt void UNMI_ISR (void)
    #elif defined(__GNUC__) && (__MSP430__)
    void __attribute__ ((interrupt(UNMI_VECTOR))) UNMI_ISR (void)
    #else
    #error Compiler not found!
    #endif
    {
        switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG))
        {
            case SYSUNIV_NONE:
                __no_operation();
                break;
            case SYSUNIV_NMIIFG:
                __no_operation();
                break;
            case SYSUNIV_OFIFG:
                UCS_clearAllOscFlagsWithTimeout(0);
                SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);
                break;
            case SYSUNIV_ACCVIFG:
                __no_operation();
                break;
            case SYSUNIV_BUSIFG:
                // If the CPU accesses USB memory while the USB module is
                // suspended, a "bus error" can occur.  This generates an NMI, and
                // execution enters this case.  This should never occur.  If USB is
                // automatically disconnecting in your software, set a breakpoint
                // here and see if execution hits it.  See the Programmer's
                // Guide for more information.
                SYSBERRIV = 0; // Clear bus error flag
                USB_disable(); // Disable USB -- USB must be reset after a bus error
        }
    }
    

  • Hey Jerry,

    Could you post PDF versions of your schematic documents? Altium files tend to get corrupted when posted to e2e for some reason.

    I am referring to a picture taken of an oscilloscope that is capturing the SPI signals during the transaction that is not working properly.

    Regards,
    Brian Pisani
  • Hi, I put the image of the schematic in the attachment cause eagle seems does not have the PDF option. 

    To the osiliscope image of this part communication, I can only get sclk as gnd and somi and DVDD.