8 #include <can/canmsg.h>
10 #include <can/lpcan_vca.h>
15 #include "constants.h"
17 #define adc_setup(src,clkdiv,on,start,edge) \
18 (((src)&0x7) | ((((clkdiv)-1)&0xff)<<8) | ((!(!(on)))<<21) | \
19 (((start)&0x7)<<24) | ((!(!(edge)))<<27))
21 /********* Variables **********/
23 /* A/D ISR <=> controller function variables */
24 volatile uint8_t timer_count
= 0;
25 volatile uint32_t adc_i
= 0;
26 volatile uint32_t adc_x
= 0;
27 volatile int8_t current_negative
= 0;
31 /* CAN Bus Timing register value */
33 /* Own message for current position signalling */
34 canmsg_t tx_msg
= {.flags
= 0, .length
= 8};
35 /* Recieved message */
38 /* Command message ID and index */
39 uint16_t cmd_msg_id
= CAN_UNDEF_ID
, cmd_msg_ndx
= 0;
41 /* Command value, current position */
42 volatile int16_t rx_cmd_value
= CTRL_OFF
;
43 volatile uint8_t tx_request
= 0;
46 volatile int16_t control_w
= 0; /* reference current (*12) */
47 volatile int32_t control_y
; /* measured current (*12*80) */
48 volatile int32_t control_x
; /* measured position (*80) */
49 volatile int32_t control_u
; /* applied PWM (*80) */
50 volatile int8_t control_on
= 0; /* switches H-bridge on/off */
53 uint8_t DBG_clk_seq
= 0;
57 void adc_irq() __attribute__((interrupt
));
60 /* zapni MAT0.1 na noze AIN0 */
61 T0PR
= 0; //prescale - 1
62 T0MR1
= PWM_PERIOD
/ADC_OVERSAMP
-1; //period
63 T0MCR
= 0x2<<3; /* counter reset on match1 */
64 T0EMR
= 0x1<<6 | 0x2; /* MAT0.1 set low on match */
65 T0CCR
= 0x0; /* no capture */
66 T0TCR
|= 0x1; /* go! */
68 sync_pwm_timer((uint32_t*)&T0TC
);
71 void set_irq_handler(uint8_t source
, uint8_t irq_vect
, void (*handler
)()) {
72 /* set interrupt vector */
73 ((uint32_t*)&VICVectAddr0
)[irq_vect
] = (uint32_t)handler
;
74 ((uint32_t*)&VICVectCntl0
)[irq_vect
] = 0x20 | source
;
75 /* enable interrupt */
76 VICIntEnable
= 1<<source
;
79 inline void adc_init() {
80 ADCR
= adc_setup(1<<ADCIN_CURRENT
, 14, 1, 0x4 /*MAT0.1*/, 1 /*FALL! edge*/);
84 inline int32_t add_sat(int32_t big
, int32_t small
, int32_t min
, int32_t max
) {
85 if (big
>= max
- small
)
87 if (big
<= min
- small
)
93 int32_t pi_ctrl(int16_t w
, int16_t y
) {
98 p
= e
; p
*= (int32_t)CTRL_PI_K
;
99 u
= add_sat(p
, s
, -CTRL_INT_MAX
, CTRL_INT_MAX
);
100 q
= e
; q
*= (int32_t)(CTRL_PI_K
-CTRL_PI_Kn
);
101 s
= add_sat(q
, s
, -CTRL_INT_MAX
-p
, CTRL_INT_MAX
-p
);
103 return u
/CTRL_INT_DIV
;
107 int32_t ctrl_ma_filter(int32_t *mem
, uint8_t *idx
, int32_t val
) {
108 int32_t diff
= val
- mem
[*idx
];
110 if (++*idx
== CAN_OVERSAMP
)
116 void control(int32_t ad_i
, int16_t ad_x
) {
117 static int32_t cy
= 0, cx
= 0, cu
= 0;
118 static int ma_y
[CAN_OVERSAMP
],
119 ma_x
[CAN_OVERSAMP
], ma_u
[CAN_OVERSAMP
];
120 static uint8_t idx_y
= 0, idx_x
= 0, idx_u
= 0;
123 u
= pi_ctrl(control_w
, ad_i
);
127 current_negative
= (u
< 0);
129 cy
+= ctrl_ma_filter(ma_y
, &idx_y
, ad_i
);
130 cx
+= ctrl_ma_filter(ma_x
, &idx_x
, ad_x
);
131 cu
+= ctrl_ma_filter(ma_u
, &idx_u
, u
);
139 static uint8_t ma_idx
= 0;
140 static int32_t ma_val
[ADC_MA_LEN
];
141 static int8_t negative
= 0;
146 /* read & clear irq flag */
150 T0EMR
= 0x1<<6 | 0x2; /* must be here due to ADC.5 erratum */
152 if ((last
= (timer_count
== ADC_OVERSAMP
-1))) {
153 /* last sample before PWM period end */
154 /* twice -- ADC.2 erratum workaround */
155 ADCR
= adc_setup(1<<ADCIN_POS
, 14, 1, 0x0 /* now! */, 1);
156 ADCR
= adc_setup(1<<ADCIN_POS
, 14, 1, 0x1 /* now! */, 1);
163 /* shift value through MA filter */
164 ma_diff
= ad
- ma_val
[ma_idx
];
166 if (++ma_idx
== ADC_MA_LEN
)
168 /* MA filter output (should be atomic): */
172 while (((ad
= ADDR
)&0x80000000) == 0);
173 adc_x
= (ad
>>6)&0x3ff;
174 /* twice -- ADC.2 erratum workaround */
175 ADCR
= adc_setup(1<<ADCIN_CURRENT
, 14, 1, 0x0 /*MAT0.1*/, 1);
176 ADCR
= adc_setup(1<<ADCIN_CURRENT
, 14, 1, 0x4 /*MAT0.1*/, 1);
178 negative
= current_negative
;
183 /* int acknowledge */
191 /*message from CAN clock*/
193 if ((uint16_t)rx_cmd_value
!= CTRL_OFF
) {
194 control_w
= rx_cmd_value
;
196 DBG_clk_seq
= rx_msg
.data
[0];
200 /*config message from control computer*/
202 /*is this message for this motor?*/
203 if ((rx_msg
.data
[0] | ((rx_msg
.data
[1])<<8)) == MOTOR_ID
) {
204 /*ID of control message for this motor*/
205 cmd_msg_id
= rx_msg
.data
[2] | ((rx_msg
.data
[3])<<8);
206 /*part of control message*/
207 cmd_msg_ndx
= rx_msg
.data
[4] | ((rx_msg
.data
[5])<<8);
211 /*control message for this motor*/
212 if (rx_msg
.id
== cmd_msg_id
) {
214 rx_cmd_value
= rx_msg
.data
[cmd_msg_ndx
] | ((rx_msg
.data
[cmd_msg_ndx
+1])<<8);
216 if ((uint16_t)rx_cmd_value
== CTRL_OFF
) {
227 /* x: 16b, y: 24b, u: 24b */
228 uint16_t control_2
= (uint16_t)(control_x
/2);
229 tx_msg
.data
[0] = *((uint8_t*)&control_2
);
230 tx_msg
.data
[1] = *((uint8_t*)&control_2
+ 1);
231 tx_msg
.data
[2] = *((uint8_t*)&control_y
);
232 tx_msg
.data
[3] = *((uint8_t*)&control_y
+ 1);
233 tx_msg
.data
[4] = *((uint8_t*)&control_y
+ 2);
234 tx_msg
.data
[5] = *((uint8_t*)&control_u
);
235 tx_msg
.data
[6] = *((uint8_t*)&control_u
+ 1);
236 tx_msg
.data
[7] = *((uint8_t*)&control_u
+ 2);
238 /* tx_msg.data[2] = *((uint8_t*)&cmd_msg_id+1);
239 tx_msg.data[3] = *((uint8_t*)&cmd_msg_id);
240 tx_msg.data[4] = *((uint8_t*)&cmd_msg_ndx+1);
241 tx_msg.data[5] = *((uint8_t*)&cmd_msg_ndx);
242 tx_msg.data[6] = *((uint8_t*)&rx_cmd_value+1);
243 tx_msg.data[7] = *((uint8_t*)&rx_cmd_value);*/
244 /* send message and do NOT wait*/
245 vca_send_msg_seq(can
,&tx_msg
,1);
251 void sys_pll_init(uint32_t f_cclk
, uint32_t f_osc
) {
252 uint32_t m
, p
, p_max
;
256 /* turn memory acceleration off */
259 /* compute PLL divider and internal osc multiplier */
261 p_max
= 160000000/f_cclk
;
262 for (p
= 3; ((1<<p
) > p_max
) && (p
> 0); p
= p
>>1);
264 PLLCFG
= (p
<<5) | ((m
-1)&0x1f);
266 PLLFEED
= 0xaa; PLLFEED
= 0x55;
268 while (!(PLLSTAT
& (1<<10)));
269 /* connect to clock */
271 PLLFEED
= 0xaa; PLLFEED
= 0x55;
273 /* turn memory acceleration on */
274 MAMTIM
= f_cclk
/20000000;
283 /* switch the CAN off due to clock change */
285 /* boost clock to 60MHz */
286 sys_pll_init(60000000, 10000000);
287 /* peripheral clock = CPU clock (60MHz) */
288 VPBDIV
= 1; /*!!! Pozor defaultne VPBDIV = 2 !!!*/
290 /* init Vector Interrupt Controller */
291 VICIntEnClr
= 0xFFFFFFFF;
292 VICIntSelect
= 0x00000000;
297 /*Nyni plne funkcni na SpejblARM desce s 10MHz xtalem*/
298 /*Zaroven funguje na euroboti desce s 10MHz xtalem*/
299 /*Zde 60MHz kvuli pll*/
300 lpcan_btr(&btr
, 1000000 /*Bd*/, 60000000, 0/*SJW*/, 70/*%sampl.pt.*/, 0/*SAM*/);
301 lpc_vca_open_handle(&can
, 0/*device*/, 1/*flags*/, btr
, 10, 11, 12);
303 tx_msg
.id
= MOTOR_ID
;
306 // hbridge_set((PWM_PERIOD/ADC_OVERSAMP-2*PWM_DEAD));
308 set_irq_handler(18 /*ADC*/, 13, adc_irq
);
314 if(vca_rec_msg_seq(can
,&rx_msg
,1)<1){
315 if (timer_count
== 1)
316 control(adc_i
, adc_x
);