NeoPixel Signal

For drive NeoPixel device, I would need a signal of 400kHz, is this doable with Signal genereator ?
I give it a try but I can’t go lower to 2,5 µs for a period, is there another solution ?

Not sure if this is the same but I have looked at an addressable LED before that needed very tight timing for individual bits, in the microseconds. Even on a native system the drivers were partially written in assembly to get the timing right. If this is the same then a native driver is needed.

explained problem with interopt in NetDuino 2

so you should create a native solution no in .NET (in NET you need marshalling to triger it)

check this

3 Likes

Thanks @valon_hoti_gmail_com, very good to read !

http://old.ghielectronics.com/community/codeshare/entry/649

2 Likes

@Justin Good hack to begin !

I succeed to drive one Led: next step is chain (I think most difficult step is done !).
Thanks again :beers:

1 Like
3 Likes

I implemented SK6812. use interop code. :blush:

https://github.com/matsujirushi/TinyCLR-Ports/blob/dev-wiolte/Devices/WioLTE/WioLTENative.cpp#L177

4 Likes

I didn’t think of that, using SPI to mimic the interface! I am not exactly sure how it works but I want to play with this.

Clock is set to 3.2MHz. One bit for led signal is represented by four bits, so led signal is 3.2/4=800kHz.
If bit for led is 0, four bits are 1000. So we are up 0.3125µs and down 0.9375µs.
If bit for led is 1, four bits are 1100. So we are up 0.625µs and down 0.625µs.

Pro:

  • No need to do Native code

Cons:

  • It can be done only with a MOSI pin.
using System;
using GHIElectronics.TinyCLR.Devices.Spi;

// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global

namespace Bauland.Adafruit
{
    /// <summary>
    /// Wrapper for Adafruit NeoPixel modules (stick, shield, ...)
    /// </summary>
    public class NeoPixel
    {
        /// <summary>
        /// Number of DELs in chain 
        /// </summary>
        public int Size { get; }
        private readonly byte[] _buffer;
        private readonly byte[] _temp;
        private readonly SpiDevice _spi;
        /// <summary>
        /// Constructor of NeoPixel class
        /// </summary>
        /// <param name="spi">Identifier of spi bus</param>
        /// <param name="numLed">Number of DELs in chain</param>
        public NeoPixel(string spi, int numLed)
        {
            Size = numLed;
            _temp = new byte[4];
            _buffer = new byte[Size * 12];
            var settings = new SpiConnectionSettings()
            {
                ClockFrequency = 3200 * 1000,
                Mode = SpiMode.Mode1,
                DataBitLength = 8,
                ChipSelectType = SpiChipSelectType.None
            };
            var controller = SpiController.FromName(spi);
            _spi = controller.GetDevice(settings);
            Reset();
        }

        private void Reset()
        {
            for (int i = 0; i < _buffer.Length; i++)
            {
                _buffer[i] = 0x0;
            }
            Show(); // Send reset cmd

            // Initialize _buffer to 0 (0x88 values)
            for (int i = 0; i < _buffer.Length; i++)
            {
                _buffer[i] = 0x88;
            }
            Show(); // Set all Black
        }

        /// <summary>
        /// Change color of one of DEL
        /// </summary>
        /// <param name="index">Index (starting from 0) of DEL</param>
        /// <param name="r">Value of red component</param>
        /// <param name="g">Value of green component</param>
        /// <param name="b">Value of blue component</param>
        /// <exception cref="ArgumentOutOfRangeException">Could be raised if index param is out of range</exception>
        public void ChangeColor(int index, byte r, byte g, byte b)
        {
            if (index < 0 || index >= Size) throw new ArgumentOutOfRangeException(nameof(index));
            var startArray = index * 12;
            Compute(g, _temp);
            Array.Copy(_temp, 0, _buffer, startArray, 4);
            Compute(r, _temp);
            Array.Copy(_temp, 0, _buffer, startArray + 4, 4);
            Compute(b, _temp);
            Array.Copy(_temp, 0, _buffer, startArray + 8, 4);
        }

        /// <summary>
        /// Change color of all DEL
        /// </summary>
        /// <param name="r">Value of red component</param>
        /// <param name="g">Value of green component</param>
        /// <param name="b">Value of blue component</param>
        public void ChangeAllColor(byte r, byte g, byte b)
        {
            Compute(g, _temp);
            for (int index = 0; index < Size; index++)
            {
                var startArray = index * 12;
                Array.Copy(_temp, 0, _buffer, startArray, 4);
            }
            Compute(r, _temp);
            for (int index = 0; index < Size; index++)
            {
                var startArray = index * 12;
                Array.Copy(_temp, 0, _buffer, startArray + 4, 4);
            }
            Compute(b, _temp);
            for (int index = 0; index < Size; index++)
            {
                var startArray = index * 12;
                Array.Copy(_temp, 0, _buffer, startArray + 8, 4);
            }
        }

        /// <summary>
        /// Turn off one DEL
        /// </summary>
        /// <param name="index">Index (starting from 0) of DEL</param>
        public void Off(int index)
        {
            ChangeColor(index, 0, 0, 0);
        }

        /// <summary>
        /// Turn off all DELs
        /// </summary>
        public void Off()
        {
            ChangeAllColor(0, 0, 0);
        }

        private static void Compute(byte b, byte[] array)
        {
            for (byte i = 0; i < 4; i++)
            {
                array[3 - i] = (byte)(((b & (0x01 << (2 * i))) == (0x01 << (2 * i)) ? 0x0c : 0x08) | ((b & (0x01 << (2 * i + 1))) == (0x01 << (2 * i + 1)) ? 0xc0 : 0x80));
            }
        }


        /// <summary>
        /// Send buffer to DELs to display
        /// </summary>
        public void Show()
        {
            _spi.Write(_buffer);
        }
    }
}
3 Likes

the SPI trick was used here on WS28xx type pixel chains for a long time… 2012 at least, even though the old codeshare was 2013… So Gus why didn’t you remember something from 6 years ago? :slight_smile: :smile:

1 Like

I must be getting old :slight_smile:

2 Likes

Your brain is still Young, but garbage collector has done is job ! :grinning:

4 Likes

Um, I too have been feeling that way, probably for longer than I’d want to admit !

3 Likes