Example #1
0
static void stmpe811_gpioinit(FAR struct stmpe811_dev_s *priv)
{
  uint8_t regval;

  if ((priv->flags & STMPE811_FLAGS_GPIO_INITIALIZED) == 0)
    {
      /* Enable Clocking for GPIO */

      regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2);
      regval &= ~SYS_CTRL2_GPIO_OFF;
      stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval);

      /* Disable all GPIO interrupts */

      stmpe811_putreg8(priv, STMPE811_GPIO_EN, 0);

      /* Enable global GPIO interrupts */

#ifndef CONFIG_STMPE811_GPIOINT_DISABLE
      regval = stmpe811_getreg8(priv, STMPE811_INT_EN);
      regval |= INT_GPIO;
      stmpe811_putreg8(priv, STMPE811_INT_EN, regval);
#endif

      priv->flags |= STMPE811_FLAGS_GPIO_INITIALIZED;
    }
}
Example #2
0
void stmpe811_gpiowrite(STMPE811_HANDLE handle, uint8_t pinconfig, bool value)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT;
  int ret;

  DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS);

  /* Get exclusive access to the device structure */

  ret = sem_wait(&priv->exclsem);
  if (ret < 0)
    {
      idbg("sem_wait failed: %d\n", errno);
      return;
    }

  /* Are we setting or clearing outputs? */

  if (value)
    {
      /* Set the output valu(s)e by writing to the SET register */

      stmpe811_putreg8(priv, STMPE811_GPIO_SETPIN, (1 << pin));
    }
  else
    {
      /* Clear the output value(s) by writing to the CLR register */

      stmpe811_putreg8(priv, STMPE811_GPIO_CLRPIN, (1 << pin));
    }

  sem_post(&priv->exclsem);
}
Example #3
0
static void stmpe811_worker(FAR void *arg)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg;
  uint8_t regval;

  DEBUGASSERT(priv && priv->config);

  /* Get the global interrupt status */

  regval =  stmpe811_getreg8(priv, STMPE811_INT_STA);

  /* Check for a touchscreen interrupt */

#ifndef CONFIG_STMPE811_TSC_DISABLE
  if ((regval & (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW)) != 0)
    {
      /* Dispatch the touchscreen interrupt if it was brought into the link */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
      if (stmpe811_tscworker)
#endif
        {
           stmpe811_tscworker(priv, regval);
        }

      stmpe811_putreg8(priv, STMPE811_INT_STA, (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW));
      regval &= ~(INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW);
    }
#endif

#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE)
  if ((regval & INT_GPIO) != 0)
    {
      /* Dispatch the GPIO interrupt if it was brought into the link */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
      if (stmpe811_gpioworker)
#endif
        {
          stmpe811_gpioworker(priv);
        }

      stmpe811_putreg8(priv, STMPE811_INT_STA, INT_GPIO);
      regval &= ~INT_GPIO;
    }
#endif

  /* Clear any other residual, unhandled pending interrupt */

  if (regval != 0)
    {
      stmpe811_putreg8(priv, STMPE811_INT_STA, regval);
    }

  /* Re-enable the STMPE811 GPIO interrupt */

  priv->config->enable(priv->config, true);
}
Example #4
0
static void stmpe811_reset(FAR struct stmpe811_dev_s *priv)
{
  /* Power Down the STMPE811 */

  stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, SYS_CTRL1_SOFTRESET);

  /* Wait a bit */

  usleep(20*1000);

  /* Then power on again.  All registers will be in their reset state. */

  stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, 0);
}
Example #5
0
uint16_t stmpe811_tempread(STMPE811_HANDLE handle)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  uint32_t temp = 0;
  uint8_t  temp1;
  uint8_t  temp2;

  /* Acquire data enable */

  stmpe811_putreg8(priv, STMPE811_TEMP_CTRL,
                   (TEMP_CTRL_ACQ | TEMP_CTRL_ENABLE));

  /* Read the temperature */

  temp1 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2);
  temp2 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2+1);

  /* Scale the temperature (where Vio is assumed to be .33) */

  temp = ((uint32_t)(temp1 & 3) << 8) | temp2;
  temp = (uint32_t)((33 * temp * 100) / 751);
  temp = (uint32_t)((temp + 5) / 10);

  return (uint16_t)temp;
}
Example #6
0
int stmpe811_tempinitialize(STMPE811_HANDLE handle)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  uint8_t regval;

  /* Enable clocking for ADC and the temperature sensor */

  regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2);
  regval &= ~(SYS_CTRL2_TS_OFF | SYS_CTRL2_ADC_OFF);
  stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval);

  /* Enable the temperature sensor */

  stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, TEMP_CTRL_ENABLE);

  /* Aquire data enable */

  stmpe811_putreg8(priv, STMPE811_TEMP_CTRL,
                   (TEMP_CTRL_ACQ | TEMP_CTRL_ENABLE));

  return OK;
}
Example #7
0
int stmpe811_gpioattach(STMPE811_HANDLE handle, uint8_t pinconfig,
                       stmpe811_handler_t handler)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT;
  uint8_t regval;
  int ret;

  DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS);

  /* Get exclusive access to the device structure */

  ret = sem_wait(&priv->exclsem);
  if (ret < 0)
    {
      int errval = errno;
      idbg("sem_wait failed: %d\n", errval);
      return -errval;
    }

  /* Make sure that the GPIO interrupt system has been gpioinitialized */

  stmpe811_gpioinit(priv);

  /* Set/clear the handler */

  priv->handlers[pin] = handler;

  /* If an handler has provided, then we are enabling interrupts */

  regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN);
  if (handler)
    {
      /* Enable interrupts for this GPIO */

      regval |= GPIO_PIN(pin);
    }
  else
    {
      /* Disable interrupts for this GPIO */

      regval &= ~GPIO_PIN(pin);
    }

  stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval);

  sem_post(&priv->exclsem);
  return OK;
}
Example #8
0
void stmpe811_gpioworker(FAR struct stmpe811_dev_s *priv)
{
  uint8_t regval;
  uint8_t pinmask;
  int pin;

  /* Get the set of pending GPIO interrupts */

  regval = stmpe811_getreg8(priv, STMPE811_GPIO_INTSTA);

  /* Look at each pin */

  for (pin = 0; pin < STMPE811_GPIO_NPINS; pin++)
    {
      pinmask = GPIO_INT(pin);
      if ((regval & pinmask) != 0)
        {
          /* Check if we have a handler for this interrupt (there should
           * be one)
           */

          if (priv->handlers[pin])
            {
              /* Interrupt is pending... dispatch the interrupt to the
               * callback
               */

              priv->handlers[pin](pin);
            }
          else
            {
              illdbg("No handler for PIN%d, GPIO_INTSTA: %02x\n", pin, regval);
            }

          /* Clear the pending GPIO interrupt by writing a '1' to the
           * pin position in the status register.
           */

          stmpe811_putreg8(priv, STMPE811_GPIO_INTSTA, pinmask);
        }
    }
}
Example #9
0
int stmpe811_gpioconfig(STMPE811_HANDLE handle, uint8_t pinconfig)
{
  FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle;
  int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT;
  uint8_t pinmask = (1 << pin);
  uint8_t regval;
  int ret;

  DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS);

  /* Get exclusive access to the device structure */

  ret = sem_wait(&priv->exclsem);
  if (ret < 0)
    {
      int errval = errno;
      idbg("sem_wait failed: %d\n", errval);
      return -errval;
    }

  /* Make sure that the pin is not already in use */

  if ((priv->inuse & pinmask) != 0)
    {
      idbg("PIN%d is already in-use\n", pin);
      sem_post(&priv->exclsem);
      return -EBUSY;
    }

  /* Make sure that the GPIO block has been initialized */

  stmpe811_gpioinit(priv);

  /* Set the alternate function bit for the pin, making it a GPIO */

  regval  = stmpe811_getreg8(priv, STMPE811_GPIO_AF);
  regval |= pinmask;
  stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval);

  /* Is the pin an input or an output? */

  if ((pinconfig & STMPE811_GPIO_DIR) == STMPE811_GPIO_OUTPUT)
    {
      /* The pin is an output */

      regval  = stmpe811_getreg8(priv, STMPE811_GPIO_DIR);
      regval &= ~pinmask;
      stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval);

      /* Set its initial output value */

      stmpe811_gpiowrite(handle, pinconfig,
                        (pinconfig & STMPE811_GPIO_VALUE) != STMPE811_GPIO_ZERO);
    }
  else
    {
      /* It is an input */

      regval  = stmpe811_getreg8(priv, STMPE811_GPIO_DIR);
      regval |= pinmask;
      stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval);

      /* Set up the falling edge detection */

      regval = stmpe811_getreg8(priv, STMPE811_GPIO_FE);
      if ((pinconfig & STMPE811_GPIO_FALLING) != 0)
        {
          regval |= pinmask;
        }
      else
        {
          regval &= pinmask;
        }
      stmpe811_putreg8(priv, STMPE811_GPIO_FE, regval);

      /* Set up the rising edge detection */

     regval = stmpe811_getreg8(priv, STMPE811_GPIO_RE);
      if ((pinconfig & STMPE811_GPIO_FALLING) != 0)
        {
          regval |= pinmask;
        }
      else
        {
          regval &= pinmask;
        }
      stmpe811_putreg8(priv, STMPE811_GPIO_RE, regval);
 
      /* Disable interrupts for now */

      regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN);
      regval &= ~pinmask;
      stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval);
    }

  /* Mark the pin as 'in use' */

  priv->inuse |= pinmask;
  sem_post(&priv->exclsem);
  return OK;
}
Example #10
0
STMPE811_HANDLE stmpe811_instantiate(FAR struct i2c_dev_s *dev,
                                     FAR struct stmpe811_config_s *config)
#endif
{
  FAR struct stmpe811_dev_s *priv;
  uint8_t regval;
  int ret;

  /* Allocate the device state structure */

#ifdef CONFIG_STMPE811_MULTIPLE
  priv = (FAR struct stmpe811_dev_s *)kmm_zalloc(sizeof(struct stmpe811_dev_s));
  if (!priv)
    {
      return NULL;
    }

  /* And save the device structure in the list of STMPE811 so that we can find it later */

  priv->flink   = g_stmpe811list;
  g_stmpe811list = priv;
#else

  /* Use the one-and-only STMPE811 driver instance */

  priv = &g_stmpe811;
#endif

  /* Initialize the device state structure */

  sem_init(&priv->exclsem, 0, 1);
  priv->config = config;

#ifdef CONFIG_STMPE811_SPI
  priv->spi = dev;
#else
  priv->i2c = dev;

  /* Set the I2C address and frequency.  REVISIT:  This logic would be
   * insufficient if we share the I2C bus with any other devices that also
   * modify the address and frequency.
   */

  I2C_SETADDRESS(dev, config->address, 7);
  I2C_SETFREQUENCY(dev, config->frequency);
#endif

  /* Read and verify the STMPE811 chip ID */

  ret = stmpe811_checkid(priv);
  if (ret < 0)
    {
#ifdef CONFIG_STMPE811_MULTIPLE
      g_stmpe811list = priv->flink;
      kmm_free(priv);
#endif
      return NULL;
    }

  /* Generate STMPE811 Software reset */

  stmpe811_reset(priv);

  /* Configure the interrupt output pin to generate interrupts on high or low level. */

  regval  = stmpe811_getreg8(priv, STMPE811_INT_CTRL);
#ifdef CONFIG_STMPE811_ACTIVELOW
  regval &= ~INT_CTRL_INT_POLARITY; /* Pin polarity: Active low / falling edge */
#else
  regval |= INT_CTRL_INT_POLARITY;  /* Pin polarity: Active high / rising edge */
#endif
#ifdef CONFIG_STMPE811_EDGE
  regval |= INT_CTRL_INT_TYPE;      /* Edge interrupt */
#else
  regval &= ~INT_CTRL_INT_TYPE;     /* Level interrupt */
#endif
  stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval);

  /* Attach the STMPE811 interrupt handler. */

  config->attach(config, stmpe811_interrupt);

  /* Clear any pending interrupts */

  stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL);
  config->clear(config);
  config->enable(config, true);

  /* Enable global interrupts */

  regval  = stmpe811_getreg8(priv, STMPE811_INT_CTRL);
  regval |= INT_CTRL_GLOBAL_INT;
  stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval);

  /* Return our private data structure as an opaque handle */

  return (STMPE811_HANDLE)priv;
}
Example #11
0
void stmpe811_tscworker(FAR struct stmpe811_dev_s *priv, uint8_t intsta)
{
  uint16_t xdiff;    /* X difference used in thresholding */
  uint16_t ydiff;    /* Y difference used in thresholding */
  uint16_t x;        /* X position */
  uint16_t y;        /* Y position */
  bool     pendown;  /* true: pen is down */

  ASSERT(priv != NULL);

  /* Cancel the missing pen up timer */

  (void)wd_cancel(priv->wdog);

  /* Check for pen up or down from the TSC_STA ibit n the STMPE811_TSC_CTRL register. */

  pendown = (stmpe811_getreg8(priv, STMPE811_TSC_CTRL) & TSC_CTRL_TSC_STA) != 0;

  /* Handle the change from pen down to pen up */

  if (!pendown)
    {
      /* The pen is up.. reset thresholding variables.  FIFOs will read zero if
       * there is no data available (hence the choice of (0,0))
       */

      priv->threshx = 0;
      priv->threshy = 0;

      /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up and
       * already reported; CONTACT_UP == pen up, but not reported)
       */

      if (priv->sample.contact == CONTACT_NONE ||
          priv->sample.contact == CONTACT_UP)
        {
          goto ignored;
        }

      /* A pen-down to up transition has been detected.  CONTACT_UP indicates the
       * initial loss of contact.  The state will be changed to CONTACT_NONE
       * after the loss of contact is sampled.
       */

       priv->sample.contact = CONTACT_UP;
    }

  /* The pen is down... check for data in the FIFO */

  else if ((intsta & (INT_FIFO_TH | INT_FIFO_OFLOW)) != 0)
    {
      /* Read the next x and y positions from the FIFO. */

#ifdef CONFIG_STMPE811_SWAPXY
      x = stmpe811_getreg16(priv, STMPE811_TSC_DATAX);
      y = stmpe811_getreg16(priv, STMPE811_TSC_DATAY);
#else
      x = stmpe811_getreg16(priv, STMPE811_TSC_DATAY);
      y = stmpe811_getreg16(priv, STMPE811_TSC_DATAX);
#endif

      /* If we have not yet processed the last pen up event, then we
       * cannot handle this pen down event. We will have to discard it.  That
       * should be okay because there will be another FIFO event right behind
       * this one.  Other kinds of data overruns are not harmful.
       *
       * Hmm.. a better design might be to disable FIFO interrupts when we
       * detect pen up.  Then re-enable them when CONTACT_UP is reported.
       * That would save processing interrupts just to discard the data.
       */

      if (priv->sample.contact == CONTACT_UP)
        {
          /* We have not closed the loop on the last touch ... don't report
           * anything.
           */

          goto ignored;
        }

      /* Perform a thresholding operation so that the results will be more stable.
       * If the difference from the last sample is small, then ignore the event.
       * REVISIT:  Should a large change in pressure also generate a event?
       */

      xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x);
      ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y);

      if (xdiff < CONFIG_STMPE811_THRESHX && ydiff < CONFIG_STMPE811_THRESHY)
        {
          /* Little or no change in either direction ... don't report anything. */

          goto ignored;
        }

      /* When we see a big difference, snap to the new x/y thresholds */

      priv->threshx       = x;
      priv->threshy       = y;

      /* Update the x/y position in the sample data */

      priv->sample.x      = priv->threshx;
      priv->sample.y      = priv->threshy;

      /* Update the Z pressure index */

      priv->sample.z      = stmpe811_getreg8(priv, STMPE811_TSC_DATAZ);
      priv->sample.valid  = true;

      /* If this is the first (acknowledged) pen down report, then report
       * this as the first contact.  If contact == CONTACT_DOWN, it will be
       * set to set to CONTACT_MOVE after the contact is first sampled.
       */

      if (priv->sample.contact != CONTACT_MOVE)
        {
          /* First contact */

          priv->sample.contact = CONTACT_DOWN;
        }
    }

  /* Pen down, but no data in FIFO */

  else
    {
      /* Ignore the interrupt... wait until there is data in the FIFO */

      goto ignored;
    }

  /* We get here if (1) we just went from a pen down to a pen up state OR (2)
   * We just get a measurement from the FIFO in a pen down state.  Indicate
   * the availability of new sample data for this ID.
   */

  priv->sample.id = priv->id;
  priv->penchange = true;

  /* Notify any waiters that new STMPE811 data is available */

  stmpe811_notify(priv);

  /* If we think that the pen is still down, the start/re-start the pen up
   * timer.
   */

ignored:
  if (priv->sample.contact == CONTACT_DOWN ||
      priv->sample.contact == CONTACT_MOVE)
    {
      (void)wd_start(priv->wdog, STMPE811_PENUP_TICKS, stmpe811_timeout,
                     1, (uint32_t)((uintptr_t)priv));
    }

  /*  Reset and clear all data in the FIFO */

  stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET);
  stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0);
}
Example #12
0
static inline void stmpe811_tscinitialize(FAR struct stmpe811_dev_s *priv)
{
  uint8_t regval;

  iinfo("Initializing touchscreen controller\n");

  /* Enable TSC and ADC functions */

  regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2);
  regval &= ~(SYS_CTRL2_TSC_OFF | SYS_CTRL2_ADC_OFF);
  stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval);

  /* Enable the TSC global interrupts */

  regval  = stmpe811_getreg8(priv, STMPE811_INT_EN);
  regval |= (uint32_t)(INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW);
  stmpe811_putreg8(priv, STMPE811_INT_EN, regval);

  /* Select Sample Time, bit number and ADC Reference */

  stmpe811_putreg8(priv, STMPE811_ADC_CTRL1, priv->config->ctrl1);

  /* Wait for 20 ms */

  up_mdelay(20);

  /* Select the ADC clock speed */

  stmpe811_putreg8(priv, STMPE811_ADC_CTRL2, priv->config->ctrl2);

  /* Select TSC pins in non-GPIO mode (AF=0) */

  regval  = stmpe811_getreg8(priv, STMPE811_GPIO_AF);
  regval &= ~(uint8_t)TSC_PIN_SET;
  stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval);

  /* Select 2 nF filter capacitor */

  stmpe811_putreg8(priv, STMPE811_TSC_CFG,
                 (TSC_CFG_AVE_CTRL_4SAMPLES | TSC_CFG_TOUCH_DELAY_500US | TSC_CFG_SETTLING_500US));

  /* Select single point reading */

  stmpe811_putreg8(priv, STMPE811_FIFO_TH, 1);

  /* Reset and clear the FIFO. */

  stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET);
  stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0);

  /* set the data format for Z value: 7 fractional part and 1 whole part */

  stmpe811_putreg8(priv, STMPE811_TSC_FRACTIONZ, 0x01);

  /* Set the driving capability of the device for TSC pins: 50mA */

  stmpe811_putreg8(priv, STMPE811_TSC_IDRIVE, TSC_IDRIVE_50MA);

  /* Enable the TSC.  Use no tracking index, touch-screen controller
   * operation mode (XYZ).
   */

  stmpe811_putreg8(priv, STMPE811_TSC_CTRL, TSC_CTRL_EN);

  /* Clear all the status pending bits */

  stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL);
}