Electronics > Repair

Advantest R6581 VFD replacement

<< < (4/14) > >>

IanJ:

--- Quote from: dietert1 on October 28, 2024, 05:52:55 pm ---Here is a zip archive with that H730 LTDC TFT replacement display project. As i have some ready to use PCBs left i thought about making them into kits, but i don't have time to support that.

Regards, Dieter

--- End quote ---

Hi,

Any chance you can export the gerbers?
Looks like and older Eagle binary .brd file which Kicad etc can't open.
Thanks,
Ian.

dietert1:
Yes, it's Eagle version 4.16. Can't you just order the PCB using the board file? I never had to supply Gerber files. The PCB is four layers, size 65 x 40 mm.
In case somebody wants to design his own PCB i added a schematic. R7 .. R12 are three voltage dividers for the 5V logic data inputs. Later i checked that those STM32H730 pins are 5 V tolerant and omitted R10 .. R12.

Regards, Dieter

branadic:

--- Quote ---Hi,

Any chance you can export the gerbers?
Looks like and older Eagle binary .brd file which Kicad etc can't open.
Thanks,
Ian.
--- End quote ---

Workflow is easy, open it with Eagle 7 Lite, save it and you can import it to KiCAD. Attached is the Eagle 7 board file.

-branadic-

IanJ:
Hi all,

So far so good, a day spent on Visual Studio and I have mapped the incoming bitmap data to ASCII characters, getting ready for driving a TFT display.

Screenshot attached, a live debug session in VS with the STM32 and that's "+ 1.2345638    VDC" appearing in the code (G1 to G18) from the R6581T.

Next, I'll deal with the AUX display G19 to G47, and the annunciators after that.
From there get a LT7680 TFT driver loaded and start send data to the new display and playing with fonts etc.

Again, completely impossible without MickleT's great work on the original reverse engineering.

PS. C is pretty new to me albeit I've done loads of C++, so it's not too far away.

Ian.

IanJ:
Incase anyone is interested, here's my MAIN.C code which creates ASCII vars/arrays for the main, aux and annunciators.
It's working as far as I can monitor the STM32 live vars in VS2022 and they are all working.
There may be some individual ASCII character issues, I still need to verify some of them i.e. the lower case ones and adjust the hex accordingly.

PS. I am not a software programmer, it's a WIP, so please be gentle!

Next step is the TFT LCD driver......at which point I will disable the existing OLED I/O as I need the pins.

Ian.


--- Code: ---/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  * Original code by MickleT, this version modded by IanJ,
  * for 4.58" 960x320 TFT LCD (ST7701S) and using LT7680 adaptor
  * Visual Studio 2022 with VisualGDB plugin:
  * To upload HEX from VS2022 = BUILD then PROGRAM AND START WITHOUT DEBUGGING
  * Use LIVE WATCH to view variables live debug
  *
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "spi.h"
#include "gpio.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

/* Private includes ----------------------------------------------------------*/
#include "SSD1322_OLED_lib/SSD1322_HW_Driver.h"
#include "SSD1322_OLED_lib/SSD1322_API.h"
#include "SSD1322_OLED_lib/SSD1322_GFX.h"


/* Private variables ---------------------------------------------------------*/
static char main_display_debug[LINE1_LEN + 1]; // Main display debug string
#define FONT_HEIGHT 7

// Buffers for each LCD graphical item
char LCD_buffer_packets[128];  // For packet data
char LCD_buffer_bitmaps[128];  // For decoded bitmap data
char LCD_buffer_chars[128];    // For decoded characters
char G1, G2, G3, G4, G5, G6, G7, G8, G9, G10, G11, G12, G13, G14, G15, G16, G17, G18;   // Main
char G19, G20, G21, G22, G23, G24, G25, G26, G27, G28, G29, G30, G31, G32, G33, G34, G35, G36, G37, G38, G39, G40, G41, G42, G43, G44, G45, G46, G47; // Aux
_Bool Annunciators[18]; // Array for MAIN annunciators. The order on LCD left to right = 8,7,6,5,4,3,2,1,017,16,15,14,13,12,11,10,9
_Bool AnnunciatorsReordered[19]; // G1 to G18 in left-to-right order


//******************************************************************************

// SPI receive buffer for packets data
volatile uint8_t rx_buffer[PACKET_WIDTH*PACKET_COUNT];

// Array with character bitmaps
uint8_t chars[CHAR_COUNT][CHAR_HEIGHT];

// Array with annunciators flags (boolean)
uint8_t flags[CHAR_COUNT];

// When scanning the display, the order of the characters output is not sequential due to optimization of the VFD PCB layout.
// The Reorder[] array is used as a lookup table to determine the correct position of characters.
const uint8_t Reorder[PACKET_COUNT] = { 8, 7, 6, 5, 4, 3, 2, 1, 0, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 17, 16, 15, 14, 13, 12, 11, 10, 9, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36 };
// Order of data to the display (effectively into the shift registers):
// 8, 7, 6, 5, 4, 3, 2, 1, 0,                                               // MAIN: G9 to G1
// 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,  // AUX: G19 to G36
// 17, 16, 15, 14, 13, 12, 11, 10, 9,                                       // MAIN: G18 to G10
// 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36                               // AUX: G47 to G37
// But the actual display left to right:
// G1 to G18 - MAIN
// G19 to G47 - AUX
// AnnunciatorsReordered[1] to AnnunciatorsReordered[18]


// Used for line-by-line recoding and scaling of the characters of the main display line.
// All 32 possible variants of a 5-pixel wide character bitmap string are converted into
// the corresponding 10 OLED display pixels with 16 color gradations and packed into 5 bytes.
const uint8_t Upscale1[32][5] = {   
        { 0x00, 0x00, 0x00, 0x00, 0 }, { 0x00, 0x00, 0x00, 0x00, 0xFF }, { 0x00, 0x00, 0x00, 0xFF, 0 }, { 0x00, 0x00, 0x00, 0xFF, 0xFF },
{ 0x00, 0x00, 0xFF, 0x00, 0 }, { 0x00, 0x00, 0xFF, 0x00, 0xFF }, { 0x00, 0x00, 0xFF, 0xFF, 0 }, { 0x00, 0x00, 0xFF, 0xFF, 0xFF },
{ 0x00, 0xFF, 0x00, 0x00, 0 }, { 0x00, 0xFF, 0x00, 0x00, 0xFF }, { 0x00, 0xFF, 0x00, 0xFF, 0 }, { 0x00, 0xFF, 0x00, 0xFF, 0xFF },
{ 0x00, 0xFF, 0xFF, 0x00, 0 }, { 0x00, 0xFF, 0xFF, 0x00, 0xFF }, { 0x00, 0xFF, 0xFF, 0xFF, 0 }, { 0x00, 0xFF, 0xFF, 0xFF, 0xFF },
{ 0xFF, 0x00, 0x00, 0x00, 0 }, { 0xFF, 0x00, 0x00, 0x00, 0xFF }, { 0xFF, 0x00, 0x00, 0xFF, 0 }, { 0xFF, 0x00, 0x00, 0xFF, 0xFF },
{ 0xFF, 0x00, 0xFF, 0x00, 0 }, { 0xFF, 0x00, 0xFF, 0x00, 0xFF }, { 0xFF, 0x00, 0xFF, 0xFF, 0 }, { 0xFF, 0x00, 0xFF, 0xFF, 0xFF },
{ 0xFF, 0xFF, 0x00, 0x00, 0 }, { 0xFF, 0xFF, 0x00, 0x00, 0xFF }, { 0xFF, 0xFF, 0x00, 0xFF, 0 }, { 0xFF, 0xFF, 0x00, 0xFF, 0xFF },
{ 0xFF, 0xFF, 0xFF, 0x00, 0 }, { 0xFF, 0xFF, 0xFF, 0x00, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF, 0 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
};

// Used for line-by-line recoding and scaling of the characters of the auxiliary display line.
// All 32 possible variants of a 5-pixel wide character bitmap string are converted into
// the corresponding 5 OLED display pixels with 16 color gradations and packed into 3 bytes.
const uint8_t Upscale2[32][3] = {
{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xF0 }, { 0x00, 0x0F, 0x00 }, { 0x00, 0x0F, 0xF0 }, { 0x00, 0xF0, 0x00 }, { 0x00, 0xF0, 0xF0 },
{ 0x00, 0xFF, 0x00 }, { 0x00, 0xFF, 0xF0 }, { 0x0F, 0x00, 0x00 }, { 0x0F, 0x00, 0xF0 }, { 0x0F, 0x0F, 0x00 }, { 0x0F, 0x0F, 0xF0 },
{ 0x0F, 0xF0, 0x00 }, { 0x0F, 0xF0, 0xF0 }, { 0x0F, 0xFF, 0x00 }, { 0x0F, 0xFF, 0xF0 }, { 0xF0, 0x00, 0x00 }, { 0xF0, 0x00, 0xF0 },
{ 0xF0, 0x0F, 0x00 }, { 0xF0, 0x0F, 0xF0 }, { 0xF0, 0xF0, 0x00 }, { 0xF0, 0xF0, 0xF0 }, { 0xF0, 0xFF, 0x00 }, { 0xF0, 0xFF, 0xF0 },
{ 0xFF, 0x00, 0x00 }, { 0xFF, 0x00, 0xF0 }, { 0xFF, 0x0F, 0x00 }, { 0xFF, 0x0F, 0xF0 }, { 0xFF, 0xF0, 0x00 }, { 0xFF, 0xF0, 0xF0 },
    { 0xFF, 0xFF, 0x00 }, { 0xFF, 0xFF, 0xF0 }
};

// A 256x5 pixel sprite (128x5 bytes) is used to draw the annunciators by copying rectangular areas into the OLED buffer.
const uint8_t Sprites[5][128] = {
        { 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0x00,0x00,0x0F,0x00,0xF0,0xF0,0xFF,0xF0,0xF0,0x00,0xF0,0x00,0xF0,0x0F,0xFF,0x00,0xF0,0x0F,0x0F,
          0x0F,0x0F,0x00,0xF0,0x00,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0xF0,0x00,0xF0,0x0F,0x00,0xFF,0xF0,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0x00,0x0F,0xFF,0x0F,0xF0,0x0F,0xF0,0x00,
          0x0F,0x0F,0x00,0xF0,0xFF,0xF0,0xF0,0x00,0xFF,0x0F,0xF0,0x00,0xF0,0x00,0xFF,0x00,0xFF,0x00,0xF0,0x0F,0xF0,0x0F,0xFF,0x0F,0x00,0xF0,0xFF,0xF0,0x0F,0x00,0xF0,0x00,
          0x00,0xFF,0xF0,0x0F,0xF0,0x0F,0xFF,0x0F,0x00,0x0F,0x00,0xFF,0xF0,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0xFF,0xF0,0xF0,0x0F,0x00,0x0F,0xFF,0x0F,0xF0,0x0F,0xFF,0x00,0x00 },
        { 0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x0F,0x0F,0x00,0xFF,0x0F,0x0F,
          0x0F,0x0F,0x00,0xF0,0x00,0x0F,0x00,0xF0,0xF0,0x00,0x00,0xFF,0x0F,0xF0,0xF0,0xF0,0x0F,0x00,0x00,0xF0,0x0F,0x00,0x00,0x0F,0x00,0x0F,0x00,0x0F,0x0F,0x0F,0x0F,0x00,
          0x0F,0x0F,0xF0,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x0F,0x0F,0x0F,0x0F,0x00,0x0F,0x0F,0x0F,0x00,
          0x0F,0x00,0x00,0x0F,0x0F,0x0F,0x00,0x0F,0xF0,0xFF,0x00,0x0F,0x00,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0x0F,0x00,0xFF,0x0F,0x00,0x0F,0x00,0x0F,0x0F,0x0F,0x0F,0x00,0x00 },
        { 0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0x00,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0x00,0xFF,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x0F,0xFF,0x00,0xF0,0xFF,0x0F,
          0x0F,0x0F,0x00,0xF0,0x00,0x0F,0x00,0xF0,0xFF,0x00,0x00,0xF0,0xF0,0xF0,0xFF,0xF0,0x0F,0x00,0x00,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x0F,0xF0,0x0F,0x0F,0x0F,0x0F,0x00,
          0x0F,0x0F,0x0F,0xF0,0xFF,0x0F,0x0F,0x00,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0xF0,0xF0,0xFF,0x0F,0xFF,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x0F,0x0F,0x0F,0x0F,
          0x0F,0x0F,0xF0,0x0F,0x0F,0x0F,0xF0,0x0F,0x0F,0x0F,0x00,0x0F,0x00,0xF0,0x0F,0xF0,0x00,0x00,0xF0,0x0F,0x00,0xF0,0xFF,0x00,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x00 },
        { 0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x00,0xF0,0x0F,0x0F,0x0F,0x00,0x00,0xF0,0x0F,0x0F,
          0x0F,0x0F,0x00,0xF0,0x00,0x0F,0x00,0xF0,0xF0,0x00,0x00,0xF0,0x00,0xF0,0xF0,0xF0,0x0F,0x00,0x00,0xF0,0x0F,0x00,0x0F,0x00,0x00,0x0F,0x00,0x0F,0xF0,0x0F,0xF0,0x00,
          0x0F,0x0F,0x00,0xF0,0xF0,0x0F,0x0F,0x00,0xF0,0x0F,0xF0,0x0F,0x0F,0x00,0xFF,0x00,0xF0,0x0F,0x0F,0x0F,0xF0,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x0F,0x0F,0x0F,0x00,
          0x0F,0x00,0xF0,0x0F,0xF0,0x0F,0x00,0x0F,0x00,0x0F,0x00,0x0F,0x00,0xF0,0x0F,0x0F,0x00,0x00,0xF0,0x0F,0x00,0xF0,0x0F,0x00,0x00,0x0F,0x0F,0xF0,0x0F,0x0F,0x00,0x00 },
        { 0x00,0x00,0x00,0xF0,0xF0,0xF0,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x00,0xF0,0xF0,0xFF,0xF0,0x0F,0x00,0xF0,0x00,0xFF,0xF0,0xF0,0x0F,0x00,0x00,0xF0,0x0F,0x0F,
          0xFF,0x0F,0xF0,0xFF,0x00,0x0F,0xFF,0x00,0xF0,0x00,0x00,0xF0,0x00,0xF0,0xF0,0xF0,0x0F,0x00,0x00,0xF0,0x0F,0x00,0xFF,0xFF,0x00,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,
          0x0F,0x0F,0x00,0xF0,0xF0,0x00,0xF0,0x00,0xF0,0x0F,0x0F,0x00,0xF0,0x00,0xF0,0xF0,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0xF0,0xF0,0x0F,0x00,0x0F,0xF0,0xF0,0x00,
          0x00,0xFF,0xF0,0x0F,0x0F,0x0F,0xFF,0x0F,0x00,0x0F,0x00,0x0F,0x00,0xFF,0x0F,0x0F,0x00,0x00,0xFF,0x0F,0x00,0xF0,0x0F,0x00,0x0F,0xFF,0x0F,0x0F,0x0F,0xF0,0xF0,0x00 } };

// Declare bytes array for a OLED frame buffer.
// Dimensions are divided by 2 because one byte contains two 4-bit grayscale pixels
uint8_t tx_buffer[64 * 256 / 2];

// Flag indicating finish of SPI transmission to OLED
volatile uint8_t SPI1_TX_completed_flag = 1;

// Flag indicating finish of SPI start-up initialization
volatile uint8_t Init_Completed_flag = 0;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);


//******************************************************************************

// Buffer to store the converted string representation of the main display line
//char main_display_line[CHAR_COUNT + 1]; // +1 for null terminator
static char main_display_line[CHAR_COUNT + 1]; // Static ensures scope is global within the file

//SPI transmission finished interrupt callback
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == SPI1)
    {
        SPI1_TX_completed_flag = 1;
    }
}
//******************************************************************************
static uint8_t InverseByte(uint8_t a)
{
    a = ((a & 0x55) << 1) | ((a & 0xAA) >> 1);
    a = ((a & 0x33) << 2) | ((a & 0xCC) >> 2);
    return (a >> 4) | (a << 4);
}


//******************************************************************************
// Function to map character bitmaps to ASCII characters
typedef struct {
    uint8_t bitmap[7]; // 7 bytes for 5x7 character bitmaps
    char ascii;        // Corresponding ASCII character
} BitmapChar;


// Font data: 96 characters, 7 bytes per character (each row)
const BitmapChar bitmap_characters[] = {
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ' '},  // Space
    {{0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04}, '!'},  // 0x21, !
    {{0x09, 0x09, 0x12, 0x00, 0x00, 0x00, 0x00}, '"'},  // 0x22, "
    {{0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A}, '#'},  // 0x23, #
    {{0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04}, '$'},  // 0x24, $
    {{0x19, 0x19, 0x02, 0x04, 0x08, 0x13, 0x13}, '%'},  // 0x25, %
    {{0x04, 0x0A, 0x0A, 0x0A, 0x15, 0x12, 0x0D}, '&'},  // 0x26, &
    {{0x04, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00}, '\''}, // 0x27, '
    {{0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02}, '('},  // 0x28, (
    {{0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08}, ')'},  // 0x29, )
    {{0x04, 0x15, 0x0E, 0x1F, 0x0E, 0x15, 0x04}, '*'},  // 0x2A, *
    {{0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00}, '+'},  // 0x2B, +
    {{0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x08}, ','},  // 0x2C, ,
    {{0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00}, '-'},  // 0x2D, -
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C}, '.'},  // 0x2E, .
    {{0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10}, '/'},  // 0x2F, /
    {{0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E}, '0'},  // 0x30, 0
    {{0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E}, '1'},  // 0x31, 1
    {{0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F}, '2'},  // 0x32, 2
    {{0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E}, '3'},  // 0x33, 3
    {{0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02}, '4'},  // 0x34, 4
    {{0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E}, '5'},  // 0x35, 5
    {{0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E}, '6'},  // 0x36, 6
    {{0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08}, '7'},  // 0x37, 7
    {{0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E}, '8'},  // 0x38, 8
    {{0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C}, '9'},  // 0x39, 9
    {{0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, ':'},  // 0x3A, :
    {{0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x04, 0x08}, ';'},  // 0x3B, ;
    {{0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02}, '<'},  // 0x3C, <
    {{0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00}, '='},  // 0x3D, =
    {{0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08}, '>'},  // 0x3E, >
    {{0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04}, '?'},  // 0x3F, ?
    {{0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0F}, '@'},  // 0x40, @
    {{0x04, 0x0A, 0x11, 0x11, 0x1F, 0x11, 0x11}, 'A'},  // 0x41, A
    {{0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, 'B'},  // 0x42, B
    {{0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E}, 'C'},  // 0x43, C
    {{0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C}, 'D'},  // 0x44, D
    {{0x1F, 0x10, 0x10, 0x1C, 0x10, 0x10, 0x1F}, 'E'},  // 0x45, E
    {{0x1F, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10}, 'F'},  // 0x46, F
    {{0x0E, 0x11, 0x10, 0x10, 0x13, 0x11, 0x0F}, 'G'},  // 0x47, G
    {{0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, 'H'},  // 0x48, H
    {{0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E}, 'I'},  // 0x49, I
    {{0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02}, 'J'},  // 0x4A, J
    {{0x11, 0x11, 0x13, 0x15, 0x19, 0x11, 0x11}, 'K'},  // 0x4B, K
    {{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F}, 'L'},  // 0x4C, L
    {{0x11, 0x1B, 0x1F, 0x1F, 0x11, 0x11, 0x11}, 'M'},  // 0x4D, M
    {{0x11, 0x1B, 0x1F, 0x1F, 0x1B, 0x11, 0x11}, 'N'},  // 0x4E, N
    {{0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, 'O'},  // 0x4F, O
    {{0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10}, 'P'},  // 0x50, P
    {{0x0E, 0x11, 0x11, 0x11, 0x11, 0x13, 0x0E}, 'Q'},  // 0x51, Q
    {{0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11}, 'R'},  // 0x52, R
    {{0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E}, 'S'},  // 0x53, S
    {{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, 'T'},  // 0x54, T
    {{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, 'U'},  // 0x55, U
    {{0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04}, 'V'},  // 0x56, V
    {{0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x11, 0x11}, 'W'},  // 0x57, W
    {{0x11, 0x11, 0x0A, 0x04, 0x04, 0x0A, 0x11}, 'X'},  // 0x58, X
    {{0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04}, 'Y'},  // 0x59, Y
    {{0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F}, 'Z'},  // 0x5A, Z
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, '['},  // 0x5B, [
    {{0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04}, '\\'}, // 0x5C, \
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ']'},  // 0x5D, ]
    {{0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01}, '^'},  // 0x5E, ^
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}, '_'},  // 0x5F, _
    {{0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00}, '`'},  // 0x60, `
    {{0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F}, 'a'},  // 0x61, a
    {{0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x0E}, 'b'},  // 0x62, b
    {{0x00, 0x00, 0x0E, 0x10, 0x10, 0x10, 0x0E}, 'c'},  // 0x63, c
    {{0x01, 0x01, 0x0D, 0x13, 0x11, 0x11, 0x0E}, 'd'},  // 0x64, d
    {{0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0F}, 'e'},  // 0x65, e
    {{0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x08}, 'f'},  // 0x66, f
    {{0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x1F}, 'g'},  // 0x67, g
    {{0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11}, 'h'},  // 0x68, h
    {{0x08, 0x00, 0x08, 0x18, 0x08, 0x08, 0x1C}, 'i'},  // 0x69, i
    {{0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C}, 'j'},  // 0x6A, j
    {{0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12}, 'k'},  // 0x6B, k
    {{0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C}, 'l'},  // 0x6C, l
    {{0x00, 0x00, 0x1A, 0x15, 0x15, 0x15, 0x15}, 'm'},  // 0x6D, m
    {{0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11}, 'n'},  // 0x6E, n
    {{0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E}, 'o'},  // 0x6F, o
    {{0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10}, 'p'},  // 0x70, p
    {{0x00, 0x00, 0x0D, 0x13, 0x0F, 0x01, 0x01}, 'q'},  // 0x71, q
    {{0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10}, 'r'},  // 0x72, r
    {{0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x1E}, 's'},  // 0x73, s
    {{0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06}, 't'},  // 0x74, t
    {{0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D}, 'u'},  // 0x75, u
    {{0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04}, 'v'},  // 0x76, v
    {{0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A}, 'w'},  // 0x77, w
    {{0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11}, 'x'},  // 0x78, x
    {{0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E}, 'y'},  // 0x79, y
    {{0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F}, 'z'},  // 0x7A, z
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, '{'},  // 0x7B, {
    {{0x01, 0x02, 0x04, 0x00, 0x04, 0x02, 0x01}, '|'},  // 0x7C, |
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, '}'},  // 0x7D, }
    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, '~'},  // 0x7E, ~
};


// Convert a 5x7 bitmap to an ASCII character
// The bitmap (7 rows of 5 bits each) is compared row by row against the font_data.
// The comparison involves the 7 rows of the bitmap against the corresponding 7 rows in each font_data entry.
char BitmapToChar(const uint8_t *bitmap) {
    // Iterate over the bitmap_characters array
    for (int i = 0; i < sizeof(bitmap_characters) / sizeof(BitmapChar); i++) {
        // Compare the input bitmap with the current character's bitmap
        if (memcmp(bitmap, bitmap_characters[i].bitmap, FONT_HEIGHT) == 0) {
            return bitmap_characters[i].ascii; // Return the matching ASCII character
        }
    }
    // If no match is found, return '?'
    return '?';
}






//******************************************************************************

// Each character on the display is encoded by a matrix of 40 bits packed
// into 5 consecutive bytes. 5x7=35 bits (S1-S35) define the pixel image of the character,
// 1 bit (S36) is the annunciator, 4 bits are not used. To optimize VFD PCB routing,
// the bit order in packets is shuffled:
//
// S17 S16 S15 S14 S13 S12 S11 S10
// S9  S8  S7  S6  S5  S4  S3  S2
// S1  S36 0   0   0   0   S35 S34
// S33 S32 S31 S30 S29 S28 S27 S26
// S25 S24 S23 S22 S21 S20 S19 S18
//
// The Packets_to_chars function sorts the character bitmap, extracts the annunciator
// flag, and stores the result in separate arrays chars[][] and flags[]
//
// 0 0 0 S1  S2  S3  S4  S5
// 0 0 0 S6  S7  S8  S9  S10
// 0 0 0 S11 S12 S13 S14 S15
// 0 0 0 S16 S17 S18 S19 S20
// 0 0 0 S21 S22 S23 S24 S25
// 0 0 0 S26 S27 S28 S29 S30
// 0 0 0 S31 S32 S33 S34 S35
//
void Packets_to_chars(void)
{
    for (int i = 0; i < PACKET_COUNT; i++) { 
        uint8_t d0 = rx_buffer[i * PACKET_WIDTH + 0];
        uint8_t d1 = rx_buffer[i * PACKET_WIDTH + 1];
        uint8_t d2 = rx_buffer[i * PACKET_WIDTH + 2];
        uint8_t d3 = rx_buffer[i * PACKET_WIDTH + 3];
        uint8_t d4 = rx_buffer[i * PACKET_WIDTH + 4];
       
        chars[Reorder[i]][0] = 0x1F & InverseByte((d1 << 4) | ((d2 & 0x80) >> 4));
        chars[Reorder[i]][1] = 0x1F & InverseByte((d0 << 7) | ((d1 & 0xF0) >> 1));
        chars[Reorder[i]][2] = 0x1F & InverseByte((d0 & 0xFE) << 2);
        chars[Reorder[i]][3] = 0x1F & InverseByte(((d0 & 0xC0) >> 3) | (d4 << 5));
        chars[Reorder[i]][4] = 0x1F & InverseByte(d4 & 0xF8);
        chars[Reorder[i]][5] = 0x1F & InverseByte(d3 << 3);
        chars[Reorder[i]][6] = 0x1F & InverseByte((d2 << 6) | ((d3 & 0xE0) >> 2));
        flags[Reorder[i]] = (d2 & 0x40) == 0x40;

        // Update annunciator boolean array for MAIN annunciators (G1 to G18)
        if (i < 18) {
            Annunciators[i] = flags[Reorder[i]];
        }

   
    }
    // Null-terminate the main display line string
    main_display_line[LINE1_LEN] = '\0';
}


void ReorderAnnunciators(void) {
    // Map Annunciators[] to AnnunciatorsReordered[] for left-to-right order.
    AnnunciatorsReordered[1] = Annunciators[8];  // G1
    AnnunciatorsReordered[2] = Annunciators[7];  // G2
    AnnunciatorsReordered[3] = Annunciators[6];  // G3
    AnnunciatorsReordered[4] = Annunciators[5];  // G4
    AnnunciatorsReordered[5] = Annunciators[4];  // G5
    AnnunciatorsReordered[6] = Annunciators[3];  // G6
    AnnunciatorsReordered[7] = Annunciators[2];  // G7
    AnnunciatorsReordered[8] = Annunciators[1];  // G8
    AnnunciatorsReordered[9] = Annunciators[0];  // G9
    AnnunciatorsReordered[10] = Annunciators[17]; // G10
    AnnunciatorsReordered[11] = Annunciators[16]; // G11
    AnnunciatorsReordered[12] = Annunciators[15]; // G12
    AnnunciatorsReordered[13] = Annunciators[14]; // G13
    AnnunciatorsReordered[14] = Annunciators[13]; // G14
    AnnunciatorsReordered[15] = Annunciators[12]; // G15
    AnnunciatorsReordered[16] = Annunciators[11]; // G16
    AnnunciatorsReordered[17] = Annunciators[10]; // G17
    AnnunciatorsReordered[18] = Annunciators[9];  // G18
}


void Main_Aux_TFT_Display(void) {
    // Clear LCD buffers
    memset(LCD_buffer_packets, 0, sizeof(LCD_buffer_packets));
    memset(LCD_buffer_bitmaps, 0, sizeof(LCD_buffer_bitmaps));
    memset(LCD_buffer_chars, 0, sizeof(LCD_buffer_chars));

    ReorderAnnunciators();  // re-order the annunciators so Annunnciator[1] is above G1
char annunciator_debug[256] = "Annunciators: "; // Buffer for annunciator state debug

    for (int i = 0; i <= 17; i++) {      // G1 to G18
        // Use already-decoded data from Packets_to_chars
        uint8_t *bitmap = chars[i]; // Get the bitmap for this character
        char ascii_char = BitmapToChar(bitmap); // Convert bitmap to ASCII character

        // MAIN Update individual variables
        if (i == 0) G1 = ascii_char;
        else if (i == 1) G2 = ascii_char;
        else if (i == 2) G3 = ascii_char;
        else if (i == 3) G4 = ascii_char;
        else if (i == 4) G5 = ascii_char;
        else if (i == 5) G6 = ascii_char;
        else if (i == 6) G7 = ascii_char;
        else if (i == 7) G8 = ascii_char;
        else if (i == 8) G9 = ascii_char;
        else if (i == 9) G10 = ascii_char;
        else if (i == 10) G11 = ascii_char;
        else if (i == 11) G12 = ascii_char;
        else if (i == 12) G13 = ascii_char;
        else if (i == 13) G14 = ascii_char;
        else if (i == 14) G15 = ascii_char;
        else if (i == 15) G16 = ascii_char;
        else if (i == 16) G17 = ascii_char;
        else if (i == 17) G18 = ascii_char;
   
        // Append MAIN to debug buffers for additional debugging
        snprintf(LCD_buffer_bitmaps + strlen(LCD_buffer_bitmaps),
                 sizeof(LCD_buffer_bitmaps) - strlen(LCD_buffer_bitmaps),
                 "%d : [%02X, %02X, %02X, %02X, %02X, %02X, %02X]\n",
                 i, bitmap[0], bitmap[1], bitmap[2], bitmap[3],
                 bitmap[4], bitmap[5], bitmap[6]);
   
            // Append annunciator states to debug string
        snprintf(annunciator_debug + strlen(annunciator_debug),
                 sizeof(annunciator_debug) - strlen(annunciator_debug),
                 "G%d=%s ", i + 1, Annunciators[i] ? "ON" : "OFF");
        }

    // Null-terminate the Main display debug string
    main_display_debug[LINE1_LEN] = '\0';

    for (int i = 18; i <= 46; i++) {      // G19 to G47
        // Use already-decoded data from Packets_to_chars
        uint8_t *bitmap = chars[i]; // Get the bitmap for this character
        char ascii_char = BitmapToChar(bitmap); // Convert bitmap to ASCII character
   
    // AUX Update individual variables
        if (i == 18) G19 = ascii_char;
        else if (i == 19) G20 = ascii_char;
        else if (i == 20) G21 = ascii_char;
        else if (i == 21) G22 = ascii_char;
        else if (i == 22) G23 = ascii_char;
        else if (i == 23) G24 = ascii_char;
        else if (i == 24) G25 = ascii_char;
        else if (i == 25) G26 = ascii_char;
        else if (i == 26) G27 = ascii_char;
        else if (i == 27) G28 = ascii_char;
        else if (i == 28) G29 = ascii_char;
        else if (i == 29) G30 = ascii_char;
        else if (i == 30) G31 = ascii_char;
        else if (i == 31) G32 = ascii_char;
        else if (i == 32) G33 = ascii_char;
        else if (i == 33) G34 = ascii_char;
        else if (i == 34) G35 = ascii_char;
        else if (i == 35) G36 = ascii_char;
        else if (i == 36) G37 = ascii_char;
        else if (i == 37) G38 = ascii_char;
        else if (i == 38) G39 = ascii_char;
        else if (i == 39) G40 = ascii_char;
        else if (i == 40) G41 = ascii_char;
        else if (i == 41) G42 = ascii_char;
        else if (i == 42) G43 = ascii_char;
        else if (i == 43) G44 = ascii_char;
        else if (i == 44) G45 = ascii_char;
        else if (i == 45) G46 = ascii_char;
        else if (i == 46) G47 = ascii_char;

        // Append AUX to debug buffers for additional debugging
        snprintf(LCD_buffer_bitmaps + strlen(LCD_buffer_bitmaps),
                 sizeof(LCD_buffer_bitmaps) - strlen(LCD_buffer_bitmaps),
                 "%d : [%02X, %02X, %02X, %02X, %02X, %02X, %02X]\n",
                 i, bitmap[0], bitmap[1], bitmap[2], bitmap[3],
                 bitmap[4], bitmap[5], bitmap[6]);
        }


    // Null-terminate the Aux display debug string
    main_display_debug[LINE2_LEN] = '\0';
}



//************************************************************************************************************************************************************


// Main
int main(void)
{

// MCU Configuration--------------------------------------------------------

// Reset of all peripherals, Initializes the Flash interface and the Systick.
HAL_Init();

// Configure the system clock
SystemClock_Config();

// Initialize all configured peripherals
MX_GPIO_Init();
MX_DMA_Init();
MX_SPI1_Init();
MX_SPI2_Init();

/* Infinite loop */

SSD1322_API_init();
Init_Completed_flag = 1; // Now is a safe time to enable the EXTI interrupt handler
set_buffer_size(256, 64); // SSD1322 OLED size

while (1)
{
Packets_to_chars();
Main_Aux_TFT_Display();
fill_buffer(tx_buffer, 0); // Clearing OLED frame buffer

// Drawing (recoding, horizontal and vertical scaling) of the characters of the main display line
for (int i = 0; i < CHAR_HEIGHT; i++)
for (int j = 0; j < LINE1_LEN; j++)
for (int k = 0; k < 5; k++)
tx_buffer[2 + j * 7 + k + (LINE1_Y + i * 5 + 0) * 128] = tx_buffer[2 + j * 7 + k + (LINE1_Y + i * 5 + 1) * 128] =
tx_buffer[2 + j * 7 + k + (LINE1_Y + i * 5 + 2) * 128] = tx_buffer[2 + j * 7 + k + (LINE1_Y + i * 5 + 3) * 128] = Upscale1[chars[j][i]][k];

// Drawing (recoding and vertical scaling) of the characters of the auxiliary display line.
for (int i = 0; i < CHAR_HEIGHT; i++)
for (int j = 0; j < LINE2_LEN; j++)
for (int k = 0; k < 3; k++)
tx_buffer[7 + j * 4 + k + (LINE2_Y + i * 2 + 0) * 128] = tx_buffer[7 + j * 4 + k + (LINE2_Y + i * 2 + 1) * 128] = Upscale2[chars[j + LINE1_LEN][i]][k];

// Drawing of the annunciators
for (int k = 0; k < LINE1_LEN; k++)
if (flags[k])
for (int i = 0; i < 5; i++)
for (int j = 0; j < 7; j++)
tx_buffer[1 + j + k * 7 + i * 128] = Sprites[i][1 + k * 7 + j];

send_buffer_to_OLED(tx_buffer, 0, 0); // Send the frame buffer content to OLED
HAL_GPIO_TogglePin(GPIOC, TEST_OUT_Pin); // Test LED toggle
}
;

}


// System Clock Configuration
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

//Initializes the RCC Oscillators according to the specified parameters in the RCC_OscInitTypeDef structure.
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

// Initializes the CPU, AHB and APB buses clocks
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                            | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}


// This function is executed in case of error occurrence.
void Error_Handler(void)
{
// User can add his own implementation to report the HAL error return state
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
   ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod