У меня есть графический 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;
}
Что не так с моим кодом? Спасибо за любые полезные советы!
Хорошо, я нашел решение сам: бит порядок байт был неправ! 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);
Теперь дисплей работает отлично. 🙂
Других решений пока нет …