From 39bbc315aa4584d98d64a3c5de9036184e5e6e9a Mon Sep 17 00:00:00 2001 From: Mize <38830121+mi-zeng@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:50:51 +0800 Subject: [PATCH] add ad5293 drivers include 1. no-os initilization 2. calibration, wiper r/w ,hard/soft reset and other operation 3. signle chip/daisy-chain multiple chips support Signed-off-by: Mize <38830121+mi-zeng@users.noreply.github.com> --- doc/sphinx/source/drivers/ad5293.rst | 1 + doc/sphinx/source/drivers_doc.rst | 7 + drivers/potentiometer/ad5293/README.rst | 265 ++++++++++++ drivers/potentiometer/ad5293/ad5293.c | 553 ++++++++++++++++++++++++ drivers/potentiometer/ad5293/ad5293.h | 148 +++++++ 5 files changed, 974 insertions(+) create mode 100644 doc/sphinx/source/drivers/ad5293.rst create mode 100644 drivers/potentiometer/ad5293/README.rst create mode 100644 drivers/potentiometer/ad5293/ad5293.c create mode 100644 drivers/potentiometer/ad5293/ad5293.h diff --git a/doc/sphinx/source/drivers/ad5293.rst b/doc/sphinx/source/drivers/ad5293.rst new file mode 100644 index 00000000000..2dad005331f --- /dev/null +++ b/doc/sphinx/source/drivers/ad5293.rst @@ -0,0 +1 @@ +.. include:: ../../../../drivers/potentiometer/ad5293/README.rst diff --git a/doc/sphinx/source/drivers_doc.rst b/doc/sphinx/source/drivers_doc.rst index 06c962300ab..aabeb0a3dc7 100644 --- a/doc/sphinx/source/drivers_doc.rst +++ b/doc/sphinx/source/drivers_doc.rst @@ -104,3 +104,10 @@ POWER MANAGEMENT drivers/lt8722 drivers/ltp8800 drivers/max42500 + +POTENTIOMETER +================ +.. toctree:: + :maxdepth: 1 + + drivers/ad5293 \ No newline at end of file diff --git a/drivers/potentiometer/ad5293/README.rst b/drivers/potentiometer/ad5293/README.rst new file mode 100644 index 00000000000..d4f9c99cb3d --- /dev/null +++ b/drivers/potentiometer/ad5293/README.rst @@ -0,0 +1,265 @@ +==================== +AD5293 no-OS driver +==================== + +Supported Devices +------------------ + +`ad5293 `_ + +Overview +--------- +The AD5293 is a single-channel, 1024-position digital potentiometer with +a <1% end-to-end resistor tolerance error. The AD5293 performs the same +electronic adjustment function as a mechanical potentiometer with enhanced +resolution, solid state reliability, and superior low temperature coefficient +performance. This device is capable of operating at high voltages and supporting +both dual-supply operation at ±10.5 V to ±15 V and single-supply operation at 21 V to 30 V. +(in this documentation, the terms digital potentiometer and RDAC are used interchangeably) + +The AD5293 contains a serial interface (SYNC, SCLK, DIN, and +SDO) that is compatible with SPI standards, as well as most DSPs. +The device allows data to be written to every register via the SPI. + +Applications +------------ +- Mechanical potentiometer replacement +- Instrumentation: gain and offset adjustment +- Programmable voltage-to-current conversion +- Programmable filters, delays, and time constants +- Programmable power supply +- Low resolution DAC replacements +- Sensor calibration + +Device Configuration +-------------------- +Single Chips Use +^^^^^^^^^^^^^^^^^^ +Single chip use is compatible for normal SPI device hardware topology. +For this configuration set chip num to 1 in initilazation struct. + +Multiple Chips Use +^^^^^^^^^^^^^^^^^^ +Multiple chips could be used in application, daisy chaining topology can +minimizes the number of port pins required from the controlling IC. For +this driver, if more than 1 chip are used, daisy-chain hardware topology +is required. All RESET pins are required to connect together. For this +configuration set chip num greater than 1 in initilazation struct. + +Device Operation +---------------- + +Write Operation +^^^^^^^^^^^^^^^ +In order to write to the RDAC calibration mode, you will need to +call the **ad5293_update_cali** to update calibration on specific +chip struct, then call the **ad5293_write_cali** to perform a write performance. + +In order to write to the RDAC wiper value, you will need to +call the **ad5293_update_wiper** to update wiper value on specific +chip struct, then call the **ad5293_write_cali** to perform a write performance. +**RDAC register write protect register** is only unlocked in **ad5293_write_cali** +to pervent undesired wiper write. + +Each write perform will write all chips, for multiple chips application, +update all relevant data before perform write. + +Read Operation +^^^^^^^^^^^^^^ +In order to read the RDAC calibration mode, you will need to +call the **ad5293_read_reg_cali**, calibration mode will be updated +to chip struct. + +In order to read the RDAC wiper value, you will need to +call the **ad5293_read_reg_wiper**, wiper value will be updated +to chip struct. + +Reset +^^^^^ +In order to read the RDAC chips, you will need to +call the **ad5293_hard_reset** to implement hardware reset +with a low-to-high transition of the hardware RESET pin, +or call the **ad5293_soft_reset** to implement software reset +through SPI interface. After reset, RDAC registers are loaded +with midscale, the control registers are restored with default bits. + +Minimize The SDO Power Dissipation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The SDO pin contains an open-drain N-channel FET that requires a pull-up +resistor if this pin is used. This pin could be place in by calling **ad5293_sdo_setfloat** +high impedence to minimize power dissipation. ( User should be careful with this operation, +SPI comminications integrity may be affected) + +Get Data +^^^^^^^^ +In order to get the RDAC calibration mode or wiper value from chips struct, +you will need to call the **ad5293_get_cali** or **ad5293_get_wiper**, which +returns data of specified chip. + +Shutdown +^^^^^^^^ +RDAC can be placed in a special state in which Terminal A is open-circuited +and Wiper W is connected to Terminal B, this is shutdown mode. Contents in +RDAC are not changed and all command through SPI are supported in this mode. +In order to RDAC to shut down mode, call **ad5293_shutdown** and input parameter +from enmu type **shutdown_t**. + +Driver Initialization +--------------------- +In order to be able to use the device, you will have to provide the support for +the communication protocol (SPI) as mentioned above. + +Device Struct Description +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: C + + struct ad5293_dev { + /* SPI */ + struct no_os_spi_desc *spi_desc; + /* GPIO */ + struct no_os_gpio_desc *gpio_reset; + /* number of chips */ + uint16_t chip_num; + /* pointer of chip struct */ + struct ad5293_chip_info* chip; //point to chip 0 + }; + +ad5293_dev + overall device information holder, multiple chips are regards as one device +no_os_spi_desc + no-os lib definded spi device instance handler +no_os_gpio_desc + no-os lib definded gpio instance handler for reset pin +chip_num + number of chip +ad5293_chip_info + pointer to allocated memory for **ad5293_chip_info** structs, total amount + is chip_num*sizeof(ad5293_chip_info), different chip information is accessed + by different pointer offset(array operation) + +Driver Initialization Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +An initialization and test example on stm32 could be + +.. code-block:: C + + #define RESET_PORT 0 //PORT A + #define RESET_PIN 11 + #define RDAC_CS_PORT 1 //PORT B + #define RDAC_CS_PIN 12 + + //function + uint32_t get_spi2_clock(void); + + //adi device pointer define + struct ad5293_dev* pad5293_dev; + + uint32_t get_spi2_clock(void) + { + return LL_RCC_GetSPIClockFreq(LL_RCC_SPI123_CLKSOURCE); + } + + void rdac_init(void) + { + int32_t ret = 0; + struct ad5293_init_param rdac_init; + + //start timer 5 as delay counter + delay_init(); + + struct no_os_gpio_init_param RESET_init; + struct stm32_gpio_init_param RESET_init_stm; + + RESET_init.port = RESET_PORT; + RESET_init.number = RESET_PIN; + RESET_init.pull = NO_OS_PULL_NONE; + RESET_init.platform_ops = & stm32_gpio_ops; + RESET_init.extra = (void*) & RESET_init_stm; + RESET_init_stm.mode = GPIO_MODE_OUTPUT_PP; + RESET_init_stm.speed = GPIO_SPEED_FREQ_HIGH; + RESET_init_stm.alternate = 0; + + rdac_init.gpio_reset = & RESET_init; + //spi GPIO init struct preparation + struct stm32_spi_init_param stm32_spi_init; + + stm32_spi_init.chip_select_port = RDAC_CS_PORT; //GPIO CS PORT + stm32_spi_init.get_input_clock = & get_spi2_clock; + stm32_spi_init.alternate = 0; + + rdac_init.spi_init.extra = (void*) & stm32_spi_init; + rdac_init.spi_init.platform_ops = & stm32_spi_ops; + + rdac_init.spi_init.device_id = 2; //spi device 1 + rdac_init.spi_init.max_speed_hz = 200 * 1000; //3mHz + rdac_init.spi_init.chip_select = RDAC_CS_PIN; //GPIO CS PIN + rdac_init.spi_init.mode = NO_OS_SPI_MODE_1; + rdac_init.spi_init.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST; + + rdac_init.spi_init.platform_delays.cs_delay_first = 0; //delay before transfer + rdac_init.spi_init.platform_delays.cs_delay_last = 0; //delay after transfer + + rdac_init.chip_num = 6; + + ret = ad5293_init( & pad5293_dev, & rdac_init); + if(ret) + printf("rdac init error. \r\n"); + + } + + void rdac_test(void) + { + int i, cali_val[pad5293_dev->chip_num]; + int16_t wp_value[pad5293_dev->chip_num]; + + + ad5293_hard_reset(pad5293_dev); + + no_os_mdelay(1); + + for(i = 0;i < pad5293_dev->chip_num;i++) + { + ad5293_update_cali(pad5293_dev, CALI_NORMAL, i); + ad5293_update_wiper(pad5293_dev, 768, i); + } + + ad5293_write_cali(pad5293_dev); + ad5293_write_wiper(pad5293_dev); + + ad5293_read_reg_cali(pad5293_dev); + ad5293_read_reg_wiper(pad5293_dev); + + no_os_mdelay(1); + + for(i = 0;i < pad5293_dev->chip_num;i++) + { + cali_val[i] = ad5293_get_cali(pad5293_dev, i); + wp_value[i] = ad5293_get_wiper(pad5293_dev, i); + } + + ad5293_shutdown(pad5293_dev, SHUTDOWN); + + no_os_mdelay(1); + + ad5293_shutdown(pad5293_dev, NORMAL); + + no_os_mdelay(1); + + ad5293_soft_reset(pad5293_dev); + + no_os_mdelay(1); + + for(i = 0;i < pad5293_dev->chip_num;i++) + { + ad5293_update_cali(pad5293_dev, CALI_NORMAL, i); + ad5293_update_wiper(pad5293_dev, 256, i); + } + + ad5293_write_cali(pad5293_dev); + ad5293_write_wiper(pad5293_dev); + + ad5293_read_reg_cali(pad5293_dev); + ad5293_read_reg_wiper(pad5293_dev); + + no_os_mdelay(1); + } \ No newline at end of file diff --git a/drivers/potentiometer/ad5293/ad5293.c b/drivers/potentiometer/ad5293/ad5293.c new file mode 100644 index 00000000000..6714a0186b5 --- /dev/null +++ b/drivers/potentiometer/ad5293/ad5293.c @@ -0,0 +1,553 @@ +/***************************************************************************//** + * @file ad5293.c + * @brief Source file for the AD5293 Driver + * @author Ming Zeng +******************************************************************************** +The MIT License (MIT) + +Copyright (c) 2024 Ming Zeng + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*******************************************************************************/ + +/***************************** Include Files **********************************/ +#include +#include +#include +#include "ad5293.h" +#include "no_os_alloc.h" +#include "no_os_delay.h" + +/***************************************************************************//** + * @brief Reset ad5293 chip info + * + * Reset ad5293 chip info to default situation after hard/soft reset + * + * @param dev - The device structure. + * + * @return void + *******************************************************************************/ +static void ad5293_reset_chip_info(struct ad5293_dev* dev) +{ + uint8_t i; + + for (i = 0; i < dev->chip_num; i++) { + (dev->chip + i)->Wiper_value = 512; + (dev->chip + i)->cali = CALI_PERFORMANCE; + } +} + +/***************************************************************************//** + * @brief Initialize the ad5293 device structure. + * + * Performs memory allocation of the device structure. + * + * @param device - Pointer to location of device structure to write. + * @param init_param - Pointer to configuration of the driver. + * + * @return ret - return code. + * Example: -ENOMEM - Memory allocation error. + * -EINVAL - No GPIO instance. + * -EINVAL - No valid chip number. + * -EIO - SPI communication error. + * -EIO - GPIO initialization error. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_init(struct ad5293_dev **device, + struct ad5293_init_param* init_param) +{ + struct ad5293_dev* dev = NULL; + struct ad5293_chip_info* chp = NULL; + int32_t ret ; + + if ((! device) || (! init_param)) + return - EINVAL; + + dev = (struct ad5293_dev*)no_os_malloc(sizeof(* dev)); + if (! dev) + return - ENOMEM; + + // hardware reset pin initialization + if (init_param->gpio_reset) { + ret = no_os_gpio_get_optional(& dev->gpio_reset, init_param->gpio_reset); + if (ret) { + ret = - EIO; + goto error; + } + + ret = no_os_gpio_set_value(dev->gpio_reset, NO_OS_GPIO_HIGH); + if (ret) { + ret = - EIO; + goto error; + } + } + + // at least 1 chip + if (init_param->chip_num < 1) { + ret = - EINVAL; + goto error; + } + + dev->chip_num = init_param->chip_num; + chp = (struct ad5293_chip_info*)no_os_malloc(dev->chip_num * sizeof(* chp)); + if (! chp) { + ret = - ENOMEM; + goto error; + } + + dev->chip = chp; + + // reset all chips + ret = ad5293_hard_reset(dev); + if (ret) + goto error; + + // spi initialization + init_param->spi_init.mode = NO_OS_SPI_MODE_1; // CPOL=0, CPHA=1 + ret = no_os_spi_init(& dev->spi_desc, & init_param->spi_init); + if (ret) { + ret = - EIO; + goto error; + } + + *device = dev; + + return ret; + +error: + if (dev->gpio_reset) + ret = no_os_gpio_remove(dev->gpio_reset); + if (dev->spi_desc) + ret = no_os_spi_remove(dev->gpio_reset); + no_os_free(chp); + no_os_free(dev); + return ret; +} + +/***************************************************************************//** + * @brief Free any resource used by the driver. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_remove(struct ad5293_dev* dev) +{ + int32_t ret ; + + if (dev->gpio_reset) { + ret = no_os_gpio_remove(dev->gpio_reset); + if (ret) + return ret; + } + + ret = no_os_spi_remove(dev->spi_desc); + if (ret) + return ret; + + no_os_free(dev->chip); + no_os_free(dev); + + return ret; +} + +/***************************************************************************//** + * @brief Reset ad5293 through Hardware Reset Pin. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_hard_reset(struct ad5293_dev* dev) +{ + int32_t ret ; + + if (! dev->gpio_reset) + return - EINVAL; + + ret = no_os_gpio_set_value(dev->gpio_reset, NO_OS_GPIO_LOW); + if (ret) + return ret; + + no_os_udelay(1); // >20ns pulse width + + ret = no_os_gpio_set_value(dev->gpio_reset, NO_OS_GPIO_HIGH); + if (ret) + return ret; + + no_os_mdelay(2); // t12: max 1.5ms reset time + + ad5293_reset_chip_info(dev); + + return ret; +} + +/***************************************************************************//** + * @brief Reset ad5293 through software reset command. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_soft_reset(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(RESET_FRAME >> 8); + buf[2 * i + 1] = (uint8_t)(RESET_FRAME); + } + + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + no_os_mdelay(2); // t12: max 1.5ms reset time + + ad5293_reset_chip_info(dev); + + return ret; +} + +/***************************************************************************//** + * @brief Place SDO pin in high impedence mode. + * + * Minimize power dissipation when pin is used. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_sdo_setfloat(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(CMD_SDO_Z >> 8); + buf[2 * i + 1] = (uint8_t)CMD_SDO_Z; + } + + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + memset(& buf, 0, sz); + + return no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); +} + +/***************************************************************************//** + * @brief Place ad5293 in shutdown mode or recovery. + * + * In shut down mode, terminal A open, Wiper and terminal B connected. + * + * @param dev - The device structure. + * @param sd - shutdown mode selection. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_shutdown(struct ad5293_dev* dev, enum shutdown_t sd) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(SHUTDOWN_FRAME(sd) >> 8); + buf[2 * i + 1] = (uint8_t)SHUTDOWN_FRAME(sd); + } + + return no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); +} + +/***************************************************************************//** + * @brief Update ad5293 chip info struct calibration information. + * + * For calibration register write operation. + * + * @param dev - The device structure. + * @param cali - calibration mode selection. + * @param num - chip indication. + * + * @return ret - return code. + * Example: -EINVAL - No valid num input. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_update_cali(struct ad5293_dev* dev, enum calibration_mode_t cali, + uint8_t num) +{ + + if (num > (dev->chip_num - 1)) + return - EINVAL; + + (dev->chip + num)->cali = cali; + + return 0; +} + +/***************************************************************************//** + * @brief Update ad5293 chip info struct wiper value information. + * + * For wiper register write operation. + * + * @param dev - The device structure. + * @param val - wiper value. + * @param num - chip indication. + * + * @return ret - return code. + * Example: -EINVAL - No valid num input. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_update_wiper(struct ad5293_dev* dev, uint16_t val, uint8_t num) +{ + if (num > (dev->chip_num - 1)) + return - EINVAL; + + (dev->chip + num)->Wiper_value = val; + + return 0; +} + +/* internal function to lock/unlock write protection of ad5293*/ +static int32_t ad5293_write_protect(struct ad5293_dev* dev, + enum protect_mode_t pm) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + enum protect_mode_t cali; + + for (i = 0; i < dev->chip_num; i++) { + cali = (dev->chip + i)->cali; + buf[2 * i] = (uint8_t)(AD5293_W_CTRL_FRAME(pm, cali) >> 8); + buf[2 * i + 1] = (uint8_t)(AD5293_W_CTRL_FRAME(pm, cali)); + } + + return no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); +} + +/***************************************************************************//** + * @brief Write ad5293 chip info struct calibration value through SPI interface. + * + * Note: multiple chips operation should in daisy-chain mode. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_write_cali(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + enum calibration_mode_t cali; + + for (i = 0; i < dev->chip_num; i++) { + cali = (dev->chip + i)->cali; + buf[2 * i] = (uint8_t)(AD5293_W_CTRL_FRAME(PROTECT_LOCK, cali) >> 8); + buf[2 * i + 1] = (uint8_t)(AD5293_W_CTRL_FRAME(PROTECT_LOCK, cali)); + } + + return no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); +} + +/***************************************************************************//** + * @brief Write ad5293 chip info struct wiper value through SPI interface. + * + * Note: multiple chips operation should in daisy-chain mode. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_write_wiper(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(AD5293_W_WIPER_FRAME((dev->chip + i)->Wiper_value) >> 8); + buf[2 * i + 1] = (uint8_t)(AD5293_W_WIPER_FRAME((dev->chip + i)->Wiper_value)); + } + + ret = ad5293_write_protect(dev, PROTECT_UNLOCK); + if (ret) + return ret; + + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + no_os_udelay(3); // performance mode, t12 > 2.4us + + return ad5293_write_protect(dev, PROTECT_LOCK); + +} + +/***************************************************************************//** + * @brief Read ad5293 device register calibration mode through SPI interface. + * + * read ad5293 calibration value and update it to chip info struct. + * Note: multiple chips operation should in daisy-chain mode. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_read_reg_cali(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(AD5293_R_CTRL_FRAME >> 8); + buf[2 * i + 1] = (uint8_t)(AD5293_R_CTRL_FRAME); + } + + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + memset(& buf, 0, sz); + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + for (i = 0; i < dev->chip_num; i++) + (dev->chip + i)->cali = no_os_field_get(CALI_MSK, buf[2 * i + 1]); + + return ret; +} + +/***************************************************************************//** + * @brief Read ad5293 device register wiper value through SPI interface. + * + * read ad5293 wiper value and update it to chip info struct. + * Note: multiple chips operation should in daisy-chain mode. + * + * @param dev - The device structure. + * + * @return ret - return code. + * Example: -EINVAL - No valid pointer input. + * -ENOSYS - No valid operation. + * 0 - No errors encountered. + *******************************************************************************/ +int32_t ad5293_read_reg_wiper(struct ad5293_dev* dev) +{ + int32_t ret ; + uint8_t i; + uint16_t sz = 2 * dev->chip_num; + uint8_t buf[sz]; + + for (i = 0; i < dev->chip_num; i++) { + buf[2 * i] = (uint8_t)(AD5293_R_WIPER_FRAME >> 8); + buf[2 * i + 1] = (uint8_t)(AD5293_R_WIPER_FRAME); + } + + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + memset(& buf, 0, sz); + ret = no_os_spi_write_and_read(dev->spi_desc, & buf[0], sz); + if (ret) + return ret; + + for (i = 0; i < dev->chip_num; i++) + (dev->chip + i)->Wiper_value = (uint16_t)buf[2 * i] << 8 | buf[2 * i + 1]; + + return ret; +} + +/***************************************************************************//** + * @brief Get calibration of a certain chip. + * + * return chip info struct calibration value to caller. + * + * @param dev - The device structure. + * @param num - The device number.( 0 to chip_num-1) + * + * @return ret - return code. + * Example: -EINVAL - No valid chip selected. + * 0 - No errors encountered. + *******************************************************************************/ +int8_t ad5293_get_cali(struct ad5293_dev* dev, uint8_t num) +{ + if (num > (dev->chip_num - 1)) + return - EINVAL; + + return (dev->chip + num)->cali; +} + +/***************************************************************************//** + * @brief Get wiper of a certain chip. + * + * return chip info struct wiper value to caller. + * + * @param dev - The device structure. + * @param num - The device number.( 0 to chip_num-1) + * + * @return ret - return code. + * Example: -EINVAL - No valid chip selected. + * 0 - No errors encountered. + *******************************************************************************/ +int16_t ad5293_get_wiper(struct ad5293_dev* dev, uint8_t num) +{ + if (num > (dev->chip_num - 1)) + return - EINVAL; + + return (dev->chip + num)->Wiper_value; +} diff --git a/drivers/potentiometer/ad5293/ad5293.h b/drivers/potentiometer/ad5293/ad5293.h new file mode 100644 index 00000000000..9c197230380 --- /dev/null +++ b/drivers/potentiometer/ad5293/ad5293.h @@ -0,0 +1,148 @@ +/***************************************************************************//** + * @file ad5293.h + * @brief Header file for the AD5293 Driver + * @author Ming Zeng +******************************************************************************** +The MIT License (MIT) + +Copyright (c) 2024 Ming Zeng + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*******************************************************************************/ + +#ifndef _AD5293_H_ +#define _AD5293_H_ + +/****************************** Include Files ********************************/ +#include +#include "no_os_gpio.h" +#include "no_os_spi.h" +#include "no_os_util.h" + +/* SPI Read/Write commands */ +#define CMD_NOP 0 +#define CMD_W_WIPER 1 +#define CMD_R_WIPER 2 +#define CMD_RESET 4 +#define CMD_W_CTRL 6 +#define CMD_R_CTRL 7 +#define CMD_PD 8 +#define CMD_SDO_Z 0x8001 + +/* Bit mask*/ +#define CALI_MSK NO_OS_BIT(2) +#define PROTECT_MSK NO_OS_BIT(1) + +/* calibration mode */ +enum calibration_mode_t { + CALI_PERFORMANCE, + CALI_NORMAL +}; + +/* protect mode */ +enum protect_mode_t { + PROTECT_LOCK, + PROTECT_UNLOCK // enable update wiper position through digital interface +}; + +/* shutdown mode */ +enum shutdown_t { + NORMAL, + SHUTDOWN +}; + +/* operation mode */ +enum operation_mode_t { + BUS, + DAISY_CHAIN +}; + +/* SDO mode */ +enum sdo_mode_t { + SDO_DISENABLE, + SDO_ENABLE +}; + +/* SPI frame */ +#define AD5293_W_CTRL_FRAME(pm,cali) (uint16_t)((CMD_W_CTRL<<10)|(pm<<1)|(cali<<2)) +#define AD5293_R_CTRL_FRAME (uint16_t)CMD_R_CTRL<<10 +#define AD5293_W_WIPER_FRAME(data) (uint16_t)((CMD_W_WIPER<<10)|data) +#define AD5293_R_WIPER_FRAME (uint16_t)CMD_R_WIPER<<10 +#define SHUTDOWN_FRAME(sd) (uint16_t)((CMD_PD<<10)|sd) +#define RESET_FRAME (uint16_t)CMD_RESET<<10 + +/**********************************struct*****************************************/ +struct ad5293_chip_info { + enum calibration_mode_t cali; + uint16_t Wiper_value; //10bit +}; + +struct ad5293_dev { + /* SPI */ + struct no_os_spi_desc *spi_desc; + /* GPIO */ + struct no_os_gpio_desc *gpio_reset; + /* number of chips */ + uint16_t chip_num; + /* pointer of chip struct */ + struct ad5293_chip_info* chip; //point to chip 0 +}; + +struct ad5293_init_param { + /* SPI */ + struct no_os_spi_init_param spi_init; + /* GPIO */ + struct no_os_gpio_init_param* gpio_reset; + /* number of chips */ + uint16_t chip_num; +}; + +/*******************************functions prototype*******************************/ +/* Initialize the ad5293 device structure. */ +int32_t ad5293_init(struct ad5293_dev **device, + struct ad5293_init_param* init_param); +/* Free any resource used by the driver. */ +int32_t ad5293_remove(struct ad5293_dev* dev); +/* Reset ad5293 through Hardware Reset Pin. */ +int32_t ad5293_hard_reset(struct ad5293_dev* dev); +/* Reset ad5293 through software reset command. */ +int32_t ad5293_soft_reset(struct ad5293_dev* dev); +/* Place SDO pin in high impedence mode. */ +int32_t ad5293_sdo_setfloat(struct ad5293_dev* dev); +/* Place ad5293 in shutdown mode or recovery. */ +int32_t ad5293_shutdown(struct ad5293_dev* dev, enum shutdown_t sd); +/* Update ad5293 chip info struct calibration information. */ +int32_t ad5293_update_cali(struct ad5293_dev* dev, enum calibration_mode_t cali, + uint8_t num); +/* Update ad5293 chip info struct wiper value information. */ +int32_t ad5293_update_wiper(struct ad5293_dev* dev, uint16_t val, uint8_t num); +/* Write ad5293 chip info struct calibration value through SPI interface. */ +int32_t ad5293_write_cali(struct ad5293_dev* dev); +/* Write ad5293 chip info struct wiper value through SPI interface. */ +int32_t ad5293_write_wiper(struct ad5293_dev* dev); +/* Read ad5293 device register calibration mode through SPI interface. */ +int32_t ad5293_read_reg_cali(struct ad5293_dev* dev); +/* Read ad5293 device register wiper value through SPI interface. */ +int32_t ad5293_read_reg_wiper(struct ad5293_dev* dev); +/* Get calibration of a certain chip. */ +int8_t ad5293_get_cali(struct ad5293_dev* dev, uint8_t num); +/* Get wiper of a certain chip. */ +int16_t ad5293_get_wiper(struct ad5293_dev* dev, uint8_t num); + +#endif // _AD5293_H_