Discussion:
[fpc-pascal] Pascal Neopixels
Anthony Walter
2018-07-29 14:19:16 UTC
Permalink
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
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
DaWorm
2018-07-29 17:15:41 UTC
Permalink
You should be able to use the library from Pascal directly rather than
trying to recreate it from scratch.

Jeff
Post by 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
http://youtu.be/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
_______________________________________________
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Michael Ring
2018-07-29 17:59:11 UTC
Permalink
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
Post by 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
http://youtu.be/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
_______________________________________________
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Anthony Walter
2018-07-29 18:50:44 UTC
Permalink
Thanks Michael, that's some good information. I'll poke around with Pascal
using the information you provided and see if I can turn an LED on/off, set
its color and brightness, and whatever else then post back here with the
results.

If anyone else cares to chime in with advice I'd much appreciate your
insights.
R0b0t1
2018-07-30 00:00:59 UTC
Permalink
Post by Anthony Walter
Thanks Michael, that's some good information. I'll poke around with
Pascal using the information you provided and see if I can turn an LED
on/off, set its color and brightness, and whatever else then post back here
with the results.
Post by Anthony Walter
If anyone else cares to chime in with advice I'd much appreciate your
insights.

There are device nodes you can interact with to drive the I2C/SPI
peripherals. This will be cleaner and more portable than interacting with
the registers yourself.

There may also be C libraries wrapping the details of the device nodes.
Creating headers for and calling that code may or may not save you any
work. Some of those libraries, like the devicemode USB one, are very poorly
written.

Should you not be able to open the device you may nneed to be root. Also
check that a "platform" driver hasn't already claimed it (like for power
management bus).

Cheers,
R0b0t1
R0b0t1
2018-07-30 00:06:46 UTC
Permalink
Post by Anthony Walter
Thanks Michael, that's some good information. I'll poke around with
Pascal using the information you provided and see if I can turn an LED
on/off, set its color and brightness, and whatever else then post back here
with the results.
Post by Anthony Walter
If anyone else cares to chime in with advice I'd much appreciate your
insights.

There are device nodes you can interact with to drive the I2C/SPI
peripherals. This will be cleaner and more portable than interacting with
the registers yourself.

There may also be C libraries wrapping the details of the device nodes.
Creating headers for and calling that code may or may not save you any
work. Some of those libraries, like the devicemode USB one,

Cheers,
R0b0t1

Loading...