Incremental Encoder

The incremental encoder IP-Core (IncreEncoder_V24) evaluates signals of an incremental encoder and is compatible to Digital Encoder 1v00. It features multiple possibilities to calculate the rotor position and the rotational speed of the encoder.

Position

Calculates the rotational position of the encoder based on counting rising and falling edges on the A and B-lane of the encoder. Resets to zero based on the I-lane (once per mechanical revolution).

Position (electrical)

Calculates the rotational position of the encoder and transforms the position to the electrical position of electric drive (e.g., permanent magnet synchronous machines). Uses the number of pole pairs to divide one mechanical turn of the encoder to (multiple) turns of the electrical system. Can only be used if the number of increments is an integer multiple of the number of pole pairs! The value of drive_pole_pair in the driver configuration has to be an integer multiple of the increments per turn or set to zero. If drive_pole_pair is an integer multiple of increments per turn, the electrical angle can be used and read by calling uz_incrementalEncoder_get_theta_el. If drive_pole_pair is set to 0, the function can not be called (assertion fires if it is called). If drive_pole_pair is not 0 and not an integer multiple of increments per turn, the initialization of the driver fails with an assertion. Note that the FPGA output port of the IP-Core outputs the (potentially false!) electrical position regardless of this setting!

Rotational speed

Calculates the rotational speed of the drive by counting the time between two consecutive rising edges of the A-lane in combination with an speed-dependent oversampling mechanism and subsequent filtering of the speed signal in the IP-Core. The oversampling mechanism allows to skip edges to improve the measurement at higher speeds.

Direction of rotation

Determines the direction of the rotation (clockwise / counterclockwise)

Configuration

Note

The IP-Core has a bug that results in an error of factor 2 on the speed calculation if Timer_FPGA_ms is supplied with the same value as done in Simulink. The bug is handled in the software driver by just writing Timer_FPGA_ms*2 to the IP-Core register, no user action is required. That is, the correct speed is read-out by the driver.

Hardware filter of rotational speed

Subsystem omega_by_measure_time outputs \(\omega_{raw}\), new_measurement and oversampling factor \(k_{Oversample}\). The following calculation is done:

\[\omega_{scaled}=\frac{1}{\omega_{raw}} \cdot k_{Oversample}\]

This is fed to the Average_linear_Reg with the constants \(S_{factor}=6\) and \(S_{invFactor} = \frac{1}{6}\) (not used at all). Whenever new_measurement is true, the current value of \(\omega_{scaled}\) is added to an internal storage that sums up the rotational speed. After six (\(S_{factor}=6\)) measurements the internal storage is reset to zero, restarting the averaging. The value of the internal storage is divided by the number of samples that are currently in the internal storage and output.

IP-Core Hardware

The IP-Core is generated using Matlab/Simulink HDL-Coder based on the model Encoder_Zynq_V24.slx (in ultrazohm_sw/ip-cores/IncreEncoder_V24_ip/Simulation/Encoder_Zynq_V24.slx).

Vivado integration

../../../_images/increEncoder_vivado.png

Fig. 118 Vivado block design of incremental encoder IP-Core.

Warning

The IP-Core (IPCORE_CLK) has to be sourced by a clock with \(50 MHz\)! For higher frequencies the timing does not close (negative slack time), for lower frequencies the accuracy of the encoder result is not tested.

Configuration registers (AXI)

The following configuration registers are available for the IP-Core. The software driver writes to the registers based on the configuration that is provided to the initialization function.

PI2_Inc_AXI

Scales the output theta_el to \(0..2\pi\). Is calculated in the processor and written to the IP-Core. Calculation: \(\frac{2 \cdot \pi}{IncPerTurn \cdot QudratureFactor} \cdot PolePair\) with PolePair being the pole pairs of the drive.

Timer_FPGA_ms

Scales the timer, that is used to calculate the rotational speed, from FPGA clock ticks to seconds w.r.t. the number of increments and \(2\pi\). Default is \(\frac{f_{IP-Core}}{IncPerTurn} \cdot \frac{1}{2\pi}=1.5915e-05\) with \(f_{IP-Core}=50 MHz\) and \(IncPerTurn=5000\).

IncPerTurn_mech

Configures the number of lines per mechanical revolution.

IncPerTurn_elec

Configures the number of lines per electrical revolution, i.e., w.r.t. to the pole pairs of a electrical machine. Set to IncPerTurn_mech divided by pole pairs of the electrical machine.

OverSamplingFactor

Calculation of the rotational speed omega is based on measuring the time between rising edges of the A-lane. If OverSampleFactor=1, every rising edge is used. For OverSampleFactor=n, every n-th rising ege is used. Based on the setting, the IP-Core adapts the OverSampleFactor over the operating range of the drive. The OverSamplingFactor is set by OmegaPerOverSampl_AXI4 in rad/s. Default value is \(500 \frac{1}{min} \cdot \frac{2\pi}{60 s}=52.3599 s^{-1}\).

PeriodEnd

Used to reset the counter that is used to calculate the rotational speed, which is output at countPerPeriod_AXI. Not recommended, use calculation based on time measurement based on counting edges of the A-lane instead (omega_AXI).

Table Interfaces of the incremental encoder IP-Core lists all input and output ports (AXI and external port) that are present in the IP-Core.

Table 27 Interfaces of the incremental encoder IP-Core

Port Name

Port Type

Data Type

Target Platform Interfaces

Function

A

Input

bool

External Signal

Lane A of encoder

B

Input

bool

External Signal

Lane B of encoder

I

Input

bool

External Signal

Lane I of encoder (zero)

PeriodEnd

Input

bool

External Signal

Resets subsystem that calculates countPerPeriod_AXI4

Theta_el

Output

sfix24_En20

External Signal

Theta electric based on the subsystem Counter_theta_ele

omega

Output

sfix24_En11

External Signal

Rotational speed based on time measurement between rising edge of A-lane (subsystem omega_by_measure_time)

position

Output

uint16_t

External Signal

Outputs the position of the encoder with a range of 0 to increments

count

Output

bool

External Signal

1 if edge counter is triggered - 0 otherwise

edge

Output

bool

External Signal

1 if an edge is detected - 0 otherwise

OverSamplFactor

Output

uint16

External Signal

Reads back the over sample factor of the speed calculation

Reset

Input

bool

AXI

Resets the IP-Core

Enable

Input

bool

AXI

Enables the IP-Core

Timestamp

Output

uint32_t

AXI

Returns unique IP timestamp

omega_AXI4

Output

sfix24_En11

AXI

same signal as omega

theta_el_AXI4

Output

sfix24_en20

AXI

same signal as Theta_el

position_AXI4

Output

uint16_t

AXI

Outputs the position of the encoder with a range of 0 to increments

direction_AXI4

Output

sfix4

AXI

1 if rotation is clockwise - 0 otherwise

counterPerPeriod_AXI4

Output

int16

AXI

Result of omega_by_count_lines subsystem

PI2_Inc_AXI

Input

ufix24_En24

AXI

Scales the output of theta_el to 0 to \(2\pi\)

Timer_FPGA_ms_AXI4

Input

ufix32_En32

AXI

Scales clock ticks to rad/s

IncPerTurn_mech_AXI4

Input

uint16_t

AXI

Number of increments of the encoder of one mechanical turn

IncPerTurn_elek_AXI4

Input

uint16_t

AXI

Number of increments of the encoder divided by pole pairs for electrical angle

OmegaPerOverSampl_AXI4

Input

sfix24_En11

AXI

Oversampling factor for speed measurement - provided as multiple

Software driver

The software driver for the IP-Core handles the configuration of the aforementioned registers.

Listing 159 Initialization of an encoder
struct uz_incrementalEncoder_config testconfig={
  .base_address=BASE_ADDRESS,
  .ip_core_frequency_Hz=50000000U,
  .line_number_per_turn_mech=5000U,
  .OmegaPerOverSample_in_rpm=500.0f,
  .drive_pole_pair=4U
};
uz_incrementalEncoder_t* test_instance=uz_incrementalEncoder_init(testconfig);
Listing 160 Read position and speed
float omega=uz_incrementalEncoder_get_omega_mech(test_instance);
float theta_el=uz_incrementalEncoder_get_theta_el(test_instance);
uint32_t position=uz_incrementalEncoder_get_position(test_instance);

Driver reference

typedef struct uz_incrementalEncoder_t uz_incrementalEncoder_t

Object data type definition of the incremental encoder IP-Core driver.

struct uz_incrementalEncoder_config

Configuration struct for the encoder driver.

Public Members

uint32_t base_address

Base address of IP-Core instance

uint32_t ip_core_frequency_Hz

Clock frequency of IP-Core

uint32_t line_number_per_turn_mech

Number of lines eper one mechanical turn of the attached encoder

float OmegaPerOverSample_in_rpm

Rotational speed omega in 1/min after which the OverSamplingFactor is increased by one

uint32_t drive_pole_pair

Number of pole pairs of the electric drive that is attached to the encoder. Set to zero if no drive is attached or increments per mechanical turn is not an integer multiple of pole pairs

uz_incrementalEncoder_t *uz_incrementalEncoder_init(struct uz_incrementalEncoder_config config)

Initialization of one instance of the driver for the incremental encoder IP-Core.

Parameters
  • config

Returns

uz_incrementalEncoder_t*

float uz_incrementalEncoder_get_omega_mech(uz_incrementalEncoder_t *self)

Returns the measured omega based on counting edges of the A-lane in 1/s.

Parameters
  • self

Returns

float

float uz_incrementalEncoder_get_theta_el(uz_incrementalEncoder_t *self)

Returns the measured electrical angle in 0..2pi range if drive_pole_pair is not zero in the config.

Parameters
  • self

Returns

float

uint32_t uz_incrementalEncoder_get_position(uz_incrementalEncoder_t *self)

Returns the measured mechanical angle in 0..increments.

Parameters
  • self

Returns

uint32_t