/* 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 */ /* standard libraries */ #include // standard integer types #include // standard I/O facilities #include // standard utilities #include // standard streams #include // error number utilities /* STM32 (including CM3) libraries */ #include // real-time control clock library #include // general purpose input output library #include // vector table definition #include // Cortex M3 utilities /* own libraries */ #include "main.h" // board definitions #include "usart.h" // USART utilities #include "usb_cdcacm.h" // USB CDC ACM utilities /* default output (i.e. for printf) */ int _write(int file, char *ptr, int len) { int i; if (file == STDOUT_FILENO || file == STDERR_FILENO) { for (i = 0; i < len; i++) { if (ptr[i] == '\n') { // add carrier return before line feed. this is recommended for most UART terminals usart_putchar_nonblocking('\r'); // a second line feed doesn't break the display cdcacm_putchar('\r'); // a second line feed doesn't break the display } usart_putchar_nonblocking(ptr[i]); // send byte over USART cdcacm_putchar(ptr[i]); // send byte over USB } return i; } errno = EIO; return -1; } static void gpio_setup(void) { rcc_periph_clock_enable(LED_RCC); //enable clock for LED gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull' rcc_periph_clock_enable(VFD_RCC); //enable clock for VFD gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_STR); // set VFD pin to 'output push-pull' gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_NLE); // set VFD pin to 'output push-pull' gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_CLK); // set VFD pin to 'output push-pull' gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_DIN); // set VFD pin to 'output push-pull' } /* the ten seven segments + dot displays * actually they also have a comma and underline, but we want to save space */ //static uint8_t digits[10]; /* the twelve 5x7 dot matrix displays * the last column dot/bit is not used, making them byte aligned */ //static uint8_t dots[12][5]; /* the three 32 bit to be shifted out to the VFD controller */ static uint32_t vfd_data[3]; /* shift out the VFD data */ static void vfd_shift(void) { gpio_clear(VFD_PORT, VFD_NLE); // do not latch data gpio_set(VFD_PORT, VFD_CLK); // clock is idle high for (uint8_t i=0; i 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, // ~ }; /* put digit into memory */ static void vfd_digit(uint8_t nb, char c) { // there are only 10 digits if (nb>9) { return; } vfd_data[0] = 0; vfd_data[1] = 1<<(4+(9-nb)); // select digit /* encode segment * here the bit order (classic 7 segment + underline and dot) * 3_ * 8|9_|4 * 7|6_|5.1 * 0_2, * */ if (false) { // add the underline (not encoded) vfd_data[1] |= (1<<(14)); } if (c&0x80) { // add the dot (encoded in the 8th bit) vfd_data[1] |= (1<<(15)); } if (false) { // add the comma (not encoded) vfd_data[1] |= (1<<(16)); } if (((c&0x7f)<' ') || ((c&0x7f)>'~')) { // unknown ASCII character vfd_data[1] |= (ascii_7segments[' '-' ']<<(17)); // add empty segments to memory } else { vfd_data[1] |= (ascii_7segments[c-' ']<<(17)); // add encoded segments to memory } vfd_data[2] = 0; } static void vfd_matrix(uint8_t nb, char c) { (void)c; // there are only 12 matrix if (nb>11) { return; } else if (nb<4) { vfd_data[0] = 0; vfd_data[1] = 1<<(3-nb); // select digit } else { vfd_data[0] = 1<<(35-nb); // select digit vfd_data[1] = 0; } vfd_data[1] |= 0xff000000; vfd_data[2] = 0xffffffff; } int main(void) { SCB_VTOR = (uint32_t) 0x08002000; // relocate vector table because of the bootloader rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock gpio_setup(); // setup main inputs/outputs usart_setup(); // setup USART (for printing) cdcacm_setup(); // setup USB CDC ACM (for printing) setbuf(stdout, NULL); // set standard out buffer to NULL to immediately print setbuf(stderr, NULL); // set standard error buffer to NULL to immediately print printf("welcome to the STM32F1 CuVoodoo display driver\n"); gpio_set(VFD_PORT, VFD_STR); // disable HV output gpio_clear(VFD_PORT, VFD_NLE); // do not latch data gpio_set(VFD_PORT, VFD_CLK); // clock is idle high bool vfd_transmit = false; uint8_t digit = 0; uint8_t c = 0; vfd_digit(0,0); /* blink the LED with every transmitted character */ while (1) { while (usart_received) { // echo every received character //gpio_toggle(LED_PORT, LED_PIN); // toggle LED printf("%c",usart_getchar()); // transmit receive character vfd_transmit = true; } while (cdcacm_received) { // echo every received character //gpio_toggle(LED_PORT, LED_PIN); // toggle LED printf("%c",cdcacm_getchar()); // transmit receive character vfd_transmit = true; } while (vfd_transmit) { vfd_transmit = false; c = digit+'0'; vfd_matrix(digit,c); vfd_shift(); digit = (digit+1)%12; // let the fluorescence glow up a bit for (uint32_t i = 0; i < 0x2000; i++) { __asm__("nop"); } } __WFI(); // go to sleep } return 0; }