[fpc-pascal] Pascal Neopixels

Michael Ring mail at michael-ring.org
Sun Jul 29 19:59:11 CEST 2018


For me, the easiest way to solve this (on a microcontroller, not a 
raspberry) was using SPI, you can create a pretty precise timing with 
that method. And looking at the code in the repository you provided it 
looks like the SPI of the Raspberry is DMA-Enabled in kernel.


In my own code I use 16Bit SPI for finer resolution, but the same 
principle applies to 8Bit SPI, the only important thing here is to keep 
the line long enough on low to generate the proper timing.

Basic idea is to define a pattern for zero's ond ones:

   ZeroPattern := %0111000000000000;
   OnePattern  := %0111111000000000;


those patterns define either a zero or a one bit and you need a total of 
24*this 16bit Pattern to make one Neopixel glow in the selected color. 
When you run SPI at 8Mhz then every bit in the pattern represents 125 
microseconds and you now simply set as much "1" bits as you need to 
reach the proper timing of the neopixels. it is important to have the 
highest bit in the pattern set to '0' so that the neopixel can properly 
detect the 0->1 change.

You can also use 8Bit Patterns, this saves a little memory but you will 
have to reduce the SPI Frequency to 4MHz (will give you 250 microseconds 
per bit)

Once you have filled up a buffer with the proper Patterns you can send 
the buffer to /dev/spidev0.0 and the linux kernel should take over and 
send the data as a continous bitstream.

Here's an example on how to create this 16 bit buffer, you start with an 
array of TColor that you fill with the color value of each neopixel you 
want to use

var

   FRGBPixel: array of TColor;

and then you iterate through the array and write the Bit-Patterns for 
each Neopixel:

     for i := 0 to MaxPixelCount - 1 do
     begin
       //BRG format needed for APA106, also often RGB format is used, 
simply change the pixel shifting here
       Value := ((FRGBPixel[i] shl 8) and $00ffff00) or ((FRGBPixel[i] 
shr 16) and $ff);
       Mask := 1 shl 23;
       for j := 0 to 23 do
       begin
         if (Value and Mask) = 0 then
           WriteBuffer[j+i*24] := ZeroPattern
         else
           // Send 1 Bit
           WriteBuffer[j+i*24] := OnePattern;
         Mask := Mask shr 1;
       end;
     end;


Now you have a properly built WriteBuffer that you cen send to the SPI 
Device.

The only other thing you should need to do is to convert the

ws2811_return_t spi_init(ws2811_t *ws2811)

startup code or look at this page:

http://wiki.freepascal.org/Raspberry_Pi_-_SPI/de

for the lowlevel initialization stuff of SPI, although I am not sure if 
DMA is enabled in this example, I never used this code.

Michael




Am 29.07.18 um 16:19 schrieb Anthony Walter:
> I'm not sure what would be the correct list for this question since it 
> involves writing Pascal code and not Lazarus, so here goes ...
>
> Can anyone offer me any advice or refer me to helpful resources on the 
> subject of using Pascal code to control WS2128 led strips 
> <https://www.youtube.com/watch?v=fh2QcmcBRpQ>, or neopixels, from a 
> Raspberry Pi?
>
> I've wired up a some neopixels 
> <https://www.amazon.com/gp/product/B072N7VGK6/ref=oh_aui_detailpage_o02_s01?ie=UTF8&psc=1> and 
> am able to control them by way of PWM (pulse wave modulation) on GPIO 
> 18 (pin 12 on a Pi 3) using this rpi_ws281x git repository 
> <https://github.com/jgarff/rpi_ws281x>. It works great either in C or 
> using Python bindings, and I am able to create effects in C code 
> easily. But obviously I'd prefer to interface with the neopixels using 
> Pascal.
>
> I've seen some Pascal libraries for both GPIO access, and DMA pin 
> mapping, but the communication protocol for controlling neopixels is a 
> bit more complex than writing a 24 bit value to a pin. Each pixel can 
> be controlled in both brightness and color, though I'm unsure how the 
> wx281x library is doing this.
>
> Assuming I was to do this in from scratch  Pascal, that is control the 
> colors and brightness of many pixels withing an entire neopixel strip, 
> I believe I need to do the following in psuedo code.
>
> // open device memory
> fd = open('/dev/mem')
> // map the file descriptor to the memory address of gpio18
> gpio18 = mmap(fd, ...)
> // fd is no longer needed
> close(fd)
> [ then write to gpio18 in some loop as a data structure ]
>   // cleanup
>   unmap(gpio18)
>
> If that psuedo code is the correct way to do things, I would need to 
> know what is the offset and page size for PWM GPIO18, what flags to 
> use with mmap, and finally what memory locations inside of the gpio18 
> pointer control which pixel, what is the brightness memory location 
> and size, what is the color memory location and size for each pixel. 
> Also, is there any other memory location inside gpio18 that is of 
> importance or relevance, such as an on/off bit?
>
> Does anyone have any insight into this subject that might be useful? 
> After I get something that works I'll be sure to share the resulting 
> Pascal code and a video plus tutorial.
>
> TIA
>
>
> _______________________________________________
> fpc-pascal maillist  -  fpc-pascal at lists.freepascal.org
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20180729/44d22462/attachment.html>


More information about the fpc-pascal mailing list