This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

multiple hx711 with nrf52832

​Hello Nordic Team,
I'm starting a project which consist in measure pressure in multiple points and send this data to central unit. At this point, using strain gauges  with hx7111 it's a good  start for a first prototipe and  i already seen the library for the hx711 developed by Vidar, but  this only  support one hx711; its feasible modify this library to work with at least two hx711?  If it's  possible, what's the better way to doing this?In this project i'm using the nRF52 DK.

Any suggest will be most appreciated.

Regards

Parents
  • Hello,

    I don't foresee problems with expanding it to support 2 ADCs. I guess the main change is to make it dynamically switch pin configuration depending on which sensor you are addressing at any given point. The GPIOTE triggering need to happen for both DOUT pins.

     
  • Hello Vidar,
    i trying to implement your suggestion, but it doesn't work for now... maybe i misunderstood something. Currently, i have modified very little the init function for switch the pins to communicate with each hx711 (attached). I using a timer, in repetead mode, for calling the this init function each 1 seconds, so i'm capable to read the data of each hx only once... after calling the init function for a second time the nrf_drv_gpiote_in_init is throwing error NRF_ERROR_INVALID_STATE, because the DOUT pin were initialized before... i try to uninitializing the pin with nrf_drv_gpiote_in_uninit but doesn't worked. Also i used nrf_drv_gpiote_in_is_set to check and avoid re initialized with nrf_drv_gpiote_in_init but im getting Unknown error code from nrfx_gpiote.c:568 and this confused me.
    Please help.

    Regards

    void hx711_init(hx711_mode_t mode, hx711_event_handler_t evt_handler, uint32_t input_PD_SCK, uint32_t input_DOUT)
    {
      PD_SCK= input_PD_SCK;
      DOUT= input_DOUT;
      ret_code_t                  ret_code;
      nrf_drv_gpiote_in_config_t  gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
    
      m_evt_handler = evt_handler;
      m_mode = mode;
    
      nrf_gpio_cfg_output(PD_SCK);
      nrf_gpio_pin_set(PD_SCK);
      
      nrf_gpio_cfg(VDD, 
                   NRF_GPIO_PIN_DIR_OUTPUT, 
                   NRF_GPIO_PIN_INPUT_DISCONNECT, 
                   NRF_GPIO_PIN_PULLUP, 
                   NRF_GPIO_PIN_S0H1, 
                   NRF_GPIO_PIN_NOSENSE);
      nrf_gpio_pin_set(VDD);
    
      nrf_gpio_cfg_input(DOUT, NRF_GPIO_PIN_NOPULL);
    
      if (!nrf_drv_gpiote_is_init())
      {
        ret_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(ret_code);
      }
       NRF_LOG_INFO(" PIN # :%d", DOUT);
       //NRF_LOG_INFO("PIN Check :%d", nrf_drv_gpiote_in_is_set(DOUT));
      if (!nrf_drv_gpiote_in_is_set(DOUT)){
      ret_code = nrf_drv_gpiote_in_init(DOUT, &gpiote_config, gpiote_evt_handler);
    
      NRF_LOG_INFO(" nrf drv :%d", ret_code);
    
      APP_ERROR_CHECK(ret_code);
      }
      
    
      /* Set up timers, gpiote, and ppi for clock signal generation*/
      NRF_TIMER1->CC[0]     = 1;
      NRF_TIMER1->CC[1]     = TIMER_COMPARE;
      NRF_TIMER1->CC[2]     = TIMER_COUNTERTOP;
      NRF_TIMER1->SHORTS    = (uint32_t) (1 << 2);    //COMPARE2_CLEAR
      NRF_TIMER1->PRESCALER = 0;
    
      NRF_TIMER2->CC[0]     = m_mode;
      NRF_TIMER2->MODE      = 2;
    
      NRF_GPIOTE->CONFIG[1] = (uint32_t) (3 | (PD_SCK << 8) | (1 << 16) | (1 << 20));
    
      NRF_PPI->CH[0].EEP   = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[0];
      NRF_PPI->CH[0].TEP   = (uint32_t) &NRF_GPIOTE->TASKS_SET[1];
      NRF_PPI->CH[1].EEP   = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[1];
      NRF_PPI->CH[1].TEP   = (uint32_t) &NRF_GPIOTE->TASKS_CLR[1];
      NRF_PPI->FORK[1].TEP = (uint32_t) &NRF_TIMER2->TASKS_COUNT; // Increment on falling edge
      NRF_PPI->CH[2].EEP   = (uint32_t) &NRF_TIMER2->EVENTS_COMPARE[0];
      NRF_PPI->CH[2].TEP   = (uint32_t) &NRF_TIMER1->TASKS_SHUTDOWN;
      NRF_PPI->CHEN = 7;
      
    }

  • Hello,

    You can try to implement something similar to what I have posted below. I haven't tested this code but the idea is to do run init->start sample->uninit for each sample.

       /* init */
       config.channel = INPUT_CH_A_128;
       config.mode = MODE_CONTINUOUS_MEASUREMENT;
       config.psel_dout = PD_SCK;
       config.psel_pd_sck = PD_SCK;
       config.psel_vdd = VDD;
       
       hx711_init(&config, hx711_callback);
    

    hx711.h:

    #include <stdint.h>
    
    #define MODE_SINGLE_MEASUREMENT       0
    #define MODE_CONTINUOUS_MEASUREMENT    1
    
    typedef enum
    {
        DATA_READY,
        DATA_ERROR
    } hx711_evt_t;
    
    typedef void (*hx711_event_handler_t)(hx711_evt_t evt, int value);
    
    typedef enum
    {
        INPUT_CH_A_128 = 25,
        INPUT_CH_B_32,
        INPUT_CH_A_64
    } hx711_mode_t;
    
    
    typedef struct
    {
        uint32_t psel_pd_sck;
        uint32_t psel_dout;
        uint32_t psel_vdd;
        uint32_t channel;
        uint32_t mode;
    } hx711_config_t;
    
    
    void hx711_init(hx711_config_t * config, hx711_event_handler_t evt_handler);
    
    void hx711_start(void);
    
    void hx711_stop(void);
    
    void hx711_uninit(void);

    hx711.c

    #include "hx711.h"
    #include "app_util_platform.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "nrf_drv_gpiote.h"
    #include <stdint.h>
    #include <string.h>
    
    
    /* 
    *  Timer settings which defines the
    *  frequency of generated clock signal. 
    */
    #define TIMER_COUNTERTOP 32
    #define TIMER_COMPARE 16
    
    #define ADC_RES 24
    
    typedef struct
    {
        uint32_t value; /* raw ADC sample */
        uint8_t count;  /* Count of how many bits have been read */
    } hx711_sample_t;
    
    
    static volatile hx711_sample_t m_sample;
    static hx711_event_handler_t m_evt_handler;
    static hx711_config_t m_config;
    
    
    static int convert_sample(uint32_t sample) { return (int)(sample << 8) >> 8; }
    
    
    /* Collect measurement from ADC when it has signaled that it's ready */
    static void hx711_sample()
    {
        NRF_TIMER2->TASKS_CLEAR = 1;
        m_sample.count = 0;
        m_sample.value = 0;
    
        /* Start clock signal to start clocking out data from the ADC */
        NRF_TIMER1->TASKS_START = 1;
    
        for (uint32_t i = 0; i < ADC_RES; i++)
        {
            do
            {
                /* The NRF_TIMER->CC[1] counter register keeps count of the number 
                   PD_SCK cycles. This is used to detect if we have lost any transitions on DOUT or not.*/
                NRF_TIMER2->TASKS_CAPTURE[1] = 1;
                if (NRF_TIMER2->CC[1] >= ADC_RES)
                    goto EXIT; // lost bit(s) during readout. Likely preempted by another interrut. Discard sample.
            } while (NRF_TIMER1->EVENTS_COMPARE[0] == 0);
            NRF_TIMER1->EVENTS_COMPARE[0] = 0;
            m_sample.value |= (nrf_gpio_pin_read(m_config.psel_dout) << (23 - i));
            m_sample.count++;
        }
    EXIT:
    
        if (m_config.mode == MODE_SINGLE_MEASUREMENT)
        {
            NRF_GPIOTE->TASKS_SET[1] = 1; 
        }
    
        if (m_sample.count == ADC_RES)
        {
            /* Valid sample readout */
            m_evt_handler(DATA_READY, convert_sample(m_sample.value));
        }
        else
        {
            /* Error during readout */
            m_evt_handler(DATA_ERROR, m_sample.value);
        }
    }
    
    
    static void gpiote_evt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        nrf_drv_gpiote_in_event_disable(m_config.psel_dout);
        hx711_sample();
        if (m_config.mode == MODE_CONTINUOUS_MEASUREMENT)
        {
            nrf_drv_gpiote_in_event_enable(m_config.psel_dout, true);
        }
    }
    
    
    static void hx711_power_down(void)
    {
        nrf_gpio_cfg_default(m_config.psel_vdd);
        nrf_gpio_cfg_default(m_config.psel_pd_sck);
        nrf_gpio_cfg_default(m_config.psel_dout);
    }
    
    void hx711_start(void)
    {
        NRF_GPIOTE->TASKS_CLR[1] = 1;
        /* Trigger gpiote_evt_handler() callback when hx711 has signaled "data" ready */
        nrf_drv_gpiote_in_event_enable(m_config.psel_dout, true);
    }
    
    void hx711_stop()
    {
        nrf_drv_gpiote_in_event_disable(m_config.psel_dout);
        NRF_GPIOTE->TASKS_SET[1] = 1;
    }
    
    void hx711_init(hx711_config_t * config, hx711_event_handler_t evt_handler)
    {
    
        ret_code_t ret_code;
    
        nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);
    
        memcpy(&m_config, config, sizeof(m_config));
    
        m_evt_handler = evt_handler;
    
        nrf_gpio_cfg_output(config->psel_pd_sck);
        nrf_gpio_pin_set(config->psel_pd_sck);
    
        nrf_gpio_cfg(config->psel_vdd, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_PULLUP,
            NRF_GPIO_PIN_S0H1, NRF_GPIO_PIN_NOSENSE);
        nrf_gpio_pin_set(config->psel_vdd);
    
        nrf_gpio_cfg_input(config->psel_dout, NRF_GPIO_PIN_NOPULL);
    
        if (!nrf_drv_gpiote_is_init())
        {
            ret_code = nrf_drv_gpiote_init();
            APP_ERROR_CHECK(ret_code);
        }
    
        ret_code = nrf_drv_gpiote_in_init(config->psel_dout, &gpiote_config, gpiote_evt_handler);
        APP_ERROR_CHECK(ret_code);
    
        /* Clock signal generation with TIMER+PPI+GPIOTE */
        NRF_TIMER1->CC[0] = 1;
        NRF_TIMER1->CC[1] = TIMER_COMPARE;
        NRF_TIMER1->CC[2] = TIMER_COUNTERTOP;
        NRF_TIMER1->SHORTS = (uint32_t)(1 << 2);
        NRF_TIMER1->PRESCALER = 0;
    
        NRF_TIMER2->CC[0] = config->channel;
        NRF_TIMER2->MODE = 2;
    
        /* Configure GPIOTE OUT task for PD_SCK*/
        NRF_GPIOTE->CONFIG[1] = (uint32_t)(3 | ((config->psel_pd_sck) << 8) | (1 << 16) | (1 << 20));
    
        /* Connect our timer event to gpiote OUT task via PPI */
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[1];
        NRF_PPI->CH[1].EEP = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[1];
        NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[1];   
        NRF_PPI->FORK[1].TEP =
            (uint32_t)&NRF_TIMER2->TASKS_COUNT; /* Counter incremented on falling edge */
        NRF_PPI->CH[2].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
        NRF_PPI->CH[2].TEP = (uint32_t)&NRF_TIMER1->TASKS_SHUTDOWN;
        NRF_PPI->CHEN = 7;
    }
    
    void hx711_uninit(void)
    {
        nrf_drv_gpiote_in_uninit(m_config.psel_dout);
        hx711_power_down();
    }

  • Hello Vidar,
    this is working good, thanks for your great help.

    Regards

Reply Children
No Data
Related