7 Replies Latest reply on Mar 3, 2016 12:46 AM by userc_16716

    P_UART interrupt enable/disable only working while tracing

      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

        • 1. Re: P_UART interrupt enable/disable only working while tracing

          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?

          • 2. Re: P_UART interrupt enable/disable only working while tracing

            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

            • 3. Re: P_UART interrupt enable/disable only working while tracing

              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

              1 of 1 people found this helpful
              • 4. Re: P_UART interrupt enable/disable only working while tracing

                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

                • 5. Re: P_UART interrupt enable/disable only working while tracing

                  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

                  • 6. Re: P_UART interrupt enable/disable only working while tracing

                    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.

                    • 7. Re: P_UART interrupt enable/disable only working while tracing

                      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