1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/dsp0401/dsp0401.c

251 lines
7.3 KiB
C

/*
* Copyright (C) 2017 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_dsp0401
* @{
*
* @file
* @brief Device driver implementation for dsp0401 alphanumeric display
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include <inttypes.h>
#include <string.h>
#include "dsp0401.h"
#include "timex.h"
#include "ztimer.h"
#include "periph/gpio.h"
#include "periph/pwm.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define LATCH_DELAY (50U) /* 50 us */
#define SCK (dev->params.clk)
#define SDI (dev->params.sdi)
#define LAT (dev->params.lat)
#define PWM_PERIPH (dev->params.pwm)
#define PWM_CHAN (dev->params.pwm_channel)
#define BRIGHTNESS (dev->params.brightness)
#define PWM_FREQ (1000U)
#define PWM_STEPS (256U)
#define MOD_COUNT (dev->params.module_count)
/* Internal Ascii char map */
#define CHAR_MAP_MIN (30U)
#define CHAR_MAP_MAX (127U)
static const uint8_t dsp0401_charmap[][2] = {
/* dec: char */
{ 0x00, 0x00 }, /* 30: */
{ 0x00, 0x00 }, /* 31: */
{ 0x00, 0x00 }, /* 32: ' ' */
{ 0x00, 0x00 }, /* 33: ! */
{ 0x00, 0x00 }, /* 34: " */
{ 0x00, 0x00 }, /* 35: # */
{ 0xB5, 0xB5 }, /* 36: $ */
{ 0xB3, 0xB3 }, /* 37: % */
{ 0x00, 0x00 }, /* 38: & */
{ 0x01, 0x00 }, /* 39: ` */
{ 0x81, 0x00 }, /* 40: ( */
{ 0x00, 0x42 }, /* 41: ) */
{ 0x53, 0x53 }, /* 42: * */
{ 0x11, 0x11 }, /* 43: + */
{ 0x00, 0x00 }, /* 44: , */
{ 0x10, 0x10 }, /* 45: - */
{ 0x00, 0x04 }, /* 46: . */
{ 0x02, 0x02 }, /* 47: / */
{ 0xAC, 0xAC }, /* 48: 0 */
{ 0x01, 0x01 }, /* 49: 1 */
{ 0x9C, 0x9C }, /* 50: 2 */
{ 0xBC, 0x84 }, /* 51: 3 */
{ 0x38, 0x30 }, /* 52: 4 */
{ 0xB4, 0xB4 }, /* 53: 5 */
{ 0xB4, 0xBC }, /* 54: 6 */
{ 0x16, 0x92 }, /* 55: 7 */
{ 0xBC, 0xBC }, /* 56: 8 */
{ 0xBC, 0xB4 }, /* 57: 9 */
{ 0x04, 0x04 }, /* 58: : */
{ 0x04, 0x02 }, /* 59: ; */
{ 0x00, 0x00 }, /* 60: < */
{ 0x90, 0x14 }, /* 61: = */
{ 0x00, 0x00 }, /* 62: > */
{ 0x00, 0x00 }, /* 63: ? */
{ 0xAC, 0x9D }, /* 64: @ */
{ 0x3C, 0xB8 }, /* 65: A */
{ 0xB1, 0xBC }, /* 66: B */
{ 0x84, 0xAC }, /* 67: C */
{ 0xAD, 0x85 }, /* 68: D */
{ 0x84, 0xBC }, /* 69: E */
{ 0x04, 0xB8 }, /* 70: F */
{ 0xB4, 0xAC }, /* 71: G */
{ 0x38, 0x38 }, /* 72: H */
{ 0x85, 0x85 }, /* 73: I */
{ 0xA8, 0x0C }, /* 74: J */
{ 0x42, 0x38 }, /* 75: K */
{ 0x80, 0x2C }, /* 76: L */
{ 0x2A, 0x68 }, /* 77: M */
{ 0x68, 0x68 }, /* 78: N */
{ 0xAC, 0xAC }, /* 79: 0 */
{ 0x1C, 0xB8 }, /* 80: P */
{ 0xEC, 0xAC }, /* 81: Q */
{ 0x5C, 0xB8 }, /* 82: R */
{ 0xB4, 0xB4 }, /* 83: S */
{ 0x05, 0x81 }, /* 84: T */
{ 0xA8, 0x2C }, /* 85: U */
{ 0x02, 0x2A }, /* 86: V */
{ 0x68, 0x2A }, /* 87: W */
{ 0x42, 0x42 }, /* 88: X */
{ 0x02, 0x42 }, /* 89: Y */
{ 0x86, 0x86 }, /* 90: Z */
{ 0x00, 0xAC }, /* 91: [ */
{ 0x40, 0x40 }, /* 92: \ */
{ 0xAC, 0x00 }, /* 93: ] */
{ 0x00, 0x00 }, /* 94: ^ */
{ 0x80, 0x04 }, /* 95: _ */
{ 0x00, 0x40 }, /* 96: ` */
{ 0x00, 0x00 }, /* 97: a */
{ 0x00, 0x00 }, /* 98: b */
{ 0x00, 0x00 }, /* 99: c */
{ 0x00, 0x00 }, /* 100: d */
{ 0x00, 0x00 }, /* 101: e */
{ 0x00, 0x00 }, /* 102: f */
{ 0x00, 0x00 }, /* 103: g */
{ 0x00, 0x00 }, /* 104: h */
{ 0x00, 0x00 }, /* 105: i */
{ 0x00, 0x00 }, /* 106: j */
{ 0x00, 0x00 }, /* 107: k */
{ 0x00, 0x00 }, /* 108: l */
{ 0x00, 0x00 }, /* 109: m */
{ 0x00, 0x00 }, /* 110: n */
{ 0x00, 0x00 }, /* 111: o */
{ 0x00, 0x00 }, /* 112: p */
{ 0x00, 0x00 }, /* 113: q */
{ 0x00, 0x00 }, /* 114: r */
{ 0x00, 0x00 }, /* 115: s */
{ 0x00, 0x00 }, /* 116: t */
{ 0x00, 0x00 }, /* 117: u */
{ 0x00, 0x00 }, /* 118: v */
{ 0x00, 0x00 }, /* 119: w */
{ 0x00, 0x00 }, /* 120: x */
{ 0x00, 0x00 }, /* 121: y */
{ 0x00, 0x00 }, /* 122: z */
{ 0x85, 0x11 }, /* 123: { */
{ 0x01, 0x01 }, /* 124: | */
{ 0x11, 0x85 }, /* 125: } */
{ 0x00, 0x00 }, /* 126: ~ */
{ 0x00, 0x00 }, /* 127: */
};
static void _shift_char(const dsp0401_t *dev, uint8_t c)
{
/* Unsupported chars not displayed */
if ((c < CHAR_MAP_MIN) || (c > CHAR_MAP_MAX)) {
c = ' ';
}
for (unsigned p = 0 ; p < 2 ; ++p) {
for (unsigned i = 0; i < 8; ++i) {
gpio_write(SDI, !!(dsp0401_charmap[c - CHAR_MAP_MIN][p] & (1 << (7 - i))));
gpio_set(SCK);
gpio_clear(SCK);
}
}
}
static void _latch(const dsp0401_t *dev)
{
ztimer_sleep(ZTIMER_USEC, LATCH_DELAY);
gpio_set(LAT);
ztimer_sleep(ZTIMER_USEC, LATCH_DELAY);
gpio_clear(LAT);
ztimer_sleep(ZTIMER_USEC, LATCH_DELAY);
}
int dsp0401_init(dsp0401_t *dev, const dsp0401_params_t *params)
{
dev->params = *params;
/* Initialize clock pin and set it to low */
if (gpio_init(SCK, GPIO_OUT) < 0) {
DEBUG("[ERROR] CLK GPIO initialization failed.");
return -DSP0401_ERR_CLK_GPIO;
}
gpio_clear(SCK);
/* Initialize data pin */
if (gpio_init(SDI, GPIO_OUT) < 0) {
DEBUG("[ERROR] SDI GPIO initialization failed.");
return -DSP0401_ERR_SDI_GPIO;
}
gpio_clear(SDI);
/* Initialize latch pin and set it to low */
if (gpio_init(LAT, GPIO_OUT) < 0) {
DEBUG("[ERROR] LAT GPIO initialization failed.");
return -DSP0401_ERR_LAT_GPIO;
}
gpio_clear(LAT);
/* Initialize PWM used for LED brightness */
if (!pwm_init(PWM_PERIPH, PWM_LEFT, PWM_FREQ, PWM_STEPS)) {
DEBUG("[ERROR] PWM initialization failed.");
return -DSP0401_ERR_PWM;
}
pwm_set(PWM_PERIPH, PWM_CHAN, BRIGHTNESS);
dsp0401_clear_text(dev);
return DSP0401_OK;
}
void dsp0401_display_text(const dsp0401_t *dev, char *text)
{
unsigned text_len = strlen(text);
for (unsigned i = 0 ; i < MOD_COUNT * 4; ++i) {
if (i < text_len) {
_shift_char(dev, text[i]);
} else {
_shift_char(dev, ' ');
}
}
_latch(dev);
}
void dsp0401_clear_text(const dsp0401_t *dev)
{
/* each module has 4 alphanumeric displays */
for (unsigned i = 0; i < MOD_COUNT * 4; ++i) {
_shift_char(dev, ' ');
}
_latch(dev);
}
void dsp0401_scroll_text(const dsp0401_t *dev, char *text, uint16_t delay)
{
dsp0401_clear_text(dev);
for (unsigned i = 0; i < strlen(text); ++i) {
_shift_char(dev, text[i]);
_latch(dev);
ztimer_sleep(ZTIMER_USEC, delay * US_PER_MS);
}
for (unsigned i = 0; i < MOD_COUNT * 4; ++i) {
_shift_char(dev, ' ');
_latch(dev);
ztimer_sleep(ZTIMER_USEC, delay * US_PER_MS);
}
}