diff --git a/components/display/CMakeLists.txt b/components/display/CMakeLists.txt new file mode 100644 index 0000000..ebf0aa8 --- /dev/null +++ b/components/display/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "display_driver.c" + INCLUDE_DIRS "." + REQUIRES driver fatal +) diff --git a/components/display/display_driver.c b/components/display/display_driver.c new file mode 100644 index 0000000..05fa5e2 --- /dev/null +++ b/components/display/display_driver.c @@ -0,0 +1,100 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#include "display_driver.h" + +#include "fatal.h" + +#include "driver/gpio.h" +#include "esp_log.h" +#include + +#define TAG "Display driver" + +#define PIN_BITMASK(n) ((uint64_t)1 << n) + +#define DIGIT_1_SELECT_PIN GPIO_NUM_15 +#define DIGIT_2_SELECT_PIN GPIO_NUM_2 +#define DIGIT_3_SELECT_PIN GPIO_NUM_0 +#define DIGIT_4_SELECT_PIN GPIO_NUM_4 + +#define SEGMENT_A_PIN GPIO_NUM_16 +#define SEGMENT_B_PIN GPIO_NUM_23 +#define SEGMENT_C_PIN GPIO_NUM_19 +#define SEGMENT_D_PIN GPIO_NUM_5 +#define SEGMENT_E_PIN GPIO_NUM_17 +#define SEGMENT_F_PIN GPIO_NUM_22 +#define SEGMENT_G_PIN GPIO_NUM_21 +#define SEGMENT_DP_PIN GPIO_NUM_18 + +static const gpio_num_t digit_select_pins[DISPLAY_DIGIT_COUNT] = { + [DISPLAY_DIGIT_1] = DIGIT_1_SELECT_PIN, + [DISPLAY_DIGIT_2] = DIGIT_2_SELECT_PIN, + [DISPLAY_DIGIT_3] = DIGIT_3_SELECT_PIN, + [DISPLAY_DIGIT_4] = DIGIT_4_SELECT_PIN, +}; + +static const gpio_num_t segment_pins[DISPLAY_SEGMENT_COUNT] = { + [DISPLAY_SEGMENT_A] = SEGMENT_A_PIN, + [DISPLAY_SEGMENT_B] = SEGMENT_B_PIN, + [DISPLAY_SEGMENT_C] = SEGMENT_C_PIN, + [DISPLAY_SEGMENT_D] = SEGMENT_D_PIN, + [DISPLAY_SEGMENT_E] = SEGMENT_E_PIN, + [DISPLAY_SEGMENT_F] = SEGMENT_F_PIN, + [DISPLAY_SEGMENT_G] = SEGMENT_G_PIN, + [DISPLAY_SEGMENT_DP] = SEGMENT_DP_PIN, +}; + +static DisplayDigit active_digit; + +DisplayState display_state; + +void display_driver_init() +{ + esp_err_t error; + + memset(&display_state, 0, sizeof(DisplayState)); + + active_digit = DISPLAY_DIGIT_1; + + uint64_t digit_select_pin_bitmask = 0; + for (unsigned i = 0; i < DISPLAY_DIGIT_COUNT; ++i) + digit_select_pin_bitmask |= PIN_BITMASK(digit_select_pins[i]); + const gpio_config_t digit_select_gpio_config = { + .pin_bit_mask = digit_select_pin_bitmask, + .mode = GPIO_MODE_OUTPUT, + }; + error = gpio_config(&digit_select_gpio_config); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error configuring digit select pins: %04x", error); + FATAL(); + } + + uint64_t segment_pin_bitmask = 0; + for (unsigned i = 0; i < DISPLAY_SEGMENT_COUNT; ++i) + segment_pin_bitmask |= PIN_BITMASK(segment_pins[i]); + const gpio_config_t segment_gpio_config = { + .pin_bit_mask = segment_pin_bitmask, + .mode = GPIO_MODE_OUTPUT_OD, + .pull_down_en = GPIO_PULLDOWN_ENABLE, + }; + error = gpio_config(&segment_gpio_config); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error configuring segment pins: %04x", error); + FATAL(); + } +} + +void display_driver_task(void *arg) +{ + (void)gpio_set_level(digit_select_pins[active_digit], 0); + active_digit = (active_digit + 1) % DISPLAY_DIGIT_COUNT; + (void)gpio_set_level(digit_select_pins[active_digit], 1); + + for (unsigned i = 0; i < DISPLAY_SEGMENT_COUNT; ++i) { + (void)gpio_set_level( + segment_pins[i], display_state[active_digit][i] ? 0 : 1); + } +} diff --git a/components/display/display_driver.h b/components/display/display_driver.h new file mode 100644 index 0000000..7dcd600 --- /dev/null +++ b/components/display/display_driver.h @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Camden Dixie O'Brien + */ + +#ifndef DISPLAY_DRIVER_H +#define DISPLAY_DRIVER_H + +#include + +typedef enum { + DISPLAY_SEGMENT_A, + DISPLAY_SEGMENT_B, + DISPLAY_SEGMENT_C, + DISPLAY_SEGMENT_D, + DISPLAY_SEGMENT_E, + DISPLAY_SEGMENT_F, + DISPLAY_SEGMENT_G, + DISPLAY_SEGMENT_DP, + DISPLAY_SEGMENT_COUNT, +} DisplaySegment; + +typedef enum { + DISPLAY_DIGIT_1, + DISPLAY_DIGIT_2, + DISPLAY_DIGIT_3, + DISPLAY_DIGIT_4, + DISPLAY_DIGIT_COUNT, +} DisplayDigit; + +typedef bool DisplayDigitState[DISPLAY_SEGMENT_COUNT]; +typedef DisplayDigitState DisplayState[DISPLAY_DIGIT_COUNT]; + +/** + * The current state of the display. + */ +extern DisplayState display_state; + +/** + * Initialize the display driver. + */ +void display_driver_init(); + +/** + * Driver update task; should be ran regularly with a short period. + */ +void display_driver_task(void *arg); + +#endif