Hello,
I have troubles trying to make work the CAN interruption implementng freeRTOS. It only triggers the ISR only once and it never is executed again.
I connected CAN2 and CAN3 between them to check the communication.
I attach the complete code below:
/** @file sys_main.c
* @brief Application main file
* @date 07-July-2017
* @version 04.07.00
*
* This file contains an empty main function,
* which can be used for the application.
*/
/*
* Copyright (C) 2009-2016 Texas Instruments Incorporated - www.ti.com
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* USER CODE BEGIN (0) */
#define EXTWD_PRIORITY ( tskIDLE_PRIORITY + 3)
#define SCI_PRIORITY ( tskIDLE_PRIORITY + 2)
#define MAIN_PRIORITY ( tskIDLE_PRIORITY + 2)
#define CAN_PRIORITY ( tskIDLE_PRIORITY + 2)
/* USER CODE END */
/* Include Files */
#include "sys_common.h"
/* USER CODE BEGIN (1) */
#include "system.h"
#include "het.h"
#include "gio.h"
#include "reg_pcr.h"
#include "sys_pcr.h"
#include "sys_pmm.h"
#include "reg_vim.h"
#include "sci.h"
#include "string.h"
#include "reg_can.h"
#include "bl_can.h"
#include "can.h"
#include "sys_common.h"
#include "sys_core.h"
/* Include FreeRTOS scheduler files */
#include "FreeRTOS.h"
#include "os_task.h"
#include "os_queue.h"
//Command List:
#include "interfacesCommandDef.h"
/* USER CODE END */
/** @fn void main(void)
* @brief Application main function
* @note This function is empty by default.
*
* This function is called after startup.
* The user can use this function to implement the application.
*/
/* USER CODE BEGIN (2) */
//Settings:
//Globals:
//Task Handlers:
xTaskHandle xTask1Handle1; //vExtWD task handle
xTaskHandle xTask2Handle1; //vUART task handle
xTaskHandle xTask3Handle1; //vMain task handle
xTaskHandle xTask4Handle1; //vCAN task handle
//Queue handlers:
QueueHandle_t xQueue1; //Queue1 is used to send data from vUART to vMain task.
QueueHandle_t xQueue2; //Queue2 is used to send data from sciNotification to vUART task.
QueueHandle_t xQueue3; //Queue3 is used to send data from canMessageNotification to vCAN task.
//Set of structures to be sent through queues:
struct qMessage
{
uint8_t len, sciRxMessage, rxData;
uint8_t buffer[128];
}xMessage;
struct qMessage2
{
uint8_t len, sciRxMessage, rxData;
uint8_t buffer[128];
}xMessage2;
struct qMessage3
{
uint8_t len, sciRxMessage, rxData;
uint8_t buffer[128];
}xMessage3;
//Functions:
void sysInit(void);
void osInit(void);
void sciDisplayData(sciBASE_t *, uint8 *,uint32);
bool cDecoder(struct qMessage *);
uint8_t delayms(uint16);
//Tasks:
void vExtWD(void *pvParameters); //External watchdog pulse generation
void vCAN(void *pvParameters); //CAN communication task
void vUART(void *pvParameters); //Debug UART communication task
void vMain(void *pvParameters); //Main task
/* USER CODE END */
int main(void)
{
/* USER CODE BEGIN (3) */
sysInit(); //System initialization.
osInit(); //Operative System initialization.
/* Run forever */
while(1);
/* USER CODE END */
return 0;
}
/* USER CODE BEGIN (4) */
/*************************************
* Functions, Tasks and ISR routines *
*************************************/
/*********************************
* CAN interrupt service routine *
*********************************/
void canMessageNotification(canBASE_t *node, uint32 messageBox)
{
//uint8_t rxKey;
uint8_t *Buffer;
uint16_t teleBuffer[8];
Buffer = ((uint8_t *)teleBuffer);
uint32_t ulBytes;
sciSend(scilinREG, 18, "CAN ISR entered.\r\n");
//struct qMessage3 *rxCanMessage;
//rxCanMessage = &xMessage3;
//We have not woken a task at the start of the ISR.
//BaseType_t canHigherPriorityTaskWoken = pdFALSE;
if(node == canREG2)
{
PacketRead(canREG2, Buffer, &ulBytes);
delayms(100);
PacketRead(canREG2, Buffer, &ulBytes);
}
else if(node == canREG3)
{
PacketRead(canREG3, Buffer, &ulBytes);
delayms(100);
PacketRead(canREG3, Buffer, &ulBytes);
}
//if(xQueueIsQueueEmptyFromISR(xQueue3) == pdTRUE)
//{
//sciDisplayData(scilinREG, (uint8 *) fillQ, 1); //Only for printing on the terminal.
// if(xQueueSendToBackFromISR(xQueue3, &rxCanMessage, &canHigherPriorityTaskWoken) == errQUEUE_FULL)
// {
//xQueueReset(xQueue2);
// sciSend(scilinREG, 68, "\r\nError: Data did not send from CAN interrupt service routine [TBD].");
// }
//}
}
/*********************************
* SCI interrupt service routine *
*********************************/
void sciNotification(sciBASE_t *sci, unsigned flags)
{
uint8_t rxKey;
struct qMessage2 *rxUartMessage;
rxUartMessage = &xMessage2;
BaseType_t sciYieldRequired;
//We have not woken a task at the start of the ISR.
BaseType_t sciHigherPriorityTaskWoken = pdFALSE;//, fillQ;
sciYieldRequired = xTaskResumeFromISR(xTask2Handle1); //This ISR wakes up the vUART task each time a character is received.
sciReceive(scilinREG, 1, (unsigned char *)&rxKey);
rxUartMessage->rxData = rxKey;
//fillQ = uxQueueSpacesAvailable(xQueue2); //xQueueIsQueueFullFromISR
if(xQueueIsQueueEmptyFromISR(xQueue2) == pdTRUE)
{
//sciDisplayData(scilinREG, (uint8 *) fillQ, 1); //Only for printing on the terminal.
if(xQueueSendToBackFromISR(xQueue2, &rxUartMessage, &sciHigherPriorityTaskWoken) == errQUEUE_FULL)
{
//xQueueReset(xQueue2);
sciSend(scilinREG, 73, "\r\nError: Data did not send from UART SCI interrupt service routine [TBD].");
}
}
portYIELD_FROM_ISR(sciYieldRequired);
}
/********************************
* Delay in ms. *
* t: time in ms to be delayed. *
* ******************************/
uint8_t delayms(uint16 t)
{
uint16 h, i, j;
for(h = 0; h < t; h++){ //ts = 1000 to set 1 second.
for(i = 0; i<1350; i++) //Time between samples 1 ms.
for(j = 0; j< 8; j++);}
return 1;
}
/********************
* sysInit function *
********************/
void sysInit()
{
uint8_t generic;
sciInit(); //SCI initialization.
canInit(); //CAN initialization.
//Enable interrupts:
_enable_interrupt_(); //General interrupt flag.
//Enable SCI interrupt:
sciEnableNotification(scilinREG,SCI_RX_INT); //Enable SCI interrupt by Rx.
//Enable CAN interrupt:
canEnableErrorNotification(canREG2); //Enable canREG2 interrupt.
canEnableErrorNotification(canREG3); //Enable canREG3 interrupt.
sciReceive(scilinREG,1, (unsigned char *)&generic);
sciSend(scilinREG, 37, (unsigned char *)"Initializing system. Please wait...\r\n");
gioInit(); //GIO module initialization.
gioSetDirection(hetPORT1, 1 << 15); //Enable N2HET1[15] as output. This is the output signal to the external watch-dog.
sciSend(scilinREG, 27, (unsigned char *)"\t************************\r\n");
sciSend(scilinREG, 27, (unsigned char *)"\tLabOSat-02 [OBC] OS V1.0\r\n");
sciSend(scilinREG, 27, (unsigned char *)"\t************************\r\n");
sciSend(scilinREG, 1, (unsigned char *)"\n");
sciSend(scilinREG, 14, (unsigned char *)"Developers: \r\n");
sciSend(scilinREG, 30, (unsigned char *)"\t Gagliardi Leandro Luciano \r\n");
sciSend(scilinREG, 22, (unsigned char *)"\t Di Nardo Federico \r\n");
sciSend(scilinREG, 1, (unsigned char *)"\n");
}
/********************
* osInit function *
********************/
void osInit()
{
//Queues Creation:
xQueue1 = xQueueCreate(20, sizeof(struct xMessage *)); //Queue used between vUART task and vMain task.
xQueue2 = xQueueCreate(200, sizeof(struct xMessage *)); //Queue used between sciNotification ISR and vUART task.
xQueue3 = xQueueCreate(200, sizeof(struct xMessage3 *)); //Queue used between canMessageNotification ISR and vCAN task.
//if( xQueue1 == NULL || xQueue2 == NULL || xQueue3 == NULL){sciSend(scilinREG, 58, (unsigned char *)"\r\nError: Queue was not created and must not be used [TBD].");}
if(xQueue1 == NULL){sciSend(scilinREG, 59, (unsigned char *)"\r\nError: Queue1 was not created and must not be used [TBD].");}
if(xQueue2 == NULL){sciSend(scilinREG, 59, (unsigned char *)"\r\nError: Queue2 was not created and must not be used [TBD].");}
if(xQueue3 == NULL){sciSend(scilinREG, 59, (unsigned char *)"\r\nError: Queue3 was not created and must not be used [TBD].");}
//Tasks Creation:
if (xTaskCreate(vExtWD,"vExtWD", configMINIMAL_STACK_SIZE, NULL, EXTWD_PRIORITY, &xTask1Handle1) != pdTRUE){while(1);} //Task could not be created
if (xTaskCreate(vUART,"vUART", configMINIMAL_STACK_SIZE, NULL, SCI_PRIORITY, &xTask2Handle1) != pdTRUE){while(1);} //Task could not be created
if (xTaskCreate(vMain,"vMain", configMINIMAL_STACK_SIZE, NULL, MAIN_PRIORITY, &xTask3Handle1) != pdTRUE){while(1);} //Task could not be created
if (xTaskCreate(vCAN,"vCAN", configMINIMAL_STACK_SIZE, NULL, CAN_PRIORITY, &xTask4Handle1) != pdTRUE){while(1);} //Task could not be created
//Start Scheduler:
vTaskStartScheduler();
}
/***************************
* sciDisplayData function *
***************************/
void sciDisplayData(sciBASE_t *sci, uint8 *text,uint32 length)
{
uint8 txt = 0;
uint8 txt1 = 0;
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
text = text + (length -1);
#endif
while(length--)
{
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
txt = *text--;
#else
txt = *text++;
#endif
txt1 = txt;
txt &= ~(0xF0);
txt1 &= ~(0x0F);
txt1 =txt1>>4;
if(txt<=0x9)
{
txt +=0x30;
}
else if(txt > 0x9 && txt <= 0xF)
{
txt +=0x37;
}
else
{
txt = 0x30;
}
if(txt1 <= 0x9)
{
txt1 +=0x30;
}
else if((txt1 > 0x9) && (txt1 <= 0xF))
{
txt1 +=0x37;
}
else
{
txt1 = 0x30;
}
while ((scilinREG->FLR & 0x4) == 4); /* wait until busy */
sciSendByte(scilinREG,txt1); /* send out text */
while ((scilinREG->FLR & 0x4) == 4); /* wait until busy */
sciSendByte(scilinREG,txt); /* send out text */
};
}
/********************************************************
* This task avoids external watch-dog reset *
* It considers the following watch-dog configuration: *
* SET0 = 0; *
* SET1 = 0; *
* twdu(min) = 77.455 s * 0.905 = 70.09 s *
* twdu(typ) = 77.4 * Ccwd + 0.055 = 77.455 s *
* twdu(max) = 1.095 * 77.455 s = 85 s *
* twdl(min) = 70096 s * 0.125 = 8.762 s *
* twdl(typ) = 77455 s * 0.125 = 9.682 s *
* twdl(max) = 70096 s * 0.125 = 10.602 s *
* 10.602 s < tpulse < 70.09 s *
********************************************************/
void vExtWD(void *pvParameters) //Watchdog send a pulse each 77 seconds.
{
uint8_t i, j;
TickType_t xLastWakeTime;
const TickType_t xTimeIncrement = 30000; //Each 30 seconds the MCU generates a pulse that avoids the system reset.
//Initialise the xLastWakeTime variable with the current time.
xLastWakeTime = xTaskGetTickCount();
//Meter un sciSend para ver si esta tarea se está ejecutando.
for(;;)
{
sciSend(scilinREG, 11, (unsigned char *)" vExtWD\r\n> "); //A signal to know if the task is executed.
vTaskDelayUntil( &xLastWakeTime, xTimeIncrement);
//vTaskDelay(xTimeIncrement);
gioSetBit(hetPORT1, 15, 1); //0x00100000
for(i = 0; i<10; i++){for(j = 0; j<100; j++){}} // It defines the pulse width (100us approximately)
gioSetBit(hetPORT1, 15, 0); //0x00000000
}
}
/********************************************************
* CAN Communication interface task *
* Through this interface the user can send commands *
* and execute experiments on the payloads. *
********************************************************/
void vCAN(void *pvParameters)
{
sciSend(scilinREG, 23, (unsigned char *)"CAN message received.\r\n");
vTaskSuspend(NULL); //The task is suspended up to the CAN interrupt wakes it up.
}
/********************************************************
* Debug UART Communication interface task *
* Through this interface the user can send commands *
* and execute experiments on the payloads. *
********************************************************/
void vUART(void *pvParameters) //Debug UART communication task
{
//Basic variables:
uint8_t com_char = 0, i = 0, message[8] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E};
uint8_t *uBuffer;
uint8_t UART_Buffer[128];
uBuffer = ((uint8_t *)UART_Buffer);
uint32_t msgId = (0 << 30 | 1 << 29 | 0x06); //CAN test ID
//qMessage Structure creation to send data through a queue
struct qMessage *uartMessage;
uartMessage = &xMessage;
//UART_Buffer initialization:
for(i = 0; i < 128; i++)
UART_Buffer[i] = 0;
//Delay of 50 ms:
const TickType_t xUART_delay = 50;
vTaskDelay(xUART_delay);
sciSend(scilinREG, 34, (unsigned char *)"Debug UART communication started\r\n"); //A signal to know if the task is executed.
sciSend(scilinREG, 17, (unsigned char *)"< Press any key >"); //Press any key to start.
for(;;)
{
//UART com
if(xQueue2 != NULL)
{
if(xQueueReceive(xQueue2, &uartMessage, (TickType_t) 10) == pdPASS)
{
//CAN Test frame
PacketWrite(canREG2, CAN_ALIVE, message, 8, 2); //Test frame sent through messageBox1. CAN_ALIVE has an ID of 0x06 and null payload.
*uBuffer = uartMessage->rxData;
sciSend(scilinREG, 1, uBuffer); //Print a keyboard symbol
if(*uBuffer == 0x0D && com_char < 128) //If we press enter...
{
sciSend(scilinREG, 4, (unsigned char *)"\r\n> "); //New command line
uBuffer++;
com_char++;
uBuffer = uBuffer - com_char; //Return to the first buffer position
uartMessage->len = com_char; //Number of characters
for(i = 0; i < com_char; i++) //Data stored in the structure
uartMessage->buffer[i] = UART_Buffer[i];
if(5 < uxQueueSpacesAvailable(xQueue1))
{
if(xQueueSendToBack(xQueue1, (void *) &uartMessage, (TickType_t) 10) == errQUEUE_FULL)
{
sciSend(scilinREG, 49, "\r\nError: Data did not send from vUART task [TBD].");
}
}
else
{
xQueueReset(xQueue1);
//sciSend(scilinREG, 30, "\r\nError: Queue1 is full [TBD].");
}
com_char = 0; //Number of characters variable reseted
}
else
{
uBuffer++;
com_char++;
if(127 < com_char)
{
uBuffer = uBuffer - com_char;
com_char = 0;
for(i = 0; i < uartMessage->len; i++)
uartMessage->buffer[i] = 0;
uartMessage->len = 1;
sciSend(scilinREG, 31, (unsigned char *)"\r\n> Error: uBuffer Filled [TBD]"); //uBuffer filled
}
}
if(uxQueueSpacesAvailable(xQueue2) < 10)
{
xQueueReset(xQueue2);
sciSend(scilinREG, 37, "\r\nError: Queue2 is almost full [TBD].");
}
}
else{} //sciSend(scilinREG, 33, "\r\nError: Data not received [TBD].");
vTaskResume(xTask3Handle1); //This task wakes up vMain task each time an enter key is pressed.
vTaskSuspend(NULL); //The task is suspended up to the sci interrupt wakes up it.
}
else{sciSend(scilinREG, 27, "\r\nError: Null Queue2 [TBD].");} //sciSend(scilinREG, 27, "\r\nError: Null Queue2 [TBD].");
}
}
/********************************************************
* Main Application task *
* Through this task all commands received from the *
* communication interfaces are decoded and an action *
* is executed. *
********************************************************/
void vMain(void *pvParameters)
{
//Basic variables:
uint8_t i=0;
bool isValid = false;
//qMessage Structure creation to receive data through a queue
struct qMessage *dMessage;
//Delay of 100 ms
//const TickType_t xDeco_delay = 100;
for(;;)
{
if(xQueue1 != NULL)
{
//sciSend(scilinREG, 6, "\r\nChau");
if(5 < uxQueueSpacesAvailable(xQueue1) && xQueueReceive(xQueue1, &dMessage, (TickType_t) 10) == pdPASS)
{
sciSend(scilinREG, dMessage->len, dMessage->buffer); //Print the command received
isValid = cDecoder(dMessage);
if(dMessage->buffer[0] == 0x0D){sciSend(scilinREG, 4, (unsigned char *)"\r\n> ");} //New command line
else
{
if(isValid == false){sciSend(scilinREG, 32, (unsigned char *)"\r\n. Error: Unknown Command [TBD]");}//Error Message.
else{sciSend(scilinREG, 22, (unsigned char *)"\r\n. Execute an action.");}
sciSend(scilinREG, 4, (unsigned char *)"\r\n> "); //New command line
}
for(i = 0; i < dMessage->len; i++)
dMessage->buffer[i] = 0;
dMessage->len = 1;
}
else{} //sciSend(scilinREG, 33, "\r\nError: Data not received [TBD].");
vTaskSuspend(NULL); //The task is suspended up to the vUART task wakes it up.
}
else{sciSend(scilinREG, 27, "\r\nError: Null Queue1 [TBD].");} //sciSend(scilinREG, 27, "\r\nError: Null Queue1 [TBD].");
}
}
//Include 'interfacesCommandDef.h' before use this function in your project.
bool cDecoder(struct qMessage * command)
{
bool isValid = false;
uint8_t i = 0, j = 0;
command->len = command->len - 1; //Enter (0x0D) is ignored.
for(i = 0; i < COMMAND_LIST_LEN; i++)
{
if(commandLength[i] == command->len) //It compares the command length received with the command in the list.
{
for(j = 0; j < command->len; j++)
{
if(command->buffer[j] == *(commandList[i] + j)) //It comapres character by character the command received and the command in list.
isValid = true;
else
{
isValid = false;
j = command->len;
}
}
if(isValid == true)
return isValid;
}
}
return isValid;
}
/* USER CODE END */
The code has four tasks at now.
vCAN has to be waked up if a CAN ISR is triggered.
vUART works as vCAN but it works fine. Inside this task, a CAN frame is sent from CAN2 to CAN3 each time an enter key is pressed. I have done it as a simple test.
I attach below a picture of the serial Terminal that shows a basic user interface:
Initializing system. Please wait...
************************
LabOSat-02 [OBC] OS V1.0
************************
Developers:
Gagliardi Leandro Luciano
Di Nardo Federico
vExtWD
> CAN message received.
Debug UART communication started
< Press any key >CAN ISR entered.
>
. Error: Unknown Command [TBD]
>
>
>
CAN ISR started is a notification after the first enter key pressed. Then, after various enter key, never is triggered again.
Somebody has an idea about this strange behaviour?
Thanks a lot and regards,
Leandro
