Nucleo SPI Sequencer
Dependencies: AverageAnalogIn N5110 Nucleo_rtos_UI_Test PinDetect RotaryEncoder Sequence mbed-rtos mbed FilterController
Fork of Nucleo_rtos_UI_Test by
main.cpp@5:e4b68faa6801, 2016-06-12 (annotated)
- Committer:
- ryood
- Date:
- Sun Jun 12 07:13:18 2016 +0000
- Revision:
- 5:e4b68faa6801
- Parent:
- 4:d9a72e07749f
- Child:
- 6:4e089888b809
Nucleo rtos UI Test?SpiSequencerSender???
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ryood | 4:d9a72e07749f | 1 | /* |
ryood | 5:e4b68faa6801 | 2 | * Nucleo SPI Sequencer |
ryood | 4:d9a72e07749f | 3 | * |
ryood | 5:e4b68faa6801 | 4 | * 2016.06.12 |
ryood | 4:d9a72e07749f | 5 | * |
ryood | 4:d9a72e07749f | 6 | */ |
ryood | 4:d9a72e07749f | 7 | |
ryood | 0:468e49a35876 | 8 | #include "mbed.h" |
ryood | 0:468e49a35876 | 9 | #include "rtos.h" |
ryood | 2:8cc6dff1d7fd | 10 | #include "PinDetect.h" |
ryood | 2:8cc6dff1d7fd | 11 | #include "RotaryEncoder.h" |
ryood | 0:468e49a35876 | 12 | #include "N5110.h" |
ryood | 4:d9a72e07749f | 13 | #include "AverageAnalogIn.h" |
ryood | 5:e4b68faa6801 | 14 | #include "SpiSequenceSender.h" |
ryood | 2:8cc6dff1d7fd | 15 | |
ryood | 5:e4b68faa6801 | 16 | #define SPI_RATE (8000000) |
ryood | 5:e4b68faa6801 | 17 | |
ryood | 5:e4b68faa6801 | 18 | #define SEQUENCE_N (16) |
ryood | 5:e4b68faa6801 | 19 | #define OCTAVE_MIN (-1) |
ryood | 5:e4b68faa6801 | 20 | #define OCTAVE_MAX (1) |
ryood | 5:e4b68faa6801 | 21 | #define PITCH_MAX (12) |
ryood | 5:e4b68faa6801 | 22 | |
ryood | 5:e4b68faa6801 | 23 | DigitalOut CheckPin(PC_8); |
ryood | 0:468e49a35876 | 24 | |
ryood | 5:e4b68faa6801 | 25 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 26 | // SPI Sequencer |
ryood | 5:e4b68faa6801 | 27 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 28 | SPI spiMaster(SPI_MOSI, SPI_MISO, SPI_SCK); |
ryood | 5:e4b68faa6801 | 29 | Sequence sequence[SEQUENCE_N]; |
ryood | 5:e4b68faa6801 | 30 | SpiSequenceSender sequenceSender(&spiMaster, D10, sequence, SEQUENCE_N, 5); |
ryood | 5:e4b68faa6801 | 31 | |
ryood | 5:e4b68faa6801 | 32 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 33 | // User Interface |
ryood | 5:e4b68faa6801 | 34 | //------------------------------------------------------------------------ |
ryood | 0:468e49a35876 | 35 | // SPI2 Morpho |
ryood | 0:468e49a35876 | 36 | // VCC, SCE, RST, D/C, MOSI, SCLK, LED |
ryood | 0:468e49a35876 | 37 | N5110 Lcd(PA_12, PB_1, PB_2, PB_12, PB_15, PB_13, PA_11); |
ryood | 2:8cc6dff1d7fd | 38 | |
ryood | 2:8cc6dff1d7fd | 39 | RotaryEncoder RotEnc1(D2, D3, 0, SEQUENCE_N - 1, 0); |
ryood | 2:8cc6dff1d7fd | 40 | RotaryEncoder RotEnc2(D4, D5, 0, PITCH_MAX, 0); |
ryood | 2:8cc6dff1d7fd | 41 | |
ryood | 4:d9a72e07749f | 42 | AverageAnalogIn Pots[] = { |
ryood | 4:d9a72e07749f | 43 | AverageAnalogIn(A0), |
ryood | 4:d9a72e07749f | 44 | AverageAnalogIn(A1), |
ryood | 4:d9a72e07749f | 45 | AverageAnalogIn(A2), |
ryood | 4:d9a72e07749f | 46 | AverageAnalogIn(A3), |
ryood | 4:d9a72e07749f | 47 | AverageAnalogIn(A4), |
ryood | 3:8c8020dfd82f | 48 | }; |
ryood | 3:8c8020dfd82f | 49 | |
ryood | 2:8cc6dff1d7fd | 50 | PinDetect Pins[] = { |
ryood | 3:8c8020dfd82f | 51 | PinDetect(PA_13, PullUp), |
ryood | 3:8c8020dfd82f | 52 | PinDetect(PA_14, PullUp), |
ryood | 3:8c8020dfd82f | 53 | PinDetect(PA_15, PullUp), |
ryood | 3:8c8020dfd82f | 54 | PinDetect(PB_7, PullUp), |
ryood | 3:8c8020dfd82f | 55 | PinDetect(PC_13, PullUp), |
ryood | 3:8c8020dfd82f | 56 | PinDetect(PB_10, PullUp), |
ryood | 3:8c8020dfd82f | 57 | PinDetect(PA_8, PullUp), |
ryood | 2:8cc6dff1d7fd | 58 | }; |
ryood | 2:8cc6dff1d7fd | 59 | |
ryood | 5:e4b68faa6801 | 60 | //DigitalOut Led1(LED1); |
ryood | 5:e4b68faa6801 | 61 | |
ryood | 0:468e49a35876 | 62 | |
ryood | 2:8cc6dff1d7fd | 63 | // Grobal Variables |
ryood | 5:e4b68faa6801 | 64 | struct sSequence { |
ryood | 2:8cc6dff1d7fd | 65 | bool noteOn; |
ryood | 2:8cc6dff1d7fd | 66 | int octave; |
ryood | 2:8cc6dff1d7fd | 67 | int pitch; |
ryood | 2:8cc6dff1d7fd | 68 | bool tie; |
ryood | 2:8cc6dff1d7fd | 69 | bool accent; |
ryood | 5:e4b68faa6801 | 70 | } sSequence[SEQUENCE_N]; |
ryood | 2:8cc6dff1d7fd | 71 | |
ryood | 4:d9a72e07749f | 72 | struct Oscillator { |
ryood | 4:d9a72e07749f | 73 | int waveForm; |
ryood | 4:d9a72e07749f | 74 | int pulseWidth; |
ryood | 4:d9a72e07749f | 75 | } Oscillator; |
ryood | 4:d9a72e07749f | 76 | |
ryood | 4:d9a72e07749f | 77 | struct Filter { |
ryood | 4:d9a72e07749f | 78 | int cutOff; |
ryood | 4:d9a72e07749f | 79 | int resonance; |
ryood | 4:d9a72e07749f | 80 | int envMod; |
ryood | 4:d9a72e07749f | 81 | } Filter; |
ryood | 4:d9a72e07749f | 82 | |
ryood | 3:8c8020dfd82f | 83 | int currentNote = 0; |
ryood | 4:d9a72e07749f | 84 | int tempo = 120; |
ryood | 3:8c8020dfd82f | 85 | bool isRunning = true; |
ryood | 3:8c8020dfd82f | 86 | bool isDirty = true; |
ryood | 2:8cc6dff1d7fd | 87 | |
ryood | 5:e4b68faa6801 | 88 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 89 | // Fuctions |
ryood | 5:e4b68faa6801 | 90 | //------------------------------------------------------------------------ |
ryood | 2:8cc6dff1d7fd | 91 | void updateLCD() |
ryood | 0:468e49a35876 | 92 | { |
ryood | 0:468e49a35876 | 93 | char buff[20]; |
ryood | 0:468e49a35876 | 94 | |
ryood | 4:d9a72e07749f | 95 | //Lcd.clear(); |
ryood | 4:d9a72e07749f | 96 | sprintf(buff, "Note#: %d ", currentNote); |
ryood | 4:d9a72e07749f | 97 | Lcd.printString(buff, 0, 0); |
ryood | 5:e4b68faa6801 | 98 | sprintf(buff, "pitch: %d ", sSequence[currentNote].pitch); |
ryood | 0:468e49a35876 | 99 | Lcd.printString(buff, 0, 1); |
ryood | 5:e4b68faa6801 | 100 | sprintf(buff, "octave: %d " ,sSequence[currentNote].octave); |
ryood | 2:8cc6dff1d7fd | 101 | Lcd.printString(buff, 0, 2); |
ryood | 4:d9a72e07749f | 102 | sprintf(buff, "%1d %1d %1d %1d %3d", |
ryood | 5:e4b68faa6801 | 103 | sSequence[currentNote].noteOn, sSequence[currentNote].tie, sSequence[currentNote].accent, |
ryood | 4:d9a72e07749f | 104 | isRunning, Oscillator.waveForm); |
ryood | 2:8cc6dff1d7fd | 105 | Lcd.printString(buff, 0, 3); |
ryood | 4:d9a72e07749f | 106 | sprintf(buff, "%3d %3d %3d", Oscillator.pulseWidth, Filter.envMod, tempo); |
ryood | 2:8cc6dff1d7fd | 107 | Lcd.printString(buff, 0, 4); |
ryood | 4:d9a72e07749f | 108 | sprintf(buff, "%3d %3d", Filter.cutOff, Filter.resonance); |
ryood | 4:d9a72e07749f | 109 | Lcd.printString(buff, 0, 5); |
ryood | 0:468e49a35876 | 110 | Lcd.refresh(); |
ryood | 0:468e49a35876 | 111 | } |
ryood | 0:468e49a35876 | 112 | |
ryood | 5:e4b68faa6801 | 113 | //------------------------------------------------------------------------ |
ryood | 2:8cc6dff1d7fd | 114 | // CallBack routines |
ryood | 5:e4b68faa6801 | 115 | //------------------------------------------------------------------------ |
ryood | 2:8cc6dff1d7fd | 116 | void swOctaveUpPressed() |
ryood | 2:8cc6dff1d7fd | 117 | { |
ryood | 5:e4b68faa6801 | 118 | sSequence[currentNote].octave++; |
ryood | 2:8cc6dff1d7fd | 119 | isDirty = true; |
ryood | 2:8cc6dff1d7fd | 120 | printf("swOctaveUpPressed\r\n"); |
ryood | 2:8cc6dff1d7fd | 121 | } |
ryood | 2:8cc6dff1d7fd | 122 | |
ryood | 2:8cc6dff1d7fd | 123 | void swOctaveDownPressed() |
ryood | 2:8cc6dff1d7fd | 124 | { |
ryood | 5:e4b68faa6801 | 125 | sSequence[currentNote].octave--; |
ryood | 2:8cc6dff1d7fd | 126 | isDirty = true; |
ryood | 2:8cc6dff1d7fd | 127 | printf("swOctaveDownPressed\r\n"); |
ryood | 2:8cc6dff1d7fd | 128 | } |
ryood | 2:8cc6dff1d7fd | 129 | |
ryood | 2:8cc6dff1d7fd | 130 | void swNoteOnOffPressed() |
ryood | 2:8cc6dff1d7fd | 131 | { |
ryood | 5:e4b68faa6801 | 132 | sSequence[currentNote].noteOn = !sSequence[currentNote].noteOn; |
ryood | 2:8cc6dff1d7fd | 133 | isDirty = true; |
ryood | 2:8cc6dff1d7fd | 134 | printf("swNoteOnOffPressed\r\n"); |
ryood | 2:8cc6dff1d7fd | 135 | } |
ryood | 2:8cc6dff1d7fd | 136 | |
ryood | 2:8cc6dff1d7fd | 137 | void swTiePressed() |
ryood | 2:8cc6dff1d7fd | 138 | { |
ryood | 5:e4b68faa6801 | 139 | sSequence[currentNote].tie = !sSequence[currentNote].tie; |
ryood | 2:8cc6dff1d7fd | 140 | isDirty = true; |
ryood | 2:8cc6dff1d7fd | 141 | printf("swTiePressed\r\n"); |
ryood | 2:8cc6dff1d7fd | 142 | } |
ryood | 2:8cc6dff1d7fd | 143 | |
ryood | 2:8cc6dff1d7fd | 144 | void swAccentPressed() |
ryood | 2:8cc6dff1d7fd | 145 | { |
ryood | 5:e4b68faa6801 | 146 | sSequence[currentNote].accent = !sSequence[currentNote].accent; |
ryood | 2:8cc6dff1d7fd | 147 | isDirty = true; |
ryood | 2:8cc6dff1d7fd | 148 | printf("swAccentPressed\r\n"); |
ryood | 2:8cc6dff1d7fd | 149 | } |
ryood | 2:8cc6dff1d7fd | 150 | |
ryood | 3:8c8020dfd82f | 151 | void swRunStopPressed() |
ryood | 3:8c8020dfd82f | 152 | { |
ryood | 3:8c8020dfd82f | 153 | isRunning = !isRunning; |
ryood | 3:8c8020dfd82f | 154 | isDirty = true; |
ryood | 3:8c8020dfd82f | 155 | printf("swRunStopPressed\r\n"); |
ryood | 3:8c8020dfd82f | 156 | } |
ryood | 3:8c8020dfd82f | 157 | |
ryood | 3:8c8020dfd82f | 158 | void swWaveFormPressed() |
ryood | 3:8c8020dfd82f | 159 | { |
ryood | 4:d9a72e07749f | 160 | Oscillator.waveForm++; |
ryood | 3:8c8020dfd82f | 161 | isDirty = true; |
ryood | 3:8c8020dfd82f | 162 | printf("swWaveFormPressed\r\n"); |
ryood | 3:8c8020dfd82f | 163 | } |
ryood | 3:8c8020dfd82f | 164 | |
ryood | 5:e4b68faa6801 | 165 | //------------------------------------------------------------------------ |
ryood | 4:d9a72e07749f | 166 | // Thread |
ryood | 5:e4b68faa6801 | 167 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 168 | /* |
ryood | 4:d9a72e07749f | 169 | void ledThread(void const *argument) |
ryood | 4:d9a72e07749f | 170 | { |
ryood | 4:d9a72e07749f | 171 | while (true) { |
ryood | 4:d9a72e07749f | 172 | Led1 = !Led1; |
ryood | 4:d9a72e07749f | 173 | Thread::wait(500); |
ryood | 4:d9a72e07749f | 174 | } |
ryood | 4:d9a72e07749f | 175 | } |
ryood | 5:e4b68faa6801 | 176 | */ |
ryood | 4:d9a72e07749f | 177 | |
ryood | 4:d9a72e07749f | 178 | void pollingRotEncs(void const *argument) |
ryood | 3:8c8020dfd82f | 179 | { |
ryood | 4:d9a72e07749f | 180 | while (true) { |
ryood | 4:d9a72e07749f | 181 | int _note = RotEnc1.getVal(); |
ryood | 4:d9a72e07749f | 182 | if (_note != currentNote) { |
ryood | 4:d9a72e07749f | 183 | currentNote = _note; |
ryood | 4:d9a72e07749f | 184 | isDirty = true; |
ryood | 4:d9a72e07749f | 185 | } |
ryood | 4:d9a72e07749f | 186 | int _pitch = RotEnc2.getVal(); |
ryood | 5:e4b68faa6801 | 187 | if (_pitch != sSequence[currentNote].pitch) { |
ryood | 5:e4b68faa6801 | 188 | sSequence[currentNote].pitch = _pitch; |
ryood | 4:d9a72e07749f | 189 | isDirty = true; |
ryood | 4:d9a72e07749f | 190 | } |
ryood | 4:d9a72e07749f | 191 | Thread::wait(10); |
ryood | 3:8c8020dfd82f | 192 | } |
ryood | 3:8c8020dfd82f | 193 | } |
ryood | 3:8c8020dfd82f | 194 | |
ryood | 4:d9a72e07749f | 195 | void pollingPots(void const *argument) |
ryood | 3:8c8020dfd82f | 196 | { |
ryood | 4:d9a72e07749f | 197 | unsigned short tmp; |
ryood | 4:d9a72e07749f | 198 | |
ryood | 4:d9a72e07749f | 199 | while (true) { |
ryood | 4:d9a72e07749f | 200 | // pulse width |
ryood | 4:d9a72e07749f | 201 | tmp = Pots[0].read_u16() >> 9; // 7bit witdth |
ryood | 4:d9a72e07749f | 202 | if (tmp != Oscillator.pulseWidth) { |
ryood | 4:d9a72e07749f | 203 | Oscillator.pulseWidth = tmp; |
ryood | 4:d9a72e07749f | 204 | isDirty = true; |
ryood | 4:d9a72e07749f | 205 | } |
ryood | 4:d9a72e07749f | 206 | // filter envelope moduration |
ryood | 4:d9a72e07749f | 207 | tmp = Pots[1].read_u16() >> 9; // 7bit witdth |
ryood | 4:d9a72e07749f | 208 | if (tmp != Filter.envMod) { |
ryood | 4:d9a72e07749f | 209 | Filter.envMod = tmp; |
ryood | 4:d9a72e07749f | 210 | isDirty = true; |
ryood | 4:d9a72e07749f | 211 | } |
ryood | 4:d9a72e07749f | 212 | // tempo |
ryood | 4:d9a72e07749f | 213 | tmp = Pots[2].read_u16() >> 9; // 7bit witdth |
ryood | 4:d9a72e07749f | 214 | if (tmp != tempo) { |
ryood | 4:d9a72e07749f | 215 | tempo = tmp; |
ryood | 4:d9a72e07749f | 216 | isDirty = true; |
ryood | 4:d9a72e07749f | 217 | } |
ryood | 4:d9a72e07749f | 218 | // cutoff |
ryood | 4:d9a72e07749f | 219 | tmp = Pots[3].read_u16() >> 10; // 6bit witdth |
ryood | 4:d9a72e07749f | 220 | if (tmp != Filter.cutOff) { |
ryood | 4:d9a72e07749f | 221 | Filter.cutOff = tmp; |
ryood | 4:d9a72e07749f | 222 | isDirty = true; |
ryood | 4:d9a72e07749f | 223 | } |
ryood | 4:d9a72e07749f | 224 | // resonance |
ryood | 4:d9a72e07749f | 225 | tmp = Pots[4].read_u16() >> 10; // 6bit witdth |
ryood | 4:d9a72e07749f | 226 | if (tmp != Filter.resonance) { |
ryood | 4:d9a72e07749f | 227 | Filter.resonance = tmp; |
ryood | 4:d9a72e07749f | 228 | isDirty = true; |
ryood | 4:d9a72e07749f | 229 | } |
ryood | 4:d9a72e07749f | 230 | Thread::wait(20); |
ryood | 4:d9a72e07749f | 231 | } |
ryood | 3:8c8020dfd82f | 232 | } |
ryood | 3:8c8020dfd82f | 233 | |
ryood | 5:e4b68faa6801 | 234 | //------------------------------------------------------------------------ |
ryood | 5:e4b68faa6801 | 235 | // Main routine |
ryood | 5:e4b68faa6801 | 236 | //------------------------------------------------------------------------ |
ryood | 0:468e49a35876 | 237 | int main() |
ryood | 0:468e49a35876 | 238 | { |
ryood | 0:468e49a35876 | 239 | printf("\n\n\r*** RTOS UI Test ***\r\n"); |
ryood | 5:e4b68faa6801 | 240 | |
ryood | 5:e4b68faa6801 | 241 | spiMaster.format(0, 8); |
ryood | 5:e4b68faa6801 | 242 | spiMaster.frequency(SPI_RATE); |
ryood | 0:468e49a35876 | 243 | |
ryood | 0:468e49a35876 | 244 | // Init devices |
ryood | 2:8cc6dff1d7fd | 245 | RotEnc1.setInterval(500); |
ryood | 2:8cc6dff1d7fd | 246 | RotEnc2.setInterval(500); |
ryood | 2:8cc6dff1d7fd | 247 | |
ryood | 2:8cc6dff1d7fd | 248 | Pins[0].attach_asserted(&swOctaveUpPressed); |
ryood | 2:8cc6dff1d7fd | 249 | Pins[1].attach_asserted(&swOctaveDownPressed); |
ryood | 2:8cc6dff1d7fd | 250 | Pins[2].attach_asserted(&swNoteOnOffPressed); |
ryood | 2:8cc6dff1d7fd | 251 | Pins[3].attach_asserted(&swTiePressed); |
ryood | 2:8cc6dff1d7fd | 252 | Pins[4].attach_asserted(&swAccentPressed); |
ryood | 3:8c8020dfd82f | 253 | Pins[5].attach_asserted(&swRunStopPressed); |
ryood | 3:8c8020dfd82f | 254 | Pins[6].attach_asserted(&swWaveFormPressed); |
ryood | 3:8c8020dfd82f | 255 | for (int i = 0; i < 7; i++) { |
ryood | 2:8cc6dff1d7fd | 256 | Pins[i].setAssertValue(0); |
ryood | 2:8cc6dff1d7fd | 257 | Pins[i].setSampleFrequency(); |
ryood | 2:8cc6dff1d7fd | 258 | } |
ryood | 0:468e49a35876 | 259 | |
ryood | 0:468e49a35876 | 260 | Lcd.init(); |
ryood | 0:468e49a35876 | 261 | Lcd.normalMode(); // normal colour mode |
ryood | 0:468e49a35876 | 262 | Lcd.setBrightness(0.5); // put LED backlight on 50% |
ryood | 0:468e49a35876 | 263 | |
ryood | 2:8cc6dff1d7fd | 264 | // Thread start |
ryood | 5:e4b68faa6801 | 265 | //Thread thLed(ledThread, NULL, osPriorityNormal, DEFAULT_STACK_SIZE); |
ryood | 4:d9a72e07749f | 266 | Thread thRotEnc(pollingRotEncs, NULL, osPriorityNormal, DEFAULT_STACK_SIZE); |
ryood | 4:d9a72e07749f | 267 | Thread thPots(pollingPots, NULL, osPriorityNormal, DEFAULT_STACK_SIZE); |
ryood | 5:e4b68faa6801 | 268 | |
ryood | 5:e4b68faa6801 | 269 | for (int i = 0; i < SEQUENCE_N; i++) { |
ryood | 5:e4b68faa6801 | 270 | Sequence& seq = sequenceSender.getSequences()[i]; |
ryood | 5:e4b68faa6801 | 271 | seq.setPitch(0); |
ryood | 5:e4b68faa6801 | 272 | seq.setOctave(0); |
ryood | 5:e4b68faa6801 | 273 | seq.tie = false; |
ryood | 5:e4b68faa6801 | 274 | } |
ryood | 5:e4b68faa6801 | 275 | sequenceSender.run(0); |
ryood | 0:468e49a35876 | 276 | |
ryood | 0:468e49a35876 | 277 | // Main loop |
ryood | 0:468e49a35876 | 278 | while (true) { |
ryood | 4:d9a72e07749f | 279 | CheckPin = !CheckPin; |
ryood | 0:468e49a35876 | 280 | if (isDirty) { |
ryood | 2:8cc6dff1d7fd | 281 | updateLCD(); |
ryood | 0:468e49a35876 | 282 | isDirty = false; |
ryood | 0:468e49a35876 | 283 | } |
ryood | 0:468e49a35876 | 284 | } |
ryood | 0:468e49a35876 | 285 | } |