]> rtime.felk.cvut.cz Git - arc.git/blob - arch/ppc/mpc55xx/drivers/Lin.c
2f4661fe3471f9458e12113de5078fdf1040879d
[arc.git] / arch / ppc / mpc55xx / drivers / Lin.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 #include "Lin.h"\r
17 #include "LinIf_Cbk.h"\r
18 #include "mpc55xx.h"\r
19 #include "Det.h"\r
20 #include "Mcu.h"\r
21 #include <stdlib.h>\r
22 #include <string.h>\r
23 #include "LinIf_Cbk.h"\r
24 #include "Os.h"\r
25 #include "isr.h"\r
26 #include "irq.h"\r
27 #include "arc.h"\r
28 \r
29 /* ERRATA for REV_A of 551x chip. Will use a GPT timer for timeout handling */\r
30 \r
31 #ifdef MPC551X_ERRATA_REV_A\r
32 #include "Gpt.h"\r
33 \r
34 static Gpt_ChannelType LinChannelTimeOutGptChannelId[ LIN_CONTROLLER_CNT ];\r
35 static uint32          LinChannelBitTimeInTicks[ LIN_CONTROLLER_CNT ];\r
36 #endif\r
37 \r
38 #define LIN_MAX_MSG_LENGTH 8\r
39 \r
40 #define ESCI(exp) (volatile struct ESCI_tag *)(0xFFFA0000 + (0x4000 * exp))\r
41 \r
42 /* LIN145: Reset -> LIN_UNINIT: After reset, the Lin module shall set its state to LIN_UNINIT. */\r
43 static Lin_DriverStatusType LinDriverStatus = LIN_UNINIT;\r
44 \r
45 static Lin_StatusType LinChannelStatus[LIN_CONTROLLER_CNT];\r
46 static Lin_StatusType LinChannelOrderedStatus[LIN_CONTROLLER_CNT];\r
47 \r
48 /* static buffers, holds one frame at a time */\r
49 static uint8 LinBufTx[LIN_CONTROLLER_CNT][LIN_MAX_MSG_LENGTH];\r
50 static uint8 LinBufRx[LIN_CONTROLLER_CNT][LIN_MAX_MSG_LENGTH];\r
51 \r
52 static uint8 *TxCurrPtr[LIN_CONTROLLER_CNT];\r
53 static uint8  TxSize[LIN_CONTROLLER_CNT];\r
54 static uint8 *RxCurrPtr[LIN_CONTROLLER_CNT];\r
55 static uint8  RxSize[LIN_CONTROLLER_CNT];\r
56 \r
57 /* Development error macros. */\r
58 #if ( LIN_DEV_ERROR_DETECT == STD_ON )\r
59 #define VALIDATE(_exp,_api,_err ) \\r
60         if( !(_exp) ) { \\r
61           Det_ReportError(MODULE_ID_LIN,0,_api,_err); \\r
62           return; \\r
63         }\r
64 \r
65 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \\r
66         if( !(_exp) ) { \\r
67           Det_ReportError(MODULE_ID_LIN,0,_api,_err); \\r
68           return (_rv); \\r
69         }\r
70 #else\r
71 #define VALIDATE(_exp,_api,_err )\r
72 #define VALIDATE_W_RV(_exp,_api,_err,_rv )\r
73 #endif\r
74 \r
75 typedef volatile union\r
76 {\r
77   uint32_t R;\r
78   struct {\r
79           uint32_t PID:8;\r
80           uint32_t :24;\r
81   } B1;\r
82   struct {\r
83           uint32_t L:8;\r
84           uint32_t :24;\r
85   } B2;\r
86   struct {\r
87           uint32_t HDCHK:1;\r
88           uint32_t CSUM:1;\r
89           uint32_t CRC:1;\r
90           uint32_t TX:1;\r
91           uint32_t TN:4;\r
92           uint32_t :24;\r
93   } B3;\r
94   struct {\r
95           uint32_t T:8;\r
96           uint32_t :24;\r
97   } B4;\r
98   struct {\r
99           uint32_t D:8;\r
100           uint32_t :24;\r
101   } B5;\r
102 }LinLTRType;\r
103 \r
104 typedef volatile union {\r
105     vuint32_t R;\r
106     struct {\r
107         vuint32_t TDRE:1;\r
108         vuint32_t TC:1;\r
109         vuint32_t RDRF:1;\r
110         vuint32_t IDLE:1;\r
111         vuint32_t OR:1;\r
112         vuint32_t NF:1;\r
113         vuint32_t FE:1;\r
114         vuint32_t PF:1;\r
115           vuint32_t:3;\r
116         vuint32_t BERR:1;\r
117           vuint32_t:3;\r
118         vuint32_t RAF:1;\r
119         vuint32_t RXRDY:1;\r
120         vuint32_t TXRDY:1;\r
121         vuint32_t LWAKE:1;\r
122         vuint32_t STO:1;\r
123         vuint32_t PBERR:1;\r
124         vuint32_t CERR:1;\r
125         vuint32_t CKERR:1;\r
126         vuint32_t FRC:1;\r
127           vuint32_t:7;\r
128         vuint32_t OVFL:1;\r
129     } B;\r
130 } LinSRtype;   /* Status Register */\r
131 \r
132 static void ResyncDriver(uint8 Channel)\r
133 {\r
134         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
135 \r
136         esciHw->LCR.B.TXIE = 0; /* Disable tx irq */\r
137         esciHw->LCR.B.RXIE = 0; /* Disable Rx Interrupt */\r
138         esciHw->LCR.B.FCIE = 0; /* Disable Rx Interrupt */\r
139 \r
140         /* Disable transmitter and receiver. */\r
141         esciHw->CR1.B.TE = 0;\r
142         esciHw->CR1.B.RE = 0;\r
143 \r
144         /* Clear flags  */\r
145         esciHw->SR.R = esciHw->SR.R;\r
146 \r
147         /* Prepare module for resynchronization. */\r
148         esciHw->LCR.B.LRES = 1; /* LIN Resynchronize. First set then cleared. */\r
149         /* Resynchronize module. */\r
150         esciHw->LCR.B.LRES = 0; /* LIN Resynchronize. First set then cleared. */\r
151 \r
152         /* Enable transmitter and receiver. */\r
153         esciHw->CR1.B.TE = 1;\r
154         esciHw->CR1.B.RE = 1;\r
155 \r
156 #if 0 /* This needs if we Disable Fast Bit Error Detection otherwise SR will not be cleared properly....strange */\r
157         volatile uint32 i;\r
158         for(i=0; i < 10000; ){\r
159           i++;\r
160         }\r
161 #endif\r
162 \r
163         /* Clear set flags again */\r
164         esciHw->SR.R = esciHw->SR.R;\r
165 }\r
166 \r
167 \r
168 void LinInterrupt(uint8 Channel)\r
169 {\r
170         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
171         LinSRtype sr, tmp;\r
172         LinLTRType tmpLtr;\r
173 #ifdef MPC551X_ERRATA_REV_A\r
174         uint8 stopTimeOutTimer = FALSE;\r
175 #endif \r
176 \r
177         sr.R = esciHw->SR.R;\r
178 \r
179         /* Clear flags */\r
180         tmp.R = 0;\r
181         if(sr.B.TXRDY == 1){tmp.B.TXRDY = 1;}\r
182         if(sr.B.RXRDY == 1){tmp.B.RXRDY = 1;}\r
183         if(sr.B.TC == 1){tmp.B.TC = 1;}\r
184         if(sr.B.RDRF == 1){tmp.B.RDRF = 1;}\r
185         if(sr.B.IDLE == 1){tmp.B.IDLE = 1;}\r
186         if(sr.B.OVFL == 1){tmp.B.OVFL = 1;}\r
187         if(sr.B.FRC == 1){tmp.B.FRC = 1;}\r
188 \r
189         esciHw->SR.R = tmp.R;\r
190         esciHw->LCR.B.TXIE = 0; /* Always disable Tx Interrupt */\r
191 \r
192         /* TX */\r
193         if (LinChannelStatus[Channel]==LIN_TX_BUSY) {\r
194                 /* Maybe transmit next byte */\r
195                 if (TxSize[Channel] > 0 && sr.B.TXRDY) {\r
196                         tmpLtr.R = 0; /* Clear */\r
197                         tmpLtr.B4.T = *TxCurrPtr[Channel];\r
198                         TxCurrPtr[Channel]++; TxSize[Channel]--;\r
199                         esciHw->LCR.B.TXIE = 1; /* Enable tx irq */\r
200                         esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
201                 }\r
202                 else {\r
203                         if(sr.B.FRC == 1){\r
204                                 /* Transmission complete */\r
205                                 if (LinChannelOrderedStatus[Channel]==LIN_CH_SLEEP){\r
206                                         LinChannelStatus[Channel] = LIN_CH_SLEEP;\r
207                                         LinChannelOrderedStatus[Channel]=LIN_CH_OPERATIONAL;\r
208                                 }else {\r
209                                         LinChannelStatus[Channel] = LIN_TX_OK;\r
210                                 }\r
211                                 esciHw->LCR.B.TXIE = 0; /* Disable tx irq */\r
212                         }\r
213                         else{\r
214                                 if (LinChannelOrderedStatus[Channel]==LIN_CH_SLEEP){\r
215                                         LinChannelStatus[Channel] = LIN_CH_SLEEP;\r
216                                         LinChannelOrderedStatus[Channel]=LIN_CH_OPERATIONAL;\r
217                                 }else {\r
218                                         LinChannelStatus[Channel] = LIN_TX_ERROR;\r
219                                 }\r
220                         }\r
221 #ifdef MPC551X_ERRATA_REV_A\r
222                         /* Transmission is over. */\r
223                         stopTimeOutTimer = TRUE;\r
224 #endif \r
225                 }\r
226         }       /* RX */\r
227         else if (LinChannelStatus[Channel]==LIN_RX_BUSY) {\r
228           /* Maybe receive next byte */\r
229                 if (RxSize[Channel] > 0 && sr.B.RXRDY) {\r
230                         tmpLtr.R = esciHw->LRR.R;\r
231                         *RxCurrPtr[Channel] = tmpLtr.B5.D;\r
232                         RxCurrPtr[Channel]++; RxSize[Channel]--;\r
233                 } else if (RxSize[Channel] == 0 && sr.B.FRC == 1){\r
234                         /* receive complete */\r
235                         LinChannelStatus[Channel] = LIN_RX_OK;\r
236                         esciHw->LCR.B.RXIE = 0; /* Disable Rx Interrupt */\r
237                         esciHw->LCR.B.FCIE = 0; /* Disable Rx Interrupt */\r
238 #ifdef MPC551X_ERRATA_REV_A\r
239                         /* Transmission is over. */\r
240                         stopTimeOutTimer = TRUE;\r
241 #endif \r
242                 }\r
243         }\r
244 \r
245         /* Error handling\r
246          * OR    - Overrun\r
247          * NF    \96 Noise fault\r
248          * FE    \96 Framing Error\r
249          * PF    \96 Parity fault\r
250          * BERR  \96 Bit error (read back)\r
251          * STO   \96 Slave Timeout\r
252          * PBERR \96 Physical bit error\r
253          * CERR  \96 CRC error\r
254          * CKERR \96 Checksum error\r
255          * OVFL  \96 Overflow flag\r
256          */\r
257         if(sr.B.OR || sr.B.NF || sr.B.FE || sr.B.PF || sr.B.BERR || sr.B.STO || sr.B.PBERR ||\r
258            sr.B.CERR || sr.B.CKERR || sr.B.OVFL) {\r
259                 static uint32 errCnt=0;\r
260                 errCnt++;\r
261                 if(LinChannelStatus[Channel]==LIN_RX_BUSY){\r
262                         LinChannelStatus[Channel] = LIN_RX_ERROR;\r
263                 }else if (LinChannelStatus[Channel]==LIN_TX_BUSY){\r
264                         LinChannelStatus[Channel] = LIN_TX_ERROR;\r
265                 }\r
266 \r
267                 /* Clear flags  */\r
268                 esciHw->SR.R=0xffffffff;\r
269 \r
270                 /* Resynchronize driver in GetStatus call */\r
271 \r
272 #ifndef MPC551X_ERRATA_REV_A\r
273         }\r
274 #else\r
275                 /* Transmission is over. */\r
276                 stopTimeOutTimer = TRUE;\r
277         }\r
278 \r
279         /* Handle LIN Wake Up reset manually. See [Freescale Device Errata MPC5510ACE, Rev. 10 APR 2009, errata ID: 8632]. */\r
280         if( sr.B.LWAKE )\r
281         {\r
282                 /* Resynchronize driver. */\r
283                 esciHw->LCR.B.LRES = 1; /* LIN Resynchronize. First set then cleared */\r
284                 esciHw->LCR.B.LRES = 0; /* LIN Resynchronize. First set then cleared */\r
285 \r
286                 /* Transmission is over. */\r
287                 stopTimeOutTimer = TRUE;\r
288         }\r
289 \r
290         if( TRUE == stopTimeOutTimer )\r
291         {\r
292                 Gpt_StopTimer( LinChannelTimeOutGptChannelId[ Channel ] );\r
293         }\r
294 #endif\r
295 }\r
296 \r
297 static void LinInterruptA()\r
298 {\r
299         LinInterrupt(LIN_CTRL_A);\r
300 }\r
301 static void LinInterruptB()\r
302 {\r
303         LinInterrupt(LIN_CTRL_B);\r
304 }\r
305 static void LinInterruptC()\r
306 {\r
307         LinInterrupt(LIN_CTRL_C);\r
308 }\r
309 static void LinInterruptD()\r
310 {\r
311         LinInterrupt(LIN_CTRL_D);\r
312 }\r
313 static void LinInterruptE()\r
314 {\r
315         LinInterrupt(LIN_CTRL_E);\r
316 }\r
317 static void LinInterruptF()\r
318 {\r
319         LinInterrupt(LIN_CTRL_F);\r
320 }\r
321 static void LinInterruptG()\r
322 {\r
323         LinInterrupt(LIN_CTRL_G);\r
324 }\r
325 static void LinInterruptH()\r
326 {\r
327         LinInterrupt(LIN_CTRL_H);\r
328 }\r
329 \r
330 #ifdef MPC551X_ERRATA_REV_A\r
331 void LinTimeOutInterrupt( uint8 channel )\r
332 {\r
333         /* We ended up here because of that the eSCI module for the given channel has stopped internally.\r
334         * Now we have to reset the LIN module state machine ourself.\r
335         * See [Freescale Device Errata MPC5510ACE, Rev. 10 APR 2009, errata ID: 8173 and 4968]. */\r
336 \r
337         volatile struct ESCI_tag *esciHw = ESCI( channel );\r
338 \r
339         /* Make sure that the timer it stopped (e.g. if by mistake setup as continuously). */\r
340         Gpt_StopTimer( LinChannelTimeOutGptChannelId[ channel ] );\r
341 \r
342         /* Disable transmitter and receiver. */\r
343         esciHw->CR1.B.TE = 0;\r
344         esciHw->CR1.B.RE = 0;\r
345 \r
346         /* Prepare module for resynchronization. */\r
347         esciHw->LCR.B.LRES = 1; /* LIN Resynchronize. First set then cleared. */\r
348 \r
349         /* Enable transmitter and receiver. */\r
350         esciHw->CR1.B.TE = 1;\r
351         esciHw->CR1.B.RE = 1;\r
352 \r
353         /* Resynchronize module. */\r
354         esciHw->LCR.B.LRES = 0; /* LIN Resynchronize. First set then cleared. */\r
355 }\r
356 \r
357 void LinTimeOutInterruptA()\r
358 {\r
359   LinTimeOutInterrupt( LIN_CTRL_A );\r
360 }\r
361 void LinTimeOutInterruptB()\r
362 {\r
363   LinTimeOutInterrupt( LIN_CTRL_B );\r
364 }\r
365 void LinTimeOutInterruptC()\r
366 {\r
367   LinTimeOutInterrupt( LIN_CTRL_C );\r
368 }\r
369 void LinTimeOutInterruptD()\r
370 {\r
371   LinTimeOutInterrupt( LIN_CTRL_D );\r
372 }\r
373 void LinTimeOutInterruptE()\r
374 {\r
375   LinTimeOutInterrupt( LIN_CTRL_E );\r
376 }\r
377 void LinTimeOutInterruptF()\r
378 {\r
379   LinTimeOutInterrupt( LIN_CTRL_F );\r
380 }\r
381 void LinTimeOutInterruptG()\r
382 {\r
383   LinTimeOutInterrupt( LIN_CTRL_G );\r
384 }\r
385 void LinTimeOutInterruptH()\r
386 {\r
387   LinTimeOutInterrupt( LIN_CTRL_H );\r
388 }\r
389 #endif\r
390 \r
391 void Lin_Init( const Lin_ConfigType* Config )\r
392 {\r
393         uint8 i;\r
394 \r
395         VALIDATE( (LinDriverStatus == LIN_UNINIT), LIN_INIT_SERVICE_ID, LIN_E_STATE_TRANSITION );\r
396         /* VALIDATE( (Config!=0), LIN_INIT_SERVICE_ID, LIN_E_INVALID_POINTER ); */\r
397 \r
398         for (i=0;i<LIN_CONTROLLER_CNT;i++)\r
399         {\r
400                 /* LIN171: On entering the state LIN_INIT, the Lin module shall set each channel into\r
401                  * state LIN_CH_UNINIT. */\r
402                 LinChannelStatus[i] = LIN_CH_UNINIT;\r
403                 LinChannelOrderedStatus[i]=LIN_CH_OPERATIONAL;\r
404                 TxCurrPtr[i] = 0;\r
405                 TxSize[i] = 0;\r
406                 RxCurrPtr[i] = 0;\r
407                 RxSize[i] = 0;\r
408 #ifdef MPC551X_ERRATA_REV_A\r
409                 LinChannelTimeOutGptChannelId[ i ] = 0;\r
410                 LinChannelBitTimeInTicks[ i ] = 0;\r
411 #endif\r
412         }\r
413 \r
414         /* LIN146: LIN_UNINIT -> LIN_INIT: The Lin module shall transition from LIN_UNINIT\r
415          * to LIN_INIT when the function Lin_Init is called. */\r
416         LinDriverStatus = LIN_INIT;\r
417 }\r
418 void Lin_DeInit()\r
419 {\r
420   LinDriverStatus = LIN_UNINIT;\r
421 }\r
422 \r
423 void Lin_WakeupValidation( void )\r
424 {\r
425 \r
426 }\r
427 \r
428 void Lin_InitChannel(  uint8 Channel,   const Lin_ChannelConfigType* Config )\r
429 {\r
430         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
431         enum\r
432         {\r
433           LIN_PRIO = 3\r
434         };\r
435 \r
436         VALIDATE( (Config!=0), LIN_INIT_CHANNEL_SERVICE_ID, LIN_E_INVALID_POINTER );\r
437         VALIDATE( (LinDriverStatus != LIN_UNINIT), LIN_INIT_CHANNEL_SERVICE_ID, LIN_E_UNINIT );\r
438         VALIDATE( (Channel < LIN_CONTROLLER_CNT), LIN_INIT_CHANNEL_SERVICE_ID, LIN_E_INVALID_CHANNEL );\r
439 \r
440         /* Install the interrupt */\r
441         switch(Channel){\r
442         case 0:\r
443                 ISR_INSTALL_ISR2("LinIsr", LinInterruptA, (IrqType)(SCI_A_COMB),LIN_PRIO, 0);\r
444                 break;\r
445         case 1:\r
446                 ISR_INSTALL_ISR2("LinIsr", LinInterruptB, (IrqType)(SCI_B_COMB),LIN_PRIO, 0);\r
447                 break;\r
448         case 2:\r
449                 ISR_INSTALL_ISR2("LinIsr", LinInterruptC, (IrqType)(SCI_C_COMB),LIN_PRIO, 0);\r
450                 break;\r
451         case 3:\r
452                 ISR_INSTALL_ISR2("LinIsr", LinInterruptD, (IrqType)(SCI_D_COMB),LIN_PRIO, 0);\r
453                 break;\r
454         case 4:\r
455                 ISR_INSTALL_ISR2("LinIsr", LinInterruptE, (IrqType)(SCI_E_COMB),LIN_PRIO, 0);\r
456                 break;\r
457         case 5:\r
458                 ISR_INSTALL_ISR2("LinIsr", LinInterruptF, (IrqType)(SCI_F_COMB),LIN_PRIO, 0);\r
459                 break;\r
460         case 6:\r
461                 ISR_INSTALL_ISR2("LinIsr", LinInterruptG, (IrqType)(SCI_G_COMB+2),LIN_PRIO, 0);\r
462                 break;\r
463         case 7:\r
464                 ISR_INSTALL_ISR2("LinIsr", LinInterruptH, (IrqType)(SCI_H_COMB+3),LIN_PRIO, 0);\r
465                 break;\r
466         default:\r
467                 break;\r
468         }\r
469 \r
470         esciHw->CR2.B.MDIS = 0;/* The module is enabled by writing the ESCIx_CR2[MDIS] bit to 0. */\r
471 \r
472         esciHw->CR1.B.RE = 1;\r
473         esciHw->CR1.B.M = 0; /* The data format bit ESCIx_CR1[M], is set to 0 (8 data bits), and the parity is disabled (PE = 0).*/\r
474         esciHw->CR1.B.PE = 0;\r
475         esciHw->CR1.B.TIE = 0; /*ESCIx_CR1[TIE], ESCIx_CR1[TCIE], ESCIx_CR1[RIE] interrupt enable bits should be inactive.*/\r
476         esciHw->CR1.B.TCIE = 0;\r
477         esciHw->CR1.B.RIE = 0;\r
478           /* Set up ESCIx_CR1 for LIN */\r
479           /*\r
480            * SCI Baud Rate. Used by the counter to determine the baud rate of the eSCI.\r
481            * The formula for calculating the baud rate is:\r
482            *\r
483            *                      eSCI system clock\r
484            * SCI baud rate =   -----------------------\r
485            *                          16 × SBR\r
486            *\r
487            * where SBR can contain a value from 1 to 8191. After reset, the baud generator\r
488            * is disabled until the TE bit or the RE bit is set for the first time. The baud\r
489            * rate generator is disabled when SBR = 0x0.\r
490            */\r
491         esciHw->CR1.B.SBR  = McuE_GetPeripheralClock(Config->LinClockRef)/(16*Config->LinChannelBaudRate);\r
492         esciHw->LCR.B.LIN = 1;  /* Instead, the LIN interrupts should be used.Switch eSCI to LIN mode (ESCIx_LCR[LIN] = 1).*/\r
493 \r
494         esciHw->CR2.B.BRK13 = 1;/* The LIN standard requires that the break character always be 13 bits long\r
495         (ESCIx_CR2[BRK13] = 1). The eSCI will work with BRK13=0, but it will violate LIN 2.0. */\r
496 \r
497 #ifdef MPC551X_ERRATA_REV_A\r
498         esciHw->LCR.B.LDBG = 1; /* Enable LIN debug => Disable automatic reset of the LIN FSM. See [Freescale Device Errata MPC5510ACE, Rev. 10 APR 2009, errata ID: 8632] */\r
499         esciHw->CR2.B.FBR = 1;  /* Disable Fast Bit Error Detection. See [Freescale Device Errata MPC5510ACE, Rev. 10 APR 2009, errata ID: 8635] */\r
500 #else\r
501         esciHw->LCR.B.LDBG = 0; /* Normally, bit errors should cause the LIN FSM to reset, stop driving the bus immediately, and stop\r
502                                  * further DMA requests until the BERR flag has been cleared. Set ESCIx_LCR[LDBG] = 0,*/\r
503         esciHw->CR2.B.FBR = 1;    /* Fast bit error detection provides superior error checking, so ESCIx_CR2[FBR] should be set; */\r
504 #endif\r
505         esciHw->LCR.B.STIE = 1; /* Enable some fault irq's */\r
506         esciHw->LCR.B.PBIE = 1;\r
507         esciHw->LCR.B.CKIE = 1;\r
508         esciHw->LCR.B.OFIE = 1;\r
509 \r
510         esciHw->CR2.B.SBSTP = 1;/*ESCIx_CR2[SBSTP] = 1, and ESCIx_CR2[BSTP] = 1 to accomplish these functions.*/\r
511         esciHw->CR2.B.BSTP = 1;\r
512 \r
513         esciHw->CR2.B.BESM13 = 1; /* normally it will be used with ESCIx_CR2[BESM13] = 1.*/\r
514 \r
515         /* The error indicators NF, FE, BERR, STO, PBERR, CERR, CKERR, and OVFL should be enabled. */\r
516         /* Should we have these interrupts or check the status register? */\r
517         /*Initially a wakeup character may need to be transmitted on the LIN bus, so that the LIN slaves\r
518         activate.*/\r
519 \r
520         esciHw->CR1.B.TE = 1; /* Both transmitter and receiver are enabled (ESCIx_CR1[TE] = 1, ESCIx_CR1[RE] = 1). */\r
521 \r
522         LinChannelStatus[Channel]=LIN_CH_OPERATIONAL;\r
523 #ifdef MPC551X_ERRATA_REV_A\r
524         LinChannelTimeOutGptChannelId[ Channel ] = Config->LinTimeOutGptChannelId;\r
525         LinChannelBitTimeInTicks[ Channel ] = McuE_GetPeripheralClock( Config->LinClockRef / Config->LinChannelBaudRate ) / Config->LinChannelBaudRate;\r
526 #endif\r
527 }\r
528 \r
529 void Lin_DeInitChannel( uint8 Channel )\r
530 {\r
531         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
532         VALIDATE( (Channel < LIN_CONTROLLER_CNT), LIN_DEINIT_CHANNEL_SERVICE_ID, LIN_E_INVALID_CHANNEL );\r
533 \r
534 #ifdef MPC551X_ERRATA_REV_A\r
535         /* Make sure that the timer is stopped. */\r
536         Gpt_StopTimer( LinChannelTimeOutGptChannelId[ Channel ] );\r
537 #endif\r
538 \r
539         /* LIN178: The function Lin_DeInitChannel shall only be executable when the LIN\r
540          * channel state-machine is in state LIN_CH_OPERATIONAL. */\r
541         if(LinChannelStatus[Channel] != LIN_CH_UNINIT){\r
542                 esciHw->CR2.B.MDIS = 1;/* The module is disabled by writing the ESCIx_CR2[MDIS] bit to 1. */\r
543 \r
544                 LinChannelStatus[Channel]=LIN_CH_UNINIT;\r
545         }\r
546 }\r
547 \r
548 Std_ReturnType Lin_SendHeader(  uint8 Channel,  Lin_PduType* PduInfoPtr )\r
549 {\r
550     LinSRtype tmp;\r
551     LinLTRType tmpLtr;\r
552         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
553         imask_t state;\r
554 \r
555         /* LIN021 */\r
556     Irq_Save(state);\r
557         if(LinChannelStatus[Channel] == LIN_TX_BUSY || LinChannelStatus[Channel] == LIN_TX_ERROR ||\r
558            LinChannelStatus[Channel] == LIN_RX_BUSY || LinChannelStatus[Channel] == LIN_RX_ERROR)\r
559         {\r
560                 ResyncDriver(Channel);\r
561                 LinChannelStatus[Channel]=LIN_CH_OPERATIONAL;\r
562         }\r
563     Irq_Restore(state);\r
564 \r
565 \r
566         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_SEND_HEADER_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
567         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_SEND_HEADER_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
568         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_SEND_HEADER_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
569         /* Send header is used to wake the net in this implementation(no actual header is sent */\r
570         /* VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_SLEEP), LIN_SEND_HEADER_SERVICE_ID, LIN_E_STATE_TRANSITION, E_NOT_OK); */\r
571         VALIDATE_W_RV( (PduInfoPtr != NULL), LIN_SEND_HEADER_SERVICE_ID, LIN_E_INVALID_POINTER, E_NOT_OK);\r
572 \r
573         /* Byte 1 */\r
574         tmpLtr.R = 0; /* Clear */\r
575         tmpLtr.B1.PID = PduInfoPtr->Pid;\r
576         tmp.R = 0; /* Clear ready flag before send */\r
577         tmp.B.TXRDY = 1;\r
578         esciHw->SR.R = tmp.R;\r
579         esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
580 \r
581         /* Byte 2 */\r
582         tmpLtr.R = 0; /* Clear */\r
583         tmpLtr.B2.L = PduInfoPtr->DI;\r
584         tmp.R = 0; /* Clear ready flag before send */\r
585         tmp.B.TXRDY = 1;\r
586         esciHw->SR.R = tmp.R;\r
587         esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
588 \r
589         /* Byte 3 */\r
590         tmpLtr.R = 0; /* Clear */\r
591         if (PduInfoPtr->Cs == LIN_ENHANCED_CS){ /*Frame identifiers 60 (0x3C) to 61 (0x3D) shall always use classic checksum */\r
592                 tmpLtr.B3.HDCHK = 1;\r
593         }\r
594         tmpLtr.B3.CSUM = 1; /* Append checksum to TX frame or verify for a RX */\r
595         tmpLtr.B3.CRC = 0; /* Append two CRC bytes(Not LIN standard) */\r
596 \r
597         /* Calculate the time out value for the frame.(10 × NDATA + 45) × 1.4 according to LIN1.3 */\r
598         uint16 timeOutValue = (uint16)( ( ( 10 * PduInfoPtr->DI + 45 ) * 14 ) / 10);\r
599 \r
600         if (PduInfoPtr->Drc == LIN_MASTER_RESPONSE)\r
601         {\r
602                 LinChannelStatus[Channel]=LIN_TX_BUSY;\r
603                 tmpLtr.B3.TX = 1; /* TX frame */\r
604                 tmpLtr.B3.TN = 0; /* Timeout not valid for TX */\r
605                 tmp.R = 0; /* Clear ready flag before send */\r
606                 tmp.B.TXRDY = 1;\r
607                 esciHw->SR.R = tmp.R;\r
608                 esciHw->LCR.B.FCIE = 1; /* Enable frame complete */\r
609                 esciHw->LCR.B.TXIE = 1; /* Enable tx irq */\r
610                 if (PduInfoPtr->DI > 0){\r
611                         TxCurrPtr[Channel] = LinBufTx[Channel];\r
612                         TxSize[Channel] = PduInfoPtr->DI;\r
613                         memcpy(TxCurrPtr[Channel],PduInfoPtr->SduPtr,PduInfoPtr->DI);\r
614                 }\r
615                 esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
616         }\r
617 \r
618 \r
619         else\r
620         {\r
621                 LinChannelStatus[Channel]=LIN_RX_BUSY;\r
622                 RxCurrPtr[Channel] = LinBufRx[Channel];\r
623                 RxSize[Channel] = PduInfoPtr->DI;\r
624 \r
625                 tmpLtr.B3.TX = 0; /* RX frame */\r
626                 tmpLtr.B3.TN = timeOutValue >> 8;     /* Most significant bits to be set here. */\r
627                 esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
628                 /* Byte 4 for RX */\r
629                 tmpLtr.R = 0; /* Clear */\r
630         tmpLtr.B4.T = timeOutValue & 0xFF;   /* Least significant bits to be set here. */\r
631                 tmp.R = 0; /* Clear ready flag before send */\r
632                 tmp.B.TXRDY = 1;\r
633                 esciHw->SR.R = tmp.R;\r
634                 esciHw->LTR.R=tmpLtr.R; /* write to transmit reg */\r
635                 esciHw->LCR.B.FCIE = 1; /* Enable frame complete */\r
636                 esciHw->LCR.B.RXIE = 1; /* Enable rx irq */\r
637         }\r
638 \r
639 #ifdef MPC551X_ERRATA_REV_A\r
640         /* Set up the GPT to twice as long time. Normally this time out shall not be needed but there are two\r
641         * Erratas telling us that the LIN message timeout (written above to byte 3 and 4) is sometimes not used\r
642         * by the LIN module and the LIN module state machine will then wait in infinity.\r
643         * See [Freescale Device Errata MPC5510ACE, Rev. 10 APR 2009, errata ID: 8173 and 4968]. */\r
644         Gpt_StopTimer( LinChannelTimeOutGptChannelId[ Channel ] );\r
645         Gpt_StartTimer( LinChannelTimeOutGptChannelId[ Channel ], LinChannelBitTimeInTicks[ Channel ] * timeOutValue * 2 );\r
646 #endif\r
647 \r
648         return E_OK;\r
649 }\r
650 \r
651 Std_ReturnType Lin_SendResponse(  uint8 Channel,   Lin_PduType* PduInfoPtr )\r
652 {\r
653         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_SEND_RESPONSE_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
654         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_SEND_RESPONSE_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
655         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_SEND_RESPONSE_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
656         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_SLEEP), LIN_SEND_RESPONSE_SERVICE_ID, LIN_E_STATE_TRANSITION, E_NOT_OK);\r
657         VALIDATE_W_RV( (PduInfoPtr != NULL), LIN_SEND_RESPONSE_SERVICE_ID, LIN_E_INVALID_POINTER, E_NOT_OK);\r
658 \r
659         /* The response is sent from within the header in this implementation since this is a master only implementation */\r
660         return E_OK;\r
661 }\r
662 \r
663 Std_ReturnType Lin_GoToSleep(  uint8 Channel )\r
664 {\r
665         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
666         Lin_PduType PduInfo;\r
667         uint8 data[8] = {0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};\r
668 \r
669         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_GO_TO_SLEEP_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
670         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_GO_TO_SLEEP_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
671         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_GO_TO_SLEEP_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
672         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_SLEEP), LIN_GO_TO_SLEEP_SERVICE_ID, LIN_E_STATE_TRANSITION, E_NOT_OK);\r
673 \r
674         if (LinChannelOrderedStatus[Channel]!=LIN_CH_SLEEP){\r
675                 LinChannelOrderedStatus[Channel]=LIN_CH_SLEEP;\r
676 \r
677                 PduInfo.Cs = LIN_CLASSIC_CS;\r
678                 PduInfo.Pid = 0x3C;\r
679                 PduInfo.SduPtr = data;\r
680                 PduInfo.DI = 8;\r
681                 PduInfo.Drc = LIN_MASTER_RESPONSE;\r
682 \r
683                 Lin_SendHeader(Channel,  &PduInfo);\r
684                 Lin_SendResponse(Channel,  &PduInfo);\r
685 \r
686                 esciHw->LCR.B.WUIE = 1; /* enable wake-up irq */\r
687         }\r
688         return E_OK;\r
689 }\r
690 \r
691 Std_ReturnType Lin_GoToSleepInternal(  uint8 Channel )\r
692 {\r
693         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_GO_TO_SLEEP_INTERNAL_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
694         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_GO_TO_SLEEP_INTERNAL_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
695         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_GO_TO_SLEEP_INTERNAL_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
696         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_SLEEP), LIN_GO_TO_SLEEP_INTERNAL_SERVICE_ID, LIN_E_STATE_TRANSITION, E_NOT_OK);\r
697         Lin_GoToSleep(Channel);\r
698         return E_OK;\r
699 }\r
700 \r
701 Std_ReturnType Lin_WakeUp( uint8 Channel )\r
702 {\r
703         volatile struct ESCI_tag * esciHw = ESCI(Channel);\r
704         Lin_PduType PduInfo;\r
705         uint8 data[2] = {0xFF,0xFF};\r
706 \r
707         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_WAKE_UP_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
708         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_WAKE_UP_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
709         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_WAKE_UP_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
710         VALIDATE_W_RV( (LinChannelStatus[Channel] == LIN_CH_SLEEP), LIN_WAKE_UP_SERVICE_ID, LIN_E_STATE_TRANSITION, E_NOT_OK);\r
711 \r
712         esciHw->LCR.B.WUIE = 0; /* disable wake-up irq */\r
713         esciHw->LCR.B.WU = 1; /* send wake up */\r
714         esciHw->LCR.B.WUD0 = 1; /* delimiter time */\r
715         esciHw->LCR.B.WUD1 = 0; /* delimiter time */\r
716 \r
717         /* Just send any header to trigger the wakeup signal */\r
718         PduInfo.Cs = LIN_CLASSIC_CS;\r
719         PduInfo.Pid = 0x00;\r
720         PduInfo.SduPtr = data;\r
721         PduInfo.DI = 2;\r
722         PduInfo.Drc = LIN_SLAVE_RESPONSE;\r
723         Lin_SendHeader(Channel,  &PduInfo);\r
724 \r
725         LinChannelStatus[Channel]=LIN_CH_OPERATIONAL;\r
726         return E_OK;\r
727 }\r
728 \r
729 Lin_StatusType Lin_GetStatus( uint8 Channel, uint8** Lin_SduPtr )\r
730 {\r
731         VALIDATE_W_RV( (LinDriverStatus != LIN_UNINIT), LIN_GETSTATUS_SERVICE_ID, LIN_E_UNINIT, E_NOT_OK);\r
732         VALIDATE_W_RV( (LinChannelStatus[Channel] != LIN_CH_UNINIT), LIN_GETSTATUS_SERVICE_ID, LIN_E_CHANNEL_UNINIT, E_NOT_OK);\r
733         VALIDATE_W_RV( (Channel < LIN_CONTROLLER_CNT), LIN_GETSTATUS_SERVICE_ID, LIN_E_INVALID_CHANNEL, E_NOT_OK);\r
734         VALIDATE_W_RV( (Lin_SduPtr!=NULL), LIN_GETSTATUS_SERVICE_ID, LIN_E_INVALID_POINTER, E_NOT_OK);\r
735 \r
736         imask_t state;\r
737     Irq_Save(state);\r
738         Lin_StatusType res = LinChannelStatus[Channel];\r
739         /* We can only check for valid sdu ptr when LIN_RX_OK */\r
740         if(LinChannelStatus[Channel] == LIN_RX_OK || LinChannelStatus[Channel] == LIN_RX_ERROR){\r
741                 *Lin_SduPtr = LinBufRx[Channel];\r
742                 if(LinChannelStatus[Channel] == LIN_RX_ERROR){\r
743                         ResyncDriver(Channel);\r
744                 }\r
745                 LinChannelStatus[Channel]=LIN_CH_OPERATIONAL;\r
746         } else if(LinChannelStatus[Channel] == LIN_TX_OK || LinChannelStatus[Channel] == LIN_TX_ERROR){\r
747                 if(LinChannelStatus[Channel] == LIN_TX_ERROR){\r
748                         ResyncDriver(Channel);\r
749                 }\r
750                 LinChannelStatus[Channel]=LIN_CH_OPERATIONAL;\r
751         }\r
752     Irq_Restore(state);\r
753         return res;\r
754 }\r
755 \r
756 \r
757 \r
758 \r
759 \r