Skip to content

Commit

Permalink
Add MAX7219 SPI display driver library + example and small SPI librar…
Browse files Browse the repository at this point in the history
…y fixes
  • Loading branch information
alexhorner committed Oct 4, 2023
1 parent efd5699 commit bf86ca2
Show file tree
Hide file tree
Showing 8 changed files with 1,029 additions and 1 deletion.
10 changes: 10 additions & 0 deletions examples/spi_max7219/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all : flash

TARGET:=spi_max7219

include ../../ch32v003fun/ch32v003fun.mk

flash : cv_flash
clean : cv_clean


19 changes: 19 additions & 0 deletions examples/spi_max7219/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 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)
Binary file added examples/spi_max7219/demo_pic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions examples/spi_max7219/funconfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H

#define CH32V003 1

#endif
236 changes: 236 additions & 0 deletions examples/spi_max7219/max7219_spi_driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
* 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
60 changes: 60 additions & 0 deletions examples/spi_max7219/max7219_spi_driver_extended.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//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
Loading

0 comments on commit bf86ca2

Please sign in to comment.