Also found a race condition between timer_disable and redraw, which
would happen if I debugger-paused inside common_hal_rgbmatrix_timer_disable
or put a delay or print inside it. That's what pausing inside reconstruct
fixes.
So that the "right timer" can be chosen, `timer_allocate` now gets the `self`
pointer. It's guaranteed at this point that the pin information is accurate,
so you can e.g., find a PWM unit related to the pins themselves.
This required touching each port to add the parameter even though it's
unused everywhere but raspberrypi.
This changes lots of files to unify `board.h` across ports. It adds
`board_deinit` when CIRCUITPY_ALARM is set. `main.c` uses it to
deinit the board before deep sleeping (even when pretending.)
Deep sleep is now a two step process for the port. First, the
port should prepare to deep sleep based on the given alarms. It
should set alarms for both deep and pretend sleep. In particular,
the pretend versions should be set immediately so that we don't
miss an alarm as we shutdown. These alarms should also wake from
`port_idle_until_interrupt` which is used when pretending to deep
sleep.
Second, when real deep sleeping, `alarm_enter_deep_sleep` is called.
The port should set any alarms it didn't during prepare based on
data it saved internally during prepare.
ESP32-S2 sleep is a bit reorganized to locate more logic with
TimeAlarm. This will help it scale to more alarm types.
Fixes#3786
Instead of unrolling the code 16 times, unroll it 4 times and loop
over it 4 times. This gives the same 16 iterations, but at an expense
of less flash space.
* No weak link for modules. It only impacts _os and _time and is
already disabled for non-full builds.
* Turn off PA00 and PA01 because they are the crystal on the Metro
M0 Express.
* Change ejected default to false to move it to BSS. It is set on
USB connection anyway.
* Set sinc_filter to const. Doesn't help flash but keeps it out of
RAM.
The time.sleep() and time.monotonic() functions break the timer
interrupt on which PewPew10 display relies, so we can't use them
anymore. Instead I'm adding a time-keeping function to the display
code itself, which then can be used in pew.tick() internally.
Lightly tested:
* no matches (catch-all)
* standard address single address matches (even and odd positions)
* standard address mask matches
* only tested that extended doesn't match non-extended
Tested & working:
* Send standard packets
* Receive standard packets (1 FIFO, no filter)
Interoperation between SAM E54 Xplained running this tree and
MicroPython running on STM32F405 Feather with an external
transceiver was also tested.
Many other aspects of a full implementation are not yet present,
such as error detection and recovery.
I recently misdiagnosed a "maybe-uninitialized" diagnostic as a bug in
asf4. However, the problem was in our SPI code.
A special case for samr21 MCUs was being applied to same54p20a and possibly
other D5x/E5x MCUs, since the check was simply for pin PC19 existing at all.
Change the check to use the macro PIN_PC19F_SERCOM4_PAD0 which is only
defined if special function F of pin PC19 is SERCOM4 PAD0.
Reorganize the code a little bit so that brace-matching in editors is
not confused by the conditionalized code, including an unrelated change
for APA102_SCK's condition.
Revert the change to the Makefile that incorrectly attempted to silence
the diagnostic.
This is a slight trade-off with code size, in places where a "_varg"
mp_raise variant is now used. The net savings on trinket_m0 is
just 32 bytes.
It also means that the translation will include the original English
text, and cannot be translated. These are usually names of Python
types such as int, set, or dict or special values such as "inf" or
"Nan".
This introduces the new macro SAM_D5X_E5X. This is mostly the same
as SAMD51 before, except in a few places where a special case for
SAME54 is required
I noticed that this code was referring to samd-specific functionality,
and isn't enabled except in one samd board (pewpew10). Move it.
There is incomplte support for _pew in mimxrt10xx which then caused build
errors; adding a #if guard to check for _pew being enabled fixes it.
The _pew module is not likely to be important on mimxrt but I'll leave the
choice to remove it to someone else.
Ujson should only worry about whitespace before JSON. This becomes apparent when you are using MP stream protocol to read directly from input buffers.
When you attempt to read(1) on a UART (and possibly other protocols) you have to wait for either the byte or the timeout.
Fixes:
- Waiting for a timeout after you have completed reading a correct and complete JSON off the input.
- Raising an OSError after reading a correct and complete JSON off the input.
- Eating more data than semantically owned off the input buffer.
- Blocking to start parsing JSON until the entire JSON body has been loaded into a potentially large, contiguous Python object.
Code you would write before:
```
line = board_busio_uart_port.read_line()
json_dict = json.loads(line)
```
or reaching for fixed buffers and swapping them around in Python.
Code that did not work before that does now:
```
json_dict = json.load(board_busio_uart_port)
```
- This removes the need for intermediate copies of data when reading JSON from micropython stream protocol inputs.
- It also increases total application speed by parsing JSON concurrently with receiving on boards that read from UART via DMA.
- It simplifies code that users write while improving their apps.
This gets all the purely internal references. Some uses of
protomatter/Protomatter/PROTOMATTER remain, as they are references
to symbols in the Protomatter C library itself.
I originally believed that there would be a wrapper library around it,
like with _pixelbuf; but this proves not to be the case, as there's
too little for the library to do.
.. 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.
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
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.