Other Parts Discussed in Thread: ADS1258,
Tool/software:
I used the ADS1258 EVM software to verify the ADC output values for known input voltages and prepared an Excel table as shown below. Could you please check if the formulae I used are correct?
Now, instead of the PGA/EVM board, I have interfaced the ADS1258 with a TMS320F28379D controller. When I apply 0 V at AIN0, the oscilloscope shows that the hex code read is 0x9595EFCECF
. Considering only the last 3 bytes (0xEFCECF
), the calculated voltage is −0.316 and expected should be close to −2.24 V, but I am not getting the expected result. I have also attached my code. Can you please review and tell me what exactly might be wrong?
Input Voltage | Hex (24-bit) | Unsigned (dec) | Signed (dec) | Formula used | VINV_{IN} (V) | Actual AIN0 (V) |
---|---|---|---|---|---|---|
3.3 V | 0x26054B | 2,491,723 | +2,491,723 | IN = (Code / 2^23) × VREF | 0.7426 | 0.7426 + VREF |
0 V (GND) | 0x8CFABD | 9,239,229 | 9,239,229 − 16,777,216 = −7,537,987 | If u ≥ 2^23 → s = u − 2^24, then IN = (s / 2^23) × VREF | −2.2465 | −2.2465 + VREF |
"F28x_Project.h" #include "ADS1258.h" /* Initialize arrays */ uint8_t DataTx[5] = { 0 }; uint8_t DataRx[5] = { 0 }; uint8_t regVal ; uint8_t data[]; uint8_t dataRx,dataPosition,byteLength; int count; int EPWM1_TIMER_TBPRD,EPWM1_MAX_CMPA,EPWM1_MIN_CMPA,EPWM1_CMP_UP,EPWM1_CMP_DOWN; // Period register static uint8_t registerMap[NUM_REGISTERS]; int i; int32_t dataValues[5]; uint8_t writeValues[7], statusBytes[5]; int32_t upperByte,middleByte,lowerByte; void main(void) { // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the F2837xD_SysCtrl.c file. InitSysCtrl(); // Step 2. Initialize GPIO: // This example function is found in the F2837xD_Gpio.c file and // illustrates how to set the GPIO to it's default state. // Setup only the GPIO only for SPI-A functionality // This function is found in F2837xD_Spi.c InitSpiaGpio(); InitADS1258Gpio(); // Enable PWM1, PWM6 CpuSysRegs.PCLKCR2.bit.EPWM1=1; // For this case just init GPIO pins for ePWM1, ePWM2, ePWM3 // These functions are in the F2837xD_EPwm.c file InitEPwm1Gpio(); // Step 3. Clear all interrupts: DINT; // // Initialize PIE control registers to their default state. // The default state is all PIE __interrupts disabled and flags // are cleared. // This function is found in the F2837xD_PieCtrl.c file. InitPieCtrl(); // Disable CPU __interrupts and clear all CPU __interrupt flags: IER = 0x0000; IFR = 0x0000; // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // This will populate the entire table, even if the __interrupt // is not used in this example. This is useful for debug purposes. // The shell ISR routines are found in F2837xD_DefaultIsr.c. // This function is found in F2837xD_PieVect.c. InitPieVectTable(); // Enable global Interrupts and higher priority real-time debug events: IER = M_INT1 |M_INT3 | M_INT8 ; // For ADCA0,EPWM1 and for SCIC_RX EPWM1_TIMER_TBPRD=2; // Period register EPWM1_MAX_CMPA=1; EPWM1_MIN_CMPA=1; EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; EDIS; InitEPwm1Example(); EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS; //worktime start PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // Step 4. Initialize the Device Peripherals: spi_fifo_init(); // Initialize the SPI FIFO // Step 5. User specific code: adcStartupRoutine(); for(;;) { readSingleRegister(0x02); DELAY_US(10000); DELAY_US(10000); DELAY_US(10000); // Wait and check that /DRDY interrupt occurred // b_pass &= waitForDRDYinterrupt(10); // Read data in read direct mode dataValues[i] = readData(&statusBytes[i], NULL, DIRECT); DELAY_US(10000); } } void adcStartupRoutine(void) { /* (OPTIONAL) Provide additional delay time for power supply settling */ DELAY_US(50000); /* (REQUIRED) Set nRESET/nPWDN pin high for ADC operation */ GpioDataRegs.GPBCLEAR.bit.GPIO52 = 1; // PWDN low DELAY_US(100); GpioDataRegs.GPBSET.bit.GPIO52 = 1; // PWDN high DELAY_US(10000); /* (REQUIRED) tWAKE delay */ DELAY_US(5000); /* (OPTIONAL) Toggle nRESET pin to assure default register settings. */ /* NOTE: This also ensures that the device registers are unlocked. */ GpioDataRegs.GPDCLEAR.bit.GPIO97 = 1; // RESET low DELAY_US(1000); GpioDataRegs.GPDSET.bit.GPIO97 = 1; // RESET high DELAY_US(3000); GpioDataRegs.GPCSET.bit.GPIO67 = 1; // START high } uint8_t spiSendReceiveByte(uint8_t dataTx) { // Wait until the transmit buffer is empty while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1); // Write data to the transmit buffer SpiaRegs.SPITXBUF =dataTx << 8; // Upper byte used dataRx = SpiaRegs.SPIRXBUF << 8; } uint8_t spiSendReceiveByte1(uint8_t dataTx) { // Wait until the transmit buffer is empty while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1); // Write data to the transmit buffer SpiaRegs.SPITXBUF =dataTx << 8; // Upper byte used dataRx = SpiaRegs.SPIRXBUF << 8; return dataRx; } void spiSendReceiveArrays(uint8_t DataTx[], uint8_t DataRx[], uint8_t byteLength) { /* Set the nCS pin LOW */ GpioDataRegs.GPBCLEAR.bit.GPIO61 = 1; // CS LOW spiSendReceiveByte(DataTx[0]); spiSendReceiveByte(DataTx[1]); DELAY_US(10); GpioDataRegs.GPBSET.bit.GPIO61 = 1; // CS HIGH } void spiSendReceiveArrays1(uint8_t DataTx[], uint8_t DataRx[], uint8_t byteLength) { /* Set the nCS pin LOW */ GpioDataRegs.GPBCLEAR.bit.GPIO61 = 1; //CS LOW for (i = 0; i < 5; i++) { DataRx[i] = spiSendReceiveByte1(DataTx[i]); } DELAY_US(1000); GpioDataRegs.GPBSET.bit.GPIO61 = 1; //CS HIGH } void spi_fifo_init() { // // Initialize SPI FIFO registers // SpiaRegs.SPIFFTX.all = 0xE040; SpiaRegs.SPIFFRX.all = 0x2044; SpiaRegs.SPIFFCT.all = 0x0; // // Initialize core SPI registers // InitSpi(); } void InitADS1258Gpio(void) { EALLOW; GpioCtrlRegs.GPBMUX2.bit.GPIO52 = 0; // GPIO80 as GPIO GpioCtrlRegs.GPBDIR.bit.GPIO52 = 1; // Output (PWDN) GpioCtrlRegs.GPDMUX1.bit.GPIO97 = 0; // GPIO84 as GPIO GpioCtrlRegs.GPDDIR.bit.GPIO97 = 1; // Output (RESET) GpioCtrlRegs.GPCMUX1.bit.GPIO67 = 0; // GPIO4 as GPIO GpioCtrlRegs.GPCDIR.bit.GPIO67 = 1; // Output (START) GpioCtrlRegs.GPBMUX2.bit.GPIO61 = 0; // GPIO4 as GPIO GpioCtrlRegs.GPBDIR.bit.GPIO61 = 1; // Output (CS) GPIO_SetupPinMux(22, GPIO_MUX_CPU1, 0); // GPIO22 as GPIO GPIO_SetupPinOptions(22, GPIO_INPUT, 0); // Input, no pullup/down EDIS; } uint8_t readSingleRegister(uint8_t address) { /* Build TX array and send it */ DataTx[0] = OPCODE_RREG | (address & OPCODE_A_MASK); spiSendReceiveArrays(DataTx, DataRx, 2); } void InitEPwm1Example() { // // Setup TBCLK // EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD; // Set timer period EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0 EPwm1Regs.TBCTR = 0x0000; // Clear counter EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // // Setup shadow register load on ZERO // EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // // Set Compare values // EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA; // Set compare A value // // Set actions // EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Set PWM1A on Zero EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clear PWM1A on event A, // // Interrupt where we will change the Compare Values // EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 3rd event } int32_t readData(uint8_t status[], uint8_t data[], readMode mode) { DataTx[0] = OPCODE_READ_COMMAND | OPCODE_MUL_MASK; dataPosition = 2; byteLength=5; spiSendReceiveArrays1(DataTx, DataRx, byteLength); data[0] = DataRx[dataPosition + 0]; data[1] = DataRx[dataPosition + 1]; data[2] = DataRx[dataPosition + 2]; int32_t signByte; if (DataRx[dataPosition] & 0x80u) { signByte = 0xFF000000; } else { signByte = 0x00000000; } upperByte = ((int32_t) DataRx[dataPosition + 0] & 0xFF) << 16; middleByte = ((int32_t) DataRx[dataPosition + 1] & 0xFF) << 8; lowerByte = ((int32_t) DataRx[dataPosition + 2] & 0xFF) << 0; return (signByte | upperByte | middleByte | lowerByte); } uint8_t getRegisterValue(uint8_t address) { assert(address < NUM_REGISTERS); return registerMap[address]; } void InitSpi(void) { // Initialize SPI-A // Set reset low before configuration changes // Clock polarity (0 == rising, 1 == falling) // 16-bit character // Enable loop-back SpiaRegs.SPICCR.bit.SPISWRESET = 0; SpiaRegs.SPIPRI.bit.TRIWIRE = 0; SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; SpiaRegs.SPICCR.bit.SPICHAR = 7; SpiaRegs.SPICCR.bit.SPILBK = 0; // Enable master (0 == slave, 1 == master) // Enable transmission (Talk) // Clock phase (0 == normal, 1 == delayed) // SPI interrupts are disabled SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; SpiaRegs.SPICTL.bit.TALK = 1; SpiaRegs.SPICTL.bit.CLK_PHASE = 1; SpiaRegs.SPICTL.bit.SPIINTENA = 0; // Set the baud rate SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = 24; // Set FREE bit // Halting on a breakpoint will not halt the SPI SpiaRegs.SPIPRI.bit.FREE = 1; // Release the SPI from reset SpiaRegs.SPICCR.bit.SPISWRESET = 1; } void InitSpiGpio() { InitSpiaGpio(); } // // InitSpiaGpio - Initialize SPIA GPIOs // void InitSpiaGpio() { EALLOW; // // Enable internal pull-up for the selected pins // // Pull-ups can be enabled or disabled by the user. // This will enable the pullups for the specified pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPBPUD.bit.GPIO58 = 0; // Enable pull-up on GPIO16 (SPISIMOA) GpioCtrlRegs.GPBPUD.bit.GPIO59 = 0; // Enable pull-up on GPIO17 (SPISOMIA) GpioCtrlRegs.GPBPUD.bit.GPIO60 = 0; // Enable pull-up on GPIO18 (SPICLKA) // GpioCtrlRegs.GPBPUD.bit.GPIO61 = 0; // Enable pull-up on GPIO19 (SPISTEA) // // Set qualification for selected pins to asynch only // // This will select asynch (no qualification) for the selected pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPBQSEL2.bit.GPIO58 = 3; // Asynch input GPIO16 (SPISIMOA) GpioCtrlRegs.GPBQSEL2.bit.GPIO59 = 3; // Asynch input GPIO17 (SPISOMIA) GpioCtrlRegs.GPBQSEL2.bit.GPIO60 = 3; // Asynch input GPIO18 (SPICLKA) // GpioCtrlRegs.GPBQSEL2.bit.GPIO61 = 3; // Asynch input GPIO19 (SPISTEA) GpioCtrlRegs.GPBGMUX2.bit.GPIO58 = 3; // Configure GPIO16 as SPISIMOA GpioCtrlRegs.GPBGMUX2.bit.GPIO59 = 3; // Configure GPIO17 as SPISOMIA GpioCtrlRegs.GPBGMUX2.bit.GPIO60 = 3; // Configure GPIO18 as SPICLKA // GpioCtrlRegs.GPBGMUX2.bit.GPIO61 = 3; // Configure GPIO19 as SPISTEA // //Configure SPI-A pins using GPIO regs // // This specifies which of the possible GPIO pins will be SPI functional // pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPBMUX2.bit.GPIO58 = 3; // Configure GPIO16 as SPISIMOA GpioCtrlRegs.GPBMUX2.bit.GPIO59 = 3; // Configure GPIO17 as SPISOMIA GpioCtrlRegs.GPBMUX2.bit.GPIO60 = 3; // Configure GPIO18 as SPICLKA // GpioCtrlRegs.GPBMUX2.bit.GPIO61 = 3; // Configure GPIO19 as SPISTEA EDIS; }