Merge pull request #337 from UncleRus/extras/max7219

MAX7219/MAX7221 dirver + example
This commit is contained in:
Ruslan V. Uss 2017-02-12 01:51:37 +06:00 committed by GitHub
commit 54ce6bbe1c
6 changed files with 383 additions and 0 deletions

View file

@ -0,0 +1,3 @@
PROGRAM = max7219_7seg
EXTRA_COMPONENTS = extras/max7219
include ../../common.mk

View file

@ -0,0 +1,52 @@
/*
* Example of using MAX7219 driver with 7 segment displays
*
* Part of esp-open-rtos
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* BSD Licensed as described in the file LICENSE
*/
#include <esp/uart.h>
#include <espressif/esp_common.h>
#include <stdio.h>
#include <max7219/max7219.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <esp/hwrand.h>
#define CS_PIN 5
#define DELAY 2000
static max7219_display_t disp = {
.cs_pin = CS_PIN,
.digits = 8,
.cascade_size = 1,
.mirrored = true
};
void user_init(void)
{
uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version());
max7219_init(&disp);
//max7219_set_decode_mode(&disp, true);
char buf[9];
while (true)
{
max7219_clear(&disp);
max7219_draw_text(&disp, 0, "7219LEDS");
vTaskDelay(DELAY / portTICK_PERIOD_MS);
max7219_clear(&disp);
sprintf(buf, "%2.4f A", 34.6782);
max7219_draw_text(&disp, 0, buf);
vTaskDelay(DELAY / portTICK_PERIOD_MS);
max7219_clear(&disp);
sprintf(buf, "%08x", hwrand());
max7219_draw_text(&disp, 0, buf);
vTaskDelay(DELAY / portTICK_PERIOD_MS);
}
}

View file

@ -0,0 +1,7 @@
# include it as 'max7219/max7219.h'
INC_DIRS += $(max7219_ROOT)..
# args for passing into compile rule generation
max7219_SRC_DIR = $(max7219_ROOT)
$(eval $(call component_compile_rules,max7219))

189
extras/max7219/max7219.c Normal file
View 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++;
}
}

96
extras/max7219/max7219.h Normal file
View file

@ -0,0 +1,96 @@
/*
* 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
*/
#ifndef EXTRAS_MAX7219_H_
#define EXTRAS_MAX7219_H_
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define MAX7219_MAX_CASCADE_SIZE 8
#define MAX7219_MAX_BRIGHTNESS 31
/**
* Display descriptor
*/
typedef struct
{
uint8_t cs_pin; //!< GPIO connected to CS/LOAD pin
uint8_t digits; //!< Accessible digits in 7seg. Up to cascade_size * 8
uint8_t cascade_size; //!< Up to 8 MAX721xx cascaded
bool mirrored; //!< true for horizontally mirrored displays
bool bcd;
} max7219_display_t;
/**
* Initialize display: switch it to normal operation from shutdown mode,
* set scan limit to the max and clear
* @param disp Pointer to display descriptor
* @return false if error occured
*/
bool max7219_init(max7219_display_t *disp);
/**
* Set decode mode and clear display
* @param disp Pointer to display descriptor
* @param bcd true to set BCD decode mode, false to normal
*/
void max7219_set_decode_mode(max7219_display_t *disp, bool bcd);
/**
* Set display brightness
* @param disp Pointer to display descriptor
* @param value Brightness value, 0..MAX7219_MAX_BRIGHTNESS
*/
void max7219_set_brightness(const max7219_display_t *disp, uint8_t value);
/**
* Shutdown display or set it to normal mode
* @param disp Pointer to display descriptor
* @param shutdown Shutdown display if true
*/
void max7219_set_shutdown_mode(const max7219_display_t *disp, bool shutdown);
/**
* Write data to display digit
* @param disp Pointer to display descriptor
* @param digit Digit index, 0..disp->digits - 1
* @param val Data
* @return false if error occured
*/
bool max7219_set_digit(const max7219_display_t *disp, uint8_t digit, uint8_t val);
/**
* Clear display
* @param disp Pointer to display descriptor
*/
void max7219_clear(const max7219_display_t *disp);
/**
* Draw text.
* Currently only 7-segment displays supported
* @param disp Pointer to display descriptor
* @param pos Start digit
* @param s Text
*/
void max7219_draw_text(const max7219_display_t *disp, uint8_t pos, const char *s);
#ifdef __cplusplus
extern "C"
}
#endif
#endif /* EXTRAS_MAX7219_H_ */

View file

@ -0,0 +1,36 @@
/*
* 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
*/
#ifndef EXTRAS_MAX7219_PRIV_H_
#define EXTRAS_MAX7219_PRIV_H_
static const uint8_t font_7seg[] = {
/* ' ' ! " # $ % & ' ( ) */
0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4e, 0x78,
/* * + , - . / 0 1 2 3 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x30, 0x6d, 0x79,
/* 4 5 6 7 8 9 : ; < = */
0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x00, 0x00, 0x0d, 0x09,
/* > ? @ A B C D E F G */
0x19, 0x65, 0x00, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47, 0x5e,
/* H I J K L M N O P Q */
0x37, 0x06, 0x38, 0x57, 0x0e, 0x76, 0x15, 0x1d, 0x67, 0x73,
/* R S T U V W X Y Z [ */
0x05, 0x5b, 0x0f, 0x1c, 0x3e, 0x2a, 0x49, 0x3b, 0x6d, 0x4e,
/* \ ] ^ _ ` a b c d e */
0x00, 0x78, 0x00, 0x08, 0x02, 0x77, 0x1f, 0x4e, 0x3d, 0x4f,
/* f g h i j k l m n o */
0x47, 0x5e, 0x37, 0x06, 0x38, 0x57, 0x0e, 0x76, 0x15, 0x1d,
/* p q r s t u v w x y */
0x67, 0x73, 0x05, 0x5b, 0x0f, 0x1c, 0x3e, 0x2a, 0x49, 0x3b,
/* z { | } ~ */
0x6d, 0x4e, 0x06, 0x78, 0x00
};
#endif /* EXTRAS_MAX7219_PRIV_H_ */