News:

;) This forum is the property of Proton software developers

Main Menu

Positron8 - NIMO Display Emulator on a circular CG9A01 TFT

Started by top204, Jul 07, 2026, 09:18 PM

Previous topic - Next topic

top204

Has anyone heard of a NIMO display? I had never heard of one until a few days ago, and as soon as I saw a picture of one, it fascinated me, but my chances of ever owning a real one is zero. :-( Those who know me, will know my fascination, and love, for CRTs, display valves (tubes) and valves themselves.

I know I will never see a real NIMO tube, so I created an emulator for one, using a PIC18F26K40 device and a circular CG9A01 TFT display, sitting on one of John's excellent Amicus8 boards. It seems a close emulation, and can be altered to work on other LCDs, if smaller is required.

The code for the emulator's main program is shown below, and it uses a few include files for control of the CG9A01 display, hardware SPI, and flash memory data files of the digit images of a NIMO device.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A NIMO diplay valve, digital emulator, using a circular CG9A01 240x240 Graphic LCD on a PIC18FxxK40 device.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook
' https://youtu.be/IugcFkk0KqE
'
    Device = 18F26K40                                                           ' Tell the compiler what device to compile for
    Declare Xtal = 64                                                           ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Heap_Arrays = On                                               ' Tell the compiler to create arrays above standard variables, so assembler code is more efficient
    Declare Auto_Heap_Strings = On                                              ' Make all Strings "Heap" types, so they always get placed after standard variables
    Declare Auto_Variable_Bank_Cross = On                                       ' Make sure all multi-byte variables remain within a single RAM bank
'
' Setup USART1 for debugging
'
    Declare Hserial1_Baud = 115200
    Declare HRSOut1_Pin = PORTC.6
'
' Define the pins used for the CG9A01 LCD display
'
$define CG9A01_CLK_Pin  PORTB.3                                                 ' Connects to the CG9A01 CLK pin (named SCL on some displays)
$define CG9A01_CLK_PPS_Pin Pin_B3                                               ' Define the CLK Pin to use for PPS
$define CG9A01_DTA_Pin  PORTB.4                                                 ' Connects to the CG9A01 DTA pin (named SDI on some displays)
$define CG9A01_DTA_PPS_Pin Pin_B4                                               ' Define the DTA Pin to use for PPS
$define CG9A01_CS_Pin   PORTB.7                                                 ' Connects to the CG9A01 CS pin
$define CG9A01_DC_Pin   PORTB.6                                                 ' Connects to the CG9A01 DC pin (named RS on some displays)
$define CG9A01_RST_Pin  PORTB.5                                                 ' Connects to the CG9A01 Reset pin
$define CG9A01_BLK_Pin  PORTC.0                                                 ' Connects to the CG9A01 BLK (Backlight) pin

$define GLCD_Backlight_On() PinHigh CG9A01_BLK_Pin                              ' A meta-macro to illuminate the LCD's backlight
$define GLCD_Backlight_Off() PinLow CG9A01_BLK_Pin                              ' A meta-macro to extinguish the LCD's backlight

    Include "CG9A01.inc"                                                        ' Load the CG9A01 library into the program
    Include "HSPI_K40.inc"                                                      ' Load the SPI peripheral library into the program
    Include "NIMO_Digits_Lengthened.inc"                                        ' Load the lengthened NIMO digit images flash memory tables
'
' Convert a 24-bit RGB888 constant value into a 16-bit RGB565 constant value
'
$define RGB565(pRed, pGreen, pBlue) $eval ((((pRed) >> 3) & 0x1F) << 11) | ((((pGreen) >> 2) & 0x3F) << 5) | (((pBlue) >> 3) & 0x1F)
$define clBRIGHT_GREEN RGB565(0, 255, 120)                                      ' Holds the RGB565 value for medium green
$define clMEDIUM_GREEN RGB565(0, 240, 100)                                      ' Holds the RGB565 value for medium green
$define clBACKGROUND   RGB565(25, 30, 10)                                       ' Holds the RGB565 background colour value for grey with a hint of green

$define cImage_Width_Elements  6                                                ' The amount of X elements for the digit image data
$define cImage_Height_Elements 130                                              ' The amount of Y elements for the digit image data
$define cImage_Elements $eval (cImage_Width_Elements * cImage_Height_Elements)  ' The amount of element bytes in the image flash memory table
'
' Create global variables and constants and aliases here
'
    Dim bCounter As Byte                                                        ' Holds the count for the NIMO digit display
    Dim wImage_Address As Word                                                  ' Holds the address of a NIMO image flash memory table
    Dim wTBLPTR_SFR As TBLPTRL.Word                                             ' Create a 16-bit SFR from TBLPTRL\H

'-------------------------------------------------------------------------------------------------------
' The main program starts here.
' Display incrementing digits on an emulated NIMO display.
'
Main:
    Setup()                                                                     ' Setup the program and peripherals

    bCounter = 0
    Do                                                                          ' Create a loop
        wImage_Address = CRead16 ImagesTable[bCounter]                          ' Extract an address of a image from the ImagesTable
        NIMO_Digit(wImage_Address)                                              ' Display the digit on the LCD
        Inc bCounter                                                            ' Increment the counter
        If bCounter > 9 Then                                                    ' Has the counter gone over the maximum digit?
            bCounter = 0                                                        ' Yes. So reset it
        EndIf
        DelayMS 1000                                                            ' A delay, so that the digits do not increment too fast
    Loop                                                                        ' Do it forever

'-------------------------------------------------------------------------------------------------------
' Display a lenghtened and width extended digit image with twice the size, read from flash memory, on the graphic LCD
' Input     : pImageAddr (wTBLPTR_SFR) holds the flash memory address of the digit image to display on the LCD
' Output    : None
' Notes     : None
'
Proc NIMO_Digit(pImageAddr As wTBLPTR_SFR)
    Dim wElements  As Word Access = cImage_Elements                             ' Holds the amount of element bytes in the flash table
    Dim bBitCount  As Byte Access                                               ' Holds the amount of bits to rotate, so a byte is scanned
    Symbol cX_Start = 72                                                        ' The start X position of the window
    Symbol cY_Start = 60                                                        ' The start Y position of the window
    Symbol cX_End = cX_Start + (((cImage_Width_Elements * 8) * 2) - 1)          ' Calculate the end X position of the window
    Symbol cY_End = cY_Start + (cImage_Height_Elements - 1)                     ' Calculate the end Y position of the window

    CG9A_WindowXY(cX_Start, cY_Start, cX_End, cY_End)                           ' Create a window for the digit to be placed into
    CG9A_SPI_Start()                                                            ' Start the SPI interface
    Repeat                                                                      ' Create a loop for the digit image's data
        Tblrd*+                                                                 ' Read the pixel data byte into TABLAT
        For bBitCount = 7 DownTo 0                                              ' Create a loop for the 8-bits of the pixel data
            Rol TABLAT                                                          ' Move the MSB of TABLAT into the Carry flag
            If STATUSbits_C = 0 Then                                            ' Is the Carry flag 0?
                CG9A_wPenColour = clBACKGROUND                                  ' Yes. So set the pixel as the background colour
            Else                                                                ' Otherwise...
                CG9A_wPenColour = clMEDIUM_GREEN                                ' Set the pixel as the colour of the digit
            EndIf
            SPI_hWrite16(CG9A_wPenColour)                                       ' \
            SPI_hWrite16(CG9A_wPenColour)                                       ' / Write 2 pixels to the window
        Next
        Dec wElements                                                           ' \ Loop until all the digit image is read and displayed
    Until wElements = 0                                                         ' /
    CG9A_SPI_Finish()                                                           ' Finish the SPI interface
EndProc

'-------------------------------------------------------------------------------------------------------
' Setup the program and peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Clear                                                                       ' Clear all user RAM before the program starts
'
' Setup the SPI1 peripheral (if used)
'
$ifndef _cSOFTWARE_SPI_                                                         ' Is the CG9A01 library using bit-bashed SPI routines?
    PPS_Unlock()                                                                ' No. So Unlock the PPS for the SPI peripheral
    Set_PPSForSCK1(CG9A01_CLK_PPS_Pin)                                          ' Setup the SPI1 peripheral's PPS, CLK for the LCD's SCK pin
    Set_PPSForSDO1(CG9A01_DTA_PPS_Pin)                                          ' Setup the SPI1 peripheral's PPS, SDO pin for the LCD's DTA pin
    Set_PPSForSDI1(Pin_C4)                                                      ' Setup the SPI1 peripheral's PPS, SDI pin (not used but needs to be setup)
    HSPI1_Init_Mode0_MaxMHz()                                                   ' Setup the SPI1 peripheral to operate in Mode 0 at its fastest speed
$endif
    CG9A_Init()                                                                 ' Initialise the CG9A01 LCD
    CG9A_Rotate(2)                                                              ' Rotate the display
    CG9A_Cls(clBACKGROUND)                                                      ' Clear the LCD, with a background colour
    GLCD_Backlight_On()                                                         ' Illuminate the LCD's backlight
EndProc

'------------------------------------------------------------------------------------------------------------
' Setup the config fuses to use the internal oscillator at 64MHz on PIC18FxxK40 devices
' With pins RA6 and RA7 as general purpose I/O
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ                                                     ' HFINTOSC with HFFRQ = 64MHz and CDIV = 1:1
    FEXTOSC = Off                                                               ' External Oscillator not enabled
    WDTE = Off                                                                  ' Watchdog Timer disabled
    CLKOUTEN = Off                                                              ' CLKOUT function is disabled
    CSWEN = On                                                                  ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                                                                 ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR                                                             ' MCLR pin is MCLR function
    PWRTE = On                                                                  ' Power Up Timer enabled
    LPBOREN = Off                                                               ' ULPBOR disabled
    BOREN = Off                                                                 ' Brown-out disabled
    BORV = VBOR_245                                                             ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                                                                   ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                                                               ' PPSLOCK bit can be set and cleared repeatedly (After the unlock sequence)
    STVREN = Off                                                                ' Stack full/underflow will not cause Reset
    Debug = Off                                                                 ' Background debugger disabled
    XINST = Off                                                                 ' Extended Instruction Set and Indexed Addressing Mode disabled
    SCANE = Off                                                                 ' Scanner module is Not available for use. SCANMD bit is ignored
    LVP = On                                                                    ' Low Voltage programming enabled
    WDTCPS = WDTCPS_2                                                           ' Watchdog Divider Ratio 1:128 (4 milliseconds)
    WDTCWS = WDTCWS_7                                                           ' Watchdog Window always open (100%). Software control. Keyed access not required
    WDTCCS = LFINTOSC                                                           ' WDT reference clock is the 31.2kHz HFINTOSC output
    WRT0 = Off                                                                  ' Block 0 (000800-001FFF) not write-protected
    WRT1 = Off                                                                  ' Block 1 (002000-003FFF) not write-protected
    WRTC = Off                                                                  ' Configuration registers (300000-30000B) not write-protected
    WRTB = Off                                                                  ' Boot Block (000000-0007FF) not write-protected
    WRTD = Off                                                                  ' Data EEPROM not write-protected
    Cp = Off                                                                    ' User NVM code protection disabled
    CPD = Off                                                                   ' Data NVM code protection disabled
    EBTR0 = Off                                                                 ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off                                                                 ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTRB = Off                                                                 ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

A video of the NIMO display working is show below, and the source codes for the emulator written in Positron8 BASIC is attached to this post.


Information concerning the NIMO displays can be found here: Wikipedia - NIMO Display Tube

Enjoy using it, as I did creating it.

Regards
Les

JonW

I had never heard of them, here is prety cool video with them working and some history.

top204

I also saw that video Jon, but I tend to ignore the egocentrics on youtube, and with the title having "dangerous" in it, it is simple stupidity, so I skipped over most of it.

Regards
Les


JonW

It had some interesting datasheets and info on it.  $29 in 1971?  expensive