Display Part 2

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 dipsplay what I wanted. A lot of the displays out there are 4 lines by 20 characters or more. I went internet diving again.

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 “trial” but should give you enough information to work through the problems of your own fonts.

User domsson created a 5×7 font, and released it for “Use in any way you want,” at https://opengameart.org/content/ascii-bitmap-font-oldschool. In the “glcd” library (https://github.com/andygock/glcd/blob/master/LICENSE) the 5×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)

Graphic 5×7 font on 128×64 Display

The previous post has quite a bit of the code for the “driver.” 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.)

Following is my “driver” code for the display. The Header file that the driver uses is inserted immediately after this code.

FullGraphicsSmartDisplay.c:

/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
*/
#include "FullGraphicSmartDisplay.h"

// only include the following code if this display is compiled into the system
#if REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER
 
static char messageToST7920[ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA];

boolean SPIDone;

static void clearDisplayInGraphicsMode(void);
static void enableGraphics(void);
static void displayStringUsingGraphicsFont(DISPLAY_TEXT_DATA_t *ddPtr);
static void fillScreenInGraphicsModeFromBitmap(const uint8* BitMap);

//-----------------------------------------------------------------------------
// currently not used.  if used may require polling by "sendToDisplay"
//-----------------------------------------------------------------------------
CY_ISR(MasterSPIDoneInterrupt) {
    SPIDone = pdTRUE;   
}
//-----------------------------------------------------------------------------
// Send the data byte to the display. 
//  NOTE: sync and command previously placed in messageToST7920[0] 
//  always assume 4 bit serial interface.
//-----------------------------------------------------------------------------
static void sendToDisplay(uint8 data){
    messageToST7920[1] = data &0xf0;// supposedly lower bits can be non-zero
    messageToST7920[2] = data << 4;    

    taskENTER_CRITICAL();// disable interrupts  can use CyIntDisable()
    // shut down all interrupts so
    // we can't be swapped out while writing to the
    // spi so the message will go out with 1 address
    // select.
    for (int16 i=0; i < ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA; i++){
        SPI_Master_WriteByte(messageToST7920[i]);
    }
    taskEXIT_CRITICAL();//  re-enable interrupts  can use CyIntEnable()
    
    // wait until display receives the command,
    // then delay proper # of microseconds 
    while (!(SPI_Master_ReadTxStatus() & SPI_Master_STS_SPI_DONE));//loop until display receives command
    
    CyDelayUs(ST7920_STANDARD_WAIT_TIME);// wait 72us for command per ST7920 data sheet
}
//-----------------------------------------------------------------------------
// send  command to display.  Instruction
//-----------------------------------------------------------------------------
static void sendCommand(uint8 command){
    messageToST7920[0] = ST7920_SERIAL_SYNC_BITS // sync
                    & ~ST7920_SERIAL_RW_BIT  // write
                    & ~ST7920_SERIAL_RS_BIT ;// instruction (command)
    sendToDisplay(command);
}
//-----------------------------------------------------------------------------
// send arbitrary data to display.  Data
//-----------------------------------------------------------------------------
static void sendData(uint8 data){
            // write is a 0
    messageToST7920[0] = ST7920_SERIAL_SYNC_BITS //  sync  Pattern
                        & ~ST7920_SERIAL_RW_BIT;//   write Select (low for write)
    
    messageToST7920[0]  |= ST7920_SERIAL_RS_BIT ;//  data  Select (high for data)
    
    sendToDisplay(data);
}
//-----------------------------------------------------------------------------
// set/reset the extended function bit in the display
//-----------------------------------------------------------------------------
static void setExtendedFunction(int16 extended, int16 graphicsEnable) {
    uint8 command = ST7920_EXTENDED_FIXED_BIT;// preload

    
    if (extended)
        command |= ST7920_EXTENDED_RE_BIT;
    
    if (graphicsEnable)
        command |= ST7920_ENABLE_GRAPHICS_BIT;
    
    sendCommand(command);
    
}
//-----------------------------------------------------------------------------
// clear the display.  Requires a wait of at least 1.6ms
// ST7920 data sheet page 35 states wait 10 milliseconds
// do TaskDelay() for the wait.  This requires a value of 3,
// because a value of 3 will provide from 2 to 3 milliseconds delay
// due to the delay timer operating on the ARM system interrupt.
// the call of TaskDelay() may occur a few microseconds from the
// millisecond tick interrupt.  End result would be 
// 2 milliseconds and a few microseconds.
//
// global, provided by all displays
//-----------------------------------------------------------------------------
void clearDisplay(TaskMonitor_t *TaskMonitorPtr) {       
    
    sendCommand(ST7920_CLEAR_DISPLAY_COMMAND);
    
    TaskDelay(ST7920_CLEAR_COMMAND_WAIT_TIME,TaskMonitorPtr);// datasheet indicates 1.6ms. delay 2 to 3 milliseconds.
}


//-----------------------------------------------------------------------------
// turn display on/off, change cursor settings
//-----------------------------------------------------------------------------
static void setDisplayStatus(uint16 ON,uint16 showCursor,uint16 blinkCursor) {
    uint8 command = ST7920_BASIC_INSTRUCTION_BITS | 
                    ST7920_DISPLAY_CONTROL_BIT;// preload basic

    if (ON)
        command |= ST7920_ENABLE_DISPLAY_ON_BIT;

    if (showCursor)
        command |= ST7920_ENABLE_CURSOR_ON_BIT;
    
    if (blinkCursor)
        command |= ST7920_ENABLE_BLINK_ON_BIT;
    
    sendCommand(command);
}


//-----------------------------------------------------------------------------
// Send the data bytes to the display.  Address was previously send to display.
// Limit ourselves to 16 bytes internally, for this ST7920 controller.
// global, provided by all displays
//-----------------------------------------------------------------------------
void sendTextToDisplay(DISPLAY_TEXT_DATA_t *ddPtr){
    
    if (ddPtr->y >= ST7920_MAXIMUM_NUMBER_OF_LINES)
        return; // error
    if (ddPtr->x >= ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE )
        return; // error
    
    int16 max =  ddPtr->byteCount ;
    if (max > ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE){
        ddPtr->byteCount=ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE;        
    }
    
    for (int i=0 ; i < max; i++){
        sendData(ddPtr->data[i]);
    }  
}
//-----------------------------------------------------------------------------
// the address definitions are in FullGraphicsSmartDisplay.h
//-----------------------------------------------------------------------------
static uint8 displayAddressesForNormalTextMode[] = {
      st7920_line1// 0x00
     ,st7920_line2// 0x10
     ,st7920_line3// 0x08
     ,st7920_line4// 0x18
};
//-----------------------------------------------------------------------------
// send the "set address" command to display.
// the address is or'd with the command bit.
//-----------------------------------------------------------------------------
static void sendLineAddressToDisplay(DISPLAY_TEXT_DATA_t *ddPtr){

    uint8 add = displayAddressesForNormalTextMode[ddPtr->y] | ddPtr->x;// line address or'd with offset 
    
    sendCommand(ST7920_SET_DDRAM_ADDRESS_COMMAND | add);// command is or'd into address
    
}
//-----------------------------------------------------------------------------
// show the text in the DISPLAY_TEXT Structure
// Step 1: send address (ST7920 document page 15)
// Step 2: send text bytes (ST7920 document page 16)
//-----------------------------------------------------------------------------
void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr){
    
    // make sure the message really is a text message
    if (displayTextCommand != ddPtr->command)
        return;
    
#if DISPLAY_IS_8_LINES_BY_16_CHARS
    displayStringUsingGraphicsFont(ddPtr);
#else        
    // "normal" text using built in font
    sendLineAddressToDisplay(ddPtr);// position the starting character
    sendTextToDisplay(ddPtr);       // display the characters
#endif

}
//-----------------------------------------------------------------------------
// Pattern to initialize the display, from the sitronix7920 data sheet page 34
// global, provided by all displays
//-----------------------------------------------------------------------------
void initializeDisplay(TaskMonitor_t *TaskMonitorPtr) {
    
    TaskDelay(pdMS_TO_TICKS(50),TaskMonitorPtr);// wait for display to power up initialize
    
#if DISPLAY_IS_8_LINES_BY_16_CHARS
    enableGraphics(); // turn on graphics mode
    clearDisplayInGraphicsMode();// set all to 0
#endif     

    // do the set function for the extended bit
    setExtendedFunction(0 /* not extended*/,0 /* no graphics*/);
    // do the set function the second time (first time keyed it to be Instruction set 0)
    setExtendedFunction(0 /* not extended*/,0 /* no graphics*/);
    // now turn display on
    setDisplayStatus(1 /* display on*/, 0 /*dont show cursor*/ , 0 /* dont blink cursor */); 
    // now clear the display of any text
    // we have to clear the "text" display in case there are left over characters
    // from any previous work. Otherwise they stay on the screen even when in 
    // graphics mode, making it look ugly.
    clearDisplay(TaskMonitorPtr);// delays at least 1.6 ms (in our case, 2 to 3 ms)
   
#if DISPLAY_IS_8_LINES_BY_16_CHARS
    enableGraphics(); // turn on graphics mode
    clearDisplayInGraphicsMode();// set all to 0
#endif     
    
}

//-----------------------------------------------------------------------------
// initialize a 5 by 7 font.
/*  
This font apparently from domsson, licensed for any purpose 
https://opengameart.org/content/ascii-bitmap-font-oldschool

 Following BSD license for the Font only

https://github.com/andygock/glcd/blob/master/fonts/font5x7.h

Modified BSD License

Copyright (c) 2012, Andy Gock
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Andy Gock nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Andy Gock BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//-----------------------------------------------------------------------------
// const with initializer forces array into flash, no ram consumed
//-----------------------------------------------------------------------------
const char Font5x7[] = {
// no characters displayed for 0x00 through 0x1f
  0x00,0x00,0x00,0x00,0x00,  // 0x20 space
  0x00,0x00,0x5f,0x00,0x00,  // 0x21 !
  0x00,0x07,0x00,0x07,0x00,  // 0x22 "
  0x14,0x7f,0x14,0x7f,0x14,  // 0x23 #
  0x24,0x2a,0x7f,0x2a,0x12,  // 0x24 $
  0x23,0x13,0x08,0x64,0x62,  // 0x25 %
  0x36,0x49,0x55,0x22,0x50,  // 0x26 &
  0x00,0x05,0x03,0x00,0x00,  // 0x27 '
  0x00,0x1c,0x22,0x41,0x00,  // 0x28 (
  0x00,0x41,0x22,0x1c,0x00,  // 0x29 )
  0x14,0x08,0x3e,0x08,0x14,  // 0x2a *
  0x08,0x08,0x3e,0x08,0x08,  // 0x2b +
  0x00,0x50,0x30,0x00,0x00,  // 0x2c ,
  0x08,0x08,0x08,0x08,0x08,  // 0x2d -
  0x00,0x60,0x60,0x00,0x00,  // 0x2e .
  0x20,0x10,0x08,0x04,0x02,  // 0x2f /
  0x3e,0x51,0x49,0x45,0x3e,  // 0x30 0
  0x00,0x42,0x7f,0x40,0x00,  // 0x31 1
  0x42,0x61,0x51,0x49,0x46,  // 0x32 2
  0x21,0x41,0x45,0x4b,0x31,  // 0x33 3
  0x18,0x14,0x12,0x7f,0x10,  // 0x34 4
  0x27,0x45,0x45,0x45,0x39,  // 0x35 5
  0x3c,0x4a,0x49,0x49,0x30,  // 0x36 6
  0x01,0x71,0x09,0x05,0x03,  // 0x37 7
  0x36,0x49,0x49,0x49,0x36,  // 0x38 8
  0x06,0x49,0x49,0x29,0x1e,  // 0x39 9
  0x00,0x36,0x36,0x00,0x00,  // 0x3a :
  0x00,0x56,0x36,0x00,0x00,  // 0x3b ;
  0x08,0x14,0x22,0x41,0x00,  // 0x3c <
  0x14,0x14,0x14,0x14,0x14,  // 0x3d =
  0x00,0x41,0x22,0x14,0x08,  // 0x3e >
  0x02,0x01,0x51,0x09,0x06,  // 0x3f ?
  0x32,0x49,0x79,0x41,0x3e,  // 0x40 @
  0x7e,0x11,0x11,0x11,0x7e,  // 0x41 A
  0x7f,0x49,0x49,0x49,0x36,  // 0x42 B
  0x3e,0x41,0x41,0x41,0x22,  // 0x43 C
  0x7f,0x41,0x41,0x22,0x1c,  // 0x44 D
  0x7f,0x49,0x49,0x49,0x41,  // 0x45 E
  0x7f,0x09,0x09,0x09,0x01,  // 0x46 F
  0x3e,0x41,0x49,0x49,0x7a,  // 0x47 G
  0x7f,0x08,0x08,0x08,0x7f,  // 0x48 H
  0x00,0x41,0x7f,0x41,0x00,  // 0x49 I
  0x20,0x40,0x41,0x3f,0x01,  // 0x4a J
  0x7f,0x08,0x14,0x22,0x41,  // 0x4b K
  0x7f,0x40,0x40,0x40,0x40,  // 0x4c L
  0x7f,0x02,0x0c,0x02,0x7f,  // 0x4d M
  0x7f,0x04,0x08,0x10,0x7f,  // 0x4e N
  0x3e,0x41,0x41,0x41,0x3e,  // 0x4f O
  0x7f,0x09,0x09,0x09,0x06,  // 0x50 P
  0x3e,0x41,0x51,0x21,0x5e,  // 0x51 Q    
  0x7f,0x09,0x19,0x29,0x46,  // 0x52 R   
  0x46,0x49,0x49,0x49,0x31,  // 0x53 S
  0x01,0x01,0x7f,0x01,0x01,  // 0x54 T
  0x3f,0x40,0x40,0x40,0x3f,  // 0x55 U
  0x1f,0x20,0x40,0x20,0x1f,  // 0x56 V
  0x3f,0x40,0x38,0x40,0x3f,  // 0x57 W
  0x63,0x14,0x08,0x14,0x63,  // 0x58 X
  0x07,0x08,0x70,0x08,0x07,  // 0x59 Y
  0x61,0x51,0x49,0x45,0x43,  // 0x5a Z
  0x00,0x7f,0x41,0x41,0x00,  // 0x5b [
  0x02,0x04,0x08,0x10,0x20,  // 0x5c 55
  0x00,0x41,0x41,0x7f,0x00,  // 0x5d ]
  0x04,0x02,0x01,0x02,0x04,  // 0x5e ^
  0x40,0x40,0x40,0x40,0x40,  // 0x5f _
  0x00,0x01,0x02,0x04,0x00,  // 0x60 `
  0x20,0x54,0x54,0x54,0x78,  // 0x61 a
  0x7f,0x48,0x44,0x44,0x38,  // 0x62 b
  0x38,0x44,0x44,0x44,0x20,  // 0x63 c
  0x38,0x44,0x44,0x48,0x7f,  // 0x64 d
  0x38,0x54,0x54,0x54,0x18,  // 0x65 e
  0x08,0x7e,0x09,0x01,0x02,  // 0x66 f
  0x0c,0x52,0x52,0x52,0x3e,  // 0x67 g
  0x7f,0x08,0x04,0x04,0x78,  // 0x68 h
  0x00,0x44,0x7d,0x40,0x00,  // 0x69 i
  0x20,0x40,0x44,0x3d,0x00,  // 0x6a j
  0x7f,0x10,0x28,0x44,0x00,  // 0x6b k
  0x00,0x41,0x7f,0x40,0x00,  // 0x6c l
  0x7c,0x04,0x18,0x04,0x78,  // 0x6d m
  0x7c,0x08,0x04,0x04,0x78,  // 0x6e n
  0x38,0x44,0x44,0x44,0x38,  // 0x6f o
  0x7c,0x14,0x14,0x14,0x08,  // 0x70 p
  0x08,0x14,0x14,0x18,0x7c,  // 0x71 q
  0x7c,0x08,0x04,0x04,0x08,  // 0x72 r
  0x48,0x54,0x54,0x54,0x20,  // 0x73 s
  0x04,0x3f,0x44,0x40,0x20,  // 0x74 t
  0x3c,0x40,0x40,0x20,0x7c,  // 0x75 u
  0x1c,0x20,0x40,0x20,0x1c,  // 0x76 v
  0x3c,0x40,0x30,0x40,0x3c,  // 0x77 w
  0x44,0x28,0x10,0x28,0x44,  // 0x78 x
  0x0c,0x50,0x50,0x50,0x3c,  // 0x79 y
  0x44,0x64,0x54,0x4c,0x44,  // 0x7a z
  0x00,0x08,0x36,0x41,0x00,  // 0x7b {
  0x00,0x00,0x7f,0x00,0x00,  // 0x7c |
  0x00,0x41,0x36,0x08,0x00,  // 0x7d }
  0x10,0x08,0x08,0x10,0x08,  // 0x7e ~
  0x08,0x1C,0x2A,0x08,0x08 }; // <-
// resume previous licenses

//-----------------------------------------------------------------------------
// Output text to the LCD in graphics mode using a 5x7 font
// Each character is 6 cols by 8 lines.
// we have 8 lines in the display by 16 characters
// (later) use x to offset into the current string, for now
// just show the entire string
//-----------------------------------------------------------------------------
static void displayStringUsingGraphicsFont(DISPLAY_TEXT_DATA_t *ddPtr){
	uint8 row;
	uint8 columnIndex;
	uint8 exitNow = 0;
	uint8 count = 0;
    uint8 *String = ddPtr->data;

    
    // we have to place 2 characters into the display space each time,
    // due to how the graphics work.
	while(*String ){
		uint8 asciiChar1 = *String++;// also point to next char
		if (!asciiChar1 ){
            // turn 0 into space, 
            // will end with 2 spaces (minimum)
			asciiChar1 = ' ';
			exitNow = 1;
		}

		// if string length is odd, last letter does not come in paired, append space			
		uint8 asciiChar2 = *String++;// also point to next char
		if (!asciiChar2) {
            // odd number of characters in
            // the string, replace with space
			asciiChar2 = ' '; 		
			exitNow = 1;
		}

        asciiChar1 = asciiChar1 < 0x80 ? asciiChar1 : 0x7f;
        asciiChar2 = asciiChar2 < 0x80 ? asciiChar2 : 0x7f;
        // for now, we only have space through 7f
		uint8 indexA = asciiChar1 >= ' ' ? asciiChar1 -' ': 0;
		uint8 indexB = asciiChar2 >= ' ' ? asciiChar2 -' ': 0;
        
        
        // keep the following arrays off of the stack
		static uint8 columnList1[5];
		static uint8 columnList2[5];
	
		columnList1[4] = Font5x7[(indexA*5)];
		columnList1[3] = Font5x7[(indexA*5)+1];
		columnList1[2] = Font5x7[(indexA*5)+2];
		columnList1[1] = Font5x7[(indexA*5)+3];
		columnList1[0] = Font5x7[(indexA*5)+4];

        columnList2[4] = Font5x7[(indexB*5)];
		columnList2[3] = Font5x7[(indexB*5)+1];
		columnList2[2] = Font5x7[(indexB*5)+2];
		columnList2[1] = Font5x7[(indexB*5)+3];
		columnList2[0] = Font5x7[(indexB*5)+4];

		for (row=0;row<8;row++)	{
			if (ddPtr->y < 4){	// first half			
				sendCommand(0x80 | (ddPtr->y * 8 + row));
				sendCommand(0x80 | count);
			} else {
				sendCommand(0x80 | ( (ddPtr->y-4) * 8 + row));
				sendCommand(0x88 | count);
			}
					
			uint8 data1 = 0x00;
			for (columnIndex=0;columnIndex<5;columnIndex++){
				if (columnList1[columnIndex] & (1 << row)){
					data1 |=  (1 << (columnIndex+3));
				}
			}

			uint8 data2 = 0x00;
			for (columnIndex=0;columnIndex<5;columnIndex++){
				if (columnList2[columnIndex] & (1 << row)){
					data2 |=  (1 << (columnIndex+3));
				}
			}
	
			sendData(data1);
			sendData(data2);
		}

		count++;
        if (exitNow)
            break;// we are done
	}// while
}

//-----------------------------------------------------------------------------
// If we are in graphics mode, we have to clear display byte by byte
// This function performs similar to the LCD_FillScreenGraphics but
// only zeros are sent into the screen instead of data from an array.
//-----------------------------------------------------------------------------
static void clearDisplayInGraphicsMode(void){
	uint8 x; // character
    uint8 y; // line
	for(y = 0; y < 64; y++)
	{
        // choose the 'line'
		if(y < 32){
			sendCommand(0x80 | y);
    		sendCommand(0x80);
		}else{
			sendCommand(0x80 | (y-32));
    		sendCommand(0x88);
		}
        // 16 characters sent 2 at a time
		for(x = 0; x < 8; x++){
			sendData(0x00);
			sendData(0x00);
		}
	}
}

//-------------------------------------------------------------------------
// put the st7920 into graphics 128x64 mode
//-------------------------------------------------------------------------
static void enableGraphics(void){
    // set extended mode, then enable graphics
    setExtendedFunction(0,0);
    setExtendedFunction(1,0);
    setExtendedFunction(1,1);

}

//-------------------------------------------------------------------------
// return the st7920 to text mode
//-------------------------------------------------------------------------
void disableGraphicsMode(void){
	setExtendedFunction(0,0);// Graphics and extended instruction mode turned off.
    setExtendedFunction(0,0);
}

//-----------------------------------------------------------------------------
// draw bitmap on the screen
//-----------------------------------------------------------------------------
static void fillScreenInGraphicsModeFromBitmap(const uint8* BitMap)
{
	uint8 x, y;
	for(y = 0; y < 64; y++){
		if(y < 32){// top half of screen.
			for(x = 0; x < 8; x++){					
				// in extended  mode, Y & x must 
                // be sent each time before data 
				sendCommand(0x80 | y);				
    			        sendCommand(0x80 | x);				
				sendData(BitMap[2*x + 16*y]);		//  upper byte 
				sendData(BitMap[2*x+1 + 16*y]);		//  lower byte
			}//for
		} else {
            //  bottom half of  screen.	
			for(x = 0; x < 8; x++){																			
				sendCommand(0x80 | (y-32));			// off by 31
				sendData(BitMap[2*x + 16*y]);
				sendData(BitMap[2*x+1 + 16*y]);
			}
		}// if		
	}// for y
}

#endif

/* [] END OF FILE */

The Header File, FullGraphicsSmartDisplay.h:

#ifndef FULL_GRAPHIC_SMART_DISPLAY_H_
    #define FULL_GRAPHIC_SMART_DISPLAY_H_
/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
    
    SEE "Display.h" for some function definitions
*/
#include "includes.h"
    
#if REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER
    // set one of the following to true
    #if ENABLE_MAXIMUM_DISPLAY_CHAR_COUNT        
        #define DISPLAY_IS_4_LINES_BY_16_CHARS 0 // is more or less redundant
        #define DISPLAY_IS_8_LINES_BY_16_CHARS 1
    #else    
        #define DISPLAY_IS_4_LINES_BY_16_CHARS 1  // is more or less redundant
        #define DISPLAY_IS_8_LINES_BY_16_CHARS 0
    #endif    
    
    /*
        The ST7920 device can handle a 400ns clock low or high. 400ns low, 400ns high
        That makes the maximum frequency 1.25mhz.  To allow for slop, the clock frequency
        in the SPI_Master is set at 1mhz.
    */
    // 0b00000000 is binary 8 bit byte
    #define ST7920_SERIAL_SYNC_BITS             (0b11111000)
    #define ST7920_SERIAL_RW_BIT                (0b00000100)    // DB2 RW high == read (read not avail serial)
    #define ST7920_SERIAL_RS_BIT                (0b00000010)    // DB1 RS high == data (low == instruction (register))    

    #define ST7920_SERIAL_INSTRUCTION_BIT       (0b00000000)
    
    #define ST7920_BASIC_INSTRUCTION_BITS       (0)
    #define ST7920_EXTENDED_FIXED_BIT           (0b00100000)    // DB5
    #define ST7920_EXTENDED_RE_BIT              (0b00000100)            // RE=1 == extended instructions

    #define ST7920_ENABLE_GRAPHICS_BIT          (0b00000010)    // DB1 == 1 (0x02)
    
    #define ST7920_ENABLE_8_BIT_INTERFACE_BIT   (0b00010000)    // DB4 1== 8 bit interface 0== 4 bit
    #define ST7920_ENABLE_4_BIT_INTERFACE_BIT   (0b00000000) 

    #define ST7920_DISPLAY_CONTROL_BIT          (0b00001000)    // DB3 1== display control
    #define ST7920_ENABLE_DISPLAY_ON_BIT        (0b00000100)    // DB2 1== display on

    #define ST7920_ENABLE_CURSOR_ON_BIT         (0b00000010)    // DB1 1== cursor on
    #define ST7920_ENABLE_BLINK_ON_BIT          (0b00000001)    // DB0 1== blink on

    #define ST7920_CLEAR_DISPLAY_COMMAND        (0b00000001)    // DB0 1== clear ram
    
    #define ST7920_SET_DDRAM_ADDRESS_COMMAND    (0b10000000)    // DB7 1== set ram (0x80)
    
    #define ST7920_STANDARD_WAIT_TIME           72              // standard for data and commands
    #define ST7920_CLEAR_COMMAND_WAIT_TIME      (int16)(1.6*2)  // 1.6 milliseconds *2, changed to 
                                                                // milliseconds for
                                                                // 1 millisecond system tick resolution
    
    // define the addresses for the lines in the ST7920 controller IC.
    // The "Set DDRAM Address" bit is 0x80, and will be added by code
    // at the time of the write.
    enum st7920_Lines {
          st7920_line1=0x00
         ,st7920_line2=0x10
         ,st7920_line3=0x08
         ,st7920_line4=0x18
    };

    #define ST7920_NUMBER_OF_BYTES_IN_COMMAND_OR_DATA       3

    #if DISPLAY_IS_4_LINES_BY_16_CHARS
        #define ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE     16
        #define ST7920_MAXIMUM_NUMBER_OF_LINES                  4        
    #endif

    #if DISPLAY_IS_8_LINES_BY_16_CHARS
        #define ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE     16
        #define ST7920_MAXIMUM_NUMBER_OF_LINES                  8    
    #endif

    // GLOBAL #define
    #define DISPLAY_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE    ST7920_MAXIMUM_NUMBER_OF_CHARACTERS_ON_LINE
    #define DISPLAY_MAXIMUM_NUMBER_OF_LINES                 ST7920_MAXIMUM_NUMBER_OF_LINES

    // SEE "Display.h" for User Global Function definitions
        
    // the following functions are exported for DisplayTask
    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr);
    extern void initializeDisplay(TaskMonitor_t *TaskMonitorPtr);

#endif

#endif
/* [] END OF FILE */

Using in FreeRTOS

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).

The answer is a layer of code in front of this display “driver,” 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 “command” is filled in. The “message” is then posted to the DisplayTask Queue. The Display Task then prints the items one at a time.

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).

The display driver which Display Task uses has two functions that are “exported” (fancy way of saying “is visible” to the Display Printing code.:

    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *ddPtr);
    extern void initializeDisplay(TaskMonitor_t *TaskMonitorPtr);

The initializeDisplay() function sets up the display based on the #define for 8×16 or 4×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.

The user’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’s print to display code, Display.c:

/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses

    USER DISPLAY INTERFACE IN THIS FILE, SUPPORTED BY ALL DISPLAYS
 */

#include "includes.h" // has Display.h and DisplayTask.h

#if ENABLE_DISPLAY

//-----------------------------------------------------------------------------
// Write a Null Terminated C String on the display, 
// text == "this is a test", null (0) terminated C string.
// ----
// lineNumber -- for *most* displays is 0 to 3 (maximum on 4 line displays)
//            --                     is 0 to 7 on 8 line displays
// offset     -- for *most* displays is 0-15       (maximum 16 character displays)
// text       -- character string to be displayed
// numberOfTriesToMake -- can be 0, number of times to try sending to the display
// delayMsBetweenTries -- can be 0, number of ms to wait between each retry
// TaskMonitorPtr      -- used for crude profiler
// ----
//-----------------------------------------------------------------------------
void showTextOnTheDisplay(int16 lineNumber,int16 offset,uint8 *text,
                          int16 numberOfTriesToMake, int16 delayMsBetweenTries,
                          TaskMonitor_t *TaskMonitorPtr){//C string. null terminated 
    
    DISPLAY_TEXT_DATA_t *dtdPtr = 0;
    int16 len = strlen((char*)text);
    
    if ( !len )
        return;// fail silently
    
    do{
        dtdPtr = getDisplayMessagePtr();
        if (!dtdPtr)
            TaskDelay(pdMS_TO_TICKS(delayMsBetweenTries),TaskMonitorPtr);

    } while (!dtdPtr && --numberOfTriesToMake);
    
    if (!dtdPtr)
        return; // fail silently
    
    int16 charCounter =0;
    // put the text in the structure
    while (*text && ( (unsigned int)(charCounter+offset)) < sizeof(dtdPtr->data) ){
        dtdPtr->data[charCounter++]=*text++;    
    };
    dtdPtr->byteCount   = charCounter;
    dtdPtr->y           = lineNumber;
    dtdPtr->x           = offset;   
    dtdPtr->command     = displayTextCommand;
    // QSend is a layered function to allow profiling and tracking.
    QSend(DisplayTaskQueue,&dtdPtr,50,TaskMonitorPtr);// ignore failures
}
 
#endif


/* [] END OF FILE */

A peek at task tracking (QSend,QReceive). Included for the curious, just replace above QSend with xQueueSend() until full project is available:

//------------------------------------------------------------------------------
// wrap the FreeRTOS function so we can track what is happening with debug
// functions
//------------------------------------------------------------------------------
BaseType_t QSend( QueueHandle_t xQueue
                , const void * const pvItemToQueue
                , TickType_t xTicksToWait
                ,TaskMonitor_t *taskMonitorPtr 
){

    BaseType_t result;
                                
    if (taskMonitorPtr){
        taskMonitorPtr->currentOperation = to_Q_SEND;  
    }
    
    result = xQueueSend(xQueue,pvItemToQueue,xTicksToWait);
    
    if (taskMonitorPtr){
        taskMonitorPtr->currentOperation = to_noOp;
    }
    
    return result;                    
}
//------------------------------------------------------------------------------
// wrap the FreeRTOS function so we can track what is happening with debug
// functions
//------------------------------------------------------------------------------
BaseType_t QReceive( QueueHandle_t xQueue, 
                            void * const pvBuffer, 
                            TickType_t xTicksToWait,
                            TaskMonitor_t *taskMonitorPtr 
){
    
    BaseType_t result;
                                
    if (taskMonitorPtr){
        taskMonitorPtr->currentOperation = to_Q_RECEIVE;  
    }
    
    result = xQueueReceive(xQueue,pvBuffer,xTicksToWait);
    
    if (taskMonitorPtr){
        taskMonitorPtr->currentOperation = to_noOp;
    }
    
    return result;
}

The structures needed to show data on the display are in Display.h:

#ifndef _DISPLAY_H_
#define _DISPLAY_H_
/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
 */
#include "includes.h"

//
// The following webpage gives information on the
// various displays available. (search for "LCD controller")
// https://marlinfw.org/docs/configuration/configuration.html
//    
// Most graphic displays 128 x 64 use the following drivers:
//    ST7920   https://www.digole.com/images/file/Digole_12864_LCD.pdf  
//                  also RepRapDiscount Full Graphic Smart Controller
//    ST7565   https://www.lcd-module.de/eng/pdf/zubehoer/st7565r.pdf
//    ST7567   https://github.com/FYSETC/FYSETC-Mini-12864-Panel/blob/master/ST7567_V1.7_G4D_120615.pdf
//    
// The DOG-M128 Display uses a ST7565
// Generic Displays usually use a ST7920
    
// The FYSETC mini-panel uses a ST7567 : https://github.com/FYSETC/FYSETC-Mini-12864-Panel
//    #define SYSETC_MINI_PANEL not yet supported
    
// set ENABLE_DISPLAY to 0 to disable display code
#define ENABLE_DISPLAY 1
    
#define ENABLE_MAXIMUM_DISPLAY_CHAR_COUNT 1 /* if non-zero, maximum display lines and chars on display */
    
#define DISPLAY_REFRESH_RATE_IN_MILLISECONDS 1000  // 1000 == once per sec, 500 == twice per second

    // uncomment the #define and/or set it to 1 to enable that particular display
    // the maximum number of lines is determined by the display hardware
#define REPRAP_DISCOUNT_FULL_GRAPHICS_SMART_CONTROLLER 1    
        
    


// enum varies in size based on value given. In our code, needs to always be placed in a word.
// start enum at 0x100 to force 16 bits 
enum displayCommandEnum {
     displayTextCommand=0x100       // force to be 16 bits
    ,displayGraphicsCommand
    ,displayClearCommand
    ,displayEndOfCommands
} ;

typedef struct display_text_data_struct {
    enum displayCommandEnum         
                  command;           // text or graphic (fill using enum)or other
    uint16        x;                 // offset into current line (or pixels X)
    uint16        y;                 // line number (0-3)        (or pixels Y)
    uint16        byteCount;         // number of chars to show
    unsigned char data[64];          // 16 bytes typically for data only    
} DISPLAY_TEXT_DATA_t;

    // the following are for all display systems
    // parameters:
    // ----
    // lineNumber -- for *most* displays is 0 to 3 (maximum 4 line displays)
    // offset     -- for *most* displays is 0-15       (maximum 16 character displays)
    // text       -- character string to be displayed
    // numberOfTriesToMake -- can be 0, number of times to try sending to the display
    // delayMsBetweenTries -- can be 0, number of ms to wait between each retry
    // TaskMonitorPtr      -- used for crude profiler
    // ----
    // the showTextOnTheDisplay function handles all the details for sending to the 
    // display task.  Any task of any priority can call this any time.
    // actual displaying of the text may be delayed due to task switching.
    //
    // the following structure is used for crude profiling and debugging purposes
    typedef struct task_monitor_struct TaskMonitor_t;// forward reference, just in case
    //
    extern void showTextOnTheDisplay(int16 lineNumber,int16 offset,uint8 *text,
                                     int16 numberOfTriesToMake, 
                                     int16 delayMsBetweenTries,TaskMonitor_t *TaskMonitorPtr);

    
// DISPLAYS UNDERSTOOD by this code
    #include "FullGraphicSmartDisplay.h"
    
#endif
/* [] END OF FILE */

The magic of keeping message memory straight is in DisplayHelper.c:

/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
 */

#include "DisplayHelper.h"

int16 dmHead,dmTail;// for ring buffer.
DISPLAY_TEXT_DATA_t DisplayDataArray[DisplayTask_QueueSize];

//-----------------------------------------------------------------------------
// point ring to next value
//-----------------------------------------------------------------------------
int16 DisplayIncRing(int16 ring){
    ring++;
    if (ring >=DisplayTask_QueueSize)
        ring=0;
    return ring;
}
//-----------------------------------------------------------------------------
// get next ring buffer entry. ARM keeps local vars in registers, so this 
// code is fairly efficient from assembly point of view.
// NOTE: Since *any* task can call this function at *any* time,
// wrap a "taskENTER_CRITICAL/taskEXIT_CRITICAL" around this 
// function so that reschedule does not occur (with a possible duplication
// of the head indicator)
// this function is more or less internal, use in your code with caution.
//-----------------------------------------------------------------------------
DISPLAY_TEXT_DATA_t *getDisplayMessagePtr(){
    DISPLAY_TEXT_DATA_t *dtdPtr;

    taskENTER_CRITICAL();// shut down all interrupts so low priority tasks don't get scheduled out

    int16 head=DisplayIncRing(dmHead);
    // if head hits tail, we are out of message space
    if (head == dmTail){
        taskEXIT_CRITICAL();// restore all interrupts.  Low priority task can be scheduled out now.
        return 0;// 0 is automatically cast to *any* type
    }
    // assign new value to global head
    dmHead=head;
    
    dtdPtr = &DisplayDataArray[head];// re-use ARM in-register head variable   
    
    taskEXIT_CRITICAL();// restore all interrupts.  Low priority task can be scheduled out now.
    
    // we are guaranteed to have a unique pointer not given to anyone else
    return dtdPtr;
}
/* [] END OF FILE */

DisplayHelper.h has some function definitions:

#ifndef DISPLAY_HELPER_H_
    #define DISPLAY_HELPER_H_
/* SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
 */

#include "includes.h"


    // display helper functions. semi-private
    extern int16                DisplayIncRing(int16 ring);
    extern DISPLAY_TEXT_DATA_t *getDisplayMessagePtr();

    extern int16                dmHead,dmTail;// for ring buffer.

    
#endif
/* [] END OF FILE */

And, finally, the DisplayTask.c that keeps everything straight:

/**
 * 3D Printer Firmware, FreeRTOS version

 * Copyright 2021, Wade Maxfield
 * Written by Wade Maxfield
 * Commercial license available
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, //either version 3 of the License, //or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, //see <http://www.gnu.org/licenses/>.
 *
   This license does not override previous licenses
 */
#define TEST_DISPLAY_CODE 0  // set to 0 for normal usage
#include "Display.h"
#include "DisplayTask.h"
#include "DisplayHelper.h"
#include "HardwareInit.h"

#if ENABLE_DISPLAY
// local defines

// variables
QueueHandle_t       DisplayTaskQueue;

static int16 _buttonPressCount;
// future use
CY_ISR(EncPressISR){
    _buttonPressCount++;
}
//-----------------------------------------------------------------------------
// Put the text onto the display, immediately.
// this is an internal "courtesy" function, 
// mainly used to keep top line code easily understood
//-----------------------------------------------------------------------------
static void _ShowTextOnDisplay(DISPLAY_TEXT_DATA_t *dtdPtr){
    // if this is not a show text command, do not display
    // using this function
    if (! (displayTextCommand == dtdPtr->command))
        return;
    
    if (!dtdPtr)
        return; // failure.  Be silent about it.
    
    // now show the text.  This is a function revealed to the world by *all*
    // versions of smart controller displays. do a global search to locate
    extern void showDTDOnDisplay(DISPLAY_TEXT_DATA_t *dtdPtr);
    showDTDOnDisplay(dtdPtr);
}
//-----------------------------------------------------------------------------
// Do the calculation for the next move.  Receive a DTD structure
//-----------------------------------------------------------------------------
static portTASK_FUNCTION( vDisplayTask, pvParameters )
{
    static TaskMonitor_t *TaskMonitorPtr = &TaskMonitorArray[DISPLAY_TASK];
    static DISPLAY_TEXT_DATA_t *mdPtr;
    (void) pvParameters;
    
    // following will handle startup delays, etc, to initialize the hardware
    // provided by ALL displays 
    initializeDisplay(TaskMonitorPtr);
    
    // be sure to add in some padding to queue size for race conditions
    DisplayTaskQueue = xQueueCreate( DisplayTask_QueueSize, 
                                            sizeof( DISPLAY_TEXT_DATA_t * ) );
       
    
	while( !DisplayTaskQueue  )   	{
    	     // Queue was not created and must not be used.
            // panic here.
            DebugPrintString("DisplayTask Queue Not Created" CRLF);
            vTaskDelay(pdMS_TO_TICKS(1000));// warn user the system is dead
            DisplayTaskQueue = xQueueCreate( DisplayTask_QueueSize, 
                                            sizeof( DISPLAY_TEXT_DATA_t * ) );
	}     

    GCodePrintString(DISPLAY_TASK_STARTED_STRING CRLF);

    for(;;){
        TaskMonitorPtr->runCounter++;// crude profile indicator.
        
        //----------------------------------------------------------------------
        // Various tasks post here, and display the strings or graphics (future) posted
        // QReceive is a layered function, can replace with FreeRTOS xQueueReceive 
        //----------------------------------------------------------------------
        if ( QReceive( DisplayTaskQueue, &mdPtr, 1000,TaskMonitorPtr) == pdPASS ){
            if (mdPtr){
                switch(mdPtr->command){
                    case    displayTextCommand://=0x100
                        // display the message  provided by ALL displays
                        _ShowTextOnDisplay(mdPtr);
                    break;
                    
                    case    displayGraphicsCommand:
                    break;
                    
                    case    displayClearCommand:{
                        // the following function provided by *all*
                        // displays
                        void clearDisplay(TaskMonitor_t *TaskMonitorPtr) ;
                        clearDisplay(TaskMonitorPtr);
                    }break;
                    
                    default: //displayEndOfCommands
                    break;
                }
            
                dmTail=DisplayIncRing(dmTail);// release the message
            }

        } else { // if QReceive
            #if TEST_DISPLAY_CODE
                // this test code fills the display with changing numbers, once per timeout 
                // from QReceive above
                {
                 uint8 counter;
                 int16 line;
                    if (line > 3)
                        line=0;
                    
                    static char testArray[18]; 
                    sprintf(testArray,"testing %03d",counter++);//0123456789012345  
                    // below will force a post to myself :)
                    showTextOnTheDisplay(line++,0,testArray,2,10,TaskMonitorPtr);
                    dmTail=DisplayIncRing(dmTail);// release the message
                }
            #endif
        }
    }// for(;;)
}//portTASK_FUNCTION

//-----------------------------------------------------------------------------
// start up the (LCD) Display Task, free RTOS
// future display technology will probably require re-writes.
//-----------------------------------------------------------------------------
void vAltStartDisplayTask(int16_t priority){// DisplayTask.c

    // set up whatever hardware is selected.  This function is provided by
    // *all* display interface code
    initializeDisplayHardware();
    isr_EncPress_StartEx(EncPressISR);// pay attention to button presses.
    
    	xTaskCreate( vDisplayTask,
                    DISPLAY_TASK_STRING , //task name
                    DisplayTaskSTACK_SIZE, 
                    (void *)NULL, 
                    priority, 
                    ( TaskHandle_t * ) &TaskMonitorArray[DISPLAY_TASK].taskHandle ); 
            
}

#endif


/* [] END OF FILE */

Future Things To Do:

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’t mean much if data can’t be permanently saved.

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.

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.

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.

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.

Next Time (I Hope)

Display Part 3, where the selector and click are enabled. (And perhaps the “stop” button)

Enjoy!

Add a Comment

Your email address will not be published. Required fields are marked *