display.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Xytronic LF-1600
  3. * Display routines
  4. *
  5. * Copyright (c) 2015-2016 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. */
  21. #include "display.h"
  22. #include "sseg.h"
  23. #include "timer.h"
  24. #include "bitmap.h"
  25. #include "ring.h"
  26. #include <string.h>
  27. #define DISPLAY_MUX_PERIOD_MS 1
  28. static const struct sseg_segment_iomap __flash big_digit = {
  29. .segment_ddr = SFR_ADDR(DDRD),
  30. .segment_port = SFR_ADDR(PORTD),
  31. .segment_masks = {
  32. [SSEG_A] = 1u << PD7,
  33. [SSEG_B] = 1u << PD0,
  34. [SSEG_C] = 1u << PD2,
  35. [SSEG_D] = 1u << PD4,
  36. [SSEG_E] = 1u << PD5,
  37. [SSEG_F] = 1u << PD6,
  38. [SSEG_G] = 1u << PD1,
  39. [SSEG_DP] = 1u << PD3,
  40. },
  41. .segment_polarity = 0,
  42. };
  43. static const struct sseg_segment_iomap __flash small_digit = {
  44. .segment_ddr = SFR_ADDR(DDRD),
  45. .segment_port = SFR_ADDR(PORTD),
  46. .segment_masks = {
  47. [SSEG_A] = 1u << PD2,
  48. [SSEG_B] = 1u << PD3,
  49. [SSEG_C] = 1u << PD0,
  50. [SSEG_D] = 1u << PD1,
  51. [SSEG_E] = 1u << PD6,
  52. [SSEG_F] = 1u << PD4,
  53. [SSEG_G] = 1u << PD7,
  54. [SSEG_DP] = 1u << PD5,
  55. },
  56. .segment_polarity = 0,
  57. };
  58. static const struct sseg_iomap __flash digit_iomaps[] = {
  59. {
  60. .segment = &big_digit,
  61. .mux_ddr = SFR_ADDR(DDRC),
  62. .mux_port = SFR_ADDR(PORTC),
  63. .mux_mask = 1u << PC3,
  64. .mux_polarity = 1,
  65. }, {
  66. .segment = &big_digit,
  67. .mux_ddr = SFR_ADDR(DDRC),
  68. .mux_port = SFR_ADDR(PORTC),
  69. .mux_mask = 1u << PC4,
  70. .mux_polarity = 1,
  71. }, {
  72. .segment = &big_digit,
  73. .mux_ddr = SFR_ADDR(DDRC),
  74. .mux_port = SFR_ADDR(PORTC),
  75. .mux_mask = 1u << PC5,
  76. .mux_polarity = 1,
  77. }, {
  78. .segment = &small_digit,
  79. .mux_ddr = SFR_ADDR(DDRB),
  80. .mux_port = SFR_ADDR(PORTB),
  81. .mux_mask = 1u << PB7,
  82. .mux_polarity = 1,
  83. },
  84. };
  85. #define DISPLAY_NR_DIGITS ARRAY_SIZE(digit_iomaps)
  86. struct display_digit {
  87. struct sseg_digit_data sseg;
  88. bool dp_force_enable;
  89. bool dp_on;
  90. };
  91. struct display_context {
  92. bool enabled;
  93. struct display_digit digit_data[DISPLAY_NR_DIGITS];
  94. uint8_t digit_mux_count;
  95. struct timer mux_timer;
  96. };
  97. static struct display_context display;
  98. void display_force_dp(int8_t dp, bool force_en, bool dp_on)
  99. {
  100. display.digit_data[dp].dp_force_enable = force_en;
  101. display.digit_data[dp].dp_on = dp_on;
  102. }
  103. void display_show(const char *digits)
  104. {
  105. struct display_digit *digit_data;
  106. char c;
  107. digit_data = &display.digit_data[0];
  108. do {
  109. c = digits[0];
  110. if (c == '\0') {
  111. c = ' ';
  112. } else {
  113. if (digits[1] == '.') {
  114. c = (char)(c | SSEG_DIGIT_DP);
  115. digits++;
  116. }
  117. if (digit_data->dp_force_enable) {
  118. if (digit_data->dp_on)
  119. c = (char)(c | SSEG_DIGIT_DP);
  120. else
  121. c = (char)(c & (char)~SSEG_DIGIT_DP);
  122. }
  123. digits++;
  124. }
  125. sseg_digit_set(&digit_data->sseg, c);
  126. digit_data++;
  127. } while (digit_data < &display.digit_data[DISPLAY_NR_DIGITS]);
  128. }
  129. void display_work(void)
  130. {
  131. uint8_t cur_mux, next_mux;
  132. if (!display.enabled)
  133. return;
  134. if (!timer_expired(&display.mux_timer))
  135. return;
  136. timer_add(&display.mux_timer, DISPLAY_MUX_PERIOD_MS);
  137. cur_mux = display.digit_mux_count;
  138. next_mux = ring_next(cur_mux, DISPLAY_NR_DIGITS - 1u);
  139. display.digit_mux_count = next_mux;
  140. sseg_multiplex(&display.digit_data[cur_mux].sseg,
  141. &display.digit_data[next_mux].sseg);
  142. }
  143. void display_enable(bool enable)
  144. {
  145. uint8_t i;
  146. struct sseg_digit_data *ddata;
  147. if (enable == display.enabled)
  148. return;
  149. display.enabled = enable;
  150. if (enable) {
  151. for (i = 0; i < DISPLAY_NR_DIGITS; i++) {
  152. ddata = &display.digit_data[i].sseg;
  153. ddata->iomap = &digit_iomaps[i];
  154. sseg_init(ddata);
  155. }
  156. timer_set_now(&display.mux_timer);
  157. } else {
  158. for (i = 0; i < DISPLAY_NR_DIGITS; i++) {
  159. ddata = &display.digit_data[i].sseg;
  160. sseg_exit(ddata);
  161. }
  162. }
  163. }
  164. void display_init(void)
  165. {
  166. display_enable(true);
  167. }