nRF52840 BLE causing display glitch on GC9A01 using SPIM

We have a product based on the nRF52840 which uses the GC9A01 display driven using SPI on battery power. The device also functions as a Bluetooth connectable so it is normally advertising data at a 1 second interval. If the display is left on for several hours while BLE is enabled, the display will randomly become glitched and stays this way until reset. It appears that the BLE is somehow interfering with SPI and causing corrupt data eventually. We are fairly confident that the issue is not hardware related, as we have eliminated noise using stable power supplies and impedance matching the SPI lines.

Is it possible that the nRF is low on resources and corrupting the SPI data or display buffer when using BLE?

The pin-out for the display is as follows.

  • DC - P0.06
  • CS - P0.08
  • RESET - P0.11
  • SDA - P0.12
  • SCL - P1.09

We are using nRF Connect SDK v2.5.1.

Parents
  • Hi,

    There is no known issue like this. 

    How much resources your program is using? If there is an overflow then the compilation would tell you about that.

    If there is run time issue then you should debug and locate where the problem is occurring.

    /br

    Naeem

  • Here is the build output. There is no overflow.

    Memory region         Used Size  Region Size  %age Used
               FLASH:      953705 B         1 MB     90.95%
                 RAM:      145660 B       256 KB     55.56%
            IDT_LIST:          0 GB         2 KB      0.00%

    The issue occurs during runtime, but I do not see how to debug it because the issue occurs randomly after several hours to several days.

  • Should be straightforward, but I see issues and have not bothered yet to try myself; here's a recent ticket where the user is trying to use a specific RAM address, pretty common requirement. noinit-section-at-a-specific-address

    Edit: tried __attribute__((at(0x20001000))) but zephyr ignored me:

    struct gpio_callback button_cb_data;
    C:\ncs>type C:\ncs\v2.7.0\zephyr\samples\basic\button\build\button\zephyr\zephyr.map | find "button_cb_data"
     .bss.button_cb_data
                    0x0000000020000288                button_cb_data
    
    struct gpio_callback button_cb_data __attribute__((at(0x20001000)));
    C:\ncs>type C:\ncs\v2.7.0\zephyr\samples\basic\button\build\button\zephyr\zephyr.map | find "button_cb_data"
     .bss.button_cb_data
                    0x0000000020000288                button_cb_data
    

  • Didn't know nRFConnect had this workaround; does the map file show that it works? I'm curious what the setting does to the build. I'll try searching for it ..

    This is what I found so far in v2.7.0 with Nordic pre-release:

    nrfx_config.h
    #ifdef CONFIG_NRF52_ANOMALY_198_WORKAROUND
    #define NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED 1
    
    nrfx_config_nrf52840.h
     * @brief NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED
    #ifndef NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED
    #define NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED 0

  • Enabling the workaround does not seem to do anything. The map files are identical before and after enabling this value. Unless I am not enabling the workaround correctly.

    Edit: Is this value enabled by default? I looked in the Kconfig and it was already enabled.

    CONFIG_NRF52_ANOMALY_198_WORKAROUND

  • The 198 handler code is here, not sure how it is ensuring buffer placement:

    v2.7.0\modules\hal\nordic\nrfx\drivers\src\nrfx_spim.c

    No 198 handler here:

    v2.7.0\zephyr\drivers\spi\spi_nrfx_spim.c

    Wonder just what this code is doing - 0x40000E00 some secret power control register?

    // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
    
    static uint32_t m_anomaly_198_preserved_value;
    
    static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
    {
        m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
        if (buf_len == 0)
        {
            return;
        }
        uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
        uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
        uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
        uint32_t occupied_blocks = 0;
        if (block_addr >= 0x20010000)
        {
            occupied_blocks = (1UL << 8);
        }
        else
        {
            do {
                occupied_blocks |= block_flag;
                block_flag <<= 1;
                block_addr  += 0x2000;
            } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
        }
        *((volatile uint32_t *)0x40000E00) = occupied_blocks;
    }
    

Reply
  • The 198 handler code is here, not sure how it is ensuring buffer placement:

    v2.7.0\modules\hal\nordic\nrfx\drivers\src\nrfx_spim.c

    No 198 handler here:

    v2.7.0\zephyr\drivers\spi\spi_nrfx_spim.c

    Wonder just what this code is doing - 0x40000E00 some secret power control register?

    // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
    
    static uint32_t m_anomaly_198_preserved_value;
    
    static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
    {
        m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
        if (buf_len == 0)
        {
            return;
        }
        uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
        uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
        uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
        uint32_t occupied_blocks = 0;
        if (block_addr >= 0x20010000)
        {
            occupied_blocks = (1UL << 8);
        }
        else
        {
            do {
                occupied_blocks |= block_flag;
                block_flag <<= 1;
                block_addr  += 0x2000;
            } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
        }
        *((volatile uint32_t *)0x40000E00) = occupied_blocks;
    }
    

Children
No Data
Related