Post Go back to editing

AN9541-BATImpedance integration with other controllers (no ADICUP3029 CPU)

Thread Summary

The user encountered issues integrating AD5940/AD5941 BAT Impedance application code with a Linux-based system, including missing jumpers (JP7, JP8, JP9) and incomplete SDK documentation. The final solution involved installing JP7 and JP9, rewriting SPI drivers to handle 16-bit and 32-bit register access correctly, and ensuring proper sequencer and interrupt configurations. The AD5940/AD5941 datasheet and SDK were criticized for lacking clarity and completeness, particularly regarding register definitions and silicon revisions.
AI Generated Content
Category: Software
Product Number: EVAL-AD5941BATZ, AD5941, AD5941, AD5941
Software Version: 1

Hi Akila, and others in you team.
I am trying to integrate the BAT Impedance application code examples with my Linux based system (no ADICUP3029 CPU)
I

Edit Notes

After further investigation progress has been made see latter posts
[edited by: CAMTEK at 11:03 AM (GMT -5) on 28 Nov 2025]
  • Further to my post.
    1. I am using example files located at ...https://github.com/analogdevicesinc/ad5940-examples/tree/master/examples/AD5940_BATImpedance    Is this the latest source of updated project files?
    2. Main issues are I cannot seem to get AD5940_BATImpedance.c and AD5940Main.c code files to produce any output.
    3. After further investigation progress has been made see latter posts

    Thanks
    Collin.



  • Further Notes.
    There appears to be massive issues with the AD5940 datasheet and ADI SDK apps and documentation. 
    I my view, the ad5940 datasheet documentation is a complete mess, not clearly defined at all.
    How many silicon versions of this chip are there I have the S2 silicon but it appears there are up to 6 different silicon versions and each one has a different library version with different instructions and I can find no documentation on these issues, their differences and all the defined registers and types. 
    ADI provides the ADICUP3029Port.c file but not the header file ADuCM3029.h ?
    The ad5940.h file does not list all the Registers or their defined names such as, 0x0104 = GPIOCON and many others?
    I would really appreciate some help with configuring the sequencer and interrupts control logic in the ad5940 chip and full library definitions for my chip ... for v0.2.1:?
    The main issues I have are the configurations and interrupt control setups. 
    ADI provides example SDK apps .. it would be great if there was some documentation on how they work .. the inline c code doc is pretty basic ?
    Surely there must exist a clear and concise document(s) and datasheets on how to configure such a great chip .. a great chip is only great if it has clear concise documentation that goes with it , unfortunately I cannot find it with the ad5940/1.
    I understand the SDK's are helpers only, but not all users want to use the ADI CPU in there applications, so a clear understanding of these setups would be very helpful, we don't want to re-invent the wheel each time. 
    Regards
    Collin.




  • Further Notes_2:

    THE ADI SDK are incomplete (the builds from GitHub or the evaluation boards must be ship with stripped-down register maps)
    WHERE ARE THESE REGISTERS AND WHY ARE THEY NOT DEFINED IN THE ADI SDK's
    #define REG_AFEINTSTA 0x21F4 // AFE interrupt status register
    #define REG_AFEINTCLR 0x21F0 // AFE interrupt clear register
    #define REG_AFEINTIEN 0x21F8 // AFE interrupt enable register
    #define REG_AFEINTGPO0 0x21C0 // Map interrupt sources to GPO0
    #define REG_AFEINTGPO1 0x21C4 // Map interrupt sources to GPO1
    #define REG_AFECON 0x2008 // AFE global control register (for control / config bits)

    This is one of the most confusing parts of the AD5940/AD5941 architecture — Analog Devices never
    properly clarified which registers are 16-bit vs 32-bit, even though the SPI interface itself is always 32-bit aligned.
    This is Why ADI’s SDK Code Is Misleading? e.g.
    ADI’s SDK just reads everything as 32 bits, regardless of actual register width.
    AFE control/config (0x2000–0x23FF) Mostly 16-bit Control/status regs like AFECON, AFEINTIEN, AFEINTSTA,
    GPOx are all 16-bit.?
    Sequencer memory (0x0800–0x09FF) 32-bit Must write full 32-bit instruction words.
    DSP data memory (0x3000–0x33FF) 32-bit FIFO, waveform data, etc.
    High-speed ADC registers 32-bit ADC result, filter coefficients, etc.
    Low-level power/oscillator/system registers Mostly 16-bit For example OSCCON, HSLOCON, LFOSCCON.
    Identification registers (CHIPID, ADIID) 32-bit but Return 0x55020441 and 0x41445502 for S2 silicon.

    Hence, the AD5940/AD5941 family is very messy in this regard.
    Analog Devices released several silicon revisions (“silicon spins” or “tape-outs” as they are normally described),
    and each one quietly changed internal register maps, bitfields, and even sequencing behavior
    — very often without updating the public documentation properly..... leaves me completely baffled!
    So each silicon revision apparently fixed the analog or sequencer timing bugs, but ADI chose not
    to re-spin the chip under a new part number — they simply may have updated internal IDs Silicon ID's?

    In AD5940 S2, the GPIO function routing to interrupt outputs changed for same reason?
    In S1 silicon you could apparently do this ? AD5940_WriteReg(REG_AFEINTGPO0, AFEINTSRC_ENDSEQ);
    But in Silicon S2 you cannot.. Why?
    The AD5940LIB v0.2.1 (S2 silicon), does not define some of the new macros used in later Analog Devices
    internal test firmware and SDK's (like BITM_AFECON_GPOEN and REG_AGPIOPINCFG).

    After further investigation progress has been made see latter posts

  • Further Notes_3

    On S2 (second silicon revision of AD5940/41), Analog Devices seems to have quietly moved or disabled the old “AGPIO” block
    used in the first revision (S1). They must have integrated it into a different digital peripheral group
    — so the 0x2000–0x2600 block that contained .... AGPIO_GP0OUT/CLR/TGL etc. is now unmapped or disappeared?

    To Use the new GPIO register map — I will need the full S2-specific documentation from Analog Devices.
    But this isn’t publicly available in the current datasheet.... Why?
    I now request full hidden details via this ADI’s Engineer Zone forum ....Can someone help?
    Has anyone been able to translate any ADI SDK apps e.g. the BATImpedence code for the EVAL-AD5941BATZ
    pcb (without ADI MCU) to work on another processor or operating system using the S2 silicon chips?

    I have re-written fully working separate SPI drivers for reading and writing 16bit and or 32bit words and off course
    they all use 16bit Register Addresses as required in the ad5940 datasheet. As mentioned earlier the ADI SDK's
    blindly use 32bit registers for both reading and writing but we have no documented valid description which registers
    are defined as 16/32bit and many registers are not defined at all?


    After further investigation progress has been made see latter posts

  • Further Notes_4

    Here is the one of the main parts that FAILS (from ADI published BATImpedance.c SDK file) .... Program hangs in this function ( AD5940Err AppBATInit(); )LOOP as Flagged in the RED COLORED code below ... ? 
    (file  location: https://github.com/analogdevicesinc/ad5940-examples/blob/master/examples/AD5940_BATImpedance/BATImpedance.c )

    After further investigation progress has been made see latter posts
     
  • Further Notes_5

    POSSIBLE ROOT CAUSES?

    The AD5940/1 chips digital/analog domain is not internally being powered or clocked, ?

    • Any register writes to the AFE block silently fail.

    • The sequencer never runs → no ENDSEQ interrupt ever appears.

    On the S2 silicon, the digital power gate is controlled by the AFECON register? — maybe need to set DIGINEN (bit 2) and DIGCLKEN (bit 3) before any sequencer or GPIO operation.

    I cannot understand/see how the original ADI SDK code works and why it should, maybe it just uses the old S1 Silicon version or different ad5940.c/.h files from the published ones or has hidden code that makes it work somehow?

    My current Debug Code Output:

    After further investigation progress has been made see latter posts

  • Further Notes_6


    Latest debug code Dump:

    === AD5940 Linux BAT capture --- starting ===
    === Hardware Reset / GPIO initialized and SPI initialized OK ===
    === Calling official ADI AD5940PlatformCfg() now ===
    INITIALIZING AD5940 REGISTERS
    Current Silicon is S2
    AD5940LIB Version:v0.2.1
    AD5940PlatformCfg() completed ===
    AD5940BATStructInit() completed ===
    === Calling AppBATInit() now ===
    AppBATInit(): starting...
    [OK] AppBATInit: Init sequence written Addr=0x00000000 Len=35
    [OK] AppBATInit: Measure sequence written Addr=0x00000023 Len=6
    [OK] AppBATInit: Init sequence triggered (ID=1)

    [ERR] AppBATInit: ENDSEQ not seen within 5000 ms
    DIAG: REG_AFE_AFECON = 0x00000008
    DIAG: AGPIO GP0 OEN=0x0005 OUT=0x0000 IN=0x0000
    DIAG: INTC FLAG (AFEINTC_1) = 0x00000000
    DIAG: INTC CFG (AFEINTC_1) = 0x00000000
    DIAG: INTC FLAG (AFEINTC_0) = 0x00000000
    DIAG: INTC CFG (AFEINTC_0) = 0x00000000
    DIAG: InitSeqInfo: SeqId=1 Addr=0x00000000 Len=35 WriteSRAM=0
    DIAG: MeasureSeqInfo: SeqId=0 Addr=0x00000023 Len=6 WriteSRAM=0
    AppBATInit failed
    === AppBATInit() FAILED ===
    Cleaning up


    Analysis:
    AFEINTC_1 is configured to capture all interrupts (including AFEINTSRC_ENDSEQ).

    AFEINTC_0 only captures FIFO threshold interrupts (for GP0 toggling).

    InitSeqInfo: SeqId=1 Addr=0x00000000 Len=35 WriteSRAM=0
    SDK expects that 35 command words are already in SRAM at address 0x0000.?
    But platform’s AD5940_SEQCmdWrite() might not actually write those commands to SRAM because WriteSRAM=0.?
    WriteSRAM = 0 → no upload occurs from MCU memory.... Thus SRAM region is blank.?
    Sequencer enabled → finds 0x00000000 (NOP), doesn’t generate ENDSEQ → HANG.?

    After further investigation progress has been made see latter posts

  • Further Notes _7

    Its a little disappointing that my issues cannot illicit even a small response/rebuke from ADI Engineer Zone?
    May need to drop the AD5940/1 Chip in the "not useable basket"?
    Its a real pity, may have lost the potential of a few million chip sales per year? Upside down

  • Hi  ,

    Ivan here. I saw this thread and wanted to chime in — I’ve used the AD5940 for the CN0565 EIT Measurement System reference design and have hands-on experience with the TinyIIOD project related to its No-OS driver. Hopefully, I can help answer some of your questions.

    For your first set of questions:


    1. static unsigned char AD5940_ReadWrite8B(unsigned char data);  -> this function is used for sending the first byte or the command byte from host to AD5940. I've compiled the command byte here in figure 1


    2. static uint16_t AD5940_ReadWrite16B(uint16_t data) -> this function is used for the read and write for 16-bit data
    3. static uint32_t AD5940_ReadWrite32B(uint32_t data)  -> this function is used for the read and write for 32-bit data
    4. void AD5940_ReadWriteNBytes(unsigned char *pSendBuffer,unsigned char *pRecvBuff,unsigned long length);  -> you can view this function as the generic spi read/write for the ad5940. I'll provide an image that may help explain how AD5940_ReadWrite8B, AD5940_ReadWrite16B, AD5940_ReadWrite32B, and AD5940_ReadWriteNBytes ties/work together.



    1. Some functions like .. AD5940_Initialize(void); appear to work ... but for some reason I cannot seem to read-back was was written to the initialization registers, is this a common issue?

    From my experience, I haven't had problems in reading back the init registers. May I ask if what you're reading in the init registers are garbage value? Or is it not reading anything at all?


    2. Running the ad5950Main.c is not retrieving and valid data as yet, not sure exactly why?

    May I ask if you have any snapshot or copy paste of the values you retrieved?


    3. I have modified the BATImpedance function "static void PreCharge(unsigned char channel) " to work with my code but the EVAL-BATZ board, does not even have the jumpers JP8 or JMP9 so I wonder why this code will even work.

    For this, I want to ask where did you get the JP8 and JP9 part? I checked the user guide for the EVAL-BATZ and I didn't saw any jumper configurations that needs to be done. You can find the user guide here: wiki.analog.com/.../cn0510


    4. Can you please confirm all the necessary functions that are needed to make the EVAL_BATZ system work, unecessary code and built-in connections with the ADI CPU (ADICUP3029) make it difficult to know precisely what code and functions are needed to make this work. 

    For a minimal application (where you can verify/test if its working you can use the following:

    1.  AD5940PlatformCfg(); -> Initialize AD5940's basic blocks

    2. AD5940BATStructInit -> configure's parameters for the EVAL-AD5941BATZ

    3. AppBATInit -> Initialize the BAT application

    4. AppBATCtrl -> Measures RCAL and Measures battery

    5. AppBATISR -> read FIFO and process data

    6. BATShowResults -> print measurement in UART

    7. AD5940_SEQMmrTrig - > starts next measurement using MMR write


    5. Also the ad5940 data sheet is sadly lacking in details, do you have a detailed Map or table listing all the ad5941 registers and their functions, that also state which registers are defined as 32 or 16 bit registers, Why I cannot read the initialization registers etc.

    I checked the datasheet and it doesn't have a summarized table consisting of all the registers but the registers and functions can be found under their category. An example would be the HSDACCON register that can be found under HIGH SPEED DAC CIRCUIT, I have also highlighted the area where you can check if that register is either 16/32-bit.


    6. The ad5940 only shows 10 x 16bit registers that need to be initialized after reset by the ADI code functions (for BATZ) show many more registers that include both 16bit and 32bit reigisters.

    The difference is due to the scope of the datasheet vs the application. The datasheet only listed "essential registers" that must be set for the device to exit reset and operate but in the ADI sample code, it includes all operational configuration for a complete application for EVAL-BATZ.

    The 16/32-bit registers is handled by the if statement in the read and write of the ad5940

    7. The ad5940 data sheet does not list any 32 bit registers .. so what's going on?

    May I ask what do you mean by this?

    I’ll go over your questions below carefully and get back to you with detailed answers. Thanks for bearing with me — I’ll reply as soon as I can.

    Regards,

    Ivan

  • Thank you for your response Ivan,

    In response to your questions,

    1. Yes I understand the Command structures and believe I have all those under control. I understand that the original ADI code used separate 8/16/32 bit SPI transactions because the code manually controlled the SPI_CS line. In my system there is no need to specifically and manually control the SPI_CS line as most modern CPU's automatically control the SPI_CS line according to the SPI mode of operation and have in fact made working SPI transactions for all these SPI transactions (see below) in my hardware porting file. 

    void AD5940_Delay10us(uint32_t time);
    void AD5940_RstClr(void);
    void AD5940_RstSet(void);
    void AD5940_Reset(void);
    void AD5940_CsClr(void);   -----> dummy does nothing since not needed 
    void AD5940_CsSet(void);  -----> dummy does nothing since not needed 
    void AD5940_D3Clr(void);   -----> replaces... Arduino_WriteDn() in  PreCharge() function [BATImpedance.c]
    void AD5940_D3Set(void);  -----> replaces... Arduino_WriteDn() in  PreCharge() function [BATImpedance.c]
    void AD5940_D4Clr(void);  -----> replaces... Arduino_WriteDn() in  PreCharge() function [BATImpedance.c]
    void AD5940_D4Set(void); -----> replaces... Arduino_WriteDn() in  PreCharge() function [BATImpedance.c]
    uint32_t AD5940_ClrMCUIntFlag(void);
    uint32_t  AD5940_GetMCUIntFlag(void);
    void AD5940_HWReset2(void);   ----> called by ad5940.c for equivalent function emulation
    void ad5940_write_reg16(uint16_t addr, uint16_t value);
    void ad5940_write_reg32(uint16_t addr, uint32_t value);
    uint32_t ad5940_read_reg32(uint16_t addr);
    uint16_t ad5940_read_reg16(uint16_t addr);
    uint8_t ad5940_read_reg8(uint16_t addr);
    void AD5940_ReadWriteNBytes();   -----> dummy does nothing since does not meet ad5940 SPI protocol
    AD5940_SPIWriteReg(uint16_t RegAddr, uint32_t RegData) ... calls either the 16/32 bit functions above


    Some not all of the 
    AD5940_Initialize() writes can be read back for confirmation OK .. I think the AD5940 chip processes some of these registers in such a way that you cannot read back exactly what was written?

    2. answered above
    3. answered above
    4. From my investigation the AD5940_ReadWriteNBytes() function is not needed it doesn't really conform the the ad5940 chip SPI protocol since my SPI functions all work..The ad5940 basically requires 2 SPI packets for reading and writing to its registers. So sending a one or two bytes using this function requires manual control of the SPI_CS line?
    I understand you screen shots on how the ADI AD5940_ReadWriteNBytes() function works but as I said I have implemented these without the need to control the SPI_CS lines using separate manual GPIO control.
    So I have replace the ADI ...  static uint32_t AD5940_SPIReadReg(uint16_t RegAddr)  in ad5940.c with my own implementation below which works fine. 

    static uint32_t AD5940_SPIReadReg(uint16_t RegAddr)
    {  
        // FUNCTION REPLACED BY COLLIN
        if (is_32bit_reg(RegAddr))
            return ad5940_read_reg32(RegAddr);  // does two 16‑bit accesses
        else
            return ad5940_read_reg16(RegAddr);  // single 16‑bit access

    }

    But I need a better definition of my function ... (is_32bit_reg(RegAddr) because I dont have a data sheet that defines ALL address space as there should be in the datasheet?
    Currently my code relies on a basic lookup of know 32bit addresses .. maybe you could help me out with a better definition to help fix confusing ADI code?

    bool is_32bit_reg(uint16_t addr)
    {
        switch(addr) {
            case 0x020C: // SEQADDR
            case 0x0210: // SEQDATA
            case 0x0218: // FIFOCNT
            case 0x021C: // FIFODATA
            case 0x0228: // SEQSRAMRDATA
            case 0x022C: // SEQSRAMWRDATA
                return true;
            default:
                return false;
        }
    }



    5. Yes I can see most (not all) of the registers in the data sheet, it doesn't spell out which registers are are 16 or 32 bit registers and what makes it even more confusing is that at times Register address are shown as 32bit addresses when in fact ALL registers addresses are 16bit wide and I think ALL data in these registers are in fact 16bit wide also ... but in some cases are read or written to as 32bits by reading or writing to consecutive 16bit register address. And what makes it even more confusing is the ADI SDK code freely uses/swaps 16bit/32bit read/write definitions, ADI has functions defined as 
    uint32_t AD5940_GetADIID(void); /* Read ADIID */
    uint32_t AD5940_GetChipID(void); /* Read Chip ID */

    These should return 16bit values not 32bit values .. If my code reads these registers as 32bit I get the two corresponding registers ? 

    6. Your image below is this ADI SDK code ... where exactly is this defined?


    7. As I said I don't think the ad5940 clearly lists all the 32bit registers and some are not listed in the ad5940.h file ?

    Please read the remainder of my posts, I have improved my code and getting closer but there are some things I do not fully understand. I still cannot get the BATImpedance example code to function correctly it is getting HUNG at the BATInit() function shown above.

    The EVAL-AD5951-BATZ board I have does not have the JP8/JP9 jumpers or headers installed.. I have installed them in case there are need for the "pre-charge" function ?

    Thanks for your help Ivan.
    Collin