sseg.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Xytronic LF-1600
  3. * Seven segment (plus decimal point) driver
  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 "sseg.h"
  22. #include "bitmap.h"
  23. static const uint8_t __flash digit_to_segment_map[] = {
  24. ['0' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  25. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  26. (0 << SSEG_G),
  27. ['1' - '0'] = (0 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  28. (0 << SSEG_D) | (0 << SSEG_E) | (0 << SSEG_F) |
  29. (0 << SSEG_G),
  30. ['2' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (0 << SSEG_C) |
  31. (1 << SSEG_D) | (1 << SSEG_E) | (0 << SSEG_F) |
  32. (1 << SSEG_G),
  33. ['3' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  34. (1 << SSEG_D) | (0 << SSEG_E) | (0 << SSEG_F) |
  35. (1 << SSEG_G),
  36. ['4' - '0'] = (0 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  37. (0 << SSEG_D) | (0 << SSEG_E) | (1 << SSEG_F) |
  38. (1 << SSEG_G),
  39. ['5' - '0'] = (1 << SSEG_A) | (0 << SSEG_B) | (1 << SSEG_C) |
  40. (1 << SSEG_D) | (0 << SSEG_E) | (1 << SSEG_F) |
  41. (1 << SSEG_G),
  42. ['6' - '0'] = (1 << SSEG_A) | (0 << SSEG_B) | (1 << SSEG_C) |
  43. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  44. (1 << SSEG_G),
  45. ['7' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  46. (0 << SSEG_D) | (0 << SSEG_E) | (0 << SSEG_F) |
  47. (0 << SSEG_G),
  48. ['8' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  49. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  50. (1 << SSEG_G),
  51. ['9' - '0'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  52. (1 << SSEG_D) | (0 << SSEG_E) | (1 << SSEG_F) |
  53. (1 << SSEG_G),
  54. };
  55. #define EMPTY_SEG 0
  56. static const uint8_t __flash char_to_segment_map[] = {
  57. ['A' - 'A'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  58. (0 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  59. (1 << SSEG_G),
  60. ['B' - 'A'] = (0 << SSEG_A) | (0 << SSEG_B) | (1 << SSEG_C) |
  61. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  62. (1 << SSEG_G),
  63. ['C' - 'A'] = (1 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  64. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  65. (0 << SSEG_G),
  66. ['D' - 'A'] = (0 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  67. (1 << SSEG_D) | (1 << SSEG_E) | (0 << SSEG_F) |
  68. (1 << SSEG_G),
  69. ['E' - 'A'] = (1 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  70. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  71. (1 << SSEG_G),
  72. ['F' - 'A'] = (1 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  73. (0 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  74. (1 << SSEG_G),
  75. ['G' - 'A'] = (1 << SSEG_A) | (0 << SSEG_B) | (1 << SSEG_C) |
  76. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  77. (1 << SSEG_G),
  78. ['H' - 'A'] = (0 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  79. (0 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  80. (1 << SSEG_G),
  81. ['I' - 'A'] = (0 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  82. (0 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  83. (0 << SSEG_G),
  84. ['J' - 'A'] = (0 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  85. (1 << SSEG_D) | (0 << SSEG_E) | (0 << SSEG_F) |
  86. (0 << SSEG_G),
  87. ['K' - 'A'] = EMPTY_SEG,
  88. ['L' - 'A'] = (0 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  89. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  90. (0 << SSEG_G),
  91. ['M' - 'A'] = EMPTY_SEG,
  92. ['N' - 'A'] = (0 << SSEG_A) | (0 << SSEG_B) | (1 << SSEG_C) |
  93. (0 << SSEG_D) | (1 << SSEG_E) | (0 << SSEG_F) |
  94. (1 << SSEG_G),
  95. ['O' - 'A'] = (1 << SSEG_A) | (1 << SSEG_B) | (1 << SSEG_C) |
  96. (1 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  97. (0 << SSEG_G),
  98. ['P' - 'A'] = (1 << SSEG_A) | (1 << SSEG_B) | (0 << SSEG_C) |
  99. (0 << SSEG_D) | (1 << SSEG_E) | (1 << SSEG_F) |
  100. (1 << SSEG_G),
  101. ['Q' - 'A'] = EMPTY_SEG,
  102. ['R' - 'A'] = (0 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  103. (0 << SSEG_D) | (1 << SSEG_E) | (0 << SSEG_F) |
  104. (1 << SSEG_G),
  105. };
  106. static const uint8_t __flash segment_mask_minus =
  107. (0 << SSEG_A) | (0 << SSEG_B) | (0 << SSEG_C) |
  108. (0 << SSEG_D) | (0 << SSEG_E) | (0 << SSEG_F) |
  109. (1 << SSEG_G);
  110. static void mux_write(const struct sseg_digit_data *ddata,
  111. bool enable)
  112. {
  113. const struct sseg_iomap __flash *iomap = ddata->iomap;
  114. if (!iomap->mux_polarity)
  115. enable = !enable;
  116. if (enable)
  117. SFR_BYTE(iomap->mux_port) |= iomap->mux_mask;
  118. else
  119. SFR_BYTE(iomap->mux_port) &= (uint8_t)~iomap->mux_mask;
  120. }
  121. static void segment_write(const struct sseg_digit_data *ddata)
  122. {
  123. const struct sseg_iomap __flash *iomap = ddata->iomap;
  124. const struct sseg_segment_iomap __flash *segment_iomap = iomap->segment;
  125. uint8_t enable_set, enable_mask;
  126. uint8_t value;
  127. enable_set = ddata->segment_enable_set;
  128. enable_mask = ddata->segment_enable_mask;
  129. if (!segment_iomap->segment_polarity)
  130. enable_set = (uint8_t)~enable_set;
  131. enable_set &= enable_mask;
  132. value = SFR_BYTE(segment_iomap->segment_port);
  133. value &= (uint8_t)~enable_mask;
  134. value |= enable_set;
  135. SFR_BYTE(segment_iomap->segment_port) = value;
  136. }
  137. void sseg_digit_set(struct sseg_digit_data *ddata,
  138. char digit)
  139. {
  140. const struct sseg_iomap __flash *iomap = ddata->iomap;
  141. const struct sseg_segment_iomap __flash *segment_iomap = iomap->segment;
  142. uint8_t segment_mask;
  143. uint8_t segment_enable_set;
  144. uint8_t dp;
  145. int8_t i;
  146. dp = (uint8_t)digit & (uint8_t)SSEG_DIGIT_DP;
  147. digit &= (char)~SSEG_DIGIT_DP;
  148. /* Get the generic segment mask for the digit. */
  149. if (digit >= 'a' && digit <= 'z')
  150. digit = (char)(digit - ('a' - 'A'));
  151. if (digit >= '0' && digit <= '9')
  152. segment_mask = digit_to_segment_map[digit - '0'];
  153. else if (digit >= 'A' &&
  154. digit <= (char)('A' + ARRAY_SIZE(char_to_segment_map) - 1))
  155. segment_mask = char_to_segment_map[digit - 'A'];
  156. else if (digit == '-')
  157. segment_mask = segment_mask_minus;
  158. else
  159. segment_mask = 0;
  160. if (dp)
  161. segment_mask |= (1 << SSEG_DP);
  162. /* Get the digit specific mask from iomap. */
  163. segment_enable_set = 0;
  164. for (i = SSEG_A; i < SSEG_NR_SEGMENTS; i++) {
  165. if (segment_mask & BITMASK8(i))
  166. segment_enable_set |= segment_iomap->segment_masks[i];
  167. }
  168. ddata->segment_enable_set = segment_enable_set;
  169. }
  170. void sseg_multiplex(const struct sseg_digit_data *ddata_from,
  171. const struct sseg_digit_data *ddata_to)
  172. {
  173. /* Turn off the previous digit. */
  174. mux_write(ddata_from, 0);
  175. /* Write the new segment data. */
  176. segment_write(ddata_to);
  177. /* Turn on the new segment. */
  178. mux_write(ddata_to, 1);
  179. }
  180. void sseg_init(struct sseg_digit_data *ddata)
  181. {
  182. const struct sseg_iomap __flash *iomap = ddata->iomap;
  183. const struct sseg_segment_iomap __flash *segment_iomap = iomap->segment;
  184. uint8_t segment_mask, mux_mask;
  185. int8_t i;
  186. /* Get the port masks. */
  187. segment_mask = 0;
  188. for (i = 0; i < SSEG_NR_SEGMENTS; i++)
  189. segment_mask |= segment_iomap->segment_masks[i];
  190. mux_mask = iomap->mux_mask;
  191. /* Configure the segment port. */
  192. ddata->segment_enable_mask = segment_mask;
  193. ddata->segment_enable_set = 0;
  194. segment_write(ddata);
  195. SFR_BYTE(segment_iomap->segment_ddr) |= segment_mask;
  196. /* Configure the multiplexer port. */
  197. mux_write(ddata, 0);
  198. SFR_BYTE(iomap->mux_ddr) |= mux_mask;
  199. }
  200. void sseg_exit(struct sseg_digit_data *ddata)
  201. {
  202. const struct sseg_iomap __flash *iomap = ddata->iomap;
  203. const struct sseg_segment_iomap __flash *segment_iomap = iomap->segment;
  204. uint8_t segment_mask, mux_mask;
  205. mux_mask = iomap->mux_mask;
  206. segment_mask = ddata->segment_enable_mask;
  207. SFR_BYTE(segment_iomap->segment_port) &= (uint8_t)~segment_mask;
  208. SFR_BYTE(segment_iomap->segment_ddr) &= (uint8_t)~segment_mask;
  209. SFR_BYTE(iomap->mux_port) &= (uint8_t)~mux_mask;
  210. SFR_BYTE(iomap->mux_ddr) &= (uint8_t)~mux_mask;
  211. }