diff --git a/.gitignore b/.gitignore index c6127b3..4d3ceeb 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ modules.order Module.symvers Mkfile.old dkms.conf + +build \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0066b80 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "cmake.sourceDirectory": "/root/ws2812b/project/odroidc4", + "cmake.debugConfig": { + "cwd": "${workspaceFolder}", + "args": [ + "-t", "write", + "--number", "24", + "--times", "100", + // "--color", "0", + "--color", "16711680", // red + // "--color", "65280", // green + // "--color", "255", // blue + ], + }, + "files.associations": { + "driver_ws2812b_basic.h": "c", + "spidev.h": "c", + "spi.h": "c", + "driver_ws2812b_interface.h": "c", + "stdlib.h": "c" + } +} \ No newline at end of file diff --git a/example/driver_ws2812b_basic.c b/example/driver_ws2812b_basic.c index 6fffcd4..7226cba 100644 --- a/example/driver_ws2812b_basic.c +++ b/example/driver_ws2812b_basic.c @@ -51,9 +51,11 @@ uint8_t ws2812b_basic_init(void) /* link interface function */ DRIVER_WS2812B_LINK_INIT(&gs_handle, ws2812b_handle_t); - DRIVER_WS2812B_LINK_SPI_10MHZ_INIT(&gs_handle, ws2812b_interface_spi_10mhz_init); + DRIVER_WS2812B_LINK_SPI_INIT(&gs_handle, ws2812b_interface_spi_init); DRIVER_WS2812B_LINK_SPI_DEINIT(&gs_handle, ws2812b_interface_spi_deinit); DRIVER_WS2812B_LINK_SPI_WRITE_COMMAND(&gs_handle, ws2812b_interface_spi_write_cmd); + DRIVER_WS2812B_LINK_ONE_CODE(&gs_handle, ws2812b_interface_one_code); + DRIVER_WS2812B_LINK_ZERO_CODE(&gs_handle, ws2812b_interface_zero_code); DRIVER_WS2812B_LINK_DELAY_MS(&gs_handle, ws2812b_interface_delay_ms); DRIVER_WS2812B_LINK_DEBUG_PRINT(&gs_handle, ws2812b_interface_debug_print); diff --git a/interface/driver_ws2812b_interface.h b/interface/driver_ws2812b_interface.h index 4a2a2ff..8800702 100644 --- a/interface/driver_ws2812b_interface.h +++ b/interface/driver_ws2812b_interface.h @@ -57,7 +57,7 @@ extern "C"{ * - 1 spi init 10mhz failed * @note none */ -uint8_t ws2812b_interface_spi_10mhz_init(void); +uint8_t ws2812b_interface_spi_init(void); /** * @brief interface spi bus deinit @@ -68,6 +68,18 @@ uint8_t ws2812b_interface_spi_10mhz_init(void); */ uint8_t ws2812b_interface_spi_deinit(void); +/** + * @brief WS1812B One Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_one_code(void); + +/** + * @brief WS1812B Zero Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_zero_code(void); + /** * @brief interface spi bus write command * @param[in] *buf points to a data buffer diff --git a/interface/driver_ws2812b_interface_template.c b/interface/driver_ws2812b_interface_template.c index 5063d17..4d56097 100644 --- a/interface/driver_ws2812b_interface_template.c +++ b/interface/driver_ws2812b_interface_template.c @@ -37,13 +37,13 @@ #include "driver_ws2812b_interface.h" /** - * @brief interface spi 10mhz bus init + * @brief interface spi bus init * @return status code * - 0 success - * - 1 spi init 10mhz failed + * - 1 spi init failed * @note none */ -uint8_t ws2812b_interface_spi_10mhz_init(void) +uint8_t ws2812b_interface_spi_init(void) { return 0; } @@ -60,6 +60,24 @@ uint8_t ws2812b_interface_spi_deinit(void) return 0; } +/** + * @brief WS1812B One Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_one_code(void) +{ + return 0xFF00U; +} + +/** + * @brief WS1812B Zero Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_zero_code(void) +{ + return 0xF000U; +} + /** * @brief interface spi bus write command * @param[in] *buf points to a data buffer diff --git a/project/odroidc4/CMakeLists.txt b/project/odroidc4/CMakeLists.txt new file mode 100644 index 0000000..15c73c6 --- /dev/null +++ b/project/odroidc4/CMakeLists.txt @@ -0,0 +1,212 @@ +# +# Copyright (c) 2015 - present LibDriver All rights reserved +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# set the cmake minimum version +cmake_minimum_required(VERSION 3.0) + +# set the project name and language +project(ws2812b C) + +# read the version from files +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/VERSION ${CMAKE_PROJECT_NAME}_VERSION) + +# set the project version +set(PROJECT_VERSION ${${CMAKE_PROJECT_NAME}_VERSION}) + +# set c standard c99 +set(CMAKE_C_STANDARD 99) + +# enable c standard required +set(CMAKE_C_STANDARD_REQUIRED True) + +# set release level +# set(CMAKE_BUILD_TYPE Release) + +# set the release flags of c +set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") + +# include cmake package config helpers +include(CMakePackageConfigHelpers) + +# find the pkgconfig and use this tool to find the third party packages +find_package(PkgConfig REQUIRED) + +# find the third party packages with pkgconfig +pkg_search_module(GPIOD REQUIRED libgpiod) + +# include all library header directories +set(LIB_INC_DIRS + ${GPIOD_INCLUDE_DIRS} + ) + +# include all linked libraries +set(LIBS + ${GPIOD_LIBRARIES} + ) + +# include all header directories +set(INC_DIRS + ${LIB_INC_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/../../src + ${CMAKE_CURRENT_SOURCE_DIR}/../../interface + ${CMAKE_CURRENT_SOURCE_DIR}/../../example + ${CMAKE_CURRENT_SOURCE_DIR}/../../test + ${CMAKE_CURRENT_SOURCE_DIR}/interface/inc + ) + +# include all installed headers +file(GLOB INSTL_INCS + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/*.h + ) + +# include all sources files +file(GLOB SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/*.c + ) + +# include executable source +file(GLOB MAIN + ${SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/../../example/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../test/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/interface/src/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/driver/src/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ) + +# enable output as a static library +add_library(${CMAKE_PROJECT_NAME}_static STATIC ${SRCS}) + +# set the static library include directories +target_include_directories(${CMAKE_PROJECT_NAME}_static PRIVATE ${INC_DIRS}) + +# set the static library link libraries +target_link_libraries(${CMAKE_PROJECT_NAME}_static + m + ) + +# rename as ${CMAKE_PROJECT_NAME} +set_target_properties(${CMAKE_PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME}) + +# don't delete ${CMAKE_PROJECT_NAME} libs +set_target_properties(${CMAKE_PROJECT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) + +# set the static library version +set_target_properties(${CMAKE_PROJECT_NAME}_static PROPERTIES VERSION ${${CMAKE_PROJECT_NAME}_VERSION}) + +# enable output as a dynamic library +add_library(${CMAKE_PROJECT_NAME} SHARED ${SRCS}) + +# set the executable program include directories +target_include_directories(${CMAKE_PROJECT_NAME} + PUBLIC $ + PRIVATE ${INC_DIRS} + ) + +# set the dynamic library link libraries +target_link_libraries(${CMAKE_PROJECT_NAME} + m + ) + +# rename as ${CMAKE_PROJECT_NAME} +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME}) + +# don't delete ${CMAKE_PROJECT_NAME} libs +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) + +# include the public header +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${INSTL_INCS}") + +# set the dynamic library version +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION ${${CMAKE_PROJECT_NAME}_VERSION}) + +# enable the executable program +add_executable(${CMAKE_PROJECT_NAME}_exe ${MAIN}) + +# set the executable program include directories +target_include_directories(${CMAKE_PROJECT_NAME}_exe PRIVATE ${INC_DIRS}) + +# set the executable program link libraries +target_link_libraries(${CMAKE_PROJECT_NAME}_exe + ${LIBS} + m + pthread + ) + +# rename as ${CMAKE_PROJECT_NAME} +set_target_properties(${CMAKE_PROJECT_NAME}_exe PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME}) + +# don't delete ${CMAKE_PROJECT_NAME} exe +set_target_properties(${CMAKE_PROJECT_NAME}_exe PROPERTIES CLEAN_DIRECT_OUTPUT 1) + +# install the binary +install(TARGETS ${CMAKE_PROJECT_NAME}_exe + RUNTIME DESTINATION bin + ) + +# install the static library +install(TARGETS ${CMAKE_PROJECT_NAME}_static + ARCHIVE DESTINATION lib + ) + +# install the dynamic library +install(TARGETS ${CMAKE_PROJECT_NAME} + EXPORT ${CMAKE_PROJECT_NAME}-targets + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include/${CMAKE_PROJECT_NAME} + ) + +# make the cmake config file +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}-config.cmake + INSTALL_DESTINATION cmake + ) + +# write the cmake config version +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}-config-version.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY AnyNewerVersion + ) + +# install the cmake files +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${CMAKE_PROJECT_NAME}-config-version.cmake" + DESTINATION cmake + ) + +# set the export items +install(EXPORT ${CMAKE_PROJECT_NAME}-targets + DESTINATION cmake + ) + +# add uninstall command +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.cmake + ) + +#include ctest module +include(CTest) + +# creat a test +add_test(NAME ${CMAKE_PROJECT_NAME}_test COMMAND ${CMAKE_PROJECT_NAME}_exe -p) diff --git a/project/odroidc4/J8Header.jpg b/project/odroidc4/J8Header.jpg new file mode 100644 index 0000000..62d1476 Binary files /dev/null and b/project/odroidc4/J8Header.jpg differ diff --git a/project/odroidc4/Makefile b/project/odroidc4/Makefile new file mode 100644 index 0000000..be59175 --- /dev/null +++ b/project/odroidc4/Makefile @@ -0,0 +1,149 @@ +# +# Copyright (c) 2015 - present LibDriver All rights reserved +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# set the project version +VERSION := 1.0.0 + +# set the application name +APP_NAME := ws2812b + +# set the shared libraries name +SHARED_LIB_NAME := libws2812b.so + +# set the static libraries name +STATIC_LIB_NAME := libws2812b.a + +# set the install directories +INSTL_DIRS := /usr/local + +# set the include directories +INC_INSTL_DIRS := $(INSTL_DIRS)/include/$(APP_NAME) + +# set the library directories +LIB_INSTL_DIRS := $(INSTL_DIRS)/lib + +# set the bin directories +BIN_INSTL_DIRS := $(INSTL_DIRS)/bin + +# set the compiler +CC := gcc + +# set the ar tool +AR := ar + +# set the packages name +PKGS := libgpiod + +# set the pck-config header directories +LIB_INC_DIRS := $(shell pkg-config --cflags $(PKGS)) + +# set the linked libraries +LIBS := -lm \ + -lpthread + +# add the linked libraries +LIBS += $(shell pkg-config --libs $(PKGS)) + +# set all header directories +INC_DIRS := -I ../../src/ \ + -I ../../interface/ \ + -I ../../example/ \ + -I ../../test/ \ + -I ./interface/inc/ + +# add the linked libraries header directories +INC_DIRS += $(LIB_INC_DIRS) + +# set the installing headers +INSTL_INCS := $(wildcard ../../src/*.h) + +# set all sources files +SRCS := $(wildcard ../../src/*.c) + +# set the main source +MAIN := $(SRCS) \ + $(wildcard ../../example/*.c) \ + $(wildcard ../../test/*.c) \ + $(wildcard ./interface/src/*.c) \ + $(wildcard ./driver/src/*.c) \ + $(wildcard ./src/main.c) + +# set flags of the compiler +CFLAGS := -O3 \ + -DNDEBUG + +# set all .PHONY +.PHONY: all + +# set the output list +all: $(APP_NAME) $(SHARED_LIB_NAME).$(VERSION) $(STATIC_LIB_NAME) + +# set the main app +$(APP_NAME) : $(MAIN) + $(CC) $(CFLAGS) $^ $(INC_DIRS) $(LIBS) -o $@ + +# set the shared lib +$(SHARED_LIB_NAME).$(VERSION) : $(SRCS) + $(CC) $(CFLAGS) -shared -fPIC $^ $(INC_DIRS) -lm -o $@ + +# set the *.o for the static libraries +OBJS := $(patsubst %.c, %.o, $(SRCS)) + +# set the static lib +$(STATIC_LIB_NAME) : $(OBJS) + $(AR) -r $@ $^ + +# .*o used by the static lib +$(OBJS) : $(SRCS) + $(CC) $(CFLAGS) -c $^ $(INC_DIRS) -o $@ + +# set install .PHONY +.PHONY: install + +# install files +install : + $(shell if [ ! -d $(INC_INSTL_DIRS) ]; then mkdir $(INC_INSTL_DIRS); fi;) + cp -rv $(INSTL_INCS) $(INC_INSTL_DIRS) + cp -rv $(SHARED_LIB_NAME).$(VERSION) $(LIB_INSTL_DIRS) + ln -sf $(LIB_INSTL_DIRS)/$(SHARED_LIB_NAME).$(VERSION) $(LIB_INSTL_DIRS)/$(SHARED_LIB_NAME) + cp -rv $(STATIC_LIB_NAME) $(LIB_INSTL_DIRS) + cp -rv $(APP_NAME) $(BIN_INSTL_DIRS) + +# set install .PHONY +.PHONY: uninstall + +# uninstall files +uninstall : + rm -rf $(INC_INSTL_DIRS) + rm -rf $(LIB_INSTL_DIRS)/$(SHARED_LIB_NAME).$(VERSION) + rm -rf $(LIB_INSTL_DIRS)/$(SHARED_LIB_NAME) + rm -rf $(LIB_INSTL_DIRS)/$(STATIC_LIB_NAME) + rm -rf $(BIN_INSTL_DIRS)/$(APP_NAME) + +# set clean .PHONY +.PHONY: clean + +# clean the project +clean : + rm -rf $(APP_NAME) $(SHARED_LIB_NAME).$(VERSION) $(STATIC_LIB_NAME) diff --git a/project/odroidc4/README.md b/project/odroidc4/README.md new file mode 100644 index 0000000..92427c4 --- /dev/null +++ b/project/odroidc4/README.md @@ -0,0 +1,184 @@ +### 1. Board + +#### 1.1 Board Info + +Board Name: Odroid C4. + +SPI Pin: SCLK/MOSI/MISO/CS GPIOX11/GPIOX8/GPIOX9/GPIOX10. + +### 2. Install + +#### 2.1 Dependencies + +Install the necessary dependencies. + +```shell +sudo apt-get install libgpiod-dev pkg-config cmake -y +``` + +#### 2.2 Makefile + +Build the project. + +```shell +make +``` + +Install the project and this is optional. + +```shell +sudo make install +``` + +Uninstall the project and this is optional. + +```shell +sudo make uninstall +``` + +#### 2.3 CMake + +Build the project. + +```shell +mkdir build && cd build +cmake .. +make +``` + +Install the project and this is optional. + +```shell +sudo make install +``` + +Uninstall the project and this is optional. + +```shell +sudo make uninstall +``` + +Test the project and this is optional. + +```shell +make test +``` + +Find the compiled library in CMake. + +```cmake +find_package(ws2812b REQUIRED) +``` + + +### 3. WS2812B + +#### 3.1 Command Instruction + +1. Show ws2812b chip and driver information. + + ```shell + ws2812b (-i | --information) + ``` + +2. Show ws2812b help. + + ```shell + ws2812b (-h | --help) + ``` + +3. Show ws2812b pin connections of the current board. + + ```shell + ws2812b (-p | --port) + ``` + +4. Run ws2812b write test, number is the ws2812b chip number and num is the test times. + + ```shell + ws2812b (-t write | --test=write) [--number=] [--times=] + ``` + +5. Run ws2812b write function, number is the ws2812b chip number and color is the rgb color. + + ```shell + ws2812b (-e write | --example=write) [--number=] [--color=] + ``` + +#### 3.2 Command Example + +```shell +./ws2812b -i + +ws2812b: chip is Worldsemi WS2812B. +ws2812b: manufacturer is Worldsemi . +ws2812b: interface is SPI. +ws2812b: driver version is 1.0. +ws2812b: min supply voltage is 3.7V. +ws2812b: max supply voltage is 5.3V. +ws2812b: max current is 16.00mA. +ws2812b: max temperature is 85.0C. +``` + +```shell +./ws2812b -p + +ws2812b: SPI interface SCK connected to GPIO11(BCM). +ws2812b: SPI interface MISO connected to GPIO9(BCM). +ws2812b: SPI interface MOSI connected to GPIO10(BCM). +ws2812b: SPI interface CS connected to GPIO8(BCM). +``` + +```shell +./ws2812b -t write --number=12 --times=10 + +ws2812b: chip is Worldsemi WS2812B. +ws2812b: manufacturer is Worldsemi . +ws2812b: interface is SPI. +ws2812b: driver version is 1.0. +ws2812b: min supply voltage is 3.7V. +ws2812b: max supply voltage is 5.3V. +ws2812b: max current is 16.00mA. +ws2812b: max temperature is 85.0C. +ws2812b: min temperature is -25.0C. +ws2812b: start register test. +ws2812b: 1/10 times. +ws2812b: 2/10 times. +ws2812b: 3/10 times. +ws2812b: 4/10 times. +ws2812b: 5/10 times. +ws2812b: 6/10 times. +ws2812b: 7/10 times. +ws2812b: 8/10 times. +ws2812b: 9/10 times. +ws2812b: 10/10 times. +ws2812b: finish register test. +``` + +```shell +./ws2812b -e write --number=12 --color=16711680 + +ws2812b: number is 12 and written color is 0xFF0000. +``` + +```shell +./ws2812b -h + +Usage: + ws2812b (-i | --information) + ws2812b (-h | --help) + ws2812b (-p | --port) + ws2812b (-t write | --test=write) [--number=] [--times=] + ws2812b (-e write | --example=write) [--number=] [--color=] + +Options: + --color= Set the chip display color.([default: 16711680]) + -e , --example= Run the driver example. + -h, --help Show the help. + -i, --information Show the chip information. + --number= Set the chip number.([default: 3]) + -p, --port Display the pin connections of the current board. + -t , --test= Run the driver test. + --times= Set the running times.([default: 3]) +``` + diff --git a/project/odroidc4/cmake/VERSION b/project/odroidc4/cmake/VERSION new file mode 100644 index 0000000..afaf360 --- /dev/null +++ b/project/odroidc4/cmake/VERSION @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/project/odroidc4/cmake/config.cmake.in b/project/odroidc4/cmake/config.cmake.in new file mode 100644 index 0000000..a982dfe --- /dev/null +++ b/project/odroidc4/cmake/config.cmake.in @@ -0,0 +1,44 @@ +# +# Copyright (c) 2015 - present LibDriver All rights reserved +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# set the package init +@PACKAGE_INIT@ + +# include dependency macro +include(CMakeFindDependencyMacro) + +# find the pkgconfig and use this tool to find the third party packages +find_package(PkgConfig REQUIRED) + +# find the third party packages with pkgconfig +pkg_search_module(GPIOD REQUIRED libgpiod) + +# include the cmake targets +include(${CMAKE_CURRENT_LIST_DIR}/@CMAKE_PROJECT_NAME@-targets.cmake) + +# get the include header directories +get_target_property(@CMAKE_PROJECT_NAME@_INCLUDE_DIRS @CMAKE_PROJECT_NAME@ INTERFACE_INCLUDE_DIRECTORIES) + +# get the library directories +get_target_property(@CMAKE_PROJECT_NAME@_LIBRARIES @CMAKE_PROJECT_NAME@ IMPORTED_LOCATION_RELEASE) diff --git a/project/odroidc4/cmake/uninstall.cmake b/project/odroidc4/cmake/uninstall.cmake new file mode 100644 index 0000000..409e6a8 --- /dev/null +++ b/project/odroidc4/cmake/uninstall.cmake @@ -0,0 +1,58 @@ +# +# Copyright (c) 2015 - present LibDriver All rights reserved +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# check the install_manifest.txt +if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") + # output the error + message(FATAL_ERROR "cannot find install manifest: ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") +endif() + +# read install_manifest.txt to uninstall_list +file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" ${CMAKE_PROJECT_NAME}_uninstall_list) + +# replace '\n' to ';' +string(REGEX REPLACE "\n" ";" ${CMAKE_PROJECT_NAME}_uninstall_list "${${CMAKE_PROJECT_NAME}_uninstall_list}") + +# uninstall the list files +foreach(${CMAKE_PROJECT_NAME}_uninstall_list ${${CMAKE_PROJECT_NAME}_uninstall_list}) + # if a link or a file + if(IS_SYMLINK "$ENV{DESTDIR}${${CMAKE_PROJECT_NAME}_uninstall_list}" OR EXISTS "$ENV{DESTDIR}${${CMAKE_PROJECT_NAME}_uninstall_list}") + # delete the file + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${${CMAKE_PROJECT_NAME}_uninstall_list} + RESULT_VARIABLE rm_retval + ) + + # check the retval + if(NOT "${rm_retval}" STREQUAL 0) + # output the error + message(FATAL_ERROR "failed to remove file: '${${CMAKE_PROJECT_NAME}_uninstall_list}'.") + else() + # uninstalling files + message(STATUS "uninstalling: $ENV{DESTDIR}${${CMAKE_PROJECT_NAME}_uninstall_list}") + endif() + else() + # output the error + message(STATUS "file: $ENV{DESTDIR}${${CMAKE_PROJECT_NAME}_uninstall_list} does not exist.") + endif() +endforeach() diff --git a/project/odroidc4/driver/src/odroidc4_driver_ws2812b_interface.c b/project/odroidc4/driver/src/odroidc4_driver_ws2812b_interface.c new file mode 100644 index 0000000..bf3ce19 --- /dev/null +++ b/project/odroidc4/driver/src/odroidc4_driver_ws2812b_interface.c @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file odroidc4_driver_ws2812b_interface.c + * @brief odroidc4 driver ws2812b interface source file + * @version 1.0.0 + * @author Shifeng Li + * @date 2021-11-13 + * + *

history

+ * + *
Date Version Author Description + *
2021/11/13 1.0 Shifeng Li first upload + *
+ */ + +#include "driver_ws2812b_interface.h" +#include "spi.h" +#include + +/** + * @brief spi device name definition + */ +#define SPI_DEVICE_NAME "/dev/spidev0.0" /**< spi device name */ +/** + * @brief spi device handle definition + */ +static int gs_fd; /**< spi handle */ + +/** + * @brief interface spi bus init + * @return status code + * - 0 success + * - 1 spi init failed + * @note none + */ +uint8_t ws2812b_interface_spi_init(void) +{ + return spi_init(SPI_DEVICE_NAME, &gs_fd, SPI_MODE_TYPE_3, 1000 * 1000 * 12); +} + +/** + * @brief interface spi bus deinit + * @return status code + * - 0 success + * - 1 spi deinit failed + * @note none + */ +uint8_t ws2812b_interface_spi_deinit(void) +{ + return spi_deinit(gs_fd); +} + +/** + * @brief WS1812B One Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_one_code(void) +{ + return 0xFF00U; +} + +/** + * @brief WS1812B Zero Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_zero_code(void) +{ + return 0xF000U; +} + +/** + * @brief interface spi bus write command + * @param[in] *buf points to a data buffer + * @param[in] len is the length of data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t ws2812b_interface_spi_write_cmd(uint8_t *buf, uint16_t len) +{ + return spi_write_cmd(gs_fd, buf, len); +} + +/** + * @brief interface delay ms + * @param[in] ms + * @note none + */ +void ws2812b_interface_delay_ms(uint32_t ms) +{ + usleep(1000 * ms); +} + +/** + * @brief interface print format data + * @param[in] fmt is the format data + * @note none + */ +void ws2812b_interface_debug_print(const char *const fmt, ...) +{ + char str[256]; + uint16_t len; + va_list args; + + memset((char *)str, 0, sizeof(char) * 256); + va_start(args, fmt); + vsnprintf((char *)str, 255, (char const *)fmt, args); + va_end(args); + + len = strlen((char *)str); + (void)printf((uint8_t *)str, len); +} diff --git a/project/odroidc4/interface/inc/spi.h b/project/odroidc4/interface/inc/spi.h new file mode 100644 index 0000000..e25318d --- /dev/null +++ b/project/odroidc4/interface/inc/spi.h @@ -0,0 +1,202 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file spi.h + * @brief spi header file + * @version 1.0.0 + * @author Shifeng Li + * @date 2022-11-11 + * + *

history

+ * + *
Date Version Author Description + *
2022/11/11 1.0 Shifeng Li first upload + *
+ */ + +#ifndef SPI_H +#define SPI_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup spi spi function + * @brief spi function modules + * @{ + */ + +/** + * @brief spi mode type enumeration definition + */ +typedef enum +{ + SPI_MODE_TYPE_0 = SPI_MODE_0, /**< mode 0 */ + SPI_MODE_TYPE_1 = SPI_MODE_1, /**< mode 1 */ + SPI_MODE_TYPE_2 = SPI_MODE_2, /**< mode 2 */ + SPI_MODE_TYPE_3 = SPI_MODE_3, /**< mode 3 */ +} spi_mode_type_t; + +/** + * @brief spi bus init + * @param[in] *name points to a spi device name buffer + * @param[out] *fd points to a spi device handle buffer + * @param[in] mode is the spi mode. + * @param[in] freq is the spi running frequence + * @return status code + * - 0 success + * - 1 init failed + * @note none + */ +uint8_t spi_init(char *name, int *fd, spi_mode_type_t mode, uint32_t freq); + +/** + * @brief spi bus deinit + * @param[in] fd is the spi handle + * @return status code + * - 0 success + * - 1 deinit failed + * @note none + */ +uint8_t spi_deinit(int fd); + +/** + * @brief spi bus read command + * @param[in] fd is the spi handle + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read_cmd(int fd, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus read + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read(int fd, uint8_t reg, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus read address 16 + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read_address16(int fd, uint16_t reg, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus write command + * @param[in] fd is the spi handle + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write_cmd(int fd, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus write + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write(int fd, uint8_t reg, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus write address 16 + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write_address16(int fd, uint16_t reg, uint8_t *buf, uint16_t len); + +/** + * @brief spi bus write read + * @param[in] fd is the spi handle + * @param[in] *in_buf points to an input buffer + * @param[in] in_len is the input length + * @param[out] *out_buf points to an output buffer + * @param[in] out_len is the output length + * @return status code + * - 0 success + * - 1 write read failed + * @note none + */ +uint8_t spi_write_read(int fd, uint8_t *in_buf, uint32_t in_len, uint8_t *out_buf, uint32_t out_len); + +/** + * @brief spi transmit + * @param[in] fd is the spi handle + * @param[in] *tx points to a tx buffer + * @param[out] *rx points to a rx buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 transmit failed + * @note none + */ +uint8_t spi_transmit(int fd, uint8_t *tx, uint8_t *rx, uint16_t len); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/odroidc4/interface/src/spi.c b/project/odroidc4/interface/src/spi.c new file mode 100644 index 0000000..08023d5 --- /dev/null +++ b/project/odroidc4/interface/src/spi.c @@ -0,0 +1,514 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file spi.c + * @brief spi source file + * @version 1.0.0 + * @author Shifeng Li + * @date 2022-11-11 + * + *

history

+ * + *
Date Version Author Description + *
2022/11/11 1.0 Shifeng Li first upload + *
+ */ + +#include "spi.h" +#include +#include +#include + +/** + * @brief spi bus init + * @param[in] *name points to a spi device name buffer + * @param[out] *fd points to a spi device handle buffer + * @param[in] mode is the spi mode. + * @param[in] freq is the spi running frequence + * @return status code + * - 0 success + * - 1 init failed + * @note none + */ +uint8_t spi_init(char *name, int *fd, spi_mode_type_t mode, uint32_t freq) +{ + int i; + + /* open the spi device */ + *fd = open(name, O_RDWR); + if ((*fd) < 0) + { + perror("spi: open failed.\n"); + + return 1; + } + else + { + /* set the spi write mode */ + i = mode; + if (ioctl(*fd, SPI_IOC_WR_MODE, &i) < 0) + { + perror("spi: write mode set failed.\n"); + + return 1; + } + + /* set the spi read mode */ + if (ioctl(*fd, SPI_IOC_RD_MODE, &i) < 0) + { + perror("spi: read mode set failed.\n"); + + return 1; + } + + /* set the spi write frequence */ + i = freq; + if (ioctl(*fd, SPI_IOC_WR_MAX_SPEED_HZ, &i) < 0) + { + perror("spi: set spi write speed failed.\n"); + + return 1; + } + + /* set the spi read frequence */ + if (ioctl(*fd, SPI_IOC_RD_MAX_SPEED_HZ, &i) < 0) + { + perror("spi: set spi read speed failed.\n"); + + return 1; + } + + /* set the spi write MSB first */ + i = 0; + if (ioctl(*fd, SPI_IOC_WR_LSB_FIRST, &i) < 0) + { + perror("spi: set spi write msb first failed.\n"); + + return 1; + } + + /* set the spi read MSB first */ + if (ioctl(*fd, SPI_IOC_RD_LSB_FIRST, &i) < 0) + { + perror("spi: set spi read msb first failed.\n"); + + return 1; + } + + /* set the spi write 8 bits mode */ + i = 8; + if (ioctl(*fd, SPI_IOC_WR_BITS_PER_WORD, &i) < 0) + { + perror("spi: set spi wirte 8 bit failed.\n"); + + return 1; + } + + /* set the spi read 8 bits mode */ + if (ioctl(*fd, SPI_IOC_RD_BITS_PER_WORD, &i) < 0) + { + perror("spi: set spi read 8 bit failed.\n"); + + return 1; + } + + return 0; + } +} + +/** + * @brief spi bus deinit + * @param[in] fd is the spi handle + * @return status code + * - 0 success + * - 1 deinit failed + * @note none + */ +uint8_t spi_deinit(int fd) +{ + /* close the spi */ + if (close(fd) < 0) + { + perror("spi: close failed.\n"); + + return 1; + } + else + { + return 0; + } +} + +/** + * @brief spi bus read command + * @param[in] fd is the spi handle + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read_cmd(int fd, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + int l; + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.rx_buf = (unsigned long)buf; + k.len = len; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; +} + +/** + * @brief spi bus read + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read(int fd, uint8_t reg, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + uint8_t command[len + 1]; + uint8_t recv[len + 1]; + int l; + + /* set the command */ + command[0] = reg; + memset(&command[1], 0x00, len); + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)command; + k.rx_buf = (unsigned long)recv; + k.len = len + 1; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + /* copy the data */ + memcpy(buf, recv + 1, len); + + return 0; +} + +/** + * @brief spi bus read address 16 + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[out] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 read failed + * @note none + */ +uint8_t spi_read_address16(int fd, uint16_t reg, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + uint8_t command[len + 2]; + uint8_t recv[len + 2]; + int l; + + /* set the command */ + command[0] = (reg >> 8) & 0xFF; + command[1] = reg & 0xFF; + memset(&command[2], 0x00, len); + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)command; + k.rx_buf = (unsigned long)recv; + k.len = len + 2; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + /* copy the data */ + memcpy(buf, recv + 2, len); + + return 0; +} + +/** + * @brief spi bus write command + * @param[in] fd is the spi handle + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write_cmd(int fd, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + int l; + + /* clear ioc transfer */ + memset(&k, 0, sizeof(k)); + + /* set the param */ + k.tx_buf = (unsigned long)buf; + k.len = len; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; +} + +/** + * @brief spi bus write + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write(int fd, uint8_t reg, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + uint8_t command[len + 1]; + int l; + + /* set the command */ + command[0] = reg; + memcpy(&command[1], buf, len); + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)command; + k.len = len + 1; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; +} + +/** + * @brief spi bus write address 16 + * @param[in] fd is the spi handle + * @param[in] reg is the spi register address + * @param[in] *buf points to a data buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 write failed + * @note none + */ +uint8_t spi_write_address16(int fd, uint16_t reg, uint8_t *buf, uint16_t len) +{ + struct spi_ioc_transfer k; + uint8_t command[len + 2]; + int l; + + /* set the command */ + command[0] = (reg >> 8) & 0xFF; + command[1] = reg & 0xFF; + memcpy(&command[2], buf, len); + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)command; + k.len = len + 2; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; +} + +/** + * @brief spi bus write read + * @param[in] fd is the spi handle + * @param[in] *in_buf points to an input buffer + * @param[in] in_len is the input length + * @param[out] *out_buf points to an output buffer + * @param[in] out_len is the output length + * @return status code + * - 0 success + * - 1 write read failed + * @note none + */ +uint8_t spi_write_read(int fd, uint8_t *in_buf, uint32_t in_len, uint8_t *out_buf, uint32_t out_len) +{ + if ((in_len > 0) && (out_len > 0)) + { + struct spi_ioc_transfer k[2]; + int l; + + /* clear ioc transfer */ + memset(k, 0, sizeof(struct spi_ioc_transfer) * 2); + + /* set the param */ + k[0].tx_buf = (unsigned long)in_buf; + k[0].len = in_len; + k[0].cs_change = 0; + k[1].rx_buf = (unsigned long)out_buf; + k[1].len = out_len; + k[1].cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(2), &k); + if (l != (k[0].len + k[1].len)) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; + } + else if (in_len > 0) + { + struct spi_ioc_transfer k; + int l; + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)in_buf; + k.len = in_len; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; + } + else + { + return 1; + } +} + +/** + * @brief spi transmit + * @param[in] fd is the spi handle + * @param[in] *tx points to a tx buffer + * @param[out] *rx points to a rx buffer + * @param[in] len is the length of the data buffer + * @return status code + * - 0 success + * - 1 transmit failed + * @note none + */ +uint8_t spi_transmit(int fd, uint8_t *tx, uint8_t *rx, uint16_t len) +{ + int l; + struct spi_ioc_transfer k; + + /* clear ioc transfer */ + memset(&k, 0, sizeof(struct spi_ioc_transfer)); + + /* set the param */ + k.tx_buf = (unsigned long)tx; + k.rx_buf = (unsigned long)rx; + k.len = len; + k.cs_change = 0; + + /* transmit */ + l = ioctl(fd, SPI_IOC_MESSAGE(1), &k); + if (l != k.len) + { + perror("spi: length check error.\n"); + + return 1; + } + + return 0; +} diff --git a/project/odroidc4/src/main.c b/project/odroidc4/src/main.c new file mode 100644 index 0000000..5ed1106 --- /dev/null +++ b/project/odroidc4/src/main.c @@ -0,0 +1,344 @@ +/** + * Copyright (c) 2015 - present LibDriver All rights reserved + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @file main.c + * @brief main source file + * @version 1.0.0 + * @author Shifeng Li + * @date 2021-11-13 + * + *

history

+ * + *
Date Version Author Description + *
2021/11/13 1.0 Shifeng Li first upload + *
+ */ + +#include "driver_ws2812b_write_test.h" +#include "driver_ws2812b_basic.h" +#include +#include + +#define LED_COUNT 24 +#define TEMP_BUF_SIZE 1152 + +/** + * @brief global var definition + */ +static uint32_t gs_rgb[LED_COUNT]; /**< rgb buffer */ +static uint8_t gs_temp[TEMP_BUF_SIZE]; /**< temp buffer*/ + +/** + * @brief ws2812b full function + * @param[in] argc is arg numbers + * @param[in] **argv is the arg address + * @return status code + * - 0 success + * - 1 run failed + * - 5 param is invalid + * @note none + */ +uint8_t ws2812b(uint8_t argc, char **argv) +{ + int c; + int longindex = 0; + const char short_options[] = "hipe:t:"; + const struct option long_options[] = + { + {"help", no_argument, NULL, 'h'}, + {"information", no_argument, NULL, 'i'}, + {"port", no_argument, NULL, 'p'}, + {"example", required_argument, NULL, 'e'}, + {"test", required_argument, NULL, 't'}, + {"color", required_argument, NULL, 1}, + {"number", required_argument, NULL, 2}, + {"times", required_argument, NULL, 3}, + {NULL, 0, NULL, 0}, + }; + char type[33] = "unknown"; + uint32_t times = 3; + uint32_t color = 16711680; + uint32_t number = 3; + + /* if no params */ + if (argc == 1) + { + /* goto the help */ + goto help; + } + + /* init 0 */ + optind = 0; + + /* parse */ + do + { + /* parse the args */ + c = getopt_long(argc, argv, short_options, long_options, &longindex); + + /* judge the result */ + switch (c) + { + /* help */ + case 'h' : + { + /* set the type */ + memset(type, 0, sizeof(char) * 33); + snprintf(type, 32, "h"); + + break; + } + + /* information */ + case 'i' : + { + /* set the type */ + memset(type, 0, sizeof(char) * 33); + snprintf(type, 32, "i"); + + break; + } + + /* port */ + case 'p' : + { + /* set the type */ + memset(type, 0, sizeof(char) * 33); + snprintf(type, 32, "p"); + + break; + } + + /* example */ + case 'e' : + { + /* set the type */ + memset(type, 0, sizeof(char) * 33); + snprintf(type, 32, "e_%s", optarg); + + break; + } + + /* test */ + case 't' : + { + /* set the type */ + memset(type, 0, sizeof(char) * 33); + snprintf(type, 32, "t_%s", optarg); + + break; + } + + /* color */ + case 1 : + { + /* set the color */ + color = atol(optarg); + + break; + } + + /* number */ + case 2 : + { + /* set the number */ + number = atoi(optarg); + + break; + } + + /* running times */ + case 3 : + { + /* set the times */ + times = atol(optarg); + + break; + } + + /* the end */ + case -1 : + { + break; + } + + /* others */ + default : + { + return 5; + } + } + } while (c != -1); + + /* run the function */ + if (strcmp("t_write", type) == 0) + { + uint8_t res; + + /* run write test */ + res = ws2812b_write_test(number, times); + if (res != 0) + { + return 1; + } + else + { + return 0; + } + } + else if (strcmp("e_write", type) == 0) + { + uint8_t res; + uint32_t i; + + /* check number */ + if (number > LED_COUNT) + { + number = LED_COUNT; + ws2812b_interface_debug_print("ws2812b: num is over %d and use %d.\n", LED_COUNT, LED_COUNT); + } + + /* init */ + res = ws2812b_basic_init(); + if (res != 0) + { + return 1; + } + + /* write color */ + for (i = 0; i < number; i++) + { + gs_rgb[i] = color; + } + + /* print */ + ws2812b_interface_debug_print("ws2812b: number is %d and written color is 0x%X.\n", number, color); + + /* write data */ + res = ws2812b_basic_write(gs_rgb, number, gs_temp, TEMP_BUF_SIZE); + if (res != 0) + { + (void)ws2812b_basic_deinit(); + + return 1; + } + + /* close the chip */ + res = ws2812b_basic_deinit(); + if (res != 0) + { + return 1; + } + else + { + return 0; + } + } + else if (strcmp("h", type) == 0) + { + help: + ws2812b_interface_debug_print("Usage:\n"); + ws2812b_interface_debug_print(" ws2812b (-i | --information)\n"); + ws2812b_interface_debug_print(" ws2812b (-h | --help)\n"); + ws2812b_interface_debug_print(" ws2812b (-p | --port)\n"); + ws2812b_interface_debug_print(" ws2812b (-t write | --test=write) [--number=] [--times=]\n"); + ws2812b_interface_debug_print(" ws2812b (-e write | --example=write) [--number=] [--color=]\n"); + ws2812b_interface_debug_print("\n"); + ws2812b_interface_debug_print("Options:\n"); + ws2812b_interface_debug_print(" --color= Set the chip display color.([default: 16711680])\n"); + ws2812b_interface_debug_print(" -e , --example= Run the driver example.\n"); + ws2812b_interface_debug_print(" -h, --help Show the help.\n"); + ws2812b_interface_debug_print(" -i, --information Show the chip information.\n"); + ws2812b_interface_debug_print(" --number= Set the chip number.([default: 3])\n"); + ws2812b_interface_debug_print(" -p, --port Display the pin connections of the current board.\n"); + ws2812b_interface_debug_print(" -t , --test= Run the driver test.\n"); + ws2812b_interface_debug_print(" --times= Set the running times.([default: 3])\n"); + + return 0; + } + else if (strcmp("i", type) == 0) + { + ws2812b_info_t info; + + /* print ws2812b info */ + ws2812b_info(&info); + ws2812b_interface_debug_print("ws2812b: chip is %s.\n", info.chip_name); + ws2812b_interface_debug_print("ws2812b: manufacturer is %s.\n", info.manufacturer_name); + ws2812b_interface_debug_print("ws2812b: interface is %s.\n", info.interface); + ws2812b_interface_debug_print("ws2812b: driver version is %d.%d.\n", info.driver_version / 1000, (info.driver_version % 1000) / 100); + ws2812b_interface_debug_print("ws2812b: min supply voltage is %0.1fV.\n", info.supply_voltage_min_v); + ws2812b_interface_debug_print("ws2812b: max supply voltage is %0.1fV.\n", info.supply_voltage_max_v); + ws2812b_interface_debug_print("ws2812b: max current is %0.2fmA.\n", info.max_current_ma); + ws2812b_interface_debug_print("ws2812b: max temperature is %0.1fC.\n", info.temperature_max); + ws2812b_interface_debug_print("ws2812b: min temperature is %0.1fC.\n", info.temperature_min); + + return 0; + } + else if (strcmp("p", type) == 0) + { + /* print pin connection */ + ws2812b_interface_debug_print("ws2812b: SPI interface SCK connected to GPIOX11(BCM).\n"); + ws2812b_interface_debug_print("ws2812b: SPI interface MISO connected to GPIOX9(BCM).\n"); + ws2812b_interface_debug_print("ws2812b: SPI interface MOSI connected to GPIOX8(BCM).\n"); + ws2812b_interface_debug_print("ws2812b: SPI interface CS connected to GPIOX10(BCM).\n"); + + return 0; + } + else + { + return 5; + } +} + +/** + * @brief main function + * @param[in] argc is arg numbers + * @param[in] **argv is the arg address + * @return status code + * - 0 success + * @note none + */ +int main(uint8_t argc, char **argv) +{ + uint8_t res; + + res = ws2812b(argc, argv); + if (res == 0) + { + /* run success */ + } + else if (res == 1) + { + ws2812b_interface_debug_print("ws2812b: run failed.\n"); + } + else if (res == 5) + { + ws2812b_interface_debug_print("ws2812b: param is invalid.\n"); + } + else + { + ws2812b_interface_debug_print("ws2812b: unknown status code.\n"); + } + + return 0; +} diff --git a/project/raspberrypi4b/CMakeLists.txt b/project/raspberrypi4b/CMakeLists.txt index eb24398..2a006a9 100644 --- a/project/raspberrypi4b/CMakeLists.txt +++ b/project/raspberrypi4b/CMakeLists.txt @@ -205,8 +205,8 @@ add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.cmake ) -#include ctest module -include(CTest) +# #include ctest module +# include(CTest) -# creat a test -add_test(NAME ${CMAKE_PROJECT_NAME}_test COMMAND ${CMAKE_PROJECT_NAME}_exe -p) +# # creat a test +# add_test(NAME ${CMAKE_PROJECT_NAME}_test COMMAND ${CMAKE_PROJECT_NAME}_exe -p) diff --git a/project/raspberrypi4b/driver/src/raspberrypi4b_driver_ws2812b_interface.c b/project/raspberrypi4b/driver/src/raspberrypi4b_driver_ws2812b_interface.c index f03acfc..d09ccdb 100644 --- a/project/raspberrypi4b/driver/src/raspberrypi4b_driver_ws2812b_interface.c +++ b/project/raspberrypi4b/driver/src/raspberrypi4b_driver_ws2812b_interface.c @@ -54,7 +54,7 @@ static int gs_fd; /**< spi handle */ * - 1 spi init 10mhz failed * @note none */ -uint8_t ws2812b_interface_spi_10mhz_init(void) +uint8_t ws2812b_interface_spi_init(void) { return spi_init(SPI_DEVICE_NAME, &gs_fd, SPI_MODE_TYPE_3, 1000 * 1000 * 10); } @@ -85,6 +85,24 @@ uint8_t ws2812b_interface_spi_write_cmd(uint8_t *buf, uint16_t len) return spi_write_cmd(gs_fd, buf, len); } +/** + * @brief WS1812B One Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_one_code(void) +{ + return 0xFFF8U; +} + +/** + * @brief WS1812B Zero Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_zero_code(void) +{ + return 0xE000U; +} + /** * @brief interface delay ms * @param[in] ms diff --git a/project/stm32f407/driver/src/stm32f407_driver_ws2812b_interface.c b/project/stm32f407/driver/src/stm32f407_driver_ws2812b_interface.c index 1463c1a..cdd6626 100644 --- a/project/stm32f407/driver/src/stm32f407_driver_ws2812b_interface.c +++ b/project/stm32f407/driver/src/stm32f407_driver_ws2812b_interface.c @@ -47,7 +47,7 @@ * - 1 spi init 10mhz failed * @note none */ -uint8_t ws2812b_interface_spi_10mhz_init(void) +uint8_t ws2812b_interface_spi_init(void) { return spi_init(SPI_MODE_3); } @@ -64,6 +64,24 @@ uint8_t ws2812b_interface_spi_deinit(void) return spi_deinit(); } +/** + * @brief WS1812B One Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_one_code(void) +{ + return 0xFF00U; +} + +/** + * @brief WS1812B Zero Code bit map + * @note Depends on SPI speed + */ +uint16_t ws2812b_interface_zero_code(void) +{ + return 0xF000U; +} + /** * @brief interface spi bus write command * @param[in] *buf points to a data buffer diff --git a/src/driver_ws2812b.c b/src/driver_ws2812b.c index 4ad3031..2a606c1 100644 --- a/src/driver_ws2812b.c +++ b/src/driver_ws2812b.c @@ -68,9 +68,9 @@ uint8_t ws2812b_init(ws2812b_handle_t *handle) { return 3; /* return error */ } - if (handle->spi_10mhz_init == NULL) /* check spi_10mhz_init */ + if (handle->spi_init == NULL) /* check spi_10mhz_init */ { - handle->debug_print("ws2812b: spi_10mhz_init is null.\n"); /* spi_10mhz_init is null */ + handle->debug_print("ws2812b: spi_init is null.\n"); /* spi_10mhz_init is null */ return 3; /* return error */ } @@ -86,6 +86,18 @@ uint8_t ws2812b_init(ws2812b_handle_t *handle) return 3; /* return error */ } + if (handle->one_code == NULL) /* check spi_deinit */ + { + handle->debug_print("ws2812b: one_code is null.\n"); /* spi_deinit is null */ + + return 3; /* return error */ + } + if (handle->zero_code == NULL) /* check spi_deinit */ + { + handle->debug_print("ws2812b: zero_code is null.\n"); /* spi_deinit is null */ + + return 3; /* return error */ + } if (handle->delay_ms == NULL) /* check delay_ms */ { handle->debug_print("ws2812b: delay_ms is null.\n"); /* delay_ms is null */ @@ -93,7 +105,7 @@ uint8_t ws2812b_init(ws2812b_handle_t *handle) return 3; /* return error */ } - if (handle->spi_10mhz_init() != 0) /* spi init */ + if (handle->spi_init() != 0) /* spi init */ { handle->debug_print("ws2812b: spi init failed.\n"); /* spi init failed */ @@ -110,13 +122,11 @@ uint8_t ws2812b_init(ws2812b_handle_t *handle) * @param[in] *temp points to a temp buffer * @note none */ -static void a_ws2812b_write_one_frame(uint32_t rgb, uint8_t temp[48]) +static void a_ws2812b_write_one_frame(uint32_t rgb, uint8_t temp[48], const uint16_t one_code, const uint16_t zero_code) { uint8_t r, g, b; uint8_t i, j; uint32_t c, point; - const uint16_t one_code = 0xFFF8U; - const uint16_t zero_code = 0xE000U; r = (uint8_t)((rgb >> 16) & 0xFF); /* set red */ g = (uint8_t)((rgb >> 8) & 0xFF); /* set green */ @@ -203,7 +213,7 @@ uint8_t ws2812b_write(ws2812b_handle_t *handle, uint32_t *rgb, uint32_t len, uin return 5; /* return error */ } - bit_size = WS2812B_RESET_BIT_FRAME_LEN; /* set the bit size */ + bit_size = bit_size = 24 * 16 * len; /* set the bit size */ bit_size = bit_size / 8; /* set the bit size */ if (bit_size > temp_len) /* check temp length */ { @@ -235,7 +245,7 @@ uint8_t ws2812b_write(ws2812b_handle_t *handle, uint32_t *rgb, uint32_t len, uin for (i = 0; i < len; i++) /* set the color frame */ { - a_ws2812b_write_one_frame(rgb[i], &temp[i * 48]); /* set color */ + a_ws2812b_write_one_frame(rgb[i], &temp[i * 48], handle->one_code(), handle->zero_code()); /* set color */ } if (handle->spi_write_cmd(temp, (uint16_t)bit_size) != 0) /* write command */ @@ -360,7 +370,7 @@ uint8_t ws2812b_write_only_color(ws2812b_handle_t *handle, uint32_t *rgb, uint32 for (i = 0; i < len; i++) /* set the color frame */ { - a_ws2812b_write_one_frame(rgb[i], &temp[i * 48]); /* set color */ + a_ws2812b_write_one_frame(rgb[i], &temp[i * 48], handle->one_code(), handle->zero_code()); /* set color */ } if (handle->spi_write_cmd(temp, (uint16_t)bit_size) != 0) /* write command */ diff --git a/src/driver_ws2812b.h b/src/driver_ws2812b.h index e1c5ca6..9dca2df 100644 --- a/src/driver_ws2812b.h +++ b/src/driver_ws2812b.h @@ -66,9 +66,11 @@ extern "C" { */ typedef struct ws2812b_handle_s { - uint8_t (*spi_10mhz_init)(void); /**< point to a spi_10mhz_init function address */ + uint8_t (*spi_init)(void); /**< point to a spi_init function address */ uint8_t (*spi_deinit)(void); /**< point to a spi_deinit function address */ uint8_t (*spi_write_cmd)(uint8_t *buf, uint16_t len); /**< point to a spi_write_cmd function address */ + uint16_t (*one_code)(void); + uint16_t (*zero_code)(void); void (*delay_ms)(uint32_t ms); /**< point to a delay_ms function address */ void (*debug_print)(const char *const fmt, ...); /**< point to a debug_print function address */ uint8_t inited; /**< inited flag */ @@ -110,12 +112,12 @@ typedef struct ws2812b_info_s #define DRIVER_WS2812B_LINK_INIT(HANDLE, STRUCTURE) memset(HANDLE, 0, sizeof(STRUCTURE)) /** - * @brief link spi_10mhz_init function + * @brief link spi_init function * @param[in] HANDLE points to a ws2812b handle structure - * @param[in] FUC points to a spi_10mhz_init function address - * @note none + * @param[in] FUC points to a spi_init function address + * @note Spi speed is limited by ardware and is related to WS1812B one and zero codes */ -#define DRIVER_WS2812B_LINK_SPI_10MHZ_INIT(HANDLE, FUC) (HANDLE)->spi_10mhz_init = FUC +#define DRIVER_WS2812B_LINK_SPI_INIT(HANDLE, FUC) (HANDLE)->spi_init = FUC /** * @brief link spi_deinit function @@ -133,6 +135,22 @@ typedef struct ws2812b_info_s */ #define DRIVER_WS2812B_LINK_SPI_WRITE_COMMAND(HANDLE, FUC) (HANDLE)->spi_write_cmd = FUC +/** + * @brief link one_code function + * @param[in] HANDLE points to a ws2812b handle structure + * @param[in] FUC points to a one_code function address + * @note Spi speed is limited by ardware and is related to WS1812B one and zero codes + */ +#define DRIVER_WS2812B_LINK_ONE_CODE(HANDLE, FUC) (HANDLE)->one_code = FUC + +/** + * @brief link zero_code function + * @param[in] HANDLE points to a ws2812b handle structure + * @param[in] FUC points to a zero_code function address + * @note Spi speed is limited by ardware and is related to WS1812B one and zero codes + */ +#define DRIVER_WS2812B_LINK_ZERO_CODE(HANDLE, FUC) (HANDLE)->zero_code = FUC + /** * @brief link delay_ms function * @param[in] HANDLE points to a ws2812b handle structure diff --git a/test/driver_ws2812b_write_test.c b/test/driver_ws2812b_write_test.c index 4eb0268..dda956d 100644 --- a/test/driver_ws2812b_write_test.c +++ b/test/driver_ws2812b_write_test.c @@ -37,9 +37,13 @@ #include "driver_ws2812b_write_test.h" #include +#define LED_COUNT 24 +#define CHANGE_SINGLE_LED 1 +#define TEMP_BUF_SIZE 1152 + static ws2812b_handle_t gs_handle; /**< ws2812b handle */ -static uint8_t gs_buffer[1024]; /**< inner temp buffer */ -static uint32_t gs_rgb[21]; /**< inner rgb buffer */ +static uint8_t gs_buffer[TEMP_BUF_SIZE]; /**< inner temp buffer */ +static uint32_t gs_rgb[LED_COUNT]; /**< inner rgb buffer */ /** * @brief write test @@ -60,7 +64,9 @@ uint8_t ws2812b_write_test(uint32_t cnt, uint32_t times) /* link interface function */ DRIVER_WS2812B_LINK_INIT(&gs_handle, ws2812b_handle_t); - DRIVER_WS2812B_LINK_SPI_10MHZ_INIT(&gs_handle, ws2812b_interface_spi_10mhz_init); + DRIVER_WS2812B_LINK_SPI_INIT(&gs_handle, ws2812b_interface_spi_init); + DRIVER_WS2812B_LINK_ONE_CODE(&gs_handle, ws2812b_interface_one_code); + DRIVER_WS2812B_LINK_ZERO_CODE(&gs_handle, ws2812b_interface_zero_code); DRIVER_WS2812B_LINK_SPI_DEINIT(&gs_handle, ws2812b_interface_spi_deinit); DRIVER_WS2812B_LINK_SPI_WRITE_COMMAND(&gs_handle, ws2812b_interface_spi_write_cmd); DRIVER_WS2812B_LINK_DELAY_MS(&gs_handle, ws2812b_interface_delay_ms); @@ -95,9 +101,9 @@ uint8_t ws2812b_write_test(uint32_t cnt, uint32_t times) return 1; } - if (cnt > 21) + if (cnt > LED_COUNT) { - ws2812b_interface_debug_print("ws2812b: cnt is over 21 and use 21.\n"); + ws2812b_interface_debug_print("ws2812b: cnt is over %d and use %d.\n", LED_COUNT, LED_COUNT); } /* start register test */ @@ -113,15 +119,20 @@ uint8_t ws2812b_write_test(uint32_t cnt, uint32_t times) } /* set number */ - num = cnt > 21 ? 21 : cnt; + num = cnt > LED_COUNT ? LED_COUNT : cnt; for (i = 0; i < times; i++) { - for (j = 0; j < num; j++) - { - gs_rgb[j] = color[i % 7]; + if (CHANGE_SINGLE_LED) { + gs_rgb[i % num] = color[i % 7]; + } else { + for (j = 0; j < num; j++) + { + gs_rgb[j] = color[i % 7]; + } } - res = ws2812b_write(&gs_handle, (uint32_t *)gs_rgb, num, gs_buffer, 1024); + + res = ws2812b_write(&gs_handle, (uint32_t *)gs_rgb, num, gs_buffer, TEMP_BUF_SIZE); if (res != 0) { ws2812b_interface_debug_print("ws2812b: write failed.\n"); @@ -131,7 +142,7 @@ uint8_t ws2812b_write_test(uint32_t cnt, uint32_t times) } /* delay 1000 ms */ - ws2812b_interface_delay_ms(1000); + ws2812b_interface_delay_ms(50); /* output */ ws2812b_interface_debug_print("ws2812b: %d/%d times.\n", i + 1, times);