Skip to content
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

Support for ATSAM arm processors #194

Merged
merged 11 commits into from
Jul 5, 2020

Conversation

CrustyAuklet
Copy link

@CrustyAuklet CrustyAuklet commented Apr 23, 2019

just a start so we can comment. Still wrapping my head around the python-template stuff.
Fixes #189.

Update 2020-04-27: @salkinium took over this PR, see #194 (comment)

@CrustyAuklet CrustyAuklet changed the title Feature/microchip sam Support for ATSAM arm processors Apr 23, 2019
@salkinium
Copy link
Member

Still wrapping my head around the python-template stuff.

In your defense, this really isn't an easy topic, you need to understand a whole lot more than just the C/C++ source code. So I'm impressed at how much you got working already! (There are some docs on lbuild module API here: https://github.com/modm-io/lbuild#modules)

I've added some commits, I figured it's more useful get you started with something that isn't the CMSIS stuff, since that's boring and super verbose. I'll review the rest tomorrow (Europe time, etc).

@salkinium
Copy link
Member

Note that there was a bug in lbuild that prevented building because :platform:i2c.bitbang depends on :platform:gpio, which doesn't exist yet. But that should be ok, since you didn't select :platform:i2c.bitbang to be built, so lbuild shouldn't consider those dependencies. I've hot-fixed that in lbuild v1.10.5.

@salkinium
Copy link
Member

salkinium commented Apr 24, 2019

ERROR in 'modm:platform:core'
Traceback (most recent call last):
  File "/root/project/src/modm/platform/core/cortex/module.lb", line 92, in common_memories
    "ram_origin": min(m["start"] for m in memories if "sram" in m["name"]),
ValueError: min() arg is an empty sequence

I guess it was a bit presumptuous of me to assume all internal memory would have sram in the name ;-P Happy fixing!

@CrustyAuklet
Copy link
Author

The sram sections in the SAM have so many wonky names I just renamed them sram in the device tree parser. the linker file always creates the MEMORY RAM that is the sum of the different sections. does this break if the memory sections are not contiguous? The samd51/l21 have a low power section but it is not contiguous with the normal ram section.

I have a starting linker file, but I am having the following the error with scons... forgive me I have never used it before:

Compiling C++·· /home/ethan/source/modm/build/feather_m0/blink/release/main.o
g++: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead
g++: error: unrecognized command line option ‘-mthumb’; did you mean ‘-mtbm’?

the stm files build correctly though, and I presume they are also using arm-none-eabi-g++

@salkinium
Copy link
Member

salkinium commented Apr 25, 2019

the linker file always creates the MEMORY RAM that is the sum of the different sections. does this break if the memory sections are not contiguous?

For STM32 the convention was that the continous memory regions were all called SRAM{1,2,3} and the special RAM was called differently (CCM, ITCM, DTCM), and so the common_memories(env) function makes that assumption too, even though it should be vendor independent.

Just copy the common_memories() function to your own modm:platform:core module, and implement it as required for the SAM platform. I'll find a proper solution later.

The samd51/l21 have a low power section but it is not contiguous with the normal ram section.

I'd just ignore it for now, this is only interesting for the TLSF heap allocator.

Compiling C++·· /home/ethan/source/modm/build/feather_m0/blink/release/main.o
g++: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead
g++: error: unrecognized command line option ‘-mthumb’; did you mean ‘-mtbm’?

This seems like SCons is not calling the right compiler. This is because this line here:
https://github.com/modm-io/modm/blob/develop/tools/build_script_generator/scons/module.lb#L101
should be

-if subs["platform"] in ["stm32"]:
+if subs["core"].startswith("cortex-m"):

Probably also want to change this https://github.com/modm-io/modm/blob/develop/tools/build_script_generator/scons/resources/SConscript.in#L110:

-%% elif platform in ["stm32"]
+%% elif core.startswith("cortex-m")

And this: https://github.com/modm-io/modm/blob/develop/tools/build_script_generator/scons/resources/build_target.py.in#L27
And this: https://github.com/modm-io/modm/blob/develop/tools/build_script_generator/scons/resources/build_target.py.in#L37
🙄🙄🙄

@salkinium
Copy link
Member

Any idea how to program this board? The way I understand the SAMD21 uses the SAM-BA bootloader, which according to the Application Note can be programmed via USB or UART. But the SAM-BA seems to have a non-standard (ie. non-DFU) like protocol, and requires something a custom host binary? https://github.com/atmelcorp/sam-ba

Ideally I'd use OpenOCD or DFU to program this (via scons program).

@CrustyAuklet
Copy link
Author

CrustyAuklet commented Apr 25, 2019

I don't know all the deep details but arduino uses bossac to load with the boot-loader. When I used to use atmel studio this tutorial worked well for getting it set up for my team.
not sure if it's the same program but this just popped up when I googled it. I always just stole it from the Arduino installation. I don't see it in the arch Linux repos or AUR.

Now I use jtag and segger pretty exclusively, so I haven't used the boot-loader for a while.

@CrustyAuklet
Copy link
Author

made those fixes stm32 -> cortex-m and it tries to compile now. So I am working on the clock stuff, SAM version of the RCC class.

I've never generalized the clock setup before and the clock in these chips have a lot of options. For functions like enableExternalCrystal() it looks like you just set the enable bit? where do you set the crystal frequency, tuning parameters, prescaler, etc?

that tutorial link I put in the last comment mentions Atmel Start. The code it generates is ok, but the clock config page is pretty helpful in understanding how the clocks work. It can also output a makefile project instead of atmel studio.

@salkinium
Copy link
Member

salkinium commented Apr 26, 2019

I've never generalized the clock setup before and the clock in these chips have a lot of options.

Don't overdo it with the abstractions. Get something started first in pure C using the CMSIS headers, verify the frequency if possible (usually blinking an LED for a 1s period is enough) and then we can figure out the abstraction.

For functions like enableExternalCrystal() it looks like you just set the enable bit? where do you set the crystal frequency, tuning parameters, prescaler, etc?

This is done in the board support package files, specifically in the SystemClock::enable() function), which is called by the Board::initialize() function in the same file, which is called first in main. (This is different from CMSIS, which calls SystemInit() very early in the startup script. We instead delegate that to the user in main, and instead run startup at a slow speed.)

Note that we use the static constexpr uint32_t frequencies to compute the peripheral baudrate prescalers at compile time. Ideally that list would be generated, however, for STM32 we haven't found a good data source yet.

that tutorial link I put in the last comment mentions Atmel Start. The code it generates is ok, but the clock config page is pretty helpful in understanding how the clocks work. It can also output a makefile project instead of atmel studio.

Yeah, we've given up on solving the clock tree at C++ compile time, it's just too complicated.

I've visualized the clock trees for STM32 already, however, the data is still very complex and probably needs some contraint solver (probably Z3/SAT based).

I would therefore build a generic HTML version of that, based on data within modm-devices, that outputs a generic config format, that modm then can specialize into HAL code. So basically you'd have a common config, that can then be reformatted into C, C++, Rust etc. It's basically an OSS clone of those configuration GUIs.

@salkinium
Copy link
Member

Any progress? My SAM board is still in the mail, but if you commit whatever you have, I can help you get something working.

@CrustyAuklet
Copy link
Author

I've been super busy at work the last week and assembling some new SAM boards at home. Made an attempt at the clock module today but for some reason lbuild build doesn't copy any of my files to the example directory.

I made an empty shell for the clocks, plan is to run lbuild, then code in the project directory so I can test it. then copy the work back into the modm src.

@salkinium salkinium force-pushed the feature/microchip-sam branch 2 times, most recently from a2cf191 to 254eb07 Compare May 6, 2019 03:10
@salkinium
Copy link
Member

I've refactored your entire branch to move things into their own commit to make it a little easier to rebase. For SAM or STM32 isn't a modm:platform:clock peripheral, so that module just contains common core. The Generic Clock Configuration is abbrevieated gclk for SAM, so there should be a modm:platform:gclk module, which I've added.

The reason why your SAM modm:platform:clock module wasn't built was that modm-devices doesn't have a "clock" driver, but vendor specific drivers like rcc for STM32 or gclk for SAM.

- if not options[":target"].has_driver("clock:sam"):
+ if not options[":target"].has_driver("gclk:sam"):
          return False

I've also fixed the linkerscript usage, so that the common linkerscript macros can be used, which will make sure that all the modm linker features work correctly.
Unfortunately the scons size tool is dividing something by zero 😨, need to investigate that.

The example is currently compiling, but I don't have any hardware to test it on yet.

These are the currently available :platform modules for ATSAM in this branch:

 $ lbuild discover -t :platform
Module(modm:platform)   Platform HAL
├── Module(modm:platform:1-wire.bitbang)   Software 1-Wire
├── Module(modm:platform:can.common)   CAN Common
├── Module(modm:platform:clock)   System Clock
├── Module(modm:platform:core)   Microchip SAM core module
├── Module(modm:platform:cortex-m)   ARM Cortex-M Core
├── Module(modm:platform:gclk)   Generic Clock Controller
├── Module(modm:platform:gpio.common)   GPIO Common
├── Module(modm:platform:i2c.bitbang)   Software Inter-Integrated Circuit (I²C)
├── Module(modm:platform:spi.bitbang)   Software Serial Peripheral Interface (SPI)
╰── Module(modm:platform:systick)   ARM Cortex-M SysTick

@CrustyAuklet
Copy link
Author

thanks for doing that! makes sense mostly but on the SAM chips the clock are configures using three peripherals SYSCTRL, GCLK, and PM (page 109 in the samd21 datasheet). so should there be a modm:platform:sysctrl modm:platform:gclk and modm:platform:pm ? does every peripheral get it's own modm:platform:xxx driver?

@salkinium
Copy link
Member

so should there be a modm:platform:sysctrl, modm:platform:gclk and modm:platform:pm?

Yes that seems reasonable. The STM32 had it easy, since the three are basically just one big peripheral, so its module structure doesn't translate well.

These aren't necesarily user-facing modules, they are depended on by other peripheral modules like :platform:uart depends on :platform:rcc for Clock&Power management, so it can use the Rcc::enable<Peripheral::UartX>(); method that hides the ugly details.

does every peripheral get it's own modm:platform:xxx driver?

I think so? I'm hesitant because at the moment the naming isn't 100% the same as in the datasheet/reference manual. For example, the USART peripherals are all placed in :platform:uart (no S), because they only implement the modm::Uart interface.
Where as the synchronous implementation is called :platform:uart.spi which implements modm::SpiMaster interface, which isnt' that intuitive.
I'm not super happy about that, but a bit hesitant to make such big changes for relatively little reason.

Since you have a mostly clean-slate, I'd use the datasheet naming, so that your port's naming scheme is consistent. Can't argue with the datasheet after all ;-P

@salkinium
Copy link
Member

The modm:platform:clock module is also a bit of a relic, it used to contain the SysTick, the power/clock peripheral implementation and the modm::Clock 1ms software timer. It should probably just be killed.

@CrustyAuklet
Copy link
Author

pulled your latest and built it. Flashed it to my Feather M0-proto and I am able to step through the code in Ozone debugger! so success for the basic build 😄

@salkinium
Copy link
Member

What's your motivation for continuing this port, @TheSlat? You've already gotten so far with modm-devices and the basic startup etc.

@CrustyAuklet
Copy link
Author

TLDR: yes still interested, just got pulled away temporarily.

I'm trying to get my current project out by the end of summer (on a SAML21) so that has pulled me away a bit. I am mainly writing drivers for the peripherals, but hopefully those are also needed at some point and I can port them over to MODM? Even without time to write, I have done a lot of reading in the modm code-base, there is some stuff I haven't seen before (ex: protothreads).

Also, I started on some python scripts to download the microchip CMSIS drivers from Atmel START ( an online only analog to cubeMX). Do you make use of that sort of thin in stm32? it is at least a good reference for the differences between models.

@salkinium
Copy link
Member

there is some stuff I haven't seen before (ex: protothreads)

Yes, and the Resumable Functions, which are derived from that. They are both stackless, which is a major pain point (no local variables) and since they are polling, not sleep-friendly. I'm holding out for C++20 coroutines, since their compiler-backed implementation is much better (or at least more consistent) than our macro-hackery.

Do you make use of that sort of thing in stm32? it is at least a good reference for the differences between models.

No, but we should. The quality of these ports wasn't great last time I checked this in depth about 5y ago. I'm very much in favor of adding significantly more data to modm-devices (like the SVD memory maps) than we currently have. Whatever data source helps with that is welcome.

I've been quite busy developing lbuild and porting modm over from xpcc, so the basic peripheral interfaces have basically remained the same since 2015. There is some serious ugly in some of them, especially I2cTransactions are super inefficient and none of the implementations are DMA enabled, or even interrupt-based (looking at you, SPI).
Now that the code generation part of modm is more stable, I can focus again on the actual HAL part of modm.

There are some good reasons to integrate the vendor HAL more into modm, especially for driving very complex peripherals (like Ethernet, USB, DSI, SDMMC). The CubeHAL has some new low-level drivers, which could be interesting for us.

@salkinium
Copy link
Member

I just got a few Feather M0 boards and can't wait until this is being merged.
Is there anything I can help you out with?

Yes you can! I'd be happy to merge this as is, even without the GPIO API, if the samd-compile-all tests pass.

You can either run them directly: (cd test/all && python3 run_all.py samd)
But I recommend starting with building the example with all platform modules added: lbuild build -m ":platform:**" && scons

Looking at the CI issues, you want to add the (generic) connector bits at least for the bit-bang peripherals (it probably doesn't even need to work, just have the right header). Not sure what's wrong with the TLSF header. There are some USB issues in the startup that needs to be #ifdef'ed.

@salkinium
Copy link
Member

I'm mostly interested in getting this merged so that it doesn't go stale. The GPIO API is still very incomplete and not a single peripheral API is implemented, not even UART logging. So the port is fairly still useless. Just as a heads up.

@salkinium
Copy link
Member

Actually let me just fix the header issues, since they are pretty damn lame ;-P

@salkinium salkinium force-pushed the feature/microchip-sam branch 2 times, most recently from da13daa to 23cdcbe Compare July 5, 2020 14:45
@salkinium
Copy link
Member

Ok, I fixed all the easy compile issues, for some reason the CMSIS Headers for SAM21E{15,16} are missing, I've disabled them for now:

  • samd21e15c-uf
  • samd21e15c-uu
  • samd21e16c-uf
  • samd21e16c-uu

@salkinium
Copy link
Member

@henrikssn @CrustyAuklet I'm finally going to merge this PR \o/

The next steps are to improve basic GPIO support and implement a basic UART for logging, and then expand into the peripherals of your choice (don't start with I2C, it's horrible).

@salkinium salkinium marked this pull request as ready for review July 5, 2020 17:05
Copy link
Member

@salkinium salkinium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get to review my own code? It's clearly the best code I've ever seen.

@salkinium salkinium merged commit d2d38a0 into modm-io:develop Jul 5, 2020
@henrikssn
Copy link
Contributor

Wohoo thanks! I'll give that blinky example a shot and then see if I'm able to contribute gpio/uart.

Is there a good sample PR for another platform for adding perpheral support that I can use as lead?

@salkinium
Copy link
Member

The only other Cortex-M platform we have is STM32, so something basic like the recent DAC driver comes to mind: #420

You can in general just hack the STM32 drivers by s/stm32/sam/g and then use plenty of print() in lbuild (or whatever else Python3 has to offer).

The GPIO and peripheral data comes from here.
I'd suggest continuing with UART, and then continue with GPIO, that way you have a logger.

@salkinium
Copy link
Member

Unfortunately since this is a Cortex-M0, you don't have the ITM, otherwise you could've used :platform:itm for logging at least for now.

@salkinium
Copy link
Member

FYI: Fixed the docs upload and the SAMD doxypress is here: https://doc.modm.io/develop/api/samd21j18a-mz/

@CrustyAuklet CrustyAuklet deleted the feature/microchip-sam branch February 3, 2022 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Support for ATSAM arm processors
4 participants