/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** library to drive vacuum fluorescent display using supertex HV518 shift register VFD drivers (code) * @details the current configuration is for a VFD extracted from a Samsung SER-6500 cash register * @file vfd_hv518.c * @author King Kévin * @date 2016 * @note peripherals used: SPI @ref vfd_hv518_spi , GPIO @ref vfd_hv518_gpio , timer @ref vfd_hv518_timer */ /* standard libraries */ #include // standard integer types #include // general utilities /* STM32 (including CM3) libraries */ #include // real-time control clock library #include // general purpose input output library #include // SPI library #include // timer library #include // interrupt handler #include "global.h" // global definitions #include "vfd_hv518.h" // VFD library API /** @defgroup vfd_hv518_gpio GPIO to control supertex HV518 VFD drivers * @{ */ #define VFD_PORT GPIOA /**< GPIO port */ #define VFD_PORT_RCC RCC_GPIOA /**< GPIO port peripheral clock */ #define VFD_STR GPIO6 /**< strobe pin to enable high voltage output, high voltage is output on low */ #define VFD_NLE GPIO4 /**< latch enable pin, stores the shifted data on low, output the parallel data on high */ /** @} */ /** @defgroup vfd_hv518_spi SPI to send data to supertex HV518 VFD drivers * @{ */ #define VFD_SPI_RCC RCC_SPI1 /**< SPI peripheral */ #define VFD_SPI_PORT GPIOA /**< GPIO port */ #define VFD_SPI_PORT_RCC RCC_GPIOA /**< GPIO port peripheral clock */ #define VFD_SPI_IRQ NVIC_SPI1_IRQ /**< SPI peripheral interrupt signal */ #define VFD_SPI_ISR spi1_isr /**< SPI interrupt service routine */ #define VFD_CLK GPIO_SPI1_SCK /**< clock signal */ #define VFD_DIN GPIO_SPI1_MOSI /**< data input, where the data is shifted to */ /** @} */ /** @defgroup vfd_hv518_timer timer for automatic display blocks refresh * @{ */ #define VFD_TIMER_RCC RCC_TIM2 /**< timer peripheral clock */ #define VFD_TIMER_IRQ NVIC_TIM2_IRQ /**< timer interrupt signal */ #define VFD_TIMER_ISR tim2_isr /**< timer interrupt service routine */ /** @} */ /** ASCII characters encoded for the 7 segments digit block * @note starts with space */ static const uint8_t ascii_7segments[] = { 0b00000000, // space 0b00110000, // ! (I) 0b00100010, // " 0b01011100, // # (o) 0b01101101, // $ (s) 0b01010010, // % (/) 0b01111101, // & (6) 0b00100000, // ' 0b00111001, // ( ([) 0b00001111, // ) 0b01110000, // * 0b01000110, // + 0b00010000, // , 0b01000000, // - 0b00010000, // . (,) 0b01010010, // / 0b00111111, // 0 0b00000110, // 1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 0b01001000, // : (=) 0b01001000, // ; (=) 0b01011000, // < 0b01001000, // = 0b01001100, // > 0b01010011, // ? 0b01111011, // @ 0b01110111, // A 0b01111111, // B 0b00111001, // C 0b01011110, // D 0b01111001, // E 0b01110001, // F 0b00111101, // G 0b01110110, // H 0b00110000, // I 0b00011110, // J 0b01110110, // K 0b00111000, // L 0b00110111, // M 0b00110111, // N 0b00111111, // O 0b01110011, // P 0b01101011, // Q 0b00110011, // R 0b01101101, // S 0b01111000, // T 0b00111110, // U 0b00111110, // V (U) 0b00111110, // W (U) 0b01110110, // X (H) 0b01101110, // Y 0b01011011, // Z 0b00111001, // [ 0b01100100, // '\' 0b00001111, // / 0b00100011, // ^ 0b00001000, // _ 0b00000010, // ` 0b01011111, // a 0b01111100, // b 0b01011000, // c 0b01011110, // d 0b01111011, // e 0b01110001, // f 0b01101111, // g 0b01110100, // h 0b00010000, // i 0b00001100, // j 0b01110110, // k 0b00110000, // l 0b01010100, // m 0b01010100, // n 0b01011100, // o 0b01110011, // p 0b01100111, // q 0b01010000, // r 0b01101101, // s 0b01111000, // t 0b00011100, // u 0b00011100, // v (u) 0b00011100, // w (u) 0b01110110, // x 0b01101110, // y 0b01011011, // z 0b00111001, // { ([) 0b00110000, // | 0b00001111, // } ([) 0b01000000, // ~ }; /** font for the 5x7 dot matrix block * @details first value is left-most line, LSB is top dot, MSB is not used * @note from http://sunge.awardspace.com/glcd-sd/node4.html */ static const uint8_t font5x7[][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}, // (space) {0x00, 0x00, 0x5F, 0x00, 0x00}, // ! {0x00, 0x07, 0x00, 0x07, 0x00}, // " {0x14, 0x7F, 0x14, 0x7F, 0x14}, // # {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $ {0x23, 0x13, 0x08, 0x64, 0x62}, // % {0x36, 0x49, 0x55, 0x22, 0x50}, // & {0x00, 0x05, 0x03, 0x00, 0x00}, // ' {0x00, 0x1C, 0x22, 0x41, 0x00}, // ( {0x00, 0x41, 0x22, 0x1C, 0x00}, // ) {0x08, 0x2A, 0x1C, 0x2A, 0x08}, // * {0x08, 0x08, 0x3E, 0x08, 0x08}, // + {0x00, 0x50, 0x30, 0x00, 0x00}, // , {0x08, 0x08, 0x08, 0x08, 0x08}, // - {0x00, 0x60, 0x60, 0x00, 0x00}, // . {0x20, 0x10, 0x08, 0x04, 0x02}, // / {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0 {0x00, 0x42, 0x7F, 0x40, 0x00}, // 1 {0x42, 0x61, 0x51, 0x49, 0x46}, // 2 {0x21, 0x41, 0x45, 0x4B, 0x31}, // 3 {0x18, 0x14, 0x12, 0x7F, 0x10}, // 4 {0x27, 0x45, 0x45, 0x45, 0x39}, // 5 {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6 {0x01, 0x71, 0x09, 0x05, 0x03}, // 7 {0x36, 0x49, 0x49, 0x49, 0x36}, // 8 {0x06, 0x49, 0x49, 0x29, 0x1E}, // 9 {0x00, 0x36, 0x36, 0x00, 0x00}, // : {0x00, 0x56, 0x36, 0x00, 0x00}, // ; {0x00, 0x08, 0x14, 0x22, 0x41}, // < {0x14, 0x14, 0x14, 0x14, 0x14}, // = {0x41, 0x22, 0x14, 0x08, 0x00}, // > {0x02, 0x01, 0x51, 0x09, 0x06}, // ? {0x32, 0x49, 0x79, 0x41, 0x3E}, // @ {0x7E, 0x11, 0x11, 0x11, 0x7E}, // A {0x7F, 0x49, 0x49, 0x49, 0x36}, // B {0x3E, 0x41, 0x41, 0x41, 0x22}, // C {0x7F, 0x41, 0x41, 0x22, 0x1C}, // D {0x7F, 0x49, 0x49, 0x49, 0x41}, // E {0x7F, 0x09, 0x09, 0x01, 0x01}, // F {0x3E, 0x41, 0x41, 0x51, 0x32}, // G {0x7F, 0x08, 0x08, 0x08, 0x7F}, // H {0x00, 0x41, 0x7F, 0x41, 0x00}, // I {0x20, 0x40, 0x41, 0x3F, 0x01}, // J {0x7F, 0x08, 0x14, 0x22, 0x41}, // K {0x7F, 0x40, 0x40, 0x40, 0x40}, // L {0x7F, 0x02, 0x04, 0x02, 0x7F}, // M {0x7F, 0x04, 0x08, 0x10, 0x7F}, // N {0x3E, 0x41, 0x41, 0x41, 0x3E}, // O {0x7F, 0x09, 0x09, 0x09, 0x06}, // P {0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q {0x7F, 0x09, 0x19, 0x29, 0x46}, // R {0x46, 0x49, 0x49, 0x49, 0x31}, // S {0x01, 0x01, 0x7F, 0x01, 0x01}, // T {0x3F, 0x40, 0x40, 0x40, 0x3F}, // U {0x1F, 0x20, 0x40, 0x20, 0x1F}, // V {0x7F, 0x20, 0x18, 0x20, 0x7F}, // W {0x63, 0x14, 0x08, 0x14, 0x63}, // X {0x03, 0x04, 0x78, 0x04, 0x03}, // Y {0x61, 0x51, 0x49, 0x45, 0x43}, // Z {0x00, 0x00, 0x7F, 0x41, 0x41}, // [ {0x02, 0x04, 0x08, 0x10, 0x20}, // '\' {0x41, 0x41, 0x7F, 0x00, 0x00}, // ] {0x04, 0x02, 0x01, 0x02, 0x04}, // ^ {0x40, 0x40, 0x40, 0x40, 0x40}, // _ {0x00, 0x01, 0x02, 0x04, 0x00}, // ` {0x20, 0x54, 0x54, 0x54, 0x78}, // a {0x7F, 0x48, 0x44, 0x44, 0x38}, // b {0x38, 0x44, 0x44, 0x44, 0x20}, // c {0x38, 0x44, 0x44, 0x48, 0x7F}, // d {0x38, 0x54, 0x54, 0x54, 0x18}, // e {0x08, 0x7E, 0x09, 0x01, 0x02}, // f {0x08, 0x14, 0x54, 0x54, 0x3C}, // g {0x7F, 0x08, 0x04, 0x04, 0x78}, // h {0x00, 0x44, 0x7D, 0x40, 0x00}, // i {0x20, 0x40, 0x44, 0x3D, 0x00}, // j {0x00, 0x7F, 0x10, 0x28, 0x44}, // k {0x00, 0x41, 0x7F, 0x40, 0x00}, // l {0x7C, 0x04, 0x18, 0x04, 0x78}, // m {0x7C, 0x08, 0x04, 0x04, 0x78}, // n {0x38, 0x44, 0x44, 0x44, 0x38}, // o {0x7C, 0x14, 0x14, 0x14, 0x08}, // p {0x08, 0x14, 0x14, 0x18, 0x7C}, // q {0x7C, 0x08, 0x04, 0x04, 0x08}, // r {0x48, 0x54, 0x54, 0x54, 0x20}, // s {0x04, 0x3F, 0x44, 0x40, 0x20}, // t {0x3C, 0x40, 0x40, 0x20, 0x7C}, // u {0x1C, 0x20, 0x40, 0x20, 0x1C}, // v {0x3C, 0x40, 0x30, 0x40, 0x3C}, // w {0x44, 0x28, 0x10, 0x28, 0x44}, // x {0x0C, 0x50, 0x50, 0x50, 0x3C}, // y {0x44, 0x64, 0x54, 0x4C, 0x44}, // z {0x00, 0x08, 0x36, 0x41, 0x00}, // { {0x00, 0x00, 0x7F, 0x00, 0x00}, // | {0x00, 0x41, 0x36, 0x08, 0x00}, // } {0b00001000, 0b00000100, 0b00001100, 0b00001000, 0b00000100} // ~ }; /** pictures for the 5x7 dot matrix block * @details first value is left-most line, LSB is top dot, MSB is not used */ static const uint8_t pict5x7[][5] = { {0x08, 0x08, 0x2A, 0x1C, 0x08}, // -> {0x08, 0x1C, 0x2A, 0x08, 0x08}, // <- {0b01110000, 0b01110000, 0b01111010, 0b01111100, 0b01011000}, // bunny side 1 {0b00100000, 0b01110000, 0b01110010, 0b01111100, 0b01011000}, // bunny side 2 {0b00111110, 0b01001001, 0b01010110, 0b01001001, 0b00111110}, // bunny face 1 {0b00111110, 0b01010001, 0b01100110, 0b01010001, 0b00111110}, // bunny face 2 {0b00111000, 0b01010111, 0b01100100, 0b01010111, 0b00111000}, // bunny face 3 {0b00111000, 0b01001111, 0b01010100, 0b01001111, 0b00111000}, // bunny face 4 {0b00111000, 0b01011110, 0b01101000, 0b01011110, 0b00111000}, // bunny face 5 {0b01000001, 0b00110110, 0b00001000, 0b00110110, 0b01000001}, // cross 1 {~0b01000001, ~0b00110110, ~0b00001000, ~0b00110110, ~0b01000001}, // cross 1 negated {0b00100010, 0b00010100, 0b00001000, 0b00010100, 0b00100010}, // cross 2 {~0b00100010, ~0b00010100, ~0b00001000, ~0b00010100, ~0b00100010}, // cross 2 negated {0x00, 0x00, 0x00, 0x00, 0x00} // nothing }; /** the 32 bits values to be shifted out to the VFD driver * @note split into 16 bit for SPI transfer * @note since the bits for digits and matrix are independent, they can be combined * @note we have more matrix (12) than digits (10) */ static uint16_t driver_data[VFD_MATRIX][VFD_DRIVERS*2] = {0}; /** which driver data is being transmitted */ static volatile uint8_t spi_i = 0; /** which grid/part to activate * @note digits and matrix can be combined */ static volatile uint8_t vfd_grid = 0; /** the bits used for selecting then digit and 7 segment anodes * @note for the second driver */ static const uint32_t digit_mask = 0x00fffff0; void vfd_digit(uint8_t nb, char c) { if (!(nb=' ') { // only take printable characters uint8_t i = c-' '; // get index for character if (i>16); // write back data (most significant half) } void vfd_matrix(uint8_t nb, char c) { // check the matrix exists if (!(nb=' ')) { // only take printable characters uint8_t i = c-' '; // get index for character if (i0x7f) { // the non ASCII character are used for pictures uint8_t i = c-0x80; // get index for character if (i>16; } } void vfd_clear(void) { for (uint8_t i=0; i