blob: 61e7f47a037260fc7cd437e967e70edb77de07ac [file] [log] [blame]
brians0ab60bb2013-01-31 02:21:51 +00001/* Standard includes. */
2#include "stdio.h"
3
4/* Scheduler includes. */
5#include "FreeRTOS.h"
6#include "queue.h"
7#include "task.h"
8
9/* Demo app includes. */
10#include "flash.h"
11#include "partest.h"
12#include "analog.h"
brians0ab60bb2013-01-31 02:21:51 +000013#include "LPCUSB/usbapi.h"
14#include "CAN.h"
15
16static xQueueHandle CAN_tx_queue = NULL, CAN_rx_queue = NULL;
17
18/** Send a CAN message. The message is stored by copy.
19 *
20 * \returns Zero on success, and one on failure to queue the message.
21 */
22int CAN_send(can_message *message) {
23 uint32_t sr = CAN1->SR;
24 // Queue the message up in a queue!
25 if (sr & 0x00040404) {
26 uint32_t IFx = (message->RTR << 30) +
27 (message->length << 16) +
28 (message->priority);
29
30 uint32_t data0 = message->wdata[0];
31 uint32_t data1 = message->wdata[1];
32
33 if(sr & 0x00000004){
34 CAN1->TFI1 = IFx;
35 CAN1->TID1 = message->id;
36 CAN1->TDA1 = data0;
37 CAN1->TDB1 = data1;
38 CAN1->CMR = 0x00000021;
39 printf("Writing 1\n");
40 return 0;
41 } else if(sr & 0x00000400) {
42 CAN1->TFI2 = IFx;
43 CAN1->TID2 = message->id;
44 CAN1->TDA2 = data0;
45 CAN1->TDB2 = data1;
46 CAN1->CMR = 0x00000041;
47 return 0;
48 } else if(sr & 0x00040000) {
49 CAN1->TFI3 = IFx;
50 CAN1->TID3 = message->id;
51 CAN1->TDA3 = data0;
52 CAN1->TDB3 = data1;
53 CAN1->CMR = 0x00000081;
54 return 0;
55 }
56 return 1;
57 }
58 return xQueueSend(CAN_tx_queue, message, 0) != pdPASS;
59}
60
61/**
62 * Get a CAN message, blocking if one isn't available.
63 * This is useful for a read/dispatch thread.
64 *
65 * \returns 0 on Success, and nonzero on failure
66 */
67int CAN_get(can_message *message) {
68 // Blocking read the queue.
69 if (xQueueReceive(CAN_rx_queue, message, portMAX_DELAY) == pdFALSE) {
70 return 1;
71 } else {
72 return message->error;
73 }
74}
75
76void CAN_IRQHandler(void) {
77 uint32_t interrupts = CAN1->ICR;
78 long lHigherPriorityTaskWoken = pdFALSE;
79 can_message message;
80 // CAN1->CMR contains all the action items, like initiating a send et all.
81 // On a bus error interrupt, set an error semaphore so the handler can set the LED, or set it ourselfs.
82 printf("CAN interrupt\n");
83
84 if (interrupts & 0x1) {
85 // Recieved a packet.
86 uint32_t rfs = CAN1->RFS;
87
88 message.RTR = (rfs & 0x40000000) >> 30;
89 message.length = (rfs & 0x000f0000) >> 16;
90 message.id = CAN1->RID & 0x000007ff;
91
92 message.wdata[0] = CAN1->RDA;
93 message.wdata[1] = CAN1->RDB;
94
95 // Release the registers
96 CAN1->CMR = 0x00000004;
97
98 message.error = 0;
99
100 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
101 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
102 return;
103 }
104
105 if (interrupts & 0x602) {
106 // TX buffers are no longer empty (now empty??)
107 if (xQueueReceiveFromISR(CAN_tx_queue, &message, &lHigherPriorityTaskWoken)) {
108 uint32_t IFx = (message.RTR << 30) +
109 (message.length << 16) +
110 (message.priority);
111 uint32_t data0 = message.wdata[0];
112 uint32_t data1 = message.wdata[1];
113
114 // Message was in the queue, and will now be sent.
115 if (interrupts & 0x2) {
116 // TX buffer 1 is no longer empty
117 CAN1->TFI1 = IFx;
118 CAN1->TID1 = message.id;
119 CAN1->TDA1 = data0;
120 CAN1->TDB1 = data1;
121 CAN1->CMR = 0x00000021;
122 } else if (interrupts & 0x200) {
123 // TX buffer 2 is no longer empty
124 CAN1->TFI2 = IFx;
125 CAN1->TID2 = message.id;
126 CAN1->TDA2 = data0;
127 CAN1->TDB2 = data1;
128 CAN1->CMR = 0x00000041;
129 } else if (interrupts & 0x400) {
130 // TX buffer 3 is no longer empty
131 CAN1->TFI3 = IFx;
132 CAN1->TID3 = message.id;
133 CAN1->TDA3 = data0;
134 CAN1->TDB3 = data1;
135 CAN1->CMR = 0x00000081;
136 }
137 }
138 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
139 return;
140 }
141
142 if (interrupts & 0x4) {
143 // Error Warning interrupt
144 message.error = 0x01;
145 if (CAN1->GSR & 0x00000040) {
146 // Reached the limit.
147 message.error = 0x01;
148 } else if (CAN1->GSR & 0x00000080) {
149 // No longer allowed to send.
150 message.error = 0x20;
151 } else {
152 message.error = 0x20;
153 }
154 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
155 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
156 return;
157 }
158
159 if (interrupts & 0x8) {
160 // Data overrun
161 CAN1->CMR = 0x00000008;
162 message.error = 0x02;
163 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
164 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
165 return;
166 }
167
168 if (interrupts & 0x20) {
169 // Error Passive Interrupt
170 message.error = 0x04;
171 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
172 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
173 return;
174 }
175
176 if (interrupts & 0x80) {
177 // Bus Error Interrupt
178 message.error = 0x08;
179 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
180 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
181 return;
182 }
183 message.error = 0x10;
184 xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
185 portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
186}
187
188extern int VCOM_getchar(void);
189
190static portTASK_FUNCTION(vCAN1Write, pvParameters) {
191 can_message message;
192 message.RTR = 0;
193 message.id = 12;
194 message.priority = 1;
195 message.length = 4;
196
197 // Enable the pins.
198 PINCON->PINSEL3 = (PINCON->PINSEL3 & 0xffc3cf3f) | 0x00141040;
199
200 portTickType xLastFlashTime;
201 xLastFlashTime = xTaskGetTickCount();
202
203 for (;;) {
brians0ab60bb2013-01-31 02:21:51 +0000204
205 int c = VCOM_getchar();
206 while (c != -1) {
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000207 printf("hello in write\n");
brians0ab60bb2013-01-31 02:21:51 +0000208 int j = c;
209 printf("Sending data 0x%x\n", j);
210 message.data[0] = j++;
211 message.data[1] = j++;
212 message.data[2] = j++;
213 message.data[3] = j;
214 CAN_send(&message);
215 c = VCOM_getchar();
216 }
217
218 vTaskDelayUntil(&xLastFlashTime, 500);
219 }
220}
221static portTASK_FUNCTION(vCAN1, pvParameters) {
222 portTickType xLastFlashTime;
223
224 CAN_rx_queue = xQueueCreate(20, sizeof(can_message));
225 CAN_tx_queue = xQueueCreate(5, sizeof(char));
226
227 if ((CAN_rx_queue == NULL) || (CAN_tx_queue == NULL)) {
228 /* Not enough heap available to create the buffer queues, can't do
229 * anything so just delete ourselves.
230 */
231 vTaskDelete(NULL);
232 }
233
brians0ab60bb2013-01-31 02:21:51 +0000234 // Enable CAN
235 SC->PCONP |= PCONP_PCCAN1;
236
237 PINCON->PINSEL0 = (PINCON->PINSEL0 & 0xfffffff0) | 0x00000005;
238 PINCON->PINMODE0 = (PINCON->PINMODE0 & 0xfffffffc) | 0x00000001;
239
240 // Enable RX, TX, overrun, Bus Error,
241 // Error Passive/Active, and Error Warning Interupts.
242 NVIC_SetPriority(CAN_IRQn, configCAN_INTERRUPT_PRIORITY);
243 NVIC_EnableIRQ(CAN_IRQn);
244
245 CAN1->IER = 0x000006af;
246
247 // Priority depends on the TX priority register
248 CAN1->MOD = 0x00000008;
249
250 CAN1->CMR = 0x00000004;
251
252 CANAF->AFMR = 0x00000002;
253
254 // CAN clocks. (Defaults look fine)
255
256 /* We need to initialise xLastFlashTime prior to the first call to
257 vTaskDelayUntil(). */
258 xLastFlashTime = xTaskGetTickCount();
259
260 can_message message;
261
262 xTaskCreate(vCAN1Write, (signed char *) "CAN1wx", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 4, NULL);
263
264 for (;;) {
265 /* Delay for half the flash period then turn the LED on. */
266 if (CAN_get(&message)) {
267 printf("Message error 0x%x\n", message.error);
268 } else {
269 printf("Got a message with a length of %d\n", message.length);
270 printf("data[0] = 0x%x\n", message.data[0]);
271 printf("data[1] = 0x%x\n", message.data[1]);
272 printf("data[2] = 0x%x\n", message.data[2]);
273 printf("data[3] = 0x%x\n", message.data[3]);
274 }
275 }
276}
277
Brian Silverman1dbe3542013-10-31 20:29:11 -0700278void CAN_PCLKSEL(void) {
279 // Set all of the CAN stuff to run at CCLK/6, which translates to about 1 Mbit
280 // (1.042).
281 SC->PCLKSEL0 |= 3 << 26 | 3 << 28 | 3 << 30;
282}
brians0ab60bb2013-01-31 02:21:51 +0000283
284void initCAN(void){
285 xTaskCreate(vCAN1, (signed char *) "CAN1rx", configMINIMAL_STACK_SIZE + 400, NULL, tskIDLE_PRIORITY + 1, NULL);
286}