From 6e16fa717b971495afe57b8db8ed4a458695ef2c Mon Sep 17 00:00:00 2001 From: Stephen M Moraco Date: Fri, 19 Feb 2021 19:03:40 -0700 Subject: [PATCH] update to v0.2.0 --- .../p2/All/isp_hub75_matrix/README.md | 7 +- .../isp_hub75_matrix/isp_hub75_color.spin2 | 26 +- .../All/isp_hub75_matrix/isp_hub75_demos.zip | 4 +- .../isp_hub75_matrix/isp_hub75_display.spin2 | 120 ++- .../isp_hub75_display_bmp.spin2 | 24 +- .../isp_hub75_hwGeometry.spin2 | 306 +++++-- .../isp_hub75_matrix/isp_hub75_panel.spin2 | 661 ++++++++++----- .../isp_hub75_matrix/isp_hub75_rgb3bit.spin2 | 802 +++++++++++++----- .../isp_hub75_screenAccess.spin2 | 100 ++- .../isp_hub75_screenUtils.spin2 | 6 +- .../isp_hub75_scrollingText.spin2 | 4 +- 11 files changed, 1511 insertions(+), 549 deletions(-) diff --git a/libraries/community/p2/All/isp_hub75_matrix/README.md b/libraries/community/p2/All/isp_hub75_matrix/README.md index 78687699..1ff754c9 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/README.md +++ b/libraries/community/p2/All/isp_hub75_matrix/README.md @@ -6,6 +6,8 @@ Language: Spin2 / Pasm2 Created: 03-DEC-2020 +Upadted: 19-FEB-2021 + Category: display Description: @@ -13,7 +15,8 @@ Driver for HUB75 controlled RGB LED Matrix Panels Related: -- See Docs, Setup Instructions at [HUB75 LED Matrix Driver Github Repository](https://github.com/ironsheep/p2-HUB75-LED-Matrix-Driver) -- Watch for P2 Eval HUB75 Driver Board soon to be for sale at [Parallax Shop](https://www.parallax.com/product-category/propeller-2/) +- See Docs, Setup Instructions at [HUB75 LED Matrix Driver Github Repository](https://github.com/ironsheep/p2-LED-Matrix-Driver) +- Buy P2 Eval HUB75 Driver Board at [Parallax Online Store](https://www.parallax.com/product/p2-eval-hub75-adapter-board/) +- See Morphing Digits software add-on at the [P2 LED-Matrix Morphing Digits Repository](https://github.com/ironsheep/P2-LED-Matrix-Morphing-Digits) License: MIT (see end of source code) diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_color.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_color.spin2 index 74aec42e..bcaf633d 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_color.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_color.spin2 @@ -33,12 +33,27 @@ CON { test colorset } cOrange = $FFA500 cBlueViolet = $8A2BE2 + cFullRed = $FF0000 + cFullGreen = $00FF00 + cFullBlue = $0000FF + ' SPECIAL non-colors - invoke alforithm to gerate actual color used' cRedWhtBlu = $deadf0 cRainbow = $deadf1 #0, LED_UNKNOWN, LED_RED, LED_GREEN, LED_BLUE + ' our 3-bit colors + BASE_BLACK = $00 + BASE_RED = $01 + BASE_GREEN = $02 + BASE_YELLOW = $03 + BASE_BLUE = $04 + BASE_MAGENTA = $05 + BASE_CYAN = $06 + BASE_WHITE = $07 + + OBJ screen : "isp_hub75_screenAccess" @@ -152,14 +167,19 @@ PUB dutyCycleForIntensity(hex8bit) : pwmBits '' CALCULATE: proper duty cycle for intensity of 0-255 ' --- VERSION 1 - Bits spread throughout --- if hex8bit == 255 - pwmBits := $ff + pwmBits := screen.MAX_PWM_FRAMES else pwmBits := hex8bit / screen.MAX_PWM_FRAMES - - +{ + if not didShow[hex8bit] + debug("clr:dcyc ", uhex_byte(hex8bit), uhex_byte(pwmBits)) + didShow[hex8bit] := TRUE +'} DAT { tables, default values } +didShow byte FALSE[256] + defaultBrightness word 256 '256 ' 205 = 80% [0-255,256] where 256 is NO brightness adjustment ' Gamma curve (lookup table) diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_demos.zip b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_demos.zip index 0d7ece12..3cb2612f 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_demos.zip +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_demos.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcf16fb8c4209b3584c09cdffb433716f7f96805538cd870f4507af46e26512b -size 18997 +oid sha256:088163fc8a12bf2ac9731d0475a485f16a0fe252b35aa2995c3865d092427751 +size 17320 diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display.spin2 index 9b6bb5d6..b3991ed4 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display.spin2 @@ -34,6 +34,7 @@ SCROLL_FOREVER = scroller.SCROLL_FOREVER SCROLL_ONCE = scroller.SCROLL_ONCE SCROLL_ONCE_TO_CLEAR = scroller.SCROLL_ONCE_TO_CLEAR +' FIXME: UNDONE make this user configurable MAX_SCROLLING_REGIONS = 3 DAT { one or more screens of pixels of 24bit color } @@ -66,18 +67,31 @@ VAR { Object Instance Variables } byte horizontalGapInPix byte verticalGapInPix byte hBitmapOffsetInPix + byte bScan_1_4 + byte bSwapRB -PUB start() : ok | scrollerIndex +PUB start() : ok | scrollerIndex, dvrConfig, driverConfigRaw '' Start the underlying driver(s) + ok := cog := -1 ' mark as failed, initially + 'debug("`term temp size 80 50 textsize 10") + if screen.MAX_PANELS_PER_COLUMN * screen.MAX_PANELS_PER_ROW <> screen.MAX_PANELS + debug("dsp:Geometry BAD in isp_hub75_hwGeometry.spin2!") + abort + - debug("- TEXT: start()") + debug("dsp:start()") ok := cog := panel.start() ' send buffer to driver if ok == -1 - debug("- TEXT: underlying drivers failed!") + debug("dsp:underlying drivers failed!") abort + dvrConfig, driverConfigRaw := screen.getDriverFlags() + bScan_1_4 := (dvrConfig & screen.SCAN_4) > 0 ? True : False + bSwapRB := (dvrConfig & screen.RB_SWAP) > 0 ? True : False + + ' tell all about location of screen buffer screen.setScreen(@screen0) @@ -104,8 +118,8 @@ PUB clearScreen() PUB fillScreen(rgbColor) | row, column '' Fill the display with 24-bit color value - repeat row from 0 to screen.MAX_DISPLAY_ROWS - 1 - repeat column from 0 to screen.MAX_DISPLAY_COLUMNS - 1 + repeat row from 0 to screen.MAX_PHYSICAL_ROWS - 1 + repeat column from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 pixels.drawPixelAtRC(row, column, rgbColor) PUB fillPanel(threeBitColor) @@ -113,9 +127,14 @@ PUB fillPanel(threeBitColor) panel.fillPanel(threeBitColor) PUB commitScreenToPanel() - '' Write sceen to panel driver - 'debug("- DISP: commit!") - panel.convertScreen2PWM(@screen0) + '' Write sceen to panel driver PWM frames (while alternating PWM frame sets) + 'debug("dsp: commit!") + + if bScan_1_4 + panel.convertScreen2PWM_14(@screen0, bSwapRB) + 'panel.convertScreen2PWM_14_spin(@screen0, bSwapRB) + else + panel.convertScreen2PWM(@screen0, bSwapRB) { -------------- Text Handling -------------- } @@ -185,7 +204,7 @@ PUB setTextFont(newFont) | scrollerIndex, hUnusedPix, vUnusedPix selectedTextFont := newFont - debug("dsp:font ", udec(charHeightInPix), udec(charWidthInPix), udec(maxTextLines), udec(maxTextColumns), udec(verticalGapInPix), udec(horizontalGapInPix), udec(topOffsetInPix), udec(leftOffsetInPix)) + 'debug("dsp:font ", udec(charHeightInPix), udec(charWidthInPix), udec(maxTextLines), udec(maxTextColumns), udec(verticalGapInPix), udec(horizontalGapInPix), udec(topOffsetInPix), udec(leftOffsetInPix)) ' configure our scrollers for font choice repeat scrollerIndex from 0 to MAX_SCROLLING_REGIONS - 1 @@ -310,7 +329,7 @@ PRI nextFreeScroller() : scrollerIndexToUse | scrollerIndex if scrollerIndexToUse == NOT_FOUND debug("Failed to locate free scroller!") abort - debug("dsp:nextFreeScroller() ", udec(scrollerIndexToUse)) + 'debug("dsp:nextFreeScroller() ", udec(scrollerIndexToUse)) { -------------- Basic Graphics -------------- } @@ -324,25 +343,25 @@ PUB drawBoxOfColor(topRow, leftColumn, width, height, filled, rgbColor) | rightC bottomRow := topRow + height - 1 if filled == TRUE repeat rowIndex from 0 to height - 1 - drawLineOfColor(topRow + rowIndex, leftColumn, topRow + rowIndex, rightColumn, currTextColor) ' horiz row + drawLineOfColor(topRow + rowIndex, leftColumn, topRow + rowIndex, rightColumn, rgbColor) ' horiz row else - drawLineOfColor(topRow, leftColumn, topRow, rightColumn, currTextColor) ' horiz top - drawLineOfColor(topRow, rightColumn, bottomRow, rightColumn, currTextColor) ' vert right - drawLineOfColor(bottomRow, leftColumn, bottomRow, rightColumn, currTextColor) ' horiz bottom - drawLineOfColor(topRow, leftColumn, bottomRow, leftColumn, currTextColor) ' vert left + drawLineOfColor(topRow, leftColumn, topRow, rightColumn, rgbColor) ' horiz top + drawLineOfColor(topRow, rightColumn, bottomRow, rightColumn, rgbColor) ' vert right + drawLineOfColor(bottomRow, leftColumn, bottomRow, rightColumn, rgbColor) ' horiz bottom + drawLineOfColor(topRow, leftColumn, bottomRow, leftColumn, rgbColor) ' vert left PUB drawLine(fmRow, fmColumn, toRow, toColumn) '' Draw line fromRC -> toRC using current text color (currently limited to horzontal/vertical lines) drawLineOfColor(fmRow, fmColumn, toRow, toColumn, currTextColor) -PUB drawLineOfColor(fmRow, fmColumn, toRow, toColumn, rgbColor) | row, column, dx, dy, ctr, incr +PUB drawLineOfColor(fmRow, fmColumn, toRow, toColumn, rgbColor) | row, column, dx, dy, ctr, incr, intD '' Draw line fromRC -> toRC using rgbColor (currently limited to horzontal/vertical lines) + fmRow := 0 #> fmRow <# screen.MAX_PHYSICAL_ROWS - 1 + fmColumn := 0 #> fmColumn <# screen.MAX_PHYSICAL_COLUMNS - 1 + toRow := 0 #> toRow <# screen.MAX_PHYSICAL_ROWS - 1 + toColumn := 0 #> toColumn <# screen.MAX_PHYSICAL_COLUMNS - 1 'debug("seg:drwLn fmRC=(", udec_(fmRow), ",", udec_(fmColumn), "), toRC=(", udec_(toRow), ",", udec_(toColumn), "), RGB=(", uhex_long(rgbColor), ")") - fmRow := 0 #> fmRow <# screen.MAX_DISPLAY_ROWS - 1 - fmColumn := 0 #> fmColumn <# screen.MAX_DISPLAY_COLUMNS - 1 - toRow := 0 #> toRow <# screen.MAX_DISPLAY_ROWS - 1 - toColumn := 0 #> toColumn <# screen.MAX_DISPLAY_COLUMNS - 1 if fmRow == toRow ' draw Horizontal Line repeat column from fmColumn to toColumn @@ -352,22 +371,53 @@ PUB drawLineOfColor(fmRow, fmColumn, toRow, toColumn, rgbColor) | row, column, d repeat row from fmRow to toRow pixels.drawPixelAtRC(row, fmColumn, rgbColor) else - dx := (toColumn - fmColumn) - dy := (toRow - fmRow) - if (abs(dx) >= abs(dy)) - incr := abs(dx) + if abs(toRow - fmRow) < abs(toColumn - fmColumn) + if fmColumn > toColumn + plotLineLow(toColumn, toRow, fmColumn, fmRow, rgbColor) + else + plotLineLow(fmColumn, fmRow, toColumn, toRow, rgbColor) else - incr := abs(dy) - dx := dx / incr - dy := dy / incr - column := fmColumn - row := fmRow - ctr := 1 - repeat while (ctr <= incr) - pixels.drawPixelAtRC(row, column, rgbColor) - column += dx - row += dy - ctr += 1 + if fmRow > toRow + plotLineHigh(toColumn, toRow, fmColumn, fmRow, rgbColor) + else + plotLineHigh(fmColumn, fmRow, toColumn, toRow, rgbColor) + + +PRI plotLineLow(x0, y0, x1, y1, rgbColor) | row, column, dy, dx, D, yi + dx := x1 - x0 + dy := y1 - y0 + yi := 1 + if dy < 0 + yi := -1 + dy := -dy + D := (2 * dy) - dx + row := y0 + + repeat column from x0 to x1 + pixels.drawPixelAtRC(row, column, rgbColor) + if D > 0 + row := row + yi + D := D + (2 * (dy - dx)) + else + D := D + 2 * dy + +PRI plotLineHigh(x0, y0, x1, y1, rgbColor) | row, column, dy, dx, D, xi + dx := x1 - x0 + dy := y1 - y0 + xi := 1 + if dx < 0 + xi := -1 + dx := -dx + D := (2 * dx) - dy + column := x0 + + repeat row from y0 to y1 + pixels.drawPixelAtRC(row, column, rgbColor) + if D > 0 + column := column + xi + D := D + (2 * (dx - dy)) + else + D := D + 2*dx { -------------- Misc Helpers -------------- } diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display_bmp.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display_bmp.spin2 index 0595ef08..cc54aef5 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display_bmp.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_display_bmp.spin2 @@ -44,8 +44,8 @@ PRI loadBitmap(pBitmapFile) | nPanelCol, nPanelRow, blue, green, red, haveError, abort ' fill screen buffer - repeat nPanelRow from 0 to screen.MAX_PANEL_ROWS - 1 - repeat nPanelCol from 0 to screen.MAX_PANEL_COLUMNS - 1 + repeat nPanelRow from 0 to screen.MAX_PHYSICAL_ROWS - 1 + repeat nPanelCol from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 'debug("loadBitmap() - RC=(", udec_(nPanelRow), ", ", udec_(nPanelCol), ")") showDebug := FALSE if isDebugLocn(nPanelRow, nPanelCol) @@ -101,7 +101,7 @@ PRI validateBmpFile(pBmpFileImage) : bValidStatus | pFileHeader, i, iStart, iEnd ' XYZZYpnl debug(" - Img-start @0x", uhex_(iStart)) ' XYZZYpnl debug(" - Img-end @0x", uhex_(iEnd)) - if biWidth <> screen.MAX_PANEL_COLUMNS or biHeight <> screen.MAX_PANEL_ROWS + if biWidth <> screen.MAX_PHYSICAL_COLUMNS or biHeight <> screen.MAX_PHYSICAL_ROWS ' XYZZYpnl debug(" !! invalid BMP size! [NOT 64x32]") bValidStatus := FALSE @@ -118,16 +118,16 @@ PRI validateBmpFile(pBmpFileImage) : bValidStatus | pFileHeader, i, iStart, iEnd 'else ' XYZZYpnl debug("-good BMP size! [64x32]") - 'dbgMemDump(@fileHeaderMsg, pBmpFileImage, bfOffBits) - 'dbgMemDump(@fileStartMsg, iStart, 32) - 'dbgMemDump(@fileEndMsg, iEnd-32-1, 32) + 'screen.dbgMemDump(@fileHeaderMsg, pBmpFileImage, bfOffBits) + 'screen.dbgMemDump(@fileStartMsg, iStart, 32) + 'screen.dbgMemDump(@fileEndMsg, iEnd-32-1, 32) PRI get24BitBMPColorForRC(nRow, nColumn) : red, green, blue | pixColorAddr - if(nRow > screen.MAX_PANEL_ROWS - 1) - debug("- ERROR bad nRow value [", udec_(nRow), " > ", udec_(screen.MAX_PANEL_ROWS - 1), "]") + if(nRow > screen.MAX_PHYSICAL_ROWS - 1) + debug("- ERROR bad nRow value [", udec_(nRow), " > ", udec_(screen.MAX_PHYSICAL_ROWS - 1), "]") - if(nColumn > screen.MAX_PANEL_COLUMNS - 1) - debug("- ERROR bad nColumn value [", udec_(nColumn), " > ", udec_(screen.MAX_PANEL_COLUMNS - 1), "]") + if(nColumn > screen.MAX_PHYSICAL_COLUMNS - 1) + debug("- ERROR bad nColumn value [", udec_(nColumn), " > ", udec_(screen.MAX_PHYSICAL_COLUMNS - 1), "]") pixColorAddr := getPixelAddressForBMPRowColumn(nRow, nColumn) ' our intername .bmp file byte order is BGR! @@ -137,7 +137,7 @@ PRI get24BitBMPColorForRC(nRow, nColumn) : red, green, blue | pixColorAddr PRI getPixelAddressForBMPRowColumn(nRow, nColumn) : pixColorAddr | rowIndex, columnIndex, nOffset, fileBitsBase, showDebug ' Row is inverted in .BMP file... - rowIndex := (screen.MAX_PANEL_ROWS - 1) - nRow + rowIndex := (screen.MAX_PHYSICAL_ROWS - 1) - nRow ' Column is normal in file... columnIndex := nColumn @@ -148,7 +148,7 @@ PRI getPixelAddressForBMPRowColumn(nRow, nColumn) : pixColorAddr | rowIndex, col showDebug := TRUE ' FALSE ' turn off debug ' now offset is simple (just multiply by 3! [bytes of color]) - nOffset := ((rowIndex * screen.MAX_PANEL_COLUMNS) + columnIndex) * screen.DISPLAY_BYTES_PER_COLOR + nOffset := ((rowIndex * screen.MAX_PHYSICAL_COLUMNS) + columnIndex) * screen.DISPLAY_BYTES_PER_COLOR fileBitsBase := @byte[pBitmapFileInMemory][bfOffBits] ' get base of image in file (skip header) pixColorAddr := @byte[fileBitsBase][nOffset] ' add in offset to 24-bit color diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_hwGeometry.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_hwGeometry.spin2 index ca858ccd..50ebd058 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_hwGeometry.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_hwGeometry.spin2 @@ -1,13 +1,13 @@ '' ================================================================================================= '' '' File....... isp_hub75_hwGeometry.spin2 -'' Purpose.... Describe layout of the attached RGB LED Matrix Panel-set +'' Purpose.... Describe layout of the users attached RGB LED Matrix Panel-set '' Authors.... Stephen M Moraco '' -- Copyright (c) 2020 Iron Sheep Productions, LLC '' -- see below for terms of use '' E-mail..... stephen@ironsheep.biz '' Started.... Oct 2020 -'' Updated.... 21 Oct 2020 +'' Updated.... 26 Dec 2020 '' '' ================================================================================================= '' @@ -19,31 +19,45 @@ CON { Hardware Description } - -#0, CHIP_UNKNOWN, CHIP_FM6126A, CHIP_FM6124 - ' ================================================================================================= -' (1) Describe where your P2 EVAL HUB75 Adapter is plugged in +' (1) here the P2 EVAL HUB75 Adapter is plugged in ' ================================================================================================= #0[16], PINS_P0_P15, PINS_P16_P31, PINS_P32_P47, PINS_P48_P63 - ' my P2 EVAL Baord - 'ADAPTER_BASE_PIN = PINS_P32_P47 ' PINS_P16_31 - ADAPTER_BASE_PIN = PINS_P16_P31 - - ' my JonnyMac Board - 'ADAPTER_BASE_PIN = PINS_P0_P15 ' PINS_P0_P15 - 'ADAPTER_BASE_PIN = PINS_P32_P47 ' PINS_P0_P15 - 'ADAPTER_BASE_PIN = PINS_P48_P63 ' PINS_P0_P15 - - ' ================================================================================================= -' (2) Describe the overall layout of your hardware panels: +' (2) The Driver Chip on your panels ' ================================================================================================= +' Driver Manual Config Flags: +#$100, LAT_STYLE_OFFSET, #$200, LAT_POSN_OVERLAP, #$400, INIT_PANEL_REQUIRED, #$800, CLK_WIDE_PULSE, #$1000, RB_SWAP, #$2000, SCAN_4 + +' Driver Pre-defined flag combinations (use these unless your hardware is not in this list) +#0, CHIP_UNKNOWN, CHIP_MANUAL_SPEC, CHIP_FM6126A, CHIP_FM6124, CHIP_UNK_LAT_END_ENCL, CHIP_ICN2037, CHIP_UNK_LAT_END_ENCL_SLO_CLK, CHIP_MBI5124_8S + +' Normal use: +' PANEL_DRIVER_CHIP = CHIP_FM6126A ' +' Manual Use when your hardware is not listed: +' PANEL_DRIVER_CHIP = CHIP_MANUAL_SPEC | {flag1} | {flag2} | etc.. + +' NOTE: +' PANEL_DRIVER_CHIP = CHIP_FM6126A ' which is: CHIP_MANUAL_SPEC | LAT_STYLE_OFFSET | LAT_POSN_OVERLAP | INIT_PANEL_REQUIRED +' PANEL_DRIVER_CHIP = CHIP_FM6124 ' which is: CHIP_MANUAL_SPEC +' PANEL_DRIVER_CHIP = CHIP_ICN2037 ' which is: CHIP_MANUAL_SPEC | CLK_WIDE_PULSE | RB_SWAP + +' ================================================================================================= +' (3) Describe the overall layout of your hardware panel(s): +' ================================================================================================= + +' SUPPORTED address widths: A-B-C, or A-B-C-D, or A-B-C-D-E +#2, ADDR_UNKNOWN, ADDR_ABC, ADDR_ABCD, ADDR_ABCDE + +' Normal use: +' PANEL_ADDR_LINES = {addrLinesNeeded} + +' ------------------------------------------------------------------------------------------------- ' AUTHORs 1st configuration ' ------------------------------------------------------------------------------------------------- -' PANEL: --- P3-6432-121-16s-D1.0 --- +' PANEL: --- P3-6432-121-16s-D1.0 --- (pink labels) ' panel theory 3 bits per pixel ' 64 columns x 32 rows = 2048 pixels ' 16 lines [0-15]: 64 pixels / line @@ -51,30 +65,34 @@ CON { Hardware Description } ' EA half: 1024 pixels ' top half (lines 0-15) driven by R1,G1,B1 pins ' bottom half (lines 16-31) driven by R2,G2,B2 pins +' Author's panel uses FM6126A chips +' max clock rate of 30MHz - [16.5ns hi/16.5ns lo] ' ---------------------------------------------------------- +{ + ADAPTER_BASE_PIN = PINS_P16_P31 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_FM6126A -' determine what form of signalling the driver should use - 'PANEL_DRIVER_CHIP = CHIP_FM6124 ' CHIP_FM6126A - PANEL_DRIVER_CHIP = CHIP_FM6126A - - ' electrical layout + ' (2) describe the panel electrical layout MAX_PANEL_COLUMNS = 64 MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABCD + ' (3) describe the organization of panel(s) ' panels organization: visual layout ' [1] - ' logical/visual display layout - MAX_DISPLAY_COLUMNS = 64 - MAX_DISPLAY_ROWS = 32 - + ' (4) describe the organization in numbers of panels MAX_PANELS = 1 + MAX_PANELS_PER_ROW = 1 + MAX_PANELS_PER_COLUMN = 1 '} +' ------------------------------------------------------------------------------------------------- ' AUTHORs 2nd configuration ' ------------------------------------------------------------------------------------------------- -' PANEL: --- P3-6432-121-16s-D1.0 --- +' PANEL: --- P3-6432-121-16s-D1.0 --- (pink labels) ' panel theory 3 bits per pixel ' 64 columns x 32 rows = 2048 pixels ' 16 lines [0-15]: 64 pixels / line @@ -84,29 +102,28 @@ CON { Hardware Description } ' bottom half (lines 16-31) driven by R2,G2,B2 pins ' ---------------------------------------------------------- { -' determine what form of signalling the driver should use - PANEL_DRIVER_CHIP = CHIP_FM6126A + ADAPTER_BASE_PIN = PINS_P16_P31 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_FM6126A - ' electrical layout - MAX_PANEL_COLUMNS = 256 + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABCD - ' panels organization: visual layout - ' [1][2] 2 rows of 2 panels each - ' [3][4] - - ' logical/visual display layout - MAX_DISPLAY_COLUMNS = 128 - MAX_DISPLAY_ROWS = 64 - - MAX_PANELS = 4 + ' (3) describe the visual layout of the panel(s) + ' [1][2] 1 row of 2 panels + ' (4) describe the organization in numbers of panels + MAX_PANELS = 2 + MAX_PANELS_PER_ROW = 2 + MAX_PANELS_PER_COLUMN = 1 '} ' -' ================================================================================================= +' ------------------------------------------------------------------------------------------------- ' AUTHORs 3rd configuration ' ------------------------------------------------------------------------------------------------- -' PANEL: --- P3-6432-121-16s-D1.0 --- +' PANEL: --- P3-6432-121-16s-D1.0 --- (pink labels) ' panel theory 3 bits per pixel ' 64 columns x 32 rows = 2048 pixels ' 16 lines [0-15]: 64 pixels / line @@ -116,27 +133,28 @@ CON { Hardware Description } ' bottom half (lines 16-31) driven by R2,G2,B2 pins ' ---------------------------------------------------------- { -' determine what form of signalling the driver should use - PANEL_DRIVER_CHIP = CHIP_FM6126A + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_FM6126A - ' electrical layout - MAX_PANEL_COLUMNS = 256 + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABCD + ' (3) describe the organization of panel(s) ' panels organization: visual layout ' [1][2][3][4] ' one row of 4 panels - ' - MAX_DISPLAY_COLUMNS = 256 - MAX_DISPLAY_ROWS = 32 - - MAX_PANELS = 4 + ' (4) describe the organization in numbers of panels + MAX_PANELS = 4 + MAX_PANELS_PER_ROW = 4 + MAX_PANELS_PER_COLUMN = 1 } ' -' ================================================================================================= +' ------------------------------------------------------------------------------------------------- ' AUTHORs 4th configuration ' ------------------------------------------------------------------------------------------------- -' PANEL: --- P3-6432-121-16s-D1.0 --- +' PANEL: --- P3-6432-121-16s-D1.0 --- (orange labels) ' panel theory 3 bits per pixel ' 64 columns x 32 rows = 2048 pixels ' 16 lines [0-15]: 64 pixels / line @@ -144,37 +162,187 @@ CON { Hardware Description } ' EA half: 1024 pixels ' top half (lines 0-15) driven by R1,G1,B1 pins ' bottom half (lines 16-31) driven by R2,G2,B2 pins +' Author's panel uses FM6124 chips (came in Hackbox) +' max clock rate of 30MHz - [16.5ns hi/16.5ns lo] +' ---------------------------------------------------------- +{ + ADAPTER_BASE_PIN = PINS_P16_P31 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_FM6124 + + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 + MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABCD + + ' (3) describe the organization of panel(s) + ' panels organization: visual layout + ' [1] + + ' (4) describe the organization in numbers of panels + MAX_PANELS = 1 + MAX_PANELS_PER_ROW = 1 + MAX_PANELS_PER_COLUMN = 1 +'} + +' +' ------------------------------------------------------------------------------------------------- +' AUTHORs 5th configuration +' ------------------------------------------------------------------------------------------------- +' PANEL: --- P2-2020210240-200 --- +' panel theory 3 bits per pixel +' 64 columns x 64 rows = 4096 pixels +' 32 lines [0-31]: 64 pixels / line +' 2 halves: 2048 pixels / half (top and bottom) +' EA half: 2048 pixels +' top half (lines 0-31) driven by R1,G1,B1 pins +' bottom half (lines 32-63) driven by R2,G2,B2 pins +' Author's panel uses ICN2037 chips +' max clock rate of 20MHz - [25ns hi/25ns lo] +' ---------------------------------------------------------- +{ + ADAPTER_BASE_PIN = PINS_P16_P31 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_ICN2037 + + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 + MAX_PANEL_ROWS = 64 + PANEL_ADDR_LINES = ADDR_ABCDE + + ' (3) describe the organization of panel(s) + ' panels organization: visual layout + ' [1] ' one panel + ' + ' (4) describe the organization in numbers of panels + MAX_PANELS = 1 + MAX_PANELS_PER_ROW = 1 + MAX_PANELS_PER_COLUMN = 1 +'} + +' ------------------------------------------------------------------------------------------------- +' AUTHORs 6th configuration +' ------------------------------------------------------------------------------------------------- +' PANEL: --- P2-2020210240-200 --- +' panel theory 3 bits per pixel +' 64 columns x 64 rows = 4096 pixels +' 32 lines [0-31]: 64 pixels / line +' 2 halves: 2048 pixels / half (top and bottom) +' EA half: 2048 pixels +' top half (lines 0-31) driven by R1,G1,B1 pins +' bottom half (lines 32-63) driven by R2,G2,B2 pins +' Author's panel uses ICN2037 chips +' max clock rate of 20MHz - [25ns hi/25ns lo] ' ---------------------------------------------------------- { -' determine what form of signalling the driver should use - PANEL_DRIVER_CHIP = CHIP_UNKNOWN + ADAPTER_BASE_PIN = PINS_P32_P47 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_ICN2037 - ' electrical layout + ' (2) describe the panel electrical layout MAX_PANEL_COLUMNS = 64 + MAX_PANEL_ROWS = 64 + PANEL_ADDR_LINES = ADDR_ABCDE + + ' (3) describe the organization of panel(s) + ' panels organization: visual layout + ' [1][2] 1 row of 2 panels + ' + ' (4) describe the organization in numbers of panels + MAX_PANELS = 2 + MAX_PANELS_PER_ROW = 2 + MAX_PANELS_PER_COLUMN = 1 +'} + + +' ------------------------------------------------------------------------------------------------- +' AUTHORs 7th configuration +' ------------------------------------------------------------------------------------------------- +' PANEL: --- P4-1921-8S-vV2.0 --- (green PCBs) +' panel theory 3 bits per pixel +' 64 columns x 32 rows = 4096 pixels 1/8 scan!!! +' 32 lines [0-31]: 64 pixels / line +' 2 halves: 2048 pixels / half (top and bottom) +' EA half: 2048 pixels +' top half (lines 0-31) driven by R1,G1,B1 pins +' bottom half (lines 32-63) driven by R2,G2,B2 pins +' Author's panel uses MBI5124 chips +' max clock rate of 20MHz - [25ns hi/25ns lo] +' ---------------------------------------------------------- +'{ + ADAPTER_BASE_PIN = PINS_P32_P47 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_MBI5124_8S + + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 'works!!!! for PWM MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABC + ' (3) describe the organization of panel(s) ' panels organization: visual layout ' [1] ' one panel - ' - MAX_DISPLAY_COLUMNS = 64 - MAX_DISPLAY_ROWS = 32 - + ' + ' (4) describe the organization in numbers of panels MAX_PANELS = 1 + MAX_PANELS_PER_ROW = 1 + MAX_PANELS_PER_COLUMN = 1 +'} +' ------------------------------------------------------------------------------------------------- +' AUTHORs 8th configuration +' ------------------------------------------------------------------------------------------------- +' PANEL: --- P4-1921-8S-vV2.0 --- (green PCBs) +' panel theory 3 bits per pixel +' 64 columns x 32 rows = 4096 pixels 1/8 scan!!! +' 32 lines [0-31]: 64 pixels / line +' 2 halves: 2048 pixels / half (top and bottom) +' EA half: 2048 pixels +' top half (lines 0-31) driven by R1,G1,B1 pins +' bottom half (lines 32-63) driven by R2,G2,B2 pins +' Author's panel uses MBI5124 chips +' max clock rate of 20MHz - [25ns hi/25ns lo] +' ---------------------------------------------------------- +{ + ADAPTER_BASE_PIN = PINS_P32_P47 + ' (1) determine what form of signalling the driver should use + PANEL_DRIVER_CHIP = CHIP_MBI5124_8S ' CHIP_UNKNOWN -} + ' (2) describe the panel electrical layout + MAX_PANEL_COLUMNS = 64 + MAX_PANEL_ROWS = 32 + PANEL_ADDR_LINES = ADDR_ABC + ' (3) describe the organization of panel(s) + ' panels organization: visual layout + ' [1][2] 1 row of 2 panels + ' + ' (4) describe the organization in numbers of panels + MAX_PANELS = 2 + MAX_PANELS_PER_ROW = 2 + MAX_PANELS_PER_COLUMN = 1 +'} ' (remember to enable (uncomment) only one configuration above here) + +' ================================================================================================= +' (3) SPECIAL for using only part of your full display panel: +' ================================================================================================= + + ' (5) describe the subset of your display you'd like to use + ' and then where would you like it placed within the full display + ' + ' TBD - these are NOT YET SUPPORTED by the driver! + ' + ' Example 1: putting a 64x32 display vertically in center of 64x64 display + 'SUBSET_DISPLAY_TOP_INDENT = 16 + 'SUBSET_DISPLAY_LEFT_INDENT = 0 + 'SUBSET_DISPLAY_COLUMNS = 64 + 'SUBSET_DISPLAY_ROWS = 32 + ' ------------------------------------------------------------------------------------------------- ' ------------------------ Add your configurations ABOVE here ------------------------------------- ' -' -' now calculate values thare are common to all geometries of hardware -' - -' ------------------------ Add ABOVE here -------------------------------------------------------- -' ------------------------------------------------------------------------------------------------- PUB null() '' This is not a top level object @@ -206,5 +374,5 @@ CON { license } OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================================= - + }} diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_panel.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_panel.spin2 index db89689f..8c80a446 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_panel.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_panel.spin2 @@ -15,7 +15,7 @@ CON { I/O PINs } -'DEBUG_PIN = 16 +' None OBJ @@ -24,46 +24,31 @@ OBJ 'matrix : "isp_hub75_rgb3bit-LE" color : "isp_hub75_color" -DAT { pre-initialized } - - usePwmFrameset1 byte TRUE - didShow byte FALSE - didShowCount byte 2 ' just the first two screens - -VAR +VAR { driver instance variables } long cog long bus ' ram/flash long pwmFrames1[screen.MAX_PWM_FRAMES * screen.MAX_PWM_FRAME_SIZE_IN_LONGS] long pwmFrames2[screen.MAX_PWM_FRAMES * screen.MAX_PWM_FRAME_SIZE_IN_LONGS] - long showed - - - -CON { RAM/FLASH } - - BASE = 0 ' Base P2 pin of your HyperRAM module - RAM = $00_000000 ' external start address of RAM - FLASH = $02_000000 ' external start address of flash - - 'FLAGS = mem.F_FASTREAD ' enable sysclk/1 reads - + long nDumpPassNbr + byte usePwmFrameset1 ' ---------------------------------------------------------- PUB start() : ok '' Start the backend pasm2 driver for the matrix - debug("- PANEL: Start Matrix COG") + debug("- PNL: Start Matrix COG clk=", udec_long(clkfreq)) ok := cog := matrix.start() ' send buffer to driver if ok == -1 - debug("- PANEL: underlying drivers failed!") + debug("- PNL: underlying drivers failed!") abort - 'dbgMemDump(testValueMsg, @testValue, 4) - showed := didShowCount + usePwmFrameset1 := TRUE + nDumpPassNbr := 0 clearPwmFrameBuffer() ' clear PWM frames and get pointer to buffer + clearPwmFrameBuffer() ' this clears 2nd frame-set, too PUB stop() '' Stop the pasm2 backend driver @@ -79,56 +64,327 @@ PUB fillPanel(threeBitColor) '' Fill screen but without PWM (for testing underlying driver) matrix.fillPanel(threeBitColor) -PUB convertScreen2PWM(p24bitScreen) | redByte, greenByte, blueByte, pPwmFrame, pPwmFrameSet, panelCol, panelRow, p24bitColor, colorValue, colorMask, bitCount, bitNumber, panelBGR, tmpVarA, tmpVarB - '' Load a 24-bit image into PWM frame buffers - ' XYZZYpnl debug("- PANEL: loading screen at @", uhex_long_(p24bitScreen)) +VAR { spin timing support } + + long intrvlStart + long intrvlStop + +PUB convertScreen2PWM_14(p24bitScreen, bSwapRB) | pPwmFrameSet, nFrameOffset, nFrameIdx, nFrameCtr, pPwmFrame + '' Load a 24-bit-color image into PWM frame buffers at 8s (4 scan-lines at a time) [PASM] + ' scan memory, write PWM bytes twice, sigh + 'debug("- PNL:cs2pwm(): scn ", uhex_long(p24bitScreen), uhex_long(bSwapRB)) + + ' ------------------------------------------------------------------------- + ' NOTES for panel P4-1921-8S-V2.0 - 1/8 scan + ' two full 64px lines are emmitted for wach row, or 128px per each of 8 rows + ' the top 16 rows are fed by RGB1, while the bottom 16 rows are fed by RGB2 + ' + ' 64px lines do NOT span multiple rows! This means we can do a simple row- + ' number translation when mapping our PWM buffers to how the panel will display + ' the pixel values. + ' + ' The mapping is as follows: + ' ----- TOP ------ ----- BOTTOM ----- + ' Row 0 is placed in PWM bffr Row 1 Row 16 into pwm Row 17 + ' ------------ ------------ + ' 0 -> 1 16 -> 17 + ' 1 -> 3 17 -> 19 + ' 2 -> 5 18 -> 21 + ' 3 -> 7 19 -> 23 + ' 4 -> 9 20 -> 25 + ' 5 -> 11 21 -> 27 + ' 6 -> 13 22 -> 29 + ' 7 -> 15 23 -> 31 + ' ------------ ------------ + ' 8 -> 0 24 -> 16 + ' 9 -> 2 25 -> 18 + ' 10 -> 4 26 -> 20 + ' 11 -> 6 27 -> 22 + ' 12 -> 8 28 -> 24 + ' 13 -> 10 29 -> 26 + ' 14 -> 12 30 -> 28 + ' 15 -> 14 31 -> 30 + ' ------------------------------------------------------------------------- + ' this routine does not prestore all the transformed bytes + ' instead it scans each pixel at RC of the screen size + ' it then places either RGB1 into the each pwm frames' buffer + ' or if we are addressing the BOTTOM then it reads RGB1 value + ' from the pwm frames' buffer and or's in the RGB2 values + ' + ' THIS means that each screen buffer byte is read once while each + ' PWM buffer byte is written twice. + ' Anyway, the math to calculate the target pixel byte in the pwm buffer + ' is: + ' ------------------------------------------------------------------------- + ' The targetRow math of: + ' rows 0 - 7: targetRow = (row * 2) + 1 + ' rows 8 - 15: targetRow = (row - 8) * 2 + ' rows 16 - 24: targetRow = ((row - 16) * 2) + 17 + ' rows 24 - 31: targetRow = (row - 24) * 2) + 16 + ' ------------------------------------------------------------------------- + + markStart() + ' init ptrs + pPwmFrameSet := getActivePwmBuffer() + org + ' init variables + ' setup for red/blue flip if needed + or bSwapRB, bSwapRB wz ' T/F where: T=nz, F=z + ' T/nz = is Swapped + if_nz mov redBitRGB1Value, #$04 + if_nz mov blueBitRGB1Value, #$01 + if_nz mov redBitRGB2Value, #$20 + if_nz mov blueBitRGB2Value, #$08 + ' F/z = is NOT Swapped + if_z mov redBitRGB1Value, #$01 + if_z mov blueBitRGB1Value, #$04 + if_z mov redBitRGB2Value, #$08 + if_z mov blueBitRGB2Value, #$20 +for8SScreen + ' for all pixels of the screen buffer + 'repeat nPhysLineIdx from 0 to screen.MAX_PHYSICAL_ROWS - 1 ' [0-31] + xor nPhysLineIdx, nPhysLineIdx + mov nPhysLineCtr, #screen.MAX_PHYSICAL_ROWS +next8SLine + ' calc nPwmRGB12ByteIdx: offset into PWM buffer + mov nTargLineIdx, nPhysLineIdx ' start with phys row number + ' if low-half rows of panel... + cmp nPhysLineIdx, oneHalfLineCt wc + if_nc jmp #bottom8SRows +top8SRows ' determine calcs to use for top half of panel - Rows [0-15] + ' if nPhysLineIdx < one4thLineCt... + cmp nPhysLineIdx, one4thLineCt wc + ' CY=1: nTargLineIdx := (nPhysLineIdx * 2) + 1 - rows [0-7] + if_c shl nTargLineIdx, #1 ' mult by 2 + if_c add nTargLineIdx, #1 ' add 1 + ' CY=0: nTargLineIdx := (nPhysLineIdx - one4thLineCt) * 2 - Rows [8-15] + if_nc sub nTargLineIdx, one4thLineCt ' subtract 8 + if_nc shl nTargLineIdx, #1 ' mult by 2 + jmp #targ8SCalcsDone +bottom8SRows ' determine calcs to use for bottom half of panel - Rows [16-31] + ' if nPhysLineIdx < three4thsLineCt + cmp nPhysLineIdx, three4thsLineCt wc + ' CY=1: nTargLineIdx := ((nPhysLineIdx - oneHalfLineCt) * 2) + oneHalfLineCt + 1 - Rows [16-23] + if_c sub nTargLineIdx, oneHalfLineCt ' minus oneHalfLineCt + if_c shl nTargLineIdx, #1 ' mult by 2 + if_c add nTargLineIdx, oneHalfLineCt ' add oneHalfLineCt + if_c add nTargLineIdx, #1 ' add 1 + ' CY=0: nTargLineIdx := ((nPhysLineIdx - three4thsLineCt) + oneHalfLineCt) * 2 - Rows [24-31] + if_nc sub nTargLineIdx, three4thsLineCt ' minus three4thsLineCt + if_nc shl nTargLineIdx, #1 ' mult by 2 + if_nc add nTargLineIdx, oneHalfLineCt ' add oneHalfLineCt +targ8SCalcsDone + ' bIsBottomHalf := (nTargLineIdx > oneHalfLineCt - 1) ? TRUE : FALSE + cmp nTargLineIdx, oneHalfLineCt wc + if_nc mov bIsBottomHalf, allOnes ' TRUE if row 16-31 + if_c xor bIsBottomHalf, bIsBottomHalf ' FALSE if row 0-15 + 'repeat nColumnIdx from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 ' [0-63] + mov nColumnCtr, #screen.MAX_PHYSICAL_COLUMNS + ' calc nRGBColorOfst: offset into screen buffer + 'nRGBColorOfst := (nPhysLineIdx * screen.MAX_PHYSICAL_COLUMNS) * screen.DISPLAY_BYTES_PER_COLOR + mov nRGBColorOfst, nPhysLineIdx + mul nRGBColorOfst, #screen.MAX_PHYSICAL_COLUMNS + mul nRGBColorOfst, #screen.DISPLAY_BYTES_PER_COLOR + ' pRGBPixAddr := @byte[p24bitScreen][nRGBColorOfst] ' add in offset to 24-bit color + mov pRGBPixAddr, p24bitScreen + add pRGBPixAddr, nRGBColorOfst + ' nPwmRGB12ByteIdx := (nTargLineIdx * screen.MAX_PHYSICAL_COLUMNS) + mov nPwmRGB12ByteIdx, nTargLineIdx + mul nPwmRGB12ByteIdx, #screen.MAX_PHYSICAL_COLUMNS +next8SColumn + ' locate and load color for scanline + rdlong colorValue24bit, pRGBPixAddr + ' red := byte[pRGBPixAddr][0] + getbyte currPwmBits, colorValue24bit,#0 + call #cvt8SCurr2pwm + mov redPwmBits, currPwmBits + ' green := byte[pRGBPixAddr][1] + getbyte currPwmBits, colorValue24bit,#1 + call #cvt8SCurr2pwm + mov greenPwmBits, currPwmBits + ' blue := byte[pRGBPixAddr][2] + getbyte currPwmBits, colorValue24bit,#2 + call #cvt8SCurr2pwm + mov bluePwmBits, currPwmBits + + ' write color information to our PWM buffers + ' expand PWM-Bit-width bits into N pwm frames of 3-bit pixels two pixels/byte + + ' for ea. bit do... + ' repeat currPwmBitIdx from 0 to screen.MAX_PWM_FRAMES - 1 + xor currPwmBitIdx, currPwmBitIdx ' start with bit0 of [0-MAX_PWM_FRAMES - 1] + mov pwmBitCtr, #screen.MAX_PWM_FRAMES ' MAX PWM FRAME bits to scan in LONG + +next8SPwmFrame + ' calculate pointer to frame for this bit # + ' nFrameOffset := frameIdx * screen.MAX_PWM_FRAME_SIZE_IN_LONGS ' 256 longs in each frame + ' pPwmFrame := @long[getActivePwmBuffer()][nFrameOffset] + mov pPwmFrame, currPwmBitIdx + mul pPwmFrame, ##screen.MAX_PWM_FRAME_SIZE_IN_BYTES + add pPwmFrame, pPwmFrameSet + ' calc address of byte in pwm frame for this nPwmRGB12ByteIdx + mov pPwmFrameByte, nPwmRGB12ByteIdx ' get base addr + and pPwmFrameByte, maskModHalfScreen ' mod ((pys rows * phys cols) / 2) + add pPwmFrameByte, pPwmFrame ' add offset + ' build top RGB1 or bottom RGB2 bits to be stored in pwm byte + ' if not bIsBottomHalf + or bIsBottomHalf, bIsBottomHalf wz ' T/F where: T=nz, F=z + if_nz jmp #bottom8SHalf +top8SHalf + ' bitsBGR := 0 + xor bitsBGR, bitsBGR ' clear all bits + mov testBGR, bitsBGR + ' set our RGB1 bits + ' bitsBGR |= (rPwm & currBitMask) > 0 ? 1 : 0 + ' bitsBGR |= (gPwm & currBitMask) > 0 ? 2 : 0 + ' bitsBGR |= (bPwm & currBitMask) > 0 ? 4 : 0 + testb redPwmBits, currPwmBitIdx wc + if_c or bitsBGR, redBitRGB1Value + testb greenPwmBits, currPwmBitIdx wc + if_c or bitsBGR, greenBitRGB1Value + testb bluePwmBits, currPwmBitIdx wc + if_c or bitsBGR, blueBitRGB1Value + jmp #write8SPwmByte +bottom8SHalf + ' bitsBGR := byte[pPwmFrame][nPwmRGB12ByteIdx] + rdbyte bitsBGR, pPwmFrameByte ' load current value + mov testBGR, bitsBGR + ' NOTE: see if there's a write w/mask so we don't have to read... +' not needed and bitsBGR, maskOnlyRGB1bits ' clear all bits except RGB1 value + ' set our RGB2 bits + ' bitsBGR |= (rPwm & currBitMask) > 0 ? 8 : 0 + ' bitsBGR |= (gPwm & currBitMask) > 0 ? $10 : 0 + ' bitsBGR |= (bPwm & currBitMask) > 0 ? $20 : 0 + testb redPwmBits, currPwmBitIdx wc + if_c or bitsBGR, redBitRGB2Value + testb greenPwmBits, currPwmBitIdx wc + if_c or bitsBGR, greenBitRGB2Value + testb bluePwmBits, currPwmBitIdx wc + if_c or bitsBGR, blueBitRGB2Value +write8SPwmByte + ' write RGB1, RGB2 value to byte + 'byte[pPwmFrame][nPwmRGB12ByteIdx] := bitsBGR + 'or bitsBGR, #$3F + wrbyte bitsBGR, pPwmFrameByte ' load current value + ' this one done, if not all 8 bits done, go do next + add currPwmBitIdx, #1 + djnz pwmBitCtr, #next8SPwmFrame + + ' count this column, go do next column if not yet done + add pRGBPixAddr, #screen.DISPLAY_BYTES_PER_COLOR + add nPwmRGB12ByteIdx, #1 + djnz nColumnCtr, #next8SColumn + ' count this row, go do next row if not yet done + add nPhysLineIdx, #1 + djnz nPhysLineCtr, #next8SLine + jmp #doneS8 + +' currPwmBits := cvtCurr2pwm(currPwmBits) ' NOTE wipes tempByte +cvt8SCurr2pwm + or currPwmBits, currPwmBits wz ' special case: if zero return all 0 bits + if_z ret + sub currPwmBits, #1 ' subtract 1 from our count + bmask currPwmBits, currPwmBits ' convert bit count into string of bits + ret +doneS8 + +' the following initialized values are simply copied into PASM area before routine is run +nPhysLineIdx long 0 +nPhysLineCtr long 0 +nColumnCtr long 0 +nTargLineIdx long 0 +nPwmRGB12ByteIdx long 0 +bIsBottomHalf long 0 +nRGBColorOfst long 0 +maskQtrRowsModulus long 0 +pRGBPixAddr long 0 +redBitRGB1Value long $01 +greenBitRGB1Value long $02 +blueBitRGB1Value long $04 +redBitRGB2Value long $08 +greenBitRGB2Value long $10 +blueBitRGB2Value long $20 +maskOnlyRGB1bits long $07 +maskOnlyRGB2bits long $38 +maskRGB1nRGB2bits long $3F +redPwmBits long 0 +greenPwmBits long 0 +bluePwmBits long 0 +colorValue24bit long 0 +pwmBitCtr long 0 +currPwmBitIdx long 0 +bitsBGR long 0 +pPwmFrameByte long 0 +currPwmBits long 0 +testBGR long 0 +allOnes long $ffffffff +one4thLineCt long (screen.MAX_PHYSICAL_ROWS / 4) +oneHalfLineCt long (screen.MAX_PHYSICAL_ROWS / 2) +three4thsLineCt long (screen.MAX_PHYSICAL_ROWS / 4) * 3 +maskModHalfScreen long ((screen.MAX_PHYSICAL_ROWS * screen.MAX_PHYSICAL_COLUMNS) / 2) - 1 + + end + + markEnd(string("pasm 8S")) + matrix.writePwmBuffer(pPwmFrameSet) +' ----------------------------------------------------------------------------- + +PUB convertScreen2PWM(p24bitScreen, bSwapRB) | pPwmFrameSet + '' Load a 24-bit image into PWM frame buffers at 16s, 32s (2 scan-lines at a time) [SPIN] + ' XYZZYpnl debug("- PNL: loading screen at @", uhex_long_(p24bitScreen)) + ' FACT: dual 64x64 panel yields 205.035 Hz (full PWM fps) ' save address of 24bit screen for use by called routines + markStart() + pScreenInMemory := p24bitScreen ' clear 8x 3-bit frames - pPwmFrameSet := clearPwmFrameBuffer() ' clear PWM frames and get pointer to buffer - -{ - if not didShow - dbgMemDump(@screenMessage, p24bitScreen, 128) - showed-- -} + pPwmFrameSet := getActivePwmBuffer() ' clear PWM frames and get pointer to buffer ' fill 8x 3-bit frames from 24-bit-screen org - ' for each row... - ' FOLLOWING use redByte tempoerarily ... as our columnIndex (multiply value) - 'encod redByte, #screen.MAX_PANEL_COLUMNS ' pre-calculate our shift vs. multiply value - mov panelRow, #screen.MAX_DISPLAY_ROWS -nextRow - ' for each column - mov panelCol, #screen.MAX_DISPLAY_COLUMNS -nextColumn - ' locate 24-bit color for pixel - ' calculate address of 24-bit color - ' - 'nOffset := ((rowIndex * screen.MAX_PANEL_COLUMNS) + columnIndex) * screen.DISPLAY_BYTES_PER_COLOR - 'pixColorAddr := @byte[pScreenInMemory][nOffset] ' add in offset to 24-bit color - mov p24bitColor, panelRow - sub p24bitColor, #1 ' get rowIndex - 1 [32-1] -> [31-0] - mul p24bitColor, #screen.MAX_DISPLAY_COLUMNS ' x maxColumns - add p24bitColor, panelCol ' + columnIndex - sub p24bitColor, #1 ' - 1 [64-1] -> [63-0] - mul p24bitColor, #screen.DISPLAY_BYTES_PER_COLOR ' * bytes / 24-bit color - add p24bitColor, p24bitScreen ' + base address of screen - rdlong colorValue, p24bitColor + ' for each pixels in half screen... + add p24bitColorTop, p24bitScreen ' convert to address of last pixel in top half + add p24bitColorBot, p24bitColorTop ' convert to address of last pixel in bottom half + ' setup for red/blue flip if needed + or bSwapRB, bSwapRB wz + if_nz mov redBitTopValue, #$04 + if_nz mov blueBitTopValue, #$01 + if_z mov redBitTopValue, #$01 + if_z mov blueBitTopValue, #$04 + if_nz mov redBitBotValue, #$20 + if_nz mov blueBitBotValue, #$08 + if_z mov redBitBotValue, #$08 + if_z mov blueBitBotValue, #$20 +nextPixel + ' load our 2 pixels color/pwm data (top and bottom half of panel) + rdlong colorValue24bit, p24bitColorTop + ' red := byte[p24bitScreen][p24bitColor][0] + getbyte currPwmBits, colorValue24bit,#0 + call #cvtCurr2pwm + mov redPwmBitsTop, currPwmBits + ' green := byte[p24bitScreen][p24bitColor][1] + getbyte currPwmBits, colorValue24bit,#1 + call #cvtCurr2pwm + mov greenPwmBitsTop, currPwmBits + ' blue := byte[p24bitScreen][p24bitColor][2] + getbyte currPwmBits, colorValue24bit,#2 + call #cvtCurr2pwm + mov bluePwmBitsTop, currPwmBits + + rdlong colorValue24bit, p24bitColorBot ' red := byte[p24bitScreen][p24bitColor][0] - GETBYTE tmpVarA, colorValue,#0 - call #cvtTmpA2pwm - mov redByte, tmpVarA + getbyte currPwmBits, colorValue24bit,#0 + call #cvtCurr2pwm + mov redPwmBitsBot, currPwmBits ' green := byte[p24bitScreen][p24bitColor][1] - GETBYTE tmpVarA, colorValue,#1 - call #cvtTmpA2pwm - mov greenByte, tmpVarA + getbyte currPwmBits, colorValue24bit,#1 + call #cvtCurr2pwm + mov greenPwmBitsBot, currPwmBits ' blue := byte[p24bitScreen][p24bitColor][2] - GETBYTE tmpVarA, colorValue,#2 - call #cvtTmpA2pwm - mov blueByte, tmpVarA + getbyte currPwmBits, colorValue24bit,#2 + call #cvtCurr2pwm + mov bluePwmBitsBot, currPwmBits ' FYI GAMMA correction, brightness are adjusted as the byte is place into our source screen buffer!! @@ -136,99 +392,131 @@ nextColumn ' expand 24-bit pixel into 8 pwm frames of 3-bit pixel ' for ea. bit do... mov bitCount, #screen.MAX_PWM_FRAMES ' MAX PWM FRAME bits to scan in LONG - mov bitNumber, #0 ' start with bit0 of [0-MAX_PWM_FRAMES - 1] + xor currBitNumber, currBitNumber ' start with bit0 of [0-MAX_PWM_FRAMES - 1] nextBit ' calculate offset to frame for this bit # ' frameIdx := 0 #> nBitNumber <# screen.MAX_PWM_FRAMES - 1 ' MAX 8 pwm frames so limit our index ' nFrameOffset := frameIdx * screen.MAX_PWM_FRAME_SIZE_IN_LONGS ' 256 longs in each frame - ' pPwmFrame := @long[getActivePwmBuffer()][nFrameOffset] - mov pPwmFrame, bitNumber - mul pPwmFrame, ##screen.MAX_PWM_FRAME_SIZE_IN_BYTES - ' calculate pointer to frame for thic bit # - add pPwmFrame, pPwmFrameSet - ' build RGB1 or RGB2 bits to be stored in panel word - ' rBit := red & (1 << bitNumber) > 0 ? 1 : 0 - ' gBit := green & (1 << bitNumber) > 0 ? 1 : 0 - ' bBit := blue & (1 << bitNumber) > 0 ? 1 : 0 - mov panelBGR, #0 ' clear color value - testb redByte, bitNumber wc - if_c or panelBGR, #$01 - testb greenByte, bitNumber wc - if_c or panelBGR, #$02 - testb blueByte, bitNumber wc - if_c or panelBGR, #$04 - ' tmpVarB := (nBffrR > 15) ? TRUE : FALSE - mov tmpVarA, panelRow - sub tmpVarA, #1 ' now [0-31] - cmp tmpVarA, #16 wc ' loading top or bottom half of screen? - if_c mov tmpVarB, #0 ' NO, is RGB1 (top) - if_nc mov tmpVarB, #1 ' YES, is RGB2 (bottom) - ' convert row number to row number of top-half of panel - if_nc sub tmpVarA, #16 ' 0-31 -> 0-15 - ' is top-RGB1 or bottom-RGB2 color? - ' if tmpVarB - ' bitsBGR <<= 3 ' mov color bits into rgb2 position - ' maskBitsBGR <<= 3 - mov colorMask, #%0000_0111 - cmp tmpVarB, #1 wz - if_z shl panelBGR, #3 ' is RGB2 move into RGB2 position: %0011_1000 - if_z shl colorMask, #3 ' and move mask as well - ' byteIdx := (nBffrR * screen.MAX_PANEL_COLUMNS) + nBffrC - mov tmpVarB, tmpVarA - mul tmpVarB, #screen.MAX_DISPLAY_COLUMNS - add tmpVarB, panelCol - sub tmpVarB, #1 - add tmpVarB, pPwmFrame - ' get byte value - ' currByte := byte[pPwmFrame][byteIdx] & !maskBitsBGR - rdbyte tmpVarA, tmpVarB - not colorMask - and tmpVarA, colorMask - ' byte[pPwmFrame][byteIdx] := currByte | bitsBGR - or tmpVarA, panelBGR - wrbyte tmpVarA, tmpVarB + ' pPwmFrameByt := @long[getActivePwmBuffer()][nFrameOffset] + mov pPwmFrameByt, currBitNumber + mul pPwmFrameByt, ##screen.MAX_PWM_FRAME_SIZE_IN_BYTES + ' calculate pointer to frame for this bit # + add pPwmFrameByt, pPwmFrameSet ' add base of frame buffer + add pPwmFrameByt, nPixelCtr ' add-in offset to current byte + sub pPwmFrameByt, #1 ' make relative to 0 + ' build RGB1 and RGB2 bits to be stored in PWM panel byte + ' rBit := red & (1 << currBitNumber) > 0 ? 1 : 0 + ' gBit := green & (1 << currBitNumber) > 0 ? 1 : 0 + ' bBit := blue & (1 << currBitNumber) > 0 ? 1 : 0 + xor panelBGR, panelBGR ' clear color value + testb redPwmBitsTop, currBitNumber wc + if_c or panelBGR, redBitTopValue + testb greenPwmBitsTop, currBitNumber wc + if_c or panelBGR, greenBitTopValue + testb bluePwmBitsTop, currBitNumber wc + if_c or panelBGR, blueBitTopValue + testb redPwmBitsBot, currBitNumber wc + if_c or panelBGR, redBitBotValue + testb greenPwmBitsBot, currBitNumber wc + if_c or panelBGR, greenBitBotValue + testb bluePwmBitsBot, currBitNumber wc + if_c or panelBGR, blueBitBotValue + + ' write our new byte value + ' byte[pPwmFrameByt][pwmByteIndex] := panelBGR + wrbyte panelBGR, pPwmFrameByt ' this one done, if not all 8 bits done, go do next - add bitNumber, #1 + add currBitNumber, #1 djnz bitCount, #nextBit - ' count this column, go do next column if not yet done - djnz panelCol, #nextColumn - ' count this row, go do next row if not yet done - djnz panelRow, #nextRow + ' point to prior pixel RGB spec in top and bottom halves + sub p24bitColorTop, #screen.DISPLAY_BYTES_PER_COLOR + sub p24bitColorBot, #screen.DISPLAY_BYTES_PER_COLOR + ' count this pixel done, go do next pixel if not yet done + djnz nPixelCtr, #nextPixel jmp #done -' tmpVarA := cvtTmpA2pwm(tmpVarA) ' NOTE wipes tmpVarB -cvtTmpA2pwm - sub tmpVarB, tmpVarB - cmp tmpVarA, #0 wz ' special case: if zero return all 0 bits - if_z jmp #noShift - cmp tmpVarA, #255 wz ' special case: if $ff return all 1 bits - if_z not tmpVarB, tmpVarB - if_z jmp #noShift - sub tmpVarA, #1 - bmask tmpVarB, tmpVarA ' successively move CY into lower bits - mov tmpVarA, tmpVarB ' return our new value -noShift +' currPwmBits := cvtCurr2pwm(currPwmBits) ' NOTE wipes tempByte +cvtCurr2pwm + or currPwmBits, currPwmBits wz ' special case: if zero return all 0 bits + if_z ret + sub currPwmBits, #1 ' subtract 1 from our count + bmask currPwmBits, currPwmBits ' convert bit count into string of bits ret - done + +' the following initialized values are simply copied into PASM area before routine is run +nPixelCtr long (screen.MAX_PHYSICAL_ROWS * screen.MAX_PHYSICAL_COLUMNS) / 2 +redBitTopValue long $01 +greenBitTopValue long $02 +blueBitTopValue long $04 +redBitBotValue long $08 +greenBitBotValue long $10 +blueBitBotValue long $20 +midDisplayRow long 0 +redPwmBitsTop long 0 +greenPwmBitsTop long 0 +bluePwmBitsTop long 0 +redPwmBitsBot long 0 +greenPwmBitsBot long 0 +bluePwmBitsBot long 0 +pPwmFrameByt long 0 +p24bitColorTop long (((screen.MAX_PHYSICAL_ROWS * screen.MAX_PHYSICAL_COLUMNS) / 2) - 1) * screen.DISPLAY_BYTES_PER_COLOR +p24bitColorBot long ((screen.MAX_PHYSICAL_ROWS * screen.MAX_PHYSICAL_COLUMNS) / 2) * screen.DISPLAY_BYTES_PER_COLOR +colorValue24bit long 0 +colorValueTop long 0 +colorValueBot long 0 +colorMask long 0 +bitCount long 0 +currBitNumber long 0 +panelBGR long 0 +rowIndexHalfPanel long 0 +pwmByteIndex long 0 +currPwmColorBits long 0 +currPwmBits long 0 +tempByte long 0 +allOnes long $ffffffff + end -{ - if not didShow - dumpFrameSet(pPwmFrameSet) - if showed == 0 - didShow := TRUE -} - ' write 8x 3-bit frames to panel + + markEnd(string("pasm 16S")) matrix.writePwmBuffer(pPwmFrameSet) +' ----------------------------------------------------------------------------- + +PRI dumpBufferHeads(pSCreenBuffer,pPwmBuffer) + screen.dbgMemDump(@bufferMsg, pSCreenBuffer, 48) + screen.dbgMemDump(@frameMsg, pPwmBuffer, 48) + +PRI dumpFrameAddrs(pPwmFrameSet) | pFrameBuffer, frameIndex + repeat frameIndex from 0 to screen.MAX_PWM_FRAMES - 1 + pFrameBuffer := @long[pPwmFrameSet][frameIndex * screen.MAX_PWM_FRAME_SIZE_IN_LONGS] + debug("PNL: PWM", udec_(frameIndex), ": ", uhex_long_(pFrameBuffer)) + PRI dumpFrameSet(pPwmFrameSet) | pFrameBuffer, frameIndex - repeat frameIndex from 0 to 7 - pFrameBuffer := @long [pPwmFrameSet][frameIndex * screen.MAX_PWM_FRAME_SIZE_IN_LONGS] - dumpFrame(pFrameBuffer) + repeat frameIndex from 0 to screen.MAX_PWM_FRAMES - 1 + pFrameBuffer := @long[pPwmFrameSet][frameIndex * screen.MAX_PWM_FRAME_SIZE_IN_LONGS] + dumpFrame(frameIndex, pFrameBuffer) + +PRI dumpFrame(frameIdx, pFrameBuffer) | frameASCII + frameASCII := frameIdx | $30 + if frameIdx > 9 + frameASCII := frameIdx - 10 + $41 + byte[@msgPwm][3] := frameASCII + + if emptyRgb2(pFrameBuffer) + byte[@msgPwm][4] := "*" + else + byte[@msgPwm][4] := $20 ' space + + screen.dbgMemDump(@msgPwm, pFrameBuffer, 32) -PRI dumpFrame(pFrameBuffer) - dbgMemDump(@frameMessage, pFrameBuffer, 32) +PRI emptyRgb2(pFrameBuffer) : isEmpty | byteIdx + isEmpty := TRUE + repeat byteIdx from 0 to 31 + if byte[pFrameBuffer][byteIdx] & $38 > 0 + isEmpty := FALSE + quit PRI clearPwmFrameBuffer() : pPwmFrameSet ' clear entire PWM buffer @@ -241,22 +529,24 @@ PRI clearPwmFrameBuffer() : pPwmFrameSet PRI getActivePwmBuffer() : pPwmFrameSet pPwmFrameSet := (usePwmFrameset1) ? @pwmFrames1 : @pwmFrames2 -PRI getPwmFrameAddressForBit(nBitNumber) : pFrameBuffer | nFrameOffset, frameIdx +PRI getPwmFrameAddressForBit(nBitNumber) : pFrameBuffer | nFrameOfst, frameIdx ' return indexed PWM Frame address - frameIdx := 0 #> nBitNumber <# screen.MAX_PWM_FRAMES - 1 ' MAX 8 pwm frames so limit our index - nFrameOffset := frameIdx * screen.MAX_PWM_FRAME_SIZE_IN_LONGS ' 192 longs in each frame - pFrameBuffer := @long[getActivePwmBuffer()][nFrameOffset] + frameIdx := 0 #> nBitNumber <# screen.MAX_PWM_FRAMES - 1 ' limit our index to MAX_PWM_FRAMES + nFrameOfst := frameIdx * screen.MAX_PWM_FRAME_SIZE_IN_LONGS ' N longs in each PWM frame + pFrameBuffer := @long[getActivePwmBuffer()][nFrameOfst] 'debug("- PWM frame(", udec_(frameIdx), "), ", uhex_long(pFrameBuffer)) VAR { buffer addresses } long pBitmapFileInMemory + long dvrConfig + long driverConfigRaw long pScreenInMemory -PRI setPanelColorBitsForRC(pPwmFrame, nPanelRow, nPanelCol, rBit, gBit, bBit) | nBffrR, nBffrC, isRGB2, byteIdx, maskBitsBGR, bitsBGR, currByte, showDebug +PRI setPanelColorBitsForRC(pPwmFrame, nPanelRow, nPanelCol, rBit, gBit, bBit) | nBffrR, nBffrC, isRGB2, byteIdx, maskBitsBGR, bitsBGR, currPwmColorBits, showDebug ' write color bits to a PWM frame at frame[r][c] - nBffrR := 0 #> nPanelRow <# screen.MAX_DISPLAY_ROWS - 1 - nBffrC := 0 #> nPanelCol <# screen.MAX_DISPLAY_COLUMNS - 1 + nBffrR := 0 #> nPanelRow <# screen.MAX_PHYSICAL_ROWS - 1 + nBffrC := 0 #> nPanelCol <# screen.MAX_PHYSICAL_COLUMNS - 1 isRGB2 := (nBffrR > 15) ? TRUE : FALSE nBffrR //= 16 @@ -266,15 +556,29 @@ PRI setPanelColorBitsForRC(pPwmFrame, nPanelRow, nPanelCol, rBit, gBit, bBit) | if isRGB2 bitsBGR <<= 3 ' mov color bits into rgb2 position maskBitsBGR <<= 3 + ' FIXME: UNDONE WAS PANEL_COLUMNS ?? + byteIdx := (nBffrR * screen.MAX_PHYSICAL_COLUMNS) + nBffrC - byteIdx := (nBffrR * screen.MAX_PANEL_COLUMNS) + nBffrC - - currByte := byte[pPwmFrame][byteIdx] & !maskBitsBGR + currPwmColorBits := byte[pPwmFrame][byteIdx] & !maskBitsBGR if byteIdx > 1023 debug("ERROR! byte index calc failure have=(" , udec_(byteIdx), ") of [0-1023]") else - byte[pPwmFrame][byteIdx] := currByte | bitsBGR - + byte[pPwmFrame][byteIdx] := currPwmColorBits | bitsBGR + +PRI markStart() + 'pinl(46) ' for timing + 'pinh(47) ' for timing + intrvlStart := getct() ' get starting time + +PRI markEnd(message) | elapsed + intrvlStop := getct() ' get stoping time + 'pinl(47) ' for timing + 'pinl(46) ' for timing + elapsed := intrvlStop - intrvlStart ' compute elapsed ticks, no need to worry about timer wrap here + 'elapsed := elapsed +/ (clkfreq/1000) ' convert to milliseconds + elapsed := elapsed +/ (clkfreq/1000000) ' convert to useconds + 'elapsed := elapsed +/ (clkfreq/1000) ' convert to useconds + debug("- runtime ", zstr_(message), ": ", udec_long(elapsed), " uS") PRI isDebugLocn(nRow, nCol) : status status := FALSE @@ -282,44 +586,21 @@ PRI isDebugLocn(nRow, nCol) : status if (nRow == 31 && nCol < 4) || (nRow < 2 && nCol < 3) || (nRow == 31 && nCol > 61) || (nRow < 2 && nCol > 61) status := TRUE ' FALSE ' turn off debug -PUB dbgMemDump(bfrId, buffer, len) | bytBffr, colIdx, rowIdx, maxCol, maxRow, dispLen - '' Dump bytes in hex format to debug() terminal - debug("`temp 13 '", zstr_(bfrId), ": bffr=", uhex_long_(buffer), "(", udec_(len), ")' 13") - maxCol := len >= 16 ? 15 : len - maxRow := (len / 16) - if maxRow * 16 < len - maxRow++ - if maxRow == 0 - maxRow := 1 - - bytBffr := buffer - waitus(35) - 'returns - dispLen := 0 - repeat rowIdx from 1 to maxRow - if rowIdx < 10 - debug("`temp ' '") ' space - debug("`temp ' ", uhex_long_(bytBffr), ": '") - repeat colIdx from 0 to maxCol - debug("`temp '", uhex_byte_(byte[bytBffr+colIdx]), " '") - dispLen++ - if dispLen >= len - quit - if colIdx == 7 - debug("`temp ' '") ' space - - bytBffr += 16 - debug("`temp 13") ' newline - waitus(85) ' 50 too short, 70 less issue, 75 better, - waitms(2) - -DAT { .bmp fiile work area } - -testValue long $87654321 -testValueMsg byte "Test value",0 - -frameMessage byte "FrameBuffer",0 +PRI waitSec(countSeconds) + repeat countSeconds + waitms(1000) + + +DAT { .bmp fiile work area } + + testValue long $87654321 + testValueMsg byte "Test value",0 + + msgScrnHd byte "Screen",0 + msgPwm byte "Pwm0 ", 0 + bufferMsg byte "SCREEN",0 + frameMsg byte "PWM[0]",0 CON { license } diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_rgb3bit.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_rgb3bit.spin2 index 2b34efe0..9ba35330 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_rgb3bit.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_rgb3bit.spin2 @@ -14,24 +14,10 @@ CON { timing } - CLK_FREQ = 335_000_000 ' system freq as a constant - MS_001 = CLK_FREQ / 1_000 ' ticks in 1ms - US_001 = CLK_FREQ / 1_000_000 ' ticks in 1us - - TM_64US = US_001 * 64 - - NS_015 = 5 ' - 2 '15 / (1_000_000_000 / CLK_FREQ) ' tics in 15 nSec - NS_030 = 10 - 2 '30 / (1_000_000_000 / CLK_FREQ) ' tics in 30 nSec - - BR_TERM = 2_000_000 ' debug baud rate - - '_clkfreq = CLK_FREQ ' set system clock +' clock is setup in top-level file CON { I/O PINs } - 'DEBUG_PIN = 16 - - ' New P2 Eval Board HUB75 Adapter: ' the user-selected location: one of 0, 16, 32, and 48 @@ -57,7 +43,7 @@ CON { I/O PINs } MTX_LED_PIN_OE = MTX_LED_BASE_PIN + 1 MTX_LED_PIN_CLK = MTX_LED_BASE_PIN + 0 - MTX_ROW_ADDR_PINS = MTX_LED_PIN_A ADDPINS 3 ' TESTING use 4, use 3 for live! + MTX_ROW_ADDR_PINS = MTX_LED_PIN_A ADDPINS 4 ' TESTING use 4, use 3 for live! MTX_COLOR_PINS = MTX_LED_PIN_R1 ADDPINS 5 MTX_COLOR_RGB1_PINS = MTX_LED_PIN_R1 ADDPINS 2 @@ -94,88 +80,176 @@ CON { Data } WHITE = $07 #0, CMD_DONE, CMD_CLEAR, CMD_SHOW_BUFFER, CMD_FILL_COLOR, CMD_SHOW_PWM_BUFFER, CMD_STOP + OBJ screen : "isp_hub75_screenAccess" + color : "isp_hub75_color" VAR - long ptrCommand ' ptra[2] - long ptrArgument ' ptra[3] @buffer -OR- color value [0-7] + long ptrCommand ' ptra[2] + long ptrArgument ' ptra[3] @buffer -OR- color value [0-7] ' write values here to pass to driver - long dvrCommand - long dvrArgument + long dvrCommand + long dvrArgument - long cog + long dvrConfig + long driverFlags + long driverConfigRaw + long bSwapRB + long bInitPanel + long bScan_1_4 + long cog ' -------------------------------------------------------------------------------------------------- -PUB start() : ok | bSetLowPins +PUB start() : ok | bSetLowPins, tmpVar, panelCt '' Setup the pasm2 driver vars, then start a new cog running the driver stop() - - - 'repeat - ' PINLOW(MTX_LED_PIN_OE) ' high! (/OE) - ' PINHIGH(MTX_LED_PIN_OE) ' high! (/OE) - - - 'testT := TRUE - 'testF := FALSE - - 'debug("TEST T/F ", uhex_long(testT), uhex_long(testF)) - - + ' calc time constants + msec_001 := CLKFREQ / 1_000 ' ticks in 1ms + usec_001 := CLKFREQ / 1_000_000 ' ticks in 1us + tm_64usec := usec_001 * 64 + debug("- times: ", sdec_long(usec_001), sdec_long(tm_64usec)) + + panelCt := screen.MAX_PANELS + dvrConfig, driverConfigRaw := screen.getDriverFlags() + debug("- Driver CONFIG ", ubin_word(driverConfigRaw)) + debug("- Driver CONFIG ", ubin_word(dvrConfig)) + if driverConfigRaw == screen.CHIP_FM6126A + debug("----> FM6126A") + elseif driverConfigRaw == screen.CHIP_MBI5124_8S + debug("----> MBI5124-8S") + elseif driverConfigRaw == screen.CHIP_FM6124 or driverConfigRaw == screen.CHIP_UNK_LAT_END_ENCL + if driverConfigRaw == screen.CHIP_FM6124 + debug("----> FM6124") + elseif driverConfigRaw == screen.CHIP_ICN2037 or driverConfigRaw == screen.CHIP_UNK_LAT_END_ENCL_SLO_CLK + if driverConfigRaw == screen.CHIP_ICN2037 + debug("----> ICN2037") + debug("----> ", udec_(panelCt), " panel(s)") + + + driverFlags := dvrConfig & $ff00 + ' if following flags are set... + modeOverlapDAT := (driverFlags & screen.LAT_POSN_OVERLAP) <> 0 ? True : False + modeLatchEnclosed := (driverFlags & screen.LAT_STYLE_OFFSET) <> 0 ? False : True + bInitPanel := (driverFlags & screen.INIT_PANEL_REQUIRED) <> 0 ? True : False + modeSlowCLK := (driverFlags & screen.CLK_WIDE_PULSE) <> 0 ? True : False + ' post value of panel needing swap so we can do correct color fixes + bSwapRB := (driverFlags & screen.RB_SWAP) > 0 ? True : False + ' post value of our need to alter our scan from 1/16, 1/32 to 1/8 + bScan_1_4 := (driverFlags & screen.SCAN_4) > 0 ? True : False + + debug("- Driver CONFIG (intrp) ", ubin_word(dvrConfig)) + debug(" -- ", ubin_word(driverFlags)) + debug(" -- ", ubin_byte(modeOverlapDAT)) + debug(" -- ", ubin_byte(modeLatchEnclosed)) + debug(" -- ", ubin_byte(bInitPanel)) + debug(" -- ", ubin_byte(modeSlowCLK)) + debug(" -- ", ubin_byte(bSwapRB)) + debug(" -- ", ubin_byte(bScan_1_4)) ' when using a panel w/FM6126A chips we have to issue a reset! ' before attempting to use the panel - if screen.PANEL_DRIVER_CHIP == screen.CHIP_FM6126A - debug("- have FM6126A") - overlappedLatch := TRUE + if bInitPanel setupPins() - resetPanel() - else - debug("- have OTHER") - overlappedLatch := FALSE + if driverConfigRaw == screen.CHIP_MBI5124_8S + resetPanel5124() + else + resetPanel() ' configure our driver - bSetLowPins := FALSE case screen.ADAPTER_BASE_PIN screen.PIN_GROUP_P0_P15: debug("- I/O P00 - P15") bSetLowPins := TRUE - usingPortA := TRUE + modeUsePortA := TRUE screen.PIN_GROUP_P16_P31: debug("- I/O P16 - P31") - usingPortA := TRUE + bSetLowPins := FALSE + modeUsePortA := TRUE screen.PIN_GROUP_P32_P47: debug("- I/O P32 - P47") bSetLowPins := TRUE - usingPortA := FALSE + modeUsePortA := FALSE screen.PIN_GROUP_P48_P63: debug("- I/O P48 - P63") - usingPortA := FALSE + bSetLowPins := FALSE + modeUsePortA := FALSE if bSetLowPins - maskAddr := %00000000_00000000_00000000_01111000 ' pins at 00-15 A-pins - maskRgb12 := %00000000_00000000_00111111_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 00-15 A-pins - maskAllPins := %00000000_00000000_00111111_01111111 ' adds new E addr bit (off for now) - pins at 00-15 A-pins - addrValue1 := $0000_0008 ' 1 but in upper 5-bits of byte - addrValue15 := $0000_0078 ' 15 but in upper 5-bits of byte + if screen.PANEL_ADDR_LINES == screen.ADDR_ABCDE + maskAllPins := %00000000_00000000_00111111_11111111 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_00000000_00000000_11111000 ' pins at 00-15 A/B-pins + addrValueMax := $0000_00F8 ' 31 but in upper 5-bits of byte + rowCtrMax := 32 + elseif screen.PANEL_ADDR_LINES == screen.ADDR_ABCD + maskAllPins := %00000000_00000000_00111111_01111111 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_00000000_00000000_01111000 ' pins at 00-15 A/B-pins + addrValueMax := $0000_0078 ' 15 but in upper 5-bits of byte + rowCtrMax := 16 + else ' == screen.ADDR_ABC + maskAllPins := %00000000_00000000_00111111_00111111 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_00000000_00000000_00111000 ' pins at 00-15 A/B-pins + addrValueMax := $0000_0038 ' 7 but in upper 5-bits of byte + rowCtrMax := 8 + maskRgb12 := %00000000_00000000_00111111_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 00-15 A/B-pins + addrValue1 := $0000_0008 ' 1 but in upper 5-bits of byte + modeDatRotLeft := TRUE else - maskAddr := %00000000_01111000_00000000_00000000 ' pins at 16-31 A-pins - maskRgb12 := %00111111_00000000_00000000_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 16-31 A-pins - maskAllPins := %00111111_01111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A-pins - addrValue1 := $0008_0000 ' 1 but in upper 5-bits of byte - addrValue15 := $0078_0000 ' 15 but in upper 5-bits of byte - - debug("- ", ubin_long(maskAddr)) - debug("- ", ubin_long(maskRgb12)) - debug("- ", ubin_long(maskAllPins)) - debug("- ", uhex_long(addrValue1)) - debug("- ", uhex_long(addrValue15)) + if screen.PANEL_ADDR_LINES == screen.ADDR_ABCDE + maskAllPins := %00111111_11111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_11111000_00000000_00000000 ' pins at 16-31 A/B-pins + addrValueMax := $00F8_0000 ' 31 but in upper 5-bits of byte + rowCtrMax := 32 + elseif screen.PANEL_ADDR_LINES == screen.ADDR_ABCD + maskAllPins := %00111111_01111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_01111000_00000000_00000000 ' pins at 16-31 A/B-pins + addrValueMax := $0078_0000 ' 15 but in upper 5-bits of byte + rowCtrMax := 16 + else ' == screen.ADDR_ABC + maskAllPins := %00111111_00111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + maskAddr := %00000000_00111000_00000000_00000000 ' pins at 16-31 A/B-pins + addrValueMax := $0038_0000 ' 7 but in upper 5-bits of byte + rowCtrMax := 8 + maskRgb12 := %00111111_00000000_00000000_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 16-31 A/B-pins + addrValue1 := $0008_0000 ' 1 but in upper 5-bits of byte + modeDatRotLeft := FALSE + if screen.MAX_PWM_SUBPAGES > 0 + rowCtrMax /= screen.MAX_PWM_SUBPAGES + + ' set width of one row + colCtrMax := screen.MAX_PHYSICAL_COLUMNS + if bScan_1_4 + colCtrMax := screen.MAX_PHYSICAL_COLUMNS * 2 + colCtrMaxLngs := colCtrMax / 4 + colCtrLatchCt := (modeOverlapDAT) ? colCtrMax - 3 : colCtrMax ' for the setup form of the driver we latch during last three columns + debug("* Driver: ", udec(rowCtrMax), udec(colCtrMax), udec(colCtrMaxLngs)) + +{ + ' test mask off rgb1 or rgb2 in ABCDE case (testing matrix) + if bSetLowPins + if screen.PANEL_ADDR_LINES == screen.ADDR_ABCDE + maskAllPins := %00000000_00000000_00111000_11111111 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + 'maskAllPins := %00000000_00000000_00000111_11111111 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + else + if screen.PANEL_ADDR_LINES == screen.ADDR_ABCDE + maskAllPins := %00111000_11111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins + 'maskAllPins := %00000111_11111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins +'} + 'debug("- ", ubin_long(maskAddr)) + 'debug("- ", ubin_long(maskRgb12)) + 'debug("- ", ubin_long(maskAllPins)) + 'debug("- ", uhex_long(addrValue1)) + 'debug("- ", uhex_long(addrValueMax)) + + tmpVar := screen.MAX_COG_BUFFER_SIZE_IN_LONGS + 'debug("- COG Buffer in Longs ", udec_long_(tmpVar)) + tmpVar := screen.MAX_PWM_SUBPAGES + 'debug("- # PWM SubPages ", udec_long_(tmpVar)) ' pass values to our driver ptrCommand := @dvrCommand @@ -209,9 +283,16 @@ PUB stop() pinclear(MTX_CTL_PINS) ' -------------------------------------------------------------------------------------------------- -PUB fillPanel(color) | cValue - '' Request that driver fill the buffer with {color} value - cValue := 0 #> color <# 7 +PUB fillPanel(color3bit) | cValue, redBit, greenBit, blueBit + '' Request that driver fill the buffer with {3bitColor} value (no PWM) + cValue := 0 #> color3bit <# 7 + if bSwapRB + ' if our driver says Red and Blue are swapped let's do so! + redBit := (cValue & color.BASE_RED) > 0 ? 1 : 0 + greenBit := (cValue & color.BASE_GREEN) > 0 ? 1 : 0 + blueBit := (cValue & color.BASE_BLUE) > 0 ? 1 : 0 + cValue := (redBit << 2) | (greenBit << 1) | blueBit + dvrArgument := cValue ' set color value of BLACK dvrCommand := CMD_FILL_COLOR repeat while (dvrCommand <> CMD_DONE) @@ -227,6 +308,7 @@ PUB writeBuffer(pBuffer) repeat while (dvrCommand <> CMD_DONE) PUB writePwmBuffer(pBuffer) + 'debug("- r3b:wrtPwmBuffer ") '' Request that driver copy each buffer of PWM bufferSet to its buffer and display it dvrArgument := pBuffer dvrCommand := CMD_SHOW_PWM_BUFFER @@ -235,6 +317,7 @@ PUB writePwmBuffer(pBuffer) PRI setupPins() ' configure Matrix Panel HUB75 pins + debug("* Driver Set up Pins") ' Enable all comm & address pins as outputs, set default states: PINLOW(MTX_LED_PIN_CLK) PINLOW(MTX_LED_PIN_LATCH) @@ -242,49 +325,18 @@ PRI setupPins() PINLOW(MTX_ROW_ADDR_PINS) PINLOW(MTX_COLOR_PINS) -PRI dbgMemDump(bfrId, buffer, len) | bytBffr, colIdx, rowIdx, maxCol, maxRow, dispLen - '' Dump bytes in hex format to debug() terminal - debug("`temp 13 '", zstr_(bfrId), ": bffr=", uhex_long_(buffer), "(", udec_(len), ")' 13") - maxCol := len >= 16 ? 15 : len - maxRow := (len / 16) - if maxRow * 16 < len - maxRow++ - if maxRow == 0 - maxRow := 1 - - bytBffr := buffer - waitus(35) - 'returns - dispLen := 0 - repeat rowIdx from 1 to maxRow - if rowIdx < 10 - debug("`temp ' '") ' space - debug("`temp ' ", uhex_long_(bytBffr), ": '") - repeat colIdx from 0 to maxCol - debug("`temp '", uhex_byte_(byte[bytBffr+colIdx]), " '") - dispLen++ - if dispLen >= len - quit - if colIdx == 7 - debug("`temp ' '") ' space - - bytBffr += 16 - debug("`temp 13") ' newline - waitus(85) ' 50 too short, 70 less issue, 75 better, - waitms(1) ' -------------------------------------------------------------------------------------------------- -PRI resetPanel() | pinIdx, groupIdx +PRI resetPanelOld() | columnIdx, bitIdx, panelIdx + debug("* Driver FM6126A Init") ' write the required init sequence to our panel drivers ' REF: https://www.gitmemory.com/issue/mrfaptastic/ESP32-RGB64x32MatrixPanel-I2S-DMA/23/665659409 ' 64 & 128 do not appear to be different?? - 64: 1x panel, 128: 2x panels, etc. - PINHIGH(MTX_LED_PIN_OE) - PINLOW(MTX_LED_PIN_LATCH) - PINLOW(MTX_LED_PIN_CLK) + ' Control Register 0 - LE w/10? clocks (FM6127!) ' Control Register 1 - LE w/11 clocks ' Control Register 2 - LE w/12 clocks @@ -315,17 +367,93 @@ PRI resetPanel() | pinIdx, groupIdx ' int C12[16] = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // HIGH *NOTE* from https://github.com/2dom/PxMatrix/blob/master/PxMatrix.h#L372 ' int C12[16] = {0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1}; // LOW ' int C13[16] = {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0}; + ' send data to Control Register 11 + + ' REF: https://gitlab.infra4future.de/lukas/pixelflut-rgb-matrix-server/-/blob/master/lib/framebuffer.cc (Ex code) + ' REF: + ' + ' Register 1 + ' 11111111 11001110 default + ' |||||||| ||||||||- Low Gray Compensation Bit 0 (0-7, default 4) (default 0) + ' |||||||| |||||||-- Output enable 1=On, 0=Off (default 1) + ' |||||||| ||||||--- Intensity Bit 0 (15-63, default 63) (default 1) + ' |||||||| |||||---- Intensity Bit 1 (15-63, default 63) (default 1) + ' |||||||| ||||----- Inflection Point Bit 0 (0-7, default 4) (default 0) + ' |||||||| |||------ Inflection Point Bit 1 (0-7, default 4) (default 0) + ' |||||||| ||------- Inflection Point Bit 2 (0-7, default 4 (FM6126=6)) (default 1) + ' |||||||| |-------- Intensity Bit 2 (15-63, default 63) (default 1) + ' + ' ||||||||---------- Intensity Bit 3 (15-63, default 63) (default 1) + ' |||||||----------- Intensity Bit 4 (15-63, default 63) (default 1) + ' ||||||------------ Intensity Bit 5 (15-63, default 63) (default 1) + ' |||||------------- Lower Blanking Level #1 Bit 0 (0-15, default 15) (default 1) + ' ||||-------------- Lower Blanking Level #1 Bit 1 (0-15, default 15) (default 1) + ' |||--------------- Lower Blanking Level #1 Bit 2 (0-15, default 15) (default 1) + ' ||---------------- Lower Blanking Level #1 Bit 3 (0-15, default 15) (default 1) + ' |----------------- First Line of Dark Compensation Bit 4 (0-15, default 8) (default 1) + ' + ' Register 2 + ' 11111000 01100010 default red + ' 11110000 01100010 default green + ' 11101000 01100010 default blue + ' |||||||| ||||||||- Low Gray Compensation Bit 1 (0-7, default 4) (default 0) + ' |||||||| |||||||-- Low Gray Compensation Bit 2 (0-7, default 4) (default 1) + ' |||||||| ||||||--- SDO Output delay 1=On, 0=Off (Default 0) + ' |||||||| |||||---- Lower Blanking Level #2 (0-1, default 0) + ' |||||||| ||||----- Ghosting Enhancement (0=off*, 1=on) + ' |||||||| |||------ Always 1 + ' |||||||| ||------- LE Data latch 1=On, 0=Off (Default 1) + ' |||||||| |-------- Always 0 + ' + ' ||||||||---------- First Line of Dark Compensation Bit 0 (0-15, default 8) (default 0) + ' |||||||----------- First Line of Dark Compensation Bit 1 (0-15, default 8) (default 0) + ' ||||||------------ First Line of Dark Compensation Bit 2 (0-15, default 8) (default 0) + ' |||||------------- OE Delay Bit 0 + ' ||||-------------- OE Delay Bit 1 (0-3, default red=3, green=2, blue=1) + ' |||--------------- Always 1 + ' ||---------------- Always 1 + ' |----------------- Always 1 + ' + ' Register 3 + ' 00011111 00000000 default + ' |||||||| ||||||||- Always 0 + ' |||||||| |||||||-- Always 0 + ' |||||||| ||||||--- Always 0 + ' |||||||| |||||---- Always 0 + ' |||||||| ||||----- Always 0 + ' |||||||| |||------ Always 0 + ' |||||||| ||------- Always 0 + ' |||||||| |-------- Always 0 + + ' ||||||||---------- Always 1 + ' |||||||----------- Always 1 + ' ||||||------------ Always 1 + ' |||||------------- Always 1 + ' ||||-------------- Always 1 + ' |||--------------- Always 0 + ' ||---------------- Bad Pixel Elimination 1=On 0=Off* + ' |----------------- Always 0 + + + + ' FM6126A LED Driver chips are 16 channels wide (so we are configuring using bitIdx=0-15) + ' for register 11 we set bit0 to low, rest of bits high indicating panel should be at 100% brightness + ' for register 12, we set bit9 to high indicating panel should be enabled + ' + PINHIGH(MTX_LED_PIN_OE) + PINLOW(MTX_LED_PIN_LATCH) + PINLOW(MTX_LED_PIN_CLK) - ' send data to Control Register 11 - repeat pinIdx from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 - groupIdx := pinIdx // 16 - if groupIdx == 0 + ' TRY #1 1 seq accross both boards + repeat columnIdx from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 + bitIdx := columnIdx // 16 + if bitIdx == 0 PINLOW(MTX_COLOR_PINS) else PINHIGH(MTX_COLOR_PINS) - ' mark the data - if pinIdx > (screen.MAX_PHYSICAL_COLUMNS - 12) + ' mark the data: drive latch during last 11 columns + if columnIdx > (screen.MAX_PHYSICAL_COLUMNS - (11+1)) PINHIGH(MTX_LED_PIN_LATCH) else PINLOW(MTX_LED_PIN_LATCH) @@ -336,17 +464,20 @@ PRI resetPanel() | pinIdx, groupIdx ' end reg 11 setup PINLOW(MTX_LED_PIN_LATCH) + 'waitms(1) ' send data to Control Register 12 - repeat pinIdx from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 - groupIdx := pinIdx // 16 - if groupIdx <> 9 + repeat columnIdx from 0 to screen.MAX_PHYSICAL_COLUMNS - 1 + bitIdx := columnIdx // 16 + 'if bitIdx <> 9 + 'if bitIdx <> 9 and bitIdx <> 6 + if bitIdx <> 9 PINLOW(MTX_COLOR_PINS) else PINHIGH(MTX_COLOR_PINS) - ' mark the data - if pinIdx > (screen.MAX_PHYSICAL_COLUMNS - 13) + ' mark the data: drive latch during last 12 columns + if columnIdx > (screen.MAX_PHYSICAL_COLUMNS - (12+1)) PINHIGH(MTX_LED_PIN_LATCH) else PINLOW(MTX_LED_PIN_LATCH) @@ -357,7 +488,165 @@ PRI resetPanel() | pinIdx, groupIdx ' end reg 12 setup PINLOW(MTX_LED_PIN_LATCH) + + ' end the setup effort PINLOW(MTX_LED_PIN_OE) + 'waitms(2) + +PRI resetPanel5124() + ' see datasheet + debug("* Driver missing MBI5124 init") + +PRI resetPanel() + debug("* Driver FM6126A Init") + + org + ' init control pins + drvl #MTX_ROW_ADDR_PINS + drvl #MTX_LED_PIN_A + drvl #MTX_COLOR_PINS + drvh #MTX_LED_PIN_OE + drvl #MTX_LED_PIN_OE + drvh #MTX_LED_PIN_OE + drvl #MTX_LED_PIN_LATCH + drvl #MTX_LED_PIN_CLK + ' execute init sequence - write reg #11 + xor columnIdx, columnIdx + rep @.end11,#screen.MAX_PHYSICAL_COLUMNS + mov bitIdx, columnIdx + and bitIdx, #$0F wz + waitx #6 ' let data settle + if_z drvl #MTX_COLOR_PINS + if_nz drvh #MTX_COLOR_PINS + waitx #6 ' let data settle + ' mark the data: drive latch during last 11 columns + cmp columnIdx, #screen.MAX_PHYSICAL_COLUMNS - (11+1) wcz + if_c_or_z drvl #MTX_LED_PIN_LATCH + if_nc_and_nz drvh #MTX_LED_PIN_LATCH + waitx #6 + add columnIdx, #1 + ' clock the data + drvh #MTX_LED_PIN_CLK + waitx #511 ' 6 = 30ns, 24= + drvl #MTX_LED_PIN_CLK + waitx #500 +.end11 + ' end reg 11 setup + waitx #6 + drvl #MTX_LED_PIN_LATCH + + waitx #50 ' delay between register loads + + ' execute init sequence - write reg #12 + xor columnIdx, columnIdx + rep @.end12,#screen.MAX_PHYSICAL_COLUMNS + mov bitIdx, columnIdx + and bitIdx, #$0F + cmp bitIdx, #9 wz + waitx #6 ' let data settle + if_z drvh #MTX_COLOR_PINS + if_nz drvl #MTX_COLOR_PINS + waitx #6 ' let data settle + ' mark the data: drive latch during last 12 columns + cmp columnIdx, #screen.MAX_PHYSICAL_COLUMNS - (12+1) wcz + if_c_or_z drvl #MTX_LED_PIN_LATCH + if_nc_and_nz drvh #MTX_LED_PIN_LATCH + waitx #6 + add columnIdx, #1 + ' clock the data + drvh #MTX_LED_PIN_CLK + waitx #511 + drvl #MTX_LED_PIN_CLK + waitx #500 +.end12 + ' end reg 12 setup + waitx #6 + drvl #MTX_LED_PIN_LATCH + + ' end the setup effort + drvl #MTX_LED_PIN_OE + ret + +columnIdx long 0 +bitIdx long 0 + + end + + +PRI resetPanelOld1() + + org + ' init control pins + drvl #MTX_ROW_ADDR_PINS + drvl #MTX_LED_PIN_A + drvl #MTX_COLOR_PINS + drvh #MTX_LED_PIN_OE + drvl #MTX_LED_PIN_OE + drvh #MTX_LED_PIN_OE + drvl #MTX_LED_PIN_LATCH + drvl #MTX_LED_PIN_CLK + + ' execute init sequence - write reg #12 + xor columnIdx, columnIdx + rep @.end12,#screen.MAX_PHYSICAL_COLUMNS + mov bitIdx, columnIdx + and bitIdx, #$0F + cmp bitIdx, #9 wz + waitx #6 ' let data settle + if_z drvh #MTX_COLOR_PINS + if_nz drvl #MTX_COLOR_PINS + waitx #6 ' let data settle + ' mark the data: drive latch during last 12 columns + cmp columnIdx, #screen.MAX_PHYSICAL_COLUMNS - (12+1) wcz + if_c_or_z drvl #MTX_LED_PIN_LATCH + if_nc_and_nz drvh #MTX_LED_PIN_LATCH + waitx #6 + add columnIdx, #1 + ' clock the data + drvh #MTX_LED_PIN_CLK + waitx #511 + drvl #MTX_LED_PIN_CLK +.end12 + ' end reg 12 setup + waitx #6 + drvl #MTX_LED_PIN_LATCH + + ' execute init sequence - write reg #11 + xor columnIdx, columnIdx + rep @.end11,#screen.MAX_PHYSICAL_COLUMNS + mov bitIdx, columnIdx + and bitIdx, #$0F wz + waitx #6 ' let data settle + if_z drvl #MTX_COLOR_PINS + if_nz drvh #MTX_COLOR_PINS + waitx #6 ' let data settle + ' mark the data: drive latch during last 11 columns + cmp columnIdx, #screen.MAX_PHYSICAL_COLUMNS - (11+1) wcz + if_c_or_z drvl #MTX_LED_PIN_LATCH + if_nc_and_nz drvh #MTX_LED_PIN_LATCH + waitx #6 + add columnIdx, #1 + ' clock the data + drvh #MTX_LED_PIN_CLK + waitx #511 ' 6 = 30ns, 24= + drvl #MTX_LED_PIN_CLK +.end11 + ' end reg 11 setup + waitx #6 + drvl #MTX_LED_PIN_LATCH + + waitx #50 ' delay between register loads + + + + ' end the setup effort + drvl #MTX_LED_PIN_OE + ret + +columnIdx long 0 +bitIdx long 0 + + end DAT { driver assembly code } @@ -376,101 +665,144 @@ drive_matrix rdlong pCommmand, ptra[0] rdlong pArgument, ptra[1] - cmp usingPortA, #0 wz - if_nz or DIRA, maskAllPins ' set all of our pins to OUTPUT! for this COG - if_z or DIRB, maskAllPins ' set all of our pins to OUTPUT! for this COG + ' init buffer display counters + mov pwmFrameCt, ##0 + mov pwmSubPgCt, ##0 + mov fillSubPgCt, ##0 - drvl #MTX_LED_PIN_CLK - drvl #MTX_LED_PIN_LATCH - drvh #MTX_LED_PIN_OE ' start with panel OFF - - mov pwmFrameCt, #0 ' initial setup: NOT doing PWM - -' clear screen color - RED/GREEN - drvl #MTX_LED_PIN_R1 - drvl #MTX_LED_PIN_G1 - drvl #MTX_LED_PIN_B1 - drvl #MTX_LED_PIN_R2 - drvl #MTX_LED_PIN_G2 - drvl #MTX_LED_PIN_B2 - - ' configure our output instructions to use A or B set of pins - ' if usingPortA is FALSE... - cmp usingPortA, #0 wz + ' configure our output & dir instructions to use A or B set of pins + ' (if modeUsePortA is FALSE...) + or modeUsePortA, modeUsePortA wz + if_nz setd dirInst1of1, #DIRA if_nz setd outInst1of3, #OUTA if_nz setd outInst2of3, #OUTA if_nz setd outInst3of3, #OUTA + if_z setd dirInst1of1, #DIRB if_z setd outInst1of3, #OUTB if_z setd outInst2of3, #OUTB if_z setd outInst3of3, #OUTB + or modeDatRotLeft, modeDatRotLeft wz + if_nz SETR rotInstr1of2,#%0000001_00 'make into ROR instruction + if_nz SETR rotInstr2of2,#%0000001_00 'make into ROR instruction + if_z SETR rotInstr1of2,#%0000000_00 'make into ROL instruction + if_z SETR rotInstr2of2,#%0000000_00 'make into ROL instruction -' init row address - mov row_addr, addrValue15 ' reset address to 15 [A-D addr all ones] + or modeOverlapDAT, modeOverlapDAT wz + if_nz SETR jmpInstr1of1,#%0000000_00 'make into NOP instruction + if_nz SETD jmpInstr1of1,##0 'make into NOP instruction + + or modeSlowCLK, modeSlowCLK wz + if_z SETR waitInst1of1,#%0000000_00 'make into NOP instruction + if_z SETD waitInst1of1,##0 'make into NOP instruction + +' configure all pins +dirInst1of1 or DIRA, maskAllPins ' set all of our pins to OUTPUT! for this COG +' default to NOT using PWM + xor pwmFrameCt, pwmFrameCt ' initial setup: NOT doing PWM + +' init row address + mov row_addr, addrValueMax ' reset address to 31|15|7 - [A-E|D|C] addr: all ones ' write address call #emitAddr 'call #dumpTwinRows getCommand 'new PWM support + cmp pwmSubPgCt, #0 wz + if_nz jmp #nextPwmSubpage + cmp fillSubPgCt, #0 wz + if_nz jmp #nextFill cmp pwmFrameCt, #0 wz if_nz jmp #nextPwmFrame rdlong nxtCommand, pCommmand rdlong nxtArgument, pArgument cmp nxtCommand, #CMD_DONE wz if_z jmp #chksDone ' redraw current buffer - 'debug("* cmd=", udec_(nxtCommand), ", arg=", uhex_long_(nxtArgument)) + cmp nxtCommand,priorCommand wz + if_z jmp #chkShow + debug("* cmd=", udec_(nxtCommand), ", arg=", uhex_long_(nxtArgument)) + mov priorCommand, nxtCommand chkShow cmp nxtCommand, #CMD_SHOW_BUFFER wz if_nz jmp #chkShowPwm - call #loadBuffer + call #loadPWMsubpage 'debug(" - load done") jmp #markCmdComplete ' redraw current buffer chkShowPwm cmp nxtCommand, #CMD_SHOW_PWM_BUFFER wz if_nz jmp #chkFill - call #loadPwmBuffers + call #displayPwmFrames 'debug(" - PWM frame done") - jmp #getCommand ' check for next command (or same still there) + jmp #getCommand ' check for next command (or same still there) chkFill cmp nxtCommand, #CMD_FILL_COLOR wz - if_nz jmp #chksDone ' redraw current buffer - call #fillBuffer + if_nz jmp #chksDone ' redraw current buffer + call #fillCogBufferWithColor + wrlong #CMD_DONE, pCommmand ' signal command completed 'debug(" - fill done") - jmp #markCmdComplete ' redraw current buffer + jmp #displayCogBffrFullFrame ' redraw current buffer ' -' loadPwmBuffers(nxtArgument=hubAddressOfPWMFrameSet) +' displayPwmFrames(nxtArgument=hubAddressOfPWMFrameSet) ' -loadPwmBuffers - mov pwmBffrStart, nxtArgument ' preserve our new start address - mov pwmFrameCt, #screen.MAX_PWM_FRAMES ' set loop to PWM 8 frames then stop to see what to do next -showPwmFrame - call #loadBuffer ' load the current frame into display buffer - jmp #wrCurrent ' display it +displayPwmFrames + mov pwmBffrStart, nxtArgument ' preserve our new start address + rdfast #0,pwmBffrStart ' initialize our FIFO (#0 means no wrap!) + mov pwmFrameCt, #screen.MAX_PWM_FRAMES ' set loop to PWM N frames then stop to see what to do next nextPwmFrame - add nxtArgument,##screen.MAX_PWM_FRAME_SIZE_IN_BYTES ' point to next frame - djnz pwmFrameCt, #showPwmFrame ' have onother of the 8 to show? - mov nxtArgument, pwmBffrStart ' no point back to first of 8 buffers - ret ' loop again to see if we should do another PWM set + call #display1PwmFrame ' load the current frame into display buffer + djnz pwmFrameCt, #nextPwmFrame ' have another of the PWM N frames to show? + mov nxtArgument, pwmBffrStart ' no point back to first of N PWM frame buffers + ret ' loop again if no command, we'll do another PWM set ' -' loadBuffer(nxtArgument=hubAddressOfFrame) +' display1PwmFrame(nxtArgument=hubAddressOfFrame) ' -loadBuffer - ' copy HUB buffer pointed to by nxtArgument to display buffer - mov ptrb, nxtArgument ' get addr of HUB RAM 256-longs buffer - mov fillOffset, #0 ' set initial offset to '0' beginning of COG RAM area (screenBffr) - mov fillCount, ##screen.MAX_PWM_FRAME_SIZE_IN_LONGS ' length in longs e.g., 64x32 is 1k bytes of 6bit values +display1PwmFrame + ' set addr to start + mov row_addr, addrValueMax ' reset address to 31|15|7 [A-E|D|C addr all ones] + ' interate over PWM Frame subpages + mov pwmSubPgCt, #screen.MAX_PWM_SUBPAGES ' set loop to PWM N frames then stop to see what to do next +showPwmSubpage + call #loadPWMsubpage ' load the current frame into display buffer + jmp #wrCogBuffer ' display subpage +nextPwmSubpage + add nxtArgument,##screen.MAX_COG_BUFFER_SIZE_IN_BYTES ' point to next frame + djnz pwmSubPgCt, #showPwmSubpage ' have another of subpage of the PWM frame to show? + ret ' loop again to see if we should do another PWM set +' +' display1PwmFrame(nxtArgument=hubAddressOfFrame) +' +displayCogBffrFullFrame + ' set addr to start + mov row_addr, addrValueMax ' reset address to 31|15|7 [A-E|D|C addr all ones] + ' interate over non-PWM Frame subpages + mov fillSubPgCt, #screen.MAX_PWM_SUBPAGES ' set loop to PWM N frames then stop to see what to do next +showFill + jmp #wrCogBuffer ' display subpage +nextFill + djnz fillSubPgCt, #showFill ' have another of subpage of the PWM frame to show? + ret ' loop again to see if we should do another PWM set +' +' loadPWMsubpage(nxtArgument=hubAddressOfFrame) +' +' NOTE: use of rdfast/rflong vs. rdlong, ptrb addressing did NOT improve our timing...!!! (leavig FIFO use in place for now) +loadPWMsubpage + ' copy HUB buffer pointed to by FIFO rdfast (set earlier) + xor fillOffset, fillOffset ' set initial offset to '0' beginning of COG RAM area (cogBuffer) + mov fillCount, ##screen.MAX_COG_BUFFER_SIZE_IN_LONGS ' length in longs e.g., 64x32 is 1k bytes of 6bit values ldLoop1 - altd fillOffset, #screenBffr ' calculate addr of next register in COG - rdlong 0-0,ptrb++ ' read long from HUB RAM + altd fillOffset, #cogBuffer ' calculate addr of next register in COG + rflong 0-0 ' read long from HUB RAM via FIFO add fillOffset, #1 ' point to next register djnz fillCount, #ldLoop1 ' count this, if more to do go... ret ' done, return to caller + ' -' fillBuffer(nxtArgument=colorvalue3bit) +' fillCogBufferWithColor(nxtArgument=colorvalue3bit) ' -fillBuffer ' fill panel buffer based on desired color +fillCogBufferWithColor ' fill COG buffer with desired 3-bit color + ' first, build our color... and nxtArgument, #$07 mov fillLong, nxtArgument shl fillLong, #3 @@ -483,71 +815,71 @@ fillBuffer ' fill panel buffer based on desired color shl fillLong, #8 or fillLong, fillOffset ' 4 bytes 'debug("- (DBG) ", uhex_long(fillLong)) - call #setBuffer + ' then fill the COG buffer with the new color + call #writeColorToBuffer 'call #dumpTwinRows ret ' -' setBuffer(fillLong=fillValueID) +' writeColorToBuffer(fillLong=fillValueID) ' -setBuffer ' fill single pwm buffer with desired long value - mov fillOffset, #0 - mov fillCount, ##screen.MAX_PWM_FRAME_SIZE_IN_LONGS -nextSet - altd fillOffset, #screenBffr +writeColorToBuffer ' fill COG buffer with 'fillLong' value + xor fillOffset, fillOffset + mov fillCount, ##screen.MAX_COG_BUFFER_SIZE_IN_LONGS +writeNextLong + altd fillOffset, #cogBuffer mov 0-0, fillLong ' fill long with value add fillOffset, #1 - djnz fillCount, #nextSet + djnz fillCount, #writeNextLong ret dumpTwinRows - 'debug(" Red TL,R ", uhex_long_(screenBffr+0), ", ", uhex_long_(screenBffr+1)) - 'debug(" Red BL,R ", uhex_long_(screenBffr+62), ", ", uhex_long_(screenBffr+63)) - 'debug(" Grn TL,R ", uhex_long_(screenBffr+64), ", ", uhex_long_(screenBffr+65)) - 'debug(" Grn BL,R ", uhex_long_(screenBffr+126), ", ", uhex_long_(screenBffr+127)) - 'debug(" Blu TL,R ", uhex_long_(screenBffr+128), ", ", uhex_long_(screenBffr+129)) - 'debug(" Blu BL,R ", uhex_long_(screenBffr+190), ", ", uhex_long_(screenBffr+191)) + 'debug(" Red TL,R ", uhex_long_(cogBuffer+0), ", ", uhex_long_(cogBuffer+1)) + 'debug(" Red BL,R ", uhex_long_(cogBuffer+62), ", ", uhex_long_(cogBuffer+63)) + 'debug(" Grn TL,R ", uhex_long_(cogBuffer+64), ", ", uhex_long_(cogBuffer+65)) + 'debug(" Grn BL,R ", uhex_long_(cogBuffer+126), ", ", uhex_long_(cogBuffer+127)) + 'debug(" Blu TL,R ", uhex_long_(cogBuffer+128), ", ", uhex_long_(cogBuffer+129)) + 'debug(" Blu BL,R ", uhex_long_(cogBuffer+190), ", ", uhex_long_(cogBuffer+191)) ret chksDone cmp nxtCommand, #CMD_DONE wz - if_z jmp #wrCurrent ' redraw current buffer + if_z jmp #wrCogBuffer ' redraw current buffer 'debug("--> *ERROR* Unknown cmd(", udec_(nxtCommand), ") arg=", uhex_long_(nxtArgument)) markCmdComplete 'debug(" - unknown cmd done") wrlong #CMD_DONE, pCommmand ' signal command completed -wrCurrent - ' repeat the following forever - ' set addr to start - mov row_addr, addrValue15 ' reset address to 15 [A-D addr all ones] - mov row_ctr, #16 ' 16 -> 0 so we can use djnz - mov reg_offset, #0 ' start of [0-1023] buffer +wrCogBuffer + ' repeat the following to end of COG buffer + mov row_ctr, rowCtrMax ' 32|16|8 -> 0 so we can use djnz + xor reg_offset, reg_offset ' start of [0-1023] buffer drvl #MTX_LED_PIN_OE - ' if overlappedLatch is FALSE... - cmp overlappedLatch, #0 wz - if_z jmp #wrLatchAtEnd + + ' following instru is modified by startup to #wrLatchAtEnd or #wrLineLatchOvlp +jmpInstr1of1 jmp #wrLatchAtEnd ' -------------------------------------------------------------------------------------------------- ' the following routine is for panels that DO overlap latching with serial data bits -' for row address 0 to 15 +' so far this is ONLY panels with FM6126A wrLineLatchOvlp ' for bit 0 to 63 -' toggle clock (18MHz) +' toggle clock (28MHz) + mov reg_ctr, rowCtrMax ' 32|16|8 -> 0 so we can use djnz ' this tracks when we need to toggle latch at right-edge of row - mov reg_ctr, #16 ' 16 -> 0 so we can use djnz - mov col_addr, #0 + xor col_addr, col_addr clkNextReg ' in buffer: RGB1 is byte-bits[0-2], RGB2 is byte-bits[3-5] mov byt_ctr, #4 ' 4 -> 0 so we can use djnz - ALTS reg_offset, #screenBffr ' calc addr of source long and place in instru + ALTS reg_offset, #cogBuffer ' calc addr of source long and place in instru mov reg_value, 0-0 ' get COG register with 4 bytes of rgb1rgb2 values - ror reg_value, #8 ' YEAH, i've no idea why! but fixes our byte ordering problem! (AUGH! this change from rol -> ror with HUB75 adapter?!) +rotInstr1of2 rol reg_value, #8 ' YEAH, i've no idea why! but fixes our byte ordering problem! (AUGH! this change from rol -> ror for some panels??!) clkNextByte + ' write our 6 color bits SETQ maskRgb12 ' load Q bit w/ RGB[12] mask outInst1of3 MUXQ OUTA, reg_value ' write contents of LS-byte anded with mask to output pins - ror reg_value, #8 ' shift next most significant into LS-byte position +noDbgOvly ror reg_value, #8 ' shift next most significant into LS-byte position ' time to begin latch? - cmp col_addr, #61 wz ' at last three columns? + cmp col_addr, colCtrLatchCt wz ' at last three columns? if_z drvh #MTX_LED_PIN_OE if_z drvh #MTX_LED_PIN_LATCH @@ -582,33 +914,35 @@ outInst1of3 MUXQ OUTA, reg_value ' write contents of LS-b ' -------------------------------------------------------------------------------------------------- ' the following routine is for panels that DO NOY overlap latching with serial data bits ' -' for row address 0 to 15 wrLatchAtEnd wrLineLatchAtEnd ' for bit 0 to 63 ' toggle clock (18MHz) ' this tracks when we need to toggle latch at right-edge of row - mov reg_ctr, #16 ' 16 -> 0 so we can use djnz + mov reg_ctr, rowCtrMax ' 32|16|8 -> 0 so we can use djnz + mov col_lng_ctr, colCtrMaxLngs ' this is physical display width wide! clkNONextReg ' in buffer: RGB1 is byte-bits[0-2], RGB2 is byte-bits[3-5] mov byt_ctr, #4 ' 4 -> 0 so we can use djnz - ALTS reg_offset, #screenBffr ' calc addr of source long and place in instru + ALTS reg_offset, #cogBuffer ' calc addr of source long and place in instru mov reg_value, 0-0 ' get COG register with 4 bytes of rgb1rgb2 values - rol reg_value, #8 ' YEAH, i've no idea why! but fixes our byte ordering problem! (AUGH! this change from rol -> ror with HUB75 adapter?!) + ' the following instru is either a ROR or ROL as configured by setup code +rotInstr2of2 ror reg_value, #8 ' YEAH, i've no idea why! but fixes our byte ordering problem! (AUGH! this change from rol -> ror for some panels??!) clkNONextByte ' write our 6 color bits SETQ maskRgb12 ' load Q bit w/ RGB[12] mask outInst2of3 MUXQ OUTA, reg_value ' write contents of LS-byte anded with mask to output pins - ror reg_value, #8 ' shift next most significant into LS-byte position +noDbgAtEnd ror reg_value, #8 ' shift next most significant into LS-byte position ' toggle clock - drvh #MTX_LED_PIN_CLK ' 15nSec pulse at 335 MHz - drvl #MTX_LED_PIN_CLK + drvh #MTX_LED_PIN_CLK ' 15nSec pulse at 335 MHz +waitInst1of1 waitx #3 ' 2 + 3 x clk ' CLK pulse width min 20ns for ICN2037: 2 is ~20ns, 3 is ~25ns @330 MHz + drvl #MTX_LED_PIN_CLK ' setup for next column djnz byt_ctr, #clkNONextByte - add reg_offset, #1 - djnz reg_ctr, #clkNONextReg + add reg_offset, #1 ' point to next COG long... + djnz col_lng_ctr, #clkNONextReg ' let's latch drvh #MTX_LED_PIN_OE @@ -618,29 +952,36 @@ outInst2of3 MUXQ OUTA, reg_value ' write contents of LS-b drvh #MTX_LED_PIN_LATCH waitx #3 ' 2 + 3 x clk ' let LATCH settle - ' LATCH DATA complete... - drvl #MTX_LED_PIN_OE - drvl #MTX_LED_PIN_LATCH ' end latch data + or modeLatchEnclosed, modeLatchEnclosed wz + if_z drvl #MTX_LED_PIN_OE + if_z drvl #MTX_LED_PIN_LATCH ' end latch data + if_nz drvl #MTX_LED_PIN_LATCH ' end latch data + if_nz waitx #3 ' 2 + 3 x clk ' let LATCH settle + if_nz drvl #MTX_LED_PIN_OE + ' ' --- inter-line gap --- ' + 'waitx #6 djnz row_ctr, #wrLineLatchAtEnd drvh #MTX_LED_PIN_OE ' ' --- inter-frame gap --- ' - ' EXPERIMENT: can we get better brightness range if we stall for a full frame at the end of each frame? - waitx ##TM_64US +' cmp pwmFrameCt,#1 wz +' if_nz jmp #getCommand +' cmp pwmSubPgCt,#1 wz + ' if_z waitx #tm_64usec jmp #getCommand ' -------------------------------------------------------------------------------------------------- ' subroutines ' emitAddr - SETQ maskAddr ' load Q with w/ Address[A-D] mask + SETQ maskAddr ' load Q with w/ Address[A-C|D|E] mask outInst3of3 MUXQ OUTA, row_addr ' but in upper 5-bits of ls byte of 31-0 depending upon pingroup - waitx #3 + waitx #3 ' 2 + 3 x clk let ADDR settle ret ' Dummy ISR routines in case we need them @@ -662,33 +1003,48 @@ isr3 ' -------------------------------------------------------------------------------------------------- ' The following variables are poulated from the initialization SPIN code before this driver starts ' -usingPortA long FALSE -overlappedLatch long FALSE +' Driver Config Values +modeUsePortA long FALSE ' T/F where T means we are using portA vs. portB +modeOverlapDAT long FALSE ' T/F where T means LATCH_OVERLAPPED, F means LATCH_AFTER +modeLatchEnclosed long FALSE ' T/F where T means LATCH_ENCLOSED, F means LATCH_OFFSET +modeDatRotLeft long FALSE ' T/F where T means ROR, F means ROL +modeSlowCLK long FALSE ' T/F where T means add waitx to slow clock, F means no use of waitx + +msec_001 long 0 ' ticks in 1ms +usec_001 long 0 ' ticks in 1us + +tm_64usec long 0 + ' the follwing are I/O pin masks and data values we use for our primary I/O -maskAddr long %00000000_01111000_00000000_00000000 ' pins at 16-31 A-pins -maskRgb12 long %00111111_00000000_00000000_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 16-31 A-pins -maskAllPins long %00111111_01111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A-pins +maskAddr long %00000000_01111000_00000000_00000000 ' pins at 16-31 A/B-pins +maskRgb12 long %00111111_00000000_00000000_00000000 ' rgb2rgb1 now grounded to lsbit - pins at 16-31 A/B-pins +maskAllPins long %00111111_01111111_00000000_00000000 ' adds new E addr bit (off for now) - pins at 16-31 A/B-pins ' PINS A 00-15 USE $0000_0008 ' PINS A 16-31 USE $0008_0000 ' PINS B 32-47 USE $0000_0008 ' PINS B 48-63 USE $0008_0000 -addrValue1 long $0008_0000 ' 1 but in upper 5-bits of byte +addrValue1 long $0008_0000 ' 1 but in upper 5-bits of byte ' PINS A 00-15 USE $0000_0078 ' PINS A 16-31 USE $0078_0000 ' PINS B 32-47 USE $0000_0078 ' PINS B 48-63 USE $0078_0000 -addrValue15 long $0078_0000 ' 15 but in upper 5-bits of byte +addrValueMax long $0078_0000 ' 15 but in upper 5-bits of byte ' +rowCtrMax long 16 ' 16 rows total +colCtrMax long 64 ' 64 columns total +colCtrMaxLngs long 16 ' 64 cols = 16 longs total +colCtrLatchCt long 61 ' colCtrMax-3 columns total + ' -------------------------------------------------------------------------------------------------- 'screen buffer 1024B of %00bgrbgr where byte is 00{rgb2}{rgb1} ALIGNL -screenBffr +cogBuffer ' test compiling 2kB LUT use for 256x64 display - long 0[screen.MAX_PWM_FRAME_SIZE_IN_LONGS] -endScreenBffr + long 0[screen.MAX_COG_BUFFER_SIZE_IN_LONGS] +endCogBuffer ' UNINITIALIZED data ' @@ -696,10 +1052,13 @@ endScreenBffr pCommmand res 1 pArgument res 1 +priorCommand res 1 nxtCommand res 1 nxtArgument res 1 pwmBffrStart res 1 pwmFrameCt res 1 +pwmSubPgCt res 1 +fillSubPgCt res 1 fillBffr res 1 ' ptr to single PWM frame sized buffer buffer -- long: where bits of each byte are 'x x B2 G2 R2 G1 B1 R1' fillLong res 1 ' value to write to each long @@ -708,7 +1067,7 @@ fillOffset res 1 ' offset into fillBffr reg_offset res 1 reg_value res 1 -byt_ctr res 1 +byt_ctr res 1 dbgBffr res 1 dbgCount res 1 @@ -716,8 +1075,9 @@ dbgCount res 1 row_addr res 1 row_ctr res 1 col_addr res 1 +col_lng_ctr res 1 reg_ctr res 1 - +' FIT 496 diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenAccess.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenAccess.spin2 index 1a8db567..08d7abf2 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenAccess.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenAccess.spin2 @@ -13,6 +13,8 @@ CON { reinterpret the users selections for driver internal use } + ' interface forwarding so driver-internal objects don't know of the hwGeometry file! + ' possible Adapter Connections PIN_GROUP_P0_P15 = user.PINS_P0_P15 PIN_GROUP_P16_P31 = user.PINS_P16_P31 @@ -22,35 +24,71 @@ CON { reinterpret the users selections for driver internal use } ' the user-selected location ADAPTER_BASE_PIN = user.ADAPTER_BASE_PIN + ' chip types CHIP_UNKNOWN = user.CHIP_UNKNOWN + CHIP_MANUAL_SPEC = user.CHIP_MANUAL_SPEC CHIP_FM6126A = user.CHIP_FM6126A + CHIP_FM6124 = user.CHIP_FM6124 + CHIP_ICN2037 = user.CHIP_ICN2037 + CHIP_MBI5124_8S = user.CHIP_MBI5124_8S + CHIP_UNK_LAT_END_ENCL = user.CHIP_UNK_LAT_END_ENCL + CHIP_UNK_LAT_END_ENCL_SLO_CLK = user.CHIP_UNK_LAT_END_ENCL_SLO_CLK + + LAT_STYLE_OFFSET = user.LAT_STYLE_OFFSET + LAT_POSN_OVERLAP = user.LAT_POSN_OVERLAP + INIT_PANEL_REQUIRED = user.INIT_PANEL_REQUIRED + CLK_WIDE_PULSE = user.CLK_WIDE_PULSE + CLK_WIDE_PULSE = user.CLK_WIDE_PULSE + RB_SWAP = user.RB_SWAP + SCAN_4 = user.SCAN_4 ' which chip driver should be used PANEL_DRIVER_CHIP = user.PANEL_DRIVER_CHIP + ' address ranges + ADDR_UNKNOWN = user.ADDR_UNKNOWN + ADDR_ABC = user.ADDR_ABC + ADDR_ABCD = user.ADDR_ABCD + ADDR_ABCDE = user.ADDR_ABCDE + + ' how many address lines are being used + PANEL_ADDR_LINES = user.PANEL_ADDR_LINES + ' how big is each panel MAX_PANEL_ROWS = user.MAX_PANEL_ROWS MAX_PANEL_COLUMNS = user.MAX_PANEL_COLUMNS - ' how big is our overall display - MAX_DISPLAY_COLUMNS = user.MAX_DISPLAY_COLUMNS - MAX_DISPLAY_ROWS = user.MAX_DISPLAY_ROWS - ' how many panels are connected MAX_PANELS = user.MAX_PANELS + MAX_PANELS_PER_ROW = user.MAX_PANELS_PER_ROW + MAX_PANELS_PER_COLUMN = user.MAX_PANELS_PER_COLUMN + + ' how big is our overall display + MAX_DISPLAY_COLUMNS = MAX_PANELS_PER_ROW * MAX_PANEL_COLUMNS + MAX_DISPLAY_ROWS = MAX_PANELS_PER_COLUMN * MAX_PANEL_ROWS ' we have to generate clocks and latching based on physical size of hardware - ' the larger of the values DISPLAY* or PANEL* is our proxy for PHYSICAL size - ' this allows us to have a display smaller than 1 panel should we wish! - MAX_PHYSICAL_COLUMNS = (MAX_DISPLAY_COLUMNS > MAX_PANEL_COLUMNS) ? MAX_DISPLAY_COLUMNS : MAX_PANEL_COLUMNS - MAX_PHYSICAL_ROWS = (MAX_DISPLAY_ROWS > MAX_PANEL_ROWS) ? MAX_DISPLAY_ROWS : MAX_PANEL_ROWS + MAX_PHYSICAL_COLUMNS = MAX_DISPLAY_COLUMNS + MAX_PHYSICAL_ROWS = MAX_DISPLAY_ROWS ' what is our PWM frame size MAX_PWM_FRAME_SIZE_IN_BYTES = ((MAX_PHYSICAL_COLUMNS * MAX_PHYSICAL_ROWS) / 2) MAX_PWM_FRAME_SIZE_IN_LONGS = MAX_PWM_FRAME_SIZE_IN_BYTES / 4 - ' how many PWM frames does our DRIVER use? + ' driver COG internal buffer size + MAX_COG_BUFFER_SIZE_IN_BYTES = 1024 + MAX_COG_BUFFER_SIZE_IN_LONGS = MAX_COG_BUFFER_SIZE_IN_BYTES / 4 + + ' how many PWM frames/subpages does our DRIVER use? + ' -------------------------------------------------------------------------- + ' NOTE: a PWM frame can be larger than our COG buffer size (1 kBytes.) + ' When it is, the driver thinks of each PWM frame as being composed of + ' a sequential list of 1kB subpages + ' -------------------------------------------------------------------------- + ' MAX_PWM_FRAMES = 16 ' compiled color depth + ' this then is the count of subpages within a single PWM frame + MAX_PWM_SUBPAGES = MAX_PWM_FRAME_SIZE_IN_LONGS / MAX_COG_BUFFER_SIZE_IN_LONGS DISPLAY_BITS_PER_COLOR = 24 PANEL_BITS_PER_COLOR = 3 @@ -59,6 +97,32 @@ CON { reinterpret the users selections for driver internal use } DISPLAY_BYTES_PER_COLOR = DISPLAY_BITS_PER_COLOR / 8 ' (rounded up to fill a full long - leaves 0-3 bytes unused at end) + ' -------------------------------------------------------------------------- + ' NOTE: the display buffer contains 3 bytes for each pixel (for R,G, and B.) + ' a single PWM frame is 1/6 the size and contains 1 byte for every 2 pixels. + ' + ' However the bottom half of the display is overlapped with the top half so + ' we can send both values at the same time. + ' In other woard the RGB1 value for the pixel is in the same byte as the RGB2 + ' value a half-panel further down in the display. + ' + ' e.g., for a 64x32 panel the byte containing the RGB1 values for the pixel at + ' the top-left of the panel (row 0, col 0) also contains the RGB2 value for the + ' pixel mid-way down the panel (row 16, col 0.) + ' + ' so, in review let's say we have a 64x32 panel: + ' Number Pixels: 64x32 = 2048 (2k Pixels) + ' Display buffer: 2048x3 = 6144 (6k Bytes) + ' PWM Buffer: 6144/6 = 1024 (1k Bytes) + ' but we in this driver version,, we have 16 PWM buffers so our buffer + ' space is 6kB + 1kB * 16 (16kB) = 22k Bytes total of static buffer for a + ' single 64x32 pixel panel. + ' + ' NOTE: the next panel type we are adding is a 1/8 scan panel meaning 4 lines + ' of pixels are written for each line. This was 2 lines (RGB1, RGB2) but in + ' this case we now write two pixels data for each column. + ' -------------------------------------------------------------------------- + ' DISPLAY_SIZE_IN_BYTES = (((MAX_DISPLAY_COLUMNS * MAX_DISPLAY_ROWS * DISPLAY_BYTES_PER_COLOR) + 3) / 4) * 4 DISPLAY_SIZE_IN_LONGS = (DISPLAY_SIZE_IN_BYTES / 4) @@ -84,9 +148,25 @@ PUB screenAddress() : pScreen '' Return the address of the external screen buffer pScreen := pExtScreen +PUB getDriverFlags() : desiredFlags, origFlags + desiredFlags := origFlags := PANEL_DRIVER_CHIP + if desiredFlags == CHIP_FM6126A + desiredFlags := CHIP_MANUAL_SPEC | LAT_POSN_OVERLAP | LAT_STYLE_OFFSET | INIT_PANEL_REQUIRED + elseif desiredFlags == CHIP_MBI5124_8S + desiredFlags := CHIP_MANUAL_SPEC | CHIP_UNK_LAT_END_ENCL | SCAN_4 | INIT_PANEL_REQUIRED + elseif desiredFlags == CHIP_FM6124 or desiredFlags == CHIP_UNK_LAT_END_ENCL + if desiredFlags == CHIP_FM6124 + elseif desiredFlags == CHIP_ICN2037 or desiredFlags == CHIP_UNK_LAT_END_ENCL_SLO_CLK + if desiredFlags == CHIP_ICN2037 + desiredFlags := CHIP_MANUAL_SPEC | CLK_WIDE_PULSE | RB_SWAP + elseif desiredFlags & $ff <> CHIP_MANUAL_SPEC + ' report ERROR and exit + debug("- have unknown CHIP ", ubin_word(desiredFlags)) + abort + PUB dbgMemDump(bfrId, buffer, len) | bytBffr, colIdx, rowIdx, maxCol, maxRow, dispLen '' Dump bytes in hex format to debug() terminal - debug("`temp 13 '", zstr_(bfrId), ": bffr=", uhex_long_(buffer), "(", udec_(len), ")' 13") + debug("`temp '", zstr_(bfrId), ": bffr=", uhex_long_(buffer), "(", udec_(len), ")' 13") maxCol := len >= 16 ? 15 : len maxRow := (len / 16) if maxRow * 16 < len diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenUtils.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenUtils.spin2 index 289973ae..8cd31f72 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenUtils.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_screenUtils.spin2 @@ -36,9 +36,9 @@ PUB drawPixelAtRC(row, column, rgbColor) | xlatedColor, fHue PUB drawPixelAtRCwithRGB(row, column, red, green, blue) | rowIndex, columnIndex, colorOffset, pColor, pScreen '' Place r,g,b color pixel at r,c - rowIndex := 0 #> row <# screen.MAX_DISPLAY_ROWS - 1 - columnIndex := 0 #> column <# screen.MAX_DISPLAY_COLUMNS - 1 - colorOffset := ((rowIndex * screen.MAX_DISPLAY_COLUMNS) + columnIndex) * screen.DISPLAY_BYTES_PER_COLOR + rowIndex := 0 #> row <# screen.MAX_PHYSICAL_ROWS - 1 + columnIndex := 0 #> column <# screen.MAX_PHYSICAL_COLUMNS - 1 + colorOffset := ((rowIndex * screen.MAX_PHYSICAL_COLUMNS) + columnIndex) * screen.DISPLAY_BYTES_PER_COLOR pScreen := screen.screenAddress() pColor := @byte[pScreen][colorOffset] 'if isDebugLocn(rowIndex, columnIndex) diff --git a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_scrollingText.spin2 b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_scrollingText.spin2 index 8496a867..29955bc2 100644 --- a/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_scrollingText.spin2 +++ b/libraries/community/p2/All/isp_hub75_matrix/isp_hub75_scrollingText.spin2 @@ -28,7 +28,7 @@ MAX_SCROLL_CHAR_LONGS = (MAX_SCROLL_CHAR_BYTES / 4) MAX_SCROLL_COLOR_BYTES = ((((MAX_SCROLL_COLORS_TO_BUFFER * screen.DISPLAY_BYTES_PER_COLOR) + 3) / 4) * 4) MAX_SCROLL_COLOR_LONGS = (MAX_SCROLL_COLOR_BYTES / 4) - 'DISPLAY_SIZE_IN_BYTES = (((MAX_DISPLAY_COLUMNS * MAX_DISPLAY_ROWS * DISPLAY_BYTES_PER_COLOR) + 3) / 4) * 4 + 'DISPLAY_SIZE_IN_BYTES = (((MAX_PHYSICAL_COLUMNS * MAX_PHYSICAL_ROWS * DISPLAY_BYTES_PER_COLOR) + 3) / 4) * 4 MAX_LONGS_PER_CHAR_BITMAP = 2 @@ -92,7 +92,7 @@ PUB initialize() instanceID := instanceNumber++ remainingPixToScroll := 0 isSetup := TRUE ' yes, now we are! - debug("stx:initialize() ", udec(instanceID)) + 'debug("stx:initialize() ", udec(instanceID)) PUB setFontInfo(nbrTextColumns, charWidth, charHeight, leadingGap, horizontalGap, hBitmapOffset, textFont) '' Call any time font changes - so we can keep up