[processor-sdk/performance-audio-sr.git] / pdk_k2g_1_0_1 / packages / ti / board / diag / dcan / src / evmk2g_dcan_frame.c
1 /*
2 * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
3 * Copyright (C) 2006 Andrey Volkov, Varma Electronics
4 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the version 2 of the GNU General Public License
8 * as published by the Free Software Foundation
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 /**
21 * \file evmc66x_dcan_frame.c
22 *
23 * \brief This file consists of wrapper functions which internally call
24 * DCAN APIs.
25 */
27 #include "platform_internal.h"
29 #if (PLATFORM_DCAN_IN)
31 /**
32 * \brief This function will configure a message object in DCAN message RAM as a
33 * transmit message object.
34 *
35 * \param baseAdd Base Address of the DCAN Module Registers.
36 * \param canPtr Pointer to can_frame structure.
37 *
38 **/
39 unsigned int CANTxObjectConfig(unsigned int baseAdd, can_frame* canPtr)
40 {
41 unsigned int msgNum;
42 unsigned int idLen;
44 idLen = (canPtr->flag & CAN_EXT_FRAME) ? DCAN_29_BIT_ID : DCAN_11_BIT_ID;
46 /* Set the message valid bit */
47 DCANMsgObjValidate(baseAdd, DCAN_IF1_REG);
49 /* Set the message id of the frame to be transmitted */
50 DCANMsgIdSet(baseAdd, canPtr->id, idLen, DCAN_IF1_REG);
52 /* Set the message object direction as transmit */
53 DCANMsgDirectionSet(baseAdd, DCAN_TX_DIR, DCAN_IF1_REG);
55 /* Set the data length code */
56 DCANDataLengthCodeSet(baseAdd, canPtr->dlc, DCAN_IF1_REG);
58 /* Write data to the DCAN data registers */
59 DCANDataWrite(baseAdd, (canPtr->data), DCAN_IF1_REG);
61 /* Enable the transmit interrupt for the message object */
62 DCANMsgObjIntEnable(baseAdd, DCAN_TRANSMIT_INT, DCAN_IF1_REG);
64 /* Enable the DCAN FIFO End of block */
65 DCANFIFOEndOfBlockControl(baseAdd, DCAN_END_OF_BLOCK_ENABLE, DCAN_IF1_REG);
67 /* Get the transmit request status */
68 msgNum = DCANTxRqstStatGet(baseAdd);
70 /* Configure the command register */
71 DCANCommandRegSet(baseAdd, (DCAN_DAT_A_ACCESS | DCAN_MSG_WRITE | DCAN_TXRQST_ACCESS |
72 DCAN_DAT_B_ACCESS | DCAN_ACCESS_CTL_BITS |
73 DCAN_ACCESS_ARB_BITS), msgNum, DCAN_IF1_REG);
75 return msgNum;
76 }
78 /**
79 * \brief This function will configure a message object in DCAN message RAM
80 * as a receive message object.
81 *
82 * \param baseAdd Base Address of the DCAN Module Registers.
83 * \param canPtr Pointer to can_frame structure.
84 *
85 **/
86 unsigned int CANRxObjectConfig(unsigned int baseAdd, can_frame* canPtr)
87 {
88 unsigned int idLen;
89 unsigned int msgIndex;
91 msgIndex = (CAN_NUM_OF_MSG_OBJS / 2) + 1;
93 idLen = (canPtr->flag & CAN_EXT_FRAME) ? DCAN_29_BIT_ID : DCAN_11_BIT_ID;
95 /* Use Acceptance mask. */
96 DCANUseAcceptanceMaskControl(baseAdd, DCAN_MASK_USED, DCAN_IF2_REG);
98 /* Configure the DCAN mask registers for acceptance filtering. */
99 DCANMsgObjectMskConfig(baseAdd, DCAN_IDENTIFIER_MSK(canPtr->msk,
100 DCAN_ID_MSK_11_BIT), DCAN_MSK_MSGDIR_DISABLE,
101 DCAN_MSK_EXT_ID_DISABLE, DCAN_IF2_REG);
103 /* Set the message valid bit */
104 DCANMsgObjValidate(baseAdd, DCAN_IF2_REG);
106 /* Set the message id of the frame to be received */
107 DCANMsgIdSet(baseAdd, canPtr->id, idLen, DCAN_IF2_REG);
109 /* Set the message object direction as receive */
110 DCANMsgDirectionSet(baseAdd, DCAN_RX_DIR, DCAN_IF2_REG);
112 /* Enable the receive interrupt for the message object */
113 DCANMsgObjIntEnable(baseAdd, DCAN_RECEIVE_INT, DCAN_IF2_REG);
115 /* Enable the FIFO end of block */
116 DCANFIFOEndOfBlockControl(baseAdd, DCAN_END_OF_BLOCK_ENABLE, DCAN_IF2_REG);
118 /* Check for the message valid status for receive objects */
119 while((DCANMsgValidStatusGet(baseAdd, msgIndex)) &&
120 (msgIndex <= (CAN_NUM_OF_MSG_OBJS - 1)))
121 {
122 msgIndex++;
123 }
125 /* Configure the command register */
126 DCANCommandRegSet(baseAdd, (DCAN_ACCESS_CTL_BITS | DCAN_MSG_WRITE |
127 DCAN_ACCESS_MSK_BITS | DCAN_ACCESS_ARB_BITS),
128 msgIndex, DCAN_IF2_REG);
130 return msgIndex;
131 }
133 /**
134 * \brief Read data from a message object.
135 *
136 * \param baseAdd Base Address of the DCAN Module Registers.
137 * \param msgNum Message object number.
138 * \param data Pointer to an unsigned integer. Used to fetch data
139 * bytes from data registers.
140 * \param ifReg Interface register set used.
141 *
142 */
143 void CANReadMsgObjData(unsigned int baseAdd, unsigned int msgNum,
144 unsigned int* data, unsigned int ifReg)
145 {
146 /* Read a message object from CAN message RAM to Interface register */
147 DCANCommandRegSet(baseAdd, (DCAN_DAT_A_ACCESS | DCAN_DAT_B_ACCESS |
148 DCAN_TXRQST_ACCESS | DCAN_CLR_INTPND |
149 DCAN_ACCESS_CTL_BITS | DCAN_ACCESS_ARB_BITS |
150 DCAN_ACCESS_MSK_BITS | DCAN_MSG_READ),
151 msgNum, ifReg);
153 /* Clear the NewData bit */
154 DCANNewDataControl(baseAdd, DCAN_NEW_DAT_CLR, ifReg);
156 /* Read data bytes from interface register */
157 DCANDataRead(baseAdd, data, ifReg);
158 }
160 /**
161 * \brief This function should be used to clear the interrupt pending status
162 * of receive objects after a new message is received. This will clear
163 * the IntPnd status of the message object represented by msgNum.
164 *
165 * \param baseAdd Base Address of the DCAN Module Registers.
166 * \param msgNum Message object number.
167 * \param ifReg Interface register set used.
168 *
169 **/
170 void CANClrIntPndStat(unsigned int baseAdd, unsigned int msgNum,
171 unsigned int ifReg)
172 {
173 /* Clear the IntPnd bit of DCAN_IFMCTL register */
174 DCANClrIntPnd(baseAdd, ifReg);
176 /* Set the ClrIntPnd bit of DCAN_IFCMD register */
177 DCANCommandRegSet(baseAdd, DCAN_CLR_INTPND, msgNum, ifReg);
178 }
181 /**
182 * \brief This function can be used by the user to validate a message object.
183 *
184 * \param baseAdd Base Address of the DCAN Module Registers.
185 * \param msgNum Message object number.
186 * \param ifReg Interface register set used.
187 *
188 **/
189 void CANValidateMsgObject(unsigned int baseAdd, unsigned int msgNum,
190 unsigned int ifReg)
191 {
192 /* Set the MsgVal bit of DCAN_IFARB register */
193 DCANMsgObjValidate(baseAdd, ifReg);
195 /* Set the Arb bit of DCAN_IFCMD register */
196 DCANCommandRegSet(baseAdd, (DCAN_ACCESS_ARB_BITS | DCAN_MSG_WRITE),
197 msgNum, ifReg);
198 }
200 /**
201 * \brief This function can be used by the user to invalidate a message
202 * object.
203 *
204 * \param baseAdd Base Address of the DCAN Module Registers.
205 * \param msgNum Message object number.
206 * \param ifReg Interface register set used.
207 *
208 **/
209 void CANInValidateMsgObject(unsigned int baseAdd, unsigned int msgNum,
210 unsigned int ifReg)
211 {
212 /* Clear the MsgVal bit of DCAN_IFARB register */
213 DCANMsgObjInvalidate(baseAdd, ifReg);
215 /* Set the Arb bit of DCAN_IFCMD register */
216 DCANCommandRegSet(baseAdd, (DCAN_ACCESS_ARB_BITS | DCAN_MSG_WRITE),
217 msgNum, ifReg);
218 }
220 /**
221 * \brief This function can be used to disable the transmit interrupt of a
222 * message object.
223 *
224 * \param baseAdd Base Address of the DCAN Module Registers.
225 * \param msgNum Message object number.
226 * \param ifReg Interface register set used.
227 *
228 **/
229 void CANTxIntDisable(unsigned int baseAdd, unsigned int msgNum,
230 unsigned int ifReg)
231 {
232 /* Disable the message object transmit interrupt */
233 DCANMsgObjIntDisable(baseAdd, DCAN_TRANSMIT_INT, ifReg);
235 /* Set the CTL bit of the command register */
236 DCANCommandRegSet(baseAdd, (DCAN_ACCESS_CTL_BITS | DCAN_MSG_WRITE),
237 msgNum, ifReg);
238 }
240 /**
241 * \brief This function can be used to disable the receive interrupt of a
242 * message object.
243 *
244 * \param baseAdd Base Address of the DCAN Module Registers.
245 * \param msgNum Message object number.
246 * \param ifReg Interface register set used.
247 *
248 **/
249 void CANRxIntDisable(unsigned int baseAdd, unsigned int msgNum,
250 unsigned int ifReg)
251 {
252 /* Disable the message object receive interrupt */
253 DCANMsgObjIntDisable(baseAdd, DCAN_RECEIVE_INT, ifReg);
255 /* Set the CTL bit of the command register */
256 DCANCommandRegSet(baseAdd, (DCAN_ACCESS_CTL_BITS | DCAN_MSG_WRITE),
257 msgNum, ifReg);
258 }
260 /**
261 * \brief This function can be used to update the data bytes of a transmit
262 * object and set TxRqst for this message object.
263 *
264 * \param baseAdd Base Address of the DCAN Module Registers.
265 * \param dataPtr Pointer to unsigned integer. Used to write data
266 * bytes to data registers.
267 * \param msgNum Message object number.
268 * \param ifReg Interface register set used.
269 *
270 **/
271 void CANUpdateDataBytes(unsigned int baseAdd, unsigned int* dataPtr,
272 unsigned int msgNum, unsigned int ifReg)
273 {
274 /* Populate the data bytes in the data registers */
275 DCANDataWrite(baseAdd, dataPtr, ifReg);
277 /* Set the DataA, DataB, TxRqst and WR of the IF_CMD register */
278 DCANCommandRegSet(baseAdd, (DCAN_DAT_A_ACCESS | DCAN_DAT_B_ACCESS |
279 DCAN_TXRQST_ACCESS | DCAN_MSG_WRITE),
280 msgNum, ifReg);
281 }
283 /**
284 * \brief This function takes I/P Clk frequency, required bit-rate on the
285 * CAN bus and calculates the value to be programmed to BTR register
286 * and sends the BTR value to 'DCANBitTimingConfig' API.
287 *
288 * \param baseAdd Base Address of the DCAN Module Registers.
289 * \param clkFreq I/P clock frequency to DCAN controller.
290 * \param bitRate Required bit-rate on the CAN bus.
291 *
292 * \return Returns the error value if error is present.
293 *
294 **/
295 unsigned int CANSetBitTiming(unsigned int baseAdd, unsigned int clkFreq,
296 unsigned int bitRate)
297 {
298 unsigned int errVal = 0, btrValue = 0, tSeg1 = 0, tSeg2 = 0;
299 struct _dcan_bittiming bit_time_values;
300 struct _dcan_hw_params *btc;
301 struct _dcan_bittiming *bt;
303 static struct _dcan_hw_params dcan_hw_params = {
304 /* tseg1Min = */ 1,
305 /* tseg1Max = */ 16,
306 /* tseg2Min = */ 1,
307 /* tseg2Max = */ 8,
308 /* sjwMax = */ 4,
309 /* brpMin = */ 1,
310 /* brpMax = */ 1024,
311 /* brpInc = */ 1,
312 };
314 bt = &bit_time_values;
315 btc = &dcan_hw_params;
317 bt->bitRate = bitRate;
319 errVal = CANbitTimeCalculator(btc, bt, clkFreq);
321 /* Calculate Time Segment2 value */
322 tSeg2 = (bt->phaseSeg2 - 1);
324 /* Calculate Time Segment1 value */
325 tSeg1 = (bt->phaseSeg1 + bt->propSeg - 1);
327 /* Write the BRP value */
328 btrValue |= ((bt->brp - 1) & DCAN_BTR_BRP);
330 /* Write the BRPE value */
331 btrValue |= (((bt->brp - 1) & EXTRACT_BRPE_VAL) << BRPE_SHIFT);
333 /* Write the Time Segment2 value */
334 btrValue |= ((tSeg2 << DCAN_BTR_TSEG2_SHIFT) & DCAN_BTR_TSEG2);
336 /* Write the Time Segment1 value */
337 btrValue |= ((tSeg1 << DCAN_BTR_TSEG1_SHIFT) & DCAN_BTR_TSEG1);
339 /* Set the BTR value to the DCAN bittiming register */
340 DCANBitTimingConfig(baseAdd, btrValue);
342 return errVal;
343 }
345 /**
346 * \brief This function will calculate the bit-timing parameters for the
347 * DCAN controller based on the input frequency and required bit-rate
348 * on the CAN bus.
349 *
350 * \param btc Pointer to _dcan_hw_params structure \n
351 * \param bt Pointer to _dcan_bittiming structure \n
352 * \param clkFreq Clock frequency to DCAN controller in MHz \n
353 *
354 * \return 'errVal' based on the bit-rate error \n
355 *
356 **/
357 unsigned int CANbitTimeCalculator(struct _dcan_hw_params *btc,
358 struct _dcan_bittiming *bt,
359 unsigned int clkFreq)
360 {
361 int sampl_pt, spt_error = 1000, tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
362 int brp = 0, spt = 0, best_tseg = 0, best_brp = 0;
363 long error = 0, best_error = 1000000000;
364 unsigned int errVal = NO_BIT_RATE_ERR;
365 unsigned long rate, timeQuanta;
367 if(bt->bitRate > 800000)
368 {
369 sampl_pt = 750;
370 }
372 else if(bt->bitRate > 500000)
373 {
374 sampl_pt = 800;
375 }
377 else
378 {
379 sampl_pt = 875;
380 }
382 for(tseg = (btc->tseg1Max + btc->tseg2Max) * 2 + 1;
383 tseg >= (btc->tseg1Min + btc->tseg2Min) * 2; tseg--)
384 {
385 tsegall = 1 + tseg / 2;
386 /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
387 brp = clkFreq / (tsegall * bt->bitRate) + tseg % 2;
388 /* chose brp step which is possible in system */
389 brp = (brp / btc->brpInc) * btc->brpInc;
390 if((brp < btc->brpMin) || (brp > btc->brpMax))
391 continue;
392 rate = clkFreq / (brp * tsegall);
393 error = bt->bitRate - rate;
394 /* tseg brp biterror */
395 if(error < 0)
396 error = -error;
397 if(error > best_error)
398 continue;
399 best_error = error;
400 if(error == 0)
401 {
402 spt = canUpdatSamPt(btc, sampl_pt, tseg / 2,
403 &tseg1, &tseg2);
404 error = sampl_pt - spt;
405 if(error < 0)
406 error = -error;
407 if(error > spt_error)
408 continue;
409 spt_error = error;
410 }
411 best_tseg = tseg / 2;
412 best_brp = brp;
413 if(error == 0)
414 break;
415 }
417 if(best_error)
418 {
419 /* Error in one-tenth of a percent */
420 error = (best_error * 1000) / bt->bitRate;
421 if(error > CAN_CALC_MAX_ERROR)
422 {
423 errVal = BIT_RATE_ERR_MAX;
424 }
425 else
426 {
427 errVal = BIT_RATE_ERR_WARN;
428 }
429 }
431 /* real sample point */
432 bt->samplePnt = canUpdatSamPt(btc, sampl_pt, best_tseg,
433 &tseg1, &tseg2);
435 timeQuanta = best_brp * 1000000000UL;
437 bt->tq = timeQuanta;
438 bt->propSeg = tseg1 / 2;
439 bt->phaseSeg1 = tseg1 - bt->propSeg;
440 bt->phaseSeg2 = tseg2;
441 bt->sjw = 1;
442 bt->brp = best_brp;
443 /* real bit-rate */
444 bt->bitRate = clkFreq / (bt->brp * (tseg1 + tseg2 + 1));
446 return errVal;
447 }
449 /**
450 * \brief This function will update the sampling point based on time
451 * segment values \n
452 *
453 * \return Updated sample point value \n
454 *
455 **/
456 int canUpdatSamPt(const struct _dcan_hw_params *ptr,
457 int sampl_pt, int tseg, int *tseg1, int *tseg2)
458 {
459 *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
461 if(*tseg2 < ptr->tseg2Min)
462 {
463 *tseg2 = ptr->tseg2Min;
464 }
466 if(*tseg2 > ptr->tseg2Max)
467 {
468 *tseg2 = ptr->tseg2Max;
469 }
471 *tseg1 = tseg - *tseg2;
473 if (*tseg1 > ptr->tseg1Max)
474 {
475 *tseg1 = ptr->tseg1Max;
476 *tseg2 = tseg - *tseg1;
477 }
479 return(1000 * (tseg + 1 - *tseg2) / (tseg + 1));
480 }
482 #endif /* #if (PLATFORM_DCAN_IN) */