Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Reading WS2812b leftover data through I2S

Hello there,

I am currently trying to read the leftover WS2812b LED strip data which was sent using a single channel I2S. The data sent from the board (through I2S) looks like this:

with around 34 mV for high and around 2~6 mV on low. I decided not to send FFF, but 888 instead.

I am aiming to calculate the length of the LED strip. Each LED chip will read the first 24 bits of the data, cascade (discard) it, then pass it to the next one. Therefore, the strategy is to get the data after being cascaded by the last chip and calculate the length of it (which later will be divided by 24 to see how many are left).

The question is: How will I be able to read those data? I tried reading as usual (set a buffer for the i2s, start it, listen for it (delay), stop it, then check its buffer), but I got my buffer filled with all FFF instead. and a thing is that... when I tried to read anything from the pin, although I am not sending any data (the LED strip is not powered on, but connected to other's ground), there will be data, which should not happen. I assigned pin 22, 23, 24, 25 to be the i2s input pin (which will be assigned and unassigned when used or unused), and they are configured as follows:

nrf_gpio_cfg_sense_input(DIN1_PIN, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);

Thank you in advance.

Parents
  • Hi Einar,

    Sorry, please disregard 34 mV and 2~6 mV, it's wrong, it should be 2.79 V for High and -15.9 mV (or 0 V) for Low. This is the data signal created on WS2812B's Data out.

    I connected the strip directly to the board's VDD to power it on, P0.11 for Data, and ground. I did not use any level converter (I know that I'm suggested to supply 5v and use a level converter, but 3.3 V is able to turn the LED on so, I'm trying it).

    When there is no data being transferred through the WS2812b, the voltage of the DOUT is around -0.8 mV ~ -78.92 mV. At this state, if I call the board to read any data, by using

    i2s_config_init(DIN2_PIN, 17);

    where DIN2_PIN is defined by

    #define DIN2_PIN 23

    , followed by

    i2s_start();
    nrf_delay_us(I2S_DETECTION);
    
    for (i = 1; i < I2S_BUFFER_SIZE; i++) {
    	if (I2SRxBuffer[i] != 0 || I2SRxBuffer[i] != -1) {
    		printf("isi: %x\r\n", I2SRxBuffer[i]);
    		printf("as: %d\r\n", I2SRxBuffer[i]);
    		if (I2SRxBuffer[i] > 0x11111110) {
    			lengthz++;
    		}
    	}
    }
    
    i2s_stop();

    , I2SRxBuffer[i] will always print ffffffff.

  • Hi,

    OK. The logical levels for the nRF are supposed to be above 0.7 * Vdd for high and below 0.3 * Vdd (but > 0 V) for low. However, I would not expect that the logical levels are OK for the nRF, and the low negative voltage for logical '0' should be ok. But I would not do it like this in an actual end product.

    I do not have any idea if the voltages are acceptable to the WS2812b, though. It is out of spec after all (according to the datasheet it should be between +3.5 and +5.3). Can you show us logic analyzer plots of the data out of the WS2812b? Is it all FF's there as well? If so then I would try using a level shifter and supplying the WS2812b with a voltage within spec before digging any further.

    By the way, are you basing your endeavors on this blog post?

  • Okay, I stopped using COMP. As discussed above, I am confident that my Level Shifter is able to do the job: step down the data's voltage to be suitable for the nRF.

    I tried to setup a ppi with the following:

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, \
                                          nrf_drv_gpiote_in_event_addr_get(PIN_IN), \
    									  nrf_drv_gpiote_out_task_addr_get(PIN_OUT));
    APP_ERROR_CHECK(err_code);

    And as a result, I got the (almost) exactly same data in the PIN_OUT as in the PIN_IN, which is as expected.

    Otherwise, this is still not done yet. nRF needs to know how many there are. Therefore, I think I should set the TEP to somewhere else. I'd like to send it to a function code. Otherwise, as Ole Morten said,

    Any task is a valid end-point for a PPI channel (not just tasks in timers and GPIOTE), but not a code function. The PPI can only be used to connect tasks and events from different peripheral blocks inside the nRF51, not co

    it seems that I can't send it to a function code. Therefore, where should I send it? Any suggestion? Timer? or..?

  • Ah right, I forgot to mention that I have made another TIMER, named "COUNTER" using this way:

    const nrf_drv_timer_t COUNTER = NRF_DRV_TIMER_INSTANCE(1);

    The argument of NRF_DRIVER_TIMER_INSTANCE is 1 because I used 0 for another timer, "MY_TIMER" (I suppose it's the right way to do it?)

    And this timer is the one I'd like to connect to the PPI as PPI's TEP.

  • Peripheral can have event end points, which generate a pulse when there is an event. They can also have task end points, which trigger a task when they get a pulse via PPI (typically coming from an event end point). That is how you connect peripherals in nRF without using CPU and is very sensible for measuring durations of pulses (and many other tasks).

    I recommend you read up on the following:

  • Okay,

    So, I tried to assess PPI's functionality by copying the signal from the input pin to output.

    Otherwise, I figured out that there are some inaccuracy (which is crucial) created by PPI:

    I use PPI to copy the signal (purple). on the self board (dark brown), some data are not displayed well, occurs on the different board as well (red).

    Is there any way for me to increase PPI's accuracy?

    I'm using SDK v14.2. (No, I'm not mentioning about the links' SDK version, thanks for those links)

    Here's the logic analyzer file if any would like to take a deeper look (open with the Logic software by Saleae Inc.): 12 MHz, 720 M Samples [9]-2.logicdata

    (or do I need to start another thread?)

  • Winz said:
    Otherwise, I figured out that there are some inaccuracy (which is crucial) created by PPI

    The main point of PPI is exactly that it has very low latency and high and predictable accuracy. The 16 MHz peripheral clock is used for PPI as well, and PPI hooks up task endpoints via a single flip-flop/register, as you can see from this figure.

    Winz said:
    Is there any way for me to increase PPI's accuracy?

    No. But the problem here is not with PPI accuracy. I don't know how you have hooked things up, but I suspect that is where you will find the problem.

Reply
  • Winz said:
    Otherwise, I figured out that there are some inaccuracy (which is crucial) created by PPI

    The main point of PPI is exactly that it has very low latency and high and predictable accuracy. The 16 MHz peripheral clock is used for PPI as well, and PPI hooks up task endpoints via a single flip-flop/register, as you can see from this figure.

    Winz said:
    Is there any way for me to increase PPI's accuracy?

    No. But the problem here is not with PPI accuracy. I don't know how you have hooked things up, but I suspect that is where you will find the problem.

Children
  • I don't know how you have hooked things up, but I suspect that is where you will find the problem.

    Here's the current setup:

    I set P0.13 as input and P0.17 (LED 1) as Output of PPI (Pink)

    and here how I initialize:

    GPIOTE:

    static void gpio_init(void)
    {
    	ret_code_t err_code;
    
    	err_code = nrf_drv_gpiote_init();
    	APP_ERROR_CHECK(err_code);
    
    	nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    
    	err_code = nrf_drv_gpiote_out_init(PIN_OUT, &out_config);
    	APP_ERROR_CHECK(err_code);
    
    	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
    	//nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    	in_config.pull = NRF_GPIO_PIN_PULLUP;
    	
    	err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    	//err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, null_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
    	nrf_drv_gpiote_out_task_enable(PIN_OUT);
    }

    PPI:

    static nrf_ppi_channel_t m_ppi_channel1;
    
    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        // Configure 1st available PPI channel to stop TIMER0 counter on TIMER1 COMPARE[0] match,
        // which is every even number of seconds.
    	
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
    	//ppi_enable_channel(FC_PPI_CH, &NRF_GPIOTE->EVENTS_IN[FC_GPIOTE_CH], &FC_TIMER->TASKS_COUNT);
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, \
    										  nrf_drv_gpiote_in_event_addr_get(PIN_IN), \
    										  nrf_drv_gpiote_out_task_addr_get(PIN_OUT));
    										  
    	//err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1, \
    										  nrf_drv_gpiote_in_event_addr_get(PIN_IN), \
    										  (uint32_t)&(NRF_TIMER1->TASKS_COUNT));
        APP_ERROR_CHECK(err_code);
    
        // Enable both configured PPI channels
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
    }

  • Why is what you get in the trace not expected with this code? What did you expect (and why/how)?

  • hmm.. I was expecting the PPI's output to be exactly the same (lower tolerance) as the input. A difference of some ns is still fine. But, I hope it won't change the data (as I received). I know about the one 16MHz delay. it's fine

  • Your code seems sensible but looking at the two lower lines more carefully (which should follow one another), it looks to me like the problem could be that you are using a too low sampling rate on the logic analyzer. 12 MHz is probably not enough. Could you increase it to say 100 MHz and see if that gives you better results?

  • Oops

    Okay, my logic analyzer is able to do it up to 24 MHz, or 24 MS/s (Mega Samples per second). And the result is still the same: some inaccuracy

    24 MHz, 1 B Samples [25].logicdata

Related