/* 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 . * */ /* Copyright (c) 2016 King Kévin */ /* this library is used to drive the vacuum fluorescent display extracted from a Samsung SER-6500 cash register * it uses three chained supertex HV518 shift register VFD drivers */ /* 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 /* supertex HV518 VFD driver pins */ /* port on which the pins to control the supertex HV518 VFD driver are * we use port A because of the SPI interface */ #define VFD_PORT GPIOA #define VFD_PORT_RCC RCC_GPIOA /* SPI port to use */ #define VFD_SPI SPI1 #if (VFD_SPI==SPI1) #define VFD_SPI_RCC RCC_SPI1 #define VFD_SPI_IRQ NVIC_SPI1_IRQ #elif (VFD_SPI==SPI2) #define VFD_SPI_RCC RCC_SPI2 #define VFD_SPI_IRQ NVIC_SPI2_IRQ #endif /* strobe pin to enable high voltage output * high voltage is output on low * drive using a GPIO PA6 (normally MISO) */ #define VFD_STR GPIO6 /* latch enable pin * store the shifted data on low * output the parallel data on high * use GPIO (PA4) (NSS does not work as SS) */ #define VFD_NLE GPIO4 /* clock signal * drive using SPI SCK (PA5) */ #define VFD_CLK GPIO_SPI1_SCK /* data input, where the data is shifted to * drive using SPI MOSI (PA7) */ #define VFD_DIN GPIO_SPI1_MOSI /* timer for automatic refresh */ #define VFD_TIMER TIM2 #if (VFD_TIMER==TIM2) #define VFD_TIMER_RCC RCC_TIM2 #define VFD_TIMER_IRQ NVIC_TIM2_IRQ #elif (VFD_TIMER==TIM3) #define VFD_TIMER_RCC RCC_TIM3 #define VFD_TIMER_IRQ NVIC_TIM3_IRQ #elif (VFD_TIMER==TIM4) #define VFD_TIMER_RCC RCC_TIM4 #define VFD_TIMER_IRQ NVIC_TIM4_IRQ #elif (VFD_TIMER==TIM5) #define VFD_TIMER_RCC RCC_TIM5 #define VFD_TIMER_IRQ NVIC_TIM5_IRQ #endif /* ASCII characters encoded for 7 segments display * 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 display * from http://sunge.awardspace.com/glcd-sd/node4.html * first value is left-most line * LSB is top dot, MSB is not used */ 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 display * 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 * split into 16 bit for SPI transfer * since the bits for digits and matrix are independent, they can be combined * we have more matrix (12) than digits (10) */ static uint16_t driver_data[VFD_MATRIX][VFD_DRIVERS*2] = {0}; static volatile uint8_t spi_i = 0; // which driver data is being transmitted static volatile uint8_t vfd_grid = 0; // which grid/part to activate (single digits and matrix can be combined) static const uint32_t digit_mask = 0x00fffff0; // the bits used for selecting then digit and 7 segment anodes (for the second driver) /* set digit to ASCII character * use the MSB of to enable the dot */ 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) } /* set dot matrix to ASCII character * non ASCII characters are used for pictures */ 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; } } /* clear VFD display */ void vfd_clear(void) { for (uint8_t i=0; i