1 /*******************************************************************
2 Motion and Robotic System (MARS) aplication components.
4 appl_pxmc.c - SPI connected motor control board specific
7 Copyright (C) 2001-2015 by Pavel Pisa - originator
9 (C) 2001-2015 by PiKRON Ltd. - originator
12 This file can be used and copied according to next
14 - GPL - GNU Public License
15 - other license provided by project originators
17 *******************************************************************/
20 #include <system_def.h>
22 #include <pxmc_internal.h>
23 #include <pxmc_inp_common.h>
24 #include <pxmc_gen_info.h>
25 #include <pxmc_dq_trans.h>
26 #include <pxmc_sin_fixed.h>
30 #if !defined(clzl) && !defined(HAVE_CLZL)
31 #define clzl __builtin_clzl
34 #include "appl_defs.h"
35 #include "appl_pxmc.h"
36 #include "appl_utils.h"
38 #include "pxmc_spimc.h"
40 pthread_t pxmc_base_thread_id;
42 int pxmc_ptofs_from_index(pxmc_state_t *mcs, unsigned long irc,
43 unsigned long index_irc, int diff2err);
45 #define PXML_MAIN_CNT 1
47 #undef PXMC_WITH_PT_ZIC
48 #define PXMC_PT_ZIC_MASK 0x8000
50 #define HAL_ERR_SENSITIVITY 20
51 #define HAL_ERR_MAX_COUNT 5
53 #define PXMC_LXPWR_PWM_CYCLE 2048
55 unsigned pxmc_spimc_pwm_magnitude = PXMC_LXPWR_PWM_CYCLE;
57 unsigned pxmc_spimc_mark_filt[PXML_MAIN_CNT];
58 unsigned pxmc_spimc_lxpwr_chips = 0;
59 int appl_errstop_mode = 0;
62 pxmc_spimc_state_t *pxmc_state2spimc_state(pxmc_state_t *mcs)
64 pxmc_spimc_state_t *mcsrc;
66 mcsrc = UL_CONTAINEROF(mcs, pxmc_spimc_state_t, base);
67 #else /*UL_CONTAINEROF*/
68 mcsrc = (pxmc_spimc_state_t*)((char*)mcs - __builtin_offsetof(pxmc_spimc_state_t, base));
69 #endif /*UL_CONTAINEROF*/
73 const uint8_t onesin10bits[1024]={
74 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
75 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
76 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
77 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
78 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
79 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
80 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
81 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
82 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
83 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
84 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
85 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
86 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
87 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
88 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
89 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,
90 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
91 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
92 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
93 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
94 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
95 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
96 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
97 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,
98 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
99 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
100 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
101 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,
102 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
103 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,
104 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,
105 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10
109 pxmc_inp_spimc_inp(struct pxmc_state *mcs)
111 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
112 int chan=mcs->pxms_inp_info;
116 /* read position from hardware */
117 irc = mcsrc->spimc_state->act_pos;
118 irc += mcsrc->spimc_state->pos_offset;
119 pos = irc << PXMC_SUBDIV(mcs);
120 mcs->pxms_as = pos - mcs->pxms_ap;
123 /* Running of the motor commutator */
124 if (mcs->pxms_flg & PXMS_PTI_m)
125 pxmc_irc_16bit_commindx(mcs, irc);
131 pxmc_inp_spimc_ap2hw(struct pxmc_state *mcs)
133 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
134 int chan=mcs->pxms_inp_info;
138 irc = mcsrc->spimc_state->act_pos;
139 pos_diff = mcs->pxms_ap - (irc << PXMC_SUBDIV(mcs));
141 irc = pos_diff >> PXMC_SUBDIV(mcs);
143 /* Adjust phase table alignemt to modified IRC readout */
144 mcs->pxms_ptofs += irc - mcsrc->spimc_state->pos_offset;
146 mcsrc->spimc_state->pos_offset = irc;
151 pxmc_spimc_bldc_hal_rd(pxmc_state_t *mcs)
153 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
155 int chan = mcs->pxms_out_info;
157 h = mcsrc->spimc_state->hal_sensors;
159 /* return 3 bits corresponding to the HAL senzor input */
164 const unsigned char pxmc_lpc_bdc_hal_pos_table[8] =
176 const unsigned char pxmc_lpc_bdc_hal_pos_table[8] =
189 int pxmc_spimc_pwm_direct_wr(unsigned chan, unsigned pwm, int en)
196 * pxmc_spimc_pwm3ph_wr - Output of the 3-phase PWM to the hardware
197 * @mcs: Motion controller state information
199 /*static*/ inline void
200 pxmc_spimc_pwm3ph_wr(pxmc_state_t *mcs, uint32_t pwm1, uint32_t pwm2, uint32_t pwm3)
202 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
203 int chan = mcs->pxms_out_info;
205 mcsrc->spimc_state->pwm[0] = pwm1;
206 mcsrc->spimc_state->pwm[1] = pwm2;
207 mcsrc->spimc_state->pwm[2] = pwm3;
211 pxmc_spimc_process_hal_error(struct pxmc_state *mcs)
213 if (mcs->pxms_halerc >= HAL_ERR_SENSITIVITY * HAL_ERR_MAX_COUNT)
215 pxmc_set_errno(mcs, PXMS_E_HAL);
220 mcs->pxms_halerc += HAL_ERR_SENSITIVITY;
223 pxmc_inp_spimc_ptofs_from_index_poll(struct pxmc_state *mcs, int diff2err)
225 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
226 int chan=mcs->pxms_inp_info;
233 irc = mcsrc->spimc_state->act_pos + mcsrc->spimc_state->pos_offset;
234 index_irc = mcsrc->spimc_state->index_pos + mcsrc->spimc_state->pos_offset;
236 return pxmc_ptofs_from_index(mcs, irc, index_irc, diff2err);
240 * pxmc_spimc_pwm3ph_out - Phase output for brush-less 3-phase motor
241 * @mcs: Motion controller state information
244 pxmc_spimc_pwm3ph_out(pxmc_state_t *mcs)
246 pxmc_spimc_state_t *mcsrc = pxmc_state2spimc_state(mcs);
247 typeof(mcs->pxms_ptvang) ptvang;
249 unsigned char hal_pos;
251 int32_t sin_val, cos_val;
252 int32_t pwm_d, pwm_q;
253 int32_t pwm_alp, pwm_bet;
254 uint32_t pwm1, pwm2, pwm3;
258 if (!(mcs->pxms_flg & PXMS_PTI_m) || !(mcs->pxms_flg & PXMS_PHA_m) ||
259 (mcs->pxms_flg & PXMS_PRA_m))
262 short ptirc = mcs->pxms_ptirc;
263 short divisor = mcs->pxms_ptper * 6;
265 hal_pos = pxmc_lpc_bdc_hal_pos_table[pxmc_spimc_bldc_hal_rd(mcs)];
270 pxmc_spimc_process_hal_error(mcs);
274 if (mcs->pxms_halerc)
277 ptindx = (hal_pos * ptirc + divisor / 2) / divisor;
279 if (!(mcs->pxms_flg & PXMS_PTI_m) || (mcs->pxms_flg & PXMS_PRA_m))
281 if (((hal_pos != mcs->pxms_hal) && (mcs->pxms_hal != 0x40)) && 1)
283 short ptindx_prev = (mcs->pxms_hal * ptirc + divisor / 2) / divisor;;
285 if ((ptindx > ptindx_prev + ptirc / 2) ||
286 (ptindx_prev > ptindx + ptirc / 2))
288 ptindx = (ptindx_prev + ptindx - ptirc) / 2;
295 ptindx = (ptindx_prev + ptindx) / 2;
298 mcs->pxms_ptindx = ptindx;
300 mcs->pxms_ptofs = (mcs->pxms_ap >> PXMC_SUBDIV(mcs)) + mcs->pxms_ptshift - ptindx;
302 pxmc_set_flag(mcs, PXMS_PTI_b);
303 pxmc_clear_flag(mcs, PXMS_PRA_b);
307 if (!(mcs->pxms_flg & PXMS_PTI_m))
308 mcs->pxms_ptindx = ptindx;
311 /* if phase table position to mask is know do fine phase table alignment */
312 if (mcs->pxms_cfg & PXMS_CFG_I2PT_m) {
314 res = pxmc_inp_spimc_ptofs_from_index_poll(mcs, 0);
316 pxmc_set_errno(mcs, PXMS_E_I2PT_TOOBIG);
318 pxmc_set_flag(mcs, PXMS_PTI_b);
319 pxmc_set_flag(mcs, PXMS_PHA_b);
323 mcs->pxms_hal = hal_pos;
328 /*wind_current[0]=(ADC->ADDR0 & 0xFFF0)>>4;*/
329 /* FIXME - check winding current against limit */
330 /* pxmc_set_errno(mcs, PXMS_E_WINDCURRENT); */
334 ptvang = mcs->pxms_ptvang;
336 pwm_q = mcs->pxms_ene;
339 pwm_d = mcs->pxms_flg & PXMS_BSY_m? mcs->pxms_me: 0;
343 if (pwm_d || pwm_q) {
345 uint32_t ptscale_mult = mcs->pxms_ptscale_mult |
346 (mcs->pxms_ptscale_shift << 16);
348 indx = mcs->pxms_ptindx;
351 pta = indx + mcs->pxms_ptirc;
357 pta -= PXMC_SIN_FIX_2PI3;
359 pxmc_sincos_fixed_inline(&sin_val, &cos_val, pta, 16);
360 pxmc_dq2alpbet(&pwm_alp, &pwm_bet, pwm_d, pwm_q, sin_val, cos_val);
361 pxmc_alpbet2pwm3ph(&pwm1, &pwm2, &pwm3, pwm_alp, pwm_bet);
363 /*printf("pwm d %4d q %4d alp %4d bet %4d a %4d b %4d c %4d\n",
364 pwm_d, pwm_q, pwm_alp >> 16, pwm_bet >> 16, pwm1, pwm2, pwm3);*/
367 #ifdef PXMC_WITH_PT_ZIC
368 if (labs(mcs->pxms_as) < (10 << PXMC_SUBDIV(mcs)))
371 #endif /*PXMC_WITH_PT_ZIC*/
373 /* Default phase-table amplitude is 0x7fff, ene max is 0x7fff */
374 /* Initialized CTM4 PWM period is 0x200 => divide by value about 2097024 */
376 unsigned long pwm_mag = pxmc_spimc_pwm_magnitude;
378 pwm1 = SPIMC_PWM_SHUTDOWN;
380 pwm1 = (((unsigned long long)pwm1 * pwm_mag) >> 15) | SPIMC_PWM_ENABLE;
382 pwm2 = SPIMC_PWM_SHUTDOWN;
384 pwm2 = (((unsigned long long)pwm2 * pwm_mag) >> 15) | SPIMC_PWM_ENABLE;
386 pwm3 = SPIMC_PWM_SHUTDOWN;
388 pwm3 = (((unsigned long long)pwm3 * pwm_mag) >> 15) | SPIMC_PWM_ENABLE;
390 pxmc_spimc_pwm3ph_wr(mcs, pwm1, pwm2, pwm3);
395 pxmc_spimc_pwm3ph_wr(mcs, 0, 0, 0);
398 /*printf("hal_pos %d pwm %4d %4d %4d\n", hal_pos, pwm1 & 0xffff,
399 pwm2 & 0xffff, pwm3 & 0xffff);*/
405 * pxmc_spimc_pwm_dc_out - DC motor CW and CCW PWM output
406 * @mcs: Motion controller state information
409 pxmc_spimc_pwm_dc_out(pxmc_state_t *mcs)
411 int chan = mcs->pxms_out_info;
412 int ene = mcs->pxms_ene;
419 ene = (ene * (pxmc_spimc_pwm_magnitude + 5)) >> 15;
421 /**pwm_reg_b = ene | 0x4000;*/
425 ene = (ene * (pxmc_spimc_pwm_magnitude + 5)) >> 15;
427 /**pwm_reg_a = ene | 0x4000;*/
433 int pxmc_ptofs_from_index(pxmc_state_t *mcs, unsigned long irc,
434 unsigned long index_irc, int diff2err)
439 ofs = ofsl = index_irc - mcs->pxms_ptmark;
443 diff = (unsigned short)ofs - (unsigned short)mcs->pxms_ptofs;
444 if (diff >= mcs->pxms_ptirc / 2)
445 diff -= mcs->pxms_ptirc;
446 if (diff <= -mcs->pxms_ptirc / 2)
447 diff += mcs->pxms_ptirc;
450 if(diff >= mcs->pxms_ptirc / 6) {
455 diff = (unsigned long)ofsl - irc;
456 ofs = ofsl - (diff / mcs->pxms_ptirc) * mcs->pxms_ptirc;
459 mcs->pxms_ptofs = ofs;
465 * pxmc_dummy_con - Dummy controller for synchronous BLDC/PMSM/steper drive
466 * @mcs: Motion controller state information
469 pxmc_dummy_con(pxmc_state_t *mcs)
474 pxmc_call_t *pxmc_get_hh_gi_4axis(pxmc_state_t *mcs)
479 int pxmc_fill_ptscale_for_sin_fixed(pxmc_state_t *mcs)
481 unsigned long ptirc = mcs->pxms_ptirc;
482 unsigned long ptper = mcs->pxms_ptper;
483 unsigned long scale_mult;
484 unsigned long scale_shift;
490 scale_mult = (ptper + ptirc / 2) / ptirc;
492 scale_mult <<= 32 - shift;
494 scale_mult >>= shift - 32;
496 mcs->pxms_ptscale_mult = scale_mult & 0xffff;
497 mcs->pxms_ptscale_shift = scale_mult >> 16;
502 spimc_state_t spimc_state0 = {
503 .spi_dev = "/dev/spidev0.1",
506 pxmc_spimc_state_t mcs0 =
514 pxmc_pid_con /*pxmc_dummy_con*/,
516 pxmc_spimc_pwm3ph_out /*pxmc_spimc_pwm_dc_out*/,
520 pxmc_inp_spimc_ap2hw,
521 .pxms_ap = 0, .pxms_as = 0,
522 .pxms_rp = 55 * 256, .pxms_rs = 0,
523 #ifndef PXMC_WITH_FIXED_SUBDIV
525 #endif /*PXMC_WITH_FIXED_SUBDIV*/
526 .pxms_md = 800 << 8, .pxms_ms = 500, .pxms_ma = 10,
529 .pxms_ene = 0, .pxms_erc = 0,
530 .pxms_p = 40, .pxms_i = 10, .pxms_d = 100, .pxms_s1 = 0, .pxms_s2 = 0,
531 .pxms_me = 0x7e00/*0x7fff*/,
533 PXMS_CFG_SMTH_m | PXMS_CFG_MD2E_m | PXMS_CFG_HLS_m | PXMS_CFG_HPS_m * 0 |
534 PXMS_CFG_HRI_m * 0 | PXMS_CFG_HDIR_m * 0 |
535 PXMS_CFG_I2PT_m * 0 | 0x2,
540 /*.pxms_ptamp = 0x7fff,*/
544 .spimc_state = &spimc_state0,
553 pxmc_state_t *pxmc_main_arr[PXML_MAIN_CNT] = {&mcs0.base};
556 pxmc_state_list_t pxmc_main_list =
564 static inline void pxmc_sfi_input(void)
568 pxmc_for_each_mcs(var, mcs)
570 /* PXMS_ENI_m - check if input (IRC) update is enabled */
571 if (mcs->pxms_flg & PXMS_ENI_m)
573 pxmc_call(mcs, mcs->pxms_do_inp);
578 static inline void pxmc_sfi_controller_and_output(void)
582 pxmc_for_each_mcs(var, mcs)
584 /* PXMS_ENR_m - check if controller is enabled */
585 if (mcs->pxms_flg & PXMS_ENR_m || mcs->pxms_flg & PXMS_ENO_m)
588 /* If output only is enabled, we skip the controller */
589 if (mcs->pxms_flg & PXMS_ENR_m)
592 pxmc_call(mcs, mcs->pxms_do_con);
594 /* PXMS_ERR_m - if axis in error state */
595 if (mcs->pxms_flg & PXMS_ERR_m)
599 /* for bushless motors, it is necessary to call do_out
600 even if the controller is not enabled and PWM should be provided. */
601 pxmc_call(mcs, mcs->pxms_do_out);
606 static inline void pxmc_sfi_generator(void)
610 pxmc_for_each_mcs(var, mcs)
612 /* PXMS_ENG_m - check if requested value (position) generator is enabled */
613 if (mcs->pxms_flg & PXMS_ENG_m)
615 pxmc_call(mcs, mcs->pxms_do_gen);
620 static inline void pxmc_sfi_dbg(void)
624 pxmc_for_each_mcs(var, mcs)
626 if (mcs->pxms_flg & PXMS_DBG_m)
628 pxmc_call(mcs, mcs->pxms_do_deb);
633 static inline void pxmc_spimc_rq_transfer(void)
637 pxmc_spimc_state_t *mcsrc;
639 pxmc_for_each_mcs(var, mcs)
641 mcsrc = pxmc_state2spimc_state(mcs);
642 spimc_transfer(mcsrc->spimc_state);
646 void pxmc_samplig_period(void)
649 pxmc_sfi_controller_and_output();
650 pxmc_spimc_rq_transfer();
651 pxmc_sfi_generator();
657 void *pxmc_base_thread(void *arg)
659 sample_period_t sample_period;
660 sample_period_setup(&sample_period, 1000 * 1000);
663 pxmc_samplig_period();
664 sample_period_wait_next(&sample_period);
668 int pxmc_clear_power_stop(void)
673 int pxmc_process_state_check(unsigned long *pbusy_bits,
674 unsigned long *perror_bits)
678 unsigned long busy_bits = 0;
679 unsigned long error_bits = 0;
682 pxmc_for_each_mcs(chan, mcs) {
684 flg |= mcs->pxms_flg;
685 if (mcs->pxms_flg & PXMS_BSY_m)
686 busy_bits |= 1 << chan;
687 if (mcs->pxms_flg & PXMS_ERR_m)
688 error_bits |= 1 << chan;
691 if (appl_errstop_mode) {
692 if((flg & PXMS_ENG_m) && (flg & PXMS_ERR_m)) {
693 pxmc_for_each_mcs(chan, mcs) {
694 if(mcs&&(mcs->pxms_flg & PXMS_ENG_m)) {
701 if (pbusy_bits != NULL)
702 *pbusy_bits = busy_bits;
703 if (error_bits != NULL)
704 *perror_bits = error_bits;
710 * pxmc_axis_mode - Sets axis mode.[extern API]
711 * @mcs: Motion controller state information
712 * @mode: 0 .. previous mode, 1 .. stepper motor mode,
713 * 2 .. stepper motor with IRC feedback and PWM ,
714 * 3 .. stepper motor with PWM control
715 * 4 .. DC motor with IRC feedback and PWM
719 pxmc_axis_mode(pxmc_state_t *mcs, int mode)
729 if (!pxmc_main_list.pxml_cnt)
732 pxmc_for_each_mcs(var, mcs)
734 pxmc_axis_release(mcs);
737 pxmc_main_list.pxml_cnt = 0;
743 int pxmc_initialize(void)
747 pxmc_main_list.pxml_cnt = 0;
748 pxmc_dbg_hist = NULL;
750 if (spimc_init(mcs0.spimc_state) < 0)
753 pxmc_fill_ptscale_for_sin_fixed(pxmc_main_list.pxml_arr[0]);
756 pxmc_main_list.pxml_cnt = PXML_MAIN_CNT;
758 if (create_rt_task(&pxmc_base_thread_id, 60, pxmc_base_thread, NULL) < 0)