With the previous change, stereo mp3 playback changed from needing
4 2304-byte allocations to needing 2 4604-byte allocations. This was
enough to cause MemoryErrors with regularity.
By using m_realloc() here, the existing memory region can be used.
m_realloc() also works on the first invocation, because m_realloc(NULL, sz)
just calls m_malloc of sz.
.. the documentation doesn't make this clear, but in practice it works
to write both of the DATABUF registers at the same time. This should
also reduce the amount of wear and tear DMA puts on the system, as the
number of transfers is cut in half. (the number of bytes transferred
remains the same, though)
In principle, this could cover all stereo cases if audio_dma_convert_signed
also learned to 16-bit extend and swap values. However, this is the
case that matters for stereo mp3 playback on PyGamer.
Testing performed: Listened to some tracks with good stereo separation.
The PewPew M4 devices come with different displays, which require
different offsets. Since the information about offsets is saved in
the bootloader, we can take it from there.
This adapts the "inline assembler" code from the UF2 bootloader, which
in turn is said to be adapted from the arduino neopixel library.
This requires the cache remain ON when using M0, and be turned OFF on M4
(determined by trial and error)
Testing performed on a Metro M4:
* measured timings using o'scope and found all values within
datasheet tolerance.
* Drove a string of 96 neopixels without visible glitches
* on-board neopixel worked
Testing performed on a Circuit Playground Express (M0):
* Color wheel code works on built-in neopixels
* Color wheel code works on 96 neopixel strip
As a bonus, this may have freed up a bit of flash on M0 targets. (2988 ->
3068 bytes free on Trinket M0)
Closes: #2297
.. inline-unit-growth was the same across all boards, and the highest
max-inline-insns-auto parameter was shared across 2 of 5 boards, so it's
worth a little work to follow the DRY principle
If you define MONITOR_BACKGROUND_TASK, then a physical output pin
(Metro M4 Express's "SCL" pin by default) will be set HIGH while in
the background task and LOW at other times
This code is shared by most parts, except where not all the #ifdefs
inside the tick function were present in all ports. This mostly would
have broken gamepad tick support on non-samd ports.
The "ms32" and "ms64" variants of the tick functions are introduced
because there is no 64-bit atomic read. Disabling interrupts avoids
a low probability bug where milliseconds could be off by ~49.5 days
once every ~49.5 days (2^32 ms).
Avoiding disabling interrupts when only the low 32 bits are needed is a minor
optimization.
Testing performed: on metro m4 express, USB still works and
time.monotonic_ns() still counts up
Fixes#2086
When the frequency of a `PWMOut` is change it re-sets the PWM's duty cycle as
well, since the registers have to be re-calculated based on the new frequency.
Unfortunately, `common_hal_pulseio_pwmout_get_duty_cycle`
will return a value very close to, but not exactly, the value passed to `common_hal_pulseio_pwmout_set_duty_cycle`. If the frequency is modified
without the calling code also re-setting the duty cycle then the duty cycle
will decay over time. This fixes that problem by tracking the unadjusted duty
cycle and re-setting the duty cycle to that value when the frequency is changed.
Make changes in asf4_conf even though I think in these cases the
"peripherals" submodule is running the show.
Arduino clocks the DAC at 12MHz but uses the CCTRL setting for
clocking < 1.2MHz (100kSPS).
A fresh clock (6) is allocated for the new 12MHz clock. This matches
the Arduino value, though not the GCLK index.
Modify other settings to more closely resemble Arduino.
In AudioOut, actually clock the waveform data from the timer we set up
for this purpose.
This gives good waveforms when setting AnalogOut full-scale in a loop,
but the rise/fall of waveforms that come from AudioOut are still erratic.
Weirdly, if AudioOut limits its range even slightly (e.g., to 1000..64000)
then the erratic
Note that this will require https://github.com/adafruit/samd-peripherals/pull/26
to be accepted for the submodule update here to work.
Previously, we depended on allocated channels to always be
"dma_channel_enabled". However, (A) sometimes, many operations
would take place between find_free_audio_dma_channel and
audio_dma_enable_channel, and (B) some debugging I did led me to believe
that "dma_channel_enabled" would become false when the hardware ended
a scheduled DMA transaction, but while a CP object would still think it
owned the DMA channel.
((B) is not documented in the datasheet and I am not 100% convinced that
my debugging session was not simply missing where we were disabling the
channel, but in either case, it shows a need to directly track allocated
separately from enabled)
Therefore,
* Add audio_dma_{allocate,free}_channel.
* audio_dma_free_channel implies audio_dma_disable_channel
* track via a new array audio_dma_allocated[]
* clear all allocated flags on soft-reboot
* Convert find_free_audio_dma_channel to audio_dma_allocate_channel
* use audio_dma_allocated[] instead of dma_channel_enabled() to check
availability
* remove find_free_audio_dma_channel
* For each one, find a matching audio_dma_disable_channel to convert
to audio_dma_free_channel
Closes: #2058
.. otherwise, a sequence like
>>> a = audioio.AudioOut(board.A0)
>>> a.play(sample, loop=True)
>>> a.deinit()
would potentially leave related DMA channel(s) active.