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

HX711 with ANT bpwr profile

Hi,

I am working with ANT bpwr tx profile and trying to implement HX711 and TWI sensor to it. TWI sensor is already working, but when I add library for HX711 from  and start sampling HX711, the ant transmission looks like it stops transmitting, or lose all packets. I can see it in AntWare II, that when hx711_start(false) function is called, AntWare can not see any transmitting device and i can see data from hx711 printing in debug terminal, but when I comment this function and let it how it was before, AntWare II can see the device and is able to receive data, so i know, that there is some conflict between hx711 data sampling and ant+ data transmission, but the project compiles succesfull. Do somebody know, what might be the problem?

using nRF52832, SDK15.2, Segger embedded studio, and library written by Vidar 

thanks in advance

/******************************************************************************/
/*                                                                            */
/******************************************************************************/

#include <stdint.h>
#include <string.h>
#include "hx711.h"
#include "nrf_drv_gpiote.h"
#include "app_util_platform.h"
#include "boards.h"
#include "nrf_delay.h"

#define NRF_LOG_MODULE_NAME hx711

#if HX711_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL           HX711_CONFIG_LOG_LEVEL
    #define NRF_LOG_INFO_COLOR      HX711_CONFIG_INFO_COLOR
    #define NRF_LOG_DEBUG_COLOR     HX711_CONFIG_DEBUG_COLOR
#else // HX711_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL           0
#endif  // HX711_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();

/* Defines frequency and duty cycle for clock signal - default: 1 MHz 50%*/  
#define TIMER_COUNTERTOP          32
#define TIMER_COMPARE             16

// Pinout
#define PD_SCK                    23    
#define DOUT                      24    
#define VDD                       25  // Note: Depending on design, GPIO may not be able to source enough current for hx711 and loadcell.    

/* HX711 ADC resolution in bits */
#define ADC_RES                   24

typedef  struct
{
   uint32_t   value;   // buffer for ADC read
   uint8_t    count;   // number of bitshifts. Read complete when count == ADC_RES 
}hx711_sample_t;

static volatile hx711_sample_t                    m_sample;
static hx711_event_handler_t                      m_evt_handler;
static uint32_t                                   m_mode;
static bool                                       m_continous_sampling;


static int convert_sample(uint32_t sample)
{
  return (int)(sample << 8) >> 8;
}


/* Clocks out HX711 result - if readout fails consistently, try to increase the clock period and/or enable compiler optimization */
static void hx711_sample()
{
    NRF_TIMER2->TASKS_CLEAR = 1;
    m_sample.count = 0;
    m_sample.value = 0;
    NRF_TIMER1->TASKS_START = 1; // Starts clock signal on PD_SCK

    for (uint32_t i=0; i < ADC_RES; i++)
    {
        do
        {
            /* NRF_TIMER->CC[1] contains number of clock cycles.*/
            NRF_TIMER2->TASKS_CAPTURE[1] = 1;
            if (NRF_TIMER2->CC[1] >= ADC_RES) goto EXIT; // Readout not in sync with PD_CLK. Abort and notify error.
        }
        while(NRF_TIMER1->EVENTS_COMPARE[0] == 0);
        NRF_TIMER1->EVENTS_COMPARE[0] = 0;
        m_sample.value |= (nrf_gpio_pin_read(DOUT) << (23 - i));
        m_sample.count++;
    }
    EXIT:

    if (!m_continous_sampling)
    {
        NRF_GPIOTE->TASKS_SET[1] = 1; // HX711 power-down
    }

    NRF_LOG_INFO("Number of bits : %d", m_sample.count);
    NRF_LOG_INFO("ADC val: 0x%x", m_sample.value);

    if (m_sample.count == ADC_RES)
    {
        // Send notification with raw ADC value
        m_evt_handler(DATA_READY, convert_sample(m_sample.value));
    }
    else
    {
       // Notify readout error
       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(DOUT);
    hx711_sample();
    
    if (m_continous_sampling)
    {
       nrf_drv_gpiote_in_event_enable(DOUT, true); 
    }   
}


void hx711_init(hx711_mode_t mode, 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);

  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);
  }

  ret_code = nrf_drv_gpiote_in_init(DOUT, &gpiote_config, gpiote_evt_handler);
  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;
}


void hx711_power_down()
{
   nrf_gpio_cfg_default(VDD);
   nrf_gpio_cfg_default(PD_SCK);
   nrf_gpio_cfg_default(DOUT);
}

void hx711_start(bool single)
{
    
    m_continous_sampling = !single;

    NRF_LOG_INFO("Start sampling");
    
    NRF_GPIOTE->TASKS_CLR[1] = 1;
    // Generates interrupt when new sampling is available. 
    nrf_drv_gpiote_in_event_enable(DOUT, true);
}

void hx711_stop()
{
    nrf_drv_gpiote_in_event_disable(DOUT);
    NRF_GPIOTE->TASKS_SET[1] = 1; // Must be kept high for >60 us to power down HX711 
}

Parents
  • Hi,

    Are you testing this on a Nordic DK? I'm wondering if maybe the continuous sampling interferes with the radio. Please try and see if it works if you only call hx711_start(true) once. 

    Thanks,

    Vidar

  • Hi,

    Solved it by moving hx711_init() and hx711_start() to the beginning of main function before code lines that handles start of softdevice and profile initiation.

    And yes, i am testing it on nRF52832 DK and when i wrote hx711_start(true) it didn`t work too. But now, when it is placed before softdevice and profile initiation it works. 

    I have one last question. Please, could you provide me some link, where i can find and learn more about these lines of code about timer and its compare registers that you used in your library?

    Thanks for answer,

    Pepam

    static void hx711_sample()
    {
        NRF_TIMER2->TASKS_CLEAR = 1;
        m_sample.count = 0;
        m_sample.value = 0;
        NRF_TIMER1->TASKS_START = 1; // Starts clock signal on PD_SCK
    
        for (uint32_t i=0; i < ADC_RES; i++)
        {
            do
            {
                /* NRF_TIMER->CC[1] contains number of clock cycles.*/
                NRF_TIMER2->TASKS_CAPTURE[1] = 1;
                if (NRF_TIMER2->CC[1] >= ADC_RES) goto EXIT; // Readout not in sync with PD_CLK. Abort and notify error.
            }
            while(NRF_TIMER1->EVENTS_COMPARE[0] == 0);
            NRF_TIMER1->EVENTS_COMPARE[0] = 0;
            m_sample.value |= (nrf_gpio_pin_read(DOUT) << (23 - i));
            m_sample.count++;
        }
        EXIT:
    
        if (!m_continous_sampling)
        {
            NRF_GPIOTE->TASKS_SET[1] = 1; // HX711 power-down
        }
        
        
        /*and also this part of Your code==========================================*/
          
          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;
    }
        

Reply
  • Hi,

    Solved it by moving hx711_init() and hx711_start() to the beginning of main function before code lines that handles start of softdevice and profile initiation.

    And yes, i am testing it on nRF52832 DK and when i wrote hx711_start(true) it didn`t work too. But now, when it is placed before softdevice and profile initiation it works. 

    I have one last question. Please, could you provide me some link, where i can find and learn more about these lines of code about timer and its compare registers that you used in your library?

    Thanks for answer,

    Pepam

    static void hx711_sample()
    {
        NRF_TIMER2->TASKS_CLEAR = 1;
        m_sample.count = 0;
        m_sample.value = 0;
        NRF_TIMER1->TASKS_START = 1; // Starts clock signal on PD_SCK
    
        for (uint32_t i=0; i < ADC_RES; i++)
        {
            do
            {
                /* NRF_TIMER->CC[1] contains number of clock cycles.*/
                NRF_TIMER2->TASKS_CAPTURE[1] = 1;
                if (NRF_TIMER2->CC[1] >= ADC_RES) goto EXIT; // Readout not in sync with PD_CLK. Abort and notify error.
            }
            while(NRF_TIMER1->EVENTS_COMPARE[0] == 0);
            NRF_TIMER1->EVENTS_COMPARE[0] = 0;
            m_sample.value |= (nrf_gpio_pin_read(DOUT) << (23 - i));
            m_sample.count++;
        }
        EXIT:
    
        if (!m_continous_sampling)
        {
            NRF_GPIOTE->TASKS_SET[1] = 1; // HX711 power-down
        }
        
        
        /*and also this part of Your code==========================================*/
          
          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;
    }
        

Children
Related