LPCOpen Platform for LPC18XX/43XX microcontrollers: C:/w/lpcopen_docs/software/lpc_core/lpc_chip/chip_18xx_43xx/ccan_18xx_43xx.c Source File

| LPCOpen Platform for LPC18XX/43XX microcontrollers 18XX43XX LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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 */
47 STATIC void configTimming(LPC_CCAN_T *pCCAN,
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 */
72 STATIC uint8_t getFreeMsgObject(LPC_CCAN_T *pCCAN)
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 */
91 STATIC CHIP_CCU_CLK_T Chip_CCAN_GetClockIndex(LPC_CCAN_T *pCCAN)
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 */
110 void Chip_CCAN_Init(LPC_CCAN_T *pCCAN)
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 }
119 Chip_CCAN_ClearStatus(pCCAN, (CCAN_STAT_RXOK | CCAN_STAT_TXOK));
120 }
121
122 /* De-initialize the CCAN peripheral */
123 void Chip_CCAN_DeInit(LPC_CCAN_T *pCCAN)
124 {
125 Chip_Clock_Disable(Chip_CCAN_GetClockIndex(pCCAN));
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;
132 pClk = Chip_Clock_GetRate(Chip_CCAN_GetClockIndex(pCCAN));
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 */
160 void Chip_CCAN_SetMsgObject(LPC_CCAN_T *pCCAN,
161 CCAN_MSG_IF_T IFSel,
162 CCAN_TRANSFER_DIR_T dir,
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
213 Chip_CCAN_TransferMsgObject(pCCAN, IFSel, CCAN_IF_CMDMSK_WR | CCAN_IF_CMDMSK_TRANSFER_ALL, msgNum);
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;
224 Chip_CCAN_TransferMsgObject(pCCAN,
225 IFSel,
226 CCAN_IF_CMDMSK_RD | CCAN_IF_CMDMSK_TRANSFER_ALL | CCAN_IF_CMDMSK_R_CLRINTPND,
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 */
246 void Chip_CCAN_TransferMsgObject(LPC_CCAN_T *pCCAN,
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
269 Chip_CCAN_TransferMsgObject(pCCAN, IFSel, CCAN_IF_CMDMSK_WR | CCAN_IF_CMDMSK_ARB, msgNum);
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