]> rtime.felk.cvut.cz Git - lincan.git/blob - embedded/app/usbcan/lpc17xx_can.c
Receiving CAN messages with usage of queue system from LinCAN - first version. Attemp...
[lincan.git] / embedded / app / usbcan / lpc17xx_can.c
1 #include "can/lpc17xx_can.h"
2
3 static void CAN_configPin();
4 static void CAN_setBusTiming(uint32_t baudrate);
5
6 extern struct canhardware_t *hardware_p;
7
8 extern volatile uint32_t cnt;
9 //---------------------------------------------------------------------------------
10 //---------------------------------------------------------------------------------
11
12 // interrupt handler
13 // for transmitting - irq when one message was transmitted (for check if another message is pending in can msg queue)
14 // for receiving - irq when message was received and is available in Receive buffer
15
16 void CAN_IRQHandler(){
17
18         uint32_t i;
19
20         i = CAN1ICR;
21
22
23         if(i & (CAN_ICR_TI1 | CAN_ICR_RI)){
24
25                 struct canchip_t *chip;
26                 chip = hardware_p->candevice[0]->chip[0];
27         
28                 lpc17xx_irq_handler(0, chip);
29
30         }
31         if(i & CAN_ICR_DOI){
32                         printf("Data overrun\n");
33                         CAN1CMR = CAN_CMR_CDO;
34         }
35         
36         
37         
38 }
39
40 //---------------------------------------------------------------------------------
41 //---------------------------------------------------------------------------------
42
43
44 // board can-lmc1 specific functions:
45
46 int can_lmc1_register(struct hwspecops_t *hwspecops){
47
48         hwspecops->request_io = can_lmc1_request_io;
49         hwspecops->reset = can_lmc1_reset;
50         hwspecops->init_hw_data = can_lmc1_init_hw_data;
51         hwspecops->init_chip_data = can_lmc1_init_chip_data;
52         hwspecops->init_obj_data = can_lmc1_init_obj_data;
53         hwspecops->write_register = can_lmc1_write_register;
54         hwspecops->read_register = can_lmc1_read_register;
55
56         return 0;
57 }
58
59 int can_lmc1_init_hw_data(struct candevice_t *candev){
60
61         candev->res_addr=0;
62         candev->nr_82527_chips=0;
63         candev->nr_sja1000_chips=0;
64         candev->nr_all_chips=1;
65         candev->flags |= 0;
66
67         return 0;
68 }
69
70 int can_lmc1_init_chip_data(struct candevice_t *candev, int chipnr){
71         
72         lpc17xx_fill_chipspecops(candev->chip[chipnr]);
73
74         candev->chip[chipnr]->flags|= CHIP_IRQ_CUSTOM;
75
76         candev->chip[chipnr]->chip_data=(void *)malloc(sizeof(struct can_lmc1_chip_data));
77         if (candev->chip[chipnr]->chip_data==NULL)
78                 return -ENOMEM;
79
80         return 0;
81 }
82
83 int can_lmc1_init_obj_data(struct canchip_t *chip, int objnr){
84         
85         //chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
86
87         return 0;
88 }
89
90 void can_lmc1_write_register(unsigned data, unsigned long address){
91
92         printf("UNSUPPORTED NOW\n");
93
94 }
95
96 unsigned can_lmc1_read_register(unsigned long address){
97
98         printf("UNSUPPORTED NOW\n");
99
100 }
101
102 int can_lmc1_request_io(struct candevice_t *candev)
103 {
104         return 0;
105 }
106
107 int can_lmc1_reset(struct candevice_t *candev)
108 {
109         return 0;
110 }
111
112
113 //---------------------------------------------------------------------------------
114 //---------------------------------------------------------------------------------
115
116
117 // lpc17xx can chip specific functions:
118
119
120 int lpc17xx_chip_config(struct canchip_t *chip){
121
122         CAN_init( (uint32_t) chip->baudrate);
123
124         return 0;
125 }
126
127 int lpc17xx_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
128                                                         struct canmsg_t *msg)
129 {
130         
131         CAN_send(msg);
132
133         return 0;
134 }
135
136 int lpc17xx_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
137                                                         struct canmsg_t *msg)
138 {
139         
140         // write transmission request
141         CAN1CMR = (CAN_CMR_TR | CAN_CMR_STB1); 
142
143         return 0;
144 }
145
146 int lpc17xx_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
147 {
148
149         can_preempt_disable();
150
151         can_msgobj_set_fl(obj,TX_PENDING);
152         can_msgobj_set_fl(obj,TX_REQUEST);
153
154         while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
155                 can_msgobj_clear_fl(obj,TX_REQUEST);
156
157
158                 if (CAN1SR & CAN_SR_TBS1){
159                         obj->tx_retry_cnt=0;
160                         lpc17xx_irq_write_handler(chip, obj);
161                 }
162
163                 can_msgobj_clear_fl(obj,TX_LOCK);
164                 if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
165
166         }
167
168         can_preempt_enable();
169
170         return 0;
171 }
172
173 int lpc17xx_irq_handler(int irq, struct canchip_t *chip)
174 {
175
176         struct msgobj_t *obj;   
177         obj = chip->msgobj[0];
178
179         
180         if(CAN1SR & CAN_SR_RBS) {
181                         lpc17xx_read(chip,obj);
182                         obj->ret = 0;
183         }
184         
185         
186         if ((can_msgobj_test_fl(obj,TX_PENDING)) || (can_msgobj_test_fl(obj,TX_REQUEST))) {
187                         
188                 can_msgobj_set_fl(obj,TX_REQUEST);
189
190                 while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)){
191
192                         obj->ret=0;
193                         can_msgobj_clear_fl(obj,TX_REQUEST);
194
195                         if (CAN1SR & CAN_SR_TBS1){
196                                 obj->tx_retry_cnt=0;
197                                 lpc17xx_irq_write_handler(chip, obj);
198                         }
199
200                         can_msgobj_clear_fl(obj,TX_LOCK);
201                         if(!can_msgobj_test_fl(obj,TX_REQUEST)) break;
202
203                 }       
204         }
205
206
207         return CANCHIP_IRQ_HANDLED;
208
209 }
210
211 void lpc17xx_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
212 {
213         int cmd;
214
215         if(obj->tx_slot){
216                 /* Do local transmitted message distribution if enabled */
217                 if (processlocal){
218                         /* fill CAN message timestamp */
219                         can_filltimestamp(&obj->tx_slot->msg.timestamp);
220
221                         obj->tx_slot->msg.flags |= MSG_LOCAL;
222                         canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
223                 }
224                 /* Free transmitted slot */
225                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
226                 obj->tx_slot=NULL;
227         }
228
229         can_msgobj_clear_fl(obj,TX_PENDING);
230         cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
231         if(cmd<0)
232                 return;
233         can_msgobj_set_fl(obj,TX_PENDING);
234
235         if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) {
236                 obj->ret = -1;
237                 canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP);
238                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
239                 obj->tx_slot=NULL;
240                 return;
241         }
242         if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) {
243                 obj->ret = -1;
244                 canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
245                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
246                 obj->tx_slot=NULL;
247                 return;
248         }
249
250 }
251
252 void lpc17xx_read(struct canchip_t *chip, struct msgobj_t *obj) {
253
254
255                 CAN_recv(&obj->rx_msg);
256                 
257                 // fill CAN message timestamp
258                 can_filltimestamp(&obj->rx_msg.timestamp);
259
260                 canque_filter_msg2edges(obj->qends, &obj->rx_msg);
261
262                 // release Receive buffer
263                 CAN1CMR = CAN_CMR_RRB;
264
265 }
266
267 int lpc17xx_fill_chipspecops(struct canchip_t *chip){
268
269         chip->max_objects=1;
270         chip->baudrate=1000000;
271
272         lpc17xx_register(chip->chipspecops);
273         return 0;
274 }
275
276 int lpc17xx_register(struct chipspecops_t *chipspecops){
277
278         CANMSG("initializing lpc17xx can chip operations\n");
279
280         chipspecops->attach_to_chip = lpc17xx_attach_to_chip;
281         chipspecops->pre_read_config = lpc17xx_pre_read_config;
282         chipspecops->chip_config = lpc17xx_chip_config;
283         chipspecops->pre_write_config = lpc17xx_pre_write_config;
284         chipspecops->send_msg = lpc17xx_send_msg;
285         chipspecops->wakeup_tx = lpc17xx_wakeup_tx;
286         chipspecops->irq_handler = lpc17xx_irq_handler;
287
288         return 0;       
289
290 }
291
292
293 int lpc17xx_attach_to_chip(struct canchip_t *chip){
294
295         return 0;
296 }
297
298 int lpc17xx_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj){
299
300         return 1;
301 }
302
303
304
305 //---------------------------------------------------------------------------------
306 //---------------------------------------------------------------------------------
307
308
309 static void CAN_configPin(){
310
311 //      CAN1 - select P0.0 as RD1. P0.1 as TD1
312
313         uint32_t pinsel0;
314         uint32_t pinmode0;
315         uint32_t pinmode_od0;
316         uint8_t pinsel0_val = 1;
317         uint8_t pinmode0_val = 0;
318         uint8_t pinmode_od0_val = 0;
319
320
321         pinsel0 = PINSEL0;
322         pinsel0 &= ~CAN1_RX_MASK;
323         pinsel0 &= ~CAN1_TX_MASK;
324         pinsel0 |= __val2mfld(CAN1_RX_MASK, pinsel0_val);
325         pinsel0 |= __val2mfld(CAN1_TX_MASK, pinsel0_val);
326         PINSEL0 = pinsel0;
327
328         pinmode0 = PINMODE0;
329         pinmode0 &= ~CAN1_RX_MASK;
330         pinmode0 &= ~CAN1_TX_MASK;
331         pinmode0 |= __val2mfld(CAN1_RX_MASK, pinmode0_val);
332         pinmode0 |= __val2mfld(CAN1_TX_MASK, pinmode0_val);
333         PINMODE0 = pinmode0;
334
335         pinmode_od0 = PINMODE_OD0;
336         if (pinmode_od0_val){
337                 pinmode_od0 |= CAN1_RX_BIT;
338                 pinmode_od0 |= CAN1_TX_BIT;
339         }
340         else{
341                 pinmode_od0 &= ~CAN1_RX_BIT;
342                 pinmode_od0 &= ~CAN1_TX_BIT;
343         }
344         PINMODE_OD0 = pinmode_od0;
345         
346
347 }
348
349 void CAN_recv(canmsg_t* msg){
350
351 /*
352         msg->id = ++cnt;
353         msg->data[0] = 0xAA;
354         msg->data[1] = 0xBB;
355         msg->length = 2;
356 */
357
358
359         uint32_t data;
360         uint32_t i;
361
362         // only for debug
363         cnt++;
364
365         // read data lenght
366         msg->length = ((CAN1RFS)>>16) & 0xF;
367
368         // read identifier
369         msg->id = CAN1RID;
370
371         // EXT frame
372         if(CAN1RFS & CAN_RFS_EXT)
373                 msg->flags |= MSG_EXT;
374         else
375                 msg->flags &= ~MSG_EXT;
376
377         
378         // RTR frame
379         if(CAN1RFS & CAN_RFS_RTR)
380                 msg->flags |= MSG_RTR;
381         else
382                 msg->flags &= ~MSG_RTR;
383
384
385         // read data
386         data = CAN1RDA;         
387         for(i=0; i<4; i++)
388                 msg->data[i] = (data>>(i*8)) & 0xFF;
389
390         data = CAN1RDB;
391         for(i=4; i<8; i++)
392                 msg->data[i] = (data>>((i-4)*8)) & 0xFF;
393
394 }
395
396 void CAN_send(canmsg_t* msg){
397
398         uint32_t data;
399         uint32_t i;
400
401         // check status of TB1
402         while (!(CAN1SR & CAN_SR_TBS1)){}
403         
404         CAN1TFI1 &= ~0x000F0000;
405         CAN1TFI1 |= (msg->length)<<16;
406
407         // EXT frame
408         if(msg->flags & MSG_EXT)
409                 CAN1TFI1 |= CAN_TFI1_EXT;
410         else
411                 CAN1TFI1 &= ~CAN_TFI1_EXT;
412                 
413         // RTR frame
414         if(msg->flags & MSG_RTR)
415                 CAN1TFI1 |= CAN_TFI1_RTR;
416         else
417                 CAN1TFI1 &= ~CAN_TFI1_RTR;
418
419         // write CAN ID
420         CAN1TID1 = msg->id;
421
422         // write first 4 data bytes
423
424         data=0;
425         for(i=0; i<4; i++)
426                 data |= (msg->data[i])<<(i*8);
427
428         CAN1TDA1 = data;
429
430         // write second 4 data bytes
431
432         data=0;
433         for(i=4; i<8; i++)
434                 data |= (msg->data[i])<<((i-4)*8);
435                 CAN1TDB1 = data;
436
437         // write transmission request
438         //CAN1CMR = 0x21;
439
440 }
441
442 void CAN_setBusTiming(uint32_t baudrate){
443
444         uint32_t PCLK_CAN;
445         uint32_t res;
446
447         uint8_t tq_numb; // number of time quantum
448         uint8_t TSEG1, TSEG2;
449         uint8_t BRP;
450         uint8_t SJW;
451         uint8_t SAM;
452         uint8_t div;
453
454         // 0 = the bus is sampled once
455         SAM = 0;
456
457         // the Synchronization Jump Width (this value plus one) 
458         SJW = 3;
459
460         // get clock divide for CAN1    
461         div = __mfld2val(PCLK_CAN1_MASK, PCLKSEL0);
462         switch(div){
463                 case 0:
464                         div = 4;
465                         break;
466                 case 1:
467                         div = 1;
468                         break;
469                 case 2:
470                         div = 2;
471                         break;
472                 case 3:
473                         // only for CAN, for other peripherials '11' value means div=8
474                         div = 6;
475                         break;
476         }
477
478
479         PCLK_CAN = system_frequency / div;
480
481         res = PCLK_CAN / baudrate;
482
483
484         // calculation of tq_numb - number of time quantum (must be in <8,25>)
485         // tq_numb = TSEG1 + TSEG2 + 3
486
487         for(tq_numb=25; tq_numb>=8; tq_numb--){
488                 
489                 if ((res%tq_numb)==0){
490                 
491                         // Baud Rate Prescaler. The PCLK clock is divided by (this value plus one) to produce the CAN clock.
492                         BRP = (res / tq_numb) - 1;
493
494                         // sync. segment allways 1 tq
495                         tq_numb--;
496
497                         // number of tq from the sample point to the next nominal Sync. point (this value plus one)                     
498                         TSEG2 = (tq_numb/3) - 1;
499
500                         // number of tq from Sync. point to the sample point (this value plus one)                      
501                         TSEG1 = tq_numb - (tq_numb/3) - 1;
502
503                         break;
504                 }
505         }
506
507         CAN1BTR = ((SAM<<23)|(TSEG2<<20)|(TSEG1<<16)|(SJW<<14)|(BRP<<0));
508
509 }
510
511 void CAN_init(uint32_t baudrate)
512 {
513         uint32_t tmp;
514         uint32_t pclksel0;
515         uint32_t val;
516         uint32_t i;
517         
518         printf("CAN INIT, baudrate: %d\n", baudrate);
519
520         // configure CAN1 pins 
521         CAN_configPin();
522
523         // turn on power and clock for CAN1 
524         PCONP |= PCCAN1;
525         
526         // set clock divide for CAN1 
527
528         val = 0x00; // 00       PCLK_peripheral = CCLK/4 
529         pclksel0 = PCLKSEL0;
530         pclksel0 &= ~PCLK_CAN1_MASK;
531         pclksel0 &= ~PCLK_CAN2_MASK;
532         pclksel0 &= ~PCLK_ACF_MASK;
533         pclksel0 |= __val2mfld(PCLK_CAN1_MASK, val);
534         pclksel0 |= __val2mfld(PCLK_CAN2_MASK, val);
535         pclksel0 |= __val2mfld(PCLK_ACF_MASK, val);
536         PCLKSEL0 = pclksel0;
537         
538         // enter reset mode
539         CAN1MOD = 1;
540
541         // disable all CAN interrupts
542         CAN1IER = 0;
543
544         // reset value of Global Status Register (global controller status and error counters) 
545         CAN1GSR = 0x3C;
546
547         // request command to release Rx, Tx buffer and clear data overrun 
548         CAN1CMR = (CAN_CMR_AT | CAN_CMR_RRB | CAN_CMR_CDO);
549
550         // read to clear interrupt pending in Interrupt Capture Register 
551         tmp = CAN1ICR;
552
553         // set bus timing 
554         CAN_setBusTiming(baudrate);
555
556         // return to normal operating 
557         CAN1MOD = 0;
558
559         //--------------------------
560
561         // Acceptance Filter Off Mode
562         CANAF_AFMR = 0x01;
563
564         // clear RAM masks
565         for (i = 0; i < 512; i++) {
566                 CANAF_RAM->mask[i] = 0x00;
567         }
568
569         CANAF_SFF_sa = 0x00;
570         CANAF_SFF_GRP_sa = 0x00;
571         CANAF_EFF_sa = 0x00;
572         CANAF_EFF_GRP_sa = 0x00;
573         CANAF_ENDofTable = 0x00;
574
575
576         // Acceptance Filter Bypass Mode - all messages accepted
577         CANAF_AFMR = 0x02;
578
579         //--------------------------
580
581         // enable interrupt after transmit
582         CAN1IER |= CAN_IER_TIE1;
583         // enable receive interrupt
584         CAN1IER |= CAN_IER_RIE;
585         // enable data overrun interrupt
586         CAN1IER |= CAN_IER_DOIE;
587         
588         // enable CAN interrupt 
589         NVIC_EnableIRQ(CAN_IRQn);
590
591
592         
593 }
594