]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/test_sw/main_pmsm.c
50e32e19ce6e4f0e2d418ac99930f3bed7fab087
[fpga/rpi-motor-control.git] / pmsm-control / test_sw / main_pmsm.c
1 /**
2  * \file main_pmsm.c
3  * \author Martin Prudek
4  * \brief Mainfile pro pmsm control.
5  */
6
7 #ifndef NULL
8 #define NULL (void*) 0
9 #endif /*NULL*/
10
11
12 #include <stdlib.h>     /*exit*/
13 #include <signal.h>     /*signal handler Ctrl+C*/
14 #include <stdio.h>      /*printf*/
15 #include <sched.h>      /*sheduler*/
16 #include <unistd.h>     /*usleep*/
17 #include <pthread.h>    /*threads*/
18 #include <time.h>       /*nanosleep*/
19
20 #include "rpin.h"       /*gpclk*/
21 #include "rp_spi.h"     /*spi*/
22 #include "misc.h"       /*structure for priorities*/
23 #include "pxmc_sin_fixed.h"     /*to test sin commutation */
24 #include "pmsm_state.h"
25 #include "cmd_proc.h"
26
27 #define PRUM_PROUD      2061
28 #define PRUM_SOUC       6183
29 #define MAX_DUTY        128
30 #define PID_P           0.1
31
32 #define PRIOR_KERN      50
33 #define PRIOR_HIGH      49
34 #define PRIOR_LOW       20
35
36 #define THREAD_SHARED   0
37 #define INIT_VALUE      1       /*init value for semaphor*/
38
39
40 #define NSEC_PER_SEC    (1000000000) /* The number of nsecs per sec. */
41
42
43 struct rpi_in data;
44 struct rpi_state rps={
45         .spi_dat=&data,
46         .thd_par_sem=NULL,
47         .test=0,
48         .pwm1=0,.pwm2=0, .pwm3=0,
49         .pwm1=0, .t_pwm2=0, .t_pwm3=0,
50         .commutate=0,
51         .duty=0,                        /* duty cycle of pwm */
52         .index_dist=0,          /* distance to index position */
53         .index_ok=0,
54         .tf_count=0,            /*number of transfer*/
55         .desired_pos=0          /* desired position */
56 };
57
58 /**
59  * \brief Initilizes GPCLK.
60  */
61 int clk_init()
62 {
63         initialise(); /*namapovani gpio*/
64         initClock(PLLD_500_MHZ, 10, 0);
65         gpioSetMode(4, FSEL_ALT0);
66         return 0;
67 }
68 /*
69  * \brief Terminates GPCLK.
70  */
71
72 inline void clk_disable(){
73         termClock(0);
74 }
75
76 /**
77  * \brief Signal handler pro Ctrl+C
78  */
79 void appl_stop(){
80         spi_disable();
81         clk_disable();
82         /*muzeme zavrit semafor*/
83         sem_destroy(&rps.thd_par_sem);
84         printf("\nprogram bezpecne ukoncen\n");
85 }
86
87 void substractOffset(struct rpi_in* data, struct rpi_in* offset){
88         data->pozice_raw=data->pozice;
89         data->pozice-=offset->pozice;
90         return;
91 }
92 /*
93  * pocita procentualni odchylku od prumerneho proudu
94  */
95 float diff_p(float value){
96         return ((float)value-PRUM_PROUD)*100/PRUM_PROUD;
97 }
98 /*
99  * pocita procentualni odchylku od prumerneho souctu proudu
100  */
101 float diff_s(float value){
102         return ((float)value-PRUM_SOUC)*100/PRUM_SOUC;
103 }
104
105 void prepare_tx(uint8_t * tx){
106
107         /*Data format:
108          * tx[4] - bity 95 downto 88 - bits that are sent first
109          * tx[5] - bity 87 downto 80
110          * tx[6] - bity 79 downto 72
111          * tx[7] - bity 71 downto 64
112          * tx[8] - bity 63 downto 56
113          * tx[9] - bity 55 downto 48
114          * tx[10] - bity 47 downto 40
115          * tx[11] - bity 39 downto 32
116          * tx[12] - bity 31 downto 24
117          * tx[13] - bity 23 downto 16
118          * tx[14] - bity 15 downto 8
119          * tx[15] - bity 7 downto 0
120          *
121          * bit 95 - ADC reset
122          * bit 94 - enable PWM1
123          * bit 93 - enable PWM2
124          * bit 92 - enable PWM3
125          * bit 91 - shutdown1
126          * bit 90 - shutdown2
127          * bit 89 - shutdown3
128          *      .
129          *      .
130          *      Unused
131          *      .
132          *      .
133          * bits 47 .. 32 - match PWM1
134          * bits 31 .. 16 - match PWM2
135          * bits 15 .. 0  - match PWM3
136          */
137
138
139         uint16_t tmp;
140
141         /* keep the 11-bit cap*/
142
143         if (rps.pwm1>2047) rps.pwm1=2047;
144         if (rps.pwm2>2047) rps.pwm2=2047;
145         if (rps.pwm3>2047) rps.pwm3=2047;
146
147         tx[0]=rps.test; /*bit 94 - enable PWM1*/
148
149         /*now we have to switch the bytes due to endianess */
150         /* ARMv6 & ARMv7 instructions are little endian */
151         /*pwm1*/
152         tx[10]=((uint8_t*)&rps.pwm1)[1]; /*MSB*/
153         tx[11]=((uint8_t*)&rps.pwm1)[0]; /*LSB*/
154
155         /*pwm2*/
156         tx[12]=((uint8_t*)&rps.pwm2)[1]; /*MSB*/
157         tx[13]=((uint8_t*)&rps.pwm2)[0]; /*LSB*/
158
159         /*pwm3*/
160         tx[14]=((uint8_t*)&rps.pwm3)[1]; /*MSB*/
161         tx[15]=((uint8_t*)&rps.pwm3)[0]; /*LSB*/
162
163
164 }
165 /**
166  * Funkce pravidelne vypisuje posledni zjistenou pozici lokalniho motoru
167  */
168 void * pos_monitor(void* param){
169         while(1){
170                 printData(&rps);
171                 usleep(1000000);        /*1 Hz*/
172         }
173         return (void*)0;
174 }
175 /*
176  * \brief
177  * Multiplication of 11 bit
178  * Zaporne vysledky prvede na nulu.
179  */
180 inline uint16_t mult_cap(int32_t s,int d){
181         int j;
182         int res=0;
183         for(j=0;j!=11;j++){
184                 /* multiplicate as if maximum sinus value was unity */
185                 res+=(!(s & 0x10000000))*(((1 << j) & s)>>j)*(d>>(10-j));
186         }
187         return res;
188 }
189 inline
190 int sin_commutator(int duty){
191         #define DEGREE_60        715827883
192         #define DEGREE_120      1431655765
193         #define DEGREE_180      2147483648
194         #define DEGREE_240      2863311531
195         #define DEGREE_300      3579139413
196         uint32_t j,pos;
197         int32_t sin;
198         pos=rps.index_dist;
199         int32_t pwm;
200         /*aby prictene uhly mohla byt kulata cisla, musime index posunout*/
201         pos+=38;
202         /*use it as cyclic 32-bit logic*/
203         pos*=4294967;
204         if (duty>=0){   /*clockwise rotation*/
205                 /* 1st phase */
206                 sin = pxmc_sin_fixed_inline(pos+DEGREE_240,10); /*10+1 bity*/ /*-120*/
207                 pwm=sin*duty/1024;
208                 if (pwm<0) pwm=0;
209                 rps.pwm1=(uint16_t)pwm;
210
211                 /* 2nd phase */
212                 sin = pxmc_sin_fixed_inline(pos+DEGREE_120,10); /*10+1 bity*/ /*-240*/
213                 pwm=sin*duty/1024;
214                 if (pwm<0) pwm=0;
215                 rps.pwm2=(uint16_t)pwm;
216
217                 /* 3rd phase */
218                 sin = pxmc_sin_fixed_inline(pos,10); /*10+1 bity*/
219                 pwm=sin*duty/1024;
220                 if (pwm<0) pwm=0;
221                 rps.pwm3=(uint16_t)pwm;
222         }else{
223                 duty=-duty;
224
225                 /* 1st phase */
226                 sin = pxmc_sin_fixed_inline(pos+DEGREE_60,10); /*10+1 bity*/ /*-300*/
227                 pwm=sin*duty/1024;
228                 if (pwm<0) pwm=0;
229                 rps.pwm1=(uint16_t)pwm;
230
231                 /* 2nd phase */
232                 sin = pxmc_sin_fixed_inline(pos+DEGREE_300,10); /*10+1 bity*/ /*-60-*/
233                 pwm=sin*duty/1024;
234                 if (pwm<0) pwm=0;
235                 rps.pwm2=(uint16_t)pwm;
236
237                 /* 3rd phase */
238                 sin = pxmc_sin_fixed_inline(pos+DEGREE_180,10); /*10+1 bity*/ /*-180*/
239                 pwm=sin*duty/1024;
240                 if (pwm<0) pwm=0;
241                 rps.pwm3=(uint16_t)pwm;
242         }
243         return 0;
244 }
245 /*
246  * \brief
247  * Test function to be placed in controll loop.
248  * Switches PWM's at point where they produce same force.
249  * This points are found thanks to IRC position,
250  */
251 inline
252 void simple_ind_dist_commutator(int duty){
253         if (duty>=0){ /* clockwise - so that position increase */
254                 /* pwm3 */
255                 if ((rps.index_dist>=45 && rps.index_dist<=373) ||
256                 (rps.index_dist>=1048 && rps.index_dist<=1377)){
257                         rps.pwm1=0;
258                         rps.pwm2=0;
259                         rps.pwm3=duty;
260                         /* pwm1 */
261                 }else if ((rps.index_dist>=373 && rps.index_dist<=711) ||
262                 (rps.index_dist>=1377 && rps.index_dist<=1711)){
263                         rps.pwm1=duty;
264                         rps.pwm2=0;
265                         rps.pwm3=0;
266                         /* pwm2 */
267                 }else if ((rps.index_dist>=0 && rps.index_dist<=45) ||
268                 (rps.index_dist>=711 && rps.index_dist<=1048) ||
269                 (rps.index_dist>=1711 && rps.index_dist<=1999)){
270                         rps.pwm1=0;
271                         rps.pwm2=duty;
272                         rps.pwm3=0;
273                 }
274         }else{  /*counter-clockwise - position decrease */
275                 /* pwm3 */
276                 if ((rps.index_dist>=544 && rps.index_dist<=881) ||
277                 (rps.index_dist>=1544 && rps.index_dist<=1878)){
278                         rps.pwm1=0;
279                         rps.pwm2=0;
280                         rps.pwm3=-duty;
281                         /* pwm1 */
282                 }else if ((rps.index_dist>=0 && rps.index_dist<=211) ||
283                 (rps.index_dist>=881 && rps.index_dist<=1210) ||
284                 (rps.index_dist>=1878 && rps.index_dist<=1999)){
285                         rps.pwm1=-duty;
286                         rps.pwm2=0;
287                         rps.pwm3=0;
288                         /* pwm2 */
289                 }else if ((rps.index_dist>=211 && rps.index_dist<=544) ||
290                 (rps.index_dist>=1210 && rps.index_dist<=1544)){
291                         rps.pwm1=0;
292                         rps.pwm2=-duty;
293                         rps.pwm3=0;
294                 }
295         }
296 }
297 /*
298  * \brief
299  * Test function to be placed in controll loop.
300  * Switches PWM's at point where they produce same force
301  */
302 inline void simple_hall_commutator(int duty){
303         if (duty>=0){ /* clockwise - so that position increase */
304                 /* pwm3 */
305                 if (data.hal2 && !data.hal3){
306                         rps.pwm1=0;
307                         rps.pwm2=0;
308                         rps.pwm3=duty;
309                         /* pwm1 */
310                 }else if (data.hal1 && !data.hal2){
311                         rps.pwm1=duty;
312                         rps.pwm2=0;
313                         rps.pwm3=0;
314                         /* pwm2 */
315                 }else if (!data.hal1 && data.hal3){
316                         rps.pwm1=0;
317                         rps.pwm2=duty;
318                         rps.pwm3=0;
319                 }
320         }else{  /*counter-clockwise - position decrease */
321                 /* pwm3 */
322                 if (!data.hal2 && data.hal3){
323                         rps.pwm1=0;
324                         rps.pwm2=0;
325                         rps.pwm3=-duty;
326                         /* pwm1 */
327                 }else if (!data.hal1 && data.hal2){
328                         rps.pwm1=-duty;
329                         rps.pwm2=0;
330                         rps.pwm3=0;
331                         /* pwm2 */
332                 }else if (data.hal1 && !data.hal3){
333                         rps.pwm1=0;
334                         rps.pwm2=-duty;
335                         rps.pwm3=0;
336                 }
337         }
338 }
339 /**
340  * \brief
341  * Computation of distance to index.
342  *
343  * K dispozici je 12-bit index, to umoznuje ulozit 4096 ruznych bodu
344  * Je nutne vyjadrit 1999 bodu proti i posmeru h.r. od indexu -
345  *      to je 3999 bodu
346  *      =>12 bitu je dostacujicich, pokud nikdy nedojde ke ztrate
347  *              signalu indexu
348  */
349 void comIndDist(){
350         uint16_t pos = 0x0FFF & data.pozice_raw;
351         uint16_t dist;
352         uint16_t index = data.index_position;
353
354         if (index<1999){                /*index e<0,1998> */
355                 if (pos<index){                 /*pozice e<0,index-1> */
356                         /*proti smeru h.r. od indexu*/
357                         dist=pos+2000-index;
358                 }else if (pos<=index+1999){     /*pozice e<index,index+1999> */
359                         /*po smeru h.r. od indexu*/
360                         dist=pos-index;
361                 }else if (pos<index+2096){      /*pozice e<index+2000,index+2095> */
362                         goto index_lost;
363                 }else{                          /*pozice e<index+2096,4095> */
364                         /*proti smeru h.r. od indexu - podtecena pozice*/
365                         dist=pos-index-2096;
366                 }
367         }else if (index<=2096){         /*index e<1999,2096>*/
368                 if (pos<index-1999){            /*pozice e<0,index-2000> */
369                         goto index_lost;
370                 }else if (pos<index){           /*pozice e<index-1999,index-1> */
371                         /*proti smeru h.r. od indexu*/
372                         dist=pos+2000-index;
373                 }else if (pos<=index+1999){     /*pozice e<index,index+1999> */
374                         /*po smeru h.r. od indexu*/
375                         dist=pos-index;
376                 }else {                         /*pozice e<index+2000,4095> */
377                         goto index_lost;
378                 }
379         }else{                          /*index e<2097,4095> */
380                 if (pos<=index-2097){           /*pozice e<0,index-2097> */
381                         /*po smeru h.r. od indexu - pretecena pozice*/
382                         dist=4096+pos-index;
383                 }else if (pos<index-1999){      /*pozice e<index-2096,index-2000> */
384                         goto index_lost;
385                 }else if (pos<index){           /*pozice e<index-1999,index-1> */
386                         /*proti smeru h.r. od indexu*/
387                         dist=pos+2000-index;
388                 }else{                          /*pozice e<index,4095> */
389                         /*po smeru h.r. od indexu*/
390                         dist=pos-index;
391                 }
392         }
393
394         rps.index_dist = dist;
395         return;
396
397         index_lost:
398                 rps.index_ok=0;
399                 return;
400 }
401 /*
402  * \brief
403  * Very simple PID regulator.
404  * Now only with P-part so that the error doesnt go to zero.
405  * TODO: add anti-wind up and I and D parts
406  */
407 inline void pid(){
408         int duty_tmp;
409         duty_tmp = PID_P*(rps.desired_pos - (int32_t)data.pozice);
410         if (duty_tmp>MAX_DUTY){
411                 rps.duty=MAX_DUTY;
412         }else if (duty_tmp<-MAX_DUTY){
413                 rps.duty=-MAX_DUTY;
414         }else{
415                 rps.duty = duty_tmp;
416         }
417 }
418 /*
419  * \brief
420  * Feedback loop.
421  */
422 void * read_data(void* param){
423         int i;
424         struct rpi_in pocatek;
425         struct timespec t;
426         int interval = 1000000; /* 1ms ~ 1kHz*/
427         uint8_t tx[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;
428         char first=1;
429         uint16_t last_index;                            /*we have index up-to date*/
430         pocatek = spi_read(tx);
431         clock_gettime(CLOCK_MONOTONIC ,&t);
432         /* start after one second */
433         t.tv_sec++;
434                 while(1){
435                         /* wait until next shot */
436                         clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t, NULL);
437                         sem_wait(&rps.thd_par_sem);             /*---take semaphore---*/
438                         prepare_tx(tx);                 /*save the data to send*/
439                         data = spi_read(tx);            /*exchange data*/
440                         /*subtract initiate postion */
441                         rps.tf_count++;
442                         substractOffset(&data,&pocatek);
443                         comIndDist();
444                         if (!rps.index_ok){
445                                 if (first){
446                                         last_index=data.index_position;
447                                         first=0;
448                                 }else if (last_index!=data.index_position){
449                                         rps.index_ok=1;
450                                 }
451                         }
452                         pid();
453                         if (rps.index_ok && rps.commutate){
454                                 /*simple_ind_dist_commutator(rps.duty);*/
455                                 sin_commutator(rps.duty);
456                         }else if(!rps.index_ok && rps.commutate){
457                                 simple_hall_commutator(rps.duty);
458                         }
459                         sem_post(&rps.thd_par_sem);             /*--post semaphore---*/
460
461                         /* calculate next shot */
462                         t.tv_nsec += interval;
463
464                         while (t.tv_nsec >= NSEC_PER_SEC) {
465                                 t.tv_nsec -= NSEC_PER_SEC;
466                                 t.tv_sec++;
467                         }
468
469                 }
470 }
471
472
473
474 /**
475  * \brief Main function.
476  */
477
478 int main(){
479         pthread_t base_thread_id;
480         clk_init();             /* inicializace gpio hodin */
481         spi_init();             /* iniicializace spi*/
482
483         /*semafor pro detekci zpracovani parametru vlaken*/
484         sem_init(&rps.thd_par_sem,THREAD_SHARED,INIT_VALUE);
485         setup_environment();
486
487         base_thread_id=pthread_self();
488
489         /*main control loop*/
490         create_rt_task(&base_thread_id,PRIOR_HIGH,read_data,NULL);
491
492         /*monitor of current state*/
493         create_rt_task(&base_thread_id,PRIOR_LOW,pos_monitor,NULL);
494
495         /*wait for commands*/
496         poll_cmd(&rps);
497
498         return 0;
499 }