-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers/digit7seg: add 4-digit 7-segment display driver
- Loading branch information
Showing
15 changed files
with
750 additions
and
499 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
USEMODULE_INCLUDES_digit7seg := $(LAST_MAKEFILEDIR)/include | ||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_digit7seg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
/* | ||
* Copyright (C) 2024 Orange | ||
* | ||
* 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_digit7seg | ||
* @file | ||
* @brief Device driver for less than 5 digits of 7 segments without IC | ||
* @author Pierre Le Meur <pierre1.lemeur@orange.com> | ||
*/ | ||
|
||
#include "digit7seg.h" | ||
|
||
#define ENABLE_DEBUG 0 | ||
#include "debug.h" | ||
|
||
#define PIN_A (dev->params.data_a) | ||
#define PIN_B (dev->params.data_b) | ||
#define PIN_C (dev->params.data_c) | ||
#define PIN_D (dev->params.data_d) | ||
#define PIN_E (dev->params.data_e) | ||
#define PIN_F (dev->params.data_f) | ||
#define PIN_G (dev->params.data_g) | ||
#define PIN_DP (dev->params.data_dp) | ||
#define PIN_DIG1 (dev->params.dig1) | ||
#define PIN_DIG2 (dev->params.dig2) | ||
#define PIN_DIG3 (dev->params.dig3) | ||
#define PIN_DIG4 (dev->params.dig4) | ||
|
||
/** The 7 segments + decimal point + the number of digits */ | ||
#define NB_PIN (8+dev->params.digits) | ||
|
||
static void _set_pin_value(digit7seg_t *dev) | ||
{ | ||
const gpio_t pins[] = | ||
{ | ||
PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_G, PIN_DP | ||
}; | ||
|
||
uint8_t mask = 0xFF; | ||
uint8_t current_value = (uint8_t)(dev->value >> (dev->current_digit * 8) & mask); | ||
|
||
for (int i = 1; i <= 8; i++) { | ||
if (current_value & (1 << (8 - i))) { | ||
gpio_set(pins[i - 1]); | ||
DEBUG("PIN SET\n"); | ||
} | ||
else { | ||
gpio_clear(pins[i - 1]); | ||
DEBUG("PIN CLEAR\n"); | ||
} | ||
} | ||
} | ||
|
||
static void _shift_display(void *arg, int chan) | ||
{ | ||
(void)chan; | ||
digit7seg_t *dev = (digit7seg_t*)arg; | ||
|
||
const gpio_t digit_pins[] = | ||
{ | ||
PIN_DIG1, PIN_DIG2, PIN_DIG3, PIN_DIG4 | ||
}; | ||
|
||
gpio_clear(digit_pins[dev->current_digit]); | ||
dev->current_digit += 1; | ||
dev->current_digit = dev->current_digit % dev->params.digits; | ||
gpio_set(digit_pins[dev->current_digit]); | ||
|
||
DEBUG("[INFO] On display %d\n", dev->current_digit); | ||
|
||
_set_pin_value(dev); | ||
} | ||
|
||
int digit7seg_init(digit7seg_t *dev, const digit7seg_params_t *params) | ||
{ | ||
dev->params = *params; | ||
dev->current_digit = 0; | ||
dev->value = 0; | ||
|
||
if (dev->params.digits <= 0 || dev->params.digits > DIGIT7SEG_MAX_DIGITS) { | ||
DEBUG("[Error] Invalid number of digit.\n"); | ||
return -DIGIT7SEG_ERR_DIGITS; | ||
} | ||
|
||
const gpio_t pins[] = | ||
{ | ||
PIN_A, PIN_B, PIN_C, PIN_D, PIN_E, PIN_F, PIN_G, PIN_DP, | ||
PIN_DIG1, PIN_DIG2, PIN_DIG3, PIN_DIG4 | ||
}; | ||
|
||
const int pin_errs[] = | ||
{ | ||
DIGIT7SEG_ERR_A_GPIO, DIGIT7SEG_ERR_B_GPIO, DIGIT7SEG_ERR_C_GPIO, DIGIT7SEG_ERR_D_GPIO, | ||
DIGIT7SEG_ERR_E_GPIO, DIGIT7SEG_ERR_F_GPIO, DIGIT7SEG_ERR_G_GPIO, DIGIT7SEG_ERR_DP_GPIO, | ||
DIGIT7SEG_ERR_DIG1_GPIO, DIGIT7SEG_ERR_DIG2_GPIO, DIGIT7SEG_ERR_DIG3_GPIO, | ||
DIGIT7SEG_ERR_DIG4_GPIO | ||
}; | ||
|
||
for (int i = 0; i < NB_PIN; i++) { | ||
if (!gpio_is_valid(pins[i])) { | ||
DEBUG("[Error] GPIO isn't valid.\n"); | ||
return -pin_errs[i]; | ||
} | ||
|
||
if (gpio_init(pins[i], GPIO_OUT) < 0) { | ||
DEBUG("[Error] Initializing gpio error.\n"); | ||
return -pin_errs[i]; | ||
} | ||
|
||
gpio_clear(pins[i]); | ||
} | ||
|
||
return DIGIT7SEG_OK; | ||
} | ||
|
||
int digit7seg_shift(digit7seg_t *dev) | ||
{ | ||
_shift_display(dev, 0); | ||
return 0; | ||
} | ||
|
||
int digit7seg_set_all_value(digit7seg_t *dev, uint32_t value) | ||
{ | ||
dev->value = value; | ||
return 0; | ||
} | ||
|
||
int digit7seg_set_value(digit7seg_t *dev, int index, uint8_t value) | ||
{ | ||
if (index < 0 || index >= dev->params.digits) { | ||
return -1; | ||
} | ||
|
||
uint32_t temp_value = value << (index * 8); | ||
uint32_t up_value = dev->value >> ((index + 1) * 8); | ||
up_value <<= ((index + 1) * 8); | ||
uint32_t down_value = ((0b00000001 << (index * 8)) - 1) & dev->value; | ||
|
||
dev->value = up_value | temp_value | down_value; | ||
|
||
return 0; | ||
} | ||
|
||
int digit7seg_poweron(digit7seg_t *dev) | ||
{ | ||
if (dev->status == TIMER_RUNNING) { | ||
DEBUG("[Error] Timer is already running.\n"); | ||
return -1; | ||
} | ||
|
||
if (timer_init(dev->params.timer, DIGIT7SEG_TIMER_HZ, _shift_display, dev) != 0) { | ||
DEBUG("[Error] Impossible to init timer.\n"); | ||
return -1; | ||
} | ||
|
||
timer_set_periodic(dev->params.timer, 0, DIGIT7SEG_DELAY, TIM_FLAG_RESET_ON_MATCH); | ||
|
||
dev->status = TIMER_RUNNING; | ||
return 0; | ||
} | ||
|
||
int digit7seg_poweroff(digit7seg_t *dev) | ||
{ | ||
if (dev->status == TIMER_STOPPED) { | ||
DEBUG("[Error] Timer is already stopped.\n"); | ||
return -1; | ||
} | ||
|
||
timer_stop(dev->params.timer); | ||
dev->status = TIMER_STOPPED; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/* | ||
* Copyright (C) 2024 Orange | ||
* | ||
* 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. | ||
*/ | ||
|
||
/** | ||
|
||
@defgroup drivers_digit7seg Generic 7 segments driver | ||
@ingroup drivers_display | ||
@brief Device driver for less than 5 digits of 7 segments without IC | ||
|
||
## About | ||
|
||
This driver was developed to works with [5461AS](http://www.topliteusa.com/uploadfile/2014/0825/A-5461AS.pdf) | ||
in a way that all 4 digits (and less) with 7 segments without integrated controller | ||
can be controlled into [RIOT-OS](https://github.com/RIOT-OS/RIOT). | ||
|
||
### 7 segments | ||
|
||
Each digit contains 7 digit (plus decimal point), if the segment is set high and his | ||
digit is set high it will be lit. | ||
Each value is cut into 8 bits (a, b, c, d, e, f, g, dp), if the bit is 1 current is sent otherwise | ||
not. | ||
|
||
To display 0 we will pass the number | ||
``` | ||
dp g f e d c b a | ||
0 0 1 1 1 1 1 1 | ||
``` | ||
``` | ||
--a-- | ||
| | | ||
f b | ||
| | | ||
--g-- | ||
| | | ||
e c | ||
| | | ||
--d-- .dp | ||
``` | ||
|
||
### 4 digits of 7 segments | ||
|
||
To set up a 4 digits of 7 segments display, we need transistors to allow current to pass | ||
only when the corresponding digit pin digX is high. | ||
|
||
All the digits share the same value pins. To display different values on each digit, we shift the value | ||
and turn on each digit at a rate that is imperceptible to the human eye. | ||
|
||
``` | ||
.----.----.----.----. | ||
| | | | |-- a | ||
| | | | |-- b | ||
| | | | |-- c | ||
| | | | |-- d | ||
| | | | |-- e | ||
| | | | |-- f | ||
| | | | |-- g | ||
| | | | |-- dp | ||
'----'----'----'----' | ||
| | | | | ||
T-------------------- dig1 | ||
| | | | | ||
| T--------------- dig2 | ||
| | | | | ||
| | T---------- dig3 | ||
| | | | | ||
| | | T----- dig4 | ||
| | | | | ||
└──--└──--└──--└──--- GND | ||
``` | ||
|
||
@note T represent a NPN transistor | ||
|
||
## Error Handling | ||
|
||
All driver functions return 0 on success or one of a negative error code defined by | ||
#digit7seg_error_codes. | ||
|
||
## Usage | ||
|
||
To use the digit7seg driver, the configuration must be set by including `digit7seg_params.h` | ||
or defining a `digit7seg_params_t` struct. | ||
|
||
The structure of a configuration is defined in #digit7seg_params_t and consists of the following | ||
parameters: | ||
|
||
Parameter | Symbol in ```digit7seg_params.h``` | Default | ||
:------------------------------|:-----------------------------------|:------------------ | ||
Data pin for a segment | DIGIT7SEG_PARAM_A_PIN | GPIO_PIN(1, 11) | ||
Data pin for b segment | DIGIT7SEG_PARAM_B_PIN | GPIO_PIN(1, 12) | ||
Data pin for c segment | DIGIT7SEG_PARAM_C_PIN | GPIO_PIN(1, 15) | ||
Data pin for d segment | DIGIT7SEG_PARAM_D_PIN | GPIO_PIN(1, 13) | ||
Data pin for e segment | DIGIT7SEG_PARAM_E_PIN | GPIO_PIN(1, 14) | ||
Data pin for f segment | DIGIT7SEG_PARAM_F_PIN | GPIO_PIN(0, 23) | ||
Data pin for g segment | DIGIT7SEG_PARAM_G_PIN | GPIO_PIN(0, 21) | ||
Data pin for dp segment | DIGIT7SEG_PARAM_DP_PIN | GPIO_PIN(0, 27) | ||
Pin to on digit 1 | DIGIT7SEG_PARAM_DIG1_PIN | GPIO_PIN(1, 2) | ||
Pin to on digit 2 | DIGIT7SEG_PARAM_DIG2_PIN | GPIO_PIN(1, 1) | ||
Pin to on digit 3 | DIGIT7SEG_PARAM_DIG3_PIN | GPIO_PIN(1, 8) | ||
Pin to on digit 4 | DIGIT7SEG_PARAM_DIG4_PIN | GPIO_PIN(0, 13) | ||
Timer for periodic interrupt | DIGIT7SEG_PARAM_TIMER | TIMER_DEV(2) | ||
Number of digits on the periph | DIGIT7SEG_PARAM_DIGITS | 4 | ||
|
||
The default configuration can be overwritten by the application. | ||
|
||
Example: | ||
``` | ||
#define DIGIT7SEG_PARAM_TIMER TIMER_DEV(1) | ||
#define DIGIT7SEG_PARAM_DIGITS (2) | ||
... | ||
#include "digit7seg.h" | ||
#include "digit7seg_param.h" | ||
``` | ||
|
||
Another way to override params is to override DIGIT7SEG_PARAMS that will | ||
be stocked into digit7seg_params. | ||
|
||
@note At least all the data_* pin must be defined, depending of the number of digits set, dig4, dig3, dig2 can be set at GPIO_UNDEF. | ||
|
||
Example: | ||
``` | ||
#define DIGIT7SEG_PARAMS { .data_a = GPIO(1, 14), \ | ||
.data_b = GPIO(1, 17), \ | ||
.data_c = GPIO(1, 15), \ | ||
.data_d = GPIO(1, 13), \ | ||
.data_e = GPIO(1, 12), \ | ||
.data_f = GPIO(0, 23), \ | ||
.data_g = GPIO(0, 21), \ | ||
.data_dp = GPIO(1, 11), \ | ||
.dig1 = GPIO(0, 13), \ | ||
.dig2 = GPIO(1, 8), \ | ||
.dig3 = GPIO_UNDEF, \ | ||
.dig4 = GPIO_UNDEF, \ | ||
.timer = TIMER_DEV(2), \ | ||
.digits = 2 } | ||
... | ||
#include "digit7seg.h" | ||
#include "digit7seg_param.h" | ||
``` | ||
|
||
The ::digit7seg_init function initializes a #digit7seg_t and checks if every parameter is correctly set. | ||
|
||
Example: | ||
``` | ||
digit7seg_t dev; | ||
|
||
if (digit7seg_init(&dev, &digit7seg_params[0]) != DIGIT7SEG_OK) { | ||
... /* error handling */ | ||
} | ||
``` | ||
|
||
Once the device is initialized and configured : | ||
- ::digit7seg_set_all_value function can be used to set the value for all the digits. | ||
- ::digit7seg_poweron function starts a periodic timer that cycles through each digit to give the impression that they are all lit simultaneously. | ||
- ::digit7seg_poweroff function stops this timer. | ||
|
||
Example: | ||
``` | ||
/* R I O T */ | ||
/* 11101110 00001100 11111100 00001110 */ | ||
uint32_t binary_riot = 0b11101110000011001111110000001110; | ||
digit7seg_set_all_value(&dev, binary_riot); | ||
|
||
if (digit7seg_poweron(&dev) == 0) { | ||
puts("Launched..."); | ||
} | ||
else { | ||
puts("Error"); | ||
} | ||
|
||
... | ||
|
||
if (digit7seg_poweroff(&dev) == 0) { | ||
puts("...Stopped"); | ||
} | ||
else { | ||
puts("Error"); | ||
} | ||
|
||
``` | ||
*/ |
Oops, something went wrong.