This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

I'd like to know how to control the Neopixel LED.

Hello

I'm trying to control the neopixeled WS2812. I referred to the following site.

https://electronut.in/nrf52-i2s-ws2812/

I'm going to use this example of neopixel LED to control LED 3chain. I want to remove the Bluetooth function from this code and use only the control part of the LED, but there seems to be a problem with my code.  This LEDs is connected to 5V, Gnd, I2S_SDIN_Pin(P0.26) on the nrf52DK board.  But the LED doesn't work at all.
I don't know because it's my first time using I2S and neopixel LED.  Can I get some help with this problem?

Thank you.


#include <stdio.h>
#include "nrf.h"
#include "nrf_drv_i2s.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "boards.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


#define NLEDS 16
#define RESET_BITS 6
#define I2S_BUFFER_SIZE 3*NLEDS + RESET_BITS

static uint32_t m_buffer_tx[I2S_BUFFER_SIZE];
static volatile int nled = 1;

volatile uint8_t g_demo_mode = 0;
volatile bool g_i2s_start = true;
volatile bool g_i2s_running = false;

// This is the I2S data handler - all data exchange related to the I2S transfers
// is done here.
static void data_handler(uint32_t const * p_data_received,
                         uint32_t       * p_data_to_send,
                         uint16_t         number_of_words)
{
    // Non-NULL value in 'p_data_to_send' indicates that the driver needs
    // a new portion of data to send.
    if (p_data_to_send != NULL)
    {
        // do nothing - buffer is updated elsewhere
    }
}

/*
    caclChannelValue()
    Sets up a 32 bit value for a channel (R/G/B). 
    A channel has 8 x 4-bit codes. Code 0xe is HIGH and 0x8 is LOW.
    So a level of 128 would be represented as:
    0xe8888888
    The 16 bit values need to be swapped because of the way I2S sends data - right/left channels.
    So for the above example, final value sent would be:
    0x8888e888
*/
uint32_t caclChannelValue(uint8_t level)
{
    uint32_t val = 0;

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

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

    return val;
}


// set LED data
void set_led_data()
{
    for(int i = 0; i < 3*NLEDS; i += 3) {
        if (i == 3*nled) {
            switch(g_demo_mode) 
            {
                case 0:
                {
                    m_buffer_tx[i] = 0x88888888;
                    m_buffer_tx[i+1] = caclChannelValue(128);
                    m_buffer_tx[i+2] = 0x88888888;
                }
                break;
                case 1:
                {
                    m_buffer_tx[i] = caclChannelValue(128);;
                    m_buffer_tx[i+1] = 0x88888888;
                    m_buffer_tx[i+2] = 0x88888888;
                }
                break;
                case 2:
                {
                    m_buffer_tx[i] = 0x88888888;
                    m_buffer_tx[i+1] = 0x88888888;
                    m_buffer_tx[i+2] = caclChannelValue(128);
                }
                break;
                default:
                break;
            }
        }
        else {
            m_buffer_tx[i] = 0x88888888;
            m_buffer_tx[i+1] = 0x88888888;
            m_buffer_tx[i+2] = 0x88888888;
        }
    }

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

int main(void)
{
    uint32_t err_code = NRF_SUCCESS;

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("I2S loopback example started.");

    set_led_data(); //first time
    //I2S setting
    nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;
    // In Master mode the MCK frequency and the MCK/LRCK ratio should be
    // set properly in order to achieve desired audio sample rate (which
    // is equivalent to the LRCK frequency).
    // For the following settings we'll get the LRCK frequency equal to
    // 15873 Hz (the closest one to 16 kHz that is possible to achieve).
    config.sdin_pin  = I2S_SDIN_PIN; //26
    config.sdout_pin = I2S_SDOUT_PIN; //27
    config.mck_setup = NRF_I2S_MCK_32MDIV10; //< 32 MHz / 10 = 3.2 MHz.
    config.ratio     = NRF_I2S_RATIO_32X; //96X, //< LRCK = MCK / 32.
    config.channels  = NRF_I2S_CHANNELS_STEREO;

    err_code = nrf_drv_i2s_init(&config, data_handler);
    APP_ERROR_CHECK(err_code);


    for (;;)
    {
        // start I2S
        g_i2s_running = true;
        g_i2s_start = true;

        g_demo_mode = 2; //0~2

        // stop I2S
        //nrf_drv_i2s_stop();

        nrf_delay_ms(250);

        // update 
        if (g_i2s_running) 
        {
            nled = (nled + 1) % NLEDS;                
            set_led_data();
        }
    }
}

/** @} */

  • Hi, do you know if the code is running or not? Can you try to check with a simple application that just blinks an LED? You said that you want to "remove the bluetooth function"; does that mean that you are starting out with an example that uses the Softdevice? If so, did you remember to flash the Softdevice as well?

    It is usually very helpful to use a logic analyzer to debug the digital interface between the nRF52 and the LED sensors. At least you can check to see if there is actually any data being transferred.

  • Hello, Stian.


    I started with the I2S example of SDK v17.0.
    'nrf_drv_i2s_start()' was missing from the code I uploaded, so I added it to main() and ran it again.

    However, an error is output from nrf_drv_i2s_start.  This example seems to have been made from the old version of SDK. Is there a problem with transplanting the old version of the SDK?

    int main(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("I2S loopback example started.");
    
        set_led_data(); //first time
        //I2S setting
        nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;
        // In Master mode the MCK frequency and the MCK/LRCK ratio should be
        // set properly in order to achieve desired audio sample rate (which
        // is equivalent to the LRCK frequency).
        // For the following settings we'll get the LRCK frequency equal to
        // 15873 Hz (the closest one to 16 kHz that is possible to achieve).
        config.sdin_pin  = I2S_SDIN_PIN; //26
        config.sdout_pin = I2S_SDOUT_PIN; //27
        config.mck_setup = NRF_I2S_MCK_32MDIV10; //< 32 MHz / 10 = 3.2 MHz.
        config.ratio     = NRF_I2S_RATIO_32X; //96X, //< LRCK = MCK / 32.
        config.channels  = NRF_I2S_CHANNELS_STEREO;
    
        err_code = nrf_drv_i2s_init(&config, data_handler);
        APP_ERROR_CHECK(err_code);
    
        // start I2S
        g_i2s_running = true;
        g_i2s_start = true;
    
        g_demo_mode = 2; //0~2
    
        err_code = nrf_drv_i2s_start(m_buffer_tx, I2S_BUFFER_SIZE, 0);
        APP_ERROR_CHECK(err_code);
    
        for (;;)
        {
            // stop I2S
            //nrf_drv_i2s_stop();
    
            nrf_delay_ms(250);
    
            // update 
            if (g_i2s_running) 
            {
                nled = (nled + 1) % NLEDS;                
                set_led_data();
            }
        }
    }

    <error> app: ERROR 16 [NRF_ERROR_INVALID_ADDR] at Y:\YSC\Project\CODE\Nordic\SDK17.0\nRF5_SDK_17.0.0_9d13099\examples\peripheral\i2s\main.c:162
    
    PC at: 0x00002441
    
    <error> app: End of error report

    Thank you for your help.

  • Description of the error code:

    NRFX_ERROR_INVALID_ADDR If the provided buffers are not placed in the Data RAM region.

    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.2.0/group__nrfx__i2s.html?cp=7_5_2_6_9_0_7_1_9#ga2c12cf4e0542b5f62303526c0ab410e5

    How are you declaring the buffers? Try to declare the buffers as static

  • Hello

    I succeeded in output one LED using I2S. However, when more LEDs are used, LEDs except the first one have a strange output. I suspect there might be a problem transferring the buffer.

    Can you tell me what the problem is with this code and how to solve it? 

    // https://rs29.tistory.com/14
    
    #include <stdio.h>
    #include "nrf.h"
    #include "nrf_drv_i2s.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    #define sk6812_led_num 3 //number of LEDs
    #define sk6812_rst_buffer 8 //reset, 32bit*8= 256bit = 0.3125us*256 = 80us
    #define sk6812_buf_len sk6812_led_num * 4 + 8 //buffer size, 32bit
    
    //[0][0]=Green, [0][1]=Red, [0][2]=Blue, [0][3]=White
    static uint32_t sk6812_buffer[2][sk6812_buf_len] = {0}; //sk6812_buffer[2][sk6812_buf_len]
    
    volatile bool i2s_running = false;
    
    //LED color data, apply in buffer
    typedef struct sk6812_rgbw{
      uint8_t red;
      uint8_t green;
      uint8_t blue;
      uint8_t white;
    }sk6812_rgbw_struct;
    
    
    
    // This is the I2S data handler - all data exchange related to the I2S transfers is done here.
    //The data handler set with I2S initialization is called immediately after transmission and after transmission completion.
    static void i2s_data_handler(nrf_drv_i2s_buffers_t const * p_released, uint32_t status)
    {
        static uint8_t transfer_chk = 0;
    
        if(p_released->p_tx_buffer != 0) //If p_tx_buffer was previously delivered to the buffer
        {
          transfer_chk++;	//when send data count++
        }
    
        if(transfer_chk != 0) //after data send, stop i2s
        {
          nrf_drv_i2s_stop();
          i2s_running = false;
          transfer_chk = 0;	
        }
    }
    
    //data send to buffer though DMA
    void sk6812_send_buffer()
    {
      uint32_t err_code = NRF_SUCCESS;
      
      nrf_drv_i2s_buffers_t const i2s_buffers = {.p_tx_buffer = sk6812_buffer[0],}; 
    
      if(i2s_running == false) //if no runnning i2s
      {
        err_code = nrf_drv_i2s_start(&i2s_buffers, sk6812_buf_len, 0); //buffer, size, flag
        
        APP_ERROR_CHECK(err_code);
    
        i2s_running == true;
      }
    }
    
    
    void sk6812_set_color(sk6812_rgbw_struct* set_color, uint8_t index)
    {
      uint32_t temp_g, temp_r, temp_b, temp_w = 0;
    
      for(uint8_t i=0;i<8;i++)	//Green
      {
        if((set_color->green>>(7-i))&0x1==1)
        {
          temp_g|=0xC<<(7-i)*4;
        }
        else
        {
          temp_g|=0x8<<(7-i)*4;
        }
    
        if((set_color->red>>(7-i))&0x1==1)	//Red
        {
          temp_r|=0xC<<(7-i)*4;
        }
        else
        {
          temp_r|=0x8<<(7-i)*4;
        }
    
        if((set_color->blue>>(7-i))&0x1==1)	//Blue
        {
          temp_b|=0xC<<(7-i)*4;
        }
        else
        {
          temp_b|=0x8<<(7-i)*4;
        }
    
        if((set_color->white>>(7-i))&0x1==1)	//White
        {
          temp_w|=0xC<<(7-i)*4;
        }
        else
        {
          temp_w|=0x8<<(7-i)*4;
        }
      }
      
      sk6812_buffer[0][index*4]=((temp_g&0x0000FFFF)<<16)|((temp_g&0xFFFF0000)>>16);
      sk6812_buffer[0][index*4+1]=((temp_r&0x0000FFFF)<<16)|((temp_r&0xFFFF0000)>>16);
      sk6812_buffer[0][index*4+2]=((temp_b&0x0000FFFF)<<16)|((temp_b&0xFFFF0000)>>16);
      sk6812_buffer[0][index*4+3]=((temp_w&0x0000FFFF)<<16)|((temp_w&0xFFFF0000)>>16);
    
      sk6812_send_buffer();	
      nrf_delay_ms(1);
    }
    
    
    
    int main(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        //NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        //NRF_LOG_INFO("I2S loopback example started.");
    
        //I2S setting
        nrf_drv_i2s_config_t config = NRF_DRV_I2S_DEFAULT_CONFIG;	
        config.sdout_pin = I2S_SDOUT_PIN;	//SDOUT PIN 27
        config.mck_setup = NRF_I2S_MCK_32MDIV10;
        config.ratio     = NRF_I2S_RATIO_32X;
        config.sample_width=NRF_I2S_SWIDTH_16BIT;	
        config.channels  = NRF_I2S_CHANNELS_STEREO;
        
        err_code = nrf_drv_i2s_init(&config, i2s_data_handler);	
        APP_ERROR_CHECK(err_code);
    
        sk6812_rgbw_struct temp_rgbw;
    
        //color setting
        temp_rgbw.red = 0;
        temp_rgbw.green = 0;
        temp_rgbw.blue = 0;
        temp_rgbw.white = 0;
    
        for(uint8_t i=0;i<sk6812_led_num;i++) //first time led off
        {
          sk6812_set_color(&temp_rgbw,i);
        }
    
    
        for (;;)
        {
            //firt led
            temp_rgbw.red = 128;
            temp_rgbw.green = 0;
            temp_rgbw.blue = 0;
            temp_rgbw.white = 0; 
    
            sk6812_set_color(&temp_rgbw,0);
    
            //second led
            temp_rgbw.red = 0;
            temp_rgbw.green = 128;
            temp_rgbw.blue = 0;
            temp_rgbw.white = 0; 
    
            sk6812_set_color(&temp_rgbw,1); 
            
            //third led
            temp_rgbw.red = 0;
            temp_rgbw.green = 0;
            temp_rgbw.blue = 128;
            temp_rgbw.white = 0; 
    
            sk6812_set_color(&temp_rgbw,2);         
        }
    }
    
    /** @} */
    


    Thank you.

  • Hi, you will have to check the output of the I2S pins with a logic analyzer, and see if there are any differences between the outputs.

Related