From 8ea6f011aca4dd48f4242902574daaf1c6d64bfe Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 15 Nov 2023 12:54:51 +0100 Subject: [PATCH] hw/bsp: Add arduino_zero bsp BSP and MCU code is mostly moved from external repository. File with apache license are now in core repository. External files with Atmel license are still in external repository which is referenced in MCU package so there is no need to add this external repo to project.yml manually. Signed-off-by: Jerzy Kasenberg --- hw/bsp/arduino_zero/arduino_zero.cfg | 35 + hw/bsp/arduino_zero/arduino_zero.ld | 30 + hw/bsp/arduino_zero/arduino_zero_boot.ld | 28 + hw/bsp/arduino_zero/arduino_zero_debug.sh | 39 + hw/bsp/arduino_zero/arduino_zero_download.sh | 55 ++ hw/bsp/arduino_zero/bsp.yml | 59 ++ hw/bsp/arduino_zero/include/bsp/bsp.h | 100 +++ hw/bsp/arduino_zero/pkg.yml | 33 + .../src/arch/cortex_m0/startup_samd21xx.s | 258 +++++++ hw/bsp/arduino_zero/src/hal_bsp.c | 217 ++++++ hw/bsp/arduino_zero/syscfg.yml | 48 ++ hw/mcu/atmel/samd21xx/ext/pkg.yml | 95 +++ .../atmel/samd21xx/include/mcu/cmsis_nvic.h | 48 ++ hw/mcu/atmel/samd21xx/include/mcu/cortex_m0.h | 23 + hw/mcu/atmel/samd21xx/include/mcu/hal_adc.h | 89 +++ hw/mcu/atmel/samd21xx/include/mcu/hal_dac.h | 46 ++ hw/mcu/atmel/samd21xx/include/mcu/hal_i2c.h | 51 ++ hw/mcu/atmel/samd21xx/include/mcu/hal_pwm.h | 74 ++ hw/mcu/atmel/samd21xx/include/mcu/hal_spi.h | 36 + hw/mcu/atmel/samd21xx/include/mcu/hal_uart.h | 49 ++ hw/mcu/atmel/samd21xx/include/mcu/mcu.h | 45 ++ hw/mcu/atmel/samd21xx/include/mcu/samd21.h | 36 + .../atmel/samd21xx/include/mcu/samd21_hal.h | 39 + hw/mcu/atmel/samd21xx/pkg.yml | 40 + hw/mcu/atmel/samd21xx/samd21xx.ld | 200 +++++ hw/mcu/atmel/samd21xx/src/hal_flash.c | 245 ++++++ hw/mcu/atmel/samd21xx/src/hal_gpio.c | 460 +++++++++++ hw/mcu/atmel/samd21xx/src/hal_i2c.c | 224 ++++++ hw/mcu/atmel/samd21xx/src/hal_os_tick.c | 46 ++ hw/mcu/atmel/samd21xx/src/hal_reset_cause.c | 40 + hw/mcu/atmel/samd21xx/src/hal_spi.c | 482 ++++++++++++ hw/mcu/atmel/samd21xx/src/hal_system.c | 56 ++ hw/mcu/atmel/samd21xx/src/hal_system_start.c | 50 ++ hw/mcu/atmel/samd21xx/src/hal_timer.c | 721 ++++++++++++++++++ hw/mcu/atmel/samd21xx/src/hal_uart.c | 312 ++++++++ hw/mcu/atmel/samd21xx/src/hal_watchdog.c | 96 +++ hw/mcu/atmel/samd21xx/src/samd21_mcu_id.c | 62 ++ hw/mcu/atmel/samd21xx/src/samd21_misc.c | 35 + hw/mcu/atmel/samd21xx/src/samd21_priv.h | 28 + hw/mcu/atmel/samd21xx/src/system_samd21.c | 37 + hw/mcu/atmel/samd21xx/syscfg.yml | 92 +++ 41 files changed, 4759 insertions(+) create mode 100644 hw/bsp/arduino_zero/arduino_zero.cfg create mode 100644 hw/bsp/arduino_zero/arduino_zero.ld create mode 100644 hw/bsp/arduino_zero/arduino_zero_boot.ld create mode 100644 hw/bsp/arduino_zero/arduino_zero_debug.sh create mode 100644 hw/bsp/arduino_zero/arduino_zero_download.sh create mode 100644 hw/bsp/arduino_zero/bsp.yml create mode 100644 hw/bsp/arduino_zero/include/bsp/bsp.h create mode 100644 hw/bsp/arduino_zero/pkg.yml create mode 100644 hw/bsp/arduino_zero/src/arch/cortex_m0/startup_samd21xx.s create mode 100644 hw/bsp/arduino_zero/src/hal_bsp.c create mode 100644 hw/bsp/arduino_zero/syscfg.yml create mode 100644 hw/mcu/atmel/samd21xx/ext/pkg.yml create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/cmsis_nvic.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/cortex_m0.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_adc.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_dac.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_i2c.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_pwm.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_spi.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/hal_uart.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/mcu.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/samd21.h create mode 100644 hw/mcu/atmel/samd21xx/include/mcu/samd21_hal.h create mode 100644 hw/mcu/atmel/samd21xx/pkg.yml create mode 100644 hw/mcu/atmel/samd21xx/samd21xx.ld create mode 100644 hw/mcu/atmel/samd21xx/src/hal_flash.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_gpio.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_i2c.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_os_tick.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_reset_cause.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_spi.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_system.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_system_start.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_timer.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_uart.c create mode 100644 hw/mcu/atmel/samd21xx/src/hal_watchdog.c create mode 100644 hw/mcu/atmel/samd21xx/src/samd21_mcu_id.c create mode 100644 hw/mcu/atmel/samd21xx/src/samd21_misc.c create mode 100644 hw/mcu/atmel/samd21xx/src/samd21_priv.h create mode 100644 hw/mcu/atmel/samd21xx/src/system_samd21.c create mode 100644 hw/mcu/atmel/samd21xx/syscfg.yml diff --git a/hw/bsp/arduino_zero/arduino_zero.cfg b/hw/bsp/arduino_zero/arduino_zero.cfg new file mode 100644 index 0000000000..762d1e9a30 --- /dev/null +++ b/hw/bsp/arduino_zero/arduino_zero.cfg @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Called $0 [identities ...] +# - binary is the path to prefix to target binary, .elf appended to name is +# the ELF file +# - identities is the project identities string. +# +# +source [find interface/cmsis-dap.cfg] + +# chip name +set CHIPNAME at91samd21g18 +set ENDIAN little +set _TARGETNAME $CHIPNAME.cpu + +source [find target/at91samdXX.cfg] + +$_TARGETNAME configure -event gdb-detach {if {[at91samd21g18.cpu curstate] eq "halted"} resume;shutdown} + + diff --git a/hw/bsp/arduino_zero/arduino_zero.ld b/hw/bsp/arduino_zero/arduino_zero.ld new file mode 100644 index 0000000000..1c9bdd6ebb --- /dev/null +++ b/hw/bsp/arduino_zero/arduino_zero.ld @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* Linker script for SAMD21 when running from flash and using the bootloader */ + +/* Memory Spaces Definitions */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x0000c000, LENGTH = 0x18000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 +} + +/* This linker script is used for images and thus contains an image header */ +_imghdr_size = 0x20; diff --git a/hw/bsp/arduino_zero/arduino_zero_boot.ld b/hw/bsp/arduino_zero/arduino_zero_boot.ld new file mode 100644 index 0000000000..57d18a04c2 --- /dev/null +++ b/hw/bsp/arduino_zero/arduino_zero_boot.ld @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* Memory Spaces Definitions */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x0000c000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 +} + +/* The bootloader does not contain an image header */ +_imghdr_size = 0x0; diff --git a/hw/bsp/arduino_zero/arduino_zero_debug.sh b/hw/bsp/arduino_zero/arduino_zero_debug.sh new file mode 100644 index 0000000000..bdda39e1c1 --- /dev/null +++ b/hw/bsp/arduino_zero/arduino_zero_debug.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - RESET set if target should be reset when attaching +# - NO_GDB set if we should not start gdb to debug +# + +. $CORE_PATH/hw/scripts/openocd.sh + +FILE_NAME=$BIN_BASENAME.elf +CFG="-f $BSP_PATH/arduino_zero.cfg" + +openocd_debug + + + diff --git a/hw/bsp/arduino_zero/arduino_zero_download.sh b/hw/bsp/arduino_zero/arduino_zero_download.sh new file mode 100644 index 0000000000..91f2ebaf3c --- /dev/null +++ b/hw/bsp/arduino_zero/arduino_zero_download.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - IMAGE_SLOT is the image slot to download to (for non-mfg-image, non-boot) +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - MFG_IMAGE is "1" if this is a manufacturing image +# - FLASH_OFFSET contains the flash offset to download to +# - BOOT_LOADER is set if downloading a bootloader + +. $CORE_PATH/hw/scripts/openocd.sh + +CFG="-f $BSP_PATH/arduino_zero.cfg" + +PROTECT_BOOT=0 +if [ "$MFG_IMAGE" ]; then + FLASH_OFFSET=0x00000000 + PROTECT_BOOT=1 +elif [ "$BOOT_LOADER" ]; then + PROTECT_BOOT=1 +fi + +if [ $PROTECT_BOOT -eq 1 ]; then + # we will unprotect and reprotect our bootloader to ensure that its + # safe. also Arduino Zero Pro boards looks like they come with the + # arduino bootloader protected via the NVM AUX + CFG_POST_INIT="at91samd bootloader 0" + + # XXX reprotect todo + #PROTECT_FLASH="at91samd bootloader 16384" +fi + +common_file_to_load +openocd_load +openocd_reset_run diff --git a/hw/bsp/arduino_zero/bsp.yml b/hw/bsp/arduino_zero/bsp.yml new file mode 100644 index 0000000000..adaf6a72b6 --- /dev/null +++ b/hw/bsp/arduino_zero/bsp.yml @@ -0,0 +1,59 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +bsp.arch: cortex_m0 +bsp.compiler: "@apache-mynewt-core/compiler/arm-none-eabi-m0" +bsp.linkerscript: + - "hw/bsp/arduino_zero/arduino_zero.ld" + - "hw/mcu/atmel/samd21xx/samd21xx.ld" +bsp.linkerscript.BOOT_LOADER.OVERWRITE: + - "hw/bsp/arduino_zero/arduino_zero_boot.ld" + - "hw/mcu/atmel/samd21xx/samd21xx.ld" +bsp.downloadscript: "hw/bsp/arduino_zero/arduino_zero_download.sh" +bsp.debugscript: "hw/bsp/arduino_zero/arduino_zero_debug.sh" + +bsp.flash_map: + areas: + FLASH_AREA_BOOTLOADER: + device: 0 + offset: 0x00000000 + size: 48kB + FLASH_AREA_IMAGE_0: + device: 0 + offset: 0x0000c000 + size: 96kB + FLASH_AREA_IMAGE_1: + device: 0 + offset: 0x00024000 + size: 96kB + FLASH_AREA_IMAGE_SCRATCH: + device: 0 + offset: 0x0003c000 + size: 7kB + + FLASH_AREA_REBOOT_LOG: + user_id: 0 + device: 0 + offset: 0x0003dc00 + size: 1kB + FLASH_AREA_NFFS: + user_id: 1 + device: 0 + offset: 0x0003e000 + size: 8kB diff --git a/hw/bsp/arduino_zero/include/bsp/bsp.h b/hw/bsp/arduino_zero/include/bsp/bsp.h new file mode 100644 index 0000000000..7be30695ea --- /dev/null +++ b/hw/bsp/arduino_zero/include/bsp/bsp.h @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef __ARDUINO_BSP_H +#define __ARDUINO_BSP_H + +#include +#include "syscfg/syscfg.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum system_device_id +{ + /* NOTE: Some HALs use a virtual enumeration of the devices, while + * other still use the actual pins (GPIO). For arduino this means + * that the sysIDs for analog and digital pins are the actual pin + * numbers */ + + ARDUINO_ZERO_D0 = (11), + ARDUINO_ZERO_D1 = (10), + ARDUINO_ZERO_D3 = (9), + ARDUINO_ZERO_D5 = (15), + ARDUINO_ZERO_D6 = (20), + ARDUINO_ZERO_D7 = (21), + ARDUINO_ZERO_D8 = (6), + ARDUINO_ZERO_D9 = (7), + ARDUINO_ZERO_D10 = (18), + ARDUINO_ZERO_D11 = (16), + ARDUINO_ZERO_D12 = (19), + ARDUINO_ZERO_D13 = (17), + +#if MYNEWT_VAL(BSP_ARDUINO_ZERO_PRO) + ARDUINO_ZERO_D2 = (8), + ARDUINO_ZERO_D4 = (14), +#else + ARDUINO_ZERO_D2 = (14), + ARDUINO_ZERO_D4 = (8), +#endif + + /* Use SPI 2 */ + ARDUINO_ZERO_SPI_ICSP = 0, + + /* Use SPI 3 */ + ARDUINO_ZERO_SPI_ALT = 1, + + /* a I2c port on SCLK and SDA */ + ARDUINO_ZERO_I2C = 4, +}; + +#define BSP_WINC1500_SPI_PORT 0 + +extern uint8_t _ram_start; +#define RAM_SIZE 0x00008000 + +#define ARDUINO_ZERO_PIN_UART_RX (ARDUINO_ZERO_D0) +#define ARDUINO_ZERO_PIN_UART_TX (ARDUINO_ZERO_D1) + +#define LED_BLINK_PIN (ARDUINO_ZERO_D13) +#define LED_2 (27) + +#define CONSOLE_UART_SPEED 115200 + +/* + * Wiring of Wifi Shield 101 chip to SAMD21. + */ +#define WINC1500_PIN_RESET /* PA15 */ MCU_GPIO_PORTA(15) + /* WINC1500_PIN_WAKE */ /* NC */ +#define WINC1500_PIN_IRQ /* PA21 */ MCU_GPIO_PORTA(21) + /* WINC1500_PIN_ENABLE */ /* NC */ + +#define WINC1500_SPI_SPEED 4000000 +#define WINC1500_SPI_SSN /* PA18 */ MCU_GPIO_PORTA(18) +#define WINC1500_SPI_SCK /* PB11 */ MCU_GPIO_PORTB(11) +#define WINC1500_SPI_MOSI /* PB10 */ MCU_GPIO_PORTB(10) +#define WINC1500_SPI_MISO /* PA12 */ MCU_GPIO_PORTA(12) + +#ifdef __cplusplus +} +#endif + +#endif /* __ARDUINO_BSP_H */ diff --git a/hw/bsp/arduino_zero/pkg.yml b/hw/bsp/arduino_zero/pkg.yml new file mode 100644 index 0000000000..d518cc239a --- /dev/null +++ b/hw/bsp/arduino_zero/pkg.yml @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "hw/bsp/arduino_zero" +pkg.type: bsp + +pkg.deps: + - "@apache-mynewt-core/hw/mcu/atmel/samd21xx" + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/libc/baselibc" + +pkg.deps.UART_0: + - "@apache-mynewt-core/hw/drivers/uart" + - "@apache-mynewt-core/hw/drivers/uart/uart_hal" + +pkg.cflags: + - -D__SAMD21G18A__ diff --git a/hw/bsp/arduino_zero/src/arch/cortex_m0/startup_samd21xx.s b/hw/bsp/arduino_zero/src/arch/cortex_m0/startup_samd21xx.s new file mode 100644 index 0000000000..1d58d800ba --- /dev/null +++ b/hw/bsp/arduino_zero/src/arch/cortex_m0/startup_samd21xx.s @@ -0,0 +1,258 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + .syntax unified + .cpu cortex-m0 + .fpu softvfp + .thumb + + .global g_pfnVectors + .global Default_Handler + .globl Reset_Handler + + .section .text.Reset_Handler + .type Reset_Handler, %function + .func Reset_Handler + +Reset_Handler: + movs r0, #0 + msr primask, r0 + + ldr r1, =_estack + mov sp, r1 /* set stack pointer */ + + /* Clear .bss section */ + ldr r2, =__bss_start__ + ldr r3, =__bss_end__ +.L_bss_zero_loop: + cmp r2, r3 + bhs .L_bss_zero_loop_end + stmia r2!, {r0} + b .L_bss_zero_loop +.L_bss_zero_loop_end: + + /* Copy .data section to RAM */ + ldr r1, =_sidata + ldr r2, =__data_start__ + ldr r3, =__data_end__ + +.L_data_copy_loop: + cmp r2, r3 + bhs .L_data_copy_loop_end + ldmia r1!, {r0} + stmia r2!, {r0} + b .L_data_copy_loop +.L_data_copy_loop_end: + + ldr r0, =__HeapBase + ldr r1, =__HeapLimit + bl _sbrkInit + + /* Call the clock system initialization function.*/ + bl SystemInit + + bl hal_system_init + + /* Call the application's entry point.*/ + bl _start + + .size Reset_Handler, .-Reset_Handler + .endfunc + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits + .globl Default_Handler + .type Default_Handler, %function +Default_Handler: + b . + .size Default_Handler, . - Default_Handler + + .section .isr_vector, "a", %progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .globl __isr_vector +__isr_vector: + + .word __StackTop + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word 0 + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word PM_Handler + .word SYSCTRL_Handler + .word WDT_Handler + .word RTC_Handler + .word EIC_Handler + .word NVMCTRL_Handler + .word DMAC_Handler + .word USB_Handler + .word EVSYS_Handler + .word SERCOM0_Handler + .word SERCOM1_Handler + .word SERCOM2_Handler + .word SERCOM3_Handler + .word SERCOM4_Handler + .word SERCOM5_Handler + .word TCC0_Handler + .word TCC1_Handler + .word TCC2_Handler + .word TC3_Handler + .word TC4_Handler + .word TC5_Handler + .word TC6_Handler + .word TC7_Handler + .word ADC_Handler + .word AC_Handler + .word DAC_Handler + .word PTC_Handler + .word I2S_Handler + .word AC1_Handler + .word TCC3_Handler + + .size __isr_vector, . - __isr_vector + + + .weak NMI_Handler + .thumb_set NMI_Handler, Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler, Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler, Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler, Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler, Default_Handler + + .weak PM_Handler, + .thumb_set PM_Handler, Default_Handler + + .weak SYSCTRL_Handler, + .thumb_set SYSCTRL_Handler, Default_Handler + + .weak WDT_Handler, + .thumb_set WDT_Handler, Default_Handler + + .weak RTC_Handler, + .thumb_set RTC_Handler, Default_Handler + + .weak EIC_Handler, + .thumb_set EIC_Handler, Default_Handler + + .weak NVMCTRL_Handler, + .thumb_set NVMCTRL_Handler, Default_Handler + + .weak DMAC_Handler, + .thumb_set DMAC_Handler, Default_Handler + + .weak USB_Handler, + .thumb_set USB_Handler, Default_Handler + + .weak EVSYS_Handler, + .thumb_set EVSYS_Handler, Default_Handler + + .weak SERCOM0_Handler, + .thumb_set SERCOM0_Handler, Default_Handler + + .weak SERCOM1_Handler, + .thumb_set SERCOM1_Handler, Default_Handler + + .weak SERCOM2_Handler, + .thumb_set SERCOM2_Handler, Default_Handler + + .weak SERCOM3_Handler, + .thumb_set SERCOM3_Handler, Default_Handler + + .weak SERCOM4_Handler, + .thumb_set SERCOM4_Handler, Default_Handler + + .weak SERCOM5_Handler, + .thumb_set SERCOM5_Handler, Default_Handler + + .weak TCC0_Handler, + .thumb_set TCC0_Handler, Default_Handler + + .weak TCC1_Handler, + .thumb_set TCC1_Handler, Default_Handler + + .weak TCC2_Handler, + .thumb_set TCC2_Handler, Default_Handler + + .weak TC3_Handler, + .thumb_set TC3_Handler, Default_Handler + + .weak TC4_Handler, + .thumb_set TC4_Handler, Default_Handler + + .weak TC5_Handler, + .thumb_set TC5_Handler, Default_Handler + + .weak TC6_Handler, + .thumb_set TC6_Handler, Default_Handler + + .weak TC7_Handler, + .thumb_set TC7_Handler, Default_Handler + + .weak ADC_Handler, + .thumb_set ADC_Handler, Default_Handler + + .weak AC_Handler, + .thumb_set AC_Handler, Default_Handler + + .weak DAC_Handler, + .thumb_set DAC_Handler, Default_Handler + + .weak PTC_Handler, + .thumb_set PTC_Handler, Default_Handler + + .weak I2S_Handler, + .thumb_set I2S_Handler, Default_Handler + + .weak AC1_Handler, + .thumb_set AC1_Handler, Default_Handler + + .weak TCC3_Handler, + .thumb_set TCC3_Handler, Default_Handler + diff --git a/hw/bsp/arduino_zero/src/hal_bsp.c b/hw/bsp/arduino_zero/src/hal_bsp.c new file mode 100644 index 0000000000..9f4da9171b --- /dev/null +++ b/hw/bsp/arduino_zero/src/hal_bsp.c @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include +#include +#include +#include +#include "syscfg/syscfg.h" +#include "hal/hal_bsp.h" +#include "bsp/bsp.h" +#include "sysinit/sysinit.h" +#include "mcu/samd21.h" +#include "bsp/bsp.h" + +/* + * hw/mcu/atmel/samd21xx/src/sam0/drivers/tc/tc.h + */ +#include + +#include "mcu/samd21_hal.h" +#include "hal/hal_spi.h" +#include "hal/hal_i2c.h" +#include "hal/hal_flash.h" +#include "mcu/hal_spi.h" +#include "mcu/hal_i2c.h" + +/* + * hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart/usart.h + */ +#include + +#include +#if MYNEWT_VAL(UART_0) +#include +#include +#include + +static struct uart_dev hal_uart0; +#endif +#if MYNEWT_VAL(SPI_0) +/* configure the SPI port for arduino external spi */ +struct samd21_spi_config icsp_spi_config = { + .dipo = 0, /* sends MISO to PAD 0 */ + .dopo = 1, /* send CLK to PAD 3 and MOSI to PAD 2 */ + .pad0_pinmux = PINMUX_PA12D_SERCOM4_PAD0, /* MISO */ + .pad3_pinmux = PINMUX_PB11D_SERCOM4_PAD3, /* SCK */ + .pad2_pinmux = PINMUX_PB10D_SERCOM4_PAD2, /* MOSI */ +}; +#endif + +#if MYNEWT_VAL(SPI_1) +/* NOTE using this will overwrite the debug interface */ +struct samd21_spi_config alt_spi_config = { + .dipo = 3, /* sends MISO to PAD 3 */ + .dopo = 0, /* send CLK to PAD 1 and MOSI to PAD 0 */ + .pad0_pinmux = PINMUX_PA04D_SERCOM0_PAD0, /* MOSI */ + .pad1_pinmux = PINMUX_PA05D_SERCOM0_PAD1, /* SCK */ + .pad2_pinmux = PINMUX_PA06D_SERCOM0_PAD2, /* SCK */ + .pad3_pinmux = PINMUX_PA07D_SERCOM0_PAD3, /* MISO */ +}; +#endif + +#if MYNEWT_VAL(I2C_5) +struct samd21_i2c_config i2c_config = { + .pad0_pinmux = PINMUX_PA22D_SERCOM5_PAD0, + .pad1_pinmux = PINMUX_PA23D_SERCOM5_PAD1, +}; +#endif + +#if MYNEWT_VAL(UART_0) +static const struct samd21_uart_config uart_cfgs[] = { + [0] = { + .suc_sercom = SERCOM2, + .suc_mux_setting = USART_RX_3_TX_2_XCK_3, + .suc_generator_source = GCLK_GENERATOR_0, + .suc_sample_rate = USART_SAMPLE_RATE_16X_ARITHMETIC, + .suc_sample_adjustment = USART_SAMPLE_ADJUSTMENT_7_8_9, + .suc_pad0 = 0, + .suc_pad1 = 0, + .suc_pad2 = PINMUX_PA10D_SERCOM2_PAD2, + .suc_pad3 = PINMUX_PA11D_SERCOM2_PAD3 + } +}; +#endif + +/* + * What memory to include in coredump. + */ +static const struct hal_bsp_mem_dump dump_cfg[] = { + [0] = { + .hbmd_start = &_ram_start, + .hbmd_size = RAM_SIZE + } +}; + +const struct hal_flash * +hal_bsp_flash_dev(uint8_t id) +{ + /* + * Internal flash mapped to id 0. + */ + if (id != 0) { + return NULL; + } + + return &samd21_flash_dev; +} + +const struct hal_bsp_mem_dump * +hal_bsp_core_dump(int *area_cnt) +{ + *area_cnt = sizeof(dump_cfg) / sizeof(dump_cfg[0]); + return dump_cfg; +} + + +/** + * Returns the configured priority for the given interrupt. If no priority + * configured, return the priority passed in + * + * @param irq_num + * @param pri + * + * @return uint32_t + */ +uint32_t +hal_bsp_get_nvic_priority(int irq_num, uint32_t pri) +{ + /* Add any interrupt priorities configured by the bsp here */ + return pri; +} + +void +hal_bsp_init(void) +{ + int rc; + + (void)rc; +#if MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) + struct samd21_timer_cfg tmr_cfg; +#endif + +#if MYNEWT_VAL(UART_0) + rc = os_dev_create((struct os_dev *) &hal_uart0, "uart0", + OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *)&uart_cfgs[0]); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif + +#if MYNEWT_VAL(TIMER_0) + tmr_cfg.clkgen = GCLK_GENERATOR_2; + tmr_cfg.src_clock = GCLK_SOURCE_OSC8M; + tmr_cfg.hwtimer = TC3; + tmr_cfg.irq_num = TC3_IRQn; + rc = hal_timer_init(0, &tmr_cfg); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_1) + tmr_cfg.clkgen = GCLK_GENERATOR_5; + tmr_cfg.src_clock = GCLK_SOURCE_OSC8M; + tmr_cfg.hwtimer = TC4; + tmr_cfg.irq_num = TC4_IRQn; + rc = hal_timer_init(1, &tmr_cfg); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_2) + tmr_cfg.clkgen = GCLK_GENERATOR_6; + tmr_cfg.src_clock = GCLK_SOURCE_OSC8M; + tmr_cfg.hwtimer = TC5; + tmr_cfg.irq_num = TC5_IRQn; + rc = hal_timer_init(2, &tmr_cfg); + assert(rc == 0); +#endif + +#if (MYNEWT_VAL(OS_CPUTIME_TIMER_NUM) >= 0) + /* + * Set cputime to count at 1 usec increments. + */ + rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ)); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(SPI_0) + rc = hal_spi_init(0, &icsp_spi_config, MYNEWT_VAL(SPI_0_TYPE)); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif + +#if MYNEWT_VAL(SPI_1) + rc = hal_spi_init(1, &alt_spi_config, MYNEWT_VAL(SPI_1_TYPE)); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif + +#if MYNEWT_VAL(I2C_5) + rc = hal_i2c_init(5, &i2c_config); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif +} + +void +hal_bsp_deinit(void) +{ + +} diff --git a/hw/bsp/arduino_zero/syscfg.yml b/hw/bsp/arduino_zero/syscfg.yml new file mode 100644 index 0000000000..9d6296381f --- /dev/null +++ b/hw/bsp/arduino_zero/syscfg.yml @@ -0,0 +1,48 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BSP_ARDUINO_ZERO_PRO: + description: 'Building for Arduino Zero Pro' + value: 0 + + UART_0: + description: 'Whether to enable UART0' + value: 1 + + TIMER_0: + description: 'Arduino zero Timer 0.' + value: 1 + TIMER_1: + description: 'Arduino zero Timer 1.' + value: 0 + TIMER_2: + description: 'Arduino zero Timer 2.' + value: 0 + +syscfg.vals: + CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS + REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG + NFFS_FLASH_AREA: FLASH_AREA_NFFS + COREDUMP_FLASH_AREA: FLASH_AREA_IMAGE_1 + + # Console history happens at interrupts and arduino is not fast + # enough to do this and to perform simultaneous transmit and + # receive at 115200 for large frames. Disable history by default + CONSOLE_HISTORY: none diff --git a/hw/mcu/atmel/samd21xx/ext/pkg.yml b/hw/mcu/atmel/samd21xx/ext/pkg.yml new file mode 100644 index 0000000000..4590209c57 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/ext/pkg.yml @@ -0,0 +1,95 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "hw/mcu/atmel/samd21xx/ext" + +pkg.type: sdk + +repository.atmel-samd21xx: + type: github + vers: mynewt_1_10_0_tag-commit + branch: master + user: runtimeco + repo: mynewt_arduino_zero + +pkg.deps: + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/hw/cmsis-core" + +pkg.include_dirs: + - "@apache-mynewt-core/hw/mcu/atmel/samd21xx/include/mcu" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/common/utils" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/ac" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/adc" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/adc/adc_sam_d_r" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/bod" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/bod/bod_sam_d_r" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/dac" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/dac/dac_sam_d_c" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/dma/module_config" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/events" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/extint" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/extint/module_config" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/i2s" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/nvm" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/pac" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/port" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/rtc" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/i2c" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi/module_config" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/spi_master_vec/module-config" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/sercom/usart" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/clock" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/clock/clock_samd21_r21_da" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/clock/clock_samd21_r21_da/module_config" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/interrupt" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/interrupt/system_interrupt_samd21" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/pinmux" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/power/power_sam_d_r" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/system/reset/reset_sam_d_r" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/tc" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers/wdt" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/utils" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/utils/header_files" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/utils/preprocessor" + +pkg.src_dirs: + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/drivers" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/sam0/utils" + - "@atmel-samd21xx/hw/mcu/atmel/samd21xx/src/common" + + +pkg.cflags: + - -std=c99 +# - -DI2C_MASTER_CALLBACK_MODE=true +# - -DI2C_SLAVE_CALLBACK_MODE=true + - -DWDT_CALLBACK_MODE=true + - -DUSART_CALLBACK_MODE=true + - -DCONF_SPI_MASTER_ENABLE=true + - -DRTC_CALENDAR_ASYNC=true + - -DRTC_COUNT_ASYNC=true + - -DI2S_CALLBACK_MODE=true + - -DAC_CALLBACK_MODE=true + - -DEVENTS_INTERRUPT_HOOKS_MODE=true + - -DEXTINT_CALLBACK_MODE=true + - -DSPI_CALLBACK_MODE=true diff --git a/hw/mcu/atmel/samd21xx/include/mcu/cmsis_nvic.h b/hw/mcu/atmel/samd21xx/include/mcu/cmsis_nvic.h new file mode 100644 index 0000000000..4b8909b61c --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/cmsis_nvic.h @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* mbed Microcontroller Library - cmsis_nvic + * Copyright (c) 2009-2011 ARM Limited. All rights reserved. + * + * CMSIS-style functionality to support dynamic vectors + */ + +#ifndef __CMSIS_NVIC_H__ +#define __CMSIS_NVIC_H__ + +#include + +#define NVIC_NUM_VECTORS (16 + 29) // CORE + MCU Peripherals +#define NVIC_USER_IRQ_OFFSET 16 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void NVIC_Relocate(void); +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector); +uint32_t NVIC_GetVector(IRQn_Type IRQn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/mcu/atmel/samd21xx/include/mcu/cortex_m0.h b/hw/mcu/atmel/samd21xx/include/mcu/cortex_m0.h new file mode 100644 index 0000000000..2d1c4315fb --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/cortex_m0.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2016 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MCU_CORTEX_M0_H__ +#define __MCU_CORTEX_M0_H__ + +#include "src/sam0/utils/cmsis/samd21/include/samd21.h" +#include "mcu.h" + +#endif /* __MCU_CORTEX_M0_H__ */ diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_adc.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_adc.h new file mode 100644 index 0000000000..ca5a91c746 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_adc.h @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _SAMD21_HAL_ADC_H +#define _SAMD21_HAL_ADC_H + +/* this structure is passed to the BSP for configuration options */ +enum samd_adc_reference_voltage { + SAMD21_ADC_REFERENCE_INT1V, + SAMD21_ADC_REFERENCE_INTVCC0, + SAMD21_ADC_REFERENCE_INTVCC1, + SAMD21_ADC_REFERENCE_AREFA, + SAMD21_ADC_REFERENCE_AREFB, +}; + +enum samd_adc_analog_channel { + SAMD21_ANALOG_0 = 0, + SAMD21_ANALOG_1, + SAMD21_ANALOG_2, + SAMD21_ANALOG_3, + SAMD21_ANALOG_4, + SAMD21_ANALOG_5, + SAMD21_ANALOG_6, + SAMD21_ANALOG_7, + SAMD21_ANALOG_8, + SAMD21_ANALOG_9, + SAMD21_ANALOG_10, + SAMD21_ANALOG_11, + SAMD21_ANALOG_12, + SAMD21_ANALOG_13, + SAMD21_ANALOG_14, + SAMD21_ANALOG_15, + SAMD21_ANALOG_16, + SAMD21_ANALOG_17, + SAMD21_ANALOG_18, + SAMD21_ANALOG_19, + SAMD21_ANALOG_TEMP, + SAMD21_ANALOG_BANDGAP, + SAMD21_ANALOG_SCALEDCOREVCC, + SAMD21_ANALOG_SCALEDIOVCC, + SAMD21_ANALOG_ADC_DAC, + SAMD21_ANALOG_MAX, +}; + +enum samd_adc_resolution { + SAMD21_RESOLUTION_8_BITS, + SAMD21_RESOLUTION_10_BITS, + SAMD21_RESOLUTION_12_BITS, +}; + +enum samd_adc_gain { + SAMD21_GAIN_DIV2, + SAMD21_GAIN_1X, + SAMD21_GAIN_2X, + SAMD21_GAIN_4X, + SAMD21_GAIN_8X, + SAMD21_GAIN_16X, +}; + +struct samd21_adc_config { + enum samd_adc_reference_voltage volt; + enum samd_adc_resolution resolution_bits; + enum samd_adc_gain gain; + int voltage_mvolts; +}; + +/* This creates a new ADC object for this ADC source */ +struct hal_adc *samd21_adc_create(enum samd_adc_analog_channel chan, + const struct samd21_adc_config *pconfig); + + +#endif /* _SAMD21_HAL_ADC_H */ + diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_dac.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_dac.h new file mode 100644 index 0000000000..f032fbacf3 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_dac.h @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef HAL_DAC_H +#define HAL_DAC_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum samd_dac_reference { + SAMD_DAC_REFERENCE_INT1V = 0, + SAMD_DAC_REFERENCE_AVCC = 1, + SAMD_DAC_REFERENCE_AREF = 2, +}; + +struct samd21_dac_config { + enum samd_dac_reference reference; + int dac_reference_voltage_mvolts; +}; + +/* This creates a new DAC object for this DAC source */ +struct hal_dac *samd21_dac_create(const struct samd21_dac_config *pconfig); + +#ifdef __cplusplus +} +#endif + +#endif /* HAL_DAC_H */ + diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_i2c.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_i2c.h new file mode 100644 index 0000000000..d5ff815c0f --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_i2c.h @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _SAMD21_HAL_I2C_H__ +#define _SAMD21_HAL_I2C_H__ + +/* this is where the pin definitions are */ +#include "src/sam0/utils/header_files/io.h" + +enum samd21_i2c_device { + SAMD21_I2C_SERCOM0, + SAMD21_I2C_SERCOM1, + SAMD21_I2C_SERCOM2, + SAMD21_I2C_SERCOM3, + SAMD21_I2C_SERCOM4, + SAMD21_I2C_SERCOM5, +}; + +enum samd21_i2c_mux_setting { + SAMD21_I2C_MUX_SETTING_C, + SAMD21_I2C_MUX_SETTING_D, +}; + +/* These have to be set appropriately to be valid combination */ +struct samd21_i2c_config { + uint32_t pad0_pinmux; + uint32_t pad1_pinmux; + /* TODO baudrate and high speed */ +}; + +/* This creates a new I2C object based on the samd21 TC devices */ +struct hal_i2c *samd21_i2c_create(enum samd21_i2c_device dev_id, + const struct samd21_i2c_config *pconfig); + +#endif /* _SAMD21_HAL_I2C_H__ */ diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_pwm.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_pwm.h new file mode 100644 index 0000000000..6cdb6a73ea --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_pwm.h @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _SAMD21_HAL_PWM_H__ +#define _SAMD21_HAL_PWM_H__ + +/* this is where the pin definitions are */ +#include "src/sam0/utils/header_files/io.h" + +/* the Samd parts have two different devices capable of doing PWM + * There are two separate drivers in the atmel source, so we + * create two different types */ + +enum samd_tc_device_id { + SAMD_TC_DEV_3 = 0, + SAMD_TC_DEV_4, + SAMD_TC_DEV_5, +}; + +enum samd_tc_tcc_clock_prescaler { + /** Divide clock by 1 */ + SAMD_TC_CLOCK_PRESCALER_DIV1, + SAMD_TC_CLOCK_PRESCALER_DIV2, + SAMD_TC_CLOCK_PRESCALER_DIV4, + SAMD_TC_CLOCK_PRESCALER_DIV8, + SAMD_TC_CLOCK_PRESCALER_DIV16, + SAMD_TC_CLOCK_PRESCALER_DIV64, + SAMD_TC_CLOCK_PRESCALER_DIV256, + SAMD_TC_CLOCK_PRESCALER_DIV1024, +}; + +struct samd21_pwm_tc_config { + enum samd_tc_tcc_clock_prescaler prescalar; + int clock_freq; +}; + +/* This creates a new PWM object based on the samd21 TC devices */ +struct hal_pwm *samd21_pwm_tc_create(enum samd_tc_device_id id, int channel, int pin, + const struct samd21_pwm_tc_config *pconfig); + + +enum samd_tcc_device_id { + SAMD_TCC_DEV_0 = 0, + SAMD_TCC_DEV_1, + SAMD_TCC_DEV_2, +}; + +struct samd21_pwm_tcc_config { + enum samd_tc_tcc_clock_prescaler prescalar; + int clock_freq; +}; + + +struct hal_pwm *samd21_pwm_tcc_create(enum samd_tcc_device_id id, int channel, int pin, + const struct samd21_pwm_tcc_config *pconfig); + + +#endif /* _SAMD21_HAL_PWM_H__ */ diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_spi.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_spi.h new file mode 100644 index 0000000000..65621c254b --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_spi.h @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _SAMD21_HAL_SPI_H__ +#define _SAMD21_HAL_SPI_H__ + +/* this is where the pin definitions are */ +#include "src/sam0/utils/header_files/io.h" + +/* These have to be set appropriately to be valid combination */ +struct samd21_spi_config { + uint8_t dipo; + uint8_t dopo; + uint32_t pad0_pinmux; + uint32_t pad1_pinmux; + uint32_t pad2_pinmux; + uint32_t pad3_pinmux; +}; + +#endif /* _SAMD21_HAL_SPI_H__ */ diff --git a/hw/mcu/atmel/samd21xx/include/mcu/hal_uart.h b/hw/mcu/atmel/samd21xx/include/mcu/hal_uart.h new file mode 100644 index 0000000000..820c7fc86a --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/hal_uart.h @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __HAL_UART_H__ +#define __HAL_UART_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct samd21_uart_config { + Sercom *suc_sercom; + enum usart_signal_mux_settings suc_mux_setting; + enum gclk_generator suc_generator_source; + enum usart_sample_rate suc_sample_rate; + enum usart_sample_adjustment suc_sample_adjustment; + uint32_t suc_pad0; + uint32_t suc_pad1; + uint32_t suc_pad2; + uint32_t suc_pad3; +}; + +/* + * This fetches UART config for this UART port. +*/ +const struct samd21_uart_config *bsp_uart_config(int port); + +#ifdef __cplusplus +} +#endif + +#endif /* HAL_UART_H */ + diff --git a/hw/mcu/atmel/samd21xx/include/mcu/mcu.h b/hw/mcu/atmel/samd21xx/include/mcu/mcu.h new file mode 100644 index 0000000000..d72f388c5c --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/mcu.h @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __MCU_MCU_H_ +#define __MCU_MCU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SVC_IRQ_NUMBER SVCall_IRQn + +/* + * Defines for naming GPIOs. + */ +#define MCU_GPIO_PORTA(pin) ((0 * 32) + (pin)) +#define MCU_GPIO_PORTB(pin) ((1 * 32) + (pin)) + +static inline void +hal_debug_break(void) +{ + __BKPT(1); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_MCU_H_ */ diff --git a/hw/mcu/atmel/samd21xx/include/mcu/samd21.h b/hw/mcu/atmel/samd21xx/include/mcu/samd21.h new file mode 100644 index 0000000000..4dbbb07c2e --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/samd21.h @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef SAMD21_H +#define SAMD21_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "src/sam0/utils/cmsis/samd21/include/samd21.h" + +extern struct hal_flash samd21_flash_dev; + +#ifdef __cplusplus +} +#endif + +#endif /* SAMD21_H */ + diff --git a/hw/mcu/atmel/samd21xx/include/mcu/samd21_hal.h b/hw/mcu/atmel/samd21xx/include/mcu/samd21_hal.h new file mode 100644 index 0000000000..e2a615afd3 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/include/mcu/samd21_hal.h @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_SAMD21_HAL_ +#define H_SAMD21_HAL_ + +#ifdef __cplusplus + extern "C" { +#endif + +struct samd21_timer_cfg { + uint8_t src_clock; + int irq_num; + enum gclk_generator clkgen; + Tc *hwtimer; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* H_SAMD21_HAL_ */ + diff --git a/hw/mcu/atmel/samd21xx/pkg.yml b/hw/mcu/atmel/samd21xx/pkg.yml new file mode 100644 index 0000000000..d55d48160f --- /dev/null +++ b/hw/mcu/atmel/samd21xx/pkg.yml @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "hw/mcu/atmel/samd21xx" + +pkg.deps: + - "@apache-mynewt-core/hw/mcu/atmel/samd21xx/ext" + - "@apache-mynewt-core/hw/hal" + - "@apache-mynewt-core/hw/cmsis-core" + +pkg.cflags: + - -std=c99 +# - -DI2C_MASTER_CALLBACK_MODE=true +# - -DI2C_SLAVE_CALLBACK_MODE=true + - -DWDT_CALLBACK_MODE=true + - -DUSART_CALLBACK_MODE=true + - -DCONF_SPI_MASTER_ENABLE=true + - -DRTC_CALENDAR_ASYNC=true + - -DRTC_COUNT_ASYNC=true + - -DI2S_CALLBACK_MODE=true + - -DAC_CALLBACK_MODE=true + - -DEVENTS_INTERRUPT_HOOKS_MODE=true + - -DEXTINT_CALLBACK_MODE=true + - -DSPI_CALLBACK_MODE=true diff --git a/hw/mcu/atmel/samd21xx/samd21xx.ld b/hw/mcu/atmel/samd21xx/samd21xx.ld new file mode 100644 index 0000000000..35e064e185 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/samd21xx.ld @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapBase + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __coredata_start__ + * __coredata_end__ + * __corebss_start__ + * __corebss_end__ + * __ecoredata + * __ecorebss + */ +ENTRY(Reset_Handler) + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + /* Reserve space at the start of the image for the header. */ + .imghdr (NOLOAD): + { + . = . + _imghdr_size; + } > FLASH + + __text = .; + + .text : + { + __isr_vector_start = .; + KEEP(*(.isr_vector)) + __isr_vector_end = .; + *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + PROVIDE(mynewt_main = main); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + + __exidx_end = .; + + __etext = .; + + .vector_relocation : + { + . = ALIGN(4); + __vector_tbl_reloc__ = .; + . = . + (__isr_vector_end - __isr_vector_start); + . = ALIGN(4); + } > RAM + + .coredata : + { + __coredata_start__ = .; + *(.data.core) + . = ALIGN(4); + __coredata_end__ = .; + } > RAM AT > FLASH + + __ecoredata = __etext + SIZEOF(.coredata); + + _sidata = LOADADDR(.data); + + .data : + { + . = ALIGN(4); + _sdata = .; + __data_start__ = _sdata; + *(vtable) + *(.data*) + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + _edata = .; + __data_end__ = _edata; + + } > RAM AT > FLASH + + .bss : + { + . = ALIGN(4); + _sbss = .; + __bss_start__ = _sbss; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + __bss_end__ = _ebss; + } > RAM + + . = ALIGN(8); + __HeapBase = .; + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + _ram_start = ORIGIN(RAM); + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM; stack limit is bottom of stack */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check for RAM overflow */ + ASSERT(__StackLimit >= __bss_end__, "RAM overflow!") +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_flash.c b/hw/mcu/atmel/samd21xx/src/hal_flash.c new file mode 100644 index 0000000000..2e011dccd0 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_flash.c @@ -0,0 +1,245 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Internal flash for STM32F3. + * Size of the flash depends on the MCU model, flash is memory mapped + * and is divided to 2k sectors throughout. + * Programming is done 2 bytes at a time. + */ +#include +#include +#include +#include + + +#define SAMD21_FLASH_START_ADDR (0x0) + +/* The samd all have 4 flash pages per row of flash. + * Each page is individually writeable. Each page is individually + * erasable */ +#define SAMD21_FLASH_PAGES_PER_ROW (4) + +/* sectors for this flash are really small. Use 4 pages per sector */ +#define SAMD21_FLASH_ROWS_PER_SECTOR (4) + +#define SAMD21_FLASH_PAGES_PER_SECTOR (SAMD21_FLASH_PAGES_PER_ROW*SAMD21_FLASH_ROWS_PER_SECTOR) + +static int samd21_flash_read(const struct hal_flash *dev, uint32_t address, + void *dst, uint32_t num_bytes); + +static int samd21_flash_write(const struct hal_flash *dev, uint32_t address, + const void *src, uint32_t num_bytes); + +static int samd21_flash_erase_sector(const struct hal_flash *dev, + uint32_t sector_address); + +static int samd21_flash_sector_info(const struct hal_flash *dev, int idx, + uint32_t *addr, uint32_t *sz); + +static int samd21_flash_init(const struct hal_flash *dev); + +static const struct hal_flash_funcs samd21_flash_funcs = { + .hff_read = samd21_flash_read, + .hff_write = samd21_flash_write, + .hff_erase_sector = samd21_flash_erase_sector, + .hff_sector_info = samd21_flash_sector_info, + .hff_init = samd21_flash_init, +}; + +/* rest will be filled out at runtime */ +struct hal_flash samd21_flash_dev = { + .hf_itf = &samd21_flash_funcs, +}; + +static int +samd21_flash_read(const struct hal_flash *dev, uint32_t address, + void *dst, uint32_t num_bytes) +{ + int base_address; + int offset; + struct nvm_parameters params; + uint8_t page_buffer[64]; + uint8_t *pdst = dst; + + /* make sure this fits into our stack buffer */ + nvm_get_parameters(¶ms); + assert(params.page_size <= sizeof(page_buffer)); + + /* get the page address (this is not a sector, there are 4 pages per + * row */ + while (num_bytes) { + int read_len; + + base_address = address & ~(params.page_size - 1); + + offset = address - base_address; + read_len = params.page_size - offset; + + if (read_len > num_bytes) { + read_len = num_bytes; + } + + if (nvm_read_buffer(base_address, page_buffer, params.page_size) + != STATUS_OK) { + return -1; + } + + /* move the pointers since this is a sure thing now */ + num_bytes -= read_len; + address += read_len; + + /* copy it into the page buffer */ + while (read_len--) { + *pdst++ = page_buffer[offset++]; + } + } + return 0; +} + +static int +samd21_flash_write(const struct hal_flash *dev, uint32_t address, + const void *src, uint32_t len) +{ + int base_address; + int offset; + struct nvm_parameters params; + uint8_t page_buffer[64]; + const uint8_t *psrc = src; + + /* make sure this fits into our stack buffer */ + nvm_get_parameters(¶ms); + assert(params.page_size <= sizeof(page_buffer)); + + /* get the page address (this is not a sector, there are 4 pages per + * row */ + while (len) { + int write_len; + + base_address = address & ~(params.page_size - 1); + + offset = address - base_address; + write_len = params.page_size - offset; + + if (write_len > len) { + write_len = len; + } + + if (nvm_read_buffer(base_address, page_buffer, params.page_size) + != STATUS_OK) { + return -1; + } + + /* move the pointers since this is a sure thing */ + len -= write_len; + address += write_len; + + /* copy it into the page buffer */ + while (write_len--) { + if (page_buffer[offset] != 0xff) { + /* + * Cannot write to non-erased location. + */ + return -1; + } + page_buffer[offset++] = *psrc++; + } + + /* 0x000054a4 */ +#if 1 + /* write back the page buffer buffer */ + if (nvm_write_buffer(base_address, page_buffer, params.page_size) + != STATUS_OK) { + return -1; + } +#endif + } + return 0; +} + +static int +samd21_flash_erase_sector(const struct hal_flash *dev, uint32_t sector_address) +{ + struct nvm_parameters params; + int rc; + int i; + + nvm_get_parameters(¶ms); + + /* erase all rows in the sector */ + for (i = 0; i < SAMD21_FLASH_ROWS_PER_SECTOR; i++) { + uint32_t row_address = sector_address + + i * SAMD21_FLASH_PAGES_PER_ROW * params.page_size; + rc = nvm_erase_row(row_address); + if (rc != STATUS_OK) { + return -1; + } + } + return 0; +} + +/* samd21 flash always starts as 0x000000 */ +static int +samd21_flash_sector_info(const struct hal_flash *dev, int idx, + uint32_t *addr, uint32_t *sz) +{ + struct nvm_parameters params; + int sector_size; + int sector_cnt; + + nvm_get_parameters(¶ms); + sector_cnt = params.nvm_number_of_pages / SAMD21_FLASH_PAGES_PER_SECTOR; + sector_size = params.page_size * SAMD21_FLASH_PAGES_PER_SECTOR; + + if ((idx >= sector_cnt) || (idx < 0)) { + return -1; + } + + *sz = sector_size; + *addr = idx * sector_size + SAMD21_FLASH_START_ADDR; + return 0; +} + +static int +samd21_flash_init(const struct hal_flash *dev) +{ + int rc; + struct nvm_config cfg; + struct nvm_parameters params; + nvm_get_config_defaults(&cfg); + + cfg.manual_page_write = false; + rc = nvm_set_config(&cfg); + if (rc != STATUS_OK) { + return -1; + } + + nvm_get_parameters(¶ms); + + /* the samd21 flash doesn't use sector terminology. They use Row and + * page. A row contains 4 pages. Each pages is a fixed size. You can + * only erase based on row. Here I will map the rows to sectors and + * deal with pages inside this driver. */ + samd21_flash_dev.hf_itf = &samd21_flash_funcs; + samd21_flash_dev.hf_base_addr = SAMD21_FLASH_START_ADDR; + samd21_flash_dev.hf_size = params.nvm_number_of_pages * params.page_size; + samd21_flash_dev.hf_sector_cnt = + params.nvm_number_of_pages / SAMD21_FLASH_PAGES_PER_SECTOR; + samd21_flash_dev.hf_align = 1; + samd21_flash_dev.hf_erased_val = 0xff; + + return 0; +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_gpio.c b/hw/mcu/atmel/samd21xx/src/hal_gpio.c new file mode 100644 index 0000000000..3d0d003fe8 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_gpio.c @@ -0,0 +1,460 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hal/hal_gpio.h" + +#include + +#include +#include +#include "port.h" +#include "extint.h" + +/* XXX: Notes + * 4) The code probably does not handle "re-purposing" gpio very well. + * "Re-purposing" means changing a gpio from input to output, or calling + * gpio_init_in and expecting previously enabled interrupts to be stopped. + * + */ + +/* + * GPIO pin mapping + * + * The samD 21G has 48 pins and 38 GPIO. + * + * They are split among 2 ports A (PA0-PA25) and B + * + * , PB8, PB9, + * PB10, PB11, + * PB3 PB2, PB23, PB22, + * + * The port A Pins exposed on the CHIP are + * PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, + * PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15, + * PA16, PA17, PA18, PA19, PA20, PA21, PA22, PA23, + * PA24, PA25, PA27, PA28, PA30, PA31, + * + * The port B pins exposed the chip are + * PB2, PB3, + * PB8, PB9, PB10, PB11, + * + * PB22, PB23, + * + * + * We keep the mapping where ports A0-A31 are pins 0 - 31 + * and ports B0-B31 are pins 32 - 64; + */ + +#define GPIO_PORT(pin) (pin / 32) +#define GPIO_PIN(pin) (pin % 32) + +#define GPIO_MAX_PORT (1) + +/* this defines which pins are valid for the ports */ +static const int valid_pins[GPIO_MAX_PORT + 1] = { + 0xdbffffff, + 0xc0000f0c, +}; + +/* + * Map from pin to external interrupt channel. + */ +static const int8_t hal_gpio_pin_exti_tbl[] = { + 0, /* PA0 */ + 1, /* PA1 */ + 2, /* PA2 */ + 3, /* PA3 */ + 4, /* PA4 */ + 5, /* PA5 */ + 6, /* PA6 */ + 7, /* PA7 */ + -1, /* PA8 */ /* NMI */ + 9, /* PA9 */ + 10, /* PA10 */ + 11, /* PA11 */ + 12, /* PA12 */ + 13, /* PA13 */ + 14, /* PA14 */ + 15, /* PA15 */ + 0, /* PA16 */ + 1, /* PA17 */ + 2, /* PA18 */ + 3, /* PA19 */ + 4, /* PA20 */ + 5, /* PA21 */ + 6, /* PA22 */ + 7, /* PA23 */ + 12, /* PA24 */ + 13, /* PA25 */ + -1, /* PA26 */ + 15, /* PA27 */ + 8, /* PA28 */ + -1, /* PA29 */ + 10, /* PA30 */ + 11, /* PA31 */ + 0, /* PB0 */ + 1, /* PB1 */ + 2, /* PB2 */ + 3, /* PB3 */ + 4, /* PB4 */ + 5, /* PB5 */ + 6, /* PB6 */ + 7, /* PB7 */ + 8, /* PB8 */ + 9, /* PB9 */ + 10, /* PB10 */ + 11, /* PB11 */ + 12, /* PB12 */ + 13, /* PB13 */ + 14, /* PB14 */ + 15, /* PB15 */ + 0, /* PB16 */ + 1, /* PB17 */ + -1, /* PB18 */ + -1, /* PB19 */ + -1, /* PB20 */ + -1, /* PB21 */ + 6, /* PB22 */ + 7, /* PB23 */ + -1, /* PB24 */ + -1, /* PB25 */ + -1, /* PB26 */ + -1, /* PB27 */ + -1, /* PB28 */ + -1, /* PB29 */ + 14, /* PB30 */ + 15, /* PB31 */ +}; + +/* + * Registered interrupt handlers. + */ +struct gpio_irq { + hal_gpio_irq_handler_t func; + void *arg; +} hal_gpio_irqs[EIC_NUMBER_OF_INTERRUPTS]; + +int +hal_gpio_init_out(int pin, int val) +{ + struct port_config cfg; + + int port = GPIO_PORT(pin); + int port_pin = GPIO_PIN(pin); + + if (port > GPIO_MAX_PORT) { + return -1; + } + + if ((port_pin & valid_pins[port]) == 0) { + return -1; + } + + cfg.direction = PORT_PIN_DIR_OUTPUT_WTH_READBACK; + cfg.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + cfg.powersave = false; + + port_pin_set_config(pin, &cfg); + + hal_gpio_write(pin, val); + + return 0; +} + +int +hal_gpio_init_in(int pin, hal_gpio_pull_t pull) +{ + struct port_config cfg; + + int port = GPIO_PORT(pin); + int port_pin = GPIO_PIN(pin); + + if (port > GPIO_MAX_PORT) { + return -1; + } + + if ((port_pin & valid_pins[port]) == 0) { + return -1; + } + + cfg.direction = PORT_PIN_DIR_INPUT; + switch (pull) { + case HAL_GPIO_PULL_NONE: + cfg.input_pull = PORT_PIN_PULL_NONE; + break; + case HAL_GPIO_PULL_UP: + cfg.input_pull = HAL_GPIO_PULL_UP; + break; + case HAL_GPIO_PULL_DOWN: + cfg.input_pull = HAL_GPIO_PULL_DOWN; + break; + default: + return -1; + } + + cfg.powersave = false; + + port_pin_set_config(pin, &cfg); + + return 0; +} + +/** + * gpio read + * + * Reads the specified pin. + * + * @param pin Pin number to read + * + * @return int 0: low, 1: high + */ +int +hal_gpio_read(int pin) +{ + int rc; + int port = GPIO_PORT(pin); + int port_pin = GPIO_PIN(pin); + + assert(port <= GPIO_MAX_PORT); + assert(((1 << port_pin) & valid_pins[port]) != 0); + + rc = port_pin_get_input_level(pin); + return rc; +} + +/** + * gpio write + * + * Write a value (either high or low) to the specified pin. + * + * @param pin Pin to set + * @param val Value to set pin (0:low 1:high) + */ +void +hal_gpio_write(int pin, int val) +{ + if (val) { + port_pin_set_output_level(pin, true); + } else { + port_pin_set_output_level(pin, false); + } +} + +/** + * gpio toggle + * + * Toggles the specified pin + * + * @param pin Pin number to toggle + */ +int +hal_gpio_toggle(int pin) +{ + int pin_state; + + pin_state = (hal_gpio_read(pin) == 0); + hal_gpio_write(pin, pin_state); + return hal_gpio_read(pin); +} + +/* + * Interrupt handler for gpio. + */ +static void +hal_gpio_irq(void) +{ + int i; + struct gpio_irq *irq; + + for (i = 0; i < EIC_NUMBER_OF_INTERRUPTS; i++) { + if (extint_chan_is_detected(i)) { + extint_chan_clear_detected(i); + irq = &hal_gpio_irqs[i]; + if (irq->func) { + irq->func(irq->arg); + } + } + } +} + +/* + * Validate pin, and return extint channel pin belongs to. + */ +static int +hal_gpio_irq_eic(int pin) +{ + int8_t eic; + int port; + int port_pin; + + port = GPIO_PORT(pin); + port_pin = GPIO_PIN(pin); + + if ((port_pin & valid_pins[port]) == 0) { + return -1; + } + eic = hal_gpio_pin_exti_tbl[pin]; + return eic; +} + +/** + * gpio irq init + * + * Initialize an external interrupt on a gpio pin. + * + * @param pin Pin number to enable gpio. + * @param handler Interrupt handler + * @param arg Argument to pass to interrupt handler + * @param trig Trigger mode of interrupt + * @param pull Push/pull mode of input. + * + * @return int + */ +int +hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg, + hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull) +{ + struct extint_chan_conf cfg; + int rc; + int8_t eic; + + NVIC_SetVector(EIC_IRQn, (uint32_t)hal_gpio_irq); + NVIC_EnableIRQ(EIC_IRQn); + + extint_chan_get_config_defaults(&cfg); + + /* Configure the gpio for an external interrupt */ + rc = 0; + switch (trig) { + case HAL_GPIO_TRIG_NONE: + rc = -1; + break; + case HAL_GPIO_TRIG_RISING: + cfg.detection_criteria = EXTINT_DETECT_RISING; + break; + case HAL_GPIO_TRIG_FALLING: + cfg.detection_criteria = EXTINT_DETECT_FALLING; + break; + case HAL_GPIO_TRIG_BOTH: + cfg.detection_criteria = EXTINT_DETECT_BOTH; + break; + case HAL_GPIO_TRIG_LOW: + cfg.detection_criteria = EXTINT_DETECT_LOW; + break; + case HAL_GPIO_TRIG_HIGH: + cfg.detection_criteria = EXTINT_DETECT_HIGH; + break; + default: + rc = -1; + break; + } + if (rc) { + return rc; + } + + switch (pull) { + case HAL_GPIO_PULL_NONE: + cfg.gpio_pin_pull = EXTINT_PULL_NONE; + break; + case HAL_GPIO_PULL_UP: + cfg.gpio_pin_pull = EXTINT_PULL_UP; + break; + case HAL_GPIO_PULL_DOWN: + cfg.gpio_pin_pull = EXTINT_PULL_DOWN; + break; + default: + rc = -1; + break; + } + if (rc) { + return rc; + } + + cfg.gpio_pin = pin; + cfg.gpio_pin_mux = 0; + + eic = hal_gpio_irq_eic(pin); + if (eic < 0) { + return -1; + } + if (hal_gpio_irqs[eic].func) { + return -1; + } + hal_gpio_irqs[eic].func = handler; + hal_gpio_irqs[eic].arg = arg; + + extint_chan_set_config(eic, &cfg); + return 0; +} + +/** + * gpio irq release + * + * No longer interrupt when something occurs on the pin. NOTE: this function + * does not change the GPIO push/pull setting. + * + * @param pin + */ +void +hal_gpio_irq_release(int pin) +{ + int8_t eic; + + eic = hal_gpio_irq_eic(pin); + if (eic < 0) { + return; + } + hal_gpio_irq_disable(pin); + hal_gpio_irqs[eic].func = NULL; +} + +/** + * gpio irq enable + * + * Enable the irq on the specified pin + * + * @param pin + */ +void +hal_gpio_irq_enable(int pin) +{ + int8_t eic; + + eic = hal_gpio_irq_eic(pin); + if (eic < 0) { + return; + } + + extint_chan_enable_callback(eic, EXTINT_CALLBACK_TYPE_DETECT); +} + +/** + * gpio irq disable + * + * + * @param pin + */ +void +hal_gpio_irq_disable(int pin) +{ + int8_t eic; + + eic = hal_gpio_irq_eic(pin); + if (eic < 0) { + return; + } + extint_chan_disable_callback(eic, EXTINT_CALLBACK_TYPE_DETECT); +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_i2c.c b/hw/mcu/atmel/samd21xx/src/hal_i2c.c new file mode 100644 index 0000000000..c56555cb9c --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_i2c.c @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "syscfg/syscfg.h" +#include "compiler.h" +#include "port.h" +#include "i2c_master.h" + +#include "hal/hal_i2c.h" +#include "mcu/hal_i2c.h" +#include "mcu/samd21.h" +#include "samd21_priv.h" + +/* + * XXX Timeout value parameter in functions is not used, because Atmel's + * SDK for i2c internally times out much faster than one OS tick takes. + */ +struct samd21_i2c_state { + struct i2c_master_module module; + const struct samd21_i2c_config *pconfig; + Sercom *hw; +}; + +#define HAL_SAMD21_I2C_MAX (6) + +#if MYNEWT_VAL(I2C_0) +static struct samd21_i2c_state samd21_i2c0; +#endif +#if MYNEWT_VAL(I2C_1) +static struct samd21_i2c_state samd21_i2c1; +#endif +#if MYNEWT_VAL(I2C_2) +static struct samd21_i2c_state samd21_i2c2; +#endif +#if MYNEWT_VAL(I2C_3) +static struct samd21_i2c_state samd21_i2c3; +#endif +#if MYNEWT_VAL(I2C_4) +static struct samd21_i2c_state samd21_i2c4; +#endif +#if MYNEWT_VAL(I2C_5) +static struct samd21_i2c_state samd21_i2c5; +#endif + +struct samd21_i2c_state *samd21_hal_i2cs[HAL_SAMD21_I2C_MAX] = { +#if MYNEWT_VAL(I2C_0) + &samd21_i2c0, +#else + NULL, +#endif +#if MYNEWT_VAL(I2C_1) + &samd21_i2c1, +#else + NULL, +#endif +#if MYNEWT_VAL(I2C_2) + &samd21_i2c2, +#else + NULL, +#endif +#if MYNEWT_VAL(I2C_3) + &samd21_i2c3, +#else + NULL, +#endif +#if MYNEWT_VAL(I2C_4) + &samd21_i2c4, +#else + NULL, +#endif +#if MYNEWT_VAL(I2C_5) + &samd21_i2c5, +#else + NULL, +#endif +}; + +#define SAMD21_I2C_RESOLVE(__n, __v) \ + if ((__n) >= HAL_SAMD21_I2C_MAX || !samd21_hal_i2cs[(__n)]) { \ + rc = EINVAL; \ + goto err; \ + } \ + (__v) = samd21_hal_i2cs[(__n)]; + + +int +hal_i2c_init(uint8_t i2c_num, void *usercfg) +{ + struct samd21_i2c_state *i2c; + enum status_code status; + struct i2c_master_config cfg; + int rc; + + SAMD21_I2C_RESOLVE(i2c_num, i2c); + + assert(usercfg != NULL); + + i2c->hw = samd21_sercom(i2c_num); + if (i2c->hw == NULL) { + rc = EINVAL; + goto err; + } + + i2c->pconfig = (struct samd21_i2c_config *)usercfg; + + i2c_master_get_config_defaults(&cfg); + cfg.pinmux_pad0 = i2c->pconfig->pad0_pinmux; + cfg.pinmux_pad1 = i2c->pconfig->pad1_pinmux; + + status = i2c_master_init(&i2c->module, i2c->hw, &cfg); + if (status != STATUS_OK) { + rc = (int)status; + goto err; + } + + i2c_master_enable(&i2c->module); + + return (0); +err: + return (rc); +} + +int +hal_i2c_master_write(uint8_t i2c_num, struct hal_i2c_master_data *ppkt, + uint32_t os_ticks, uint8_t last_op) +{ + struct samd21_i2c_state *i2c; + struct i2c_master_packet pkt; + enum status_code status; + int rc; + + SAMD21_I2C_RESOLVE(i2c_num, i2c); + + memset(&pkt, 0, sizeof(pkt)); + pkt.address = ppkt->address; + pkt.data_length = ppkt->len; + pkt.data = ppkt->buffer; + + if (last_op) { + status = i2c_master_write_packet_wait(&i2c->module, &pkt); + } else { + status = i2c_master_write_packet_wait_no_stop(&i2c->module, &pkt); + } + if (status != STATUS_OK) { + rc = (int) status; + goto err; + } + + return (0); +err: + return (rc); +} + +int +hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *ppkt, + uint32_t os_ticks, uint8_t last_op) +{ + struct samd21_i2c_state *i2c; + struct i2c_master_packet pkt; + enum status_code status; + int rc; + + SAMD21_I2C_RESOLVE(i2c_num, i2c); + + memset(&pkt, 0, sizeof(pkt)); + pkt.address = ppkt->address; + pkt.data_length = ppkt->len; + pkt.data = ppkt->buffer; + + if (last_op) { + status = i2c_master_read_packet_wait(&i2c->module, &pkt); + } else { + status = i2c_master_read_packet_wait_no_stop(&i2c->module, &pkt); + } + if (status != STATUS_OK) { + rc = (int)status; + goto err; + } + return (0); +err: + return (rc); +} + +int +hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t os_ticks) +{ + struct samd21_i2c_state *i2c; + struct i2c_master_packet pkt; + enum status_code status; + int rc; + uint8_t buf; + + SAMD21_I2C_RESOLVE(i2c_num, i2c); + + memset(&pkt, 0, sizeof(pkt)); + pkt.address = address; + pkt.data_length = 0; + pkt.data = &buf; + + status = i2c_master_read_packet_wait(&i2c->module, &pkt); + if (status != STATUS_OK) { + rc = (int)status; + goto err; + } + + return (0); +err: + return (rc); +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_os_tick.c b/hw/mcu/atmel/samd21xx/src/hal_os_tick.c new file mode 100644 index 0000000000..97dfe731ff --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_os_tick.c @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +/* + * XXX implement tickless mode. + */ +void +os_tick_idle(os_time_t ticks) +{ + OS_ASSERT_CRITICAL(); + __DSB(); + __WFI(); +} + +void +os_tick_init(uint32_t os_ticks_per_sec, int prio) +{ + uint32_t reload_val; + + reload_val = ((uint64_t)SystemCoreClock / os_ticks_per_sec) - 1; + + /* Set the system time ticker up */ + SysTick->LOAD = reload_val; + SysTick->VAL = 0; + SysTick->CTRL = 0x0007; + + /* Set the system tick priority */ + NVIC_SetPriority(SysTick_IRQn, prio); +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_reset_cause.c b/hw/mcu/atmel/samd21xx/src/hal_reset_cause.c new file mode 100644 index 0000000000..c43703dc12 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_reset_cause.c @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include "hal/hal_system.h" + +#include "reset.h" + +enum hal_reset_reason +hal_reset_cause(void) +{ + switch (system_get_reset_cause()) { + case SYSTEM_RESET_CAUSE_SOFTWARE: + return HAL_RESET_SOFT; + case SYSTEM_RESET_CAUSE_WDT: + return HAL_RESET_WATCHDOG; + case SYSTEM_RESET_CAUSE_BOD33: + case SYSTEM_RESET_CAUSE_BOD12: + return HAL_RESET_BROWNOUT; + case SYSTEM_RESET_CAUSE_EXTERNAL_RESET: + return HAL_RESET_PIN; + case SYSTEM_RESET_CAUSE_POR: + default: + return HAL_RESET_POR; + } +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_spi.c b/hw/mcu/atmel/samd21xx/src/hal_spi.c new file mode 100644 index 0000000000..6030480079 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_spi.c @@ -0,0 +1,482 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "syscfg/syscfg.h" +#include "hal/hal_spi.h" +#include "compiler.h" +#include "port.h" +#include "mcu/hal_spi.h" +#include "mcu/samd21.h" +#include "sercom.h" +#include "spi.h" +#include "spi_interrupt.h" +#include "samd21_priv.h" + +#define SAMD21_SPI_FLAG_MASTER (0x1) +#define SAMD21_SPI_FLAG_ENABLED (0x2) +#define SAMD21_SPI_FLAG_XFER (0x4) + +struct samd21_hal_spi { + struct spi_module module; + const struct samd21_spi_config *pconfig; + uint8_t flags; + + hal_spi_txrx_cb txrx_cb; + void *txrx_cb_arg; +}; + +#define HAL_SAMD21_SPI_MAX (6) + +#if MYNEWT_VAL(SPI_0) +static struct samd21_hal_spi samd21_hal_spi0; +#endif +#if MYNEWT_VAL(SPI_1) +static struct samd21_hal_spi samd21_hal_spi1; +#endif +#if MYNEWT_VAL(SPI_2) +static struct samd21_hal_spi samd21_hal_spi2; +#endif +#if MYNEWT_VAL(SPI_3) +static struct samd21_hal_spi samd21_hal_spi3; +#endif +#if MYNEWT_VAL(SPI_4) +static struct samd21_hal_spi samd21_hal_spi4; +#endif +#if MYNEWT_VAL(SPI_5) +static struct samd21_hal_spi samd21_hal_spi5; +#endif + +static struct samd21_hal_spi *samd21_hal_spis[HAL_SAMD21_SPI_MAX] = { +#if MYNEWT_VAL(SPI_0) + &samd21_hal_spi0, +#else + NULL, +#endif +#if MYNEWT_VAL(SPI_1) + &samd21_hal_spi1, +#else + NULL, +#endif +#if MYNEWT_VAL(SPI_2) + &samd21_hal_spi2, +#else + NULL, +#endif +#if MYNEWT_VAL(SPI_3) + &samd21_hal_spi3, +#else + NULL, +#endif +#if MYNEWT_VAL(SPI_4) + &samd21_hal_spi4, +#else + NULL, +#endif +#if MYNEWT_VAL(SPI_5) + &samd21_hal_spi5, +#else + NULL, +#endif +}; + +static int +samd21_hal_spi_rc_from_status(enum status_code status) +{ + switch (status) { + case STATUS_OK: + return 0; + + case STATUS_ERR_INVALID_ARG: + return EINVAL; + + case STATUS_ERR_TIMEOUT: + case STATUS_ERR_DENIED: + case STATUS_ERR_OVERFLOW: + default: + return EIO; + } +} + +static struct samd21_hal_spi * +samd21_hal_spi_resolve(int spi_num) +{ + struct samd21_hal_spi *spi; + + if (spi_num >= HAL_SAMD21_SPI_MAX) { + spi = NULL; + } else { + spi = samd21_hal_spis[spi_num]; + } + + return spi; +} + +static struct samd21_hal_spi * +samd21_hal_spi_resolve_module(const struct spi_module *module) +{ + struct samd21_hal_spi *spi; + int i; + + for (i = 0; i < HAL_SAMD21_SPI_MAX; i++) { + spi = samd21_hal_spis[i]; + if (&spi->module == module) { + return spi; + } + } + + return NULL; +} + +int +hal_spi_init(int spi_num, void *cfg, uint8_t spi_type) +{ + struct samd21_hal_spi *spi; + + if (cfg == NULL) { + return EINVAL; + } + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + memset(spi, 0, sizeof *spi); + + spi->module.hw = samd21_sercom(spi_num); + if (spi->module.hw == NULL) { + return EINVAL; + } + + switch (spi_type) { + case HAL_SPI_TYPE_MASTER: + spi->flags |= SAMD21_SPI_FLAG_MASTER; + break; + + case HAL_SPI_TYPE_SLAVE: + break; + + default: + return EINVAL; + } + + spi->pconfig = cfg; + + return 0; +} + +static int +samd21_spi_config(struct samd21_hal_spi *spi, + struct hal_spi_settings *settings) +{ + struct spi_config cfg; + int rc; + + spi_get_config_defaults(&cfg); + + cfg.pinmux_pad0 = spi->pconfig->pad0_pinmux; + cfg.pinmux_pad1 = spi->pconfig->pad1_pinmux; + cfg.pinmux_pad2 = spi->pconfig->pad2_pinmux; + cfg.pinmux_pad3 = spi->pconfig->pad3_pinmux; + + cfg.mux_setting = spi->pconfig->dopo << SERCOM_SPI_CTRLA_DOPO_Pos | + spi->pconfig->dipo << SERCOM_SPI_CTRLA_DIPO_Pos; + + + /* apply the hal_settings */ + switch (settings->word_size) { + case HAL_SPI_WORD_SIZE_8BIT: + cfg.character_size = SPI_CHARACTER_SIZE_8BIT; + break; + case HAL_SPI_WORD_SIZE_9BIT: + cfg.character_size = SPI_CHARACTER_SIZE_9BIT; + break; + default: + return EINVAL; + } + + switch (settings->data_order) { + case HAL_SPI_LSB_FIRST: + cfg.data_order = SPI_DATA_ORDER_LSB; + break; + case HAL_SPI_MSB_FIRST: + cfg.data_order = SPI_DATA_ORDER_MSB; + break; + default: + return EINVAL; + } + + switch (settings->data_mode) { + case HAL_SPI_MODE0: + cfg.transfer_mode = SPI_TRANSFER_MODE_0; + break; + case HAL_SPI_MODE1: + cfg.transfer_mode = SPI_TRANSFER_MODE_1; + break; + case HAL_SPI_MODE2: + cfg.transfer_mode = SPI_TRANSFER_MODE_2; + break; + case HAL_SPI_MODE3: + cfg.transfer_mode = SPI_TRANSFER_MODE_3; + break; + default: + return EINVAL; + } + + if (spi->flags & SAMD21_SPI_FLAG_MASTER) { + cfg.mode = SPI_MODE_MASTER; + cfg.mode_specific.master.baudrate = settings->baudrate; + } else { + cfg.mode = SPI_MODE_SLAVE; + cfg.mode_specific.slave.frame_format = SPI_FRAME_FORMAT_SPI_FRAME; + cfg.mode_specific.slave.preload_enable = true; + } + + rc = spi_init(&spi->module, spi->module.hw, &cfg); + if (rc != STATUS_OK) { + return EIO; + } + + return 0; +} + +int +hal_spi_config(int spi_num, struct hal_spi_settings *settings) +{ + struct samd21_hal_spi *spi; + int rc; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + if (spi->flags & SAMD21_SPI_FLAG_ENABLED) { + return EACCES; + } + + rc = samd21_spi_config(spi, settings); + if (rc != 0) { + return rc; + } + + return 0; +} + +int +hal_spi_enable(int spi_num) +{ + struct samd21_hal_spi *spi; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + /* Configure and initialize software device instance of peripheral slave */ + spi_enable(&spi->module); + spi->flags |= SAMD21_SPI_FLAG_ENABLED; + + return 0; +} + +int +hal_spi_disable(int spi_num) +{ + struct samd21_hal_spi *spi; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + spi_disable(&spi->module); + spi->flags &= ~SAMD21_SPI_FLAG_ENABLED; + + return 0; +} + +uint16_t +hal_spi_tx_val(int spi_num, uint16_t tx) +{ + struct samd21_hal_spi *spi; + enum status_code status; + uint16_t rx; + + spi = samd21_hal_spi_resolve(spi_num); + assert(spi != NULL); + assert(!(spi->flags & SAMD21_SPI_FLAG_XFER)); + + status = spi_transceive_wait(&spi->module, tx, &rx); + assert(status == 0); + + return rx; +} + +static void +samd21_hal_spi_cb(struct spi_module *module, enum spi_callback callback_type, + uint16_t xfr_count) +{ + struct samd21_hal_spi *spi; + + spi = samd21_hal_spi_resolve_module(module); + if (spi == NULL) { + return; + } + + if (spi->flags & SAMD21_SPI_FLAG_XFER) { + spi->flags &= ~SAMD21_SPI_FLAG_XFER; + + assert(spi->txrx_cb != NULL); + spi->txrx_cb(spi->txrx_cb_arg, xfr_count); + } +} + +int +hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg) +{ + struct samd21_hal_spi *spi; + enum spi_callback type; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + if (spi->flags & SAMD21_SPI_FLAG_XFER) { + return EACCES; + } + + for (type = SPI_CALLBACK_BUFFER_TRANSMITTED; + type != SPI_CALLBACK_N; + type++) { + + if (txrx_cb == NULL) { + spi_disable_callback(&spi->module, type); + } else { + spi_register_callback(&spi->module, samd21_hal_spi_cb, type); + spi_enable_callback(&spi->module, type); + } + } + + spi->txrx_cb = txrx_cb; + spi->txrx_cb_arg = arg; + + return 0; +} + +static int +samd21_hal_spi_txrx_blocking(struct samd21_hal_spi *spi, void *txbuf, + void *rxbuf, uint16_t len) +{ + enum status_code status; + + spi->flags |= SAMD21_SPI_FLAG_XFER; + status = spi_transceive_buffer_wait(&spi->module, txbuf, rxbuf, len); + spi->flags &= ~SAMD21_SPI_FLAG_XFER; + + return samd21_hal_spi_rc_from_status(status); +} + +static int +samd21_hal_spi_txrx_nonblocking(struct samd21_hal_spi *spi, void *txbuf, + void *rxbuf, uint16_t len) +{ + enum status_code status; + + spi->flags |= SAMD21_SPI_FLAG_XFER; + + status = spi_transceive_buffer_job(&spi->module, txbuf, rxbuf, len); + + return samd21_hal_spi_rc_from_status(status); +} + +int +hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int len) +{ + struct samd21_hal_spi *spi; + int rc; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + if (len <= 0 || len > UINT16_MAX) { + return EINVAL; + } + + if (spi->flags & SAMD21_SPI_FLAG_XFER) { + return EALREADY; + } + + if (spi->flags & SAMD21_SPI_FLAG_MASTER) { + if (txbuf == NULL) { + return EINVAL; + } + } else { + if (txbuf == NULL && rxbuf == NULL) { + return EINVAL; + } + } + + if (spi->txrx_cb == NULL) { + rc = samd21_hal_spi_txrx_blocking(spi, txbuf, rxbuf, len); + } else { + rc = samd21_hal_spi_txrx_nonblocking(spi, txbuf, rxbuf, len); + } + if (rc != 0) { + return rc; + } + + return 0; +} + +/** + * Not supported by the Atmel SPI API. + */ +int +hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val) +{ + struct samd21_hal_spi *spi; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + spi_set_dummy(&spi->module, val); + + return 0; +} + +int +hal_spi_abort(int spi_num) +{ + struct samd21_hal_spi *spi; + + spi = samd21_hal_spi_resolve(spi_num); + if (spi == NULL) { + return EINVAL; + } + + spi_abort_job(&spi->module); + spi->flags &= ~SAMD21_SPI_FLAG_XFER; + + return 0; +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_system.c b/hw/mcu/atmel/samd21xx/src/hal_system.c new file mode 100644 index 0000000000..c8b52c11de --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_system.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "hal/hal_system.h" +#include + +void +hal_system_reset(void) +{ + while (1) { + if (hal_debugger_connected()) { + /* + * If debugger is attached, breakpoint here. + */ + __asm__("bkpt"); + } + + /* Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) + are only accessible over DAP and not via processor. Therefore + they are not covered by the Cortex-M0 header file. */ + + NVIC_SystemReset(); + } +} + +int +hal_debugger_connected(void) +{ + return DSU->STATUSB.reg & DSU_STATUSB_DBGPRES; +} + +uint32_t +HAL_GetTick(void) +{ + return 0; +} + +int +HAL_InitTick (uint32_t TickPriority) +{ + return 0; +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_system_start.c b/hw/mcu/atmel/samd21xx/src/hal_system_start.c new file mode 100644 index 0000000000..efa8f0472c --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_system_start.c @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +/** + * Boots the image described by the supplied image header. + * + * @param hdr The header for the image to boot. + */ +void +hal_system_start(void *img_start) +{ + typedef void jump_fn(void); + + uint32_t base0entry; + uint32_t jump_addr; + jump_fn *fn; + + /* First word contains initial MSP value. */ + __set_MSP(*(uint32_t *)img_start); + __set_PSP(*(uint32_t *)img_start); + + /* Second word contains address of entry point (Reset_Handler). */ + base0entry = *(uint32_t *)(img_start + 4); + jump_addr = base0entry; + fn = (jump_fn *)jump_addr; + + /* Jump to image. */ + fn(); +} + diff --git a/hw/mcu/atmel/samd21xx/src/hal_timer.c b/hw/mcu/atmel/samd21xx/src/hal_timer.c new file mode 100644 index 0000000000..4535d3fb9d --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_timer.c @@ -0,0 +1,721 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include "syscfg/syscfg.h" +#include "mcu/cmsis_nvic.h" +#include "hal/hal_timer.h" +#include "src/sam0/drivers/tc/tc.h" +#include "src/sam0/utils/status_codes.h" +#include "src/common/utils/interrupt/interrupt_sam_nvic.h" +#include "mcu/samd21_hal.h" + +/* IRQ prototype */ +typedef void (*hal_timer_irq_handler_t)(void); + +/* Number of timers for HAL */ +#define SAMD21_HAL_TIMER_MAX (3) + +/* Internal timer data structure */ +struct samd21_hal_timer { + uint8_t tmr_enabled; + uint8_t tmr_irq_num; + uint8_t tmr_srcclk; + uint8_t tmr_initialized; + uint32_t tmr_cntr; + uint32_t timer_isrs; + uint32_t tmr_freq; + TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q; + struct tc_module tc_mod; + enum gclk_generator tmr_clkgen; +}; + +#if MYNEWT_VAL(TIMER_0) +struct samd21_hal_timer samd21_hal_timer0; +#endif +#if MYNEWT_VAL(TIMER_1) +struct samd21_hal_timer samd21_hal_timer1; +#endif +#if MYNEWT_VAL(TIMER_2) +struct samd21_hal_timer samd21_hal_timer2; +#endif + +static const struct samd21_hal_timer *samd21_hal_timers[SAMD21_HAL_TIMER_MAX] = { +#if MYNEWT_VAL(TIMER_0) + &samd21_hal_timer0, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_1) + &samd21_hal_timer1, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_2) + &samd21_hal_timer2, +#else + NULL, +#endif +}; + +/* Resolve timer number into timer structure */ +#define SAMD21_HAL_TIMER_RESOLVE(__n, __v) \ + if ((__n) >= SAMD21_HAL_TIMER_MAX) { \ + rc = EINVAL; \ + goto err; \ + } \ + (__v) = (struct samd21_hal_timer *) samd21_hal_timers[(__n)]; \ + if ((__v) == NULL) { \ + rc = EINVAL; \ + goto err; \ + } + +/** + * samd21 timer set ocmp + * + * Set the OCMP used by the timer to the desired expiration tick + * + * NOTE: Must be called with interrupts disabled. + * + * @param timer Pointer to timer. + */ +static void +samd21_timer_set_ocmp(struct samd21_hal_timer *bsptimer, uint32_t expiry) +{ + Tc *hwtimer; + uint16_t expiry16; + uint32_t temp; + int32_t delta_t; + + hwtimer = bsptimer->tc_mod.hw; + + /* Disable ocmp interrupt and set new value */ + hwtimer->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0; + + temp = expiry & 0xffff0000; + delta_t = (int32_t)(temp - bsptimer->tmr_cntr); + if (delta_t < 0) { + goto set_ocmp_late; + } else if (delta_t == 0) { + /* Set ocmp and check if missed it */ + expiry16 = (uint16_t)expiry; + + /* Set output compare register to timer expiration */ + tc_set_compare_value(&bsptimer->tc_mod, TC_COMPARE_CAPTURE_CHANNEL_0, + expiry16); + + /* Clear interrupt flag */ + hwtimer->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; + + /* Enable the output compare interrupt */ + hwtimer->COUNT16.INTENSET.reg = TC_INTENSET_MC0; + + /* Force interrupt to occur as we may have missed it */ + if (tc_get_count_value(&bsptimer->tc_mod) >= expiry16) { + goto set_ocmp_late; + } + } else { + /* Nothing to do; wait for overflow interrupt to set ocmp */ + } + return; + +set_ocmp_late: + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); +} + +/* Disable output compare used for timer */ +static void +samd21_timer_disable_ocmp(Tc *hwtimer) +{ + hwtimer->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0; +} + +static uint32_t +hal_timer_read_bsptimer(struct samd21_hal_timer *bsptimer) +{ + uint16_t low; + uint32_t tcntr; + Tc *hwtimer; + + hwtimer = bsptimer->tc_mod.hw; + cpu_irq_enter_critical(); + tcntr = bsptimer->tmr_cntr; + low = tc_get_count_value(&bsptimer->tc_mod); + if (hwtimer->COUNT16.INTFLAG.reg & TC_INTFLAG_OVF) { + tcntr += 65536; + bsptimer->tmr_cntr = tcntr; + low = tc_get_count_value(&bsptimer->tc_mod); + hwtimer->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + tcntr |= low; + cpu_irq_leave_critical(); + + return tcntr; +} + + +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2)) +/** + * hal timer chk queue + * + * @param bsptimer + */ +static void +hal_timer_chk_queue(struct samd21_hal_timer *bsptimer) +{ + uint32_t tcntr; + struct hal_timer *timer; + + /* disable interrupts */ + cpu_irq_enter_critical(); + + while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) { + tcntr = hal_timer_read_bsptimer(bsptimer); + if ((int32_t)(tcntr - timer->expiry) >= 0) { + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + timer->cb_func(timer->cb_arg); + } else { + break; + } + } + + /* Any timers left on queue? If so, we need to set OCMP */ + timer = TAILQ_FIRST(&bsptimer->hal_timer_q); + if (timer) { + samd21_timer_set_ocmp(bsptimer, timer->expiry); + } else { + samd21_timer_disable_ocmp(bsptimer->tc_mod.hw); + } + + cpu_irq_leave_critical(); +} +#endif + +/** + * hal timer irq handler + * + * Generic HAL timer irq handler. + * + * @param tmr + */ +/** + * hal timer irq handler + * + * This is the global timer interrupt routine. + * + */ +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2)) +static void +hal_timer_irq_handler(struct samd21_hal_timer *bsptimer) +{ + uint8_t compare; + uint8_t ovf_int; + Tc *hwtimer; + + /* Check interrupt source. If set, clear them */ + hwtimer = bsptimer->tc_mod.hw; + compare = hwtimer->COUNT16.INTFLAG.reg & TC_INTFLAG_MC0; + if (compare) { + hwtimer->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; + } + + ovf_int = hwtimer->COUNT16.INTFLAG.reg & TC_INTFLAG_OVF; + if (ovf_int) { + hwtimer->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF; + bsptimer->tmr_cntr += 65536; + } + + + /* XXX: make these stats? */ + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + hal_timer_chk_queue(bsptimer); + compare = hwtimer->COUNT16.INTFLAG.reg; +} +#endif + +#if MYNEWT_VAL(TIMER_0) +void +samd21_timer0_irq_handler(void) +{ + hal_timer_irq_handler(&samd21_hal_timer0); +} +#endif + +#if MYNEWT_VAL(TIMER_1) +void +samd21_timer1_irq_handler(void) +{ + hal_timer_irq_handler(&samd21_hal_timer1); +} +#endif + +#if MYNEWT_VAL(TIMER_2) +void +samd21_timer2_irq_handler(void) +{ + hal_timer_irq_handler(&samd21_hal_timer2); +} +#endif + +/** + * hal timer init + * + * Initialize platform specific timer items + * + * @param timer_num Timer number to initialize + * @param cfg Pointer to platform specific configuration + * + * @return int 0: success; error code otherwise + */ +int +hal_timer_init(int timer_num, void *cfg) +{ + int rc; + uint8_t irq_num; + struct samd21_hal_timer *bsptimer; + struct samd21_timer_cfg *tmr_cfg; + hal_timer_irq_handler_t irq_isr; + struct system_gclk_gen_config gcfg; + + /* Get timer. Make sure not enabled */ + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + if (bsptimer->tmr_enabled) { + rc = EINVAL; + goto err; + } + tmr_cfg = (struct samd21_timer_cfg *)cfg; + + rc = 0; + switch (timer_num) { +#if MYNEWT_VAL(TIMER_0) + case 0: + irq_isr = samd21_timer0_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_1) + case 1: + irq_isr = samd21_timer1_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_2) + case 2: + irq_isr = samd21_timer2_irq_handler; + break; +#endif + default: + rc = -1; + break; + } + + if (rc) { + goto err; + } + + /* set up gclk generator to source this timer */ + gcfg.division_factor = 1; + gcfg.high_when_disabled = false; + gcfg.output_enable = false; + gcfg.run_in_standby = true; + gcfg.source_clock = tmr_cfg->src_clock; + system_gclk_gen_set_config(tmr_cfg->clkgen, &gcfg); + + irq_num = tmr_cfg->irq_num; + bsptimer->tmr_irq_num = irq_num; + bsptimer->tmr_srcclk = tmr_cfg->src_clock; + bsptimer->tmr_clkgen = tmr_cfg->clkgen; + bsptimer->tc_mod.hw = tmr_cfg->hwtimer; + bsptimer->tmr_initialized = 1; + + NVIC_DisableIRQ(irq_num); + NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); + NVIC_SetVector(irq_num, (uint32_t)irq_isr); + + tc_disable(&bsptimer->tc_mod); + + return 0; + +err: + return rc; +} + +/** + * hal timer config + * + * Configure a timer to run at the desired frequency. This starts the timer. + * + * @param timer_num + * @param freq_hz + * + * @return int + */ +int +hal_timer_config(int timer_num, uint32_t freq_hz) +{ + int rc; + uint8_t prescaler; + uint16_t prescaler_reg; + uint32_t div; + uint32_t min_delta; + uint32_t max_delta; + uint32_t max_frequency; + struct samd21_hal_timer *bsptimer; + enum status_code tc_rc; + struct tc_config cfg; + + /* Get timer. Make sure not enabled */ + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + if (bsptimer->tmr_enabled || (bsptimer->tmr_initialized == 0) || + (freq_hz == 0)) { + rc = EINVAL; + goto err; + } + + /* Set tc config to default values */ + tc_get_config_defaults(&cfg); + + /* Determine max frequency based on clock source */ + rc = 0; + switch (bsptimer->tmr_srcclk) { + case GCLK_SOURCE_DFLL48M: + max_frequency = 48000000; + break; + case GCLK_SOURCE_FDPLL: + max_frequency = 96000000; + break; + case GCLK_SOURCE_OSCULP32K: + case GCLK_SOURCE_OSC32K: + case GCLK_SOURCE_XOSC32K: + max_frequency = 32768; + break; + case GCLK_SOURCE_OSC8M: + max_frequency = 8000000; + break; + default: + max_frequency = 0; + rc = -1; + break; + } + div = max_frequency / freq_hz; + + if (rc || (freq_hz > max_frequency) || (div == 0) || (div > 1024)) { + goto err; + } + + /* Set up timer counter. Need to determine prescaler */ + cfg.counter_size = TC_COUNTER_SIZE_16BIT; + + if (div == 1) { + prescaler = 0; + prescaler_reg = 0; + } else { + /* Find closest prescaler */ + prescaler = 1; + prescaler_reg = 1; + while (prescaler < 11) { + if (div <= (1 << prescaler)) { + min_delta = div - (1 << (prescaler - 1)); + max_delta = (1 << prescaler) - div; + if (min_delta < max_delta) { + prescaler -= 1; + } + break; + } + if (prescaler < 4) { + ++prescaler; + } else { + prescaler += 2; + } + ++prescaler_reg; + } + } + cfg.clock_prescaler = prescaler_reg << TC_CTRLA_PRESCALER_Pos; + cfg.clock_source = bsptimer->tmr_clkgen; + + /* set up gclk generator to source this timer */ + system_gclk_gen_enable(bsptimer->tmr_clkgen); + + tc_rc = tc_init(&bsptimer->tc_mod, bsptimer->tc_mod.hw, &cfg); + if (tc_rc == STATUS_OK) { + bsptimer->tc_mod.hw->COUNT16.INTENSET.reg = TC_INTFLAG_OVF; + tc_enable(&bsptimer->tc_mod); + } else { + rc = EINVAL; + goto err; + } + + /* Now set the actual frequency */ + bsptimer->tmr_freq = max_frequency / (1 << prescaler); + bsptimer->tmr_enabled = 1; + + /* Set isr in vector table and enable interrupt */ + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + return 0; + +err: + return rc; +} + +/** + * hal timer deinit + * + * De-initialize a HW timer. + * + * @param timer_num + * + * @return int + */ +int +hal_timer_deinit(int timer_num) +{ + int rc; + struct samd21_hal_timer *bsptimer; + + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + tc_disable(&bsptimer->tc_mod); + system_gclk_gen_disable(bsptimer->tmr_clkgen); + bsptimer->tmr_enabled = 0; + bsptimer->tmr_initialized = 0; + +err: + return rc; +} + +/** + * hal timer get resolution + * + * Get the resolution of the timer. This is the timer period, in nanoseconds + * + * @param timer_num + * + * @return uint32_t The resolution of the timer, in nanoseconds. + */ +uint32_t +hal_timer_get_resolution(int timer_num) +{ + int rc; + uint32_t resolution; + struct samd21_hal_timer *bsptimer; + + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + resolution = 1000000000 / bsptimer->tmr_freq; + return resolution; + +err: + rc = 0; + return rc; +} + +/** + * hal timer read + * + * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only + * the lower 16 bits are valid. If the timer is a 64-bit timer, only the + * low 32-bits are returned. + * + * @return uint32_t The timer counter register. + */ +uint32_t +hal_timer_read(int timer_num) +{ + int rc; + uint32_t tcntr; + struct samd21_hal_timer *bsptimer; + + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + tcntr = hal_timer_read_bsptimer(bsptimer); + return tcntr; + + /* Assert here since there is no invalid return code */ +err: + assert(0); + rc = 0; + return rc; +} + +/** + * hal timer delay + * + * Blocking delay for n ticks + * + * @param timer_num + * @param ticks + * + * @return int 0 on success; error code otherwise. + */ +int +hal_timer_delay(int timer_num, uint32_t ticks) +{ + uint32_t until; + + until = hal_timer_read(timer_num) + ticks; + while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) { + /* Loop here till finished */ + } + + return 0; +} + +/** + * + * Initialize the HAL timer structure with the callback and the callback + * argument. Also initializes the HW specific timer pointer. + * + * @param cb_func + * + * @return int + */ +int +hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func, + void *arg) +{ + int rc; + struct samd21_hal_timer *bsptimer; + + SAMD21_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + timer->cb_func = cb_func; + timer->cb_arg = arg; + timer->link.tqe_prev = NULL; + timer->bsp_timer = bsptimer; + + rc = 0; + +err: + return rc; +} + +int +hal_timer_start(struct hal_timer *timer, uint32_t ticks) +{ + int rc; + uint32_t tick; + struct samd21_hal_timer *bsptimer; + + /* Set the tick value at which the timer should expire */ + bsptimer = (struct samd21_hal_timer *)timer->bsp_timer; + tick = hal_timer_read_bsptimer(bsptimer) + ticks; + rc = hal_timer_start_at(timer, tick); + return rc; +} + +int +hal_timer_start_at(struct hal_timer *timer, uint32_t tick) +{ + struct hal_timer *entry; + struct samd21_hal_timer *bsptimer; + + if ((timer == NULL) || (timer->link.tqe_prev != NULL) || + (timer->cb_func == NULL)) { + return EINVAL; + } + bsptimer = (struct samd21_hal_timer *)timer->bsp_timer; + timer->expiry = tick; + + cpu_irq_enter_critical(); + + if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) { + TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link); + } else { + TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) { + if ((int32_t)(timer->expiry - entry->expiry) < 0) { + TAILQ_INSERT_BEFORE(entry, timer, link); + break; + } + } + if (!entry) { + TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link); + } + } + + /* If this is the head, we need to set new OCMP */ + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + samd21_timer_set_ocmp(bsptimer, timer->expiry); + } + + cpu_irq_leave_critical(); + + return 0; +} + +/** + * hal timer stop + * + * Stop a timer. + * + * @param timer + * + * @return int + */ +int +hal_timer_stop(struct hal_timer *timer) +{ + int reset_ocmp; + struct hal_timer *entry; + struct samd21_hal_timer *bsptimer; + + if (timer == NULL) { + return EINVAL; + } + + bsptimer = (struct samd21_hal_timer *)timer->bsp_timer; + + cpu_irq_enter_critical(); + + if (timer->link.tqe_prev != NULL) { + reset_ocmp = 0; + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + /* If first on queue, we will need to reset OCMP */ + entry = TAILQ_NEXT(timer, link); + reset_ocmp = 1; + } + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + if (reset_ocmp) { + if (entry) { + samd21_timer_set_ocmp((struct samd21_hal_timer *)entry->bsp_timer, + entry->expiry); + } else { + samd21_timer_disable_ocmp(bsptimer->tc_mod.hw); + } + } + } + + cpu_irq_leave_critical(); + + return 0; +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_uart.c b/hw/mcu/atmel/samd21xx/src/hal_uart.c new file mode 100644 index 0000000000..056fb310d1 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_uart.c @@ -0,0 +1,312 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hal/hal_uart.h" +#include "hal/hal_gpio.h" +#include "mcu/cmsis_nvic.h" +#include "bsp/bsp.h" +#include +#include +#include +#include +#include "usart_interrupt.h" +#include + +#define UART_CNT (SERCOM_INST_NUM) +#define TX_BUFFER_SIZE (8) + +struct hal_uart { + struct usart_module instance; /* must be at top */ + uint8_t u_open; + uint8_t tx_on; + int16_t rxdata; + uint8_t txdata[TX_BUFFER_SIZE]; + hal_uart_rx_char u_rx_func; + hal_uart_tx_char u_tx_func; + hal_uart_tx_done u_tx_done; + void *u_func_arg; + const struct samd21_uart_config *u_cfg; +}; +static struct hal_uart uarts[UART_CNT]; + +static int +fill_tx_buf(struct hal_uart *u) +{ + int i; + + for (i = 0; i < TX_BUFFER_SIZE; i++) { + int val; + val = u->u_tx_func(u->u_func_arg); + if (val < 0) { + break; + } + u->txdata[i] = val; + } + return i; +} + +static void +usart_callback_txdone(struct usart_module *const module) +{ + int sz; + + struct hal_uart *u = (struct hal_uart *)module; + + if (!u->u_open) { + return; + } + + sz = fill_tx_buf(u); + + if (sz > 0) { + u->tx_on = 1; + usart_write_buffer_job(&u->instance, u->txdata, sz); + } else { + u->tx_on = 0; + if (u->u_tx_done) { + u->u_tx_done(u->u_func_arg); + } + } +} + +static void +usart_callback_rx(struct usart_module *const module) +{ + struct hal_uart *u = (struct hal_uart *)module; + + if (!u->u_open) { + return; + } + + if (u->u_rx_func) { + u->u_rx_func(u->u_func_arg, (uint8_t)u->rxdata); + } + usart_read_job(&u->instance, (uint16_t *)&u->rxdata); +} + +int +hal_uart_init_cbs(int port, hal_uart_tx_char tx_func, hal_uart_tx_done tx_done, + hal_uart_rx_char rx_func, void *arg) +{ + struct hal_uart *u; + + u = &uarts[port]; + if (port >= UART_CNT || u->u_open) { + return -1; + } + u->u_rx_func = rx_func; + u->u_tx_func = tx_func; + u->u_tx_done = tx_done; + u->u_func_arg = arg; + return 0; +} + +void +hal_uart_start_rx(int port) +{ + struct hal_uart *u; + + u = &uarts[port]; + if (port >= UART_CNT || !u->u_open) { + return; + } + usart_read_job(&u->instance, (uint16_t *)&u->rxdata); +} + +void +hal_uart_start_tx(int port) +{ + struct hal_uart *u; + u = &uarts[port]; + if (port >= UART_CNT || !u->u_open) { + return; + } + + if (u->tx_on) { + /* we are already transmitting */ + return; + } + + if (u->u_tx_func) { + int sz; + sz = fill_tx_buf(u); + if (sz > 0) { + u->tx_on = 1; + usart_write_buffer_job(&u->instance, u->txdata, sz); + } + } +} + +void +hal_uart_blocking_tx(int port, uint8_t data) +{ + struct hal_uart *u; + u = &uarts[port]; + + if (!u->u_open) { + return; + } + + usart_disable_callback(&u->instance, USART_CALLBACK_BUFFER_TRANSMITTED); + usart_write_wait(&u->instance, data); + usart_enable_callback(&u->instance, USART_CALLBACK_BUFFER_TRANSMITTED); +} + +int +hal_uart_config(int port, int32_t baudrate, uint8_t databits, uint8_t stopbits, + enum hal_uart_parity parity, enum hal_uart_flow_ctl flow_ctl) +{ + struct usart_module *pinst = &uarts[port].instance; + struct usart_config config_usart; + const struct samd21_uart_config *samd21_cfg; + SercomUsart *su; + int i; + + if (uarts[port].u_open) { + return -1; + } + + samd21_cfg = uarts[port].u_cfg; + if (!samd21_cfg) { + return -1; + } + + usart_get_config_defaults(&config_usart); + + config_usart.baudrate = baudrate; + + config_usart.transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY; + + switch (databits) { + case 5: + config_usart.character_size = USART_CHARACTER_SIZE_5BIT; + break; + case 6: + config_usart.character_size = USART_CHARACTER_SIZE_6BIT; + break; + case 7: + config_usart.character_size = USART_CHARACTER_SIZE_7BIT; + break; + case 8: + config_usart.character_size = USART_CHARACTER_SIZE_8BIT; + break; + case 9: + config_usart.character_size = USART_CHARACTER_SIZE_9BIT; + break; + default: + return -1; + } + + switch (parity) { + case HAL_UART_PARITY_NONE: + config_usart.parity = USART_PARITY_NONE; + break; + case HAL_UART_PARITY_ODD: + config_usart.parity = USART_PARITY_ODD; + break; + case HAL_UART_PARITY_EVEN: + config_usart.parity = USART_PARITY_EVEN; + break; + default: + return -1; + } + + switch (stopbits) { + case 1: + config_usart.stopbits = USART_STOPBITS_1; + break; + case 2: + config_usart.stopbits = USART_STOPBITS_2; + break; + default: + return -1; + } + + switch (flow_ctl) { + case HAL_UART_FLOW_CTL_RTS_CTS: + break; + case HAL_UART_FLOW_CTL_NONE: + break; + default: + return -1; + } + + config_usart.mux_setting = samd21_cfg->suc_mux_setting; + config_usart.generator_source = samd21_cfg->suc_generator_source; + config_usart.sample_adjustment = samd21_cfg->suc_sample_adjustment; + config_usart.sample_rate = samd21_cfg->suc_sample_rate; + config_usart.pinmux_pad0 = samd21_cfg->suc_pad0; + config_usart.pinmux_pad1 = samd21_cfg->suc_pad1; + config_usart.pinmux_pad2 = samd21_cfg->suc_pad2; + config_usart.pinmux_pad3 = samd21_cfg->suc_pad3; + + /* Reset module */ + su = &samd21_cfg->suc_sercom->USART; + su->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE; + su->CTRLA.reg |= SERCOM_USART_CTRLA_SWRST; + + for (i = 0; i < 100; i++) { + if ((su->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) == 0) { + break; + } + } + + if (usart_init(pinst, samd21_cfg->suc_sercom, &config_usart) != STATUS_OK) { + return -1; + } + + /* register callbacks */ + usart_register_callback(pinst, usart_callback_txdone, + USART_CALLBACK_BUFFER_TRANSMITTED); + + usart_register_callback(pinst, usart_callback_rx, + USART_CALLBACK_BUFFER_RECEIVED); + + usart_enable_callback(pinst, USART_CALLBACK_BUFFER_TRANSMITTED); + usart_enable_callback(pinst, USART_CALLBACK_BUFFER_RECEIVED); + usart_enable(pinst); + uarts[port].u_open = 1; + + hal_uart_start_rx(port); + + return 0; +} + +int +hal_uart_close(int port) +{ + struct usart_module *pinst = &uarts[port].instance; + + usart_disable_callback(pinst, USART_CALLBACK_BUFFER_TRANSMITTED); + usart_disable_callback(pinst, USART_CALLBACK_BUFFER_RECEIVED); + usart_disable(pinst); + + return 0; +} + +int +hal_uart_init(int port, void *arg) +{ + struct hal_uart *u; + + if (port >= UART_CNT) { + return -1; + } + u = &uarts[port]; + u->u_cfg = (const struct samd21_uart_config *)arg; + + return 0; +} diff --git a/hw/mcu/atmel/samd21xx/src/hal_watchdog.c b/hw/mcu/atmel/samd21xx/src/hal_watchdog.c new file mode 100644 index 0000000000..e3a954864d --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/hal_watchdog.c @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "hal/hal_watchdog.h" +#include "wdt.h" + +struct wdt_conf g_wdt_config; + +int +hal_watchdog_init(uint32_t expire_msecs) +{ + uint32_t clocks; + uint16_t temp; + uint16_t to_period; + enum status_code rc; + struct system_gclk_gen_config gcfg; + + /* Get the defaults */ + wdt_get_config_defaults(&g_wdt_config); + g_wdt_config.enable = false; + + /* + * We are using the low-power oscillator for the WDT and we use clock + * generator 4. This clock generator has a maximum of 8 divide bits. The + * samd21 allows the divisor to be 2^divisor to increase the divisor range. + * Since we want to allow for a long watchdog timeout, we want to divide + * the 32.768 clock by a large amount, as the watchdog timeout can be a + * maximum of 16384 clock cycles. We thus chose 2048 as a divisor. This + * gives the watchdog timeout a range of 2048 seconds, or ~34 minutes. + * If a large watchdog timeout period is requested, we return error. + * + * XXX: change this! + * Another note: since we dont know if the oscillator is calibrated, + * we multiply the number of clocks by 2. + */ + clocks = 32768 / 2048; + clocks = (clocks * expire_msecs) / 1000; + clocks = clocks * 2; + + /* The watchdog count starts at 8 and goes up to 16384 max. */ + temp = 8; + to_period = WDT_PERIOD_8CLK; + while (1) { + if (clocks <= temp) { + break; + } + temp <<= 1; + ++to_period; + if (to_period > WDT_PERIOD_16384CLK) { + return -1; + } + } + g_wdt_config.timeout_period = to_period; + + gcfg.division_factor = 2048; + gcfg.high_when_disabled = false; + gcfg.output_enable = true; /* XXX: why is this set true? */ + gcfg.run_in_standby = true; + gcfg.source_clock = GCLK_SOURCE_OSCULP32K; + system_gclk_gen_set_config(g_wdt_config.clock_source, &gcfg); + system_gclk_gen_enable(g_wdt_config.clock_source); + + /* We init but dont turn on device */ + rc = wdt_set_config(&g_wdt_config); + + return ((int)rc); +} + +void +hal_watchdog_enable(void) +{ + g_wdt_config.enable = true; + wdt_set_config(&g_wdt_config); +} + +void +hal_watchdog_tickle(void) +{ + wdt_reset_count(); +} diff --git a/hw/mcu/atmel/samd21xx/src/samd21_mcu_id.c b/hw/mcu/atmel/samd21xx/src/samd21_mcu_id.c new file mode 100644 index 0000000000..7370cfb308 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/samd21_mcu_id.c @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * In SAM D20 / SAM D21 / SAM R21 devices, each device has a unique + * 128-bit serial number which is a concatenation of four 32-bit words + * contained at the following addresses: + * + * Word 0: 0x0080A00C + * Word 1: 0x0080A040 + * Word 2: 0x0080A044 + * Word 3: 0x0080A048 + */ +#include +#include + +#include "hal/hal_bsp.h" + +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif + +int +hal_bsp_hw_id_len(void) +{ + return 16; +} + +/* + * This can be used as the unique hardware identifier for the platform, as + * it's supposed to be unique for this particular MCU. + */ +int +hal_bsp_hw_id(uint8_t *id, int max_len) +{ + int len, cnt; + + cnt = min(sizeof(uint32_t), max_len); + memcpy(id, (void *)0x0080A00C, cnt); + len = cnt; + + cnt = min(3 * sizeof(uint32_t), max_len - len); + memcpy(id + len, (void *)0x0080A040, cnt); + + return len + cnt; +} diff --git a/hw/mcu/atmel/samd21xx/src/samd21_misc.c b/hw/mcu/atmel/samd21xx/src/samd21_misc.c new file mode 100644 index 0000000000..90741d0af9 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/samd21_misc.c @@ -0,0 +1,35 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +#include "samd21_priv.h" + +static Sercom *const samd21_sercoms[SERCOM_INST_NUM] = SERCOM_INSTS; + +Sercom * +samd21_sercom(int inst_num) +{ + if (inst_num < 0 || inst_num >= SERCOM_INST_NUM) { + return NULL; + } + + return samd21_sercoms[inst_num]; +} diff --git a/hw/mcu/atmel/samd21xx/src/samd21_priv.h b/hw/mcu/atmel/samd21xx/src/samd21_priv.h new file mode 100644 index 0000000000..383a74e004 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/samd21_priv.h @@ -0,0 +1,28 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_SAMD21_PRIV_ +#define H_SAMD21_PRIV_ + +#include "mcu/samd21.h" + +Sercom *samd21_sercom(int inst_num); + +#endif diff --git a/hw/mcu/atmel/samd21xx/src/system_samd21.c b/hw/mcu/atmel/samd21xx/src/system_samd21.c new file mode 100644 index 0000000000..56dc50da60 --- /dev/null +++ b/hw/mcu/atmel/samd21xx/src/system_samd21.c @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015 Runtime Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "samd21.h" +#include "system.h" + +void hal_system_init(void) +{ + /* Change default QOS values to have the best performance and correct USB behaviour */ + SBMATRIX->SFR[SBMATRIX_SLAVE_HMCRAMC0].reg = 2; +#if defined(ID_USB) + USB->DEVICE.QOSCTRL.bit.CQOS = 2; + USB->DEVICE.QOSCTRL.bit.DQOS = 2; +#endif + DMAC->QOSCTRL.bit.DQOS = 2; + DMAC->QOSCTRL.bit.FQOS = 2; + DMAC->QOSCTRL.bit.WRBQOS = 2; + + /* Overwriting the default value of the NVMCTRL.CTRLB.MANW bit (errata reference 13134) */ + NVMCTRL->CTRLB.bit.MANW = 1; + + /* Configure GCLK and clock sources according to conf_clocks.h */ + system_init(); +} diff --git a/hw/mcu/atmel/samd21xx/syscfg.yml b/hw/mcu/atmel/samd21xx/syscfg.yml new file mode 100644 index 0000000000..766290a5da --- /dev/null +++ b/hw/mcu/atmel/samd21xx/syscfg.yml @@ -0,0 +1,92 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + MCU_FLASH_MIN_WRITE_SIZE: + description: > + Specifies the required alignment for internal flash writes. + Used internally by the newt tool. + value: 1 + + SPI_0: + description: 'Whether to enable SPI0' + value: 0 + SPI_0_TYPE: + description: 'Decide whether SPI0 operates in master or slave mode' + value: 'HAL_SPI_TYPE_MASTER' + + SPI_1: + description: 'Whether to enable SPI1' + value: 0 + SPI_1_TYPE: + description: 'Decide whether SPI1 operates in master or slave mode' + value: 'HAL_SPI_TYPE_MASTER' + + SPI_2: + description: 'Whether to enable SPI2, aka WINC1500 SPI' + value: 0 + SPI_2_TYPE: + description: 'SPI2 mode, should be master' + value: 'HAL_SPI_TYPE_MASTER' + + SPI_3: + description: 'Whether to enable SPI3' + value: 0 + SPI_3_TYPE: + description: 'Decide whether SPI3 operates in master or slave mode' + value: 'HAL_SPI_TYPE_MASTER' + + I2C_0: + description: 'Whether to enable I2C interface 0' + value: 0 + I2C_0_FREQ_KHZ: + description: 'Frequency in khz for I2C_0 bus' + value: 100 + I2C_1: + description: 'Whether to enable I2C interface 1' + value: 0 + I2C_1_FREQ_KHZ: + description: 'Frequency in khz for I2C_1 bus' + value: 100 + I2C_2: + description: 'Whether to enable I2C interface 2' + value: 0 + I2C_2_FREQ_KHZ: + description: 'Frequency in khz for I2C_2 bus' + value: 100 + I2C_3: + description: 'Whether to enable I2C interface 3' + value: 0 + I2C_3_FREQ_KHZ: + description: 'Frequency in khz for I2C_3 bus' + value: 100 + I2C_4: + description: 'Whether to enable I2C interface 4' + value: 0 + I2C_4_FREQ_KHZ: + description: 'Frequency in khz for I2C_4 bus' + value: 100 + I2C_5: + description: 'Whether to enable I2C interface 5' + value: 0 + I2C_5_FREQ_KHZ: + description: 'Frequency in khz for I2C_5 bus' + value: 100 + +syscfg.vals: + OS_TICKS_PER_SEC: 1000