Wrangling SAMD51's ADCs

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Post Reply
User avatar
bitbybitphoto
 
Posts: 7
Joined: Thu Apr 21, 2022 2:41 pm

Wrangling SAMD51's ADCs

Post by bitbybitphoto »

Short question: I've been trying to use the averaging and oversampling features of the 51's ADC but I can't seem to get those to work reliably and was curious if anyone has a working solution? I'm hoping I can use oversampling to help smooth out a few places within the voltage range where the ADC seems to be fairly noisy.

Long story:

I've been digging through the Adafruit repositories, the SAMD51 datasheet, the Interwebs, and still haven't quite been able to figure this one out. I'm using 2 pins for ADCs work, one for V/Oct (Voltage Per Octave) input and the other for normal CV input. The V/Oct is the one that's of course more important.

I notice that the ADC "out of the box" is mostly ok, but it goes pretty off at the extremes. In the middle though the values I'm reading for each note up the scale aren't perfect. This is fine because I just ended up doing adjustments on a per-note basis. That's tedious but it seems to be consistent enough once going through that exercise.

The problem though is certain notes are "noisy" - most aren't but some are - the ADC values wiggle around like crazy and because of this, it makes other parts of the program a bit more difficult. I had hoped to only update the timer for the DAC (which ends up being audio output and is running at a variable rate) when the ADC value changes, but since the values "wiggle" on certain notes, that's hard to do. I can just chop off the low bits but to completely remove said wiggle, I'd also impact in between note values (portamento, slides, etc.) which isn't great.

I might end up using another timer to poll the V/Oct at interfaces (instead of doing it as fast as possible as part of the main loop). I think that might help avoid getting the display involved (talking to the ssd1306 display over I2C seems to mess with the timers or interrupts but I haven't figured out how that's actually happening).

The program can keep up with the wiggling but I'm not sure if that's causing the DAC output to get skewed. I can compensate for that too but I've been chasing what is causing that to begin with. The values I calculate for what the resulting sample rate should be for the DAC aren't what I end up with when I measure it. It's not that I'm running into limits of the DAC or timer since I can go higher in pitch than I'd care to without issue. It's just that, say, if I end up with calculating the V/Oct to be A-4 (440Hz), what I measure might be say 435Hz. I can compensate for this as part of the note-tuning solution where the measured output ends up being 440Hz but then the pitch calculation on the module might say 450Hz.

Anyways that's a separate issue but I think if I can clean up the ADC some I can better solve for that if I don't have to deal with a constant changing value.

Way more info than needed but wanted to cover the bases. It's for my chiptune style Eurorack module, the code of which is avialable here: https://gitlab.com/m00dawg/waveboy

User avatar
bitbybitphoto
 
Posts: 7
Joined: Thu Apr 21, 2022 2:41 pm

Re: Wrangling SAMD51's ADCs

Post by bitbybitphoto »

Spent some hours on this and ended up with this:

https://gitlab.com/m00dawg/waveboy/-/bl ... type=heads

This grabs stuff from the SAMD51 analogRead routine. If I tried to use AR directly while setting the config registers I'm setting (lines 33-42), I was getting wired results. I think due to the multiplexer. I made a custom read function (starts at line 278) just for reading V/Oct.

Some of this I think I'll put into a more generic but customized ADC lib as I need to read from 3 sources (V/Oct, CV, and the Pitch knob). V/Oct is most important.

I still have some timing issues I suspect and tried to solve those by setting up a timer that runs at 50Hz which sets a bool to then read/update the V/Oct in the main loop. If I tried to do reads within the ISR of the timer, I ran into some funky issues. When V/Oct is read, I then update the period for the DAC timer (which is the sampleRate calculated from the V/Oct read op).

So far the thing that's made the most difference is setting a high average (lines 41-43) but it's still not perfect. Wondering if I need a cap somewhere to smooth things out in a future PCB revision to really dial things in.

User avatar
bitbybitphoto
 
Posts: 7
Joined: Thu Apr 21, 2022 2:41 pm

Re: Wrangling SAMD51's ADCs

Post by bitbybitphoto »

I ended up trying all sorts of things and opted to do a combination of ADC's built-in averaging with a rolling average function. I adjusted those sort of "to taste" so I had a minimal "portamento" effect while having nearly all notes sound in pitch without steppy wobbles. Smoothing out the steps is mostly the function of the rolling average function since it uses floating point.

This might be good enough but I suspect a better answer is going to be a low-pass filter on the ADC pin. These are slow speed signals for the most part (I don't plan on supporting things like audio rate feedback) which means the low-pass filter could be set pretty low I think. I'm currently sampling at a rate of 4kHz but that's because I'm doing effectively a low-ass via the averaging. Really something as low as 50Hz would be generally fine as long as it's stable. Anyways that means a board revision might be in the future.

User avatar
bitbybitphoto
 
Posts: 7
Joined: Thu Apr 21, 2022 2:41 pm

Re: Wrangling SAMD51's ADCs

Post by bitbybitphoto »

Turns out, while I was able to mitigate the noise with averaging, the actual problem may have been simply updating the sample rate (so the speed of the timer) at the wrong time. Namely, I was constantly updating the frequency, even in the middle of outputting a cyclic waveform. This was likely causing the artifacts I was hearing, and it also was making tuning non-linear. Simply having a check to only reset the sampling-rate after a full wave cycle seems to have made a significant impact in both tuning accuracy and noise.

I haven't yet tested with no sample-averaging, but I was able to significantly pull back on how many samples I was taking to average without introducing noise.

Post Reply
Please be positive and constructive with your questions and comments.

Return to “Itsy Bitsy Boards”