]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blobdiff - sw/app/rocon/appl_pxmc.c
RoCoN: correct computation of channel location for case with multiple LXPWR slaves.
[fpga/lx-cpu1/lx-rocon.git] / sw / app / rocon / appl_pxmc.c
index 777b4657aa0f1ad6bdb826f429838f386a1d08de..7d35393b20da1a78f1490ae8d2feccb578528b63 100644 (file)
 #include <hal_gpio.h>
 #include <hal_machperiph.h>
 #include <stdlib.h>
+#include <string.h>
+#include <LPC17xx.h>
+#include <lpcTIM.h>
 
 #include "appl_defs.h"
 #include "appl_fpga.h"
 
+int pxmc_ptofs_from_index(pxmc_state_t *mcs, unsigned long irc,
+                           unsigned long index_irc, int diff2err);
+
+#ifndef pxmc_fast_tick_time
+#define pxmc_fast_tick_time() (LPC_TIM0->TC)
+#endif
+
 #define PXML_MAIN_CNT 8
 
 #define PXMC_WITH_PT_ZIC 1
 #define HAL_ERR_SENSITIVITY 20
 #define HAL_ERR_MAX_COUNT    5
 
+#define LXPWR_WITH_SIROLADC  1
+
+#define LX_MASTER_DATA_OFFS  8
+
 unsigned pxmc_rocon_pwm_magnitude = 2500;
 
 long pxmc_rocon_irc_offset[PXML_MAIN_CNT];
@@ -111,7 +125,8 @@ pxmc_inp_rocon_is_mark(pxmc_state_t *mcs)
 
   irc_state = *fpga_irc_state[chan];
 
-  mark = (irc_state ^ (mcs->pxms_cfg >> PXMS_CFG_HPS_b)) & 1;
+  mark = ((irc_state >> (ffs(FPGA_IRC_STATE_MARK_MASK) - 1)) ^
+         (mcs->pxms_cfg >> PXMS_CFG_HPS_b)) & 1;
 
   filt = pxmc_rocon_mark_filt[chan];
   filt = (filt << 1) | mark;
@@ -128,9 +143,9 @@ pxmc_inp_rocon_is_index_edge(pxmc_state_t *mcs)
   int chan=mcs->pxms_inp_info;
 
   irc_state = *fpga_irc_state[chan];
-  *fpga_irc_state[chan] = 1 << 2;
+  *fpga_irc_state[chan] = FPGA_IRC_STATE_INDEX_EVENT_MASK;
 
-  index = (irc_state >> 2) & 1;
+  index = (irc_state >> (ffs(FPGA_IRC_STATE_INDEX_EVENT_MASK) - 1)) & 1;
 
   return index;
 }
@@ -140,6 +155,8 @@ pxmc_inp_rocon_adjust_to_irc_change(struct pxmc_state *mcs, long irc_diff)
 {
   long pos_diff = irc_diff << PXMC_SUBDIV(mcs);
 
+  mcs->pxms_ptofs += irc_diff;
+
   mcs->pxms_ap += pos_diff;
   mcs->pxms_rp += pos_diff;
   return 0;
@@ -180,16 +197,75 @@ pxmc_inp_rocon_ap2hw(struct pxmc_state *mcs)
 
   irc = fpga_irc[chan]->count;
   pos_diff = mcs->pxms_ap - (irc << PXMC_SUBDIV(mcs));
-  pxmc_rocon_irc_offset[chan] = pos_diff >> PXMC_SUBDIV(mcs);
+
+  irc = pos_diff >> PXMC_SUBDIV(mcs);
+
+  /* Adjust phase table alignemt to modified IRC readout  */
+  mcs->pxms_ptofs += irc - pxmc_rocon_irc_offset[chan];
+
+  pxmc_rocon_irc_offset[chan] = irc;
   return 0;
 }
 
+int
+pxmc_inp_rocon_ptofs_from_index_poll(struct pxmc_state *mcs, int diff2err)
+{
+  int chan=mcs->pxms_inp_info;
+  long irc;
+  long index_irc;
+
+  if (!(*fpga_irc_state[chan] & FPGA_IRC_STATE_INDEX_EVENT_MASK))
+    return 0;
+
+  irc = fpga_irc[chan]->count + pxmc_rocon_irc_offset[chan];
+  index_irc = fpga_irc[chan]->count_index + pxmc_rocon_irc_offset[chan];
+
+  return pxmc_ptofs_from_index(mcs, irc, index_irc, diff2err);
+}
+
+uint32_t pxmc_rocon_receiver_dummy_reg;
+
+static inline volatile uint32_t *
+pxmc_rocon_receiver_chan2reg(unsigned chan)
+{
+  volatile uint32_t *rec_reg;
+
+  if (chan >= 16)
+    return &pxmc_rocon_receiver_dummy_reg;
+
+  rec_reg = fpga_lx_master_receiver_base;
+
+ #ifdef LXPWR_WITH_SIROLADC
+  rec_reg += LX_MASTER_DATA_OFFS + 1 + (chan >> 3) * 3 + chan * 2;
+ #else /*LXPWR_WITH_SIROLADC*/
+  rec_reg += LX_MASTER_DATA_OFFS + chan;
+ #endif /*LXPWR_WITH_SIROLADC*/
+
+  return rec_reg;
+}
+
 inline unsigned
-pxmc_rocon_bdc_hal_rd(pxmc_state_t *mcs)
+pxmc_rocon_bldc_hal_rd(pxmc_state_t *mcs)
 {
   unsigned h = 0;
-  /* FIXME */
-  h = 1;
+  volatile uint32_t *rec_reg_a, *rec_reg_b, *rec_reg_c;
+  int chan = mcs->pxms_out_info;
+  int hal_offs;
+
+ #ifdef LXPWR_WITH_SIROLADC
+  hal_offs = 1;
+ #else /*LXPWR_WITH_SIROLADC*/
+  hal_offs = 0;
+ #endif /*LXPWR_WITH_SIROLADC*/
+
+  rec_reg_a = pxmc_rocon_receiver_chan2reg(chan + 0);
+  rec_reg_b = pxmc_rocon_receiver_chan2reg(chan + 1);
+  rec_reg_c = pxmc_rocon_receiver_chan2reg(chan + 2);
+
+  h  = (rec_reg_a[hal_offs] >> 14) & 1;
+  h |= (rec_reg_b[hal_offs] >> 13) & 2;
+  h |= (rec_reg_c[hal_offs] >> 12) & 4;
+
   /* return 3 bits corresponding to the HAL senzor input */
   return h;
 }
@@ -231,7 +307,13 @@ pxmc_rocon_pwm_chan2reg(unsigned chan)
     return &pxmc_rocon_pwm_dummy_reg;
 
   pwm_reg = fpga_lx_master_transmitter_base;
-  pwm_reg += chan + 8;
+
+ #ifdef LXPWR_WITH_SIROLADC
+  pwm_reg += LX_MASTER_DATA_OFFS + 1 + (chan >> 3) + chan;
+ #else /*LXPWR_WITH_SIROLADC*/
+  pwm_reg += LX_MASTER_DATA_OFFS + chan;
+ #endif /*LXPWR_WITH_SIROLADC*/
+
   return pwm_reg;
 }
 
@@ -245,9 +327,9 @@ pxmc_rocon_pwm3ph_wr(pxmc_state_t *mcs, short pwm1, short pwm2, short pwm3)
   volatile uint32_t *pwm_reg_a, *pwm_reg_b, *pwm_reg_c;
   int chan = mcs->pxms_out_info;
 
-  pwm_reg_a = pxmc_rocon_pwm_chan2reg(chan + 0);
+  pwm_reg_c = pxmc_rocon_pwm_chan2reg(chan + 0);
   pwm_reg_b = pxmc_rocon_pwm_chan2reg(chan + 1);
-  pwm_reg_c = pxmc_rocon_pwm_chan2reg(chan + 2);
+  pwm_reg_a = pxmc_rocon_pwm_chan2reg(chan + 2);
 
   *pwm_reg_a = pwm1;
   *pwm_reg_b = pwm2;
@@ -274,6 +356,8 @@ pxmc_rocon_process_hal_error(struct pxmc_state *mcs)
 int
 pxmc_rocon_pwm3ph_out(pxmc_state_t *mcs)
 {
+  typeof(mcs->pxms_ptvang) ptvang;
+  int sync_mode = 0;
   unsigned char hal_pos;
   short pwm1;
   short pwm2;
@@ -289,7 +373,23 @@ pxmc_rocon_pwm3ph_out(pxmc_state_t *mcs)
     short ptirc = mcs->pxms_ptirc;
     short divisor = mcs->pxms_ptper * 6;
 
-    hal_pos = pxmc_lpc_bdc_hal_pos_table[pxmc_rocon_bdc_hal_rd(mcs)];
+   #if 0
+    pxmc_irc_16bit_commindx(mcs, mcs->pxms_rp >> PXMC_SUBDIV(mcs));
+    sync_mode = 1;
+   #elif 0
+    {
+      int res;
+      res = pxmc_inp_rocon_ptofs_from_index_poll(mcs, 0);
+      if (res < 0) {
+        pxmc_set_errno(mcs, PXMS_E_I2PT_TOOBIG);
+      } else if (res) {
+        pxmc_set_flag(mcs, PXMS_PTI_b);
+        pxmc_set_flag(mcs, PXMS_PHA_b);
+      }
+    }
+   #else
+
+    hal_pos = pxmc_lpc_bdc_hal_pos_table[pxmc_rocon_bldc_hal_rd(mcs)];
 
     if (hal_pos == 0xff)
     {
@@ -328,21 +428,28 @@ pxmc_rocon_pwm3ph_out(pxmc_state_t *mcs)
 
           pxmc_set_flag(mcs, PXMS_PTI_b);
           pxmc_clear_flag(mcs, PXMS_PRA_b);
-
-          /* if phase table position to mask is know do fine phase table alignment */
-          if (mcs->pxms_cfg & PXMS_CFG_I2PT_m)
-            lpc_qei_setup_index_catch(&lpc_qei_state);
-
         }
         else
         {
           if (!(mcs->pxms_flg & PXMS_PTI_m))
             mcs->pxms_ptindx = ptindx;
         }
+      } else {
+        /* if phase table position to mask is know do fine phase table alignment */
+        if (mcs->pxms_cfg & PXMS_CFG_I2PT_m) {
+          int res;
+          res = pxmc_inp_rocon_ptofs_from_index_poll(mcs, 0);
+          if (res < 0) {
+            pxmc_set_errno(mcs, PXMS_E_I2PT_TOOBIG);
+          } else if (res) {
+            pxmc_set_flag(mcs, PXMS_PTI_b);
+            pxmc_set_flag(mcs, PXMS_PHA_b);
+          }
+        }
       }
-
       mcs->pxms_hal = hal_pos;
     }
+   #endif
   }
 
   {
@@ -351,10 +458,15 @@ pxmc_rocon_pwm3ph_out(pxmc_state_t *mcs)
     /* pxmc_set_errno(mcs, PXMS_E_WINDCURRENT); */
   }
 
-  ene = mcs->pxms_ene;
+  if (!sync_mode) {
+    ptvang = mcs->pxms_ptvang;
+    ene = mcs->pxms_ene;
+  } else {
+    ptvang = 0;
+    ene = mcs->pxms_flg & PXMS_BSY_m? mcs->pxms_me: 0;
+  }
 
-  if (ene)
-  {
+  if (ene) {
     indx = mcs->pxms_ptindx;
 #if 1
     /* tuning of magnetic field/voltage advance angle */
@@ -366,13 +478,13 @@ pxmc_rocon_pwm3ph_out(pxmc_state_t *mcs)
       /* Generating direction of stator mag. field for backward torque */
       ene = -ene;
 
-      if ((indx -= mcs->pxms_ptvang) < 0)
+      if ((indx -= ptvang) < 0)
         indx += mcs->pxms_ptirc;
     }
     else
     {
       /* Generating direction of stator mag. field for forward torque */
-      if ((indx += mcs->pxms_ptvang) >= mcs->pxms_ptirc)
+      if ((indx += ptvang) >= mcs->pxms_ptirc)
         indx -= mcs->pxms_ptirc;
     }
 
@@ -429,10 +541,10 @@ pxmc_rocon_pwm2ph_wr(pxmc_state_t *mcs, short pwm1, short pwm2)
   volatile uint32_t *pwm_reg_ap, *pwm_reg_an, *pwm_reg_bp, *pwm_reg_bn;
   int chan = mcs->pxms_out_info;
 
-  pwm_reg_ap = pxmc_rocon_pwm_chan2reg(chan + 0);
-  pwm_reg_an = pxmc_rocon_pwm_chan2reg(chan + 1);
-  pwm_reg_bp = pxmc_rocon_pwm_chan2reg(chan + 2);
-  pwm_reg_bn = pxmc_rocon_pwm_chan2reg(chan + 3);
+  pwm_reg_bn = pxmc_rocon_pwm_chan2reg(chan + 0);
+  pwm_reg_bp = pxmc_rocon_pwm_chan2reg(chan + 1);
+  pwm_reg_an = pxmc_rocon_pwm_chan2reg(chan + 2);
+  pwm_reg_ap = pxmc_rocon_pwm_chan2reg(chan + 3);
 
   if (pwm2 >= 0) {
     *pwm_reg_bp = pwm2 | 0x4000;
@@ -458,6 +570,8 @@ pxmc_rocon_pwm2ph_wr(pxmc_state_t *mcs, short pwm1, short pwm2)
 int
 pxmc_rocon_pwm2ph_out(pxmc_state_t *mcs)
 {
+  typeof(mcs->pxms_ptvang) ptvang;
+  int sync_mode = 0;
   short pwm1;
   short pwm2;
   int indx = 0;
@@ -469,7 +583,21 @@ pxmc_rocon_pwm2ph_out(pxmc_state_t *mcs)
     short ptindx;
     short ptirc=mcs->pxms_ptirc;
 
-    pxmc_irc_16bit_commindx(mcs,mcs->pxms_rp>>PXMC_SUBDIV(mcs));
+   #if 0
+    pxmc_irc_16bit_commindx(mcs, mcs->pxms_rp >> PXMC_SUBDIV(mcs));
+    sync_mode = 1;
+   #elif 1
+    {
+      int res;
+      res = pxmc_inp_rocon_ptofs_from_index_poll(mcs, 0);
+      if (res < 0) {
+        pxmc_set_errno(mcs, PXMS_E_I2PT_TOOBIG);
+      } else if (res) {
+        pxmc_set_flag(mcs, PXMS_PTI_b);
+        pxmc_set_flag(mcs, PXMS_PHA_b);
+      }
+    }
+   #else
 
     ptindx = mcs->pxms_ptindx;
 
@@ -490,6 +618,7 @@ pxmc_rocon_pwm2ph_out(pxmc_state_t *mcs)
       if(!(mcs->pxms_flg&PXMS_PTI_m))
             mcs->pxms_ptindx = ptindx;
     }
+   #endif
   }
 
   {
@@ -498,24 +627,28 @@ pxmc_rocon_pwm2ph_out(pxmc_state_t *mcs)
     /* pxmc_set_errno(mcs, PXMS_E_WINDCURRENT); */
   }
 
-  ene = mcs->pxms_ene;
-  //if (ene) { /*FIXME*/
-  if (mcs->pxms_flg&PXMS_BSY_m){
-    ene = mcs->pxms_me; /*FIXME*/
+  if (!sync_mode) {
+    ptvang = mcs->pxms_ptvang;
+    ene = mcs->pxms_ene;
+  } else {
+    ptvang = 0;
+    ene = mcs->pxms_flg & PXMS_BSY_m? mcs->pxms_me: 0;
+  }
 
+  if (ene) {
     indx = mcs->pxms_ptindx;
-   #if 1
+   #if 0
     /* tuning of magnetic field/voltage advance angle */
     indx += (mcs->pxms_s1 * mcs->pxms_as) >> (PXMC_SUBDIV(mcs) + 8);
    #endif
     if (ene<0){
       /* Generating direction of stator mag. field for backward torque */
       ene = -ene;
-      if ((indx -= mcs->pxms_ptvang)<0)
+      if ((indx -= ptvang)<0)
         indx += mcs->pxms_ptirc;
     }else{
       /* Generating direction of stator mag. field for forward torque */
-      if ((indx += mcs->pxms_ptvang) >= mcs->pxms_ptirc)
+      if ((indx += ptvang) >= mcs->pxms_ptirc)
         indx -= mcs->pxms_ptirc;
     }
 
@@ -573,23 +706,198 @@ pxmc_rocon_pwm_dc_out(pxmc_state_t *mcs)
   return 0;
 }
 
-/* PWM outputs placed on (PWM1), PWM2, PWM4, PWM6 */
+volatile void *pxmc_rocon_rx_data_hist_buff;
+volatile void *pxmc_rocon_rx_data_hist_buff_end;
+
+uint32_t pxmc_rocon_rx_last_irq;
+uint32_t pxmc_rocon_rx_cycle_time;
+uint32_t pxmc_rocon_rx_irq_latency;
+uint32_t pxmc_rocon_rx_irq_latency_max;
+
+IRQ_HANDLER_FNC(pxmc_rocon_rx_done_isr)
+{
+  uint32_t ir;
+
+  ir = ROCON_RX_TIM->IR & LPC_TIM_IR_ALL_m;
+  ROCON_RX_TIM->IR = ir;
+  if (ir & LPC_TIM_IR_CR1INT_m) {
+    uint32_t cr0, cr1;
+    cr0 = ROCON_RX_TIM->CR0;
+    cr1 = ROCON_RX_TIM->CR1;
+
+    pxmc_rocon_rx_cycle_time = cr1 - pxmc_rocon_rx_last_irq;
+    pxmc_rocon_rx_last_irq = cr1;
+
+    hal_gpio_set_value(T2MAT0_PIN, 1);
+    hal_gpio_set_value(T2MAT1_PIN, 0);
+    hal_gpio_set_value(T2MAT0_PIN, 0);
+
+    if (pxmc_rocon_rx_data_hist_buff >= pxmc_rocon_rx_data_hist_buff_end)
+      pxmc_rocon_rx_data_hist_buff = NULL;
+
+    if (pxmc_rocon_rx_data_hist_buff != NULL) {
+      int i;
+      volatile uint32_t *pwm_reg = fpga_lx_master_transmitter_base + 8;
+      volatile uint32_t *rec_reg = fpga_lx_master_receiver_base + 8;
+      uint16_t *pbuf = (uint16_t *)pxmc_rocon_rx_data_hist_buff;
+      for (i = 0; i < 8; i++) {
+        *(pbuf++) = *(rec_reg++);
+      }
+      for (i = 0; i < 8; i++) {
+        *(pbuf++) = *(pwm_reg++);
+      }
+      pxmc_rocon_rx_data_hist_buff = pbuf;
+    }
+
+    pxmc_rocon_rx_irq_latency = ROCON_RX_TIM->TC - cr1;
+    if (pxmc_rocon_rx_irq_latency > pxmc_rocon_rx_irq_latency_max)
+      pxmc_rocon_rx_irq_latency_max = pxmc_rocon_rx_irq_latency;
+
+   #ifdef PXMC_ROCON_TIMED_BY_RX_DONE
+    pxmc_sfi_isr();
+    do_pxmc_coordmv();
+   #endif /*PXMC_ROCON_TIMED_BY_RX_DONE*/
+  }
+
+  return IRQ_HANDLED;
+}
+
+int
+pxmc_rocon_rx_done_isr_setup(irq_handler_t rx_done_isr_handler)
+{
+
+  disable_irq(ROCON_RX_IRQn);
+
+  hal_pin_conf_set(T2MAT0_PIN, PORT_CONF_GPIO_OUT_LO);
+  hal_pin_conf_set(T2MAT1_PIN, PORT_CONF_GPIO_OUT_LO);
+  hal_pin_conf(T2CAP0_PIN);
+  hal_pin_conf(T2CAP1_PIN);
+
+  hal_gpio_direction_output(T2MAT0_PIN, 1);
+  hal_gpio_direction_output(T2MAT1_PIN, 0);
+  hal_gpio_set_value(T2MAT0_PIN, 0);
+
+  /* Enable CLKOUT pin function, source CCLK, divide by 1 */
+  LPC_SC->CLKOUTCFG = 0x0100;
+
+  request_irq(ROCON_RX_IRQn, rx_done_isr_handler, 0, NULL,NULL);
+
+  ROCON_RX_TIM->TCR = 0;
+  ROCON_RX_TIM->CTCR = 0;
+  ROCON_RX_TIM->PR = 0;        /* Divide by 1 */
+
+  ROCON_RX_TIM->CCR = LPC_TIM_CCR_CAP0RE_m | LPC_TIM_CCR_CAP1FE_m |
+                   LPC_TIM_CCR_CAP1I_m;
+
+  ROCON_RX_TIM->EMR = __val2mfld(LPC_TIM_EMR_EMC0_m, LPC_TIM_EMR_NOP) |
+                   __val2mfld(LPC_TIM_EMR_EMC1_m, LPC_TIM_EMR_NOP);
+
+  ROCON_RX_TIM->MCR = 0;                       /* No IRQ on MRx */
+  ROCON_RX_TIM->TCR = LPC_TIM_TCR_CEN_m;       /* Enable timer counting */
+  enable_irq(ROCON_RX_IRQn);           /* Enable interrupt */
+
+  return 0;
+
+}
+
 int
 pxmc_rocon_pwm_master_init(void)
 {
   int i;
+  int grp_in = 0;
+  int grp_out = 0;
+  unsigned word_slot;
+  unsigned receiver_done_div = 1;
+ #ifdef LXPWR_WITH_SIROLADC
+  unsigned lxpwr_header = 1;
+  unsigned lxpwr_words = 1 + 8 * 2 + 2;
+  unsigned lxpwr_chips = 2;
+  unsigned lxpwr_chip_pwm_cnt = 8;
+ #else /*LXPWR_WITH_SIROLADC*/
+  unsigned lxpwr_header = 0;
+  unsigned lxpwr_words = 8;
+  unsigned lxpwr_chips = 2;
+  unsigned lxpwr_chip_pwm_cnt = 8;
+ #endif /*LXPWR_WITH_SIROLADC*/
+
+ #ifdef PXMC_ROCON_TIMED_BY_RX_DONE
+  receiver_done_div = 5;
+ #endif /*PXMC_ROCON_TIMED_BY_RX_DONE*/
 
   *fpga_lx_master_reset = 1;
   *fpga_lx_master_transmitter_reg = 0;
+  *fpga_lx_master_transmitter_cycle = 2500; /* 50 MHz -> 20 kHz */
+  *fpga_lx_master_receiver_done_div = receiver_done_div << 8;
+
+  for (i = 0; i < LX_MASTER_DATA_OFFS + lxpwr_words * lxpwr_chips; i++)
+    fpga_lx_master_receiver_base[i] = 0;
+
+  word_slot = LX_MASTER_DATA_OFFS;
+  fpga_lx_master_receiver_base[grp_in++] = (word_slot << 8) | lxpwr_words;
+  fpga_lx_master_receiver_base[grp_in++] = 0x0000;
 
-  for (i = 0; i < 8 + 16; i ++)
+  for (i = 0; i < LX_MASTER_DATA_OFFS + lxpwr_words * lxpwr_chips; i++)
     fpga_lx_master_transmitter_base[i] = 0;
 
-  fpga_lx_master_transmitter_base[0] = 0x0808;
-  fpga_lx_master_transmitter_base[1] = 0x0000;
+  word_slot = LX_MASTER_DATA_OFFS + lxpwr_header + lxpwr_chip_pwm_cnt;
+  fpga_lx_master_transmitter_base[grp_out++] = (word_slot << 8) | lxpwr_words;
+ #ifdef LXPWR_WITH_SIROLADC
+  fpga_lx_master_transmitter_base[word_slot] = 0xc100 | (lxpwr_words - 1);
+ #endif /*LXPWR_WITH_SIROLADC*/
+
+  word_slot = LX_MASTER_DATA_OFFS + 0;
+  fpga_lx_master_transmitter_base[grp_out++] = (word_slot << 8) | lxpwr_words;
+ #ifdef LXPWR_WITH_SIROLADC
+  fpga_lx_master_transmitter_base[word_slot] = 0xc100 | (lxpwr_words - 1);
+ #endif /*LXPWR_WITH_SIROLADC*/
+
+  fpga_lx_master_transmitter_base[grp_out++] = 0x0000;
 
   *fpga_lx_master_reset = 0;
+  *fpga_lx_master_transmitter_cycle = 2500; /* 50 MHz -> 20 kHz */
+  *fpga_lx_master_receiver_done_div = receiver_done_div << 8;
+
+  return 0;
+}
+
+int pxmc_ptofs_from_index(pxmc_state_t *mcs, unsigned long irc,
+                           unsigned long index_irc, int diff2err)
+{
+  long ofsl;
+  short ofs;
+
+  ofs = ofsl = index_irc - mcs->pxms_ptmark;
+
+  if (diff2err) {
+    short diff;
+    diff = (unsigned short)ofs - (unsigned short)mcs->pxms_ptofs;
+    if (diff >= mcs->pxms_ptirc / 2)
+      diff -= mcs->pxms_ptirc;
+    if (diff <= -mcs->pxms_ptirc / 2)
+      diff += mcs->pxms_ptirc;
+    if (diff < 0)
+      diff = -diff;
+    if(diff >= mcs->pxms_ptirc / 6) {
+      return -1;
+    }
+  } else {
+    long diff;
+    diff = (unsigned long)ofsl - irc;
+    ofs = ofsl - (diff / mcs->pxms_ptirc) * mcs->pxms_ptirc;
+  }
+
+  mcs->pxms_ptofs = ofs;
+
+  return 1;
+}
 
+/**
+ * pxmc_dummy_con - Dummy controller for synchronous BLDC/PMSM/steper drive
+ * @mcs:        Motion controller state information
+ */
+int
+pxmc_dummy_con(pxmc_state_t *mcs)
+{
   return 0;
 }
 
@@ -760,9 +1068,9 @@ pxms_flg:
 pxms_do_inp:
   pxmc_inp_rocon_inp,
 pxms_do_con:
-  pxmc_pid_con,
+  pxmc_pid_con /*pxmc_dummy_con*/,
 pxms_do_out:
-  pxmc_rocon_pwm_dc_out,
+  pxmc_rocon_pwm_dc_out /*pxmc_rocon_pwm3ph_out*/,
   pxms_do_deb: 0,
   pxms_do_gen: 0,
 pxms_do_ap2hw:
@@ -776,11 +1084,13 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
+  PXMS_CFG_HRI_m * 0 | PXMS_CFG_HDIR_m * 0 |
+  PXMS_CFG_I2PT_m * 0 | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
+  pxms_ptmark: 1180,
   /*pxms_ptamp: 0x7fff,*/
 
   pxms_hal: 0x40,
@@ -809,8 +1119,9 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
+  PXMS_CFG_HRI_m * 0 | PXMS_CFG_HDIR_m * 0 |
+  PXMS_CFG_I2PT_m * 0 | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
@@ -842,8 +1153,9 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
+  PXMS_CFG_I2PT_m * 0 | PXMS_CFG_HRI_m |
+  PXMS_CFG_HDIR_m | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
@@ -875,8 +1187,9 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
+  PXMS_CFG_I2PT_m * 0 | PXMS_CFG_HRI_m |
+  PXMS_CFG_HDIR_m * 0 | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
@@ -908,8 +1221,9 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
+  PXMS_CFG_HRI_m | PXMS_CFG_I2PT_m * 0 |
+  PXMS_CFG_HDIR_m | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
@@ -941,8 +1255,9 @@ pxms_do_ap2hw:
   pxms_p: 80, pxms_i: 30, pxms_d: 200, pxms_s1: 200, pxms_s2: 0,
   pxms_me: 0x7e00/*0x7fff*/,
 pxms_cfg:
-  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_I2PT_m * 0 |
-  0x1,
+  PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m |
+  PXMS_CFG_HRI_m | PXMS_CFG_I2PT_m * 0 |
+  PXMS_CFG_HDIR_m | 0x2,
 
   pxms_ptper: 1,
   pxms_ptirc: 1000,
@@ -1257,19 +1572,57 @@ int pxmc_rocon_pthalalign(pxmc_state_t *mcs, int periods)
   return res;
 }
 
+int pxmc_axis_rdmode(pxmc_state_t *mcs)
+{
+  if (mcs->pxms_do_out == pxmc_rocon_pwm2ph_out)
+    return PXMC_AXIS_MODE_STEPPER_WITH_IRC;
+  if (mcs->pxms_do_out == pxmc_rocon_pwm_dc_out)
+    return PXMC_AXIS_MODE_DC;
+  if (mcs->pxms_do_out == pxmc_rocon_pwm3ph_out)
+    return PXMC_AXIS_MODE_BLDC;
+  return -1;
+}
+
+
 int
 pxmc_axis_pt4mode(pxmc_state_t *mcs, int mode)
 {
-  int res;
+  static const typeof(*mcs->pxms_ptptr1) dummy0 = 0;
+  int res = 0;
 
-  mcs->pxms_ptvang = pxmc_ptvang_deg2irc(mcs, 90);
+  if (mode == PXMC_AXIS_MODE_NOCHANGE)
+    mode = pxmc_axis_rdmode(mcs);
+  if (mode < 0)
+    return -1;
 
-  /* res = pxmc_init_ptable(mcs, PXMC_PTPROF_SIN3FUP); */
-#ifndef PXMC_WITH_PT_ZIC
-  res = pxmc_ptable_set_profile(mcs, &pxmc_ptprofile_sin3phup, 0, 0);
-#else /*PXMC_WITH_PT_ZIC*/
-  res = pxmc_ptable_set_profile(mcs, &pxmc_ptprofile_sin3phup_zic, 0, 0);
-#endif /*PXMC_WITH_PT_ZIC*/
+  switch (mode) {
+    /*case PXMC_AXIS_MODE_STEPPER:*/
+    case PXMC_AXIS_MODE_STEPPER_WITH_IRC:
+      res = pxmc_ptable_set_profile(mcs, &pxmc_ptprofile_sin, 0, 0);
+      break;
+    /*case PXMC_AXIS_MODE_STEPPER_WITH_PWM:*/
+    case PXMC_AXIS_MODE_DC:
+      /*profive some sane dummy values*/
+      mcs->pxms_ptptr1 = (typeof(mcs->pxms_ptptr1))&dummy0;
+      mcs->pxms_ptptr2 = (typeof(mcs->pxms_ptptr1))&dummy0;
+      mcs->pxms_ptptr3 = (typeof(mcs->pxms_ptptr1))&dummy0;
+
+      mcs->pxms_ptscale_mult=1;
+      mcs->pxms_ptscale_shift=15;
+      break;
+    case PXMC_AXIS_MODE_BLDC:
+      /* res = pxmc_init_ptable(mcs, PXMC_PTPROF_SIN3FUP); */
+     #ifndef PXMC_WITH_PT_ZIC
+      res = pxmc_ptable_set_profile(mcs, &pxmc_ptprofile_sin3phup, 0, 0);
+     #else /*PXMC_WITH_PT_ZIC*/
+      res = pxmc_ptable_set_profile(mcs, &pxmc_ptprofile_sin3phup_zic, 0, 0);
+     #endif /*PXMC_WITH_PT_ZIC*/
+      break;
+    default:
+      return -1;
+  }
+
+  mcs->pxms_ptvang = pxmc_ptvang_deg2irc(mcs, 90);
 
   return res;
 }
@@ -1290,24 +1643,53 @@ pxmc_axis_mode(pxmc_state_t *mcs, int mode)
 
   pxmc_set_const_out(mcs, 0);
   pxmc_clear_flag(mcs, PXMS_ENI_b);
+  pxmc_clear_flags(mcs,PXMS_ENO_m);
+  /* Clear possible stall index flags from hardware */
+  pxmc_inp_rocon_is_index_edge(mcs);
   pxmc_clear_flag(mcs, PXMS_PHA_b);
   pxmc_clear_flag(mcs, PXMS_PTI_b);
 
+
+  if (mode == PXMC_AXIS_MODE_NOCHANGE)
+    mode = pxmc_axis_rdmode(mcs);
+  if (mode < 0)
+    return -1;
   if (!mode)
-  {
-    /*mode=pxmc_axis_rdmode(mcs);*/
-    if (!mode)
-      mode = PXMC_AXIS_MODE_BLDC;
-  }
+    mode = PXMC_AXIS_MODE_DC;
 
   res = pxmc_axis_pt4mode(mcs, mode);
+  if (res < 0)
+    return -1;
+
+  switch (mode) {
+    /*case PXMC_AXIS_MODE_STEPPER:*/
+    case PXMC_AXIS_MODE_STEPPER_WITH_IRC:
+      mcs->pxms_do_out = pxmc_rocon_pwm2ph_out;
+      break;
+    /*case PXMC_AXIS_MODE_STEPPER_WITH_PWM:*/
+    case PXMC_AXIS_MODE_DC:
+      mcs->pxms_do_out = pxmc_rocon_pwm_dc_out;
+      break;
+    case PXMC_AXIS_MODE_BLDC:
+      mcs->pxms_do_out = pxmc_rocon_pwm3ph_out;
+      break;
+    default:
+      return -1;
+  }
 
+  /* Clear possible stall index flags from hardware */
+  pxmc_inp_rocon_is_index_edge(mcs);
+  /* Request new phases alignment for changed parameters */
+  pxmc_clear_flag(mcs, PXMS_PHA_b);
+  pxmc_clear_flag(mcs, PXMS_PTI_b);
   pxmc_set_flag(mcs, PXMS_ENI_b);
   return res;
 }
 
 void pxmc_sfi_isr(void)
 {
+  unsigned long spent = pxmc_fast_tick_time();
+
   pxmc_sfi_input();
   pxmc_sfi_controller_and_output();
   pxmc_sfi_generator();
@@ -1315,6 +1697,53 @@ void pxmc_sfi_isr(void)
   /* Kick LX Master watchdog */
   if (pxmc_main_list.pxml_cnt != 0)
     *fpga_lx_master_transmitter_wdog = 1;
+
+  spent = pxmc_fast_tick_time() - spent;
+
+  if(spent > pxmc_sfi_spent_time_max)
+    pxmc_sfi_spent_time_max = spent;
+
+}
+
+int pxmc_clear_power_stop(void)
+{
+  return 0;
+}
+
+int pxmc_process_state_check(unsigned long *pbusy_bits,
+                             unsigned long *perror_bits)
+{
+  unsigned short flg;
+  unsigned short chan;
+  unsigned long busy_bits = 0;
+  unsigned long error_bits = 0;
+  pxmc_state_t *mcs;
+  flg=0;
+  pxmc_for_each_mcs(chan, mcs) {
+    if(mcs) {
+      flg |= mcs->pxms_flg;
+      if (mcs->pxms_flg & PXMS_BSY_m)
+        busy_bits |= 1 << chan;
+      if (mcs->pxms_flg & PXMS_ERR_m)
+        error_bits |= 1 << chan;
+    }
+  }
+  if (appl_errstop_mode) {
+    if((flg & PXMS_ENG_m) && (flg & PXMS_ERR_m)) {
+      pxmc_for_each_mcs(chan, mcs) {
+        if(mcs&&(mcs->pxms_flg & PXMS_ENG_m)) {
+          pxmc_stop(mcs, 0);
+        }
+      }
+    }
+  }
+
+  if (pbusy_bits != NULL)
+    *pbusy_bits = busy_bits;
+  if (error_bits != NULL)
+    *perror_bits = error_bits;
+
+  return flg;
 }
 
 int pxmc_done(void)
@@ -1339,12 +1768,19 @@ int pxmc_done(void)
 int pxmc_initialize(void)
 {
   int res;
+  int i;
 
   pxmc_state_t *mcs = &mcs0;
   lpc_qei_state_t *qst = &lpc_qei_state;
 
   *fpga_irc_reset = 1;
 
+  for (i = 0; i < 8; i++) {
+    fpga_irc[i]->count = 0;
+    fpga_irc[i]->count_index = 0;
+    *fpga_irc_state[i] = FPGA_IRC_STATE_INDEX_EVENT_MASK;
+  }
+
   /* Initialize QEI module for IRC counting */
   pxmc_inp_lpc_qei_init(mcs->pxms_inp_info);
 
@@ -1360,6 +1796,9 @@ int pxmc_initialize(void)
   //pxmc_rocon_pwm3ph_wr(mcs, 0, 0, 0);
 
   pxmc_rocon_pwm_master_init();
+ #ifdef PXMC_ROCON_TIMED_BY_RX_DONE
+  pxmc_rocon_rx_done_isr_setup(pxmc_rocon_rx_done_isr);
+ #endif /*PXMC_ROCON_TIMED_BY_RX_DONE*/
 
   pxmc_main_list.pxml_cnt = 0;
   pxmc_dbg_hist = NULL;