From 50a374b2d80016f36c1c9119e679e585501a9737 Mon Sep 17 00:00:00 2001 From: Advaith Menon Date: Tue, 20 Jan 2026 15:02:00 -0500 Subject: [PATCH] Initial commit * Reorganize Espressif hello_world example * Add a .gitignore file * Write a basic README --- .gitignore | 24 +++++++++++++++++++ CMakeLists.txt | 8 +++++++ LICENSE | 20 ++++++++++++++++ README.adoc | 20 ++++++++++++++++ main/CMakeLists.txt | 3 +++ main/main.c | 52 ++++++++++++++++++++++++++++++++++++++++ pytest_hello_world.py | 55 +++++++++++++++++++++++++++++++++++++++++++ sdkconfig.ci | 0 8 files changed, 182 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.adoc create mode 100644 main/CMakeLists.txt create mode 100644 main/main.c create mode 100644 pytest_hello_world.py create mode 100644 sdkconfig.ci diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2067b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.pytest_cache/ +__pycache__/ + +# esp-idf built binaries +build/ +build_*_*/ +sdkconfig +sdkconfig.old + +# idf-ci build run output +build_summary_*.xml +app_info_*.txt +size_info_*.txt + +# pytest-embedded log folder +pytest_embedded_log/ + +# idf-component-manager output +dependencies.lock + +.vscode/ +managed_components/ + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..75a2178 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(ulcd_nolib) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9e6b0e6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2026 Advaith Menon + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..44b2071 --- /dev/null +++ b/README.adoc @@ -0,0 +1,20 @@ += Writing to the uLCD without a library +Advaith Menon ; Diego Fratta +v0.1.0, 2026-01-20 +:toc: +:link-goldelox: https://github.com/4dsystems/Goldelox-Serial-Linux-Library +:link-spe: https://resources.4dsystems.com.au/manuals/workshop4/serial/goldelox/#text-and-string-commands +:link-repository: https://git.devinivas.org/?p=4dulcd-nolibrary.git;a=summary + +== Abstract +This document details the necessary steps to write to the uLCD without using the +libraries provided by 4D Systems. Most of this code was written by +reverse-engineering the {link-goldelox}[Linux library] provided by 4D Systems. +This is not necessary - 4D provides {link-spe}[comprehensive +documentation] on the opcodes and how to use them. It is left as an exercise to +the reader to replicate the same without referring to library code. + +== Code +Code can be found at Advaith's personal Git server. The link is as follows: +{link-repository}. To clone the repository, run `git clone +git://git.devinivas.org/4dulcd-nolibrary.git`. diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..6692d62 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "main.c" + PRIV_REQUIRES spi_flash + INCLUDE_DIRS "") diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..7010f3e --- /dev/null +++ b/main/main.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "esp_system.h" + +void app_main(void) +{ + printf("Hello world!\n"); + + /* Print chip information */ + esp_chip_info_t chip_info; + uint32_t flash_size; + esp_chip_info(&chip_info); + printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", + (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", + (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); + + unsigned major_rev = chip_info.revision / 100; + unsigned minor_rev = chip_info.revision % 100; + printf("silicon revision v%d.%d, ", major_rev, minor_rev); + if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { + printf("Get flash size failed"); + return; + } + + printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); + + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/pytest_hello_world.py b/pytest_hello_world.py new file mode 100644 index 0000000..eb02bd7 --- /dev/null +++ b/pytest_hello_world.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import hashlib +import logging +from typing import Callable + +import pytest +from pytest_embedded_idf.dut import IdfDut +from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_qemu.app import QemuApp +from pytest_embedded_qemu.dut import QemuDut + + +@pytest.mark.generic +@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target']) +def test_hello_world(dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]) -> None: + dut.expect('Hello world!') + log_minimum_free_heap_size() + + +@pytest.mark.host_test +@idf_parametrize('target', ['linux'], indirect=['target']) +def test_hello_world_linux(dut: IdfDut) -> None: + dut.expect('Hello world!') + + +@pytest.mark.host_test +@pytest.mark.macos_shell +@idf_parametrize('target', ['linux'], indirect=['target']) +def test_hello_world_macos(dut: IdfDut) -> None: + dut.expect('Hello world!') + + +def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None: + sha256 = hashlib.sha256() + with open(app.elf_file, 'rb') as f: + sha256.update(f.read()) + sha256_expected = sha256.hexdigest() + + logging.info(f'ELF file SHA256: {sha256_expected}') + logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}') + + # the app reports only the first several hex characters of the SHA256, check that they match + if not sha256_expected.startswith(sha256_reported): + raise ValueError('ELF file SHA256 mismatch') + + +@pytest.mark.host_test +@pytest.mark.qemu +@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) +def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None: + sha256_reported = dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8') + verify_elf_sha256_embedding(app, sha256_reported) + + dut.expect('Hello world!') diff --git a/sdkconfig.ci b/sdkconfig.ci new file mode 100644 index 0000000..e69de29 -- 2.47.3