]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/blobdiff - hw/lx-rocon_firmware/firmware.c
RoCoN and TUMBL firmware: reimplemented control of stepper motor without feedback.
[fpga/lx-cpu1/lx-rocon.git] / hw / lx-rocon_firmware / firmware.c
index 997bfba51c139b7905b6689fb3a0118044afedc1..a117a62e0fba18f8b3d9f0777a1ae8b05a5bfa14 100644 (file)
@@ -2,7 +2,7 @@
   Components for embedded applications builded for
   laboratory and medical instruments firmware
 
-  firmware.c - multi axis motion controller comprocesor
+  firmware.c - multi axis motion controller coprocessor
                firmware for FPGA tumble CPU of lx-rocon system
 
   (C) 2001-2014 by Pavel Pisa pisa@cmp.felk.cvut.cz
@@ -33,6 +33,9 @@
 /* 1 / (2 * k3) * 65536 */
 #define RECI16_2_K3  37837
 
+#define offsbychar(_ptr, _offs) \
+   ((typeof(&(_ptr)[0]))((char*)(_ptr) + (_offs)))
+
 pxmcc_data_t pxmcc_data;
 
 void init_defvals(void)
@@ -79,21 +82,27 @@ void main(void)
   uint32_t last_rx_done_sqn = 0;
   pxmcc_axis_data_t *pxmcc;
 
-  pxmcc_data.common.fwversion = PXMCC_FWVERSION;
   pxmcc_data.common.pwm_cycle = 2500;
   pxmcc_data.common.min_idle = 0x7fff;
-  pxmcc = pxmcc_data.axis;
-  pxmcc->ccflg = 0;
-  pxmcc->ptindx = 0;
-  /*pxmcc->ptofs = *FPGA_IRC0;*/
-  pxmcc->ptirc = 1000;
-  pxmcc->ptreci = 4294967; /* (1LL<<32)*ptper/ptirc */
-  pxmcc->pwm_dq = 0;
+  pxmcc_data.common.irc_base = (uint32_t)FPGA_IRC0;
   pxmcc_data.curadc[0].siroladc_offs = 0x0c17;
   pxmcc_data.curadc[1].siroladc_offs = 0x0c66;
   pxmcc_data.curadc[2].siroladc_offs = 0x0c66;
+  pxmcc_data.curadc[3].siroladc_offs = 0x0c66;
+
+  pxmcc = pxmcc_data.axis;
+  do {
+    pxmcc->ccflg  = 0;
+    pxmcc->mode   = PXMCC_MODE_IDLE;
+    pxmcc->ptirc  = 1000;
+    pxmcc->ptreci = 4294967; /* (1LL<<32)*ptper/ptirc */
+    pxmcc->pwm_dq = 0;
+    pxmcc++;
+  } while(pxmcc != pxmcc_data.axis + PXMCC_AXIS_COUNT);
 
   asm volatile("": : : "memory");
+  pxmcc_data.common.fwversion = PXMCC_FWVERSION;
+  asm volatile("": : : "memory");
 
  #if 0
   find_sin_lat();
@@ -110,10 +119,16 @@ void main(void)
       uint32_t pwmtx_info;
       volatile uint32_t *uptr;
 
-      irc = *(FPGA_IRC0 + (FPGA_IRC1 - FPGA_IRC0) * pxmcc->inp_info);
+      irc = *(uint32_t*)pxmcc->inp_info;
 
       pti = irc - ofs;
-      if ((uint32_t)pti >= per) {
+      /*
+       * the '>=' is appropriate to keep pti in <0;per-1> range,
+       * but sine and cosine computations can work over multiple
+       * periods and value of per=0xffffffff allows to control/stop
+       * updates if only '>' is used.
+       */
+      if ((uint32_t)pti > per) {
         if (pti < 0) {
           ofs -= per;
         } else {
@@ -127,11 +142,11 @@ void main(void)
       pta = pti * pxmcc->ptreci;
 
       *FPGA_FNCAPPROX_SIN = pta;
-      asm volatile("nop\n": : : "memory");
-      asm volatile("nop\n": : : "memory");
-      asm volatile("nop\n": : : "memory");
+      asm volatile("nop\n");
+      asm volatile("nop\n");
+      asm volatile("nop\n");
       pxmcc->ptsin = *FPGA_FNCAPPROX_SIN;
-      asm volatile("nop\n": : : "memory");
+      asm volatile("nop\n");
       pxmcc->ptcos = *FPGA_FNCAPPROX_COS;
 
       if (pxmcc->ccflg) {
@@ -155,7 +170,7 @@ void main(void)
         pwm_alp = pwm_d * pxmcc->ptcos - pwm_q * pxmcc->ptsin;
         pwm_bet = pwm_d * pxmcc->ptsin + pwm_q * pxmcc->ptcos;
 
-        if (!pxmcc->mode) {
+        if (pxmcc->mode == PXMCC_MODE_BLDC) {
           pwm_bet_div_2_k3 = RECI16_2_K3 * (pwm_bet >> 16);
 
          #ifndef SUPPRESS_CONDITIONALS
@@ -272,14 +287,14 @@ void main(void)
           *uptr = pwm1 | 0x4000;
          #endif
         } else {
-          uint32_t bet_sgn = pwm_bet >> 31;
           uint32_t alp_sgn = pwm_alp >> 31;
-          pwm1 = pwm2 = pwm_bet | 0x4000;
-          pwm3 = pwm4 = pwm_alp | 0x4000;
-          pwm1 &= ~bet_sgn;
-          pwm2 &= bet_sgn;
-          pwm3 &= ~alp_sgn;
-          pwm4 &= alp_sgn;
+          uint32_t bet_sgn = pwm_bet >> 31;
+          pwm_alp >>= 16;
+          pwm_bet >>= 16;
+          pwm1 = -pwm_alp & alp_sgn;
+          pwm2 = pwm_alp & ~alp_sgn;
+          pwm3 = -pwm_bet & bet_sgn;
+          pwm4 = pwm_bet & ~bet_sgn;
 
           pwmtx_info = pxmcc->pwmtx_info;
           uptr = FPGA_LX_MASTER_TX + ((pwmtx_info >>  0) & 0xff);
@@ -294,9 +309,18 @@ void main(void)
           uptr = FPGA_LX_MASTER_TX + ((pwmtx_info >> 24) & 0xff);
           pxmcc->pwm_prew[3] = *uptr & 0x3fff;
           *uptr = pwm4 | 0x4000;
+          if (pxmcc->mode == PXMCC_MODE_STEPPER) {
+            if ((pxmcc->steps_sqn_next ^ last_rx_done_sqn) & 0x1f) {
+              pxmcc->steps_pos += pxmcc->steps_inc;
+            } else {
+              pxmcc->steps_pos = pxmcc->steps_pos_next;
+              pxmcc->steps_inc = pxmcc->steps_inc_next;
+              pxmcc->steps_inc_next = 0;
+            }
+          }
         }
       } else {
-        if (!pxmcc->mode) {
+        if (pxmcc->mode == PXMCC_MODE_BLDC) {
           pwmtx_info = pxmcc->pwmtx_info;
           uptr = FPGA_LX_MASTER_TX + ((pwmtx_info >>  0) & 0xff);
           pxmcc->pwm_prew[1] = *uptr & 0x3fff;
@@ -343,15 +367,14 @@ void main(void)
       int i;
       pxmcc_curadc_data_t *curadc = pxmcc_data.curadc;
       volatile uint32_t *siroladc = FPGA_LX_MASTER_RX_ADC0;
-      uint16_t val;
+      uint32_t val;
 
       for (i = 0; i < PXMCC_CURADC_CHANNELS; ) {
         val = *siroladc;
 
-        curadc->cur_val = val - curadc->siroladc_last
-                              - curadc->siroladc_offs;
+        curadc->cur_val = (uint16_t)(val - curadc->siroladc_last) -
+                          curadc->siroladc_offs;
         curadc->siroladc_last = val;
-        curadc->reserved1=0x11aa;
 
         i++;
         curadc += 1;
@@ -371,10 +394,10 @@ void main(void)
       uint32_t pwm1;
       uint32_t pwm2;
       uint32_t pwm3;
-      int32_t  cur[3];
       int32_t  cur1;
       int32_t  cur2;
       int32_t  cur3;
+      int32_t  *pcurmult;
       uint32_t curmult_idx;
       uint32_t pwm_reci;
       uint32_t out_info;
@@ -386,10 +409,7 @@ void main(void)
      #endif /*COMPUTE_PHASE_SECTOR*/
 
       out_info = pxmcc->out_info;
-      if (!pxmcc->mode) {
-        cur[1] = pxmcc_data.curadc[out_info + 0].cur_val;
-        cur[2] = pxmcc_data.curadc[out_info + 1].cur_val;
-        cur[0] = pxmcc_data.curadc[out_info + 2].cur_val;
+      if (pxmcc->mode == PXMCC_MODE_BLDC) {
 
         pwm1 = pxmcc->pwm_prew[0];
         pwm2 = pxmcc->pwm_prew[1];
@@ -416,11 +436,22 @@ void main(void)
         curmult_idx = (0x00201201 >> (4 * phs)) & 3;
         pwm_reci = pxmcc_data.common.pwm_cycle - pxmcc->pwm_prew[curmult_idx];
         pwm_reci = (pxmcc_data.common.pwm_cycle << 16) / pwm_reci;
-        cur[curmult_idx] = (int32_t)(pwm_reci * cur[curmult_idx]) >> 16;
 
-        cur1 = cur[0];
-        cur2 = cur[1];
-        cur3 = cur[2];
+        /*
+         * Translate index from pwm1, pwm2, pwm3 order to
+         * to order of current sources 0->2 1->0 2->1
+         *
+         * This solution modifies directly value in pxmcc_curadc_data_t
+         * so it is destructive and has not to be applied twice,
+         * but it is much better optimized
+         */
+        curmult_idx = (0x102 >> (curmult_idx * 4)) & 3;
+        pcurmult = &pxmcc_data.curadc[out_info + curmult_idx].cur_val;
+        *pcurmult = (int32_t)(pwm_reci * (*pcurmult)) >> 16;
+
+        cur2 = pxmcc_data.curadc[out_info + 0].cur_val;
+        cur3 = pxmcc_data.curadc[out_info + 1].cur_val;
+        cur1 = pxmcc_data.curadc[out_info + 2].cur_val;
 
         if ((phs == 5) || (phs == 0))
           cur_alp = -(cur2 + cur3);
@@ -450,9 +481,19 @@ void main(void)
           uint32_t u2gtu3 = (int32_t)(pwm3 - pwm2) >> 31;
           uint32_t state50_msk = u1gtu2 & u1gtu3;
           uint32_t pwm_reci_bits;
+          uint32_t sz4idx = sizeof(*pxmcc->pwm_prew);
+          uint32_t sz4cur = sizeof(*pxmcc_data.curadc);
+          uint32_t curmult_idx2curadc;
 
+         #if 0
           curmult_idx = (((u1gtu3 ^ u1gtu2) | 1) ^ u2gtu3 ^ u1gtu2) & 3;
           pwm_reci = pxmcc_data.common.pwm_cycle - pxmcc->pwm_prew[curmult_idx];
+         #else
+          /* Variant where curmult_idx is directly computed as byte offset to uint32_t array */
+          curmult_idx = (((u1gtu3 ^ u1gtu2) | (1 * sz4idx)) ^ u2gtu3 ^ u1gtu2) & (3 * sz4idx);
+          pwm_reci = pxmcc_data.common.pwm_cycle - *offsbychar(pxmcc->pwm_prew, curmult_idx);
+         #endif
+
          #if 0
           pwm_reci_bits = __builtin_clzl(pwm_reci);
          #else
@@ -460,18 +501,38 @@ void main(void)
          #endif
           pwm_reci <<= pwm_reci_bits;
           *FPGA_FNCAPPROX_RECI = pwm_reci;
-          asm volatile("nop\n": : : "memory");
-          asm volatile("nop\n": : : "memory");
-          asm volatile("nop\n": : : "memory");
+          asm volatile("nop\n");
+          asm volatile("nop\n");
+          asm volatile("nop\n");
           pwm_reci = *FPGA_FNCAPPROX_RECI;
           pwm_reci >>= 16;
           pwm_reci *= pxmcc_data.common.pwm_cycle;
           pwm_reci >>= 30 - pwm_reci_bits;
-          cur[curmult_idx] = (int32_t)(pwm_reci * cur[curmult_idx]) >> 16;
 
-          cur1 = cur[0];
-          cur2 = cur[1];
-          cur3 = cur[2];
+          /*
+           * Translate index from pwm1, pwm2, pwm3 order to
+           * to order of current sources 0->2 1->0 2->1
+           *
+           * This solution modifies directly value in pxmcc_curadc_data_t
+           * so it is destructive and has not to be applied twice,
+           * but it is much better optimized
+           */
+         #if 0
+          curmult_idx = (0x102 >> (curmult_idx * 4)) & 3;
+          pcurmult = &pxmcc_data.curadc[out_info + curmult_idx].cur_val;
+         #else
+          curmult_idx2curadc = ((2 * sz4cur) << (0 * sz4idx)) |
+                               ((0 * sz4cur) << (1 * sz4idx)) |
+                               ((1 * sz4cur) << (2 * sz4idx));
+          curmult_idx = (curmult_idx2curadc >> curmult_idx) & (sz4cur | (sz4cur << 1));
+          pcurmult = &pxmcc_data.curadc[out_info].cur_val;
+          pcurmult = offsbychar(pcurmult, curmult_idx);
+         #endif
+          *pcurmult = (int32_t)(pwm_reci * (*pcurmult)) >> 16;
+
+          cur2 = pxmcc_data.curadc[out_info + 0].cur_val;
+          cur3 = pxmcc_data.curadc[out_info + 1].cur_val;
+          cur1 = pxmcc_data.curadc[out_info + 2].cur_val;
 
           cur_alp = -(cur2 + cur3);                /* 5 0 */
           cur_alp &= state50_msk;                  /* 1 2 3 4 */
@@ -490,14 +551,14 @@ void main(void)
         cur_bet *= CONST16_K3;
         cur_bet >>= 16;
       } else {
-        int32_t bet_pwm = pxmcc->pwm_prew[1];
+        int32_t bet_pwm = pxmcc->pwm_prew[2];
         uint32_t bet_sgn = (bet_pwm - 1) >> 31;
-        int32_t alp_pwm = pxmcc->pwm_prew[3];
+        int32_t alp_pwm = pxmcc->pwm_prew[0];
         uint32_t alp_sgn = (alp_pwm - 1) >> 31;
-        cur_bet = (pxmcc_data.curadc[out_info + 0].cur_val & ~bet_sgn) -
-                  (pxmcc_data.curadc[out_info + 1].cur_val & bet_sgn);
-        cur_alp = (pxmcc_data.curadc[out_info + 2].cur_val & ~alp_sgn) -
-                  (pxmcc_data.curadc[out_info + 3].cur_val & alp_sgn);
+        cur_bet = (pxmcc_data.curadc[out_info + 3].cur_val & ~bet_sgn) -
+                  (pxmcc_data.curadc[out_info + 2].cur_val & bet_sgn);
+        cur_alp = (pxmcc_data.curadc[out_info + 1].cur_val & ~alp_sgn) -
+                  (pxmcc_data.curadc[out_info + 0].cur_val & alp_sgn);
       }
 
       cur_d =  cur_alp * pxmcc->ptcos + cur_bet * pxmcc->ptsin;