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.

[参考译文] ADS1262:来自 RREG 命令的 SPI 数据

Guru**** 2390755 points
Other Parts Discussed in Thread: ADS1262

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/1010774/ads1262-no-spi-data-from-rreg-command

器件型号:ADS1262

我使用 TM4C123GH6PMI 尝试查询 ADS1262 ADC 的输入多路复用器寄存器、但未接收到器件中的任何数据。

通道 A (蓝色)- MOSI

通道 B (红色)- SCLK

通道 C (黄色)- CS

通道 D (绿色)- MISO

我在 Tiva MCU 上使用以下代码、

//*****************************************************************************
//
// uart_echo.c - Example for reading data from and writing data to the UART in
//               an interrupt driven fashion.
//
// Copyright (c) 2012-2017 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.1.4.178 of the EK-TM4C123GXL Firmware Package.
//
//*****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/ssi.h"
#include "driverlib/timer.h"
#include "inc/hw_types.h"



//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>UART Echo (uart_echo)</h1>
//!
//! This example application utilizes the UART to echo text.  The first UART
//! (connected to the USB debug virtual serial port on the evaluation board)
//! will be configured in 115,200 baud, 8-n-1 mode.  All characters received on
//! the UART are transmitted back to the UART.
//
//*****************************************************************************

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// The UART interrupt handler.
//
//*****************************************************************************
void
UARTIntHandler(void)
{
    uint32_t ui32Status;

    //
    // Get the interrrupt status.
    //
    ui32Status = ROM_UARTIntStatus(UART0_BASE, true);

    //
    // Clear the asserted interrupts.
    //
    ROM_UARTIntClear(UART0_BASE, ui32Status);

    //
    // Loop while there are characters in the receive FIFO.
    //
    while(ROM_UARTCharsAvail(UART0_BASE))
    {
        //
        // Read the next character from the UART and write it back to the UART.
        //
        ROM_UARTCharPutNonBlocking(UART0_BASE,
                                   ROM_UARTCharGetNonBlocking(UART0_BASE));

        //
        // Blink the LED to show a character transfer is occuring.
        //
        //GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);

        //
        // Delay for 1 millisecond.  Each SysCtlDelay is about 3 clocks.
        //
        SysCtlDelay(SysCtlClockGet() / (1000 * 3));

        //
        // Turn off the LED
        //
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);

    }
}

void ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}

//
// Flags that contain the current value of the interrupt indicator as displayed
// on the UART.
//
uint32_t g_ui32Flags;

void delayMs(uint32_t ui32Ms) {

    // 1 clock cycle = 1 / SysCtlClockGet() second
    // 1 SysCtlDelay = 3 clock cycle = 3 / SysCtlClockGet() second
    // 1 second = SysCtlClockGet() / 3
    // 0.001 second = 1 ms = SysCtlClockGet() / 3 / 1000

    SysCtlDelay(ui32Ms * (SysCtlClockGet() / 3 / 1000));
}

void tx_spi0(unsigned char data){
    //
    // Send the data using the "blocking" put function.  This function
    // will wait until there is room in the send FIFO before returning.
    // This allows you to assure that all the data you send makes it into
    // the send FIFO.
    //
    SSIDataPut(SSI0_BASE, data);
    //
    // Wait until SSI0 is done transferring all the data in the transmit FIFO.
    //
    while(SSIBusy(SSI0_BASE))
    {
    }
}

unsigned char rx_spi0(){
    unsigned char data;
    uint32_t trashBin[1] = {0};

    //a. Send Nothing (Get the bus going).
    ROM_SSIDataPut(SSI0_BASE, 0);
    while(ROM_SSIBusy(SSI0_BASE))
    {
    }
    //
    // Receive the data using the "blocking" Get function. This function
    // will wait until there is data in the receive FIFO before returning.
    //
    SSIDataGet(SSI0_BASE, &data);

    //
    // Since we are using 8-bit data, mask off the MSB.
    //
    data &= 0x00FF;

    while (ROM_SSIDataGetNonBlocking(SSI0_BASE, &trashBin[0])) {}

    return data;
}

void ads1262_write_reg(unsigned char addr, unsigned char data) {

    //Vars
    unsigned char cmd = 0x40;
    unsigned char reg = cmd | addr;

    //0. Toggle the chip select line low (active low).
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0);

    //1. Delay 2ms
    delayMs(2);

    //1. Send the write command and register.
    tx_spi0(reg);
    //2. Send the number of addrs.
    tx_spi0(0);
    //3. Send the register value.
    tx_spi0(data);

    //4. Toggle the chip select line high (active low).
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, GPIO_PIN_3);
}

unsigned int ads1262_read_reg(unsigned char addr) {

    //Vars
    unsigned char cmd = 0x20;
    unsigned char reg = cmd | addr;

    //0. Toggle the chip select line low (active low).
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0); //ADC_RST High (Active Low)
    delayMs(1);
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1); //ADC_RST High (Active Low)
    delayMs(1);
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, 0);

    //1. Delay 2ms
    //delayMs(2);

    //1. Send the write command and register.
    tx_spi0(reg);
    //2. Send the number of addrs.
    tx_spi0(0);
    //3. Rx the register value.
    unsigned char data1 = rx_spi0();
    unsigned char data2 = rx_spi0();

    //4. Toggle the chip select line high (active low).
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, GPIO_PIN_3);
    unsigned int data = data1 << 8 | data2;
    return data;
}

int read_adc() {

    #define NUM_SSI_DATA_ADC            6

    uint32_t pui32DataTx[NUM_SSI_DATA_ADC];
    uint32_t pui32DataRx[NUM_SSI_DATA_ADC];
    uint32_t ui32Index;
    uint32_t trashBin[1] = {0};
    int adc_voltage;
    uint32_t adc_data;
    char status;

    //Set the Chip Select Pin of the ADC Low. (Active Low)
    ROM_GPIOPinWrite(GPIO_PORTJ_BASE, GPIO_PIN_0, 0x0);
    for(ui32Index = 0; ui32Index < NUM_SSI_DATA_ADC; ui32Index++)
    {
        //a. Send Nothing (Get the bus going).
        ROM_SSIDataPut(SSI1_BASE, 0);
        while(ROM_SSIBusy(SSI1_BASE))
        {
        }
        //b. Read ADC
        //
        // Receive the data using the "blocking" Get function. This function
        // will wait until there is data in the receive FIFO before returning.
        //
        ROM_SSIDataGet(SSI1_BASE, &pui32DataRx[ui32Index]);
        //
        // Since we are using 8-bit data, mask off the MSB.
        //
        pui32DataRx[ui32Index] &= 0x00FF;
        //ROM_SysCtlDelay(10);
    }
    //Set the Chip Select Pin of the ADC High. (Active Low)
    ROM_GPIOPinWrite(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_PIN_0);

    /* Clear SSI0 RX Buffer */
    while (ROM_SSIDataGetNonBlocking(SSI1_BASE, &trashBin[0])) {}

    return adc_voltage;

}

//*****************************************************************************
//
// This code runs the channels on the KIRT board.
//
//*****************************************************************************


int
main(void)
{
    uint32_t pui32DataRx[6];
    //
    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPUEnable();
    ROM_FPULazyStackingEnable();

    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    //
    // ============================================== GPIO for the Range, Zero Check Relay, and ADC I/O ==============================================
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA))
    {
    }
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB))
    {
    }
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD))
    {
    }
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE))
    {
    }
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF))
    {
    }

    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_0); //R1
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_1); //R2
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_2); //R3
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_3); //R4
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_2); //R5
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_3); //R6
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_4); //R7
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_7); //ZERO_CHK

    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0); //ADC_START
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); //ADC_RST
    ROM_GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_2); //ADC_DRDY
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_3); //ADC_CS

    //INIT Meter
    //R1 ON
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_PIN_0); //R1
    //R2-R7, and ZERO_CHK off.
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0); //R2
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0); //R3
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0); //R4
    ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_2, 0); //R5
    ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_3, 0); //R6
    ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, 0); //R7
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_7, 0); //ZERO_CHK

    //ADC INIT
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_PIN_0); //ADC_START Low
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1); //ADC_RST High (Active Low)
    ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_3, GPIO_PIN_3); //ADC_CS High (Active Low)

    //  ============================================== UART  ==============================================
    ConfigureUART();

    //  ============================================== SSI ==============================================
    //
    // Set the clocking to run directly from the external crystal/oscillator.
    // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    // crystal on your board.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    // The SSI0 peripheral must be enabled for use.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    //
    // For this example SSI0 is used with PortA[5:2].  The actual port and pins
    // used may be different on your part, consult the data sheet for more
    // information.  GPIO port A needs to be enabled so these pins can be used.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    //
    // Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0RX);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);

    //
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware.  Consult the data sheet to
    // see which functions are allocated per pin.
    // The pins are assigned as follows:
    //      PA5 - SSI0Tx
    //      PA4 - SSI0Rx
    //      PA3 - SSI0Fss
    //      PA2 - SSI0CLK
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
                   GPIO_PIN_2);

    //
    // Configure and enable the SSI port for SPI master mode.  Use SSI0,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    // For SPI mode, you can set the polarity of the SSI clock when the SSI
    // unit is idle.  You can also configure what clock edge you want to
    // capture data on.  Please reference the datasheet for more information on
    // the different SPI modes.
    //
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
                           SSI_MODE_MASTER, 1000000, 8);

    //
    // Enable the SSI0 module.
    //
    SSIEnable(SSI0_BASE);

    //
    // Read any residual data from the SSI port.  This makes sure the receive
    // FIFOs are empty, so we don't read any unwanted junk.  This is done here
    // because the SPI SSI mode is full-duplex, which allows you to send and
    // receive at the same time.  The SSIDataGetNonBlocking function returns
    // "true" when data was returned, and "false" when no data was returned.
    // The "non-blocking" function checks if there is any data in the receive
    // FIFO and does not "hang" if there isn't.
    //
    while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    {
    }

    // ============================================== Configure ADC ==============================================
    unsigned char reg = 0x06;
    unsigned char reg_data = 0 << 4 | 0xA;

    ads1262_write_reg(reg, reg_data);
    unsigned int input_mux = ads1262_read_reg(reg);

    // ============================================== TIMER Module ==============================================
    //uint32_t ui32Temp, ui32PHYConfig, ui32SysClock;

    //
    // Enable the peripherals used by this example.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    //
    // Enable processor interrupts.
    //
    ROM_IntMasterEnable();

    //
    // Configure the two 32-bit periodic timers.
    //
    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet());

    //
    // Setup the interrupts for the timer timeouts.
    //
    ROM_IntEnable(INT_TIMER0A);
    ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Enable the timers.
    //
    ROM_TimerEnable(TIMER0_BASE, TIMER_A);

    //
    // Loop forever echoing data through the UART.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
// The interrupt handler for the first timer interrupt.
//
//*****************************************************************************
void
Timer0IntHandler(void)
{
    char cOne, cTwo;

    //
    // Clear the timer interrupt.
    //
    ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Toggle the flag for the first timer.
    //
    HWREGBITW(&g_ui32Flags, 0) ^= 1;

    //
    // Use the flags to Toggle the LED for this timer
    //
    //GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, g_ui32Flags << 1);
    unsigned char reg = 0x06;
    unsigned char reg_data = 0 << 4 | 0xA;
    //ads1262_write_reg(reg, reg_data);
    unsigned int input_mux = ads1262_read_reg(reg);

    //
    // Update the interrupt status on the display.
    //
    ROM_IntMasterDisable();
    cOne = HWREGBITW(&g_ui32Flags, 0) ? '1' : '0';
    cTwo = HWREGBITW(&g_ui32Flags, 1) ? '1' : '0';
    //UARTprintf("\rT1: %c  T2: %c", cOne, cTwo);
    ROM_IntMasterEnable();
}

+/- 2.5V 和3.3V 电压轨正常、但我不确定为什么没有什么东西。 有人有什么建议吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗯、如果 SPI 模式正确、

    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_1,
                               SSI_MODE_MASTER, 1000000, 8);

    至少我现在要获取数据。 虽然结果有点自私? 默认值为 XX XX 00 01 (H)而非 XX XX XX 01 00 (H)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、JAOverstreet、

    如果我了解您在这里要做的事情:

    • 在前8个 SCLK 期间、您将向寄存器地址06h (INPMUX 寄存器)发送 RREG 命令
    • 在第二个8个 SCLK 期间、您将发送要读取的寄存器数量- 1。 在这种情况下、发送00h、这意味着您只想从一个寄存器(INPMUX)读取数据
    • 因此、在第3组8个 SCLK 期间、DOUT 应仅提供来自 INPMUX 寄存器的8位寄存器数据。 在这种情况下、输出为01h、这是 INPMUX 寄存器的默认值
    • 我不确定第4组 SCLK 的用途是什么

    根据我可以收集的数据、ADC 看起来按预期和期望工作。

    布莱恩