From e8b99665be55157b6fea8f737e76c6259aa343f7 Mon Sep 17 00:00:00 2001 From: Tropicananass Date: Sat, 1 May 2021 00:06:38 +0100 Subject: [PATCH] beta with artnet protocol --- RpiLedBars/.clang-format | 149 ++++++ RpiLedBars/.gitignore | 2 + RpiLedBars/.vscode/launch.json | 31 ++ {.vscode => RpiLedBars/.vscode}/tasks.json | 6 +- RpiLedBars/Makefile | 7 +- RpiLedBars/sgdb.sh | 3 + RpiLedBars/src/rpi_dma_utils.h | 2 +- RpiLedBars/src/rpi_pixleds.c | 528 +++++++++++---------- 8 files changed, 471 insertions(+), 257 deletions(-) create mode 100644 RpiLedBars/.clang-format create mode 100644 RpiLedBars/.gitignore create mode 100644 RpiLedBars/.vscode/launch.json rename {.vscode => RpiLedBars/.vscode}/tasks.json (87%) create mode 100755 RpiLedBars/sgdb.sh diff --git a/RpiLedBars/.clang-format b/RpiLedBars/.clang-format new file mode 100644 index 0000000..ac1699d --- /dev/null +++ b/RpiLedBars/.clang-format @@ -0,0 +1,149 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveBitFields: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE +... + diff --git a/RpiLedBars/.gitignore b/RpiLedBars/.gitignore new file mode 100644 index 0000000..8d4a6c0 --- /dev/null +++ b/RpiLedBars/.gitignore @@ -0,0 +1,2 @@ +bin +obj \ No newline at end of file diff --git a/RpiLedBars/.vscode/launch.json b/RpiLedBars/.vscode/launch.json new file mode 100644 index 0000000..1031ce1 --- /dev/null +++ b/RpiLedBars/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/pixled", + "args": [ + "-n", "5", + // "-t" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "miDebuggerPath": "${workspaceFolder}/sgdb.sh" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/RpiLedBars/.vscode/tasks.json similarity index 87% rename from .vscode/tasks.json rename to RpiLedBars/.vscode/tasks.json index 8a8fe47..17c3765 100644 --- a/.vscode/tasks.json +++ b/RpiLedBars/.vscode/tasks.json @@ -2,7 +2,7 @@ "version": "2.0.0", "tasks": [ { - "type": "cppbuild", + "type": "shell", "label": "Build project", "command": "make", "options": { @@ -15,6 +15,10 @@ "kind": "build", "isDefault": true }, + "presentation": { + "reveal": "always", + "panel": "new" + }, "detail": "compiler: /usr/bin/gcc" }, { diff --git a/RpiLedBars/Makefile b/RpiLedBars/Makefile index 0536f1e..5cebba3 100644 --- a/RpiLedBars/Makefile +++ b/RpiLedBars/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -g -DDEBUG +CFLAGS=-Wall -g #-DDEBUG LDFLAGS=#-lpthread SRCDIR=src OBJDIR=obj @@ -8,7 +8,7 @@ SRC=$(notdir $(wildcard $(SRCDIR)/*.c)) OBJ=$(SRC:.c=.o) BIN=pixled -all: $(addprefix $(BINDIR)/, $(BIN)) +all: clean $(addprefix $(BINDIR)/, $(BIN)) $(OBJDIR)/%.o: $(SRCDIR)/%.c if [ ! -d $(OBJDIR) ]; then mkdir "$(OBJDIR)"; fi @@ -20,4 +20,5 @@ $(BINDIR)/$(BIN) : $(addprefix $(OBJDIR)/, $(OBJ)) clean: rm -rf $(BINDIR)/* $(OBJDIR)/* - rmdir $(BINDIR) $(OBJDIR) \ No newline at end of file + if [ -d $(OBJDIR) ]; then rmdir "$(OBJDIR)"; fi + if [ -d "$(BINDIR)" ]; then rmdir "$(BINDIR)"; fi \ No newline at end of file diff --git a/RpiLedBars/sgdb.sh b/RpiLedBars/sgdb.sh new file mode 100755 index 0000000..c8220c5 --- /dev/null +++ b/RpiLedBars/sgdb.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +sudo /usr/bin/gdb "$@" \ No newline at end of file diff --git a/RpiLedBars/src/rpi_dma_utils.h b/RpiLedBars/src/rpi_dma_utils.h index 2fff08b..d618b63 100644 --- a/RpiLedBars/src/rpi_dma_utils.h +++ b/RpiLedBars/src/rpi_dma_utils.h @@ -16,7 +16,7 @@ // // Location of peripheral registers in physical memory -#define PHYS_REG_BASE PI_01_REG_BASE +#define PHYS_REG_BASE PI_23_REG_BASE #define PI_01_REG_BASE 0x20000000 // Pi Zero or 1 #define PI_23_REG_BASE 0x3F000000 // Pi 2 or 3 #define PI_4_REG_BASE 0xFE000000 // Pi 4 diff --git a/RpiLedBars/src/rpi_pixleds.c b/RpiLedBars/src/rpi_pixleds.c index e545d26..5f2a1d7 100644 --- a/RpiLedBars/src/rpi_pixleds.c +++ b/RpiLedBars/src/rpi_pixleds.c @@ -30,42 +30,45 @@ // v0.11 JPB 29/9/20 Added enable_dma before transfer (in case still active) // Corrected DMA nsamp value (was byte count) -#include -#include -#include -#include -#include -#include -#include #include "rpi_dma_utils.h" #include "rpi_smi_defs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#if PHYS_REG_BASE==PI_4_REG_BASE // Timings for RPi v4 (1.5 GHz) -#define SMI_TIMING 10, 15, 30, 15 // 400 ns cycle time -#else // Timings for RPi v0-3 (1 GHz) -#define SMI_TIMING 10, 10, 20, 10 // 400 ns cycle time +#if PHYS_REG_BASE == PI_4_REG_BASE // Timings for RPi v4 (1.5 GHz) +#define SMI_TIMING 10, 15, 30, 15 // 400 ns cycle time +#else // Timings for RPi v0-3 (1 GHz) +#define SMI_TIMING 10, 10, 20, 10 // 400 ns cycle time #endif -#define TX_TEST 0 // If non-zero, use dummy Tx data -#define LED_D0_PIN 8 // GPIO pin for D0 output -#define LED_NCHANS 8 // Number of LED channels (8 or 16) -#define LED_NBITS 24 // Number of data bits per LED -#define LED_PREBITS 4 // Number of zero bits before LED data -#define LED_POSTBITS 4 // Number of zero bits after LED data -#define BIT_NPULSES 3 // Number of O/P pulses per LED bit -#define CHAN_MAXLEDS 50 // Maximum number of LEDs per channel -#define CHASE_MSEC 100 // Delay time for chaser light test -#define REQUEST_THRESH 2 // DMA request threshold -#define DMA_CHAN 10 // DMA channel to use +#define TX_TEST 0 // If non-zero, use dummy Tx data +#define LED_D0_PIN 8 // GPIO pin for D0 output +#define LED_NCHANS 8 // Number of LED channels (8 or 16) +#define LED_NBITS 24 // Number of data bits per LED +#define LED_PREBITS 4 // Number of zero bits before LED data +#define LED_POSTBITS 4 // Number of zero bits after LED data +#define BIT_NPULSES 3 // Number of O/P pulses per LED bit +#define CHAN_MAXLEDS 50 // Maximum number of LEDs per channel +#define CHASE_MSEC 100 // Delay time for chaser light test +#define REQUEST_THRESH 2 // DMA request threshold +#define DMA_CHAN 10 // DMA channel to use // Length of data for 1 row (1 LED on each channel) -#define LED_DLEN (LED_NBITS * BIT_NPULSES) +#define LED_DLEN (LED_NBITS * BIT_NPULSES) // Transmit data type, 8 or 16 bits #if LED_NCHANS > 8 -#define TXDATA_T uint16_t +#define TXDATA_T uint16_t #else -#define TXDATA_T uint8_t +#define TXDATA_T uint8_t #endif // Structures for mapped I/O devices, and non-volatile memory @@ -73,10 +76,10 @@ extern MEM_MAP gpio_regs, dma_regs; MEM_MAP vc_mem, clk_regs, smi_regs; // Pointers to SMI registers -volatile SMI_CS_REG *smi_cs; -volatile SMI_L_REG *smi_l; -volatile SMI_A_REG *smi_a; -volatile SMI_D_REG *smi_d; +volatile SMI_CS_REG *smi_cs; +volatile SMI_L_REG *smi_l; +volatile SMI_A_REG *smi_a; +volatile SMI_D_REG *smi_d; volatile SMI_DMC_REG *smi_dmc; volatile SMI_DSR_REG *smi_dsr; volatile SMI_DSW_REG *smi_dsw; @@ -85,18 +88,18 @@ volatile SMI_DCA_REG *smi_dca; volatile SMI_DCD_REG *smi_dcd; // Ofset into Tx data buffer, given LED number in chan -#define LED_TX_OSET(n) (LED_PREBITS + (LED_DLEN * (n))) +#define LED_TX_OSET(n) (LED_PREBITS + (LED_DLEN * (n))) // Size of data buffers & NV memory, given number of LEDs per chan -#define TX_BUFF_LEN(n) (LED_TX_OSET(n) + LED_POSTBITS) -#define TX_BUFF_SIZE(n) (TX_BUFF_LEN(n) * sizeof(TXDATA_T)) -#define VC_MEM_SIZE (PAGE_SIZE + TX_BUFF_SIZE(CHAN_MAXLEDS)) +#define TX_BUFF_LEN(n) (LED_TX_OSET(n) + LED_POSTBITS) +#define TX_BUFF_SIZE(n) (TX_BUFF_LEN(n) * sizeof(TXDATA_T)) +#define VC_MEM_SIZE (PAGE_SIZE + TX_BUFF_SIZE(CHAN_MAXLEDS)) + +const char artnetId[] = "Art-Net"; // RGB values for test mode (1 value for each of 16 channels) -int on_rgbs[16] = {0xff0000, 0x00ff00, 0x0000ff, 0xffffff, - 0xff4040, 0x40ff40, 0x4040ff, 0x404040, - 0xff0000, 0x00ff00, 0x0000ff, 0xffffff, - 0xff4040, 0x40ff40, 0x4040ff, 0x404040}; +int on_rgbs[16] = {0xff0000, 0x00ff00, 0x0000ff, 0xffffff, 0xff4040, 0x40ff40, 0x4040ff, 0x404040, + 0xff0000, 0x00ff00, 0x0000ff, 0xffffff, 0xff4040, 0x40ff40, 0x4040ff, 0x404040}; int off_rgbs[16]; #if TX_TEST @@ -104,11 +107,12 @@ int off_rgbs[16]; TXDATA_T tx_test_data[] = {1, 2, 3, 4, 5, 6, 7, 0}; #endif -TXDATA_T *txdata; // Pointer to uncached Tx data buffer -TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)]; // Tx buffer for assembling data -int testmode, chan_ledcount=1; // Command-line parameters -int rgb_data[CHAN_MAXLEDS][LED_NCHANS]; // RGB data -int chan_num; // Current channel for data I/P +TXDATA_T *txdata; // Pointer to uncached Tx data buffer +TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)]; // Tx buffer for assembling data +int testmode, chan_ledcount = 1; // Command-line parameters +int rgb_data[CHAN_MAXLEDS][LED_NCHANS]; // RGB data +int chan_num; // Current channel for data I/P +int udpSocket; void rgb_txdata(int *rgbs, TXDATA_T *txd); int str_rgb(char *s, int rgbs[][LED_NCHANS], int chan); @@ -121,269 +125,289 @@ void init_smi(int width, int ns, int setup, int hold, int strobe); void setup_smi_dma(MEM_MAP *mp, int nsamp); void start_smi(MEM_MAP *mp); -int main(int argc, char *argv[]) -{ - int args=0, n, oset=0; +int main(int argc, char *argv[]) { + // setup + int args = 0, n, oset = 0; + memset(off_rgbs, 0, sizeof(int) * 16); - while (argc > ++args) // Process command-line args - { - if (argv[args][0] == '-') - { - switch (toupper(argv[args][1])) - { - case 'N': // -N: number of LEDs per channel - if (args >= argc-1) - fprintf(stderr, "Error: no numeric value\n"); - else - chan_ledcount = atoi(argv[++args]); - break; - case 'T': // -T: test mode - testmode = 1; - break; - default: // Otherwise error - printf("Unrecognised option '%c'\n", argv[args][1]); - printf("Options:\n" - " -n num number of LEDs per channel\n"\ - " -t Test mode (flash LEDs)\n"\ - ); - return(1); - } - } - else if (chan_num=0 && - (n=str_rgb(argv[args], rgb_data, chan_num))>0) - { - chan_ledcount = n > chan_ledcount ? n : chan_ledcount; - chan_num++; - } + while (argc > ++args) // Process command-line args + { + if (argv[args][0] == '-') { + switch (toupper(argv[args][1])) { + case 'N': // -N: number of LEDs per channel + if (args >= argc - 1) + fprintf(stderr, "Error: no numeric value\n"); + else + chan_ledcount = atoi(argv[++args]); + break; + case 'T': // -T: test mode + testmode = 1; + break; + default: // Otherwise error + printf("Unrecognised option '%c'\n", argv[args][1]); + printf("Options:\n" + " -n num number of LEDs per channel\n" + " -t Test mode (flash LEDs)\n"); + return (1); + } + } else if (chan_num < LED_NCHANS && hexdig(argv[args][0]) >= 0 && + (n = str_rgb(argv[args], rgb_data, chan_num)) > 0) { + chan_ledcount = n > chan_ledcount ? n : chan_ledcount; + chan_num++; } - signal(SIGINT, terminate); - map_devices(); - init_smi(LED_NCHANS>8 ? SMI_16_BITS : SMI_8_BITS, SMI_TIMING); - map_uncached_mem(&vc_mem, VC_MEM_SIZE); -#if TX_TEST - oset = oset; - setup_smi_dma(&vc_mem, sizeof(tx_test_data)/sizeof(TXDATA_T)); + } + signal(SIGINT, terminate); + map_devices(); + init_smi(LED_NCHANS > 8 ? SMI_16_BITS : SMI_8_BITS, SMI_TIMING); + map_uncached_mem(&vc_mem, VC_MEM_SIZE); + + setup_smi_dma(&vc_mem, TX_BUFF_LEN(chan_ledcount)); + printf("%s %u LED%s per channel, %u channels\n", testmode ? "Testing" : "Setting", chan_ledcount, + chan_ledcount == 1 ? "" : "s", LED_NCHANS); + + int nBytes; + char buffer[1024]; + struct sockaddr_in serverAddr; + struct sockaddr_storage serverStorage; + socklen_t addr_size; + + /*Create UDP socket*/ + udpSocket = socket(PF_INET, SOCK_DGRAM, 0); + + /*Configure settings in address struct*/ + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(0x1936); + serverAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); + memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); + + /*Bind socket with address struct*/ + bind(udpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + + /*Initialize size variable to be used later on*/ + addr_size = sizeof serverStorage; + + memcpy(txdata, tx_buffer, TX_BUFF_SIZE(chan_ledcount)); + start_smi(&vc_mem); + // loops + if (testmode) { + while (1) { + if (chan_ledcount < 2) + rgb_txdata(oset & 1 ? off_rgbs : on_rgbs, tx_buffer); + else { + for (n = 0; n < chan_ledcount; n++) { + rgb_txdata(n == oset % chan_ledcount ? on_rgbs : off_rgbs, &tx_buffer[LED_TX_OSET(n)]); + } + } + oset++; #if LED_NCHANS <= 8 - swap_bytes(tx_test_data, sizeof(tx_test_data)); + swap_bytes(tx_buffer, TX_BUFF_SIZE(chan_ledcount)); #endif - memcpy(txdata, tx_test_data, sizeof(tx_test_data)); - start_smi(&vc_mem); - usleep(10); - while (dma_active(DMA_CHAN)) - usleep(10); -#else - setup_smi_dma(&vc_mem, TX_BUFF_LEN(chan_ledcount)); - printf("%s %u LED%s per channel, %u channels\n", testmode ? "Testing" : "Setting", - chan_ledcount, chan_ledcount==1 ? "" : "s", LED_NCHANS); - - if (testmode) - { - while (1) - { - if (chan_ledcount < 2) - rgb_txdata(oset&1 ? off_rgbs : on_rgbs, tx_buffer); - else - { - for (n=0; n 0) { + if (memcmp(buffer, artnetId, sizeof(artnetId)) == 0) { + uint16_t opcode = buffer[8] | (buffer[9] << 8); + if (opcode == 0x5000) { + // uint8_t sequence = buffer[12]; + // uint16_t incomingUniverse = buffer[14] | (buffer[15] << 8); + uint16_t dmxDataLength = buffer[17] | (buffer[16] << 8); + char *dmxData = buffer + 18; + uint16_t maxBound = + (dmxDataLength / 3) < chan_ledcount ? (dmxDataLength / 3) : chan_ledcount; + for (size_t i = 0; i < maxBound; ++i) { + for (size_t j = 0; j < LED_NCHANS; ++j) { + char *rgb = dmxData + (i * 3); + rgb_data[i][j] = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; + } + rgb_txdata(rgb_data[i], &tx_buffer[LED_TX_OSET(i)]); } - oset++; + #if LED_NCHANS <= 8 swap_bytes(tx_buffer, TX_BUFF_SIZE(chan_ledcount)); #endif + memcpy(txdata, tx_buffer, TX_BUFF_SIZE(chan_ledcount)); + // enable_dma(DMA_CHAN); start_smi(&vc_mem); - usleep(CHASE_MSEC * 1000); + // usleep(10); + // while (dma_active(DMA_CHAN)) + // usleep(10); + } } + } } - else - { - for (n=0; n=0) - { - rgbs[i++][chan] = strtoul(s, &p, 16); - s = *p ? p+1 : p; - } - return(i); + while (chan < LED_NCHANS && i < CHAN_MAXLEDS && hexdig(*s) >= 0) { + rgbs[i++][chan] = strtoul(s, &p, 16); + s = *p ? p + 1 : p; + } + return (i); } // Set Tx data for 8 or 16 chans, 1 LED per chan, given 1 RGB val per chan // Logic 1 is 0.8us high, 0.4 us low, logic 0 is 0.4us high, 0.8us low -void rgb_txdata(int *rgbs, TXDATA_T *txd) -{ - int i, n, msk; +void rgb_txdata(int *rgbs, TXDATA_T *txd) { + int i, n, msk; - // For each bit of the 24-bit RGB values.. - for (n=0; n>1; - // 1st byte or word is a high pulse on all lines - txd[0] = (TXDATA_T)0xffff; - // 2nd has high or low bits from data - // 3rd is a low pulse - txd[1] = txd[2] = 0; - for (i=0; i> 1; + // 1st byte or word is a high pulse on all lines + txd[0] = (TXDATA_T)0xffff; + // 2nd has high or low bits from data + // 3rd is a low pulse + txd[1] = txd[2] = 0; + for (i = 0; i < LED_NCHANS; i++) { + if (rgbs[i] & msk) + txd[1] |= (1 << i); } + txd += BIT_NPULSES; + } } // Swap adjacent bytes in transmit data -void swap_bytes(void *data, int len) -{ - uint16_t *wp = (uint16_t *)data; +void swap_bytes(void *data, int len) { + uint16_t *wp = (uint16_t *)data; - len = (len + 1) / 2; - while (len-- > 0) - { - *wp = __builtin_bswap16(*wp); - wp++; - } + len = (len + 1) / 2; + while (len-- > 0) { + *wp = __builtin_bswap16(*wp); + wp++; + } } // Return hex digit value, -ve if not hex -int hexdig(char c) -{ - c = toupper(c); - return((c>='0' && c<='9') ? c-'0' : (c>='A' && c<='F') ? c-'A'+10 : -1); +int hexdig(char c) { + c = toupper(c); + return ((c >= '0' && c <= '9') ? c - '0' : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : -1); } // Map GPIO, DMA and SMI registers into virtual mem (user space) // If any of these fail, program will be terminated -void map_devices(void) -{ - map_periph(&gpio_regs, (void *)GPIO_BASE, PAGE_SIZE); - map_periph(&dma_regs, (void *)DMA_BASE, PAGE_SIZE); - map_periph(&clk_regs, (void *)CLK_BASE, PAGE_SIZE); - map_periph(&smi_regs, (void *)SMI_BASE, PAGE_SIZE); +void map_devices(void) { + map_periph(&gpio_regs, (void *)GPIO_BASE, PAGE_SIZE); + map_periph(&dma_regs, (void *)DMA_BASE, PAGE_SIZE); + map_periph(&clk_regs, (void *)CLK_BASE, PAGE_SIZE); + map_periph(&smi_regs, (void *)SMI_BASE, PAGE_SIZE); } // Catastrophic failure in initial setup -void fail(char *s) -{ - printf(s); - terminate(0); +void fail(char *s) { + printf(s); + terminate(0); } // Free memory segments and exit -void terminate(int sig) -{ - int i; +void terminate(int sig) { + int i; - printf("Closing\n"); - if (gpio_regs.virt) - { - for (i=0; ivalue = smi_l->value = smi_a->value = 0; - smi_dsr->value = smi_dsw->value = smi_dcs->value = smi_dca->value = 0; - if (*REG32(clk_regs, CLK_SMI_DIV) != divi << 12) - { - *REG32(clk_regs, CLK_SMI_CTL) = CLK_PASSWD | (1 << 5); - usleep(10); - while (*REG32(clk_regs, CLK_SMI_CTL) & (1 << 7)) ; - usleep(10); - *REG32(clk_regs, CLK_SMI_DIV) = CLK_PASSWD | (divi << 12); - usleep(10); - *REG32(clk_regs, CLK_SMI_CTL) = CLK_PASSWD | 6 | (1 << 4); - usleep(10); - while ((*REG32(clk_regs, CLK_SMI_CTL) & (1 << 7)) == 0) ; - usleep(100); - } - if (smi_cs->seterr) - smi_cs->seterr = 1; - smi_dsr->rsetup = smi_dsw->wsetup = setup; - smi_dsr->rstrobe = smi_dsw->wstrobe = strobe; - smi_dsr->rhold = smi_dsw->whold = hold; - smi_dmc->panicr = smi_dmc->panicw = 8; - smi_dmc->reqr = smi_dmc->reqw = REQUEST_THRESH; - smi_dsr->rwidth = smi_dsw->wwidth = width; - for (i=0; ivalue = smi_l->value = smi_a->value = 0; + smi_dsr->value = smi_dsw->value = smi_dcs->value = smi_dca->value = 0; + if (*REG32(clk_regs, CLK_SMI_DIV) != divi << 12) { + *REG32(clk_regs, CLK_SMI_CTL) = CLK_PASSWD | (1 << 5); + usleep(10); + while (*REG32(clk_regs, CLK_SMI_CTL) & (1 << 7)) + ; + usleep(10); + *REG32(clk_regs, CLK_SMI_DIV) = CLK_PASSWD | (divi << 12); + usleep(10); + *REG32(clk_regs, CLK_SMI_CTL) = CLK_PASSWD | 6 | (1 << 4); + usleep(10); + while ((*REG32(clk_regs, CLK_SMI_CTL) & (1 << 7)) == 0) + ; + usleep(100); + } + if (smi_cs->seterr) + smi_cs->seterr = 1; + smi_dsr->rsetup = smi_dsw->wsetup = setup; + smi_dsr->rstrobe = smi_dsw->wstrobe = strobe; + smi_dsr->rhold = smi_dsw->whold = hold; + smi_dmc->panicr = smi_dmc->panicw = 8; + smi_dmc->reqr = smi_dmc->reqw = REQUEST_THRESH; + smi_dsr->rwidth = smi_dsw->wwidth = width; + for (i = 0; i < LED_NCHANS; i++) + gpio_mode(LED_D0_PIN + i, GPIO_ALT1); } // Set up SMI transfers using DMA -void setup_smi_dma(MEM_MAP *mp, int nsamp) -{ - DMA_CB *cbs=mp->virt; +void setup_smi_dma(MEM_MAP *mp, int nsamp) { + DMA_CB *cbs = mp->virt; - txdata = (TXDATA_T *)(cbs+1); - smi_dmc->dmaen = 1; - smi_cs->enable = 1; - smi_cs->clear = 1; - smi_cs->pxldat = 1; - smi_l->len = nsamp * sizeof(TXDATA_T); - smi_cs->write = 1; - enable_dma(DMA_CHAN); - cbs[0].ti = DMA_DEST_DREQ | (DMA_SMI_DREQ << 16) | DMA_CB_SRCE_INC | DMA_WAIT_RESP; - cbs[0].tfr_len = nsamp; - cbs[0].srce_ad = MEM_BUS_ADDR(mp, txdata); - cbs[0].dest_ad = REG_BUS_ADDR(smi_regs, SMI_D); + txdata = (TXDATA_T *)(cbs + 1); + smi_dmc->dmaen = 1; + smi_cs->enable = 1; + smi_cs->clear = 1; + smi_cs->pxldat = 1; + smi_l->len = nsamp * sizeof(TXDATA_T); + smi_cs->write = 1; + enable_dma(DMA_CHAN); + cbs[0].ti = DMA_DEST_DREQ | (DMA_SMI_DREQ << 16) | DMA_CB_SRCE_INC | DMA_WAIT_RESP; + cbs[0].tfr_len = nsamp; + cbs[0].srce_ad = MEM_BUS_ADDR(mp, txdata); + cbs[0].dest_ad = REG_BUS_ADDR(smi_regs, SMI_D); } // Start SMI DMA transfers -void start_smi(MEM_MAP *mp) -{ - DMA_CB *cbs=mp->virt; +void start_smi(MEM_MAP *mp) { + DMA_CB *cbs = mp->virt; - start_dma(mp, DMA_CHAN, &cbs[0], 0); - smi_cs->start = 1; + start_dma(mp, DMA_CHAN, &cbs[0], 0); + smi_cs->start = 1; } // EOF