UART interrupt in FreeRTOS using PDL

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Ramya1811
Level 1
Level 1
First reply posted 5 sign-ins First question asked

Hi all,

    I am using the PSoC 6 cy8ckit-064b0s2-4343w . I attempted to construct a UART interrupt in Modustoolbox (version 3.0)using SCB blocks without FreeRTOS, and the hardware interrupt happened at that time. However, when I implemented the same code again with FreeRTOS(v10.4.302), I did not encounter a hardware interrupt since FreeRTOS does not call the interrupt function while transmitting.

The PDL(v3.2.0) API's used:

   For configuration:

        (void) Cy_SCB_UART_Init(SCB5, &uartConfig, &uartContext)
        Cy_GPIO_SetHSIOM(UART_PORT, UART_RX_NUM, P5_0_SCB5_UART_RX)

        Cy_GPIO_SetDrivemode(UART_PORT, UART_RX_NUM, CY_GPIO_DM_HIGHZ)

   For transmit data:

           (void) Cy_SCB_UART_Transmit(SCB5, txBuffer, sizeof(txBuffer) and &uartContext)
   For enable Interrupt:

            (void) Cy_SysInt_Init(&uartIntrConfig, &UART_Isr) and NVIC_EnableIRQ(UART_INTR_NUM)

 For other API's I referred   https://infineon.github.io/psoc6pdl/pdl_api_reference_manual/html/group__group__scb__uart.html . Can anyone suggest why in FreeRTOS the same code I implemented without FreeRTOS is not working and does I have to include any PDL API for interrupt in FreeRTOS?

0 Likes
1 Solution
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @pblemel ,

Please refer the below example for UART Tx and Rx interrupt with FreeRTOS.

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
#include <string.h>

/*******************************************************************************
* Macros
*******************************************************************************/
#define UART_TASK_STACK_SIZE        (1024*10)
#define UART_TASK_PRIORITY          (configMAX_PRIORITIES - 3)
#define DEBUG_UART_HW SCB5
#define DEBUG_UART_IRQ scb_5_interrupt_IRQn
/*******************************************************************************
* Function Prototypes
********************************************************************************/

/*******************************************************************************
* Global Variables
*******************************************************************************/
/* This enables RTOS aware debugging. */
volatile int uxTopUsedPriority;
cy_stc_scb_uart_context_t uart_context;
char txBuffer[100];
char rxBuffer[5];
int txcounter = 0;
int rxcounter = 0;

void UART_Isr(void)
{
	Cy_SCB_UART_Interrupt(DEBUG_UART_HW, &uart_context);
}

void HandleEventsUart(uint32 event)
{
	if((event & CY_SCB_TX_INTR_LEVEL ) == 	CY_SCB_TX_INTR_LEVEL )
	{
		txcounter++;
	}

	if((event & CY_SCB_RX_INTR_NOT_EMPTY) == CY_SCB_RX_INTR_NOT_EMPTY)
	{
		rxcounter++;
	}
}

/*******************************************************************************
* Function Name: int main(void)
********************************************************************************
*
* Summary: This is the main for this code example.  This function initializes
*          the BSP, creates the tft-task and starts the scheduler.
*
* Parameters:
*  None
*
* Return:
*  int
*
*******************************************************************************/
int main(void)
{
    cy_rslt_t result;

#if defined (CY_DEVICE_SECURE)
    cyhal_wdt_t wdt_obj;

    /* Clear watchdog timer so that it doesn't trigger a reset */
    result = cyhal_wdt_init(&wdt_obj, cyhal_wdt_get_max_timeout_ms());
    CY_ASSERT(CY_RSLT_SUCCESS == result);
    cyhal_wdt_free(&wdt_obj);
#endif
    /* This enables RTOS aware debugging in OpenOCD */
    uxTopUsedPriority = configMAX_PRIORITIES - 1 ;

    /* Initialize the device and board peripherals */
    result = cybsp_init();
    CY_ASSERT(result == CY_RSLT_SUCCESS);   

    /* To avoid compiler warning */
    (void)result;

    __enable_irq();

    /* Create the TFT task */
    xTaskCreate(uart_task, "UARTTask", UART_TASK_STACK_SIZE,
                    NULL,  UART_TASK_PRIORITY,  NULL);

    /* Start the FreeRTOS scheduler. */
    vTaskStartScheduler();

    /* Should never get here. */
    CY_ASSERT(0);
}

void uart_task(void *arg)
{
    /* Initialize the SCB block to use the debug UART port */
    Cy_SCB_UART_Init(DEBUG_UART_HW, &DEBUG_UART_config, &uart_context);
   	const cy_stc_sysint_t uartIntrConfig =
   	{
   		.intrsrc=DEBUG_UART_IRQ,
   		.intrPriority = 3UL,
   	};

   	(void) Cy_SysInt_Init(&uartIntrConfig, &UART_Isr);
   	NVIC_EnableIRQ(DEBUG_UART_IRQ);
   	Cy_SCB_UART_RegisterCallback(DEBUG_UART_HW, (cy_cb_scb_uart_handle_events_t)HandleEventsUart, &uart_context);
   	Cy_SCB_SetRxInterruptMask(DEBUG_UART_HW, CY_SCB_RX_INTR_NOT_EMPTY);

   	/* Enabling the SCB block for UART operation */
   	Cy_SCB_UART_Enable(DEBUG_UART_HW);

   /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen */
	sprintf(txBuffer, "\x1b[2J\x1b[;H");
	Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, 12,&uart_context);
	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}
	sprintf(txBuffer, "******************  FreeRTOS UART Example  ****************** \r\n");
	Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, strcspn(txBuffer,"\r\n")+2,&uart_context);
	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}

    for(;;)
    {
        sprintf(txBuffer, "Tx = %d\tRx = %d\r\n", txcounter, rxcounter);
        Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, strcspn(txBuffer,"\r\n")+2,&uart_context);
    	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}

        Cy_SCB_UART_Receive(DEBUG_UART_HW, rxBuffer, 1,&uart_context);

    	while((Cy_SCB_UART_GetReceiveStatus	(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_RECEIVE_ACTIVE) != 0){}
    }
}

/* [] END OF FILE */

 

Kindly let me know when there are any further issues.

Best regards,

Bhamy Narasimha Shenoy

 

 

View solution in original post

0 Likes
12 Replies
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @Ramya1811 ,

 

While using FreeRTOS , for hardware interrupts to be in processed the Cy_SCB_UART_Transmit function is to be called inside the tasks. Also check if the transmit complete interrupt is enabled properly. Can you please share the basic UART FreeRTOS project? 

Best regards,

Bhamy Narasimha Shenoy

0 Likes
pblemel
Level 4
Level 4
25 replies posted 25 sign-ins First like received

Hi,

Here's what I put together between the Cypress and FreeRTOS tutorials.  Note: For my purposes, I do not allow the "bottom half" to block forever. It times out periodically, at which time I take care of some book keeping.  Hope it helps.

#include "project.h"
#include "FreeRTOS.h"
#include "timers.h"
#include "semphr.h"
#include "datalogger.h"
#include "timers.h"

#include <stdio.h>

void uartTask(void *arg);
static TaskHandle_t uartTaskHandle = NULL;

// UART interrupt service handler.
// https://www.freertos.org/RTOS_Task_Notification_As_Counting_Semaphore.html
//
static void UART_Isr()
{
    BaseType_t xHigherPriorityTaskWoken;

    // Disable and clear the interrupt.
    Cy_SCB_SetRxInterruptMask(UART_HW, 0);
    Cy_SCB_ClearRxInterrupt(UART_HW, CY_SCB_RX_INTR_NOT_EMPTY);
    NVIC_ClearPendingIRQ((IRQn_Type) UART_SCB_IRQ_cfg.intrSrc);
 
    /* xHigherPriorityTaskWoken must be initialised to pdFALSE.
    ** If calling vTaskNotifyGiveFromISR() unblocks the handling
    ** task, and the priority of the handling task is higher than
    ** the priority of the currently running task, then
    ** xHigherPriorityTaskWoken will be automatically set to pdTRUE.
    */
    xHigherPriorityTaskWoken = pdFALSE;

    /* Unblock the handling task so the task can perform
    ** any processing necessitated by the interrupt.  xHandlingTask
    ** is the task's handle, which was obtained when the task was
    ** created.  vTaskNotifyGiveFromISR() also increments
    ** the receiving task's notification value.
    */
    vTaskNotifyGiveFromISR(uartTaskHandle, &xHigherPriorityTaskWoken);

    /* Force a context switch if xHigherPriorityTaskWoken is now
    ** set to pdTRUE. The macro used to do this is dependent on
    ** the port and may be called portEND_SWITCHING_ISR.
    */
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void uartTask(void *arg) {
    (void) arg; // Turn off compiler warning about unused argument.
 
    uartTaskHandle = xTaskGetCurrentTaskHandle();

    // Configure interrupt handler.
    (void) Cy_SysInt_Init(&UART_SCB_IRQ_cfg, &UART_Isr); // Installs ISR into CM4 vector table.
    NVIC_EnableIRQ((IRQn_Type) UART_SCB_IRQ_cfg.intrSrc); // Turns on interrupt handling.
    Cy_SCB_SetRxInterruptMask(UART_HW, CY_SCB_RX_INTR_NOT_EMPTY); // Interrupt when RX buffer is not empty.

    const TickType_t xBlockTime = pdMS_TO_TICKS(500);

    puts("Started UART task\r");
    while (1) {
        /* Block to wait for a notification.  Here the RTOS
        ** task notification is being used as a counting semaphore.
        ** The task's notification value is incremented each time
        ** the ISR calls vTaskNotifyGiveFromISR(), and decremented
        ** each time the RTOS task calls ulTaskNotifyTake() - so in
        ** effect holds a count of the number of outstanding interrupts.
        ** The first parameter is set to pdFALSE, so the notification
        ** value is only decremented and not cleared to zero, and one
        ** deferred interrupt event is processed at a time.  See
        ** example 2 for a more pragmatic approach.
        **
        ** PAB: We have to use ulTaskNotifyTake ("Example 1" in the
        ** link) because ulTaskNotifyTakeIndexed requires FreeRTOS
        ** 10.4 while PSoC Creator only supplies 10.3. However, the
        ** FIFO has the count, so we can pass pdTRUE as the first
        ** parameter.
        */
        uint32_t ulNotifiedValue = ulTaskNotifyTake(pdFALSE, xBlockTime);
        if (ulNotifiedValue == 0) {
            // No interrupt.
            continue;
        }

        // Presumably 'num in fifo' should match ulNotifiedValue. Process
        // whatever's in the UART FIFO.
        //
        printf("uartTask: %d chars in fifo\r\n", Cy_SCB_UART_GetNumInRxFifo(UART_HW));
        if (Cy_SCB_UART_GetNumInRxFifo(UART_HW) > 0) {
            uint32_t c;
            while ((c = Cy_SCB_UART_Get(UART_HW)) != CY_SCB_UART_RX_NO_DATA)
                // My code to copy the characters out of the UART

            Cy_SCB_UART_ClearRxFifo(UART_HW);
        }

        // After processing all RX_FIFO data, re-enable interrupt.
        Cy_SCB_SetRxInterruptMask(UART_HW, CY_SCB_RX_INTR_NOT_EMPTY);
    }
}
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @pblemel ,

Please refer the below example for UART Tx and Rx interrupt with FreeRTOS.

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
#include <string.h>

/*******************************************************************************
* Macros
*******************************************************************************/
#define UART_TASK_STACK_SIZE        (1024*10)
#define UART_TASK_PRIORITY          (configMAX_PRIORITIES - 3)
#define DEBUG_UART_HW SCB5
#define DEBUG_UART_IRQ scb_5_interrupt_IRQn
/*******************************************************************************
* Function Prototypes
********************************************************************************/

/*******************************************************************************
* Global Variables
*******************************************************************************/
/* This enables RTOS aware debugging. */
volatile int uxTopUsedPriority;
cy_stc_scb_uart_context_t uart_context;
char txBuffer[100];
char rxBuffer[5];
int txcounter = 0;
int rxcounter = 0;

void UART_Isr(void)
{
	Cy_SCB_UART_Interrupt(DEBUG_UART_HW, &uart_context);
}

void HandleEventsUart(uint32 event)
{
	if((event & CY_SCB_TX_INTR_LEVEL ) == 	CY_SCB_TX_INTR_LEVEL )
	{
		txcounter++;
	}

	if((event & CY_SCB_RX_INTR_NOT_EMPTY) == CY_SCB_RX_INTR_NOT_EMPTY)
	{
		rxcounter++;
	}
}

/*******************************************************************************
* Function Name: int main(void)
********************************************************************************
*
* Summary: This is the main for this code example.  This function initializes
*          the BSP, creates the tft-task and starts the scheduler.
*
* Parameters:
*  None
*
* Return:
*  int
*
*******************************************************************************/
int main(void)
{
    cy_rslt_t result;

#if defined (CY_DEVICE_SECURE)
    cyhal_wdt_t wdt_obj;

    /* Clear watchdog timer so that it doesn't trigger a reset */
    result = cyhal_wdt_init(&wdt_obj, cyhal_wdt_get_max_timeout_ms());
    CY_ASSERT(CY_RSLT_SUCCESS == result);
    cyhal_wdt_free(&wdt_obj);
#endif
    /* This enables RTOS aware debugging in OpenOCD */
    uxTopUsedPriority = configMAX_PRIORITIES - 1 ;

    /* Initialize the device and board peripherals */
    result = cybsp_init();
    CY_ASSERT(result == CY_RSLT_SUCCESS);   

    /* To avoid compiler warning */
    (void)result;

    __enable_irq();

    /* Create the TFT task */
    xTaskCreate(uart_task, "UARTTask", UART_TASK_STACK_SIZE,
                    NULL,  UART_TASK_PRIORITY,  NULL);

    /* Start the FreeRTOS scheduler. */
    vTaskStartScheduler();

    /* Should never get here. */
    CY_ASSERT(0);
}

void uart_task(void *arg)
{
    /* Initialize the SCB block to use the debug UART port */
    Cy_SCB_UART_Init(DEBUG_UART_HW, &DEBUG_UART_config, &uart_context);
   	const cy_stc_sysint_t uartIntrConfig =
   	{
   		.intrsrc=DEBUG_UART_IRQ,
   		.intrPriority = 3UL,
   	};

   	(void) Cy_SysInt_Init(&uartIntrConfig, &UART_Isr);
   	NVIC_EnableIRQ(DEBUG_UART_IRQ);
   	Cy_SCB_UART_RegisterCallback(DEBUG_UART_HW, (cy_cb_scb_uart_handle_events_t)HandleEventsUart, &uart_context);
   	Cy_SCB_SetRxInterruptMask(DEBUG_UART_HW, CY_SCB_RX_INTR_NOT_EMPTY);

   	/* Enabling the SCB block for UART operation */
   	Cy_SCB_UART_Enable(DEBUG_UART_HW);

   /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen */
	sprintf(txBuffer, "\x1b[2J\x1b[;H");
	Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, 12,&uart_context);
	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}
	sprintf(txBuffer, "******************  FreeRTOS UART Example  ****************** \r\n");
	Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, strcspn(txBuffer,"\r\n")+2,&uart_context);
	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}

    for(;;)
    {
        sprintf(txBuffer, "Tx = %d\tRx = %d\r\n", txcounter, rxcounter);
        Cy_SCB_UART_Transmit(DEBUG_UART_HW, txBuffer, strcspn(txBuffer,"\r\n")+2,&uart_context);
    	while((Cy_SCB_UART_GetTransmitStatus(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_TRANSMIT_ACTIVE) != 0){}

        Cy_SCB_UART_Receive(DEBUG_UART_HW, rxBuffer, 1,&uart_context);

    	while((Cy_SCB_UART_GetReceiveStatus	(DEBUG_UART_HW,&uart_context) & CY_SCB_UART_RECEIVE_ACTIVE) != 0){}
    }
}

/* [] END OF FILE */

 

Kindly let me know when there are any further issues.

Best regards,

Bhamy Narasimha Shenoy

 

 

0 Likes

Hi @Bhamy ,

      I have tried the code that you have mentioned above but still I am facing the same issue . It shows transmit is success but the data is not transferred and the interrupt is also not being called while transmitting .

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @Ramya1811 ,

Can you please share your Modustoolbox project to check it in my setup?

Best regards,

Bhamy Narasimha Shenoy

0 Likes
lock attach
Attachments are accessible only for community members.

Hi @Bhamy ,

     Please find the attachment.

Thanks

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @Ramya1811 ,

Please enable the peripheral clock for the respective SCB 10 block before using it.

Best regards,

Bhamy Narasimha Shenoy 

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @Ramya1811 ,

As mentioned above when the clock were enabled to the SCB10 the interrupts started working in my setup.

Add the below code:

    Cy_SysClk_PeriphDisableDivider(CY_SYSCLK_DIV_8_BIT, 1U);
    Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT, 1U, 108U);
    Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT, 1U);
    Cy_SysClk_PeriphAssignDivider(PCLK_SCB10_CLOCK, CY_SYSCLK_DIV_8_BIT, 1U);
(void) Cy_SCB_UART_Init(SCB10, &scb_10_config, &g_SCB10_suartContext);

 Kindly verify it and let me know if you have further issues.

Best regards,

Bhamy Narasimha Shenoy

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @pblemel ,

Did you get chance to review the previous response? Kindly let me know if you need any further support on this topic.

Best regards,

Bhamy Narasimha Shenoy 

0 Likes
pblemel
Level 4
Level 4
25 replies posted 25 sign-ins First like received

Hi Bhamy,

This question was posted by @Ramya1811. I provided a some code based on a FreeRTOS blog post that's working for me in reply.  I did find your post informative and appreciate that you took the time to provide code. I hope that Ramya found it as informative as I did. 

Thanks & Regards

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @pblemel,

Sorry for confusing with the names. Thank you for providing the code snippet. I appreciate you for spending time on providing informative response . 

Best regards,

Bhamy Narasimha Shenoy

0 Likes
Bhamy
Moderator
Moderator
Moderator
100 replies posted 10 likes given 10 likes received

Hi @Ramya1811 ,

Did you get chance to try the solution mentioned in my response?

https://community.infineon.com/t5/PSoC-6/UART-interrupt-in-FreeRTOS-using-PDL/m-p/398475#M15487

Best regards,

Bhamy Narasimha Shenoy

0 Likes