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.

[参考译文] ADS1256:DSP F28335的 SPI 通信问题

Guru**** 2535750 points
Other Parts Discussed in Thread: ADS1256

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

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/1028951/ads1256-spi-communication-issue-with-dsp-f28335

器件型号:ADS1256

您好!

在 DSP F28335和 ADS1256之间通过 SPI 进行通信时、我需要一些帮助来解决一些问题。 ADS1256未响应任何命令、每当我读取寄存器或数据时、MISO 始终返回 FF。 我怀疑发送到 ADC 的命令未被识别、因此没有响应。 Data Ready 连接到 GPIO、上电时、数据就绪信号的周期为33us、即大约2.4us 高电平、然后大约30.6us 低电平、

F28335 SPI SCLK 设置为1.25MHz、在上升沿发送数据、在下降沿接收数据、无相位延迟、空闲低电平。

我已附上显示 SCLK、CS 和 MOSI 的波形。 SCLK、CS 和 MOSI 之间的时序符合如下所示的时序规格。 并且连续的 MOSI 字节也满足时序要求。 MISO 未显示、但在测试中、它始终保持高电平。

下图显示了写入单个字节时的情况。 蓝线-- CS,黄线-- SCLK,紫线-- MOSI。

下图显示了写入多个字节时的情况。 绿线-- CS,紫线-- SCLK,蓝线-- MOSI

我还附上了配置代码。 这是 ADC 设置。

// adc_spi.c

#include "adc_spi.h"
#include "DSP28x_Project.h"
#include "spi.h"

enum
{

	REG_STATUS = 0x0000,	// x1H
	REG_MUX    = 0x0100, // 01H
	REG_ADCON  = 0x0200, // 20H
	REG_DRATE  = 0x0300, // F0H
	REG_IO     = 0x0400, // E0H
	REG_OFC0   = 0x0500, // xxH
	REG_OFC1   = 0x0600, // xxH
	REG_OFC2   = 0x0700, // xxH
	REG_FSC0   = 0x0800, // xxH
	REG_FSC1   = 0x0900, // xxH
	REG_FSC2   = 0x0A00, // xxH
};


// Command Table

enum
{
	CMD_WAKEUP  = 0x0000,	// Completes SYNC and Exits Standby Mode 0000  0000 (00h)
	CMD_RDATA   = 0x0100, // Read Data 0000  0001 (01h)
	CMD_RDATAC  = 0x0300, // Read Data Continuously 0000   0011 (03h)
	CMD_SDATAC  = 0x0F00, // Stop Read Data Continuously 0000   1111 (0Fh)
	CMD_RREG    = 0x1000, // Read from REG rrr 0001 rrrr (1xh)
	CMD_WREG    = 0x5000, // Write to REG rrr 0101 rrrr (5xh)
	CMD_SELFCAL = 0xF000, // Offset and Gain Self-Calibration 1111    0000 (F0h)
	CMD_SELFOCAL= 0xF100, // Offset Self-Calibration 1111    0001 (F1h)
	CMD_SELFGCAL= 0xF200, // Gain Self-Calibration 1111    0010 (F2h)
	CMD_SYSOCAL = 0xF300, // System Offset Calibration 1111   0011 (F3h)
	CMD_SYSGCAL = 0xF400, // System Gain Calibration 1111    0100 (F4h)
	CMD_SYNC    = 0xFC00, // Synchronize the A/D Conversion 1111   1100 (FCh)
	CMD_STANDBY = 0xFD00, // Begin Standby Mode 1111   1101 (FDh)
	CMD_RESET   = 0xFE00, // Reset to Power-Up Values 1111   1110 (FEh)
	//CMD_WAKEUP  = 0xFF, // Completes SYNC and Exits Standby Mode (FFh)
};

static void bsp_DelayMS(Uint16 nms);
static void bsp_DelayUS(Uint16 nus);

static void ADS1256_WaitDRDY(void);
static void ADS1256_ResetHard(void);
static void ADS1256_DelaySCLK(void);
static void ADS1256_DelayDATA(void);
static void ADS1256_DelayCS(void);
static void ADS1256_DelaySYNC(void);

static void ADS1256_WriteCmd(Uint16 _cmd);
//static void ADS1256_WriteReg(Uint16 _RegID, Uint16 _RegValue);
//static Uint16 ADS1256_ReadReg(Uint16 _RegID);
static Uint32 ADS1256_ReadData(void);
static void ADS1256_SetChannal(Uint16 _ch);
//static void ADS1256_StopScan(void);

ADS1256_VAR_T g_tADS1256;
static const Uint16 s_tabDataRate[ADS1256_DRATE_MAX] =
{
	0xF000,		// 30K SPS 
	0xE000,		// 15K
	0xD000,		// 7.5K
	0xC000,		// 3750
	0xB000,		// 2000
	0xA100,		// 1000
	0x9200,		// 500
	0x8200,		// 100
	0x7200,		// 60
	0x6300,		// 50
	0x5300,		// 30
	0x4300,		// 25
	0x3300,		// 15
	0x2300,		// 10
	0x1300,		// 5
	0x0300		// 2.5
};


void bsp_DelayUS(Uint16 nus)
{
	DELAY_US(nus);
}


void ADS1256_Init(){
    EALLOW;
	
	// CS
	GpioCtrlRegs.GPAMUX1.bit.GPIO6=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO6=0; // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO6=1; // Output 

	//RST
    GpioCtrlRegs.GPAMUX1.bit.GPIO7=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO7=0; // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO7=1; // Output 

	//SYNC
    GpioCtrlRegs.GPAMUX1.bit.GPIO8=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO8=0;  // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO8=1;  // Output 
	
	//DATA READY
	SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1; // GPIO input clock
    GpioCtrlRegs.GPAMUX1.bit.GPIO9=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO9=1;  // Disable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO9=0;  // Input
	GpioCtrlRegs.GPAQSEL1.bit.GPIO9= 0;
	

	GpioDataRegs.GPASET.bit.GPIO6=1; // Set value
    GpioDataRegs.GPASET.bit.GPIO7=1; // Set value
    GpioDataRegs.GPASET.bit.GPIO8=1; // Set value
	
	
	
	EDIS;
};

// t11 -> min 1/7.68M * 4 = 0.52 us Delay for final SCLK falling edge to first
// rising edge of next command, WREG, RREG, RDATA
// RESET and SYNC must be low for at least 0.52 us to be effective
static void ADS1256_DelaySCLK(void)
{
	bsp_DelayUS(1);
}

// t11 -> min 1/7.68M * 24 = 3.12 us Delay for final SCLK falling edge to first
// rising edge of next command, RDATAC, SYNC

static void ADS1256_DelaySYNC(void)
{
	bsp_DelayUS(5);
}

// t8 -> min 1/7.68M * 8 = 1.04 us Delay for final SCLK falling edge to first
// CS goes high

static void ADS1256_DelayCS(void)
{
	bsp_DelayUS(3);
}

// t6 -> min  50 * 0.13uS = 6.5uS
// Delay from last SCLK edge for DIN to first SCLK rising edge for 
// DOUT: RDATA, RDATAC,RREG Commands

static void ADS1256_DelayDATA(void)
{
	bsp_DelayUS(10);	
}

// SCLK period 37.5 M / 60 = 625K
// 1/625k = 1.6 us

// Data ready time 

static void ADS1256_WaitDRDY(void)
{
	Uint32 i;

	for (i = 0; i < 40000000; i++)
	{
		if (DRDY_IS_LOW())
		{
			break;
		}
	}
}

// Write register

void ADS1256_WriteReg(Uint16 _RegID, Uint16 _RegValue)
{
	ADS1256_WaitDRDY();

	spi_xmit(CMD_WREG | _RegID);	

	DELAY_US(10);
	ADS1256_WaitDRDY();
	spi_xmit(0x0000);	

	DELAY_US(10);
	ADS1256_WaitDRDY();
	spi_xmit(_RegValue);	
	
}

// Send command

static void ADS1256_WriteCmd(Uint16 _cmd)
{

	DELAY_US(10);
	spi_xmit(_cmd);
	DELAY_US(10);

}


void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)
{
	g_tADS1256.Gain = _gain;
	g_tADS1256.DataRate = _drate;

	ADS1256_StopScan();			

	ADS1256_ResetHard();
	
 	ADS1256_WriteCmd(CMD_RESET);
 	DELAY_US(60);
 	ADS1256_WriteCmd(CMD_SDATAC);
 	DELAY_US(60);

	{
		Uint16 buf[4];	
		buf[0] = (((0 << 3) | (1 << 2) | (0 << 1))<<8);
		// write 00000100, MSB, auto-calibration, buffer disable
		buf[1] = 0x0800;
		// output mux 00001000
		buf[2] = (((0 << 5) | (0 << 3) | (_gain << 0))<<8);
		// no clock out, sensor detect off, gain 1
		buf[3] = s_tabDataRate[_drate];

		//ADS1256_DelaySCLK();
		DELAY_US(20);
		spi_xmit(CMD_WREG | 0);

		DELAY_US(20);
		spi_xmit(0x0303);			

		DELAY_US(20);
		spi_xmit(buf[0]);	

		DELAY_US(20);
		spi_xmit(buf[1]);	

		DELAY_US(20);
		spi_xmit(buf[2]);	
        DELAY_US(20);

		spi_xmit(buf[3]);	
		DELAY_US(20);
	}


	DELAY_US(50);
		
	ADS1256_WriteCmd(CMD_SYNC);
	DELAY_US(20);
	ADS1256_WriteCmd(CMD_WAKEUP);
	DELAY_US(800);
	
}		


static void ADS1256_ResetHard(void)
{
	RST(0);
	DELAY_US(10);
	RST(1);
	
	SYNC(0);
	bsp_DelayUS(2);
	DELAY_US(10);
	SYNC(1);
	DELAY_US(800);

	ADS1256_WaitDRDY();	/* Ready time 630us */
}

Uint16 ADS1256_ReadReg(Uint16 _RegID)
{
	Uint16 read;
	read = 0;
	ADS1256_WaitDRDY();

	DELAY_US(20);
	spi_xmit(CMD_RREG | _RegID);	 
	DELAY_US(20);
	spi_xmit(0x0000);	

	DELAY_US(20);
	spi_xmit(0xEEEE);

	read = SpiaRegs.SPIRXBUF;

	DELAY_US(10);

	
	return read;
}

Uint16 ADS1256_ReadChipID(void)
{
	Uint16 id;
	
	id = ADS1256_ReadReg(REG_STATUS);

	return (id >> 4);
}

这是 SPI 设置。

#include "spi.h"
#include "SCI.h"
#include "adc.h"

//SPI send out data
void spi_xmit(Uint16 a){
	SpiaRegs.SPISTS.bit.INT_FLAG = 1;
    SpiaRegs.SPITXBUF = a;
    while(!SpiaRegs.SPISTS.bit.INT_FLAG){}
    //DELAY_US(20);
}

void spi_init(){
    // Initialize spigpio:16--SIMO, 17--SOMI, 18--CLK, 19--STEA
	
    EALLOW;
    
    GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0;   //Enable pull-up on GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0;   //Enable pull-up on GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0;   //Enable pull-up on GPIO18 (SPICLKA)
    GpioCtrlRegs.GPAPUD.bit.GPIO19 = 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.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (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.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
    GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
    GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA

    EDIS;
	
   
	SpiaRegs.SPICCR.all = 0x0008;  // Reset SPI, send out on rising edge, receive on falling edge, 8 bit
 
    SpiaRegs.SPICTL.all = 0x0006;   //no phase delay master mode

    SpiaRegs.SPIBRR = 0x001D;   // SPICLK(SPICLK 37.5M/(29+1))

    SpiaRegs.SPIPRI.bit.FREE = 1;   // Free run
    //SPI FIFO
    SpiaRegs.SPIFFTX.all = 0xE040;  //enable SPI TX interrupt

	SpiaRegs.SPICCR.all= 0x0088; // Renable SPI

}

interrupt void spi_rx_isr(void){

    SpiaRegs.SPIFFRX.bit.RXFFINTCLR = 1; //Clear inerrupt
    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //
}

interrupt void spi_tx_isr(void){
    SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1; // Clear interrupt
    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //
}

期待您的帮助。

谢谢

乍得

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

    乍得、您好!

    您是否有要分享的原理图?

    DRDY 信号是一个良好的迹象、因为它似乎在以默认数据速率(30kSPS)切换。 这意味着 ADC 以一定的容量工作。

    是否在字节之间切换 CS? 您显示的第一个图像是 CS 在字节开始时变为低电平、CS 在字节结束时变为高电平 您要发送的命令看起来是0101 0011、这是从寄存器3 (DRATE)开始的 WREG。 但是、在该字节复位 SPI 接口后将 CS 拉为高电平、因此永远不会执行该命令。 对于所有不同的信号、我无法真正说明第二幅图像中的情况、但 CS 在每个字节后似乎变为高电平。 这对于某些命令是可以接受的、但对于 RREG 和 WREG 来说是不可以接受的。

    当计时输出数据(发送 RDATA 命令、等待时间 T6、然后发出24个 SCLK)时、您还需要保持 CS 处于低电平。

    请告诉我、改变任何这种行为是否会改善您的结果。

    布莱恩

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

    您好、Bryan:

    非常感谢您的快速响应。 这对我有很大帮助、我会尝试一下。

    我使用的是现成的 ADS1256模块、因此这里没有原理图。 我使用 DSP F28335作为 SPI 主设备、ADS1256连接原始28335 SPI 接口。 F28335 SPI CS 连接到 ADC 的 CS、F28335每次发送8位、这就是 CS 先被拉低、然后被拉高的原因。 我想我需要使用 GPIO 作为 CS 线路。

    此外,我还有两个跟进问题。

    WREG 和 RREG 命令的连续字节之间的时序间隔要求是什么? 是 T11 (1/CLKIN * 4)吗? 例如、"0001 rrrrrrrrr"和"0000 nn"之间的间隔?

    2.发送 WREG 和 RREG 命令时、是否需要等待数据就绪先变为低电平?

    谢谢

    乍得

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

    乍得、您好!

    如果您有两个独立的板、请确保它们之间具有牢固、牢固的接地连接。 两个电路板中接地电位的任何变化都会导致噪声和未定义的通信行为。

    要回答您的问题:

    1. 发送 WREG 或 RREG 命令时、字节之间不需要时序延迟。 ADS1256数据表第34页的命令定义部分对此进行了说明
    2. 可以随时发出 WREG 和 RREG、您无需等到 DRDY 变为低电平。 但是、请记住、如果更改 ADC 设置、则应重新启动转换过程、因为正在进行的转换可能会因设置的更改而损坏。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Bryan:

    现在、我使用 GPIO 作为 CS 线路、当我发送命令字节时、它在整个周期内保持低电平。 当我读取寄存器时、它返回的值为"00"。 您对此问题有什么建议吗?

    此外、我怀疑在发送 WREG 或 RREG 时、在连续字节之间插入延迟是否有害。 由于 F28335数据为16位宽度、我注意到、有时当我无延迟地发送连续字节时、某些 SCLK 波形将崩溃。

    谢谢

    乍得  

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

    乍得、您好!

    两个(或更多)之间是否有牢固的接地连接? 电路板? 由于 SCLK 信号由 MCU 驱动、除非存在某种噪声或电压差、否则我不知道为什么它会折叠。 换句话说、这不会是 ADC 的问题。

    此外、如何在电路板上控制复位和 PWDN 引脚? 它们是否保持悬空、是否由 MCU 控制、或是否连接到 DVDD?

    布莱恩

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

    您好、Bryan:

    我修改了我的代码、今天取得了一些进展。 现在、ADC 能够接收单字节命令并响应 RREG 命令。 不过,我还有其他一些问题。  

    首先、ADC 无法响应 WREG 命令。 如以下波形所示、我尝试发送 WREG 命令。 因为我使用的是仅支持16位宽度数据的 DSP F28335。 命令字节被放置在较高的两个字节上。  

    5000 //从地址0x00写入

    0300 //写入四个字节

    0400 //地址0x00写入04

    0800 //地址0x01写入08

    0000 //地址0x02写入00

    D000 //地址0x03写入 D0、7500SPS

    但是、WREG 命令未成功。 执行 WREG 命令后、数据就绪周期仍在33us 左右(1/30K)。 此外、当我读取寄存器0x00时、它返回"81"、如果 WREG 成功、则应为"85"、   

    黄色-- CS,蓝色-- SCLK,紫色-- MOSI,绿色--数据就绪

    下图显示了上图的详细信息。

    其次、在我发送 SDATAC 命令后、数据就绪仍然在33us (30K SPS)周期内是否正常?

    第三、当我读取寄存器0x00时、它一直返回 DD81、因为我使用的是仅支持16位宽度数据的 DSP F28335、返回的值显示在低两个字节上、这是正常的。 但是、当我读取寄存器0x03时、返回的值在以下值之间跳转到:

    DC07

    DD87

    DC07

    DC2F

    我将 RREG 命令作为发出

    1300

    0000

    这是波形。

    最后、当我执行单通道读取时。 返回的值在0、1024和65535之间跳过。  

    期待收到您的回复、

    谢谢

    乍得

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

    乍得、您好!

    我在上一篇帖子中仍未收到问题的答案:

    1. 两个(或更多)之间是否有牢固的接地连接? 电路板? 由于 SCLK 信号由 MCU 驱动、除非存在某种噪声或电压差、否则我不知道为什么它会折叠。 换句话说、这不会是 ADC 的问题。
    2. 如何在电路板上控制复位和 PWDN 引脚? 它们是保持悬空、是由 MCU 的 GPIO 控制还是连接到 DVDD?

    此外、在发送的图像中很难分辨、但看起来每个帧中发出的 SCLK 为9个、而不是8个。 这意味着每次输入/输出一个额外位时钟、ADC 将无法正确读取该位。

    布莱恩

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

    您好、Bryan:

    很抱歉我迟到了。  

    MCU 和 ADC 通过 Dupont 线进行连接、它们具有很强的接地连接。

    2、RESET 和 PWDN 引脚连接到 MCU GPIO、并被拉至高电平。

    下图显示了 MCU 发送8位时的详细波形。 实际上有8.5个 SCLK 周期、MCU 正在向外发送8个虚拟位(EE)以准备就绪8位数据。 这是正确的波形吗?

    和以前一样,黄线-- CS,蓝线-- SCLK,紫线-- MOSI,绿线-- MISO

    期待收到您的回复。

    谢谢

    乍得

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

    您好、Bryan:

    实际上、这篇文章已经解决了我的问题。 我检查了 SPI 设置、并意识到我的 SPI 数据宽度实际上设置为9位、这就是我在波形中看到八个半时钟的原因。 在我更正了这个错误后、一切都正常。

    此外、通过引用 SCLK Collapsed、我意味着以下波形。 我尝试写入寄存器0x00、我的命令是:

    0500

    0000

    8400

    在发送这三个字节时不插入一些延迟、中间字节会以某种方式消失。 通过在连续字节之间插入一些延迟来解决此问题。

    总之、非常感谢您的帮助。

    乍得

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

    乍得、您好!

    很高兴我们能提供帮助!

    布莱恩