/////////////////////////////////////////////////////////////////////////////
//! Checks for pin changes, and calls given callback function with following parameters:
//! \code
//!   void DIN_NotifyToggle(u32 pin, u32 value)
//! \endcode
//! \param[in] _callback pointer to callback function
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_DIN_Handler(void *_callback)
{
  s32 sr;
  s32 sr_pin;
  u8 changed;
  void (*callback)(u32 pin, u32 value) = _callback;
  u8 num_sr = MIOS32_SRIO_ScanNumGet();

  // no SRIOs?
#if MIOS32_SRIO_NUM_SR == 0
  return -1;
#endif

  if( num_sr == 0 )
    return -1;

  // no callback function?
  if( _callback == NULL )
    return -1;

  // check all shift registers for DIN pin changes
  for(sr=0; sr<num_sr; ++sr) {
    
    // check if there are pin changes (mask all pins)
    changed = MIOS32_DIN_SRChangedGetAndClear(sr, 0xff);

    // any pin change at this SR?
    if( !changed )
      continue;

    // check all 8 pins of the SR
    for(sr_pin=0; sr_pin<8; ++sr_pin)
      if( changed & (1 << sr_pin) ) {
	// call the notification function
	callback(8*sr+sr_pin, (mios32_srio_din[sr] & (1 << sr_pin)) ? 1 : 0);

	// start debouncing (if enabled in SRIO driver)
	MIOS32_SRIO_DebounceStart();
      }
  }

  return 0;
}
示例#2
0
/////////////////////////////////////////////////////////////////////////////
//! Returns encoder configuration
//! \param[in] encoder encoder number (0..MIOS32_ENC_NUM_MAX-1)
//! \return enc_config.cfg.type encoder type (DISABLED/NON_DETENTED/DETENTED1..3)
//! \return enc_config.cfg.speed encoder speed mode (NORMAL/FAST/SLOW)
//! \return enc_config.cfg.speed_par speed parameter (0-7)
//! \return enc_config.cfg.sr shift register (1-16) or application control (0) for the case that encoders are directly connected to GPIO pins<BR>
//! \return enc_config.cfg.pos pin position of first pin (0, 2, 4 or 6)
/////////////////////////////////////////////////////////////////////////////
mios32_enc_config_t MIOS32_ENC_ConfigGet(u32 encoder)
{
  // encoder number valid?
  if( encoder >= MIOS32_ENC_NUM_MAX ) {
    const mios32_enc_config_t dummy = { .cfg.type=DISABLED, .cfg.speed=NORMAL, .cfg.speed_par=0, .cfg.sr=0, .cfg.pos=0 };
    return dummy;
  }

  return enc_config[encoder];
}


/////////////////////////////////////////////////////////////////////////////
//! This function can be called from an application to update the state of
//! an encoder that isn't connected to the SRIO chain (in this case, the
//! appr. enc_config.cfg.sr field has to be set to 0!)
//!
//! Usage examples can be found in following tutorials: 014b_enc_j5_relative
//! and 015b_enc_j5_absolute
//! \param[in] encoder encoder number (0..MIOS32_ENC_NUM_MAX-1)
//! \param[in] new_state two bits with the new encoder pin values
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC_StateSet(u32 encoder, u8 new_state)
{
  // encoder number valid?
  if( encoder >= MIOS32_ENC_NUM_MAX )
    return -1; // invalid number

  // this operation should be atomic
  MIOS32_IRQ_Disable();
  enc_state_t *enc_state_ptr = &enc_state[encoder];
  enc_state_ptr->last12 = enc_state_ptr->act12;
  enc_state_ptr->act12 = new_state;
  MIOS32_IRQ_Enable();

  return 0; // no error
}


/////////////////////////////////////////////////////////////////////////////
//! This function is only intented for debugging purposes - it returns
//! the current state of the given encoder.
//! \param[in] encoder encoder number (0..MIOS32_ENC_NUM_MAX-1)
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC_StateGet(u32 encoder)
{
  // encoder number valid?
  if( encoder >= MIOS32_ENC_NUM_MAX )
    return -1; // invalid number

  // return current state
  return enc_state[encoder].act12;
}


/////////////////////////////////////////////////////////////////////////////
//! This function has to be called after a SRIO scan to update encoder states
//! \return < 0 on errors
/////////////////////////////////////////////////////////////////////////////
s32 MIOS32_ENC_UpdateStates(void)
{
  u8 enc;

  // check all encoders
  // Note: scanning of 64 encoders takes ca. 30 uS @ 72 MHz :-)
  for(enc=0; enc<MIOS32_ENC_NUM_MAX; ++enc) {
    mios32_enc_config_t *enc_config_ptr = &enc_config[enc];

    // skip if encoder not configured
    if( enc_config_ptr->cfg.type == DISABLED )
      continue;

    enc_state_t *enc_state_ptr = &enc_state[enc];

    // decrement accelerator until it is zero (used to determine rotation speed)
    if( enc_state_ptr->accelerator )
      --enc_state_ptr->accelerator;

    // take over encoder state from SRIO handler if SR != 0
    // (if SR configured with 0 we expect that the state is controlled from application, e.g. by scanning GPIOs)
    if( enc_config_ptr->cfg.sr != 0 ) {
      // check if encoder state has been changed, and clear changed flags, so that the changes won't be propagated to DIN handler
      u8 sr = enc_config_ptr->cfg.sr-1;
      u8 pos = enc_config_ptr->cfg.pos;
      u8 changed_mask = 3 << pos; // note: by checking mios32_srio_din_changed[sr] directly, we speed up the scanning of unmoved encoders by factor 3!
      enc_state_ptr->last12 = enc_state_ptr->act12;
      if( (mios32_srio_din_changed[sr] & changed_mask) && MIOS32_DIN_SRChangedGetAndClear(sr, changed_mask) )
	enc_state_ptr->act12 = (MIOS32_DIN_SRGet(sr) >> pos) & 3;
    }

    // new encoder state?
    if( enc_state_ptr->last12 != enc_state_ptr->act12 ) {
      mios32_enc_type_t enc_type = enc_config_ptr->cfg.type;
      s32 predivider;
      s32 acc;

      // State Machine (own Design from 1999)
      // changed 2000-1-5: special "analyse" state which corrects the ENC direction
      // if encoder is rotated to fast - I should patent it ;-)
      // changed 2009-09-14: new ENC_MODE-format, using Bits of ENC_MODE_xx to
      // indicate edges, which trigger Do_Inc / Do_Dec

      // if Bit N of ENC_MODE is set, according ENC_STAT triggers Do_Inc / Do_Dec
      //
      // Bit N     7   6   5   4  
      // ENC_STAT  8   E   7   1
      // DEC      <-  <-  <-  <-  
      // Pin A ____|-------|_______
      // Pin B ________|-------|___
      // INC       ->  ->  ->  ->  
      // ENC_STAT  2   B   D   4
      // Bit N     0   1   2   3 
      // This method is based on ideas from Avogra

      if( (enc_state_ptr->state == 0x01 && (enc_type & (1 << 4))) ||
	  (enc_state_ptr->state == 0x07 && (enc_type & (1 << 5))) ||
	  (enc_state_ptr->state == 0x0e && (enc_type & (1 << 6))) ||
	  (enc_state_ptr->state == 0x08 && (enc_type & (1 << 7))) ) {
	// DEC
	// plausibility check: when accelerator > 0xe0, exit if last event was a INC.
	// if non-detented encoder: only do anything if the state has actually changed
	if( (enc_state_ptr->decinc || enc_state_ptr->accelerator <= 0xe0) && 
	    (enc_type != 0xff || enc_state_ptr->state != enc_state_ptr->prev_state_dec) ) {
	  // memorize DEC
	  enc_state_ptr->decinc = 1;

	  // limit maximum increase of accelerator
	  if( (int)enc_state_ptr->accelerator - (int)enc_state_ptr->prev_acc > 20) {
	    enc_state_ptr->accelerator = enc_state_ptr->prev_acc + 20;
	  }

	  // branch depending on speed mode
	  switch( enc_config_ptr->cfg.speed ) {
	  case FAST:
	    if( (acc=(enc_state_ptr->accelerator >> (7-enc_config_ptr->cfg.speed_par))) == 0 )
	      acc = 1;
	    enc_state_ptr->incrementer -= acc;
	    break;

	  case SLOW:
	    predivider = enc_state_ptr->predivider - (enc_config_ptr->cfg.speed_par+1);
	    // increment on 4bit underrun
	    if( predivider < 0 )
	      --enc_state_ptr->incrementer;
	    enc_state_ptr->predivider = predivider;
	    break;

	  default: // NORMAL
	    --enc_state_ptr->incrementer;
	    break;
	  }
	  // save last acceleration value
	  enc_state_ptr->prev_acc = enc_state_ptr->accelerator;

	  // set accelerator to max value (will be decremented on each tick, so that the encoder speed can be determined)
	  enc_state_ptr->accelerator = 0xff;

	  // save last state to compare whether the state changed in the next run
	  enc_state_ptr->prev_state_dec = enc_state_ptr->state;
	}
      } else if( (enc_state_ptr->state == 0x02 && (enc_type & (1 << 0))) ||