VFD now uses SPI to shift data to driver

This commit is contained in:
King Kévin 2016-01-22 16:22:47 +01:00
parent 15100f6e21
commit ad7754d488
3 changed files with 150 additions and 28 deletions

133
lib/vfd.c
View File

@ -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
}
}
}

View File

@ -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
View File

@ -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++) {