3 * \author Martin Prudek
4 * \brief Mainfile pro pmsm control.
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*/
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"
27 #define PRUM_PROUD 2061
28 #define PRUM_SOUC 6183
36 #define THREAD_SHARED 0
37 #define INIT_VALUE 1 /*init value for semaphor*/
40 #define NSEC_PER_SEC (1000000000) /* The number of nsecs per sec. */
44 struct rpi_state rps={
48 .pwm1=0,.pwm2=0, .pwm3=0,
49 .pwm1=0, .t_pwm2=0, .t_pwm3=0,
51 .duty=0, /* duty cycle of pwm */
52 .index_dist=0, /* distance to index position */
54 .tf_count=0, /*number of transfer*/
55 .desired_pos=0 /* desired position */
59 * \brief Initilizes GPCLK.
63 initialise(); /*namapovani gpio*/
64 initClock(PLLD_500_MHZ, 10, 0);
65 gpioSetMode(4, FSEL_ALT0);
69 * \brief Terminates GPCLK.
72 inline void clk_disable(){
77 * \brief Signal handler pro Ctrl+C
82 /*muzeme zavrit semafor*/
83 sem_destroy(&rps.thd_par_sem);
84 printf("\nprogram bezpecne ukoncen\n");
87 void substractOffset(struct rpi_in* data, struct rpi_in* offset){
88 data->pozice_raw=data->pozice;
89 data->pozice-=offset->pozice;
93 * pocita procentualni odchylku od prumerneho proudu
95 float diff_p(float value){
96 return ((float)value-PRUM_PROUD)*100/PRUM_PROUD;
99 * pocita procentualni odchylku od prumerneho souctu proudu
101 float diff_s(float value){
102 return ((float)value-PRUM_SOUC)*100/PRUM_SOUC;
105 void prepare_tx(uint8_t * tx){
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
122 * bit 94 - enable PWM1
123 * bit 93 - enable PWM2
124 * bit 92 - enable PWM3
133 * bits 47 .. 32 - match PWM1
134 * bits 31 .. 16 - match PWM2
135 * bits 15 .. 0 - match PWM3
141 /* keep the 11-bit cap*/
143 if (rps.pwm1>2047) rps.pwm1=2047;
144 if (rps.pwm2>2047) rps.pwm2=2047;
145 if (rps.pwm3>2047) rps.pwm3=2047;
147 tx[0]=rps.test; /*bit 94 - enable PWM1*/
149 /*now we have to switch the bytes due to endianess */
150 /* ARMv6 & ARMv7 instructions are little endian */
152 tx[10]=((uint8_t*)&rps.pwm1)[1]; /*MSB*/
153 tx[11]=((uint8_t*)&rps.pwm1)[0]; /*LSB*/
156 tx[12]=((uint8_t*)&rps.pwm2)[1]; /*MSB*/
157 tx[13]=((uint8_t*)&rps.pwm2)[0]; /*LSB*/
160 tx[14]=((uint8_t*)&rps.pwm3)[1]; /*MSB*/
161 tx[15]=((uint8_t*)&rps.pwm3)[0]; /*LSB*/
166 * Funkce pravidelne vypisuje posledni zjistenou pozici lokalniho motoru
168 void * pos_monitor(void* param){
171 usleep(1000000); /*1 Hz*/
177 * Multiplication of 11 bit
178 * Zaporne vysledky prvede na nulu.
180 inline uint16_t mult_cap(int32_t s,int d){
184 /* multiplicate as if maximum sinus value was unity */
185 res+=(!(s & 0x10000000))*(((1 << j) & s)>>j)*(d>>(10-j));
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
200 /*aby prictene uhly mohla byt kulata cisla, musime index posunout*/
202 /*use it as cyclic 32-bit logic*/
204 if (duty>=0){ /*clockwise rotation*/
206 sin = pxmc_sin_fixed_inline(pos+DEGREE_240,10); /*10+1 bity*/ /*-120*/
209 rps.pwm1=(uint16_t)pwm;
212 sin = pxmc_sin_fixed_inline(pos+DEGREE_120,10); /*10+1 bity*/ /*-240*/
215 rps.pwm2=(uint16_t)pwm;
218 sin = pxmc_sin_fixed_inline(pos,10); /*10+1 bity*/
221 rps.pwm3=(uint16_t)pwm;
226 sin = pxmc_sin_fixed_inline(pos+DEGREE_60,10); /*10+1 bity*/ /*-300*/
229 rps.pwm1=(uint16_t)pwm;
232 sin = pxmc_sin_fixed_inline(pos+DEGREE_300,10); /*10+1 bity*/ /*-60-*/
235 rps.pwm2=(uint16_t)pwm;
238 sin = pxmc_sin_fixed_inline(pos+DEGREE_180,10); /*10+1 bity*/ /*-180*/
241 rps.pwm3=(uint16_t)pwm;
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,
252 void simple_ind_dist_commutator(int duty){
253 if (duty>=0){ /* clockwise - so that position increase */
255 if ((rps.index_dist>=45 && rps.index_dist<=373) ||
256 (rps.index_dist>=1048 && rps.index_dist<=1377)){
261 }else if ((rps.index_dist>=373 && rps.index_dist<=711) ||
262 (rps.index_dist>=1377 && rps.index_dist<=1711)){
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)){
274 }else{ /*counter-clockwise - position decrease */
276 if ((rps.index_dist>=544 && rps.index_dist<=881) ||
277 (rps.index_dist>=1544 && rps.index_dist<=1878)){
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)){
289 }else if ((rps.index_dist>=211 && rps.index_dist<=544) ||
290 (rps.index_dist>=1210 && rps.index_dist<=1544)){
299 * Test function to be placed in controll loop.
300 * Switches PWM's at point where they produce same force
302 inline void simple_hall_commutator(int duty){
303 if (duty>=0){ /* clockwise - so that position increase */
305 if (data.hal2 && !data.hal3){
310 }else if (data.hal1 && !data.hal2){
315 }else if (!data.hal1 && data.hal3){
320 }else{ /*counter-clockwise - position decrease */
322 if (!data.hal2 && data.hal3){
327 }else if (!data.hal1 && data.hal2){
332 }else if (data.hal1 && !data.hal3){
341 * Computation of distance to index.
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 -
346 * =>12 bitu je dostacujicich, pokud nikdy nedojde ke ztrate
350 uint16_t pos = 0x0FFF & data.pozice_raw;
352 uint16_t index = data.index_position;
354 if (index<1999){ /*index e<0,1998> */
355 if (pos<index){ /*pozice e<0,index-1> */
356 /*proti smeru h.r. od indexu*/
358 }else if (pos<=index+1999){ /*pozice e<index,index+1999> */
359 /*po smeru h.r. od indexu*/
361 }else if (pos<index+2096){ /*pozice e<index+2000,index+2095> */
363 }else{ /*pozice e<index+2096,4095> */
364 /*proti smeru h.r. od indexu - podtecena pozice*/
367 }else if (index<=2096){ /*index e<1999,2096>*/
368 if (pos<index-1999){ /*pozice e<0,index-2000> */
370 }else if (pos<index){ /*pozice e<index-1999,index-1> */
371 /*proti smeru h.r. od indexu*/
373 }else if (pos<=index+1999){ /*pozice e<index,index+1999> */
374 /*po smeru h.r. od indexu*/
376 }else { /*pozice e<index+2000,4095> */
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*/
383 }else if (pos<index-1999){ /*pozice e<index-2096,index-2000> */
385 }else if (pos<index){ /*pozice e<index-1999,index-1> */
386 /*proti smeru h.r. od indexu*/
388 }else{ /*pozice e<index,4095> */
389 /*po smeru h.r. od indexu*/
394 rps.index_dist = dist;
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
409 duty_tmp = PID_P*(rps.desired_pos - (int32_t)data.pozice);
410 if (duty_tmp>MAX_DUTY){
412 }else if (duty_tmp<-MAX_DUTY){
422 void * read_data(void* param){
424 struct rpi_in pocatek;
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} ;
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 */
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 */
442 substractOffset(&data,&pocatek);
446 last_index=data.index_position;
448 }else if (last_index!=data.index_position){
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);
459 sem_post(&rps.thd_par_sem); /*--post semaphore---*/
461 /* calculate next shot */
462 t.tv_nsec += interval;
464 while (t.tv_nsec >= NSEC_PER_SEC) {
465 t.tv_nsec -= NSEC_PER_SEC;
475 * \brief Main function.
479 pthread_t base_thread_id;
480 clk_init(); /* inicializace gpio hodin */
481 spi_init(); /* iniicializace spi*/
483 /*semafor pro detekci zpracovani parametru vlaken*/
484 sem_init(&rps.thd_par_sem,THREAD_SHARED,INIT_VALUE);
487 base_thread_id=pthread_self();
489 /*main control loop*/
490 create_rt_task(&base_thread_id,PRIOR_HIGH,read_data,NULL);
492 /*monitor of current state*/
493 create_rt_task(&base_thread_id,PRIOR_LOW,pos_monitor,NULL);
495 /*wait for commands*/