VFD now uses SPI to shift data to driver
This commit is contained in:
parent
15100f6e21
commit
ad7754d488
133
lib/vfd.c
133
lib/vfd.c
@ -23,6 +23,8 @@
|
||||
/* STM32 (including CM3) libraries */
|
||||
#include <libopencm3/stm32/rcc.h> // real-time control clock library
|
||||
#include <libopencm3/stm32/gpio.h> // general purpose input output library
|
||||
#include <libopencm3/stm32/spi.h> // SPI library
|
||||
#include <libopencm3/cm3/nvic.h> // interrupt handler
|
||||
|
||||
#include "vfd.h" // VFD definitions
|
||||
|
||||
@ -254,8 +256,11 @@ static const uint8_t pict5x7[][5] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00} // nothing
|
||||
};
|
||||
|
||||
/* the three 32 bits values to be shifted out to the VFD driver */
|
||||
static uint32_t vfd_data[3] = {0};
|
||||
/* the 32 bits values to be shifted out to the VFD driver
|
||||
* split into 16 bit for SPI transfer */
|
||||
static uint32_t vfd_data[VFD_DRIVERS] = {0};
|
||||
static uint16_t vfd_spi[VFD_DRIVERS*2] = {0};
|
||||
static volatile uint8_t vfd_spi_i = 0;
|
||||
|
||||
char vfd_digits[VFD_DIGITS] = {0};
|
||||
char vfd_matrixs[VFD_MATRIX] = {0};
|
||||
@ -267,7 +272,12 @@ void vfd_digit(uint8_t nb, char c)
|
||||
if (!(nb<VFD_DIGITS)) { // check the digit exists
|
||||
return;
|
||||
}
|
||||
vfd_data[0] = 0;
|
||||
|
||||
// clear data
|
||||
for (uint8_t i=0; i<LENGTH(vfd_data); i++) {
|
||||
vfd_data[i] = 0;
|
||||
}
|
||||
|
||||
vfd_data[1] = 1<<(4+(9-nb)); // select digit
|
||||
/* encode segment
|
||||
* here the bit order (classic 7 segment + underline and dot)
|
||||
@ -293,25 +303,29 @@ void vfd_digit(uint8_t nb, char c)
|
||||
vfd_data[1] |= (ascii_7segments[i]<<(17)); // add encoded segments to memory
|
||||
}
|
||||
}
|
||||
|
||||
vfd_data[2] = 0; // last part is not used
|
||||
}
|
||||
|
||||
/* set dot matrix <nb> to ASCII character <c>
|
||||
* non ASCII characters are used for pictures */
|
||||
void vfd_matrix(uint8_t nb, char c)
|
||||
{
|
||||
if (!(nb<VFD_MATRIX)) { // check the matrix exists
|
||||
// check the matrix exists
|
||||
if (!(nb<VFD_MATRIX)) {
|
||||
return;
|
||||
} else if (nb<4) {
|
||||
vfd_data[0] = 0;
|
||||
vfd_data[1] = 1<<(3-nb); // select matrix
|
||||
} else {
|
||||
vfd_data[0] = 1<<(35-nb); // select matrix
|
||||
vfd_data[1] = 0;
|
||||
}
|
||||
|
||||
// clear data
|
||||
for (uint8_t i=0; i<LENGTH(vfd_data); i++) {
|
||||
vfd_data[i] = 0;
|
||||
}
|
||||
|
||||
// select matrix
|
||||
if (nb<4) {
|
||||
vfd_data[1] = 1<<(3-nb);
|
||||
} else {
|
||||
vfd_data[0] = 1<<(35-nb);
|
||||
}
|
||||
|
||||
vfd_data[2] = 0;
|
||||
if ((c<0x80) && (c>=' ')) { // only take printable characters
|
||||
uint8_t i = c-' '; // get index for character
|
||||
if (i<LENGTH(font5x7)) {
|
||||
@ -336,6 +350,20 @@ void vfd_matrix(uint8_t nb, char c)
|
||||
/* shift out the VFD data */
|
||||
void vfd_shift(void)
|
||||
{
|
||||
|
||||
// prepare SPI data
|
||||
for (uint8_t i=0; i<LENGTH(vfd_data) && (uint8_t)(i*2+1)<LENGTH(vfd_spi); i++) {
|
||||
vfd_spi[i*2] = vfd_data[i];
|
||||
vfd_spi[i*2+1] = vfd_data[i]>>16;
|
||||
}
|
||||
vfd_spi_i = 0;
|
||||
|
||||
spi_enable(VFD_SPI); // enable SPI (the tx empty interrupt will trigger)
|
||||
//while (true) {
|
||||
//spi_send(VFD_SPI, vfd_spi[vfd_spi_i++]); // send first data (also enables latch)
|
||||
//}
|
||||
|
||||
/*
|
||||
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<sizeof(vfd_data)/sizeof(vfd_data[0]); i++) {
|
||||
@ -350,10 +378,9 @@ void vfd_shift(void)
|
||||
}
|
||||
}
|
||||
|
||||
gpio_set(VFD_PORT, VFD_STR); // disable HV output
|
||||
gpio_set(VFD_PORT, VFD_NLE); // latch data
|
||||
gpio_clear(VFD_PORT, VFD_STR); // enable HV output
|
||||
gpio_clear(VFD_PORT, VFD_NLE); // stop latching data
|
||||
*/
|
||||
}
|
||||
|
||||
/* transmit every digit and matrix */
|
||||
@ -413,18 +440,80 @@ void vfd_test(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* switch VFD display on */
|
||||
void vfd_on(void)
|
||||
{
|
||||
gpio_clear(VFD_PORT, VFD_STR); // enable HV output
|
||||
}
|
||||
|
||||
/* switch VFD display off */
|
||||
void vfd_off(void)
|
||||
{
|
||||
gpio_set(VFD_PORT, VFD_STR); // disable HV output
|
||||
}
|
||||
|
||||
/* setup VFD */
|
||||
void vfd_setup(void)
|
||||
{
|
||||
rcc_periph_clock_enable(VFD_RCC); //enable clock for VFD
|
||||
rcc_periph_clock_enable(VFD_PORT_RCC); // enable clock for VFD GPIO
|
||||
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'
|
||||
gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_NLE); // set VFD pin to alternative function push-pull
|
||||
|
||||
vfd_clear(); // initialize values
|
||||
//gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_DIN);
|
||||
//gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, VFD_CLK);
|
||||
|
||||
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
|
||||
gpio_clear(VFD_PORT, VFD_NLE); // do not output latched data
|
||||
//gpio_set(VFD_PORT, VFD_CLK); // clock is idle high
|
||||
|
||||
rcc_periph_clock_enable(VFD_SPI_RCC); // enable SPI clock
|
||||
gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, VFD_CLK); // set VFD pin to alternative function push-pull
|
||||
gpio_set_mode(VFD_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, VFD_DIN); // set VFD pin to alternative function push-pull
|
||||
|
||||
spi_reset(VFD_SPI); // clear SPI values
|
||||
/* set SPI:
|
||||
* - use VFD_SPI port
|
||||
* - divide clock by 8 for generating the baudrate (F_PCLK1 is 36MHz, max HV518 is 6MHz)
|
||||
* - clock idle high polarity
|
||||
* - data is valid on rising edge (second clock phase)
|
||||
* - send 16 bits at a time
|
||||
* - send least significant bit first (that's how I coded the data)
|
||||
*/
|
||||
spi_init_master(VFD_SPI, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_LSBFIRST);
|
||||
//spi_set_bidirectional_transmit_only_mode(VFD_SPI); // only use MOSI to transmit
|
||||
//spi_set_unidirectional_mode(VFD_SPI); // MISO is unused
|
||||
//spi_disable_software_slave_management(VFD_SPI); // use hardware NSS
|
||||
spi_enable_software_slave_management(VFD_SPI);
|
||||
//spi_enable_ss_output(VFD_SPI); // allow slave select
|
||||
spi_set_nss_high(VFD_SPI); // set NSS high
|
||||
spi_enable_tx_buffer_empty_interrupt(VFD_SPI); // enable TX empty interrupt
|
||||
nvic_enable_irq(VFD_SPI_IRQ); // enable SPI interrupt
|
||||
|
||||
//spi_enable(VFD_SPI);
|
||||
//SPI_CR1(VFD_SPI) &= ~SPI_CR1_SSM;
|
||||
//SPI_CR2(VFD_SPI) |= SPI_CR2_SSOE;
|
||||
|
||||
vfd_clear(); // initialize values
|
||||
}
|
||||
|
||||
#if (VFD_SPI==SPI1)
|
||||
void spi1_isr(void)
|
||||
#elif (VFD_SPI==SPI2)
|
||||
void spi2_isr(void)
|
||||
#endif
|
||||
{
|
||||
if (SPI_SR(VFD_SPI) & SPI_SR_TXE) { // transmission buffer empty
|
||||
if (vfd_spi_i<LENGTH(vfd_spi)) { // check if data is available
|
||||
gpio_clear(VFD_PORT, VFD_NLE); // slave select to latch data
|
||||
spi_send(VFD_SPI, vfd_spi[vfd_spi_i++]); // send next data
|
||||
} else { // all data transmitted
|
||||
while (SPI_SR(VFD_SPI) & SPI_SR_BSY); // wait until transmission is complete (not sure it's a good idea in an isr)
|
||||
gpio_set(VFD_PORT, VFD_NLE); // output latched data
|
||||
//spi_set_nss_high(VFD_SPI); // set NSS high
|
||||
spi_clean_disable(VFD_SPI); // disable latch to output data
|
||||
//spi_set_nss_high(VFD_SPI); // set NSS high
|
||||
gpio_set(GPIOA, GPIO1); // toggle LED
|
||||
//gpio_set(VFD_PORT, VFD_NLE); // do not output latched data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
37
lib/vfd.h
37
lib/vfd.h
@ -17,14 +17,37 @@
|
||||
* it used three chained supertex HV518P shift register VFD drivers */
|
||||
|
||||
/* supertex HV518 VFD driver pins */
|
||||
#define VFD_RCC RCC_GPIOA
|
||||
/* 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_STR GPIO4
|
||||
#define VFD_NLE GPIO5
|
||||
#define VFD_CLK GPIO6
|
||||
#define VFD_DIN GPIO7
|
||||
#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 the SPI NSS (PA4) */
|
||||
#define VFD_NLE GPIO_SPI1_NSS
|
||||
/* 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
|
||||
|
||||
/* the number of blocks available on the VFD */
|
||||
#define VFD_DRIVERS 3
|
||||
#define VFD_DIGITS 10
|
||||
#define VFD_MATRIX 12
|
||||
|
||||
@ -48,5 +71,9 @@ void vfd_clear(void);
|
||||
void vfd_test(void);
|
||||
/* transmit every digit and matrix */
|
||||
void vfd_transmit(void);
|
||||
/* switch VFD display on */
|
||||
void vfd_on(void);
|
||||
/* switch VFD display off */
|
||||
void vfd_off(void);
|
||||
/* setup VFD */
|
||||
void vfd_setup(void);
|
||||
|
8
main.c
8
main.c
@ -27,6 +27,8 @@
|
||||
#include <libopencm3/cm3/scb.h> // vector table definition
|
||||
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
||||
|
||||
#include <libopencm3/stm32/spi.h> // SPI library
|
||||
|
||||
/* own libraries */
|
||||
#include "main.h" // board definitions
|
||||
#include "usart.h" // USART utilities
|
||||
@ -69,7 +71,7 @@ int main(void)
|
||||
|
||||
gpio_setup(); // setup main inputs/outputs
|
||||
usart_setup(); // setup USART (for printing)
|
||||
cdcacm_setup(); // setup USB CDC ACM (for printing)
|
||||
cdcacm_setup(); // setup USB CDC ACM (for printing)
|
||||
vfd_setup(); // setup VFD
|
||||
|
||||
setbuf(stdout, NULL); // set standard out buffer to NULL to immediately print
|
||||
@ -77,6 +79,8 @@ int main(void)
|
||||
|
||||
printf("welcome to the STM32F1 CuVoodoo display driver\n");
|
||||
|
||||
|
||||
vfd_on(); // switch on VFD
|
||||
vfd_test();
|
||||
vfd_shift();
|
||||
for (uint32_t i = 0; i < 0x800000; i++) {
|
||||
@ -84,6 +88,8 @@ int main(void)
|
||||
}
|
||||
vfd_clear();
|
||||
vfd_shift();
|
||||
vfd_digit(0,'0');
|
||||
vfd_shift();
|
||||
|
||||
bool vfd_flag = false;
|
||||
for (uint8_t i=0; i<LENGTH(vfd_digits); i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user