Uart Rx wake-up from Deep Sleep

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

cross mob
Anonymous
Not applicable

Hi,

   

I have seen a few postings concerning this topic but have not read anything that helps.

   

I am using the CYBLE-022001 module and in an attempt to keep the power usage as low as possible it has been configured to use Deep Sleep as much as possible.

   

The BLE module is setup with a long connection interval which brings the unit out of Deep Sleep on a regular basis but I also need to react quickly to a couple of external sources.

   

I have an external input GPIO which has an interrupt component attached and a callback function setup so I know if this input caused the exit from Deep Sleep. The callback clears the interrupt and toggles GPIO pin as feedback.

   

I am also using a UART with the "enable wakeup from deep sleep" option enabled so that the incoming serial stream will bring the system out of deep sleep also. In a similar manner to the GPIO interrupt callback, I have set up a callback on the UART_RX_WAKEUP_IRQ_Interrupt(). The interrupt sets an activity flag and toggles a GPIO pin so I can detect when serial data has woken up the system from Deep Sleep. The activity flag can then hold off Deep Sleep until the serial data has been received.

   

In addition I am toggling another GPIO pin showing when the system goes in and out of Deep Sleep as a reference.

   

When the GPIO wake up input is asserted the module wakes and toggles the GPIO output pin so I can see this caused the wakeup.

   

When I send serial data to the UART I can see the module wake up from Deep Sleep but there is no indication that the callback function is called. Because my code is not aware that the incoming serial stream caused the interrupt (as the callback function is not called) the module enters Deep Sleep again before the whole character is received by the UART.

   

I am at a loss why the GPIO pin interrupt callback works fine but UART interrupt callback is failing.

   

I have tried using the StartEx(xxx_isr) function also which again works with the GPIO input but not the UART!

   

If anyone can point me in the right direction I would appreciate the input.

   
        
  • PSoc Creator 3.3
  •     
  • All components at latest versions.
  •    
0 Likes
11 Replies
Anonymous
Not applicable

Progress update:

   

I have got around the ISR issue for the moment by checking the interrupt status register on wakeup and setting an activity flag.

   

UART_Wakeup() clears the status register so I needed to check it first.

   

                    UART_Sleep();
                    CySysPmDeepSleep();
                                    
                    if((UART_rx_wake_INTSTAT & UART_rx_wake_MASK) >> UART_rx_wake_SHIFT)
                    {
                        UartActive = 1;
                    }
                    
                    UART_Wakeup();

   

The rest of the code is now working reliably but I don't think I should need to use this kludge. I would rather keep the code elegant and use the functions provided.

   

Does anyone know if there is a bug in the Uart Rx wakeup code?

0 Likes
Anonymous
Not applicable

Continuing on with my initial post.....

   

 

   

Can someone explain when the functions in xxx_RX_WAKEUP_IRQ.c and xxx_UART.c should be used in relation to the low power uart wake-up from deep sleep?

   

Both files have interrupt setup/modification and service routine functions that seem to deal with the wakeup interrupt which is confusing. There are no app notes dealing with this and very little in the component datasheet.

   

Which functions should be used in the context of my post?

   

Thanks

   

Dan.

0 Likes
Anonymous
Not applicable

Hi,

   

Can anyone from Cypress Tech support comment on this please.

   

Has anyone successfully used the uart wake up from deep sleep ISR or the new callbacks added to the ISR?

   

    CY_ISR(UART_1_UART_WAKEUP_ISR)
    {
    #ifdef UART_1_UART_WAKEUP_ISR_ENTRY_CALLBACK
        UART_1_UART_WAKEUP_ISR_EntryCallback();
    #endif /* UART_1_UART_WAKEUP_ISR_ENTRY_CALLBACK */

   

        /* Clear interrupt source: the event becomes multi triggered and is
        * only disabled by UART_1_UartRestoreConfig() call.
        */
    #if(UART_1_SCB_MODE_UNCONFIG_CONST_CFG)
        #if(UART_1_MOSI_SCL_RX_WAKE_PIN)
            (void) UART_1_uart_rx_wake_i2c_sda_spi_mosi_ClearInterrupt();
        #endif /* (UART_1_MOSI_SCL_RX_WAKE_PIN) */
    #else
        #if(UART_1_UART_RX_WAKE_PIN)
            (void) UART_1_rx_wake_ClearInterrupt();
        #endif /* (UART_1_UART_RX_WAKE_PIN) */
    #endif /* (UART_1_SCB_MODE_UNCONFIG_CONST_CFG) */

   

    #ifdef UART_1_UART_WAKEUP_ISR_EXIT_CALLBACK
        UART_1_UART_WAKEUP_ISR_ExitCallback();
    #endif /* UART_1_UART_WAKEUP_ISR_EXIT_CALLBACK */
    }

   

Thanks Dan.

0 Likes
Anonymous
Not applicable

Hi,

   

Would it be possible to upload your project bundle, I am also working on the similar Project.

   

Thanks,

0 Likes
BrKu_1344346
Level 1
Level 1
Distributor - Weikeng(GC)
5 replies posted First question asked First reply posted

Hi

   

I has same issue, cypress response below

   

It's an known issue, if we use the Uart wake up function and also we have other wake up source in project.

   

Tips: 1. disable the uart wake up function, and use the GPIO to wake up if possible.

   

2. We may fix it in Creator 3.3 SP2 with SCB 3.2. But need to wait the verification. Time is not settled as I know.
 

   

Thanks.

0 Likes
Anonymous
Not applicable

I've recently been working on a project that implements UART RX wake-up reliably at any baud rate, but requires the use of a dummy byte (I use 0x00 for a few reasons). It doesn't use the component-provided RX interrupt, but instead uses an application-set falling-edge interrupt on the RX pin. This interrupt is enabled only when entering deep sleep mode, and immediately disabled upon waking.

   

The implementation also doesn't use the SKIP_START register flag, which is why it works at any baud rate, and why it requires a 0x00 dummy byte to wake. As in your second post, I also trigger some special behavior when the RX pin interrupt source flag is set: I prevent sleep again until at least two full byte time intervals have elapsed.

   

I can provide more detail if your design can tolerate a dummy byte. Without a dummy byte, it becomes more complicated and challenging in light of the two requirements for UART RX wake in the SCB datasheet (25 usec minimum bit time and Bit 0 must be high for SKIP_START resync).

0 Likes
Anonymous
Not applicable

Hi jrow,

   

Thanks for the thread update.

   

I would be interested in any details of your method for waking up the module without having to use problematic RX wake-up. The dummy byte can probably be catered for as I have to use a dummy byte anyway to ensure no data is lost.

   

Dan.

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

Hi Dan,

   

Thanks for your patience. I've attached a new project bundle that demonstrates my approach in a pretty minimal project that incorporates both BLE and UART. It's a modified version of the "BLE_Device_Information_Service" code example that comes with PSoC Creator. It's tweaked for demonstration with the CYBLE-022001-EVAL board in the BLE Pioneer kit.

   

You can run a diff on it or use WinMerge, but the main changes are:

   
        
  • Addition of UART component on P1_4+P1_5 (115200,8/N/1, no flow control, 16-byte internal RX/TX SW buffer enabled)
  •     
  • Addition of GlobalSignal component and AllPortInt ISR
  •     
  • Addition of Power_State output pin on P5_1 for monitoring CPU sleep state (LOW when active, HIGH when in Deep Sleep)
  •     
  • Global uartTXPending flag variable to prevent entry into Deep Sleep while data is still transmitting
  •     
  • Global uartRXCountdown counter variable to prevent entry into Deep Sleep while more data is expected
  •     
  • GPIOInterruptHandler ISR for Global Signal AllPortInt
  •     
  • UARTInterruptHandler function assigned as custom interrupt handler on the UART component
  •     
  • Local echo of incoming UART data back to the host
  •    
   

To use, just flash and open the serial port in your terminal of choice. Prepend all continuous transmissions to the module with a 0x00 byte. The attached image shows what it looks like on my logic analyzer.

   

   

0 Likes
Anonymous
Not applicable

Hi jrow,

   

Interestingly your solution logic looks very similar to my final workaround. Especially setting the rxWake flag and clearing the Rx pin interrupt flag when exiting the deep-sleep state (post #2). I had imagined this would have been implemented in your AllPortInt ISR, probably as that is where I originally intended to do it but became unstuck.

   

I finally kept the Uart Rx wakeup configured in the component as the baud rate limitation wasn't an issue. I had a defined serial protocol with fixed packet length and so detecting the end of the packet to resume deep sleep was less of a problem for me. I did however have to clear the Rx buffer after waking up the UART as another undocumented issue causes the serial buffer to fill with junk.

   

I would imagine your calculation for the byte length with respect to main loop execution period could become problematic if the main loop was any more complex . Using another hardware timer, enabled after the serial stream begins, might simplify the timing for the next character received logic and avoid the unpredictable nature of the main loop timing and other interrupt latencies.

   

Do you have any knowledge of what the main issues are with the Rx wakeup feature of the UART component? I know your solution is mainly to obviate the baud rate limitation of this feature but you may be able to shed some light on the causes of the malfunction.

   

Dan.

0 Likes
Anonymous
Not applicable

Hi Dan,

   

The component's built-in wake-on-RX functionality has the following two requirements, documented on page 163 of the current "SCB_P4_v3_10" component datasheet:

   
        
  • The 1st data bit of wakeup transfer has to be '1'. The UART skips the start bit and synchronizes on the 1st data bit. If synchronization does not occur, the received data will be corrupted.
  •     
  • The wakeup time of the device must be less than one bit duration; otherwise, the received data will be incorrect.
  •    
   

The first requirement is challenging because UART uses LSB bit ordering, so you can't just require a large range of data (e.g. 0x7F and lower, or 0x80 and above). In order to work, the transmitted wake-up byte must be an odd value (0x01, 0x03, and so on). The use of the SKIP_START peripheral register bit causes the UART to begin processing data immediately as soon as the device wakes up, since it no longer waits for a UART start bit (falling edge). It tries to synchronize on the first rising edge that it encounters--hence this requirement--but it will "detect" a 0xFF byte after a very short while even if there is no activity whatsoever on the UART RX pin. This is why it's problematic if you have other potential wake-up sources in the design, such as BLE or GPIOs.

   

The second requirement concerns the maximum baud rate that allows (1) meeting the first requirement and (2) doing so in a long enough time interval that the first rising edge used to re-sync occurs after the CPU is awake. For a 25 usec wake time, this means a maximum safe baud rate of 40k, or more commonly, 38400. Anything faster will by definition result in corrupt data, since you'll be in the middle of the first data bit before the CPU wakes up.

   

The behavior here is more of a set of limitations rather than bugs/malfunctions, due to the way the functionality is implemented inside the component. Because of the way UART data transmission works and the CPU wake timing, there's no way around it if you don't want to require a dummy byte.

   

The solution in the previously attached example solves both of these problems. By not using the SKIP_START function, there's no need to attempt to throw out a spurious 0xFF byte if the wake source was something other than UART. You only need to make sure you don't send anything except dummy bytes until the CPU is fully awake.

   

You're correct that the byte length calculation is very simple. However, if you use a sufficiently short constant value based on a best-case measurement, then the worst thing that happens is that the CPU stays awake a little longer than it needs to. It only becomes a problem if there are any execution paths that result in a faster loop than you allowed.

Anonymous
Not applicable

Hi jrow,

   

Thanks for your description of the UART wakeup. Interestingly I note that the component and datasheet has been updated to V3.20 which expands on the limitations. It makes the implementation issues much clearer with useful illustrations and the suggestion of using a 0x00 dummy byte as preamble when not using skip start. I was aware of how the UART used the skip start feature for wakeup but now understanding the intricacies of the first bit sync (especially the level rather than edge triggering) certainly clarify why things can go wrong.

   

Dan.

0 Likes