0

Original Board: Raspberry Pi 4 model B New Board: Up Squared 7100 LCD: NHD-PCB12832A1Zrev2

import RPi.GPIO as GPIO
from ascii_values import ASCII168
import icon_manager

# Mapping based on BCM (Broadcom) pinout from https://pinout.xyz/
LCD_CS = 8
LCD_RST = 22
LCD_A0 = 23
LCD_CLK = 11
LCD_SI = 10


class LCD:
    _instance = None

    def __new__(cls, *args, **kwargs):
        """Ensure only one instance of the LCD class exists."""
        if cls._instance is None:
            cls._instance = super(LCD, cls).__new__(cls)
            cls._instance._initialize_lcd()
        return cls._instance

    def __del__(self):
        GPIO.cleanup()

    def _initialize_lcd(self):
        self.io_init()
        self.lcd_init()
        GPIO.setwarnings(False)

    def cleanup(self):
        GPIO.cleanup()

    def io_init(self):
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(LCD_CS, GPIO.OUT)
        GPIO.setup(LCD_RST, GPIO.OUT)
        GPIO.setup(LCD_A0, GPIO.OUT)
        GPIO.setup(LCD_CLK, GPIO.OUT)
        GPIO.setup(LCD_SI, GPIO.OUT)

    def lcd_init(self):
        GPIO.output(LCD_CS, True)
        GPIO.output(LCD_RST, False)
        GPIO.output(LCD_RST, True)
        self.lcd_transfer_data(0xe2, 0)  # Internal reset

        self.lcd_transfer_data(0xa2, 0)  # Sets the LCD drive voltage bias ratio
        ##A2: 1/9 bias
        ##A3: 1/7 bias (ST7565V)

        self.lcd_transfer_data(0xa0, 0)  # Sets the display RAM address SEG output correspondence
        ##A0: normal
        ##A1: reverse

        self.lcd_transfer_data(0xc8, 0)  # Select COM output scan direction
        ##C0~C7: normal direction
        ##C8~CF: reverse direction

        self.lcd_transfer_data(0xa4, 0)  # Display all points ON/OFF
        ##A4: normal display
        ##A5: all points ON

        self.lcd_transfer_data(0xa6, 0)  # Sets the LCD display normal/inverted
        ##A6: normal
        ##A7: inverted

        self.lcd_transfer_data(0x2F, 0)  # Select internal power supply operating mode
        ##28~2F: Operating mode

        self.lcd_transfer_data(0x40, 0)  # Display start line set
        ##40~7F: Display start address

        self.lcd_transfer_data(0x20, 0)  # V5 voltage regulator internal resistor ratio set (contrast)
        ##20~27: small~large

        self.lcd_transfer_data(0x81, 0)  # Electronic volume mode set
        ##81: Set the V5 output voltage

        self.lcd_transfer_data(0x30, 0)  # Electronic volume register set
        ##00~3F: electronic volume register

        self.lcd_transfer_data(0b10101111, 0)  # Display ON/OFF
        ##    0b10101111: ON
        ##    0b10101110: OFF
        self.lcd_clear()

    def display_icon(self, x_pos, y_pos, icon, negative=False):
        icon_matrix = icon_manager.format_icon(icon, negative)

        if not isinstance(icon_matrix, list) or not all(isinstance(i, int) for i in icon_matrix):
            raise TypeError("icon_matrix must be a list of integers")

        quadrant_offsets = [
            (0, 0, 0, 8),  # Quadrant 1: Top-left
            (1, 0, 8, 16),  # Quadrant 2: Bottom-left
            (0, 8, 16, 24),  # Quadrant 3: Top-right
            (1, 8, 24, 32),  # Quadrant 4: Bottom-right
        ]

        for y_offset, x_offset, start_idx, end_idx in quadrant_offsets:
            self.lcd_set_page(y_pos + y_offset, x_pos + x_offset)
            # Transfer the entire quadrant data at once
            data = icon_matrix[start_idx:end_idx]
            self.lcd_transfer_data_bulk(data)

    def lcd_ascii168_string(self, x_pos, y_pos, string):
        string_len = len(string)
        for i in range(0, string_len):
            self.lcd_ascii168(x_pos + i * 8, y_pos, ord(string[i]) - 32)

    def lcd_ascii168(self, x_pos, y_pos, char):
        self.lcd_set_page(y_pos, x_pos)

        for i in range(0, 8):
            self.lcd_transfer_data(ASCII168[char][i], 1)

        self.lcd_set_page(y_pos + 1, x_pos)
        for i in range(8, 16):
            self.lcd_transfer_data(ASCII168[char][i], 1)

    def lcd_clear(self):
        GPIO.output(LCD_CS, False)
        for i in range(0, 8):
            self.lcd_set_page(i, 0)
            for j in range(0, 128):
                self.lcd_transfer_data(0x00, 1)
        GPIO.output(LCD_CS, True)

    def lcd_set_page(self, page, column):
        lsb = column & 0x0f
        msb = column & 0xf0
        msb >>= 4
        msb |= 0x10
        page |= 0xb0
        self.lcd_transfer_data(page, 0)
        self.lcd_transfer_data(msb, 0)
        self.lcd_transfer_data(lsb, 0)

    def lcd_transfer_data(self, value, A0):
        GPIO.output(LCD_CS, False)
        GPIO.output(LCD_CLK, True)
        if (A0):
            GPIO.output(LCD_A0, True)
        else:
            GPIO.output(LCD_A0, False)
        self.lcd_byte(value)
        GPIO.output(LCD_CS, True)

    def lcd_transfer_data_bulk(self, data_list):
        """Transfers a list of data in bulk, minimizing GPIO operations."""
        GPIO.output(LCD_CS, False)
        GPIO.output(LCD_CLK, True)

        for data in data_list:
            GPIO.output(LCD_A0, True)  # Data mode
            self.lcd_byte(data)

        GPIO.output(LCD_CS, True)

    def lcd_byte(self, bits):
        tmp = bits
        for i in range(0, 8):
            GPIO.output(LCD_CLK, False)
            if (tmp & 0x80):
                GPIO.output(LCD_SI, True)
            else:
                GPIO.output(LCD_SI, False)
            tmp = (tmp << 1)
            GPIO.output(LCD_CLK, True)

I am able to send data to display on the LCD using the RPi.GPIO package; however, I want to run the code on an up squared board and the RPi.GPIO package does not work on a non-raspberry pi.

I am using an UP Squared 7100 that has the same 40 pin header as a Raspberry Pi. I am trying to connect to the LCD using the spidev package

1

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.