Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support is needed for interfacing the NHD-C12864 display, which uses 8080 parallel communication, with the Pico-SDK framework. #2579

Open
mahesh-slx opened this issue Jan 23, 2025 · 4 comments

Comments

@mahesh-slx
Copy link

mahesh-slx commented Jan 23, 2025

I am using a Pico W board with the Pico-SDK framework and a display module, NHD-C12864B2Z-RN-FBW, which features an ST7565 controller and operates using 8080 parallel communication. I have included my code below. While the code compiles successfully and the initScreen() function causes some random pixels to light up, nothing is being displayed on the screen.

My source file: main.cpp

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include <u8g2.h>

#define PIN_DB0 0
#define PIN_DB1 1
#define PIN_DB2 2
#define PIN_DB3 3
#define PIN_DB4 4
#define PIN_DB5 5
#define PIN_DB6 6
#define PIN_DB7 7
#define PIN_CS 20
#define PIN_DC 18 // A0
#define PIN_WR 17
#define PIN_RD 16
#define PIN_RST 19

#define HIGH 1
#define LOW 0

u8g2_t u8g2;
uint8_t current_page = 0;

void sendCommand(uint8_t command)
{
    gpio_put(PIN_CS, LOW);
    gpio_put(PIN_DC, LOW);
    gpio_put(PIN_WR, LOW);
    const int dataPins[8] = {PIN_DB7, PIN_DB6, PIN_DB5, PIN_DB4, PIN_DB3, PIN_DB2, PIN_DB1, PIN_DB0};
    for (int i = 0; i < 8; i++)
    {
        gpio_put(dataPins[i], (command >> (7 - i)) & 0x01);
    }
    gpio_put(PIN_WR, HIGH);
    gpio_put(PIN_CS, HIGH);
    sleep_ms(10);
}

uint8_t u8x8_byte_pico_parallel_8080(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    uint8_t *data;
    switch (msg)
    {
    case U8X8_MSG_BYTE_SEND:
        data = (uint8_t *)arg_ptr;
        while (arg_int--)
        {
            sendCommand(*data++);
        }
        break;
    case U8X8_MSG_BYTE_INIT:
        u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
        break;
    case U8X8_MSG_BYTE_SET_DC:
        u8x8_gpio_SetDC(u8x8, arg_int);
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
        break;
    default:
        return 0;
    }
    return 1;
}

uint8_t u8x8_gpio_and_delay_pico(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_GPIO_AND_DELAY_INIT:
        for (int i = 0; i < 8; i++)
        {
            gpio_init(i);
            gpio_set_dir(i, GPIO_OUT);
        }
        gpio_init(PIN_RST);
        gpio_init(PIN_DC);
        gpio_init(PIN_CS);
        gpio_init(PIN_RD);
        gpio_init(PIN_WR);
        gpio_set_dir(PIN_RST, GPIO_OUT);
        gpio_set_dir(PIN_DC, GPIO_OUT);
        gpio_set_dir(PIN_CS, GPIO_OUT);
        gpio_set_dir(PIN_RD, GPIO_OUT);
        gpio_set_dir(PIN_WR, GPIO_OUT);
        gpio_put(PIN_RST, 1);
        break;
    case U8X8_MSG_DELAY_MILLI:
        sleep_ms(arg_int);
        break;
    case U8X8_MSG_GPIO_CS:
        gpio_put(PIN_CS, arg_int);
        break;
    case U8X8_MSG_GPIO_DC:
        gpio_put(PIN_DC, arg_int);
        break;
    case U8X8_MSG_GPIO_RESET:
        gpio_put(PIN_RST, arg_int);
        break;
    default:
        u8x8_SetGPIOResult(u8x8, 1);
        break;
    }
    return 1;
}

void draw_page()
{
    u8g2_ClearBuffer(&u8g2);
    u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr);
    u8g2_DrawStr(&u8g2, 10, 30, "ST7565 128x64 Display");
    u8g2_SendBuffer(&u8g2);
}

void display_sequence()
{
    u8g2_Setup_st7565_nhd_c12864_f(&u8g2, U8G2_R2, u8x8_byte_pico_parallel_8080, u8x8_gpio_and_delay_pico);
    u8g2_InitDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0);
}

void initScreen()
{
    gpio_put(PIN_RD, HIGH);
    gpio_put(PIN_WR, HIGH);
    gpio_put(PIN_CS, LOW);
    gpio_put(PIN_RST, LOW);
    sleep_ms(150);
    gpio_put(PIN_RST, HIGH);
    sleep_ms(150);

    sendCommand(0x0a2); // LCD bias set to 1/9
    sendCommand(0x0a0); // ADC set to reverse
    sendCommand(0x0c8); // COM set to reverse
    sendCommand(0x025); // resistor ratio set to large
    sendCommand(0x081); // electronic volume set (contrast)
    sendCommand(0x010); // electronic volume set
    sendCommand(0x02f); // operating mode - all power control circuits on
    sendCommand(0x0f8); // set booster ratio
    sendCommand(0x000); // booster ratio to 4x
    sendCommand(0x040); // start line set to 0
    sendCommand(0x0af); // display on

    sleep_ms(10);
}

int main()
{
    stdio_init_all();
    display_sequence();

    gpio_set_dir(PIN_RD, GPIO_OUT);
    gpio_put(PIN_RD, HIGH);
    initScreen();

    while (1)
    {
        draw_page();
        sleep_ms(5000);
    }
}

my cmake file:

# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.0)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.1.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
    include(${picoVscode})
endif()
# ====================================================================================
cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Initialise pico_sdk from installed location
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.0)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.1.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
    include(${picoVscode})
endif()

set(PICO_BOARD pico_w CACHE STRING "Board type")
include(pico_sdk_import.cmake)

project(btremote C CXX ASM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wl,--gc-sections")

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Fetch U8g2 from GitHub
include(FetchContent)
FetchContent_Declare(
    u8g2
    GIT_REPOSITORY https://github.com/olikraus/u8g2.git
    GIT_TAG ef893381f9385df6e3351483272c31ccb89172e3
    GIT_SHALLOW YES
)
FetchContent_MakeAvailable(u8g2)

# Collect all source files from U8g2
file(GLOB U8G2_SOURCES
    ${u8g2_SOURCE_DIR}/csrc/*.c
    ${u8g2_SOURCE_DIR}/cppsrc/*.cpp
)

# Add the main executable
add_executable(btremote
    src/main.cpp
    ${U8G2_SOURCES} # Include U8g2 source files directly
)

# Include U8g2 headers
target_include_directories(btremote PRIVATE
    ${u8g2_SOURCE_DIR}/csrc
    ${u8g2_SOURCE_DIR}/cppsrc
)

# Link standard libraries and other dependencies
target_link_libraries(btremote PRIVATE pico_stdlib hardware_spi pico_unique_id pico_multicore pico_stdio_usb)

# Additional settings
target_compile_options(btremote PRIVATE -Wall -Wextra)
target_link_options(btremote PRIVATE -Xlinker --print-memory-usage)
pico_add_extra_outputs(btremote)
pico_enable_stdio_usb(btremote 1)
pico_enable_stdio_uart(btremote 0)

I referred to this discussion for display initialization and this thread for implementing the delay function.

I am wondering if you have any idea how to make this work.

Thank you.

@olikraus
Copy link
Owner

void sendCommand(uint8_t command)
{
    gpio_put(PIN_CS, LOW);   // don't do this here, u8g2 will take care
    gpio_put(PIN_DC, LOW);  // wrong, this will overwrite the setting done by u8g2
    gpio_put(PIN_WR, LOW);
    const int dataPins[8] = {PIN_DB7, PIN_DB6, PIN_DB5, PIN_DB4, PIN_DB3, PIN_DB2, PIN_DB1, PIN_DB0};
    for (int i = 0; i < 8; i++)
    {
        gpio_put(dataPins[i], (command >> (7 - i)) & 0x01);
    }
    gpio_put(PIN_WR, HIGH);
    gpio_put(PIN_CS, HIGH);  // also not required 
    sleep_ms(10);
}

@mahesh-slx
Copy link
Author

mahesh-slx commented Jan 23, 2025

Thanks @olikraus

I am now able to display the data with the changes you suggested.

The text is not appearing all at once; instead, it is being drawn pixel by pixel.

Can you help me in solving this?

@olikraus
Copy link
Owner

Remove the sleep_ms call.

@mahesh-slx
Copy link
Author

Yeah, after removing sleep_ms call, it is working now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants