#include "ADS1256tb.h"
#include "main.h"
#include "cmsis_os.h"
/**
  ******************************************************************************
  * @file    ADS1256.c
  ******************************************************************************
  * @attention
  *	ADS1256模块
  * +5V   <------  5.0V      5V供电
  * GND   -------  GND       地
  * DRDY  ------>  PA11      准备就绪 低准备好  高未准备好
  *	CS    <------  PB12      SPI_CS 低有效，操作完拉高
  *	DIN   <------  PB15      SPI_MOSI
  *	DOUT  ------>  PB14      SPI_MISO
  *	SCLK  <------  PB13      SPI时钟
  *	GND   -------  GND       地
  *	PDWN  <------  VDD       掉电控制 常高
  *	RST   <------  PA8       复位信号 常高，拉低再拉高生效复位
  *	
  *	ADS1256基本特性:
  *	1、模拟部分供电5V;
  *	2、SPI数字接口电平：3.3V
  *	3、PGA设置范围： 1、2、4、8、16、32、64、
  *	4、参考电压2.5V (推荐缺省的，外置的）
  *	5、输入电压范围：PGA = 1 时, 可输入正负5V
  *	6. 自动校准 （当设置了PGA,BUF使能、数据采样率时，会启动自校准)
  *	7. 输入的缓冲器可设置启用和关闭（一般选启用）
  *	外部晶振频率 = 7.68MHz,
  *	时钟频率 tCLK = 1/7.68M = 0.13uS
  *	输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

  *	对SPI的时钟速度要求: (ads1256.pdf page 6)
  *	最快 4个tCLK = 0.52uS
  *	最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

  *	SCL高电平和低电平持续时间最小 200ns

  *	RREG, WREG, RDATA 命令之后，需要延迟 4 * tCLK = 0.52uS;
  *	RDATAC, RESET, SYNC 命令之后，需要延迟 24 * tCLK = 3.12uS;

  *	实际测试，在3.3V上电后, 及时不做任何配置，ADS125的DRDY 口线即开始输出脉冲信号（2.6us高,33.4低，频率30KHz）
	
	* (AVSS + 0.05V) ~ (AVDD – 1.5V) 如果AVSS = 0V,AVDD = 5.0V，则最大输入电压 = 5.0 - 1.5 = 3.5V，所以输入范围为0.05-3.5V
	* 可尝试关闭输入缓冲器，

  ******************************************************************************
  */
static SPI_HandleTypeDef *ads_spi;

static void ADS_Delay_us(uint16_t us)
{
  uint32_t delay = us * (SystemCoreClock / 1000000 / 5);
  while (delay--) __NOP();
}

static void ADS1256_SendCmd(uint8_t cmd)
{
  ADS1256_CS_LOW();
  HAL_SPI_Transmit(ads_spi, &cmd, 1, 10);
  ADS_Delay_us(5);
  ADS1256_CS_HIGH();
  ADS_Delay_us(2);
}

static void ADS1256_WriteReg(uint8_t reg, uint8_t val)
{
  uint8_t buf[3] = { CMD_WREG | (reg & 0x0F), 0x00, val };
  ADS1256_CS_LOW();
  HAL_SPI_Transmit(ads_spi, buf, 3, 10);
  ADS_Delay_us(5);
  ADS1256_CS_HIGH();
}

//static uint8_t ADS1256_ReadReg(uint8_t reg)
//{
//  uint8_t cmd[2] = { CMD_RREG | (reg & 0x0F), 0x00 };
//  uint8_t val;
//  ADS1256_CS_LOW();
//  HAL_SPI_Transmit(ads_spi, cmd, 2, 10);
//  ADS_Delay_us(2);
//  HAL_SPI_Receive(ads_spi, &val, 1, 10);
//  ADS1256_CS_HIGH();
//  return val;
//}

void ADS1256_Init(SPI_HandleTypeDef *hspi)
{
  ads_spi = hspi;

  ADS1256_CS_HIGH();
  osDelay(5);

  ADS1256_SendCmd(CMD_RESET);
  osDelay(5);

  ADS1256_SendCmd(CMD_SDATAC); // Stop continuous mode
  ADS1256_WriteReg(REG_STATUS, 0x06);  // Auto-cal, MSB first 开启缓冲器
	// 启用缓冲器的好处是输入阻抗更高、稳定性更强，但代价是 可输入范围缩窄（不能接近 AVDD） 
	//	ADS1256_WriteReg(REG_STATUS, 0x02);  // 关闭输入缓冲器 ,缺少了滤波 输出偏差变大
	
  ADS1256_WriteReg(REG_ADCON, 0x00 | GAIN_1);
  ADS1256_WriteReg(REG_DRATE, DRATE_1000SPS); // 数据率
  ADS1256_SendCmd(CMD_SELFCAL);  // Self-calibrate
  osDelay(10);
}

void ADS1256_SetChannel(uint8_t mux_pos)
{
  while (ADS1256_DRDY_Read() == GPIO_PIN_SET);
  ADS1256_WriteReg(REG_MUX, mux_pos | MUX_AINCOM); 
//	ADS1256_WriteReg(REG_MUX, mux_pos);
  ADS1256_SendCmd(CMD_SYNC);
  ADS1256_SendCmd(CMD_WAKEUP);
}

int32_t ADS1256_ReadChannel(uint8_t channel)
{
  ADS1256_SetChannel(channel << 4);  // AINx = channel

  while (ADS1256_DRDY_Read() == GPIO_PIN_SET); // 等待DRDY拉低

  ADS1256_CS_LOW();
  uint8_t cmd = CMD_RDATA;
  HAL_SPI_Transmit(ads_spi, &cmd, 1, 10);
  ADS_Delay_us(10);
  ADS_Delay_us(10);
  uint8_t buf[3];
  HAL_SPI_Receive(ads_spi, buf, 3, 10);
  ADS1256_CS_HIGH();

  int32_t raw = (buf[0] << 16) | (buf[1] << 8) | buf[2];
  if (raw & 0x800000) raw |= 0xFF000000;  // 符号扩展

  return raw;
}

int32_t ADS1256_Readdata(void)
{
	
  while (ADS1256_DRDY_Read() == GPIO_PIN_SET); // 等待DRDY拉低

  ADS1256_CS_LOW();
  uint8_t cmd = CMD_RDATA;
  HAL_SPI_Transmit(ads_spi, &cmd, 1, 10);
  ADS_Delay_us(10);
  ADS_Delay_us(10);
  uint8_t buf[3];
  HAL_SPI_Receive(ads_spi, buf, 3, 10);
  ADS1256_CS_HIGH();

  int32_t raw = (buf[0] << 16) | (buf[1] << 8) | buf[2];
  if (raw & 0x800000) raw |= 0xFF000000;  // 符号扩展

  return raw;
}

float ADS1256_ConvertToVoltage(int32_t adc_val, float vref, uint8_t gain)
{
//  return ((float)adc_val / 0x7FFFFF) * vref / gain *2;
		return ((float)adc_val / 0x400000) * vref / gain;
}
