|
Post by dizzeesatchel on Jan 14, 2022 21:50:28 GMT
New core.ae owner here!
Aside from the examples included in the Arduino IDE (and the Wonkystuff specific examples), are there any resources people can recommend for those relatively new to programming, especially resources which lean more in the direction of working with audio?
Also, when writing code how do you test it? Do you need to upload it to the physical module with each revision or is there some way to 'emulate' a core.ae in software? I've seen stuff like TinkerCAD but i guess that's more for working with an actual raw Arduino board? Maybe these are stupid questions?
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Jan 14, 2022 22:01:33 GMT
I'll leave this for a bit, to see if anyone else chips in… as for debugging, I just keep uploading to the module! There's often some head-scratching as things don't tend to work first time
|
|
|
Post by dizzeesatchel on Jan 14, 2022 22:13:54 GMT
Well where would the fun be if it worked first time
|
|
|
Post by admin on Jan 14, 2022 22:20:49 GMT
|
|
|
Post by dizzeesatchel on Jan 14, 2022 22:42:42 GMT
Ooh that looks good, i'll have to try to track it down
edit: ok found it
|
|
|
Post by MikMo on Jan 14, 2022 23:53:42 GMT
yes that book is really a goldmine.
There are some caveats that the book cover, especially the problem Arduinos have with floating point calculations, which are so slow that it is a no go in audio applications.
it also has lots of good examples.
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Jan 15, 2022 21:47:15 GMT
yes that book is really a goldmine. There are some caveats that the book cover, especially the problem Arduinos have with floating point calculations, which are so slow that it is a no go in audio applications. it also has lots of good examples. If you want to avoid floating point, but also do some 'non-integer' (or fractional) maths, then 'fixed-point' is the way to go. It's used in some of the core.æ examples, but I can write a post about it if there is interest! … alternatively, it looks like this post has it all covered: hackaday.com/2016/04/22/embed-with-elliot-keeping-it-integral/
|
|
|
Post by MikMo on Jan 16, 2022 17:09:08 GMT
Nice reading.
And the 8:8 fixed point notation is exactly what is covered in the Arduino for musicians book.
|
|
tgergo
Junior Member
Posts: 59
|
Post by tgergo on Feb 12, 2022 13:21:09 GMT
Hi namke, where can I find documentations for the API I can use with the board? I noticed for example that the millis and micros methods are not available. Is there a recommended way to get the time passed between 2 loop calls? Are there any other libraries that I can use? I was looking for a timing library that would let me do an async delay for example. Is there any method for trigger detection in the WS library?
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Feb 13, 2022 11:30:39 GMT
Hi namke , where can I find documentations for the API I can use with the board? I noticed for example that the millis and micros methods are not available. Is there a recommended way to get the time passed between 2 loop calls? Are there any other libraries that I can use? I was looking for a timing library that would let me do an async delay for example. Is there any method for trigger detection in the WS library? Good question! I had forgotten that I had disabled this functionality (since my libraries reassign the timers, the functionality of millis() wasn't correct). (I also must produce documentation for the APIs, you are right to highlight this. I'm very glad that someone else is interested in writing code - my initial impression was that most people are interested in simply using pre-existing firmware) The way that I tend to do timing is to increment a (volatile) counter in the sample-rate interrupt routine, which can then be read by code elsewhere - you then get an idea of 'ticks' to show elapsed time (there is a SRATE macro defined which reflects the selected sample rate). /* * Elapsed time * * modified Feb 2022 by John Tuffen * */
#include "wonkystuffCommon.h"
volatile uint16_t wsTimeUpper; volatile uint16_t wsTimeLower;
// the setup function runs once when you press reset or power the board void setup(void) { wsInit(); // general initialisation wsInitPWM(); // output 1 is now controlled by PWM wsInitAudioLoop(); // initialise the timer to give us an interrupt at the sample rate // make sure to define the wsAudioLoop function! }
// the loop function runs over and over again forever void loop(void) { uint16_t secondsSinceStart = sayKidsWhatTimeIsIt() / SRATE; }
uint32_t sayKidsWhatTimeIsIt(void) { cli(); uint32_t now = wsTimeUpper << 16 | wsTimeLower; sei(); return now; }
// This ISR is running at the rate specified by SR (e.g 50kHz) void wsAudioLoop(void) { // Audio code goes here… // // … // …
// Increment the timing info: wsTimeLower++; if (wsTimeLower == 0) { wsTimeUpper++; } }
If you have only a single reader of the time, and you just need to count ticks before a subsequent action, you can simply reset wsTimeLower to zero when you want to 'start' the timer, and then wait until the appropriate number of ticks have elapsed (bearing in mind the limited size of datatypes; e.g. a uint16_t will only count up to 65535 so will only be able to time up to 1.3 seconds at a 50kHz sample rate). The delay() APIs are still available if you need to just insert a delay between two events (although this will be affected by code running in the interrupt routines).
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Feb 13, 2022 11:38:13 GMT
Hi namke , where can I find documentations for the API I can use with the board? I noticed for example that the millis and micros methods are not available. Is there a recommended way to get the time passed between 2 loop calls? Are there any other libraries that I can use? I was looking for a timing library that would let me do an async delay for example. Is there any method for trigger detection in the WS library? For trigger detection, the 'pin change interrupt' can be used; I do something like this: volatile uint8_t clockHappened = 0;
void setup(void) { wsInit(); // general initialisation wsInitPWM(); // output 1 is now controlled by PWM
GIMSK |= (1 << PCIE); // turns on pin change interrupts PCMSK |= (1 << PCINT2); // turn on pin-change interrupts on pin PB2 (pin 7/input B on the panel)
wsInitAudioLoop(); // initialise the timer to give us an interrupt at the sample rate // make sure to define the wsAudioLoop function! }
// the loop function runs over and over again forever void loop(void) { // Insert non time-critical code here }
// This ISR is running at the sample rate (e.g 5kHz) void wsAudioLoop(void) { // ... // If the pin is high then we're interested if (clockHappened) { // Do the thing
// ...
// Now we've processed the edge, mark it as done. clockHappened = 0; } }
// Pin change interrupt - set on state change of I/O. We set this up // to only be enabled on PCINT0 (PB2) so if we get here we know that // something happened on PB2 (/input B on the panel) ISR(PCINT0_vect) { // If the pin is currently 'high' then signal to the timing ISR // that a clock occurred. This will hopefully do a bit of // debouncing for us. if (PINB & _BV(PB2)) { clockHappened = 1; } } Since the clockHappened variable is only set in the pin-change interrupt routine, there is an element of 'debouncing' implied here as the pin state is effectively sampled in the audio ISR.
|
|
tgergo
Junior Member
Posts: 59
|
Post by tgergo on Feb 13, 2022 21:52:31 GMT
Thank you namke for the answers and examples. I learned quite a bit with some additional reading. This was really interesting. I have some questions. Which pins do the 3 CV inputs correspond to? Let's say I want to detect triggers on all 3 would it be something like this? Here I'm assuming that PB3 = CV input C and PB4 = CV input D. volatile uint8_t clockHappenedB = 0; volatile uint8_t clockHappenedC = 0; volatile uint8_t clockHappenedD = 0;
void setup(void) { wsInit(); // general initialisation wsInitPWM(); // output 1 is now controlled by PWM
GIMSK |= (1 << PCIE); // turns on pin change interrupts PCMSK |= (1 << PCINT2); // turn on pin-change interrupts on pin PB2 (pin 7/input B on the panel) PCMSK |= (1 << PCINT3); // turn on pin-change interrupts on pin PB3 PCMSK |= (1 << PCINT4); // turn on pin-change interrupts on pin PB4 wsInitAudioLoop(); // initialise the timer to give us an interrupt at the sample rate // make sure to define the wsAudioLoop function! }
// some things happen here ... ... ...
// Pin change interrupt // We are listening for the PCINT0_vect interrupts (i.e. pins of the PB group). ISR(PCINT0_vect) { // Check the bit of the PB status register corresponding to one of the pins if (PINB & _BV(PB2)) { clockHappenedB = 1; }
if (PINB & _BV(PB3)) { clockHappenedC = 1; }
if (PINB & _BV(PB4)) { clockHappenedD = 1; } }
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Feb 13, 2022 22:32:29 GMT
Glad that was helpful!
Pin assignments are as follows:
#define wsKnob1 (A0) // PB5 #define wsKnob2 (A1) // PB2
// Hardware difference between the standalone Core1.D board // and the AE modular version. #if defined AECORE #define wsKnob3 (A3) // PB3 #define wsKnob4 (A2) // PB4 #elif defined CORE1D #define wsKnob3 (A2) // PB4 #define wsKnob4 (A3) // PB3 #endif
#define wsOut1 (PB1) // m-out #define wsOut2 (PB0) // s-out
… where knob1-4 correspond with knobs a-d on the AE version
|
|
|
Post by dizzeesatchel on Feb 13, 2022 22:53:16 GMT
This is super useful! I was wondering about the absense of ‘millis()’ also, just hadn’t got round to asking
|
|
tgergo
Junior Member
Posts: 59
|
Post by tgergo on Feb 20, 2022 13:14:15 GMT
* What does the wsFetchOctaveLookup function do? * Can I only use output 1 for PWM?
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 686
|
Post by namke on Feb 21, 2022 17:16:41 GMT
* What does the wsFetchOctaveLookup function do? * Can I only use output 1 for PWM? The wsFetchOctaveLookup function converts the (linear) value from a potentiometer (for example) into a 'phase Increment' so that a phase-accumulator can be easily be implemented (using fixed point arithmetic as mentioned above). There is only a reconstruction filter on output 1 for converting the PWM into 'analogue', however I have found that it is also possible to write PWM values to output 2 and simply rely on then next module in the chain to do the filtering — often this is 'good enough'
|
|