Skip to content

ports: adafruit grand central board support #11104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

graeme-winter
Copy link
Contributor

Extend existing support for SAMD51 based boards to Adafruit Grand Central.

Includes fixes to DAC implementation to support two channels, fixes to the RTC module which are probably applicable to other boards.

@graeme-winter graeme-winter changed the title Adafruit grand central board support ports: adafruit grand central board support Mar 22, 2023
@robert-hh
Copy link
Contributor

Thank you for the contribution. A few questions to the DAC code.

  • at first, thank you for reminding that practically the dac_init flag was not used. Your change makes proper use of that flag, which is now a pair.
  • I see that you disable DAC before the clock is applied. I'm not sure if setting registers of the DAC works without a clock. So the first thing I did usually was enabling the clock. And I had not the impression that disable is required, because reset disables the DAC as well, and enabling an enabled DAC is a NOP. Alternatively, you can check the enable flag before enabling the DAC.

The pins.csv looks like a pins.csv for the board which I made recently, without making a PR. Beside some pin naming differences, I added the following pin names as well:

PIN_PB11,QSPI_CS
PIN_PB10,QSPI_SCK
PIN_PA08,QSPI_D0
PIN_PA09,QSPI_D1
PIN_PA10,QSPI_D2
PIN_PA11,QSPI_D3

With these, the flash chip is easier accessible for a Python based flash driver (see e.g. https://github.com/robert-hh/SPI_Flash), and the PR for using the on board flash will uses these.

You mentioned changes to the RTC module, but did not include them.

@robert-hh
Copy link
Contributor

Another note:
You might not need the line:
#define MICROPY_HW_MCU_OSC32KULP (1)
This is a special workaround for PCB layout problems of some Adafruit boards. Without that line, the CPU clock and with that systick is more precise.

About the PR structure: You could combine the commits of this PR into one with the board files and one with the DAC change, or make two PRs out of it.

@graeme-winter
Copy link
Contributor Author

The pins.csv looks like a pins.csv for the board which I made recently, without making a PR. Beside some pin naming differences, I added the following pin names as well:

PIN_PB11,QSPI_CS
PIN_PB10,QSPI_SCK
PIN_PA08,QSPI_D0
PIN_PA09,QSPI_D1
PIN_PA10,QSPI_D2
PIN_PA11,QSPI_D3

With these, the flash chip is easier accessible for a Python based flash driver (see e.g. https://github.com/robert-hh/SPI_Flash), and the PR for using the on board flash will uses these.

Added - will rewrite the change set as suggested once other points you raised addressed.

@graeme-winter
Copy link
Contributor Author

  • I see that you disable DAC before the clock is applied. I'm not sure if setting registers of the DAC works without a clock. So the first thing I did usually was enabling the clock. And I had not the impression that disable is required, because reset disables the DAC as well, and enabling an enabled DAC is a NOP. Alternatively, you can check the enable flag before enabling the DAC.

§47.6.2.3 of the SAMD5x family data sheet states

DAC Configuration

Each individual DAC is configured by its respective DAC Control register (DACCTRLx)). These settings are applied when DAC Controller is enabled and can be changed only when DAC Controller is disabled.

I recall I also found that the second dac would not be correctly configured while leaving the first configured if I did not disable the system when updating the registers.

@graeme-winter
Copy link
Contributor Author

graeme-winter commented Mar 23, 2023

You mentioned changes to the RTC module, but did not include them.

This was something of a discovery process for me (first time I have ported micropython) and this change related to adding these defines

+#define MICROPY_HW_XOSC32K          (1)
+#define MICROPY_HW_MCU_OSC32KULP    (1)

which you make further reference to and I need to investigate some more...

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch 3 times, most recently from c0cee7f to 1d57860 Compare March 23, 2023 04:48
@graeme-winter
Copy link
Contributor Author

About the PR structure: You could combine the commits of this PR into one with the board files and one with the DAC change, or make two PRs out of it.

Rewrote, but got distracted by trying to satisfy the formatting checks and realised that the changes are not split quite the way you suggested. Will come back to this later... many thanks for your suggestions.

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch from 1d57860 to 1390055 Compare March 23, 2023 05:25
@graeme-winter
Copy link
Contributor Author

About the PR structure: You could combine the commits of this PR into one with the board files and one with the DAC change, or make two PRs out of it.

Rewrote, but got distracted by trying to satisfy the formatting checks and realised that the changes are not split quite the way you suggested. Will come back to this later... many thanks for your suggestions.

Now rewritten...

@robert-hh
Copy link
Contributor

Thank you for the changes.

I recall I also found that the second dac would not be correctly configured while leaving the first configured if I did not disable the system when updating the registers.

That's fine. At first glance I did not notice, that the path for if (!dac_init[self->id]) can be executed even if the path if (!(dac_init[0] | dac_init[1])) { was not, and then DAC is not disabled. My major concern was accessing the DAC before the bus clock in the APBD register is enabled. As said, I do not recall the behavior for the DAC peripheral, but in my test a non-enabled bus clock was often the reason for code lock-up. You should be able to move DAC disable into the if (!dac_init[self->id]) block.

You added init value for vref into the static DAC structure. That's fine. But you used numeric constants, instead of the DEFAULT_DAC_VREF defines. Using the latter requires to shift around the code blocks a little bit.

@robert-hh
Copy link
Contributor

About manifest.py: Do not change manifest.py at the boards directory. These would apply to all boards, even if they do not have the respective hardware enabled of sufficient free code space. If you want to add additional files for a board, add a manifest.py file to the board's directory, and add a line:
FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py
to mpconfigboard.mk of the board.

@robert-hh
Copy link
Contributor

robert-hh commented Mar 23, 2023

Another note: If you want to use the SDCARD using the sdcard driver in https://github.com/micropython/micropython-lib/tree/c8603192d1d142fdeb7f9578e000c9834669a082/micropython/drivers/storage/sdcard, It is useful to have the following lines in mpconfigboard.h:

// fatfs configuration used in ffconf.h
#define MICROPY_FATFS_ENABLE_LFN            (1)
#define MICROPY_FATFS_RPATH                 (2)
#define MICROPY_FATFS_MAX_SS                (4096)
#define MICROPY_FATFS_LFN_CODE_PAGE         437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */

@robert-hh
Copy link
Contributor

About DAC disable before enabling the APBD clock. That works, but maybe by chance. I looked at it with a debugger.
After reset, with the APBD clock for DAC disabled, both the CTRLA and SYNCBUSY register show a value of 0. So the first disable will pass, even if the DAC would not respond to a setting. Probably, trying to enable DAC without a APBD clock would fail. At least that's what happens when I try it with the debugger.

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch from 1390055 to 89ed6e6 Compare March 23, 2023 20:22
@graeme-winter
Copy link
Contributor Author

About manifest.py: Do not change manifest.py at the boards directory. These would apply to all boards, even if they do not have the respective hardware enabled of sufficient free code space. If you want to add additional files for a board, add a manifest.py file to the board's directory, and add a line: FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py to mpconfigboard.mk of the board.

Done, was not aware of convention

@graeme-winter
Copy link
Contributor Author

Will have to get to remaining suggestions later, but thank you

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch from 89ed6e6 to 74febb5 Compare March 24, 2023 05:15
@graeme-winter
Copy link
Contributor Author

You added init value for vref into the static DAC structure. That's fine. But you used numeric constants, instead of the DEFAULT_DAC_VREF defines. Using the latter requires to shift around the code blocks a little bit.

Removed init value in preference to the broader re-arrangement

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch from 74febb5 to 83df65a Compare March 24, 2023 05:26
@graeme-winter
Copy link
Contributor Author

About DAC disable before enabling the APBD clock. That works, but maybe by chance. I looked at it with a debugger. After reset, with the APBD clock for DAC disabled, both the CTRLA and SYNCBUSY register show a value of 0. So the first disable will pass, even if the DAC would not respond to a setting. Probably, trying to enable DAC without a APBD clock would fail. At least that's what happens when I try it with the debugger.

Understood, change incoming - the "works by chance" is probably why I had not stumbled over this

@graeme-winter graeme-winter force-pushed the adafruit-grand-central branch from 83df65a to 9248298 Compare March 24, 2023 05:29
@graeme-winter
Copy link
Contributor Author

Just by way of some commentary:

from machine import DAC

dac0 = DAC(0)
dac1 = DAC(1)

for j in range(0, 0x1000, 0x10):
    dac0.write(j)
    dac1.write(j)

del(dac0)
del(dac1)

dac0 = DAC(0)
dac1 = DAC(1)

for j in range(0, 0x1000, 0x10):
    dac0.write(j)
    dac1.write(j)

del(dac0)
del(dac1)

dac0 = DAC(0)
dac1 = DAC(1)

while 1:
    for j in range(0, 0x1000, 0x10):
        dac0.write(j)
        dac1.write(j)

Seems to not lock up and generate the (rather jittery...) sawtooth one may expect

@graeme-winter graeme-winter requested a review from robert-hh March 24, 2023 05:36
@robert-hh
Copy link
Contributor

generate the (rather jittery...) sawtooth one may expect

That looks fine. For repeating DAC output and ADC sampling, you may as well have a look at PR #9624, which implements a timed DAC.write ADC.read using DMA and a timer.

@graeme-winter
Copy link
Contributor Author

generate the (rather jittery...) sawtooth one may expect

That looks fine. For repeating DAC output and ADC sampling, you may as well have a look at PR #9624, which implements a timed DAC.write ADC.read using DMA and a timer.

That's in my queue - I have done a fair chunk of register bashing on the rp2040 with assembly and machine.mem32 to do chained DMA etc. with a resistor DAC - part of my motivation of picking up the Grand Central was for a decent hardware DAC.

Your PR mentioned above looks exactly like what was next on my to-do by more register bashing 🙂 thank you

@robert-hh
Copy link
Contributor

The PR looks fine now and the DAC code makes just the minimal changes. And it is good that you can confirm it works. I had made board files for the board before for another user, but lacking a board I could not test them, and I did not get any feedback. I cannot tell if and how long it takes for the PR to get merged. Sometimes it's days, sometimes months, sometimes never. But independent form that PR are a good source of information for all of us.

You did not mention a picture of the board in the json file. A picture is used for the download page. Adding it requires another PR at the micropython-media repository at https://github.com/micropython/micropython-media. The name of the picture file and the directory name of the board must be the same in both repositories. See also the other boards as example.

If you have time and since you have the board, you could try PR #10233, which uses an on-board external flash chip for the file system. You would have to specify the flash chip in mpconfigboard.h, with a line:

#define MICROPY_HW_QSPIFLASH GD25Q64C

projectgus and others added 22 commits September 21, 2024 08:00
Original commit was by @millosolomillo from 2022, but CI no longer accepts
their auto-generated GitHub commit email...

Signed-off-by: Angus Gratton <angus@redyak.com.au>
Signed-off-by: Christopher Parrott <chris@pimoroni.com>
To allow more pins when other ways are used to provide external GPIO (ie
not via cyw43).

Signed-off-by: Christopher Parrott <chris@pimoroni.com>
The `#if` check only checks that `MICROPY_PY_NETWORK_CYW43` and
`MICROPY_HW_PIN_EXT_COUNT` are defined.  This is a reasonable assumption
for the Pico W, but causes conflicts if someone wants to attach an external
IO expander to their Pico W and have its pins appear as Pin objects.

This commit addresses this by adding the additional checks, letting board
builds include wireless but separately choose whether the external IO pins
come from the cyw43 or not.

Signed-off-by: Christopher Parrott <chris@pimoroni.com>
This change helps detect if the filesystem is invalid, by also including
the first mount attempt within the try-except.  Then the FAT is reformatted
if needed.

Fixes issue micropython#15779.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
Otherwise it's very difficult to reason about thread safety in a
scheduler callback, as it can run at any time on any thread - including
racing against any bytecode operation on any thread.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
If GIL is disabled then there's threat of a race condition if some other
code specifically requests USB processing (i.e. to unblock stdio), while
a scheduled TinyUSB callback is already running on another thread.

Relies on the change in the parent commit, where scheduler is restricted
to main thread if GIL is disabled.

Fixes micropython#15390 - "TinyUSB callback can't recurse" exceptions on rp2 when
using _thread module and USB serial I/O.

Adds a unit test for stdin functioning correctly in threads (fails on rp2
port without this fix).

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
With the recent qemu (d9a0fdd and
0426934) and zephyr
(05cad7b) changes to how their tests are
run, two things became unused:

- The tinytest framework, which embedded a set of tests and their expected
  output within firmware, so these tests could be run stand-alone.

- The `--write-exp` and `--list-tests` options to `tests/run-tests.py`,
  which were needed primarily to generated the expected test output for
  tinytest (also the associated `tests/run-tests-exp.py/.sh` scripts are
  now unused).

This commit removes the tinytest component and all its helper code.  This
eliminates a maintenance burden.

Signed-off-by: Damien George <damien@micropython.org>
Removing the now-unused (see previous commit for details) `--write-exp` and
`--list-tests` options helps to simplify the rather complex logic in
`run-tests.py`.

Signed-off-by: Damien George <damien@micropython.org>
The Unix port's MIPS target CI steps have been updated to be more in
line with the other targets (the MicroPython binary now runs as a
dynamic executable), and the test exceptions for ffi have been lifted.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
The FFI helper definition was accidentally omitted when committing the
necessary shell code for building RV64 Unix builds in the CI
environment.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
The Unix port's Arm target CI steps have been updated to be more in
line with the other targets (the MicroPython binary doesn't need an
environment variable to be set in order to run now).

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
Native .mpy files targetting armv6m (eg RP2040) cannot currently have more
than about 2kiB of native code (between the start of the file and the init
function).

This commit fixes that by using bigger jumps to jump to the init function.

Signed-off-by: Damien George <damien@micropython.org>
Casting an ffi_arg to a signed int may truncate the value. E.g., when the
ffi_arg is 64-bit and the signed int is 32-bit. Also, casting an ffi_arg
to a larger signed type will not sign extend the value. E.g., when the
ffi_arg is 32-bit and the larger signed type is int64_t. If the value is
signed, it should be cast to ffi_sarg, which is the same size as ffi_arg.

Signed-off-by: Michael Sawyer <mjfsawyer@gmail.com>
Added the "long" modffi tests. The tests could not be added to the existing
ffi_types test because two .exp files were required for the 32-bit and
64-bit results. Code common to both the ffi_types and type "long" tests was
factored into ffi_int_base. ffi_types was renamed to ffi_int_types to group
the related tests under the "ffi_int" prefix.

Signed-off-by: Michael Sawyer <mjfsawyer@gmail.com>
Signed-off-by: Seon Rozenblum <seon@unexpectedmaker.com>
This adds two new UM boards: OMGS3 and RGB Touch Mini.  Also fixed the
NanoS3 deploy info.

Signed-off-by: Seon Rozenblum <seon@unexpectedmaker.com>
This is for boards not covered by the Olimex ESP32 PoE implementation.  The
major setting is about the PHY interface configuration.

Tested with esp-idf v5.0.4 and Olimex ESP32 EVB boards.

Signed-off-by: shiggy <mail@shiggytech.de>
This commit adds a new `RingIO` type which exposes the internal ring-buffer
code for general use in Python programs.  It has the stream interface
making it similar to `StringIO` and `BytesIO`, except `RingIO` has a fixed
buffer size and is automatically safe when reads and writes are in
different threads or an IRQ.

This new type is enabled at the "extra features" ROM level.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Signed-off-by: Seon Rozenblum <seon@unexpectedmaker.com>
Copy link

codecov bot commented Sep 21, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.57%. Comparing base (b08ddbb) to head (b495a46).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #11104   +/-   ##
=======================================
  Coverage   98.57%   98.57%           
=======================================
  Files         164      164           
  Lines       21341    21341           
=======================================
  Hits        21036    21036           
  Misses        305      305           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:   +52 +0.019% ADAFRUIT_ITSYBITSY_M4_EXPRESS[incl +4(bss)]

@robert-hh
Copy link
Contributor

This PR seems to be messed up, looking at the number of commits it wants to include. First step should be to rebase your branch on to the current master. Or better close it and restart with the board files based on the current master.
The format of the pins.csv file has been changed. The columns are swapped, and at the port ID the PIN_ prefix is dropped, e.g. A0,PA02. Attached is a sample version of a new pin.csv. The changes to DAC are still fine. I'm just surprised that they did not make it into the master. I recall that they did. Anyhow, better make DAC change and the new board separate PRs.

pins.zip

@graeme-winter
Copy link
Contributor Author

Closing in favour of a rewritten PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
board-definition New or updated board definition files. Combine with a port- label. port-samd
Projects
None yet
Development

Successfully merging this pull request may close these issues.