esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
420 stars 26 forks source link

Add an new component ad5291 5292 Digital Potentiometers #2515

Open userosos opened 11 months ago

userosos commented 11 months ago

(https://www.analog.com/media/en/technical-documentation/data-sheets/ad5291_5292.pdf)

It is Digital Potentiometers. Used SPI. The AD5291/AD5292 contain a serial interface (SYNC, SCLK, DIN and SDO) that is compatible with SPI interface standards, as well as most DSPs. The part allows writing of data via the serial interface to every register. SHIFT REGISTER The AD5291/AD5292 shift register is 16 bits wide (see Figure 2). The 16-bit input word consists of two zeros, followed by four control bits, and 10 RDAC data bits. For the AD5291, the lower two RDAC data bits are don’t cares if the RDAC register is read from or written to. Data is loaded MSB first (Bit DB15). The four control bits determine the function of the software command (see Table 11). Figure 3 shows a timing diagram of a typical AD5291 and AD5292 write sequence. The write sequence begins by bringing the SYNC line low. The SYNC pin must be held low until the complete data-word is loaded from the DIN pin. When SYNC returns high, the serial data-word is decoded according to the commands in Table 11. The command bits (Cx) control the operation of the digital potentiometer. The data bits (Dx) are the values that are loaded into the decoded register. The AD5291/AD5292 have an internal counter that counts a multiple of 16 bits (a frame) for proper operation. For example, AD5291/AD5292 work with a 32-bit word but does not work proper- ly with a 31-bit or 33-bit word. The AD5291/AD5292 do not require a continuous SCLK, when SYNC is high, and all serial interface pins should be operated at close to the VLOGIC supply rails to minimize power consumption in the digital input buffers.

userosos commented 11 months ago

I found an old library for AD5292 for arduino. May be it will be help https://github.com/That8BitMan/AD5292

userosos commented 10 months ago

Anybody can help me for add the component in ESPHOME? How can i just send a numbers at SPI interface in an address?

userosos commented 9 months ago

Hi, Everyone. I create the AD5292.h used an example but i can't check it. Somebody can help me?

#include "esphome.h"

using namespace esphome;

class AD5292 : public Component, public FloatOutput {
 public:
  /*
  AD5292 Digital Pot Control

  The AD5292 is SPI-compatible. The hardware is managed by sending two bytes:
  Command Bits[DB13:DB10]
  Data Bits[DB9:DB0]
  */

  // Define the MCP41100 OP command bits (only one POT)
  // Note: command byte format xxCCxxPP, CC command, PP pot number (01 if selected) 
  #define AD5292_NOP 0b0000000000000000 // NOP command: do nothing. Command 0.
  #define AD5292_WRITE 0b000001 // Write contents of serial data to RDAC. Command 1.
  #define AD5292_SHTDWN 0b0010000000000001 // Software shutdown. D0 = 0 (normal mode). D0 = 1 (device placed in shutdown mode). Command 8.
  //                                     ^D0 bit
  #define AD5292_READ_RDAC 0b0000100000000000 // Read RDAC wiper setting from the SDO output in the next frame. Command 2.
  #define AD5292_SAVE_20TP 0b0000110000000000 // Store wiper setting: store RDAC setting to 20-TP memory. Save 20-TP memory settings in RDAC. Command 3.
  #define AD5292_RESET_20TP 0b0001000000000000 // Reset: refresh RDAC with 20-TP stored value. Command 4.
  #define AD5292_READ_20TP 0b00010000000 // Read contents of 20-TP memory, or status of 20-TP memory, from the SDO output in the next frame. Command 5.
  #define AD5292_WRITE_CR 0b000110000000 // Write contents of serial data to control register. Command 6.
  #define AD5292_READ_CR 0b0001110000000000 // Read control register from the SDO output in the next frame.. Command 7.

  // Define the CS (chip select) for the digital pot
  int CS_PIN = 5;

  void setup() override {
    SPI.begin();
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
  }

  void write_state(float state) override {
    // state is the amount this output should be on, from 0.0 to 1.0
    // we need to convert it to an integer first
    int value = state * 255;

    SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));
    digitalWrite(CS_PIN, LOW); // CS pin low to select chip
    delay(50);
    SPI.transfer(AD5292_WRITE);   // Send command code
    SPI.transfer(value);       // Send associated value
    delay(50);
    digitalWrite(CS_PIN, HIGH);// CS pin high to de-select chip
    SPI.endTransaction();
  }
};

AD5292.zip

In yaml:

esphome:
  name: pool-pump-controller
  friendly_name: Pool Pump Controller
  includes:
    AD5292/AD5292.h

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23

number:
  - platform: template
    name: "Speed"
    min_value: 0
    max_value: 100
    step: 1
    optimistic: true
    unit_of_measurement: "%"
    mode: slider
    set_action:
      - output.set_level:
          id: pot_out
          level: !lambda "return x / 100.0;"

output:
- platform: custom
  type: float
  lambda: |-
    auto AD5292= new AD5292();
    App.register_component(AD5292);
    return {AD5292};

  outputs:
    id: pot_out
userosos commented 9 months ago

Now i have the errors:

INFO ESPHome 2023.12.9
INFO Reading configuration /config/esphome/hv-control.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing hv-control (board: esp32dev; framework: arduino; platform: platformio/espressif32@5.4.0)
--------------------------------------------------------------------------------
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
 - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
Dependency Graph
|-- AsyncTCP-esphome @ 2.0.1
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.1.0
|-- DNSServer @ 2.0.0
|-- ESPmDNS @ 2.0.0
|-- noise-c @ 0.1.4
|-- SPI @ 2.0.0
Compiling .pioenvs/hv-control/src/main.cpp.o
Compiling .pioenvs/hv-control/lib64d/WiFi/WiFiUdp.cpp.o
Archiving .pioenvs/hv-control/lib64d/libWiFi.a
Compiling .pioenvs/hv-control/lib01c/FS/FS.cpp.o
<unicode string>: In lambda function:
<unicode string>:57:25: error: expected type-specifier before 'AD5292'
<unicode string>:59:21: error: could not convert '{AD5292}' from '<brace-enclosed initializer list>' to 'std::vector<esphome::output::FloatOutput*>'
*** [.pioenvs/hv-control/src/main.cpp.o] Error 1
========================== [FAILED] Took 7.41 seconds ==========================
userosos commented 9 months ago

Now i want configure the potentiometer used an config:

esphome:
  name: hv-control
  friendly_name: HV control
#  includes:
#    - AD5292/AD5292.h

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: DEBUG
  hardware_uart: UART0
# Enable Home Assistant API
api:
  encryption:
    key: 
ota:
  password: 

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Hv-Control Fallback Hotspot"
    password: 

captive_portal:

spi:
  clk_pin: GPIO32
  mosi_pin: GPIO26
  miso_pin: GPIO25

  interface: hardware
spi_device:
  id: Pot
#  cs_pin: GPIO27
  data_rate: 1MHz
  mode: 2
  bit_order: msb_first  

number:
  - platform: template
    name: "Potentiometr"
    min_value: 0
    max_value: 255
    step: 1
    optimistic: true
    unit_of_measurement: "V"
    mode: box
    update_interval: 1s
    id: Potentiometr_temp
    on_value:
      then:
        - lambda: !lambda |-
            id(Pot).enable();
            id(Pot).write_byte(0b000001);
            id(Pot).write_byte(id(Potentiometr_temp).state);
            id(Pot).disable();

#output:
#- platform: custom
#  type: float
#  lambda: |-
#    auto AD5292 = new AD5292();
#    App.register_component(AD5292);
#    return {AD5292};

#  outputs:
#    id: pot_out  

sensor:
  - platform: adc
    pin: A5
    name: "Out from AD5292"
    update_interval: 500ms
    attenuation: auto
    id: V_from_AD5292
    accuracy_decimals: 4
    unit_of_measurement: V 

I want enabled logs in terminal for get info about send some data in the SPI. But the config has no data about send to the SPI.

userosos commented 9 months ago

Today i make it:

spi:
  clk_pin: GPIO32
  mosi_pin: GPIO26
  miso_pin: GPIO25

  interface: hardware
spi_device:
  id: Pot
#  cs_pin: GPIO27
  data_rate: 1MHz
  mode: 3
  bit_order: msb_first  

number:
  - platform: template
    name: "Potentiometr"
    min_value: 0
    max_value: 10000
    step: 1
    optimistic: true
    unit_of_measurement: "ohms"
    mode: box
    update_interval: 1s
    id: Potentiometr_temp
    on_value:
      then:
        - lambda: !lambda |-
              uint16_t desired_value = x;
              uint16_t command = 1; //  command for write
              uint16_t data = desired_value & 0x3FF; // from 0 to 1023 include 
              data |= command <<10; // add command first
              uint8_t first_byte =  data >> 8;
              uint8_t second_byte =  data & 0xff;
              id(Pot).enable();
              id(Pot).write_byte(first_byte);
              id(Pot).write_byte(second_byte);
              id(Pot).disable();
              ESP_LOGD("desired_values", "%d", desired_value);
              ESP_LOGD("SPI",  "send to the AD5292 0x%x", data);

button:
  - platform: template
    name: "Reset RDAC"
    id: Reset_RDAC

    # Optional variables:
    icon: "mdi:emoticon-outline"
    on_press:
      then:
        - lambda: !lambda |-
              uint16_t command = 0b000100; //  command for RESET RDAC
              id(Pot).enable();
              id(Pot).write_byte(command);
              id(Pot).write_byte(0b0000000000);
              id(Pot).disable();
              ESP_LOGD("RESET", "%t");
  - platform: template
    name: "SEND 1023 ohms"
    id: Send_1023

    # Optional variables:
    icon: "mdi:emoticon-outline"
    on_press:
      then:
        - lambda: !lambda |-
              uint16_t command = 0b01; //  command for write to RDAC
              id(Pot).enable();
              id(Pot).write_byte(command);
              id(Pot).write_byte(0b00001111111111);
              id(Pot).disable();
              ESP_LOGD("1023 ohms", "%t");

#            id(Pot).enable();
#            id(Pot).write_byte(0b000001>>x);
#            id(Pot).write_byte(x);
#            id(Pot).disable();
#            esp_logd("SPI send to the AD5292", id(Pot).write_byte(second_byte));

#output:
#- platform: custom
#  type: float
#  lambda: |-
#    auto AD5292 = new AD5292();
#    App.register_component(AD5292);
#    return {AD5292};

#  outputs:
#    id: pot_out  

sensor:
  - platform: adc
    pin: A5
    name: "Out from AD5292"
    update_interval: 500ms
    attenuation: auto
    id: V_from_AD5292
    accuracy_decimals: 4
    unit_of_measurement: V  

It not work

userosos commented 9 months ago

Hi! I found the library https://github.com/nostoslabs/AD5292