Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
682 tk 1
$Id: README.txt 2425 2016-11-03 00:44:22Z tk $
2
 
3
MIOS32 Tutorial #006: RTOS Tasks
4
===============================================================================
5
Copyright (C) 2009 Thorsten Klose (tk@midibox.org)
6
Licensed for personal non-commercial use only.
7
All other rights reserved.
8
===============================================================================
9
 
10
Required tools:
11
  -> http://www.ucapps.de/mio32_c.html
12
 
13
===============================================================================
14
 
15
Required hardware:
1941 tk 16
   o MBHP_CORE_STM32 or MBHP_CORE_LPC17 or MBHP_CORE_STM32F4 or similar
682 tk 17
   o 12 Jumpers for J5A/J5B/J5C, or a cable to ground
18
 
19
===============================================================================
20
 
21
In the previous lesson we learnt how to poll J5 pins to trigger MIDI notes.
22
Now we want to debounce the pins by polling the pins with a defined period, and
23
delaying the polling for a given time whenever the pin state has been changed
24
(low-pass filter function)
25
 
26
The proposed method for such frequently repeated "jobs" is the usage of
27
FreeRTOS tasks. They are explained in great detail under http://www.FreeRTOS.org,
28
in this example I will only explain the usage in a MIOS32 application.
29
 
30
 
31
Two tasks are already running in background, they are defined under
32
$MIOS32_PATH/programming_models/traditional/main.c
33
 
34
One task polls for MIDI input, and the other scans for SRIO, AIN and COM
35
activity (part of some following tutorial lessons)
36
 
37
 
38
Both tasks are running with a priority of 3.
39
The allowed priority range is between 0 and 5, where 0 is the lowest
40
priority (equal to the APP_Background task), and 5 the highest priority.
41
 
42
Tasks with higher priority can always interrupt tasks with lower priority.
43
Accordingly, tasks with lower priority will only run when no higher priority
44
task is executed.
45
If --- and this is the big advantage of a RTOS scheduler --- tasks at
46
the same priority level are running for more than 1 mS (the system tick),
47
the current task will be interrupted automatically and the next waiting
48
task with the same priority is started.
49
This is called preemption -> http://en.wikipedia.org/wiki/Preemption_(computing)
50
 
51
You will love this feature, because it allows to run time consuming
52
loops quasi-parallel without taking care for compute time sharing (so
53
long tasks are running at the same priority level).
54
 
55
However, usually one one task would run endless: the idle task APP_Background().
56
All other tasks would wait for a certain number of system ticks (multiple
57
of 1 ms), would be woken up by the schedule, and do some quick
58
processing before waiting for the next cycle.
59
 
60
This is what we will do in our J5 input scanning routine.
61
 
62
 
63
First let's include some FreeRTOS specific header files, and let's
64
define a priority for our task at the top of app.c (to improve the
65
oversight):
66
 
67
 
68
-------------------------------------------------------------------------------
69
// include everything FreeRTOS related we don't understand yet ;)
70
#include <FreeRTOS.h>
71
#include <portmacro.h>
72
#include <task.h>
73
#include <queue.h>
74
#include <semphr.h>
75
 
76
 
77
// define priority level for J5_SCAN task:
78
// use same priority as MIOS32 specific tasks (3)
79
#define PRIORITY_TASK_J5_SCAN	( tskIDLE_PRIORITY + 3 )
80
 
81
// local prototype of the task function
82
static void TASK_J5_Scan(void *pvParameters);
83
-------------------------------------------------------------------------------
84
 
85
 
86
Inside the APP_Init() hook we start the scan task the following way:
87
-------------------------------------------------------------------------------
88
  // start task
2425 tk 89
  xTaskCreate(TASK_J5_Scan, "J5_Scan", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_J5_SCAN, NULL);
682 tk 90
-------------------------------------------------------------------------------
91
 
92
 
93
The J5_Scan task can be found at the bottom of app.c:
94
-------------------------------------------------------------------------------
95
static void TASK_J5_Scan(void *pvParameters)
96
{
97
  u8 old_state[12]; // to store the state of 12 pins
98
  portTickType xLastExecutionTime;
99
 
100
  // initialize pin state to inactive value
101
  int pin;
102
  for(pin=0; pin<12; ++pin)
103
    old_state[pin] = 1;
104
 
105
  // Initialise the xLastExecutionTime variable on task entry
106
  xLastExecutionTime = xTaskGetTickCount();
107
 
108
  while( 1 ) {
109
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);
110
 
111
    // toggle Status LED to as a sign of live
112
    MIOS32_BOARD_LED_Set(1, ~MIOS32_BOARD_LED_Get());
113
 
114
    // check each J5 pin for changes
115
    int pin;
116
    for(pin=0; pin<12; ++pin) {
117
      u8 new_state = MIOS32_BOARD_J5_PinGet(pin);
118
 
119
      // pin changed?
120
      if( new_state != old_state[pin] ) {
121
	// store new state
122
	old_state[pin] = new_state;
123
 
124
	// send Note On/Off Event depending on new pin state
125
	if( new_state == 0 ) // Jumper closed -> 0V
126
	  MIOS32_MIDI_SendNoteOn(DEFAULT, Chn1, 0x3c + pin, 127);
127
	else                 // Jumper opened -> ca. 3.3V
128
	  MIOS32_MIDI_SendNoteOff(DEFAULT, Chn1, 0x3c + pin, 0);
129
      }
130
    }
131
  }
132
}
133
-------------------------------------------------------------------------------
134
 
135
 
136
What is the big difference compared to the variant in 005_polling_j5_pins:
137
 
138
  - this task loops each millisecond (1 / portTICK_RATE_MS)
139
 
140
  - it is *guaranteed* that this task will get CPU time within 1 mS
141
    (assumed, that no higher prio task blocks for more than 1 mS)
142
 
143
  - now we have a time base which allows proper debouncing.
144
 
145
 
146
Debouncing J5 pins: each pin gets a dedicated counter which counts
147
down on each pin state change until zero is reached again, before
148
checking the pin state again.
149
 
150
Since the task loops each mS, initialising the counter with 20
151
*guarantees* a delay of 20 mS - thats quite handy, isn't it?
152
 
153
 
154
The code variant with debounce counters can be found in app.c
155
 
156
===============================================================================