// // Created by erki on 17/02/24. // #include "vfd_driver.hpp" #include #include #include #include namespace { template constexpr T bitValue(const T& shift) { return T(T(1) << shift); } constexpr auto SEG_A = bitValue(0); constexpr auto SEG_B = bitValue(1); constexpr auto SEG_C = bitValue(2); constexpr auto SEG_D = bitValue(3); constexpr auto SEG_E = bitValue(4); constexpr auto SEG_F = bitValue(5); constexpr auto SEG_G = bitValue(6); constexpr auto SEG_DEGREE = bitValue(7); constexpr auto SEG_MINUS = SEG_G; constexpr auto SEG_DOT = bitValue(7); constexpr auto GRID_0 = bitValue(8); constexpr auto GRID_1 = bitValue(9); constexpr auto GRID_2 = bitValue(10); constexpr auto GRID_3 = bitValue(11); constexpr auto GRID_4 = bitValue(12); constexpr auto GRID_5 = bitValue(13); constexpr auto GRID_6 = bitValue(14); constexpr auto GRID_7 = bitValue(15); constexpr auto GRID_8 = bitValue(16); constexpr auto DIGIT_0 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F; constexpr auto DIGIT_1 = SEG_B | SEG_C; constexpr auto DIGIT_2 = SEG_A | SEG_B | SEG_D | SEG_E | SEG_G; constexpr auto DIGIT_3 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_G; constexpr auto DIGIT_4 = SEG_B | SEG_C | SEG_F | SEG_G; constexpr auto DIGIT_5 = SEG_A | SEG_C | SEG_D | SEG_F | SEG_G; constexpr auto DIGIT_6 = SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_7 = SEG_A | SEG_B | SEG_C; constexpr auto DIGIT_8 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_9 = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G; constexpr auto DIGIT_A = SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_B = SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_C = SEG_A | SEG_D | SEG_E | SEG_F; constexpr auto DIGIT_D = SEG_B | SEG_C | SEG_D | SEG_E | SEG_G; constexpr auto DIGIT_E = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_F = SEG_A | SEG_E | SEG_F | SEG_G; constexpr auto DIGIT_ALL = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DOT; } VfdDriver::VfdDriver(spi_host_device_t spi_host, Hal::Gpio load, Hal::Gpio blank, transaction_cb_t spi_post_up_cb) : load_(load) , blank_(blank) { auto dev_config = Utility::zeroInitialized(); dev_config.clock_source = SPI_CLK_SRC_DEFAULT; dev_config.clock_speed_hz = 800000; // 800kHz dev_config.spics_io_num = -1; dev_config.queue_size = 3; dev_config.pre_cb = nullptr; dev_config.post_cb = spi_post_up_cb; ESP_ERROR_CHECK(spi_bus_add_device(spi_host, &dev_config, &spi_device_)); display_data_.fill(0); } esp_err_t VfdDriver::defaultInitializeBus(spi_host_device_t spi_host, gpio_num_t clock, gpio_num_t mosi, std::optional miso) { spi_bus_config_t bus_config; bus_config.sclk_io_num = clock; bus_config.mosi_io_num = mosi; bus_config.miso_io_num = miso ? *miso : -1; bus_config.quadwp_io_num = -1; bus_config.quadhd_io_num = -1; bus_config.max_transfer_sz = 0; bus_config.flags = 0; bus_config.intr_flags = 0; return spi_bus_initialize(spi_host, &bus_config, SPI_DMA_CH_AUTO); } void VfdDriver::update() { load_.set(false); const std::uint32_t raw = getRawCharAndAdvance_(); spiWrite_(raw); load_.set(true); } void VfdDriver::updateNonBlocking() { load_.set(false); const std::uint32_t raw = getRawCharAndAdvance_(); spiWriteNonBlocking_(raw); } void VfdDriver::spiWrite_(std::uint32_t raw) { std::memcpy(buffer_data_.data(), &raw, buffer_data_.size()); auto transaction = Utility::zeroInitialized(); transaction.length = DISPLAY_BUFFER_LEN * 8; transaction.tx_buffer = buffer_data_.data(); transaction.rx_buffer = buffer_data_.data(); spi_device_polling_transmit(spi_device_, &transaction); } void VfdDriver::spiWriteNonBlocking_(std::uint32_t raw) { std::memcpy(buffer_data_.data(), &raw, buffer_data_.size()); auto transaction = Utility::zeroInitialized(); transaction.length = DISPLAY_BUFFER_LEN * 8; transaction.tx_buffer = buffer_data_.data(); transaction.rx_buffer = buffer_data_.data(); spi_device_queue_trans(spi_device_, &transaction, 0); } std::uint32_t VfdDriver::getRawCharAndAdvance_() { constexpr std::uint32_t grids[] = { GRID_8, GRID_7, GRID_6, GRID_5, GRID_4, GRID_3, GRID_2, GRID_1, GRID_0 }; auto char_to_code = [](char c) -> std::uint32_t { c = std::isalpha(c) ? std::tolower(c) : c; constexpr std::uint32_t characters[] = { DIGIT_A, DIGIT_B, DIGIT_C, DIGIT_D, DIGIT_E, DIGIT_F }; constexpr std::uint32_t numbers[] = { DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3, DIGIT_4, DIGIT_5, DIGIT_6, DIGIT_7, DIGIT_8, DIGIT_9 }; if (c <= 'f' && c >= 'a') return characters[c - 'a']; else if (c <= '9' && c >= '0') return numbers[c - '0']; else if (c == '.') return SEG_DOT; else if (c == '-') return SEG_MINUS; else if (c == '*') return SEG_DEGREE; else if (c == ' ') return 0; else return 0; }; const char& to_write = display_data_[display_index_]; const std::uint32_t raw = grids[display_index_] | char_to_code(to_write); display_index_++; if (display_index_ >= DISPLAY_BUFFER_LEN) display_index_ = 0; return raw; }