EIS
This commit is contained in:
commit
9eff1ecd36
|
|
@ -0,0 +1,22 @@
|
||||||
|
.vscode
|
||||||
|
Packed
|
||||||
|
*.py
|
||||||
|
venv
|
||||||
|
build
|
||||||
|
*.swp
|
||||||
|
*.cmake
|
||||||
|
requirements.txt
|
||||||
|
ad5940*
|
||||||
|
pico_sdk_import.cmake
|
||||||
|
build*
|
||||||
|
*.png
|
||||||
|
icons/
|
||||||
|
*.pdf
|
||||||
|
|
||||||
|
build/
|
||||||
|
build_android/
|
||||||
|
build_ios/
|
||||||
|
build_macos/
|
||||||
|
build_windows/
|
||||||
|
icons
|
||||||
|
*.png
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
# File: CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
include(pico_sdk_import.cmake)
|
||||||
|
|
||||||
|
project(EIS C CXX ASM)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
pico_sdk_init()
|
||||||
|
|
||||||
|
# Add ad5940.c to the build
|
||||||
|
add_executable(EIS
|
||||||
|
main.c
|
||||||
|
ad5940.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define CHIPSEL_594X for the library
|
||||||
|
target_compile_definitions(EIS PRIVATE CHIPSEL_594X)
|
||||||
|
|
||||||
|
# REQUIRED: Tell CMake where to find headers
|
||||||
|
target_include_directories(EIS PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(EIS
|
||||||
|
pico_stdlib
|
||||||
|
hardware_spi
|
||||||
|
hardware_gpio
|
||||||
|
hardware_dma
|
||||||
|
hardware_irq
|
||||||
|
hardware_vreg
|
||||||
|
hardware_clocks
|
||||||
|
m
|
||||||
|
)
|
||||||
|
|
||||||
|
pico_enable_stdio_usb(EIS 1)
|
||||||
|
pico_enable_stdio_uart(EIS 0)
|
||||||
|
|
||||||
|
pico_add_extra_outputs(EIS)
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Name of your build directory
|
||||||
|
BUILD_DIR = build
|
||||||
|
|
||||||
|
# Name of the output file (Must match what is in CMakeLists.txt)
|
||||||
|
TARGET = EIS
|
||||||
|
|
||||||
|
# Default target: Build the project
|
||||||
|
all: $(BUILD_DIR)/Makefile
|
||||||
|
@$(MAKE) -C $(BUILD_DIR)
|
||||||
|
|
||||||
|
# Ensure the build directory exists and run CMake if needed
|
||||||
|
$(BUILD_DIR)/Makefile: CMakeLists.txt
|
||||||
|
@mkdir -p $(BUILD_DIR)
|
||||||
|
@cd $(BUILD_DIR) && cmake ..
|
||||||
|
|
||||||
|
# Clean up the build directory
|
||||||
|
clean:
|
||||||
|
@rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
# Helper to automatically flash (Mac specific path)
|
||||||
|
flash: all
|
||||||
|
@echo "Waiting for RPI-RP2 volume..."
|
||||||
|
@while [ ! -d /Volumes/RPI-RP2 ]; do sleep 0.1; done
|
||||||
|
@echo "Flashing..."
|
||||||
|
@cp $(BUILD_DIR)/$(TARGET).uf2 /Volumes/RPI-RP2/
|
||||||
|
@echo "Done."
|
||||||
|
|
||||||
|
.PHONY: all clean flash
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
/* Library Version */
|
||||||
|
AD5940LIB_VER_MAJOR, AD5940LIB_VER_MINOR, AD5940LIB_VER_PATCH, AD5940LIB_VER
|
||||||
|
|
||||||
|
/* AGPIO Registers (0x00) */
|
||||||
|
REG_AGPIO_GP0CON, REG_AGPIO_GP0OEN, REG_AGPIO_GP0PE, REG_AGPIO_GP0IEN
|
||||||
|
REG_AGPIO_GP0IN, REG_AGPIO_GP0OUT, REG_AGPIO_GP0SET, REG_AGPIO_GP0CLR, REG_AGPIO_GP0TGL
|
||||||
|
|
||||||
|
/* AGPIO Bitmasks */
|
||||||
|
BITP/M_AGPIO_GP0CON_PINxCFG (x=0-7)
|
||||||
|
BITP/M_AGPIO_GP0OEN_OEN, BITP/M_AGPIO_GP0PE_PE, BITP/M_AGPIO_GP0IEN_IEN
|
||||||
|
BITP/M_AGPIO_GP0IN_IN, BITP/M_AGPIO_GP0OUT_OUT, BITP/M_AGPIO_GP0SET_SET
|
||||||
|
BITP/M_AGPIO_GP0CLR_CLR, BITP/M_AGPIO_GP0TGL_TGL
|
||||||
|
|
||||||
|
/* AFECON Registers (0x400) */
|
||||||
|
REG_AFECON_ADIID, REG_AFECON_CHIPID, REG_AFECON_CLKCON0, REG_AFECON_CLKEN1
|
||||||
|
REG_AFECON_CLKSEL, REG_AFECON_CLKCON0KEY, REG_AFECON_SWRSTCON, REG_AFECON_TRIGSEQ
|
||||||
|
|
||||||
|
/* AFECON Bitmasks */
|
||||||
|
BITP/M_AFECON_ADIID_ADIID, BITP/M_AFECON_CHIPID_PARTID/REVISION
|
||||||
|
BITP/M_AFECON_CLKCON0_SFFTCLKDIVCNT, ADCCLKDIV, SYSCLKDIV
|
||||||
|
BITP/M_AFECON_CLKEN1_GPT1DIS, GPT0DIS, ACLKDIS
|
||||||
|
BITP/M_AFECON_CLKSEL_ADCCLKSEL, SYSCLKSEL
|
||||||
|
BITP/M_AFECON_CLKCON0KEY_DIVSYSCLK_ULP_EN
|
||||||
|
BITP/M_AFECON_SWRSTCON_SWRSTL
|
||||||
|
BITP/M_AFECON_TRIGSEQ_TRIGx (x=0-3)
|
||||||
|
|
||||||
|
/* AFEWDT Registers (0x900) */
|
||||||
|
REG_AFEWDT_WDTLD, REG_AFEWDT_WDTVALS, REG_AFEWDT_WDTCON, REG_AFEWDT_WDTCLRI
|
||||||
|
REG_AFEWDT_WDTSTA, REG_AFEWDT_WDTMINLD
|
||||||
|
|
||||||
|
/* AFEWDT Bitmasks */
|
||||||
|
BITP/M_AFEWDT_WDTLD_LOAD, BITP/M_AFEWDT_WDTVALS_CCOUNT
|
||||||
|
BITP/M_AFEWDT_WDTCON_WDTIRQEN, MINLOAD_EN, CLKDIV2, MDE, EN, PRE, IRQ, PDSTOP
|
||||||
|
ENUM_AFEWDT_WDTCON_RESET, INTERRUPT, CONTINUE, STOP
|
||||||
|
BITP/M_AFEWDT_WDTCLRI_CLRWDG
|
||||||
|
BITP/M_AFEWDT_WDTSTA_TMINLD, OTPWRDONE, LOCK, CON, TLD, CLRI, IRQ
|
||||||
|
ENUM_AFEWDT_WDTSTA_OPEN, LOCKED, SYNC_COMPLETE, SYNC_IN_PROGRESS, CLEARED, PENDING
|
||||||
|
BITP/M_AFEWDT_WDTMINLD_MIN_LOAD
|
||||||
|
|
||||||
|
/* WUPTMR Registers (0x800) */
|
||||||
|
REG_WUPTMR_CON, REG_WUPTMR_SEQORDER
|
||||||
|
REG_WUPTMR_SEQxWUPL/H (x=0-3), REG_WUPTMR_SEQxSLEEPL/H (x=0-3)
|
||||||
|
|
||||||
|
/* WUPTMR Bitmasks */
|
||||||
|
BITP/M_WUPTMR_CON_MSKTRG, CLKSEL, ENDSEQ, EN
|
||||||
|
ENUM_WUPTMR_CON_SWT32K0, SWTEXT0, SWT32K, SWTEXT, SWTEN, SWTDIS
|
||||||
|
ENUM_WUPTMR_CON_ENDSEQx (x=A-H)
|
||||||
|
BITP/M_WUPTMR_SEQORDER_SEQx (x=A-H)
|
||||||
|
ENUM_WUPTMR_SEQORDER_SEQx0-3
|
||||||
|
BITP/M_WUPTMR_SEQxWUPL/H_WAKEUPTIMEx, BITP/M_WUPTMR_SEQxSLEEPL/H_SLEEPTIMEx
|
||||||
|
|
||||||
|
/* ALLON Registers (0xA00) */
|
||||||
|
REG_ALLON_PWRMOD, REG_ALLON_PWRKEY, REG_ALLON_OSCKEY, REG_ALLON_OSCCON
|
||||||
|
REG_ALLON_TMRCON, REG_ALLON_EI0CON, REG_ALLON_EI1CON, REG_ALLON_EI2CON
|
||||||
|
REG_ALLON_EICLR, REG_ALLON_RSTSTA, REG_ALLON_RSTCONKEY, REG_ALLON_LOSCTST, REG_ALLON_CLKEN0
|
||||||
|
|
||||||
|
/* ALLON Bitmasks */
|
||||||
|
BITP/M_ALLON_PWRMOD_RAMRETEN, ADCRETEN, SEQSLPEN, TMRSLPEN, PWRMOD
|
||||||
|
BITP/M_ALLON_PWRKEY_PWRKEY, BITP/M_ALLON_OSCKEY_OSCKEY
|
||||||
|
BITP/M_ALLON_OSCCON_HFXTALOK, HFOSCOK, LFOSCOK, HFXTALEN, HFOSCEN, LFOSCEN
|
||||||
|
BITP/M_ALLON_TMRCON_TMRINTEN
|
||||||
|
BITP/M_ALLON_EI0CON_IRQxEN/MDE (x=0-3)
|
||||||
|
BITP/M_ALLON_EI1CON_IRQxEN/MDE (x=4-7)
|
||||||
|
BITP/M_ALLON_EI2CON_BUSINTEN, BUSINTMDE
|
||||||
|
BITP/M_ALLON_EICLR_AUTCLRBUSEN, BUSINT
|
||||||
|
BITP/M_ALLON_RSTSTA_PINSWRST, MMRSWRST, WDRST, EXTRST, POR
|
||||||
|
BITP/M_ALLON_RSTCONKEY_KEY
|
||||||
|
BITP/M_ALLON_LOSCTST_TRIM
|
||||||
|
BITP/M_ALLON_CLKEN0_TIACHPDIS, SLPWUTDIS, WDTDIS
|
||||||
|
|
||||||
|
/* AGPT0 Registers (0xD00) & AGPT1 Registers (0xE00) */
|
||||||
|
REG_AGPT0_LD0, REG_AGPT0_VAL0, REG_AGPT0_CON0, REG_AGPT0_CLRI0, REG_AGPT0_CAP0
|
||||||
|
REG_AGPT0_ALD0, REG_AGPT0_AVAL0, REG_AGPT0_STA0, REG_AGPT0_PWMCON0, REG_AGPT0_PWMMAT0, REG_AGPT0_INTEN
|
||||||
|
REG_AGPT1_LD1, REG_AGPT1_VAL1, REG_AGPT1_CON1, REG_AGPT1_CLRI1, REG_AGPT1_CAP1
|
||||||
|
REG_AGPT1_ALD1, REG_AGPT1_AVAL1, REG_AGPT1_STA1, REG_AGPT1_PWMCON1, REG_AGPT1_PWMMAT1, REG_AGPT1_INTEN1
|
||||||
|
|
||||||
|
/* AGPT Bitmasks */
|
||||||
|
BITP/M_AGPTx_CONx_SYNCBYP, RSTEN, EVTEN, EVENT, RLD, CLK, ENABLE, MOD, UP, PRE
|
||||||
|
BITP/M_AGPTx_CLRIx_CAP, TMOUT
|
||||||
|
BITP/M_AGPTx_STAx_RSTCNT, PDOK, BUSY, CAP, TMOUT
|
||||||
|
BITP/M_AGPTx_PWMCONx_IDLE, MATCHEN
|
||||||
|
|
||||||
|
/* AFECRC Registers (0x1000) */
|
||||||
|
REG_AFECRC_CTL, REG_AFECRC_IPDATA, REG_AFECRC_RESULT, REG_AFECRC_POLY
|
||||||
|
REG_AFECRC_IPBITS, REG_AFECRC_IPBYTE, REG_AFECRC_CRC_SIG_COMP, REG_AFECRC_CRCINTEN, REG_AFECRC_INTSTA
|
||||||
|
|
||||||
|
/* AFECRC Bitmasks */
|
||||||
|
BITP/M_AFECRC_CTL_REVID, MON_EN, W16SWP, BYTMIRR, BITMIRR, LSBFIRST, EN
|
||||||
|
|
||||||
|
/* AFE Registers (0x2000) */
|
||||||
|
REG_AFE_AFECON, REG_AFE_SEQCON, REG_AFE_FIFOCON, REG_AFE_SWCON, REG_AFE_HSDACCON
|
||||||
|
REG_AFE_WGCON, REG_AFE_WGDCLEVEL1/2, REG_AFE_WGDELAY1/2, REG_AFE_WGSLOPE1/2
|
||||||
|
REG_AFE_WGFCW, REG_AFE_WGPHASE, REG_AFE_WGOFFSET, REG_AFE_WGAMPLITUDE
|
||||||
|
REG_AFE_ADCFILTERCON, REG_AFE_HSDACDAT, REG_AFE_LPREFBUFCON, REG_AFE_SYNCEXTDEVICE
|
||||||
|
REG_AFE_SEQCRC, REG_AFE_SEQCNT, REG_AFE_SEQTIMEOUT, REG_AFE_DATAFIFORD, REG_AFE_CMDFIFOWRITE
|
||||||
|
REG_AFE_ADCDAT, REG_AFE_DFTREAL, REG_AFE_DFTIMAG, REG_AFE_SINC2DAT, REG_AFE_TEMPSENSDAT
|
||||||
|
REG_AFE_AFEGENINTSTA, REG_AFE_ADCMIN/SM, REG_AFE_ADCMAX/SMEN, REG_AFE_ADCDELTA
|
||||||
|
REG_AFE_HPOSCCON, REG_AFE_DFTCON
|
||||||
|
REG_AFE_LPTIASW0/1, REG_AFE_LPTIACON0/1
|
||||||
|
REG_AFE_HSRTIACON, REG_AFE_DE0/1RESCON, REG_AFE_HSTIACON
|
||||||
|
REG_AFE_LPMODEKEY, REG_AFE_LPMODECLKSEL, REG_AFE_LPMODECON
|
||||||
|
REG_AFE_SEQSLPLOCK, REG_AFE_SEQTRGSLP
|
||||||
|
REG_AFE_LPDACDAT0/1, REG_AFE_LPDACSW0/1, REG_AFE_LPDACCON0/1
|
||||||
|
REG_AFE_DSWFULLCON, REG_AFE_NSWFULLCON, REG_AFE_PSWFULLCON, REG_AFE_TSWFULLCON
|
||||||
|
REG_AFE_TEMPSENS, REG_AFE_BUFSENCON, REG_AFE_ADCCON
|
||||||
|
REG_AFE_DSWSTA, REG_AFE_PSWSTA, REG_AFE_NSWSTA, REG_AFE_TSWSTA
|
||||||
|
REG_AFE_STATSVAR, REG_AFE_STATSCON, REG_AFE_STATSMEAN
|
||||||
|
REG_AFE_SEQ0/1/2/3INFO, REG_AFE_CMDFIFOWADDR, REG_AFE_CMDDATACON, REG_AFE_DATAFIFOTHRES
|
||||||
|
REG_AFE_REPEATADCCNV, REG_AFE_FIFOCNTSTA, REG_AFE_CALDATLOCK
|
||||||
|
REG_AFE_ADCOFFSETHSTIA, REG_AFE_ADCGAINTEMPSENS0, REG_AFE_ADCOFFSETTEMPSENS0/1
|
||||||
|
REG_AFE_ADCGAINGN1/1P5/2/4/9, REG_AFE_ADCOFFSETGN1/1P5/2/4/9
|
||||||
|
REG_AFE_DACGAIN, REG_AFE_DACOFFSET, REG_AFE_DACOFFSETATTEN/HP
|
||||||
|
REG_AFE_ADCPGAOFFSETCANCEL, REG_AFE_ADCGNHSTIA, REG_AFE_ADCPGAGN4OFCAL
|
||||||
|
REG_AFE_ADCOFFSETLPTIA0/1, REG_AFE_ADCGNLPTIA0/1, REG_AFE_ADCGAINDIOTEMPSENS
|
||||||
|
REG_AFE_PMBW, REG_AFE_SWMUX, REG_AFE_AFE_TEMPSEN_DIO, REG_AFE_ADCBUFCON
|
||||||
|
|
||||||
|
/* AFE Bitmasks & Enums */
|
||||||
|
BITP/M_AFE_AFECON_DACBUFEN, DACREFEN, ALDOILIMITEN, SINC2EN, DFTEN, WAVEGENEN
|
||||||
|
BITP/M_AFE_AFECON_TEMPCONVEN, TEMPSENSEN, TIAEN, INAMPEN, EXBUFEN, ADCCONVEN, ADCEN, DACEN, HPREFDIS
|
||||||
|
ENUM_AFE_AFECON_OFF, ENUM_AFE_AFECON_ON
|
||||||
|
BITP/M_AFE_SEQCON_SEQWRTMR, SEQHALT, SEQHALTFIFOEMPTY, SEQEN
|
||||||
|
BITP/M_AFE_FIFOCON_DATAFIFOSRCSEL, DATAFIFOEN
|
||||||
|
BITP/M_AFE_SWCON_TxCON, SWSOURCESEL, TMUXCON, NMUXCON, PMUXCON, DMUXCON
|
||||||
|
BITP/M_AFE_HSDACCON_INAMPGNMDE, RATE, ATTENEN
|
||||||
|
BITP/M_AFE_WGCON_DACGAINCAL, DACOFFSETCAL, TYPESEL, TRAPRSTEN
|
||||||
|
BITP/M_AFE_ADCFILTERCON_AVRGNUM, SINC3OSR, SINC2OSR, AVRGEN, SINC3BYP, LPFBYPEN, ADCCLK
|
||||||
|
BITP/M_AFE_LPREFBUFCON_BOOSTCURRENT, LPBUF2P5DIS, LPREFDIS
|
||||||
|
BITP/M_AFE_CMDFIFOWRITE_CMDFIFOIN
|
||||||
|
BITP/M_AFE_CMDDATACON_DATAMEMMDE, DATA_MEM_SEL, CMDMEMMDE, CMD_MEM_SEL
|
||||||
|
ENUM_AFE_CMDDATACON_DFIFO, DSTM, DMEM32B, DMEM2K, DMEM4K, DMEM6K, CMEM, CFIFO, CSTM, CMEM32B, CMEM2K, CMEM4K, CMEM6K
|
||||||
|
BITP/M_AFE_DFTCON_DFTINSEL, DFTNUM, HANNINGEN
|
||||||
|
BITP/M_AFE_LPTIASWx_TIABIASSEL, PABIASSEL, TIASWCON
|
||||||
|
ENUM_AFE_LPTIASWx_CAPA_LP, NORM, DIO, SHORTSW, LOWNOISE, CAPA_RAMP_H, BUFDIS, BUFEN/2, TWOLEAD, SESHORTRE
|
||||||
|
BITP/M_AFE_LPTIACONx_CHOPEN, TIARF, TIARL, TIAGAIN, IBOOST, HALFPWR, PAPDEN, TIAPDEN
|
||||||
|
ENUM_AFE_LPTIACONx_DISCONRF, BYPRF, RF20K, RF100K, RF200K, RF400K, RF600K, RF1MOHM
|
||||||
|
ENUM_AFE_LPTIACONx_RL0, RL10, RL30, RL50, RL100, RL1P6K, RL3P1K, RL3P5K
|
||||||
|
ENUM_AFE_LPTIACONx_DISCONTIA, TIAGAIN200, 1K, 2K...512K
|
||||||
|
BITP/M_AFE_HSRTIACON_CTIACON, TIASW6CON, RTIACON
|
||||||
|
BITP/M_AFE_DExRESCON_DExRCON
|
||||||
|
BITP/M_AFE_HSTIACON_VBIASSEL
|
||||||
|
BITP/M_AFE_DACDCBUFCON_CHANSEL, CHAN0, CHAN1
|
||||||
|
BITP/M_AFE_LPMODECON_ALDOEN, V1P1HPADCEN, V1P8HPADCEN, PTATEN, ZTATEN, REPEATADCCNVEN_P, ADCCONVEN, HPREFDIS, HFOSCPD
|
||||||
|
BITP/M_AFE_LPDACSWx_LPMODEDIS, LPDACSW, DACCONBIT5, OVRRIDE
|
||||||
|
BITP/M_AFE_LPDACCONx_WAVETYPE, DACMDE, VZEROMUX, VBIASMUX, REFSEL, PWDEN, RSTEN
|
||||||
|
ENUM_AFE_LPDACCONx_MMR, WAVEGEN, NORM, DIAG, BITS6, BITS12, 12BIT, EN, ULPREF, AVDD, PWREN, PWRDIS, WRITEDIS, WRITEEN
|
||||||
|
BITP/M_AFE_DSWFULLCON_Dx (x=2-8), DR0
|
||||||
|
BITP/M_AFE_NSWFULLCON_NL2, NL, NR1, Nx (x=1-9)
|
||||||
|
BITP/M_AFE_PSWFULLCON_PL2, PL, Px (x=2-12), PR0
|
||||||
|
BITP/M_AFE_TSWFULLCON_TR1, Tx (x=1-11)
|
||||||
|
BITP/M_AFE_TEMPSENS_CHOPFRESEL, CHOPCON, ENABLE
|
||||||
|
BITP/M_AFE_BUFSENCON_V1P8THERMSTEN, V1P1LPADCCHGDIS, V1P1LPADCEN, V1P1HPADCEN, V1P8HPADCCHGDIS, V1P8LPADCEN, V1P8HPADCILIMITEN, V1P8HPADCEN
|
||||||
|
BITP/M_AFE_ADCCON_GNPGA, GNOFSELPGA, GNOFFSEL, MUXSELN, MUXSELP
|
||||||
|
BITP/M_AFE_STATSCON_STDDEV, SAMPLENUM, RESRVED, STATSEN
|
||||||
|
BITP/M_AFE_PMBW_SYSBW, SYSHP, BWNA, BW50, BW100, BW250, LP, HP
|
||||||
|
|
||||||
|
/* INTC Registers (0x3000) */
|
||||||
|
REG_INTC_INTCPOL, REG_INTC_INTCCLR, REG_INTC_INTCSEL0/1, REG_INTC_INTCFLAG0/1
|
||||||
|
|
||||||
|
/* SPI Commands */
|
||||||
|
SPICMD_SETADDR, SPICMD_READREG, SPICMD_WRITEREG, SPICMD_READFIFO
|
||||||
|
|
||||||
|
/* Interrupt Controller Constants */
|
||||||
|
AFEINTC_0, AFEINTC_1
|
||||||
|
AFEINTSRC_ADCRDY, DFTRDY, SINC2RDY, TEMPRDY, ADCMINERR, ADCMAXERR, ADCDIFFERR, MEANRDY, VARRDY
|
||||||
|
AFEINTSRC_CUSTOMINTx (x=0-3), BOOTLDDONE, WAKEUP, ENDSEQ, SEQTIMEOUT, SEQTIMEOUTERR
|
||||||
|
AFEINTSRC_CMDFIFOFULL, CMDFIFOEMPTY, CMDFIFOTHRESH, CMDFIFOOF, CMDFIFOUF
|
||||||
|
AFEINTSRC_DATAFIFOFULL, DATAFIFOEMPTY, DATAFIFOTHRESH, DATAFIFOOF, DATAFIFOUF
|
||||||
|
AFEINTSRC_WDTIRQ, CRC_OUTLIER, GPT0INT_SLPWUT, GPT1INT_TRYBRK, ALLINT
|
||||||
|
|
||||||
|
/* Power & Bandwidth */
|
||||||
|
AFEPWR_LP, AFEPWR_HP
|
||||||
|
AFEBW_AUTOSET, AFEBW_50KHZ, AFEBW_100KHZ, AFEBW_250KHZ
|
||||||
|
|
||||||
|
/* AFE Control Signals (Masks) */
|
||||||
|
AFECTRL_HPREFPWR, HSDACPWR, ADCPWR, ADCCNV, EXTBUFPWR, INAMPPWR, HSTIAPWR
|
||||||
|
AFECTRL_TEMPSPWR, TEMPCNV, WG, DFT, SINC2NOTCH, ALDOLIMIT, DACREFPWR, DCBUFPWR, ALL
|
||||||
|
|
||||||
|
/* Low Power Mode Control Signals */
|
||||||
|
LPMODECTRL_HFOSCEN, HPREFPWR, ADCCNV, REPEATEN, GLBBIASZ, GLBBIASP, BUFHP1P8V, BUFHP1P1V, ALDOPWR, ALL, NONE
|
||||||
|
|
||||||
|
/* Result Types */
|
||||||
|
AFERESULT_SINC3, SINC2, TEMPSENSOR, DFTREAL, DFTIMAGE, STATSMEAN, STATSVAR
|
||||||
|
|
||||||
|
/* Switch Matrix Definitions */
|
||||||
|
SWD_OPEN, RCAL0, AIN1, AIN2, AIN3, CE0, CE1, AFE1, SE0, SE1, AFE3
|
||||||
|
SWP_OPEN, RCAL0, AIN1, AIN2, AIN3, RE0, RE1, AFE2, SE0, DE0, SE1, AFE3, DE1, CE0, CE1, AFE1, PL, PL2
|
||||||
|
SWN_OPEN, RCAL1, AIN0, AIN1, AIN2, AIN3, SE0LOAD, DE0LOAD, SE1LOAD, AFE3LOAD, DE1LOAD, SE0, NL, NL2
|
||||||
|
SWT_OPEN, RCAL1, AIN0, AIN1, AIN2, AIN3, SE0LOAD, DE0, SE1LOAD, AFE3LOAD, DE1, TRTIA, DE0LOAD, DE1LOAD
|
||||||
|
|
||||||
|
/* Waveform Generator Types */
|
||||||
|
WGTYPE_MMR, WGTYPE_SIN, WGTYPE_TRAPZ
|
||||||
|
|
||||||
|
/* HSDAC Constants */
|
||||||
|
EXCITBUFGAIN_2, EXCITBUFGAIN_0P25
|
||||||
|
HSDACGAIN_1, HSDACGAIN_0P2
|
||||||
|
|
||||||
|
/* HSTIA Constants */
|
||||||
|
HSTIABIAS_1P1, VZERO0, VZERO1
|
||||||
|
HSTIARTIA_200, 1K, 5K, 10K, 20K, 40K, 80K, 160K, OPEN
|
||||||
|
HSTIADERTIA_50, 100, 200, 1K, 5K, 10K, 20K, 40K, 80K, 160K, TODE, OPEN
|
||||||
|
HSTIADERLOAD_0R, 10R, 30R, 50R, 100R, OPEN
|
||||||
|
HSTIAPWRMOE_LP, HP
|
||||||
|
|
||||||
|
/* LPDAC Constants */
|
||||||
|
LPDAC0, LPDAC1
|
||||||
|
LPDACSRC_MMR, WG
|
||||||
|
LPDACSW_VBIAS2LPPA, VBIAS2PIN, VZERO2LPTIA, VZERO2PIN, VZERO2HSTIA
|
||||||
|
LPDACVZERO_6BIT, 12BIT
|
||||||
|
LPDACVBIAS_6BIT, 12BIT
|
||||||
|
LPDACREF_2P5, AVDD
|
||||||
|
|
||||||
|
/* LPAMP/LPTIA Constants */
|
||||||
|
LPTIA0, LPTIA1
|
||||||
|
LPTIARF_OPEN, SHORT, 20K, 100K, 200K, 400K, 600K, 1M
|
||||||
|
LPTIARLOAD_SHORT, 10R, 30R, 50R, 100R, 1K6, 3K1, 3K6
|
||||||
|
LPTIARTIA_OPEN, 200R, 1K...512K
|
||||||
|
LPAMP0, LPAMP1
|
||||||
|
LPAMPPWR_NORM, BOOST1, BOOST2, BOOST3, HALF
|
||||||
|
LPTIASW(n)
|
||||||
|
|
||||||
|
/* ADC Constants */
|
||||||
|
ADCPGA_1, 1P5, 2, 4, 9
|
||||||
|
ADCMUXP_FLOAT, HSTIA_P, AIN0-6, AVDD_2, DVDD_2, AVDDREG, TEMPP/N, VSET1P1, VDE0, VSE0/1, VAFE1-4, VREF2P5, VREF1P8DAC, VZERO0/1, VBIAS0/1, VCE0/1, VRE0/1, VCE0_2, VCE1_2, LPTIA0_P, LPTIA1_P, AGND, P_NODE, IOVDD_2
|
||||||
|
ADCMUXN_FLOAT, HSTIA_N, LPTIA0_N, LPTIA1_N, AIN0-6, VSET1P1, VREF1P1, TEMPN, VZERO0/1, VBIAS0/1, AFE4, N_NODE
|
||||||
|
ADCRATE_800KHZ, 1P6MHZ
|
||||||
|
ADCSINC3OSR_2, 4, 5
|
||||||
|
ADCSINC2OSR_22, 44...1333
|
||||||
|
ADCAVGNUM_2, 4, 8, 16
|
||||||
|
|
||||||
|
/* DFT & Statistics Constants */
|
||||||
|
DFTSRC_SINC2NOTCH, SINC3, ADCRAW, AVG
|
||||||
|
DFTNUM_4, 8...16384
|
||||||
|
STATSAMPLE_128, 64, 32, 16, 8
|
||||||
|
STATDEV_1, 4, 9, 16, 25
|
||||||
|
|
||||||
|
/* Sequencer & FIFO Constants */
|
||||||
|
SEQID_0, 1, 2, 3
|
||||||
|
SEQMEMSIZE_32B, 2KB, 4KB, 6KB
|
||||||
|
SEQPINTRIGMODE_RISING, FALLING, BOTHEDGE, HIGHL, LOWL
|
||||||
|
SEQ_WAIT(ClkNum), SEQ_TOUT(ClkNum), SEQ_WR(addr,data)
|
||||||
|
SEQ_NOP(), SEQ_HALT(), SEQ_STOP(), SEQ_SLP(), SEQ_INTx(), SEQ_LEN(n)
|
||||||
|
FIFOMODE_FIFO, STREAM
|
||||||
|
FIFOSRC_SINC3, DFT, SINC2NOTCH, VAR, MEAN
|
||||||
|
FIFO_SEQID(data), ECC, CHANID
|
||||||
|
FIFOSIZE_32B, 2KB, 4KB, 6KB
|
||||||
|
WUPTENDSEQ_A - H
|
||||||
|
|
||||||
|
/* Misc Constants */
|
||||||
|
DATATYPE_ADCRAW, SINC3, SINC2, DFT, NOTCH
|
||||||
|
SLPKEY_LOCK, UNLOCK
|
||||||
|
HPOSCOUT_32MHZ, 16MHZ
|
||||||
|
AGPIO_Pin0 - Pin7
|
||||||
|
GPx_INT/TRIG/SYNC/GPIO/SLEEP/PORB/EXTCLK
|
||||||
|
LPMODECLK_HFOSC, LFOSC
|
||||||
|
SYSCLKSRC_HFOSC, XTAL, LFOSC, EXT
|
||||||
|
ADCCLKSRC_HFOSC, XTAL, EXT
|
||||||
|
ADCCLKDIV_1, 2
|
||||||
|
SYSCLKDIV_1, 2
|
||||||
|
PGACALTYPE_OFFSET, GAIN, OFFSETGAIN
|
||||||
|
AD5940ERR_OK, ERROR, PARA, NULLP, BUFF, ADDROR, SEQGEN, SEQREG, SEQLEN, WAKEUP, TIMEOUT, CALOR, APPERROR
|
||||||
|
MATH_PI, AD5940_ADIID, AD5940_CHIPID, M355_ADIID, M355_CHIPID, AD5940_SWRST
|
||||||
|
KEY_OSCCON, KEY_CALDATLOCK, KEY_LPMODEKEY
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
build/
|
||||||
|
build_android/
|
||||||
|
build_ios/
|
||||||
|
build_macos/
|
||||||
|
build_windows/
|
||||||
|
icons
|
||||||
|
*.png
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
# File: host/CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
|
project(EISConfigurator VERSION 1.0 LANGUAGES CXX C)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
# Added PrintSupport and OpenGLWidgets which are often needed by QCustomPlot
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets SerialPort PrintSupport OpenGLWidgets)
|
||||||
|
|
||||||
|
# --- QCustomPlot Integration ---
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
QCustomPlot
|
||||||
|
URL https://www.qcustomplot.com/release/2.1.1/QCustomPlot.tar.gz
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(QCustomPlot)
|
||||||
|
if(NOT qcustomplot_POPULATED)
|
||||||
|
FetchContent_Populate(QCustomPlot)
|
||||||
|
# QCustomPlot source distribution doesn't have a CMakeLists.txt
|
||||||
|
add_library(QCustomPlot
|
||||||
|
${qcustomplot_SOURCE_DIR}/qcustomplot.cpp
|
||||||
|
${qcustomplot_SOURCE_DIR}/qcustomplot.h
|
||||||
|
)
|
||||||
|
# Link required Qt modules to the library
|
||||||
|
target_link_libraries(QCustomPlot PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets Qt6::PrintSupport)
|
||||||
|
target_include_directories(QCustomPlot PUBLIC ${qcustomplot_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# --- Icon Generation ---
|
||||||
|
|
||||||
|
set(ICON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/assets/icon_source.png")
|
||||||
|
set(ICON_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icons.sh")
|
||||||
|
set(MACOS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/assets/icons/app_icon.icns")
|
||||||
|
set(WINDOWS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/assets/icons/app_icon.ico")
|
||||||
|
|
||||||
|
# Find ImageMagick 'magick' executable
|
||||||
|
find_program(MAGICK_EXECUTABLE NAMES magick)
|
||||||
|
if(NOT MAGICK_EXECUTABLE)
|
||||||
|
message(WARNING "ImageMagick 'magick' not found. Icons will not be generated.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(EXISTS "${ICON_SOURCE}" AND MAGICK_EXECUTABLE)
|
||||||
|
execute_process(COMMAND chmod +x "${ICON_SCRIPT}")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${MACOS_ICON}" "${WINDOWS_ICON}"
|
||||||
|
COMMAND "${ICON_SCRIPT}" "${MAGICK_EXECUTABLE}"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
DEPENDS "${ICON_SOURCE}" "${ICON_SCRIPT}"
|
||||||
|
COMMENT "Generating icons from source using ${MAGICK_EXECUTABLE}..."
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(GenerateIcons DEPENDS "${MACOS_ICON}" "${WINDOWS_ICON}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# --- Sources ---
|
||||||
|
|
||||||
|
set(PROJECT_SOURCES
|
||||||
|
src/main.cpp
|
||||||
|
src/MainWindow.cpp
|
||||||
|
src/GraphWidget.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(EXISTS "${ICON_SOURCE}")
|
||||||
|
list(APPEND PROJECT_SOURCES ${MACOS_ICON} ${WINDOWS_ICON})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PROJECT_HEADERS
|
||||||
|
src/MainWindow.h
|
||||||
|
src/GraphWidget.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
add_library(EISConfigurator SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
|
||||||
|
else()
|
||||||
|
add_executable(EISConfigurator MANUAL_FINALIZATION ${PROJECT_SOURCES} ${PROJECT_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(EXISTS "${ICON_SOURCE}" AND MAGICK_EXECUTABLE)
|
||||||
|
add_dependencies(EISConfigurator GenerateIcons)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(EISConfigurator PRIVATE
|
||||||
|
Qt6::Core Qt6::Gui Qt6::Widgets Qt6::SerialPort
|
||||||
|
QCustomPlot
|
||||||
|
)
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
set_target_properties(EISConfigurator PROPERTIES QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set_target_properties(EISConfigurator PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "EIS Configurator"
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER "com.eis.configurator"
|
||||||
|
MACOSX_BUNDLE_ICON_FILE "app_icon.icns"
|
||||||
|
RESOURCE "${MACOS_ICON}"
|
||||||
|
)
|
||||||
|
elseif(WIN32)
|
||||||
|
set_target_properties(EISConfigurator PROPERTIES
|
||||||
|
WIN32_EXECUTABLE TRUE
|
||||||
|
)
|
||||||
|
if(EXISTS "${WINDOWS_ICON}")
|
||||||
|
set_target_properties(EISConfigurator PROPERTIES
|
||||||
|
WIN32_ICON "${WINDOWS_ICON}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ANDROID)
|
||||||
|
qt_finalize_executable(EISConfigurator)
|
||||||
|
endif()
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
# Makefile
|
||||||
|
|
||||||
|
QT_ANDROID_KIT ?= $(HOME)/Qt/6.8.3/android_arm64_v8a
|
||||||
|
QT_IOS_KIT ?= $(HOME)/Qt/6.8.3/ios
|
||||||
|
QT_MACOS_PATH ?= /opt/homebrew/opt/qt@6
|
||||||
|
QT_WIN_PATH ?= C:/Qt/6.8.3/msvc2019_64
|
||||||
|
|
||||||
|
BUILD_DIR_MACOS = build_macos
|
||||||
|
BUILD_DIR_WIN = build_windows
|
||||||
|
BUILD_DIR_ANDROID = build_android
|
||||||
|
BUILD_DIR_IOS = build_ios
|
||||||
|
TARGET = EISConfigurator
|
||||||
|
|
||||||
|
# Android Specifics
|
||||||
|
PKG_NAME = org.qtproject.example.EISConfigurator
|
||||||
|
# CRITICAL FIX: Qt6 generates 'android-build-debug.apk' by default
|
||||||
|
APK_PATH = $(BUILD_DIR_ANDROID)/android-build/build/outputs/apk/debug/android-build-debug.apk
|
||||||
|
|
||||||
|
all: macos
|
||||||
|
|
||||||
|
desktop: macos
|
||||||
|
|
||||||
|
macos:
|
||||||
|
@echo "Building for macOS (Apple Silicon)..."
|
||||||
|
@mkdir -p $(BUILD_DIR_MACOS)
|
||||||
|
@cd $(BUILD_DIR_MACOS) && cmake .. \
|
||||||
|
-DCMAKE_PREFIX_PATH="$(QT_MACOS_PATH);/opt/homebrew" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
@$(MAKE) -C $(BUILD_DIR_MACOS)
|
||||||
|
@echo "Build Complete. Run with: open $(BUILD_DIR_MACOS)/$(TARGET).app"
|
||||||
|
|
||||||
|
windows:
|
||||||
|
@echo "Building for Windows..."
|
||||||
|
@mkdir -p $(BUILD_DIR_WIN)
|
||||||
|
@cd $(BUILD_DIR_WIN) && cmake .. \
|
||||||
|
-DCMAKE_PREFIX_PATH="$(QT_WIN_PATH)" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build $(BUILD_DIR_WIN)
|
||||||
|
|
||||||
|
android:
|
||||||
|
@if [ ! -d "$(QT_ANDROID_KIT)" ]; then echo "Error: QT_ANDROID_KIT not found at $(QT_ANDROID_KIT)"; exit 1; fi
|
||||||
|
@mkdir -p $(BUILD_DIR_ANDROID)
|
||||||
|
@cd $(BUILD_DIR_ANDROID) && cmake .. \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=$(QT_ANDROID_KIT)/lib/cmake/Qt6/qt.toolchain.cmake \
|
||||||
|
-DQT_ANDROID_ABIS="arm64-v8a" \
|
||||||
|
-DANDROID_PLATFORM=android-24 \
|
||||||
|
-DQT_ANDROID_BUILD_ALL_ABIS=OFF \
|
||||||
|
-DBUILD_ANDROID=ON \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug
|
||||||
|
@cmake --build $(BUILD_DIR_ANDROID) --target apk
|
||||||
|
@echo "APK generated at $(APK_PATH)"
|
||||||
|
|
||||||
|
ios:
|
||||||
|
@if [ ! -d "$(QT_IOS_KIT)" ]; then echo "Error: QT_IOS_KIT not found at $(QT_IOS_KIT)"; exit 1; fi
|
||||||
|
@mkdir -p $(BUILD_DIR_IOS)
|
||||||
|
@echo "Configuring iOS CMake..."
|
||||||
|
@cd $(BUILD_DIR_IOS) && cmake .. -G Xcode \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=$(QT_IOS_KIT)/lib/cmake/Qt6/qt.toolchain.cmake \
|
||||||
|
-DCMAKE_SYSTEM_NAME=iOS \
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=16.0 \
|
||||||
|
-DBUILD_IOS=ON
|
||||||
|
@echo "iOS Project generated at $(BUILD_DIR_IOS)/$(TARGET).xcodeproj"
|
||||||
|
|
||||||
|
|
||||||
|
run:
|
||||||
|
@open $(BUILD_DIR_MACOS)/$(TARGET).app
|
||||||
|
|
||||||
|
# --- Android Deployment Wrappers ---
|
||||||
|
|
||||||
|
install_android: android
|
||||||
|
@echo "Installing $(APK_PATH) to device..."
|
||||||
|
@adb install -r $(APK_PATH)
|
||||||
|
|
||||||
|
run_android: install_android
|
||||||
|
@echo "Launching $(PKG_NAME)..."
|
||||||
|
@adb shell am start -n $(PKG_NAME)/org.qtproject.qt.android.bindings.QtActivity
|
||||||
|
|
||||||
|
debug_android: run_android
|
||||||
|
@echo "Attaching Logcat (Ctrl+C to exit)..."
|
||||||
|
@adb logcat -v color -s EISConfigurator Qt:* DEBUG
|
||||||
|
|
||||||
|
# --- Cleaning ---
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning build artifacts..."
|
||||||
|
@if [ -f "$(BUILD_DIR_MACOS)/Makefile" ]; then cmake --build $(BUILD_DIR_MACOS) --target clean; fi
|
||||||
|
@if [ -f "$(BUILD_DIR_WIN)/Makefile" ] || [ -f "$(BUILD_DIR_WIN)/build.ninja" ]; then cmake --build $(BUILD_DIR_WIN) --target clean; fi
|
||||||
|
@if [ -f "$(BUILD_DIR_ANDROID)/Makefile" ] || [ -f "$(BUILD_DIR_ANDROID)/build.ninja" ]; then cmake --build $(BUILD_DIR_ANDROID) --target clean; fi
|
||||||
|
@if [ -d "$(BUILD_DIR_IOS)/$(TARGET).xcodeproj" ]; then cmake --build $(BUILD_DIR_IOS) --target clean; fi
|
||||||
|
|
||||||
|
distclean:
|
||||||
|
@rm -rf $(BUILD_DIR_MACOS) $(BUILD_DIR_WIN) $(BUILD_DIR_ANDROID) $(BUILD_DIR_IOS)
|
||||||
|
@echo "Removed all build directories."
|
||||||
|
|
||||||
|
.PHONY: all desktop macos windows android ios run install_android run_android debug_android clean distclean
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.qtproject.example.YrCrystals"
|
||||||
|
android:versionName="1.0"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<application android:label="Yr Crystals"
|
||||||
|
android:name="org.qtproject.qt.android.bindings.QtApplication"
|
||||||
|
android:requestLegacyExternalStorage="true">
|
||||||
|
|
||||||
|
<activity android:name="org.qtproject.qt.android.bindings.QtActivity"
|
||||||
|
android:label="Yr Crystals"
|
||||||
|
android:screenOrientation="unspecified"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data android:name="android.app.lib_name" android:value="YrCrystals"/>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Yr Crystals</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIRequiresFullScreen</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- Permissions -->
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>This app requires audio access to visualize music.</string>
|
||||||
|
<key>NSAppleMusicUsageDescription</key>
|
||||||
|
<string>This app requires access to your music library to play tracks.</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>This app requires access to the photo library to load album art.</string>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>This app requires camera access for visualizer input.</string>
|
||||||
|
|
||||||
|
<!-- File Access -->
|
||||||
|
<key>UIFileSharingEnabled</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<!-- Document Types -->
|
||||||
|
<key>CFBundleDocumentTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Audio</string>
|
||||||
|
<key>LSHandlerRank</key>
|
||||||
|
<string>Alternate</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>public.audio</string>
|
||||||
|
<string>public.mp3</string>
|
||||||
|
<string>public.mpeg-4-audio</string>
|
||||||
|
<string>public.folder</string>
|
||||||
|
<string>public.directory</string>
|
||||||
|
<string>public.content</string>
|
||||||
|
<string>public.data</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>audio</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
# scripts/generate_icons.sh
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Argument 1: Path to magick executable
|
||||||
|
MAGICK_BIN="$1"
|
||||||
|
|
||||||
|
# Fallback if not provided
|
||||||
|
if [ -z "$MAGICK_BIN" ]; then
|
||||||
|
MAGICK_BIN="magick"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Assumes running from Project Root
|
||||||
|
SOURCE="assets/icon_source.png"
|
||||||
|
OUT_DIR="assets/icons"
|
||||||
|
|
||||||
|
if [ ! -f "$SOURCE" ]; then
|
||||||
|
echo "Error: Source image '$SOURCE' not found in $(pwd)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify magick works
|
||||||
|
"$MAGICK_BIN" -version >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: ImageMagick tool '$MAGICK_BIN' not found or not working."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
ICONSET="$OUT_DIR/icon.iconset"
|
||||||
|
mkdir -p "$ICONSET"
|
||||||
|
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 16x16 "$ICONSET/icon_16x16.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 32x32 "$ICONSET/icon_16x16@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 32x32 "$ICONSET/icon_32x32.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 64x64 "$ICONSET/icon_32x32@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 128x128 "$ICONSET/icon_128x128.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 256x256 "$ICONSET/icon_128x128@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 256x256 "$ICONSET/icon_256x256.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 512x512 "$ICONSET/icon_256x256@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 512x512 "$ICONSET/icon_512x512.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 1024x1024 "$ICONSET/icon_512x512@2x.png"
|
||||||
|
|
||||||
|
iconutil -c icns "$ICONSET" -o "$OUT_DIR/app_icon.icns"
|
||||||
|
rm -rf "$ICONSET"
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
"$MAGICK_BIN" "$SOURCE" \
|
||||||
|
\( -clone 0 -scale 256x256 \) \
|
||||||
|
\( -clone 0 -scale 128x128 \) \
|
||||||
|
\( -clone 0 -scale 64x64 \) \
|
||||||
|
\( -clone 0 -scale 48x48 \) \
|
||||||
|
\( -clone 0 -scale 32x32 \) \
|
||||||
|
\( -clone 0 -scale 16x16 \) \
|
||||||
|
-delete 0 -alpha off -colors 256 "$OUT_DIR/app_icon.ico"
|
||||||
|
|
||||||
|
# Android
|
||||||
|
ANDROID_DIR="$OUT_DIR/android/res"
|
||||||
|
|
||||||
|
mkdir -p "$ANDROID_DIR/mipmap-mdpi"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 48x48 "$ANDROID_DIR/mipmap-mdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
mkdir -p "$ANDROID_DIR/mipmap-hdpi"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 72x72 "$ANDROID_DIR/mipmap-hdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
mkdir -p "$ANDROID_DIR/mipmap-xhdpi"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 96x96 "$ANDROID_DIR/mipmap-xhdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
mkdir -p "$ANDROID_DIR/mipmap-xxhdpi"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 144x144 "$ANDROID_DIR/mipmap-xxhdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
mkdir -p "$ANDROID_DIR/mipmap-xxxhdpi"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 192x192 "$ANDROID_DIR/mipmap-xxxhdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
# iOS
|
||||||
|
XCASSETS_DIR="$OUT_DIR/ios/Assets.xcassets"
|
||||||
|
IOS_DIR="$XCASSETS_DIR/AppIcon.appiconset"
|
||||||
|
mkdir -p "$IOS_DIR"
|
||||||
|
|
||||||
|
cat > "$XCASSETS_DIR/Contents.json" <<EOF
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 20x20 "$IOS_DIR/Icon-20.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 40x40 "$IOS_DIR/Icon-20@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 60x60 "$IOS_DIR/Icon-20@3x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 29x29 "$IOS_DIR/Icon-29.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 58x58 "$IOS_DIR/Icon-29@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 87x87 "$IOS_DIR/Icon-29@3x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 40x40 "$IOS_DIR/Icon-40.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 80x80 "$IOS_DIR/Icon-40@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 120x120 "$IOS_DIR/Icon-40@3x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 120x120 "$IOS_DIR/Icon-60@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 180x180 "$IOS_DIR/Icon-60@3x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 76x76 "$IOS_DIR/Icon-76.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 152x152 "$IOS_DIR/Icon-76@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 167x167 "$IOS_DIR/Icon-83.5@2x.png"
|
||||||
|
"$MAGICK_BIN" "$SOURCE" -scale 1024x1024 "$IOS_DIR/Icon-1024.png"
|
||||||
|
|
||||||
|
cat > "$IOS_DIR/Contents.json" <<EOF
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{ "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-20@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-20@3x.png", "scale" : "3x" },
|
||||||
|
{ "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-29.png", "scale" : "1x" },
|
||||||
|
{ "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-29@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-29@3x.png", "scale" : "3x" },
|
||||||
|
{ "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@3x.png", "scale" : "3x" },
|
||||||
|
{ "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@3x.png", "scale" : "3x" },
|
||||||
|
{ "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-20.png", "scale" : "1x" },
|
||||||
|
{ "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-20@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-29.png", "scale" : "1x" },
|
||||||
|
{ "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-29@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40.png", "scale" : "1x" },
|
||||||
|
{ "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76.png", "scale" : "1x" },
|
||||||
|
{ "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-83.5@2x.png", "scale" : "2x" },
|
||||||
|
{ "size" : "1024x1024", "idiom" : "ios-marketing", "filename" : "Icon-1024.png", "scale" : "1x" }
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "GraphWidget.h"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
GraphWidget::GraphWidget(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
plot = new JKQTPlotter(this);
|
||||||
|
layout->addWidget(plot);
|
||||||
|
|
||||||
|
// Initialize Graphs
|
||||||
|
graphY1 = new JKQTPXYLineGraph(plot);
|
||||||
|
graphY2 = new JKQTPXYLineGraph(plot);
|
||||||
|
|
||||||
|
// Styling Y1 (e.g., Blue)
|
||||||
|
graphY1->setColor(QColor("blue"));
|
||||||
|
graphY1->setSymbolColor(QColor("blue"));
|
||||||
|
graphY1->setSymbol(JKQTPCircle);
|
||||||
|
graphY1->setSymbolSize(7);
|
||||||
|
graphY1->setLineWidth(2);
|
||||||
|
|
||||||
|
// Styling Y2 (e.g., Red)
|
||||||
|
graphY2->setColor(QColor("red"));
|
||||||
|
graphY2->setSymbolColor(QColor("red"));
|
||||||
|
graphY2->setSymbol(JKQTPTriangle);
|
||||||
|
graphY2->setSymbolSize(7);
|
||||||
|
graphY2->setLineWidth(2);
|
||||||
|
|
||||||
|
plot->addGraph(graphY1);
|
||||||
|
plot->addGraph(graphY2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::setupPlot(QString title, QString xLabel, QString y1Label, QString y2Label)
|
||||||
|
{
|
||||||
|
// Basic Settings
|
||||||
|
plot->getPlotter()->setPlotLabel(title);
|
||||||
|
plot->getXAxis()->setAxisLabel(xLabel);
|
||||||
|
|
||||||
|
// Y-Axis setup
|
||||||
|
plot->getYAxis()->setAxisLabel(y1Label); // Left Axis
|
||||||
|
|
||||||
|
// If we want a secondary axis for Y2, JKQTPlotter supports it,
|
||||||
|
// but for simplicity here we might plot on the same if scales are similar,
|
||||||
|
// or rely on user interpretation.
|
||||||
|
// For Bode (Ohm vs Degree), scales are vastly different.
|
||||||
|
// Ideally, Y2 should be on the right axis.
|
||||||
|
|
||||||
|
// Assign Y1 to Left Axis
|
||||||
|
graphY1->setTitle(y1Label);
|
||||||
|
|
||||||
|
// Assign Y2 to Right Axis (if supported by specific JKQT config, otherwise same axis)
|
||||||
|
// Assuming simple usage for now:
|
||||||
|
graphY2->setTitle(y2Label);
|
||||||
|
|
||||||
|
// Enable Legend
|
||||||
|
plot->getPlotter()->setShowKey(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::setLogAxis(bool logX, bool logY)
|
||||||
|
{
|
||||||
|
plot->getXAxis()->setLogAxis(logX);
|
||||||
|
plot->getYAxis()->setLogAxis(logY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::addData(double x, double y1, double y2)
|
||||||
|
{
|
||||||
|
xData.append(x);
|
||||||
|
y1Data.append(y1);
|
||||||
|
y2Data.append(y2);
|
||||||
|
|
||||||
|
// Update graph data pointers
|
||||||
|
graphY1->setXColumn(xData);
|
||||||
|
graphY1->setYColumn(y1Data);
|
||||||
|
|
||||||
|
graphY2->setXColumn(xData);
|
||||||
|
graphY2->setYColumn(y2Data);
|
||||||
|
|
||||||
|
// Redraw
|
||||||
|
plot->redrawPlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::clear()
|
||||||
|
{
|
||||||
|
xData.clear();
|
||||||
|
y1Data.clear();
|
||||||
|
y2Data.clear();
|
||||||
|
plot->redrawPlot();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef GRAPHWIDGET_H
|
||||||
|
#define GRAPHWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVector>
|
||||||
|
#include "jkqtplotter/jkqtplotter.h"
|
||||||
|
#include "jkqtplotter/graphs/jkqtpigraph.h"
|
||||||
|
#include "jkqtplotter/graphs/jkqtpimage.h"
|
||||||
|
#include "jkqtplotter/graphs/jkqtpscatter.h"
|
||||||
|
#include "jkqtplotter/graphs/jkqtplyines.h"
|
||||||
|
|
||||||
|
class GraphWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit GraphWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
void setupPlot(QString title, QString xLabel, QString y1Label, QString y2Label);
|
||||||
|
void setLogAxis(bool logX, bool logY);
|
||||||
|
|
||||||
|
// Data Access
|
||||||
|
void addData(double x, double y1, double y2);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
JKQTPlotter *plot;
|
||||||
|
|
||||||
|
// Internal Data Storage
|
||||||
|
QVector<double> xData;
|
||||||
|
QVector<double> y1Data;
|
||||||
|
QVector<double> y2Data;
|
||||||
|
|
||||||
|
// Graph Objects
|
||||||
|
JKQTPXYLineGraph *graphY1;
|
||||||
|
JKQTPXYLineGraph *graphY2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GRAPHWIDGET_H
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include <QSerialPortInfo>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
{
|
||||||
|
serial = new QSerialPort(this);
|
||||||
|
connect(serial, &QSerialPort::readyRead, this, &MainWindow::onReadData);
|
||||||
|
|
||||||
|
setupUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
if (serial->isOpen())
|
||||||
|
serial->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setupUi()
|
||||||
|
{
|
||||||
|
centralWidget = new QWidget(this);
|
||||||
|
setCentralWidget(centralWidget);
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
|
||||||
|
|
||||||
|
// --- Toolbar Area ---
|
||||||
|
QHBoxLayout *toolLayout = new QHBoxLayout();
|
||||||
|
|
||||||
|
portSelector = new QComboBox();
|
||||||
|
const auto ports = QSerialPortInfo::availablePorts();
|
||||||
|
for (const QSerialPortInfo &info : ports) {
|
||||||
|
portSelector->addItem(info.portName());
|
||||||
|
}
|
||||||
|
|
||||||
|
btnConnect = new QPushButton("Connect");
|
||||||
|
connect(btnConnect, &QPushButton::clicked, [this]() {
|
||||||
|
onPortToggled(serial->isOpen());
|
||||||
|
});
|
||||||
|
|
||||||
|
btnMeasure = new QPushButton("Measure");
|
||||||
|
btnMeasure->setEnabled(false);
|
||||||
|
connect(btnMeasure, &QPushButton::clicked, this, &MainWindow::onMeasureClicked);
|
||||||
|
|
||||||
|
btnCalibrate = new QPushButton("Calibrate");
|
||||||
|
btnCalibrate->setEnabled(false);
|
||||||
|
connect(btnCalibrate, &QPushButton::clicked, this, &MainWindow::onCalibrateClicked);
|
||||||
|
|
||||||
|
viewSelector = new QComboBox();
|
||||||
|
viewSelector->addItem("Tabs (Swipe)");
|
||||||
|
viewSelector->addItem("Split (Dual)");
|
||||||
|
connect(viewSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onViewModeChanged);
|
||||||
|
|
||||||
|
toolLayout->addWidget(portSelector);
|
||||||
|
toolLayout->addWidget(btnConnect);
|
||||||
|
toolLayout->addWidget(btnMeasure);
|
||||||
|
toolLayout->addWidget(btnCalibrate);
|
||||||
|
toolLayout->addWidget(viewSelector); // Add view switcher
|
||||||
|
|
||||||
|
mainLayout->addLayout(toolLayout);
|
||||||
|
|
||||||
|
// --- Graphs Initialization ---
|
||||||
|
finalGraph = new GraphWidget();
|
||||||
|
finalGraph->setupPlot("Bode Plot", "Frequency (Hz)", "Impedance (Ohm)", "Phase (Rad)");
|
||||||
|
finalGraph->setLogAxis(true, true); // Log-Log for Bode
|
||||||
|
|
||||||
|
rawGraph = new GraphWidget();
|
||||||
|
rawGraph->setupPlot("Raw Data (DFT)", "Frequency (Hz)", "Real", "Imaginary");
|
||||||
|
rawGraph->setLogAxis(true, false); // Log X, Linear Y (Raw data can be neg)
|
||||||
|
|
||||||
|
// --- Layout Containers ---
|
||||||
|
|
||||||
|
// 1. Tab Widget (Mobile Style)
|
||||||
|
tabWidget = new QTabWidget();
|
||||||
|
tabWidget->addTab(finalGraph, "Final Data");
|
||||||
|
tabWidget->addTab(rawGraph, "Raw Data");
|
||||||
|
|
||||||
|
// 2. Splitter (Desktop Style)
|
||||||
|
splitter = new QSplitter(Qt::Horizontal);
|
||||||
|
// Note: We can't add the same widget to two parents.
|
||||||
|
// We will reparent them in onViewModeChanged.
|
||||||
|
|
||||||
|
// Default to Tabs (Mobile friendly default)
|
||||||
|
mainLayout->addWidget(tabWidget);
|
||||||
|
|
||||||
|
// Status Bar
|
||||||
|
statusLabel = new QLabel("Ready");
|
||||||
|
statusBar()->addWidget(statusLabel);
|
||||||
|
|
||||||
|
// Auto-detect Platform for default view
|
||||||
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
|
viewSelector->setCurrentIndex(0); // Tabs
|
||||||
|
viewSelector->setVisible(false); // Hide selector on mobile, force tabs
|
||||||
|
#else
|
||||||
|
viewSelector->setCurrentIndex(1); // Default to Split on Desktop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onViewModeChanged(int index)
|
||||||
|
{
|
||||||
|
// 0 = Tabs, 1 = Split
|
||||||
|
|
||||||
|
// Remove graphs from their current parents
|
||||||
|
finalGraph->setParent(nullptr);
|
||||||
|
rawGraph->setParent(nullptr);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = qobject_cast<QVBoxLayout*>(centralWidget->layout());
|
||||||
|
|
||||||
|
if (index == 0) { // Tabs
|
||||||
|
if (splitter->isVisible()) {
|
||||||
|
layout->removeWidget(splitter);
|
||||||
|
splitter->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
tabWidget->clear();
|
||||||
|
tabWidget->addTab(finalGraph, "Final Data");
|
||||||
|
tabWidget->addTab(rawGraph, "Raw Data");
|
||||||
|
|
||||||
|
if (!tabWidget->isVisible()) {
|
||||||
|
layout->addWidget(tabWidget);
|
||||||
|
tabWidget->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // Split
|
||||||
|
if (tabWidget->isVisible()) {
|
||||||
|
layout->removeWidget(tabWidget);
|
||||||
|
tabWidget->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
splitter->addWidget(finalGraph);
|
||||||
|
splitter->addWidget(rawGraph);
|
||||||
|
|
||||||
|
if (!splitter->isVisible()) {
|
||||||
|
layout->addWidget(splitter);
|
||||||
|
splitter->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onPortToggled(bool connected)
|
||||||
|
{
|
||||||
|
if (connected) {
|
||||||
|
serial->close();
|
||||||
|
btnConnect->setText("Connect");
|
||||||
|
btnMeasure->setEnabled(false);
|
||||||
|
btnCalibrate->setEnabled(false);
|
||||||
|
statusLabel->setText("Disconnected");
|
||||||
|
} else {
|
||||||
|
serial->setPortName(portSelector->currentText());
|
||||||
|
serial->setBaudRate(115200); // Or whatever your Pico uses, standard 115200 usually
|
||||||
|
|
||||||
|
if (serial->open(QIODevice::ReadWrite)) {
|
||||||
|
btnConnect->setText("Disconnect");
|
||||||
|
btnMeasure->setEnabled(true);
|
||||||
|
btnCalibrate->setEnabled(true);
|
||||||
|
statusLabel->setText("Connected");
|
||||||
|
|
||||||
|
// Clear old data on connect
|
||||||
|
finalGraph->clear();
|
||||||
|
rawGraph->clear();
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, "Error", "Could not open serial port.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onMeasureClicked()
|
||||||
|
{
|
||||||
|
if (serial->isOpen()) {
|
||||||
|
finalGraph->clear();
|
||||||
|
rawGraph->clear();
|
||||||
|
// Trigger a sweep or single measurement
|
||||||
|
// Example command logic
|
||||||
|
// For single: serial->write("MEAS 10000\n");
|
||||||
|
// For sweep logic, the MCU might handle it or we loop here.
|
||||||
|
// Assuming user triggers 'MEAS 1000' style commands manually or logic exists.
|
||||||
|
// Let's just send a command if needed, or rely on user knowing what to do.
|
||||||
|
// For now, let's assume we want to measure 10kHz as a test
|
||||||
|
serial->write("MEAS 10000\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onCalibrateClicked()
|
||||||
|
{
|
||||||
|
if (serial->isOpen()) {
|
||||||
|
serial->write("CAL\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onReadData()
|
||||||
|
{
|
||||||
|
while (serial->canReadLine()) {
|
||||||
|
QByteArray line = serial->readLine().trimmed();
|
||||||
|
processLine(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::processLine(const QByteArray &line)
|
||||||
|
{
|
||||||
|
if (line.startsWith("DATA")) {
|
||||||
|
// Format: DATA,freq,impedance,phase,raw_real,raw_imag
|
||||||
|
float freq, imp, phase;
|
||||||
|
int raw_real, raw_imag;
|
||||||
|
|
||||||
|
// sscanf is dangerous with comma delimited strings if not careful, but works for fixed format
|
||||||
|
int count = sscanf(line.constData(), "DATA,%f,%f,%f,%d,%d", &freq, &imp, &phase, &raw_real, &raw_imag);
|
||||||
|
|
||||||
|
if (count >= 3) {
|
||||||
|
// We have at least the final data
|
||||||
|
finalGraph->addData(freq, imp, phase); // Y1=Imp, Y2=Phase
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= 5) {
|
||||||
|
// We have raw data too
|
||||||
|
rawGraph->addData(freq, (double)raw_real, (double)raw_imag);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusLabel->setText(QString("Received: %1 Hz").arg(freq));
|
||||||
|
}
|
||||||
|
else if (line.startsWith("LOG")) {
|
||||||
|
statusLabel->setText(line);
|
||||||
|
qDebug() << "Device Log:" << line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QSerialPort>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "GraphWidget.h"
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onPortToggled(bool connected);
|
||||||
|
void onReadData();
|
||||||
|
void onMeasureClicked();
|
||||||
|
void onCalibrateClicked();
|
||||||
|
void onViewModeChanged(int index); // New slot for desktop view switching
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUi();
|
||||||
|
void processLine(const QByteArray &line);
|
||||||
|
|
||||||
|
// Hardware
|
||||||
|
QSerialPort *serial;
|
||||||
|
|
||||||
|
// UI Elements
|
||||||
|
QComboBox *portSelector;
|
||||||
|
QPushButton *btnConnect;
|
||||||
|
QPushButton *btnMeasure;
|
||||||
|
QPushButton *btnCalibrate;
|
||||||
|
QLabel *statusLabel;
|
||||||
|
|
||||||
|
// Graphs
|
||||||
|
GraphWidget *finalGraph; // Bode Plot
|
||||||
|
GraphWidget *rawGraph; // Raw Real/Imag Plot
|
||||||
|
|
||||||
|
// Layout Containers
|
||||||
|
QWidget *centralWidget;
|
||||||
|
QTabWidget *tabWidget; // For Mobile/Tab Mode
|
||||||
|
QSplitter *splitter; // For Desktop/Split Mode
|
||||||
|
QComboBox *viewSelector; // For Desktop to toggle modes
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// File: aluf/src/main.cpp
|
||||||
|
#include <QApplication>
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QApplication::setApplicationName("EIS Configurator");
|
||||||
|
QApplication::setApplicationVersion("1.0");
|
||||||
|
|
||||||
|
// Dark Theme
|
||||||
|
QPalette p = app.palette();
|
||||||
|
p.setColor(QPalette::Window, QColor(30, 30, 30));
|
||||||
|
p.setColor(QPalette::WindowText, Qt::white);
|
||||||
|
p.setColor(QPalette::Base, QColor(15, 15, 15));
|
||||||
|
p.setColor(QPalette::AlternateBase, QColor(45, 45, 45));
|
||||||
|
p.setColor(QPalette::Text, Qt::white);
|
||||||
|
p.setColor(QPalette::Button, QColor(45, 45, 45));
|
||||||
|
p.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
app.setPalette(p);
|
||||||
|
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,474 @@
|
||||||
|
// File: EIS/main.c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/spi.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "ad5940.h"
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Pin Definitions
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
#define PIN_MISO 0
|
||||||
|
#define PIN_CS 1
|
||||||
|
#define PIN_SCK 2
|
||||||
|
#define PIN_MOSI 3
|
||||||
|
#define PIN_RESET 9
|
||||||
|
#define PIN_AD_INTERRUPT 29
|
||||||
|
|
||||||
|
#define SPI_PORT spi0
|
||||||
|
#define SPI_BAUDRATE_HIGH 500000
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Switch Matrix Bit Definitions
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
#ifndef SWT_SE0
|
||||||
|
#define SWT_SE0 (1 << 6) // T7
|
||||||
|
#endif
|
||||||
|
#ifndef SWT_T9
|
||||||
|
#define SWT_T9 (1 << 8) // T9
|
||||||
|
#endif
|
||||||
|
#ifndef SWT_TR1
|
||||||
|
#define SWT_TR1 (1 << 11) // TR1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DSWFULLCON
|
||||||
|
#ifndef SWD_AIN2
|
||||||
|
#define SWD_AIN2 (1 << 2) // D3
|
||||||
|
#endif
|
||||||
|
#ifndef SWD_CE0
|
||||||
|
#define SWD_CE0 (1 << 4) // D5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TSWFULLCON
|
||||||
|
#ifndef SWT_AIN3
|
||||||
|
#define SWT_AIN3 (1 << 3) // T4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// AD5940 Library Interface
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AD5940_CsClr(void) {
|
||||||
|
gpio_put(PIN_CS, 0);
|
||||||
|
sleep_us(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AD5940_CsSet(void) {
|
||||||
|
sleep_us(1);
|
||||||
|
gpio_put(PIN_CS, 1);
|
||||||
|
sleep_us(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AD5940_RstClr(void) { gpio_put(PIN_RESET, 0); }
|
||||||
|
void AD5940_RstSet(void) { gpio_put(PIN_RESET, 1); }
|
||||||
|
void AD5940_Delay10us(uint32_t time) { sleep_us(time * 10); }
|
||||||
|
|
||||||
|
uint32_t AD5940_GetMCUIntFlag(void) {
|
||||||
|
uint32_t flag = AD5940_ReadReg(REG_INTC_INTCFLAG0);
|
||||||
|
return (flag != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AD5940_ReadWriteNBytes(unsigned char *pSendBuffer, unsigned char *pRecvBuffer, unsigned long length) {
|
||||||
|
if (pRecvBuffer == NULL) {
|
||||||
|
if (pSendBuffer != NULL) {
|
||||||
|
spi_write_blocking(SPI_PORT, pSendBuffer, length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pSendBuffer == NULL) {
|
||||||
|
uint8_t dummy = 0x00;
|
||||||
|
for (unsigned long i = 0; i < length; i++) {
|
||||||
|
spi_write_read_blocking(SPI_PORT, &dummy, &pRecvBuffer[i], 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spi_write_read_blocking(SPI_PORT, pSendBuffer, pRecvBuffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AD5940_PulseReset(void) {
|
||||||
|
AD5940_RstClr();
|
||||||
|
sleep_ms(10);
|
||||||
|
AD5940_RstSet();
|
||||||
|
sleep_ms(50); // Increased wait for boot stability
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to map Register Macro to Actual Sample Count for calculations
|
||||||
|
uint32_t GetDftSamples(uint32_t dft_num_macro) {
|
||||||
|
if (dft_num_macro == DFTNUM_256) return 256;
|
||||||
|
if (dft_num_macro == DFTNUM_512) return 512;
|
||||||
|
if (dft_num_macro == DFTNUM_1024) return 1024;
|
||||||
|
if (dft_num_macro == DFTNUM_2048) return 2048;
|
||||||
|
if (dft_num_macro == DFTNUM_4096) return 4096;
|
||||||
|
if (dft_num_macro == DFTNUM_8192) return 8192;
|
||||||
|
if (dft_num_macro == DFTNUM_16384) return 16384;
|
||||||
|
return 2048; // Safe default
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structure to hold calculated configuration
|
||||||
|
typedef struct {
|
||||||
|
uint32_t DftNum;
|
||||||
|
uint32_t DftSrc;
|
||||||
|
uint32_t Sinc3Osr;
|
||||||
|
uint32_t Sinc2Osr;
|
||||||
|
float SampleRate; // Estimated
|
||||||
|
} FilterConfig_Type;
|
||||||
|
|
||||||
|
// Calculates optimal DFT and Filter settings based on frequency
|
||||||
|
// Optimized for High Speed Loop (HFOSC 16MHz) only
|
||||||
|
void AD5940_GetFilterCfg(float freq, FilterConfig_Type *pCfg) {
|
||||||
|
// Strategy:
|
||||||
|
// For > 50Hz, use SINC3 (Fast, ~200kHz)
|
||||||
|
// For <= 50Hz, use SINC2 path (Slower, ~9kHz) to capture full waves
|
||||||
|
|
||||||
|
if (freq >= 50.0f) {
|
||||||
|
pCfg->DftSrc = DFTSRC_SINC3;
|
||||||
|
pCfg->Sinc3Osr = ADCSINC3OSR_4;
|
||||||
|
pCfg->Sinc2Osr = ADCSINC2OSR_22; // Don't care for SINC3 src
|
||||||
|
pCfg->SampleRate = 200000.0f; // 800k / 4
|
||||||
|
|
||||||
|
// Adjust DFT size for speed vs accuracy at high freq
|
||||||
|
if (freq > 40000.0f) pCfg->DftNum = DFTNUM_2048;
|
||||||
|
else if (freq > 1000.0f) pCfg->DftNum = DFTNUM_4096;
|
||||||
|
else pCfg->DftNum = DFTNUM_8192;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Low Frequency High Speed (e.g. 10Hz)
|
||||||
|
// Use SINC2 filter to slow down data rate
|
||||||
|
// Rate = 800k / (4 * 22) = 9090 Hz
|
||||||
|
pCfg->DftSrc = DFTSRC_SINC2NOTCH;
|
||||||
|
pCfg->Sinc3Osr = ADCSINC3OSR_4;
|
||||||
|
pCfg->Sinc2Osr = ADCSINC2OSR_22;
|
||||||
|
pCfg->SampleRate = 9090.0f;
|
||||||
|
|
||||||
|
// 8192 samples @ 9kHz = ~0.9 seconds
|
||||||
|
// Covers 9 cycles of 10Hz. Perfect.
|
||||||
|
pCfg->DftNum = DFTNUM_8192;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Measurement Functions
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static uint32_t AppBuff[512];
|
||||||
|
|
||||||
|
// Internal Helper for Calibration
|
||||||
|
static AD5940Err RunCalibration(void)
|
||||||
|
{
|
||||||
|
ADCPGACal_Type pga_cal;
|
||||||
|
|
||||||
|
pga_cal.AdcClkFreq = 16000000.0;
|
||||||
|
pga_cal.SysClkFreq = 16000000.0;
|
||||||
|
pga_cal.ADCPga = ADCPGA_1;
|
||||||
|
pga_cal.ADCSinc2Osr = ADCSINC2OSR_1333;
|
||||||
|
pga_cal.ADCSinc3Osr = ADCSINC3OSR_4;
|
||||||
|
pga_cal.TimeOut10us = 100000;
|
||||||
|
pga_cal.VRef1p82 = 1.82;
|
||||||
|
pga_cal.VRef1p11 = 1.11;
|
||||||
|
pga_cal.PGACalType = PGACALTYPE_OFFSETGAIN;
|
||||||
|
|
||||||
|
return AD5940_ADCPGACal(&pga_cal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command Handler for "CAL"
|
||||||
|
static void AppADCPgaCal(void)
|
||||||
|
{
|
||||||
|
printf("LOG,Preparing for Calibration...\n");
|
||||||
|
// Ensure clean state before CAL
|
||||||
|
AD5940_PulseReset();
|
||||||
|
AD5940_Initialize();
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCSEL0, 0xFFFFFFFF);
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCCLR, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
AD5940Err err = RunCalibration();
|
||||||
|
if(err != AD5940ERR_OK) printf("LOG,ADC Cal Failed: %d\n", err);
|
||||||
|
else printf("LOG,ADC Cal Passed.\n");
|
||||||
|
|
||||||
|
// Cleanup: Turn off everything after CAL to leave clean slate
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// High Speed Loop (HSTIA + HSDAC) for ALL Frequencies
|
||||||
|
void MeasureHighSpeed(float freq)
|
||||||
|
{
|
||||||
|
// 1. HARD RESET & Re-Initialize
|
||||||
|
AD5940_PulseReset();
|
||||||
|
AD5940_Initialize();
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCSEL0, 0xFFFFFFFF);
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCCLR, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
// 2. Calibrate
|
||||||
|
// Note: Calibration routines are invasive. They might leave the AFE in weird states.
|
||||||
|
AD5940Err calErr = RunCalibration();
|
||||||
|
if(calErr != AD5940ERR_OK) {
|
||||||
|
printf("LOG,Auto-Calibration Failed: %d\n", calErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Shut down EVERYTHING after calibration.
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||||
|
|
||||||
|
// CRITICAL: Disable Sequencer
|
||||||
|
AD5940_SEQCtrlS(bFALSE);
|
||||||
|
|
||||||
|
// 3. Clock Configuration
|
||||||
|
AD5940_WriteReg(REG_ALLON_OSCKEY, 0xCB14);
|
||||||
|
AD5940_WriteReg(REG_ALLON_OSCCON, 0x0003); // Enable HFOSC
|
||||||
|
sleep_ms(2);
|
||||||
|
|
||||||
|
AD5940_WriteReg(REG_AFE_LPMODEKEY, 0xC59D6);
|
||||||
|
AD5940_WriteReg(REG_AFE_LPMODECLKSEL, 0); // Select HFOSC
|
||||||
|
|
||||||
|
spi_set_baudrate(SPI_PORT, SPI_BAUDRATE_HIGH);
|
||||||
|
|
||||||
|
// 4. Switch Matrix Cleanup
|
||||||
|
AD5940_WriteReg(REG_AFE_LPTIASW0, 0x0000);
|
||||||
|
AD5940_WriteReg(REG_AFE_LPDACSW0, 0x0000);
|
||||||
|
|
||||||
|
// 5. Configure Loop
|
||||||
|
HSLoopCfg_Type hs_loop;
|
||||||
|
hs_loop.HsDacCfg.ExcitBufGain = EXCITBUFGAIN_2;
|
||||||
|
hs_loop.HsDacCfg.HsDacGain = HSDACGAIN_1;
|
||||||
|
hs_loop.HsDacCfg.HsDacUpdateRate = 7;
|
||||||
|
|
||||||
|
if (freq > 1000.0f) {
|
||||||
|
hs_loop.HsTiaCfg.HstiaRtiaSel = HSTIARTIA_1K;
|
||||||
|
} else {
|
||||||
|
hs_loop.HsTiaCfg.HstiaRtiaSel = HSTIARTIA_5K;
|
||||||
|
}
|
||||||
|
|
||||||
|
hs_loop.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
|
||||||
|
hs_loop.HsTiaCfg.HstiaCtia = 16;
|
||||||
|
hs_loop.HsTiaCfg.DiodeClose = bFALSE;
|
||||||
|
|
||||||
|
AD5940_HSLoopCfgS(&hs_loop);
|
||||||
|
|
||||||
|
// 6. Switch Matrix (S+/S-)
|
||||||
|
AD5940_WriteReg(REG_AFE_SWCON, BITM_AFE_SWCON_SWSOURCESEL);
|
||||||
|
AD5940_WriteReg(REG_AFE_DSWFULLCON, SWD_CE0);
|
||||||
|
AD5940_WriteReg(REG_AFE_PSWFULLCON, 0x0000);
|
||||||
|
AD5940_WriteReg(REG_AFE_NSWFULLCON, 0x0000);
|
||||||
|
AD5940_WriteReg(REG_AFE_TSWFULLCON, SWT_SE0 | SWT_T9);
|
||||||
|
|
||||||
|
// 7. Get Dynamic Configuration
|
||||||
|
FilterConfig_Type cfg;
|
||||||
|
AD5940_GetFilterCfg(freq, &cfg);
|
||||||
|
|
||||||
|
// 8. ADC Configuration
|
||||||
|
ADCBaseCfg_Type adc_cfg;
|
||||||
|
memset(&adc_cfg, 0, sizeof(adc_cfg));
|
||||||
|
adc_cfg.ADCMuxP = ADCMUXP_HSTIA_P;
|
||||||
|
adc_cfg.ADCMuxN = ADCMUXN_HSTIA_N;
|
||||||
|
adc_cfg.ADCPga = ADCPGA_1;
|
||||||
|
AD5940_ADCBaseCfgS(&adc_cfg);
|
||||||
|
|
||||||
|
// Initialize and Enable Clocks
|
||||||
|
ADCFilterCfg_Type filter_cfg;
|
||||||
|
memset(&filter_cfg, 0, sizeof(filter_cfg));
|
||||||
|
|
||||||
|
filter_cfg.ADCSinc3Osr = cfg.Sinc3Osr;
|
||||||
|
filter_cfg.ADCSinc2Osr = cfg.Sinc2Osr;
|
||||||
|
filter_cfg.ADCAvgNum = ADCAVGNUM_16;
|
||||||
|
filter_cfg.ADCRate = ADCRATE_800KHZ;
|
||||||
|
filter_cfg.BpNotch = bTRUE;
|
||||||
|
filter_cfg.BpSinc3 = bFALSE;
|
||||||
|
filter_cfg.Sinc2NotchEnable = bTRUE;
|
||||||
|
|
||||||
|
// Explicitly Enable Clocks
|
||||||
|
filter_cfg.DFTClkEnable = bTRUE;
|
||||||
|
filter_cfg.WGClkEnable = bTRUE;
|
||||||
|
filter_cfg.Sinc3ClkEnable = bTRUE;
|
||||||
|
filter_cfg.Sinc2NotchClkEnable = bTRUE;
|
||||||
|
|
||||||
|
AD5940_ADCFilterCfgS(&filter_cfg);
|
||||||
|
|
||||||
|
// Configure ADC Buffers
|
||||||
|
AD5940_WriteReg(REG_AFE_ADCBUFCON, 0x005F3D0F);
|
||||||
|
|
||||||
|
// 9. Waveform
|
||||||
|
AD5940_WriteReg(REG_AFE_WGFCW, AD5940_WGFreqWordCal(freq, 16000000.0));
|
||||||
|
AD5940_WriteReg(REG_AFE_WGAMPLITUDE, 2047);
|
||||||
|
AD5940_WriteReg(REG_AFE_WGOFFSET, 0);
|
||||||
|
AD5940_WriteReg(REG_AFE_WGPHASE, 0);
|
||||||
|
AD5940_WriteReg(REG_AFE_WGCON, WGTYPE_SIN);
|
||||||
|
|
||||||
|
// 10. DFT
|
||||||
|
DFTCfg_Type dft_cfg;
|
||||||
|
dft_cfg.DftNum = cfg.DftNum;
|
||||||
|
dft_cfg.DftSrc = cfg.DftSrc;
|
||||||
|
dft_cfg.HanWinEn = bTRUE;
|
||||||
|
AD5940_DFTCfgS(&dft_cfg);
|
||||||
|
|
||||||
|
// 11. Configure FIFO for DFT
|
||||||
|
// Ensure we capture DFT results in FIFO
|
||||||
|
FIFOCfg_Type fifo_cfg;
|
||||||
|
fifo_cfg.FIFOEn = bTRUE;
|
||||||
|
fifo_cfg.FIFOMode = FIFOMODE_FIFO;
|
||||||
|
fifo_cfg.FIFOSize = FIFOSIZE_4KB;
|
||||||
|
fifo_cfg.FIFOSrc = FIFOSRC_DFT;
|
||||||
|
fifo_cfg.FIFOThresh = 4;
|
||||||
|
AD5940_FIFOCfg(&fifo_cfg);
|
||||||
|
|
||||||
|
// 12. Run
|
||||||
|
|
||||||
|
// Power Up Analog Blocks
|
||||||
|
AD5940_AFECtrlS(AFECTRL_HSDACPWR|AFECTRL_HSTIAPWR|AFECTRL_ADCPWR|AFECTRL_DACREFPWR|AFECTRL_EXTBUFPWR|AFECTRL_INAMPPWR, bTRUE);
|
||||||
|
|
||||||
|
sleep_ms(20);
|
||||||
|
|
||||||
|
// CRITICAL FIX: Force AFECON Clean
|
||||||
|
uint32_t current_afecon = AD5940_ReadReg(REG_AFE_AFECON);
|
||||||
|
current_afecon &= ~(0x00003000); // Clear Temp bits
|
||||||
|
AD5940_WriteReg(REG_AFE_AFECON, current_afecon);
|
||||||
|
|
||||||
|
// Enable ADC Repeat Mode
|
||||||
|
AD5940_ADCRepeatCfgS(0xffffffff);
|
||||||
|
|
||||||
|
// Clear and Enable Interrupts
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCCLR, 0xFFFFFFFF);
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCSEL0, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
// Start Conversion
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG, bTRUE);
|
||||||
|
|
||||||
|
// Calculate Timeout using Helper
|
||||||
|
uint32_t sample_count = GetDftSamples(cfg.DftNum);
|
||||||
|
float duration = (float)sample_count / cfg.SampleRate;
|
||||||
|
uint32_t timeout_us = (uint32_t)(duration * 1000000.0f) + 2000000;
|
||||||
|
|
||||||
|
// Polling Loop with Exit Condition
|
||||||
|
uint32_t start_time = to_us_since_boot(get_absolute_time());
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// Results
|
||||||
|
int32_t real = 0;
|
||||||
|
int32_t image = 0;
|
||||||
|
|
||||||
|
while((to_us_since_boot(get_absolute_time()) - start_time) < timeout_us) {
|
||||||
|
|
||||||
|
// Polling Strategy: Check FIFO Count instead of Interrupt Flags
|
||||||
|
// One DFT result = 2 words (Real + Image). We wait for >= 2 words.
|
||||||
|
uint32_t fifo_cnt = (AD5940_ReadReg(REG_AFE_FIFOCNTSTA) & 0x07FF0000) >> 16;
|
||||||
|
|
||||||
|
if(fifo_cnt >= 2) {
|
||||||
|
// Read result from FIFO
|
||||||
|
uint32_t buffer[2];
|
||||||
|
AD5940_FIFORd(buffer, 2);
|
||||||
|
real = (int32_t)buffer[0];
|
||||||
|
image = (int32_t)buffer[1];
|
||||||
|
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCCLR, 0xFFFFFFFF);
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep_us(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
uint32_t flags = AD5940_ReadReg(REG_INTC_INTCFLAG0);
|
||||||
|
uint32_t afecon_read = AD5940_ReadReg(REG_AFE_AFECON);
|
||||||
|
uint32_t fifo_cnt = (AD5940_ReadReg(REG_AFE_FIFOCNTSTA) & 0x07FF0000) >> 16;
|
||||||
|
printf("LOG,Error: Measurement Timeout (HS). Exp Duration: %.2fs. Flags: 0x%08X, AFECON: 0x%08X, FIFO: %d\n", duration, flags, afecon_read, fifo_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13. Process Result
|
||||||
|
// Sign Extend 18-bit to 32-bit
|
||||||
|
// Store original raw values before processing
|
||||||
|
int32_t raw_real = real;
|
||||||
|
int32_t raw_image = image;
|
||||||
|
|
||||||
|
if(real & (1<<17)) real |= 0xFFFC0000;
|
||||||
|
if(image & (1<<17)) image |= 0xFFFC0000;
|
||||||
|
|
||||||
|
float mag = sqrt((float)real*real + (float)image*image);
|
||||||
|
float rtia_val = (freq > 1000.0f) ? 1000.0f : 5000.0f;
|
||||||
|
float impedance = (mag > 0) ? (2047.0f / mag) * rtia_val : 0;
|
||||||
|
float phase = atan2((float)image, (float)real);
|
||||||
|
|
||||||
|
// Updated Output Format: Freq, Impedance, Phase, RawReal, RawImag
|
||||||
|
printf("DATA,%.2f,%.4f,%.4f,%d,%d\n", freq, impedance, phase, raw_real, raw_image);
|
||||||
|
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Main
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void process_command(char* cmd) {
|
||||||
|
char* token = strtok(cmd, " ");
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
if (strcmp(token, "CAL") == 0) {
|
||||||
|
AppADCPgaCal();
|
||||||
|
}
|
||||||
|
else if (strcmp(token, "MEAS") == 0) {
|
||||||
|
char* arg1 = strtok(NULL, " ");
|
||||||
|
if (arg1) {
|
||||||
|
float freq = strtof(arg1, NULL);
|
||||||
|
if (freq < 10.0f) {
|
||||||
|
freq = 10.0f;
|
||||||
|
}
|
||||||
|
MeasureHighSpeed(freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(token, "ID") == 0) {
|
||||||
|
uint32_t chip_id = AD5940_ReadReg(REG_AFECON_CHIPID);
|
||||||
|
printf("LOG,Chip ID: 0x%04X\n", chip_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
stdio_init_all();
|
||||||
|
sleep_ms(1000);
|
||||||
|
|
||||||
|
spi_init(SPI_PORT, SPI_BAUDRATE_HIGH);
|
||||||
|
spi_set_format(SPI_PORT, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
||||||
|
|
||||||
|
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
|
||||||
|
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
|
||||||
|
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
|
||||||
|
|
||||||
|
gpio_init(PIN_CS);
|
||||||
|
gpio_set_dir(PIN_CS, GPIO_OUT);
|
||||||
|
gpio_put(PIN_CS, 1);
|
||||||
|
|
||||||
|
gpio_init(PIN_RESET);
|
||||||
|
gpio_set_dir(PIN_RESET, GPIO_OUT);
|
||||||
|
gpio_put(PIN_RESET, 1);
|
||||||
|
|
||||||
|
gpio_init(PIN_AD_INTERRUPT);
|
||||||
|
gpio_set_dir(PIN_AD_INTERRUPT, GPIO_IN);
|
||||||
|
gpio_pull_up(PIN_AD_INTERRUPT);
|
||||||
|
|
||||||
|
// Initial Start
|
||||||
|
AD5940_PulseReset();
|
||||||
|
AD5940_Initialize();
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCSEL0, 0xFFFFFFFF);
|
||||||
|
AD5940_WriteReg(REG_INTC_INTCCLR, 0xFFFFFFFF);
|
||||||
|
AD5940_SEQGenInit(AppBuff, 512);
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int c = getchar_timeout_us(1000);
|
||||||
|
if (c != PICO_ERROR_TIMEOUT) {
|
||||||
|
if (c == '\n' || c == '\r') {
|
||||||
|
if (pos > 0) {
|
||||||
|
buffer[pos] = 0;
|
||||||
|
process_command(buffer);
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
} else if (pos < 63) {
|
||||||
|
buffer[pos++] = (char)c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue