Hello there,
I'm trying to read cell voltages using a pcb and the max14921 chip, i have attached 3 cells (min requirement of the chip) and in total currently 9.7V (6V min).
Unfortunately i was not able to find any working code for this chip, there are a few libraries out there (Github, different forums,...) but none of them are really working.
I've tried to contact the vendor, but i haven't got any response for like 3 weeks..
Attached the Code which i'm using and the corresponding schematic.
Does anyone have an idea, why its not working? I'm receiving raw values of the adc of 65535, which indicates theres something quite wrong.
PS: GPIO38 needs to be high for giving power to the various devices. 14 is the EN_AFE for the max14921.
#include <SPI.h>
// Pinbelegung
const int clockPin = 12; // SCLK
const int miso = 13; // MISO
const int mosi = 11; // MOSI
const int adcCS = 44; // Chip Select für den ADC (AD7685)
const int afeCS = 42; // Chip Select für den AFE (MAX14921)
const int sampl = 43; // SAMPL-Pin
// SPI Befehlsdefinitionen aus der Bibliothek
#define MD_AK35_SPI_SAMPLB_ENABLE 0x04
#define MD_AK35_SPI_SAMPLB_DISABLE 0x00
#define MD_AK35_SPI_DIAG_ENABLE 0x02
#define MD_AK35_SPI_DIAG_DISABLE 0x00
#define MD_AK35_SPI_LOPW_ENABLE 0x01
#define MD_AK35_SPI_LOPW_DISABLE 0x00
#define MD_AK35_SPI_TXSEL_BUFFERED 0x18
#define GPIO38 38
#define GPIO14 14
// Zellen Auswahl Tabelle aus der Bibliothek
uint8_t gMD_AK35_CellSelect_Table[16] = {
0x80, 0xC0, 0xA0, 0xE0, 0x90, 0xD0, 0xB0, 0xF0,
0x88, 0xC8, 0xA8, 0xE8, 0x98, 0xD8, 0xB8, 0xF8
};
// Globale Variablen für die Objektparameter
typedef struct {
uint8_t acqCellNumber;
int acqCellSampleTmrValueMsec;
int acqCellRepeatTmrValueMsec;
int acqCellSettlingTimeUsec;
uint8_t spiSamplB;
uint8_t spiDiag;
uint8_t spiLoPw;
} MD_AK35_INSTANCE_T;
MD_AK35_INSTANCE_T MD_AK35_obj;
void setup() {
delay(5000);
pinMode(clockPin, OUTPUT);
pinMode(miso, INPUT);
pinMode(mosi, OUTPUT);
pinMode(adcCS, OUTPUT);
pinMode(afeCS, OUTPUT);
pinMode(sampl, OUTPUT);
pinMode(GPIO38, OUTPUT);
pinMode(GPIO14, OUTPUT);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV8); // Verlangsamt den SPI-Bus
SPI.setDataMode(SPI_MODE0); // SPI Modus 0
SPI.setBitOrder(MSBFIRST); // MSB zuerst
digitalWrite(afeCS, HIGH); // CS für AFE initial auf HIGH
digitalWrite(adcCS, HIGH); // CS für ADC initial auf HIGH
digitalWrite(sampl, HIGH); // SAMPL-Pin initial auf HIGH
digitalWrite(GPIO38, HIGH);
digitalWrite(GPIO14, LOW);
Serial.begin(9600);
// Setup initial parameters
MD_AK35_obj.acqCellNumber = 16;
MD_AK35_obj.acqCellSampleTmrValueMsec = 4; // Standard: 4 ms
MD_AK35_obj.acqCellRepeatTmrValueMsec = 6; // Standard: 6 ms
MD_AK35_obj.acqCellSettlingTimeUsec = 10; // Standard: 10 us
MD_AK35_obj.spiSamplB = MD_AK35_SPI_SAMPLB_DISABLE;
MD_AK35_obj.spiDiag = MD_AK35_SPI_DIAG_DISABLE;
MD_AK35_obj.spiLoPw = MD_AK35_SPI_LOPW_DISABLE;
// Durchführung einer Offset-Kalibrierung
offsetCalibration();
}
void loop() {
// Zellen 1 bis 8 auslesen und Spannungen anzeigen
for (uint8_t cell = 1; cell <= 8; cell++) {
float voltage = measureCellVoltage(cell);
Serial.print("Spannung an Zelle ");
Serial.print(cell);
Serial.print(": ");
Serial.print(voltage, 3); // Spannung mit 3 Dezimalstellen
Serial.println(" V");
}
Serial.println("\n\n\n");
delay(5000); // Fünf Sekunden warten, bevor erneut gemessen wird
}
void offsetCalibration() {
// SAMPL aktivieren
digitalWrite(sampl, HIGH);
// Offset-Kalibrierung starten
digitalWrite(afeCS, LOW);
SPI.transfer16(0x000040); // SPI-Befehl für Offset-Kalibrierung
digitalWrite(afeCS, HIGH);
delay(8); // 8ms warten, wie im Flowchart angegeben
// SAMPL deaktivieren
digitalWrite(sampl, LOW);
}
float measureCellVoltage(uint8_t cell) {
uint16_t rawValue = 0;
float voltage = 0.0;
// SAMPL aktivieren
digitalWrite(sampl, HIGH);
// Zellenauswahl SPI-Befehl erstellen
uint8_t spiCmd = gMD_AK35_CellSelect_Table[cell - 1];
spiCmd |= (MD_AK35_obj.spiSamplB | MD_AK35_obj.spiDiag | MD_AK35_obj.spiLoPw);
// SPI-Befehl zur Zellenspannungsmessung senden
rawValue = MD_AK35_SpiTransfer24(0x00, 0x00, spiCmd);
// Chip Select toggeln und erneut senden
digitalWrite(afeCS, HIGH);
digitalWrite(afeCS, LOW);
rawValue = MD_AK35_SpiTransfer24(0x00, 0x00, spiCmd);
digitalWrite(afeCS, HIGH);
// SAMPL deaktivieren
digitalWrite(sampl, LOW);
// Rohwert in Spannung umrechnen
voltage = convertToVoltage(readAD7685());
return voltage;
}
// Funktion zur Umrechnung des ADC-Wertes in Spannung
float convertToVoltage(uint16_t adcValue) {
// Beispiel: Umrechnung für 16-Bit-ADC mit Referenzspannung von 5V
Serial.print("RAW: ");
Serial.println(adcValue);
float voltage = (adcValue / 65535.0) * 5.0;
return voltage;
}
// Funktion zur Messung vom AD7685
uint16_t readAD7685() {
uint16_t result = 0;
// Chip Select des ADC aktivieren
digitalWrite(adcCS, LOW);
// Kurze Verzögerung, um den Chip zu stabilisieren
delayMicroseconds(1);
// 16-Bit Wert über SPI auslesen
result = SPI.transfer16(0x0000);
// Chip Select des ADC deaktivieren
digitalWrite(adcCS, HIGH);
return result;
}
// SPI Transfer von 3 Datenbytes (aus der Bibliothek)
long MD_AK35_SpiTransfer24(uint8_t byte1, uint8_t byte2, uint8_t byte3) {
long ak35Data = 0;
byte spiData = 0;
spiData = SPI.transfer(byte1);
ak35Data = spiData;
ak35Data <<= 8;
spiData = SPI.transfer(byte2);
ak35Data |= spiData;
ak35Data <<= 8;
spiData = SPI.transfer(byte3);
ak35Data |= spiData;
return ak35Data;
}