blob: 591c6fc34b7305fd4a265e6e7bb0d773809b21de [file] [log] [blame]
/* Standard includes. */
#include "stdio.h"
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
/* Demo app includes. */
#include "flash.h"
#include "partest.h"
#include "analog.h"
#include "LPCUSB/usbapi.h"
#include "CAN.h"
static xQueueHandle CAN_tx_queue = NULL, CAN_rx_queue = NULL;
/** Send a CAN message. The message is stored by copy.
*
* \returns Zero on success, and one on failure to queue the message.
*/
int CAN_send(can_message *message) {
uint32_t sr = CAN1->SR;
// Queue the message up in a queue!
if (sr & 0x00040404) {
uint32_t IFx = (message->RTR << 30) +
(message->length << 16) +
(message->priority);
uint32_t data0 = message->wdata[0];
uint32_t data1 = message->wdata[1];
if(sr & 0x00000004){
CAN1->TFI1 = IFx;
CAN1->TID1 = message->id;
CAN1->TDA1 = data0;
CAN1->TDB1 = data1;
CAN1->CMR = 0x00000021;
printf("Writing 1\n");
return 0;
} else if(sr & 0x00000400) {
CAN1->TFI2 = IFx;
CAN1->TID2 = message->id;
CAN1->TDA2 = data0;
CAN1->TDB2 = data1;
CAN1->CMR = 0x00000041;
return 0;
} else if(sr & 0x00040000) {
CAN1->TFI3 = IFx;
CAN1->TID3 = message->id;
CAN1->TDA3 = data0;
CAN1->TDB3 = data1;
CAN1->CMR = 0x00000081;
return 0;
}
return 1;
}
return xQueueSend(CAN_tx_queue, message, 0) != pdPASS;
}
/**
* Get a CAN message, blocking if one isn't available.
* This is useful for a read/dispatch thread.
*
* \returns 0 on Success, and nonzero on failure
*/
int CAN_get(can_message *message) {
// Blocking read the queue.
if (xQueueReceive(CAN_rx_queue, message, portMAX_DELAY) == pdFALSE) {
return 1;
} else {
return message->error;
}
}
void CAN_IRQHandler(void) {
uint32_t interrupts = CAN1->ICR;
long lHigherPriorityTaskWoken = pdFALSE;
can_message message;
// CAN1->CMR contains all the action items, like initiating a send et all.
// On a bus error interrupt, set an error semaphore so the handler can set the LED, or set it ourselfs.
printf("CAN interrupt\n");
if (interrupts & 0x1) {
// Recieved a packet.
uint32_t rfs = CAN1->RFS;
message.RTR = (rfs & 0x40000000) >> 30;
message.length = (rfs & 0x000f0000) >> 16;
message.id = CAN1->RID & 0x000007ff;
message.wdata[0] = CAN1->RDA;
message.wdata[1] = CAN1->RDB;
// Release the registers
CAN1->CMR = 0x00000004;
message.error = 0;
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
if (interrupts & 0x602) {
// TX buffers are no longer empty (now empty??)
if (xQueueReceiveFromISR(CAN_tx_queue, &message, &lHigherPriorityTaskWoken)) {
uint32_t IFx = (message.RTR << 30) +
(message.length << 16) +
(message.priority);
uint32_t data0 = message.wdata[0];
uint32_t data1 = message.wdata[1];
// Message was in the queue, and will now be sent.
if (interrupts & 0x2) {
// TX buffer 1 is no longer empty
CAN1->TFI1 = IFx;
CAN1->TID1 = message.id;
CAN1->TDA1 = data0;
CAN1->TDB1 = data1;
CAN1->CMR = 0x00000021;
} else if (interrupts & 0x200) {
// TX buffer 2 is no longer empty
CAN1->TFI2 = IFx;
CAN1->TID2 = message.id;
CAN1->TDA2 = data0;
CAN1->TDB2 = data1;
CAN1->CMR = 0x00000041;
} else if (interrupts & 0x400) {
// TX buffer 3 is no longer empty
CAN1->TFI3 = IFx;
CAN1->TID3 = message.id;
CAN1->TDA3 = data0;
CAN1->TDB3 = data1;
CAN1->CMR = 0x00000081;
}
}
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
if (interrupts & 0x4) {
// Error Warning interrupt
message.error = 0x01;
if (CAN1->GSR & 0x00000040) {
// Reached the limit.
message.error = 0x01;
} else if (CAN1->GSR & 0x00000080) {
// No longer allowed to send.
message.error = 0x20;
} else {
message.error = 0x20;
}
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
if (interrupts & 0x8) {
// Data overrun
CAN1->CMR = 0x00000008;
message.error = 0x02;
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
if (interrupts & 0x20) {
// Error Passive Interrupt
message.error = 0x04;
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
if (interrupts & 0x80) {
// Bus Error Interrupt
message.error = 0x08;
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
return;
}
message.error = 0x10;
xQueueSendFromISR(CAN_rx_queue, &message, &lHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(lHigherPriorityTaskWoken);
}
extern int VCOM_getchar(void);
static portTASK_FUNCTION(vCAN1Write, pvParameters) {
can_message message;
message.RTR = 0;
message.id = 12;
message.priority = 1;
message.length = 4;
// Enable the pins.
PINCON->PINSEL3 = (PINCON->PINSEL3 & 0xffc3cf3f) | 0x00141040;
portTickType xLastFlashTime;
xLastFlashTime = xTaskGetTickCount();
for (;;) {
int c = VCOM_getchar();
while (c != -1) {
printf("hello in write\n");
int j = c;
printf("Sending data 0x%x\n", j);
message.data[0] = j++;
message.data[1] = j++;
message.data[2] = j++;
message.data[3] = j;
CAN_send(&message);
c = VCOM_getchar();
}
vTaskDelayUntil(&xLastFlashTime, 500);
}
}
static portTASK_FUNCTION(vCAN1, pvParameters) {
portTickType xLastFlashTime;
CAN_rx_queue = xQueueCreate(20, sizeof(can_message));
CAN_tx_queue = xQueueCreate(5, sizeof(char));
if ((CAN_rx_queue == NULL) || (CAN_tx_queue == NULL)) {
/* Not enough heap available to create the buffer queues, can't do
* anything so just delete ourselves.
*/
vTaskDelete(NULL);
}
// Enable CAN
SC->PCONP |= PCONP_PCCAN1;
PINCON->PINSEL0 = (PINCON->PINSEL0 & 0xfffffff0) | 0x00000005;
PINCON->PINMODE0 = (PINCON->PINMODE0 & 0xfffffffc) | 0x00000001;
// Enable RX, TX, overrun, Bus Error,
// Error Passive/Active, and Error Warning Interupts.
NVIC_SetPriority(CAN_IRQn, configCAN_INTERRUPT_PRIORITY);
NVIC_EnableIRQ(CAN_IRQn);
CAN1->IER = 0x000006af;
// Priority depends on the TX priority register
CAN1->MOD = 0x00000008;
CAN1->CMR = 0x00000004;
CANAF->AFMR = 0x00000002;
// CAN clocks. (Defaults look fine)
/* We need to initialise xLastFlashTime prior to the first call to
vTaskDelayUntil(). */
xLastFlashTime = xTaskGetTickCount();
can_message message;
xTaskCreate(vCAN1Write, (signed char *) "CAN1wx", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 4, NULL);
for (;;) {
/* Delay for half the flash period then turn the LED on. */
if (CAN_get(&message)) {
printf("Message error 0x%x\n", message.error);
} else {
printf("Got a message with a length of %d\n", message.length);
printf("data[0] = 0x%x\n", message.data[0]);
printf("data[1] = 0x%x\n", message.data[1]);
printf("data[2] = 0x%x\n", message.data[2]);
printf("data[3] = 0x%x\n", message.data[3]);
}
}
}
void initCAN(void){
xTaskCreate(vCAN1, (signed char *) "CAN1rx", configMINIMAL_STACK_SIZE + 400, NULL, tskIDLE_PRIORITY + 1, NULL);
}