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