Futaba GP9002A01A графический VFD на Raspbery Pi

У меня есть графический VFD Futaba GP9002A01A, и я хочу запустить его на Raspberry Pi 3: https://cdn-shop.adafruit.com/datasheets/GP9002A+Appnote.pdf

Эта проблема заключается в следующем: он будет отображать только пиксель снега независимо от того, какие данные я отправляю. Вот исходный код:

vfd.h:

// Header file for vfd.cpp class file.
// This class controls the Futaba GP9002A01A graphic VFD attached to the host via SPI link.

#ifndef VFD_H
#define VFD_H

using namespace std;

class vfd {
private:
static const int CHANNEL                      =  0;             // SPI channel 0 means that we use pin CE0_N (#24) to address the display.
static const int CD_PIN                       = 17;             // Additionally, our VFD requireds an extra GPIO input (here it's pin #11 aka GPIO17).
static const uint32_t wait_interval_extralong = (uint32_t) 400; // Wait interval used to let the VFD module clear its display buffer (command 0x06)
static const uint32_t wait_interval_long      = (uint32_t) 1;   // Wait interval used after each command
static const uint32_t wait_interval_short     = (uint32_t) 1;   // Wait interval used before each command
static bool  on;

public:
static int  Initialize (); // Initializes the display.
static bool IsSwitchedOn (); // Whether the display is currently on.
static void DisplayChar (int spi_handle, char pos_x, char pos_y, char size_x, char size_y, string text); // Displays a character.
static void DisplayPixel (int spi_handle, char addr_upper, char addr_lower, char pixels []); // Displays a series of pixels.
static void SwitchOn (int spi_handle); // Switches the display on.
static void SwitchOff (int spi_handle); // Switches the display off.
static void Clear (int spi_handle);     // Clears the display.
};

#endif

vfd.cpp:

#include <iostream>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include "vfd.h"
extern "C" {
#include <pigpio.h>
}

using namespace std;

bool     vfd::on;

int vfd::Initialize ()
{
int fd_spi;

on = false;

cout << "Initializing display...";

fd_spi = spiOpen(CHANNEL, 500000, 3);

if (fd_spi == -1)  cout << "failed! Error code: " << errno  << endl;
else               cout << "done. Handler: " << fd_spi << endl;

gpioSetMode (CD_PIN, PI_OUTPUT);

return fd_spi;
}

void vfd::DisplayPixel (int spi_handle, char addr_upper, char addr_lower, char pixels [])
{
char buffer [100];

gpioWrite (CD_PIN, 1);
buffer [0] = 0x01;                      // Activates display buffer #1.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

buffer [0] = 0x0E;                      // Sets the lower portion of the pixel address.
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
gpioWrite (CD_PIN, 0);
buffer [0] = addr_lower;                // address
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

gpioWrite (CD_PIN, 1);
buffer [0] = 0x0F;                      // Sets the upper portion of the pixel address.
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
gpioWrite (CD_PIN, 0);
buffer [0] = addr_upper;                // address
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

gpioWrite (CD_PIN, 1);
buffer [0] = 0x08;                      // Illuminates the selected pixel.
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
gpioWrite (CD_PIN, 0);
buffer [0] = pixels [0];                // pixel data
gpioDelay (wait_interval_short);
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

cout << "Splashscreen displayed." << endl;
}

void vfd::Clear (int spi_handle)
{
char buffer [100];

gpioWrite (CD_PIN, 1);
buffer [0] = 0x00;                      // De-activates both display buffers.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
buffer [0] = 0x06;                      // Clears the display.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_extralong);
gpioWrite (CD_PIN, 0);
}

void vfd::SwitchOn (int spi_handle)
{
char buffer [100];

gpioWrite (CD_PIN, 1);
gpioDelay (wait_interval_short);
buffer [0] = 0x14;                      // Sets the operating mode of the display.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
gpioWrite (CD_PIN, 0);
gpioDelay (wait_interval_short);
buffer [0] = 0x10;                      // Green-white without grayscale.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

gpioWrite (CD_PIN, 1);
gpioDelay (wait_interval_short);
buffer [0] = 0x13;                      // Sets the brightness of the display.
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);
gpioWrite (CD_PIN, 0);
gpioDelay (wait_interval_short);
buffer [0] = 0x12;                      // 70%
spiWrite (spi_handle, buffer, 1);
gpioDelay (wait_interval_long);

vfd::Clear (spi_handle);

vfd::on = true;
cout << "Display ready." << endl;
}

void vfd::SwitchOff (int spi_handle)
{
vfd::Clear (spi_handle);

vfd::on = false;
cout << "Display switched off." << endl;
}

bool vfd::IsSwitchedOn ()
{
return on;
}

Что не так с моим кодом? Спасибо за любые полезные советы!

1

Решение

Хорошо, я нашел решение сам: бит порядок байт был неправ! RPi 3 использует в своем интерфейсе SPI значение с прямым порядком байтов, но дисплей ожидает порядка с прямым порядком байтов. Поэтому я провел небольшое исследование и обнаружил, что этот простой алгоритм меняет биты в байте:

char vfd::Reverse (char b)
{
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}

Все, что мне нужно было сделать в коде, обращающемся к дисплею, это использовать вышеупомянутую функцию:

buffer [0] = Reverse (0x01);

Теперь дисплей работает отлично. 🙂

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]