Subversion Repositories svn.mios32

Rev

Rev 1290 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1216 tk 1
// $Id: app.c 2425 2016-11-03 00:44:22Z tk $
2
/*
3
 * Code is used from some MIOS32 tutorials
4
 *
5
 * ==========================================================================
6
 *
7
 *  Copyright (C) 2011 Thorsten Klose (tk@midibox.org)
8
 *  Licensed for personal non-commercial use only.
9
 *  All other rights reserved.
10
 *
11
 * ==========================================================================
12
 */
13
 
14
/////////////////////////////////////////////////////////////////////////////
15
// Include files
16
/////////////////////////////////////////////////////////////////////////////
17
 
18
#include <mios32.h>
19
#include "app.h"
20
 
21
#include <glcd_font.h>
22
 
23
// include everything FreeRTOS related we don't understand yet ;)
24
#include <FreeRTOS.h>
25
#include <portmacro.h>
26
#include <task.h>
27
#include <queue.h>
28
#include <semphr.h>
29
 
30
 
31
/////////////////////////////////////////////////////////////////////////////
32
// Local definitions
33
/////////////////////////////////////////////////////////////////////////////
34
 
35
#define NUM_ENCODERS 40
36
#define NUM_MATRICES 2
37
 
38
// define priority level for MATRIX_SCAN task:
39
// use same priority as MIOS32 specific tasks (3)
40
#define PRIORITY_TASK_MATRIX_SCAN   ( tskIDLE_PRIORITY + 3 )
41
 
42
// local prototype of the task function
43
static void TASK_MATRIX_Scan(void *pvParameters);
44
 
45
/////////////////////////////////////////////////////////////////////////////
46
// Local variables
47
/////////////////////////////////////////////////////////////////////////////
48
 
49
static u8 enc_virtual_pos[NUM_ENCODERS];
50
 
51
static u16 matrix16x16_button_row_values[NUM_MATRICES][16];
52
static u16 matrix16x16_button_row_changed[NUM_MATRICES][16];
53
 
54
static u8 matrix16x16_ctr;
55
 
56
// "ampelcode"
57
const u8 ledring_pattern[8] = {
58
  0x01,
59
  0x03,
60
  0x07,
61
  0x0f,
62
  0x1f,
63
  0x3f,
64
  0x7f,
65
  0xff,
66
};
67
 
68
/////////////////////////////////////////////////////////////////////////////
69
// Local prototypes
70
/////////////////////////////////////////////////////////////////////////////
71
static void TASK_MATRIX_Scan(void *pvParameters);
72
 
73
 
74
/////////////////////////////////////////////////////////////////////////////
75
// This hook is called after startup to initialize the application
76
/////////////////////////////////////////////////////////////////////////////
77
void APP_Init(void)
78
{
79
  // initialize all LEDs
80
  MIOS32_BOARD_LED_Init(0xffffffff);
81
 
82
  // initialize rotary encoders of the same type (DETENTED2)
83
  int enc;
84
  for(enc=0; enc<NUM_ENCODERS; ++enc) {
85
#if FIRST_ENC_DIN_SR
86
    u8 pin_sr = (FIRST_ENC_DIN_SR-1) + (enc >> 2); // each DIN SR has 4 encoders connected
87
    u8 pin_pos = (enc & 0x3) << 1; // Pin position of first ENC channel: either 0, 2, 4 or 6
88
 
89
    mios32_enc_config_t enc_config = MIOS32_ENC_ConfigGet(enc);
90
    enc_config.cfg.type = DETENTED2; // see mios32_enc.h for available types
91
    enc_config.cfg.sr = pin_sr;
92
    enc_config.cfg.pos = pin_pos;
93
#if 1
94
    // normal speed, incrementer either 1 or -1
95
    enc_config.cfg.speed = NORMAL;
96
    enc_config.cfg.speed_par = 0;
97
#else
98
    // higher incrementer values on fast movements
99
    enc_config.cfg.speed = FAST;
100
    enc_config.cfg.speed_par = 2;
101
#endif
102
    MIOS32_ENC_ConfigSet(enc, enc_config);
103
#endif
104
 
105
    // reset virtual positions
106
    enc_virtual_pos[enc] = 0;
107
  }
108
 
109
  matrix16x16_ctr = 0;
110
 
111
  u8 mod;
112
  for(mod=0; mod<NUM_MATRICES; ++mod) {
113
    u8 row;
114
    for(row=0; row<16; ++row) {
115
      matrix16x16_button_row_values[mod][row] = 0xffff;
116
      matrix16x16_button_row_changed[mod][row] = 0x0000;
117
    }
118
  }
119
 
120
  // start task
2425 tk 121
  xTaskCreate(TASK_MATRIX_Scan, "MATRIX_Scan", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_MATRIX_SCAN, NULL);
1216 tk 122
}
123
 
124
 
125
/////////////////////////////////////////////////////////////////////////////
126
// This task is running endless in background
127
/////////////////////////////////////////////////////////////////////////////
128
void APP_Background(void)
129
{
130
  // print static screen
131
  MIOS32_LCD_FontInit((u8 *)GLCD_FONT_NORMAL);
132
 
133
  // clear LCD
134
  MIOS32_LCD_Clear();
135
 
136
  // endless loop - LED will flicker on each iteration
137
  while( 1 ) {
138
    // toggle the state of all LEDs (allows to measure the execution speed with a scope)
139
    MIOS32_BOARD_LED_Set(0xffffffff, ~MIOS32_BOARD_LED_Get());
140
 
141
    // X/Y "position" of displays (see also comments in $MIOS32_PATH/modules/app_lcd/pcd8544/README.txt)
142
    const u8 lcd_x[8] = {0, 1, 2, 0, 1, 2, 0, 1}; // CS#0..7
143
    const u8 lcd_y[8] = {0, 0, 0, 1, 1, 1, 2, 2};
144
 
145
    u8 i;
146
    for(i=0; i<8; ++i) {
147
      u8 x_offset = 84*lcd_x[i];
148
      u8 y_offset = 6*8*lcd_y[i];
149
 
150
      // print text
151
      MIOS32_LCD_GCursorSet(x_offset + 0, y_offset + 0*8);
152
      MIOS32_LCD_PrintFormattedString("  PCD8544 #%d", i+1);
153
 
154
      MIOS32_LCD_GCursorSet(x_offset + 0, y_offset + 2*8);
155
      MIOS32_LCD_PrintString("  powered by  ");
156
 
157
      MIOS32_LCD_FontInit((u8 *)GLCD_FONT_BIG);
158
      MIOS32_LCD_GCursorSet(x_offset + 0, y_offset + 3*8);
159
      MIOS32_LCD_PrintString("MIOS");
160
 
161
      MIOS32_LCD_FontInit((u8 *)GLCD_FONT_NORMAL);
162
      MIOS32_LCD_GCursorSet(x_offset + 64, y_offset + 4*8);
163
      MIOS32_LCD_PrintString("32");
164
    }
165
  }
166
}
167
 
168
 
169
/////////////////////////////////////////////////////////////////////////////
170
// This hook is called when a MIDI package has been received
171
/////////////////////////////////////////////////////////////////////////////
172
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
173
{
174
}
175
 
176
 
177
/////////////////////////////////////////////////////////////////////////////
178
// This hook is called before the shift register chain is scanned
179
/////////////////////////////////////////////////////////////////////////////
180
void APP_SRIO_ServicePrepare(void)
181
{
182
  // 2 * 16x16 Matrix DOUTs
183
  if( ++matrix16x16_ctr >= 16 )
184
    matrix16x16_ctr = 0;
185
 
1217 tk 186
  u16 matrix_select = ~(1 << matrix16x16_ctr); // if cathodes are connected to DOUTs
1216 tk 187
 
188
#if DOUT_16x16_L
189
  MIOS32_DOUT_SRSet(DOUT_16x16_L-1, (matrix_select >> 0) & 0xff);
190
#endif
191
#if DOUT_16x16_R
192
  MIOS32_DOUT_SRSet(DOUT_16x16_R-1, (matrix_select >> 8) & 0xff);
193
#endif
194
 
195
  // 32x8 LED rings DOUTs
196
  u8 enc_offset = matrix16x16_ctr % 8;
197
#if DOUT_LEDRINGS_CATHODES
198
  u8 ledring_cathodes = ~(1 << enc_offset);
199
  MIOS32_DOUT_SRSet(DOUT_LEDRINGS_CATHODES-1, ledring_cathodes);
200
#endif
201
 
202
#if DOUT_LEDRINGS_1_8
203
  {
204
    u8 pattern = ledring_pattern[enc_virtual_pos[0 + enc_offset] >> 4];
205
    MIOS32_DOUT_SRSet(DOUT_LEDRINGS_1_8-1, pattern);
206
  }
207
#endif
208
#if DOUT_LEDRINGS_9_16
209
  {
210
    u8 pattern = ledring_pattern[enc_virtual_pos[8 + enc_offset] >> 4];
211
    MIOS32_DOUT_SRSet(DOUT_LEDRINGS_9_16-1, pattern);
212
  }
213
#endif
214
#if DOUT_LEDRINGS_17_24
215
  {
216
    u8 pattern = ledring_pattern[enc_virtual_pos[16 + enc_offset] >> 4];
217
    MIOS32_DOUT_SRSet(DOUT_LEDRINGS_17_24-1, pattern);
218
  }
219
#endif
220
#if DOUT_LEDRINGS_25_32
221
  {
222
    u8 pattern = ledring_pattern[enc_virtual_pos[24 + enc_offset] >> 4];
223
    MIOS32_DOUT_SRSet(DOUT_LEDRINGS_25_32-1, pattern);
224
  }
225
#endif
226
 
227
}
228
 
229
 
230
/////////////////////////////////////////////////////////////////////////////
231
// This hook is called after the shift register chain has been scanned
232
/////////////////////////////////////////////////////////////////////////////
233
void APP_SRIO_ServiceFinish(void)
234
{
235
  const u8 din_map[2*2] = {
236
    DIN_16x16_L0,
237
    DIN_16x16_R0,
238
    DIN_16x16_L1,
239
    DIN_16x16_R1
240
  };
241
 
242
  // check for DIN changes
243
  // Note: matrix16x16_ctr was incremented before in APP_SRIO_ServicePrepare()
244
  int selected_row = (matrix16x16_ctr-1) & 0xf;
245
 
246
  // check DINs
247
  int mod;
248
  for(mod=0; mod<NUM_MATRICES; ++mod) {
1218 tk 249
    int sr0 = din_map[2*mod+0];
250
    int sr1 = din_map[2*mod+1];
1216 tk 251
 
1218 tk 252
    u16 sr_value = 0;
253
    if( sr0 ) {
254
      MIOS32_DIN_SRChangedGetAndClear(sr0-1, 0xff); // ensure that change won't be propagated to normal DIN handler
255
      sr_value |= (MIOS32_DIN_SRGet(sr0-1) << 0);
256
    }
1216 tk 257
 
1218 tk 258
    if( sr1 ) {
259
      MIOS32_DIN_SRChangedGetAndClear(sr1-1, 0xff); // ensure that change won't be propagated to normal DIN handler
260
      sr_value |= (MIOS32_DIN_SRGet(sr1-1) << 8);
261
    }
1216 tk 262
 
1218 tk 263
    // determine pin changes
264
    u16 changed = sr_value ^ matrix16x16_button_row_values[mod][selected_row];
265
 
266
    if( changed ) {
267
      // add them to existing notifications
268
      matrix16x16_button_row_changed[mod][selected_row] |= changed;
269
 
270
      // store new value
271
      matrix16x16_button_row_values[mod][selected_row] = sr_value;
1216 tk 272
    }
273
  }
274
}
275
 
276
 
277
/////////////////////////////////////////////////////////////////////////////
278
// This hook is called when a button has been toggled
279
// pin_value is 1 when button released, and 0 when button pressed
280
/////////////////////////////////////////////////////////////////////////////
281
void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
282
{
283
}
284
 
285
 
286
/////////////////////////////////////////////////////////////////////////////
287
// This hook is called when an encoder has been moved
288
// incrementer is positive when encoder has been turned clockwise, else
289
// it is negative
290
/////////////////////////////////////////////////////////////////////////////
291
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
292
{
293
  // increment to virtual position and ensure that the value is in range 0..127
294
  int value = enc_virtual_pos[encoder] + incrementer;
295
  if( value < 0 )
296
    value = 0;
297
  else if( value > 127 )
298
    value = 127;
299
 
300
  // only send if value has changed
301
  if( enc_virtual_pos[encoder] != value ) {
302
    // store new value
303
    enc_virtual_pos[encoder] = value;
304
 
305
    // send event
306
    MIOS32_MIDI_SendCC(DEFAULT, Chn1, 0x20 + encoder, value);
307
  }
308
}
309
 
310
 
311
/////////////////////////////////////////////////////////////////////////////
312
// This hook is called when a pot has been moved
313
/////////////////////////////////////////////////////////////////////////////
314
void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
315
{
316
  // we have 128 pots
317
  // 8 pots assigned per channel
318
 
319
  // channel
320
  u8 chn = pin / 8;
321
 
322
  // CC number
323
  u8 cc_number = 0x10 + (pin % 8);
324
 
325
  // convert 12bit value to 7bit value
326
  u8 value_7bit = pin_value >> 5;
327
 
328
  // send MIDI event
329
  MIOS32_MIDI_SendCC(DEFAULT, chn, cc_number, value_7bit);
330
}
331
 
332
 
333
/////////////////////////////////////////////////////////////////////////////
334
// This task scans MATRIX pins periodically
335
/////////////////////////////////////////////////////////////////////////////
336
static void TASK_MATRIX_Scan(void *pvParameters)
337
{
338
  u8 old_state[12]; // to store the state of 12 pins
339
  u8 debounce_ctr[12]; // to store debounce delay counters
340
  portTickType xLastExecutionTime;
341
 
342
  // initialize pin state and debounce counters to inactive value
343
  int pin;
344
  for(pin=0; pin<12; ++pin) {
345
    old_state[pin] = 1;
346
    debounce_ctr[pin] = 0;
347
  }
348
 
349
  // Initialise the xLastExecutionTime variable on task entry
350
  xLastExecutionTime = xTaskGetTickCount();
351
 
352
  while( 1 ) {
353
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);
354
 
355
    // check all shift registers for DIN pin changes
356
    int mod;
357
    for(mod=0; mod<NUM_MATRICES; ++mod) {
358
      int row;
359
      for(row=0; row<16; ++row) {
360
    // check if there are pin changes - must be atomic!
361
    MIOS32_IRQ_Disable();
1290 tk 362
    u16 changed = matrix16x16_button_row_changed[mod][row];
1216 tk 363
    matrix16x16_button_row_changed[mod][row] = 0;
364
    MIOS32_IRQ_Enable();
365
 
366
    // any pin change at this SR?
367
    if( !changed )
368
      continue;
369
 
370
    // check all 16 pins of the SR
371
    int sr_pin;
372
    for(sr_pin=0; sr_pin<16; ++sr_pin)
373
      if( changed & (1 << sr_pin) ) {
1290 tk 374
 
1216 tk 375
        u32 pin = 16*row + sr_pin;
376
        u8 value = (matrix16x16_button_row_values[mod][row] & (1 << sr_pin)) ? 1 : 0;
377
 
378
        // decoding: 2*256 pins mapped to channel 1..16
379
        u8 chn = pin / 16;
380
 
381
        // each channel has 16 buttons
1279 tk 382
        u8 note = mod*16 + 0x3c + sr_pin; // 0x3c is C-3
1216 tk 383
 
384
        // velocity: 0x7f if button pressed, 0x00 if button depressed
385
        u8 velocity = value ? 0x00 : 0x7f;
386
 
387
        // send MIDI event
388
        MIOS32_MIDI_SendNoteOn(DEFAULT, chn, note, velocity);
1290 tk 389
 
390
        // a useful debug message to print out temporary variables
391
        // disable it by changing "#if 1" by "#if 0"
392
#if 1
393
        MIOS32_MIDI_SendDebugMessage("Mod:%d  Row:%d  sr_pin: %d  value:%d\n",
394
                     mod, row, sr_pin, value);
395
#endif
1216 tk 396
      }
397
      }
398
    }
399
  }
400
}