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