Add 4pi support. (Extremely experimental) - #28533
Draft
ellensp wants to merge 8 commits into
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SAM3U4E / 4pi — new HAL
Description
Adds a new HAL family,
SAM3U, for the Atmel AT91SAM3U4E, and board supportfor the 4pi controller (
BOARD_4PI, 3200) — a 96 MHz Cortex-M3 board thatMarlin has never supported.
This is the first bare-metal HAL in the tree. There is no Arduino core for
the SAM3U, so the environment builds directly on the CMSIS device headers with
frameworkdeliberately empty, and the HAL supplies everything a core wouldnormally provide: the vector table and
Reset_Handler, clock bring-up, amillis()/micros()time base, and anArduino.hshim covering the slice ofthe Arduino API that Marlin's shared layer calls.
What is implemented:
(port * 32 + bit), so pin files read like the schematic (PA20,PC28)SDIO_*interface (ONBOARD_SDIO)HAS_MOTOR_CURRENT_SPIpathThree hardware constraints shaped the design and are worth a reviewer's
attention, each covered in detail below:
so
hal_timer_tisuint16_tas on AVR.be enabled.
Marlin's software PWM — as the original 4pi firmware did.
Requirements
RESETpads on top of the board and powercycle to reach the bootloader.
Benefits
which the SAM3U is unlikely to be the last of.
header pinouts, the RGB indicator LEDs, and the UART/USB pin assignments,
all traced from the board's schematic rather than copied from its pinmap.
Companion documents:
Marlin/src/HAL/SAM3U/AGENTS.md— how the HAL is put together, and the trapsin it. Read that before changing HAL code.
Marlin/src/pins/sam3u/pins_4PI.h— the board pin map and the full expansionheader pinouts, traced from the schematic.
Status
It compiles and links correctly. It has never been run on hardware.
That distinction matters for everything below. What has actually been verified:
pio run -e 4piexception_table@0x00080000_seeprom@0x000BF000, outside theromregion_estack@0x2000C000,_sstack@0x2000B000flash_write_page@0x20000000Dummy_HandlerEverything else — that the clock actually comes up, that steps come out of the
right pins, that the ADC reads sane values — is unverified. See
Bring-up checklist.
Build and flash
The environment is bare-metal:
frameworkis deliberately empty, andbuildroot/share/PlatformIO/scripts/sam3u_build.pysupplies the CMSIS includepaths and restores libc/libm/libgcc (the bare builder links
-nostdlib).Upload is over SAM-BA. To reach the bootloader, short the
RESETpads ontop of the board and power-cycle it.
Six host links are available and any of them can go in any of Marlin's three
slots (
SERIAL_PORT,SERIAL_PORT_2,SERIAL_PORT_3) in any combination —SERIAL_PORT 0withSERIAL_PORT_2 -1is valid, and so on. Only the portsactually named get compiled in.
On the 4pi, though, only two of them are practically usable:
-1— native USB CDC (the default, and how the board is meant to be used).The 4pi has no USB-serial chip; this is the chip's own UDPHS device
controller. It enumerates as
1d50:6019, the same VID/PID the original 4pifirmware used, so existing udev rules and host tooling keep working.
0— the chip's UART, on the 14-pin peripheral header. Worth keeping inmind for bring-up, especially if USB enumeration is itself what's broken:
250000 baud, 8N1. (96 MHz / (250000 × 16) = 24 exactly, so no baud error.)
The HAL also implements ports
1–4(USART0–3), but on this board every oneof them shares pins with something already in use, so the board's SanityCheck
rejects or warns on them:
The hardware, versus the Due
The SAM3X8E HAL (
HAL/DUE) is the closest relative — same vendor, same PIO/TC/UART peripherals — and this HAL is recognisably descended from it. The parts are
not interchangeable:
PIO_ABSR)Design decisions worth knowing
16-bit timers.
hal_timer_tisuint16_t, as on AVR — notuint32_tas onthe Due. Marlin's stepper ISR already copes by clamping the interval to
HAL_TIMER_TYPE_MAXand re-entering. Do not "fix" this by widening the type.Stepper clock = MCK/32 = 3 MHz. Chosen to mirror AVR's proven 2 MHz rather
than for maximum resolution. The slowest representable step rate is
3000000 / 65535≈ 46 steps/s, far below any usable feedrate.TIMER_CLOCK2(12 MHz) would give finer resolution but raise that floor to ~183 steps/s,
which slow Z and extruder moves genuinely reach.
All three timer channels are spoken for — stepper, temperature, tone. There
is no fourth, so
inc/SanityCheck.hrejects enabling servos and sound together.Software PWM for heaters and fans. The four hardware PWM channels do not
reach the 4pi's FETs, so
inc/Conditionals_adv.hforcesFAN_SOFT_PWMandset_pwm_duty()degrades to an on/off threshold. This is exactly what theoriginal 4pi firmware did (soft PWM every 100 µs).
4 flash wait states, not 2. The datasheet requires
FWS = 3(4 read cycles)at 96 MHz with VDDCORE 1.80V (Table 42-55). The original 4pi/Sprinter firmware
programmed 2 while still running at 96 MHz, which is out of spec. Do not copy
that.
WDT_MRis write-once after reset.clock.cppdisables the watchdog onlywhen
USE_WATCHDOGis off; otherwise it leaves the 16 s default running so thatMarlinHAL::watchdog_init()gets the one write that counts.USB CDC forced to full speed. UDPHS is high-speed capable and the original
firmware ran at 480 Mbit/s with 512-byte bulk endpoints. This driver pins the
link to full speed: 12 Mbit/s is already far more than Marlin can use, and it
means one descriptor set instead of two (a high-speed device must also publish
a device_qualifier and an other_speed_configuration and keep both endpoint-size
sets in step) and 64-byte banks instead of 512 out of the 4 KB DPRAM. Switching
back is three small edits, documented at the top of
usb/usb_cdc.cpp.Onboard SD over HSMCI, with programmed I/O. The socket is wired to the
High Speed Multimedia Card Interface in 4-bit mode, not SPI, so Marlin's stock
Sd2Cardcannot drive it;sdio.cppimplements theSDIO_*interface thatDiskIODriver_SDIOcalls instead, and the board file selects it withONBOARD_SDIO. Transfers are programmed I/O rather than DMA —RDPROOFandWRPROOFstall the card clock whenever the FIFO would over- or underrun, sothe transfer waits for the CPU instead of losing data, which is what makes PIO
safe at 24 MHz. DMA would only matter if the card had to be serviced
concurrently with something else, and Marlin reads it from the foreground.
Bit-banged SPI. The only device on the bus is the AD5206 digipot — write-only
and low-rate — so a bit-banged master costs nothing and keeps the bus usable on
any pin combination.
Working around the CMSIS package
framework-cmsis-atmelis incomplete for the SAM3U, in two ways that both hadto be handled:
instance/headers. It shipscomponent/andpio/but notinstance/, whichsam3u4e.hincludes unconditionally — so the vendorheader will not even parse.
Marlin/src/HAL/SAM3U/include/instance/holds 31generated replacements (600 register macros). Regenerate with
buildroot/share/scripts/gen_sam3u_instance_headers.pyif the package isupdated. Names are instance-qualified (
REG_PIOA_PER, notREG_PIO_PER) soinstances sharing a struct type do not collide; the script fails loudly if
any do.
startup_sam3u.cdoes not compile against itsown
sam3u4e.h— it names reserved vector slots (pvReserved7,12,16)that the SAM3U4E
DeviceVectorsstruct does not have.Marlin/src/HAL/SAM3U/startup.creplaces it.Also note
SPIis a macro insam3u4e.h(the peripheral base pointer),which collides with the global
SPIobject Marlin core code expects.include/SPI.hpulls the device header in first, saves the base asSAM3U_SPI_REGS, then#undefs the macro. Keep that ordering.Not done, and why
1. Hardware SPI
HAL_SPI.cppbit-bangs. Worth revisiting only if something fast lands on thebus (an external SD reader would qualify). The peripheral's pins are the ones
already in use (
MISO=PA13,MOSI=PA14,SPCK=PA15,NPCS0=PA16), and theexpansion header exposes three more chip selects, so the move is mechanical.
2. Servos
SHARED_SERVOSis declared but there is no free timer channel to drive it (seeabove).
inc/SanityCheck.hcatches the conflicting case rather than letting itcompile into something that silently does not work.
3. TFT / graphical LCD
No
u8gortftsubfolder. The 20-pin GPIO header has sixteen uncommitted PIOlines, which is where a display would attach — but nothing is wired up for it
yet. Character LCDs over the software SPI/parallel paths are the least work.
Known risks in what is written
These are the places a first hardware test is most likely to catch something,
roughly in order of suspicion:
usb/usb_cdc.cpp). The newest and largest untestedpiece. If the device does not enumerate, fall back to
SERIAL_PORT 0on theUART to get console output, then work the USB problem with visibility.
Specific things to check first:
word twice; this driver reads the 8 bytes linearly, per the datasheet and
Atmel's later ASF driver. If enumeration fails immediately (no descriptor
request ever completes), that is the first thing to question.
EPT_MAPDafterep_configure()— reads back clear if the endpointtable asks for more than the 4 KB DPRAM.
PMC_SR_LOCKU) inusb_cdc_init().clock.cpp). The PLLA/MCK sequence follows the datasheetand the original firmware, but a wrong
MOSCXTSTor a missedMCKRDYwaitshows up as a dead board. If nothing at all happens, suspect this first.
sdio.cpp). Untested, and the card init sequencehas several places to get wrong. If the card never mounts, the useful
split is identification (CMD0/CMD8/ACMD41/CMD2/CMD3) versus transfer
(CMD17/CMD24) — a card that reports a plausible size from
M21got throughidentification and read its CSD, so the problem is in the data path.
Specific things to check: the two masked error cases (
RCRCEon ACMD41'sR3,
RTOEon CMD8 for a v1.x card), the 4-bit switch order (ACMD6 mustreach the card before
SDCRchanges), and byte-vs-block addressing on astandard-capacity card — SDHC is far more common, so that path is the more
likely to be wrong and the less likely to be noticed.
adc.cpp).ADC_STARTUPandADC_SHTIMare computed fromthe datasheet's minimums with integer arithmetic; if temperatures read noisy
or biased, widen the sample-and-hold time.
eeprom/eeprom_flash.cpp). The riskiest code in the HAL —it programs flash from a RAM-resident routine with interrupts masked. The
placement is verified statically, but a bad
M500/M501cycle is the waythis fails. Test with
M502→M500→M501early, before trusting it.fixed 8N1 and the XON/XOFF path have not been exercised.
original firmware, but never observed.
Two latent bugs of this shape were already found and fixed by compiling with
SDSUPPORTenabled — a missing<ctype.h>in theArduino.hshim, andSD_SS_PIN == -1reaching the unguarded fastio macros (where it resolves toPA31, i.e.
Y_DIR). Enabling unusual feature combinations is a cheap way tofind more; the HAL is only as tested as the config it has been built against.
Bring-up checklist
Roughly the cheapest-first order:
(
lsusbshould show1d50:6019) and for Marlin's startup banner on theresulting
/dev/ttyACM*. If nothing enumerates, rebuild withSERIAL_PORT 0and watch the UART at 250000 baud instead — that separates"the board is dead" from "USB is wrong".
M115— confirms the board string and that the G-code pipeline runs.M105— confirms ADC12B. Room temperature on the hotend and bed withthermistors fitted;
TEMP_0_PINis PB4,TEMP_BED_PINis PC16.M119— confirms endstop reads and pull-ups. Trigger each by hand.M502→M500→M501— confirms flash EEPROM emulation survives apower cycle. Do this before relying on stored settings.
M17, then single-axisG0moves — confirms the stepper timer, step/dirpins, and the AD5206 current setting. Start slow; check direction against
INVERT_*_DIR.M104/M140with a low setpoint — confirms software PWM on the heaterFETs. Watch it. Have the power switch in reach.
M106— confirms fan output on the FET header.M42/M43— the board has three RGB indicator LEDs on nine free pins(
LED1_PIN..LED9_PIN, colour-mapped in the pins file); toggling one withM42is the cheapest possible "is the firmwarerunning and are pins reaching the board" test, and getting the colour you
expect confirms the mapping.
M43pin reporting needsPINS_DEBUGGINGin Configuration_adv.h,which is off by default and costs about 3.4KB of flash — worth turning on
while bringing the board up.
M21, thenM20— confirms the HSMCI SD driver: mount the card andlist it. A plausible card size means identification and the CSD read worked;
a successful
M20means the data path does too. Follow withM28/M29toexercise writes.
Configuration changes on this branch
Marlin/Configuration.handMarlin/Configuration_adv.hare set up for the4pi so the branch builds and runs as-is. These are working-tree changes for
convenience — keep them out of any upstream PR; only the HAL, pins, board
and build-system files belong there.
Only board-specific settings are changed. Machine-specific values — steps/mm,
feedrates, accelerations, travel limits, axis directions — are deliberately
left at Marlin's defaults, because they describe a printer rather than a
controller and would be wrong for anyone else's machine:
MOTHERBOARDBOARD_4PICUSTOM_MACHINE_NAME"4pi"M115SERIAL_PORT-1EEPROM_SETTINGSSDSUPPORTMICROSTEP_MODES{ 16, … }DIGIPOT_MOTOR_CURRENT{ 128, … }The two driver values come from the original 4pi/Sprinter firmware's
init_configuration.h(_AXIS_CURRENT), and are a starting point rather than arecommendation — set the current to suit the motors actually fitted.
File map
Everything added by this branch:
Modified:
Marlin/src/HAL/platforms.h(family branch),Marlin/src/core/boards.h(BOARD_4PI),Marlin/src/pins/pins.h(pins file),
platformio.ini(ini include).Reference material used
Atmel-6430-…-SAM3U4-…_Datasheet.pdf. Sections usedhere: 8.2.3 flash organisation, 35.6 timer/counter, 42-55 flash wait states.
4pi-firmware/— the original Sprinter port for this board. The bestsource for UDPHS USB (
at91lib/usb/), HSMCI SD (at91lib/memories/sdmmc/),and the stock machine defaults (
src/init_configuration.h).reup/— the board's EAGLE schematic and pinmap. The expansion headertables in
pins_4PI.hwere traced fromuntitled.sch.Configurations
4pi example configuration.zip
Related Issues