]> rtime.felk.cvut.cz Git - fpga/rpi-motor-control.git/blob - pmsm-control/test_sw/main_pmsm.c
State variables moved to new structure 'rpi_state'. Added semaphore to controll acces...
[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
19 #include "rpin.h"       /*gpclk*/
20 #include "rp_spi.h"     /*spi*/
21 #include "misc.h"       /*structure for priorities*/
22
23
24 #define PRUM_PROUD      2061
25 #define PRUM_SOUC       6183
26
27 #define PRIOR_KERN      50
28 #define PRIOR_HIGH      49
29 #define PRIOR_LOW       20
30
31 #define THREAD_SHARED   0
32 #define INIT_VALUE      0       /*init value for semaphor*/
33
34 struct sigaction sighnd; /*struktura pro signal handler*/
35 struct rpi_in data;
36 struct rpi_state{
37         uint8_t test;
38         uint16_t pwm1, pwm2, pwm3;
39         char commutate;
40         int simple_hall_duty;
41         uint16_t index_dist;            /* distance to index position */
42         unsigned char index_ok;
43         uint32_t tf_count;              /*number of transfer*/
44 }rps;
45
46
47 /**
48  * \brief Initilizes GPCLK.
49  */
50 int clk_init()
51 {
52         initialise(); /*namapovani gpio*/
53         initClock(PLLD_500_MHZ, 10, 0);
54         gpioSetMode(4, FSEL_ALT0);
55         return 0;
56 }
57 /*
58  * \brief Terminates GPCLK.
59  */
60
61 inline void clk_disable(){
62         termClock(0);
63 }
64
65 /**
66  * \brief Signal handler pro Ctrl+C
67  */
68 void sighnd_fnc(){
69         spi_disable();
70         clk_disable();
71         /*muzeme zavrit semafor*/
72         sem_destroy(&thd_par_sem);
73         printf("\nprogram bezpecne ukoncen\n");
74         exit(0);
75 }
76
77 void substractOffset(struct rpi_in* data, struct rpi_in* offset){
78         data->pozice_raw=data->pozice;
79         data->pozice-=offset->pozice;
80         return;
81 }
82 /*
83  * pocita procentualni odchylku od prumerneho proudu
84  */
85 float diff_p(float value){
86         return ((float)value-PRUM_PROUD)*100/PRUM_PROUD;
87 }
88 /*
89  * pocita procentualni odchylku od prumerneho souctu proudu
90  */
91 float diff_s(float value){
92         return ((float)value-PRUM_SOUC)*100/PRUM_SOUC;
93 }
94 /*
95  * tiskne potrebna data
96  */
97 void printData(){
98         struct rpi_in data_p;
99         struct rpi_state s;     /*state*/
100         float cur0, cur1, cur2;
101         int i;
102         /* copy the data */
103         sem_wait(&thd_par_sem);
104         data_p = data;
105         s=rps;
106         sem_post(&thd_par_sem);
107
108         if (data_p.adc_m_count){
109                 cur0=data_p.ch0/data_p.adc_m_count;
110                 cur1=data_p.ch1/data_p.adc_m_count;
111                 cur2=data_p.ch2/data_p.adc_m_count;
112         }
113         for (i = 0; i < 16; i++) {
114                         if (!(i % 6))
115                                 puts("");
116                         printf("%.2X ", data_p.debug_rx[i]);
117         }
118         puts("");
119         printf("\npozice=%d\n",(int32_t)data_p.pozice);
120         printf("transfer count=%u\n",s.tf_count);
121         printf("raw_pozice=%d\n",(int32_t)data_p.pozice_raw);
122         printf("raw_pozice last12=%u\n",(data_p.pozice_raw&0x0FFF));
123         printf("index position=%u\n",data_p.index_position);
124         printf("distance to index=%u\n",s.index_dist);
125         printf("hal1=%d, hal2=%d, hal3=%d\n",data_p.hal1,data_p.hal2,data_p.hal3);
126         printf("en1=%d, en2=%d, en3=%d (Last sent)\n",!!(0x40&s.test),!!(0x20&s.test),!!(0x10&s.test));
127         printf("shdn1=%d, shdn2=%d, shdn3=%d (L.s.)\n",!!(0x08&s.test),!!(0x04&s.test),!!(0x02&s.test));
128         printf("PWM1=%u(L.s.)\n",s.pwm1);
129         printf("PWM2=%u(L.s.)\n",s.pwm2);
130         printf("PWM3=%u(L.s.)\n",s.pwm3);
131         printf("Pocet namerenych proudu=%u\n",data_p.adc_m_count);
132         printf("(pwm1) (ch1)=%d (avg=%4.0f) (%2.2f%%)\n",data_p.ch1,cur1,diff_p(cur1));
133         printf("(pwm2) (ch2)=%d (avg=%4.0f)(%2.2f%%)\n",data_p.ch2,cur2,diff_p(cur2));
134         printf("(pwm3) (ch0)=%d (avg=%4.0f)(%2.2f%%)\n",data_p.ch0,cur0,diff_p(cur0));
135         printf("soucet prumeru=%5.0f (%2.2f%%)\n",cur0+cur1+cur2,diff_s(cur0+cur1+cur2));
136         printf("duty=%d\n",s.simple_hall_duty);
137         if (s.index_ok) printf("index ok\n");
138         if (s.commutate) printf("commutation in progress\n");
139 }
140 void prepare_tx(uint8_t * tx){
141
142         /*Data format:
143          * tx[4] - bity 95 downto 88 - bits that are sent first
144          * tx[5] - bity 87 downto 80
145          * tx[6] - bity 79 downto 72
146          * tx[7] - bity 71 downto 64
147          * tx[8] - bity 63 downto 56
148          * tx[9] - bity 55 downto 48
149          * tx[10] - bity 47 downto 40
150          * tx[11] - bity 39 downto 32
151          * tx[12] - bity 31 downto 24
152          * tx[13] - bity 23 downto 16
153          * tx[14] - bity 15 downto 8
154          * tx[15] - bity 7 downto 0
155          *
156          * bit 95 - ADC reset
157          * bit 94 - enable PWM1
158          * bit 93 - enable PWM2
159          * bit 92 - enable PWM3
160          * bit 91 - shutdown1
161          * bit 90 - shutdown2
162          * bit 89 - shutdown3
163          *      .
164          *      .
165          *      .
166          * bits 66 .. 56 - match PWM1
167          * bits 55 .. 45 - match PWM2
168          * bit 11,12 - Unused
169          * bits 42 .. 32  - match PWM3
170          */
171
172
173         uint16_t tmp;
174
175         /* keep the cap*/
176         if (rps.pwm1>2047) rps.pwm1=2047;
177         if (rps.pwm2>2047) rps.pwm2=2047;
178         if (rps.pwm3>2047) rps.pwm3=2047;
179
180         tx[0]=rps.test; /*bit 94 - enable PWM1*/
181
182         /*pwm1*/
183         tx[7]=(tx[7] & 0xF8) | (0x07 & ((uint8_t*)&rps.pwm1)[1]); /*MSB*/
184         tx[8]=((uint8_t*)&rps.pwm1)[0]; /*LSB*/
185
186         /*pwm2*/
187         tmp=rps.pwm2;
188         tmp<<=5;
189         tx[9]=((uint8_t*)&tmp)[1]; /*MSB*/
190         tx[10]=(tx[10] & 0x1F) | (0xE0 & ((uint8_t*)&tmp)[0]); /*LSB*/
191
192         /*pwm3*/
193         tx[10]=(tx[10] & 0xF8) | (0x07 & ((uint8_t*)&rps.pwm3)[1]); /*MSB*/
194         tx[11]=((uint8_t*)&rps.pwm3)[0]; /*LSB*/
195
196
197 }
198 /**
199  * Funkce pravidelne vypisuje posledni zjistenou pozici lokalniho motoru
200  */
201 void * pos_monitor(void* param){
202         set_priority(param);            /*set priority*/
203         while(1){
204                 printData();
205                 usleep(1000000);        /*1 Hz*/
206         }
207         return (void*)0;
208 }
209 /*
210  * \brief
211  * Test function to be placed in controll loop.
212  * Switches PWM's at point where they produce same force
213  */
214 inline void simple_hall_commutator(struct rpi_in data, int duty){
215         if (duty>=0){ /* clockwise - so that position increase */
216                 /* pwm3 */
217                 if (data.hal2 && !data.hal3){
218                         rps.pwm1=0;
219                         rps.pwm2=0;
220                         rps.pwm3=duty;
221                         /* pwm1 */
222                 }else if (data.hal1 && !data.hal2){
223                         rps.pwm1=duty;
224                         rps.pwm2=0;
225                         rps.pwm3=0;
226                         /* pwm2 */
227                 }else if (!data.hal1 && data.hal3){
228                         rps.pwm1=0;
229                         rps.pwm2=duty;
230                         rps.pwm3=0;
231                 }
232         }else{  /*counter-clockwise - position decrease */
233                 /* pwm3 */
234                 if (!data.hal2 && data.hal3){
235                         rps.pwm1=0;
236                         rps.pwm2=0;
237                         rps.pwm3=-duty;
238                         /* pwm1 */
239                 }else if (!data.hal1 && data.hal2){
240                         rps.pwm1=-duty;
241                         rps.pwm2=0;
242                         rps.pwm3=0;
243                         /* pwm2 */
244                 }else if (data.hal1 && !data.hal3){
245                         rps.pwm1=0;
246                         rps.pwm2=-duty;
247                         rps.pwm3=0;
248                 }
249         }
250 }
251 /**
252  * Funkce pravidelne vycita data z motoru
253  */
254 inline void comIndDist(){
255         rps.index_dist=0x0FFF & (data.pozice_raw - data.index_position);
256         /*
257          * if distance is bigger than 2047, the distance underflown
258          * -> if 12th bit is set, substract 2096
259          */
260         rps.index_dist-=((rps.index_dist & 0x0800)>>11)*2096;
261 }
262 void * read_data(void* param){
263         int i;
264         struct rpi_in pocatek;
265         uint8_t tx[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;
266         char first=1;
267         uint16_t last_index;                            /*we have index up-to date*/
268         set_priority(param);                            /*set priority*/
269         pocatek = spi_read(tx);
270                 while(1){
271                         prepare_tx(tx);                 /*save the data to send*/
272                         sem_wait(&thd_par_sem);         /*---take semaphore---*/
273                         data = spi_read(tx);            /*exchange data*/
274                         /*subtract initiate postion */
275                         rps.tf_count++;
276                         substractOffset(&data,&pocatek);
277                         comIndDist();
278                         if (!rps.index_ok){
279                                 if (first){
280                                         last_index=data.index_position;
281                                         first=0;
282                                 }else if (last_index!=data.index_position){
283                                         rps.index_ok=1;
284                                 }
285                         }
286                         if (rps.index_ok && rps.commutate){
287                                 simple_hall_commutator(data,rps.simple_hall_duty);
288                         }else if(!rps.index_ok && rps.commutate){
289                                 simple_hall_commutator(data,rps.simple_hall_duty);
290                         }
291                         sem_post(&thd_par_sem);         /*--post semaphore---*/
292                         usleep(1000);                           /*1kHz*/
293                 }
294 }
295
296 /**
297  * \brief Main function.
298  */
299
300 int main(){
301         unsigned int tmp;
302
303         /*nastaveni priorit vlaken*/
304         struct thread_param tsp;
305         tsp.sch_policy = SCHED_FIFO;
306
307         /*nastaveni signalu pro vypnuti pomoci Ctrl+C*/
308         sighnd.sa_handler=&sighnd_fnc;
309         sigaction(SIGINT, &sighnd, NULL );
310
311         clk_init();             /* inicializace gpio hodin */
312         spi_init();             /* iniicializace spi*/
313
314         /*semafor pro detekci zpracovani parametru vlaken*/
315         sem_init(&thd_par_sem,THREAD_SHARED,INIT_VALUE);
316
317         /*vlakna*/
318         pthread_t tid;                  /*identifikator vlakna*/
319         pthread_attr_t attr;            /*atributy vlakna*/
320         pthread_attr_init(&attr);       /*inicializuj implicitni atributy*/
321
322
323
324         /*ziskavani dat z motoru*//*vysoka priorita*/
325         tsp.sch_prior = PRIOR_HIGH;
326         pthread_create(&tid, &attr, read_data, (void*)&tsp);
327
328         /*vypisovani lokalni pozice*//*nizka priorita*/
329         tsp.sch_prior = PRIOR_LOW;
330         sem_wait(&thd_par_sem);
331         pthread_create(&tid, &attr, pos_monitor, (void*)&tsp);
332
333
334
335         /*
336          * Note:
337          * pri pouziti scanf("%u",&simple_hall_duty); dochazelo
338          * k preukladani hodnot na promenne test. Dost divne.
339          */
340         while (1){
341                 scanf("%u",&tmp);
342                 printf("volba=%u\n",tmp);
343                 switch (tmp){
344                 case 1:
345                         scanf("%u",&tmp);
346                         sem_wait(&thd_par_sem);
347                         rps.pwm1=tmp&0xFFF;
348                         sem_post(&thd_par_sem);
349                         break;
350                 case 2:
351                         scanf("%u",&tmp);
352                         sem_wait(&thd_par_sem);
353                         rps.pwm2=tmp&0xFFF;
354                         sem_post(&thd_par_sem);
355                         break;
356                 case 3:
357                         scanf("%u",&tmp);
358                         sem_wait(&thd_par_sem);
359                         rps.pwm3=tmp&0xFFF;
360                         sem_post(&thd_par_sem);
361                         break;
362                 case 4:
363                         scanf("%u",&tmp);
364                         sem_wait(&thd_par_sem);
365                         rps.test=tmp&0xFF;
366                         sem_post(&thd_par_sem);
367                         break;
368                 case 5:
369                         sem_wait(&thd_par_sem);
370                         rps.commutate=!rps.commutate;
371                         /* switch off pwms at the end of commutation */
372                         rps.pwm1&=rps.commutate*0xFFFF;
373                         rps.pwm2&=rps.commutate*0xFFFF;
374                         rps.pwm3&=rps.commutate*0xFFFF;
375                         sem_post(&thd_par_sem);
376                         break;
377                 case 6:
378                         scanf("%d",&tmp);
379                         sem_wait(&thd_par_sem);
380                         rps.simple_hall_duty=tmp;
381                         sem_post(&thd_par_sem);
382                         break;
383
384                 default:
385                         break;
386                 }
387
388         }
389         return 0;
390 }