{"id":884,"date":"2021-03-28T21:28:57","date_gmt":"2021-03-28T21:28:57","guid":{"rendered":"https:\/\/socmaker.com\/?p=884"},"modified":"2021-10-20T12:38:06","modified_gmt":"2021-10-20T12:38:06","slug":"display-part-2","status":"publish","type":"post","link":"https:\/\/socmaker.com\/?p=884","title":{"rendered":"Display Part 2"},"content":{"rendered":"\n<p>Last time I had (finally!) correctly initialized the display and printed ASCII text on it.  The problem I immediately ran into was the fact that 4 lines by 16 characters was not enough to display what I wanted.  A lot of the displays out there are 4 lines by 20 characters or more.  I went internet diving again.<\/p>\n\n\n\n<p>I found where someone had put the display into graphics mode, and viewed the commands used.  Looking at the data sheet, a font can be created using an array of integers that represent the dots on the display.  There are a lot of options for creating those dots.  For example Bitmap2LCD.com has a program you can download and install.  It runs as a &#8220;trial&#8221; but should give you enough information to work through the problems of your own fonts.<\/p>\n\n\n\n<p>User domsson created a 5&#215;7 font, and released it for &#8220;Use in any way you want,&#8221; at <a href=\"https:\/\/opengameart.org\/content\/ascii-bitmap-font-oldschool\" data-type=\"URL\" data-id=\"https:\/\/opengameart.org\/content\/ascii-bitmap-font-oldschool\">https:\/\/opengameart.org\/content\/ascii-bitmap-font-oldschool<\/a>.  In the &#8220;glcd&#8221; library (<a href=\"https:\/\/github.com\/andygock\/glcd\/blob\/master\/LICENSE\">https:\/\/github.com\/andygock\/glcd\/blob\/master\/LICENSE<\/a>) the 5&#215;7 font that I used (which I suspect comes from domsson) is presented, under the BSD license.  I took the domsson derived font and used it in this project.  It give us 8 lines by 16 characters on the RepRapDiscount display with the ST7920 I.C., all quite readable.  I may be able to get 20 chars across, but that will be much later.  (see the following image)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"852\" src=\"https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-1024x852.jpg\" alt=\"\" class=\"wp-image-887\" srcset=\"https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-1024x852.jpg 1024w, https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-300x250.jpg 300w, https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-768x639.jpg 768w, https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-1536x1279.jpg 1536w, https:\/\/socmaker.com\/wp-content\/uploads\/2021\/03\/GraphicLCD-2048x1705.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Graphic 5&#215;7 font on 128&#215;64 Display<\/figcaption><\/figure>\n\n\n\n<p>The previous post has quite a bit of the code for the &#8220;driver.&#8221;  This post should round it out for use either stand alone or with FreeRTOS, tailored for an ARM processor, using the ST7920 device, with an SPI port using some generic logic within the PSOC.  (See the previous post.)<\/p>\n\n\n\n<p>Following is my &#8220;driver&#8221; code for the display.   The Header file that the driver uses is inserted immediately after this code.<\/p>\n\n\n\n<p>FullGraphicsSmartDisplay.c:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n*\/\n#include \"FullGraphicSmartDisplay.h\"\n\n\/\/ only include the following code if this display is compiled \n\/\/ into the system\n#if REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER\n \nstatic char messageToST7920&#91;ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA];\n\nboolean SPIDone;\n\nstatic void clearDisplayInGraphicsMode(void);\nstatic void enableGraphics(void);\nstatic void displayStringUsingGraphicsFont(DISPLAY_TEXT_DATA_t *ddPtr);\nstatic void fillScreenInGraphicsModeFromBitmap(const uint8* BitMap);\n\n\/\/-----------------------------------------------------------------\n\/\/ currently not used.  if used may require polling by \"sendToDisplay\"\n\/\/-----------------------------------------------------------------\nCY_ISR(MasterSPIDoneInterrupt) {\n    SPIDone = pdTRUE;   \n}\n\/\/-----------------------------------------------------------------\n\/\/ Send the data byte to the display. \n\/\/  NOTE: sync and command previously placed in messageToST7920&#91;0] \n\/\/  always assume 4 bit serial interface.\n\/\/-----------------------------------------------------------------\nstatic void sendToDisplay(uint8 data){\n    messageToST7920&#91;1] = data &amp;0xf0;\/\/ supposedly lower bits can be non-zero\n    messageToST7920&#91;2] = data &lt;&lt; 4;    \n\n    taskENTER_CRITICAL();\/\/ disable interrupts  can use CyIntDisable()\n    \/\/ shut down all interrupts so\n    \/\/ we can't be swapped out while writing to the\n    \/\/ spi so the message will go out with 1 address\n    \/\/ select.\n    for (int16 i=0; i &lt; ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA; i++){\n        SPI_Master_WriteByte(messageToST7920&#91;i]);\n    }\n    taskEXIT_CRITICAL();\/\/  re-enable interrupts  can use CyIntEnable()\n    \n    \/\/ wait until display receives the command,\n    \/\/ then delay proper # of microseconds \n    while (!(SPI_Master_ReadTxStatus() &amp; SPI_Master_STS_SPI_DONE));\/\/loop until display receives command\n    \n    CyDelayUs(ST7920_STANDARD_WAIT_TIME);\/\/ wait 72us for command per ST7920 data sheet\n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ send  command to display.  Instruction\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void sendCommand(uint8 command){\n    messageToST7920&#91;0] = ST7920_SERIAL_SYNC_BITS \/\/ sync\n                    &amp; ~ST7920_SERIAL_RW_BIT  \/\/ write\n                    &amp; ~ST7920_SERIAL_RS_BIT ;\/\/ instruction (command)\n    sendToDisplay(command);\n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ send arbitrary data to display.  Data\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void sendData(uint8 data){\n            \/\/ write is a 0\n    messageToST7920&#91;0] = ST7920_SERIAL_SYNC_BITS \/\/  sync  Pattern\n                        &amp; ~ST7920_SERIAL_RW_BIT;\/\/   write Select (low for write)\n    \n    messageToST7920&#91;0]  |= ST7920_SERIAL_RS_BIT ;\/\/  data  Select (high for data)\n    \n    sendToDisplay(data);\n}\n\/\/-----------------------------------------------------------------\n\/\/ set\/reset the extended function bit in the display\n\/\/-----------------------------------------------------------------\nstatic void setExtendedFunction(int16 extended, int16 graphicsEnable) {\n    uint8 command = ST7920_EXTENDED_FIXED_BIT;\/\/ preload\n\n    \n    if (extended)\n        command |= ST7920_EXTENDED_RE_BIT;\n    \n    if (graphicsEnable)\n        command |= ST7920_ENABLE_GRAPHICS_BIT;\n    \n    sendCommand(command);\n    \n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ clear the display.  Requires a wait of at least 1.6ms\n\/\/ ST7920 data sheet page 35 states wait 10 milliseconds\n\/\/ do TaskDelay() for the wait.  This requires a value of 3,\n\/\/ because a value of 3 will provide from 2 to 3 milliseconds delay\n\/\/ due to the delay timer operating on the ARM system interrupt.\n\/\/ the call of TaskDelay() may occur a few microseconds from the\n\/\/ millisecond tick interrupt.  End result would be \n\/\/ 2 milliseconds and a few microseconds.\n\/\/\n\/\/ global, provided by all displays\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nvoid clearDisplay(TaskMonitor_t *TaskMonitorPtr) {       \n    \n    sendCommand(ST7920_CLEAR_DISPLAY_COMMAND);\n    \n    TaskDelay(ST7920_CLEAR_COMMAND_WAIT_TIME,TaskMonitorPtr);\/\/ datasheet indicates 1.6ms. delay 2 to 3 milliseconds.\n}\n\n\n\/\/-----------------------------------------------------------------\n\/\/ turn display on\/off, change cursor settings\n\/\/-----------------------------------------------------------------\nstatic void setDisplayStatus(uint16 ON,uint16 showCursor,uint16 blinkCursor) {\n    uint8 command = ST7920_BASIC_INSTRUCTION_BITS | \n                    ST7920_DISPLAY_CONTROL_BIT;\/\/ preload basic\n\n    if (ON)\n        command |= ST7920_ENABLE_DISPLAY_ON_BIT;\n\n    if (showCursor)\n        command |= ST7920_ENABLE_CURSOR_ON_BIT;\n    \n    if (blinkCursor)\n        command |= ST7920_ENABLE_BLINK_ON_BIT;\n    \n    sendCommand(command);\n}\n\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ Send the data bytes to the display.  Address was previously send\n\/\/ to display.\n\/\/ Limit ourselves to 16 bytes internally, for this ST7920 \n\/\/  controller.\n\/\/ This is Global, provided by all displays\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nvoid sendTextToDisplay(DISPLAY_TEXT_DATA_t *ddPtr){\n    \n    if (ddPtr->y >= ST7920_MAXIMUM_NUMBER_OF_LINES)\n        return; \/\/ error\n    if (ddPtr->x >= ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE )\n        return; \/\/ error\n    \n    int16 max =  ddPtr->byteCount ;\n    if (max > ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE){\n        ddPtr->byteCount=ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE;        \n    }\n    \n    for (int i=0 ; i &lt; max; i++){\n        sendData(ddPtr->data&#91;i]);\n    }  \n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ the address definitions are in FullGraphicsSmartDisplay.h\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic uint8 displayAddressesForNormalTextMode&#91;] = {\n      st7920_line1\/\/ 0x00\n     ,st7920_line2\/\/ 0x10\n     ,st7920_line3\/\/ 0x08\n     ,st7920_line4\/\/ 0x18\n};\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ send the \"set address\" command to display.\n\/\/ the address is or'd with the command bit.\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void sendLineAddressToDisplay(DISPLAY_TEXT_DATA_t *ddPtr){\n\n    \/\/ line address or'd with offset\n    uint8 add = displayAddressesForNormalTextMode&#91;ddPtr->y] | ddPtr->x; \n    \n    \/\/ command is or'd into address\n    sendCommand(ST7920_SET_DDRAM_ADDRESS_COMMAND | add);\n    \n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ show the text in the DISPLAY_TEXT Structure\n\/\/ Step 1: send address (ST7920 document page 15)\n\/\/ Step 2: send text bytes (ST7920 document page 16)\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nvoid showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr){\n    \n    \/\/ make sure the message really is a text message\n    if (displayTextCommand != ddPtr->command)\n        return;\n    \n#if DISPLAY_IS_8_LINES_BY_16_CHARS\n    displayStringUsingGraphicsFont(ddPtr);\n#else        \n    \/\/ \"normal\" text using built in font\n    sendLineAddressToDisplay(ddPtr);\/\/ position the starting character\n    sendTextToDisplay(ddPtr);       \/\/ display the characters\n#endif\n\n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ Pattern to initialize the display, from the sitronix7920 data \n\/\/ sheet page 34\n\/\/ This is global, provided by all displays\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nvoid initializeDisplay(TaskMonitor_t *TaskMonitorPtr) {\n    \n    TaskDelay(pdMS_TO_TICKS(50),TaskMonitorPtr);\/\/ wait for display to power up initialize\n    \n#if DISPLAY_IS_8_LINES_BY_16_CHARS\n    enableGraphics(); \/\/ turn on graphics mode\n    clearDisplayInGraphicsMode();\/\/ set all to 0\n#endif     \n\n    \/\/ do the set function for the extended bit\n    setExtendedFunction(0 \/* not extended*\/,0 \/* no graphics*\/);\n    \/\/ do the set function the second time (first time keyed it to be Instruction set 0)\n    setExtendedFunction(0 \/* not extended*\/,0 \/* no graphics*\/);\n    \/\/ now turn display on\n    setDisplayStatus(1 \/* display on*\/, 0 \/*dont show cursor*\/ , 0 \/* dont blink cursor *\/); \n    \/\/ now clear the display of any text\n    \/\/ we have to clear the \"text\" display in case there are left \n    \/\/ over characters\n    \/\/ from any previous work. Otherwise they stay on the screen even when in \n    \/\/ graphics mode, making it look ugly.\n    clearDisplay(TaskMonitorPtr);\/\/ delays at least 1.6 ms (in our case, 2 to 3 ms)\n   \n#if DISPLAY_IS_8_LINES_BY_16_CHARS\n    enableGraphics(); \/\/ turn on graphics mode\n    clearDisplayInGraphicsMode();\/\/ set all to 0\n#endif     \n    \n}\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ initialize a 5 by 7 font.\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/*  \nThis font apparently from domsson, licensed for any purpose \nhttps:&#47;&#47;opengameart.org\/content\/ascii-bitmap-font-oldschool\n\n Following BSD license for the Font only\n\nhttps:\/\/github.com\/andygock\/glcd\/blob\/master\/fonts\/font5x7.h\n\nModified BSD License\n\nCopyright (c) 2012, Andy Gock\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and\/or other materials provided with the distribution.\n    * Neither the name of Andy Gock nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS \n FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Any Authors\n of this software BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \n SPECIAL, EXEMPLARY,  OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \n OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \n HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, \n STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE \n POSSIBILITY OF SUCH DAMAGE.\n*\/\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ const with initializer forces array into flash, no ram consumed\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nconst char Font5x7&#91;] = {\n\/\/ no characters displayed for 0x00 through 0x1f\n  0x00,0x00,0x00,0x00,0x00,  \/\/ 0x20 space\n  0x00,0x00,0x5f,0x00,0x00,  \/\/ 0x21 !\n  0x00,0x07,0x00,0x07,0x00,  \/\/ 0x22 \"\n  0x14,0x7f,0x14,0x7f,0x14,  \/\/ 0x23 #\n  0x24,0x2a,0x7f,0x2a,0x12,  \/\/ 0x24 $\n  0x23,0x13,0x08,0x64,0x62,  \/\/ 0x25 %\n  0x36,0x49,0x55,0x22,0x50,  \/\/ 0x26 &amp;\n  0x00,0x05,0x03,0x00,0x00,  \/\/ 0x27 '\n  0x00,0x1c,0x22,0x41,0x00,  \/\/ 0x28 (\n  0x00,0x41,0x22,0x1c,0x00,  \/\/ 0x29 )\n  0x14,0x08,0x3e,0x08,0x14,  \/\/ 0x2a *\n  0x08,0x08,0x3e,0x08,0x08,  \/\/ 0x2b +\n  0x00,0x50,0x30,0x00,0x00,  \/\/ 0x2c ,\n  0x08,0x08,0x08,0x08,0x08,  \/\/ 0x2d -\n  0x00,0x60,0x60,0x00,0x00,  \/\/ 0x2e .\n  0x20,0x10,0x08,0x04,0x02,  \/\/ 0x2f \/\n  0x3e,0x51,0x49,0x45,0x3e,  \/\/ 0x30 0\n  0x00,0x42,0x7f,0x40,0x00,  \/\/ 0x31 1\n  0x42,0x61,0x51,0x49,0x46,  \/\/ 0x32 2\n  0x21,0x41,0x45,0x4b,0x31,  \/\/ 0x33 3\n  0x18,0x14,0x12,0x7f,0x10,  \/\/ 0x34 4\n  0x27,0x45,0x45,0x45,0x39,  \/\/ 0x35 5\n  0x3c,0x4a,0x49,0x49,0x30,  \/\/ 0x36 6\n  0x01,0x71,0x09,0x05,0x03,  \/\/ 0x37 7\n  0x36,0x49,0x49,0x49,0x36,  \/\/ 0x38 8\n  0x06,0x49,0x49,0x29,0x1e,  \/\/ 0x39 9\n  0x00,0x36,0x36,0x00,0x00,  \/\/ 0x3a :\n  0x00,0x56,0x36,0x00,0x00,  \/\/ 0x3b ;\n  0x08,0x14,0x22,0x41,0x00,  \/\/ 0x3c &lt;\n  0x14,0x14,0x14,0x14,0x14,  \/\/ 0x3d =\n  0x00,0x41,0x22,0x14,0x08,  \/\/ 0x3e >\n  0x02,0x01,0x51,0x09,0x06,  \/\/ 0x3f ?\n  0x32,0x49,0x79,0x41,0x3e,  \/\/ 0x40 @\n  0x7e,0x11,0x11,0x11,0x7e,  \/\/ 0x41 A\n  0x7f,0x49,0x49,0x49,0x36,  \/\/ 0x42 B\n  0x3e,0x41,0x41,0x41,0x22,  \/\/ 0x43 C\n  0x7f,0x41,0x41,0x22,0x1c,  \/\/ 0x44 D\n  0x7f,0x49,0x49,0x49,0x41,  \/\/ 0x45 E\n  0x7f,0x09,0x09,0x09,0x01,  \/\/ 0x46 F\n  0x3e,0x41,0x49,0x49,0x7a,  \/\/ 0x47 G\n  0x7f,0x08,0x08,0x08,0x7f,  \/\/ 0x48 H\n  0x00,0x41,0x7f,0x41,0x00,  \/\/ 0x49 I\n  0x20,0x40,0x41,0x3f,0x01,  \/\/ 0x4a J\n  0x7f,0x08,0x14,0x22,0x41,  \/\/ 0x4b K\n  0x7f,0x40,0x40,0x40,0x40,  \/\/ 0x4c L\n  0x7f,0x02,0x0c,0x02,0x7f,  \/\/ 0x4d M\n  0x7f,0x04,0x08,0x10,0x7f,  \/\/ 0x4e N\n  0x3e,0x41,0x41,0x41,0x3e,  \/\/ 0x4f O\n  0x7f,0x09,0x09,0x09,0x06,  \/\/ 0x50 P\n  0x3e,0x41,0x51,0x21,0x5e,  \/\/ 0x51 Q    \n  0x7f,0x09,0x19,0x29,0x46,  \/\/ 0x52 R   \n  0x46,0x49,0x49,0x49,0x31,  \/\/ 0x53 S\n  0x01,0x01,0x7f,0x01,0x01,  \/\/ 0x54 T\n  0x3f,0x40,0x40,0x40,0x3f,  \/\/ 0x55 U\n  0x1f,0x20,0x40,0x20,0x1f,  \/\/ 0x56 V\n  0x3f,0x40,0x38,0x40,0x3f,  \/\/ 0x57 W\n  0x63,0x14,0x08,0x14,0x63,  \/\/ 0x58 X\n  0x07,0x08,0x70,0x08,0x07,  \/\/ 0x59 Y\n  0x61,0x51,0x49,0x45,0x43,  \/\/ 0x5a Z\n  0x00,0x7f,0x41,0x41,0x00,  \/\/ 0x5b &#91;\n  0x02,0x04,0x08,0x10,0x20,  \/\/ 0x5c 55\n  0x00,0x41,0x41,0x7f,0x00,  \/\/ 0x5d ]\n  0x04,0x02,0x01,0x02,0x04,  \/\/ 0x5e ^\n  0x40,0x40,0x40,0x40,0x40,  \/\/ 0x5f _\n  0x00,0x01,0x02,0x04,0x00,  \/\/ 0x60 `\n  0x20,0x54,0x54,0x54,0x78,  \/\/ 0x61 a\n  0x7f,0x48,0x44,0x44,0x38,  \/\/ 0x62 b\n  0x38,0x44,0x44,0x44,0x20,  \/\/ 0x63 c\n  0x38,0x44,0x44,0x48,0x7f,  \/\/ 0x64 d\n  0x38,0x54,0x54,0x54,0x18,  \/\/ 0x65 e\n  0x08,0x7e,0x09,0x01,0x02,  \/\/ 0x66 f\n  0x0c,0x52,0x52,0x52,0x3e,  \/\/ 0x67 g\n  0x7f,0x08,0x04,0x04,0x78,  \/\/ 0x68 h\n  0x00,0x44,0x7d,0x40,0x00,  \/\/ 0x69 i\n  0x20,0x40,0x44,0x3d,0x00,  \/\/ 0x6a j\n  0x7f,0x10,0x28,0x44,0x00,  \/\/ 0x6b k\n  0x00,0x41,0x7f,0x40,0x00,  \/\/ 0x6c l\n  0x7c,0x04,0x18,0x04,0x78,  \/\/ 0x6d m\n  0x7c,0x08,0x04,0x04,0x78,  \/\/ 0x6e n\n  0x38,0x44,0x44,0x44,0x38,  \/\/ 0x6f o\n  0x7c,0x14,0x14,0x14,0x08,  \/\/ 0x70 p\n  0x08,0x14,0x14,0x18,0x7c,  \/\/ 0x71 q\n  0x7c,0x08,0x04,0x04,0x08,  \/\/ 0x72 r\n  0x48,0x54,0x54,0x54,0x20,  \/\/ 0x73 s\n  0x04,0x3f,0x44,0x40,0x20,  \/\/ 0x74 t\n  0x3c,0x40,0x40,0x20,0x7c,  \/\/ 0x75 u\n  0x1c,0x20,0x40,0x20,0x1c,  \/\/ 0x76 v\n  0x3c,0x40,0x30,0x40,0x3c,  \/\/ 0x77 w\n  0x44,0x28,0x10,0x28,0x44,  \/\/ 0x78 x\n  0x0c,0x50,0x50,0x50,0x3c,  \/\/ 0x79 y\n  0x44,0x64,0x54,0x4c,0x44,  \/\/ 0x7a z\n  0x00,0x08,0x36,0x41,0x00,  \/\/ 0x7b {\n  0x00,0x00,0x7f,0x00,0x00,  \/\/ 0x7c |\n  0x00,0x41,0x36,0x08,0x00,  \/\/ 0x7d }\n  0x10,0x08,0x08,0x10,0x08,  \/\/ 0x7e ~\n  0x08,0x1C,0x2A,0x08,0x08 }; \/\/ &lt;-\n\/\/ resume previous licenses\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ Output text to the LCD in graphics mode using a 5x7 font\n\/\/ Each character is 6 cols by 8 lines.\n\/\/ we have 8 lines in the display by 16 characters\n\/\/ (later) use x to offset into the current string, for now\n\/\/ just show the entire string\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void displayStringUsingGraphicsFont(DISPLAY_TEXT_DATA_t *ddPtr){\n\tuint8 row;\n\tuint8 columnIndex;\n\tuint8 exitNow = 0;\n\tuint8 count = 0;\n    uint8 *String = ddPtr->data;\n\n    \n    \/\/ we have to place 2 characters into the display space each time,\n    \/\/ due to how the graphics work.\n\twhile(*String ){\n\t\tuint8 asciiChar1 = *String++;\/\/ also point to next char\n\t\tif (!asciiChar1 ){\n            \/\/ turn 0 into space, \n            \/\/ will end with 2 spaces (minimum)\n\t\t\tasciiChar1 = ' ';\n\t\t\texitNow = 1;\n\t\t}\n\n\t\t\/\/ if string length is odd, last letter does not come in paired, append space\t\t\t\n\t\tuint8 asciiChar2 = *String++;\/\/ also point to next char\n\t\tif (!asciiChar2) {\n            \/\/ odd number of characters in\n            \/\/ the string, replace with space\n\t\t\tasciiChar2 = ' '; \t\t\n\t\t\texitNow = 1;\n\t\t}\n\n        asciiChar1 = asciiChar1 &lt; 0x80 ? asciiChar1 : 0x7f;\n        asciiChar2 = asciiChar2 &lt; 0x80 ? asciiChar2 : 0x7f;\n        \/\/ for now, we only have space through 7f\n\t\tuint8 indexA = asciiChar1 >= ' ' ? asciiChar1 -' ': 0;\n\t\tuint8 indexB = asciiChar2 >= ' ' ? asciiChar2 -' ': 0;\n        \n        \n        \/\/ keep the following arrays off of the stack\n\t\tstatic uint8 columnList1&#91;5];\n\t\tstatic uint8 columnList2&#91;5];\n\t\n\t\tcolumnList1&#91;4] = Font5x7&#91;(indexA*5)];\n\t\tcolumnList1&#91;3] = Font5x7&#91;(indexA*5)+1];\n\t\tcolumnList1&#91;2] = Font5x7&#91;(indexA*5)+2];\n\t\tcolumnList1&#91;1] = Font5x7&#91;(indexA*5)+3];\n\t\tcolumnList1&#91;0] = Font5x7&#91;(indexA*5)+4];\n\n        columnList2&#91;4] = Font5x7&#91;(indexB*5)];\n\t\tcolumnList2&#91;3] = Font5x7&#91;(indexB*5)+1];\n\t\tcolumnList2&#91;2] = Font5x7&#91;(indexB*5)+2];\n\t\tcolumnList2&#91;1] = Font5x7&#91;(indexB*5)+3];\n\t\tcolumnList2&#91;0] = Font5x7&#91;(indexB*5)+4];\n\n\t\tfor (row=0;row&lt;8;row++)\t{\n\t\t\tif (ddPtr->y &lt; 4){\t\/\/ first half\t\t\t\n\t\t\t\tsendCommand(0x80 | (ddPtr->y * 8 + row));\n\t\t\t\tsendCommand(0x80 | count);\n\t\t\t} else {\n\t\t\t\tsendCommand(0x80 | ( (ddPtr->y-4) * 8 + row));\n\t\t\t\tsendCommand(0x88 | count);\n\t\t\t}\n\t\t\t\t\t\n\t\t\tuint8 data1 = 0x00;\n\t\t\tfor (columnIndex=0;columnIndex&lt;5;columnIndex++){\n\t\t\t\tif (columnList1&#91;columnIndex] &amp; (1 &lt;&lt; row)){\n\t\t\t\t\tdata1 |=  (1 &lt;&lt; (columnIndex+3));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuint8 data2 = 0x00;\n\t\t\tfor (columnIndex=0;columnIndex&lt;5;columnIndex++){\n\t\t\t\tif (columnList2&#91;columnIndex] &amp; (1 &lt;&lt; row)){\n\t\t\t\t\tdata2 |=  (1 &lt;&lt; (columnIndex+3));\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsendData(data1);\n\t\t\tsendData(data2);\n\t\t}\n\n\t\tcount++;\n        if (exitNow)\n            break;\/\/ we are done\n\t}\/\/ while\n}\n\n<meta charset=\"utf-8\"><meta charset=\"utf-8\">\/\/------------------------------------------------------------------\n\/\/ If we are in graphics mode, we have to clear display byte by byte\n\/\/ This function performs similar to the LCD_FillScreenGraphics but\n\/\/ only zeros are sent into the screen instead of data from an array.\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void clearDisplayInGraphicsMode(void){\n\tuint8 x; \/\/ character\n    uint8 y; \/\/ line\n\tfor(y = 0; y &lt; 64; y++)\n\t{\n        \/\/ choose the 'line'\n\t\tif(y &lt; 32){\n\t\t\tsendCommand(0x80 | y);\n    \t\tsendCommand(0x80);\n\t\t}else{\n\t\t\tsendCommand(0x80 | (y-32));\n    \t\tsendCommand(0x88);\n\t\t}\n        \/\/ 16 characters sent 2 at a time\n\t\tfor(x = 0; x &lt; 8; x++){\n\t\t\tsendData(0x00);\n\t\t\tsendData(0x00);\n\t\t}\n\t}\n}\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ put the st7920 into graphics 128x64 mode\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void enableGraphics(void){\n    \/\/ set extended mode, then enable graphics\n    setExtendedFunction(0,0);\n    setExtendedFunction(1,0);\n    setExtendedFunction(1,1);\n\n}\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ return the st7920 to text mode\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nvoid disableGraphicsMode(void){\n\tsetExtendedFunction(0,0);\/\/ Graphics and extended \n                                 \/\/ instruction mode turned off.\n    setExtendedFunction(0,0);\n}\n\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ draw bitmap on the screen\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\nstatic void fillScreenInGraphicsModeFromBitmap(const uint8* BitMap)\n{\n\tuint8 x, y;\n\tfor(y = 0; y &lt; 64; y++){\n\t\tif(y &lt; 32){\/\/ top half of screen.\n\t\t\tfor(x = 0; x &lt; 8; x++){\t\t\t\t\t\n\t\t\t\t\/\/ in extended  mode, Y &amp; x must \n                \/\/ be sent each time before data \n\t\t\t\tsendCommand(0x80 | y);\t\t\t\t\n    \t\t\t        sendCommand(0x80 | x);\t\t\t\t\n\t\t\t\tsendData(BitMap&#91;2*x + 16*y]);\t\t\/\/  upper byte \n\t\t\t\tsendData(BitMap&#91;2*x+1 + 16*y]);\t\t\/\/  lower byte\n\t\t\t}\/\/for\n\t\t} else {\n            \/\/  bottom half of  screen.\t\n\t\t\tfor(x = 0; x &lt; 8; x++){\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\tsendCommand(0x80 | (y-32));\t\t\t\/\/ off by 31\n\t\t\t\tsendData(BitMap&#91;2*x + 16*y]);\n\t\t\t\tsendData(BitMap&#91;2*x+1 + 16*y]);\n\t\t\t}\n\t\t}\/\/ if\t\t\n\t}\/\/ for y\n}\n\n#endif\n\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<p>The Header File, FullGraphicsSmartDisplay.h:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#ifndef FULL_GRAPHIC_SMART_DISPLAY_H_\n    #define FULL_GRAPHIC_SMART_DISPLAY_H_\n\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n<meta charset=\"utf-8\"> * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n    \n    SEE \"Display.h\" for some function definitions\n*\/\n#include \"includes.h\"\n    \n#if REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER\n    \/\/ set one of the following to true\n    #if ENABLE_MAXIMUM_DISPLAY_CHAR_COUNT        \n        #define DISPLAY_IS_4_LINES_BY_16_CHARS 0 \/\/ is more or less redundant\n        #define DISPLAY_IS_8_LINES_BY_16_CHARS 1\n    #else    \n        #define DISPLAY_IS_4_LINES_BY_16_CHARS 1  \/\/ is more or less redundant\n        #define DISPLAY_IS_8_LINES_BY_16_CHARS 0\n    #endif    \n    \n    \/*\n        The ST7920 device can handle a 400ns clock low or high. 400ns low, 400ns high\n        That makes the maximum frequency 1.25mhz.  To allow for slop, the clock frequency\n        in the SPI_Master is set at 1mhz.\n    *\/\n    \/\/ 0b00000000 is binary 8 bit byte\n    #define ST7920_SERIAL_SYNC_BITS             (0b11111000)\n    #define ST7920_SERIAL_RW_BIT                (0b00000100)    \/\/ DB2 RW high == read (read not avail serial)\n    #define ST7920_SERIAL_RS_BIT                (0b00000010)    \/\/ DB1 RS high == data (low == instruction (register))    \n\n    #define ST7920_SERIAL_INSTRUCTION_BIT       (0b00000000)\n    \n    #define ST7920_BASIC_INSTRUCTION_BITS       (0)\n    #define ST7920_EXTENDED_FIXED_BIT           (0b00100000)    \/\/ DB5\n    #define ST7920_EXTENDED_RE_BIT              (0b00000100)            \/\/ RE=1 == extended instructions\n\n    #define ST7920_ENABLE_GRAPHICS_BIT          (0b00000010)    \/\/ DB1 == 1 (0x02)\n    \n    #define ST7920_ENABLE_8_BIT_INTERFACE_BIT   (0b00010000)    \/\/ DB4 1== 8 bit interface 0== 4 bit\n    #define ST7920_ENABLE_4_BIT_INTERFACE_BIT   (0b00000000) \n\n    #define ST7920_DISPLAY_CONTROL_BIT          (0b00001000)    \/\/ DB3 1== display control\n    #define ST7920_ENABLE_DISPLAY_ON_BIT        (0b00000100)    \/\/ DB2 1== display on\n\n    #define ST7920_ENABLE_CURSOR_ON_BIT         (0b00000010)    \/\/ DB1 1== cursor on\n    #define ST7920_ENABLE_BLINK_ON_BIT          (0b00000001)    \/\/ DB0 1== blink on\n\n    #define ST7920_CLEAR_DISPLAY_COMMAND        (0b00000001)    \/\/ DB0 1== clear ram\n    \n    #define ST7920_SET_DDRAM_ADDRESS_COMMAND    (0b10000000)    \/\/ DB7 1== set ram (0x80)\n    \n    #define ST7920_STANDARD_WAIT_TIME           72              \/\/ standard for data and commands\n    #define ST7920_CLEAR_COMMAND_WAIT_TIME      (int16)(1.6*2)  \/\/ 1.6 milliseconds *2, changed to \n                                                                \/\/ milliseconds for\n                                                                \/\/ 1 millisecond system tick resolution\n    \n    \/\/ define the addresses for the lines in the ST7920 controller IC.\n    \/\/ The \"Set DDRAM Address\" bit is 0x80, and will be added by code\n    \/\/ at the time of the write.\n    enum st7920_Lines {\n          st7920_line1=0x00\n         ,st7920_line2=0x10\n         ,st7920_line3=0x08\n         ,st7920_line4=0x18\n    };\n\n    #define ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA       3\n\n    #if DISPLAY_IS_4_LINES_BY_16_CHARS\n        #define ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE     16\n        #define ST7920_MAXIMUM_NUMBER_OF_LINES                  4        \n    #endif\n\n    #if DISPLAY_IS_8_LINES_BY_16_CHARS\n        #define ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE     16\n        #define ST7920_MAXIMUM_NUMBER_OF_LINES                  8    \n    #endif\n\n    \/\/ GLOBAL #define\n    #define DISPLAY_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE    ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE\n    #define DISPLAY_MAXIMUM_NUMBER_OF_LINES                 ST7920_MAXIMUM_NUMBER_OF_LINES\n\n    \/\/ SEE \"Display.h\" for User Global Function definitions\n        \n    \/\/ the following functions are exported for DisplayTask\n    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr);\n    extern void initializeDisplay(TaskMonitor_t *TaskMonitorPtr);\n\n#endif\n\n#endif\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Using in FreeRTOS<\/h4>\n\n\n\n<p>If you have been following this thread, and have an idea of how real time software works, you may wonder how this code keeps the display from stepping on its own feet when called from other code in the system (except for the part where interrupts are disabled).<\/p>\n\n\n\n<p>The answer is a layer of code in front of this display &#8220;driver,&#8221; along with a message format that helps keep things straight.  A structure is filled with information to be printed.  The coordinates are placed in the structure.  The message &#8220;command&#8221; is filled in.  The &#8220;message&#8221; is then posted to the DisplayTask Queue.  The Display Task then prints the items one at a time.  <\/p>\n\n\n\n<p>Even if switched out, the Display Task keeps things straight due to only working on one message at a time.  Using Messages, you can write your code in a linear fashion without having to worry about multi-tasking issues (most of the time).  <\/p>\n\n\n\n<p>The display driver which Display Task uses has two functions that are &#8220;exported&#8221; (fancy way of saying &#8220;is visible&#8221; to the Display Printing code.:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr);\n    extern void initializeDisplay(TaskMonitor_t *TaskMonitorPtr);\n<\/code><\/pre>\n\n\n\n<p>The initializeDisplay() function sets up the display based on the #define for 8&#215;16 or 4&#215;16 characters on the display.  For this driver, it is assumed that ASCII is being used.  The driver can be expanded or re-purposed to show something different.  Just change the message structure for character length, plus the initialization and printing code.<\/p>\n\n\n\n<p>The user&#8217;s software only sees a function that posts to a FIFO Queue.  This function keeps messages from stepping on each other.    Here is the user&#8217;s print to display code, Display.c:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n<meta charset=\"utf-8\"> * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n\n    USER DISPLAY INTERFACE IN THIS FILE, SUPPORTED BY ALL DISPLAYS\n *\/\n\n#include \"includes.h\" \/\/ has Display.h and DisplayTask.h\n\n#if ENABLE_DISPLAY\n\n\/\/-----------------------------------------------------------------\n\/\/ Write a Null Terminated C String on the display, \n\/\/ text == \"this is a test\", null (0) terminated C string.\n\/\/ ----\n\/\/ lineNumber -- for *most* displays is 0 to 3 (maximum on 4 line displays)\n\/\/            --                     is 0 to 7 on 8 line displays\n\/\/ offset     -- for *most* displays is 0-15       (maximum 16 character displays)\n\/\/ text       -- character string to be displayed\n\/\/ numberOfTriesToMake -- can be 0, number of times to try sending to the display\n\/\/ delayMsBetweenTries -- can be 0, number of ms to wait between each retry\n\/\/ TaskMonitorPtr      -- used for crude profiler\n\/\/ ----\n\/\/-----------------------------------------------------------------\nvoid showTextOnTheDisplay(int16 lineNumber,int16 offset,uint8 *text,\n                          int16 numberOfTriesToMake, int16 delayMsBetweenTries,\n                          TaskMonitor_t *TaskMonitorPtr){\/\/C string. null terminated \n    \n    DISPLAY_TEXT_DATA_t *dtdPtr = 0;\n    int16 len = strlen((char*)text);\n    \n    if ( !len )\n        return;\/\/ fail silently\n    \n    do{\n        dtdPtr = getDisplayMessagePtr();\n        if (!dtdPtr)\n            TaskDelay(pdMS_TO_TICKS(delayMsBetweenTries),TaskMonitorPtr);\n\n    } while (!dtdPtr &amp;&amp; --numberOfTriesToMake);\n    \n    if (!dtdPtr)\n        return; \/\/ fail silently\n    \n    int16 charCounter =0;\n    \/\/ put the text in the structure\n    while (*text &amp;&amp; ( (unsigned int)(charCounter+offset)) &lt; sizeof(dtdPtr->data) ){\n        dtdPtr->data&#91;charCounter++]=*text++;    \n    };\n    dtdPtr->byteCount   = charCounter;\n    dtdPtr->y           = lineNumber;\n    dtdPtr->x           = offset;   \n    dtdPtr->command     = displayTextCommand;\n    \/\/ QSend is a layered function to allow profiling and tracking.\n    QSend(DisplayTaskQueue,&amp;dtdPtr,50,TaskMonitorPtr);\/\/ ignore failures\n}\n \n#endif\n\n\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<p>A peek at task tracking (QSend,QReceive).  Included for the curious, just replace above QSend with xQueueSend() until full project is available:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>\/\/-------------------------------------------------------\n\/\/ wrap the FreeRTOS function so we can track what is \n\/\/ happening with debug functions\n\/\/-------------------------------------------------------\nBaseType_t QSend( QueueHandle_t xQueue\n                , const void * const pvItemToQueue\n                , TickType_t xTicksToWait\n                ,TaskMonitor_t *taskMonitorPtr \n){\n\n    BaseType_t result;\n                                \n    if (taskMonitorPtr){\n        taskMonitorPtr->currentOperation = to_Q_SEND;  \n    }\n    \n    result = xQueueSend(xQueue,pvItemToQueue,xTicksToWait);\n    \n    if (taskMonitorPtr){\n        taskMonitorPtr->currentOperation = to_noOp;\n    }\n    \n    return result;                    \n}\n\/\/------------------------------------------------------\n\/\/ wrap the FreeRTOS function so we can track what is \n\/\/ happening with debug functions\n\/\/------------------------------------------------------\nBaseType_t QReceive( QueueHandle_t xQueue, \n                            void * const pvBuffer, \n                            TickType_t xTicksToWait,\n                            TaskMonitor_t *taskMonitorPtr \n){\n    \n    BaseType_t result;\n                                \n    if (taskMonitorPtr){\n        taskMonitorPtr->currentOperation = to_Q_RECEIVE;  \n    }\n    \n    result = xQueueReceive(xQueue,pvBuffer,xTicksToWait);\n    \n    if (taskMonitorPtr){\n        taskMonitorPtr->currentOperation = to_noOp;\n    }\n    \n    return result;\n}<\/code><\/pre>\n\n\n\n<p>The structures needed to show data on the display are in Display.h:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#ifndef _DISPLAY_H_\n#define _DISPLAY_H_\n\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n<meta charset=\"utf-8\"> * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n *\/\n#include \"includes.h\"\n\n\/\/\n\/\/ The following webpage gives information on the\n\/\/ various displays available. (search for \"LCD controller\")\n\/\/ https:\/\/marlinfw.org\/docs\/configuration\/configuration.html\n\/\/    \n\/\/ Most graphic displays 128 x 64 use the following drivers:\n\/\/    ST7920   https:\/\/www.digole.com\/images\/file\/Digole_12864_LCD.pdf  \n\/\/                  also RepRapDiscount Full Graphic Smart Controller\n\/\/    ST7565   https:\/\/www.lcd-module.de\/eng\/pdf\/zubehoer\/st7565r.pdf\n\/\/    ST7567   https:\/\/github.com\/FYSETC\/FYSETC-Mini-12864-Panel\/blob\/master\/ST7567_V1.7_G4D_120615.pdf\n\/\/    \n\/\/ The DOG-M128 Display uses a ST7565\n\/\/ Generic Displays usually use a ST7920\n    \n\/\/ The FYSETC mini-panel uses a ST7567 : https:\/\/github.com\/FYSETC\/FYSETC-Mini-12864-Panel\n\/\/    #define SYSETC_MINI_PANEL not yet supported\n    \n\/\/ set ENABLE_DISPLAY to 0 to disable display code\n#define ENABLE_DISPLAY 1\n    \n#define ENABLE_MAXIMUM_DISPLAY_CHAR_COUNT 1 \/* if non-zero, maximum display lines and chars on display *\/\n    \n#define DISPLAY_REFRESH_RATE_IN_MILLISECONDS 1000  \/\/ 1000 == once per sec, 500 == twice per second\n\n    \/\/ uncomment the #define and\/or set it to 1 to enable that particular display\n    \/\/ the maximum number of lines is determined by the display hardware\n#define REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER 1    \n        \n    \n\n\n\/\/ enum varies in size based on value given. In our code, needs to always be placed in a word.\n\/\/ start enum at 0x100 to force 16 bits \nenum displayCommandEnum {\n     displayTextCommand=0x100       \/\/ force to be 16 bits\n    ,displayGraphicsCommand\n    ,displayClearCommand\n    ,displayEndOfCommands\n} ;\n\ntypedef struct display_text_data_struct {\n    enum displayCommandEnum         \n                  command;           \/\/ text or graphic (fill using enum)or other\n    uint16        x;                 \/\/ offset into current line (or pixels X)\n    uint16        y;                 \/\/ line number (0-3)        (or pixels Y)\n    uint16        byteCount;         \/\/ number of chars to show\n    unsigned char data&#91;64];          \/\/ 16 bytes typically for data only    \n} DISPLAY_TEXT_DATA_t;\n\n    \/\/ the following are for all display systems\n    \/\/ parameters:\n    \/\/ ----\n    \/\/ lineNumber -- for *most* displays is 0 to 3 (maximum 4 line displays)\n    \/\/ offset     -- for *most* displays is 0-15       (maximum 16 character displays)\n    \/\/ text       -- character string to be displayed\n    \/\/ numberOfTriesToMake -- can be 0, number of times to try sending to the display\n    \/\/ delayMsBetweenTries -- can be 0, number of ms to wait between each retry\n    \/\/ TaskMonitorPtr      -- used for crude profiler\n    \/\/ ----\n    \/\/ the showTextOnTheDisplay function handles all the details for sending to the \n    \/\/ display task.  Any task of any priority can call this any time.\n    \/\/ actual displaying of the text may be delayed due to task switching.\n    \/\/\n    \/\/ the following structure is used for crude profiling and debugging purposes\n    typedef struct task_monitor_struct TaskMonitor_t;\/\/ forward reference, just in case\n    \/\/\n    extern void showTextOnTheDisplay(int16 lineNumber,int16 offset,uint8 *text,\n                                     int16 numberOfTriesToMake, \n                                     int16 delayMsBetweenTries,TaskMonitor_t *TaskMonitorPtr);\n\n    \n\/\/ DISPLAYS UNDERSTOOD by this code\n    #include \"FullGraphicSmartDisplay.h\"\n    \n#endif\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<p>The magic of keeping message memory straight is in DisplayHelper.c:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n<meta charset=\"utf-8\"> * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n *\/\n\n#include \"DisplayHelper.h\"\n\nint16 dmHead,dmTail;\/\/ for ring buffer.\nDISPLAY_TEXT_DATA_t DisplayDataArray&#91;DisplayTask_QueueSize];\n\n\/\/------------------------------------------------------------------\n\/\/ point ring to next value\n\/\/------------------------------------------------------------------\nint16 DisplayIncRing(int16 ring){\n    ring++;\n    if (ring >=DisplayTask_QueueSize)\n        ring=0;\n    return ring;\n}\n\/\/-------------------------------------------------------------------\n\/\/ get next ring buffer entry. ARM keeps local vars in registers, so this \n\/\/ code is fairly efficient from assembly point of view.\n\/\/ NOTE: Since *any* task can call this function at *any* time,\n\/\/ wrap a \"taskENTER_CRITICAL\/taskEXIT_CRITICAL\" around this \n\/\/ function so that reschedule does not occur (with a possible duplication\n\/\/ of the head indicator)\n\/\/ this function is more or less internal, use in your code with caution.\n\/\/-------------------------------------------------------------------\nDISPLAY_TEXT_DATA_t *getDisplayMessagePtr(){\n    DISPLAY_TEXT_DATA_t *dtdPtr;\n\n    taskENTER_CRITICAL();\/\/ shut down all interrupts so low priority tasks don't get scheduled out\n\n    int16 head=DisplayIncRing(dmHead);\n    \/\/ if head hits tail, we are out of message space\n    if (head == dmTail){\n        taskEXIT_CRITICAL();\/\/ restore all interrupts.  Low priority task can be scheduled out now.\n        return 0;\/\/ 0 is automatically cast to *any* type\n    }\n    \/\/ assign new value to global head\n    dmHead=head;\n    \n    dtdPtr = &amp;DisplayDataArray&#91;head];\/\/ re-use ARM in-register head variable   \n    \n    taskEXIT_CRITICAL();\/\/ restore all interrupts.  Low priority task can be scheduled out now.\n    \n    \/\/ we are guaranteed to have a unique pointer not given to anyone else\n    return dtdPtr;\n}\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<p>DisplayHelper.h has some function definitions:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#ifndef DISPLAY_HELPER_H_\n    #define DISPLAY_HELPER_H_\n\/* SOCino 3d printer firmware, FreeRTOS version\n *\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n *\n * Commercial license Available.\n *\n * This program is free software: you can redistribute it and\/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see &lt;http:\/\/www.gnu.org\/licenses\/&gt;.\n *\n   This license does not override previous licenses\n *\/\n\n#include \"includes.h\"\n\n\n    \/\/ display helper functions. semi-private\n    extern int16                DisplayIncRing(int16 ring);\n    extern DISPLAY_TEXT_DATA_t *getDisplayMessagePtr();\n\n    extern int16                dmHead,dmTail;\/\/ for ring buffer.\n\n    \n#endif\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<p>And, finally, the DisplayTask.c that keeps everything straight:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>\/**\n * 3D Printer Firmware, FreeRTOS version\n\n * Copyright 2021, Wade Maxfield\n * Written by Wade Maxfield\n * Commercial license available\n *\n<meta charset=\"utf-8\"> * This program is free software: you can redistribute it and\/or\n * modify it under the terms of the GNU General Public License \n * as published by the Free Software Foundation, either \n * version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see \n * &lt;http:\/\/www.gnu.org\/licenses\/>.\n *\n   This license does not override previous licenses\n *\/\n#define TEST_DISPLAY_CODE 0  \/\/ set to 0 for normal usage\n#include \"Display.h\"\n#include \"DisplayTask.h\"\n#include \"DisplayHelper.h\"\n#include \"HardwareInit.h\"\n\n#if ENABLE_DISPLAY\n\/\/ local defines\n\n\/\/ variables\nQueueHandle_t       DisplayTaskQueue;\n\nstatic int16 _buttonPressCount;\n\/\/ future use\nCY_ISR(EncPressISR){\n    _buttonPressCount++;\n}\n<meta charset=\"utf-8\">\/\/------------------------------------------------------------\n\/\/ Put the text onto the display, immediately.\n\/\/ this is an internal \"courtesy\" function, \n\/\/ mainly used to keep top line code easily understood\n<meta charset=\"utf-8\">\/\/------------------------------------------------------------\nstatic void _ShowTextOnDisplay(DISPLAY_TEXT_DATA_t *dtdPtr){\n    \/\/ if this is not a show text command, do not display\n    \/\/ using this function\n    if (! (displayTextCommand == dtdPtr->command))\n        return;\n    \n    if (!dtdPtr)\n        return; \/\/ failure.  Be silent about it.\n    \n    \/\/ now show the text.  This is a function revealed to the world by *all*\n    \/\/ versions of smart controller displays. do a global search to locate\n    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *dtdPtr);\n    showDTDOnDisplay(dtdPtr);\n}\n<meta charset=\"utf-8\">\/\/-----------------------------------------------------------------\n\/\/ Do the calculation for the next move.  Receive a DTD structure\n\/\/-----------------------------------------------------------------\nstatic portTASK_FUNCTION( vDisplayTask, pvParameters )\n{\n    static TaskMonitor_t *TaskMonitorPtr = &amp;TaskMonitorArray&#91;DISPLAY_TASK];\n    static DISPLAY_TEXT_DATA_t *mdPtr;\n    (void) pvParameters;\n    \n    \/\/ following will handle startup delays, etc, to initialize the hardware\n    \/\/ provided by ALL displays \n    initializeDisplay(TaskMonitorPtr);\n    \n    \/\/ be sure to add in some padding to queue size for race conditions\n    DisplayTaskQueue = xQueueCreate( DisplayTask_QueueSize, \n                                            sizeof( DISPLAY_TEXT_DATA_t * ) );\n       \n    \n\twhile( !DisplayTaskQueue  )   \t{\n    \t     \/\/ Queue was not created and must not be used.\n            \/\/ panic here.\n            DebugPrintString(\"DisplayTask Queue Not Created\" CRLF);\n            vTaskDelay(pdMS_TO_TICKS(1000));\/\/ warn user the system is dead\n            DisplayTaskQueue = xQueueCreate( DisplayTask_QueueSize, \n                                            sizeof( DISPLAY_TEXT_DATA_t * ) );\n\t}     \n\n    GCodePrintString(DISPLAY_TASK_STARTED_STRING CRLF);\n\n    for(;;){\n        TaskMonitorPtr->runCounter++;\/\/ crude profile indicator.\n        \n        \/\/----------------------------------------------------------\n        \/\/ Various tasks post here, and display the strings or graphics \n        \/\/ (future) posted\n        \/\/ QReceive is a layered function, can replace with \n        \/\/ FreeRTOS xQueueReceive \n        \/\/----------------------------------------------------------\n        if ( QReceive( DisplayTaskQueue, &amp;mdPtr, 1000,TaskMonitorPtr) == pdPASS ){\n            if (mdPtr){\n                switch(mdPtr->command){\n                    case    displayTextCommand:\/\/=0x100\n                        \/\/ display the message  provided by ALL displays\n                        _ShowTextOnDisplay(mdPtr);\n                    break;\n                    \n                    case    displayGraphicsCommand:\n                    break;\n                    \n                    case    displayClearCommand:{\n                        \/\/ the following function provided by *all*\n                        \/\/ displays\n                        void clearDisplay(TaskMonitor_t *TaskMonitorPtr) ;\n                        clearDisplay(TaskMonitorPtr);\n                    }break;\n                    \n                    default: \/\/displayEndOfCommands\n                    break;\n                }\n            \n                dmTail=DisplayIncRing(dmTail);\/\/ release the message\n            }\n\n        } else { \/\/ if QReceive\n            #if TEST_DISPLAY_CODE\n                \/\/ this test code fills the display with changing numbers, once per timeout \n                \/\/ from QReceive above\n                {\n                 uint8 counter;\n                 int16 line;\n                    if (line > 3)\n                        line=0;\n                    \n                    static char testArray&#91;18]; \n                    sprintf(testArray,\"testing %03d\",counter++);\/\/0123456789012345  \n                    \/\/ below will force a post to myself :)\n                    showTextOnTheDisplay(line++,0,testArray,2,10,TaskMonitorPtr);\n                    dmTail=DisplayIncRing(dmTail);\/\/ release the message\n                }\n            #endif\n        }\n    }\/\/ for(;;)\n}\/\/portTASK_FUNCTION\n\n\/\/-----------------------------------------------------------------\n\/\/ start up the (LCD) Display Task, free RTOS\n\/\/ future display technology will probably require re-writes.\n\/\/------------------------------------------------------------------\nvoid vAltStartDisplayTask(int16_t priority){\/\/ DisplayTask.c\n\n    \/\/ set up whatever hardware is selected.  This function is provided by\n    \/\/ *all* display interface code\n    initializeDisplayHardware();\n    isr_EncPress_StartEx(EncPressISR);\/\/ pay attention to button presses.\n    \n    \txTaskCreate( vDisplayTask,\n                    DISPLAY_TASK_STRING , \/\/task name\n                    DisplayTaskSTACK_SIZE, \n                    (void *)NULL, \n                    priority, \n                    ( TaskHandle_t * ) &amp;TaskMonitorArray&#91;DISPLAY_TASK].taskHandle ); \n            \n}\n\n#endif\n\n\n\/* &#91;] END OF FILE *\/\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Future Things To Do:<\/h4>\n\n\n\n<p>Saving system variables in EEPROM is next after button minding.  I should be able to post EEPROM code after display buttons are done, with a crude menu.  Selecting menu items doesn&#8217;t mean much if data can&#8217;t be permanently saved.  <\/p>\n\n\n\n<p>I expect to have the button and selector working on the display, along with the beginnings of a very primitive menu system very soon. I have already tested and debugged an X\/Y movement issue, and refined some of the heater code.<\/p>\n\n\n\n<p>Hopefully soon, a test print will be done.  Once that happens properly, the release of the Eagle files will occur for the circuit board, along with a rough parts list.  Most of the items are multiple-source, so providing a parts list tied to a particular vendor is probably not ideal.  Also, to keep heat down, I used a Murata switcher to provide 5 volts from the incoming 12V.  If you take an LM7805 equivalent and flip it, it will install in place of the murata (Pins 1 and 3 are swapped).  You will not realize the efficiencies that come from using switching power supplies, but it should work well, considering the PSOC only draws around 30 to 40 milliamps running full out.<\/p>\n\n\n\n<p>I plan to make the carrier boards available as inexpensively as possible through an E-Bay store, and possibly other ways.  That information will be posted as it is ready.  In the meantime, if you want the board files, contact me on this blog.<\/p>\n\n\n\n<p>Once a print occurs, and the buttons work, the CY8CKit-059 to RAMPS carrier board should be more or less finished. There may be changes in the future for other smart displays or other extruders.  As many as 3 high speed pins can be recovered on the PSOC if ADC filter caps are removed from them.  In that case, we could support 2 extruders, but that is a future version at this point.  Eventually you have to stop polishing and publish.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Next Time (I Hope)<\/h4>\n\n\n\n<p>Display Part 3, where the selector and click are enabled.  (And perhaps the &#8220;stop&#8221; button)<\/p>\n\n\n\n<p><strong>Enjoy!<\/strong><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time I had (finally!) correctly initialized the display and printed ASCII text on it. The problem I immediately ran into was the fact that 4 lines by 16 characters was not enough to display what I wanted. A lot of the displays out there are 4 lines by 20 characters or more. I went [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-884","post","type-post","status-publish","format-standard","hentry","category-blogposts"],"_links":{"self":[{"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/posts\/884","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/socmaker.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=884"}],"version-history":[{"count":20,"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/posts\/884\/revisions"}],"predecessor-version":[{"id":999,"href":"https:\/\/socmaker.com\/index.php?rest_route=\/wp\/v2\/posts\/884\/revisions\/999"}],"wp:attachment":[{"href":"https:\/\/socmaker.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=884"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/socmaker.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=884"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/socmaker.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=884"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}