MAX7219/MAX7221 dirver + example
This commit is contained in:
parent
c21f70366f
commit
87b4befd87
6 changed files with 383 additions and 0 deletions
189
extras/max7219/max7219.c
Normal file
189
extras/max7219/max7219.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Driver for MAX7219/MAX7221
|
||||
* Serially Interfaced, 8-Digit LED Display Drivers
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "max7219.h"
|
||||
#include <esp/spi.h>
|
||||
#include <esp/gpio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "max7219_priv.h"
|
||||
|
||||
#define SPI_BUS 1
|
||||
|
||||
//#define MAX7219_DEBUG
|
||||
|
||||
#ifdef MAX7219_DEBUG
|
||||
#include <stdio.h>
|
||||
#define debug(fmt, ...) printf("%s: " fmt "\n", "MAX7219", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define ALL_CHIPS 0xff
|
||||
#define ALL_DIGITS 8
|
||||
|
||||
#define REG_DIGIT_0 (1 << 8)
|
||||
#define REG_DECODE_MODE (9 << 8)
|
||||
#define REG_INTENSITY (10 << 8)
|
||||
#define REG_SCAN_LIMIT (11 << 8)
|
||||
#define REG_SHUTDOWN (12 << 8)
|
||||
#define REG_DISPLAY_TEST (15 << 8)
|
||||
|
||||
#define VAL_CLEAR_BCD 0x0f
|
||||
#define VAL_CLEAR_NORMAL 0x00
|
||||
|
||||
static const spi_settings_t bus_settings = {
|
||||
.mode = SPI_MODE0,
|
||||
.freq_divider = SPI_FREQ_DIV_10M,
|
||||
.msb = true,
|
||||
.minimal_pins = true,
|
||||
.endianness = SPI_BIG_ENDIAN
|
||||
};
|
||||
|
||||
static void send(const max7219_display_t *disp, uint8_t chip, uint16_t value)
|
||||
{
|
||||
uint16_t buf[MAX7219_MAX_CASCADE_SIZE] = { 0 };
|
||||
if (chip == ALL_CHIPS)
|
||||
{
|
||||
for (uint8_t i = 0; i < disp->cascade_size; i++)
|
||||
buf[i] = value;
|
||||
}
|
||||
else buf[chip] = value;
|
||||
|
||||
spi_settings_t old_settings;
|
||||
spi_get_settings(SPI_BUS, &old_settings);
|
||||
spi_set_settings(SPI_BUS, &bus_settings);
|
||||
gpio_write(disp->cs_pin, false);
|
||||
|
||||
spi_transfer(SPI_BUS, buf, NULL, disp->cascade_size, SPI_16BIT);
|
||||
|
||||
gpio_write(disp->cs_pin, true);
|
||||
spi_set_settings(SPI_BUS, &old_settings);
|
||||
}
|
||||
|
||||
bool max7219_init(max7219_display_t *disp)
|
||||
{
|
||||
if (!disp->cascade_size || disp->cascade_size > MAX7219_MAX_CASCADE_SIZE)
|
||||
{
|
||||
debug("Invalid cascade size %d", disp->cascade_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t max_digits = disp->cascade_size * ALL_DIGITS;
|
||||
if (!disp->digits || disp->digits > max_digits)
|
||||
{
|
||||
debug("Invalid digits count %d, max %d", disp->cascade_size, max_digits);
|
||||
return false;
|
||||
}
|
||||
|
||||
gpio_enable(disp->cs_pin, GPIO_OUTPUT);
|
||||
gpio_write(disp->cs_pin, true);
|
||||
|
||||
// Shutdown all chips
|
||||
max7219_set_shutdown_mode(disp, true);
|
||||
// Disable test
|
||||
send(disp, ALL_CHIPS, REG_DISPLAY_TEST);
|
||||
// Set max scan limit
|
||||
send(disp, ALL_CHIPS, REG_SCAN_LIMIT | (ALL_DIGITS - 1));
|
||||
// Set normal decode mode & clear display
|
||||
max7219_set_decode_mode(disp, false);
|
||||
// Set minimal brightness
|
||||
max7219_set_brightness(disp, 0);
|
||||
// Wake up
|
||||
max7219_set_shutdown_mode(disp, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void max7219_set_decode_mode(max7219_display_t *disp, bool bcd)
|
||||
{
|
||||
disp->bcd = bcd;
|
||||
send(disp, ALL_CHIPS, REG_DECODE_MODE | (bcd ? 0xff : 0));
|
||||
max7219_clear(disp);
|
||||
}
|
||||
|
||||
void max7219_set_brightness(const max7219_display_t *disp, uint8_t value)
|
||||
{
|
||||
send(disp, ALL_CHIPS, REG_INTENSITY | (value > MAX7219_MAX_BRIGHTNESS ? MAX7219_MAX_BRIGHTNESS : value));
|
||||
}
|
||||
|
||||
void max7219_set_shutdown_mode(const max7219_display_t *disp, bool shutdown)
|
||||
{
|
||||
send(disp, ALL_CHIPS, REG_SHUTDOWN | !shutdown);
|
||||
}
|
||||
|
||||
bool max7219_set_digit(const max7219_display_t *disp, uint8_t digit, uint8_t val)
|
||||
{
|
||||
if (digit >= disp->digits)
|
||||
{
|
||||
debug("Invalid digit: %d", digit);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (disp->mirrored)
|
||||
digit = disp->digits - digit - 1;
|
||||
|
||||
uint8_t c = digit / ALL_DIGITS;
|
||||
uint8_t d = digit % ALL_DIGITS;
|
||||
|
||||
send(disp, c, (REG_DIGIT_0 + ((uint16_t)d << 8)) | val);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void max7219_clear(const max7219_display_t *disp)
|
||||
{
|
||||
uint8_t val = disp->bcd ? VAL_CLEAR_BCD : VAL_CLEAR_NORMAL;
|
||||
for (uint8_t i = 0; i < ALL_DIGITS; i++)
|
||||
send(disp, ALL_CHIPS, (REG_DIGIT_0 + ((uint16_t)i << 8)) | val);
|
||||
}
|
||||
|
||||
inline static uint8_t get_char(const max7219_display_t *disp, char c)
|
||||
{
|
||||
if (disp->bcd)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
switch (c)
|
||||
{
|
||||
case '-':
|
||||
return 0x0a;
|
||||
case 'E':
|
||||
case 'e':
|
||||
return 0x0b;
|
||||
case 'H':
|
||||
case 'h':
|
||||
return 0x0c;
|
||||
case 'L':
|
||||
case 'l':
|
||||
return 0x0d;
|
||||
case 'P':
|
||||
case 'p':
|
||||
return 0x0e;
|
||||
}
|
||||
return VAL_CLEAR_BCD;
|
||||
}
|
||||
|
||||
return font_7seg[(c - 0x20) & 0x7f];
|
||||
}
|
||||
|
||||
void max7219_draw_text(const max7219_display_t *disp, uint8_t pos, const char *s)
|
||||
{
|
||||
while (s && pos < disp->digits)
|
||||
{
|
||||
uint8_t c = get_char(disp, *s);
|
||||
if (*(s + 1) == '.')
|
||||
{
|
||||
c |= 0x80;
|
||||
s++;
|
||||
}
|
||||
max7219_set_digit(disp, pos, c);
|
||||
pos++;
|
||||
s++;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue