P_UART interrupt enable/disable only working while tracing

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

cross mob
Anonymous
Not applicable

Hello everybody,

I'm still working on the BCM20736S and its connection using the P_UART to a master MCU.

At the moment I'm trying to fix a bug that prevents the P_UART from sending and receiving data as soon as tracing is disabled. The issue is located inside this function:

static inline void enableRxInterrupt(BOOL enable)

{

#ifdef BT_BLE_TRACING

    if (enable == TRUE)

    {

        ble_trace0("enableRxInterrupt(TRUE)");

    }

    else

    {

        ble_trace0("enableRxInterrupt(FALSE)");

    }

#endif

    if (enable == TRUE)

    {

        // set watermark to 1 byte - will interrupt on every byte received.

        //bleprofile_PUARTSetRxWaterlevel(waterMark);

        //P_UART_WATER_MARK_RX_LEVEL(waterMark);

        // enable UART interrupt in the Main Interrupt Controller and RX Almost Full in the UART

        // Interrupt Controller

        P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

    }

    else

    {

        P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

    }

}

This is called frequently while handling P_UART data. If I undefine BT_BLE_TRACING no data is sent by the BLE module.

I'm guessing this is a timing problem?

Or are the P_UART_INT... macros (originally only for internal use) having side effects?

It does also work with disabled traces inside the function enableRxInterrupt if I send traces before calling it.

Thanks for your help!

Best regards

Hannes Baumgart

0 Likes
1 Solution
Anonymous
Not applicable

Hi Hannes,

the problem might be fixed with a delay, but it does not have to be the cause of the problem:

your code is not really disabling the interrupt at all:

P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

does not disable the interrupt - it clears the interrupt status bit! (as soon as the next bit comes it, it will set this bit again, and in your case -fire the interrupt!)

So, just as

P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

enables the interrupt,

P_UART_INT_ENABLE &= ~(P_UART_ISR_RX_AFF_MASK);

disables the interrupt (you have to unset the bit for the RX AFF)

however, this means that your buffer might well overflow in the meantime - I'm quite sure this is not what you want either!

Also, I would avoid delays at all costs, and never ever use them in interrupt service routines!

So instead, I would keep the interrupt callback function as short as possible. Create your own buffer, big enough for any packets you're expecting, and in the callback function for the interrupt, only copy the bytes from the Puart Rx FIFO into your buffer. That's it.

then, in a different place of your code (eg in the fine timer callback), check if there's data in your software buffer, and parse all the data that's in there.

I hope to have helped.

Oliver

View solution in original post

7 Replies
Anonymous
Not applicable

Would you like to turn interrupt enabled/disabled frequently during PUART communicating?

Please tell us what you exactly want to do.

By the way, calling bleprofile_PUARTRxOn() and bleprofile_PUARTRxOff() doesn't work for you?

0 Likes
Anonymous
Not applicable

Dear dmiya,

I want to disable the interrupt as soon as my PUART RX callback handler is invoked, handle the received bytes (they have to be decoded into a packet structure and have to be "executed" as they form some type of command) and enable the interrupt after this.

I want to do this, because I was afraid that new interrupts would intercept the handling of the last RX interrupt.

Your suggestion using bleprofile_PUARTRxOn() and ...Off() from bleprofile.h looks interesting. I have to admit, that I only use puart_enableTx() in my PUART init function.

PUART init:

static BOOL ttl_ble_puart_init(UINT8 rxPortPin, UINT8 txPortPin, UINT32 bdRate)

{

    extern puart_UartConfig puart_config;

    //puart_init(); //should be called by bleapp_set_cfg, but still needs to be called here

    ble_trace1("ttl_ble_puart_init(GPIO_PIN_UART_RX, GPIO_PIN_UART_TX, %u)", bdRate);

    // Set the baud rate we want to use. Default is 115200.

    puart_config.baudrate = bdRate;

    if(puart_checkRxdPortPin(rxPortPin))

    {

        return FALSE;

    }

    if(puart_checkTxdPortPin(txPortPin))

    {

        return FALSE;

    }

    // Select the uart pins for RXD, TXD and optionally CTS and RTS.

    // If hardware flow control is not required like here, set these

    // pins to 0x00. See Table 1 and Table 2 for valid options.

    if(puart_selectUartPads(rxPortPin, txPortPin, 0x00, 0x00))

    {

        return FALSE;

    }

    // Initialize the peripheral uart driver

    puart_init(); //should be called by bleapp_set_cfg, but still needs to be called here

    // Since we are not configuring CTS and RTS here, turn off

    // hardware flow control. If HW flow control is used, then

    // puart_flowOff should not be invoked.

    puart_flowOff();

    puart_enableTx();

    // BEGIN - puart interrupt

    //  The following lines enable interrupt when one (or more) bytes

    //  are received over the peripheral uart interface. This is optional.

    //  In the absense of this, the app is expected to poll the peripheral

    //  uart to pull out received bytes.

    // clear interrupt

    P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

    // set watermark to 1 byte - will interrupt on every byte received.

    P_UART_WATER_MARK_RX_LEVEL(1);

    // enable UART interrupt in the Main Interrupt Controller and RX Almost Full in the UART

    // Interrupt Controller

    P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

    // Set callback function to app callback function.

    puart_rxCb = btup_receiveDataCallback;

    // Enable the CPU level interrupt

    puart_enableInterrupt();

    /* END - puart interrupt */

    return TRUE;

}

RX callback:

void btup_receiveDataCallback(void* unused)

{

    //ble_trace0("void btup_receiveDataCallback(void* unused)");

    //enableRxInterrupt(FALSE);

    bleapputils_delayUs((UINT32) 1200);

    P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

    P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

    packetReceiveAndDecode();

    packetExec();

    //enableRxInterrupt(TRUE);

//    ble_trace0("void btup_receiveDataCallback(void* unused) out");

}

And interrupt enable/disable function:

static inline void enableRxInterrupt(BOOL enable)

{

//#ifdef BT_BLE_TRACING

//    if (enable == TRUE)

//    {

//        ble_trace0("enableRxInterrupt(TRUE)");

//    }

//    else

//    {

//        ble_trace0("enableRxInterrupt(FALSE)");

//    }

//#endif

    if (enable == TRUE)

    {

        // set watermark to 1 byte - will interrupt on every byte received.

        //bleprofile_PUARTSetRxWaterlevel(waterMark);

        //P_UART_WATER_MARK_RX_LEVEL(waterMark);

        // enable UART interrupt in the Main Interrupt Controller and RX Almost Full in the UART

        // Interrupt Controller

        P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

    }

    else

    {

        P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

    }

}

I figured it's a timing problem - when I insert a delay of 1200µs it works even without traces.

I did give bleprofile_PUARTRxOn()/Off() a try, instead of waiting in the btup_receiveDataCallback function in place of enableRxInterrupt(), i.e. disabled Rx when disabling the interrupt and switching it to on instead of enabling the interrupt again.

Best regards

Hannes Baumgart

0 Likes
Anonymous
Not applicable

Hi Hannes,

the problem might be fixed with a delay, but it does not have to be the cause of the problem:

your code is not really disabling the interrupt at all:

P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

does not disable the interrupt - it clears the interrupt status bit! (as soon as the next bit comes it, it will set this bit again, and in your case -fire the interrupt!)

So, just as

P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

enables the interrupt,

P_UART_INT_ENABLE &= ~(P_UART_ISR_RX_AFF_MASK);

disables the interrupt (you have to unset the bit for the RX AFF)

however, this means that your buffer might well overflow in the meantime - I'm quite sure this is not what you want either!

Also, I would avoid delays at all costs, and never ever use them in interrupt service routines!

So instead, I would keep the interrupt callback function as short as possible. Create your own buffer, big enough for any packets you're expecting, and in the callback function for the interrupt, only copy the bytes from the Puart Rx FIFO into your buffer. That's it.

then, in a different place of your code (eg in the fine timer callback), check if there's data in your software buffer, and parse all the data that's in there.

I hope to have helped.

Oliver

Anonymous
Not applicable

Hi Oliver,

thanks for your reply.

You're right, I'm just clearing the interrupt set bit and not disabling the interrupt. But it's fixed now.

I'll change the PUART handler and copy the bytes to another buffer, the handler will use these data - so no disabling of interrupts for now.

Instead of using the fine timer interrupt, I'll give

BOOL32 bleappevt_serialize(INT32 (*fn)(void*), void* data);

a try.

Best regards

Hannes Baumgart

0 Likes
Anonymous
Not applicable

Hi everybody,

I experimented with different settings and rewrote the handling of bytes from the PUART. Now my callback looks like this:

#define PACKET_BUFFER_SIZE 64

static unsigned char rxBuffer[PACKET_BUFFER_SIZE];

static unsigned char rxReadPointer;

static unsigned char rxWritePointer;

static unsigned char rxBytes;

void btup_receiveDataCallback(void* unused)

{

    uint8_t readByte;

    while((puart_rxFifoNotEmpty() == TRUE)

      && (rxBytes < PACKET_BUFFER_SIZE))

    {

        puart_read(&readByte);

        rxBuffer[rxWritePointer++] = (unsigned char) readByte;

        if(rxWritePointer >= PACKET_BUFFER_SIZE)

        {

            rxWritePointer = 0;

        }

        rxBytes++;

        if(rxBytes > PACKET_BUFFER_SIZE)

        {

            rxBytes = PACKET_BUFFER_SIZE;

        }

        bleapputils_delayUs(125); //this or the trace needs to be here to prevent crashing

    }

    if(rxBytes > 0)

    {

        bleappevt_serialize(btup_handleData, NULL); //serialize handler function

    }

    P_UART_INT_CLEAR(P_UART_ISR_RX_AFF_MASK);

        P_UART_INT_ENABLE |= P_UART_ISR_RX_AFF_MASK;

}

This works better than before, handling is serialized to btup_handleData that does the processing.

But still one question remains: If I don't add a delay of 125µs (or a ble_trace0 instead with at least two characters) to the while loop, that copies the received data to my own buffer, the program crashes and does only receive one byte.

Why is it like that?

Thanks for your help!

Hannes Baumgart

0 Likes
Anonymous
Not applicable

You might want to declare your buffer variables volatile, as you're accessing them in the ISR context as well as the app context.

I don't know if that's all, but definitely something you should be careful with.

0 Likes
Anonymous
Not applicable

Hi foolography,

you're right, this would be cleaner.

But the callback is also running in app context.

I changed it to volatile and it still needs the delay (besides having to cast volatile pointers to nonvolatile ones for memcpy).

Best regards

Hannes Baumgart

0 Likes