Blame view

RIOT/boards/calliope-mini/mini/mini.c 5.39 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  /*
   * Copyright (C) 2016 Freie Universitรคt Berlin
   *
   * 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     boards_calliope-mini
   * @{
   *
   * @file
   * @brief       Calliope mini specific LED matrix handling
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   *
   * @}
   */
  
  #include <string.h>
  #include "xtimer.h"
  
  #include "board.h"
  #include "mini.h"
  #include "mineplex.h"
  #include "periph/gpio.h"
  #include "periph/timer.h"
  
  #define ENABLE_DEBUG        (0)
  #include "debug.h"
  
  /**
   * @brief   The visible number of rows and columns of the LED matrix
   */
  #define ROWS                MINI_MATRIX_ROWS
  #define COLS                MINI_MATRIX_COLS
  
  /**
   * @brief   The electrical number of rows and columns
   */
  #define ROWS_HW             (3)
  #define COLS_HW             (9)
  
  /**
   * @brief   The refresh rate used for drawing the contents
   *
   * We want a refresh rate of at least 50Hz (->20ms), so the LEDs do not flicker.
   */
  #define REFRESH             (6000)      /* 6ms * 3 rows -> ~55Hz */
  
  /**
   * @brief   GPIO pins driving the rows
   */
  static const gpio_t rows[ROWS_HW] = {
      MINI_LED_ROW1,
      MINI_LED_ROW2,
      MINI_LED_ROW3
  };
  
  /**
   * @brief   GPIO pins driving the columns
   */
  static const gpio_t cols[COLS_HW] = {
      MINI_LED_COL1,
      MINI_LED_COL2,
      MINI_LED_COL3,
      MINI_LED_COL4,
      MINI_LED_COL5,
      MINI_LED_COL6,
      MINI_LED_COL7,
      MINI_LED_COL8,
      MINI_LED_COL9,
  };
  
  /**
   * @brief   Map electrical layout to visible layout
   *
   * The electrical layout of the matrix is different than the visible layout
   * (3x9 -> 5x5). This array maps from the visible 5 by 5 layout to the actual
   * 3 by 9 layout used by the hardware.
   */
  static const uint8_t pixmap[5][5] = {
      {  0, 12,  1, 13,  2 },
      { 21, 22, 23, 24, 25 },
      { 10,  8, 11, 26,  9 },
      {  7,  6,  5,  4,  3 },
      { 20, 15, 18, 14, 19 }
  };
  
  /**
   * @brief   Buffer holding the current 'image' that is displayed
   */
  static uint8_t framebuf[ROWS_HW * COLS_HW] = { 0 };
  
  /**
   * @brief   Internal counter to keep track of which row needs to be refreshed
   *          next
   */
  static unsigned cur_row = 0;
  
  /**
   * @brief   Write a Mineplex encoded character into the given buffer
   *
   * @param[in]  c    character to write
   * @param[out] buf  buffer to write the encoded character into, MUST be able to
   *                  hold 25 byte
   */
  static void char2buf(char c, uint8_t *buf)
  {
      const uint8_t *raw = mineplex_char(c);
  
      /* set each row */
      for (int row = 0; row < ROWS; row++) {
          for (int col = 0; col < COLS; col++) {
              buf[(row * COLS) + col] = (raw[row] & (1 << col));
          }
      }
  }
  
  /**
   * @brief   Shift out and replace an image with the next, column by column
   *
   * @param[in|out] cur   current 'image', will be overwritten
   * @param[in] next      image to shift in
   * @param[in] delay     delay between each column
   */
  static void shift_next(uint8_t *cur, const uint8_t *next, uint32_t delay)
  {
      for (int i = 0; i < COLS; i++) {
          for (int r = 0; r < ROWS; r++) {
              for (int c = 0; c < (COLS - 1); c++) {
                  cur[(r * COLS) + c] = cur[(r * COLS) + c + 1];
              }
              cur[(r * COLS) + COLS - 1] = next[(r * COLS) + i];
          }
          mini_matrix_set_raw((uint8_t *)cur);
          xtimer_usleep(delay);
      }
  }
  
  static void refresh(void *arg, int channel)
  {
      (void)arg;
      (void)channel;
  
      /* set next refresh */
      timer_set(TIMER_DEV(2), 0, REFRESH);
  
      /* disable current row */
      gpio_clear(rows[cur_row]);
      /* goto next row */
      cur_row = ((++cur_row) < ROWS_HW) ? cur_row : 0;
      /* setup columns */
      int base = (COLS_HW * cur_row);
      for (int i = 0; i < COLS_HW; i++) {
          gpio_write(cols[i], !(framebuf[base + i]));
      }
      /* and finally enable the new row */
      gpio_set(rows[cur_row]);
  }
  
  void mini_matrix_init(void)
  {
      /* initialize rows */
      for (int i = 0; i < ROWS_HW; i++) {
          gpio_init(rows[i], GPIO_OUT);
          gpio_clear(rows[i]);
      }
      /* initialize columns */
      for (int i = 0; i < COLS_HW; i++) {
          gpio_init(cols[i], GPIO_OUT);
          gpio_set(cols[i]);
      }
      /* and finally initialize and start the refresh timer */
      timer_init(TIMER_DEV(2), 1000000, refresh, NULL);
      timer_set(TIMER_DEV(2), 0, REFRESH);
  }
  
  void mini_matrix_on(uint8_t row, uint8_t col)
  {
      if ((row >= 5) || (col >= 5)) {
          return;
      }
  
      framebuf[pixmap[row][col]] = 0x01;
  }
  
  void mini_matrix_off(uint8_t row, uint8_t col)
  {
      if ((row >= 5) || (col >= 5)) {
          return;
      }
  
      framebuf[pixmap[row][col]] = 0x00;
  }
  
  void mini_matrix_set_raw(const uint8_t *buf) {
      for (int row = 0; row < ROWS; row++) {
          for (int col = 0; col < COLS; col++) {
              framebuf[pixmap[row][col]] = buf[(row * COLS) + col];
          }
      }
  }
  
  void mini_matrix_set_char(char c)
  {
      uint8_t buf[ROWS * COLS];
  
      char2buf(c, buf);
      mini_matrix_set_raw(buf);
  }
  
  void mini_matrix_shift_str(const char *str, uint32_t delay)
  {
      uint8_t curbuf[ROWS][COLS];
      uint8_t newbuf[ROWS][COLS];
  
      char2buf(' ', (uint8_t *)curbuf);
      mini_matrix_set_raw((uint8_t *)curbuf);
      while (*str) {
          char2buf(*str++, (uint8_t *)newbuf);
          shift_next((uint8_t *)curbuf, (uint8_t *)newbuf, delay);
      }
      char2buf(' ', (uint8_t *)newbuf);
      shift_next((uint8_t *)curbuf, (uint8_t *)newbuf, delay);
  }