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?

  • Please ignore my last comment about the question (it was referring to a old question, my bad).

  • Okay, here is the full source code: pin_change_int.zip

    Note on the code:

    1. I use UART for some communication and controls. I use PuTTY, but I believe other apps will work. The configuration is set like other examples:
    - Speed: 115200
    - Data bits: 8
    - Stop bits: 1
    - Parity: None
    - Flow control: XON / XOFF
    Commands available through serials:
    - Press the number "1", "2", "3" (normal keys and keypad) and followed by [ENTER] or [SPACE] to send data to turn on the LED to some color. 1 = sapphire? 2 = lime? 3 = magenta?
    - "4" will call the count_get() function. This function is connected to a TIMER. I'd like to use this TIMER to capture the duration. (Spoiler: I'll have some questions about this later).

    2. The definition "MAX_LED" defines the number of LEDs connected. I connected 1 and would like to have 1 extra data for the analysis, so I wrote 2. If you got a strip of N LEDs, please change it to N+L to receive L data on the output of last LED bit.

    And here's the latest plot I captured, when I was typing this: Cap7.zip

    No extra external hardware needed. Only a logic converter and the WS2812B. I am currently using only 1 DK

    (I hope I did not miss any other description)

  • Hi,

    I do not have a WS2812B to test with. My point was that we need to skip that to look at the PPI behaviour and only use the DK. Then I think you will find that PPI works as expected.

  • Oh, my bad.

    I tried shorting pin 11 and pin 13 (which are the pin used to drive the LED and the pin used to receive leftover data). I am able to see that the PPI was working. Otherwise, still: the same delay. Cap8-no led.zip *Updated file*

    The output of PPI was inverted. Probably since I did not set it somewhere. But I don't think it's a problem now

    *edit*: This version is not inverted anymore. I've fixed it.

  • OK, so we agree that PPI works as expected. Then we can move on. What is actually the problem now? I have lost track of this thread...

Reply Children
  • Yes. PPI works. Otherwise, I am experiencing some inaccuracy. According to my 100 MHz Logic Analyzer, the HIGH signal was sent, from the end of a WS2812 or from nRF52DK's Pin 11, for +350 ns.

    Otherwise, after being captured by the same nRF52DK's Pin 13, and being copied (by triggering) to Pin 17, the HIGH signal was sent only for +240 ns.

    The same thing happened on LOW signal: sent: +900 ns, copied: +1.01 us.

    I think a table will describe it better:

    Something Type Acutal Duration Copied Duration
    Test 1 HIGH 350 ns 240 ns
    Test 2 HIGH 340 ns 230 ns
    Test 3 LOW  890 ns 1000 ns (1us)
    Test 4 LOW  270 ns 130 ns
    Test 5 HIGH 960 ns 980 ns
    Test 6 LOW  900 ns 1.01 us
    Test 7 HIGH 350 ns 240 ns
    Test 8 LOW  890 ns 1000 ns (1us)

    I hope this thing is visible

  • I see. If these are worst case numbers, then that is not unexpected. The 16 MHz peripheral clock means that you will have some variation on the GPIOTE sampling of the input signal. If you are looking at a pulse with two tranzitions, that means  up to two 16 MHz periods,  62.5 ns * 2 = 125 ns.

  • hmm, I don't quite get it. (Is the variation expected?)

    Are you saying that I let GPIOTE to handle this accidentally? But I remember that GPIOTE is not fast enough to handle it. Therefore, I do not think it is GPIOTE.

    In my case, one pulse (one high and one low) 1.24 us (~ 1240 ns). Is that what you mean?

    I also read another question that (I think) is achieving the similar thing. If I am asking PPI to transfer the data to a timer, will I need to make 2 timers that does:
    1. one records high (HT) and one waits for low (LT)
    2. once a transition to low is sensed, PPI calls LT. LT stops and captures HT's duration and save it
    3. once a transition to high is sensed, PPI calls HT. HT stops and captures LT's duration and save it

    ?

  • Hi,

    Winz said:
    hmm, I don't quite get it. (Is the variation expected?)

    There will be some variation between the input signal and output signal, as the input signal is not synchronized to the 16 MHz peripheral clock, but the output signal is.

    Winz said:

    Are you saying that I let GPIOTE to handle this accidentally? But I remember that GPIOTE is not fast enough to handle it. Therefore, I do not think it is GPIOTE.

    In my case, one pulse (one high and one low) 1.24 us (~ 1240 ns). Is that what you mean?

    I did not get this. I am sorry, but am still unable to get a proper understanding of the previous question, context and test setup. I suggest you create a new question starting with absolutely all the information you have in a single post, making it stand alone and not referring to this thread. 

    Winz said:
    I also read another question that (I think) is achieving the similar thing. If I am asking PPI to transfer the data to a timer, will I need to make 2 timers that does:
    1. one records high (HT) and one waits for low (LT)
    2. once a transition to low is sensed, PPI calls LT. LT stops and captures HT's duration and save it
    3. once a transition to high is sensed, PPI calls HT. HT stops and captures LT's duration and save it

    Yes, your points about what you want to achieve are sensible. You need to calculate the pulse durations by hooking up the GPIOTE input to a timer so that you start the timer on one event and capture it on another (or capture bot start and stop in different CC registers, depending on what suits you best).

  • ahh.. let's leave the second question alone.

    Okay so what I'm achieving now is to capture all the pulse's timing. I am really curious about this: will I be able to capture all rising edge and falling edge using one PPI channel and set GPIOTE's task to sense toggle?

    And I would like to know how to store the data in. Will you be able to provide me some info on how to do that? I've searched anywhere but did not really see how to store the value when it detects transitions.

    I referred here, and the example code provided was able to capture the time. I adapted here, but I was able to capture (at most) the periods of 16 data, when I expect 24. I guess it's GPIOTE, not PPI.

Related