Userspace Raspberry Pi library for controlling WS281X LEDs.
Posted: Wed Dec 22, 2021 3:05 pm
I have found a simple library for led strings. Since my case has 4 led's, I could also try to control them with PB.
Do not forget. Hardware needs root rights. PB so start with sudo
Update v1.01.6
WS2811.pbi
Do not forget. Hardware needs root rights. PB so start with sudo
Update v1.01.6
WS2811.pbi
Code: Select all
;TOP
; Comment : Userspace Raspberry Pi library for controlling WS281X LEDs.
; Author : mk-soft
; Version : v1.01.6
; Create : 21.12.2021
; Update : 28.12.2021
; Lisence : MIT and see github project
; Library : https://github.com/jgarff/rpi_ws281x
; Compile library: (See github projekt)
; -------------------------------------
;
; Open terminal:
;
; first install cmake:
;
; sudo apt-get install cmake
;
; also if git is not installed, install it:
;
; sudo apt-get install git
;
; now get the repository from the web:
;
; git clone https://github.com/jgarff/rpi_ws281x.git
;
; then go to the new directory:
;
; cd rpi_ws281x
;
; follow:
; mkdir build
; cd build
; cmake -D BUILD_SHARED=ON -D BUILD_TEST=OFF .. <--- don't forget double dots ;)
; cmake --build . <--- don't forget dot ;)
; sudo make install
; *********
EnableExplicit
; Header pwm.h
#RPI_PWM_CHANNELS = 2
; Header ws2811.h
#WS2811_TARGET_FREQ = 800000 ; Can go As low As 400000
#WS2811_TARGET_FREQ_LOW = 400000
; 4 color R, G, B And W ordering
#SK6812_STRIP_RGBW = $18100800
#SK6812_STRIP_RBGW = $18100008
#SK6812_STRIP_GRBW = $18081000
#SK6812_STRIP_GBRW = $18080010
#SK6812_STRIP_BRGW = $18001008
#SK6812_STRIP_BGRW = $18000810
#SK6812_SHIFT_WMASK = $f0000000
; 3 color R, G And B ordering
#WS2811_STRIP_RGB = $00100800
#WS2811_STRIP_RBG = $00100008
#WS2811_STRIP_GRB = $00081000
#WS2811_STRIP_GBR = $00080010
#WS2811_STRIP_BRG = $00001008
#WS2811_STRIP_BGR = $00000810
; predefined fixed LED types
#WS2812_STRIP = #WS2811_STRIP_GRB
#SK6812_STRIP = #WS2811_STRIP_GRB
#SK6812W_STRIP = #SK6812_STRIP_GRBW
;struct ws2811_device;
;typedef uint32_t ws2811_led_t; //< 0xWWRRGGBB
Structure ws2811_led_t
Led.l[0]
EndStructure
;typedef struct ws2811_channel_t
Structure ws2811_channel_t Align #PB_Structure_AlignC
;{
gpionum.l ; //< GPIO Pin with PWM alternate function, 0 if unused
invert.l ; //< Invert output signal
count.l ; //< Number of LEDs, 0 if channel is unused
strip_type.l ; //< Strip color layout -- one of WS2811_STRIP_xxx constants
*leds.ws2811_led_t; //< LED buffers, allocated by driver based on count
brightness.a ; //< Brightness value between 0 and 255
wshift.a ; //< White shift value
rshift.a ; //< Red shift value
gshift.a ; //< Green shift value
bshift.a ; //< Blue shift value
*gamma ; //< Gamma correction table
EndStructure
;typedef struct ws2811_t
Structure ws2811_t Align #PB_Structure_AlignC
;{
render_wait_time.q; //< time in µs before the next render can run
*device ; //< Private data for driver use
*rpi_hw ; //< RPI Hardware Information
freq.l ; //< Required output frequency
dmanum.l ; //< DMA number _not_ already in use
channel.ws2811_channel_t[#RPI_PWM_CHANNELS];
EndStructure
;#define WS2811_RETURN_STATES(X)
#WS2811_SUCCESS = 0 ; "Success"
#WS2811_ERROR_GENERIC = -1 ; "Generic failure"
#WS2811_ERROR_OUT_OF_MEMORY = -2 ; "Out of memory"
#WS2811_ERROR_HW_NOT_SUPPORTED = -3 ; "Hardware revision is not supported"
#WS2811_ERROR_MEM_LOCK = -4 ; "Memory lock failed"
#WS2811_ERROR_MMAP = -5 ; "mmap() failed"
#WS2811_ERROR_MAP_REGISTERS = -6 ; "Unable to map registers into userspace"
#WS2811_ERROR_GPIO_INIT = -7 ; "Unable to initialize GPIO"
#WS2811_ERROR_PWM_SETUP = -8 ; "Unable to initialize PWM"
#WS2811_ERROR_MAILBOX_DEVICE = -9 ; "Failed to create mailbox device"
#WS2811_ERROR_DMA = -10 ; "DMA error"
#WS2811_ERROR_ILLEGAL_GPIO = -11 ; "Selected GPIO not possible"
#WS2811_ERROR_PCM_SETUP = -12 ; "Unable to initialize PCM"
#WS2811_ERROR_SPI_SETUP = -13 ; "Unable to initialize SPI"
#WS2811_ERROR_SPI_TRANSFER = -14 ; "SPI transfer error"
; ws2811_return_t ws2811_init(ws2811_t *ws2811); //< Initialize buffers/hardware
; void ws2811_fini(ws2811_t *ws2811); //< Tear it all down
; ws2811_return_t ws2811_render(ws2811_t *ws2811); //< Send LEDs off to hardware
; ws2811_return_t ws2811_wait(ws2811_t *ws2811); //< Wait for DMA completion
; const char * ws2811_get_return_t_str(const ws2811_return_t state); //< Get string representation of the given return state
; void ws2811_set_custom_gamma_factor(ws2811_t *ws2811, double gamma_factor); //< Set a custom Gamma correction array based on a gamma correction factor
PrototypeC ws2811_init(*ws2811.ws2811_t); //< Initialize buffers/hardware
PrototypeC ws2811_fini(*ws2811.ws2811_t); //< Tear it all down
PrototypeC ws2811_render(*ws2811.ws2811_t); //< Send LEDs off to hardware
PrototypeC ws2811_wait(*ws2811.ws2811_t) ; //< Wait for DMA completion
PrototypeC ws2811_get_return_t_str(ws2811_return_t_state); //< Get string representation of the given return state
PrototypeC ws2811_set_custom_gamma_factor(*ws2811.ws2811_t, gamma_factor.d); //< Set a custom Gamma correction array based on a gamma correction factor
Global libws2811
Procedure InitLib_ws2811(pathlib.s = "libws2811.so")
libws2811 = OpenLibrary(#PB_Any, pathlib)
If libws2811
Global ws2811_init.ws2811_init = GetFunction(libws2811, "ws2811_init")
Global ws2811_fini.ws2811_fini = GetFunction(libws2811, "ws2811_fini")
Global ws2811_render.ws2811_render = GetFunction(libws2811, "ws2811_render")
Global ws2811_wait.ws2811_wait = GetFunction(libws2811, "ws2811_wait")
Global __ws2811_get_return_t_str.ws2811_get_return_t_str = GetFunction(libws2811, "ws2811_get_return_t_str")
Global ws2811_set_custom_gamma_factor.ws2811_set_custom_gamma_factor = GetFunction(libws2811, "ws2811_set_custom_gamma_factor")
EndIf
ProcedureReturn libws2811
EndProcedure
Procedure.s ws2811_get_return_t_str(state)
Protected *state
*state = __ws2811_get_return_t_str(state)
If *state
ProcedureReturn PeekS(*state, -1, #PB_UTF8)
EndIf
EndProcedure
Procedure CloseLib_ws2811()
CloseLibrary(libws2811)
EndProcedure
;- Example ws2812b (4 LEDs on GPIO 18 PWM)
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
;IncludeFile "WS2811.pbi"
If Not InitLib_ws2811()
Debug "Error open library ws2811"
End
EndIf
#TARGET_FREQ = #WS2811_TARGET_FREQ ; Default 800000
#GPIO_PIN = 18
#DMA = 10
; #STRIP_TYPE = WS2811_STRIP_RGB ; WS2812/SK6812RGB integrated chip+leds
#STRIP_TYPE = #WS2811_STRIP_GRB ; WS2812/SK6812RGB integrated chip+leds
;#STRIP_TYPE = #SK6812_STRIP_RGBW ; SK6812RGBW (Not SK6812RGB)
#LED_COUNT = 4
Global ledstring.ws2811_t
Global r1
With ledstring
\freq = #TARGET_FREQ
\dmanum = #DMA
\channel[0]\gpionum = #GPIO_PIN
\channel[0]\count = #LED_COUNT
\channel[0]\invert = 0
\channel[0]\brightness = 255
\channel[0]\strip_type = #STRIP_TYPE
Repeat ; Do
r1 = ws2811_init(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Init: " + ws2811_get_return_t_str(r1)
CloseLib_ws2811()
End
EndIf
; LEDs 0xWWRRGGBB
\channel[0]\leds\led[0] = $00FF0000
\channel[0]\leds\led[1] = $0000FF00
\channel[0]\leds\led[2] = $000000FF
\channel[0]\leds\led[3] = $00FFFFFF
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
ws2811_wait(ledstring)
Delay(2000)
; LEDs
\channel[0]\leds\led[0] = $00FFFFFF
\channel[0]\leds\led[1] = $00FF0000
\channel[0]\leds\led[2] = $0000FF00
\channel[0]\leds\led[3] = $000000FF
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
ws2811_wait(ledstring)
Delay(2000)
; LEDs
\channel[0]\leds\led[0] = $000000FF
\channel[0]\leds\led[1] = $00FFFFFF
\channel[0]\leds\led[2] = $00FF0000
\channel[0]\leds\led[3] = $0000FF00
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
ws2811_wait(ledstring)
Delay(2000)
\channel[0]\leds\led[0] = $00000000
\channel[0]\leds\led[1] = $00000000
\channel[0]\leds\led[2] = $00000000
\channel[0]\leds\led[3] = $00000000
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
Delay(1000)
\channel[0]\leds\led[0] = $0000FF00
\channel[0]\leds\led[1] = $0000FF00
\channel[0]\leds\led[2] = $0000FF00
\channel[0]\leds\led[3] = $0000FF00
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
Delay(1000)
\channel[0]\leds\led[0] = $00000000
\channel[0]\leds\led[1] = $00000000
\channel[0]\leds\led[2] = $00000000
\channel[0]\leds\led[3] = $00000000
r1 = ws2811_render(ledstring)
If r1 <> #WS2811_SUCCESS
Debug "Error Render: " + ws2811_get_return_t_str(r1)
Break
EndIf
Delay(1000)
Until #True ; EndDo
EndWith
; Clear controler - DMA, etx
ws2811_fini(ledstring)
; Close library
CloseLib_ws2811()
CompilerEndIf