Skip to content
Snippets Groups Projects
Commit bf86ca26 authored by Alexander Horner's avatar Alexander Horner
Browse files

Add MAX7219 SPI display driver library + example and small SPI library fixes

parent efd56994
No related branches found
No related tags found
No related merge requests found
all : flash
TARGET:=spi_max7219
include ../../ch32v003fun/ch32v003fun.mk
flash : cv_flash
clean : cv_clean
# MAX7219 8 digit 7 segment display demo
This example for the `max7219_spi_driver` and `max7219_spi_driver_extended` library demonstrates controlling a MAX7219 or MAX7221 based display over SPI with basic and advanced text writing, and at least one example of every available display function in some capacity.
---
The MAX7219 and MAX7221 chipsets are used in many 8 character 7 segment and 8x8 single colour dot matrix displays which can be purchased preassembled on eBay and AliExpress very cheaply. The abundance and low cost of these displays makes them a great companion for small projects requiring a display output that is more capable than single LEDs but not as complex as something like an LCD.
---
The example expects you to connect a MAX7219 based 7 segment 8 character display to your CH32V003 like so:
- `DIN` / `MOSI` to `PC6`
- `SCLK` to `PC5`
- `CS` to `PD0`
You can choose which examples will be shown on the display by changing the `spi_max7219.c` file in the marked demo selection section. All examples are enabled by default.
Once running, you'll see one of the many examples being displayed like so:
![Demo of the MAX7219 based 8 digit 7 segment display connected to a CH32V003 dev board, in operation](demo_pic.jpg)
\ No newline at end of file
examples/spi_max7219/demo_pic.jpg

220 KiB

#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#define CH32V003 1
#endif
/*
* SPI based driver for the MAX7219 display driver (https://www.analog.com/media/en/technical-documentation/data-sheets/MAX7219-MAX7221.pdf)
*
* The driver can be used for 64 discrete LED control, or for 8 digits of 7 segment (+ decimal) displays. It includes a basic 7 segment display font called Code B
* which is made available with this library, as well as various other functions such as multiplexer scan limiting, digital brightness control and font decoding.
*
* The one-byte segment arrangement in the digit registers appear like so:
*
* A
* ---
* F | G | B
* ---
* E | | C
* ---
* D . DP
*
* +-----+----+----+----+----+----+----+----+----+
* | Bit | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
* +-----+----+----+----+----+----+----+----+----+
* | Seg | DP | A | B | C | D | E | F | G |
* +-----+----+----+----+----+----+----+----+----+
*
* On standard 8 digit boards, the 0th digit (MAX7219_REGISTER_DIGIT0) is on the right and the 7th digit (MAX7219_REGISTER_DIGIT7) is on the left.
*/
//Include guard
#ifndef MAX7219_SPI_DRIVER_H
#define MAX7219_SPI_DRIVER_H
//Includes
#include "ch32v003_SPI.h"
#include <stdbool.h>
//Instance struct
struct MAX7219_Display
{
uint8_t displays_in_chain;
GPIO_TypeDef* chip_select_port;
uint8_t chip_select_pin;
uint8_t last_set_decode_mode;
};
//Chip select methods
void MAX7219_select(struct MAX7219_Display display)
{
display.chip_select_port->BSHR |= 0b00000001 << display.chip_select_pin << 16; //Reset pin (active low)
}
void MAX7219_deselect(struct MAX7219_Display display)
{
display.chip_select_port->BSHR |= 0b00000001 << display.chip_select_pin; //Set pin (active low)
}
//Raw communication
#define MAX7219_REGISTER_NOOP 0x00
/*#define MAX7219_REGISTER_DIGIT0 0x01
#define MAX7219_REGISTER_DIGIT1 0x02
#define MAX7219_REGISTER_DIGIT2 0x03
#define MAX7219_REGISTER_DIGIT3 0x04
#define MAX7219_REGISTER_DIGIT4 0x05
#define MAX7219_REGISTER_DIGIT5 0x06
#define MAX7219_REGISTER_DIGIT6 0x07
#define MAX7219_REGISTER_DIGIT7 0x08*/
#define MAX7219_REGISTER_DECODE_MODE 0x09
#define MAX7219_REGISTER_INTENSITY 0x0A
#define MAX7219_REGISTER_SCANLIMIT 0x0B
#define MAX7219_REGISTER_SHUTDOWN 0x0C
#define MAX7219_REGISTER_DISPLAYTEST 0x0F
void MAX7219_write_register(struct MAX7219_Display display, uint8_t reg, uint8_t data)
{
reg &= 0b00001111; //Remove the top 4 bits as they are not used for the register, and only retain the last 4 bits
uint16_t packet = reg << 8; //Apply the register address to the final packet in the top 8 bits
packet |= data; //Apply the data to the final packet in the bottom 8 bits
MAX7219_select(display); //Select the chip select line
//Write the packet to the display
SPI_begin_16();
SPI_write_16(packet);
SPI_wait_transmit_finished();
SPI_end();
MAX7219_deselect(display); //Deselect the chip select line
}
//Register helpers
void MAX7219_shutdown(struct MAX7219_Display display, bool set)
{
MAX7219_write_register(display, MAX7219_REGISTER_SHUTDOWN, !set);
}
void MAX7219_test(struct MAX7219_Display display, bool set)
{
MAX7219_write_register(display, MAX7219_REGISTER_DISPLAYTEST, set);
}
#define MAX7219_DECODE_MODE_NONE 0x00
#define MAX7219_DECODE_MODE_0_ONLY 0x01
#define MAX7219_DECODE_MODE_0_TO_3_ONLY 0x0F
#define MAX7219_DECODE_MODE_ALL 0xFF
void MAX7219_set_decode_mode(struct MAX7219_Display display, uint8_t mode)
{
MAX7219_write_register(display, MAX7219_REGISTER_DECODE_MODE, mode);
display.last_set_decode_mode = mode;
}
#define MAX7219_SCANLIMIT_0_ONLY 0x00
#define MAX7219_SCANLIMIT_01 0x01
#define MAX7219_SCANLIMIT_012 0x02
#define MAX7219_SCANLIMIT_0123 0x03
#define MAX7219_SCANLIMIT_01234 0x04
#define MAX7219_SCANLIMIT_012345 0x05
#define MAX7219_SCANLIMIT_0123456 0x06
#define MAX7219_SCANLIMIT_ALL 0x07
void MAX7219_set_scan_limit(struct MAX7219_Display display, uint8_t limit)
{
limit &= 0b00000111; //Only accept the 3 lsbs for this register
MAX7219_write_register(display, MAX7219_REGISTER_SCANLIMIT, limit);
}
#define MAX7219_BRIGHTNESS_MAX 0x0F
#define MAX7219_MRIGHTNESS_MIN 0x00
void MAX7219_set_brightness(struct MAX7219_Display display, uint8_t brightness)
{
brightness &= 0b00001111; //Only accept the 4 lsbs for this register
MAX7219_write_register(display, MAX7219_REGISTER_INTENSITY, brightness);
}
//Built in CODE B font
#define MAX7219_CODEB_ADD_DECPOINT 0x80
#define MAX7219_CODEB_DASH 0x0A
#define MAX7219_CODEB_BLANK 0x0F
#define MAX7219_CODEB_0 0x00
#define MAX7219_CODEB_1 0x01
#define MAX7219_CODEB_2 0x02
#define MAX7219_CODEB_3 0x03
#define MAX7219_CODEB_4 0x04
#define MAX7219_CODEB_5 0x05
#define MAX7219_CODEB_6 0x06
#define MAX7219_CODEB_7 0x07
#define MAX7219_CODEB_8 0x08
#define MAX7219_CODEB_9 0x09
#define MAX7219_CODEB_E 0x0B
#define MAX7219_CODEB_H 0x0C
#define MAX7219_CODEB_L 0x0D
#define MAX7219_CODEB_P 0x0E
//Raw segment
#define MAX7219_SEGMENT_DP 0b10000000
#define MAX7219_SEGMENT_A 0b01000000
#define MAX7219_SEGMENT_B 0b00100000
#define MAX7219_SEGMENT_C 0b00010000
#define MAX7219_SEGMENT_D 0b00001000
#define MAX7219_SEGMENT_E 0b00000100
#define MAX7219_SEGMENT_F 0b00000010
#define MAX7219_SEGMENT_G 0b00000001
void MAX7219_set_digit(struct MAX7219_Display display, uint32_t digit, uint8_t value)
{
uint32_t literalDigit = digit % 8;
//uint32_t displayIndex = digit / 8;
MAX7219_write_register(display, literalDigit + 1, value);
}
void MAX7219_reset(struct MAX7219_Display display)
{
//Set display brightness to maximum
MAX7219_set_brightness(display, MAX7219_BRIGHTNESS_MAX);
//Set the scan limit to all 8 digits enabled
MAX7219_set_scan_limit(display, MAX7219_SCANLIMIT_ALL);
//Enable Code-B decode on all digits
MAX7219_set_decode_mode(display, MAX7219_DECODE_MODE_ALL);
//Clear all digits
for (size_t digitPos = 0; digitPos < display.displays_in_chain * 8; digitPos++)
{
MAX7219_set_digit(display, digitPos, MAX7219_CODEB_BLANK);
}
//Take the display out of shutdown
MAX7219_shutdown(display, false);
//Take the display out of test mode
MAX7219_test(display, false);
}
void MAX7219_init(struct MAX7219_Display display)
{
//Default deselected
MAX7219_deselect(display);
//Ensure port is enabled
uint32_t selectedPortAddress = (uint32_t)display.chip_select_port;
switch (selectedPortAddress)
{
case GPIOA_BASE:
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA;
break;
case GPIOC_BASE:
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
break;
case GPIOD_BASE:
RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
break;
default: break;
}
//Enable push-pull on pin
display.chip_select_port->CFGLR &= ~(0xf<<(4*display.chip_select_pin));
display.chip_select_port->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*display.chip_select_pin);
//Initialise SPI
SPI_init();
//Clear display to driver defaults
MAX7219_reset(display);
}
#endif //MAX7219_SPI_DRIVER_H include guard
\ No newline at end of file
//Include guard
#ifndef MAX7219_SPI_DRIVER_EXTENDED_H
#define MAX7219_SPI_DRIVER_EXTENDED_H
//Includes
#include "max7219_spi_driver.h"
//---Extended Font---
//Letters
#define MAX7219_EXTFONT_A MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_B MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_C MAX7219_SEGMENT_A | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_C_LOWER MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_D MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_E MAX7219_SEGMENT_A | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_F MAX7219_SEGMENT_A | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_H MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_H_LOWER MAX7219_SEGMENT_C | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_I MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_I_LOWER MAX7219_SEGMENT_E
#define MAX7219_EXTFONT_L MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_L_LOWER MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_N MAX7219_SEGMENT_C | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_O MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_O_LOWER MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_P MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_S MAX7219_SEGMENT_A | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_T MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_U MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_U_LOWER MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E
#define MAX7219_EXTFONT_X MAX7219_SEGMENT_C | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_Y MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_Z MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
//Numbers
#define MAX7219_EXTFONT_0 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F
#define MAX7219_EXTFONT_1 MAX7219_SEGMENT_B | MAX7219_SEGMENT_C
#define MAX7219_EXTFONT_2 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_3 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_4 MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_5 MAX7219_SEGMENT_A | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_6 MAX7219_SEGMENT_A | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_7 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C
#define MAX7219_EXTFONT_8 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_E | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_9 MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_C | MAX7219_SEGMENT_D | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
//Symbols
#define MAX7219_EXTFONT_BLANK 0x00
#define MAX7219_EXTFONT_DEGREES MAX7219_SEGMENT_A | MAX7219_SEGMENT_B | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_EQUALS_TOP MAX7219_SEGMENT_A | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_EQUALS_BOTTOM MAX7219_SEGMENT_D | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_TRIEQUALS MAX7219_SEGMENT_A | MAX7219_SEGMENT_D | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_HYPHEN MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_UNDERSCORE MAX7219_SEGMENT_D
#define MAX7219_EXTFONT_OVERSCORE MAX7219_SEGMENT_A
#define MAX7219_EXTFONT_FORWARDSLASH MAX7219_SEGMENT_B | MAX7219_SEGMENT_E | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_BACKSLASH MAX7219_SEGMENT_C | MAX7219_SEGMENT_F | MAX7219_SEGMENT_G
#define MAX7219_EXTFONT_DECIMAL MAX7219_SEGMENT_DP
#endif //MAX7219_SPI_DRIVER_EXTENDED_H include guard
\ No newline at end of file
This diff is collapsed.
......@@ -333,7 +333,13 @@ static inline uint8_t SPI_is_RX_empty() {
static inline void SPI_wait_RX_available() {
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
}
static inline void SPI_wait_not_busy() {
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
}
static inline void SPI_wait_transmit_finished() {
SPI_wait_TX_complete();
SPI_wait_not_busy();
}
//######## implementation block
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment