It is rather hard to think of such a system without carving out a shaft position/velocity estimator as a separate concept whose properties you can adjust independently of the other components.
The estimator would update the position/velocity estimate each time you update the control loop. The inputs to the estimator are passage of time (e.g. control loop ticks) and the Hall input changes. Expressed in C++, the estimator's API would look as follows:
class ShaftEstimator { ... float m_angle = 0., m_speed = 0.; /// Initializes the estimator with null angle and speed ShaftEstimator(); /// Called every loop tick. Updates the angle and speed. void update(bool hall_a, bool hall_b, bool hall_c); /// Shaft position in radians. float angle() const { return m_angle; } /// Shaft speed in radians per tick. float speed() const { return m_speed; } };
The estimator doesn't need access to any hardware: the API above is all you need to interface it with the rest of the system. Since update() is called periodically at a fixed rate, the estimator can keep track of how many ticks it took the shaft to rotate between Hall state changes. You could apply filtering commensurate with the ratio of the inertia in the system vs. expected disturbing torque (whether generated by the motor or applied externally), you could also make a more complex estimator that uses the torque generated by the motor to estimate the effective inertia of the motor system and applied external load torque. None of it is particularly complicated; here you have a starting point that clarifies how the interface of the estimator should look.
If you want a starting point AVR32732 app note has a link to source code that includes a crude implementation of such an estimator, although it unnecessarily uses interrupts to read the Hall inputs - you don't need it, nor does it give any benefits to do so.