CANBUS example for LPC17xx

snarlingfox wrote on Sunday, May 15, 2016:

Hi folks,

I’m looking to try utilising FreeRTOS with a NXP LPC1788 MPU (Specifically the HY-LPC1788-CORE board), however I’ve had difficulties getting the CAN IRQ to fire or read any usable data.

My setup is as follows;

  • LPC1788 as above
  • FreeRTOS included with LPCOpen (FreeRTOS version 7.3.0 - yep I know it’s old)
  • Keil uVision v4.71.2.0

The issue seems to be the CAN IRQ isn’t firing, if I manually poke it with Keils debugger, there’s no usable data. I’d class myself as an intermediate developer (not an expert) but my gut feeling is the CAN subsystem / memory space isn’t being initialised properly.

I am aware of the LPC17xx IRQ priority inversion, I have tried tweaking numerous values and I’ve hopefully ruled this out by manually firing an IRQ in the code. When this happens, my IRQ handler code is executed but alas no usable data.

My small project works as a standard non-RTOS project, albeit with performance issues (which is why I want to rewrite it with an RTOS).

What I was hoping for is a working example from one of you wonderful people in the hope to further my knowledge and get my little project working in what looks like an excellent framework (I love the idea of semaphores and queues) :slight_smile:

rtel wrote on Monday, May 16, 2016:

Am I right in thinking from your description that the CAN ISR is
executing correctly in an application that is running without FreeRTOS,
but is not executing when you are running FreeRTOS? If so, are you
trying the ISR after the scheduler has started, or before the scheduler
has started? As soon as you start using FreeRTOS API functions
interrupts will remain disabled until the scheduler is started - that is
done to prevent interrupts trying to use FreeRTOS calls prior to
FreeRTOS actually running.

Other than that - FreeRTOS does not do anything itself with interrupts,
and as long as you have the interrupt’s priority set at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY if you want to use an API function,
then you should not notice any difference with or without FreeRTOS.

If the ISR is being called, but the code in the ISR is not doing what
you want or expect, then please post the code.

Regards.

snarlingfox wrote on Tuesday, May 17, 2016:

Hi there,

I’ve had CANBUS working successfully on the LPC1788 platform for a good couple of years, using the standard CMSIS / LPCOpen frameworks.

I’m less inclined to believe it’s IRQ related as even when I manually trigger the IRQ using Keils debugger, the program will return gibberish. I know for a fact there should be something in the buffer because I’m firing data at it from an MBED LPC1768 which is received fine using non-RTOS code.

I honestly don’t know if it’s my setup, if I’m incorrectly initialising the CAN subsystem or what. Possibly the memory isn’t assigned properly. Attempting to send fails too with a transmission timeout.

Here’s a slimmed down code block (it may not compile as I’ve removed non-relevant blocks), it’s also hasn’t been touched in months as I took a break;

/*********************************\
* Includes and required variables *
\*********************************/

#include "board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#include <stdlib.h>
#include <string.h>
// #include <stdarg.h>

LPC_CAN_T *CANPort;
bool CANIRQInitialised;
const unsigned char CAN_INTERFACE = 0;
#define CAN_BAUD_RATE 500000UL
#define CAN_FILTER_FRAMES 0

xSemaphoreHandle xCANReceiveSemaphore;

typedef struct {
    unsigned char length;
    char *data;
} xMessage;



/*********************************\
* Callable functions              *
\*********************************/



/* Sets up the CAN controller */
void InitCAN(void) {
    if (CANIRQInitialised) {
        Chip_CAN_IntDisable(CANPort, CAN_IER_BITMASK);
        Chip_CAN_DeInit(CANPort);
    }
    if (CAN_INTERFACE == 1) CANPort = LPC_CAN2;
    else                    CANPort = LPC_CAN1;
    Chip_CAN_Init(CANPort);
    Chip_CAN_SetBitRate(CANPort, CAN_BAUD_RATE);
    Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE);
    Chip_CAN_IntEnable(CANPort, CAN_IER_BITMASK);
    CANIRQInitialised = 1;
}

/* Sets up system hardware */
static void prvSetupHardware (void) {
    Board_Init();
    InitCAN();
}



/*********************************\
* Tasks                           *
\*********************************/



/* CAN receive task */
static void vTaskCANReceive (void *pvParameters) {
    xMessage message;
    portBASE_TYPE xQueueStatus;
    CAN_MSG_T canframe;
    xSemaphoreTake(xCANReceiveSemaphore, 0);
    while (1) {
        Chip_CAN_IntEnable(CANPort, CAN_IER_BITMASK);
        message.length = 12;
        message.data = (char *)calloc(12, 0x0);
        while (Chip_CAN_Receive(CANPort, &canframe)) {
            canframe.ID &= ~CAN_EXTEND_ID_USAGE;
            message.data[0] = ((canframe.ID >> 24) & 0xFF);
            message.data[1] = ((canframe.ID >> 16) & 0xFF);
            message.data[2] = ((canframe.ID >> 8) & 0xFF);
            message.data[3] = ((canframe.ID >> 0) & 0xFF);
            memcpy(message.data + 4, canframe.Data, 8);
            DEBUGOUT("Received: %s", &message);
        }
    }
}



/*********************************\
* Interrupt handlers              *
\*********************************/



/* CAN IRQ handler */
void CAN_IRQHandler(void) {
    portBASE_TYPE xCurrentTaskInterrupted = pdFALSE;
    unsigned long IRQStatus = Chip_CAN_GetIntStatus(CANPort);
    DEBUGOUT("CAN IRQ received: 0x%04X\r\n", IRQStatus);
    if (!(IRQStatus & CAN_ICR_RI)) return;
    NVIC_ClearPendingIRQ(CAN_IRQn);
    Chip_CAN_IntDisable(CANPort, CAN_IER_BITMASK);
    DEBUGOUT("-");
    xSemaphoreGiveFromISR(xCANReceiveSemaphore, &xCurrentTaskInterrupted);
    portEND_SWITCHING_ISR(xCurrentTaskInterrupted);
}



/*********************************\
* Main function                   *
\*********************************/



int main (void) {
    /* Init */
    unsigned long i;
    prvSetupHardware();

    /* Queues and Semaphore */
    vSemaphoreCreateBinary(xCANReceiveSemaphore); if (xCANReceiveSemaphore == NULL) { DEBUGOUT("Unable to create xCANReceiveSemaphore\r\n"); return 1; }

    /* IRQs */
    Chip_UART_IntConfig(LPC_UART0, UART_INTCFG_RBR, ENABLE);
    NVIC_SetPriority(UART0_IRQn, configKERNEL_INTERRUPT_PRIORITY);
    NVIC_EnableIRQ(UART0_IRQn);
    DEBUGOUT("Waiting for CAN init... ");
    InitCAN();
    for (i=0; i<50000000; i++) { }
    NVIC_SetPriority(CAN_IRQn, configKERNEL_INTERRUPT_PRIORITY - 1);
    NVIC_EnableIRQ(CAN_IRQn);
    CANIRQInitialised = 1;
    AddFrameToAFLUT(0, 0x600UL, 0x700UL);
    InitCAN();
    DEBUGOUT("Done!\r\n");

    /* Tasks */
    xTaskCreate(vTaskCANReceive, (signed char *) "CAN Receive", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 1UL), (xTaskHandle *) NULL);

    /* Start the scheduler */
    vTaskStartScheduler();

    /* Should never arrive here */
    return 1;
}

edwards3 wrote on Tuesday, May 17, 2016:

What does DEBUGOUT() do? If it uses semihosting to output chars that could be your issue as it will interfere with FreeRTOS interrupts. Even if it is not using semihosting I would recommend trying without DEBUGOUT() as you are calling it from tasks and interrupts.

snarlingfox wrote on Tuesday, May 17, 2016:

Hi MEdwards,

DEBUGOUT is a simple function to write a message (filtered through printf) to the debug UART so I can get some measure of feedback over what is exactly happening.

I’m unsure it’ll be tampering with much. I’m just firing up the code now to see exactly what was failing.