Source file: /~heha/ewa/Logger/logger1.zip/ads1256_test.cpp

/*
Belegung des GPIO im Gesamtprojekt (Temperatur-)Logger
G___F___E___D__C____B____A__________A______B___C____D___F___G___
        3P3    3P3       3,3V   | | 5V         5P
        SDA         SDA  GPIO2  | | 5V         5P       5P  5P
        SCL TA      SCL  GPIO3  | | GND        DGND     GND GND
    RCK                  GPIO4  | | GPIO14 TX       EOP
GND     GND              GND    | | GPIO15 RX
O1             DRDY      GPIO17 | | GPIO18     RST          O2
O3             PDWN      GPIO27 | | GND        DGND         GND
O4             CS0       GPIO22 | | GPIO23     CS1          O5
               3P3       3,3V   | | GPIO24                  O6
    DIN        DIN  MOSI GPIO10 | | GND        DGND         GND
               DOUT MISO GPIO9  | | GPIO25                  O7
    SCK        SCLK SCK  GPIO11 | | GPIO8  CE0
GND            DGND      GND    | | GPIO7  CE1
                    idD  GPIO0  | | GPIO1  idC
                         GPIO5  | | GND        DGND         GND
A7             H7-4      GPIO6  | | GPIO12                  A6
A5             H7-3      GPIO13 | | GND        DGND         GND
A4             H7-2      GPIO19 | | GPIO16                  A3
A2             H7-1      GPIO26 | | GPIO20                  A1
GND            DGND      GND    | | GPIP21                  A0

G = DAC8 für Secon XPL (hier nur Digitalausgänge mit ULN2003), nur „messpi1“
F = Analogmultiplexer-Vorsatzplatine
E = Echtzeituhr mit DS3231
D = Shutdown-Taster (TA) und End-Of-Powerdown (EOP)
C = A/D+D/A-Karte mit ADS1256 von HighResolution
B = GPIO-Zusatzfunktionen
A = GPIO-Ports
*/

#include <bcm2835.h>
#include <stdio.h>
#include <signal.h>

enum gpio{
 DRDY = 17,	// Eingang, Low = A/D-Konversion fertig
 RST = 18,	// Ausgang, Low = Reset
 CS0 = 22,	// Ausgang, Low = A/D-Konverter adressieren
 CS1 = 23,	// Ausgang, Low = D/A-Konverter adressieren
 PDWN = 27,	// Ausgang: Low = Stromsparmodus
};

inline void CS(uint8_t lh) {bcm2835_gpio_write(CS0,lh);}
inline bool RDY() {return !bcm2835_gpio_lev(DRDY);}
//inline void RESET(uint8_t lh) {bcm2835_gpio_write(RST,lh);}

struct ADS1256_t{
/*Register definition: Table 23. Register Map --- ADS1256 datasheet Page 30*/
 enum REG{	/*Register address, followed by reset the default values */
  STATUS,	// x1H
  MUX,		// 01H
  ADCON,	// 20H
  DRATE,	// F0H
  IO,		// E0H
  OFC0,		// undefined
  OFC1,
  OFC2,
  FSC0,
  FSC1,
  FSC2,
 };
/* Command definition: TTable 24. Command Definitions --- ADS1256 datasheet Page 34 */
 enum CMD{
  WAKEUP  = 0x00, // Completes SYNC and Exits Standby Mode
  RDATA   = 0x01, // Read Data
  RDATAC  = 0x03, // Read Data Continuously
  SDATAC  = 0x0F, // Stop Read Data Continuously
  RREG    = 0x10, // Read from REG r (1rh)
  WREG    = 0x50, // Write to REG r (5rh)
  SELFCAL = 0xF0, // Offset and Gain Self-Calibration
  SELFOCAL= 0xF1, // Offset Self-Calibration
  SELFGCAL= 0xF2, // Gain Self-Calibration
  SYSOCAL = 0xF3, // System Offset Calibration
  SYSGCAL = 0xF4, // System Gain Calibration
  SYNC    = 0xFC, // Synchronize the A/D Conversion
  STANDBY = 0xFD, // Begin Standby Mode
  RESET   = 0xFE, // Reset to Power-Up Values
 };
 const int DRAE_COUNT = 15;
 enum GAIN_e{
  GAIN_1,
  GAIN_2,
  GAIN_4,
  GAIN_8,
  GAIN_16,
  GAIN_32,
  GAIN_64,
 }Gain;		/* GAIN  */
 enum RATE_e{
  S30000,
  S15000,
  S7500,
  S3750,
  S2000,
  S1000,
  S500,
  S100,
  S60,
  S50,
  S30,
  S25,
  S15,
  S10,
  S5,
  S2d5,
  RATE_MAX
 }Rate;	/* DATA output  speed*/
 static const float rates[16];
 int32_t AdcNow[8];	/* ADC conversion value */
 uint8_t Channel;	/* The current channel*/
 uint8_t ScanMode;	/*Scanning mode,   0  Single-ended input  8 channel, 1 Differential input  4 channel*/
 void StartScan(uint8_t _ucScanMode);
 void CfgADC(GAIN_e _gain, RATE_e _rate);
 static void DelayDATA();
 static void WaitDRDY();
 static void WriteReg(uint8_t _RegID, uint8_t _RegValue);
 static uint8_t ReadReg(uint8_t _RegID);
 static void WriteCmd(uint8_t _cmd);
 static uint8_t ReadChipID();
 static void SetChannel(uint8_t _ch);
 static void SetDiffChannel(uint8_t _ch);
 static int32_t ReadData();
 int32_t GetAdc(uint8_t _ch) const;
 void ISR();
 bool Scan();
}ADS1256;

const float ADS1256_t::rates[16]={
 30000,15000,7500,3750,2000,1000,500,100,60,50,30,25,15,10,5,2.5};

void  bsp_DelayUS(uint64_t micros) {
 bcm2835_delayMicroseconds (micros);
}


// Configuration of the STM32 GPIO and SPI interface, The connection ADS1256
void bsp_InitADS1256(void) {
#ifdef SOFT_SPI
 CS(1);
 SCK_0();
 DI_0();
#endif
//CfgADC(GAIN_1,S1000);	/* 配置ADC参数: 增益1:1, 数据输出速率 1KHz */
}

// Configuration DRDY PIN for external interrupt is triggered
// _ucDiffMode : 0  Single-ended input  8 channel, 1 Differential input  4 channe
void ADS1256_t::StartScan(uint8_t _ucScanMode) {
 ScanMode = _ucScanMode;
/* 开始扫描前, 清零结果缓冲区 */
 Channel = 0;
 for (uint8_t i = 0; i < 8; i++) AdcNow[i] = 0;
}

// SPI bus to send 8 bit data
static void spiSendByte(uint8_t _data) {
 bsp_DelayUS(2);
 bcm2835_spi_transfer(_data);
}

//delay time: wait for automatic calibration
void ADS1256_t::WaitDRDY() {
 for (uint32_t i = 0; i < 400000; i++) {
  if (RDY()) return;
 }
 printf("ADS1256_t::WaitDRDY() Time Out ...\n");
}

// The configuration parameters of ADC, gain and data rate
// _gain: select gain from 1 to 64
// _drate: select one of the possible data rates
void ADS1256_t::CfgADC(GAIN_e _gain, RATE_e _rate) {
 Gain = _gain;
 Rate = _rate;
 WaitDRDY();

/*Status register define
 Bits 7-4 ID3, ID2, ID1, ID0  Factory Programmed Identification Bits (Read Only)
 Bit 3 ORDER: Data Output Bit Order
		0 = Most Significant Bit First (default)
		1 = Least Significant Bit First
 Input data  is always shifted in most significant byte and bit first.
 Output data is always shifted out most significant byte first.
 The ORDER bit only controls the bit order of the output data within the byte.
 Bit 2 ACAL : Auto-Calibration
		0 = Auto-Calibration Disabled (default)
		1 = Auto-Calibration Enabled
 When Auto-Calibration is enabled, self-calibration begins
 at the completion of the WREG command that changes the PGA
 (bits 0-2 of ADCON register), DR (bits 7-0 in the DRATE register)
 or BUFEN (bit 1 in the STATUS register) values.
 Bit 1 BUFEN: Analog Input Buffer Enable
		0 = Buffer Disabled (default)
		1 = Buffer Enabled
 Bit 0 DRDY :  Data Ready (Read Only)
		This bit duplicates the state of the DRDY pin.
		ACAL=1  enable  calibration
*/
//WriteReg(REG::STATUS, (0 << 3) | (1 << 2) | (1 << 1));
/* ADCON: A/D Control Register (Address 02h)
	Bit 7 Reserved, always 0 (Read Only)
	Bits 6-5 CLK1, CLK0 : D0/CLKOUT Clock Out Rate Setting
			00 = Clock Out OFF
			01 = Clock Out Frequency = fCLKIN (default)
			10 = Clock Out Frequency = fCLKIN/2
			11 = Clock Out Frequency = fCLKIN/4
	When not using CLKOUT, it is recommended that it be turned off. These bits can only be reset using the RESET pin.
	Bits 4-3 SDCS1, SCDS0: Sensor Detect Current Sources
			00 = Sensor Detect OFF (default)
			01 = Sensor Detect Current = 0.5 μ A
			10 = Sensor Detect Current = 2 μ A
			11 = Sensor Detect Current = 10μ A
			The Sensor Detect Current Sources can be activated to verify  the integrity of an external sensor supplying a signal to the
			ADS1255/6. A shorted sensor produces a very small signal while an open-circuit sensor produces a very large signal.
	Bits 2-0 PGA2, PGA1, PGA0: Programmable Gain Amplifier Setting
			000 = 1 (default)
			001 = 2
			010 = 4
			011 = 8
			100 = 16
			101 = 32
			110 = 64
			111 = 64
*/
//WriteReg(REG::ADCON, (0 << 5) | (0 << 2) | (GAIN_1 << 1));	/*choose 1: gain 1 ;input 5V/

 CS(0);	/* SPI片选 = 0 */
 spiSendByte(CMD::WREG | 0);	/* Write command register, send the register address */
 spiSendByte(0x03);	/* Register number 4,Initialize the number  -1*/
 spiSendByte(1<<2);	/* Set the status register */
 spiSendByte(0x08);	/* Set the input channel parameters */
 spiSendByte(_gain);	/* Set the ADCON control register,gain */
 static const uint8_t tabRate[] = {
  0xF0,0xE0,0xD0,0xC0,0xB0,0xA1,0x92,0x82,0x72,0x63,0x53,0x43,0x33,0x20,0x13,0x03};
 spiSendByte(tabRate[_rate]);	/* Set the output rate */
 CS(1);	/* SPI  cs = 1 */
 bsp_DelayUS(50);
}

void ADS1256_t::DelayDATA() {
/* Delay from last SCLK edge for DIN to first SCLK rising edge for DOUT: RDATA, RDATAC,RREG Commands
	min  50   CLK = 50 * 0.13uS = 6.5uS
*/
 bsp_DelayUS(10);	/* The minimum time delay 6.5us */
}

// SPI bus receive function
static uint8_t spiRecvByte() {
 return bcm2835_spi_transfer(0xff);
}

// Write the corresponding register
// _RegID: register  ID
// _RegValue: register Value
void ADS1256_t::WriteReg(uint8_t _RegID, uint8_t _RegValue) {
 CS(0);	/* SPI  cs  = 0 */
 spiSendByte(CMD::WREG|_RegID);	/*Write command register */
 spiSendByte(0x00);		/*Write the register number */
 spiSendByte(_RegValue);	/*send register value */
 CS(1);	/* SPI   cs = 1 */
}

// Read  the corresponding register
// _RegID: register  ID
// return: read register value
uint8_t ADS1256_t::ReadReg(uint8_t _RegID) {
 CS(0);	/* SPI  cs  = 0 */
 spiSendByte(CMD::RREG|_RegID);	/* Write command register */
 spiSendByte(0x00);	/* Write the register number */
 DelayDATA();	/*delay time */
 uint8_t read = spiRecvByte();	/* Read the register values */
 CS(1);	/* SPI   cs  = 1 */
 return read;
}

// Sending a single byte order
void ADS1256_t::WriteCmd(uint8_t _cmd) {
 CS(0);	/* SPI   cs = 0 */
 spiSendByte(_cmd);
 CS(1);	/* SPI  cs  = 1 */
}

// Read the chip ID
// return: four high status register bits
uint8_t ADS1256_t::ReadChipID() {
 WaitDRDY();
 return ReadReg(REG::STATUS)>>4;
}

// Select Configuration channel number
void ADS1256_t::SetChannel(uint8_t _ch) {
/*
 Bits 7-4 PSEL3, PSEL2, PSEL1, PSEL0: Positive Input Channel (AINP) Select
	0000 = AIN0 (default)
	0001 = AIN1
	0010 = AIN2
	0011 = AIN3
	0100 = AIN4
	0101 = AIN5
	0110 = AIN6
	0111 = AIN7
	1xxx = AINCOM
	NOTE: When using an ADS1255 make sure to only select the available inputs.
 Bits 3-0 NSEL3, NSEL2, NSEL1, NSEL0: Negative Input Channel (AINN)Select
	0000 = AIN0
	0001 = AIN1 (default)
	0010 = AIN2
	0011 = AIN3
	0100 = AIN4
	0101 = AIN5
	0110 = AIN6
	0111 = AIN7
	1xxx = AINCOM
*/
 WriteReg(REG::MUX, _ch<<4 | 0x08);	/* Bit3 = 1, AINN connection AINCOM */
}

// konfiguriert differenzielle Kanäle AIN0-AIN1, AIN2-AIN3, AIN4-AIN5 oder AIN6-AIN7
// (nur diese!)
void ADS1256_t::SetDiffChannel(uint8_t _ch) {
 WriteReg(REG::MUX,_ch<<5|_ch<<1|1);
}

// function: read ADC value
int32_t ADS1256_t::ReadData() {
 CS(0);
 spiSendByte(CMD::RDATA);	/* read ADC command  */
 DelayDATA();
	/*Read the sample results 24bit*/
 int32_t read = spiRecvByte();
 read<<=8;
 read|= spiRecvByte();
 read<<=8;
 read|= spiRecvByte();
 CS(1);
 read<<=8;	// Extend to signed number
 read>>=8;
 return read;
}

// read cached ADC value
// parameter:  channel number 0--7
int32_t ADS1256_t::GetAdc(uint8_t _ch) const{
 if (_ch > 7) return 0;
 return AdcNow[_ch];
}

// Collection procedure
void ADS1256_t::ISR() {
 switch (ScanMode) {
  case 0: {	//  Single-ended 8 channel
   SetChannel(Channel);
   bsp_DelayUS(5);
   WriteCmd(CMD::SYNC);
   bsp_DelayUS(5);
   WriteCmd(CMD::WAKEUP);
   bsp_DelayUS(25);
   AdcNow[Channel-1&7] = ReadData();
   Channel=Channel+1&7;
  }break;
  case 1: {	/*DiffChannel*/
   SetDiffChannel(Channel);
   bsp_DelayUS(5);
   WriteCmd(CMD::SYNC);
   bsp_DelayUS(5);
   WriteCmd(CMD::WAKEUP);
   bsp_DelayUS(25);
   AdcNow[Channel-1&3] = ReadData();
   Channel=Channel+1&3;
  }break;
 }
}

bool ADS1256_t::Scan() {
 if (RDY()) {
  ISR();
  return true;
 }
 return false;
}

bool abort;
void sig_handler(int) {
 abort=true;
}

int  main() {
 const uint8_t ch_num=8;
 if (!bcm2835_init()) return 1;
 bcm2835_spi_begin();
// bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
 bcm2835_spi_setDataMode(BCM2835_SPI_MODE1);
 bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256);

 bcm2835_gpio_fsel(CS0, BCM2835_GPIO_FSEL_OUTP);
 CS(1);
 bcm2835_gpio_fsel(DRDY, BCM2835_GPIO_FSEL_INPT);
 bcm2835_gpio_set_pud(DRDY, BCM2835_GPIO_PUD_UP);
 bcm2835_gpio_fsel(RST, BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_write(RST,1);
 bcm2835_gpio_fsel(CS1, BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_write(CS1,1);
 bcm2835_gpio_fsel(PDWN, BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_write(PDWN,1);
    //ADS1256.WriteReg(REG::MUX,0x01);
    //ADS1256.WriteReg(REG::ADCON,0x20);
   // ADS1256.CfgADC(ADS1256.GAIN_1,ADS1256.S15);
 uint8_t id = ADS1256.ReadChipID();
 printf("ASD1256 Chip ID = 0x%d (\33[1;%s\33[0m)\n",
  id, id==3?"32mOK":"31mError");
 signal(SIGINT,sig_handler);
 ADS1256.CfgADC(ADS1256.GAIN_1, ADS1256.S50);
 ADS1256.StartScan(0);
 printf("\n\n\n\n\n\n\n");	// 7x
 while (!abort) {
  while (!ADS1256.Scan());
  uint8_t i=ADS1256.Channel-2&7;
  int32_t adc = ADS1256.GetAdc(i);
  float volt = adc * 5.988E-7F;	// 100/167 µV
  printf("%d = %06X, %8ld (%.6f V)\n", i, adc&0xFFFFFF, adc, volt);
  if (i==7)
   printf("\33[%dA", ch_num);	// Kursor hoch
  bsp_DelayUS(19000);
 }
 bcm2835_spi_end();
 bcm2835_close();
 for (uint8_t i=ADS1256.Channel-1&7;i<8;i++) putchar('\n');
 return 0;
}
Detected encoding: UTF-80