mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-27 06:51:04 +08:00
SAME54 Ethernet driver
This commit is contained in:
parent
3a06b4833c
commit
b5213c13dd
56
examples/microchip/same54/Makefile
Normal file
56
examples/microchip/same54/Makefile
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
|
||||||
|
CFLAGS += -Wformat-truncation -fno-common -Wconversion
|
||||||
|
CFLAGS += -g -O2 -ffunction-sections -fdata-sections
|
||||||
|
CFLAGS += -I. -Icmsis_core/CMSIS/Core/Include
|
||||||
|
CFLAGS += -D__SAME54P20A__ -Icmsis_sam/include #-Icmsis_sam/xc32/include
|
||||||
|
#CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
||||||
|
CFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp -mfpu=fpv4-sp-d16
|
||||||
|
LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||||
|
|
||||||
|
SOURCES = main.c syscalls.c startup.c
|
||||||
|
#SOURCES += cmsis_sam/xc32/ATSAME54P20A/startup_atsame54p20a.c
|
||||||
|
|
||||||
|
SOURCES += mongoose.c net.c packed_fs.c
|
||||||
|
CFLAGS += -DMG_ENABLE_TCPIP=1 -DMG_ARCH=MG_ARCH_NEWLIB -DMG_ENABLE_CUSTOM_MILLIS=1
|
||||||
|
CFLAGS += -DMG_ENABLE_DRIVER_SAME54=1 -DMG_ENABLE_CUSTOM_RANDOM=1 -DMG_ENABLE_PACKED_FS=1 $(CFLAGS_EXTRA)
|
||||||
|
|
||||||
|
VCON_API_KEY=IBrJL5K4arSGMiAXbUKWdG6I2gM
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RM = cmd /C del /Q /F
|
||||||
|
else
|
||||||
|
RM = rm -rf
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: firmware.bin
|
||||||
|
|
||||||
|
firmware.elf: cmsis_core cmsis_sam hal.h link.ld Makefile $(SOURCES)
|
||||||
|
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
firmware.bin: firmware.elf
|
||||||
|
arm-none-eabi-objcopy -O binary $< $@
|
||||||
|
|
||||||
|
flash: firmware.bin
|
||||||
|
bossac -p /dev/cu.usb* -w -v -b $<
|
||||||
|
|
||||||
|
cmsis_core:
|
||||||
|
git clone --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
|
||||||
|
|
||||||
|
cmsis_sam:
|
||||||
|
curl -sL https://packs.download.microchip.com/Microchip.SAME54_DFP.3.8.234.pack -o $@.zip
|
||||||
|
mkdir $@ && cd $@ && unzip ../$@.zip
|
||||||
|
# git clone --depth 1 -b master https://github.com/modm-io/cmsis-header-sam $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) firmware.* cmsis_* *.zip
|
||||||
|
|
||||||
|
# Automated test via https://vcon.io/automated-firmware-tests/. Set VCON_API_KEY and update DEVICE_URL
|
||||||
|
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/9
|
||||||
|
fota: CFLAGS += -DUART_DEBUG=USART1
|
||||||
|
fota: firmware.bin
|
||||||
|
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota --data-binary @$<
|
||||||
|
test: fota
|
||||||
|
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
|
||||||
|
egrep '^tick:.*CPU 180 MHz' /tmp/output.txt
|
||||||
|
watch: fota
|
||||||
|
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=999
|
178
examples/microchip/same54/hal.h
Normal file
178
examples/microchip/same54/hal.h
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/DataSheets/SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf
|
||||||
|
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
|
||||||
|
|
||||||
|
#ifndef LED_PIN
|
||||||
|
#define LED_PIN PIN('C', 18)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BUTTON_PIN
|
||||||
|
#define BUTTON_PIN PIN('B', 31)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UART_DEBUG
|
||||||
|
#define UART_DEBUG USART1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <sam.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define BIT(x) (1UL << (x))
|
||||||
|
#define SETBITS(R, CLEARMASK, SETMASK) (R) = ((R) & ~(CLEARMASK)) | (SETMASK)
|
||||||
|
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
|
||||||
|
#define PINNO(pin) (pin & 255)
|
||||||
|
#define PINBANK(pin) (pin >> 8)
|
||||||
|
|
||||||
|
static inline void spin(volatile uint32_t count) {
|
||||||
|
while (count--) (void) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t clock_sys_freq(void) {
|
||||||
|
return 48000000U;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
|
||||||
|
enum { GPIO_OTYPE_PUSH_PULL, GPIO_OTYPE_OPEN_DRAIN };
|
||||||
|
enum { GPIO_SPEED_LOW, GPIO_SPEED_MEDIUM, GPIO_SPEED_HIGH, GPIO_SPEED_INSANE };
|
||||||
|
enum { GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN };
|
||||||
|
#define GPIO(N) ((port_group_registers_t *) (PORT_BASE_ADDRESS + 0x80 * (N)))
|
||||||
|
typedef port_group_registers_t GPIO_TypeDef;
|
||||||
|
static inline GPIO_TypeDef *gpio_bank(uint16_t pin) {
|
||||||
|
return GPIO(PINBANK(pin));
|
||||||
|
}
|
||||||
|
static inline void gpio_toggle(uint16_t pin) {
|
||||||
|
gpio_bank(pin)->PORT_OUTTGL = BIT(PINNO(pin));
|
||||||
|
}
|
||||||
|
static inline bool gpio_read(uint16_t pin) {
|
||||||
|
return gpio_bank(pin)->PORT_IN & BIT(PINNO(pin));
|
||||||
|
}
|
||||||
|
static inline void gpio_write(uint16_t pin, bool val) {
|
||||||
|
GPIO_TypeDef *gpio = gpio_bank(pin);
|
||||||
|
if (val) {
|
||||||
|
gpio->PORT_OUTSET = BIT(PINNO(pin));
|
||||||
|
} else {
|
||||||
|
gpio->PORT_OUTCLR = BIT(PINNO(pin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
||||||
|
uint8_t speed, uint8_t pull, uint8_t af) {
|
||||||
|
(void) type, (void) speed, (void) pull, (void) af;
|
||||||
|
GPIO_TypeDef *gpio = gpio_bank(pin);
|
||||||
|
uint32_t mask = BIT(PINNO(pin));
|
||||||
|
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk;
|
||||||
|
if (mode == GPIO_MODE_INPUT) {
|
||||||
|
gpio->PORT_DIRCLR = mask;
|
||||||
|
} else {
|
||||||
|
gpio->PORT_DIRSET = mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void gpio_input(uint16_t pin) {
|
||||||
|
gpio_init(pin, GPIO_MODE_INPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
|
||||||
|
GPIO_PULL_NONE, 0);
|
||||||
|
}
|
||||||
|
static inline void gpio_output(uint16_t pin) {
|
||||||
|
gpio_init(pin, GPIO_MODE_OUTPUT, GPIO_OTYPE_PUSH_PULL, GPIO_SPEED_HIGH,
|
||||||
|
GPIO_PULL_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef sercom_usart_int_registers_t USART_TypeDef;
|
||||||
|
#define USART1 ((USART_TypeDef *) SERCOM0_BASE_ADDRESS)
|
||||||
|
#define USART2 ((USART_TypeDef *) SERCOM1_BASE_ADDRESS)
|
||||||
|
#define USART3 ((USART_TypeDef *) SERCOM2_BASE_ADDRESS)
|
||||||
|
static inline bool uart_init(USART_TypeDef *uart, unsigned long baud) {
|
||||||
|
uint16_t rx = 0, tx = 0; // Pins
|
||||||
|
uint8_t rx_mux = 0, tx_mux = 0;
|
||||||
|
if (uart == USART1) {
|
||||||
|
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM0_Msk;
|
||||||
|
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_CORE] =
|
||||||
|
GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN_Msk;
|
||||||
|
GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_SLOW] =
|
||||||
|
GCLK_PCHCTRL_GEN_GCLK3 | GCLK_PCHCTRL_CHEN_Msk;
|
||||||
|
tx = PIN('A', 4), rx = PIN('A', 5);
|
||||||
|
rx_mux = MUX_PA05D_SERCOM0_PAD1, tx_mux = MUX_PA04D_SERCOM0_PAD0;
|
||||||
|
} else if (uart == USART2) {
|
||||||
|
MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM1_Msk;
|
||||||
|
tx = PIN('C', 27), rx = PIN('C', 28);
|
||||||
|
} else if (uart == USART3) {
|
||||||
|
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_SERCOM2_Msk;
|
||||||
|
tx = PIN('A', 9), rx = PIN('A', 8);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gpio_bank(rx)->PORT_WRCONFIG =
|
||||||
|
PORT_WRCONFIG_PMUX(rx_mux) | PORT_WRCONFIG_WRPMUX(1) |
|
||||||
|
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(rx));
|
||||||
|
gpio_bank(tx)->PORT_WRCONFIG =
|
||||||
|
PORT_WRCONFIG_PMUX(tx_mux) | PORT_WRCONFIG_WRPMUX(1) |
|
||||||
|
PORT_WRCONFIG_PMUXEN(1) | PORT_WRCONFIG_WRPINCFG(1) | BIT(PINNO(tx));
|
||||||
|
uart->SERCOM_CTRLA = SERCOM_USART_INT_CTRLA_DORD(1) |
|
||||||
|
SERCOM_USART_INT_CTRLA_MODE(1 /* INT_CLK */) |
|
||||||
|
SERCOM_USART_INT_CTRLA_RXPO(1 /* PAD1 */) |
|
||||||
|
SERCOM_USART_INT_CTRLA_TXPO(0 /* PAD0 */) |
|
||||||
|
SERCOM_USART_INT_CTRLA_SAMPR(1);
|
||||||
|
uart->SERCOM_BAUD = (uint16_t) (clock_sys_freq() / (16 * baud));
|
||||||
|
uart->SERCOM_CTRLB = SERCOM_USART_INT_CTRLB_RXEN(1) |
|
||||||
|
SERCOM_USART_INT_CTRLB_TXEN(1) |
|
||||||
|
SERCOM_USART_INT_CTRLB_CHSIZE(0);
|
||||||
|
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_CTRLB_Msk) spin(1);
|
||||||
|
uart->SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_ENABLE(1);
|
||||||
|
while (uart->SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_ENABLE_Msk) spin(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static inline void uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
|
||||||
|
while (!(uart->SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_DRE_Msk)) spin(1);
|
||||||
|
uart->SERCOM_DATA = byte;
|
||||||
|
}
|
||||||
|
static inline void uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
|
||||||
|
while (len-- > 0) uart_write_byte(uart, *(uint8_t *) buf++);
|
||||||
|
}
|
||||||
|
static inline bool uart_read_ready(USART_TypeDef *uart) {
|
||||||
|
return (uart->SERCOM_INTFLAG & SERCOM_USART_EXT_INTFLAG_RXC_Msk);
|
||||||
|
}
|
||||||
|
static inline uint8_t uart_read_byte(USART_TypeDef *uart) {
|
||||||
|
return (uint8_t) (uart->SERCOM_DATA & 255U);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rng_init(void) {
|
||||||
|
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_TRNG_Msk;
|
||||||
|
TRNG_REGS->TRNG_CTRLA = TRNG_CTRLA_ENABLE_Msk;
|
||||||
|
}
|
||||||
|
static inline uint32_t rng_read(void) {
|
||||||
|
while ((TRNG_REGS->TRNG_INTFLAG & TRNG_INTFLAG_DATARDY_Msk) == 0) spin(1);
|
||||||
|
return TRNG_REGS->TRNG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UUID ((uint8_t *) UID_BASE) // Unique 96-bit chip ID. TRM 39.1
|
||||||
|
|
||||||
|
// Helper macro for MAC generation
|
||||||
|
#define GENERATE_LOCALLY_ADMINISTERED_MAC() \
|
||||||
|
{ \
|
||||||
|
2, UUID[0] ^ UUID[1], UUID[2] ^ UUID[3], UUID[4] ^ UUID[5], \
|
||||||
|
UUID[6] ^ UUID[7] ^ UUID[8], UUID[9] ^ UUID[10] ^ UUID[11] \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool timer_expired(volatile uint64_t *t, uint64_t prd,
|
||||||
|
uint64_t now) {
|
||||||
|
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
|
||||||
|
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
|
||||||
|
if (*t > now) return false; // Not expired yet, return
|
||||||
|
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
|
||||||
|
return true; // Expired, return true
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clock_init(void) {
|
||||||
|
SCB->CPACR |= (15U << 20); // Enable FPU
|
||||||
|
SysTick_Config(clock_sys_freq() / 1000); // Sys tick every 1ms
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_set_irq_handler(uint16_t pin, void (*fn)(void *),
|
||||||
|
void *arg) {
|
||||||
|
(void) pin, (void) fn, (void) arg;
|
||||||
|
}
|
25
examples/microchip/same54/link.ld
Normal file
25
examples/microchip/same54/link.ld
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
ENTRY(Reset_Handler);
|
||||||
|
MEMORY {
|
||||||
|
flash(rx) : ORIGIN = 0x00000000, LENGTH = 1024k
|
||||||
|
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
|
||||||
|
}
|
||||||
|
_estack = ORIGIN(sram) + LENGTH(sram);
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
.vectors : { FILL(256) KEEP(*(.vectors)) } > flash
|
||||||
|
.text : { *(.text*) } > flash
|
||||||
|
.rodata : { *(.rodata*) } > flash
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
_sdata = .;
|
||||||
|
*(.first_data)
|
||||||
|
*(.data SORT(.data.*))
|
||||||
|
_edata = .;
|
||||||
|
} > sram AT > flash
|
||||||
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
|
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
|
||||||
|
|
||||||
|
. = ALIGN(8);
|
||||||
|
_end = .;
|
||||||
|
}
|
77
examples/microchip/same54/main.c
Normal file
77
examples/microchip/same54/main.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
#define BLINK_PERIOD_MS 500 // LED blinking period in millis
|
||||||
|
#define LOG_PERIOD_MS 1000 // Info log period in millis
|
||||||
|
|
||||||
|
void SystemInit(void) { // Called automatically by startup code
|
||||||
|
clock_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile uint64_t s_ticks; // Milliseconds since boot
|
||||||
|
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
|
||||||
|
s_ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t mg_millis(void) { // Let Mongoose use our uptime function
|
||||||
|
return s_ticks; // Return number of milliseconds since boot
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_random(void *buf, size_t len) { // Use on-board RNG
|
||||||
|
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
|
||||||
|
uint32_t r = rng_read();
|
||||||
|
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_fn(void *arg) {
|
||||||
|
struct mg_tcpip_if *ifp = arg; // show network stats
|
||||||
|
const char *names[] = {"down", "up", "req", "ready"};
|
||||||
|
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
|
||||||
|
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
||||||
|
ifp->ndrop, ifp->nerr));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
gpio_input(BUTTON_PIN);
|
||||||
|
gpio_output(LED_PIN);
|
||||||
|
uart_init(UART_DEBUG, 115200);
|
||||||
|
rng_init();
|
||||||
|
|
||||||
|
MG_INFO(("Starting, CPU freq %g MHz", (double) clock_sys_freq() / 1000000));
|
||||||
|
|
||||||
|
struct mg_mgr mgr; // Initialise
|
||||||
|
mg_mgr_init(&mgr); // Mongoose event manager
|
||||||
|
mg_log_set(MG_LL_DEBUG); // Set log level
|
||||||
|
|
||||||
|
// Initialise Mongoose network stack
|
||||||
|
struct mg_tcpip_driver_same54_data driver_data = {.mdc_cr = 4};
|
||||||
|
struct mg_tcpip_if mif = {.mac = {0x02, 0x14, 0x30, 0x00, 0x1a, 0x00},
|
||||||
|
// Uncomment below for static configuration:
|
||||||
|
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
|
||||||
|
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
|
||||||
|
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
|
||||||
|
.driver = &mg_tcpip_driver_same54,
|
||||||
|
.driver_data = &driver_data};
|
||||||
|
mg_tcpip_init(&mgr, &mif);
|
||||||
|
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
|
||||||
|
|
||||||
|
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
|
||||||
|
while (mif.state != MG_TCPIP_STATE_READY) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MG_INFO(("Initialising application..."));
|
||||||
|
web_init(&mgr);
|
||||||
|
|
||||||
|
MG_INFO(("Starting event loop"));
|
||||||
|
for (;;) {
|
||||||
|
mg_mgr_poll(&mgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
1
examples/microchip/same54/mongoose.c
Symbolic link
1
examples/microchip/same54/mongoose.c
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.c
|
1
examples/microchip/same54/mongoose.h
Symbolic link
1
examples/microchip/same54/mongoose.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../mongoose.h
|
1
examples/microchip/same54/net.c
Symbolic link
1
examples/microchip/same54/net.c
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../device-dashboard/net.c
|
1
examples/microchip/same54/net.h
Symbolic link
1
examples/microchip/same54/net.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../device-dashboard/net.h
|
1
examples/microchip/same54/packed_fs.c
Symbolic link
1
examples/microchip/same54/packed_fs.c
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../device-dashboard/packed_fs.c
|
332
examples/microchip/same54/startup.c
Normal file
332
examples/microchip/same54/startup.c
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022-2023 Cesanta Software Limited
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
void Reset_Handler(void); // Defined below
|
||||||
|
void Dummy_Handler(void); // Defined below
|
||||||
|
void SysTick_Handler(void); // Defined in main.c
|
||||||
|
void SystemInit(void); // Defined in main.c, called by reset handler
|
||||||
|
void _estack(void); // Defined in link.ld
|
||||||
|
|
||||||
|
#define WEAK_ALIAS __attribute__((weak, alias("Default_Handler")))
|
||||||
|
|
||||||
|
WEAK_ALIAS void NMI_Handler(void);
|
||||||
|
WEAK_ALIAS void HardFault_Handler(void);
|
||||||
|
WEAK_ALIAS void MemoryManagement_Handler(void);
|
||||||
|
WEAK_ALIAS void BusFault_Handler(void);
|
||||||
|
WEAK_ALIAS void UsageFault_Handler(void);
|
||||||
|
WEAK_ALIAS void SVCall_Handler(void);
|
||||||
|
WEAK_ALIAS void DebugMonitor_Handler(void);
|
||||||
|
WEAK_ALIAS void PendSV_Handler(void);
|
||||||
|
WEAK_ALIAS void SysTick_Handler(void);
|
||||||
|
|
||||||
|
WEAK_ALIAS void PM_Handler(void);
|
||||||
|
WEAK_ALIAS void MCLK_Handler(void);
|
||||||
|
WEAK_ALIAS void OSCCTRL_XOSC0_Handler(void);
|
||||||
|
WEAK_ALIAS void OSCCTRL_XOSC1_Handler(void);
|
||||||
|
WEAK_ALIAS void OSCCTRL_DFLL_Handler(void);
|
||||||
|
WEAK_ALIAS void OSCCTRL_DPLL0_Handler(void);
|
||||||
|
WEAK_ALIAS void OSCCTRL_DPLL1_Handler(void);
|
||||||
|
WEAK_ALIAS void OSC32KCTRL_Handler(void);
|
||||||
|
WEAK_ALIAS void SUPC_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SUPC_BODDET_Handler(void);
|
||||||
|
WEAK_ALIAS void WDT_Handler(void);
|
||||||
|
WEAK_ALIAS void RTC_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_0_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_1_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_2_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_3_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_4_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_5_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_6_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_7_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_8_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_9_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_10_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_11_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_12_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_13_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_14_Handler(void);
|
||||||
|
WEAK_ALIAS void EIC_EXTINT_15_Handler(void);
|
||||||
|
WEAK_ALIAS void FREQM_Handler(void);
|
||||||
|
WEAK_ALIAS void NVMCTRL_0_Handler(void);
|
||||||
|
WEAK_ALIAS void NVMCTRL_1_Handler(void);
|
||||||
|
WEAK_ALIAS void DMAC_0_Handler(void);
|
||||||
|
WEAK_ALIAS void DMAC_1_Handler(void);
|
||||||
|
WEAK_ALIAS void DMAC_2_Handler(void);
|
||||||
|
WEAK_ALIAS void DMAC_3_Handler(void);
|
||||||
|
WEAK_ALIAS void DMAC_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void EVSYS_0_Handler(void);
|
||||||
|
WEAK_ALIAS void EVSYS_1_Handler(void);
|
||||||
|
WEAK_ALIAS void EVSYS_2_Handler(void);
|
||||||
|
WEAK_ALIAS void EVSYS_3_Handler(void);
|
||||||
|
WEAK_ALIAS void EVSYS_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void PAC_Handler(void);
|
||||||
|
WEAK_ALIAS void RAMECC_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM0_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM0_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM0_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM0_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM1_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM1_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM1_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM1_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM2_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM2_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM2_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM2_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM3_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM3_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM3_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM3_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM4_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM4_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM4_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM4_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM5_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM5_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM5_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM5_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM6_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM6_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM6_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM6_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM7_0_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM7_1_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM7_2_Handler(void);
|
||||||
|
WEAK_ALIAS void SERCOM7_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void CAN0_Handler(void);
|
||||||
|
WEAK_ALIAS void CAN1_Handler(void);
|
||||||
|
WEAK_ALIAS void USB_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void USB_SOF_HSOF_Handler(void);
|
||||||
|
WEAK_ALIAS void USB_TRCPT0_Handler(void);
|
||||||
|
WEAK_ALIAS void USB_TRCPT1_Handler(void);
|
||||||
|
WEAK_ALIAS void GMAC_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC2_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC3_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC4_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC0_MC5_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC1_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC1_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC1_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC1_MC2_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC1_MC3_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC2_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC2_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC2_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC2_MC2_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC3_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC3_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC3_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC4_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC4_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TCC4_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TC0_Handler(void);
|
||||||
|
WEAK_ALIAS void TC1_Handler(void);
|
||||||
|
WEAK_ALIAS void TC2_Handler(void);
|
||||||
|
WEAK_ALIAS void TC3_Handler(void);
|
||||||
|
WEAK_ALIAS void TC4_Handler(void);
|
||||||
|
WEAK_ALIAS void TC5_Handler(void);
|
||||||
|
WEAK_ALIAS void TC6_Handler(void);
|
||||||
|
WEAK_ALIAS void TC7_Handler(void);
|
||||||
|
WEAK_ALIAS void PDEC_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void PDEC_MC0_Handler(void);
|
||||||
|
WEAK_ALIAS void PDEC_MC1_Handler(void);
|
||||||
|
WEAK_ALIAS void ADC0_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void ADC0_RESRDY_Handler(void);
|
||||||
|
WEAK_ALIAS void ADC1_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void ADC1_RESRDY_Handler(void);
|
||||||
|
WEAK_ALIAS void AC_Handler(void);
|
||||||
|
WEAK_ALIAS void DAC_OTHER_Handler(void);
|
||||||
|
WEAK_ALIAS void DAC_EMPTY_0_Handler(void);
|
||||||
|
WEAK_ALIAS void DAC_EMPTY_1_Handler(void);
|
||||||
|
WEAK_ALIAS void DAC_RESRDY_0_Handler(void);
|
||||||
|
WEAK_ALIAS void DAC_RESRDY_1_Handler(void);
|
||||||
|
WEAK_ALIAS void I2S_Handler(void);
|
||||||
|
WEAK_ALIAS void PCC_Handler(void);
|
||||||
|
WEAK_ALIAS void AES_Handler(void);
|
||||||
|
WEAK_ALIAS void TRNG_Handler(void);
|
||||||
|
WEAK_ALIAS void ICM_Handler(void);
|
||||||
|
WEAK_ALIAS void PUKCC_Handler(void);
|
||||||
|
WEAK_ALIAS void QSPI_Handler(void);
|
||||||
|
WEAK_ALIAS void SDHC0_Handler(void);
|
||||||
|
WEAK_ALIAS void SDHC1_Handler(void);
|
||||||
|
|
||||||
|
__attribute__((section(".vectors"))) void (*const tab[16 + 138])(void) = {
|
||||||
|
_estack,
|
||||||
|
Reset_Handler,
|
||||||
|
NMI_Handler,
|
||||||
|
HardFault_Handler,
|
||||||
|
MemoryManagement_Handler,
|
||||||
|
BusFault_Handler,
|
||||||
|
UsageFault_Handler,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
SVCall_Handler,
|
||||||
|
DebugMonitor_Handler,
|
||||||
|
NULL,
|
||||||
|
PendSV_Handler,
|
||||||
|
SysTick_Handler,
|
||||||
|
PM_Handler, // 0 Power
|
||||||
|
MCLK_Handler, // 1 Main
|
||||||
|
OSCCTRL_XOSC0_Handler, // 2 Oscillators
|
||||||
|
OSCCTRL_XOSC1_Handler, // 3 Oscillators
|
||||||
|
OSCCTRL_DFLL_Handler, // 4 Oscillators
|
||||||
|
OSCCTRL_DPLL0_Handler, // 5 Oscillators
|
||||||
|
OSCCTRL_DPLL1_Handler, // 6 Oscillators
|
||||||
|
OSC32KCTRL_Handler, // 7 32kHz
|
||||||
|
SUPC_OTHER_Handler, // 8 Supply
|
||||||
|
SUPC_BODDET_Handler, // 9 Supply
|
||||||
|
WDT_Handler, // 10 Watchdog
|
||||||
|
RTC_Handler, // 11 Real-Time
|
||||||
|
EIC_EXTINT_0_Handler, // 12 External
|
||||||
|
EIC_EXTINT_1_Handler, // 13 External
|
||||||
|
EIC_EXTINT_2_Handler, // 14 External
|
||||||
|
EIC_EXTINT_3_Handler, // 15 External
|
||||||
|
EIC_EXTINT_4_Handler, // 16 External
|
||||||
|
EIC_EXTINT_5_Handler, // 17 External
|
||||||
|
EIC_EXTINT_6_Handler, // 18 External
|
||||||
|
EIC_EXTINT_7_Handler, // 19 External
|
||||||
|
EIC_EXTINT_8_Handler, // 20 External
|
||||||
|
EIC_EXTINT_9_Handler, // 21 External
|
||||||
|
EIC_EXTINT_10_Handler, // 22 External
|
||||||
|
EIC_EXTINT_11_Handler, // 23 External
|
||||||
|
EIC_EXTINT_12_Handler, // 24 External
|
||||||
|
EIC_EXTINT_13_Handler, // 25 External
|
||||||
|
EIC_EXTINT_14_Handler, // 26 External
|
||||||
|
EIC_EXTINT_15_Handler, // 27 External
|
||||||
|
FREQM_Handler, // 28 Frequency
|
||||||
|
NVMCTRL_0_Handler, // 29 Non-Volatile
|
||||||
|
NVMCTRL_1_Handler, // 30 Non-Volatile
|
||||||
|
DMAC_0_Handler, // 31 Direct
|
||||||
|
DMAC_1_Handler, // 32 Direct
|
||||||
|
DMAC_2_Handler, // 33 Direct
|
||||||
|
DMAC_3_Handler, // 34 Direct
|
||||||
|
DMAC_OTHER_Handler, // 35 Direct
|
||||||
|
EVSYS_0_Handler, // 36 Event
|
||||||
|
EVSYS_1_Handler, // 37 Event
|
||||||
|
EVSYS_2_Handler, // 38 Event
|
||||||
|
EVSYS_3_Handler, // 39 Event
|
||||||
|
EVSYS_OTHER_Handler, // 40 Event
|
||||||
|
PAC_Handler, // 41 Peripheral
|
||||||
|
0, // 42 Reserved
|
||||||
|
0, // 43 Reserved
|
||||||
|
0, // 44 Reserved
|
||||||
|
RAMECC_Handler, // 45 RAM
|
||||||
|
SERCOM0_0_Handler, // 46 Serial
|
||||||
|
SERCOM0_1_Handler, // 47 Serial
|
||||||
|
SERCOM0_2_Handler, // 48 Serial
|
||||||
|
SERCOM0_OTHER_Handler, // 49 Serial
|
||||||
|
SERCOM1_0_Handler, // 50 Serial
|
||||||
|
SERCOM1_1_Handler, // 51 Serial
|
||||||
|
SERCOM1_2_Handler, // 52 Serial
|
||||||
|
SERCOM1_OTHER_Handler, // 53 Serial
|
||||||
|
SERCOM2_0_Handler, // 54 Serial
|
||||||
|
SERCOM2_1_Handler, // 55 Serial
|
||||||
|
SERCOM2_2_Handler, // 56 Serial
|
||||||
|
SERCOM2_OTHER_Handler, // 57 Serial
|
||||||
|
SERCOM3_0_Handler, // 58 Serial
|
||||||
|
SERCOM3_1_Handler, // 59 Serial
|
||||||
|
SERCOM3_2_Handler, // 60 Serial
|
||||||
|
SERCOM3_OTHER_Handler, // 61 Serial
|
||||||
|
SERCOM4_0_Handler, // 62 Serial
|
||||||
|
SERCOM4_1_Handler, // 63 Serial
|
||||||
|
SERCOM4_2_Handler, // 64 Serial
|
||||||
|
SERCOM4_OTHER_Handler, // 65 Serial
|
||||||
|
SERCOM5_0_Handler, // 66 Serial
|
||||||
|
SERCOM5_1_Handler, // 67 Serial
|
||||||
|
SERCOM5_2_Handler, // 68 Serial
|
||||||
|
SERCOM5_OTHER_Handler, // 69 Serial
|
||||||
|
SERCOM6_0_Handler, // 70 Serial
|
||||||
|
SERCOM6_1_Handler, // 71 Serial
|
||||||
|
SERCOM6_2_Handler, // 72 Serial
|
||||||
|
SERCOM6_OTHER_Handler, // 73 Serial
|
||||||
|
SERCOM7_0_Handler, // 74 Serial
|
||||||
|
SERCOM7_1_Handler, // 75 Serial
|
||||||
|
SERCOM7_2_Handler, // 76 Serial
|
||||||
|
SERCOM7_OTHER_Handler, // 77 Serial
|
||||||
|
CAN0_Handler, // 78 Control
|
||||||
|
CAN1_Handler, // 79 Control
|
||||||
|
USB_OTHER_Handler, // 80 Universal
|
||||||
|
USB_SOF_HSOF_Handler, // 81 Universal
|
||||||
|
USB_TRCPT0_Handler, // 82 Universal
|
||||||
|
USB_TRCPT1_Handler, // 83 Universal
|
||||||
|
GMAC_Handler, // 84 Ethernet
|
||||||
|
TCC0_OTHER_Handler, // 85 Timer
|
||||||
|
TCC0_MC0_Handler, // 86 Timer
|
||||||
|
TCC0_MC1_Handler, // 87 Timer
|
||||||
|
TCC0_MC2_Handler, // 88 Timer
|
||||||
|
TCC0_MC3_Handler, // 89 Timer
|
||||||
|
TCC0_MC4_Handler, // 90 Timer
|
||||||
|
TCC0_MC5_Handler, // 91 Timer
|
||||||
|
TCC1_OTHER_Handler, // 92 Timer
|
||||||
|
TCC1_MC0_Handler, // 93 Timer
|
||||||
|
TCC1_MC1_Handler, // 94 Timer
|
||||||
|
TCC1_MC2_Handler, // 95 Timer
|
||||||
|
TCC1_MC3_Handler, // 96 Timer
|
||||||
|
TCC2_OTHER_Handler, // 97 Timer
|
||||||
|
TCC2_MC0_Handler, // 98 Timer
|
||||||
|
TCC2_MC1_Handler, // 99 Timer
|
||||||
|
TCC2_MC2_Handler, // 100 Timer
|
||||||
|
TCC3_OTHER_Handler, // 101 Timer
|
||||||
|
TCC3_MC0_Handler, // 102 Timer
|
||||||
|
TCC3_MC1_Handler, // 103 Timer
|
||||||
|
TCC4_OTHER_Handler, // 104 Timer
|
||||||
|
TCC4_MC0_Handler, // 105 Timer
|
||||||
|
TCC4_MC1_Handler, // 106 Timer
|
||||||
|
TC0_Handler, // 107 Basic
|
||||||
|
TC1_Handler, // 108 Basic
|
||||||
|
TC2_Handler, // 109 Basic
|
||||||
|
TC3_Handler, // 110 Basic
|
||||||
|
TC4_Handler, // 111 Basic
|
||||||
|
TC5_Handler, // 112 Basic
|
||||||
|
TC6_Handler, // 113 Basic
|
||||||
|
TC7_Handler, // 114 Basic
|
||||||
|
PDEC_OTHER_Handler, // 115 Quadrature
|
||||||
|
PDEC_MC0_Handler, // 116 Quadrature
|
||||||
|
PDEC_MC1_Handler, // 117 Quadrature
|
||||||
|
ADC0_OTHER_Handler, // 118 Analog
|
||||||
|
ADC0_RESRDY_Handler, // 119 Analog
|
||||||
|
ADC1_OTHER_Handler, // 120 Analog
|
||||||
|
ADC1_RESRDY_Handler, // 121 Analog
|
||||||
|
AC_Handler, // 122 Analog
|
||||||
|
DAC_OTHER_Handler, // 123 Digital-to-Analog
|
||||||
|
DAC_EMPTY_0_Handler, // 124 Digital-to-Analog
|
||||||
|
DAC_EMPTY_1_Handler, // 125 Digital-to-Analog
|
||||||
|
DAC_RESRDY_0_Handler, // 126 Digital-to-Analog
|
||||||
|
DAC_RESRDY_1_Handler, // 127 Digital-to-Analog
|
||||||
|
I2S_Handler, // 128 Inter-IC
|
||||||
|
PCC_Handler, // 129 Parallel
|
||||||
|
AES_Handler, // 130 Advanced
|
||||||
|
TRNG_Handler, // 131 True
|
||||||
|
ICM_Handler, // 132 Integrity
|
||||||
|
PUKCC_Handler, // 133 PUblic-Key
|
||||||
|
QSPI_Handler, // 134 Quad
|
||||||
|
SDHC0_Handler, // 135 SD/MMC
|
||||||
|
SDHC1_Handler // 136 SD/MMC
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((naked, noreturn)) void Reset_Handler(void) {
|
||||||
|
// Clear BSS section, and copy data section from flash to RAM
|
||||||
|
extern long _sbss, _ebss, _sdata, _edata, _sidata;
|
||||||
|
for (long *src = &_sbss; src < &_ebss; src++) *src = 0;
|
||||||
|
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
|
||||||
|
|
||||||
|
SCB->VTOR = (uint32_t) &tab;
|
||||||
|
SystemInit();
|
||||||
|
|
||||||
|
// Call main()
|
||||||
|
extern void main(void);
|
||||||
|
main();
|
||||||
|
for (;;) (void) 0; // Infinite loop
|
||||||
|
}
|
||||||
|
|
||||||
|
void Default_Handler(void) {
|
||||||
|
for (;;) (void) 0;
|
||||||
|
}
|
89
examples/microchip/same54/syscalls.c
Normal file
89
examples/microchip/same54/syscalls.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2022 Cesanta Software Limited
|
||||||
|
// All rights reserved
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
int _fstat(int fd, struct stat *st) {
|
||||||
|
if (fd < 0) return -1;
|
||||||
|
st->st_mode = S_IFCHR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *_sbrk(int incr) {
|
||||||
|
extern char _end;
|
||||||
|
static unsigned char *heap = NULL;
|
||||||
|
unsigned char *prev_heap;
|
||||||
|
if (heap == NULL) heap = (unsigned char *) &_end;
|
||||||
|
prev_heap = heap;
|
||||||
|
heap += incr;
|
||||||
|
return prev_heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _open(const char *path) {
|
||||||
|
(void) path;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _close(int fd) {
|
||||||
|
(void) fd;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _isatty(int fd) {
|
||||||
|
(void) fd;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _lseek(int fd, int ptr, int dir) {
|
||||||
|
(void) fd, (void) ptr, (void) dir;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _exit(int status) {
|
||||||
|
(void) status;
|
||||||
|
for (;;) asm volatile("BKPT #0");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _kill(int pid, int sig) {
|
||||||
|
(void) pid, (void) sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _getpid(void) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _write(int fd, char *ptr, int len) {
|
||||||
|
(void) fd, (void) ptr, (void) len;
|
||||||
|
if (fd == 1) uart_write_buf(UART_DEBUG, ptr, (size_t) len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _read(int fd, char *ptr, int len) {
|
||||||
|
(void) fd, (void) ptr, (void) len;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _link(const char *a, const char *b) {
|
||||||
|
(void) a, (void) b;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _unlink(const char *a) {
|
||||||
|
(void) a;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _stat(const char *path, struct stat *st) {
|
||||||
|
(void) path, (void) st;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mkdir(const char *path, mode_t mode) {
|
||||||
|
(void) path, (void) mode;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _init(void) {
|
||||||
|
}
|
286
mongoose.c
286
mongoose.c
@ -6858,6 +6858,292 @@ struct mg_tcpip_driver mg_tcpip_driver_imxrt1020 = {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MG_ENABLE_LINES
|
||||||
|
#line 1 "src/tcpip/driver_same54.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
|
||||||
|
|
||||||
|
#undef BIT
|
||||||
|
#define BIT(x) ((uint32_t) 1 << (x))
|
||||||
|
#define ETH_PKT_SIZE 1536 // Max frame size
|
||||||
|
#define GMAC_DESC_CNT 4 // Descriptors count
|
||||||
|
#define GMAC_DS 2 // Descriptor size (words)
|
||||||
|
|
||||||
|
static uint8_t s_rxbuf[GMAC_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
||||||
|
static uint8_t s_txbuf[GMAC_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
||||||
|
static uint32_t s_rxdesc[GMAC_DESC_CNT][GMAC_DS]; // RX descriptors
|
||||||
|
static uint32_t s_txdesc[GMAC_DESC_CNT][GMAC_DS]; // TX descriptors
|
||||||
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
|
|
||||||
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
|
enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1};
|
||||||
|
|
||||||
|
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||||
|
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(2) | // Setting the read operation
|
||||||
|
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
|
||||||
|
GMAC_MAN_REGA(reg); // Setting the register
|
||||||
|
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the read op is complete
|
||||||
|
return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||||
|
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation
|
||||||
|
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
|
||||||
|
GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register
|
||||||
|
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
|
||||||
|
struct mg_tcpip_driver_same54_data *d =
|
||||||
|
(struct mg_tcpip_driver_same54_data *) ifp->driver_data;
|
||||||
|
s_ifp = ifp;
|
||||||
|
|
||||||
|
// enabling GMAC bus clocks
|
||||||
|
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC(1);
|
||||||
|
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC(1);
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCR &= ~GMAC_NCR_RXEN_Msk; // Disable receive circuit
|
||||||
|
GMAC_REGS->GMAC_NCR &= ~GMAC_NCR_TXEN_Msk; // Disable transmit circuit
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_TXPBMS(1);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_RXBMS(2);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_FBLDO(4);
|
||||||
|
|
||||||
|
// Init RX descriptors
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
s_rxdesc[i][0] = ((uint32_t) s_rxbuf[i]) & 0xfffffffc; // Point to data buffer (bits [31:2])
|
||||||
|
s_rxdesc[i][1] = 0;
|
||||||
|
}
|
||||||
|
s_rxdesc[GMAC_DESC_CNT - 1][0] |= BIT(1); // Marking last rx descriptor
|
||||||
|
|
||||||
|
// Init TX descriptors
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer
|
||||||
|
s_txdesc[i][1] = BIT(31); // Setting the OWN bit
|
||||||
|
}
|
||||||
|
s_txdesc[GMAC_DESC_CNT - 1][1] |= BIT(30); // Marking last tx descriptor
|
||||||
|
|
||||||
|
// let the controller know about the descriptor addresses
|
||||||
|
GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc;
|
||||||
|
GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc;
|
||||||
|
|
||||||
|
// GPIO pin configuration
|
||||||
|
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk; // //enable bus clock for PORT
|
||||||
|
uint16_t pins[] = {PIN('A', 12), PIN('A', 13), PIN('A', 14), PIN('A', 15),
|
||||||
|
PIN('A', 17), PIN('A', 18), PIN('A', 19),
|
||||||
|
PIN('C', 11), PIN('C', 12), PIN('C', 20)};
|
||||||
|
|
||||||
|
uint32_t pin_fns[] = {
|
||||||
|
MUX_PA12L_GMAC_GRX1, MUX_PA13L_GMAC_GRX0, MUX_PA14L_GMAC_GTXCK,
|
||||||
|
MUX_PA15L_GMAC_GRXER, MUX_PA17L_GMAC_GTXEN, MUX_PA18L_GMAC_GTX0,
|
||||||
|
MUX_PA19L_GMAC_GTX1, MUX_PC11L_GMAC_GMDC, MUX_PC12L_GMAC_GMDIO,
|
||||||
|
MUX_PC20L_GMAC_GRXDV
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sizeof(pins) / sizeof(uint16_t); i++) {
|
||||||
|
uint8_t group = (uint8_t) (pins[i] >> 8);
|
||||||
|
uint8_t pin_no = (uint8_t) pins[i];
|
||||||
|
PORT_REGS->GROUP[group].PORT_PINCFG[pin_no] |= PORT_PINCFG_PMUXEN_Msk;
|
||||||
|
if (pin_no % 2)
|
||||||
|
PORT_REGS->GROUP[group].PORT_PMUX[pin_no / 2] |= (uint8_t) PORT_PMUX_PMUXO(pin_fns[i]);
|
||||||
|
else
|
||||||
|
PORT_REGS->GROUP[group].PORT_PMUX[pin_no / 2] |= (uint8_t) PORT_PMUX_PMUXE(pin_fns[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[17] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[18] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[19] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // RMII operation mode
|
||||||
|
|
||||||
|
// Resetting the PHY
|
||||||
|
/*uint64_t start = mg_millis(), now = start;
|
||||||
|
PORT_REGS->GROUP[2].PORT_DIRSET = PORT_PC21;
|
||||||
|
PORT_REGS->GROUP[2].PORT_OUTCLR = PORT_PC21;
|
||||||
|
for (; now - start < 10000; now = mg_millis());
|
||||||
|
PORT_REGS->GROUP[2].PORT_OUTSET = PORT_PC21;
|
||||||
|
for (start = mg_millis(), now = start; now - start < 10000; now = mg_millis());*/
|
||||||
|
|
||||||
|
// Clock advanced configuration
|
||||||
|
#if 0
|
||||||
|
uint8_t mdc_clk_div = 5;
|
||||||
|
|
||||||
|
// get MCLK from GCLK_GENERATOR 0
|
||||||
|
uint32_t div = 512;
|
||||||
|
uint32_t mclk;
|
||||||
|
if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk))
|
||||||
|
div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16);
|
||||||
|
switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) {
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC0_Val:
|
||||||
|
mclk = 32000000UL; /* 32MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC1_Val:
|
||||||
|
mclk = 32000000UL; /* 32MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_OSCULP32K_Val:
|
||||||
|
mclk = 32000UL;
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC32K_Val:
|
||||||
|
mclk = 32000UL;
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DFLL_Val:
|
||||||
|
mclk = 48000000UL; /* 48MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DPLL0_Val:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DPLL1_Val:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
}
|
||||||
|
|
||||||
|
mclk /= div;
|
||||||
|
|
||||||
|
uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values
|
||||||
|
uint8_t dividers[] = {8, 16, 32, 48, 64, 128}; // Respective CLK dividers
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) {
|
||||||
|
mdc_clk_div = crs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(5); // set the MDC clock
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; //enable management port
|
||||||
|
|
||||||
|
// configure MAC
|
||||||
|
GMAC_REGS->SA[0].GMAC_SAT = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
|
||||||
|
GMAC_REGS->SA[0].GMAC_SAB = (uint32_t) (ifp->mac[3] << 24) |
|
||||||
|
((uint32_t) ifp->mac[2] << 16) |
|
||||||
|
((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
|
||||||
|
|
||||||
|
//Configure the receive filter
|
||||||
|
GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk;
|
||||||
|
|
||||||
|
//GMAC_REGS->GMAC_IER = GMAC_IER_RCOMP(1); // Enable the receive interrupt
|
||||||
|
GMAC_REGS->GMAC_IER = 0x3ffcfcff; // Enabling all interrupts
|
||||||
|
NVIC_EnableIRQ(GMAC_IRQn);
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk; // Enable transmit circuit
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_RXEN_Msk ; // Enable receive circuit
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp) {
|
||||||
|
//MG_INFO(("DMAC_CTRL: 0x%x", DMAC_REGS->DMAC_CTRL));
|
||||||
|
MG_INFO(("GMAC_TSR: 0x%x", GMAC_REGS->GMAC_TSR));
|
||||||
|
GMAC_REGS->GMAC_TSR |= 0x21;
|
||||||
|
uint32_t rsr = GMAC_REGS->GMAC_RSR;
|
||||||
|
MG_INFO(("GMAC_RSR: 0x%x", rsr));
|
||||||
|
GMAC_REGS->GMAC_RSR = rsr;
|
||||||
|
if (len > sizeof(s_txbuf[s_txno])) {
|
||||||
|
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||||
|
len = 0; // Frame is too big
|
||||||
|
} else if (!(s_txdesc[s_txno][1] & BIT(31))) {
|
||||||
|
ifp->nerr++;
|
||||||
|
MG_ERROR(("No free descriptors"));
|
||||||
|
len = 0; // All descriptors are busy, fail
|
||||||
|
} else {
|
||||||
|
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||||
|
if (++s_txno >= GMAC_DESC_CNT) {
|
||||||
|
s_txdesc[GMAC_DESC_CNT - 1][1] = (len & (BIT(14) - 1)) | BIT(15)| BIT(30);
|
||||||
|
s_txno = 0;
|
||||||
|
MG_INFO(("s_tx_no: %d, tx_desc.status: 0x%x", GMAC_DESC_CNT - 1, s_txdesc[GMAC_DESC_CNT - 1][1]));
|
||||||
|
} else {
|
||||||
|
s_txdesc[s_txno - 1][1] = (len & (BIT(14) - 1)) | BIT(15);
|
||||||
|
MG_INFO(("s_tx_no: %d, tx_desc.status: 0x%x", s_txno - 1, s_txdesc[s_txno - 1][1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__DSB(); // Ensure descriptors have been written
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_same54_up(struct mg_tcpip_if *ifp) {
|
||||||
|
uint16_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
|
||||||
|
//MG_INFO(("BSR: 0x%x", bsr));
|
||||||
|
bool up = bsr & BIT(2) ? 1 : 0;
|
||||||
|
(void) ifp;
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMAC_Handler(void);
|
||||||
|
void GMAC_Handler(void) {
|
||||||
|
MG_INFO(("Entering GMAC IRQ HANDLER"));
|
||||||
|
uint32_t isr = GMAC_REGS->GMAC_ISR;
|
||||||
|
MG_INFO(("isr: 0x%x", isr));
|
||||||
|
if (/*GMAC_REGS->GMAC_ISR*/ isr & GMAC_ISR_RCOMP_Msk) {
|
||||||
|
int frame_start = -1;
|
||||||
|
int frame_end = -1;
|
||||||
|
|
||||||
|
// find the start of the frame
|
||||||
|
for (int i = s_rxno; i < GMAC_DESC_CNT + s_rxno; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (!(s_rxdesc[desc_index][0] & 1)) break;
|
||||||
|
if (s_rxdesc[desc_index][1] & BIT(14))
|
||||||
|
frame_start = desc_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if frame start not found, then clear the own bit
|
||||||
|
if (frame_start == -1) {
|
||||||
|
for (int i = s_rxno; i < GMAC_DESC_CNT + s_rxno; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (!(s_rxdesc[desc_index][0] & 1)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the end of the frame
|
||||||
|
for (int i = frame_start; i < GMAC_DESC_CNT + frame_start; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (s_rxdesc[desc_index][1] & BIT(15))
|
||||||
|
frame_end = desc_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear all used buffers until you reach start of frame
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
int desc_index = (i + s_rxno) % GMAC_DESC_CNT;
|
||||||
|
if (s_rxno == frame_start) break;
|
||||||
|
if (++s_rxno >= GMAC_DESC_CNT) s_rxno = 0;
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0)); // Clearing the OWN bit
|
||||||
|
}
|
||||||
|
|
||||||
|
// from start of frame to end of frame you copy into queue
|
||||||
|
size_t offset = 0, len;
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
int desc_index = (i + s_rxno) % GMAC_DESC_CNT;
|
||||||
|
if (desc_index == frame_start)
|
||||||
|
offset = (GMAC_REGS->GMAC_NCFGR & GMAC_NCFGR_RXBUFO_Msk) >> GMAC_NCFGR_RXBUFO_Pos;
|
||||||
|
else
|
||||||
|
offset = 0;
|
||||||
|
len = s_rxdesc[s_rxno][1] & (BIT(13) - 1);
|
||||||
|
mg_tcpip_qwrite(s_rxbuf[s_rxno] + offset, len, s_ifp);
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0)); // Clearing the OWN bit
|
||||||
|
if (++s_rxno >= GMAC_DESC_CNT) s_rxno = 0;
|
||||||
|
if (desc_index == frame_end) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_tcpip_driver mg_tcpip_driver_same54 = {mg_tcpip_driver_same54_init,
|
||||||
|
mg_tcpip_driver_same54_tx, NULL,
|
||||||
|
mg_tcpip_driver_same54_up};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MG_ENABLE_LINES
|
#ifdef MG_ENABLE_LINES
|
||||||
#line 1 "src/tcpip/driver_stm32.c"
|
#line 1 "src/tcpip/driver_stm32.c"
|
||||||
#endif
|
#endif
|
||||||
|
12
mongoose.h
12
mongoose.h
@ -1696,6 +1696,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
|
|||||||
extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
|
extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
|
extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
|
extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_same54;
|
||||||
|
|
||||||
// Drivers that require SPI, can use this SPI abstraction
|
// Drivers that require SPI, can use this SPI abstraction
|
||||||
struct mg_tcpip_spi {
|
struct mg_tcpip_spi {
|
||||||
@ -1722,6 +1723,17 @@ struct mg_tcpip_driver_imxrt1020_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
|
||||||
|
|
||||||
|
#include "hal.h" // keep this include
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_same54_data {
|
||||||
|
int mdc_cr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct mg_tcpip_driver_stm32_data {
|
struct mg_tcpip_driver_stm32_data {
|
||||||
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
// MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz
|
||||||
// HCLK range DIVIDER mdc_cr VALUE
|
// HCLK range DIVIDER mdc_cr VALUE
|
||||||
|
282
src/tcpip/driver_same54.c
Normal file
282
src/tcpip/driver_same54.c
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#include "tcpip.h"
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
|
||||||
|
|
||||||
|
#undef BIT
|
||||||
|
#define BIT(x) ((uint32_t) 1 << (x))
|
||||||
|
#define ETH_PKT_SIZE 1536 // Max frame size
|
||||||
|
#define GMAC_DESC_CNT 4 // Descriptors count
|
||||||
|
#define GMAC_DS 2 // Descriptor size (words)
|
||||||
|
|
||||||
|
static uint8_t s_rxbuf[GMAC_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
||||||
|
static uint8_t s_txbuf[GMAC_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
||||||
|
static uint32_t s_rxdesc[GMAC_DESC_CNT][GMAC_DS]; // RX descriptors
|
||||||
|
static uint32_t s_txdesc[GMAC_DESC_CNT][GMAC_DS]; // TX descriptors
|
||||||
|
static uint8_t s_txno; // Current TX descriptor
|
||||||
|
static uint8_t s_rxno; // Current RX descriptor
|
||||||
|
|
||||||
|
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||||
|
enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1};
|
||||||
|
|
||||||
|
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||||
|
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(2) | // Setting the read operation
|
||||||
|
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
|
||||||
|
GMAC_MAN_REGA(reg); // Setting the register
|
||||||
|
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the read op is complete
|
||||||
|
return GMAC_REGS->GMAC_MAN & GMAC_MAN_DATA_Msk; // Getting the read value
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||||
|
GMAC_REGS->GMAC_MAN = GMAC_MAN_CLTTO_Msk | GMAC_MAN_OP(1) | // Setting the write operation
|
||||||
|
GMAC_MAN_WTN(2) | GMAC_MAN_PHYA(addr) | // PHY address
|
||||||
|
GMAC_MAN_REGA(reg) | GMAC_MAN_DATA(val); // Setting the register
|
||||||
|
while (!(GMAC_REGS->GMAC_NSR & GMAC_NSR_IDLE_Msk)); // Waiting until the write op is complete
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_same54_init(struct mg_tcpip_if *ifp) {
|
||||||
|
struct mg_tcpip_driver_same54_data *d =
|
||||||
|
(struct mg_tcpip_driver_same54_data *) ifp->driver_data;
|
||||||
|
s_ifp = ifp;
|
||||||
|
|
||||||
|
// enabling GMAC bus clocks
|
||||||
|
MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_GMAC(1);
|
||||||
|
MCLK_REGS->MCLK_APBCMASK |= MCLK_APBCMASK_GMAC(1);
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCR &= ~GMAC_NCR_RXEN_Msk; // Disable receive circuit
|
||||||
|
GMAC_REGS->GMAC_NCR &= ~GMAC_NCR_TXEN_Msk; // Disable transmit circuit
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_DCFGR = GMAC_DCFGR_DRBS(0x18);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_TXPBMS(1);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_RXBMS(2);
|
||||||
|
GMAC_REGS->GMAC_DCFGR |= GMAC_DCFGR_FBLDO(4);
|
||||||
|
|
||||||
|
// Init RX descriptors
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
s_rxdesc[i][0] = ((uint32_t) s_rxbuf[i]) & 0xfffffffc; // Point to data buffer (bits [31:2])
|
||||||
|
s_rxdesc[i][1] = 0;
|
||||||
|
}
|
||||||
|
s_rxdesc[GMAC_DESC_CNT - 1][0] |= BIT(1); // Marking last rx descriptor
|
||||||
|
|
||||||
|
// Init TX descriptors
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
s_txdesc[i][0] = (uint32_t) s_txbuf[i]; // Point to data buffer
|
||||||
|
s_txdesc[i][1] = BIT(31); // Setting the OWN bit
|
||||||
|
}
|
||||||
|
s_txdesc[GMAC_DESC_CNT - 1][1] |= BIT(30); // Marking last tx descriptor
|
||||||
|
|
||||||
|
// let the controller know about the descriptor addresses
|
||||||
|
GMAC_REGS->GMAC_RBQB = (uint32_t) s_rxdesc;
|
||||||
|
GMAC_REGS->GMAC_TBQB = (uint32_t) s_txdesc;
|
||||||
|
|
||||||
|
// GPIO pin configuration
|
||||||
|
MCLK_REGS->MCLK_APBBMASK |= MCLK_APBBMASK_PORT_Msk; // //enable bus clock for PORT
|
||||||
|
uint16_t pins[] = {PIN('A', 12), PIN('A', 13), PIN('A', 14), PIN('A', 15),
|
||||||
|
PIN('A', 17), PIN('A', 18), PIN('A', 19),
|
||||||
|
PIN('C', 11), PIN('C', 12), PIN('C', 20)};
|
||||||
|
|
||||||
|
uint32_t pin_fns[] = {
|
||||||
|
MUX_PA12L_GMAC_GRX1, MUX_PA13L_GMAC_GRX0, MUX_PA14L_GMAC_GTXCK,
|
||||||
|
MUX_PA15L_GMAC_GRXER, MUX_PA17L_GMAC_GTXEN, MUX_PA18L_GMAC_GTX0,
|
||||||
|
MUX_PA19L_GMAC_GTX1, MUX_PC11L_GMAC_GMDC, MUX_PC12L_GMAC_GMDIO,
|
||||||
|
MUX_PC20L_GMAC_GRXDV
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sizeof(pins) / sizeof(uint16_t); i++) {
|
||||||
|
uint8_t group = (uint8_t) (pins[i] >> 8);
|
||||||
|
uint8_t pin_no = (uint8_t) pins[i];
|
||||||
|
PORT_REGS->GROUP[group].PORT_PINCFG[pin_no] |= PORT_PINCFG_PMUXEN_Msk;
|
||||||
|
if (pin_no % 2)
|
||||||
|
PORT_REGS->GROUP[group].PORT_PMUX[pin_no / 2] |= (uint8_t) PORT_PMUX_PMUXO(pin_fns[i]);
|
||||||
|
else
|
||||||
|
PORT_REGS->GROUP[group].PORT_PMUX[pin_no / 2] |= (uint8_t) PORT_PMUX_PMUXE(pin_fns[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[17] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[18] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
PORT_REGS->GROUP[0].PORT_PINCFG[19] |= PORT_PINCFG_DRVSTR_Msk;
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_UR &= ~GMAC_UR_MII_Msk; // RMII operation mode
|
||||||
|
|
||||||
|
// Resetting the PHY
|
||||||
|
/*uint64_t start = mg_millis(), now = start;
|
||||||
|
PORT_REGS->GROUP[2].PORT_DIRSET = PORT_PC21;
|
||||||
|
PORT_REGS->GROUP[2].PORT_OUTCLR = PORT_PC21;
|
||||||
|
for (; now - start < 10000; now = mg_millis());
|
||||||
|
PORT_REGS->GROUP[2].PORT_OUTSET = PORT_PC21;
|
||||||
|
for (start = mg_millis(), now = start; now - start < 10000; now = mg_millis());*/
|
||||||
|
|
||||||
|
// Clock advanced configuration
|
||||||
|
#if 0
|
||||||
|
uint8_t mdc_clk_div = 5;
|
||||||
|
|
||||||
|
// get MCLK from GCLK_GENERATOR 0
|
||||||
|
uint32_t div = 512;
|
||||||
|
uint32_t mclk;
|
||||||
|
if (!(GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_DIVSEL_Msk))
|
||||||
|
div = ((GCLK_REGS->GCLK_GENCTRL[0] & 0x00FF0000) >> 16);
|
||||||
|
switch (GCLK_REGS->GCLK_GENCTRL[0] & GCLK_GENCTRL_SRC_Msk) {
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC0_Val:
|
||||||
|
mclk = 32000000UL; /* 32MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC1_Val:
|
||||||
|
mclk = 32000000UL; /* 32MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_OSCULP32K_Val:
|
||||||
|
mclk = 32000UL;
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_XOSC32K_Val:
|
||||||
|
mclk = 32000UL;
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DFLL_Val:
|
||||||
|
mclk = 48000000UL; /* 48MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DPLL0_Val:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
break;
|
||||||
|
case GCLK_GENCTRL_SRC_DPLL1_Val:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mclk = 200000000UL; /* 200MHz */
|
||||||
|
}
|
||||||
|
|
||||||
|
mclk /= div;
|
||||||
|
|
||||||
|
uint8_t crs[] = {0, 1, 2, 3, 4, 5}; // GMAC->NCFGR::CLK values
|
||||||
|
uint8_t dividers[] = {8, 16, 32, 48, 64, 128}; // Respective CLK dividers
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
if (mclk / dividers[i] <= 2375000UL /* 2.5MHz - 5% */) {
|
||||||
|
mdc_clk_div = crs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCFGR = GMAC_NCFGR_CLK(5); // set the MDC clock
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_MPE_Msk; //enable management port
|
||||||
|
|
||||||
|
// configure MAC
|
||||||
|
GMAC_REGS->SA[0].GMAC_SAT = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
|
||||||
|
GMAC_REGS->SA[0].GMAC_SAB = (uint32_t) (ifp->mac[3] << 24) |
|
||||||
|
((uint32_t) ifp->mac[2] << 16) |
|
||||||
|
((uint32_t) ifp->mac[1] << 8) | ifp->mac[0];
|
||||||
|
|
||||||
|
//Configure the receive filter
|
||||||
|
GMAC_REGS->GMAC_NCFGR |= GMAC_NCFGR_MAXFS_Msk;
|
||||||
|
|
||||||
|
//GMAC_REGS->GMAC_IER = GMAC_IER_RCOMP(1); // Enable the receive interrupt
|
||||||
|
GMAC_REGS->GMAC_IER = 0x3ffcfcff; // Enabling all interrupts
|
||||||
|
NVIC_EnableIRQ(GMAC_IRQn);
|
||||||
|
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TXEN_Msk; // Enable transmit circuit
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_RXEN_Msk ; // Enable receive circuit
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t mg_tcpip_driver_same54_tx(const void *buf, size_t len,
|
||||||
|
struct mg_tcpip_if *ifp) {
|
||||||
|
//MG_INFO(("DMAC_CTRL: 0x%x", DMAC_REGS->DMAC_CTRL));
|
||||||
|
MG_INFO(("GMAC_TSR: 0x%x", GMAC_REGS->GMAC_TSR));
|
||||||
|
GMAC_REGS->GMAC_TSR |= 0x21;
|
||||||
|
uint32_t rsr = GMAC_REGS->GMAC_RSR;
|
||||||
|
MG_INFO(("GMAC_RSR: 0x%x", rsr));
|
||||||
|
GMAC_REGS->GMAC_RSR = rsr;
|
||||||
|
if (len > sizeof(s_txbuf[s_txno])) {
|
||||||
|
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||||
|
len = 0; // Frame is too big
|
||||||
|
} else if (!(s_txdesc[s_txno][1] & BIT(31))) {
|
||||||
|
ifp->nerr++;
|
||||||
|
MG_ERROR(("No free descriptors"));
|
||||||
|
len = 0; // All descriptors are busy, fail
|
||||||
|
} else {
|
||||||
|
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||||
|
if (++s_txno >= GMAC_DESC_CNT) {
|
||||||
|
s_txdesc[GMAC_DESC_CNT - 1][1] = (len & (BIT(14) - 1)) | BIT(15)| BIT(30);
|
||||||
|
s_txno = 0;
|
||||||
|
MG_INFO(("s_tx_no: %d, tx_desc.status: 0x%x", GMAC_DESC_CNT - 1, s_txdesc[GMAC_DESC_CNT - 1][1]));
|
||||||
|
} else {
|
||||||
|
s_txdesc[s_txno - 1][1] = (len & (BIT(14) - 1)) | BIT(15);
|
||||||
|
MG_INFO(("s_tx_no: %d, tx_desc.status: 0x%x", s_txno - 1, s_txdesc[s_txno - 1][1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__DSB(); // Ensure descriptors have been written
|
||||||
|
GMAC_REGS->GMAC_NCR |= GMAC_NCR_TSTART_Msk; // Enable transmission
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mg_tcpip_driver_same54_up(struct mg_tcpip_if *ifp) {
|
||||||
|
uint16_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
|
||||||
|
//MG_INFO(("BSR: 0x%x", bsr));
|
||||||
|
bool up = bsr & BIT(2) ? 1 : 0;
|
||||||
|
(void) ifp;
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMAC_Handler(void);
|
||||||
|
void GMAC_Handler(void) {
|
||||||
|
MG_INFO(("Entering GMAC IRQ HANDLER"));
|
||||||
|
uint32_t isr = GMAC_REGS->GMAC_ISR;
|
||||||
|
MG_INFO(("isr: 0x%x", isr));
|
||||||
|
if (/*GMAC_REGS->GMAC_ISR*/ isr & GMAC_ISR_RCOMP_Msk) {
|
||||||
|
int frame_start = -1;
|
||||||
|
int frame_end = -1;
|
||||||
|
|
||||||
|
// find the start of the frame
|
||||||
|
for (int i = s_rxno; i < GMAC_DESC_CNT + s_rxno; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (!(s_rxdesc[desc_index][0] & 1)) break;
|
||||||
|
if (s_rxdesc[desc_index][1] & BIT(14))
|
||||||
|
frame_start = desc_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if frame start not found, then clear the own bit
|
||||||
|
if (frame_start == -1) {
|
||||||
|
for (int i = s_rxno; i < GMAC_DESC_CNT + s_rxno; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (!(s_rxdesc[desc_index][0] & 1)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the end of the frame
|
||||||
|
for (int i = frame_start; i < GMAC_DESC_CNT + frame_start; i++) {
|
||||||
|
int desc_index = i % GMAC_DESC_CNT;
|
||||||
|
if (s_rxdesc[desc_index][1] & BIT(15))
|
||||||
|
frame_end = desc_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear all used buffers until you reach start of frame
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
int desc_index = (i + s_rxno) % GMAC_DESC_CNT;
|
||||||
|
if (s_rxno == frame_start) break;
|
||||||
|
if (++s_rxno >= GMAC_DESC_CNT) s_rxno = 0;
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0)); // Clearing the OWN bit
|
||||||
|
}
|
||||||
|
|
||||||
|
// from start of frame to end of frame you copy into queue
|
||||||
|
size_t offset = 0, len;
|
||||||
|
for (int i = 0; i < GMAC_DESC_CNT; i++) {
|
||||||
|
int desc_index = (i + s_rxno) % GMAC_DESC_CNT;
|
||||||
|
if (desc_index == frame_start)
|
||||||
|
offset = (GMAC_REGS->GMAC_NCFGR & GMAC_NCFGR_RXBUFO_Msk) >> GMAC_NCFGR_RXBUFO_Pos;
|
||||||
|
else
|
||||||
|
offset = 0;
|
||||||
|
len = s_rxdesc[s_rxno][1] & (BIT(13) - 1);
|
||||||
|
mg_tcpip_qwrite(s_rxbuf[s_rxno] + offset, len, s_ifp);
|
||||||
|
s_rxdesc[desc_index][0] &= ~(BIT(0)); // Clearing the OWN bit
|
||||||
|
if (++s_rxno >= GMAC_DESC_CNT) s_rxno = 0;
|
||||||
|
if (desc_index == frame_end) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mg_tcpip_driver mg_tcpip_driver_same54 = {mg_tcpip_driver_same54_init,
|
||||||
|
mg_tcpip_driver_same54_tx, NULL,
|
||||||
|
mg_tcpip_driver_same54_up};
|
||||||
|
#endif
|
11
src/tcpip/driver_same54.h
Normal file
11
src/tcpip/driver_same54.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54
|
||||||
|
|
||||||
|
#include "hal.h" // keep this include
|
||||||
|
|
||||||
|
struct mg_tcpip_driver_same54_data {
|
||||||
|
int mdc_cr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -54,6 +54,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_w5500;
|
|||||||
extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
|
extern struct mg_tcpip_driver mg_tcpip_driver_tm4c;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
|
extern struct mg_tcpip_driver mg_tcpip_driver_stm32h;
|
||||||
extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
|
extern struct mg_tcpip_driver mg_tcpip_driver_imxrt;
|
||||||
|
extern struct mg_tcpip_driver mg_tcpip_driver_same54;
|
||||||
|
|
||||||
// Drivers that require SPI, can use this SPI abstraction
|
// Drivers that require SPI, can use this SPI abstraction
|
||||||
struct mg_tcpip_spi {
|
struct mg_tcpip_spi {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user