LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
ccan_18xx_43xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC18xx/43xx CCAN driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /*****************************************************************************
39  * Public types/enumerations/variables
40  ****************************************************************************/
41 
42 /*****************************************************************************
43  * Private functions
44  ****************************************************************************/
45 
46 /* Configure the bit timing for CCAN bus */
48  uint32_t ClkDiv,
49  uint32_t BaudRatePrescaler,
50  uint8_t SynJumpWidth,
51  uint8_t Tseg1,
52  uint8_t Tseg2)
53 {
54  /* Reset software */
55  if (!(pCCAN->CNTL & CCAN_CTRL_INIT)) {
56  pCCAN->CNTL |= CCAN_CTRL_INIT;
57  }
58 
59  /*Set bus timing */
60  pCCAN->CLKDIV = ClkDiv; /* Divider for CAN VPB3 clock */
61  pCCAN->CNTL |= CCAN_CTRL_CCE; /* Start configuring bit timing */
62  pCCAN->BT = (BaudRatePrescaler & 0x3F) | (SynJumpWidth & 0x03) << 6 | (Tseg1 & 0x0F) << 8 | (Tseg2 & 0x07) << 12;
63  pCCAN->BRPE = BaudRatePrescaler >> 6; /* Set Baud Rate Prescaler MSBs */
64  pCCAN->CNTL &= ~CCAN_CTRL_CCE; /* Stop configuring bit timing */
65 
66  /* Finish software initialization */
67  pCCAN->CNTL &= ~CCAN_CTRL_INIT;
68  while ( pCCAN->CNTL & CCAN_CTRL_INIT ) {}
69 }
70 
71 /* Return 1->32; 0 if not find free msg */
73 {
74  uint32_t msg_valid;
75  uint8_t i;
76  msg_valid = Chip_CCAN_GetValidMsg(pCCAN);
77  for (i = 0; i < CCAN_MSG_MAX_NUM; i++) {
78  if (!((msg_valid >> i) & 1UL)) {
79  return i + 1;
80  }
81  }
82  return 0; // No free object
83 }
84 
85 STATIC void freeMsgObject(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, uint8_t msgNum)
86 {
87  Chip_CCAN_SetValidMsg(pCCAN, IFSel, msgNum, false);
88 }
89 
90 /* Returns clock index for the peripheral block */
92 {
93  CHIP_CCU_CLK_T clkCCAN;
94 
95  if (pCCAN == LPC_C_CAN1) {
96  clkCCAN = CLK_APB1_CAN1;
97  }
98  else {
99  clkCCAN = CLK_APB3_CAN0;
100  }
101 
102  return clkCCAN;
103 }
104 
105 /*****************************************************************************
106  * Public functions
107  ****************************************************************************/
108 
109 /* Initialize the CCAN peripheral, free all message object in RAM */
111 {
112  uint8_t i;
113 
114  Chip_Clock_EnableOpts(Chip_CCAN_GetClockIndex(pCCAN), true, false, 1);
115 
116  for (i = 1; i <= CCAN_MSG_MAX_NUM; i++) {
117  freeMsgObject(pCCAN, CCAN_MSG_IF1, i);
118  }
120 }
121 
122 /* De-initialize the CCAN peripheral */
124 {
126 }
127 
128 /* Select bit rate for CCAN bus */
129 Status Chip_CCAN_SetBitRate(LPC_CCAN_T *pCCAN, uint32_t bitRate)
130 {
131  uint32_t pClk, div, quanta, segs, seg1, seg2, clk_per_bit, can_sjw;
133  clk_per_bit = pClk / bitRate;
134 
135  for (div = 0; div <= 15; div++) {
136  for (quanta = 1; quanta <= 32; quanta++) {
137  for (segs = 3; segs <= 17; segs++) {
138  if (clk_per_bit == (segs * quanta * (div + 1))) {
139  segs -= 3;
140  seg1 = segs / 2;
141  seg2 = segs - seg1;
142  can_sjw = seg1 > 3 ? 3 : seg1;
143  configTimming(pCCAN, div, quanta - 1, can_sjw, seg1, seg2);
144  return SUCCESS;
145  }
146  }
147  }
148  }
149  return ERROR;
150 }
151 
152 /* Clear the status of CCAN bus */
153 void Chip_CCAN_ClearStatus(LPC_CCAN_T *pCCAN, uint32_t val)
154 {
155  uint32_t tmp = Chip_CCAN_GetStatus(pCCAN);
156  Chip_CCAN_SetStatus(pCCAN, tmp & (~val));
157 }
158 
159 /* Set a message into the message object in message RAM */
161  CCAN_MSG_IF_T IFSel,
163  bool remoteFrame,
164  uint8_t msgNum,
165  const CCAN_MSG_OBJ_T *pMsgObj)
166 {
167  uint16_t *pData;
168  uint32_t msgCtrl = 0;
169 
170  if (pMsgObj == NULL) {
171  return;
172  }
173  pData = (uint16_t *) (pMsgObj->data);
174 
175  msgCtrl |= CCAN_IF_MCTRL_UMSK | CCAN_IF_MCTRL_RMTEN(remoteFrame) | CCAN_IF_MCTRL_EOB |
176  (pMsgObj->dlc & CCAN_IF_MCTRL_DLC_MSK);
177  if (dir == CCAN_TX_DIR) {
178  msgCtrl |= CCAN_IF_MCTRL_TXIE;
179  if (!remoteFrame) {
180  msgCtrl |= CCAN_IF_MCTRL_TXRQ;
181  }
182  }
183  else {
184  msgCtrl |= CCAN_IF_MCTRL_RXIE;
185  }
186 
187  pCCAN->IF[IFSel].MCTRL = msgCtrl;
188  pCCAN->IF[IFSel].DA1 = *pData++; /* Lower two bytes of message pointer */
189  pCCAN->IF[IFSel].DA2 = *pData++; /* Upper two bytes of message pointer */
190  pCCAN->IF[IFSel].DB1 = *pData++; /* Lower two bytes of message pointer */
191  pCCAN->IF[IFSel].DB2 = *pData; /* Upper two bytes of message pointer */
192 
193  /* Configure arbitration */
194  if (!(pMsgObj->id & (0x1 << 30))) { /* bit 30 is 0, standard frame */
195  /* Mxtd: 0, Mdir: 1, Mask is 0x7FF */
196  pCCAN->IF[IFSel].MSK2 = CCAN_IF_MASK2_MDIR(dir) | (CCAN_MSG_ID_STD_MASK << 2);
197  pCCAN->IF[IFSel].MSK1 = 0x0000;
198 
199  /* MsgVal: 1, Mtd: 0, Dir: 1, ID = 0x200 */
200  pCCAN->IF[IFSel].ARB2 = CCAN_IF_ARB2_MSGVAL | CCAN_IF_ARB2_DIR(dir) | (pMsgObj->id << 2);
201  pCCAN->IF[IFSel].ARB1 = 0x0000;
202  }
203  else { /* Extended frame */
204  /* Mxtd: 1, Mdir: 1, Mask is 0x1FFFFFFF */
205  pCCAN->IF[IFSel].MSK2 = CCAN_IF_MASK2_MXTD | CCAN_IF_MASK2_MDIR(dir) | (CCAN_MSG_ID_EXT_MASK >> 16);
206  pCCAN->IF[IFSel].MSK1 = CCAN_MSG_ID_EXT_MASK & 0x0000FFFF;
207 
208  /* MsgVal: 1, Mtd: 1, Dir: 1, ID = 0x200000 */
209  pCCAN->IF[IFSel].ARB2 = CCAN_IF_ARB2_MSGVAL | CCAN_IF_ARB2_XTD | CCAN_IF_ARB2_DIR(dir) | (pMsgObj->id >> 16);
210  pCCAN->IF[IFSel].ARB1 = pMsgObj->id & 0x0000FFFF;
211  }
212 
214 }
215 
216 /* Get a message object in message RAM into the message buffer */
217 void Chip_CCAN_GetMsgObject(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, uint8_t msgNum, CCAN_MSG_OBJ_T *pMsgObj)
218 {
219  uint32_t *pData;
220  if (!pMsgObj) {
221  return;
222  }
223  pData = (uint32_t *) pMsgObj->data;
225  IFSel,
227  msgNum);
228 
229  if (pCCAN->IF[IFSel].MCTRL & CCAN_IF_MCTRL_NEWD) {
230  pMsgObj->id = (pCCAN->IF[IFSel].ARB1) | (pCCAN->IF[IFSel].ARB2 << 16);
231  pMsgObj->dlc = pCCAN->IF[IFSel].MCTRL & CCAN_IF_MCTRL_DLC_MSK;
232  *pData++ = (pCCAN->IF[IFSel].DA2 << 16) | pCCAN->IF[IFSel].DA1;
233  *pData = (pCCAN->IF[IFSel].DB2 << 16) | pCCAN->IF[IFSel].DB1;
234 
235  if (pMsgObj->id & (0x1 << 30)) {
236  pMsgObj->id &= CCAN_MSG_ID_EXT_MASK;
237  }
238  else {
239  pMsgObj->id >>= 18;
240  pMsgObj->id &= CCAN_MSG_ID_STD_MASK;
241  }
242  }
243 }
244 
245 /* Data transfer between IF registers and Message RAM */
247  CCAN_MSG_IF_T IFSel,
248  uint32_t mask,
249  uint32_t msgNum) {
250  msgNum &= 0x3F;
251  pCCAN->IF[IFSel].CMDMSK = mask;
252  pCCAN->IF[IFSel].CMDREQ = msgNum;
253  while (pCCAN->IF[IFSel].CMDREQ & CCAN_IF_CMDREQ_BUSY ) {}
254 }
255 
256 /* Enable/Disable the message object to valid */
257 void Chip_CCAN_SetValidMsg(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, uint8_t msgNum, bool valid)
258 {
259 
260  uint32_t temp;
261  temp = pCCAN->IF[IFSel].ARB2;
262  if (!valid) {
263  pCCAN->IF[IFSel].ARB2 = (temp & (~CCAN_IF_ARB2_MSGVAL));
264  }
265  else {
266  pCCAN->IF[IFSel].ARB2 = (temp | (CCAN_IF_ARB2_MSGVAL));
267  }
268 
270 }
271 
272 /* Send a message */
273 void Chip_CCAN_Send(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, bool remoteFrame, CCAN_MSG_OBJ_T *pMsgObj)
274 {
275  uint8_t msgNum = getFreeMsgObject(pCCAN);
276  if (!msgNum) {
277  return;
278  }
279  Chip_CCAN_SetMsgObject(pCCAN, IFSel, CCAN_TX_DIR, remoteFrame, msgNum, pMsgObj);
280  while (Chip_CCAN_GetTxRQST(pCCAN) >> (msgNum - 1)) { // blocking , wait for sending completed
281  }
282  if (!remoteFrame) {
283  freeMsgObject(pCCAN, IFSel, msgNum);
284  }
285 }
286 
287 /* Register a message ID for receiving */
288 void Chip_CCAN_AddReceiveID(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, uint32_t id)
289 {
290  CCAN_MSG_OBJ_T temp;
291  uint8_t msgNum = getFreeMsgObject(pCCAN);
292  if (!msgNum) {
293  return;
294  }
295  temp.id = id;
296  Chip_CCAN_SetMsgObject(pCCAN, IFSel, CCAN_RX_DIR, false, msgNum, &temp);
297 }
298 
299 /* Remove a registered message ID from receiving */
300 void Chip_CCAN_DeleteReceiveID(LPC_CCAN_T *pCCAN, CCAN_MSG_IF_T IFSel, uint32_t id)
301 {
302  uint8_t i;
303  CCAN_MSG_OBJ_T temp;
304  for (i = 1; i <= CCAN_MSG_MAX_NUM; i++) {
305  Chip_CCAN_GetMsgObject(pCCAN, IFSel, i, &temp);
306  if (temp.id == id) {
307  freeMsgObject(pCCAN, IFSel, i);
308  }
309  }
310 }
311