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.

[参考译文] ADS8691:ADS8691 SPI 通信问题

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

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/1275753/ads8691-ads8691-spi-communication-issue

器件型号:ADS8691

您好!

我对您的 ADC 有一些问题:ADS8691IPW。

主要问题是缺乏可靠的工作。


通过跳线连接到 STM32F411E-DISCOS 开发板。

ADC 本身焊接在执行板上以用于调试。
它主要内置于具有四个菊花链单元的定制 PCB 中、但问题是类似的。


STM 由 USB 供电、ADC 模拟端和数字端通过 Keithley SMU 提供5V 电压。
使用1uF 电解电容器进行去耦。

我已经通过具有类似效果的多个 ADC 进行了迭代。

问题是它仅在连接示波器时起作用。
但在重新设置 STM 或将接地端连接到逻辑分析仪或将数字引脚连接到逻辑分析仪后、或一段时间后、它会停止工作。

我可以通过以下方式使其正常工作:

为 ADC 重置跳线、

断开跳线与逻辑分析仪的连接、

断开逻辑分析仪的接地、

重新连接到逻辑分析仪、

和许多其他组合。



定制 PCB ADC 原理图:





在定制 PCB 上、由于寄生引起的过冲和下冲显著降低。
绕过是根据指南进行的。

请注意、还有一个接地引线电感、它看起来会更糟。

(在所有屏幕中、示波器在 SPI 总线上触发)
当它工作时、数据会清晰地显示





有时在重置后、看起来是这样的:


或者根本无法正常工作。


我还在 MCU 以及靠近 ADC 的硬件中尝试了上拉和下拉电阻。

此外、还测试了不同的 CLK 速度。

代码:

来自 main 的零件:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == ADC_ALARM_Pin)
	{
	   //This block will be triggered after pin activated.
		if(BUTTON_Pin == 1)
		{
			for(int i = 0; i < 4; i++)
			{
			read_hword_data();
	    	char *msg = "ADC Alarm working\r\n";
	        HAL_UART_Transmit(&huart2, msg, sizeof(msg), 100);
			}
		}
	}
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef * hspi)
{
    HAL_SPI_Receive_DMA(&hspi1, RX_Buffer, sizeof(RX_Buffer));
    if(sample < 50000)
    {
    	read_adc_data(&adc_handle, RX_Buffer, sample);
    	sample++;
    }
    else if(sample == 50000)
    {
    	char *msg = "50 000 samples gathered\r\n";
        HAL_UART_Transmit(&huart2, msg, sizeof(msg), 100);
    }

}


自定义库:


struct adc_state adc_init() {
	struct adc_state state;
/*
	for(uint16_t i=0; i<12500; i++) state.data0[i] = '\0';
	for(uint16_t i=0; i<12500; i++) state.data1[i] = '\0';
	for(uint16_t i=0; i<12500; i++) state.data2[i] = '\0';
	for(uint16_t i=0; i<12500; i++) state.data3[i] = '\0';
*/
	return state;
}

/*
 * 11000_xx_<9-bit address>_ <16-bit data>
 * Command used to clear any (or a group of) bits of a register.
 * Any bit marked 1 in the data field results in that particular bit of the specified register being reset to 0, leaving the other bits unchanged.
 * Half-word command (that is, the command functions on 16 bits at a time).
 * LSB of the 9-bit address is always ignored and considered as 0b.(2)
 */
void clear_hword(char *reg)
{
	char command[16];
	sprintf(command, "11000000%s", reg);
	HAL_SPI_Transmit(&hspi1, command, sizeof(command), 0);
}

/*
 * 11001_xx_<9-bit address>_ 00000000_00000000
 * Command used to perform a 16-bit read operation.
 * Half-word command (that is, the device outputs 16 bits of register data at a time).
 * LSB of the 9-bit address is always ignored and considered as 0b.
 * Upon receiving this command, the device sends out 16 bits of the register in the next frame.
 */
void read_hword(char *reg)
{
	char x[8] = "00000000";
	char command[16];
	sprintf(command, "11001000%s", reg);
	HAL_SPI_Transmit(&hspi1, command, sizeof(command), 0);
	HAL_SPI_Transmit(&hspi1, x, sizeof(x), 0);
}


void read_hword_data()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
		{
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
			for(int i = 0; i < 4; i++)
			{
				read_hword(DATAOUT_CTL_REG);
			}
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
		}
}

/*
 * 01001_xx_<9-bit address>_ 00000000_00000000
 * Same as the READ_HWORD except that only eight bits of the register (byte read) are returned in the next frame.
*/
void read_word(char *reg)
{
	char command[16];
	sprintf(command, "01001000%s", reg);
	HAL_SPI_Transmit(&hspi1, command, sizeof(command), 0);
}

/*
 * 11010_00_<9-bit address>_ <16-bit data>
 * Half-word write command (two bytes of input data are written into the specified address).
 * LSB of the 9-bit address is always ignored and considered as 0b.
 *
 * 11010_01_<9-bit address>_ <16-bit data>
 * Half-word write command.
 * LSB of the 9-bit address is always ignored and considered as 0b.
 * With this command, only the MS byte of the 16-bit data word is written at the specified register address. The LS byte is ignored.
 *
 * 11010_10_<9-bit address>_ <16-bit data>
 * Half-word write command.
 * LSB of the 9-bit address is always ignored and considered as 0b.
 * With this command, only the LS byte of the 16-bit data word is written at the specified register address. The MS byte is ignored.
 */
void write_word(char *reg)
{
	char command[16];
	sprintf(command, "11010000%s", reg);
	HAL_SPI_Transmit(&hspi1, command, sizeof(command), 0);
}

/*
 * 11011_xx_<9-bit address>_ <16-bit data>
 * Command used to set any (or a group of) bits of a register.
 * Any bit marked 1 in the data field results in that particular bit of the specified register being set to 1, leaving the other bits unchanged.
 * Half-word command (that is, the command functions on 16 bits at a time).
 * LSB of the 9-bit address is always ignored and considered as 0b.
 */
void set_hword(char *reg)
{
	char command[16];
	sprintf(command, "11011000%s", reg);
	HAL_SPI_Transmit(&hspi1, command, sizeof(command), 0);
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void id_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(DEVICE_ID_REG);
			char command[16];
			sprintf(command,"0000000000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void reset_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(RST_PWRCTL_REG);
			char command[16];
			sprintf(command,"0100010100100000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void sdi_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(SDI_CTL_REG);
			char command[16];
			sprintf(command,"0000000000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void sdo_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(SDO_CTL_REG);
			char command[16];
			sprintf(command,"0000000100000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void data_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(DATAOUT_CTL_REG);
			char command[16];
			sprintf(command,"0100110000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void ref_vol_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(RANGE_SEL_REG);
			char command[16];
			sprintf(command,"0000000000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void alarms_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(ALARM_REG);
			char command[16];
			sprintf(command,"0000110000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void alarmh_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(ALARM_H_TH_REG);
			char command[16];
			sprintf(command,"0000000000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);
		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

/*
 * Configuration described in the documentation in chapter "7.6 Register Maps" (p.48)
 * www.ti.com/.../ads8691.pdf
 */
void alarml_config()
{
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 1)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
		for(int i = 0; i < 4; i++)
		{
			write_word(ALARM_L_TH_REG);
			char command[16];
			sprintf(command,"0000000000000000");
			HAL_SPI_Transmit(&hspi1, command, sizeof(command), 10);		}
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
	}
}

// Initialization of all ADC's registers
void adc_config()
{
	id_config();
	reset_config();
	sdi_config();
	sdo_config();
	data_config();
	ref_vol_config();
	alarms_config();
	alarmh_config();
	alarml_config();

}

//
void read_adc_data(struct adc_state *state, uint8_t *val, uint16_t x)
{
	x = x/4;
	receiver_check(state, val, x);
	read_hword_data();

}

//
void receiver_check(struct adc_state *state, uint8_t *val, uint16_t x)
{
	int16_t data;
	data = (val[3] << 8) | val[2];



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

    大家好、Radoslaw、

    感谢您的发帖。

    我将通过尝试一些方法来开始调试、以提高设置的稳健性。 几个指针:

    1. 在 ADC 板、STM 板和外部电源之间共享一个实心 GND 连接。 还要确保 AIN_GND 和 DGND 之间的接地连接牢固。 通常建议使用共用接地。
    2. 为了减少 SPI 线路上的过冲和振铃、添加一些串联端接(即33欧姆)来抑制高频成分。 SCLK 上的小电容(即10 pF)也有助于实现相同目的。 这可能就是示波器探头看似有用的原因。
    3. 一旦电源接通并稳定、复位脉冲可能有助于确保所有 ADC 在已知正常状态下加电。 然后、如有必要、继续配置所有寄存器。

    此致、

    瑞安

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

    您好、Ryan、

    非常感谢您的答复、很遗憾、我的问题没有得到解决。

    我已应用所有建议的更改以及增加电容以增加 HF 负载。
    出于某种原因、我可以通过用手指触摸引脚使其工作、但仅当"Reset"悬空且在建立数据传输后、将其拉高。

    它看起来像是存在信号完整性问题、但根据数据表执行的所有操作都无法正常工作。

    测量所有引脚和电源电压后、也不存在禁止状态。

    可能我拥有的单元有缺陷。



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

    您好 Radosaw、

    RSTN  引脚不应悬空。 它应该始终被驱动为高电平或低电平。 默认情况下、RSTN 引脚用于上电复位(POR)。 在 POR 延时时间(TD_RST_POR)之后、您可以将 RSTn 拉高并开始数据采集。

    到目前为止、这似乎不是器件问题。 如您所说、它有时会起作用。 我相信、改进设置和上电序列将产生更一致的结果。

    此致、

    瑞安