Hello,
I have 4 tasks with different delays working as expected. Then, I add a 5th task to handle interrupts synchronized with two binary semaphores to send and receive data via DMA.
Individually the 4 tasks work as one after the other depending on their delays when the interrupt task is not initialized. On the other hand, the task with the semaphores works fine when the first 4 tasks are initialized.
The problem comes when I want to have all five tasks together. Each of them execute once and then loops around portTASK_FUNCTION
from tasks.c
. More precisely, inside an infinite for loop, in if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
which if it is true, it calls taskYIELD()
which is never the case. That way, all 5 tasks are only executed once and then the OS stays in that infinite for loop.
The simple tasks (without interrupt or semaphore) all look like this but with different values in xDelay:
static void task1(void *p)
{
const TickType_t xDelay = 250 / portTICK_PERIOD_MS;
while(1){
printf("Task 1\n");
vTaskDelay(xDelay);
}
}
And the task with the interrupts is:
xSemaphoreHandle SemPLtoPS = NULL;
xSemaphoreHandle SemPStoPL = NULL;
#define SemTime 0xffff
static void InterruptSemaphoreTask(void *p)
{
const TickType_t xDelay = 250 / portTICK_PERIOD_MS;
int Status;
XAxiDma_Config *Config;
int Index;
u8 *TxBufferPtr;
u8 *RxBufferPtr;
u8 Value;
TxBufferPtr = (u8 *)TX_BUFFER_BASE ;
RxBufferPtr = (u8 *)RX_BUFFER_BASE;
Config = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!Config) {
xil_printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}
/* Initialize DMA engine */
Status = XAxiDma_CfgInitialize(&AxiDma, Config);
if (Status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", Status);
return XST_FAILURE;
}
if(XAxiDma_HasSg(&AxiDma)){
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
/* Set up Interrupt system */
Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
if (Status != XST_SUCCESS) {
xil_printf("Failed intr setup\r\n");
return XST_FAILURE;
}
/* Disable all interrupts before setup */
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Enable all interrupts */
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
/* Initialize flags before start transfer test */
TxDone = 0;
RxDone = 0;
Error = 0;
unsigned char stream[68]={0x03,0x3f,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0xac,0x8f,0xa6,0x5e,0x3e,0xf6,0xa0,0x07,0x0a,0x00,0x00,0x00,0x74,0x65,0x73,0x74,0x5f,0x69,0x6d,0x61,0x67,0x65,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x72,0x67,0x62,0x38,0x01,0x06,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x11,0x12,0x13,0x21,0x22,0x23,0x31,0x32,0x33,0x41,0x42,0x43};
for(int i=0; i<MAX_PKT_LEN; i++)
TxBufferPtr[i] = stream[i];
/* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
* is enabled
*/
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
// Create semaphores
SemPLtoPS = xSemaphoreCreateBinary();
if(SemPLtoPS==NULL){
xil_printf("Could not create semaphore SemPLtoPS\n");
return XST_FAILURE;
}
SemPStoPL = xSemaphoreCreateBinary();
if(SemPStoPL==NULL){
xil_printf("Could not create semaphore SemPStoPL\n");
return XST_FAILURE;
}
while(1){
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) TxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
if((xSemaphoreTake(SemPLtoPS, SemTime)== pdTRUE) && (xSemaphoreTake(SemPStoPL, SemTime)== pdTRUE)){
if (Error) {
xil_printf("Failed test transmit%s done, "
"receive%s done\r\n", TxDone? "":" not",
RxDone? "":" not");
}
for(int i=0; i<MAX_PKT_LEN; i++)
{
printf("0x%.2x ", RxBufferPtr[i]);
}
printf("\n");
}
vTaskDelay(xDelay);
}
}
I have 2 callbacks as I am sending and receiving data just looping around, in which I call xSemaphoreGiveFromISR(SemPStoPL, NULL);
and xSemaphoreGiveFromISR(SemPLtoPS, NULL);
when data is properly sent/received.
static void TxIntrHandler(void *Callback)
{
u32 IrqStatus;
int TimeOut;
XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
static BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/*
* Reset should never fail for transmit channel
*/
XAxiDma_Reset(AxiDmaInst);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if (XAxiDma_ResetIsDone(AxiDmaInst)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If Completion interrupt is asserted, then set the TxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
TxDone = 1;
xSemaphoreGiveFromISR(SemPStoPL, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR( xHigherPriorityTaskWoken);
}
static void RxIntrHandler(void *Callback)
{
u32 IrqStatus;
int TimeOut;
XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
//static signed BaseType_t xHigherPriorityTaskWoken;
static BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
/* Read pending interrupts */
IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
/* Acknowledge pending interrupts */
XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
/*
* If no interrupt is asserted, we do not do anything
*/
if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
return;
}
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
Error = 1;
/* Reset could fail and hang
* NEED a way to handle this or do not call it??
*/
XAxiDma_Reset(AxiDmaInst);
TimeOut = RESET_TIMEOUT_COUNTER;
while (TimeOut) {
if(XAxiDma_ResetIsDone(AxiDmaInst)) {
break;
}
TimeOut -= 1;
}
return;
}
/*
* If completion interrupt is asserted, then set RxDone flag
*/
if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
RxDone = 1;
xSemaphoreGiveFromISR(SemPLtoPS, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR( xHigherPriorityTaskWoken);
}
The example from the documentation does not have a call to vTaskDelay
though. If I don’t include it, only the task with the semaphores executes. That is why I added it to have a context switching to the other tasks.
What am I doing wrong that I cannot get all 4 simple tasks to execute while the 5th one waits for to get the semaphore via the interrupts?
Thanks for the help.