This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

NRF52840DK driving Neopixel is flickering

Goodday all

Im trying to  drive some Neopixel LEDs with 52840DK  SDK_17.1.0. and have been following this example. https://devzone.nordicsemi.com/f/nordic-q-a/70560/nrfx_i2s-library-never-recognized

The code works but there is a severe flicker on my LEDs as if they are switching on and off continuously. I have  played around with the  i2s_init() function but the best I can get is a solid white. I have a suspicion the method this code use to address the Neopixels is not correct

Any advice or dedicated neopixel libraries avail would be greatly appreciated

Other than the flickering, the colors and brightness work as expected.

#include "nrf_delay.h"
#include "nrf_drv_i2s.h"

#define neopixels_number                20                                       /**< Neopixels number. */
#define neopixel_pin                    29                                      /**< Neopixel pin number. */

#define reset_bits                      6                                       /**< Reset bits. */
#define i2s_buffer_size                 ((3 * neopixels_number) + reset_bits)   /**< i2d buffer size for driving the neopixel. */
static uint32_t m_buffer_tx[i2s_buffer_size];
static uint32_t       * volatile mp_block_to_fill  = NULL;

static void set_neopixel_data(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b);

/**@brief Function for handeling the i2s data.
 *
 */
static void i2s_data_handler(nrf_drv_i2s_buffers_t const * p_released,
                             uint32_t                      status)
{
    ret_code_t err_code;
    ASSERT(p_released);

    if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED))
    {
        return;
    }

    if (!p_released->p_rx_buffer)
    {
        nrf_drv_i2s_buffers_t const next_buffers = {
            .p_tx_buffer = m_buffer_tx,
        };
        err_code = nrf_drv_i2s_next_buffers_set(&next_buffers);
        APP_ERROR_CHECK(err_code);

        mp_block_to_fill = m_buffer_tx;
    }
    else
    {      
        err_code = nrf_drv_i2s_next_buffers_set(p_released);
        APP_ERROR_CHECK(err_code);
        mp_block_to_fill = (uint32_t *)p_released->p_tx_buffer;
    }
}

/**@brief Function for calculating the rgb channels data value.
 *
 */
static uint32_t rgb_channels_value(uint8_t channel_level)
{
    uint32_t value = 0;

    // 0 
    if(channel_level == 0) {
        value = 0x88888888;
    }
    // 255
    else if (channel_level == 255) {
        value = 0xeeeeeeee;
    }
    else 
    {
        // apply 4-bit 0xe HIGH pattern wherever level bits are 1.
        value = 0x88888888;
        for (uint8_t i = 0; i < 8; i++) 
        {
            if((1 << i) & channel_level) 
            {
                uint32_t mask = ~(0x0f << 4*i);
                uint32_t patt = (0x0e << 4*i);
                value = (value & mask) | patt;
            }
        }

        // swap 16 bits
        value = (value >> 16) | (value << 16);
    }

    return value;
}

/**@brief Function for setting the leds (rgb) data in the i2s buffer.
 *
 *@param led_n   neopixel number in the array starting with 0.
 *@param r       red led level.
 *@param g       green led level.
 *@param b       blue led level.
 */
static void set_neopixel_data(uint8_t led_index, uint8_t r, uint8_t g, uint8_t b)
{
    for(int i = 0; i < (3 * neopixels_number); i += 3) 
    {
        if (i == (3 * led_index)) 
        {          
           m_buffer_tx[i]   = rgb_channels_value(g);
           m_buffer_tx[i+1] = rgb_channels_value(r);
           m_buffer_tx[i+2] = rgb_channels_value(b);
          
        }
        else 
        {
            m_buffer_tx[i]   = 0x88888888;
            m_buffer_tx[i+1] = 0x88888888;
            m_buffer_tx[i+2] = 0x88888888;
        }
    }

    // reset 
    for(int i = (3 * neopixels_number); i < i2s_buffer_size; i++) 
    {
        m_buffer_tx[i] = 0;
    }

     nrf_drv_i2s_buffers_t const initial_buffers = {
            .p_tx_buffer = m_buffer_tx,
        };
}

/**@brief Function for initialising the i2s.
 *
 */
static void i2s_init()
{
    uint32_t err_code = NRF_SUCCESS;

    nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;
    config.sdin_pin  = NRFX_I2S_PIN_NOT_USED;
    config.sdout_pin = neopixel_pin;

    config.mck_setup = NRF_I2S_MCK_32MDIV10;
    config.ratio     = NRF_I2S_RATIO_32X;
    config.channels  = NRF_I2S_CHANNELS_STEREO;
    err_code = nrf_drv_i2s_init(&config, i2s_data_handler);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for application main entry.
 */
int main(void)
{
    ret_code_t err_code;
    bool erase_bonds;

    nrf_drv_i2s_buffers_t const initial_buffers = 
    {
        .p_tx_buffer = m_buffer_tx 
    };

    i2s_init();

    err_code = nrf_drv_i2s_start(&initial_buffers, i2s_buffer_size, 0);            
    APP_ERROR_CHECK(err_code);
   

    // Enter main loop.
    for (;;)
    {
        set_neopixel_data(0,0,0,50); // Ttest some random colors
        set_neopixel_data(1,0,0,50); // 
        set_neopixel_data(2,0,0,50); // 
        set_neopixel_data(3,0,0,50); // 
        set_neopixel_data(4,0,0,50); // 
        set_neopixel_data(5,0,0,50); // 
        set_neopixel_data(6,0,0,50); // 
        set_neopixel_data(0,0,0,50); // 
        set_neopixel_data(7,0,0,50); // 
        set_neopixel_data(8,0,0,50); // 
        set_neopixel_data(9,0,0,50); // 
        set_neopixel_data(10,0,0,50); // 
        set_neopixel_data(11,0,50,0); // 
        set_neopixel_data(12,0,50,0); // 
        set_neopixel_data(13,0,50,0); // 
        set_neopixel_data(14,0,50,0); // 
        set_neopixel_data(15,50,0,0); // 
        set_neopixel_data(16,50,0,0); // 
        set_neopixel_data(17,50,0,0); // 
        set_neopixel_data(18,50,0,0); // 
        set_neopixel_data(19,50,0,0); // 
        set_neopixel_data(20,50,0,0); // 
         
    }
}


/**
 * @}
 */
/**/
  

  • Hi,

    This post might be helpful: https://devzone.nordicsemi.com/f/nordic-q-a/72958/ws2812-driver

    PS: The mentioned ws2812 driver in the light_bulb example uses PWM and not i2s.

  • Thanks Sigurd. I suspect that I2S is the problem here. I can successfully drive these LEDs with a Particle Photon board, so I know the hardware is working. With only 1 LED it works find but as soon as I add more Neopixels the flickering becomes more noticeable. With 20 LEDs they are definitely switching on and off as if the FOR(;;) loop is to slow. Hence me playing with the  i2s_init()  function to increase the frequency. I have also noted that setting channels Left or Right only lights up every 2nd LED.

    Will play around with the light_bulb example today - 

  • The Bulb example has proven most useful. I have removed all the Zigbee code and files and was left with a barebone framework to experiment with the neopixel driver. No more flickering or flashing. I can address each LED individually and I can adjust the brightness. But for some reason im only get shades of blue. 

    my code below

    #include "sdk_config.h"
    #include "bsp.h"
    #include "boards.h"
    #include "app_pwm.h"
    #include "app_timer.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "drv_ws2812.h"
    #define LED_CHAIN_DOUT_PIN                NRF_GPIO_PIN_MAP(1,7)                 /**< GPIO pin used as DOUT (to be connected to DIN pin of the first ws2812 led in chain) */
    #define DRV_WS2812_LED_CHAIN_PIXELS_COUNT_MAX 20
    
    
    #if (APP_BULB_USE_WS2812_LED_CHAIN)
    /**@brief Timer responsible for triggering periodic led chain refresh */
    APP_TIMER_DEF(m_ws2812_refresh_timer);
    
    /** @brief Requests a led chain refresh */
    static volatile bool m_ws2812_refresh_request;
    #endif
    
    /**@brief Function for initializing the application timer.
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Callback for button events.
     *
     * @param[in]   evt      Incoming event from the BSP subsystem.
     */
    static void buttons_handler(bsp_event_t evt)
    {
    
    }
    
    
    /**@brief Function for initializing LEDs and a single PWM channel.
     */
    static void leds_buttons_init(void)
    {
    
    
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
           /* Initialize timer, logging system and GPIOs. */
        timer_init();
        log_init();
        leds_buttons_init();
        drv_ws2812_init(LED_CHAIN_DOUT_PIN);
        drv_ws2812_set_pixel_all(60);
    
         //   drv_ws2812_set_pixel_all(25);
       drv_ws2812_display(NULL, NULL);
    }
    
    
    /**
     * @}
     */
    
     

    How do I set the color? according to the driver the 2nd variable should set the RGB color.

    drv_ws2812_set_pixel(uint32_t pixel_no, uint32_t color);

    but my 2nd variable set brightness (of blue only)

  • melt said:
    No more flickering or flashing. I can address each LED individually and I can adjust the brightness.

    Great!

    melt said:
    How do I set the color?

    Here is the doc for drv_ws2812_set_pixel:

    /**@brief Function for setting the specified pixel in the LED state buffer to the specified color.
     *
     * @param[in] pixel_no  Number of the pixel in the LED chain.
     *                      Specify a value in the range from 0 to @ref WS2812_LED_CHAIN_PIXELS_COUNT_MAX-1.
     *                      Values out of the range are ignored.
     * @param[in] color     Color to be set. Use the RGB format. Bits 23 to 16 are for the red component,
     *                      bits 15 to 8 are for the green component, and bits 7 to 0 are for the blue component.
     *
     * @note Call @ref drv_ws2812_display to update the LED chain from the frame buffer.
     */
    void drv_ws2812_set_pixel(uint32_t pixel_no, uint32_t color);

    So for red, try setting color to  e.g. 16711680 (bit 23 to 16 set to 1).

Related