Initial commit

This commit is contained in:
Bottersnike 2024-06-29 21:17:34 +01:00
commit 81873aa1ec
No known key found for this signature in database
87 changed files with 34307 additions and 0 deletions

6
.clang-format Normal file
View File

@ -0,0 +1,6 @@
BasedOnStyle: Google
UseTab: Never
BreakBeforeBraces: Custom
IndentWidth: 4
ColumnLimit: 100
Cpp11BracedListStyle: false

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# Picolibc
picolibc/*
# Misc testing files
*.py
# Build artifacts
obj/*
host_aprom.bin

11
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "GCC",
"includePath": ["C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/13.2 Rel1/arm-none-eabi/include", "NUC123/inc", "NUC123/StdDriver/inc"],
"defines": [],
"intelliSenseMode": "gcc-arm"
}
],
"version": 4
}

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"aaron-bond.better-comments",
"marus25.cortex-debug",
"llvm-vs-code-extensions.vscode-clangd"
]
}

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Host APROM Debug",
"preLaunchTask": "Build Host APROM",
"cwd": "${workspaceFolder}",
"executable": "./obj/host_aprom.elf",
"request": "launch",
"type": "cortex-debug",
"runToEntryPoint": "_start",
"servertype": "openocd",
"serverpath": "../../openocd-0.12.0-3/bin/openocd",
"configFiles": ["interface/stlink-v2.cfg", "../../nucxxx.cfg"],
"showDevDebugOutput": "raw",
}
]
}

16
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"clangd.arguments": ["--query-driver=*arm-none-eabi-*"],
"clangd.fallbackFlags": [
"-IC:/Program Files (x86)/GNU Arm Embedded Toolchain/13.2 Rel1/arm-none-eabi/include",
"-I${workspaceFolder}/NUC123/inc",
"-I${workspaceFolder}/NUC123/StdDriver/inc",
"-D__GNUC__",
"-Wno-pointer-to-int-cast",
"-Wno-int-to-pointer-cast",
],
"cortex-debug.variableUseNaturalFormat": true,
"cortex-debug.liveWatchRefreshRate": 1000,
"cortex-debug.enableTelemetry": false,
"files.trimFinalNewlines": true,
"editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd",
}

19
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Host APROM",
"command": "make",
"args": [
"-j",
"all"
],
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}

27
Development.md Normal file
View File

@ -0,0 +1,27 @@
# Development
## Requirements
- Windows (Strongly recommend. Compiling on anything else is not officially supported.)
- [Make for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)
- On the path, please
- [Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) (Currently using 13.2 Rel1)
- To make your life easier, ensure this is located at `C:\Program Files (x86)\GNU Arm Embedded Toolchain\13.2 Rel1`
- [picolibc 1.8.6](https://github.com/picolibc/picolibc/releases/download/1.8.6/picolibc-1.8.6-13.2.Rel1.zip)
- Place the contents of this zip file in `picolibc`
VSCode is recommended for development, and all recommended extensions should be installed.
## Compiling and Uploading
Run `make -j` to compile the firmware.
For rapid development, the HID bootloader is quite annoying. `flash.cmd` is provided which reprograms the chip using an ST-Link V2. This requires an OpenOCD installation in the root project folder, along with an existing compiled host bootloader binary.
For debugging in VSCode, install the recommended extensions then hit F5. This requires an OpenOCD installation in the root project folder, and an ST-Link V2.
## NUC123 BSP
The `NUC123` folder is a heavily reduced form of the complete BSP provided by Nuvoton. Modifications should not be made to any files within the `inc` or `StdDriver` folder.
`startup_NUC123.s` is the program entrypoint, and may require modification.
`NUC123.ld` is a modified version of the GCC linker script provided by Nuvoton, and may require modification.
To pull in additional BSP library modules, if required, the `Makefile` should be modified.

21
GCC.mk Normal file
View File

@ -0,0 +1,21 @@
PREFIX = arm-none-eabi-
CC = $(PREFIX)gcc
CXX = $(PREFIX)g++
AS = $(PREFIX)gcc # Rather than AS, so we get preprocessing
AR = $(PREFIX)ar
LD = $(PREFIX)gcc # To pull in stdlib as needed
OBJCOPY = $(PREFIX)objcopy
OBJDUMP = $(PREFIX)objdump
SIZE = $(PREFIX)size
SPECS := -specs=./picolibc/lib/gcc/arm-none-eabi/13.2.1/picolibc.specs
INCLUDES += -I./picolibc/arm-none-eabi/picolibc/arm-none-eabi/include
OPTIM ?= -flto -Os
GCCFLAGS := $(SPECS) -nolibc -nostdlib -nostartfiles -nodefaultlibs -mcpu=cortex-m0 -mthumb -Wl,--gc-sections $(OPTIM) -g
CFLAGS := $(GCCFLAGS) -c -ffunction-sections -fdata-sections -fsigned-char \
-fmessage-length=0 -ffreestanding
ASFLAGS := $(GCCFLAGS) -c -x assembler-with-cpp
LDFLAGS := $(GCCFLAGS) -Lpicolibc/arm-none-eabi/picolibc/arm-none-eabi/lib/thumb/v6-m/nofp

14
Makefile Normal file
View File

@ -0,0 +1,14 @@
SRC_DIR := src
OBJ_DIR := obj
BINARY_NAME := host_aprom
OPTIM := -O0
# OPTIM := -Ofast -flto
# OPTIM := -Os -flto
include GCC.mk
LIBRARY_MODULES := clk uart timer i2c
include NUC123/NUC123.mk
CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
include generic.mk

165
NUC123/NUC123.ld Normal file
View File

@ -0,0 +1,165 @@
/* Linker script to configure memory regions. */
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x10000 /* 64k */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x5000 /* 20k */
}
/* Library configurations */
GROUP(libgcc.a libc.a libm.a libnosys.a)
/* 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
* __copy_table_start__
* __copy_table_end__
* __zero_table_start__
* __zero_table_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
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
* __Vectors_End
* __Vectors_Size
*/
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*(.vectors))
__Vectors_End = .;
__Vectors_Size = __Vectors_End - __Vectors;
__end__ = .;
. = . + 16;
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .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*))
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
. = ALIGN(4);
__etext = .;
.data : AT (__etext)
{
. = ALIGN(4);
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* 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 = .);
KEEP(*(.jcr*))
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (COPY):
{
__HeapBase = .;
__end__ = .;
end = __end__;
KEEP(*(.heap*))
__HeapLimit = .;
} > 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):
{
KEEP(*(.stack*))
} > RAM
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

32
NUC123/NUC123.mk Normal file
View File

@ -0,0 +1,32 @@
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
INCLUDES += -I${SELF_DIR}inc
INCLUDES += -I${SELF_DIR}StdDriver/inc
LDFLAGS += -T ${SELF_DIR}NUC123.ld
$(OBJ_DIR)/startup_NUC123.o: $(SELF_DIR)startup_NUC123.s
@echo Compiling $<
@$(AS) $(ASFLAGS) -o $@ $<
$(OBJ_DIR)/system_NUC123.o: $(SELF_DIR)system_NUC123.c
@echo Compiling $<
@$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(OBJ_DIR)/_syscalls.o: $(SELF_DIR)_syscalls.c
@echo Compiling $<
@$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
.PRECIOUS: $(OBJ_DIR)/NUC123_%.o
$(OBJ_DIR)/NUC123_%.o: $(SELF_DIR)StdDriver/src/%.c
@echo Compiling $<
@$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
DEVICE_OBJECTS :=
DEVICE_OBJECTS += $(OBJ_DIR)/system_NUC123.o
ifneq ($(USE_CUSTOM_STARTUP_ASSEMBLY), 1)
DEVICE_OBJECTS += $(OBJ_DIR)/startup_NUC123.o
endif
DEVICE_OBJECTS += $(OBJ_DIR)/_syscalls.o
$(foreach module,$(LIBRARY_MODULES),$(eval DEVICE_OBJECTS += $(OBJ_DIR)/NUC123_$(module).o))

786
NUC123/NUC123.svd Normal file
View File

@ -0,0 +1,786 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- File naming: <part/series name>.svd -->
<!--
Copyright (C) 2012-2014 ARM Limited. All rights reserved.
Purpose: System Viewer Description (SVD) Example (Schema Version 1.1)
This is a description of a none-existent and incomplete device
for demonstration purposes only.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->
<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" >
<vendor>ARM Ltd.</vendor> <!-- device vendor name -->
<vendorID>ARM</vendorID> <!-- device vendor short name -->
<name>ARM_Example</name> <!-- name of part-->
<series>ARMCM3</series> <!-- device series the device belongs to -->
<version>1.2</version> <!-- version of this description, adding CMSIS-SVD 1.1 tags -->
<description>ARM 32-bit Cortex-M3 Microcontroller based device, CPU clock up to 80MHz, etc. </description>
<licenseText> <!-- this license text will appear in header file. \n force line breaks -->
ARM Limited (ARM) is supplying this software for use with Cortex-M\n
processor based microcontroller, but can be equally used for other\n
suitable processor architectures. This file can be freely distributed.\n
Modifications to this file shall be clearly marked.\n
\n
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED\n
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF\n
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.\n
ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR\n
CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
</licenseText>
<cpu> <!-- details about the cpu embedded in the device -->
<name>CM3</name>
<revision>r1p0</revision>
<endian>little</endian>
<mpuPresent>true</mpuPresent>
<fpuPresent>false</fpuPresent>
<nvicPrioBits>3</nvicPrioBits>
<vendorSystickConfig>false</vendorSystickConfig>
</cpu>
<addressUnitBits>8</addressUnitBits> <!-- byte addressable memory -->
<width>32</width> <!-- bus width is 32 bits -->
<!-- default settings implicitly inherited by subsequent sections -->
<size>32</size> <!-- this is the default size (number of bits) of all peripherals
and register that do not define "size" themselves -->
<access>read-write</access> <!-- default access permission for all subsequent registers -->
<resetValue>0x00000000</resetValue> <!-- by default all bits of the registers are initialized to 0 on reset -->
<resetMask>0xFFFFFFFF</resetMask> <!-- by default all 32Bits of the registers are used -->
<peripherals>
<!-- Timer 0 -->
<peripheral>
<name>TIMER0</name>
<version>1.0</version>
<description>32 Timer / Counter, counting up or down from different sources</description>
<groupName>TIMER</groupName>
<baseAddress>0x40010000</baseAddress>
<size>32</size>
<access>read-write</access>
<addressBlock>
<offset>0</offset>
<size>0x100</size>
<usage>registers</usage>
</addressBlock>
<interrupt>
<name>TIMER0</name>
<value>0</value>
</interrupt>
<registers>
<!-- CR: Control Register -->
<register>
<name>CR</name>
<description>Control Register</description>
<addressOffset>0x00</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0x1337F7F</resetMask>
<fields>
<!-- EN: Enable -->
<field>
<name>EN</name>
<description>Enable</description>
<bitRange>[0:0]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Disable</name>
<description>Timer is disabled and does not operate</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Enable</name>
<description>Timer is enabled and can operate</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- RST: Reset -->
<field>
<name>RST</name>
<description>Reset Timer</description>
<bitRange>[1:1]</bitRange>
<access>write-only</access>
<enumeratedValues>
<enumeratedValue>
<name>No_Action</name>
<description>Write as ZERO if necessary</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Reset_Timer</name>
<description>Reset the Timer</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- CNT: Counting Direction -->
<field>
<name>CNT</name>
<description>Counting direction</description>
<bitRange>[3:2]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Count_UP</name>
<description>Timer Counts UO and wraps, if no STOP condition is set</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Count_DOWN</name>
<description>Timer Counts DOWN and wraps, if no STOP condition is set</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>Toggle</name>
<description>Timer Counts up to MAX, then DOWN to ZERO, if no STOP condition is set</description>
<value>2</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- MODE: Operation Mode -->
<field>
<name>MODE</name>
<description>Operation Mode</description>
<bitRange>[6:4]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Continous</name>
<description>Timer runs continously</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Single_ZERO_MAX</name>
<description>Timer counts to 0x00 or 0xFFFFFFFF (depending on CNT) and stops</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>Single_MATCH</name>
<description>Timer counts to the Value of MATCH Register and stops</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>Reload_ZERO_MAX</name>
<description>Timer counts to 0x00 or 0xFFFFFFFF (depending on CNT), loads the RELOAD Value and continues</description>
<value>3</value>
</enumeratedValue>
<enumeratedValue>
<name>Reload_MATCH</name>
<description>Timer counts to the Value of MATCH Register, loads the RELOAD Value and continues</description>
<value>4</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- PSC: Use Prescaler -->
<field>
<name>PSC</name>
<description>Use Prescaler</description>
<bitRange>[7:7]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Disabled</name>
<description>Prescaler is not used</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Enabled</name>
<description>Prescaler is used as divider</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- CNTSRC: Timer / Counter Soruce Divider -->
<field>
<name>CNTSRC</name>
<description>Timer / Counter Source Divider</description>
<bitRange>[11:8]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>CAP_SRC</name>
<description>Capture Source is used directly</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div2</name>
<description>Capture Source is divided by 2</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div4</name>
<description>Capture Source is divided by 4</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div8</name>
<description>Capture Source is divided by 8</description>
<value>3</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div16</name>
<description>Capture Source is divided by 16</description>
<value>4</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div32</name>
<description>Capture Source is divided by 32</description>
<value>5</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div64</name>
<description>Capture Source is divided by 64</description>
<value>6</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div128</name>
<description>Capture Source is divided by 128</description>
<value>7</value>
</enumeratedValue>
<enumeratedValue>
<name>CAP_SRC_div256</name>
<description>Capture Source is divided by 256</description>
<value>8</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- CAPSRC: Timer / COunter Capture Source -->
<field>
<name>CAPSRC</name>
<description>Timer / Counter Capture Source</description>
<bitRange>[15:12]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>CClk</name>
<description>Core Clock</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_0</name>
<description>GPIO A, PIN 0</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_1</name>
<description>GPIO A, PIN 1</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_2</name>
<description>GPIO A, PIN 2</description>
<value>3</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_3</name>
<description>GPIO A, PIN 3</description>
<value>4</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_4</name>
<description>GPIO A, PIN 4</description>
<value>5</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_5</name>
<description>GPIO A, PIN 5</description>
<value>6</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_6</name>
<description>GPIO A, PIN 6</description>
<value>7</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOA_7</name>
<description>GPIO A, PIN 7</description>
<value>8</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOB_0</name>
<description>GPIO B, PIN 0</description>
<value>9</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOB_1</name>
<description>GPIO B, PIN 1</description>
<value>10</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOB_2</name>
<description>GPIO B, PIN 2</description>
<value>11</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOB_3</name>
<description>GPIO B, PIN 3</description>
<value>12</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOC_0</name>
<description>GPIO C, PIN 0</description>
<value>13</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOC_5</name>
<description>GPIO C, PIN 1</description>
<value>14</value>
</enumeratedValue>
<enumeratedValue>
<name>GPIOC_6</name>
<description>GPIO C, PIN 2</description>
<value>15</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- CAPEDGE: Capture Edge -->
<field>
<name>CAPEDGE</name>
<description>Capture Edge, select which Edge should result in a counter increment or decrement</description>
<bitRange>[17:16]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>RISING</name>
<description>Only rising edges result in a counter increment or decrement</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>FALLING</name>
<description>Only falling edges result in a counter increment or decrement</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>BOTH</name>
<description>Rising and falling edges result in a counter increment or decrement</description>
<value>2</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- TRGEXT: Triggers an other Peripheral -->
<field>
<name>TRGEXT</name>
<description>Triggers an other Peripheral</description>
<bitRange>[21:20]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>NONE</name>
<description>No Trigger is emitted</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>DMA1</name>
<description>DMA Controller 1 is triggered, dependant on MODE</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>DMA2</name>
<description>DMA Controller 2 is triggered, dependant on MODE</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>UART</name>
<description>UART is triggered, dependant on MODE</description>
<value>3</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- Reload: Selects Reload Register n -->
<field>
<name>RELOAD</name>
<description>Select RELOAD Register n to reload Timer on condition</description>
<bitRange>[25:24]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>RELOAD0</name>
<description>Selects Reload Register number 0</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD1</name>
<description>Selects Reload Register number 1</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD2</name>
<description>Selects Reload Register number 2</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD3</name>
<description>Selects Reload Register number 3</description>
<value>3</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- IDR: Inc or dec Reload Register Selection -->
<field>
<name>IDR</name>
<description>Selects, if Reload Register number is incremented, decremented or not modified</description>
<bitRange>[27:26]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>KEEP</name>
<description>Reload Register number does not change automatically</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>INCREMENT</name>
<description>Reload Register number is incremented on each match</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>DECREMENT</name>
<description>Reload Register number is decremented on each match</description>
<value>2</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- START: Starts / Stops the Timer/Counter -->
<field>
<name>S</name>
<description>Starts and Stops the Timer / Counter</description>
<bitRange>[31:31]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>STOP</name>
<description>Timer / Counter is stopped</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>START</name>
<description>Timer / Counter is started</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
</fields>
</register>
<!-- SR: Status Register -->
<register>
<name>SR</name>
<description>Status Register</description>
<addressOffset>0x04</addressOffset>
<size>16</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xD701</resetMask>
<fields>
<!-- RUN: Shows if Timer is running -->
<field>
<name>RUN</name>
<description>Shows if Timer is running or not</description>
<bitRange>[0:0]</bitRange>
<access>read-only</access>
<enumeratedValues>
<enumeratedValue>
<name>Stopped</name>
<description>Timer is not running</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Running</name>
<description>Timer is running</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- MATCH: Shows if a Match was hit -->
<field>
<name>MATCH</name>
<description>Shows if the MATCH was hit</description>
<bitRange>[8:8]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>No_Match</name>
<description>The MATCH condition was not hit</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Match_Hit</name>
<description>The MATCH condition was hit</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- UN: Shows if an underflow occured -->
<field>
<name>UN</name>
<description>Shows if an underflow occured. This flag is sticky</description>
<bitRange>[9:9]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>No_Underflow</name>
<description>No underflow occured since last clear</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Underflow</name>
<description>A minimum of one underflow occured since last clear</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- OV: Shows if an overflow occured -->
<field>
<name>OV</name>
<description>Shows if an overflow occured. This flag is sticky</description>
<bitRange>[10:10]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>No_Overflow</name>
<description>No overflow occured since last clear</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Overflow_occured</name>
<description>A minimum of one overflow occured since last clear</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- RST: Shows if Timer is in RESET state -->
<field>
<name>RST</name>
<description>Shows if Timer is in RESET state</description>
<bitRange>[12:12]</bitRange>
<access>read-only</access>
<enumeratedValues>
<enumeratedValue>
<name>Ready</name>
<description>Timer is not in RESET state and can operate</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>In_Reset</name>
<description>Timer is in RESET state and can not operate</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- RELOAD: Shows the currently active Reload Register -->
<field>
<name>RELOAD</name>
<description>Shows the currently active RELOAD Register</description>
<bitRange>[15:14]</bitRange>
<access>read-only</access>
<enumeratedValues>
<enumeratedValue>
<name>RELOAD0</name>
<description>Reload Register number 0 is active</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD1</name>
<description>Reload Register number 1 is active</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD2</name>
<description>Reload Register number 2 is active</description>
<value>2</value>
</enumeratedValue>
<enumeratedValue>
<name>RELOAD3</name>
<description>Reload Register number 3 is active</description>
<value>3</value>
</enumeratedValue>
</enumeratedValues>
</field>
</fields>
</register>
<!-- INT: Interrupt Register -->
<register>
<name>INT</name>
<description>Interrupt Register</description>
<addressOffset>0x10</addressOffset>
<size>16</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0x0771</resetMask>
<fields>
<!-- EN: Interrupt Enable -->
<field>
<name>EN</name>
<description>Interrupt Enable</description>
<bitRange>[0:0]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Disabled</name>
<description>Timer does not generate Interrupts</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Enable</name>
<description>Timer triggers the TIMERn Interrupt</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
<!-- MODE: Interrupt Mode -->
<field>
<name>MODE</name>
<description>Interrupt Mode, selects on which condition the Timer should generate an Interrupt</description>
<bitRange>[6:4]</bitRange>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>Match</name>
<description>Timer generates an Interrupt when the MATCH condition is hit</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Underflow</name>
<description>Timer generates an Interrupt when it underflows</description>
<value>1</value>
</enumeratedValue>
<enumeratedValue>
<name>Overflow</name>
<description>Timer generates an Interrupt when it overflows</description>
<value>2</value>
</enumeratedValue>
</enumeratedValues>
</field>
</fields>
</register>
<!-- COUNT: Counter Register -->
<register>
<name>COUNT</name>
<description>The Counter Register reflects the actual Value of the Timer/Counter</description>
<addressOffset>0x20</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xFFFFFFFF</resetMask>
</register>
<!-- MATCH: Match Register -->
<register>
<name>MATCH</name>
<description>The Match Register stores the compare Value for the MATCH condition</description>
<addressOffset>0x24</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xFFFFFFFF</resetMask>
</register>
<!-- PRESCALE: Prescale Read Register -->
<register>
<name>PRESCALE_RD</name>
<description>The Prescale Register stores the Value for the prescaler. The cont event gets divided by this value</description>
<addressOffset>0x28</addressOffset>
<size>32</size>
<access>read-only</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xFFFFFFFF</resetMask>
</register>
<!-- PRESCALE: Prescale Write Register -->
<register>
<name>PRESCALE_WR</name>
<description>The Prescale Register stores the Value for the prescaler. The cont event gets divided by this value</description>
<addressOffset>0x28</addressOffset>
<size>32</size>
<access>write-only</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xFFFFFFFF</resetMask>
</register>
<!-- RELOAD: Array of Reload Register with 4 elements-->
<register>
<dim>4</dim>
<dimIncrement>4</dimIncrement>
<dimIndex>0,1,2,3</dimIndex>
<name>RELOAD[%s]</name>
<description>The Reload Register stores the Value the COUNT Register gets reloaded on a when a condition was met.</description>
<addressOffset>0x50</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<resetMask>0xFFFFFFFF</resetMask>
</register>
</registers>
</peripheral>
<!-- Timer 1 -->
<peripheral derivedFrom="TIMER0">
<name>TIMER1</name>
<baseAddress>0x40010100</baseAddress>
<interrupt>
<name>TIMER1</name>
<value>4</value>
</interrupt>
</peripheral>
<!-- Timer 2 -->
<peripheral derivedFrom="TIMER0">
<name>TIMER2</name>
<baseAddress>0x40010200</baseAddress>
<interrupt>
<name>TIMER2</name>
<value>6</value>
</interrupt>
</peripheral>
</peripherals>
</device>

343
NUC123/StdDriver/inc/adc.h Normal file
View File

@ -0,0 +1,343 @@
/**************************************************************************//**
* @file adc.h
* @version V3.00
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series ADC Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __ADC_H__
#define __ADC_H__
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup ADC_Driver ADC Driver
@{
*/
/** @addtogroup ADC_EXPORTED_CONSTANTS ADC Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* ADCR Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_ADCR_ADEN_CONVERTER_DISABLE (0UL<<ADC_ADCR_ADEN_Pos) /*!< ADC converter disable */
#define ADC_ADCR_ADEN_CONVERTER_ENABLE (1UL<<ADC_ADCR_ADEN_Pos) /*!< ADC converter enable */
#define ADC_ADCR_ADMD_SINGLE (0UL<<ADC_ADCR_ADMD_Pos) /*!< Single mode */
#define ADC_ADCR_ADMD_SINGLE_CYCLE (2UL<<ADC_ADCR_ADMD_Pos) /*!< Single cycle scan mode */
#define ADC_ADCR_ADMD_CONTINUOUS (3UL<<ADC_ADCR_ADMD_Pos) /*!< Continuous scan mode */
#define ADC_ADCR_TRGEN_DISABLE (0UL<<ADC_ADCR_TRGEN_Pos) /*!< Disable triggering of A/D conversion by external STADC pin or PWM */
#define ADC_ADCR_TRGEN_ENABLE (1UL<<ADC_ADCR_TRGEN_Pos) /*!< Enable triggering of A/D conversion by external STADC pin or PWM */
#define ADC_ADCR_TRGS_STADC (0UL<<ADC_ADCR_TRGS_Pos) /*!< A/D conversion is started by external STADC pin */
#define ADC_ADCR_TRGS_PWM (3UL<<ADC_ADCR_TRGS_Pos) /*!< A/D conversion is started by PWM */
#define ADC_ADCR_TRGCOND_LOW_LEVEL (0UL<<ADC_ADCR_TRGCOND_Pos) /*!< STADC Low level active */
#define ADC_ADCR_TRGCOND_HIGH_LEVEL (1UL<<ADC_ADCR_TRGCOND_Pos) /*!< STADC High level active */
#define ADC_ADCR_TRGCOND_FALLING_EDGE (2UL<<ADC_ADCR_TRGCOND_Pos) /*!< STADC Falling edge active */
#define ADC_ADCR_TRGCOND_RISING_EDGE (3UL<<ADC_ADCR_TRGCOND_Pos) /*!< STADC Rising edge active */
/*---------------------------------------------------------------------------------------------------------*/
/* ADCHER Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_ADCHER_PRESEL_EXT_INPUT_SIGNAL (0UL<<ADC_ADCHER_PRESEL_Pos) /*!< The input source of channel 7 is the external analog input */
#define ADC_ADCHER_PRESEL_INT_BANDGAP (1UL<<ADC_ADCHER_PRESEL_Pos) /*!< The input source of channel 7 is the internal bandgap voltage */
/*---------------------------------------------------------------------------------------------------------*/
/* ADCMPR Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_ADCMPR_CMPD(x) ((x) << ADC_ADCMPR_CMPD_Pos) /*!< Compare value for compare function */
#define ADC_ADCMPR_CMPMATCNT(x) (((x)-1) << ADC_ADCMPR_CMPMATCNT_Pos) /*!< Match count for compare function */
#define ADC_ADCMPR_CMPCH(x) ((x) << ADC_ADCMPR_CMPCH_Pos) /*!< Compare channel for compare function */
#define ADC_ADCMPR_CMPCOND_LESS_THAN (0<<ADC_ADCMPR_CMPCOND_Pos) /*!< The compare condition is "less than" */
#define ADC_ADCMPR_CMPCOND_GREATER_OR_EQUAL (1<<ADC_ADCMPR_CMPCOND_Pos) /*!< The compare condition is "greater than or equal to" */
#define ADC_ADCMPR_CMPIE_INTERRUPT_ENABLE (ADC_ADCMPR_CMPIE_Msk) /*!< The compare function interrupt enable */
/*---------------------------------------------------------------------------------------------------------*/
/* ADC Interrupt Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_ADF_INT (ADC_ADSR_ADF_Msk) /*!< ADC convert complete interrupt */
#define ADC_CMP0_INT (ADC_ADSR_CMPF0_Msk) /*!< ADC comparator 0 interrupt */
#define ADC_CMP1_INT (ADC_ADSR_CMPF1_Msk) /*!< ADC comparator 1 interrupt */
/*---------------------------------------------------------------------------------------------------------*/
/* ADC Operation Mode Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_SINGLE_MODE 0 /*!< ADC single mode */
#define ADC_SINGLE_CYCLE_MODE 2 /*!< ADC single-cycle scan mode */
#define ADC_CONTINUOUS_MODE 3 /*!< ADC continuous scan mode */
/*---------------------------------------------------------------------------------------------------------*/
/* ADC Trigger Condition Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_LOW_LEVEL 0 /*!< ADC external trigger condition is low level trigger */
#define ADC_HIGH_LEVEL 1 /*!< ADC external trigger condition is high level trigger */
#define ADC_FALLING_EDGE 2 /*!< ADC external trigger condition is falling edge trigger */
#define ADC_RISING_EDGE 3 /*!< ADC external trigger condition is rising edge trigger */
/*---------------------------------------------------------------------------------------------------------*/
/* ADC Compare Condition Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_LESS_THAN 0 /*!< ADC compare condition is "less than the compare value" */
#define ADC_GREATER_OR_EQUAL 1 /*!< ADC compare condition is "greater than or equal to the compare value" */
/*---------------------------------------------------------------------------------------------------------*/
/* Constant Definitions of ADC Channel 7 Input Source */
/*---------------------------------------------------------------------------------------------------------*/
#define ADC_CH7_EXT_INPUT_SIGNAL 0 /*!< External input signal */
#define ADC_CH7_INT_BANDGAP 1 /*!< Internal band-gap voltage */
/*@}*/ /* end of group ADC_EXPORTED_CONSTANTS */
/** @addtogroup ADC_EXPORTED_FUNCTIONS ADC Exported Functions
@{
*/
/**
* @brief Configure the analog input source of channel 7.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Source Decides the analog input source of channel 7. Valid values are:
* - \ref ADC_ADCHER_PRESEL_EXT_INPUT_SIGNAL : External analog input.
* - \ref ADC_ADCHER_PRESEL_INT_BANDGAP : Internal bandgap voltage.
* @return None
* @details Channel 7 supports 2 input sources: External analog voltage, and internal Band-gap voltage.
* @note While using VBG as channel 7 source, ADC module clock must /b not exceed 300kHz.
*/
#define ADC_CONFIG_CH7(adc, u32Source) ((adc)->ADCHER = ((adc)->ADCHER & ~ADC_ADCHER_PRESEL_Msk) | (u32Source))
/**
* @brief Enable PDMA transfer.
* @param[in] adc The pointer of the specified ADC module
* @return None
* @details Enable PDMA to transfer the conversion data.
* @note While enable PDMA transfer, software must set ADIE = 0 to disable interrupt.
*/
#define ADC_ENABLE_PDMA(adc) ((adc)->ADCR |= ADC_ADCR_PTEN_Msk)
/**
* @brief Disable PDMA transfer.
* @param[in] adc The pointer of the specified ADC module
* @return None
* @details Disable PDMA to transfer the conversion data.
*/
#define ADC_DISABLE_PDMA(adc) ((adc)->ADCR &= ~ADC_ADCR_PTEN_Msk)
/**
* @brief Get conversion data of specified channel.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32ChNum ADC Channel, valid value are from 0 to 7.
* @return 16-bit data.
* @details Read RSLT bit field to get conversion data.
*/
#define ADC_GET_CONVERSION_DATA(adc, u32ChNum) ((adc)->ADDR[(u32ChNum)] & ADC_ADDR_RSLT_Msk)
/**
* @brief Return the user-specified interrupt flags.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Mask The combination of following interrupt status bits. Each bit corresponds to a interrupt status.
* Valid values are:
* - \ref ADC_ADF_INT :Convert complete interrupt flag.
* - \ref ADC_CMP0_INT :Comparator 0 interrupt flag.
* - \ref ADC_CMP1_INT :Comparator 1 interrupt flag.
* @return User specified interrupt flags.
* @details Get the status of the ADC interrupt flag.
*/
#define ADC_GET_INT_FLAG(adc, u32Mask) ((adc)->ADSR & (u32Mask))
/**
* @brief This macro clear the selected interrupt status bits.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Mask The combination of following interrupt status bits. Each bit corresponds to a interrupt status.
* Valid values are:
* - \ref ADC_ADF_INT :Convert complete interrupt flag.
* - \ref ADC_CMP0_INT :Comparator 0 interrupt flag.
* - \ref ADC_CMP1_INT :Comparator 1 interrupt flag.
* @return None
* @details ADF (ADSR[0])/CMPF0 (ADSR[1])/CMPF0 (ADSR[2]) can be cleared by writing 1 to itself.
*/
#define ADC_CLR_INT_FLAG(adc, u32Mask) ((adc)->ADSR = (u32Mask))
/**
* @brief Get the busy state of ADC.
* @param[in] adc The pointer of the specified ADC module.
* @retval 0 ADC is not busy.
* @retval 1 ADC is busy.
* @details BUSY(ADSR[3])is mirror of as ADST bit (ADCR[11]).
*/
#define ADC_IS_BUSY(adc) ((adc)->ADSR & ADC_ADSR_BUSY_Msk ? 1 : 0)
/**
* @brief Check if the ADC conversion data is over written or not.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32ChNum ADC Channel, valid value are from 0 to 7.
* @retval 0 ADC data is not overrun.
* @retval 1 ADC data is overrun.
* @details OVERRUN (ADSR[23:16]) is a mirror to OVERRUN (ADDR0~7[16]).
*/
#define ADC_IS_DATA_OVERRUN(adc, u32ChNum) ((adc)->ADSR & (0x1 << (ADC_ADSR_OVERRUN_Pos + (u32ChNum))) ? 1 : 0)
/**
* @brief Check if the ADC conversion data is valid or not.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32ChNum ADC Channel, valid value are from 0 to 7.
* @retval 0 ADC data is not valid.
* @retval 1 ADC data is valid.
* @details VALID (ADDR0~7[17]) is set to 1 when corresponding channel analog input conversion is completed and cleared by hardware after ADDR register is read.
*/
#define ADC_IS_DATA_VALID(adc, u32ChNum) ((adc)->ADSR & (0x1 << (ADC_ADSR_VALID_Pos + (u32ChNum))) ? 1 : 0)
/**
* @brief Power down ADC module.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Disable A/D converter analog circuit for saving power consumption.
* @note None
*/
#define ADC_POWER_DOWN(adc) ((adc)->ADCR &= ~ADC_ADCR_ADEN_Msk)
/**
* @brief Power on ADC module.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Before starting A/D conversion function, ADEN bit (ADCR[0]) should be set to 1.
*/
#define ADC_POWER_ON(adc) ((adc)->ADCR |= ADC_ADCR_ADEN_Msk)
/**
* @brief Configure the comparator 0 and enable it.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32ChNum Specifies the source channel, valid value are from 0 to 7.
* @param[in] u32Condition Specifies the compare condition. Valid values are:
* - \ref ADC_ADCMPR_CMPCOND_LESS_THAN :The compare condition is "less than the compare value".
* - \ref ADC_ADCMPR_CMPCOND_GREATER_OR_EQUAL :The compare condition is "greater than or equal to the compare value.
* @param[in] u32Data Specifies the compare value, valid value are between 0 ~ 0x3FF.
* @param[in] u32MatchCount Specifies the match count setting, valid values are between 1~16.
* @return None
* @details For example, ADC_ENABLE_CMP0(ADC, 5, ADC_ADCMPR_CMPCOND_GREATER_OR_EQUAL, 0x200, 10);
* Means ADC will assert comparator 0 flag if channel 5 conversion result is greater or
* equal to 0x200 for 10 times continuously.
* \hideinitializer
*/
#define ADC_ENABLE_CMP0(adc, \
u32ChNum, \
u32Condition, \
u32Data, \
u32MatchCount) ((adc)->ADCMPR[0] = ((u32ChNum) << ADC_ADCMPR_CMPCH_Pos) | \
(u32Condition) | \
((u32Data) << ADC_ADCMPR_CMPD_Pos) | \
(((u32MatchCount) - 1) << ADC_ADCMPR_CMPMATCNT_Pos) |\
ADC_ADCMPR_CMPEN_Msk)
/**
* @brief Disable comparator 0.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Set CMPEN (ADCMPR0[0]) to 0 to disable ADC controller to compare CMPD (ADCMPR0[25:16]).
*/
#define ADC_DISABLE_CMP0(adc) ((adc)->ADCMPR[0] = 0)
/**
* @brief Configure the comparator 1 and enable it.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32ChNum Specifies the source channel, valid value are from 0 to 7.
* @param[in] u32Condition Specifies the compare condition. Valid values are:
* - \ref ADC_ADCMPR_CMPCOND_LESS_THAN :The compare condition is "less than the compare value".
* - \ref ADC_ADCMPR_CMPCOND_GREATER_OR_EQUAL :The compare condition is "greater than or equal to the compare value.
* @param[in] u32Data Specifies the compare value, valid value are between 0 ~ 0x3FF.
* @param[in] u32MatchCount Specifies the match count setting, valid values are between 1~16.
* @return None
* @details For example, ADC_ENABLE_CMP1(ADC, 5, ADC_ADCMPR_CMPCOND_GREATER_OR_EQUAL, 0x200, 10);
* Means ADC will assert comparator 1 flag if channel 5 conversion result is greater or
* equal to 0x200 for 10 times continuously.
* \hideinitializer
*/
#define ADC_ENABLE_CMP1(adc, \
u32ChNum, \
u32Condition, \
u32Data, \
u32MatchCount) ((adc)->ADCMPR[1] = ((u32ChNum) << ADC_ADCMPR_CMPCH_Pos) | \
(u32Condition) | \
((u32Data) << ADC_ADCMPR_CMPD_Pos) | \
(((u32MatchCount) - 1) << ADC_ADCMPR_CMPMATCNT_Pos) |\
ADC_ADCMPR_CMPEN_Msk)
/**
* @brief Disable comparator 1.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Set CMPEN (ADCMPR1[0]) to 0 to disable ADC controller to compare CMPD (ADCMPR1[25:16]).
*/
#define ADC_DISABLE_CMP1(adc) ((adc)->ADCMPR[1] = 0)
/**
* @brief Set ADC input channel.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Mask Channel enable bit. Each bit corresponds to a input channel. Bit 0 is channel 0, bit 1 is channel 1..., bit 7 is channel 7.
* @return None
* @details Enabled channel will be converted while ADC starts.
* @note NUC123 series MCU ADC can only convert 1 channel at a time. If more than 1 channels are enabled, only channel
* with smallest number will be convert.
*/
#define ADC_SET_INPUT_CHANNEL(adc, u32Mask) ((adc)->ADCHER = ((adc)->ADCHER & ~ADC_ADCHER_CHEN_Msk) | (u32Mask))
/**
* @brief Start the A/D conversion.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details ADST (ADCR[11]) can be set to 1 from three sources: software, PWM Center-aligned trigger and external pin STADC.
*/
#define ADC_START_CONV(adc) ((adc)->ADCR |= ADC_ADCR_ADST_Msk)
/**
* @brief Stop the A/D conversion.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details ADST (ADCR[11]) will be cleared to 0 by hardware automatically at the ends of single mode and single-cycle scan mode.
* In continuous scan mode, A/D conversion is continuously performed until software writes 0 to this bit or chip reset.
*/
#define ADC_STOP_CONV(adc) ((adc)->ADCR &= ~ADC_ADCR_ADST_Msk)
void ADC_Open(ADC_T *adc,
uint32_t u32InputMode,
uint32_t u32OpMode,
uint32_t u32ChMask);
void ADC_Close(ADC_T *adc);
void ADC_EnableHWTrigger(ADC_T *adc,
uint32_t u32Source,
uint32_t u32Param);
void ADC_DisableHWTrigger(ADC_T *adc);
void ADC_EnableInt(ADC_T *adc, uint32_t u32Mask);
void ADC_DisableInt(ADC_T *adc, uint32_t u32Mask);
/*@}*/ /* end of group ADC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group ADC_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__ADC_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

453
NUC123/StdDriver/inc/clk.h Normal file
View File

@ -0,0 +1,453 @@
/**************************************************************************//**
* @file clk.h
* @version V3.0
* $Revision: 16 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series Clock Control Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __CLK_H__
#define __CLK_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup CLK_Driver CLK Driver
@{
*/
/** @addtogroup CLK_EXPORTED_CONSTANTS CLK Exported Constants
@{
*/
#define FREQ_25MHZ 25000000
#define FREQ_50MHZ 50000000
#define FREQ_72MHZ 72000000
#define FREQ_100MHZ 100000000
#define FREQ_200MHZ 200000000
/*---------------------------------------------------------------------------------------------------------*/
/* CLKSEL0 constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
#define CLK_CLKSEL0_HCLK_S_HXT (0x0UL<<CLK_CLKSEL0_HCLK_S_Pos) /*!< Setting HCLK clock source as HXT */
#define CLK_CLKSEL0_HCLK_S_PLL_DIV2 (0x1UL<<CLK_CLKSEL0_HCLK_S_Pos) /*!< Setting HCLK clock source as PLL/2 */
#define CLK_CLKSEL0_HCLK_S_PLL (0x2UL<<CLK_CLKSEL0_HCLK_S_Pos) /*!< Setting HCLK clock source as PLL */
#define CLK_CLKSEL0_HCLK_S_LIRC (0x3UL<<CLK_CLKSEL0_HCLK_S_Pos) /*!< Setting HCLK clock source as LIRC */
#define CLK_CLKSEL0_HCLK_S_HIRC (0x7UL<<CLK_CLKSEL0_HCLK_S_Pos) /*!< Setting HCLK clock source as HIRC */
#define CLK_CLKSEL0_STCLK_S_HXT (0x0UL<<CLK_CLKSEL0_STCLK_S_Pos) /*!< Setting STCLK clock source as HXT */
#define CLK_CLKSEL0_STCLK_S_HXT_DIV2 (0x2UL<<CLK_CLKSEL0_STCLK_S_Pos) /*!< Setting STCLK clock source as HXT/2 */
#define CLK_CLKSEL0_STCLK_S_HCLK_DIV2 (0x3UL<<CLK_CLKSEL0_STCLK_S_Pos) /*!< Setting STCLK clock source as HCLK/2 */
#define CLK_CLKSEL0_STCLK_S_HIRC_DIV2 (0x7UL<<CLK_CLKSEL0_STCLK_S_Pos) /*!< Setting STCLK clock source as HIRC/2 */
#define CLK_CLKSEL0_STCLK_S_HCLK (0x1UL<<SysTick_CTRL_CLKSOURCE_Pos) /*!< Setting STCLK clock source as HCLK */
/*---------------------------------------------------------------------------------------------------------*/
/* CLKSEL1 constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
#define CLK_CLKSEL1_WDT_S_HCLK_DIV2048 (0x2UL<<CLK_CLKSEL1_WDT_S_Pos) /*!< Setting WDT clock source as HCLK/2048 */
#define CLK_CLKSEL1_WDT_S_LIRC (0x3UL<<CLK_CLKSEL1_WDT_S_Pos) /*!< Setting WDT clock source as LIRC */
#define CLK_CLKSEL1_ADC_S_HXT (0x0UL<<CLK_CLKSEL1_ADC_S_Pos) /*!< Setting ADC clock source as HXT */
#define CLK_CLKSEL1_ADC_S_PLL (0x1UL<<CLK_CLKSEL1_ADC_S_Pos) /*!< Setting ADC clock source as PLL */
#define CLK_CLKSEL1_ADC_S_HCLK (0x2UL<<CLK_CLKSEL1_ADC_S_Pos) /*!< Setting ADC clock source as HCLK */
#define CLK_CLKSEL1_ADC_S_HIRC (0x3UL<<CLK_CLKSEL1_ADC_S_Pos) /*!< Setting ADC clock source as HIRC */
#define CLK_CLKSEL1_SPI0_S_PLL (0x0UL<<CLK_CLKSEL1_SPI0_S_Pos) /*!< Setting SPI0 clock source as PLL */
#define CLK_CLKSEL1_SPI0_S_HCLK (0x1UL<<CLK_CLKSEL1_SPI0_S_Pos) /*!< Setting SPI0 clock source as HCLK */
#define CLK_CLKSEL1_SPI1_S_PLL (0x0UL<<CLK_CLKSEL1_SPI1_S_Pos) /*!< Setting SPI1 clock source as PLL */
#define CLK_CLKSEL1_SPI1_S_HCLK (0x1UL<<CLK_CLKSEL1_SPI1_S_Pos) /*!< Setting SPI1 clock source as HCLK */
#define CLK_CLKSEL1_SPI2_S_PLL (0x0UL<<CLK_CLKSEL1_SPI2_S_Pos) /*!< Setting SPI2 clock source as PLL */
#define CLK_CLKSEL1_SPI2_S_HCLK (0x1UL<<CLK_CLKSEL1_SPI2_S_Pos) /*!< Setting SPI2 clock source as HCLK */
#define CLK_CLKSEL1_TMR0_S_HXT (0x0UL<<CLK_CLKSEL1_TMR0_S_Pos) /*!< Setting TMR0 clock source as HXT */
#define CLK_CLKSEL1_TMR0_S_HCLK (0x2UL<<CLK_CLKSEL1_TMR0_S_Pos) /*!< Setting TMR0 clock source as HCLK */
#define CLK_CLKSEL1_TMR0_S_EXT_TRG (0x3UL<<CLK_CLKSEL1_TMR0_S_Pos) /*!< Setting TMR0 clock source as external trigger */
#define CLK_CLKSEL1_TMR0_S_LIRC (0x5UL<<CLK_CLKSEL1_TMR0_S_Pos) /*!< Setting TMR0 clock source as LIRC */
#define CLK_CLKSEL1_TMR0_S_HIRC (0x7UL<<CLK_CLKSEL1_TMR0_S_Pos) /*!< Setting TMR0 clock source as HIRC */
#define CLK_CLKSEL1_TMR1_S_HXT (0x0UL<<CLK_CLKSEL1_TMR1_S_Pos) /*!< Setting TMR1 clock source as HXT */
#define CLK_CLKSEL1_TMR1_S_HCLK (0x2UL<<CLK_CLKSEL1_TMR1_S_Pos) /*!< Setting TMR1 clock source as HCLK */
#define CLK_CLKSEL1_TMR1_S_EXT_TRG (0x3UL<<CLK_CLKSEL1_TMR1_S_Pos) /*!< Setting TMR1 clock source as external trigger */
#define CLK_CLKSEL1_TMR1_S_LIRC (0x5UL<<CLK_CLKSEL1_TMR1_S_Pos) /*!< Setting TMR1 clock source as LIRC */
#define CLK_CLKSEL1_TMR1_S_HIRC (0x7UL<<CLK_CLKSEL1_TMR1_S_Pos) /*!< Setting TMR1 clock source as HIRC*/
#define CLK_CLKSEL1_TMR2_S_HXT (0x0UL<<CLK_CLKSEL1_TMR2_S_Pos) /*!< Setting TMR2 clock source as external X'tal */
#define CLK_CLKSEL1_TMR2_S_HCLK (0x2UL<<CLK_CLKSEL1_TMR2_S_Pos) /*!< Setting TMR2 clock source as HCLK */
#define CLK_CLKSEL1_TMR2_S_EXT_TRG (0x3UL<<CLK_CLKSEL1_TMR2_S_Pos) /*!< Setting TMR2 clock source as external trigger */
#define CLK_CLKSEL1_TMR2_S_LIRC (0x5UL<<CLK_CLKSEL1_TMR2_S_Pos) /*!< Setting TMR2 clock source as LIRC */
#define CLK_CLKSEL1_TMR2_S_HIRC (0x7UL<<CLK_CLKSEL1_TMR2_S_Pos) /*!< Setting TMR2 clock source as HIRC */
#define CLK_CLKSEL1_TMR3_S_HXT (0x0UL<<CLK_CLKSEL1_TMR3_S_Pos) /*!< Setting TMR3 clock source as HXT */
#define CLK_CLKSEL1_TMR3_S_HCLK (0x2UL<<CLK_CLKSEL1_TMR3_S_Pos) /*!< Setting TMR3 clock source as HCLK */
#define CLK_CLKSEL1_TMR3_S_EXT_TRG (0x3UL<<CLK_CLKSEL1_TMR3_S_Pos) /*!< Setting TMR3 clock source as external trigger */
#define CLK_CLKSEL1_TMR3_S_LIRC (0x5UL<<CLK_CLKSEL1_TMR3_S_Pos) /*!< Setting TMR3 clock source as LIRC*/
#define CLK_CLKSEL1_TMR3_S_HIRC (0x7UL<<CLK_CLKSEL1_TMR3_S_Pos) /*!< Setting TMR3 clock source as HIRC */
#define CLK_CLKSEL1_UART_S_HXT (0x0UL<<CLK_CLKSEL1_UART_S_Pos) /*!< Setting UART clock source as HXT */
#define CLK_CLKSEL1_UART_S_PLL (0x1UL<<CLK_CLKSEL1_UART_S_Pos) /*!< Setting UART clock source as PLL */
#define CLK_CLKSEL1_UART_S_HIRC (0x3UL<<CLK_CLKSEL1_UART_S_Pos) /*!< Setting UART clock source as HIRC */
#define CLK_CLKSEL1_PWM01_S_HXT (0x0UL<<CLK_CLKSEL1_PWM01_S_Pos) /*!< Setting PWM01 clock source as HXT,
user must set CLK_CLKSEL2_PWM01_EXT_HXT concurrently to complete clock source as HXT setting*/
#define CLK_CLKSEL1_PWM01_S_HCLK (0x2UL<<CLK_CLKSEL1_PWM01_S_Pos) /*!< Setting PWM01 clock source as HCLK
user must set CLK_CLKSEL2_PWM01_EXT_HCLK concurrently to complete clock source as HCLK setting*/
#define CLK_CLKSEL1_PWM01_S_HIRC (0x3UL<<CLK_CLKSEL1_PWM01_S_Pos) /*!< Setting PWM01 clock source as HIRC clock,
user must set CLK_CLKSEL2_PWM01_EXT_HIRC concurrently to complete clock source as HIRC clock setting*/
#define CLK_CLKSEL1_PWM01_S_LIRC (0x3UL<<CLK_CLKSEL1_PWM01_S_Pos) /*!< Setting PWM01 clock source as LIRC clock,
user must set CLK_CLKSEL2_PWM01_EXT_LIRC concurrently to complete clock source as LIRC clock setting*/
#define CLK_CLKSEL1_PWM23_S_HXT (0x0UL<<CLK_CLKSEL1_PWM23_S_Pos) /*!< Setting PWM23 clock source as HXT,
user must set CLK_CLKSEL2_PWM23_EXT_HXT concurrently to complete clock source as HXT setting*/
#define CLK_CLKSEL1_PWM23_S_HCLK (0x2UL<<CLK_CLKSEL1_PWM23_S_Pos) /*!< Setting PWM23 clock source as HCLK,
user must set CLK_CLKSEL2_PWM23_EXT_HCLK concurrently to complete clock source as HCLK setting*/
#define CLK_CLKSEL1_PWM23_S_HIRC (0x3UL<<CLK_CLKSEL1_PWM23_S_Pos) /*!< Setting PWM23 clock source as HIRC clock,
user must set CLK_CLKSEL2_PWM23_EXT_HIRC concurrently to complete clock source as HIRC clock setting*/
#define CLK_CLKSEL1_PWM23_S_LIRC (0x3UL<<CLK_CLKSEL1_PWM23_S_Pos) /*!< Setting PWM23 clock source as LIRC clock,
user must set CLK_CLKSEL2_PWM23_EXT_LIRC concurrently to complete clock source as LIRC setting*/
/*---------------------------------------------------------------------------------------------------------*/
/* CLKSEL2 constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
#define CLK_CLKSEL2_I2S_S_HXT (0x0UL<<CLK_CLKSEL2_I2S_S_Pos) /*!< Setting I2S clock source as HXT */
#define CLK_CLKSEL2_I2S_S_PLL (0x1UL<<CLK_CLKSEL2_I2S_S_Pos) /*!< Setting I2S clock source as PLL */
#define CLK_CLKSEL2_I2S_S_HCLK (0x2UL<<CLK_CLKSEL2_I2S_S_Pos) /*!< Setting I2S clock source as HCLK */
#define CLK_CLKSEL2_I2S_S_HIRC (0x3UL<<CLK_CLKSEL2_I2S_S_Pos) /*!< Setting I2S clock source as HIRC */
#define CLK_CLKSEL2_FRQDIV_S_HXT (0x0UL<<CLK_CLKSEL2_FRQDIV_S_Pos) /*!< Setting FRQDIV clock source as HXT */
#define CLK_CLKSEL2_FRQDIV_S_HCLK (0x2UL<<CLK_CLKSEL2_FRQDIV_S_Pos) /*!< Setting FRQDIV clock source as HCLK */
#define CLK_CLKSEL2_FRQDIV_S_HIRC (0x3UL<<CLK_CLKSEL2_FRQDIV_S_Pos) /*!< Setting FRQDIV clock source as HIRC */
#define CLK_CLKSEL2_PWM01_EXT_HXT (0x0UL<<CLK_CLKSEL2_PWM01_S_E_Pos)/*!< Setting PWM01 clock source as HXT,
user must set CLK_CLKSEL1_PWM01_HXT concurrently to complete clock source as HXT setting*/
#define CLK_CLKSEL2_PWM01_EXT_HCLK (0x0UL<<CLK_CLKSEL2_PWM01_S_E_Pos)/*!< Setting PWM01 clock source as HCLK,
user must set CLK_CLKSEL1_PWM01_HCLK concurrently to complete clock source as HCLK setting*/
#define CLK_CLKSEL2_PWM01_EXT_HIRC (0x0UL<<CLK_CLKSEL2_PWM01_S_E_Pos)/*!< Setting PWM01 clock source as HIRC,
user must set CLK_CLKSEL1_PWM01_HIRC concurrently to complete clock source as HIRC setting*/
#define CLK_CLKSEL2_PWM01_EXT_LIRC (0x1UL<<CLK_CLKSEL2_PWM01_S_E_Pos)/*!< Setting PWM01 clock source as LIRC,
user must set CLK_CLKSEL1_PWM01_LIRC concurrently to complete clock source as LIRC setting*/
#define CLK_CLKSEL2_PWM23_EXT_HXT (0x0UL<<CLK_CLKSEL2_PWM23_S_E_Pos)/*!< Setting PWM23 clock source as HXT,
user must set CLK_CLKSEL1_PWM23_HXT concurrently to complete clock source as HXT setting*/
#define CLK_CLKSEL2_PWM23_EXT_HCLK (0x0UL<<CLK_CLKSEL2_PWM23_S_E_Pos)/*!< Setting PWM23 clock source as HCLK,
user must set CLK_CLKSEL1_PWM23_HCLK concurrently to complete clock source as HCLK setting*/
#define CLK_CLKSEL2_PWM23_EXT_HIRC (0x0UL<<CLK_CLKSEL2_PWM23_S_E_Pos)/*!< Setting PWM23 clock source as HIRC clock,
user must set CLK_CLKSEL1_PWM23_HIRC concurrently to complete clock source as HIRC setting*/
#define CLK_CLKSEL2_PWM23_EXT_LIRC (0x1UL<<CLK_CLKSEL2_PWM23_S_E_Pos)/*!< Setting PWM23 clock source as LIRC,
user must set CLK_CLKSEL1_PWM23_LIRC concurrently to complete clock source as LIRC setting*/
#define CLK_CLKSEL2_WWDT_S_HCLK_DIV2048 (0x2UL<<CLK_CLKSEL2_WWDT_S_Pos) /*!< Setting WWDT clock source as HCLK/2048 */
#define CLK_CLKSEL2_WWDT_S_LIRC (0x3UL<<CLK_CLKSEL2_WWDT_S_Pos) /*!< Setting WWDT clock source as LIRC */
#define CLK_CLKSEL12_PWM01_S_HXT (CLK_CLKSEL1_PWM01_S_HXT | CLK_CLKSEL2_PWM01_EXT_HXT ) /*!< Setting PWM01 clock source as HXT */
#define CLK_CLKSEL12_PWM01_S_HCLK (CLK_CLKSEL1_PWM01_S_HCLK | CLK_CLKSEL2_PWM01_EXT_HCLK) /*!< Setting PWM01 clock source as HCLK */
#define CLK_CLKSEL12_PWM01_S_HIRC (CLK_CLKSEL1_PWM01_S_HIRC | CLK_CLKSEL2_PWM01_EXT_HIRC) /*!< Setting PWM01 clock source as HIRC */
#define CLK_CLKSEL12_PWM01_S_LIRC (CLK_CLKSEL1_PWM01_S_LIRC | CLK_CLKSEL2_PWM01_EXT_LIRC) /*!< Setting PWM01 clock source as LIRC */
#define CLK_CLKSEL12_PWM23_S_HXT (CLK_CLKSEL1_PWM23_S_HXT | CLK_CLKSEL2_PWM23_EXT_HXT ) /*!< Setting PWM23 clock source as HXT */
#define CLK_CLKSEL12_PWM23_S_HCLK (CLK_CLKSEL1_PWM23_S_HCLK | CLK_CLKSEL2_PWM23_EXT_HCLK) /*!< Setting PWM23 clock source as HCLK */
#define CLK_CLKSEL12_PWM23_S_HIRC (CLK_CLKSEL1_PWM23_S_HIRC | CLK_CLKSEL2_PWM23_EXT_HIRC) /*!< Setting PWM23 clock source as HIRC */
#define CLK_CLKSEL12_PWM23_S_LIRC (CLK_CLKSEL1_PWM23_S_LIRC | CLK_CLKSEL2_PWM23_EXT_LIRC) /*!< Setting PWM23 clock source as LIRC */
/*---------------------------------------------------------------------------------------------------------*/
/* CLKDIV constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
#define CLK_CLKDIV_HCLK(x) ((x)-1) /*!< CLKDIV Setting for HCLK clock divider. It could be 1~16 */
#define CLK_CLKDIV_USB(x) (((x)-1) << CLK_CLKDIV_USB_N_Pos) /*!< CLKDIV Setting for USB clock divider. It could be 1~16 */
#define CLK_CLKDIV_UART(x) (((x)-1) << CLK_CLKDIV_UART_N_Pos) /*!< CLKDIV Setting for UART clock divider. It could be 1~16 */
#define CLK_CLKDIV_ADC(x) (((x)-1) << CLK_CLKDIV_ADC_N_Pos) /*!< CLKDIV Setting for ADC clock divider. It could be 1~256 */
/*---------------------------------------------------------------------------------------------------------*/
/* PLLCON constant definitions. PLL = FIN * NF / NR / NO */
/*---------------------------------------------------------------------------------------------------------*/
#define CLK_PLLCON_PLL_SRC_HXT 0x00000000UL /*!< For PLL clock source is HXT. 4MHz < FIN < 24MHz */
#define CLK_PLLCON_PLL_SRC_HIRC 0x00080000UL /*!< For PLL clock source is HIRC.4MHz < FIN < 24MHz */
#define CLK_PLLCON_NR(x) (((x)-2)<<9) /*!< x must be constant and 2 <= x <= 33. 1.6MHz < FIN/NR < 15MHz */
#define CLK_PLLCON_NF(x) ((x)-2) /*!< x must be constant and 2 <= x <= 513. 100MHz < FIN*NF/NR < 200MHz. (120MHz < FIN*NF/NR < 200MHz is preferred.) */
#define CLK_PLLCON_NO_1 0x0000UL /*!< For output divider is 1 */
#define CLK_PLLCON_NO_2 0x4000UL /*!< For output divider is 2 */
#define CLK_PLLCON_NO_4 0xC000UL /*!< For output divider is 4 */
#if (__HXT == 12000000)
#define CLK_PLLCON_FOR_I2S (0xA54) /*!< Predefined PLLCON setting for 147428571.428571Hz PLL output with 12MHz X'tal */
#define CLK_PLLCON_144MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(2) | CLK_PLLCON_NF( 24) | CLK_PLLCON_NO_1) /*!< Predefined PLLCON setting for 72MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_72MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(2) | CLK_PLLCON_NF( 24) | CLK_PLLCON_NO_2) /*!< Predefined PLLCON setting for 72MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_50MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(3) | CLK_PLLCON_NF( 25) | CLK_PLLCON_NO_2) /*!< Predefined PLLCON setting for 50MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_48MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(7) | CLK_PLLCON_NF(112) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 48MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_36MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(7) | CLK_PLLCON_NF( 84) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 36MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_32MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(6) | CLK_PLLCON_NF( 64) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 32MHz PLL output with 12MHz X'tal */
#define CLK_PLLCON_24MHz_HXT (CLK_PLLCON_PLL_SRC_HXT | CLK_PLLCON_NR(2) | CLK_PLLCON_NF( 16) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 24MHz PLL output with 12MHz X'tal */
#else
# error "The PLL pre-definitions are only valid when external crystal is 12MHz"
#endif
#define CLK_PLLCON_72MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR( 4) | CLK_PLLCON_NF( 26) | CLK_PLLCON_NO_2) /*!< Predefined PLLCON setting for 71.88488MHz PLL output with 22.1184MHz IRC */
#define CLK_PLLCON_50MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR(13) | CLK_PLLCON_NF( 59) | CLK_PLLCON_NO_2) /*!< Predefined PLLCON setting for 50.1918MHz PLL output with 22.1184MHz IRC */
#define CLK_PLLCON_48MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR(13) | CLK_PLLCON_NF(113) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 48.064985MHz PLL output with 22.1184MHz IRC*/
#define CLK_PLLCON_36MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR(12) | CLK_PLLCON_NF( 78) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 35.9424MHz PLL output with 22.1184MHz IRC */
#define CLK_PLLCON_32MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR( 9) | CLK_PLLCON_NF( 52) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 31.9488MHz PLL output with 22.1184MHz IRC*/
#define CLK_PLLCON_24MHz_HIRC (CLK_PLLCON_PLL_SRC_HIRC | CLK_PLLCON_NR( 3) | CLK_PLLCON_NF( 13) | CLK_PLLCON_NO_4) /*!< Predefined PLLCON setting for 23.9616MHz PLL output with 22.1184MHz IRC*/
/*---------------------------------------------------------------------------------------------------------*/
/* MODULE constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
/* APBCLK(31:30)|CLKSEL(29:28)|CLKSEL_Msk(27:25) |CLKSEL_Pos(24:20)|CLKDIV(19:18)|CLKDIV_Msk(17:10)|CLKDIV_Pos(9:5)|IP_EN_Pos(4:0) */
#define MODULE_APBCLK(x) (((x) >>30) & 0x3) /*!< Calculate APBCLK offset on MODULE index, 0x0:AHBCLK, 0x1:APBCLK */
#define MODULE_CLKSEL(x) (((x) >>28) & 0x3) /*!< Calculate CLKSEL offset on MODULE index, 0x0:CLKSEL0, 0x1:CLKSEL1, 0x2:CLKSEL2 */
#define MODULE_CLKSEL_Msk(x) (((x) >>25) & 0x7) /*!< Calculate CLKSEL mask offset on MODULE index */
#define MODULE_CLKSEL_Pos(x) (((x) >>20) & 0x1f) /*!< Calculate CLKSEL position offset on MODULE index */
#define MODULE_CLKDIV(x) (((x) >>18) & 0x3) /*!< Calculate APBCLK CLKDIV on MODULE index, 0x0:CLKDIV */
#define MODULE_CLKDIV_Msk(x) (((x) >>10) & 0xff) /*!< Calculate CLKDIV mask offset on MODULE index */
#define MODULE_CLKDIV_Pos(x) (((x) >>5 ) & 0x1f) /*!< Calculate CLKDIV position offset on MODULE index */
#define MODULE_IP_EN_Pos(x) (((x) >>0 ) & 0x1f) /*!< Calculate APBCLK offset on MODULE index */
#define MODULE_NoMsk 0x0 /*!< Not mask on MODULE index */
#define NA MODULE_NoMsk /*!< Not Available */
#define MODULE_APBCLK_ENC(x) (((x) & 0x03) << 30) /*!< MODULE index, 0x0:AHBCLK, 0x1:APBCLK */
#define MODULE_CLKSEL_ENC(x) (((x) & 0x03) << 28) /*!< CLKSEL offset on MODULE index, 0x0:CLKSEL0, 0x1:CLKSEL1, 0x2:CLKSEL2 */
#define MODULE_CLKSEL_Msk_ENC(x) (((x) & 0x07) << 25) /*!< CLKSEL mask offset on MODULE index */
#define MODULE_CLKSEL_Pos_ENC(x) (((x) & 0x1f) << 20) /*!< CLKSEL position offset on MODULE index */
#define MODULE_CLKDIV_ENC(x) (((x) & 0x03) << 18) /*!< APBCLK CLKDIV on MODULE index, 0x0:CLKDIV */
#define MODULE_CLKDIV_Msk_ENC(x) (((x) & 0xff) << 10) /*!< CLKDIV mask offset on MODULE index */
#define MODULE_CLKDIV_Pos_ENC(x) (((x) & 0x1f) << 5) /*!< CLKDIV position offset on MODULE index */
#define MODULE_IP_EN_Pos_ENC(x) (((x) & 0x1f) << 0) /*!< APBCLK offset on MODULE index */
#define PDMA_MODULE (MODULE_APBCLK_ENC( 0)|MODULE_IP_EN_Pos_ENC(CLK_AHBCLK_PDMA_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< PDMA Module */
#define ISP_MODULE (MODULE_APBCLK_ENC( 0)|MODULE_IP_EN_Pos_ENC(CLK_AHBCLK_ISP_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< ISP Module */
#define WDT_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_WDT_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC( 0)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< WDT Module */
#define TMR0_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_TMR0_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 7)|MODULE_CLKSEL_Pos_ENC( 8)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< TMR0 Module */
#define TMR1_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_TMR1_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 7)|MODULE_CLKSEL_Pos_ENC(12)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< TMR1 Module */
#define TMR2_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_TMR2_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 7)|MODULE_CLKSEL_Pos_ENC(16)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< TMR2 Module */
#define TMR3_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_TMR3_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 7)|MODULE_CLKSEL_Pos_ENC(20)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< TMR3 Module */
#define FDIV_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_FDIV_EN_Pos) |\
MODULE_CLKSEL_ENC( 2)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC( 2)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< FDIV Module */
#define I2C0_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_I2C0_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< I2C0 Module */
#define I2C1_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_I2C1_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< I2C1 Module */
#define SPI0_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_SPI0_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 1)|MODULE_CLKSEL_Pos_ENC( 4)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< SPI0 Module */
#define SPI1_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_SPI1_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 1)|MODULE_CLKSEL_Pos_ENC( 5)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< SPI1 Module */
#define SPI2_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_SPI2_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 1)|MODULE_CLKSEL_Pos_ENC( 6)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< SPI2 Module */
#define UART0_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_UART0_EN_Pos)|\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC(24)|\
MODULE_CLKDIV_ENC( 0)|MODULE_CLKDIV_Msk_ENC(0x0F)|MODULE_CLKDIV_Pos_ENC( 8)) /*!< UART0 Module */
#define UART1_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_UART1_EN_Pos)|\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC(24)|\
MODULE_CLKDIV_ENC( 0)|MODULE_CLKDIV_Msk_ENC(0x0F)|MODULE_CLKDIV_Pos_ENC( 8)) /*!< UART1 Module */
#define PWM01_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_PWM01_EN_Pos)|\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC(28)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< PWM01 Module */
#define PWM23_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_PWM23_EN_Pos)|\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC(30)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< PWM23 Module */
#define USBD_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_USBD_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC( 0)|MODULE_CLKDIV_Msk_ENC(0x0F)|MODULE_CLKDIV_Pos_ENC(4)) /*!< USBD Module */
#define ADC_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_ADC_EN_Pos) |\
MODULE_CLKSEL_ENC( 1)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC( 2)|\
MODULE_CLKDIV_ENC( 0)|MODULE_CLKDIV_Msk_ENC(0xFF)|MODULE_CLKDIV_Pos_ENC(16)) /*!< ADC Module */
#define I2S_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_I2S_EN_Pos) |\
MODULE_CLKSEL_ENC( 2)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC( 0)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< I2S Module */
#define PS2_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_PS2_EN_Pos) |\
MODULE_CLKSEL_ENC(NA)|MODULE_CLKSEL_Msk_ENC(NA)|MODULE_CLKSEL_Pos_ENC(NA)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< PS2 Module */
#define WWDT_MODULE (MODULE_APBCLK_ENC( 1)|MODULE_IP_EN_Pos_ENC(CLK_APBCLK_WDT_EN_Pos) |\
MODULE_CLKSEL_ENC( 2)|MODULE_CLKSEL_Msk_ENC( 3)|MODULE_CLKSEL_Pos_ENC(16)|\
MODULE_CLKDIV_ENC(NA)|MODULE_CLKDIV_Msk_ENC(NA)|MODULE_CLKDIV_Pos_ENC(NA)) /*!< WWDT Module */
/*@}*/ /* end of group CLK_EXPORTED_CONSTANTS */
/** @addtogroup CLK_EXPORTED_FUNCTIONS CLK Exported Functions
@{
*/
/**
* @brief Get PLL clock frequency
* @param None
* @return PLL frequency
* @details This function get PLL frequency. The frequency unit is Hz.
*/
__STATIC_INLINE uint32_t CLK_GetPLLClockFreq(void)
{
uint32_t u32PllFreq = 0, u32PllReg;
uint32_t u32FIN, u32NF, u32NR, u32NO;
uint8_t au8NoTbl[4] = {1, 2, 2, 4};
u32PllReg = CLK->PLLCON;
if(u32PllReg & (CLK_PLLCON_PD_Msk | CLK_PLLCON_OE_Msk))
return 0; /* PLL is in power down mode or fix low */
if(u32PllReg & CLK_PLLCON_PLL_SRC_HIRC)
u32FIN = __HIRC; /* PLL source clock from HIRC */
else
u32FIN = __HXT; /* PLL source clock from HXT */
if(u32PllReg & CLK_PLLCON_BP_Msk)
return u32FIN; /* PLL is in bypass mode */
/* PLL is output enabled in normal work mode */
u32NO = au8NoTbl[((u32PllReg & CLK_PLLCON_OUT_DV_Msk) >> CLK_PLLCON_OUT_DV_Pos)];
u32NF = ((u32PllReg & CLK_PLLCON_FB_DV_Msk) >> CLK_PLLCON_FB_DV_Pos) + 2;
u32NR = ((u32PllReg & CLK_PLLCON_IN_DV_Msk) >> CLK_PLLCON_IN_DV_Pos) + 2;
/* u32FIN is shifted 2 bits to avoid overflow */
u32PllFreq = (((u32FIN >> 2) * u32NF) / (u32NR * u32NO) << 2);
return u32PllFreq;
}
/**
* @brief This function execute delay function.
* @param[in] us Delay time. The Max value is 2^24 / CPU Clock(MHz). Ex:
* 72MHz => 233016us, 50MHz => 335544us,
48MHz => 349525us, 28MHz => 699050us ...
* @return None
* @details Use the SysTick to generate the delay time and the UNIT is in us.
* The SysTick clock source is from HCLK, i.e the same as system core clock.
* User can use SystemCoreClockUpdate() to calculate CyclesPerUs automatically before using this function.
*/
__STATIC_INLINE void CLK_SysTickDelay(uint32_t us)
{
SysTick->LOAD = us * CyclesPerUs;
SysTick->VAL = (0x00);
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
/* Waiting for down-count to zero */
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
/* Disable SysTick counter */
SysTick->CTRL = 0;
}
/**
* @brief This function execute long delay function.
* @param[in] us Delay time.
* @return None
* @details Use the SysTick to generate the long delay time and the UNIT is in us.
* The SysTick clock source is from HCLK, i.e the same as system core clock.
* User can use SystemCoreClockUpdate() to calculate CyclesPerUs automatically before using this function.
*/
__STATIC_INLINE void CLK_SysTickLongDelay(uint32_t us)
{
uint32_t delay;
/* It should <= 233016us for each delay loop */
delay = 233016L;
do
{
if(us > delay)
{
us -= delay;
}
else
{
delay = us;
us = 0UL;
}
SysTick->LOAD = delay * CyclesPerUs;
SysTick->VAL = (0x0UL);
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
/* Waiting for down-count to zero */
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0UL);
/* Disable SysTick counter */
SysTick->CTRL = 0UL;
}while(us > 0UL);
}
void CLK_DisableCKO(void);
void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv, uint32_t u32ClkDivBy1En);
void CLK_PowerDown(void);
void CLK_Idle(void);
uint32_t CLK_GetHXTFreq(void);
uint32_t CLK_GetHCLKFreq(void);
uint32_t CLK_GetPCLKFreq(void);
uint32_t CLK_GetCPUFreq(void);
uint32_t CLK_SetCoreClock(uint32_t u32Hclk);
void CLK_SetHCLK(uint32_t u32ClkSrc, uint32_t u32ClkDiv);
void CLK_SetModuleClock(uint32_t u32ModuleIdx, uint32_t u32ClkSrc, uint32_t u32ClkDiv);
void CLK_SetSysTickClockSrc(uint32_t u32ClkSrc);
void CLK_EnableXtalRC(uint32_t u32ClkMask);
void CLK_DisableXtalRC(uint32_t u32ClkMask);
void CLK_EnableModuleClock(uint32_t u32ModuleIdx);
void CLK_DisableModuleClock(uint32_t u32ModuleIdx);
uint32_t CLK_EnablePLL(uint32_t u32PllClkSrc, uint32_t u32PllFreq);
void CLK_DisablePLL(void);
uint32_t CLK_WaitClockReady(uint32_t u32ClkMask);
void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count);
void CLK_DisableSysTick(void);
/*@}*/ /* end of group CLK_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group CLK_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__CLK_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

166
NUC123/StdDriver/inc/crc.h Normal file
View File

@ -0,0 +1,166 @@
/**************************************************************************//**
* @file crc.h
* @version V3.00
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series CRC driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __CRC_H__
#define __CRC_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup CRC_Driver CRC Driver
@{
*/
/** @addtogroup CRC_EXPORTED_CONSTANTS CRC Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* CRC Polynomial Mode Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define CRC_CCITT 0x00000000UL /*!<CRC Polynomial Mode - CCITT */
#define CRC_8 0x40000000UL /*!<CRC Polynomial Mode - CRC8 */
#define CRC_16 0x80000000UL /*!<CRC Polynomial Mode - CRC16 */
#define CRC_32 0xC0000000UL /*!<CRC Polynomial Mode - CRC32 */
/*---------------------------------------------------------------------------------------------------------*/
/* Checksum, Write data Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define CRC_CHECKSUM_COM 0x08000000UL /*!<CRC Checksum Complement */
#define CRC_CHECKSUM_RVS 0x02000000UL /*!<CRC Checksum Reverse */
#define CRC_WDATA_COM 0x04000000UL /*!<CRC Write Data Complement */
#define CRC_WDATA_RVS 0x01000000UL /*!<CRC Write Data Reverse */
/*---------------------------------------------------------------------------------------------------------*/
/* CPU Write Data Length Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define CRC_CPU_WDATA_8 0x00000000UL /*!<CRC 8-bit CPU Write Data */
#define CRC_CPU_WDATA_16 0x10000000UL /*!<CRC 16-bit CPU Write Data */
#define CRC_CPU_WDATA_32 0x20000000UL /*!<CRC 32-bit CPU Write Data */
/*@}*/ /* end of group CRC_EXPORTED_CONSTANTS */
/** @addtogroup CRC_EXPORTED_FUNCTIONS CRC Exported Functions
@{
*/
/**
* @brief Enable CRC Interrupt
*
* @param[in] u32Mask Interrupt mask. Valid values are:
* - \ref CRC_DMAIER_CRC_BLKD_IE_Msk
* - \ref CRC_DMAIER_CRC_TABORT_IE_Msk
*
* @return None
*
* @details This macro enable the specify CRC interrupt function by u32Mask setting.
*/
#define CRC_ENABLE_INT(u32Mask) (CRC->DMAIER |= (u32Mask))
/**
* @brief Disable CRC Interrupt
*
* @param[in] u32Mask Interrupt mask. Valid values are:
* - \ref CRC_DMAIER_CRC_BLKD_IE_Msk
* - \ref CRC_DMAIER_CRC_TABORT_IE_Msk
*
* @return None
*
* @details This macro disable the specify CRC interrupt function by u32Mask setting.
*/
#define CRC_DISABLE_INT(u32Mask) (CRC->DMAIER &= ~(u32Mask))
/**
* @brief Get CRC Interrupt Flag
*
* @param None
*
* @return Interrupt Flag Status
*
* @details This macro gets the CRC interrupt flags.
*/
#define CRC_GET_INT_FLAG() ((uint32_t)(CRC->DMAISR))
/**
* @brief Clear CRC Interrupt Flag
*
* @param[in] u32Mask Interrupt mask. Valid values are:
* - \ref CRC_DMAISR_CRC_BLKD_IF_Msk
* - \ref CRC_DMAISR_CRC_TABORT_IF_Msk
*
* @return None
*
* @details This macro clear the specify CRC interrupt flag by u32Mask setting.
*/
#define CRC_CLR_INT_FLAG(u32Mask) (CRC->DMAISR = (u32Mask))
/**
* @brief Set CRC seed value
*
* @param[in] u32Seed Seed value
*
* @return None
*
* @details This macro set CRC seed value.
*
* @note User must to setting CRC_RST (CRC_CTL[1] CRC Engine Reset) to reload the new seed value
* to CRC controller.
*/
#define CRC_SET_SEED(u32Seed) { CRC->SEED = (u32Seed); CRC->CTL |= CRC_CTL_CRC_RST_Msk; }
/**
* @brief Get CRC Seed value
*
* @param None
*
* @return Seed Value
*
* @details This macro gets the current CRC seed value.
*/
#define CRC_GET_SEED() ((uint32_t)(CRC->SEED))
/**
* @brief CRC write data
*
* @param[in] u32Data write data
*
* @return None
*
* @details User can write data directly by this macro to perform CRC operation.
*/
#define CRC_WRITE_DATA(u32Data) (CRC->WDATA = (u32Data))
/*********************************************************************/
void CRC_Open(uint32_t u32Mode, uint32_t u32Attribute, uint32_t u32Seed, uint32_t u32DataLen);
void CRC_StartDMATransfer(uint32_t u32SrcAddr, uint32_t u32ByteCount);
uint32_t CRC_GetChecksum(void);
/*@}*/ /* end of group CRC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group CRC_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__CRC_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

481
NUC123/StdDriver/inc/fmc.h Normal file
View File

@ -0,0 +1,481 @@
/**************************************************************************//**
* @file FMC.h
* @version V3.0
* $Revision: 10 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series Flash Memory Controller Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __FMC_H__
#define __FMC_H__
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup FMC_Driver FMC Driver
@{
*/
/** @addtogroup FMC_EXPORTED_CONSTANTS FMC Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* Define Base Address */
/*---------------------------------------------------------------------------------------------------------*/
#define FMC_APROM_BASE 0x00000000UL /*!< APROM Base Address */
#define FMC_LDROM_BASE 0x00100000UL /*!< LDROM Base Address */
#define FMC_CONFIG_BASE 0x00300000UL /*!< CONFIG Base Address */
#define FMC_FLASH_PAGE_SIZE 0x200 /*!< Flash Page Size (512 Bytes) */
#define FMC_LDROM_SIZE 0x1000 /*!< LDROM Size (4K Bytes) */
/*---------------------------------------------------------------------------------------------------------*/
/* ISPCON constant definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define FMC_ISPCON_BS_LDROM 0x2 /*!< ISPCON setting to select to boot from LDROM */
#define FMC_ISPCON_BS_APROM 0x0 /*!< ISPCON setting to select to boot from APROM */
/*---------------------------------------------------------------------------------------------------------*/
/* ISPCMD constant definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define FMC_ISPCMD_READ 0x00 /*!< ISP Command: Read Flash */
#define FMC_ISPCMD_PROGRAM 0x21 /*!< ISP Command: Program Flash */
#define FMC_ISPCMD_PAGE_ERASE 0x22 /*!< ISP Command: Page Erase Flash */
#define FMC_ISPCMD_VECMAP 0x2e /*!< ISP Command: Set VECMAP */
#define FMC_ISPCMD_READ_UID 0x04 /*!< ISP Command: Read Unique ID */
#define FMC_ISPCMD_READ_CID 0x0B /*!< ISP Command: Read Company ID */
#define FMC_ISPCMD_READ_DID 0x0C /*!< ISP Command: Read Device ID */
/*@}*/ /* end of group FMC_EXPORTED_CONSTANTS */
/** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* FMC Macro Definitions */
/*---------------------------------------------------------------------------------------------------------*/
/**
* @brief Enable ISP Function
*
* @param None
*
* @return None
*
* @details This function will set ISPEN bit of ISPCON control register to enable ISP function.
*
*/
#define FMC_ENABLE_ISP() (FMC->ISPCON |= FMC_ISPCON_ISPEN_Msk)
/**
* @brief Disable ISP Function
*
* @param None
*
* @return None
*
* @details This function will clear ISPEN bit of ISPCON control register to disable ISP function.
*
*/
#define FMC_DISABLE_ISP() (FMC->ISPCON &= ~FMC_ISPCON_ISPEN_Msk)
/**
* @brief Enable LDROM Update Function
*
* @param None
*
* @return None
*
* @details This function will set LDUEN bit of ISPCON control register to enable LDROM update function.
* User needs to set LDUEN bit before they can update LDROM.
*
*/
#define FMC_ENABLE_LD_UPDATE() (FMC->ISPCON |= FMC_ISPCON_LDUEN_Msk)
/**
* @brief Disable LDROM Update Function
*
* @param None
*
* @return None
*
* @details This function will set ISPEN bit of ISPCON control register to disable LDROM update function.
*
*/
#define FMC_DISABLE_LD_UPDATE() (FMC->ISPCON &= ~FMC_ISPCON_LDUEN_Msk) /*!< Disable LDROM Update Function */
/**
* @brief Enable User Configuration Update Function
*
* @param None
*
* @return None
*
* @details This function will set CFGUEN bit of ISPCON control register to enable User Configuration update function.
* User needs to set CFGUEN bit before they can update User Configuration area.
*
*/
#define FMC_ENABLE_CFG_UPDATE() (FMC->ISPCON |= FMC_ISPCON_CFGUEN_Msk)
/**
* @brief Disable User Configuration Update Function
*
* @param None
*
* @return None
*
* @details This function will clear CFGUEN bit of ISPCON control register to disable User Configuration update function.
*
*/
#define FMC_DISABLE_CFG_UPDATE() (FMC->ISPCON &= ~FMC_ISPCON_CFGUEN_Msk) /*!< Disable CONFIG Update Function */
/**
* @brief Enable APROM Update Function
*
* @param None
*
* @return None
*
* @details This function will set APUEN bit of ISPCON control register to enable APROM update function.
* User needs to set APUEN bit before they can update APROM in APROM boot mode.
*
*/
#define FMC_ENABLE_AP_UPDATE() (FMC->ISPCON |= FMC_ISPCON_APUEN_Msk)
/**
* @brief Disable APROM Update Function
*
* @param None
*
* @return None
*
* @details This function will clear APUEN bit of ISPCON control register to disable APROM update function.
*
*/
#define FMC_DISABLE_AP_UPDATE() (FMC->ISPCON &= ~FMC_ISPCON_APUEN_Msk) /*!< Disable APROM Update Function */
/**
* @brief Get ISP fail flag
*
* @param None
*
* @retval 0 Previous ISP command execution result is successful
* @retval 1 Previous ISP command execution result is fail
*
* @details ISPFF flag of ISPCON is used to indicate ISP command success or fail.
* This function will return the ISPFF flag to identify ISP command OK or fail.
*
*/
#define FMC_GET_FAIL_FLAG() ((FMC->ISPCON & FMC_ISPCON_ISPFF_Msk) ? 1 : 0)
/**
* @brief Select booting from APROM
*
* @param None
*
* @return None
*
* @details If MCU is working without IAP, user need to set BS bit of ISPCON and reset CPU to execute the code of LDROM/APROM.
* This function is used to set BS bit of ISPCON to boot to APROM.
*
* @note To valid new BS bit setting, user also need to trigger CPU reset or System Reset Request after setting BS bit.
*
*/
#define FMC_SET_APROM_BOOT() (FMC->ISPCON &= ~FMC_ISPCON_BS_Msk)
/**
* @brief Select booting from APROM
*
* @param None
*
* @return None
*
* @details If MCU is working without IAP, user need to set/clear BS bit of ISPCON and reset CPU to execute the code of APROM/LDROM.
* This function is used to clear BS bit of ISPCON to boot to LDROM.
*
* @note To valid new BS bit setting, user also need to trigger CPU reset or System Reset Request after clear BS bit.
*
*/
#define FMC_SET_LDROM_BOOT() (FMC->ISPCON |= FMC_ISPCON_BS_Msk)
/*---------------------------------------------------------------------------------------------------------*/
/* inline functions */
/*---------------------------------------------------------------------------------------------------------*/
/**
* @brief Program 32-bit data into specified address of flash
*
* @param[in] u32addr Flash address include APROM, LDROM, Data Flash, and CONFIG
* @param[in] u32data 32-bit Data to program
*
* @return None
*
* @details To program word data into Flash include APROM, LDROM, Data Flash, and CONFIG.
* The corresponding functions in CONFIG are listed in FMC section of Technical Reference Manual.
*
*/
static __INLINE void FMC_Write(uint32_t u32addr, uint32_t u32data)
{
FMC->ISPCMD = FMC_ISPCMD_PROGRAM; /* Set ISP Command Code */
FMC->ISPADR = u32addr; /* Set Target ROM Address. The address must be word alignment. */
FMC->ISPDAT = u32data; /* Set Data to Program */
FMC->ISPTRG = 0x1; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG); /* Waiting for ISP Done */
}
/**
* @brief Read 32-bit Data from specified address of flash
*
* @param[in] u32addr Flash address include APROM, LDROM, Data Flash, and CONFIG
*
* @return The data of specified address
*
* @details To read word data from Flash include APROM, LDROM, Data Flash, and CONFIG.
*
*/
static __INLINE uint32_t FMC_Read(uint32_t u32addr)
{
FMC->ISPCMD = FMC_ISPCMD_READ; /* Set ISP Command Code */
FMC->ISPADR = u32addr; /* Set Target ROM Address. The address must be word alignment. */
FMC->ISPTRG = 0x1; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG); /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief Flash page erase
*
* @param[in] u32addr Flash address including APROM, LDROM, Data Flash, and CONFIG
*
* @details To do flash page erase. The target address could be APROM, LDROM, Data Flash, or CONFIG.
* The page size is 512 bytes.
*
* @retval 0 Success
* @retval -1 Erase failed
*
*/
static __INLINE int32_t FMC_Erase(uint32_t u32addr)
{
FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE; /* Set ISP Command Code */
FMC->ISPADR = u32addr; /* Set Target ROM Address. The address must be page alignment. */
FMC->ISPTRG = 0x1; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG); /* Waiting for ISP Done */
/* Check ISPFF flag to know whether erase OK or fail. */
if(FMC->ISPCON & FMC_ISPCON_ISPFF_Msk)
{
FMC->ISPCON |= FMC_ISPCON_ISPFF_Msk;
return -1;
}
return 0;
}
/**
* @brief Read Unique ID
*
* @param[in] u8index UID index. 0 = UID[31:0], 1 = UID[63:32], 2 = UID[95:64]
*
* @return The 32-bit unique ID data of specified UID index.
*
* @details To read out 96-bit Unique ID.
*
*/
static __INLINE uint32_t FMC_ReadUID(uint8_t u8index)
{
FMC->ISPCMD = FMC_ISPCMD_READ_UID; /* Set ISP Command Code */
FMC->ISPADR = (u8index << 2); /* Set UID Address. It must be word alignment. */
FMC->ISPTRG = 0x1; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG); /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief Read company ID
*
* @param None
*
* @return The company ID (32-bit)
*
* @details The company ID of Nuvoton is fixed to be 0xDA
*
*/
static __INLINE uint32_t FMC_ReadCID(void)
{
FMC->ISPCMD = FMC_ISPCMD_READ_CID; /* Set ISP Command Code */
FMC->ISPADR = 0x0; /* Must keep 0x0 when read CID */
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) ; /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief Read device ID
*
* @param None
*
* @return The device ID (32-bit)
*
* @details This function is used to read device ID.
*
*/
static __INLINE uint32_t FMC_ReadDID(void)
{
FMC->ISPCMD = FMC_ISPCMD_READ_DID; /* Set ISP Command Code */
FMC->ISPADR = 0; /* Must keep 0x0 when read DID */
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk); /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief Read product ID
*
* @param None
*
* @return The product ID (32-bit)
*
* @details This function is used to read product ID.
*
*/
static __INLINE uint32_t FMC_ReadPID(void)
{
FMC->ISPCMD = FMC_ISPCMD_READ_DID; /* Set ISP Command Code */
FMC->ISPADR = 0x04; /* Must keep 0x4 when read PID */
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk); /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief To read UCID
*
* @param[in] u32Index Index of the UCID to read. u32Index must be 0, 1, 2, or 3.
*
* @return The UCID of specified index
*
* @details This function is used to read unique chip ID (UCID).
*
*/
static __INLINE uint32_t FMC_ReadUCID(uint32_t u32Index)
{
FMC->ISPCMD = FMC_ISPCMD_READ_UID; /* Set ISP Command Code */
FMC->ISPADR = (0x04 * u32Index) + 0x10; /* The UCID is at offset 0x10 with word alignment. */
FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk); /* Waiting for ISP Done */
return FMC->ISPDAT;
}
/**
* @brief Set vector mapping address
*
* @param[in] u32PageAddr The page address to remap to address 0x0. The address must be page alignment.
*
* @return None
*
* @details This function is used to set VECMAP to map specified page to vector page (0x0).
*
* @note
* VECMAP only valid when new IAP function is enabled. (CBS = 10'b or 00'b)
*
*/
static __INLINE void FMC_SetVectorPageAddr(uint32_t u32PageAddr)
{
FMC->ISPCMD = FMC_ISPCMD_VECMAP; /* Set ISP Command Code */
FMC->ISPADR = u32PageAddr; /* The address of specified page which will be map to address 0x0. It must be page alignment. */
FMC->ISPTRG = 0x1; /* Trigger to start ISP procedure */
__ISB(); /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG); /* Waiting for ISP Done */
}
/**
* @brief Get current vector mapping address.
*
* @param None
*
* @return The current vector mapping address.
*
* @details To get VECMAP value which is the page address for remapping to vector page (0x0).
*
* @note
* VECMAP only valid when new IAP function is enabled. (CBS = 10'b or 00'b)
*
*/
static __INLINE uint32_t FMC_GetVECMAP(void)
{
return (FMC->ISPSTA & FMC_ISPSTA_VECMAP_Msk);
}
extern void FMC_Open(void);
extern void FMC_Close(void);
extern void FMC_EnableAPUpdate(void);
extern void FMC_DisableAPUpdate(void);
extern void FMC_EnableConfigUpdate(void);
extern void FMC_DisableConfigUpdate(void);
extern void FMC_EnableLDUpdate(void);
extern void FMC_DisableLDUpdate(void);
extern int32_t FMC_ReadConfig(uint32_t *u32Config, uint32_t u32Count);
extern int32_t FMC_WriteConfig(uint32_t *u32Config, uint32_t u32Count);
extern void FMC_SetBootSource(int32_t i32BootSrc);
extern int32_t FMC_GetBootSource(void);
extern uint32_t FMC_ReadDataFlashBaseAddr(void);
/*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group FMC_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif

458
NUC123/StdDriver/inc/gpio.h Normal file
View File

@ -0,0 +1,458 @@
/**************************************************************************//**
* @file GPIO.h
* @version V3.00
* $Revision: 13 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series General Purpose I/O Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup GPIO_Driver GPIO Driver
@{
*/
/** @addtogroup GPIO_EXPORTED_CONSTANTS GPIO Exported Constants
@{
*/
#define GPIO_PIN_MAX 16 /*!< Specify Maximum Pins of Each GPIO Port */
/*---------------------------------------------------------------------------------------------------------*/
/* PMD Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define GPIO_PMD_INPUT 0x0UL /*!< Input Mode */
#define GPIO_PMD_OUTPUT 0x1UL /*!< Output Mode */
#define GPIO_PMD_OPEN_DRAIN 0x2UL /*!< Open-Drain Mode */
#define GPIO_PMD_QUASI 0x3UL /*!< Quasi-bidirectional Mode */
/*---------------------------------------------------------------------------------------------------------*/
/* GPIO Interrupt Type Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define GPIO_INT_RISING 0x00010000UL /*!< Interrupt enable by Input Rising Edge */
#define GPIO_INT_FALLING 0x00000001UL /*!< Interrupt enable by Input Falling Edge */
#define GPIO_INT_BOTH_EDGE 0x00010001UL /*!< Interrupt enable by both Rising Edge and Falling Edge */
#define GPIO_INT_HIGH 0x01010000UL /*!< Interrupt enable by Level-High */
#define GPIO_INT_LOW 0x01000001UL /*!< Interrupt enable by Level-Level */
/*---------------------------------------------------------------------------------------------------------*/
/* IMD Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define GPIO_IMD_EDGE 0UL /*!< IMD Setting for Edge Trigger Mode */
#define GPIO_IMD_LEVEL 1UL /*!< IMD Setting for Edge Level Mode */
/*---------------------------------------------------------------------------------------------------------*/
/* DBNCECON Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define GPIO_INT_CLK_ON 0x00000020UL /*!< DBNCECON setting for all IO pins edge detection circuit is always active after reset */
#define GPIO_INT_CLK_OFF 0x00000000UL /*!< DBNCECON setting for edge detection circuit is active only if IO pin corresponding GPIOx_IEN bit is set to 1 */
#define GPIO_DBCLKSRC_LIRC 0x00000010UL /*!< DBNCECON setting for de-bounce counter clock source is the internal 10 kHz */
#define GPIO_DBCLKSRC_HCLK 0x00000000UL /*!< DBNCECON setting for de-bounce counter clock source is the HCLK */
#define GPIO_DBCLKSEL_1 0x00000000UL /*!< DBNCECON setting for sampling cycle = 1 clocks */
#define GPIO_DBCLKSEL_2 0x00000001UL /*!< DBNCECON setting for sampling cycle = 2 clocks */
#define GPIO_DBCLKSEL_4 0x00000002UL /*!< DBNCECON setting for sampling cycle = 4 clocks */
#define GPIO_DBCLKSEL_8 0x00000003UL /*!< DBNCECON setting for sampling cycle = 8 clocks */
#define GPIO_DBCLKSEL_16 0x00000004UL /*!< DBNCECON setting for sampling cycle = 16 clocks */
#define GPIO_DBCLKSEL_32 0x00000005UL /*!< DBNCECON setting for sampling cycle = 32 clocks */
#define GPIO_DBCLKSEL_64 0x00000006UL /*!< DBNCECON setting for sampling cycle = 64 clocks */
#define GPIO_DBCLKSEL_128 0x00000007UL /*!< DBNCECON setting for sampling cycle = 128 clocks */
#define GPIO_DBCLKSEL_256 0x00000008UL /*!< DBNCECON setting for sampling cycle = 256 clocks */
#define GPIO_DBCLKSEL_512 0x00000009UL /*!< DBNCECON setting for sampling cycle = 512 clocks */
#define GPIO_DBCLKSEL_1024 0x0000000AUL /*!< DBNCECON setting for sampling cycle = 1024 clocks */
#define GPIO_DBCLKSEL_2048 0x0000000BUL /*!< DBNCECON setting for sampling cycle = 2048 clocks */
#define GPIO_DBCLKSEL_4096 0x0000000CUL /*!< DBNCECON setting for sampling cycle = 4096 clocks */
#define GPIO_DBCLKSEL_8192 0x0000000DUL /*!< DBNCECON setting for sampling cycle = 8192 clocks */
#define GPIO_DBCLKSEL_16384 0x0000000EUL /*!< DBNCECON setting for sampling cycle = 16384 clocks */
#define GPIO_DBCLKSEL_32768 0x0000000FUL /*!< DBNCECON setting for sampling cycle = 32768 clocks */
/* Define GPIO Pin Data Input/Output. It could be used to control each I/O pin by pin address mapping.
Example 1:
PA10 = 1;
It is used to set GPIO PA.10 to high;
Example 2:
if (PA10)
PA10 = 0;
If GPIO PA.10 pin status is high, then set GPIO PA.10 data output to low.
*/
#define GPIO_PIN_DATA(port, pin) (*((volatile uint32_t *)((GPIO_PIN_DATA_BASE+(0x40*(port))) + ((pin)<<2))))
#define PA10 GPIO_PIN_DATA(0, 10) /*!< Specify PA.10 Pin Data Input/Output */
#define PA11 GPIO_PIN_DATA(0, 11) /*!< Specify PA.11 Pin Data Input/Output */
#define PA12 GPIO_PIN_DATA(0, 12) /*!< Specify PA.12 Pin Data Input/Output */
#define PA13 GPIO_PIN_DATA(0, 13) /*!< Specify PA.13 Pin Data Input/Output */
#define PA14 GPIO_PIN_DATA(0, 14) /*!< Specify PA.14 Pin Data Input/Output */
#define PA15 GPIO_PIN_DATA(0, 15) /*!< Specify PA.15 Pin Data Input/Output */
#define PB0 GPIO_PIN_DATA(1, 0 ) /*!< Specify PB.0 Pin Data Input/Output */
#define PB1 GPIO_PIN_DATA(1, 1 ) /*!< Specify PB.1 Pin Data Input/Output */
#define PB2 GPIO_PIN_DATA(1, 2 ) /*!< Specify PB.2 Pin Data Input/Output */
#define PB3 GPIO_PIN_DATA(1, 3 ) /*!< Specify PB.3 Pin Data Input/Output */
#define PB4 GPIO_PIN_DATA(1, 4 ) /*!< Specify PB.4 Pin Data Input/Output */
#define PB5 GPIO_PIN_DATA(1, 5 ) /*!< Specify PB.5 Pin Data Input/Output */
#define PB6 GPIO_PIN_DATA(1, 6 ) /*!< Specify PB.6 Pin Data Input/Output */
#define PB7 GPIO_PIN_DATA(1, 7 ) /*!< Specify PB.7 Pin Data Input/Output */
#define PB8 GPIO_PIN_DATA(1, 8 ) /*!< Specify PB.8 Pin Data Input/Output */
#define PB9 GPIO_PIN_DATA(1, 9 ) /*!< Specify PB.9 Pin Data Input/Output */
#define PB10 GPIO_PIN_DATA(1, 10) /*!< Specify PB.10 Pin Data Input/Output */
#define PB12 GPIO_PIN_DATA(1, 12) /*!< Specify PB.12 Pin Data Input/Output */
#define PB13 GPIO_PIN_DATA(1, 13) /*!< Specify PB.13 Pin Data Input/Output */
#define PB14 GPIO_PIN_DATA(1, 14) /*!< Specify PB.14 Pin Data Input/Output */
#define PB15 GPIO_PIN_DATA(1, 15) /*!< Specify PB.15 Pin Data Input/Output */
#define PC0 GPIO_PIN_DATA(2, 0 ) /*!< Specify PC.0 Pin Data Input/Output */
#define PC1 GPIO_PIN_DATA(2, 1 ) /*!< Specify PC.1 Pin Data Input/Output */
#define PC2 GPIO_PIN_DATA(2, 2 ) /*!< Specify PC.2 Pin Data Input/Output */
#define PC3 GPIO_PIN_DATA(2, 3 ) /*!< Specify PC.3 Pin Data Input/Output */
#define PC4 GPIO_PIN_DATA(2, 4 ) /*!< Specify PC.4 Pin Data Input/Output */
#define PC5 GPIO_PIN_DATA(2, 5 ) /*!< Specify PC.5 Pin Data Input/Output */
#define PC8 GPIO_PIN_DATA(2, 8 ) /*!< Specify PC.8 Pin Data Input/Output */
#define PC9 GPIO_PIN_DATA(2, 9 ) /*!< Specify PC.9 Pin Data Input/Output */
#define PC10 GPIO_PIN_DATA(2, 10) /*!< Specify PC.10 Pin Data Input/Output */
#define PC11 GPIO_PIN_DATA(2, 11) /*!< Specify PC.11 Pin Data Input/Output */
#define PC12 GPIO_PIN_DATA(2, 12) /*!< Specify PC.12 Pin Data Input/Output */
#define PC13 GPIO_PIN_DATA(2, 13) /*!< Specify PC.13 Pin Data Input/Output */
#define PD0 GPIO_PIN_DATA(3, 0 ) /*!< Specify PD.0 Pin Data Input/Output */
#define PD1 GPIO_PIN_DATA(3, 1 ) /*!< Specify PD.1 Pin Data Input/Output */
#define PD2 GPIO_PIN_DATA(3, 2 ) /*!< Specify PD.2 Pin Data Input/Output */
#define PD3 GPIO_PIN_DATA(3, 3 ) /*!< Specify PD.3 Pin Data Input/Output */
#define PD4 GPIO_PIN_DATA(3, 4 ) /*!< Specify PD.4 Pin Data Input/Output */
#define PD5 GPIO_PIN_DATA(3, 5 ) /*!< Specify PD.5 Pin Data Input/Output */
#define PD8 GPIO_PIN_DATA(3, 8 ) /*!< Specify PD.8 Pin Data Input/Output */
#define PD9 GPIO_PIN_DATA(3, 9 ) /*!< Specify PD.9 Pin Data Input/Output */
#define PD10 GPIO_PIN_DATA(3, 10) /*!< Specify PD.10 Pin Data Input/Output */
#define PD11 GPIO_PIN_DATA(3, 11) /*!< Specify PD.11 Pin Data Input/Output */
#define PF0 GPIO_PIN_DATA(5, 0 ) /*!< Specify PF.0 Pin Data Input/Output */
#define PF1 GPIO_PIN_DATA(5, 1 ) /*!< Specify PF.1 Pin Data Input/Output */
#define PF2 GPIO_PIN_DATA(5, 2 ) /*!< Specify PF.2 Pin Data Input/Output */
#define PF3 GPIO_PIN_DATA(5, 3 ) /*!< Specify PF.3 Pin Data Input/Output */
/*@}*/ /* end of group GPIO_EXPORTED_CONSTANTS */
/** @addtogroup GPIO_EXPORTED_FUNCTIONS GPIO Exported Functions
@{
*/
/**
* @brief Clear GPIO Pin Interrupt Flag
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Clear the interrupt status of specified GPIO pin.
*/
#define GPIO_CLR_INT_FLAG(port, u32PinMask) ((port)->ISRC = (u32PinMask))
/**
* @brief Disable Pin De-bounce Function
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Disable the interrupt de-bounce function of specified GPIO pin.
*/
#define GPIO_DISABLE_DEBOUNCE(port, u32PinMask) ((port)->DBEN &= ~(u32PinMask))
/**
* @brief Enable Pin De-bounce Function
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Enable the interrupt de-bounce function of specified GPIO pin.
*/
#define GPIO_ENABLE_DEBOUNCE(port, u32PinMask) ((port)->DBEN |= (u32PinMask))
/**
* @brief Disable I/O Digital Input Path
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Disable I/O digital input path of specified GPIO pin.
*/
#define GPIO_DISABLE_DIGITAL_PATH(port, u32PinMask) ((port)->OFFD |= ((u32PinMask)<<16))
/**
* @brief Enable I/O Digital Input Path
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port \n.
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Enable I/O digital input path of specified GPIO pin.
*/
#define GPIO_ENABLE_DIGITAL_PATH(port, u32PinMask) ((port)->OFFD &= ~((u32PinMask)<<16))
/**
* @brief Disable I/O DOUT mask
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Disable I/O DOUT mask of specified GPIO pin.
*/
#define GPIO_DISABLE_DOUT_MASK(port, u32PinMask) ((port)->DMASK &= ~(u32PinMask))
/**
* @brief Enable I/O DOUT mask
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @return None
*
* @details Enable I/O DOUT mask of specified GPIO pin.
*/
#define GPIO_ENABLE_DOUT_MASK(port, u32PinMask) ((port)->DMASK |= (u32PinMask))
/**
* @brief Get GPIO Pin Interrupt Flag
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
*
* @retval 0 No interrupt at specified GPIO pin
* @retval 1 The specified GPIO pin generate an interrupt
*
* @details Get the interrupt status of specified GPIO pin.
*/
#define GPIO_GET_INT_FLAG(port, u32PinMask) ((port)->ISRC & (u32PinMask))
/**
* @brief Set De-bounce Sampling Cycle Time
*
* @param[in] u32ClkSrc The de-bounce counter clock source. It could be :
* - \ref GPIO_DBCLKSRC_HCLK
* - \ref GPIO_DBCLKSRC_LIRC
* @param[in] u32ClkSel The de-bounce sampling cycle selection. It could be :
* - \ref GPIO_DBCLKSEL_1
* - \ref GPIO_DBCLKSEL_2
* - \ref GPIO_DBCLKSEL_4
* - \ref GPIO_DBCLKSEL_8
* - \ref GPIO_DBCLKSEL_16
* - \ref GPIO_DBCLKSEL_32
* - \ref GPIO_DBCLKSEL_64
* - \ref GPIO_DBCLKSEL_128
* - \ref GPIO_DBCLKSEL_256
* - \ref GPIO_DBCLKSEL_512
* - \ref GPIO_DBCLKSEL_1024
* - \ref GPIO_DBCLKSEL_2048
* - \ref GPIO_DBCLKSEL_4096
* - \ref GPIO_DBCLKSEL_8192
* - \ref GPIO_DBCLKSEL_16384
* - \ref GPIO_DBCLKSEL_32768
*
* @return None
*
* @details Set the interrupt de-bounce sampling cycle time based on the debounce counter clock source. \n
* Example: GPIO_SET_DEBOUNCE_TIME(GPIO_DBNCECON_DBCLKSRC_LIRC, GPIO_DBCLKSEL_4). \n
* It's meaning the De-debounce counter clock source is internal 10 KHz and sampling cycle selection is 4. \n
* Then the target de-bounce sampling cycle time is (4)*(1/(10*1000)) s = 4*0.0001 s = 400 us,
* and system will sampling interrupt input once per 400 us.
*/
#define GPIO_SET_DEBOUNCE_TIME(u32ClkSrc, u32ClkSel) (GPIO->DBNCECON = (GPIO_DBNCECON_ICLK_ON_Msk | (u32ClkSrc) | (u32ClkSel)))
/**
* @brief Get GPIO Port IN Data
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
*
* @return The specified port data
*
* @details Get the PIN register of specified GPIO port.
*/
#define GPIO_GET_IN_DATA(port) ((port)->PIN)
/**
* @brief Set GPIO Port OUT Data
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Data GPIO port data.
*
* @return None
*
* @details Set the Data into specified GPIO port.
*/
#define GPIO_SET_OUT_DATA(port, u32Data) ((port)->DOUT = (u32Data))
/**
* @brief Toggle Specified GPIO pin
*
* @param[in] u32Pin Pxy
*
* @return None
*
* @details Toggle the specified GPIO pint.
*/
#define GPIO_TOGGLE(u32Pin) ((u32Pin) ^= 1)
/**
* @brief Enable External GPIO Interrupt 0
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
* @param[in] u32IntAttribs The interrupt attribute of specified GPIO pin. It could be \n
* - \ref GPIO_INT_RISING
* - \ref GPIO_INT_FALLING
* - \ref GPIO_INT_BOTH_EDGE
* - \ref GPIO_INT_HIGH
* - \ref GPIO_INT_LOW
*
* @return None
*
* @details This function is used to enable specified GPIO pin interrupt.
*/
#define GPIO_EnableEINT0 GPIO_EnableInt
/**
* @brief Disable External GPIO Interrupt 0
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
*
* @return None
*
* @details This function is used to disable specified GPIO pin interrupt.
*/
#define GPIO_DisableEINT0 GPIO_DisableInt
/**
* @brief Enable External GPIO Interrupt 1
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
* @param[in] u32IntAttribs The interrupt attribute of specified GPIO pin. It could be \n
* GPIO_INT_RISING, GPIO_INT_FALLING, GPIO_INT_BOTH_EDGE, GPIO_INT_HIGH, GPIO_INT_LOW.
*
* @return None
*
* @details This function is used to enable specified GPIO pin interrupt.
*/
#define GPIO_EnableEINT1 GPIO_EnableInt
/**
* @brief Disable External GPIO Interrupt 1
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
*
* @return None
*
* @details This function is used to disable specified GPIO pin interrupt.
*/
#define GPIO_DisableEINT1 GPIO_DisableInt
void GPIO_SetMode(GPIO_T *port, uint32_t u32PinMask, uint32_t u32Mode);
void GPIO_EnableInt(GPIO_T *port, uint32_t u32Pin, uint32_t u32IntAttribs);
void GPIO_DisableInt(GPIO_T *port, uint32_t u32Pin);
/*@}*/ /* end of group GPIO_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group GPIO_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__GPIO_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

212
NUC123/StdDriver/inc/i2c.h Normal file
View File

@ -0,0 +1,212 @@
/**************************************************************************//**
* @file I2C.h
* @version V3.0
* $Revision: 10 $
* $Date: 16/06/22 11:46a $
* @brief NUC123 Series I2C Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __I2C_H__
#define __I2C_H__
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup I2C_Driver I2C Driver
@{
*/
/** @addtogroup I2C_EXPORTED_CONSTANTS I2C Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* I2CON constant definitions. */
/*---------------------------------------------------------------------------------------------------------*/
#define I2C_I2CON_STA_STO_SI 0x38UL /*!< I2CON setting for I2C control bits. It would set STA, STO and SI bits */
#define I2C_I2CON_STA_STO_SI_AA 0x3CUL /*!< I2CON setting for I2C control bits. It would set STA, STO, SI and AA bits */
#define I2C_I2CON_STA_SI 0x28UL /*!< I2CON setting for I2C control bits. It would set STA and SI bits */
#define I2C_I2CON_STA_SI_AA 0x2CUL /*!< I2CON setting for I2C control bits. It would set STA, SI and AA bits */
#define I2C_I2CON_STO_SI 0x18UL /*!< I2CON setting for I2C control bits. It would set STO and SI bits */
#define I2C_I2CON_STO_SI_AA 0x1CUL /*!< I2CON setting for I2C control bits. It would set STO, SI and AA bits */
#define I2C_I2CON_SI 0x08UL /*!< I2CON setting for I2C control bits. It would set SI bit */
#define I2C_I2CON_SI_AA 0x0CUL /*!< I2CON setting for I2C control bits. It would set SI and AA bits */
#define I2C_I2CON_STA 0x20UL /*!< I2CON setting for I2C control bits. It would set STA bit */
#define I2C_I2CON_STO 0x10UL /*!< I2CON setting for I2C control bits. It would set STO bit */
#define I2C_I2CON_AA 0x04UL /*!< I2CON setting for I2C control bits. It would set AA bit */
#define I2C_GCMODE_ENABLE 1 /*!< Enable I2C GC Mode */
#define I2C_GCMODE_DISABLE 0 /*!< Disable I2C GC Mode */
/*@}*/ /* end of group I2C_EXPORTED_CONSTANTS */
/** @addtogroup I2C_EXPORTED_FUNCTIONS I2C Exported Functions
@{
*/
/**
* @brief The macro is used to set I2C bus condition at One Time
*
* @param[in] i2c Specify I2C port
* @param[in] u8Ctrl A byte writes to I2C control register
*
* @return None
*
* @details Set I2CON register to control I2C bus conditions of START, STOP, SI, ACK.
*/
#define I2C_SET_CONTROL_REG(i2c, u8Ctrl) ((i2c)->I2CON = ((i2c)->I2CON & ~0x3c) | (u8Ctrl))
/**
* @brief The macro is used to set START condition of I2C Bus
*
* @param[in] i2c Specify I2C port
*
* @return None
*
* @details Set the I2C bus START condition in I2CON register.
*/
#define I2C_START(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_SI_Msk) | I2C_I2CON_STA_Msk)
/**
* @brief The macro is used to set STOP condition of I2C Bus
*
* @param[in] i2c Specify I2C port
*
* @return None
*
* @details Set the I2C bus STOP condition in I2CON register.
*/
#define I2C_STOP(i2c) ((i2c)->I2CON = ((i2c)->I2CON | I2C_I2CON_SI_Msk) | I2C_I2CON_STO_Msk)
/**
* @brief The macro is used to wait I2C bus status get ready
*
* @param[in] i2c Specify I2C port
*
* @return None
*
* @details When a new status is presented of I2C bus, the SI flag will be set in I2CON register.
*/
#define I2C_WAIT_READY(i2c) while(!((i2c)->I2CON & I2C_I2CON_SI_Msk))
/**
* @brief The macro is used to Read I2C Bus Data Register
*
* @param[in] i2c Specify I2C port
*
* @return A byte of I2C data register
*
* @details I2C controller read data from bus and save it in I2CDAT register.
*/
#define I2C_GET_DATA(i2c) ((i2c)->I2CDAT)
/**
* @brief Write a Data to I2C Data Register
*
* @param[in] i2c Specify I2C port
* @param[in] u8Data A byte that writes to data register
*
* @return None
*
* @details When write a data to I2CDAT register, the I2C controller will shift it to I2C bus.
*/
#define I2C_SET_DATA(i2c, u8Data) ((i2c)->I2CDAT = (u8Data))
/**
* @brief Get I2C Bus status code
*
* @param[in] i2c Specify I2C port
*
* @return I2C status code
*
* @details To get this status code to monitor I2C bus event.
*/
#define I2C_GET_STATUS(i2c) ((i2c)->I2CSTATUS)
/**
* @brief Get Time-out flag from I2C Bus
*
* @param[in] i2c Specify I2C port
*
* @retval 0 I2C Bus time-out is not happened
* @retval 1 I2C Bus time-out is happened
*
* @details When I2C bus occurs time-out event, the time-out flag will be set.
*/
#define I2C_GET_TIMEOUT_FLAG(i2c) ( ((i2c)->I2CTOC & I2C_I2CTOC_TIF_Msk) == I2C_I2CTOC_TIF_Msk ? 1:0 )
/**
* @brief To get wake-up flag from I2C Bus
*
* @param[in] i2c Specify I2C port
*
* @retval 0 Chip is not woken-up from power-down mode
* @retval 1 Chip is woken-up from power-down mode
*
* @details I2C bus occurs wake-up event, wake-up flag will be set.
*/
#define I2C_GET_WAKEUP_FLAG(i2c) ( ((i2c)->I2CWKUPSTS & I2C_I2CWKUPSTS_WKUPIF_Msk) == I2C_I2CWKUPSTS_WKUPIF_Msk ? 1:0 )
/**
* @brief To clear wake-up flag
*
* @param[in] i2c Specify I2C port
*
* @return None
*
* @details If wake-up flag is set, use this macro to clear it.
*/
#define I2C_CLEAR_WAKEUP_FLAG(i2c) ((i2c)->I2CWKUPSTS |= I2C_I2CWKUPSTS_WKUPIF_Msk)
void I2C_ClearTimeoutFlag(I2C_T *i2c);
void I2C_Close(I2C_T *i2c);
void I2C_Trigger(I2C_T *i2c, uint8_t u8Start, uint8_t u8Stop, uint8_t u8Si, uint8_t u8Ack);
void I2C_DisableInt(I2C_T *i2c);
void I2C_EnableInt(I2C_T *i2c);
uint32_t I2C_GetBusClockFreq(I2C_T *i2c);
uint32_t I2C_SetBusClockFreq(I2C_T *i2c, uint32_t u32BusClock);
uint32_t I2C_GetIntFlag(I2C_T *i2c);
uint32_t I2C_GetStatus(I2C_T *i2c);
uint32_t I2C_Open(I2C_T *i2c, uint32_t u32BusClock);
uint8_t I2C_GetData(I2C_T *i2c);
void I2C_SetSlaveAddr(I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddr, uint8_t u8GCMode);
void I2C_SetSlaveAddrMask(I2C_T *i2c, uint8_t u8SlaveNo, uint8_t u8SlaveAddrMask);
void I2C_EnableTimeout(I2C_T *i2c, uint8_t u8LongTimeout);
void I2C_DisableTimeout(I2C_T *i2c);
void I2C_EnableWakeup(I2C_T *i2c);
void I2C_DisableWakeup(I2C_T *i2c);
void I2C_SetData(I2C_T *i2c, uint8_t u8Data);
uint8_t I2C_WriteByte(I2C_T *i2c, uint8_t u8SlaveAddr, const uint8_t data);
uint32_t I2C_WriteMultiBytes(I2C_T *i2c, uint8_t u8SlaveAddr, const uint8_t *data, uint32_t u32wLen);
uint8_t I2C_WriteByteOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, const uint8_t data);
uint32_t I2C_WriteMultiBytesOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, const uint8_t *data, uint32_t u32wLen);
uint8_t I2C_WriteByteTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, const uint8_t data);
uint32_t I2C_WriteMultiBytesTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, const uint8_t *data, uint32_t u32wLen);
uint8_t I2C_ReadByte(I2C_T *i2c, uint8_t u8SlaveAddr);
uint32_t I2C_ReadMultiBytes(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t *rdata, uint32_t u32rLen);
uint8_t I2C_ReadByteOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr);
uint32_t I2C_ReadMultiBytesOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, uint8_t *rdata, uint32_t u32rLen);
uint8_t I2C_ReadByteTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr);
uint32_t I2C_ReadMultiBytesTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, uint8_t *rdata, uint32_t u32rLen);
/*@}*/ /* end of group I2C_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group I2C_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__I2C_H__

324
NUC123/StdDriver/inc/i2s.h Normal file
View File

@ -0,0 +1,324 @@
/**************************************************************************//**
* @file i2s.h
* @version V3.0
* $Revision: 6 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series I2S driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#ifndef __I2S_H__
#define __I2S_H__
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup I2S_Driver I2S Driver
@{
*/
/** @addtogroup I2S_EXPORTED_CONSTANTS I2S Exported Constants
@{
*/
#define I2S_DATABIT_8 (0 << I2S_CON_WORDWIDTH_Pos) /*!< I2S data width is 8-bit */
#define I2S_DATABIT_16 (1 << I2S_CON_WORDWIDTH_Pos) /*!< I2S data width is 16-bit */
#define I2S_DATABIT_24 (2 << I2S_CON_WORDWIDTH_Pos) /*!< I2S data width is 24-bit */
#define I2S_DATABIT_32 (3 << I2S_CON_WORDWIDTH_Pos) /*!< I2S data width is 32-bit */
/* Audio Format */
#define I2S_MONO I2S_CON_MONO_Msk /*!< Mono channel */
#define I2S_STEREO 0 /*!< Stereo channel */
/* I2S Data Format */
#define I2S_FORMAT_MSB I2S_CON_FORMAT_Msk /*!< MSB data format */
#define I2S_FORMAT_I2S 0 /*!< I2S data format */
#define I2S_FORMAT_PCM_A I2S_CON_PCM_Msk /*!< PCM mode A data format */
#define I2S_FORMAT_PCM_B (I2S_CON_PCM_Msk|I2S_CON_FORMAT_Msk) /*!< PCM mode B data format */
/* I2S Operation mode */
#define I2S_MODE_SLAVE I2S_CON_SLAVE_Msk /*!< As slave mode */
#define I2S_MODE_MASTER 0 /*!< As master mode */
/* I2S FIFO Threshold */
#define I2S_FIFO_TX_LEVEL_WORD_0 0 /*!< TX threshold is 0 word */
#define I2S_FIFO_TX_LEVEL_WORD_1 (1 << I2S_CON_TXTH_Pos) /*!< TX threshold is 1 word */
#define I2S_FIFO_TX_LEVEL_WORD_2 (2 << I2S_CON_TXTH_Pos) /*!< TX threshold is 2 words */
#define I2S_FIFO_TX_LEVEL_WORD_3 (3 << I2S_CON_TXTH_Pos) /*!< TX threshold is 3 words */
#define I2S_FIFO_TX_LEVEL_WORD_4 (4 << I2S_CON_TXTH_Pos) /*!< TX threshold is 4 words */
#define I2S_FIFO_TX_LEVEL_WORD_5 (5 << I2S_CON_TXTH_Pos) /*!< TX threshold is 5 words */
#define I2S_FIFO_TX_LEVEL_WORD_6 (6 << I2S_CON_TXTH_Pos) /*!< TX threshold is 6 words */
#define I2S_FIFO_TX_LEVEL_WORD_7 (7 << I2S_CON_TXTH_Pos) /*!< TX threshold is 7 words */
#define I2S_FIFO_RX_LEVEL_WORD_1 0 /*!< RX threshold is 1 word */
#define I2S_FIFO_RX_LEVEL_WORD_2 (1 << I2S_CON_RXTH_Pos) /*!< RX threshold is 2 words */
#define I2S_FIFO_RX_LEVEL_WORD_3 (2 << I2S_CON_RXTH_Pos) /*!< RX threshold is 3 words */
#define I2S_FIFO_RX_LEVEL_WORD_4 (3 << I2S_CON_RXTH_Pos) /*!< RX threshold is 4 words */
#define I2S_FIFO_RX_LEVEL_WORD_5 (4 << I2S_CON_RXTH_Pos) /*!< RX threshold is 5 words */
#define I2S_FIFO_RX_LEVEL_WORD_6 (5 << I2S_CON_RXTH_Pos) /*!< RX threshold is 6 words */
#define I2S_FIFO_RX_LEVEL_WORD_7 (6 << I2S_CON_RXTH_Pos) /*!< RX threshold is 7 words */
#define I2S_FIFO_RX_LEVEL_WORD_8 (7 << I2S_CON_RXTH_Pos) /*!< RX threshold is 8 words */
/* I2S Record Channel */
#define I2S_MONO_RIGHT 0 /*!< Record mono right channel */
#define I2S_MONO_LEFT I2S_CON_RXLCH_Msk /*!< Record mono left channel */
/* I2S Channel */
#define I2S_RIGHT 0 /*!< Select right channel */
#define I2S_LEFT 1 /*!< Select left channel */
/*@}*/ /* end of group I2S_EXPORTED_CONSTANTS */
/** @addtogroup I2S_EXPORTED_FUNCTIONS I2S Exported Functions
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* inline functions */
/*---------------------------------------------------------------------------------------------------------*/
/**
* @brief Enable zero cross detection function.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32ChMask The mask for left or right channel. Valid values are:
* - \ref I2S_RIGHT
* - \ref I2S_LEFT
* @return None
* @details This function will set RCHZCEN or LCHZCEN bit of I2SCON register to enable zero cross detection function.
*/
static __INLINE void I2S_ENABLE_TX_ZCD(I2S_T *i2s, uint32_t u32ChMask)
{
if(u32ChMask == I2S_RIGHT)
i2s->CON |= I2S_CON_RCHZCEN_Msk;
else
i2s->CON |= I2S_CON_LCHZCEN_Msk;
}
/**
* @brief Disable zero cross detection function.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32ChMask The mask for left or right channel. Valid values are:
* - \ref I2S_RIGHT
* - \ref I2S_LEFT
* @return None
* @details This function will clear RCHZCEN or LCHZCEN bit of I2SCON register to disable zero cross detection function.
*/
static __INLINE void I2S_DISABLE_TX_ZCD(I2S_T *i2s, uint32_t u32ChMask)
{
if(u32ChMask == I2S_RIGHT)
i2s->CON &= ~I2S_CON_RCHZCEN_Msk;
else
i2s->CON &= ~I2S_CON_LCHZCEN_Msk;
}
/**
* @brief Enable I2S TX DMA function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will set TXDMA bit of I2SCON register to transmit data with PDMA.
*/
#define I2S_ENABLE_TXDMA(i2s) ( (i2s)->CON |= I2S_CON_TXDMA_Msk )
/**
* @brief Disable I2S TX DMA function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear TXDMA bit of I2SCON register to disable TX DMA function.
*/
#define I2S_DISABLE_TXDMA(i2s) ( (i2s)->CON &= ~I2S_CON_TXDMA_Msk )
/**
* @brief Enable I2S RX DMA function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will set RXDMA bit of I2SCON register to receive data with PDMA.
*/
#define I2S_ENABLE_RXDMA(i2s) ( (i2s)->CON |= I2S_CON_RXDMA_Msk )
/**
* @brief Disable I2S RX DMA function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear RXDMA bit of I2SCON register to disable RX DMA function.
*/
#define I2S_DISABLE_RXDMA(i2s) ( (i2s)->CON &= ~I2S_CON_RXDMA_Msk )
/**
* @brief Enable I2S TX function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will set TXEN bit of I2SCON register to enable I2S TX function.
*/
#define I2S_ENABLE_TX(i2s) ( (i2s)->CON |= I2S_CON_TXEN_Msk )
/**
* @brief Disable I2S TX function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear TXEN bit of I2SCON register to disable I2S TX function.
*/
#define I2S_DISABLE_TX(i2s) ( (i2s)->CON &= ~I2S_CON_TXEN_Msk )
/**
* @brief Enable I2S RX function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will set RXEN bit of I2SCON register to enable I2S RX function.
*/
#define I2S_ENABLE_RX(i2s) ( (i2s)->CON |= I2S_CON_RXEN_Msk )
/**
* @brief Disable I2S RX function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear RXEN bit of I2SCON register to disable I2S RX function.
*/
#define I2S_DISABLE_RX(i2s) ( (i2s)->CON &= ~I2S_CON_RXEN_Msk )
/**
* @brief Enable TX Mute function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will set MUTE bit of I2SCON register to enable I2S TX mute function.
*/
#define I2S_ENABLE_TX_MUTE(i2s) ( (i2s)->CON |= I2S_CON_MUTE_Msk )
/**
* @brief Disable TX Mute function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear MUTE bit of I2SCON register to disable I2S TX mute function.
*/
#define I2S_DISABLE_TX_MUTE(i2s) ( (i2s)->CON &= ~I2S_CON_MUTE_Msk )
/**
* @brief Clear TX FIFO.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear TX FIFO. The internal TX FIFO pointer will be reset to FIFO start point.
*/
#define I2S_CLR_TX_FIFO(i2s) ( (i2s)->CON |= I2S_CON_CLR_TXFIFO_Msk )
/**
* @brief Clear RX FIFO.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details This macro will clear RX FIFO. The internal RX FIFO pointer will be reset to FIFO start point.
*/
#define I2S_CLR_RX_FIFO(i2s) ( (i2s)->CON |= I2S_CON_CLR_RXFIFO_Msk )
/**
* @brief This function sets the recording source channel when mono mode is used.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Ch Left or right channel. Valid values are:
* - \ref I2S_MONO_LEFT
* - \ref I2S_MONO_RIGHT
* @return None
* @details This function selects the recording source channel of monaural mode.
*/
static __INLINE void I2S_SET_MONO_RX_CHANNEL(I2S_T *i2s, uint32_t u32Ch)
{
u32Ch == I2S_MONO_LEFT ?
(i2s->CON |= I2S_CON_RXLCH_Msk) :
(i2s->CON &= ~I2S_CON_RXLCH_Msk);
}
/**
* @brief Write data to I2S TX FIFO.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Data The value written to TX FIFO.
* @return None
* @details This macro will write a value to TX FIFO.
*/
#define I2S_WRITE_TX_FIFO(i2s, u32Data) ( (i2s)->TXFIFO = (u32Data) )
/**
* @brief Read RX FIFO.
* @param[in] i2s The pointer of the specified I2S module.
* @return The value read from RX FIFO.
* @details This function will return a value read from RX FIFO.
*/
#define I2S_READ_RX_FIFO(i2s) ( (i2s)->RXFIFO )
/**
* @brief Get the interrupt flag.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Mask The mask value for all interrupt flags. Valid values are:
* - \ref I2S_STATUS_LZCF_Msk
* - \ref I2S_STATUS_RZCF_Msk
* - \ref I2S_STATUS_TXTHF_Msk
* - \ref I2S_STATUS_TXOVF_Msk
* - \ref I2S_STATUS_TXUDF_Msk
* - \ref I2S_STATUS_RXTHF_Msk
* - \ref I2S_STATUS_RXOVF_Msk
* - \ref I2S_STATUS_RXUDF_Msk
* - \ref I2S_STATUS_I2STXINT_Msk
* - \ref I2S_STATUS_I2SRXINT_Msk
* - \ref I2S_STATUS_I2SINT_Msk
* @return The interrupt flags specified by the u32mask parameter.
* @details This macro will return the combination flags of I2SSTATUS register. The flags are specified by the u32mask parameter.
*/
#define I2S_GET_INT_FLAG(i2s, u32Mask) ( (i2s)->STATUS & (u32Mask) )
/**
* @brief Clear the interrupt flag.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Mask The mask value for all interrupt flags. Valid values are:
* - \ref I2S_STATUS_LZCF_Msk
* - \ref I2S_STATUS_RZCF_Msk
* - \ref I2S_STATUS_TXOVF_Msk
* - \ref I2S_STATUS_TXUDF_Msk
* - \ref I2S_STATUS_RXOVF_Msk
* - \ref I2S_STATUS_RXUDF_Msk
* @return None
* @details This macro will clear the interrupt flags specified by the u32mask parameter.
*/
#define I2S_CLR_INT_FLAG(i2s, u32Mask) ( (i2s)->STATUS = (u32Mask) )
/**
* @brief Get transmit FIFO level
* @param[in] i2s The pointer of the specified I2S module.
* @return TX FIFO level
* @details This macro will return the number of available words in TX FIFO.
*/
#define I2S_GET_TX_FIFO_LEVEL(i2s) ( (((i2s)->STATUS & I2S_STATUS_TX_LEVEL_Msk) >> I2S_STATUS_TX_LEVEL_Pos) & 0xF )
/**
* @brief Get receive FIFO level
* @param[in] i2s The pointer of the specified I2S module.
* @return RX FIFO level
* @details This macro will return the number of available words in RX FIFO.
*/
#define I2S_GET_RX_FIFO_LEVEL(i2s) ( (((i2s)->STATUS & I2S_STATUS_RX_LEVEL_Msk) >> I2S_STATUS_RX_LEVEL_Pos) & 0xF )
/* Function prototype declaration */
uint32_t I2S_Open(I2S_T *i2s, uint32_t u32MasterSlave, uint32_t u32SampleRate, uint32_t u32WordWidth, uint32_t u32Channels, uint32_t u32DataFormat);
void I2S_Close(I2S_T *i2s);
void I2S_EnableInt(I2S_T *i2s, uint32_t u32Mask);
void I2S_DisableInt(I2S_T *i2s, uint32_t u32Mask);
uint32_t I2S_EnableMCLK(I2S_T *i2s, uint32_t u32BusClock);
void I2S_DisableMCLK(I2S_T *i2s);
/*@}*/ /* end of group I2S_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group I2S_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

199
NUC123/StdDriver/inc/pdma.h Normal file
View File

@ -0,0 +1,199 @@
/**************************************************************************//**
* @file PDMA.h
* @version V1.00
* $Revision: 6 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series PDMA Controller Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __PDMA_H__
#define __PDMA_H__
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
* @{
*/
/** @addtogroup PDMA_Driver PDMA Driver
* @{
*/
/** @addtogroup PDMA_EXPORTED_CONSTANTS PDMA Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* Data Width Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define PDMA_WIDTH_8 0x00080000UL /*!<DMA Transfer Width 8-bit */
#define PDMA_WIDTH_16 0x00100000UL /*!<DMA Transfer Width 16-bit */
#define PDMA_WIDTH_32 0x00000000UL /*!<DMA Transfer Width 32-bit */
/*---------------------------------------------------------------------------------------------------------*/
/* Address Attribute Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define PDMA_SAR_INC 0x00000000UL /*!<DMA SAR increment */
#define PDMA_SAR_FIX 0x00000020UL /*!<DMA SAR fix address */
#define PDMA_DAR_INC 0x00000000UL /*!<DMA DAR increment */
#define PDMA_DAR_FIX 0x00000080UL /*!<DMA DAR fix address */
/*---------------------------------------------------------------------------------------------------------*/
/* Peripheral Transfer Mode Constant Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define PDMA_SPI0_TX 0x00000000UL /*!<DMA Connect to SPI0 TX */
#define PDMA_SPI1_TX 0x00000001UL /*!<DMA Connect to SPI1 TX */
#define PDMA_SPI2_TX 0x00000002UL /*!<DMA Connect to SPI2 TX */
#define PDMA_UART0_TX 0x00000003UL /*!<DMA Connect to UART0 TX */
#define PDMA_UART1_TX 0x00000004UL /*!<DMA Connect to UART1 TX */
#define PDMA_I2S_TX 0x00000005UL /*!<DMA Connect to I2S TX */
#define PDMA_SPI0_RX 0x00000006UL /*!<DMA Connect to SPI0 RX */
#define PDMA_SPI1_RX 0x00000007UL /*!<DMA Connect to SPI1 RX */
#define PDMA_SPI2_RX 0x00000008UL /*!<DMA Connect to SPI2 RX */
#define PDMA_UART0_RX 0x00000009UL /*!<DMA Connect to UART0 RX */
#define PDMA_UART1_RX 0x0000000AUL /*!<DMA Connect to UART1 RX */
#define PDMA_I2S_RX 0x0000000BUL /*!<DMA Connect to I2S RX */
#define PDMA_ADC 0x0000000CUL /*!<DMA Connect to ADC */
#define PDMA_PWM0_RX 0x0000000DUL /*!<DMA Connect to PWM0 RX */
#define PDMA_PWM1_RX 0x0000000EUL /*!<DMA Connect to PWM1 RX */
#define PDMA_PWM2_RX 0x0000000FUL /*!<DMA Connect to PWM2 RX */
#define PDMA_PWM3_RX 0x00000010UL /*!<DMA Connect to PWM3 RX */
#define PDMA_MEM 0x0000001FUL /*!<DMA Connect to Memory */
/*@}*/ /* end of group PDMA_EXPORTED_CONSTANTS */
/** @addtogroup PDMA_EXPORTED_FUNCTIONS PDMA Exported Functions
@{
*/
/**
* @brief Get PDMA Global Interrupt Status
*
* @param None
*
* @return Interrupt Status
*
* @details This macro gets the global interrupt status.
*/
#define PDMA_GET_INT_STATUS() ((uint32_t)(PDMA_GCR->GCRISR))
/**
* @brief Get PDMA Channel Interrupt Status
*
* @param[in] u32Ch Selected DMA channel
*
* @return Interrupt Status
*
* @details This macro gets the channel interrupt status.
*/
#define PDMA_GET_CH_INT_STS(u32Ch) (*((__IO uint32_t *)((uint32_t)&PDMA0->ISR + (uint32_t)((u32Ch)*0x100))))
/**
* @brief Clear PDMA Channel Interrupt Flag
*
* @param[in] u32Ch Selected DMA channel
* @param[in] u32Mask Interrupt Mask
*
* @return None
*
* @details This macro clear the channel interrupt flag.
*/
#define PDMA_CLR_CH_INT_FLAG(u32Ch, u32Mask) (*((__IO uint32_t *)((uint32_t)&PDMA0->ISR + (uint32_t)((u32Ch)*0x100))) = (u32Mask))
/**
* @brief Check Channel Status
*
* @param[in] u32Ch The selected channel
*
* @retval 0 The selected channel is idle
* @retval 1 The selected channel is busy
*
* @details Check the selected channel is busy or not.
*/
#define PDMA_IS_CH_BUSY(u32Ch) ((*((__IO uint32_t *)((uint32_t)&PDMA0->CSR +(uint32_t)((u32Ch)*0x100)))&PDMA_CSR_TRIG_EN_Msk)? 1 : 0)
/**
* @brief Set Source Address
*
* @param[in] u32Ch The selected channel
* @param[in] u32Addr The selected address
*
* @return None
*
* @details This macro set the selected channel source address.
*/
#define PDMA_SET_SRC_ADDR(u32Ch, u32Addr) (*((__IO uint32_t *)((uint32_t)&PDMA0->SAR + (uint32_t)((u32Ch)*0x100))) = (u32Addr))
/**
* @brief Set Destination Address
*
* @param[in] u32Ch The selected channel
* @param[in] u32Addr The selected address
*
* @return None
*
* @details This macro set the selected channel destination address.
*/
#define PDMA_SET_DST_ADDR(u32Ch, u32Addr) (*((__IO uint32_t *)((uint32_t)&PDMA0->DAR + (uint32_t)((u32Ch)*0x100))) = (u32Addr))
/**
* @brief Set Transfer Count
*
* @param[in] u32Ch The selected channel
* @param[in] u32Count Transfer Count
*
* @return None
*
* @details This macro set the selected channel transfer count.
* \hideinitializer
*/
#define PDMA_SET_TRANS_CNT(u32Ch, u32Count) { \
if (((uint32_t)*((__IO uint32_t *)((uint32_t)&PDMA0->CSR + (uint32_t)((u32Ch)*0x100))) & PDMA_CSR_APB_TWS_Msk) == PDMA_WIDTH_32) \
*((__IO uint32_t *)((uint32_t)&PDMA0->BCR + (uint32_t)((u32Ch)*0x100))) = ((u32Count) << 2); \
else if (((uint32_t)*((__IO uint32_t *)((uint32_t)&PDMA0->CSR + (uint32_t)((u32Ch)*0x100))) & PDMA_CSR_APB_TWS_Msk) == PDMA_WIDTH_8) \
*((__IO uint32_t *)((uint32_t)&PDMA0->BCR + (uint32_t)((u32Ch)*0x100))) = (u32Count); \
else if (((uint32_t)*((__IO uint32_t *)((uint32_t)&PDMA0->CSR + (uint32_t)((u32Ch)*0x100))) & PDMA_CSR_APB_TWS_Msk) == PDMA_WIDTH_16) \
*((__IO uint32_t *)((uint32_t)&PDMA0->BCR + (uint32_t)((u32Ch)*0x100))) = ((u32Count) << 1); \
}
/**
* @brief Stop the channel
*
* @param[in] u32Ch The selected channel
*
* @return None
*
* @details This macro stop the selected channel.
*/
#define PDMA_STOP(u32Ch) (*((__IO uint32_t *)((uint32_t)&PDMA0->CSR + (uint32_t)((u32Ch)*0x100))) &= ~PDMA_CSR_PDMACEN_Msk)
void PDMA_Open(uint32_t u32Mask);
void PDMA_Close(void);
void PDMA_SetTransferCnt(uint32_t u32Ch, uint32_t u32Width, uint32_t u32TransCount);
void PDMA_SetTransferAddr(uint32_t u32Ch, uint32_t u32SrcAddr, uint32_t u32SrcCtrl, uint32_t u32DstAddr, uint32_t u32DstCtrl);
void PDMA_SetTransferMode(uint32_t u32Ch, uint32_t u32Periphral, uint32_t u32ScatterEn, uint32_t u32DescAddr);
void PDMA_Trigger(uint32_t u32Ch);
void PDMA_EnableInt(uint32_t u32Ch, uint32_t u32Mask);
void PDMA_DisableInt(uint32_t u32Ch, uint32_t u32Mask);
/**
* @} End of PDMA Device Function Interface
*/
/**
* @} End of Function Interface
*/
/**
* @} End of PDMA_Driver
*/
#endif // __PDMA_H__

255
NUC123/StdDriver/inc/ps2.h Normal file
View File

@ -0,0 +1,255 @@
/**************************************************************************//**
* @file PS2.h
* @version V3.00
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series PS/2 Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#ifndef __PS2_H__
#define __PS2_H__
/*---------------------------------------------------------------------------------------------------------*/
/* Include related headers */
/*---------------------------------------------------------------------------------------------------------*/
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup PS2_Driver PS2 Driver
@{
*/
/** @addtogroup PS2_EXPORTED_FUNCTIONS PS2 Exported Functions
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* Define Macros and functions */
/*---------------------------------------------------------------------------------------------------------*/
/**
* @brief To Set PS/2 Tx FIFO length
*
* @param[in] u32Count Tx FIFO length
*
* @return None
*
* @details Before PS/2 data transmit, program needs to set the FIFO depth.
* \hideinitializer
*/
#define PS2_SET_TX_BYTE_CNT(u32Count) (PS2->PS2CON = (PS2->PS2CON & ~PS2_PS2CON_TXFIFO_DEPTH_Msk) \
| (((u32Count)-1) << PS2_PS2CON_TXFIFO_DEPTH_Pos))
/**
* @brief This function use to Get PS/2 Status
*
* @param None
*
* @return PS/2 bus status
*
* @details To get PS/2 bus status which are about Byte index, Tx/Rx status, Error status and PS/2 line status.
*/
#define PS2_GET_STATUS() (PS2->PS2STATUS)
/**
* @brief This function is used to Clear PS/2 Status
*
* @param[in] u32Mask Clear the specified status of PS/2 module:
* 1. PS2D_PS2STATUS_FRAMERR_Msk 2. PS2D_PS2STATUS_RXOVF_Msk
*
* @return None
*
* @details To clear PS/2 bus status which are about Byte index, TX/RX status, Error status, PS/2 line status.
*/
#define PS2_CLR_STATUS(u32Mask) (PS2->PS2STATUS = (u32Mask))
/**
* @brief This function is used to Clear PS/2 Tx FIFO
*
* @param None
*
* @return None
*
* @details Write 1 to terminate PS/2 device to host transmission.
*
* @note Write 1 is always clear Tx FIFO, and need write 0 to STOP the clear action.
*/
__STATIC_INLINE void PS2_CLEAR_TX_FIFO(void)
{
PS2->PS2CON |= PS2_PS2CON_CLRFIFO_Msk;
PS2->PS2CON &= ~PS2_PS2CON_CLRFIFO_Msk;
}
/**
* @brief This function is used to Clear PS2 Rx interrupt
*
* @param None
*
* @return None
*
* @details To disable PS/2 receive interrupt occurs.
*/
#define PS2_CLR_RX_INT_FLAG() (PS2->PS2INTID = PS2_PS2INTID_RXINT_Msk)
/**
* @brief This function is used to Clear PS/2 Tx Interrupt
*
* @param None
*
* @return None
*
* @details To disable PS/2 transmit interrupt occurs.
*/
#define PS2_CLR_TX_INT_FLAG() (PS2->PS2INTID = PS2_PS2INTID_TXINT_Msk)
/**
* @brief This function is used to Get PS/2 Interrupt
*
* @param[in] u32IntFlag Interrupt flag of PS2D_PS2INTID_TXINT_Msk, PS2D_PS2INTID_RXINT_Msk
*
* @retval 1 Interrupt occurs
* @retval 0 Interrupt not occurs
*
* @details To check PS/2 bus interrupt occur from TX or RX
*/
#define PS2_GET_INT_FLAG(u32IntFlag) ((PS2->PS2INTID & (u32IntFlag))?1:0)
/**
* @brief Disable PS2CLK and PS2DATA pins override.
*
* @param None
*
* @return None
*
* @details To disable the override control of PS2CLK and PS2DATA pins.
*/
#define PS2_DISABLE_OVERRIDE() (PS2->PS2CON &= ~PS2_PS2CON_OVERRIDE_Msk)
/**
* @brief Enable PS2CLK and PS2DATA pins Override.
*
* @param None
*
* @return None
*
* @details TO enable the override control of PS2CLK and PS2DATA pins.
*/
#define PS2_ENABLE_OVERRIDE() (PS2->PS2CON |= PS2_PS2CON_OVERRIDE_Msk)
/**
* @brief This function is used to Get Indicates which data byte in transmit data shift register
*
* @param None
*
* @return The indicates which data byte in transmit data shift register.
*
* @details To get a indication which a data byte in the data shift register.
*/
#define PS2_GET_TX_BYTE_INDEX() ((PS2->PS2STATUS & PS2_PS2STATUS_BYTEIDX_Msk) >> PS2_PS2STATUS_BYTEIDX_Pos)
/**
* @brief This function is used to set PS2DATA Pin low.
*
* @param None
*
* @return None
*
* @details To control the PS2DATA pin state to low.
*/
#define PS2_SET_DATA_LOW() (PS2->PS2CON &= ~PS2_PS2CON_FPS2DAT_Msk)
/**
* @brief This function is used to set PS2DATA Pin high
*
* @param None
*
* @return None
*
* @details To control the PS2DATA pin state to high.
*/
#define PS2_SET_DATA_HIGH() (PS2->PS2CON |= PS2_PS2CON_FPS2DAT_Msk)
/**
* @brief This function is used to set PS2CLK Pin low.
*
* @param None
*
* @return None
*
* @details To control the PS2CLK pin state to low.
*/
#define PS2_SET_CLK_LOW() (PS2->PS2CON &= ~PS2_PS2CON_FPS2CLK_Msk)
/**
* @brief This function is used to set PS2CLK Pin high.
*
* @param None
*
* @return None
*
* @details To control the PS2CLK pin state to high.
*/
#define PS2_SET_CLK_HIGH() (PS2->PS2CON |= PS2_PS2CON_FPS2CLK_Msk)
/**
* @brief Disable always sends acknowledge
*
* @param None
*
* @return None
*
* @details If parity error or Stop bit is not received correctly, acknowledge will not be sent to host at 12th clock.
*/
#define PS2_DISABLE_ACK_ALWAYS() (PS2->PS2CON |= PS2_PS2CON_ACK_Msk)
/**
* @brief Always sends acknowledge
*
* @param None
*
* @return None
*
* @details Always send acknowledge to host at 12th clock for host to device communication.
*/
#define PS2_ENABLE_ACK_ALWAYS() (PS2->PS2CON &= ~PS2_PS2CON_ACK_Msk)
/*---------------------------------------------------------------------------------------------------------*/
/* Define Function Prototypes */
/*---------------------------------------------------------------------------------------------------------*/
void PS2_Open(void);
void PS2_Close(void);
uint8_t PS2_Read(void);
int32_t PS2_Write(uint32_t *pu32Buf, uint32_t u32ByteCount);
void PS2_EnableInt(uint32_t u32Mask);
void PS2_DisableInt(uint32_t u32Mask);
/*@}*/ /* end of group PS2_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group PS2_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__PS2_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

231
NUC123/StdDriver/inc/pwm.h Normal file
View File

@ -0,0 +1,231 @@
/**************************************************************************//**
* @file pwm.h
* @version V3.00
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series PWM driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __PWM_H__
#define __PWM_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup PWM_Driver PWM Driver
@{
*/
/** @addtogroup PWM_EXPORTED_CONSTANTS PWM Exported Constants
@{
*/
#define PWM_CHANNEL_NUM (4) /*!< PWM channel number */
#define PWM_CLK_DIV_1 (4UL) /*!< PWM clock divide by 1 */
#define PWM_CLK_DIV_2 (0UL) /*!< PWM clock divide by 2 */
#define PWM_CLK_DIV_4 (1UL) /*!< PWM clock divide by 4 */
#define PWM_CLK_DIV_8 (2UL) /*!< PWM clock divide by 8 */
#define PWM_CLK_DIV_16 (3UL) /*!< PWM clock divide by 16 */
#define PWM_EDGE_ALIGNED (0UL) /*!< PWM working in edge aligned type */
#define PWM_CENTER_ALIGNED (1UL) /*!< PWM working in center aligned type */
#define PWM_PERIOD_INT_UNDERFLOW (0) /*!< PWM period interrupt triggered if counter underflow */
#define PWM_PERIOD_INT_MATCH_CNR (PWM_PIER_INT01TYPE_Msk) /*!< PWM period interrupt triggered if counter match CNR */
#define PWM_CAPTURE_INT_RISING_LATCH (PWM_CCR0_CRL_IE0_Msk) /*!< PWM capture interrupt if channel has rising transition */
#define PWM_CAPTURE_INT_FALLING_LATCH (PWM_CCR0_CFL_IE0_Msk) /*!< PWM capture interrupt if channel has falling transition */
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Group channel number constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_CH0 0x0 /*!< PWM Group A channel 0 */
#define PWM_CH1 0x1 /*!< PWM Group A channel 1 */
#define PWM_CH2 0x2 /*!< PWM Group A channel 2 */
#define PWM_CH3 0x3 /*!< PWM Group A channel 3 */
#define PWM_CCR_MASK 0x000F000F /*!< PWM CCR0/CCR2 bit0~3 and bit16~19 mask */
/*@}*/ /* end of group PWM_EXPORTED_CONSTANTS */
/** @addtogroup PWM_EXPORTED_FUNCTIONS PWM Exported Functions
@{
*/
/**
* @brief Enable output inverter of specified channel(s)
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel
* Bit 0 represents channel 0, bit 1 represents channel 1...
* @return None
* @details This macro is used to enable capture input inverter for specified channel(s).
* \hideinitializer
*/
#define PWM_ENABLE_OUTPUT_INVERTER(pwm, u32ChannelMask) \
do{ \
int i;\
(pwm)->PCR &= ~(PWM_PCR_CH0INV_Msk|PWM_PCR_CH1INV_Msk|PWM_PCR_CH2INV_Msk|PWM_PCR_CH3INV_Msk);\
for(i = 0; i < 4; i++) { \
if((u32ChannelMask) & (1 << i)) \
(pwm)->PCR |= (PWM_PCR_CH0INV_Msk << (PWM_PCR_CH0INV_Pos * (i * 4))); \
} \
}while(0)
/**
* @brief Get captured rising data of specified channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return The timer counter, 0~0xFFFF
* @details This macro is used to get captured rising data for specified channel.
*/
#define PWM_GET_CAPTURE_RISING_DATA(pwm, u32ChannelNum) (*((__IO uint32_t *) ((((uint32_t)&((pwm)->CRLR0)) + (u32ChannelNum) * 8))))
/**
* @brief Get captured falling data of specified channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return The timer counter, 0~0xFFFF
* @details This macro is used to get captured falling data for specified channel.
*/
#define PWM_GET_CAPTURE_FALLING_DATA(pwm, u32ChannelNum) (*((__IO uint32_t *) ((((uint32_t)&((pwm)->CFLR0)) + (u32ChannelNum) * 8))))
/**
* @brief Set the prescaler of the selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Prescaler Clock prescaler of specified channel. Valid values are between 1 ~ 0xFF
* @return None
* @details This macro is used to set timer pre-scale for specified channel.
* @note If u32Prescaler = 0, corresponding PWM-timer will be stopped.
* @note If u32Prescaler = x (x not equal to 0), it means Clock input is divided by (x + 1) before it is fed to the corresponding PWM counter.
*/
#define PWM_SET_PRESCALER(pwm, u32ChannelNum, u32Prescaler) \
((pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << (((u32ChannelNum) >> 1) * 8))) | ((u32Prescaler) << (((u32ChannelNum) >> 1) * 8)))
/**
* @brief Set the divider of the selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Divider Clock divider of specified channel. Valid values are
* - \ref PWM_CLK_DIV_1
* - \ref PWM_CLK_DIV_2
* - \ref PWM_CLK_DIV_4
* - \ref PWM_CLK_DIV_8
* - \ref PWM_CLK_DIV_16
* @return None
* @details This macro is used to set Timer clock source divider selection for specified channel.
*/
#define PWM_SET_DIVIDER(pwm, u32ChannelNum, u32Divider) \
((pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << ((u32ChannelNum) * 4))) | ((u32Divider) << ((u32ChannelNum) * 4)))
/**
* @brief Set the duty of the selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32CMR Duty of specified channel. Valid values are between 0~0xFFFF
* @return None
* @details This macro is used to set PWM Comparator value for specified channel.
* @note This new setting will take effect on next PWM period.
*/
#define PWM_SET_CMR(pwm, u32ChannelNum, u32CMR) (*((__IO uint32_t *) ((((uint32_t)&((pwm)->CMR0)) + (u32ChannelNum) * 12))) = (u32CMR))
/**
* @brief Set the period of the selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32CNR Period of specified channel. Valid values are between 0~0xFFFF
* @return None
* @details This macro is used to set timer loaded value(CNR) for specified channel.\n
* Loaded value determines the PWM period.
* @note This new setting will take effect on next PWM period.
* @note PWM counter will stop if period length set to 0.
*/
#define PWM_SET_CNR(pwm, u32ChannelNum, u32CNR) (*((__IO uint32_t *) ((((uint32_t)&((pwm)->CNR0)) + (u32ChannelNum) * 12))) = (u32CNR))
/**
* @brief Set the PWM aligned type
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel
* Bit 0 represents channel 0, bit 1 represents channel 1...
* @param[in] u32AlignedType PWM aligned type, valid values are:
* - \ref PWM_EDGE_ALIGNED
* - \ref PWM_CENTER_ALIGNED
* @return None
* @details This macro is used to set the PWM aligned type.
* @note PWM trigger ADC function is only supported when PWM operating at Center-aligned type.
* \hideinitializer
*/
#define PWM_SET_ALIGNED_TYPE(pwm, u32ChannelMask, u32AlignedType) \
do{ \
int i; \
for(i = 0; i < 4; i++) { \
if((u32ChannelMask) & (1 << i)) \
(pwm)->PCR = ((pwm)->PCR & ~(PWM_PCR_PWM01TYPE_Msk << (i >> 1))) | ((u32AlignedType) << (PWM_PCR_PWM01TYPE_Pos + (i >> 1))); \
} \
}while(0)
uint32_t PWM_ConfigCaptureChannel(PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32UnitTimeNsec,
uint32_t u32CaptureEdge);
uint32_t PWM_ConfigOutputChannel(PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32Frequncy,
uint32_t u32DutyCycle);
void PWM_Start(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_Stop(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_ForceStop(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_EnableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition);
void PWM_DisableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_ClearADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition);
uint32_t PWM_GetADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_EnableCapture(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_DisableCapture(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_EnableOutput(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_DisableOutput(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_EnablePDMA(PWM_T *pwm, uint32_t u32ChannelMask, uint32_t u32RisingFirst);
void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelMask);
void PWM_EnableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration);
void PWM_DisableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_EnableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge);
void PWM_DisableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge);
void PWM_ClearCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge);
uint32_t PWM_GetCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_EnableDutyInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntDutyType);
void PWM_DisableDutyInt(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_ClearDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum);
uint32_t PWM_GetDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_EnablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType);
void PWM_DisablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum);
void PWM_ClearPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum);
uint32_t PWM_GetPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum);
/*@}*/ /* end of group PWM_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group PWM_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__PWM_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

393
NUC123/StdDriver/inc/spi.h Normal file
View File

@ -0,0 +1,393 @@
/**************************************************************************//**
* @file spi.h
* @version V3.0
* $Revision: 11 $
* $Date: 15/07/02 3:18p $
* @brief NUC123 Series SPI Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __SPI_H__
#define __SPI_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup SPI_Driver SPI Driver
@{
*/
/** @addtogroup SPI_EXPORTED_CONSTANTS SPI Exported Constants
@{
*/
#define SPI_MODE_0 (SPI_CNTRL_TX_NEG_Msk) /*!< CLKP=0; RX_NEG=0; TX_NEG=1 */
#define SPI_MODE_1 (SPI_CNTRL_RX_NEG_Msk) /*!< CLKP=0; RX_NEG=1; TX_NEG=0 */
#define SPI_MODE_2 (SPI_CNTRL_CLKP_Msk | SPI_CNTRL_RX_NEG_Msk) /*!< CLKP=1; RX_NEG=1; TX_NEG=0 */
#define SPI_MODE_3 (SPI_CNTRL_CLKP_Msk | SPI_CNTRL_TX_NEG_Msk) /*!< CLKP=1; RX_NEG=0; TX_NEG=1 */
#define SPI_SLAVE (SPI_CNTRL_SLAVE_Msk) /*!< Set as slave */
#define SPI_MASTER (0x0) /*!< Set as master */
#define SPI_SS0 (1<<SPI_SSR_SSR_Pos) /*!< Select SPIn_SS0 */
#define SPI_SS1 (2<<SPI_SSR_SSR_Pos) /*!< Select SPIn_SS1 */
#define SPI_SS_ACTIVE_HIGH (SPI_SSR_SS_LVL_Msk) /*!< SS active high */
#define SPI_SS_ACTIVE_LOW (0x0) /*!< SS active low */
#define SPI_UNIT_INT_MASK (0x01) /*!< Unit transfer interrupt mask */
#define SPI_SSTA_INT_MASK (0x02) /*!< Slave 3-Wire mode start interrupt mask */
#define SPI_FIFO_TX_INT_MASK (0x04) /*!< FIFO TX interrupt mask */
#define SPI_FIFO_RX_INT_MASK (0x08) /*!< FIFO RX interrupt mask */
#define SPI_FIFO_RXOV_INT_MASK (0x10) /*!< FIFO RX overrun interrupt mask */
#define SPI_FIFO_TIMEOUT_INT_MASK (0x20) /*!< FIFO RX timeout interrupt mask */
#define SPI_BUSY_MASK (0x01) /*!< Busy status mask */
#define SPI_RX_EMPTY_MASK (0x02) /*!< RX empty status mask */
#define SPI_RX_FULL_MASK (0x04) /*!< RX full status mask */
#define SPI_TX_EMPTY_MASK (0x08) /*!< TX empty status mask */
#define SPI_TX_FULL_MASK (0x10) /*!< TX full status mask */
/*@}*/ /* end of group SPI_EXPORTED_CONSTANTS */
/** @addtogroup SPI_EXPORTED_FUNCTIONS SPI Exported Functions
@{
*/
/**
* @brief Abort the current transfer in Slave 3-wire mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set the SLV_ABORT bit of SPI_CNTRL2 register to abort the current transfer in Slave 3-wire mode.
*/
#define SPI_ABORT_3WIRE_TRANSFER(spi) ((spi)->CNTRL2 |= SPI_CNTRL2_SLV_ABORT_Msk)
/**
* @brief Clear the Slave 3-wire mode start interrupt flag.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Write 1 to SLV_START_INTSTS bit of SPI_STATUS register to clear the Slave 3-wire mode start interrupt flag.
*/
#define SPI_CLR_3WIRE_START_INT_FLAG(spi) ((spi)->STATUS = SPI_STATUS_SLV_START_INTSTS_Msk)
/**
* @brief Clear the unit transfer interrupt flag.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Write 1 to IF bit of SPI_STATUS register to clear the unit transfer interrupt flag.
*/
#define SPI_CLR_UNIT_TRANS_INT_FLAG(spi) ((spi)->STATUS = SPI_STATUS_IF_Msk)
/**
* @brief Disable 2-bit Transfer mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear TWOB bit of SPI_CNTRL register to disable 2-bit Transfer mode.
*/
#define SPI_DISABLE_2BIT_MODE(spi) ((spi)->CNTRL &= ~SPI_CNTRL_TWOB_Msk)
/**
* @brief Disable Slave 3-wire mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear NOSLVSEL bit of SPI_CNTRL2 register to disable Slave 3-wire mode.
*/
#define SPI_DISABLE_3WIRE_MODE(spi) ((spi)->CNTRL2 &= ~SPI_CNTRL2_NOSLVSEL_Msk)
/**
* @brief Disable Dual I/O mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear DUAL_IO_EN bit of SPI_CNTRL2 register to disable Dual I/O mode.
*/
#define SPI_DISABLE_DUAL_MODE(spi) ((spi)->CNTRL2 &= ~SPI_CNTRL2_DUAL_IO_EN_Msk)
/**
* @brief Enable 2-bit Transfer mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set TWOB bit of SPI_CNTRL register to enable 2-bit Transfer mode.
*/
#define SPI_ENABLE_2BIT_MODE(spi) ((spi)->CNTRL |= SPI_CNTRL_TWOB_Msk)
/**
* @brief Enable Slave 3-wire mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set NOSLVSEL bit of SPI_CNTRL2 register to enable Slave 3-wire mode.
* Only available in Slave mode.
*/
#define SPI_ENABLE_3WIRE_MODE(spi) ((spi)->CNTRL2 |= SPI_CNTRL2_NOSLVSEL_Msk)
/**
* @brief Enable Dual input mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear DUAL_IO_DIR bit and set DUAL_IO_EN bit of SPI_CNTRL2 register to enable Dual input mode.
*/
#define SPI_ENABLE_DUAL_INPUT_MODE(spi) ((spi)->CNTRL2 = ((spi)->CNTRL2 & (~SPI_CNTRL2_DUAL_IO_DIR_Msk)) | SPI_CNTRL2_DUAL_IO_EN_Msk)
/**
* @brief Enable Dual output mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set DUAL_IO_DIR bit and DUAL_IO_EN bit of SPI_CNTRL2 register to enable Dual output mode.
*/
#define SPI_ENABLE_DUAL_OUTPUT_MODE(spi) ((spi)->CNTRL2 |= (SPI_CNTRL2_DUAL_IO_EN_Msk | SPI_CNTRL2_DUAL_IO_DIR_Msk))
/**
* @brief Trigger RX PDMA function.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set RX_DMA_GO bit of SPI_DMA register to enable RX PDMA transfer function.
*/
#define SPI_TRIGGER_RX_PDMA(spi) ((spi)->DMA |= SPI_DMA_RX_DMA_GO_Msk)
/**
* @brief Trigger TX PDMA function.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set TX_DMA_GO bit of SPI_DMA register to enable TX PDMA transfer function.
*/
#define SPI_TRIGGER_TX_PDMA(spi) ((spi)->DMA |= SPI_DMA_TX_DMA_GO_Msk)
/**
* @brief Trigger TX and RX PDMA function.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set TX_DMA_GO bit and RX_DMA_GO bit of SPI_DMA register to enable TX and RX PDMA transfer function.
*/
#define SPI_TRIGGER_TX_RX_PDMA(spi) ((spi)->DMA |= (SPI_DMA_TX_DMA_GO_Msk | SPI_DMA_RX_DMA_GO_Msk))
/**
* @brief Get the count of available data in RX FIFO.
* @param[in] spi The pointer of the specified SPI module.
* @return The count of available data in RX FIFO.
* @details Read RX_FIFO_COUNT (SPI_STATUS[15:12]) to get the count of available data in RX FIFO.
*/
#define SPI_GET_RX_FIFO_COUNT(spi) (((spi)->STATUS & SPI_STATUS_RX_FIFO_COUNT_Msk) >> SPI_STATUS_RX_FIFO_COUNT_Pos)
/**
* @brief Get the RX FIFO empty flag.
* @param[in] spi The pointer of the specified SPI module.
* @retval 0 RX FIFO is not empty.
* @retval 1 RX FIFO is empty.
* @details Read RX_EMPTY bit of SPI_STATUS register to get the RX FIFO empty flag.
*/
#define SPI_GET_RX_FIFO_EMPTY_FLAG(spi) (((spi)->STATUS & SPI_STATUS_RX_EMPTY_Msk)>>SPI_STATUS_RX_EMPTY_Pos)
/**
* @brief Get the TX FIFO empty flag.
* @param[in] spi The pointer of the specified SPI module.
* @retval 0 TX FIFO is not empty.
* @retval 1 TX FIFO is empty.
* @details Read TX_EMPTY bit of SPI_STATUS register to get the TX FIFO empty flag.
*/
#define SPI_GET_TX_FIFO_EMPTY_FLAG(spi) (((spi)->STATUS & SPI_STATUS_TX_EMPTY_Msk)>>SPI_STATUS_TX_EMPTY_Pos)
/**
* @brief Get the TX FIFO full flag.
* @param[in] spi The pointer of the specified SPI module.
* @retval 0 TX FIFO is not full.
* @retval 1 TX FIFO is full.
* @details Read TX_FULL bit of SPI_STATUS register to get the TX FIFO full flag.
*/
#define SPI_GET_TX_FIFO_FULL_FLAG(spi) (((spi)->STATUS & SPI_STATUS_TX_FULL_Msk)>>SPI_STATUS_TX_FULL_Pos)
/**
* @brief Get the datum read from RX0 register.
* @param[in] spi The pointer of the specified SPI module.
* @return Data in RX0 register.
* @details Read SPI_RX0 register to get the received datum.
*/
#define SPI_READ_RX0(spi) ((spi)->RX[0])
/**
* @brief Get the datum read from RX1 register.
* @param[in] spi The pointer of the specified SPI module.
* @return Data in RX1 register.
* @details Read SPI_RX1 register to get the received datum.
*/
#define SPI_READ_RX1(spi) ((spi)->RX[1])
/**
* @brief Write datum to TX0 register.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32TxData The datum which user attempt to transfer through SPI bus.
* @return None.
* @details Write u32TxData to TX0 register.
*/
#define SPI_WRITE_TX0(spi, u32TxData) ((spi)->TX[0] = (u32TxData))
/**
* @brief Write datum to TX1 register.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32TxData The datum which user attempt to transfer through SPI bus.
* @return None.
* @details Write u32TxData to TX1 register.
*/
#define SPI_WRITE_TX1(spi, u32TxData) ((spi)->TX[1] = (u32TxData))
/**
* @brief Set SPIn_SS0, SPIn_SS1 pin to high or low state.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] ss0 0 = Set SPIn_SS0 to low. 1 = Set SPIn_SS0 to high.
* @param[in] ss1 0 = Set SPIn_SS1 to low. 1 = Set SPIn_SS1 to high.
* @return None.
* @details Disable automatic slave selection function and set SPIn_SS0/SPIn_SS1 pin to specified high/low state.
* Only available in Master mode.
*/
#define SPI_SET_SS_LEVEL(spi, ss0, ss1) ((spi)->SSR = ((spi)->SSR & ~(SPI_SSR_AUTOSS_Msk|SPI_SSR_SS_LVL_Msk|SPI_SSR_SSR_Msk)) | (((ss1)^1) << 1) | ((ss0)^1))
/**
* @brief Set SPIn_SS0 pin to high state.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Disable automatic slave selection function and set SPIn_SS0 pin to high state. Only available in Master mode.
*/
#define SPI_SET_SS0_HIGH(spi) ((spi)->SSR = ((spi)->SSR & ~(SPI_SSR_AUTOSS_Msk|SPI_SSR_SS_LVL_Msk|SPI_SS0)))
/**
* @brief Set SPIn_SS1 pin to high state.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Disable automatic slave selection function and set SPIn_SS1 pin to high state. Only available in Master mode.
*/
#define SPI_SET_SS1_HIGH(spi) ((spi)->SSR = ((spi)->SSR & ~(SPI_SSR_AUTOSS_Msk|SPI_SSR_SS_LVL_Msk|SPI_SS1)))
/**
* @brief Set SPIn_SS0 pin to low state.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Disable automatic slave selection function and set SPIn_SS0 pin to low state. Only available in Master mode.
*/
#define SPI_SET_SS0_LOW(spi) ((spi)->SSR = ((spi)->SSR & ~(SPI_SSR_AUTOSS_Msk|SPI_SSR_SS_LVL_Msk|SPI_SS0)) | SPI_SS0)
/**
* @brief Set SPIn_SS1 pin to low state.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Disable automatic slave selection function and set SPIn_SS1 pin to low state. Only available in Master mode.
*/
#define SPI_SET_SS1_LOW(spi) ((spi)->SSR = ((spi)->SSR & ~(SPI_SSR_AUTOSS_Msk|SPI_SSR_SS_LVL_Msk|SPI_SS1)) | SPI_SS1)
/**
* @brief Enable Byte Reorder function.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set REORDER bit of SPI_CNTRL register to enable Byte Reorder function.
*/
#define SPI_ENABLE_BYTE_REORDER(spi) ((spi)->CNTRL |= SPI_CNTRL_REORDER_Msk)
/**
* @brief Disable Byte Reorder function.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear REORDER bit of SPI_CNTRL register to disable Byte Reorder function.
*/
#define SPI_DISABLE_BYTE_REORDER(spi) ((spi)->CNTRL &= ~SPI_CNTRL_REORDER_Msk)
/**
* @brief Set the length of suspend interval.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32SuspCycle Decides the length of suspend interval. It could be 0 ~ 15.
* @return None.
* @details Set the length of suspend interval according to u32SuspCycle.
* The length of suspend interval is ((u32SuspCycle + 0.5) * the length of one SPI bus clock cycle).
* Only available in Master mode.
*/
#define SPI_SET_SUSPEND_CYCLE(spi, u32SuspCycle) ((spi)->CNTRL = ((spi)->CNTRL & ~SPI_CNTRL_SP_CYCLE_Msk) | ((u32SuspCycle) << SPI_CNTRL_SP_CYCLE_Pos))
/**
* @brief Set the SPI transfer sequence with LSB first.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Set LSB bit of SPI_CNTRL register to set the SPI transfer sequence with LSB first.
*/
#define SPI_SET_LSB_FIRST(spi) ((spi)->CNTRL |= SPI_CNTRL_LSB_Msk)
/**
* @brief Set the SPI transfer sequence with MSB first.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details Clear LSB bit of SPI_CNTRL register to set the SPI transfer sequence with MSB first.
*/
#define SPI_SET_MSB_FIRST(spi) ((spi)->CNTRL &= ~SPI_CNTRL_LSB_Msk)
/**
* @brief Set the data width of a SPI transaction.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Width The bit width of transfer data.
* @return None.
* @details The data width can be 8 ~ 32 bits.
*/
#define SPI_SET_DATA_WIDTH(spi, u32Width) ((spi)->CNTRL = ((spi)->CNTRL & ~SPI_CNTRL_TX_BIT_LEN_Msk) | (((u32Width)&0x1F) << SPI_CNTRL_TX_BIT_LEN_Pos))
/**
* @brief Get the SPI busy state.
* @param[in] spi The pointer of the specified SPI module.
* @retval 0 SPI controller is not busy.
* @retval 1 SPI controller is busy.
* @details This macro will return the busy state of SPI controller.
*/
#define SPI_IS_BUSY(spi) ( ((spi)->CNTRL & SPI_CNTRL_GO_BUSY_Msk)>>SPI_CNTRL_GO_BUSY_Pos )
/**
* @brief Set the GO_BUSY bit to trigger SPI transfer.
* @param[in] spi The pointer of the specified SPI module.
* @return None.
* @details If FIFO mode is disabled, user can use this macro to trigger the data transfer after all configuration is ready.
* If FIFO mode is enabled, user should not use this macro to trigger the data transfer. SPI controller will trigger the data transfer
* automatically after user write to SPI_TX0/1 register.
*/
#define SPI_TRIGGER(spi) ((spi)->CNTRL |= SPI_CNTRL_GO_BUSY_Msk)
/* Function prototype declaration */
uint32_t SPI_Open(SPI_T *spi, uint32_t u32MasterSlave, uint32_t u32SPIMode, uint32_t u32DataWidth, uint32_t u32BusClock);
void SPI_Close(SPI_T *spi);
void SPI_ClearRxFIFO(SPI_T *spi);
void SPI_ClearTxFIFO(SPI_T *spi);
void SPI_DisableAutoSS(SPI_T *spi);
void SPI_EnableAutoSS(SPI_T *spi, uint32_t u32SSPinMask, uint32_t u32ActiveLevel);
uint32_t SPI_SetBusClock(SPI_T *spi, uint32_t u32BusClock);
void SPI_EnableFIFO(SPI_T *spi, uint32_t u32TxThreshold, uint32_t u32RxThreshold);
void SPI_DisableFIFO(SPI_T *spi);
uint32_t SPI_GetBusClock(SPI_T *spi);
void SPI_EnableInt(SPI_T *spi, uint32_t u32Mask);
void SPI_DisableInt(SPI_T *spi, uint32_t u32Mask);
uint32_t SPI_GetIntFlag(SPI_T *spi, uint32_t u32Mask);
void SPI_ClearIntFlag(SPI_T *spi, uint32_t u32Mask);
uint32_t SPI_GetStatus(SPI_T *spi, uint32_t u32Mask);
/**
* @} End of SPI Device Function Interface
*/
/**
* @} End of NUC123 Function Interface
*/
/**
* @} End of Standard_Driver
*/
#ifdef __cplusplus
}
#endif
#endif

1369
NUC123/StdDriver/inc/sys.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,394 @@
/**************************************************************************//**
* @file timer.h
* @version V3.00
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series Timer driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __TIMER_H__
#define __TIMER_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup TIMER_Driver TIMER Driver
@{
*/
/** @addtogroup TIMER_EXPORTED_CONSTANTS TIMER Exported Constants
@{
*/
#define TIMER_ONESHOT_MODE (0UL << TIMER_TCSR_MODE_Pos) /*!< Timer working in one-shot mode */
#define TIMER_PERIODIC_MODE (1UL << TIMER_TCSR_MODE_Pos) /*!< Timer working in periodic mode */
#define TIMER_TOGGLE_MODE (2UL << TIMER_TCSR_MODE_Pos) /*!< Timer working in toggle-output mode */
#define TIMER_CONTINUOUS_MODE (3UL << TIMER_TCSR_MODE_Pos) /*!< Timer working in continuous counting mode */
#define TIMER_CAPTURE_FREE_COUNTING_MODE (0UL << TIMER_TEXCON_RSTCAPSEL_Pos) /*!< Timer capture event to get timer counter value */
#define TIMER_CAPTURE_COUNTER_RESET_MODE (1UL << TIMER_TEXCON_RSTCAPSEL_Pos) /*!< Timer capture event to reset timer counter */
#define TIMER_CAPTURE_FALLING_EDGE (0UL << TIMER_TEXCON_TEX_EDGE_Pos) /*!< Falling edge trigger timer capture */
#define TIMER_CAPTURE_RISING_EDGE (1UL << TIMER_TEXCON_TEX_EDGE_Pos) /*!< Rising edge trigger timer capture */
#define TIMER_CAPTURE_FALLING_AND_RISING_EDGE (2UL << TIMER_TEXCON_TEX_EDGE_Pos) /*!< Both falling and rising edge trigger timer capture */
#define TIMER_COUNTER_FALLING_EDGE (0UL << TIMER_TEXCON_TX_PHASE_Pos) /*!< Counter increase on falling edge */
#define TIMER_COUNTER_RISING_EDGE (1UL << TIMER_TEXCON_TX_PHASE_Pos) /*!< Counter increase on rising edge */
/*@}*/ /* end of group TIMER_EXPORTED_CONSTANTS */
/** @addtogroup TIMER_EXPORTED_FUNCTIONS TIMER Exported Functions
@{
*/
/**
* @brief Set Timer Compare Value
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32Value Timer compare value. Valid values are between 2 to 0xFFFFFF.
*
* @return None
*
* @details This macro is used to set new Timer compared value.
*/
#define TIMER_SET_CMP_VALUE(timer, u32Value) ((timer)->TCMPR = (u32Value))
/**
* @brief Set Timer Prescale Value
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32Value Timer prescale value. Valid values are between 0 to 0xFF.
*
* @return None
*
* @details This macro is used to set new Timer prescale value.
* @note Clock input is divided by (prescale + 1) before it is fed into timer.
*/
#define TIMER_SET_PRESCALE_VALUE(timer, u32Value) ((timer)->TCSR = ((timer)->TCSR & ~TIMER_TCSR_PRESCALE_Msk) | (u32Value))
/**
* @brief Check specify Timer Status
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @retval 0 Timer 24-bit up counter is inactive
* @retval 1 Timer 24-bit up counter is active
*
* @details This macro is used to check if specify Timer channel is inactive or active.
*/
#define TIMER_IS_ACTIVE(timer) ((timer)->TCSR & TIMER_TCSR_CACT_Msk ? 1 : 0)
/**
* @brief Start Timer Counting
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to start Timer counting.
*/
static __INLINE void TIMER_Start(TIMER_T *timer)
{
timer->TCSR |= TIMER_TCSR_CEN_Msk;
}
/**
* @brief Stop Timer Counting
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to stop/suspend Timer counting.
*/
static __INLINE void TIMER_Stop(TIMER_T *timer)
{
timer->TCSR &= ~TIMER_TCSR_CEN_Msk;
}
/**
* @brief Enable Timer Interrupt Wakeup Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to enable the Timer interrupt wake-up function.
* @note To wake the system from Power-down mode, timer clock source must be ether LXT or LIRC.
*/
static __INLINE void TIMER_EnableWakeup(TIMER_T *timer)
{
timer->TCSR |= TIMER_TCSR_WAKE_EN_Msk;
}
/**
* @brief Disable Timer Wakeup Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to disable the Timer interrupt wake-up function.
*/
static __INLINE void TIMER_DisableWakeup(TIMER_T *timer)
{
timer->TCSR &= ~TIMER_TCSR_WAKE_EN_Msk;
}
/**
* @brief Enable Capture Pin De-bounce
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to enable the capture pin detection de-bounce function.
*/
static __INLINE void TIMER_EnableCaptureDebounce(TIMER_T *timer)
{
timer->TEXCON |= TIMER_TEXCON_TEXDB_Msk;
}
/**
* @brief Disable Capture Pin De-bounce
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to disable the capture pin detection de-bounce function.
*/
static __INLINE void TIMER_DisableCaptureDebounce(TIMER_T *timer)
{
timer->TEXCON &= ~TIMER_TEXCON_TEXDB_Msk;
}
/**
* @brief Enable Counter Pin De-bounce
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to enable the counter pin detection de-bounce function.
*/
static __INLINE void TIMER_EnableEventCounterDebounce(TIMER_T *timer)
{
timer->TEXCON |= TIMER_TEXCON_TCDB_Msk;
}
/**
* @brief Disable Counter Pin De-bounce
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to disable the counter pin detection de-bounce function.
*/
static __INLINE void TIMER_DisableEventCounterDebounce(TIMER_T *timer)
{
timer->TEXCON &= ~TIMER_TEXCON_TCDB_Msk;
}
/**
* @brief Enable Timer Time-out Interrupt
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to enable the Timer time-out interrupt function.
*/
static __INLINE void TIMER_EnableInt(TIMER_T *timer)
{
timer->TCSR |= TIMER_TCSR_IE_Msk;
}
/**
* @brief Disable Timer Time-out Interrupt
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to disable the Timer time-out interrupt function.
*/
static __INLINE void TIMER_DisableInt(TIMER_T *timer)
{
timer->TCSR &= ~TIMER_TCSR_IE_Msk;
}
/**
* @brief Enable Capture Interrupt
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to enable the Timer capture trigger interrupt function.
*/
static __INLINE void TIMER_EnableCaptureInt(TIMER_T *timer)
{
timer->TEXCON |= TIMER_TEXCON_TEXIEN_Msk;
}
/**
* @brief Disable Capture Interrupt
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function is used to disable the Timer capture trigger interrupt function.
*/
static __INLINE void TIMER_DisableCaptureInt(TIMER_T *timer)
{
timer->TEXCON &= ~TIMER_TEXCON_TEXIEN_Msk;
}
/**
* @brief Get Timer Time-out Interrupt Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @retval 0 Timer time-out interrupt did not occur
* @retval 1 Timer time-out interrupt occurred
*
* @details This function indicates Timer time-out interrupt occurred or not.
*/
static __INLINE uint32_t TIMER_GetIntFlag(TIMER_T *timer)
{
return (timer->TISR & TIMER_TISR_TIF_Msk ? 1 : 0);
}
/**
* @brief Clear Timer time-out Interrupt Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function clears Timer time-out interrupt flag.
*/
static __INLINE void TIMER_ClearIntFlag(TIMER_T *timer)
{
timer->TISR = TIMER_TISR_TIF_Msk;
}
/**
* @brief Get Timer Capture Interrupt Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @retval 0 Timer capture interrupt did not occur
* @retval 1 Timer capture interrupt occurred
*
* @details This function indicates Timer capture interrupt occurred or not.
*/
static __INLINE uint32_t TIMER_GetCaptureIntFlag(TIMER_T *timer)
{
return timer->TEXISR;
}
/**
* @brief Clear Timer capture Interrupt Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function clears Timer capture interrupt flag.
*/
static __INLINE void TIMER_ClearCaptureIntFlag(TIMER_T *timer)
{
timer->TEXISR = TIMER_TEXISR_TEXIF_Msk;
}
/**
* @brief Get Timer Wakeup Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @retval 0 Timer did not wake up system
* @retval 1 Timer Timer wake up system
*
* @details This function indicates Timer has waked up system or not.
*/
static __INLINE uint32_t TIMER_GetWakeupFlag(TIMER_T *timer)
{
return (timer->TISR & TIMER_TISR_TWF_Msk ? 1 : 0);
}
/**
* @brief Clear Timer Wake-up Flag
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This function clears the Timer wake-up system flag.
*/
static __INLINE void TIMER_ClearWakeupFlag(TIMER_T *timer)
{
timer->TISR = TIMER_TISR_TWF_Msk;
}
/**
* @brief Get Capture value
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return Capture Value
*
* @details This function reports the current timer capture data value.
*/
static __INLINE uint32_t TIMER_GetCaptureData(TIMER_T *timer)
{
return timer->TCAP;
}
/**
* @brief Get Counter value
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return Counter Value
*
* @details This function reports the current 24-bit timer counter value.
*/
static __INLINE uint32_t TIMER_GetCounter(TIMER_T *timer)
{
return timer->TDR;
}
uint32_t TIMER_Open(TIMER_T *timer, uint32_t u32Mode, uint32_t u32Freq);
void TIMER_Close(TIMER_T *timer);
void TIMER_Delay(TIMER_T *timer, uint32_t u32Usec);
void TIMER_EnableCapture(TIMER_T *timer, uint32_t u32CapMode, uint32_t u32Edge);
void TIMER_DisableCapture(TIMER_T *timer);
void TIMER_EnableEventCounter(TIMER_T *timer, uint32_t u32Edge);
void TIMER_DisableEventCounter(TIMER_T *timer);
uint32_t TIMER_GetModuleClock(TIMER_T *timer);
/*@}*/ /* end of group TIMER_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group TIMER_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__TIMER_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

428
NUC123/StdDriver/inc/uart.h Normal file
View File

@ -0,0 +1,428 @@
/**************************************************************************//**
* @file UART.h
* @version V3.0
* $Revision: 15 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series UART Interface Controller Driver Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __UART_H__
#define __UART_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup UART_Driver UART Driver
@{
*/
/** @addtogroup UART_EXPORTED_CONSTANTS UART Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* UART FIFO size constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART0_FIFO_SIZE 16 /*!< UART0 supports separated receive/transmit 16/16 bytes entry FIFO */
#define UART1_FIFO_SIZE 16 /*!< UART1 supports separated receive/transmit 16/16 bytes entry FIFO */
/*---------------------------------------------------------------------------------------------------------*/
/* UA_FCR constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_FCR_RFITL_1BYTE (0x0 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 1 byte */
#define UART_FCR_RFITL_4BYTES (0x1 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 4 bytes */
#define UART_FCR_RFITL_8BYTES (0x2 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 8 bytes */
#define UART_FCR_RFITL_14BYTES (0x3 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 14 bytes */
#define UART_FCR_RTS_TRI_LEV_1BYTE (0x0 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 1 byte */
#define UART_FCR_RTS_TRI_LEV_4BYTES (0x1 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 4 bytes */
#define UART_FCR_RTS_TRI_LEV_8BYTES (0x2 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 8 bytes */
#define UART_FCR_RTS_TRI_LEV_14BYTES (0x3 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 14 bytes */
/*---------------------------------------------------------------------------------------------------------*/
/* UA_LCR constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_WORD_LEN_5 (0) /*!< UA_LCR setting to set UART word length to 5 bits */
#define UART_WORD_LEN_6 (1) /*!< UA_LCR setting to set UART word length to 6 bits */
#define UART_WORD_LEN_7 (2) /*!< UA_LCR setting to set UART word length to 7 bits */
#define UART_WORD_LEN_8 (3) /*!< UA_LCR setting to set UART word length to 8 bits */
#define UART_PARITY_NONE (0x0 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as no parity */
#define UART_PARITY_ODD (0x1 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as odd parity */
#define UART_PARITY_EVEN (0x3 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as even parity */
#define UART_PARITY_MARK (0x5 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to keep parity bit as '1' */
#define UART_PARITY_SPACE (0x7 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to keep parity bit as '0' */
#define UART_STOP_BIT_1 (0x0 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for one stop bit */
#define UART_STOP_BIT_1_5 (0x1 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for 1.5 stop bit when 5-bit word length */
#define UART_STOP_BIT_2 (0x1 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for two stop bit when 6, 7, 8-bit word length */
/*---------------------------------------------------------------------------------------------------------*/
/* UART RTS LEVEL TRIGGER constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_RTS_IS_LOW_LEV_ACTIVE (0x1 << UART_MCR_LEV_RTS_Pos) /*!< Set RTS is Low Level Active */
#define UART_RTS_IS_HIGH_LEV_ACTIVE (0x0 << UART_MCR_LEV_RTS_Pos) /*!< Set RTS is High Level Active */
/*---------------------------------------------------------------------------------------------------------*/
/* UA_IRCR constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_IRCR_TX_SELECT (0x1 << UART_IRCR_TX_SELECT_Pos) /*!< Set IrDA function Tx mode */
#define UART_IRCR_RX_SELECT (0x0 << UART_IRCR_TX_SELECT_Pos) /*!< Set IrDA function Rx mode */
/*---------------------------------------------------------------------------------------------------------*/
/* UA_FUNC_SEL constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_FUNC_SEL_UART (0x0 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set UART Function (Default) */
#define UART_FUNC_SEL_IrDA (0x2 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set IrDA Function */
#define UART_FUNC_SEL_RS485 (0x3 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set RS485 Function */
/*---------------------------------------------------------------------------------------------------------*/
/* UART BAUDRATE MODE constants definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define UART_BAUD_MODE0 (0) /*!< Set UART Baudrate Mode is Mode0 */
#define UART_BAUD_MODE2 (UART_BAUD_DIV_X_EN_Msk | UART_BAUD_DIV_X_ONE_Msk) /*!< Set UART Baudrate Mode is Mode2 */
/*@}*/ /* end of group UART_EXPORTED_CONSTANTS */
/** @addtogroup UART_EXPORTED_FUNCTIONS UART Exported Functions
@{
*/
/**
* @brief Calculate UART baudrate mode0 divider
*
* @param[in] u32SrcFreq UART clock frequency
* @param[in] u32BaudRate Baudrate of UART module
*
* @return UART baudrate mode0 divider
*
* @details This macro calculate UART baudrate mode0 divider.
*/
#define UART_BAUD_MODE0_DIVIDER(u32SrcFreq, u32BaudRate) ((((u32SrcFreq) + ((u32BaudRate)*8)) / (u32BaudRate) >> 4)-2)
/**
* @brief Calculate UART baudrate mode2 divider
*
* @param[in] u32SrcFreq UART clock frequency
* @param[in] u32BaudRate Baudrate of UART module
*
* @return UART baudrate mode2 divider
*
* @details This macro calculate UART baudrate mode2 divider.
*/
#define UART_BAUD_MODE2_DIVIDER(u32SrcFreq, u32BaudRate) ((((u32SrcFreq) + ((u32BaudRate)/2)) / (u32BaudRate))-2)
/**
* @brief Write data
*
* @param[in] uart The pointer of the specified UART module
* @param[in] u8Data Data byte to transmit
*
* @return None
*
* @details This macro write Data to Tx data register.
*/
#define UART_WRITE(uart, u8Data) ((uart)->THR = (u8Data))
/**
* @brief Read data
*
* @param[in] uart The pointer of the specified UART module
*
* @return The oldest data byte in RX FIFO
*
* @details This macro read Rx data register.
*/
#define UART_READ(uart) ((uart)->RBR)
/**
* @brief Get Tx empty
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Tx FIFO is not empty
* @retval >=1 Tx FIFO is empty
*
* @details This macro get Tx empty register value.
*/
#define UART_GET_TX_EMPTY(uart) ((uart)->FSR & UART_FSR_TX_EMPTY_Msk)
/**
* @brief Get Rx empty
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Rx FIFO is not empty
* @retval >=1 Rx FIFO is empty
*
* @details This macro get Rx empty register value.
*/
#define UART_GET_RX_EMPTY(uart) ((uart)->FSR & UART_FSR_RX_EMPTY_Msk)
/**
* @brief Check specified uart port transmission is over.
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Transmission is not over.
* @retval 1 Transmission is over.
*
* @details This macro return if Tx FIFO is empty and specified uart port transmission is over nor not.
*/
#define UART_IS_TX_EMPTY(uart) (((uart)->FSR & UART_FSR_TE_FLAG_Msk) >> UART_FSR_TE_FLAG_Pos)
/**
* @brief Wait specified uart port transmission is over
*
* @param[in] uart The pointer of the specified UART module
*
* @return None
*
* @details This macro wait specified uart port transmission is over.
*/
#define UART_WAIT_TX_EMPTY(uart) while(!((((uart)->FSR) & UART_FSR_TE_FLAG_Msk) >> UART_FSR_TE_FLAG_Pos))
/**
* @brief Check RX is ready or not
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 The number of bytes in the RX FIFO is less than the RFITL
* @retval 1 The number of bytes in the RX FIFO equals or larger than RFITL
*
* @details This macro check receive data available interrupt flag is set or not.
*/
#define UART_IS_RX_READY(uart) (((uart)->ISR & UART_ISR_RDA_IF_Msk)>>UART_ISR_RDA_IF_Pos)
/**
* @brief Check TX FIFO is full or not
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 1 TX FIFO is full
* @retval 0 TX FIFO is not full
*
* @details This macro check TX FIFO is full or not.
*/
#define UART_IS_TX_FULL(uart) (((uart)->FSR & UART_FSR_TX_FULL_Msk)>>UART_FSR_TX_FULL_Pos)
/**
* @brief Check RX FIFO is full or not
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 1 RX FIFO is full
* @retval 0 RX FIFO is not full
*
* @details This macro check RX FIFO is full or not.
*/
#define UART_IS_RX_FULL(uart) (((uart)->FSR & UART_FSR_RX_FULL_Msk)>>UART_FSR_RX_FULL_Pos)
/**
* @brief Get Tx full register value
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Tx FIFO is not full.
* @retval >=1 Tx FIFO is full.
*
* @details This macro get Tx full register value.
*/
#define UART_GET_TX_FULL(uart) ((uart)->FSR & UART_FSR_TX_FULL_Msk)
/**
* @brief Get Rx full register value
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Rx FIFO is not full.
* @retval >=1 Rx FIFO is full.
*
* @details This macro get Rx full register value.
*/
#define UART_GET_RX_FULL(uart) ((uart)->FSR & UART_FSR_RX_FULL_Msk)
/**
* @brief Enable specified UART interrupt
*
* @param[in] uart The pointer of the specified UART module
* @param[in] u32eIntSel Interrupt type select
* - UART_IER_WAKE_EN_Msk : Wakeup interrupt
* - UART_IER_BUF_ERR_IEN_Msk : Buffer Error interrupt
* - UART_IER_TOUT_IEN_Msk : Rx time-out interrupt
* - UART_IER_MODEM_IEN_Msk : Modem interrupt
* - UART_IER_RLS_IEN_Msk : Rx Line status interrupt
* - UART_IER_THRE_IEN_Msk : Tx empty interrupt
* - UART_IER_RDA_IEN_Msk : Rx ready interrupt
*
* @return None
*
* @details This macro enable specified UART interrupt.
*/
#define UART_ENABLE_INT(uart, u32eIntSel) ((uart)->IER |= (u32eIntSel))
/**
* @brief Disable specified UART interrupt
*
* @param[in] uart The pointer of the specified UART module
* @param[in] u32eIntSel Interrupt type select
* - UART_IER_WAKE_EN_Msk : Wakeup interrupt
* - UART_IER_BUF_ERR_IEN_Msk : Buffer Error interrupt
* - UART_IER_TOUT_IEN_Msk : Rx time-out interrupt
* - UART_IER_MODEM_IEN_Msk : Modem interrupt
* - UART_IER_RLS_IEN_Msk : Rx Line status interrupt
* - UART_IER_THRE_IEN_Msk : Tx empty interrupt
* - UART_IER_RDA_IEN_Msk : Rx ready interrupt
* @return None
*
* @details This macro disable specified UART interrupt.
*/
#define UART_DISABLE_INT(uart, u32eIntSel) ((uart)->IER &= ~ (u32eIntSel))
/**
* @brief Get specified interrupt indicator status
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32eIntTypeFlag Interrupt Type Flag, should be
* - UART_ISR_HW_BUF_ERR_INT_Msk : In DMA Mode, Buffer Error Interrupt Indicator
* - UART_ISR_HW_TOUT_INT_Msk : In DMA Mode, Rx Time-out Interrupt Indicator
* - UART_ISR_HW_MODEM_INT_Msk : In DMA Mode, MODEM Status Interrupt Indicator
* - UART_ISR_HW_RLS_INT_Msk : In DMA Mode, Rx Line Status Interrupt Indicator
* - UART_ISR_HW_BUF_ERR_IF_Msk : In DMA Mode, Buffer Error Interrupt Flag
* - UART_ISR_HW_TOUT_IF_Msk : In DMA Mode, Rx Time-out Interrupt Flag
* - UART_ISR_HW_MODEM_IF_Msk : In DMA Mode, MODEM Status Interrupt Flag
* - UART_ISR_HW_RLS_IF_Msk : In DMA Mode, Rx Line Status Interrupt Flag
* - UART_ISR_LIN_INT_Msk : LIN Bus Interrupt Indicator
* - UART_ISR_BUF_ERR_INT_Msk : Buffer Error Interrupt Indicator
* - UART_ISR_TOUT_INT_Msk : Rx Time-out Interrupt Indicator
* - UART_ISR_MODEM_INT_Msk : MODEM Status Interrupt Indicator
* - UART_ISR_RLS_INT_Msk : Rx Line Status Interrupt Indicator
* - UART_ISR_THRE_INT_Msk : Tx Empty Interrupt Indicator
* - UART_ISR_RDA_INT_Msk : Rx Ready Interrupt Indicator
* - UART_ISR_LIN_IF_Msk : LIN Bus Interrupt Flag
* - UART_ISR_BUF_ERR_IF_Msk : Buffer Error Interrupt Flag
* - UART_ISR_TOUT_IF_Msk : Rx Time-out Interrupt Flag
* - UART_ISR_MODEM_IF_Msk : MODEM Status Interrupt Flag
* - UART_ISR_RLS_IF_Msk : Rx Line Status Interrupt Flag
* - UART_ISR_THRE_IF_Msk : Tx Empty Interrupt Flag
* - UART_ISR_RDA_IF_Msk : Rx Ready Interrupt Flag
*
* @retval 0 The specified interrupt is not happened.
* @retval 1 The specified interrupt is happened.
*
* @details This macro get specified interrupt flag or interrupt indicator status.
*/
#define UART_GET_INT_FLAG(uart,u32eIntTypeFlag) (((uart)->ISR & (u32eIntTypeFlag))?1:0)
/**
* @brief Set RTS pin to low
*
* @param[in] uart The pointer of the specified UART module
*
* @return None
*
* @details This macro set RTS pin to low.
*/
__STATIC_INLINE void UART_CLEAR_RTS(UART_T* uart)
{
(uart)->MCR |= UART_MCR_LEV_RTS_Msk;
(uart)->MCR &= ~UART_MCR_RTS_Msk;
}
/**
* @brief Set RTS pin to high
*
* @param[in] uart The pointer of the specified UART module
* @return None
*
* @details This macro set RTS pin to high.
*/
__STATIC_INLINE void UART_SET_RTS(UART_T* uart)
{
(uart)->MCR |= UART_MCR_LEV_RTS_Msk | UART_MCR_RTS_Msk;
}
/**
* @brief Clear RS-485 Address Byte Detection Flag
*
* @param[in] uart The pointer of the specified UART module
*
* @return None
*
* @details This macro clear RS-485 address byte detection flag.
*/
#define UART_RS485_CLEAR_ADDR_FLAG(uart) ((uart)->FSR = UART_FSR_RS485_ADD_DETF_Msk)
/**
* @brief Get RS-485 Address Byte Detection Flag
*
* @param[in] uart The pointer of the specified UART module
*
* @retval 0 Receiver detects a data that is not an address bit.
* @retval 1 Receiver detects a data that is an address bit.
*
* @details This macro get RS-485 address byte detection flag.
*/
#define UART_RS485_GET_ADDR_FLAG(uart) (((uart)->FSR & UART_FSR_RS485_ADD_DETF_Msk) >> UART_FSR_RS485_ADD_DETF_Pos)
void UART_ClearIntFlag(UART_T* uart , uint32_t u32InterruptFlag);
void UART_Close(UART_T* uart);
void UART_DisableFlowCtrl(UART_T* uart);
void UART_DisableInt(UART_T* uart, uint32_t u32InterruptFlag);
void UART_EnableFlowCtrl(UART_T* uart);
void UART_EnableInt(UART_T* uart, uint32_t u32InterruptFlag);
void UART_Open(UART_T* uart, uint32_t u32baudrate);
uint32_t UART_Read(UART_T* uart, uint8_t *pu8RxBuf, uint32_t u32ReadBytes);
void UART_SetLine_Config(UART_T* uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits);
void UART_SetTimeoutCnt(UART_T* uart, uint32_t u32TOC);
void UART_SelectIrDAMode(UART_T* uart, uint32_t u32Buadrate, uint32_t u32Direction);
void UART_SelectRS485Mode(UART_T* uart, uint32_t u32Mode, uint32_t u32Addr);
uint32_t UART_Write(UART_T* uart, uint8_t *pu8TxBuf, uint32_t u32WriteBytes);
/*@}*/ /* end of group UART_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group UART_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__UART_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

663
NUC123/StdDriver/inc/usbd.h Normal file
View File

@ -0,0 +1,663 @@
/**************************************************************************//**
* @file usbd.h
* @version V3.0
* $Revision: 18 $
* $Date: 15/09/03 11:15a $
* @brief NUC123 series USB driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#ifndef __USBD_H__
#define __USBD_H__
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup USBD_Driver USBD Driver
@{
*/
/** @addtogroup USBD_EXPORTED_STRUCTS USBD Exported Structs
@{
*/
typedef struct s_usbd_info
{
const uint8_t *gu8DevDesc; /*!< Pointer for USB Device Descriptor */
const uint8_t *gu8ConfigDesc; /*!< Pointer for USB Configuration Descriptor */
const uint8_t **gu8StringDesc; /*!< Pointer for USB String Descriptor pointers */
const uint8_t **gu8HidReportDesc; /*!< Pointer for USB HID Report Descriptor */
const uint32_t *gu32HidReportSize; /*!< Pointer for HID Report descriptor Size */
const uint32_t *gu32ConfigHidDescIdx; /*!< Pointer for HID Descriptor start index */
} S_USBD_INFO_T;
extern const S_USBD_INFO_T gsInfo;
/*@}*/ /* end of group USBD_EXPORTED_STRUCTS */
/** @addtogroup USBD_EXPORTED_CONSTANTS USBD Exported Constants
@{
*/
#define USBD_BUF_BASE (USBD_BASE+0x100)
#define USBD_MAX_EP 8
#define EP0 0 /*!< Endpoint 0 */
#define EP1 1 /*!< Endpoint 1 */
#define EP2 2 /*!< Endpoint 2 */
#define EP3 3 /*!< Endpoint 3 */
#define EP4 4 /*!< Endpoint 4 */
#define EP5 5 /*!< Endpoint 5 */
#define EP6 6 /*!< Endpoint 6 */
#define EP7 7 /*!< Endpoint 7 */
/*!<USB Request Type */
#define REQ_STANDARD 0x00
#define REQ_CLASS 0x20
#define REQ_VENDOR 0x40
/*!<USB Standard Request */
#define GET_STATUS 0x00
#define CLEAR_FEATURE 0x01
#define SET_FEATURE 0x03
#define SET_ADDRESS 0x05
#define GET_DESCRIPTOR 0x06
#define SET_DESCRIPTOR 0x07
#define GET_CONFIGURATION 0x08
#define SET_CONFIGURATION 0x09
#define GET_INTERFACE 0x0A
#define SET_INTERFACE 0x0B
#define SYNC_FRAME 0x0C
/*!<USB Descriptor Type */
#define DESC_DEVICE 0x01
#define DESC_CONFIG 0x02
#define DESC_STRING 0x03
#define DESC_INTERFACE 0x04
#define DESC_ENDPOINT 0x05
#define DESC_QUALIFIER 0x06
#define DESC_OTHERSPEED 0x07
/*!<USB HID Descriptor Type */
#define DESC_HID 0x21
#define DESC_HID_RPT 0x22
/*!<USB Descriptor Length */
#define LEN_DEVICE 18
#define LEN_CONFIG 9
#define LEN_INTERFACE 9
#define LEN_ENDPOINT 7
#define LEN_HID 9
#define LEN_CCID 0x36
/*!<USB Endpoint Type */
#define EP_ISO 0x01
#define EP_BULK 0x02
#define EP_INT 0x03
#define EP_INPUT 0x80
#define EP_OUTPUT 0x00
/*!<USB Feature Selector */
#define FEATURE_DEVICE_REMOTE_WAKEUP 0x01
#define FEATURE_ENDPOINT_HALT 0x00
/******************************************************************************/
/* USB Specific Macros */
/******************************************************************************/
#define USBD_WAKEUP_EN USBD_INTEN_WAKEUP_EN_Msk /*!< USB Wake-up Enable */
#define USBD_DRVSE0 USBD_DRVSE0_DRVSE0_Msk /*!< Drive SE0 */
#define USBD_DPPU_EN USBD_ATTR_DPPU_EN_Msk /*!< USB D+ Pull-up Enable */
#define USBD_PWRDN USBD_ATTR_PWRDN_Msk /*!< PHY Turn-On */
#define USBD_PHY_EN USBD_ATTR_PHY_EN_Msk /*!< PHY Enable */
#define USBD_USB_EN USBD_ATTR_USB_EN_Msk /*!< USB Enable */
#define USBD_INT_BUS USBD_INTEN_BUS_IE_Msk /*!< USB Bus Event Interrupt */
#define USBD_INT_USB USBD_INTEN_USB_IE_Msk /*!< USB USB Event Interrupt */
#define USBD_INT_FLDET USBD_INTEN_FLDET_IE_Msk /*!< USB Float Detect Interrupt */
#define USBD_INT_WAKEUP (USBD_INTEN_WAKEUP_IE_Msk | USBD_INTEN_WAKEUP_EN_Msk) /*!< USB Wake-up Interrupt */
#define USBD_INTSTS_WAKEUP USBD_INTSTS_WAKEUP_STS_Msk /*!< USB Wakeup Interrupt Status */
#define USBD_INTSTS_FLDET USBD_INTSTS_FLDET_STS_Msk /*!< USB Float Detect Interrupt Status */
#define USBD_INTSTS_BUS USBD_INTSTS_BUS_STS_Msk /*!< USB Bus Event Interrupt Status */
#define USBD_INTSTS_USB USBD_INTSTS_USB_STS_Msk /*!< USB USB Event Interrupt Status */
#define USBD_INTSTS_SETUP USBD_INTSTS_SETUP_Msk /*!< USB Setup Event */
#define USBD_INTSTS_EP0 USBD_INTSTS_EPEVT0_Msk /*!< USB Endpoint 0 Event */
#define USBD_INTSTS_EP1 USBD_INTSTS_EPEVT1_Msk /*!< USB Endpoint 1 Event */
#define USBD_INTSTS_EP2 USBD_INTSTS_EPEVT2_Msk /*!< USB Endpoint 2 Event */
#define USBD_INTSTS_EP3 USBD_INTSTS_EPEVT3_Msk /*!< USB Endpoint 3 Event */
#define USBD_INTSTS_EP4 USBD_INTSTS_EPEVT4_Msk /*!< USB Endpoint 4 Event */
#define USBD_INTSTS_EP5 USBD_INTSTS_EPEVT5_Msk /*!< USB Endpoint 5 Event */
#define USBD_INTSTS_EP6 USBD_INTSTS_EPEVT6_Msk /*!< USB Endpoint 6 Event */
#define USBD_INTSTS_EP7 USBD_INTSTS_EPEVT7_Msk /*!< USB Endpoint 7 Event */
#define USBD_STATE_USBRST USBD_ATTR_USBRST_Msk /*!< USB Bus Reset */
#define USBD_STATE_SUSPEND USBD_ATTR_SUSPEND_Msk /*!< USB Bus Suspend */
#define USBD_STATE_RESUME USBD_ATTR_RESUME_Msk /*!< USB Bus Resume */
#define USBD_STATE_TIMEOUT USBD_ATTR_TIMEOUT_Msk /*!< USB Bus Timeout */
#define USBD_CFGP_SSTALL USBD_CFGP_SSTALL_Msk /*!< Set Stall */
#define USBD_CFG_CSTALL USBD_CFG_CSTALL_Msk /*!< Clear Stall */
#define USBD_CFG_EPMODE_DISABLE (0ul << USBD_CFG_STATE_Pos)/*!< Endpoint Disable */
#define USBD_CFG_EPMODE_OUT (1ul << USBD_CFG_STATE_Pos)/*!< Out Endpoint */
#define USBD_CFG_EPMODE_IN (2ul << USBD_CFG_STATE_Pos)/*!< In Endpoint */
#define USBD_CFG_TYPE_ISO (1ul << USBD_CFG_ISOCH_Pos) /*!< Isochronous */
/*@}*/ /* end of group USBD_EXPORTED_CONSTANTS */
/** @addtogroup USBD_EXPORTED_FUNCTIONS USBD Exported Functions
@{
*/
/**
* @brief Compare two input numbers and return maximum one.
*
* @param[in] a First number to be compared.
* @param[in] b Second number to be compared.
*
* @return Maximum value between a and b.
*
* @details If a > b, then return a. Otherwise, return b.
*/
#define Maximum(a,b) ((a)>(b) ? (a) : (b))
/**
* @brief Compare two input numbers and return minimum one
*
* @param[in] a First number to be compared
* @param[in] b Second number to be compared
*
* @return Minimum value between a and b
*
* @details If a < b, then return a. Otherwise, return b.
*/
#define Minimum(a,b) ((a)<(b) ? (a) : (b))
/**
* @brief Enable USB
*
* @param None
*
* @return None
*
* @details To set USB ATTR control register to enable USB and PHY.
*
*/
#define USBD_ENABLE_USB() ((uint32_t)(USBD->ATTR |= (USBD_USB_EN|USBD_PHY_EN)))
/**
* @brief Disable USB
*
* @param None
*
* @return None
*
* @details To set USB ATTR control register to disable USB.
*
*/
#define USBD_DISABLE_USB() ((uint32_t)(USBD->ATTR &= ~USBD_USB_EN))
/**
* @brief Enable USB PHY
*
* @param None
*
* @return None
*
* @details To set USB ATTR control register to enable USB PHY.
*
*/
#define USBD_ENABLE_PHY() ((uint32_t)(USBD->ATTR |= USBD_PHY_EN))
/**
* @brief Disable USB PHY
*
* @param None
*
* @return None
*
* @details To set USB ATTR control register to disable USB PHY.
*
*/
#define USBD_DISABLE_PHY() ((uint32_t)(USBD->ATTR &= ~USBD_PHY_EN))
/**
* @brief Enable SE0. Force USB PHY transceiver to drive SE0.
*
* @param None
*
* @return None
*
* @details Set DRVSE0 bit of USB_DRVSE0 register to enable software-disconnect function. Force USB PHY transceiver to drive SE0 to bus.
*
*/
#define USBD_SET_SE0() ((uint32_t)(USBD->DRVSE0 |= USBD_DRVSE0))
/**
* @brief Disable SE0
*
* @param None
*
* @return None
*
* @details Clear DRVSE0 bit of USB_DRVSE0 register to disable software-disconnect function.
*
*/
#define USBD_CLR_SE0() ((uint32_t)(USBD->DRVSE0 &= ~USBD_DRVSE0))
/**
* @brief Set USB device address
*
* @param[in] addr The USB device address.
*
* @return None
*
* @details Write USB device address to USB_FADDR register.
*
*/
#define USBD_SET_ADDR(addr) (USBD->FADDR = (addr))
/**
* @brief Get USB device address
*
* @param None
*
* @return USB device address
*
* @details Read USB_FADDR register to get USB device address.
*
*/
#define USBD_GET_ADDR() ((uint32_t)(USBD->FADDR))
/**
* @brief Enable USB interrupt function
*
* @param[in] intr The combination of the specified interrupt enable bits.
* Each bit corresponds to a interrupt enable bit.
* This parameter decides which interrupts will be enabled.
* (USBD_INT_WAKEUP, USBD_INT_FLDET, USBD_INT_USB, USBD_INT_BUS)
*
* @return None
*
* @details Enable USB related interrupt functions specified by intr parameter.
*
*/
#define USBD_ENABLE_INT(intr) (USBD->INTEN |= (intr))
/**
* @brief Get interrupt status
*
* @param None
*
* @return The value of USB_INTSTS register
*
* @details Return all interrupt flags of USB_INTSTS register.
*
*/
#define USBD_GET_INT_FLAG() ((uint32_t)(USBD->INTSTS))
/**
* @brief Clear USB interrupt flag
*
* @param[in] flag The combination of the specified interrupt flags.
* Each bit corresponds to a interrupt source.
* This parameter decides which interrupt flags will be cleared.
* (USBD_INTSTS_WAKEUP, USBD_INTSTS_FLDET, USBD_INTSTS_BUS, USBD_INTSTS_USB)
*
* @return None
*
* @details Clear USB related interrupt flags specified by flag parameter.
*
*/
#define USBD_CLR_INT_FLAG(flag) (USBD->INTSTS = (flag))
/**
* @brief Get endpoint status
*
* @param None
*
* @return The value of USB_EPSTS register.
*
* @details Return all endpoint status.
*
*/
#define USBD_GET_EP_FLAG() ((uint32_t)(USBD->EPSTS))
/**
* @brief Get USB bus state
*
* @param None
*
* @return The value of USB_ATTR[3:0].
* Bit 0 indicates USB bus reset status.
* Bit 1 indicates USB bus suspend status.
* Bit 2 indicates USB bus resume status.
* Bit 3 indicates USB bus time-out status.
*
* @details Return USB_ATTR[3:0] for USB bus events.
*
*/
#define USBD_GET_BUS_STATE() ((uint32_t)(USBD->ATTR & 0xf))
/**
* @brief Check cable connection state
*
* @param None
*
* @retval 0 USB cable is not attached.
* @retval 1 USB cable is attached.
*
* @details Check the connection state by FLDET bit of USB_FLDET register.
*
*/
#define USBD_IS_ATTACHED() ((uint32_t)(USBD->FLDET & USBD_FLDET_FLDET_Msk))
/**
* @brief Stop USB transaction of the specified endpoint ID
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return None
*
* @details Write 1 to CLRRDY bit of USB_CFGPx register to stop USB transaction of the specified endpoint ID.
*
*/
#define USBD_STOP_TRANSACTION(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFGP + (uint32_t)((ep) << 4))) |= USBD_CFGP_CLRRDY_Msk)
/**
* @brief Set USB DATA1 PID for the specified endpoint ID
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return None
*
* @details Set DSQ_SYNC bit of USB_CFGx register to specify the DATA1 PID for the following IN token transaction.
* Base on this setting, hardware will toggle PID between DATA0 and DATA1 automatically for IN token transactions.
*
*/
#define USBD_SET_DATA1(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))) |= USBD_CFG_DSQ_SYNC_Msk)
/**
* @brief Set USB DATA0 PID for the specified endpoint ID
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return None
*
* @details Clear DSQ_SYNC bit of USB_CFGx register to specify the DATA0 PID for the following IN token transaction.
* Base on this setting, hardware will toggle PID between DATA0 and DATA1 automatically for IN token transactions.
*
*/
#define USBD_SET_DATA0(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))) &= (~USBD_CFG_DSQ_SYNC_Msk))
/**
* @brief Set USB payload size (IN data)
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @param[in] size The transfer length.
*
* @return None
*
* @details This macro will write the transfer length to USB_MXPLDx register for IN data transaction.
*
*/
#define USBD_SET_PAYLOAD_LEN(ep, size) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].MXPLD + (uint32_t)((ep) << 4))) = (size))
/**
* @brief Get USB payload size (OUT data)
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return The value of USB_MXPLDx register.
*
* @details Get the data length of OUT data transaction by reading USB_MXPLDx register.
*
*/
#define USBD_GET_PAYLOAD_LEN(ep) ((uint32_t)*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].MXPLD + (uint32_t)((ep) << 4))))
/**
* @brief Configure endpoint
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @param[in] config The USB configuration.
*
* @return None
*
* @details This macro will write config parameter to USB_CFGx register of specified endpoint ID.
*
*/
#define USBD_CONFIG_EP(ep, config) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))) = (config))
/**
* @brief Set USB endpoint buffer
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @param[in] offset The SRAM offset.
*
* @return None
*
* @details This macro will set the SRAM offset for the specified endpoint ID.
*
*/
#define USBD_SET_EP_BUF_ADDR(ep, offset) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].BUFSEG + (uint32_t)((ep) << 4))) = (offset))
/**
* @brief Get the offset of the specified USB endpoint buffer
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return The offset of the specified endpoint buffer.
*
* @details This macro will return the SRAM offset of the specified endpoint ID.
*
*/
#define USBD_GET_EP_BUF_ADDR(ep) ((uint32_t)*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].BUFSEG + (uint32_t)((ep) << 4))))
/**
* @brief Set USB endpoint stall state
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return None
*
* @details Set USB endpoint stall state for the specified endpoint ID. Endpoint will respond STALL token automatically.
*
*/
#define USBD_SET_EP_STALL(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFGP + (uint32_t)((ep) << 4))) |= USBD_CFGP_SSTALL_Msk)
/**
* @brief Clear USB endpoint stall state
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @return None
*
* @details Clear USB endpoint stall state for the specified endpoint ID. Endpoint will respond ACK/NAK token.
*/
#define USBD_CLR_EP_STALL(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFGP + (uint32_t)((ep) << 4))) &= ~USBD_CFGP_SSTALL_Msk)
/**
* @brief Get USB endpoint stall state
*
* @param[in] ep The USB endpoint ID. NUC123 supports 8 hardware endpoint ID. This parameter could be 0 ~ 7.
*
* @retval 0 USB endpoint is not stalled.
* @retval Others USB endpoint is stalled.
*
* @details Get USB endpoint stall state of the specified endpoint ID.
*
*/
#define USBD_GET_EP_STALL(ep) (*((__IO uint32_t *) ((uint32_t)&USBD->EP[0].CFGP + (uint32_t)((ep) << 4))) & USBD_CFGP_SSTALL_Msk)
/**
* @brief To support byte access between USB SRAM and system SRAM
*
* @param[in] dest Destination pointer.
*
* @param[in] src Source pointer.
*
* @param[in] size Byte count.
*
* @return None
*
* @details This function will copy the number of data specified by size and src parameters to the address specified by dest parameter.
*
*/
static __INLINE void USBD_MemCopy(uint8_t *dest, uint8_t *src, int32_t size)
{
while(size--) *dest++ = *src++;
}
/**
* @brief Set USB endpoint stall state
*
* @param[in] epnum USB endpoint number
*
* @return None
*
* @details Set USB endpoint stall state. Endpoint will respond STALL token automatically.
*
*/
static __INLINE void USBD_SetStall(uint8_t epnum)
{
uint32_t u32CfgAddr;
uint32_t u32Cfg;
int i;
for(i = 0; i < USBD_MAX_EP; i++)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFG; /* USBD_CFG0 */
u32Cfg = *((__IO uint32_t *)(u32CfgAddr));
if((u32Cfg & 0xf) == epnum)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFGP; /* USBD_CFGP0 */
u32Cfg = *((__IO uint32_t *)(u32CfgAddr));
*((__IO uint32_t *)(u32CfgAddr)) = (u32Cfg | USBD_CFGP_SSTALL);
break;
}
}
}
/**
* @brief Clear USB endpoint stall state
*
* @param[in] epnum USB endpoint number
*
* @return None
*
* @details Clear USB endpoint stall state. Endpoint will respond ACK/NAK token.
*/
static __INLINE void USBD_ClearStall(uint8_t epnum)
{
uint32_t u32CfgAddr;
uint32_t u32Cfg;
int i;
for(i = 0; i < USBD_MAX_EP; i++)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFG; /* USBD_CFG0 */
u32Cfg = *((__IO uint32_t *)(u32CfgAddr));
if((u32Cfg & 0xf) == epnum)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFGP; /* USBD_CFGP0 */
u32Cfg = *((__IO uint32_t *)(u32CfgAddr));
*((__IO uint32_t *)(u32CfgAddr)) = (u32Cfg & ~USBD_CFGP_SSTALL);
break;
}
}
}
/**
* @brief Get USB endpoint stall state
*
* @param[in] epnum USB endpoint number
*
* @retval 0 USB endpoint is not stalled.
* @retval Others USB endpoint is stalled.
*
* @details Get USB endpoint stall state.
*
*/
static __INLINE uint32_t USBD_GetStall(uint8_t epnum)
{
uint32_t u32CfgAddr;
uint32_t u32Cfg;
int i;
for(i = 0; i < USBD_MAX_EP; i++)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFG; /* USBD_CFG0 */
u32Cfg = *((__IO uint32_t *)(u32CfgAddr));
if((u32Cfg & 0xf) == epnum)
{
u32CfgAddr = (uint32_t)(i << 4) + (uint32_t)&USBD->EP[0].CFGP; /* USBD_CFGP0 */
break;
}
}
return ((*((__IO uint32_t *)(u32CfgAddr))) & USBD_CFGP_SSTALL);
}
extern volatile uint8_t g_usbd_RemoteWakeupEn;
typedef void (*VENDOR_REQ)(void); /*!< Functional pointer type declaration for Vendor class */
typedef void (*CLASS_REQ)(void); /*!< Functional pointer type declaration for USB class request callback handler */
typedef void (*SET_INTERFACE_REQ)(void); /*!< Functional pointer type declaration for USB set interface request callback handler */
typedef void (*SET_CONFIG_CB)(void); /*!< Functional pointer type declaration for USB set configuration request callback handler */
/*--------------------------------------------------------------------*/
void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface);
void USBD_Start(void);
void USBD_GetSetupPacket(uint8_t *buf);
void USBD_ProcessSetupPacket(void);
void USBD_StandardRequest(void);
void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size);
void USBD_CtrlIn(void);
void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size);
void USBD_CtrlOut(void);
void USBD_SwReset(void);
void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq);
void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback);
void USBD_LockEpStall(uint32_t u32EpBitmap);
/*@}*/ /* end of group USBD_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group USBD_Driver */
/*@}*/ /* end of group Device_Driver */
#endif //__USBD_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

201
NUC123/StdDriver/inc/wdt.h Normal file
View File

@ -0,0 +1,201 @@
/**************************************************************************//**
* @file wdt.h
* @version V3.00
* $Revision: 3 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series WDT driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __WDT_H__
#define __WDT_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup WDT_Driver WDT Driver
@{
*/
/** @addtogroup WDT_EXPORTED_CONSTANTS WDT Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* WTCR Constants Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define WDT_TIMEOUT_2POW4 (0UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^4 * WDT clocks */
#define WDT_TIMEOUT_2POW6 (1UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^6 * WDT clocks */
#define WDT_TIMEOUT_2POW8 (2UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^8 * WDT clocks */
#define WDT_TIMEOUT_2POW10 (3UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^10 * WDT clocks */
#define WDT_TIMEOUT_2POW12 (4UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^12 * WDT clocks */
#define WDT_TIMEOUT_2POW14 (5UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^14 * WDT clocks */
#define WDT_TIMEOUT_2POW16 (6UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^16 * WDT clocks */
#define WDT_TIMEOUT_2POW18 (7UL << WDT_WTCR_WTIS_Pos) /*!< Setting WDT time-out interval to 2^18 * WDT clocks */
/*---------------------------------------------------------------------------------------------------------*/
/* WTCRALT Constants Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define WDT_RESET_DELAY_1026CLK (0UL << WDT_WTCRALT_WTRDSEL_Pos) /*!< Setting WDT reset delay period to 1026 * WDT clocks */
#define WDT_RESET_DELAY_130CLK (1UL << WDT_WTCRALT_WTRDSEL_Pos) /*!< Setting WDT reset delay period to 130 * WDT clocks */
#define WDT_RESET_DELAY_18CLK (2UL << WDT_WTCRALT_WTRDSEL_Pos) /*!< Setting WDT reset delay period to 18 * WDT clocks */
#define WDT_RESET_DELAY_3CLK (3UL << WDT_WTCRALT_WTRDSEL_Pos) /*!< Setting WDT reset delay period to 3 * WDT clocks */
/*@}*/ /* end of group WDT_EXPORTED_CONSTANTS */
/** @addtogroup WDT_EXPORTED_FUNCTIONS WDT Exported Functions
@{
*/
/**
* @brief Clear WDT Reset System Flag
*
* @param None
*
* @return None
*
* @details This macro clear WDT time-out reset system flag.
*/
#define WDT_CLEAR_RESET_FLAG() (WDT->WTCR = (WDT->WTCR & ~(WDT_WTCR_WTIF_Msk | WDT_WTCR_WTWKF_Msk)) | WDT_WTCR_WTRF_Msk)
/**
* @brief Clear WDT Time-out Interrupt Flag
*
* @param None
*
* @return None
*
* @details This macro clear WDT time-out interrupt flag.
*/
#define WDT_CLEAR_TIMEOUT_INT_FLAG() (WDT->WTCR = (WDT->WTCR & ~(WDT_WTCR_WTRF_Msk | WDT_WTCR_WTWKF_Msk)) | WDT_WTCR_WTIF_Msk)
/**
* @brief Clear WDT Wake-up Flag
*
* @param None
*
* @return None
*
* @details This macro clear WDT time-out wake-up system flag.
*/
#define WDT_CLEAR_TIMEOUT_WAKEUP_FLAG() (WDT->WTCR = (WDT->WTCR & ~(WDT_WTCR_WTRF_Msk | WDT_WTCR_WTIF_Msk)) | WDT_WTCR_WTWKF_Msk)
/**
* @brief Get WDT Time-out Reset Flag
*
* @param None
*
* @retval 0 WDT did not cause system reset
* @retval 1 WDT caused system reset
*
* @details This macro indicate WDT time-out to reset system or not.
*/
#define WDT_GET_RESET_FLAG() ((WDT->WTCR & WDT_WTCR_WTRF_Msk)? 1 : 0)
/**
* @brief Get WDT Time-out Interrupt Flag
*
* @param None
*
* @retval 0 WDT time-out interrupt did not occur
* @retval 1 WDT time-out interrupt occurred
*
* @details This macro indicate WDT time-out interrupt occurred or not.
*/
#define WDT_GET_TIMEOUT_INT_FLAG() ((WDT->WTCR & WDT_WTCR_WTIF_Msk)? 1 : 0)
/**
* @brief Get WDT Time-out Wake-up Flag
*
* @param None
*
* @retval 0 WDT did not wake up system
* @retval 1 WDT waked up system
*
* @details This macro indicate WDT time-out waked system up or not
*/
#define WDT_GET_TIMEOUT_WAKEUP_FLAG() ((WDT->WTCR & WDT_WTCR_WTWKF_Msk)? 1 : 0)
/**
* @brief Reset WDT Counter
*
* @param None
*
* @return None
*
* @details This macro is used to reset 18-bit WDT counter.
* @note If WDT is activated and enabled to reset system, user must reset WDT counter \n
* before WDT time-out plus reset delay reached. Or WDT generate a reset signal.
*/
#define WDT_RESET_COUNTER() (WDT->WTCR = (WDT->WTCR & ~(WDT_WTCR_WTIF_Msk | WDT_WTCR_WTWKF_Msk | WDT_WTCR_WTRF_Msk)) | WDT_WTCR_WTR_Msk)
/**
* @brief Stop WDT Counting
*
* @param None
*
* @return None
*
* @details This function stops WDT counting and disable WDT module.
*/
static __INLINE void WDT_Close(void)
{
WDT->WTCR = 0;
return;
}
/**
* @brief Enable WDT Time-out Interrupt
*
* @param None
*
* @return None
*
* @details This function enable the WDT time-out interrupt.
*/
static __INLINE void WDT_EnableInt(void)
{
WDT->WTCR |= WDT_WTCR_WTIE_Msk;
return;
}
/**
* @brief Disable WDT Time-out Interrupt
*
* @param None
*
* @return None
*
* @details This function disables the WDT time-out interrupt.
*/
static __INLINE void WDT_DisableInt(void)
{
// Do not touch write 1 clear bits
WDT->WTCR &= ~(WDT_WTCR_WTIE_Msk | WDT_WTCR_WTRF_Msk | WDT_WTCR_WTIF_Msk | WDT_WTCR_WTWKF_Msk);
return;
}
void WDT_Open(uint32_t u32TimeoutInterval, uint32_t u32ResetDelay, uint32_t u32EnableReset, uint32_t u32EnableWakeup);
/*@}*/ /* end of group WDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group WDT_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__WDT_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

145
NUC123/StdDriver/inc/wwdt.h Normal file
View File

@ -0,0 +1,145 @@
/**************************************************************************//**
* @file wwdt.h
* @version V3.00
* $Revision: 3 $
* $Date: 15/07/02 11:21a $
* @brief WWDT driver header file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __WWDT_H__
#define __WWDT_H__
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup WWDT_Driver WWDT Driver
@{
*/
/** @addtogroup WWDT_EXPORTED_CONSTANTS WWDT Exported Constants
@{
*/
/*---------------------------------------------------------------------------------------------------------*/
/* WWDTCR Constants Definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define WWDT_PRESCALER_1 (0 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 1 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_2 (1 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 2 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_4 (2 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 4 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_8 (3 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 8 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_16 (4 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 16 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_32 (5 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 32 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_64 (6 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 64 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_128 (7 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 128 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_192 (8 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 192 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_256 (9 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 256 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_384 (10 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 384 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_512 (11 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 512 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_768 (12 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 768 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_1024 (13 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 1024 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_1536 (14 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 1536 * (64*WWDT_CLK) */
#define WWDT_PRESCALER_2048 (15 << WWDT_WWDTCR_PERIODSEL_Pos) /*!< Select max time-out period to 2048 * (64*WWDT_CLK) */
#define WWDT_RELOAD_WORD (0x00005AA5) /*!< Fill this value to WWDTRLD register to reload WWDT counter */
/*@}*/ /* end of group WWDT_EXPORTED_CONSTANTS */
/** @addtogroup WWDT_EXPORTED_FUNCTIONS WWDT Exported Functions
@{
*/
/**
* @brief Clear WWDT Reset System Flag
*
* @param None
*
* @return None
*
* @details This macro is used to clear WWDT counter time-out reset system flag.
*/
#define WWDT_CLEAR_RESET_FLAG() (WWDT->WWDTSR = WWDT_WWDTSR_WWDTRF_Msk)
/**
* @brief Clear WWDT Compared Match Interrupt Flag
*
* @param None
*
* @return None
*
* @details This macro is used to clear WWDT counter compare match interrupt flag.
*/
#define WWDT_CLEAR_INT_FLAG() (WWDT->WWDTSR = WWDT_WWDTSR_WWDTIF_Msk)
/**
* @brief Get WWDT Reset Flag
*
* @param None
*
* @retval 0 WWDT did not cause system reset
* @retval 1 WWDT counter time-out caused system reset
*
* @details This macro is used to indicate WWDT counter time-out reset system flag.
*/
#define WWDT_GET_RESET_FLAG() ((WWDT->WWDTSR & WWDT_WWDTSR_WWDTRF_Msk)? 1:0)
/**
* @brief Get WWDT Compared Match Interrupt Flag
*
* @param None
*
* @retval 0 WWDT counter compare match interrupt did not occur
* @retval 1 WWDT counter compare match interrupt occurred
*
* @details This macro is used to indicate WWDT counter compare match interrupt occurred or not.
*/
#define WWDT_GET_INT_FLAG() ((WWDT->WWDTSR & WWDT_WWDTSR_WWDTIF_Msk)? 1:0)
/**
* @brief Get WWDT Counter value
*
* @param None
*
* @return WWDT Counter Value
*
* @details This macro to reflects the current WWDT counter value.
*/
#define WWDT_GET_COUNTER() (WWDT->WWDTCVR)
/**
* @brief Reload WWDT Counter
*
* @param None
*
* @return None
*
* @details This macro is used to reload the WWDT counter value to 0x3F.
* @note After WWDT enabled, user must reload WWDT counter while current counter is less than compare value \n
* and larger than 0, otherwise WWDT will cause system reset immediately.
*/
#define WWDT_RELOAD_COUNTER() (WWDT->WWDTRLD = WWDT_RELOAD_WORD)
void WWDT_Open(uint32_t u32PreScale, uint32_t u32CmpValue, uint32_t u32EnableInt);
/*@}*/ /* end of group WWDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group WWDT_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
#endif //__WWDT_H__
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

152
NUC123/StdDriver/src/adc.c Normal file
View File

@ -0,0 +1,152 @@
/**************************************************************************//**
* @file adc.c
* @version V3.00
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series ADC driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup ADC_Driver ADC Driver
@{
*/
/** @addtogroup ADC_EXPORTED_FUNCTIONS ADC Exported Functions
@{
*/
/**
* @brief This function configures ADC module to be ready for convert the input from selected channel.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32InputMode Decides the ADC analog input mode. This parameter is not used.
* @param[in] u32OpMode Decides the ADC operation mode. Valid values are:
* - \ref ADC_ADCR_ADMD_SINGLE :Single mode.
* - \ref ADC_ADCR_ADMD_SINGLE_CYCLE :Single cycle scan mode.
* - \ref ADC_ADCR_ADMD_CONTINUOUS :Continuous scan mode.
* @param[in] u32ChMask Channel enable bit. Each bit corresponds to a input channel. Bit 0 is channel 0, bit 1 is channel 1..., bit 7 is channel 7.
* @return None
* @details Before starting A/D conversion function, ADEN(ADCR[0]) should be set to 1.
* @note NUC123 series MCU ADC can only convert 1 channel at a time. If more than 1 channels are enabled, only channel
* with smallest number will be convert.
* @note This function does not turn on ADC power nor does trigger ADC conversion.
*/
void ADC_Open(ADC_T *adc,
uint32_t u32InputMode,
uint32_t u32OpMode,
uint32_t u32ChMask)
{
(adc)->ADCR = ((adc)->ADCR & (~ADC_ADCR_ADMD_Msk)) | (u32OpMode);
(adc)->ADCHER = ((adc)->ADCHER & ~ADC_ADCHER_CHEN_Msk) | (u32ChMask);
}
/**
* @brief Disable ADC module.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Disable A/D converter analog circuit for saving power consumption.
*/
void ADC_Close(ADC_T *adc)
{
(adc)->ADCR &= (~ADC_ADCR_ADEN_Msk);
}
/**
* @brief Configure the hardware trigger condition and enable hardware trigger.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Source Decides the hardware trigger source. Valid values are:
* - \ref ADC_ADCR_TRGS_STADC :A/D conversion is started by external STADC pin.
* - \ref ADC_ADCR_TRGS_PWM :A/D conversion is started by PWM.
* @param[in] u32Param ADC trigger by external pin, this parameter is used to set trigger condition. Valid values are:
* - \ref ADC_ADCR_TRGCOND_LOW_LEVEL :STADC Low level active.
* - \ref ADC_ADCR_TRGCOND_HIGH_LEVEL :STADC High level active.
* - \ref ADC_ADCR_TRGCOND_FALLING_EDGE :STADC Falling edge active.
* - \ref ADC_ADCR_TRGCOND_RISING_EDGE :STADC Rising edge active.
* @return None
* @details Software should disable TRGEN (ADCR[8]) and ADST (ADCR[11]) before change TRGS(ADCR[5:4]).
*/
void ADC_EnableHWTrigger(ADC_T *adc,
uint32_t u32Source,
uint32_t u32Param)
{
(adc)->ADCR &= ~(ADC_ADCR_TRGS_Msk | ADC_ADCR_TRGCOND_Msk | ADC_ADCR_TRGEN_Msk);
(adc)->ADCR |= (u32Source) | (u32Param) | ADC_ADCR_TRGEN_Msk;
}
/**
* @brief Disable hardware trigger ADC function.
* @param[in] adc The pointer of the specified ADC module.
* @return None
* @details Disable triggering of A/D conversion by hardware (external STADC pin or PWM Center-aligned trigger).
*/
void ADC_DisableHWTrigger(ADC_T *adc)
{
(adc)->ADCR &= ~(ADC_ADCR_TRGS_Msk | ADC_ADCR_TRGCOND_Msk | ADC_ADCR_TRGEN_Msk);
}
/**
* @brief Enable the interrupt(s) selected by u32Mask parameter.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
* corresponds to a interrupt status. This parameter decides which
* interrupts will be enabled.
* - \ref ADC_ADF_INT :ADC convert complete interrupt.
* - \ref ADC_CMP0_INT :ADC comparator 0 interrupt.
* - \ref ADC_CMP1_INT :ADC comparator 1 interrupt.
* @return None
* @details A/D conversion end interrupt request is generated if ADIE bit (ADCR[1]) is set to 1.
* If the compare function is enabled and the compare condition matches the setting of CMPCOND (ADCMPR0/1[2])
* and CMPMATCNT (ADCMPR0/1[11:8]), CMPF0/1 bit (ADSR[1]/[2]) will be asserted, in the meanwhile,
* if CMPIE (ADCMPR0/1[1]) is set to 1, a compare interrupt request is generated.
*/
void ADC_EnableInt(ADC_T *adc, uint32_t u32Mask)
{
if((u32Mask) & ADC_ADF_INT)
(adc)->ADCR |= ADC_ADCR_ADIE_Msk;
if((u32Mask) & ADC_CMP0_INT)
(adc)->ADCMPR[0] |= ADC_ADCMPR_CMPIE_Msk;
if((u32Mask) & ADC_CMP1_INT)
(adc)->ADCMPR[1] |= ADC_ADCMPR_CMPIE_Msk;
}
/**
* @brief Disable the interrupt(s) selected by u32Mask parameter.
* @param[in] adc The pointer of the specified ADC module.
* @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
* corresponds to a interrupt status. This parameter decides which
* interrupts will be disabled.
* - \ref ADC_ADF_INT :ADC convert complete interrupt.
* - \ref ADC_CMP0_INT :ADC comparator 0 interrupt.
* - \ref ADC_CMP1_INT :ADC comparator 1 interrupt.
* @return None
* @details The function is used to disable convert complete interrupt, comparator 0 interrupt or comparator 1 interrupt.
*/
void ADC_DisableInt(ADC_T *adc, uint32_t u32Mask)
{
if((u32Mask) & ADC_ADF_INT)
(adc)->ADCR &= ~ADC_ADCR_ADIE_Msk;
if((u32Mask) & ADC_CMP0_INT)
(adc)->ADCMPR[0] &= ~ADC_ADCMPR_CMPIE_Msk;
if((u32Mask) & ADC_CMP1_INT)
(adc)->ADCMPR[1] &= ~ADC_ADCMPR_CMPIE_Msk;
}
/*@}*/ /* end of group ADC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group ADC_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

679
NUC123/StdDriver/src/clk.c Normal file
View File

@ -0,0 +1,679 @@
/**************************************************************************//**
* @file clk.c
* @version V3.00
* $Revision: 26 $
* $Date: 15/10/30 8:44a $
* @brief NUC123 series CLK driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup CLK_Driver CLK Driver
@{
*/
/** @addtogroup CLK_EXPORTED_FUNCTIONS CLK Exported Functions
@{
*/
/**
* @brief Disable frequency output function
* @param None
* @return None
* @details This function disable frequency output function.
*/
void CLK_DisableCKO(void)
{
/* Disable CKO clock source */
CLK_DisableModuleClock(FDIV_MODULE);
}
/**
* @brief This function enable frequency divider module clock.
* enable frequency divider clock function and configure frequency divider.
* @param[in] u32ClkSrc is frequency divider function clock source. Including :
* - \ref CLK_CLKSEL2_FRQDIV_S_HXT
* - \ref CLK_CLKSEL2_FRQDIV_S_HCLK
* - \ref CLK_CLKSEL2_FRQDIV_S_HIRC
* @param[in] u32ClkDiv is divider output frequency selection.
* @param[in] u32ClkDivBy1En is not supported.
* @return None
*
* @details Output selected clock to CKO. The output clock frequency is divided by u32ClkDiv.
* The formula is:
* CKO frequency = (Clock source frequency) / 2^(u32ClkDiv + 1)
* This function is just used to set CKO clock.
* User must enable I/O for CKO clock output pin by themselves.
*/
void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv, uint32_t u32ClkDivBy1En)
{
/* CKO = clock source / 2^(u32ClkDiv + 1) */
CLK->FRQDIV = (CLK_FRQDIV_DIVIDER_EN_Msk | u32ClkDiv) ;
/* Enable CKO clock source */
CLK_EnableModuleClock(FDIV_MODULE);
/* Select CKO clock source */
CLK_SetModuleClock(FDIV_MODULE, u32ClkSrc, 0);
}
/**
* @brief Enter to Power-down mode
* @param None
* @return None
* @details This function is used to let system enter to Power-down mode.
* The register write-protection function should be disabled before using this function.
*/
void CLK_PowerDown(void)
{
/* Set the processor uses deep sleep as its low power mode */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* Set system Power-down enabled and Power-down entry condition */
CLK->PWRCON |= (CLK_PWRCON_PWR_DOWN_EN_Msk | CLK_PWRCON_PD_WAIT_CPU_Msk);
/* Chip enter Power-down mode after CPU run WFI instruction */
__WFI();
}
/**
* @brief Enter to Idle mode
* @param None
* @return None
* @details This function let system enter to Idle mode.
* The register write-protection function should be disabled before using this function.
*/
void CLK_Idle(void)
{
/* Set the processor uses sleep as its low power mode */
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
/* Set chip in idle mode because of WFI command */
CLK->PWRCON &= ~CLK_PWRCON_PWR_DOWN_EN_Msk;
/* Chip enter idle mode after CPU run WFI instruction */
__WFI();
}
/**
* @brief Get external high speed crystal clock frequency
* @param None
* @return External high frequency crystal frequency
* @details This function get external high frequency crystal frequency. The frequency unit is Hz.
*/
uint32_t CLK_GetHXTFreq(void)
{
if(CLK->PWRCON & CLK_PWRCON_XTL12M_EN_Msk)
return __HXT;
else
return 0;
}
/**
* @brief Get HCLK frequency
* @param None
* @return HCLK frequency
* @details This function get HCLK frequency. The frequency unit is Hz.
*/
uint32_t CLK_GetHCLKFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief Get PCLK frequency
* @param None
* @return PCLK frequency
* @details This function get PCLK frequency. The frequency unit is Hz.
*/
uint32_t CLK_GetPCLKFreq(void)
{
SystemCoreClockUpdate();
if(CLK->APBDIV & CLK_APBDIV_APBDIV_Msk)
return SystemCoreClock / 2;
else
return SystemCoreClock;
}
/**
* @brief Get CPU frequency
* @param None
* @return CPU frequency
* @details This function get CPU frequency. The frequency unit is Hz.
*/
uint32_t CLK_GetCPUFreq(void)
{
SystemCoreClockUpdate();
return SystemCoreClock;
}
/**
* @brief Set HCLK frequency
* @param[in] u32Hclk is HCLK frequency. The range of u32Hclk is 25 MHz ~ 72 MHz.
* @return HCLK frequency
* @details This function is used to set HCLK frequency. The frequency unit is Hz.
* It would configure PLL frequency to 50MHz ~ 144MHz,
* set HCLK clock divider as 2 and switch HCLK clock source to PLL.
* The register write-protection function should be disabled before using this function.
*/
uint32_t CLK_SetCoreClock(uint32_t u32Hclk)
{
uint32_t u32HIRCSTB;
/* Read HIRC clock source stable flag */
u32HIRCSTB = CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk;
/* The range of u32Hclk is 25 MHz ~ 72 MHz */
if(u32Hclk > FREQ_72MHZ)
u32Hclk = FREQ_72MHZ;
if(u32Hclk < FREQ_25MHZ)
u32Hclk = FREQ_25MHZ;
/* Switch HCLK clock source to HIRC clock for safe */
CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
CLK->CLKSEL0 |= CLK_CLKSEL0_HCLK_S_Msk;
CLK->CLKDIV &= (~CLK_CLKDIV_HCLK_N_Msk);
/* Configure PLL setting if HXT clock is stable */
if(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk)
u32Hclk = CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HXT, (u32Hclk << 1));
/* Configure PLL setting if HXT clock is not stable */
else
{
u32Hclk = CLK_EnablePLL(CLK_PLLCON_PLL_SRC_HIRC, (u32Hclk << 1));
/* Read HIRC clock source stable flag */
u32HIRCSTB = CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk;
}
/* Select HCLK clock source to PLL,
Select HCLK clock source divider as 2
and update system core clock
*/
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_PLL, CLK_CLKDIV_HCLK(2));
/* Disable HIRC if HIRC is disabled before setting core clock */
if( u32HIRCSTB == 0 )
CLK->PWRCON &= ~CLK_PWRCON_OSC22M_EN_Msk;
/* Return actually HCLK frequency is PLL frequency divide 2 */
return u32Hclk >> 1;
}
/**
* @brief Set HCLK clock source and HCLK clock divider
* @param[in] u32ClkSrc is HCLK clock source. Including :
* - \ref CLK_CLKSEL0_HCLK_S_HXT
* - \ref CLK_CLKSEL0_HCLK_S_PLL_DIV2
* - \ref CLK_CLKSEL0_HCLK_S_PLL
* - \ref CLK_CLKSEL0_HCLK_S_LIRC
* - \ref CLK_CLKSEL0_HCLK_S_HIRC
* @param[in] u32ClkDiv is HCLK clock divider. Including :
* - \ref CLK_CLKDIV_HCLK(x)
* @return None
* @details This function set HCLK clock source and HCLK clock divider.
* The register write-protection function should be disabled before using this function.
*/
void CLK_SetHCLK(uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
uint32_t u32HIRCSTB;
/* Read HIRC clock source stable flag */
u32HIRCSTB = CLK->CLKSTATUS & CLK_CLKSTATUS_OSC22M_STB_Msk;
/* Switch to HIRC for Safe. Avoid HCLK too high when applying new divider. */
CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLK_S_Msk)) | CLK_CLKSEL0_HCLK_S_HIRC;
/* Apply new Divider */
CLK->CLKDIV = (CLK->CLKDIV & (~CLK_CLKDIV_HCLK_N_Msk)) | u32ClkDiv;
/* Switch HCLK to new HCLK source */
CLK->CLKSEL0 = (CLK->CLKSEL0 & (~CLK_CLKSEL0_HCLK_S_Msk)) | u32ClkSrc;
/* Update System Core Clock */
SystemCoreClockUpdate();
/* Disable HIRC if HIRC is disabled before switching HCLK source */
if( u32HIRCSTB == 0 )
CLK->PWRCON &= ~CLK_PWRCON_OSC22M_EN_Msk;
}
/**
* @brief This function set selected module clock source and module clock divider
* @param[in] u32ModuleIdx is module index.
* @param[in] u32ClkSrc is module clock source.
* @param[in] u32ClkDiv is module clock divider.
* @return None
* @details Valid parameter combinations listed in following table:
*
* |Module index |Clock source |Divider |
* | :---------------- | :------------------------------------| :--------------------- |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDT_S_LIRC | x |
* |\ref WDT_MODULE |\ref CLK_CLKSEL1_WDT_S_HCLK_DIV2048 | x |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HXT |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_PLL |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HCLK |\ref CLK_CLKDIV_ADC(x) |
* |\ref ADC_MODULE |\ref CLK_CLKSEL1_ADC_S_HIRC |\ref CLK_CLKDIV_ADC(x) |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPI0_S_HCLK | x |
* |\ref SPI0_MODULE |\ref CLK_CLKSEL1_SPI0_S_PLL | x |
* |\ref SPI1_MODULE |\ref CLK_CLKSEL1_SPI1_S_HCLK | x |
* |\ref SPI1_MODULE |\ref CLK_CLKSEL1_SPI1_S_PLL | x |
* |\ref SPI2_MODULE |\ref CLK_CLKSEL1_SPI2_S_HCLK | x |
* |\ref SPI2_MODULE |\ref CLK_CLKSEL1_SPI2_S_PLL | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HXT | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HCLK | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_EXT_TRG | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_LIRC | x |
* |\ref TMR0_MODULE |\ref CLK_CLKSEL1_TMR0_S_HIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1_S_HXT | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1_S_HCLK | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1_S_EXT_TRG | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1_S_LIRC | x |
* |\ref TMR1_MODULE |\ref CLK_CLKSEL1_TMR1_S_HIRC | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HXT | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HCLK | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_EXT_TRG | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_LIRC | x |
* |\ref TMR2_MODULE |\ref CLK_CLKSEL1_TMR2_S_HIRC | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HXT | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HCLK | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_EXT_TRG | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_LIRC | x |
* |\ref TMR3_MODULE |\ref CLK_CLKSEL1_TMR3_S_HIRC | x |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_HXT |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART0_MODULE |\ref CLK_CLKSEL1_UART_S_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_HXT |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_PLL |\ref CLK_CLKDIV_UART(x) |
* |\ref UART1_MODULE |\ref CLK_CLKSEL1_UART_S_HIRC |\ref CLK_CLKDIV_UART(x) |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL12_PWM01_S_HXT | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL12_PWM01_S_HCLK | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL12_PWM01_S_HIRC | x |
* |\ref PWM01_MODULE |\ref CLK_CLKSEL12_PWM01_S_LIRC | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL12_PWM23_S_HXT | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL12_PWM23_S_HCLK | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL12_PWM23_S_HIRC | x |
* |\ref PWM23_MODULE |\ref CLK_CLKSEL12_PWM23_S_LIRC | x |
* |\ref I2S_MODULE |\ref CLK_CLKSEL2_I2S_S_HXT | x |
* |\ref I2S_MODULE |\ref CLK_CLKSEL2_I2S_S_PLL | x |
* |\ref I2S_MODULE |\ref CLK_CLKSEL2_I2S_S_HCLK | x |
* |\ref I2S_MODULE |\ref CLK_CLKSEL2_I2S_S_HIRC | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HXT | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HCLK | x |
* |\ref FDIV_MODULE |\ref CLK_CLKSEL2_FRQDIV_S_HIRC | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL2_WWDT_S_HCLK_DIV2048 | x |
* |\ref WWDT_MODULE |\ref CLK_CLKSEL2_WWDT_S_LIRC | x |
* |\ref USBD_MODULE | x |\ref CLK_CLKDIV_USB(x) |
*/
void CLK_SetModuleClock(uint32_t u32ModuleIdx, uint32_t u32ClkSrc, uint32_t u32ClkDiv)
{
uint32_t u32sel = 0, u32div = 0;
uint32_t u32SelTbl[3] = {0x0, 0x4, 0xC};
if(MODULE_CLKSEL_Msk(u32ModuleIdx) != MODULE_NoMsk)
{
/* Get clock select control register address */
u32sel = (uint32_t)&CLK->CLKSEL0 + (u32SelTbl[MODULE_CLKSEL(u32ModuleIdx)]);
/* Set new clock selection setting */
M32(u32sel) = (M32(u32sel) & (~(MODULE_CLKSEL_Msk(u32ModuleIdx) << MODULE_CLKSEL_Pos(u32ModuleIdx)))) | u32ClkSrc;
/* We need to set CLKSEL2 ext control bit for PWM */
if(u32ModuleIdx == PWM01_MODULE)
CLK->CLKSEL2 = (CLK->CLKSEL2 & (~CLK_CLKSEL2_PWM01_S_E_Msk)) | (u32ClkSrc & CLK_CLKSEL2_PWM01_S_E_Msk);
else if(u32ModuleIdx == PWM23_MODULE)
CLK->CLKSEL2 = (CLK->CLKSEL2 & (~CLK_CLKSEL2_PWM23_S_E_Msk)) | (u32ClkSrc & CLK_CLKSEL2_PWM23_S_E_Msk);
}
if(MODULE_CLKDIV_Msk(u32ModuleIdx) != MODULE_NoMsk)
{
/* Get clock divider control register address */
u32div = (uint32_t)&CLK->CLKDIV + ((MODULE_CLKDIV(u32ModuleIdx)) * 4);
/* Apply new divider */
M32(u32div) = (M32(u32div) & (~(MODULE_CLKDIV_Msk(u32ModuleIdx) << MODULE_CLKDIV_Pos(u32ModuleIdx)))) | u32ClkDiv;
}
}
/**
* @brief Set SysTick clock source
* @param[in] u32ClkSrc is module clock source. Including:
* - \ref CLK_CLKSEL0_STCLK_S_HXT
* - \ref CLK_CLKSEL0_STCLK_S_HXT_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HCLK_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HIRC_DIV2
* @return None
* @details This function set SysTick clock source.
* The register write-protection function should be disabled before using this function.
*/
void CLK_SetSysTickClockSrc(uint32_t u32ClkSrc)
{
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLK_S_Msk) | u32ClkSrc;
}
/**
* @brief Enable clock source
* @param[in] u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCON_XTL12M_EN_Msk
* - \ref CLK_PWRCON_OSC22M_EN_Msk
* - \ref CLK_PWRCON_OSC10K_EN_Msk
* @return None
* @details This function enable clock source.
* The register write-protection function should be disabled before using this function.
*/
void CLK_EnableXtalRC(uint32_t u32ClkMask)
{
CLK->PWRCON |= u32ClkMask;
}
/**
* @brief Disable clock source
* @param[in] u32ClkMask is clock source mask. Including :
* - \ref CLK_PWRCON_XTL12M_EN_Msk
* - \ref CLK_PWRCON_OSC22M_EN_Msk
* - \ref CLK_PWRCON_OSC10K_EN_Msk
* @return None
* @details This function disable clock source.
* The register write-protection function should be disabled before using this function.
*/
void CLK_DisableXtalRC(uint32_t u32ClkMask)
{
CLK->PWRCON &= ~u32ClkMask;
}
/**
* @brief Enable module clock
* @param[in] u32ModuleIdx is module index. Including :
* - \ref PDMA_MODULE
* - \ref ISP_MODULE
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref FDIV_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref SPI1_MODULE
* - \ref SPI2_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWM01_MODULE
* - \ref PWM23_MODULE
* - \ref USBD_MODULE
* - \ref ADC_MODULE
* - \ref I2S_MODULE
* - \ref PS2_MODULE
* @return None
* @details This function enable module clock.
*/
void CLK_EnableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->AHBCLK + ((MODULE_APBCLK(u32ModuleIdx)) * 4)) |= 1 << MODULE_IP_EN_Pos(u32ModuleIdx);
}
/**
* @brief Disable module clock
* @param[in] u32ModuleIdx is module index. Including :
* - \ref PDMA_MODULE
* - \ref ISP_MODULE
* - \ref WDT_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref FDIV_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref SPI0_MODULE
* - \ref SPI1_MODULE
* - \ref SPI2_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref PWM01_MODULE
* - \ref PWM23_MODULE
* - \ref USBD_MODULE
* - \ref ADC_MODULE
* - \ref I2S_MODULE
* - \ref PS2_MODULE
* @return None
* @details This function disable module clock.
*/
void CLK_DisableModuleClock(uint32_t u32ModuleIdx)
{
*(volatile uint32_t *)((uint32_t)&CLK->AHBCLK + ((MODULE_APBCLK(u32ModuleIdx)) * 4)) &= ~(1 << MODULE_IP_EN_Pos(u32ModuleIdx));
}
/**
* @brief Set PLL frequency
* @param[in] u32PllClkSrc is PLL clock source. Including :
* - \ref CLK_PLLCON_PLL_SRC_HXT
* - \ref CLK_PLLCON_PLL_SRC_HIRC
* @param[in] u32PllFreq is PLL frequency
* @return PLL frequency
* @details This function is used to configure PLLCON register to set specified PLL frequency.
* The register write-protection function should be disabled before using this function.
*/
uint32_t CLK_EnablePLL(uint32_t u32PllClkSrc, uint32_t u32PllFreq)
{
uint32_t u32PllSrcClk, u32NR, u32NF, u32NO, u32CLK_SRC;
uint32_t u32Tmp, u32Tmp2, u32Tmp3, u32Min, u32MinNF, u32MinNR;
/* Disable PLL first to avoid unstable when setting PLL. */
CLK->PLLCON = CLK_PLLCON_PD_Msk;
/* PLL source clock is from HXT */
if(u32PllClkSrc == CLK_PLLCON_PLL_SRC_HXT)
{
/* Enable HXT clock */
CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk;
/* Wait for HXT clock ready */
CLK_WaitClockReady(CLK_CLKSTATUS_XTL12M_STB_Msk);
/* Select PLL source clock from HXT */
u32CLK_SRC = CLK_PLLCON_PLL_SRC_HXT;
u32PllSrcClk = __HXT;
/* u32NR start from 2 */
u32NR = 2;
}
/* PLL source clock is from HIRC */
else
{
/* Enable HIRC clock */
CLK->PWRCON |= CLK_PWRCON_OSC22M_EN_Msk;
/* Wait for HIRC clock ready */
CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
/* Select PLL source clock from HIRC */
u32CLK_SRC = CLK_PLLCON_PLL_SRC_HIRC;
u32PllSrcClk = __HIRC;
/* u32NR start from 4 when FIN = 22.1184MHz to avoid calculation overflow */
u32NR = 4;
}
/* Select "NO" according to request frequency */
if((u32PllFreq <= FREQ_200MHZ) && (u32PllFreq > FREQ_100MHZ))
{
u32NO = 0;
}
else if((u32PllFreq <= FREQ_100MHZ) && (u32PllFreq > FREQ_50MHZ))
{
u32NO = 1;
u32PllFreq = u32PllFreq << 1;
}
else if((u32PllFreq <= FREQ_50MHZ) && (u32PllFreq >= FREQ_25MHZ))
{
u32NO = 3;
u32PllFreq = u32PllFreq << 2;
}
else
{
/* Wrong frequency request. Just return default setting. */
goto lexit;
}
/* Find best solution */
u32Min = (uint32_t) - 1;
u32MinNR = 0;
u32MinNF = 0;
for(; u32NR <= 33; u32NR++)
{
u32Tmp = u32PllSrcClk / u32NR;
if((u32Tmp > 1600000) && (u32Tmp < 16000000))
{
for(u32NF = 2; u32NF <= 513; u32NF++)
{
u32Tmp2 = u32Tmp * u32NF;
if((u32Tmp2 >= 100000000) && (u32Tmp2 <= 200000000))
{
u32Tmp3 = (u32Tmp2 > u32PllFreq) ? u32Tmp2 - u32PllFreq : u32PllFreq - u32Tmp2;
if(u32Tmp3 < u32Min)
{
u32Min = u32Tmp3;
u32MinNR = u32NR;
u32MinNF = u32NF;
/* Break when get good results */
if(u32Min == 0)
break;
}
}
}
}
}
/* Enable and apply new PLL setting. */
CLK->PLLCON = u32CLK_SRC | (u32NO << 14) | ((u32MinNR - 2) << 9) | (u32MinNF - 2);
/* Waiting for PLL clock stable */
CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);
/* Return actual PLL output clock frequency */
return u32PllSrcClk / ((u32NO + 1) * u32MinNR) * u32MinNF;
lexit:
/* Apply default PLL setting and return */
if(u32PllClkSrc == CLK_PLLCON_PLL_SRC_HXT)
CLK->PLLCON = 0xC22E; /* 48MHz */
else
CLK->PLLCON = 0x8D66F; /* 48.06498462MHz */
CLK_WaitClockReady(CLK_CLKSTATUS_PLL_STB_Msk);
return CLK_GetPLLClockFreq();
}
/**
* @brief Disable PLL
* @param None
* @return None
* @details This function disable PLL.
*/
void CLK_DisablePLL(void)
{
CLK->PLLCON |= CLK_PLLCON_PD_Msk;
}
/**
* @brief This function check selected clock source status
* @param[in] u32ClkMask is selected clock source. Including :
* - \ref CLK_CLKSTATUS_XTL12M_STB_Msk
* - \ref CLK_CLKSTATUS_OSC22M_STB_Msk
* - \ref CLK_CLKSTATUS_OSC10K_STB_Msk
* - \ref CLK_CLKSTATUS_PLL_STB_Msk
*
* @retval 0 clock is not stable
* @retval 1 clock is stable
*
* @details To wait for clock ready by specified CLKSTATUS bit or timeout (~300ms)
*/
uint32_t CLK_WaitClockReady(uint32_t u32ClkMask)
{
int32_t i32TimeOutCnt = 2160000;
while((CLK->CLKSTATUS & u32ClkMask) != u32ClkMask)
{
if(i32TimeOutCnt-- <= 0)
return 0;
}
return 1;
}
/**
* @brief Enable System Tick counter
* @param[in] u32ClkSrc is System Tick clock source. Including:
* - \ref CLK_CLKSEL0_STCLK_S_HXT
* - \ref CLK_CLKSEL0_STCLK_S_HXT_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HCLK_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HIRC_DIV2
* - \ref CLK_CLKSEL0_STCLK_S_HCLK
* @param[in] u32Count is System Tick reload value. It could be 0~0xFFFFFF.
* @return None
* @details This function set System Tick clock source, reload value, enable System Tick counter and interrupt.
* The register write-protection function should be disabled before using this function.
*/
void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count)
{
/* Set System Tick counter disabled */
SysTick->CTRL = 0;
/* Set System Tick clock source */
if( u32ClkSrc == CLK_CLKSEL0_STCLK_S_HCLK )
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
else
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_STCLK_S_Msk) | u32ClkSrc;
/* Set System Tick reload value */
SysTick->LOAD = u32Count;
/* Clear System Tick current value and counter flag */
SysTick->VAL = 0;
/* Set System Tick interrupt enabled and counter enabled */
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief Disable System Tick counter
* @param None
* @return None
* @details This function disable System Tick counter.
*/
void CLK_DisableSysTick(void)
{
/* Set System Tick counter disabled */
SysTick->CTRL = 0;
}
/*@}*/ /* end of group CLK_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group CLK_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

113
NUC123/StdDriver/src/crc.c Normal file
View File

@ -0,0 +1,113 @@
/**************************************************************************//**
* @file crc.c
* @version V3.00
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series CRC driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup CRC_Driver CRC Driver
@{
*/
/** @addtogroup CRC_EXPORTED_FUNCTIONS CRC Exported Functions
@{
*/
/**
* @brief CRC Open
*
* @param[in] u32Mode CRC operation polynomial mode. Valid values are:
* - \ref CRC_CCITT
* - \ref CRC_8
* - \ref CRC_16
* - \ref CRC_32
* @param[in] u32Attribute CRC operation data attribute. Valid values are combined with:
* - \ref CRC_CHECKSUM_COM
* - \ref CRC_CHECKSUM_RVS
* - \ref CRC_WDATA_COM
* - \ref CRC_WDATA_RVS
* @param[in] u32Seed Seed value.
* @param[in] u32DataLen CPU Write Data Length. Valid values are:
* - \ref CRC_CPU_WDATA_8
* - \ref CRC_CPU_WDATA_16
* - \ref CRC_CPU_WDATA_32
*
* @return None
*
* @details This function enable the CRC channel by specify CRC polynomial mode, data attribute, initial seed and write data length.
*/
void CRC_Open(uint32_t u32Mode, uint32_t u32Attribute, uint32_t u32Seed, uint32_t u32DataLen)
{
/* Enable CRC channel clock */
PDMA_GCR->GCRCSR |= PDMA_GCRCSR_CRC_CLK_EN_Msk;
CRC->SEED = u32Seed;
CRC->CTL = u32Mode | u32Attribute | u32DataLen | CRC_CTL_CRCCEN_Msk;
/* Setting RST bit will reload the initial seed value (CRC_SEED register) */
CRC->CTL |= CRC_CTL_CRC_RST_Msk;
}
/**
* @brief CRC Start DMA transfer
*
* @param[in] u32SrcAddr Starting source address of CRC DMA transfer.
* @param[in] u32ByteCount Calculate byte counts of CRC DMA transfer.
*
* @return None
*
* @details This function start CRC DMA transfer from specify source address and byte counts.
*/
void CRC_StartDMATransfer(uint32_t u32SrcAddr, uint32_t u32ByteCount)
{
CRC->DMASAR = u32SrcAddr;
CRC->DMABCR = u32ByteCount;
CRC->CTL |= CRC_CTL_TRIG_EN_Msk;
}
/**
* @brief Get CRC Checksum
*
* @param None
*
* @return Checksum Value
*
* @details This macro get the CRC checksum result by current CRC polynomial mode.
*/
uint32_t CRC_GetChecksum(void)
{
switch(CRC->CTL & CRC_CTL_CRC_MODE_Msk)
{
case CRC_CCITT:
case CRC_16:
return (CRC->CHECKSUM & 0xFFFF);
case CRC_32:
return (CRC->CHECKSUM);
case CRC_8:
return (CRC->CHECKSUM & 0xFF);
default:
return 0;
}
}
/*@}*/ /* end of group CRC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group CRC_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

282
NUC123/StdDriver/src/fmc.c Normal file
View File

@ -0,0 +1,282 @@
/**************************************************************************//**
* @file fmc.c
* @version V3.00
* $Revision: 4 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series FMC driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
//* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup FMC_Driver FMC Driver
@{
*/
/** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
@{
*/
/**
* @brief Set boot source from LDROM or APROM after next software reset
*
* @param[in] i32BootSrc
* 1: Boot from LDROM,
* 0: Boot from APROM
*
* @return None
*
* @details This function is used to switch APROM boot or LDROM boot. User need to call
* FMC_SetBootSource to select boot source first, then use CPU reset or
* System Reset Request to reset system.
*
*/
void FMC_SetBootSource(int32_t i32BootSrc)
{
if(i32BootSrc)
FMC->ISPCON |= FMC_ISPCON_BS_Msk; /* Boot from LDROM */
else
FMC->ISPCON &= ~FMC_ISPCON_BS_Msk;/* Boot from APROM */
}
/**
* @brief Disable ISP Functions
*
* @param None
*
* @return None
*
* @details This function will clear ISPEN bit of ISPCON to disable ISP function
*
*/
void FMC_Close(void)
{
FMC->ISPCON &= ~FMC_ISPCON_ISPEN_Msk;
}
/**
* @brief Disable APROM update function
*
* @param None
*
* @return None
*
* @details Disable APROM update function will forbid APROM programming when boot form APROM.
* APROM update is default to be disable.
*
*/
void FMC_DisableAPUpdate(void)
{
FMC->ISPCON &= ~FMC_ISPCON_APUEN_Msk;
}
/**
* @brief Disable User Configuration update function
*
* @param None
*
* @return None
*
* @details Disable User Configuration update function will forbid User Configuration programming.
* User Configuration update is default to be disable.
*/
void FMC_DisableConfigUpdate(void)
{
FMC->ISPCON &= ~FMC_ISPCON_CFGUEN_Msk;
}
/**
* @brief Disable LDROM update function
*
* @param None
*
* @return None
* @details Disable LDROM update function will forbid LDROM programming.
* LDROM update is default to be disable.
*/
void FMC_DisableLDUpdate(void)
{
FMC->ISPCON &= ~FMC_ISPCON_LDUEN_Msk;
}
/**
* @brief Enable APROM update function
*
* @param None
*
* @return None
*
* @details Enable APROM to be able to program when boot from APROM.
*
*/
void FMC_EnableAPUpdate(void)
{
FMC->ISPCON |= FMC_ISPCON_APUEN_Msk;
}
/**
* @brief Enable User Configuration update function
*
* @param None
*
* @return None
*
* @details Enable User Configuration to be able to program.
*
*/
void FMC_EnableConfigUpdate(void)
{
FMC->ISPCON |= FMC_ISPCON_CFGUEN_Msk;
}
/**
* @brief Enable LDROM update function
*
* @param None
*
* @return None
*
* @details Enable LDROM to be able to program.
*
*/
void FMC_EnableLDUpdate(void)
{
FMC->ISPCON |= FMC_ISPCON_LDUEN_Msk;
}
/**
* @brief Get the current boot source
*
* @param None
*
* @retval 0 This chip is currently booting from APROM
* @retval 1 This chip is currently booting from LDROM
*
* @note This function only show the boot source.
* User need to read ISPSTA register to know if IAP mode supported or not in relative boot.
*/
int32_t FMC_GetBootSource(void)
{
if(FMC->ISPCON & FMC_ISPCON_BS_Msk)
return 1;
else
return 0;
}
/**
* @brief Enable FMC ISP function
*
* @param None
*
* @return None
*
* @details ISPEN bit of ISPCON must be set before we can use ISP commands.
* Therefore, To use all FMC function APIs, user needs to call FMC_Open() first to enable ISP functions.
*
* @note ISP functions are write-protected. user also needs to unlock it by calling SYS_UnlockReg() before using all ISP functions.
*
*/
void FMC_Open(void)
{
FMC->ISPCON |= FMC_ISPCON_ISPEN_Msk;
}
/**
* @brief Get the base address of Data Flash if enabled.
*
* @param None
*
* @return The base address of Data Flash
*
* @details This function is used to return the base address of Data Flash.
*
*/
uint32_t FMC_ReadDataFlashBaseAddr(void)
{
return FMC->DFBADR;
}
/**
* @brief Read the User Configuration words.
*
* @param[out] u32Config The word buffer to store the User Configuration data.
* @param[in] u32Count The word count to be read.
*
* @retval 0 Success
* @retval -1 Failed
*
* @details This function is used to read the settings of user configuration.
* if u32Count = 1, Only CONFIG0 will be returned to the buffer specified by u32Config.
* if u32Count = 2, Both CONFIG0 and CONFIG1 will be returned.
*/
int32_t FMC_ReadConfig(uint32_t *u32Config, uint32_t u32Count)
{
int32_t i;
for(i = 0; i < u32Count; i++)
u32Config[i] = FMC_Read(FMC_CONFIG_BASE + i * 4);
return 0;
}
/**
* @brief Write User Configuration
*
* @param[in] u32Config The word buffer to store the User Configuration data.
* @param[in] u32Count The word count to program to User Configuration.
*
* @retval 0 Success
* @retval -1 Failed
*
* @details User must enable User Configuration update before writing it.
* User must erase User Configuration before writing it.
* User Configuration is also be page erase. User needs to backup necessary data
* before erase User Configuration.
*/
int32_t FMC_WriteConfig(uint32_t *u32Config, uint32_t u32Count)
{
int32_t i;
for(i = 0; i < u32Count; i++)
{
FMC_Write(FMC_CONFIG_BASE + i * 4, u32Config[i]);
if(FMC_Read(FMC_CONFIG_BASE + i * 4) != u32Config[i])
return -1;
}
return 0;
}
/*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group FMC_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

122
NUC123/StdDriver/src/gpio.c Normal file
View File

@ -0,0 +1,122 @@
/**************************************************************************//**
* @file gpio.c
* @version V3.00
* $Revision: 8 $
* $Date: 16/06/08 9:58a $
* @brief NUC123 series GPIO driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup GPIO_Driver GPIO Driver
@{
*/
/** @addtogroup GPIO_EXPORTED_FUNCTIONS GPIO Exported Functions
@{
*/
/**
* @brief Set GPIO operation mode
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32PinMask The single or multiple pins of specified GPIO port. \n
* It could be BIT10 ~ BIT15 for PA GPIO port. \n
* It could be BIT0 ~ BIT10 and BIT12 ~ BIT15 for PB GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT13 for PC GPIO port. \n
* It could be BIT0 ~ BIT5 and BIT8 ~ BIT11 for PD GPIO port. \n
* It could be BIT0 ~ BIT3 for PF GPIO port.
* @param[in] u32Mode Operation mode. It could be :
* - \ref GPIO_PMD_INPUT,
* - \ref GPIO_PMD_OUTPUT,
* - \ref GPIO_PMD_OPEN_DRAIN,
* - \ref GPIO_PMD_QUASI
*
* @return None
*
* @details This function is used to set specified GPIO operation mode.
*/
void GPIO_SetMode(GPIO_T *port, uint32_t u32PinMask, uint32_t u32Mode)
{
uint32_t i;
for(i = 0; i < GPIO_PIN_MAX; i++)
{
if(u32PinMask & (1 << i))
{
port->PMD = (port->PMD & ~(0x3 << (i << 1))) | (u32Mode << (i << 1));
}
}
}
/**
* @brief Enable GPIO interrupt
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
* @param[in] u32IntAttribs The interrupt attribute of specified GPIO pin. It could be :
* - \ref GPIO_INT_RISING
* - \ref GPIO_INT_FALLING
* - \ref GPIO_INT_BOTH_EDGE
* - \ref GPIO_INT_HIGH
* - \ref GPIO_INT_LOW
*
* @return None
*
* @details This function is used to enable specified GPIO pin interrupt.
*/
void GPIO_EnableInt(GPIO_T *port, uint32_t u32Pin, uint32_t u32IntAttribs)
{
/* Configure interrupt mode of specified pin */
port->IMD = (port->IMD & ~(1ul << u32Pin)) | (((u32IntAttribs >> 24) & 0xFFUL) << u32Pin);
/* Enable interrupt function of specified pin */
port->IEN = (port->IEN & ~(0x00010001ul << u32Pin)) | ((u32IntAttribs & 0xFFFFFFUL) << u32Pin);
}
/**
* @brief Disable GPIO interrupt
*
* @param[in] port GPIO port. It could be PA, PB, PC, PD or PF.
* @param[in] u32Pin The pin of specified GPIO port. \n
* It could be 10 ~ 15 for PA GPIO port. \n
* It could be 0 ~ 10 and 12 ~ 15 for PB GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 13 for PC GPIO port. \n
* It could be 0 ~ 5 and 8 ~ 11 for PD GPIO port. \n
* It could be 0 ~ 3 for PF GPIO port.
*
* @return None
*
* @details This function is used to disable specified GPIO pin interrupt.
*/
void GPIO_DisableInt(GPIO_T *port, uint32_t u32Pin)
{
/* Configure interrupt mode of specified pin */
port->IMD &= ~(1UL << u32Pin);
/* Disable interrupt function of specified pin */
port->IEN &= ~((0x00010001UL) << u32Pin);
}
/*@}*/ /* end of group GPIO_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group GPIO_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

1159
NUC123/StdDriver/src/i2c.c Normal file

File diff suppressed because it is too large Load Diff

222
NUC123/StdDriver/src/i2s.c Normal file
View File

@ -0,0 +1,222 @@
/**************************************************************************//**
* @file i2s.c
* @version V3.0
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series I2S driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup I2S_Driver I2S Driver
@{
*/
/** @addtogroup I2S_EXPORTED_FUNCTIONS I2S Exported Functions
@{
*/
/**
* @brief This function is used to get I2S source clock frequency.
* @param[in] i2s The pointer of the specified I2S module.
* @return I2S source clock frequency (Hz).
* @details Return the source clock frequency according to the setting of I2S_S (CLKSEL2[1:0]).
*/
static uint32_t I2S_GetSourceClockFreq(I2S_T *i2s)
{
uint32_t u32Freq, u32ClkSrcSel;
u32ClkSrcSel = CLK->CLKSEL2 & CLK_CLKSEL2_I2S_S_Msk;
switch(u32ClkSrcSel)
{
case CLK_CLKSEL2_I2S_S_HXT:
u32Freq = __HXT;
break;
case CLK_CLKSEL2_I2S_S_PLL:
u32Freq = CLK_GetPLLClockFreq();
break;
case CLK_CLKSEL2_I2S_S_HIRC:
u32Freq = __HIRC;
break;
case CLK_CLKSEL2_I2S_S_HCLK:
u32Freq = SystemCoreClock;
break;
default:
u32Freq = __HIRC;
break;
}
return u32Freq;
}
/**
* @brief This function configures some parameters of I2S interface for general purpose use.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32MasterSlave I2S operation mode. Valid values are:
* - \ref I2S_MODE_MASTER
* - \ref I2S_MODE_SLAVE
* @param[in] u32SampleRate Sample rate
* @param[in] u32WordWidth Data length. Valid values are:
* - \ref I2S_DATABIT_8
* - \ref I2S_DATABIT_16
* - \ref I2S_DATABIT_24
* - \ref I2S_DATABIT_32
* @param[in] u32Channels Audio format. Valid values are:
* - \ref I2S_MONO
* - \ref I2S_STEREO
* @param[in] u32DataFormat Data format. Valid values are:
* - \ref I2S_FORMAT_I2S
* - \ref I2S_FORMAT_MSB
* - \ref I2S_FORMAT_PCM_A
* - \ref I2S_FORMAT_PCM_B
* @return Real sample rate.
* @details This function will configure I2S controller according to the input parameters. Set TX and RX FIFO threshold to middle value.
* The actual sample rate may be different from the target sample rate. The real sample rate will be returned for reference.
* @note Both the TX and RX functions will be enabled.
*/
uint32_t I2S_Open(I2S_T *i2s, uint32_t u32MasterSlave, uint32_t u32SampleRate, uint32_t u32WordWidth, uint32_t u32Channels, uint32_t u32DataFormat)
{
uint32_t u32Divider;
uint32_t u32BitRate, u32SrcClk;
/* Reset I2S */
SYS->IPRSTC2 |= SYS_IPRSTC2_I2S_RST_Msk;
SYS->IPRSTC2 &= ~SYS_IPRSTC2_I2S_RST_Msk;
/* Configure I2S controller according to input parameters. */
i2s->CON = u32MasterSlave | u32WordWidth | u32Channels | u32DataFormat | I2S_FIFO_TX_LEVEL_WORD_4 | I2S_FIFO_RX_LEVEL_WORD_4;
/* Get I2S source clock frequency */
u32SrcClk = I2S_GetSourceClockFreq(i2s);
/* Calculate bit clock rate */
u32BitRate = u32SampleRate * (((u32WordWidth >> 4) & 0x3) + 1) * 16;
u32Divider = ((u32SrcClk / u32BitRate) >> 1) - 1;
i2s->CLKDIV = (i2s->CLKDIV & ~I2S_CLKDIV_BCLK_DIV_Msk) | (u32Divider << 8);
/* Calculate real sample rate */
u32BitRate = u32SrcClk / ((u32Divider + 1) * 2);
u32SampleRate = u32BitRate / ((((u32WordWidth >> 4) & 0x3) + 1) * 16);
/* Enable TX, RX and I2S controller */
i2s->CON |= (I2S_CON_RXEN_Msk | I2S_CON_TXEN_Msk | I2S_CON_I2SEN_Msk);
return u32SampleRate;
}
/**
* @brief Disable I2S function.
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details Disable I2S function.
*/
void I2S_Close(I2S_T *i2s)
{
i2s->CON &= ~I2S_CON_I2SEN_Msk;
}
/**
* @brief Enable interrupt function.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Mask The combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit. Valid values are:
* - \ref I2S_IE_LZCIE_Msk
* - \ref I2S_IE_RZCIE_Msk
* - \ref I2S_IE_TXTHIE_Msk
* - \ref I2S_IE_TXOVFIE_Msk
* - \ref I2S_IE_TXUDFIE_Msk
* - \ref I2S_IE_RXTHIE_Msk
* - \ref I2S_IE_RXOVFIE_Msk
* - \ref I2S_IE_RXUDFIE_Msk
* @return None
* @details This function enables the interrupt according to the mask parameter.
*/
void I2S_EnableInt(I2S_T *i2s, uint32_t u32Mask)
{
i2s->IE |= u32Mask;
}
/**
* @brief Disable interrupt function.
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32Mask The combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit. Valid values are:
* - \ref I2S_IE_LZCIE_Msk
* - \ref I2S_IE_RZCIE_Msk
* - \ref I2S_IE_TXTHIE_Msk
* - \ref I2S_IE_TXOVFIE_Msk
* - \ref I2S_IE_TXUDFIE_Msk
* - \ref I2S_IE_RXTHIE_Msk
* - \ref I2S_IE_RXOVFIE_Msk
* - \ref I2S_IE_RXUDFIE_Msk
* @return None
* @details This function disables the interrupt according to the mask parameter.
*/
void I2S_DisableInt(I2S_T *i2s, uint32_t u32Mask)
{
i2s->IE &= ~u32Mask;
}
/**
* @brief Enable master clock (MCLK).
* @param[in] i2s The pointer of the specified I2S module.
* @param[in] u32BusClock The target MCLK clock.
* @return Actual MCLK clock
* @details Set the master clock rate according to u32BusClock parameter and enable master clock output.
* The actual master clock rate may be different from the target master clock rate. The real master clock rate will be returned for reference.
*/
uint32_t I2S_EnableMCLK(I2S_T *i2s, uint32_t u32BusClock)
{
uint32_t u32Divider;
uint32_t u32SrcClk, u32Reg;
u32SrcClk = I2S_GetSourceClockFreq(i2s);
if(u32BusClock == u32SrcClk)
u32Divider = 0;
else
u32Divider = (u32SrcClk / u32BusClock) >> 1;
i2s->CLKDIV = (i2s->CLKDIV & ~I2S_CLKDIV_MCLK_DIV_Msk) | u32Divider;
i2s->CON |= I2S_CON_MCLKEN_Msk;
u32Reg = i2s->CLKDIV & I2S_CLKDIV_MCLK_DIV_Msk;
if(u32Reg == 0)
return u32SrcClk;
else
return ((u32SrcClk >> 1) / u32Reg);
}
/**
* @brief Disable master clock (MCLK).
* @param[in] i2s The pointer of the specified I2S module.
* @return None
* @details Disable master clock output.
*/
void I2S_DisableMCLK(I2S_T *i2s)
{
i2s->CON &= ~I2S_CON_MCLKEN_Msk;
}
/*@}*/ /* end of group I2S_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group I2S_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

292
NUC123/StdDriver/src/pdma.c Normal file
View File

@ -0,0 +1,292 @@
/**************************************************************************//**
* @file pdma.c
* @version V3.00
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series PDMA driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup PDMA_Driver PDMA Driver
@{
*/
/** @addtogroup PDMA_EXPORTED_FUNCTIONS PDMA Exported Functions
@{
*/
/**
* @brief PDMA Open
*
* @param[in] u32Mask Channel enable bits.
*
* @return None
*
* @details This function enable the PDMA channels.
*/
void PDMA_Open(uint32_t u32Mask)
{
PDMA_GCR->GCRCSR |= (u32Mask << 8);
}
/**
* @brief PDMA Close
*
* @param None
*
* @return None
*
* @details This function disable all PDMA channels.
*/
void PDMA_Close(void)
{
PDMA_GCR->GCRCSR = 0;
}
/**
* @brief Set PDMA Transfer Count
*
* @param[in] u32Ch The selected channel
* @param[in] u32Width Data width. Valid values are
* - \ref PDMA_WIDTH_8
* - \ref PDMA_WIDTH_16
* - \ref PDMA_WIDTH_32
* @param[in] u32TransCount Transfer count
*
* @return None
*
* @details This function set the selected channel data width and transfer count.
*/
void PDMA_SetTransferCnt(uint32_t u32Ch, uint32_t u32Width, uint32_t u32TransCount)
{
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
pdma->CSR = (pdma->CSR & ~PDMA_CSR_APB_TWS_Msk) | u32Width;
switch(u32Width)
{
case PDMA_WIDTH_32:
pdma->BCR = (u32TransCount << 2);
break;
case PDMA_WIDTH_8:
pdma->BCR = u32TransCount;
break;
case PDMA_WIDTH_16:
pdma->BCR = (u32TransCount << 1);
break;
default:
;
}
}
/**
* @brief Set PDMA Transfer Address
*
* @param[in] u32Ch The selected channel
* @param[in] u32SrcAddr Source address
* @param[in] u32SrcCtrl Source control attribute. Valid values are
* - \ref PDMA_SAR_INC
* - \ref PDMA_SAR_FIX
* @param[in] u32DstAddr destination address
* @param[in] u32DstCtrl destination control attribute. Valid values are
* - \ref PDMA_DAR_INC
* - \ref PDMA_DAR_FIX
*
* @return None
*
* @details This function set the selected channel source/destination address and attribute.
*/
void PDMA_SetTransferAddr(uint32_t u32Ch, uint32_t u32SrcAddr, uint32_t u32SrcCtrl, uint32_t u32DstAddr, uint32_t u32DstCtrl)
{
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
pdma->SAR = u32SrcAddr;
pdma->DAR = u32DstAddr;
pdma->CSR = (pdma->CSR & ~(PDMA_CSR_SAD_SEL_Msk | PDMA_CSR_DAD_SEL_Msk)) | (u32SrcCtrl | u32DstCtrl);
}
/**
* @brief Set PDMA Transfer Mode
*
* @param[in] u32Ch The selected channel
* @param[in] u32Peripheral The selected peripheral. Valid values are
* - \ref PDMA_SPI0_TX
* - \ref PDMA_SPI1_TX
* - \ref PDMA_SPI2_TX
* - \ref PDMA_UART0_TX
* - \ref PDMA_UART1_TX
* - \ref PDMA_I2S_TX
* - \ref PDMA_SPI0_RX
* - \ref PDMA_SPI1_RX
* - \ref PDMA_SPI2_RX
* - \ref PDMA_UART0_RX
* - \ref PDMA_UART1_RX
* - \ref PDMA_I2S_RX
* - \ref PDMA_ADC
* - \ref PDMA_PWM0_RX
* - \ref PDMA_PWM1_RX
* - \ref PDMA_PWM2_RX
* - \ref PDMA_PWM3_RX
* - \ref PDMA_MEM
* @param[in] u32ScatterEn Scatter-gather mode enable
* @param[in] u32DescAddr Scatter-gather descriptor address
*
* @return None
*
* @details This function set the selected channel transfer mode. Include peripheral setting.
*/
void PDMA_SetTransferMode(uint32_t u32Ch, uint32_t u32Peripheral, uint32_t u32ScatterEn, uint32_t u32DescAddr)
{
uint32_t u32Index = 0;
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
if(u32Peripheral > PDMA_PWM3_RX) /* Memory-to-Memory */
pdma->CSR = (pdma->CSR & ~(PDMA_CSR_MODE_SEL_Msk));
else if(u32Peripheral > PDMA_I2S_TX) /* Peripheral-to-Memory */
pdma->CSR = (pdma->CSR & ~(PDMA_CSR_MODE_SEL_Msk) | (0x1 << PDMA_CSR_MODE_SEL_Pos));
else /* Memory-to-Peripheral */
pdma->CSR = (pdma->CSR & ~(PDMA_CSR_MODE_SEL_Msk) | (0x2 << PDMA_CSR_MODE_SEL_Pos));
switch(u32Peripheral)
{
case 0:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI0_TXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI0_TXSEL_Pos);
break;
case 1:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI1_TXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI1_TXSEL_Pos);
break;
case 2:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI2_TXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI2_TXSEL_Pos);
break;
case 3:
PDMA_GCR->PDSSR1 = (PDMA_GCR->PDSSR1 & ~PDMA_PDSSR1_UART0_TXSEL_Msk) | (u32Ch << PDMA_PDSSR1_UART0_TXSEL_Pos);
break;
case 4:
PDMA_GCR->PDSSR1 = (PDMA_GCR->PDSSR1 & ~PDMA_PDSSR1_UART1_TXSEL_Msk) | (u32Ch << PDMA_PDSSR1_UART1_TXSEL_Pos);
break;
case 5:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_I2S_TXSEL_Msk) | (u32Ch << PDMA_PDSSR2_I2S_TXSEL_Pos);
break;
case 6:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI0_RXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI0_RXSEL_Pos);
break;
case 7:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI1_RXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI1_RXSEL_Pos);
break;
case 8:
PDMA_GCR->PDSSR0 = (PDMA_GCR->PDSSR0 & ~PDMA_PDSSR0_SPI2_RXSEL_Msk) | (u32Ch << PDMA_PDSSR0_SPI2_RXSEL_Pos);
break;
case 9:
PDMA_GCR->PDSSR1 = (PDMA_GCR->PDSSR1 & ~PDMA_PDSSR1_UART0_RXSEL_Msk) | (u32Ch << PDMA_PDSSR1_UART0_RXSEL_Pos);
break;
case 10:
PDMA_GCR->PDSSR1 = (PDMA_GCR->PDSSR1 & ~PDMA_PDSSR1_UART1_RXSEL_Msk) | (u32Ch << PDMA_PDSSR1_UART1_RXSEL_Pos);
break;
case 11:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_I2S_RXSEL_Msk) | (u32Ch << PDMA_PDSSR2_I2S_RXSEL_Pos);
break;
case 12:
PDMA_GCR->PDSSR1 = (PDMA_GCR->PDSSR1 & ~PDMA_PDSSR1_ADC_RXSEL_Msk) | (u32Ch << PDMA_PDSSR1_ADC_RXSEL_Pos);
break;
case 13:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_PWM0_RXSEL_Msk) | (u32Ch << PDMA_PDSSR2_PWM0_RXSEL_Pos);
break;
case 14:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_PWM1_RXSEL_Msk) | (u32Ch << PDMA_PDSSR2_PWM1_RXSEL_Pos);
break;
case 15:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_PWM2_RXSEL_Msk) | (u32Ch << PDMA_PDSSR2_PWM2_RXSEL_Pos);
break;
case 16:
PDMA_GCR->PDSSR2 = (PDMA_GCR->PDSSR2 & ~PDMA_PDSSR2_PWM3_RXSEL_Msk) | (u32Ch << PDMA_PDSSR2_PWM3_RXSEL_Pos);
break;
default:/* select PDMA channel as memory to memory */
for(u32Index = 0; u32Index < 8; u32Index++)
{
if((PDMA_GCR->PDSSR0 & (0xF << (u32Index * 4))) == (u32Ch << (u32Index * 4)))
PDMA_GCR->PDSSR0 |= 0xF << (u32Index * 4);
if((PDMA_GCR->PDSSR1 & (0xF << (u32Index * 4))) == (u32Ch << (u32Index * 4)))
PDMA_GCR->PDSSR1 |= 0xF << (u32Index * 4);
if((PDMA_GCR->PDSSR2 & (0xF << (u32Index * 4))) == (u32Ch << (u32Index * 4)))
PDMA_GCR->PDSSR2 |= 0xF << (u32Index * 4);
}
}
}
/**
* @brief Trigger PDMA
*
* @param[in] u32Ch The selected channel
*
* @return None
*
* @details This function trigger the selected channel.
*/
void PDMA_Trigger(uint32_t u32Ch)
{
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
pdma->CSR |= (PDMA_CSR_TRIG_EN_Msk | PDMA_CSR_PDMACEN_Msk);
}
/**
* @brief Enable Interrupt
*
* @param[in] u32Ch The selected channel
* @param[in] u32Mask The Interrupt Type
*
* @return None
*
* @details This function enable the selected channel interrupt.
*/
void PDMA_EnableInt(uint32_t u32Ch, uint32_t u32Mask)
{
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
pdma->IER |= u32Mask;
}
/**
* @brief Disable Interrupt
*
* @param[in] u32Ch The selected channel
* @param[in] u32Mask The Interrupt Type
*
* @return None
*
* @details This function disable the selected channel interrupt.
*/
void PDMA_DisableInt(uint32_t u32Ch, uint32_t u32Mask)
{
PDMA_T *pdma;
pdma = (PDMA_T *)((uint32_t) PDMA0_BASE + (0x100 * u32Ch));
pdma->IER &= ~u32Mask;
}
/*@}*/ /* end of group PDMA_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group PDMA_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

201
NUC123/StdDriver/src/ps2.c Normal file
View File

@ -0,0 +1,201 @@
/**************************************************************************//**
* @file ps2.c
* @version V3.00
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series PS/2 driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "NUC123.h"
/*---------------------------------------------------------------------------------------------------------*/
/* Includes of local headers */
/*---------------------------------------------------------------------------------------------------------*/
#include "ps2.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup PS2_Driver PS2 Driver
@{
*/
/** @addtogroup PS2_EXPORTED_FUNCTIONS PS2 Exported Functions
@{
*/
/**
* @brief Enable PS/2 Interrupt
*
* @param[in] u32Mask The specified interrupt of PS/2 module:
* - PS2D_PS2CON_TXINTEN_Msk: PS/2 Tx interrupt
* - PS2D_PS2CON_RXINTEN_Msk: PS/2 Rx interrupt
*
* @return None
*
* @details The function is used to enable PS/2 specified Tx or Rx interrupt.
*/
void PS2_EnableInt(uint32_t u32Mask)
{
PS2->PS2CON |= u32Mask;
}
/**
* @brief Disable PS/2 Interrupt.
*
* @param[in] u32Mask The specified interrupt of PS2 module:
* - PS2D_PS2CON_TXINTEN_Msk: PS2 Tx interrupt
* - PS2D_PS2CON_RXINTEN_Msk: PS2 Rx interrupt
*
* @return None
*
* @details The function is used to disable PS/2 specified Tx or Rx interrupt.
*/
void PS2_DisableInt(uint32_t u32Mask)
{
PS2->PS2CON &= ~u32Mask;
}
/**
* @brief Enable PS/2 function and Set Parameter
*
* @param None
*
* @return None
*
* @details This function is used to enable PS/2 function and set one byte per transfer.
*/
void PS2_Open(void)
{
/* Reset PS2 device */
SYS->IPRSTC2 |= SYS_IPRSTC2_PS2_RST_Msk;
SYS->IPRSTC2 &= ~SYS_IPRSTC2_PS2_RST_Msk;
/* Enable PS2 module */
PS2->PS2CON |= PS2_PS2CON_PS2EN_Msk;
/* Set One byte per transfer */
PS2->PS2CON &= ~PS2_PS2CON_TXFIFO_DEPTH_Msk;
/* Clear Tx FIFO */
PS2->PS2CON |= PS2_PS2CON_CLRFIFO_Msk;
PS2->PS2CON &= (~PS2_PS2CON_CLRFIFO_Msk);
}
/**
* @brief Disable PS/2 function
*
* @param None
*
* @return None
*
* @details This function use to disable PS/2 function.
*/
void PS2_Close(void)
{
/* Enable PS2 module */
PS2->PS2CON &= ~PS2_PS2CON_PS2EN_Msk;
}
/**
* @brief This function use to read PS/2 Rx data.
*
* @param None
*
* @return Rx data
*
* @details To get PS/2 receive 8 bits data from PS2RXDATA register.
*/
uint8_t PS2_Read(void)
{
return (uint8_t)(PS2->PS2RXDATA & PS2_PS2RXDATA_RXDATA_Msk);
}
/**
* @brief This function use to transmit PS/2 data.
*
* @param[in] pu32Buf The buffer to send the data to PS/2 transmission FIFO.
* @param[in] u32ByteCount The byte number of data.
*
* @retval 0 transmit data time-out
* @retval 1 transmit data successful
*
* @details Write data to PS/2 transmit FIFO and set the depth of Tx transmit bytes, then check every data transmission success or time-out.
*/
int32_t PS2_Write(uint32_t *pu32Buf, uint32_t u32ByteCount)
{
uint32_t u32TxFIFO_Depth = 16;
uint32_t u32delayno, txcnt, remainder;
uint8_t i = 0;
txcnt = u32ByteCount / u32TxFIFO_Depth;
remainder = u32ByteCount % u32TxFIFO_Depth;
if(remainder) txcnt++;
u32delayno = 0;
while(!(PS2->PS2STATUS & PS2_PS2STATUS_TXEMPTY_Msk))
{
u32delayno++;
if(u32delayno >= 0xF00000)
return FALSE; // Time Out
}
if(u32ByteCount >= u32TxFIFO_Depth)//Tx FIFO is 16 bytes
PS2_SET_TX_BYTE_CNT(u32TxFIFO_Depth);
do
{
u32delayno = 0;
while(!(PS2->PS2STATUS & PS2_PS2STATUS_TXEMPTY_Msk))
{
u32delayno++;
if(u32delayno >= 0xF00000)
return FALSE; // Time Out
}
if((txcnt == 1) && (remainder != 0))
PS2_SET_TX_BYTE_CNT(u32ByteCount);
PS2->PS2TXDATA0 = pu32Buf[i];
PS2->PS2TXDATA1 = pu32Buf[i + 1];
PS2->PS2TXDATA2 = pu32Buf[i + 2];
PS2->PS2TXDATA3 = pu32Buf[i + 3];
i = i + 4;
}
while(--txcnt);
u32delayno = 0;
while(!(PS2->PS2STATUS & PS2_PS2STATUS_TXEMPTY_Msk))
{
u32delayno++;
if(u32delayno >= 0xF00000)
return FALSE; // Time Out
}
return TRUE;
}
/*@}*/ /* end of group PS2_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group PS2_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

678
NUC123/StdDriver/src/pwm.c Normal file
View File

@ -0,0 +1,678 @@
/**************************************************************************//**
* @file pwm.c
* @version V3.00
* $Revision: 9 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series PWM driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup PWM_Driver PWM Driver
@{
*/
/** @addtogroup PWM_EXPORTED_FUNCTIONS PWM Exported Functions
@{
*/
/**
* @brief Configure PWM capture and get the nearest unit time.
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32UnitTimeNsec The unit time of counter
* @param[in] u32CaptureEdge The condition to latch the counter. This parameter is not used
* @return The nearest unit time in nano second.
* @details This function is used to configure PWM capture and get the nearest unit time.
*/
uint32_t PWM_ConfigCaptureChannel(PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32UnitTimeNsec,
uint32_t u32CaptureEdge)
{
uint32_t u32Src;
uint32_t u32PWMClockSrc;
uint32_t u32PWMClkTbl[8] = {__HXT, NULL, NULL, __HIRC, NULL, NULL, NULL, __LIRC};
uint32_t u32NearestUnitTimeNsec;
uint8_t u8Divider = 1;
/* this table is mapping divider value to register configuration */
uint32_t u32PWMDividerToRegTbl[17] = {NULL, 4, 0, NULL, 1, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3};
uint16_t u16Prescale = 2;
uint16_t u16CNR = 0xFFFF;
if(u32ChannelNum < 2)/* channel 0 and channel 1 */
u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM01_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM01_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk)) >> (CLK_CLKSEL1_PWM01_S_Pos);
else /* channel 2 and channel 3 */
u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM23_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM23_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM23_S_Msk)) >> (CLK_CLKSEL1_PWM23_S_Pos);
if(u32Src == 2)
{
SystemCoreClockUpdate();
u32PWMClockSrc = SystemCoreClock;
}
else
{
u32PWMClockSrc = u32PWMClkTbl[u32Src];
}
u32PWMClockSrc /= 1000;
for(; u16Prescale <= 0x100; u16Prescale++)
{
u32NearestUnitTimeNsec = (1000000 * u16Prescale * u8Divider) / u32PWMClockSrc;
if(u32NearestUnitTimeNsec < (u32UnitTimeNsec))
{
if((u16Prescale == 0x100) && (u8Divider == 16)) //limit to the maximum unit time(nano second)
break;
if(u16Prescale == 0x100)
{
u16Prescale = 2;
u8Divider <<= 1; // clk divider could only be 1, 2, 4, 8, 16
continue;
}
if(!((1000000 * ((u16Prescale * u8Divider) + 1)) > (u32NearestUnitTimeNsec * u32PWMClockSrc)))
break;
continue;
}
break;
}
// Store return value here 'cos we're gonna change u8Divider & u16Prescale & u16CNR to the real value to fill into register
u16Prescale -= 1;
// convert to real register value
u8Divider = u32PWMDividerToRegTbl[u8Divider];
// every two channels share a prescaler
(pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u16Prescale << ((u32ChannelNum >> 1) * 8));
(pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
// set PWM to edge aligned type
(pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (u32ChannelNum >> 1));
(pwm)->PCR |= PWM_PCR_CH0MOD_Msk << (8 * u32ChannelNum);
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + u32ChannelNum * 12))) = u16CNR;
return (u32NearestUnitTimeNsec);
}
/**
* @brief Configure PWM generator and get the nearest frequency in edge aligned auto-reload mode
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Frequency Target generator frequency
* @param[in] u32DutyCycle Target generator duty cycle percentage. Valid range are between 0 ~ 100. 10 means 10%, 20 means 20%...
* @return Nearest frequency clock in nano second
* @details This function is used to configure PWM generator and get the nearest frequency in edge aligned auto-reload mode.
* @note Since every two channels, (0 & 1), (2 & 3), shares a prescaler. Call this API to configure PWM frequency may affect
* existing frequency of other channel.
*/
uint32_t PWM_ConfigOutputChannel(PWM_T *pwm,
uint32_t u32ChannelNum,
uint32_t u32Frequency,
uint32_t u32DutyCycle)
{
uint32_t u32Src;
uint32_t u32PWMClockSrc;
uint32_t u32PWMClkTbl[8] = {__HXT, NULL, NULL, __HIRC, NULL, NULL, NULL, __LIRC};
uint32_t i;
uint8_t u8Divider = 1, u8Prescale = 0xFF;
/* this table is mapping divider value to register configuration */
uint32_t u32PWMDividerToRegTbl[17] = {NULL, 4, 0, NULL, 1, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3};
uint16_t u16CNR = 0xFFFF;
if(u32ChannelNum < 2)/* channel 0 and channel 1 */
u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM01_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM01_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk)) >> (CLK_CLKSEL1_PWM01_S_Pos);
else /* channel 2 and channel 3 */
u32Src = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM23_S_EXT_Msk)) >> (CLK_CLKSEL2_PWM23_S_EXT_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM23_S_Msk)) >> (CLK_CLKSEL1_PWM23_S_Pos);
if(u32Src == 2)
{
SystemCoreClockUpdate();
u32PWMClockSrc = SystemCoreClock;
}
else
{
u32PWMClockSrc = u32PWMClkTbl[u32Src];
}
for(; u8Divider < 17; u8Divider <<= 1) // clk divider could only be 1, 2, 4, 8, 16
{
i = (u32PWMClockSrc / (u32Frequency)) / u8Divider;
// If target value is larger than CNR * prescale, need to use a larger divider
if(i > (0x10000 * 0x100))
continue;
// CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF
u8Prescale = (i + 0xFFFF) / 0x10000;
// u8Prescale must at least be 2, otherwise the output stop
if(u8Prescale < 3)
u8Prescale = 2;
i /= u8Prescale;
if(i <= 0x10000)
{
if(i == 1)
u16CNR = 1; // Too fast, and PWM cannot generate expected frequency...
else
u16CNR = i;
break;
}
}
// Store return value here 'cos we're gonna change u8Divider & u8Prescale & u16CNR to the real value to fill into register
i = u32PWMClockSrc / (u8Prescale * u8Divider * u16CNR);
u8Prescale -= 1;
u16CNR -= 1;
// convert to real register value
u8Divider = u32PWMDividerToRegTbl[u8Divider];
// every two channels share a prescaler
(pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8));
(pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << (4 * u32ChannelNum))) | (u8Divider << (4 * u32ChannelNum));
// set PWM to edge aligned type
(pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (u32ChannelNum >> 1));
(pwm)->PCR |= PWM_PCR_CH0MOD_Msk << (8 * u32ChannelNum);
if(u32DutyCycle)
{
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMR0)) + u32ChannelNum * 12))) = u32DutyCycle * (u16CNR + 1) / 100 - 1;
}
else
{
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMR0)) + u32ChannelNum * 12))) = 0;
}
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + u32ChannelNum * 12))) = u16CNR;
return(i);
}
/**
* @brief Start PWM module
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @details This function is used to start PWM module.
*/
void PWM_Start(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t u32Mask = 0, i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
u32Mask |= (PWM_PCR_CH0EN_Msk << (i * 8));
}
}
(pwm)->PCR |= u32Mask;
}
/**
* @brief Stop PWM module
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @details This function is used to stop PWM module.
*/
void PWM_Stop(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + i * 12))) = 0;
}
}
}
/**
* @brief Stop PWM generation immediately by clear channel enable bit
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @details This function is used to stop PWM generation immediately by clear channel enable bit.
*/
void PWM_ForceStop(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t u32Mask = 0, i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
u32Mask |= (PWM_PCR_CH0EN_Msk << (i * 8));
}
}
(pwm)->PCR &= ~u32Mask;
}
/**
* @brief Enable selected channel to trigger ADC
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Condition This parameter is not used
* @return None
* @details This function is used to enable selected channel to trigger ADC.
* @note This function is only supported when PWM operating at Center-aligned type.
*/
void PWM_EnableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
{
(pwm)->TCON |= (PWM_TCON_PWM0TEN_Msk << u32ChannelNum);
}
/**
* @brief Disable selected channel to trigger ADC
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to disable selected channel to trigger ADC.
*/
void PWM_DisableADCTrigger(PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->TCON = ((pwm)->TCON & ~(PWM_TCON_PWM0TEN_Msk << u32ChannelNum));
}
/**
* @brief Clear selected channel trigger ADC flag
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Condition This parameter is not used
* @return None
* @details This function is used to clear selected channel trigger ADC flag.
*/
void PWM_ClearADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Condition)
{
(pwm)->TSTATUS = (PWM_TSTATUS_PWM0TF_Msk << u32ChannelNum);
}
/**
* @brief Get selected channel trigger ADC flag
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @retval 0 The specified channel trigger ADC to start of conversion flag is not set
* @retval 1 The specified channel trigger ADC to start of conversion flag is set
* @details This function is used to get PWM trigger ADC to start of conversion flag for specified channel.
*/
uint32_t PWM_GetADCTriggerFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
return (((pwm)->TSTATUS & (PWM_TSTATUS_PWM0TF_Msk << (u32ChannelNum))) ? 1 : 0);
}
/**
* @brief Enable capture of selected channel(s)
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @details This function is used to enable capture of selected channel(s).
*/
void PWM_EnableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
if(i < 2)
{
(pwm)->CCR0 |= PWM_CCR0_CAPCH0EN_Msk << (i * 16);
}
else
{
(pwm)->CCR2 |= PWM_CCR2_CAPCH2EN_Msk << ((i - 2) * 16);
}
}
}
(pwm)->CAPENR |= u32ChannelMask;
}
/**
* @brief Disable capture of selected channel(s)
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Bit 0 is channel 0, bit 1 is channel 1...
* @return None
* @details This function is used to disable capture of selected channel(s).
*/
void PWM_DisableCapture(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
if(i < 2)
{
(pwm)->CCR0 &= ~(PWM_CCR0_CAPCH0EN_Msk << (i * 16));
}
else
{
(pwm)->CCR2 &= ~(PWM_CCR2_CAPCH2EN_Msk << ((i - 2) * 16));
}
}
}
(pwm)->CAPENR &= ~u32ChannelMask;
}
/**
* @brief Enables PWM output generation of selected channel(s)
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Set bit 0 to 1 enables channel 0 output, set bit 1 to 1 enables channel 1 output...
* @return None
* @details This function is used to enables PWM output generation of selected channel(s).
*/
void PWM_EnableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
{
(pwm)->POE |= u32ChannelMask;
}
/**
* @brief Disables PWM output generation of selected channel(s)
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel
* Set bit 0 to 1 disables channel 0 output, set bit 1 to 1 disables channel 1 output...
* @return None
* @details This function is used to disables PWM output generation of selected channel(s).
*/
void PWM_DisableOutput(PWM_T *pwm, uint32_t u32ChannelMask)
{
(pwm)->POE &= ~u32ChannelMask;
}
/**
* @brief Enables PDMA transfer of selected channel(s) for PWM capture
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Set bit 0 to 1 enables channel 0 output, set bit 1 to 1 enables channel 1 output...
* @param[in] u32RisingFirst The capture order is rising, falling first. Every two channels share the same setting.
* @return None
* @details This function is used to enables PDMA transfer of selected channel(s) for PWM capture
*/
void PWM_EnablePDMA(PWM_T *pwm, uint32_t u32ChannelMask, uint32_t u32RisingFirst)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
(pwm)->CAPPDMACTL = ((pwm)->CAPPDMACTL & ~(PWM_CAPPDMACTL_CAP0RFORDER_Msk << (i * 8))) | \
(((u32RisingFirst << PWM_CAPPDMACTL_CAP0RFORDER_Pos) | \
PWM_CAPPDMACTL_CAP0PDMAMOD_Msk | PWM_CAPPDMACTL_CAP0PDMAEN_Msk) << (i * 8));
}
}
}
/**
* @brief Disables PDMA transfer of selected channel(s) for PWM capture
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelMask Combination of enabled channels. Each bit corresponds to a channel.
* Set bit 0 to 1 enables channel 0 output, set bit 1 to 1 enables channel 1 output...
* @return None
* @details This function is used to enables PDMA transfer of selected channel(s) for PWM capture
*/
void PWM_DisablePDMA(PWM_T *pwm, uint32_t u32ChannelMask)
{
uint32_t i;
for(i = 0; i < PWM_CHANNEL_NUM; i ++)
{
if(u32ChannelMask & (1 << i))
{
(pwm)->CAPPDMACTL &= ~(PWM_CAPPDMACTL_CAP0PDMAEN_Msk << (i * 8));
}
}
}
/**
* @brief Enable Dead zone of selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Duration Dead Zone length in PWM clock count, valid values are between 0~0xFF, but 0 means there is no
* dead zone.
* @return None
* @details This function is used to enable Dead zone of selected channel.
*/
void PWM_EnableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Duration)
{
// every two channels shares the same setting
u32ChannelNum >>= 1;
// set duration
(pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_DZI01_Msk << (8 * u32ChannelNum))) | (u32Duration << (PWM_PPR_DZI01_Pos + 8 * u32ChannelNum));
// enable dead zone
(pwm)->PCR |= (PWM_PCR_DZEN01_Msk << u32ChannelNum);
}
/**
* @brief Disable Dead zone of selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to disable Dead zone of selected channel.
*/
void PWM_DisableDeadZone(PWM_T *pwm, uint32_t u32ChannelNum)
{
// every two channels shares the same setting
u32ChannelNum >>= 1;
// enable dead zone
(pwm)->PCR &= ~(PWM_PCR_DZEN01_Msk << u32ChannelNum);
}
/**
* @brief Enable capture interrupt of selected channel.
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Edge Rising or falling edge to latch counter.
* - \ref PWM_CAPTURE_INT_RISING_LATCH
* - \ref PWM_CAPTURE_INT_FALLING_LATCH
* @return None
* @details This function is used to enable capture interrupt of selected channel.
*/
void PWM_EnableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
{
if(u32ChannelNum < 2)
(pwm)->CCR0 |= u32Edge << (u32ChannelNum * 16);
else
(pwm)->CCR2 |= u32Edge << ((u32ChannelNum - 2) * 16);
}
/**
* @brief Disable capture interrupt of selected channel.
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Edge Rising or falling edge to latch counter.
* - \ref PWM_CAPTURE_INT_RISING_LATCH
* - \ref PWM_CAPTURE_INT_FALLING_LATCH
* @return None
* @details This function is used to disable capture interrupt of selected channel.
*/
void PWM_DisableCaptureInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
{
if(u32ChannelNum < 2)
(pwm)->CCR0 &= ~(u32Edge << (u32ChannelNum * 16));
else
(pwm)->CCR2 &= ~(u32Edge << ((u32ChannelNum - 2) * 16));
}
/**
* @brief Clear capture interrupt of selected channel.
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32Edge Rising or falling edge to latch counter.
* - \ref PWM_CAPTURE_INT_RISING_LATCH
* - \ref PWM_CAPTURE_INT_FALLING_LATCH
* @return None
* @details This function is used to clear capture interrupt of selected channel.
*/
void PWM_ClearCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32Edge)
{
//clear capture interrupt flag, and clear CRLR or CFLR latched indicator
if(u32ChannelNum < 2)
(pwm)->CCR0 = ((pwm)->CCR0 & PWM_CCR_MASK) | (PWM_CCR0_CAPIF0_Msk << (u32ChannelNum * 16)) | (u32Edge << (u32ChannelNum * 16 + 5));
else
(pwm)->CCR2 = ((pwm)->CCR2 & PWM_CCR_MASK) | (PWM_CCR2_CAPIF2_Msk << ((u32ChannelNum - 2) * 16)) | (u32Edge << ((u32ChannelNum - 2) * 16 + 5));
}
/**
* @brief Get capture interrupt of selected channel.
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @retval 0 No capture interrupt
* @retval 1 Rising edge latch interrupt
* @retval 2 Falling edge latch interrupt
* @retval 3 Rising and falling latch interrupt
* @details This function is used to get capture interrupt of selected channel.
*/
uint32_t PWM_GetCaptureIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
if(u32ChannelNum < 2)
{
return (((pwm)->CCR0 & ((PWM_CCR0_CRLRI0_Msk | PWM_CCR0_CFLRI0_Msk) << (u32ChannelNum * 16))) >> (PWM_CCR0_CRLRI0_Pos + u32ChannelNum * 16));
}
else
{
return (((pwm)->CCR2 & ((PWM_CCR2_CRLRI2_Msk | PWM_CCR2_CFLRI2_Msk) << ((u32ChannelNum - 2) * 16))) >> (PWM_CCR2_CRLRI2_Pos + (u32ChannelNum - 2) * 16));
}
}
/**
* @brief Enable duty interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32IntDutyType This parameter is not used
* @return None
* @details This function is used to enable duty interrupt of selected channel.
*/
void PWM_EnableDutyInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntDutyType)
{
(pwm)->PIER |= (PWM_PIER_PWMDIE0_Msk << u32ChannelNum);
}
/**
* @brief Disable duty interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* - PWMA : PWM Group A
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to disable duty interrupt of selected channel.
*/
void PWM_DisableDutyInt(PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->PIER &= ~(PWM_PIER_PWMDIE0_Msk << u32ChannelNum);
}
/**
* @brief Clear duty interrupt flag of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to clear duty interrupt flag of selected channel.
*/
void PWM_ClearDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->PIIR = PWM_PIIR_PWMDIF0_Msk << u32ChannelNum;
}
/**
* @brief Get duty interrupt flag of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @retval 0 Duty interrupt did not occur
* @retval 1 Duty interrupt occurred
* @details This function is used to get duty interrupt flag of selected channel.
*/
uint32_t PWM_GetDutyIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
return (((pwm)->PIIR & (PWM_PIIR_PWMDIF0_Msk << u32ChannelNum)) ? 1 : 0);
}
/**
* @brief Enable period interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @param[in] u32IntPeriodType Period interrupt type, could be either
* - \ref PWM_PERIOD_INT_UNDERFLOW
* - \ref PWM_PERIOD_INT_MATCH_CNR
* @return None
* @details This function is used to enable period interrupt of selected channel.
* Every two channels, (0 & 1), (2 & 3), shares the period interrupt type setting.
*/
void PWM_EnablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32IntPeriodType)
{
(pwm)->PIER = ((pwm)->PIER & ~(PWM_PIER_INT01TYPE_Msk << (u32ChannelNum >> 1))) | \
(PWM_PIER_PWMIE0_Msk << u32ChannelNum) | (u32IntPeriodType << (u32ChannelNum >> 1));
}
/**
* @brief Disable period interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to disable period interrupt of selected channel.
*/
void PWM_DisablePeriodInt(PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->PIER &= ~(PWM_PIER_PWMIE0_Msk << u32ChannelNum);
}
/**
* @brief Clear period interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @return None
* @details This function is used to clear period interrupt of selected channel.
*/
void PWM_ClearPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
(pwm)->PIIR = (PWM_PIIR_PWMIF0_Msk << u32ChannelNum);
}
/**
* @brief Get period interrupt of selected channel
* @param[in] pwm The pointer of the specified PWM module
* @param[in] u32ChannelNum PWM channel number. Valid values are between 0~3
* @retval 0 Period interrupt did not occur
* @retval 1 Period interrupt occurred
* @details This function is used to get period interrupt of selected channel.
*/
uint32_t PWM_GetPeriodIntFlag(PWM_T *pwm, uint32_t u32ChannelNum)
{
return (((pwm)->PIIR & (PWM_PIIR_PWMIF0_Msk << (u32ChannelNum))) ? 1 : 0);
}
/*@}*/ /* end of group PWM_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group PWM_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

View File

@ -0,0 +1,761 @@
/**************************************************************************//**
* @file retarget.c
* @version V3.00
* $Revision: 13 $
* $Date: 16/06/13 7:50p $
* @brief NUC123 Series Debug Port and Semihost Setting Source File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "NUC123.h"
#if defined ( __CC_ARM )
#if (__ARMCC_VERSION < 400000)
#else
/* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
#pragma import _printf_widthprec
#endif
#endif
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------------------------------------*/
#if !(defined(__ICCARM__) && (__VER__ >= 6010000)) || (defined(__ICCARM__) && (__VER__ >= 8000000))
struct __FILE
{
int handle; /* Add whatever you need here */
};
#endif
FILE __stdout;
FILE __stdin;
enum { r0, r1, r2, r3, r12, lr, pc, psr};
/**
* @brief Helper function to dump register while hard fault occurred
* @param[in] stack pointer points to the dumped registers in SRAM
* @return None
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
*/
static void stackDump(uint32_t stack[])
{
printf("r0 = 0x%x\n", stack[r0]);
printf("r1 = 0x%x\n", stack[r1]);
printf("r2 = 0x%x\n", stack[r2]);
printf("r3 = 0x%x\n", stack[r3]);
printf("r12 = 0x%x\n", stack[r12]);
printf("lr = 0x%x\n", stack[lr]);
printf("pc = 0x%x\n", stack[pc]);
printf("psr = 0x%x\n", stack[psr]);
}
/**
* @brief Hard fault handler
* @param[in] stack pointer points to the dumped registers in SRAM
* @return None
* @details Replace while(1) at the end of this function with chip reset if WDT is not enabled for end product
*/
void Hard_Fault_Handler(uint32_t stack[])
{
printf("In Hard Fault Handler\n");
stackDump(stack);
// Replace while(1) with chip reset if WDT is not enabled for end product
while(1);
//SYS->IPRSTC1 = SYS_IPRSTC1_CHIP_RST_Msk;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Routine to write a char */
/*---------------------------------------------------------------------------------------------------------*/
#if defined(DEBUG_ENABLE_SEMIHOST)
/* The static buffer is used to speed up the semihost */
static char g_buf[16];
static char g_buf_len = 0;
/* Make sure won't goes here only because --gnu is defined , so
add !__CC_ARM and !__ICCARM__ checking */
# if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
# elif defined(__ICCARM__)
void SH_End(void)
{
asm("MOVS R0,#1 \n" //; Set return value to 1
"BX lr \n" //; Return
);
}
void SH_ICE(void)
{
asm("CMP R2,#0 \n"
"BEQ SH_End \n"
"STR R0,[R2] \n" //; Save the return value to *pn32Out_R0
);
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
asm("BKPT 0xAB \n" //; This instruction will cause ICE trap or system HardFault
"B SH_ICE \n"
"SH_HardFault: \n" //; Captured by HardFault
"MOVS R0,#0 \n" //; Set return value to 0
"BX lr \n" //; Return
);
return 1; //; Return 1 when it is trap by ICE
}
/**
* @brief Get LR value and branch to Hard_Fault_Handler function
* @param None
* @return None
* @details This function is use to get LR value and branch to Hard_Fault_Handler function.
*/
void Get_LR_and_Branch(void)
{
asm("MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
}
/**
* @brief Get MSP value and branch to Get_LR_and_Branch function
* @param None
* @return None
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void Stack_Use_MSP(void)
{
asm("MRS R0, MSP \n" //; read MSP
"B Get_LR_and_Branch \n"
);
}
/**
* @brief Get stack pointer value and branch to Get_LR_and_Branch function
* @param None
* @return None
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void HardFault_Handler_Ret(void)
{
asm("MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n" //; check LR bit 2
"BEQ Stack_Use_MSP \n" //; stack use MSP
"MRS R0, PSP \n" //; stack use PSP, read PSP
"B Get_LR_and_Branch \n"
);
}
/**
* @brief This function is implemented to support semihost
* @param None
* @returns None
* @details This function is implement to support semihost message print.
*
*/
void SP_Read_Ready(void)
{
asm("LDR R1, [R0, #24] \n" //; Get previous PC
"LDRH R3, [R1] \n" //; Get instruction
"LDR R2, [pc, #8] \n" //; The special BKPT instruction
"CMP R3, R2 \n" //; Test if the instruction at previous PC is BKPT
"BNE HardFault_Handler_Ret \n" //; Not BKPT
"ADDS R1, #4 \n" //; Skip BKPT and next line
"STR R1, [R0, #24] \n" //; Save previous PC
"BX lr \n" //; Return
"DCD 0xBEAB \n" //; BKPT instruction code
"B HardFault_Handler_Ret \n"
);
}
/**
* @brief Get stack pointer value and branch to Get_LR_and_Branch function
* @param None
* @return None
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
*/
void SP_is_PSP(void)
{
asm(
"MRS R0, PSP \n" //; stack use PSP, read PSP
"B Get_LR_and_Branch \n"
);
}
/**
* @brief This HardFault handler is implemented to support semihost
*
* @param None
*
* @returns None
*
* @details This function is implement to support semihost message print.
*
*/
void HardFault_Handler (void)
{
asm("MOV R0, lr \n"
"LSLS R0, #29 \n" //; Check bit 2
"BMI SP_is_PSP \n" //; previous stack is PSP
"MRS R0, MSP \n" //; previous stack is MSP, read MSP
"B SP_Read_Ready \n"
);
while(1);
}
# else
/**
* @brief This HardFault handler is implemented to support semihost
* @param None
* @returns None
* @details This function is implement to support semihost message print.
*
*/
__asm int32_t HardFault_Handler(void)
{
MOV R0, LR
LSLS R0, #29 //; Check bit 2
BMI SP_is_PSP //; previous stack is PSP
MRS R0, MSP //; previous stack is MSP, read MSP
B SP_Read_Ready
SP_is_PSP
MRS R0, PSP //; Read PSP
SP_Read_Ready
LDR R1, [R0, #24] //; Get previous PC
LDRH R3, [R1] //; Get instruction
LDR R2, =0xBEAB //; The special BKPT instruction
CMP R3, R2 //; Test if the instruction at previous PC is BKPT
BNE HardFault_Handler_Ret //; Not BKPT
ADDS R1, #4 //; Skip BKPT and next line
STR R1, [R0, #24] //; Save previous PC
BX LR //; Return
HardFault_Handler_Ret
/* TODO: Implement your own hard fault handler here. */
MOVS r0, #4
MOV r1, LR
TST r0, r1 //; check LR bit 2
BEQ Stack_Use_MSP //; stack use MSP
MRS R0, PSP ;stack use PSP //; stack use PSP, read PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP ; stack use MSP //; read MSP
Get_LR_and_Branch
MOV R1, LR ; LR current value //; LR current value
LDR R2,=__cpp(Hard_Fault_Handler) //; branch to Hard_Fault_Handler
BX R2
B .
ALIGN
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
__asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
BKPT 0xAB //; Wait ICE or HardFault
//; ICE will step over BKPT directly
//; HardFault will step BKPT and the next line
B SH_ICE
SH_HardFault //; Captured by HardFault
MOVS R0, #0 //; Set return value to 0
BX lr //; Return
SH_ICE //; Captured by ICE
//; Save return value
CMP R2, #0
BEQ SH_End
STR R0, [R2] //; Save the return value to *pn32Out_R0
SH_End
MOVS R0, #1 //; Set return value to 1
BX lr //; Return
}
#endif
#else
/* Make sure won't goes here only because --gnu is defined , so
add !__CC_ARM and !__ICCARM__ checking */
# if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
asm("MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n" /*; check LR bit 2 */
"BEQ 1f \n" /*; stack use MSP */
"MRS R0, PSP \n" /*; stack use PSP, read PSP */
"MOV R1, LR \n" /*; LR current value */
"B Hard_Fault_Handler \n"
"1: \n"
"MRS R0, MSP \n" /*; LR current value */
"B Hard_Fault_Handler \n"
::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
);
while(1);
}
# elif defined(__ICCARM__)
void Get_LR_and_Branch(void)
{
asm("MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
}
void Stack_Use_MSP(void)
{
asm("MRS R0, MSP \n" //; read MSP
"B Get_LR_and_Branch \n"
);
}
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
asm("MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n" //; check LR bit 2
"BEQ Stack_Use_MSP \n" //; stack use MSP
"MRS R0, PSP \n" //; stack use PSP, read PSP
"B Get_LR_and_Branch \n"
);
while(1);
}
# else
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @return None
*
* @details The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
*
*/
__asm int32_t HardFault_Handler(void)
{
MOVS r0, #4
MOV r1, LR
TST r0, r1 //; check LR bit 2
BEQ Stack_Use_MSP //; stack use MSP
MRS R0, PSP //; stack use PSP, read PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP //; read MSP
Get_LR_and_Branch
MOV R1, LR //; LR current value
LDR R2,=__cpp(Hard_Fault_Handler) //; branch to Hard_Fault_Handler
BX R2
}
#endif
#endif
/**
* @brief Routine to send a char
*
* @param[in] ch Character to send to debug port.
*
* @returns Send value from UART debug port
*
* @details Send a target char to UART debug port .
*/
#ifndef NONBLOCK_PRINTF
void SendChar_ToUART(int ch)
{
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
if(ch == '\n')
{
DEBUG_PORT->DATA = '\r';
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
}
DEBUG_PORT->DATA = ch;
}
#else
/* Non-block implement of send char */
#define BUF_SIZE 2048
void SendChar_ToUART(int ch)
{
static uint8_t u8Buf[BUF_SIZE] = {0};
static int32_t i32Head = 0;
static int32_t i32Tail = 0;
int32_t i32Tmp;
/* Only flush the data in buffer to UART when ch == 0 */
if(ch)
{
// Push char
if(ch == '\n')
{
i32Tmp = i32Head + 1;
if(i32Tmp >= BUF_SIZE) i32Tmp = 0;
if(i32Tmp != i32Tail)
{
u8Buf[i32Head] = '\r';
i32Head = i32Tmp;
}
}
i32Tmp = i32Head + 1;
if(i32Tmp >= BUF_SIZE) i32Tmp = 0;
if(i32Tmp != i32Tail)
{
u8Buf[i32Head] = ch;
i32Head = i32Tmp;
}
}
else
{
if(i32Tail == i32Head)
return;
}
// pop char
do
{
i32Tmp = i32Tail + 1;
if(i32Tmp > BUF_SIZE) i32Tmp = 0;
if((DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk) == 0)
{
DEBUG_PORT->THR = u8Buf[i32Tail];
i32Tail = i32Tmp;
}
else
break; // FIFO full
}
while(i32Tail != i32Head);
}
#endif
/**
* @brief Routine to send a char
*
* @param[in] ch Character to send to debug port.
*
* @returns Send value from UART debug port or semihost
*
* @details Send a target char to UART debug port or semihost.
*/
void SendChar(int ch)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
g_buf[g_buf_len++] = ch;
g_buf[g_buf_len] = '\0';
if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
{
/* Send the char */
if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
{
g_buf_len = 0;
return;
}
else
{
g_buf_len = 0;
}
}
#else
SendChar_ToUART(ch);
#endif
}
/**
* @brief Routine to get a char
*
* @param None
*
* @returns Get value from UART debug port or semihost
*
* @details Wait UART debug port or semihost to input a char.
*/
char GetChar(void)
{
#ifdef DEBUG_ENABLE_SEMIHOST
# if defined ( __CC_ARM )
int nRet;
while(SH_DoCommand(0x101, 0, &nRet) != 0)
{
if(nRet != 0)
{
SH_DoCommand(0x07, 0, &nRet);
return (char)nRet;
}
}
# else
int nRet;
while(SH_DoCommand(0x7, 0, &nRet) != 0)
{
if(nRet != 0)
return (char)nRet;
}
# endif
return (0);
#else
while(1)
{
if((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0)
{
return (DEBUG_PORT->DATA);
}
}
#endif
}
/**
* @brief Check any char input from UART
*
* @param None
*
* @retval 1: No any char input
* @retval 0: Have some char input
*
* @details Check UART RSR RX EMPTY or not to determine if any char input from UART
*/
int kbhit(void)
{
return !((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0);
}
/**
* @brief Check if debug message finished
*
* @param None
*
* @retval 1: Message is finished
* @retval 0: Message is transmitting.
*
* @details Check if message finished (FIFO empty of debug port)
*/
int IsDebugFifoEmpty(void)
{
return ((DEBUG_PORT->FSR & UART_FSR_TE_FLAG_Msk) != 0);
}
/**
* @brief C library retargetting
*
* @param[in] ch Character to send to debug port.
*
* @returns None
*
* @details Check if message finished (FIFO empty of debug port)
*/
void _ttywrch(int ch)
{
SendChar(ch);
return;
}
/**
* @brief Write character to stream
*
* @param[in] ch Character to be written. The character is passed as its int promotion.
* @param[in] stream Pointer to a FILE object that identifies the stream where the character is to be written.
*
* @returns If there are no errors, the same character that has been written is returned.
* If an error occurs, EOF is returned and the error indicator is set (see ferror).
*
* @details Writes a character to the stream and advances the position indicator.\n
* The character is written at the current position of the stream as indicated \n
* by the internal position indicator, which is then advanced one character.
*
* @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
*
*
*/
int fputc(int ch, FILE *stream)
{
SendChar(ch);
return ch;
}
#if defined ( __GNUC__ )
#if !defined (OS_USE_SEMIHOSTING)
int _write (int fd, char *ptr, int len)
{
int i = len;
while(i--)
{
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
if(*ptr == '\n')
{
DEBUG_PORT->DATA = '\r';
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
}
DEBUG_PORT->DATA = *ptr++;
}
return len;
}
int _read (int fd, char *ptr, int len)
{
while((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) != 0);
*ptr = DEBUG_PORT->DATA;
return 1;
}
#endif
#else
/**
* @brief Get character from UART debug port or semihosting input
*
* @param[in] stream Pointer to a FILE object that identifies the stream on which the operation is to be performed.
*
* @returns The character read from UART debug port or semihosting
*
* @details For get message from debug port or semihosting.
*
*/
int fgetc(FILE *stream)
{
return (GetChar());
}
/**
* @brief Check error indicator
*
* @param[in] stream Pointer to a FILE object that identifies the stream.
*
* @returns If the error indicator associated with the stream was set, the function returns a nonzero value.
* Otherwise, it returns a zero value.
*
* @details Checks if the error indicator associated with stream is set, returning a value different
* from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
*
* @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
*
*/
int ferror(FILE *stream)
{
return EOF;
}
#endif
#ifdef DEBUG_ENABLE_SEMIHOST
# ifdef __ICCARM__
void __exit(int return_code)
{
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
{
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label:
goto label; /* endless loop */
}
# else
void _sys_exit(int return_code)
{
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
{
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label:
goto label; /* endless loop */
}
# endif
#endif

603
NUC123/StdDriver/src/spi.c Normal file
View File

@ -0,0 +1,603 @@
/**************************************************************************//**
* @file spi.c
* @version V3.00
* $Revision: 8 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series SPI driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup SPI_Driver SPI Driver
@{
*/
/** @addtogroup SPI_EXPORTED_FUNCTIONS SPI Exported Functions
@{
*/
/**
* @brief This function make SPI module be ready to transfer.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32MasterSlave Decides the SPI module is operating in master mode or in Slave mode. (SPI_SLAVE, SPI_MASTER)
* @param[in] u32SPIMode Decides the transfer timing. (SPI_MODE_0, SPI_MODE_1, SPI_MODE_2, SPI_MODE_3)
* @param[in] u32DataWidth Decides the data width of a SPI transaction.
* @param[in] u32BusClock The expected frequency of SPI bus clock in Hz.
* @return Actual frequency of SPI peripheral clock.
* @details By default, the SPI transfer sequence is MSB first and the automatic slave selection function is disabled.
* In Slave mode, the u32BusClock parameter is useless and the SPI clock divider setting will be 0.
* The actual clock rate may be different from the target SPI clock rate.
* For example, if the SPI source clock rate is 12 MHz and the target SPI bus clock rate is 7 MHz, the
* actual SPI clock rate will be 6MHz.
* @note If u32BusClock = 0, DIVIDER setting will be set to the maximum value.
* @note If u32BusClock >= system clock frequency, SPI peripheral clock source will be set to HCLK and DIVIDER will be set to 0.
* @note In Slave mode, the SPI peripheral clock rate will be set to equal the system clock rate, and slave selection signal is low level active.
*/
uint32_t SPI_Open(SPI_T *spi,
uint32_t u32MasterSlave,
uint32_t u32SPIMode,
uint32_t u32DataWidth,
uint32_t u32BusClock)
{
uint32_t u32ClkSrc = 0, u32Div, u32HCLKFreq;
if(u32DataWidth == 32)
u32DataWidth = 0;
/* Default setting: MSB first, disable unit transfer interrupt, SP_CYCLE = 0. */
spi->CNTRL = u32MasterSlave | (u32DataWidth << SPI_CNTRL_TX_BIT_LEN_Pos) | (u32SPIMode);
/* Set BCn = 1: f_spi = f_spi_clk_src / (DIVIDER + 1) */
spi->CNTRL2 |= SPI_CNTRL2_BCn_Msk;
/* Get system clock frequency */
u32HCLKFreq = CLK_GetHCLKFreq();
if(u32MasterSlave == SPI_MASTER)
{
/* Default setting: slave select signal is active low; disable automatic slave select function. */
spi->SSR = SPI_SS_ACTIVE_LOW;
/* Check clock source of SPI */
if(spi == SPI0)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI0_S_Msk) == CLK_CLKSEL1_SPI0_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else if(spi == SPI1)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI1_S_Msk) == CLK_CLKSEL1_SPI1_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI2_S_Msk) == CLK_CLKSEL1_SPI2_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
if(u32BusClock >= u32HCLKFreq)
{
/* Select HCLK as the clock source of SPI */
if(spi == SPI0)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI0_S_Msk)) | CLK_CLKSEL1_SPI0_S_HCLK;
else if(spi == SPI1)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI1_S_Msk)) | CLK_CLKSEL1_SPI1_S_HCLK;
else
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI2_S_Msk)) | CLK_CLKSEL1_SPI2_S_HCLK;
/* Set DIVIDER = 0 */
spi->DIVIDER = 0;
/* Return slave peripheral clock rate */
return u32HCLKFreq;
}
else if(u32BusClock >= u32ClkSrc)
{
/* Set DIVIDER = 0 */
spi->DIVIDER = 0;
/* Return master peripheral clock rate */
return u32ClkSrc;
}
else if(u32BusClock == 0)
{
/* Set BCn = 0: f_spi = f_spi_clk_src / ((DIVIDER + 1) * 2) */
spi->CNTRL2 &= (~SPI_CNTRL2_BCn_Msk);
/* Set DIVIDER to the maximum value 0xFF */
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (0xFF << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / ((0xFF + 1) * 2));
}
else
{
u32Div = (((u32ClkSrc * 10) / u32BusClock + 5) / 10) - 1; /* Round to the nearest integer */
if(u32Div > 0xFF)
{
/* Set BCn = 0: f_spi = f_spi_clk_src / ((DIVIDER + 1) * 2) */
spi->CNTRL2 &= (~SPI_CNTRL2_BCn_Msk);
u32Div = (((u32ClkSrc * 10) / (u32BusClock * 2) + 5) / 10) - 1; /* Round to the nearest integer */
if(u32Div > 0xFF)
u32Div = 0xFF;
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (u32Div << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / ((u32Div + 1) * 2));
}
else
{
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (u32Div << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / (u32Div + 1));
}
}
}
else /* For Slave mode, force the SPI peripheral clock rate to equal the system clock rate. */
{
/* Default setting: slave selection signal is low level active. */
spi->SSR = SPI_SSR_SS_LTRIG_Msk;
/* Select HCLK as the clock source of SPI */
if(spi == SPI0)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI0_S_Msk)) | CLK_CLKSEL1_SPI0_S_HCLK;
else if(spi == SPI1)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI1_S_Msk)) | CLK_CLKSEL1_SPI1_S_HCLK;
else
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI2_S_Msk)) | CLK_CLKSEL1_SPI2_S_HCLK;
/* Set DIVIDER = 0 */
spi->DIVIDER = 0;
/* Return slave peripheral clock rate */
return u32HCLKFreq;
}
}
/**
* @brief Disable SPI controller.
* @param[in] spi The pointer of the specified SPI module.
* @return None
* @details This function will reset SPI controller.
*/
void SPI_Close(SPI_T *spi)
{
if(spi == SPI0)
{
/* Reset SPI */
SYS->IPRSTC2 |= SYS_IPRSTC2_SPI0_RST_Msk;
SYS->IPRSTC2 &= ~SYS_IPRSTC2_SPI0_RST_Msk;
}
else if(spi == SPI1)
{
/* Reset SPI */
SYS->IPRSTC2 |= SYS_IPRSTC2_SPI1_RST_Msk;
SYS->IPRSTC2 &= ~SYS_IPRSTC2_SPI1_RST_Msk;
}
else
{
/* Reset SPI */
SYS->IPRSTC2 |= SYS_IPRSTC2_SPI2_RST_Msk;
SYS->IPRSTC2 &= ~SYS_IPRSTC2_SPI2_RST_Msk;
}
}
/**
* @brief Clear RX FIFO buffer.
* @param[in] spi The pointer of the specified SPI module.
* @return None
* @details This function will clear SPI RX FIFO buffer.
*/
void SPI_ClearRxFIFO(SPI_T *spi)
{
spi->FIFO_CTL |= SPI_FIFO_CTL_RX_CLR_Msk;
}
/**
* @brief Clear TX FIFO buffer.
* @param[in] spi The pointer of the specified SPI module.
* @return None
* @details This function will clear SPI TX FIFO buffer.
*/
void SPI_ClearTxFIFO(SPI_T *spi)
{
spi->FIFO_CTL |= SPI_FIFO_CTL_TX_CLR_Msk;
}
/**
* @brief Disable the automatic slave selection function.
* @param[in] spi The pointer of the specified SPI module.
* @return None
* @details This function will disable the automatic slave selection function and set slave selection signal to inactive state.
*/
void SPI_DisableAutoSS(SPI_T *spi)
{
spi->SSR &= ~(SPI_SSR_AUTOSS_Msk | SPI_SSR_SSR_Msk);
}
/**
* @brief Enable the automatic slave selection function.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32SSPinMask Specifies slave selection pins. (SPI_SS0, SPI_SS1)
* @param[in] u32ActiveLevel Specifies the active level of slave selection signal. (SPI_SS_ACTIVE_HIGH, SPI_SS_ACTIVE_LOW)
* @return None
* @details This function will enable the automatic slave selection function. Only available in Master mode.
* The slave selection pin and the active level will be set in this function.
*/
void SPI_EnableAutoSS(SPI_T *spi, uint32_t u32SSPinMask, uint32_t u32ActiveLevel)
{
spi->SSR = (spi->SSR & (~(SPI_SSR_AUTOSS_Msk | SPI_SSR_SS_LVL_Msk | SPI_SSR_SSR_Msk))) | (u32SSPinMask | u32ActiveLevel | SPI_SSR_AUTOSS_Msk);
}
/**
* @brief Set the SPI bus clock.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32BusClock The expected frequency of SPI bus clock in Hz.
* @return Actual frequency of SPI bus clock.
* @details This function is only available in Master mode. The actual clock rate may be different from the target SPI bus clock rate.
* For example, if the SPI source clock rate is 12MHz and the target SPI bus clock rate is 7MHz, the actual SPI bus clock
* rate will be 6MHz.
* @note If u32BusClock = 0, DIVIDER setting will be set to the maximum value.
* @note If u32BusClock >= system clock frequency, SPI peripheral clock source will be set to HCLK and DIVIDER will be set to 0.
*/
uint32_t SPI_SetBusClock(SPI_T *spi, uint32_t u32BusClock)
{
uint32_t u32ClkSrc, u32HCLKFreq;
uint32_t u32Div;
/* Set BCn = 1: f_spi = f_spi_clk_src / (DIVIDER + 1) */
spi->CNTRL2 |= SPI_CNTRL2_BCn_Msk;
/* Get system clock frequency */
u32HCLKFreq = CLK_GetHCLKFreq();
/* Check clock source of SPI */
if(spi == SPI0)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI0_S_Msk) == CLK_CLKSEL1_SPI0_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else if(spi == SPI1)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI1_S_Msk) == CLK_CLKSEL1_SPI1_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI2_S_Msk) == CLK_CLKSEL1_SPI2_S_HCLK)
u32ClkSrc = u32HCLKFreq;
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
if(u32BusClock >= u32HCLKFreq)
{
/* Select HCLK as the clock source of SPI */
if(spi == SPI0)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI0_S_Msk)) | CLK_CLKSEL1_SPI0_S_HCLK;
else if(spi == SPI1)
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI1_S_Msk)) | CLK_CLKSEL1_SPI1_S_HCLK;
else
CLK->CLKSEL1 = (CLK->CLKSEL1 & (~CLK_CLKSEL1_SPI2_S_Msk)) | CLK_CLKSEL1_SPI2_S_HCLK;
/* Set DIVIDER = 0 */
spi->DIVIDER = 0;
/* Return slave peripheral clock rate */
return u32HCLKFreq;
}
else if(u32BusClock >= u32ClkSrc)
{
/* Set DIVIDER = 0 */
spi->DIVIDER = 0;
/* Return master peripheral clock rate */
return u32ClkSrc;
}
else if(u32BusClock == 0)
{
/* Set BCn = 0: f_spi = f_spi_clk_src / ((DIVIDER + 1) * 2) */
spi->CNTRL2 &= (~SPI_CNTRL2_BCn_Msk);
/* Set DIVIDER to the maximum value 0xFF */
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (0xFF << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / ((0xFF + 1) * 2));
}
else
{
u32Div = (((u32ClkSrc * 10) / u32BusClock + 5) / 10) - 1; /* Round to the nearest integer */
if(u32Div > 0xFF)
{
/* Set BCn = 0: f_spi = f_spi_clk_src / ((DIVIDER + 1) * 2) */
spi->CNTRL2 &= (~SPI_CNTRL2_BCn_Msk);
u32Div = (((u32ClkSrc * 10) / (u32BusClock * 2) + 5) / 10) - 1; /* Round to the nearest integer */
if(u32Div > 0xFF)
u32Div = 0xFF;
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (u32Div << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / ((u32Div + 1) * 2));
}
else
{
spi->DIVIDER = (spi->DIVIDER & (~SPI_DIVIDER_DIVIDER_Msk)) | (u32Div << SPI_DIVIDER_DIVIDER_Pos);
/* Return master peripheral clock rate */
return (u32ClkSrc / (u32Div + 1));
}
}
}
/**
* @brief Enable FIFO mode.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32TxThreshold Decides the TX FIFO threshold.
* @param[in] u32RxThreshold Decides the RX FIFO threshold.
* @return None
* @details Enable FIFO mode with user-specified TX FIFO threshold and RX FIFO threshold configurations.
*/
void SPI_EnableFIFO(SPI_T *spi, uint32_t u32TxThreshold, uint32_t u32RxThreshold)
{
spi->FIFO_CTL = (spi->FIFO_CTL & ~(SPI_FIFO_CTL_TX_THRESHOLD_Msk | SPI_FIFO_CTL_RX_THRESHOLD_Msk) |
(u32TxThreshold << SPI_FIFO_CTL_TX_THRESHOLD_Pos) |
(u32RxThreshold << SPI_FIFO_CTL_RX_THRESHOLD_Pos));
spi->CNTRL |= SPI_CNTRL_FIFO_Msk;
}
/**
* @brief Disable FIFO mode.
* @param[in] spi The pointer of the specified SPI module.
* @return None
* @details Clear FIFO bit of SPI_CNTRL register to disable FIFO mode.
*/
void SPI_DisableFIFO(SPI_T *spi)
{
spi->CNTRL &= ~SPI_CNTRL_FIFO_Msk;
}
/**
* @brief Get the actual frequency of SPI bus clock. Only available in Master mode.
* @param[in] spi The pointer of the specified SPI module.
* @return Actual SPI bus clock frequency.
* @details This function will calculate the actual SPI bus clock rate according to the settings of SPIn_S, BCn and DIVIDER. Only available in Master mode.
*/
uint32_t SPI_GetBusClock(SPI_T *spi)
{
uint32_t u32Div;
uint32_t u32ClkSrc;
/* Get DIVIDER setting */
u32Div = (spi->DIVIDER & SPI_DIVIDER_DIVIDER_Msk) >> SPI_DIVIDER_DIVIDER_Pos;
/* Check clock source of SPI */
if(spi == SPI0)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI0_S_Msk) == CLK_CLKSEL1_SPI0_S_HCLK)
u32ClkSrc = CLK_GetHCLKFreq();
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else if(spi == SPI1)
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI1_S_Msk) == CLK_CLKSEL1_SPI1_S_HCLK)
u32ClkSrc = CLK_GetHCLKFreq();
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
else
{
if((CLK->CLKSEL1 & CLK_CLKSEL1_SPI2_S_Msk) == CLK_CLKSEL1_SPI2_S_HCLK)
u32ClkSrc = CLK_GetHCLKFreq();
else
u32ClkSrc = CLK_GetPLLClockFreq();
}
if(spi->CNTRL2 & SPI_CNTRL2_BCn_Msk) /* BCn = 1: f_spi = f_spi_clk_src / (DIVIDER + 1) */
{
/* Return SPI bus clock rate */
return (u32ClkSrc / (u32Div + 1));
}
else /* BCn = 0: f_spi = f_spi_clk_src / ((DIVIDER + 1) * 2) */
{
/* Return SPI bus clock rate */
return (u32ClkSrc / ((u32Div + 1) * 2));
}
}
/**
* @brief Enable interrupt function.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Mask The combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit.
* This parameter decides which interrupts will be enabled.
* (SPI_UNIT_INT_MASK, SPI_SSTA_INT_MASK, SPI_FIFO_TX_INT_MASK,
* SPI_FIFO_RX_INT_MASK, SPI_FIFO_RXOV_INT_MASK, SPI_FIFO_TIMEOUT_INT_MASK)
* @return None
* @details Enable SPI related interrupts specified by u32Mask parameter.
*/
void SPI_EnableInt(SPI_T *spi, uint32_t u32Mask)
{
/* Enable unit transfer interrupt flag */
if((u32Mask & SPI_UNIT_INT_MASK) == SPI_UNIT_INT_MASK)
spi->CNTRL |= SPI_CNTRL_IE_Msk;
/* Enable slave 3-wire mode start interrupt flag */
if((u32Mask & SPI_SSTA_INT_MASK) == SPI_SSTA_INT_MASK)
spi->CNTRL2 |= SPI_CNTRL2_SSTA_INTEN_Msk;
/* Enable TX threshold interrupt flag */
if((u32Mask & SPI_FIFO_TX_INT_MASK) == SPI_FIFO_TX_INT_MASK)
spi->FIFO_CTL |= SPI_FIFO_CTL_TX_INTEN_Msk;
/* Enable RX threshold interrupt flag */
if((u32Mask & SPI_FIFO_RX_INT_MASK) == SPI_FIFO_RX_INT_MASK)
spi->FIFO_CTL |= SPI_FIFO_CTL_RX_INTEN_Msk;
/* Enable RX overrun interrupt flag */
if((u32Mask & SPI_FIFO_RXOV_INT_MASK) == SPI_FIFO_RXOV_INT_MASK)
spi->FIFO_CTL |= SPI_FIFO_CTL_RXOV_INTEN_Msk;
/* Enable RX time-out interrupt flag */
if((u32Mask & SPI_FIFO_TIMEOUT_INT_MASK) == SPI_FIFO_TIMEOUT_INT_MASK)
spi->FIFO_CTL |= SPI_FIFO_CTL_TIMEOUT_INTEN_Msk;
}
/**
* @brief Disable interrupt function.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Mask The combination of all related interrupt enable bits.
* Each bit corresponds to a interrupt bit.
* This parameter decides which interrupts will be disabled.
* (SPI_UNIT_INT_MASK, SPI_SSTA_INT_MASK, SPI_FIFO_TX_INT_MASK,
* SPI_FIFO_RX_INT_MASK, SPI_FIFO_RXOV_INT_MASK, SPI_FIFO_TIMEOUT_INT_MASK)
* @return None
* @details Disable SPI related interrupts specified by u32Mask parameter.
*/
void SPI_DisableInt(SPI_T *spi, uint32_t u32Mask)
{
/* Disable unit transfer interrupt flag */
if((u32Mask & SPI_UNIT_INT_MASK) == SPI_UNIT_INT_MASK)
spi->CNTRL &= ~SPI_CNTRL_IE_Msk;
/* Disable slave 3-wire mode start interrupt flag */
if((u32Mask & SPI_SSTA_INT_MASK) == SPI_SSTA_INT_MASK)
spi->CNTRL2 &= ~SPI_CNTRL2_SSTA_INTEN_Msk;
/* Disable TX threshold interrupt flag */
if((u32Mask & SPI_FIFO_TX_INT_MASK) == SPI_FIFO_TX_INT_MASK)
spi->FIFO_CTL &= ~SPI_FIFO_CTL_TX_INTEN_Msk;
/* Disable RX threshold interrupt flag */
if((u32Mask & SPI_FIFO_RX_INT_MASK) == SPI_FIFO_RX_INT_MASK)
spi->FIFO_CTL &= ~SPI_FIFO_CTL_RX_INTEN_Msk;
/* Disable RX overrun interrupt flag */
if((u32Mask & SPI_FIFO_RXOV_INT_MASK) == SPI_FIFO_RXOV_INT_MASK)
spi->FIFO_CTL &= ~SPI_FIFO_CTL_RXOV_INTEN_Msk;
/* Disable RX time-out interrupt flag */
if((u32Mask & SPI_FIFO_TIMEOUT_INT_MASK) == SPI_FIFO_TIMEOUT_INT_MASK)
spi->FIFO_CTL &= ~SPI_FIFO_CTL_TIMEOUT_INTEN_Msk;
}
/**
* @brief Get interrupt flag.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Mask The combination of all related interrupt sources.
* Each bit corresponds to a interrupt source.
* This parameter decides which interrupt flags will be read.
* (SPI_UNIT_INT_MASK, SPI_SSTA_INT_MASK, SPI_FIFO_TX_INT_MASK,
* SPI_FIFO_RX_INT_MASK, SPI_FIFO_RXOV_INT_MASK, SPI_FIFO_TIMEOUT_INT_MASK)
* @return Interrupt flags of selected sources.
* @details Get SPI related interrupt flags specified by u32Mask parameter.
*/
uint32_t SPI_GetIntFlag(SPI_T *spi, uint32_t u32Mask)
{
uint32_t u32IntFlag = 0;
/* Check unit transfer interrupt flag */
if((u32Mask & SPI_UNIT_INT_MASK) && (spi->CNTRL & SPI_CNTRL_IF_Msk))
u32IntFlag |= SPI_UNIT_INT_MASK;
/* Check slave 3-wire mode start interrupt flag */
if((u32Mask & SPI_SSTA_INT_MASK) && (spi->CNTRL2 & SPI_CNTRL2_SLV_START_INTSTS_Msk))
u32IntFlag |= SPI_SSTA_INT_MASK;
/* Check TX threshold interrupt flag */
if((u32Mask & SPI_FIFO_TX_INT_MASK) && (spi->STATUS & SPI_STATUS_TX_INTSTS_Msk))
u32IntFlag |= SPI_FIFO_TX_INT_MASK;
/* Check RX threshold interrupt flag */
if((u32Mask & SPI_FIFO_RX_INT_MASK) && (spi->STATUS & SPI_STATUS_RX_INTSTS_Msk))
u32IntFlag |= SPI_FIFO_RX_INT_MASK;
/* Check RX overrun interrupt flag */
if((u32Mask & SPI_FIFO_RXOV_INT_MASK) && (spi->STATUS & SPI_STATUS_RX_OVERRUN_Msk))
u32IntFlag |= SPI_FIFO_RXOV_INT_MASK;
/* Check RX time-out interrupt flag */
if((u32Mask & SPI_FIFO_TIMEOUT_INT_MASK) && (spi->STATUS & SPI_STATUS_TIMEOUT_Msk))
u32IntFlag |= SPI_FIFO_TIMEOUT_INT_MASK;
return u32IntFlag;
}
/**
* @brief Clear interrupt flag.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Mask The combination of all related interrupt sources.
* Each bit corresponds to a interrupt source.
* This parameter decides which interrupt flags will be cleared.
* (SPI_UNIT_INT_MASK, SPI_SSTA_INT_MASK,
* SPI_FIFO_RXOV_INT_MASK, SPI_FIFO_TIMEOUT_INT_MASK)
* @return None
* @details Clear SPI related interrupt flags specified by u32Mask parameter.
*/
void SPI_ClearIntFlag(SPI_T *spi, uint32_t u32Mask)
{
if(u32Mask & SPI_UNIT_INT_MASK)
spi->CNTRL |= SPI_CNTRL_IF_Msk; /* Clear unit transfer interrupt flag */
if(u32Mask & SPI_SSTA_INT_MASK)
spi->CNTRL2 |= SPI_CNTRL2_SLV_START_INTSTS_Msk; /* Clear slave 3-wire mode start interrupt flag */
if(u32Mask & SPI_FIFO_RXOV_INT_MASK)
spi->STATUS = SPI_STATUS_RX_OVERRUN_Msk; /* Clear RX overrun interrupt flag */
if(u32Mask & SPI_FIFO_TIMEOUT_INT_MASK)
spi->STATUS = SPI_STATUS_TIMEOUT_Msk; /* Clear RX time-out interrupt flag */
}
/**
* @brief Get SPI status.
* @param[in] spi The pointer of the specified SPI module.
* @param[in] u32Mask The combination of all related sources.
* Each bit corresponds to a source.
* This parameter decides which flags will be read.
* (SPI_BUSY_MASK, SPI_RX_EMPTY_MASK, SPI_RX_FULL_MASK,
* SPI_TX_EMPTY_MASK, SPI_TX_FULL_MASK)
* @return Flags of selected sources.
* @details Get SPI related status specified by u32Mask parameter.
*/
uint32_t SPI_GetStatus(SPI_T *spi, uint32_t u32Mask)
{
uint32_t u32Flag = 0;
/* Check busy status */
if((u32Mask & SPI_BUSY_MASK) && (spi->CNTRL & SPI_CNTRL_GO_BUSY_Msk))
u32Flag |= SPI_BUSY_MASK;
/* Check RX empty flag */
if((u32Mask & SPI_RX_EMPTY_MASK) && (spi->CNTRL & SPI_CNTRL_RX_EMPTY_Msk))
u32Flag |= SPI_RX_EMPTY_MASK;
/* Check RX full flag */
if((u32Mask & SPI_RX_FULL_MASK) && (spi->CNTRL & SPI_CNTRL_RX_FULL_Msk))
u32Flag |= SPI_RX_FULL_MASK;
/* Check TX empty flag */
if((u32Mask & SPI_TX_EMPTY_MASK) && (spi->CNTRL & SPI_CNTRL_TX_EMPTY_Msk))
u32Flag |= SPI_TX_EMPTY_MASK;
/* Check TX full flag */
if((u32Mask & SPI_TX_FULL_MASK) && (spi->CNTRL & SPI_CNTRL_TX_FULL_Msk))
u32Flag |= SPI_TX_FULL_MASK;
return u32Flag;
}
/*@}*/ /* end of group SPI_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group SPI_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

205
NUC123/StdDriver/src/sys.c Normal file
View File

@ -0,0 +1,205 @@
/**************************************************************************//**
* @file sys.c
* @version V3.00
* $Revision: 7 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series SYS driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup SYS_Driver SYS Driver
@{
*/
/** @addtogroup SYS_EXPORTED_FUNCTIONS SYS Exported Functions
@{
*/
/**
* @brief Clear reset source
* @param[in] u32Src is system reset source. Including :
* - \ref SYS_RSTSRC_RSTS_CPU_Msk
* - \ref SYS_RSTSRC_RSTS_SYS_Msk
* - \ref SYS_RSTSRC_RSTS_BOD_Msk
* - \ref SYS_RSTSRC_RSTS_LVR_Msk
* - \ref SYS_RSTSRC_RSTS_WDT_Msk
* - \ref SYS_RSTSRC_RSTS_RESET_Msk
* - \ref SYS_RSTSRC_RSTS_POR_Msk
* @return None
* @details This function clear the selected system reset source.
*/
void SYS_ClearResetSrc(uint32_t u32Src)
{
SYS->RSTSRC |= u32Src;
}
/**
* @brief Get Brown-out detector output status
* @param None
* @retval 0 System voltage is higher than BOD_VL setting or BOD_EN is 0.
* @retval 1 System voltage is lower than BOD_VL setting.
* @details This function get Brown-out detector output status.
*/
uint32_t SYS_GetBODStatus(void)
{
return (SYS->BODCR & SYS_BODCR_BOD_OUT_Msk) ? 1 : 0;
}
/**
* @brief Get reset status register value
* @param None
* @return Reset source
* @details This function get the system reset status register value.
*/
uint32_t SYS_GetResetSrc(void)
{
return (SYS->RSTSRC);
}
/**
* @brief Check if register lock is set
* @param None
* @retval 0 Write-protection function is disabled.
* @retval 1 Write-protection function is enabled.
* @details This function check register write-protection bit setting.
*/
uint32_t SYS_IsRegLocked(void)
{
return !(SYS->REGWRPROT & SYS_REGWRPROT_REGPROTDIS_Msk);
}
/**
* @brief Get product ID
* @param None
* @return Product ID
* @details This function get product ID.
*/
uint32_t SYS_ReadPDID(void)
{
return SYS->PDID;
}
/**
* @brief Reset chip with chip reset
* @param None
* @return None
* @details This function reset chip with chip reset.
* The register write-protection function should be disabled before using this function.
*/
void SYS_ResetChip(void)
{
SYS->IPRSTC1 |= SYS_IPRSTC1_CHIP_RST_Msk;
}
/**
* @brief Reset chip with CPU reset
* @param None
* @return None
* @details This function reset CPU with CPU reset.
* The register write-protection function should be disabled before using this function.
*/
void SYS_ResetCPU(void)
{
SYS->IPRSTC1 |= SYS_IPRSTC1_CPU_RST_Msk;
}
/**
* @brief Reset Module
* @param[in] u32ModuleIndex is module index. Including :
* - \ref PDMA_RST
* - \ref GPIO_RST
* - \ref TMR0_RST
* - \ref TMR1_RST
* - \ref TMR2_RST
* - \ref TMR3_RST
* - \ref I2C0_RST
* - \ref I2C1_RST
* - \ref SPI0_RST
* - \ref SPI1_RST
* - \ref SPI2_RST
* - \ref UART0_RST
* - \ref UART1_RST
* - \ref PWM03_RST
* - \ref PS2_RST
* - \ref USBD_RST
* - \ref ADC_RST
* - \ref I2S_RST
* @return None
* @details This function reset selected modules.
*/
void SYS_ResetModule(uint32_t u32ModuleIndex)
{
/* Generate reset signal to the corresponding module */
*(volatile uint32_t *)((uint32_t)&SYS->IPRSTC1 + (u32ModuleIndex >> 24)) |= 1 << (u32ModuleIndex & 0x00ffffff);
/* Release corresponding module from reset state */
*(volatile uint32_t *)((uint32_t)&SYS->IPRSTC1 + (u32ModuleIndex >> 24)) &= ~(1 << (u32ModuleIndex & 0x00ffffff));
}
/**
* @brief Enable and set Brown-out detector function
* @param[in] i32Mode is reset or interrupt mode. Including :
* - \ref SYS_BODCR_BOD_RST_EN
* - \ref SYS_BODCR_BOD_INTERRUPT_EN
* @param[in] u32BODLevel is Brown-out voltage level. Including :
* - \ref SYS_BODCR_BOD_VL_4_5V
* - \ref SYS_BODCR_BOD_VL_3_8V
* - \ref SYS_BODCR_BOD_VL_2_7V
* - \ref SYS_BODCR_BOD_VL_2_2V
* @return None
* @details This function configure Brown-out detector reset or interrupt mode, enable Brown-out function and set Brown-out voltage level.
* The register write-protection function should be disabled before using this function.
*
*/
void SYS_EnableBOD(int32_t i32Mode, uint32_t u32BODLevel)
{
/* Enable Brown-out Detector function */
SYS->BODCR |= SYS_BODCR_BOD_EN_Msk;
/* Enable Brown-out interrupt or reset function */
SYS->BODCR = (SYS->BODCR & ~SYS_BODCR_BOD_RSTEN_Msk) | i32Mode;
/* Select Brown-out Detector threshold voltage */
SYS->BODCR = (SYS->BODCR & ~SYS_BODCR_BOD_VL_Msk) | u32BODLevel;
}
/**
* @brief Disable Brown-out detector function
* @param None
* @return None
* @details This function disable Brown-out detector function.
* The register write-protection function should be disabled before using this function.
*/
void SYS_DisableBOD(void)
{
SYS->BODCR &= ~SYS_BODCR_BOD_EN_Msk;
}
/*@}*/ /* end of group SYS_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group SYS_Driver */
/*@}*/ /* end of group Standard_Driver */
#ifdef __cplusplus
}
#endif
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

View File

@ -0,0 +1,269 @@
/**************************************************************************//**
* @file timer.c
* @version V3.00
* $Revision: 6 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series Timer driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup TIMER_Driver TIMER Driver
@{
*/
/** @addtogroup TIMER_EXPORTED_FUNCTIONS TIMER Exported Functions
@{
*/
/**
* @brief Open Timer in specified mode and frequency
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32Mode Operation mode. Possible options are
* - \ref TIMER_ONESHOT_MODE
* - \ref TIMER_PERIODIC_MODE
* - \ref TIMER_TOGGLE_MODE
* - \ref TIMER_CONTINUOUS_MODE
* @param[in] u32Freq Target working frequency
*
* @return Real Timer working frequency
*
* @details This API is used to configure timer to operate in specified mode and frequency.
* If timer cannot work in target frequency, a closest frequency will be chose and returned.
* @note After calling this API, Timer is \b NOT running yet. But could start timer running be calling
* \ref TIMER_Start macro or program registers directly.
*/
uint32_t TIMER_Open(TIMER_T *timer, uint32_t u32Mode, uint32_t u32Freq)
{
uint32_t u32Clk = TIMER_GetModuleClock(timer);
uint32_t u32Cmpr = 0UL, u32Prescale = 0UL;
/* Fastest possible timer working freq is (u32Clk / 2). While cmpr = 2, prescaler = 0. */
if(u32Freq > (u32Clk / 2UL))
{
u32Cmpr = 2UL;
}
else
{
u32Cmpr = u32Clk / u32Freq;
u32Prescale = (u32Cmpr >> 24); /* for 24 bits CMPDAT */
if (u32Prescale > 0UL)
u32Cmpr = u32Cmpr / (u32Prescale + 1UL);
}
timer->TCSR = u32Mode | u32Prescale;
timer->TCMPR = u32Cmpr;
return(u32Clk / (u32Cmpr * (u32Prescale + 1)));
}
/**
* @brief Stop Timer Counting
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This API stops Timer counting and disable all Timer interrupt function.
*/
void TIMER_Close(TIMER_T *timer)
{
timer->TCSR = 0;
timer->TEXCON = 0;
}
/**
* @brief Create a specify delay time
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32Usec Delay period in micro seconds. Valid values are between 100~1000000 (100 micro second ~ 1 second).
*
* @return None
*
* @details This API is used to create a delay loop for u32usec micro seconds.
* @note This API overwrites the register setting of the timer used to count the delay time.
* @note This API use polling mode. So there is no need to enable interrupt for the timer module used to generate delay.
*/
void TIMER_Delay(TIMER_T *timer, uint32_t u32Usec)
{
uint32_t u32Clk = TIMER_GetModuleClock(timer);
uint32_t u32Prescale = 0UL, u32Delay = (SystemCoreClock / u32Clk) + 1UL;
uint32_t u32Cmpr, u32NsecPerTick;
/* Clear current timer configuration */
timer->TCSR = 0UL;
timer->TEXCON = 0UL;
if(u32Clk <= 1000000UL) /* min delay is 1000 us if timer clock source is <= 1 MHz */
{
if(u32Usec < 1000UL)
{
u32Usec = 1000UL;
}
if(u32Usec > 1000000UL)
{
u32Usec = 1000000UL;
}
}
else
{
if(u32Usec < 100UL)
{
u32Usec = 100UL;
}
if(u32Usec > 1000000UL)
{
u32Usec = 1000000UL;
}
}
if(u32Clk <= 1000000UL)
{
u32Prescale = 0UL;
u32NsecPerTick = 1000000000UL / u32Clk;
u32Cmpr = (u32Usec * 1000UL) / u32NsecPerTick;
}
else
{
u32Cmpr = u32Usec * (u32Clk / 1000000UL);
u32Prescale = (u32Cmpr >> 24); /* for 24 bits CMPDAT */
if (u32Prescale > 0UL)
u32Cmpr = u32Cmpr / (u32Prescale + 1UL);
}
timer->TCMPR = u32Cmpr;
timer->TCSR = TIMER_TCSR_CEN_Msk | TIMER_ONESHOT_MODE | u32Prescale;
/*
When system clock is faster than timer clock, it is possible timer active bit cannot set in time while we check it.
And the while loop below return immediately, so put a tiny delay here allowing timer start counting and raise active flag.
*/
for(; u32Delay > 0; u32Delay--)
{
__NOP();
}
while(timer->TCSR & TIMER_TCSR_CACT_Msk);
}
/**
* @brief Enable Timer Capture Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32CapMode Timer capture mode. Could be
* - \ref TIMER_CAPTURE_FREE_COUNTING_MODE
* - \ref TIMER_CAPTURE_COUNTER_RESET_MODE
* @param[in] u32Edge Timer capture edge. Possible values are
* - \ref TIMER_CAPTURE_FALLING_EDGE
* - \ref TIMER_CAPTURE_RISING_EDGE
* - \ref TIMER_CAPTURE_FALLING_AND_RISING_EDGE
*
* @return None
*
* @details This API is used to enable timer capture function with specified mode and capture edge.
* @note Timer frequency should be configured separately by using \ref TIMER_Open API, or program registers directly.
*/
void TIMER_EnableCapture(TIMER_T *timer, uint32_t u32CapMode, uint32_t u32Edge)
{
timer->TEXCON = (timer->TEXCON & ~(TIMER_TEXCON_RSTCAPSEL_Msk |
TIMER_TEXCON_TEX_EDGE_Msk)) |
u32CapMode | u32Edge | TIMER_TEXCON_TEXEN_Msk;
}
/**
* @brief Disable Timer Capture Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This API is used to disable the Timer capture function.
*/
void TIMER_DisableCapture(TIMER_T *timer)
{
timer->TEXCON &= ~TIMER_TEXCON_TEXEN_Msk;
}
/**
* @brief Enable Timer Counter Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
* @param[in] u32Edge Detection edge of counter pin. Could be ether
* - \ref TIMER_COUNTER_FALLING_EDGE, or
* - \ref TIMER_COUNTER_RISING_EDGE
*
* @return None
*
* @details This function is used to enable the Timer counter function with specify detection edge.
* @note Timer compare value should be configured separately by using \ref TIMER_SET_CMP_VALUE macro or program registers directly.
* @note While using event counter function, \ref TIMER_TOGGLE_MODE cannot set as timer operation mode.
*/
void TIMER_EnableEventCounter(TIMER_T *timer, uint32_t u32Edge)
{
timer->TEXCON = (timer->TEXCON & ~TIMER_TEXCON_TX_PHASE_Msk) | u32Edge;
timer->TCSR |= TIMER_TCSR_CTB_Msk;
}
/**
* @brief Disable Timer Counter Function
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return None
*
* @details This API is used to disable the Timer event counter function.
*/
void TIMER_DisableEventCounter(TIMER_T *timer)
{
timer->TCSR &= ~TIMER_TCSR_CTB_Msk;
}
/**
* @brief Get Timer Clock Frequency
*
* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3.
*
* @return Timer clock frequency
*
* @details This API is used to get the clock frequency of Timer.
* @note This API cannot return correct clock rate if timer source is external clock input.
*/
uint32_t TIMER_GetModuleClock(TIMER_T *timer)
{
uint32_t u32Src;
const uint32_t au32Clk[] = {__HXT, 0, 0, 0, 0, __LIRC, 0, __HIRC};
if(timer == TIMER0)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR0_S_Msk) >> CLK_CLKSEL1_TMR0_S_Pos;
else if(timer == TIMER1)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR1_S_Msk) >> CLK_CLKSEL1_TMR1_S_Pos;
else if(timer == TIMER2)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR2_S_Msk) >> CLK_CLKSEL1_TMR2_S_Pos;
else // Timer 3
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR3_S_Msk) >> CLK_CLKSEL1_TMR3_S_Pos;
if(u32Src == 2)
{
return(SystemCoreClock);
}
return(au32Clk[u32Src]);
}
/*@}*/ /* end of group TIMER_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group TIMER_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

453
NUC123/StdDriver/src/uart.c Normal file
View File

@ -0,0 +1,453 @@
/**************************************************************************//**
* @file uart.c
* @version V3.00
* $Revision: 11 $
* $Date: 16/03/04 9:22a $
* @brief NUC123 series UART driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup UART_Driver UART Driver
@{
*/
/** @addtogroup UART_EXPORTED_FUNCTIONS UART Exported Functions
@{
*/
/**
* @brief Clear UART specified interrupt flag
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module.
* - UART_ISR_BUF_ERR_INT_Msk : Buffer Error interrupt
* - UART_ISR_MODEM_INT_Msk : Modem interrupt
* - UART_ISR_RLS_INT_Msk : Rx Line status interrupt
*
* @return None
*
* @details The function is used to clear UART specified interrupt flag.
*/
void UART_ClearIntFlag(UART_T* uart , uint32_t u32InterruptFlag)
{
if(u32InterruptFlag & UART_ISR_RLS_INT_Msk) /* clear Receive Line Status Interrupt */
{
uart->FSR = UART_FSR_BIF_Msk | UART_FSR_FEF_Msk | UART_FSR_PEF_Msk;
uart->FSR = UART_FSR_RS485_ADD_DETF_Msk;
}
if(u32InterruptFlag & UART_ISR_MODEM_INT_Msk) /* clear Modem Interrupt */
uart->MSR |= UART_MSR_DCTSF_Msk;
if(u32InterruptFlag & UART_ISR_BUF_ERR_INT_Msk) /* clear Buffer Error Interrupt */
{
uart->FSR = UART_FSR_RX_OVER_IF_Msk | UART_FSR_TX_OVER_IF_Msk;
}
}
/**
* @brief Disable UART interrupt
*
* @param[in] uart The pointer of the specified UART module.
*
* @return None
*
* @details The function is used to disable UART interrupt.
*/
void UART_Close(UART_T* uart)
{
uart->IER = 0;
}
/**
* @brief Disable UART auto flow control function
*
* @param[in] uart The pointer of the specified UART module.
*
* @return None
*
* @details The function is used to disable UART auto flow control.
*/
void UART_DisableFlowCtrl(UART_T* uart)
{
uart->IER &= ~(UART_IER_AUTO_RTS_EN_Msk | UART_IER_AUTO_CTS_EN_Msk);
}
/**
* @brief Disable UART specified interrupt
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module.
* - UART_IER_WAKE_EN_Msk : Wakeup interrupt
* - UART_IER_BUF_ERR_IEN_Msk : Buffer Error interrupt
* - UART_IER_RTO_IEN_Msk : Rx time-out interrupt
* - UART_IER_MODEM_IEN_Msk : Modem interrupt
* - UART_IER_RLS_IEN_Msk : Rx Line status interrupt
* - UART_IER_THRE_IEN_Msk : Tx empty interrupt
* - UART_IER_RDA_IEN_Msk : Rx ready interrupt
*
* @return None
*
* @details The function is used to disable UART specified interrupt and disable NVIC UART IRQ.
*/
void UART_DisableInt(UART_T* uart, uint32_t u32InterruptFlag)
{
/* Disable UART specified interrupt */
UART_DISABLE_INT(uart, u32InterruptFlag);
/* Disable NVIC UART IRQ */
if(uart == UART0)
NVIC_DisableIRQ(UART0_IRQn);
else
NVIC_DisableIRQ(UART1_IRQn);
}
/**
* @brief Enable UART auto flow control function
*
* @param[in] uart The pointer of the specified UART module.
*
* @return None
*
* @details The function is used to enable UART auto flow control.
*/
void UART_EnableFlowCtrl(UART_T* uart)
{
/* Set RTS pin output is low level active */
uart->MCR |= UART_MCR_LEV_RTS_Msk;
/* Set CTS pin input is low level active */
uart->MSR |= UART_MSR_LEV_CTS_Msk;
/* Set RTS and CTS auto flow control enable */
uart->IER |= UART_IER_AUTO_RTS_EN_Msk | UART_IER_AUTO_CTS_EN_Msk;
}
/**
* @brief Enable UART specified interrupt
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32InterruptFlag The specified interrupt of UART module:
* - UART_IER_WAKE_EN_Msk : Wakeup interrupt
* - UART_IER_BUF_ERR_IEN_Msk : Buffer Error interrupt
* - UART_IER_RTO_IEN_Msk : Rx time-out interrupt
* - UART_IER_MODEM_IEN_Msk : Modem interrupt
* - UART_IER_RLS_IEN_Msk : Rx Line status interrupt
* - UART_IER_THRE_IEN_Msk : Tx empty interrupt
* - UART_IER_RDA_IEN_Msk : Rx ready interrupt
*
* @return None
*
* @details The function is used to enable UART specified interrupt and enable NVIC UART IRQ.
*/
void UART_EnableInt(UART_T* uart, uint32_t u32InterruptFlag)
{
/* Enable UART specified interrupt */
UART_ENABLE_INT(uart, u32InterruptFlag);
/* Enable NVIC UART IRQ */
if(uart == UART0)
NVIC_EnableIRQ(UART0_IRQn);
else
NVIC_EnableIRQ(UART1_IRQn);
}
/**
* @brief Open and set UART function
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32baudrate The baudrate of UART module.
*
* @return None
*
* @details This function use to enable UART function and set baud-rate.
*/
void UART_Open(UART_T* uart, uint32_t u32baudrate)
{
uint8_t u8UartClkSrcSel, u8UartClkDivNum;
uint32_t u32ClkTbl[4] = {__HXT, 0, 0, __HIRC};
uint32_t u32Baud_Div = 0;
/* Get UART clock source selection */
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UART_S_Msk) >> CLK_CLKSEL1_UART_S_Pos;
/* Get UART clock divider number */
u8UartClkDivNum = (CLK->CLKDIV & CLK_CLKDIV_UART_N_Msk) >> CLK_CLKDIV_UART_N_Pos;
/* Select UART function */
uart->FUN_SEL = UART_FUNC_SEL_UART;
/* Set UART line configuration */
uart->LCR = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
/* Set UART Rx and RTS trigger level */
uart->FCR &= ~(UART_FCR_RFITL_Msk | UART_FCR_RTS_TRI_LEV_Msk);
/* Get PLL clock frequency if UART clock source selection is PLL */
if(u8UartClkSrcSel == 1)
u32ClkTbl[u8UartClkSrcSel] = CLK_GetPLLClockFreq();
/* Set UART baud rate */
if(u32baudrate != 0)
{
u32Baud_Div = UART_BAUD_MODE2_DIVIDER((u32ClkTbl[u8UartClkSrcSel]) / (u8UartClkDivNum + 1), u32baudrate);
if(u32Baud_Div > 0xFFFF)
uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER((u32ClkTbl[u8UartClkSrcSel]) / (u8UartClkDivNum + 1), u32baudrate));
else
uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
}
}
/**
* @brief Read UART data
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] pu8RxBuf The buffer to receive the data of receive FIFO.
* @param[in] u32ReadBytes The read bytes number of data.
*
* @return u32Count Receive byte count
*
* @details The function is used to read Rx data from RX FIFO and the data will be stored in pu8RxBuf.
*/
uint32_t UART_Read(UART_T* uart, uint8_t *pu8RxBuf, uint32_t u32ReadBytes)
{
uint32_t u32Count, u32delayno;
for(u32Count = 0; u32Count < u32ReadBytes; u32Count++)
{
u32delayno = 0;
while(uart->FSR & UART_FSR_RX_EMPTY_Msk) /* Check RX empty => failed */
{
u32delayno++;
if(u32delayno >= 0x40000000)
return u32Count;
}
pu8RxBuf[u32Count] = uart->RBR; /* Get Data from UART RX */
}
return u32Count;
}
/**
* @brief Set UART line configuration
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32baudrate The baudrate of UART module.
* If u32baudrate = 0, UART baudrate will not change.
* @param[in] u32data_width The data length of UART module.
* - UART_WORD_LEN_5
* - UART_WORD_LEN_6
* - UART_WORD_LEN_7
* - UART_WORD_LEN_8
* @param[in] u32parity The parity setting (none/odd/even/mark/space) of UART module.
* - UART_PARITY_NONE
* - UART_PARITY_ODD
* - UART_PARITY_EVEN
* - UART_PARITY_MARK
* - UART_PARITY_SPACE
* @param[in] u32stop_bits The stop bit length (1/1.5/2 bit) of UART module.
* - UART_STOP_BIT_1
* - UART_STOP_BIT_1_5
* - UART_STOP_BIT_2
*
* @return None
*
* @details This function use to config UART line setting.
*/
void UART_SetLine_Config(UART_T* uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits)
{
uint8_t u8UartClkSrcSel, u8UartClkDivNum;
uint32_t u32ClkTbl[4] = {__HXT, 0, 0, __HIRC};
uint32_t u32Baud_Div = 0;
/* Get UART clock source selection */
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UART_S_Msk) >> CLK_CLKSEL1_UART_S_Pos;
/* Get UART clock divider number */
u8UartClkDivNum = (CLK->CLKDIV & CLK_CLKDIV_UART_N_Msk) >> CLK_CLKDIV_UART_N_Pos;
/* Get PLL clock frequency if UART clock source selection is PLL */
if(u8UartClkSrcSel == 1)
u32ClkTbl[u8UartClkSrcSel] = CLK_GetPLLClockFreq();
/* Set UART baud rate */
if(u32baudrate != 0)
{
u32Baud_Div = UART_BAUD_MODE2_DIVIDER((u32ClkTbl[u8UartClkSrcSel]) / (u8UartClkDivNum + 1), u32baudrate);
if(u32Baud_Div > 0xFFFF)
uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER((u32ClkTbl[u8UartClkSrcSel]) / (u8UartClkDivNum + 1), u32baudrate));
else
uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
}
/* Set UART line configuration */
uart->LCR = u32data_width | u32parity | u32stop_bits;
}
/**
* @brief Set Rx timeout count
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32TOC Rx timeout counter.
*
* @return None
*
* @details This function use to set Rx timeout count.
*/
void UART_SetTimeoutCnt(UART_T* uart, uint32_t u32TOC)
{
/* Set time-out interrupt comparator */
uart->TOR = (uart->TOR & ~UART_TOR_TOIC_Msk) | (u32TOC);
/* Set time-out counter enable */
uart->IER |= UART_IER_TIME_OUT_EN_Msk;
}
/**
* @brief Select and configure IrDA function
*
* @param[in] uart The pointer of the specified UART module
* @param[in] u32Buadrate The baudrate of UART module.
* @param[in] u32Direction The direction of UART module in IrDA mode:
* - UART_IRCR_TX_SELECT
* - UART_IRCR_RX_SELECT
*
* @return None
*
* @details The function is used to configure IrDA relative settings. It consists of TX or RX mode and baudrate.
*/
void UART_SelectIrDAMode(UART_T* uart, uint32_t u32Buadrate, uint32_t u32Direction)
{
uint8_t u8UartClkSrcSel, u8UartClkDivNum;
uint32_t u32ClkTbl[4] = {__HXT, 0, 0, __HIRC};
uint32_t u32Baud_Div;
/* Select IrDA function mode */
uart->FUN_SEL = UART_FUNC_SEL_IrDA;
/* Get UART clock source selection */
u8UartClkSrcSel = (CLK->CLKSEL1 & CLK_CLKSEL1_UART_S_Msk) >> CLK_CLKSEL1_UART_S_Pos;
/* Get UART clock divider number */
u8UartClkDivNum = (CLK->CLKDIV & CLK_CLKDIV_UART_N_Msk) >> CLK_CLKDIV_UART_N_Pos;
/* Get PLL clock frequency if UART clock source selection is PLL */
if(u8UartClkSrcSel == 1)
u32ClkTbl[u8UartClkSrcSel] = CLK_GetPLLClockFreq();
/* Set UART IrDA baud rate in mode 0 */
if(u32Buadrate != 0)
{
u32Baud_Div = UART_BAUD_MODE0_DIVIDER((u32ClkTbl[u8UartClkSrcSel]) / (u8UartClkDivNum + 1), u32Buadrate);
if(u32Baud_Div < 0xFFFF)
uart->BAUD = (UART_BAUD_MODE0 | u32Baud_Div);
}
/* Configure IrDA relative settings */
if(u32Direction == UART_IRCR_RX_SELECT)
{
uart->IRCR |= UART_IRCR_INV_RX_Msk; //Rx signal is inverse
uart->IRCR &= ~UART_IRCR_TX_SELECT_Msk;
}
else
{
uart->IRCR &= ~UART_IRCR_INV_TX_Msk; //Tx signal is not inverse
uart->IRCR |= UART_IRCR_TX_SELECT_Msk;
}
}
/**
* @brief Select and configure RS485 function
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] u32Mode The operation mode(NMM/AUD/AAD).
* - UART_ALT_CSR_RS485_NMM_Msk
* - UART_ALT_CSR_RS485_AUD_Msk
* - UART_ALT_CSR_RS485_AAD_Msk
* @param[in] u32Addr The RS485 address.
*
* @return None
*
* @details The function is used to set RS485 relative setting.
*/
void UART_SelectRS485Mode(UART_T* uart, uint32_t u32Mode, uint32_t u32Addr)
{
/* Select UART RS485 function mode */
uart->FUN_SEL = UART_FUNC_SEL_RS485;
/* Set RS485 configuration */
uart->ALT_CSR &= ~(UART_ALT_CSR_RS485_NMM_Msk | UART_ALT_CSR_RS485_AUD_Msk | UART_ALT_CSR_RS485_AAD_Msk | UART_ALT_CSR_ADDR_MATCH_Msk);
uart->ALT_CSR |= (u32Mode | (u32Addr << UART_ALT_CSR_ADDR_MATCH_Pos));
}
/**
* @brief Write UART data
*
* @param[in] uart The pointer of the specified UART module.
* @param[in] pu8TxBuf The buffer to send the data to UART transmission FIFO.
* @param[out] u32WriteBytes The byte number of data.
*
* @return u32Count transfer byte count
*
* @details The function is to write data into TX buffer to transmit data by UART.
*/
uint32_t UART_Write(UART_T* uart, uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
uint32_t u32Count, u32delayno;
for(u32Count = 0; u32Count != u32WriteBytes; u32Count++)
{
u32delayno = 0;
while(uart->FSR & UART_FSR_TX_FULL_Msk) /* Wait Tx not full or Time-out manner */
{
u32delayno++;
if(u32delayno >= 0x40000000)
return u32Count;
}
uart->THR = pu8TxBuf[u32Count]; /* Send UART Data from buffer */
}
return u32Count;
}
/*@}*/ /* end of group UART_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group UART_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

717
NUC123/StdDriver/src/usbd.c Normal file
View File

@ -0,0 +1,717 @@
/**************************************************************************//**
* @file usbd.c
* @version V3.00
* $Revision: 22 $
* $Date: 15/09/01 3:15p $
* @brief NUC123 series USBD driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "NUC123.h"
#if 0
#define DBG_PRINTF printf
#else
#define DBG_PRINTF(...)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup USBD_Driver USBD Driver
@{
*/
/** @addtogroup USBD_EXPORTED_FUNCTIONS USBD Exported Functions
@{
*/
/* Global variables for Control Pipe */
uint8_t g_usbd_SetupPacket[8] = {0}; /*!< Setup packet buffer */
volatile uint8_t g_usbd_RemoteWakeupEn = 0; /*!< Remote wake up function enable flag */
/**
* @cond HIDDEN_SYMBOLS
*/
static volatile uint8_t *g_usbd_CtrlInPointer = 0;
static volatile uint32_t g_usbd_CtrlInSize = 0;
static volatile uint8_t *g_usbd_CtrlOutPointer = 0;
static volatile uint32_t g_usbd_CtrlOutSize = 0;
static volatile uint32_t g_usbd_CtrlOutSizeLimit = 0;
static volatile uint32_t g_usbd_UsbAddr = 0;
static volatile uint32_t g_usbd_UsbConfig = 0;
static volatile uint32_t g_usbd_CtrlMaxPktSize = 8;
static volatile uint32_t g_usbd_UsbAltInterface = 0;
static volatile uint32_t g_usbd_CtrlOutToggle = 0;
static volatile uint8_t g_usbd_CtrlInZeroFlag = 0;
/**
* @endcond
*/
const S_USBD_INFO_T *g_usbd_sInfo; /*!< A pointer for USB information structure */
VENDOR_REQ g_usbd_pfnVendorRequest = NULL; /*!< USB Vendor Request Functional Pointer */
CLASS_REQ g_usbd_pfnClassRequest = NULL; /*!< USB Class Request Functional Pointer */
SET_INTERFACE_REQ g_usbd_pfnSetInterface = NULL; /*!< USB Set Interface Functional Pointer */
SET_CONFIG_CB g_usbd_pfnSetConfigCallback = NULL; /*!< USB Set configuration callback function pointer */
uint32_t g_u32EpStallLock = 0; /*!< Bit map flag to lock specified EP when SET_FEATURE */
/**
* @brief This function makes USBD module to be ready to use
*
* @param[in] param The structure of USBD information.
* @param[in] pfnClassReq USB Class request callback function.
* @param[in] pfnSetInterface USB Set Interface request callback function.
*
* @return None
*
* @details This function will enable USB controller, USB PHY transceiver and pull-up resistor of USB_D+ pin. USB PHY will drive SE0 to bus.
*/
void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
{
g_usbd_sInfo = param;
g_usbd_pfnClassRequest = pfnClassReq;
g_usbd_pfnSetInterface = pfnSetInterface;
/* get EP0 maximum packet size */
g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7];
/* Initial USB engine */
USBD->ATTR = 0x7D0;
/* Force SE0 */
USBD_SET_SE0();
}
/**
* @brief This function makes USB host to recognize the device
*
* @param None
*
* @return None
*
* @details Enable WAKEUP, FLDET, USB and BUS interrupts. Disable software-disconnect function after 100ms delay with SysTick timer.
*/
void USBD_Start(void)
{
CLK_SysTickDelay(100000);
/* Disable software-disconnect function */
USBD_CLR_SE0();
/* Clear USB-related interrupts before enable interrupt */
USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
/* Enable USB-related interrupts. */
USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
}
/**
* @brief Get the received SETUP packet
*
* @param[in] buf A buffer pointer used to store 8-byte SETUP packet.
*
* @return None
*
* @details Store SETUP packet to a user-specified buffer.
*
*/
void USBD_GetSetupPacket(uint8_t *buf)
{
USBD_MemCopy(buf, g_usbd_SetupPacket, 8);
}
/**
* @brief Process SETUP packet
*
* @param None
*
* @return None
*
* @details Parse SETUP packet and perform the corresponding action.
*
*/
void USBD_ProcessSetupPacket(void)
{
g_usbd_CtrlOutToggle = 0;
/* Get SETUP packet from USB buffer */
USBD_MemCopy(g_usbd_SetupPacket, (uint8_t *)USBD_BUF_BASE, 8);
/* Check the request type */
switch(g_usbd_SetupPacket[0] & 0x60)
{
case REQ_STANDARD: // Standard
{
USBD_StandardRequest();
break;
}
case REQ_CLASS: // Class
{
if(g_usbd_pfnClassRequest != NULL)
{
g_usbd_pfnClassRequest();
}
break;
}
case REQ_VENDOR: // Vendor
{
if(g_usbd_pfnVendorRequest != NULL)
{
g_usbd_pfnVendorRequest();
}
break;
}
default: // reserved
{
/* Setup error, stall the device */
USBD_SET_EP_STALL(EP0);
USBD_SET_EP_STALL(EP1);
break;
}
}
}
/**
* @brief Process GetDescriptor request
*
* @param None
*
* @return None
*
* @details Parse GetDescriptor request and perform the corresponding action.
*
*/
void USBD_GetDescriptor(void)
{
uint32_t u32Len;
g_usbd_CtrlInZeroFlag = (uint8_t)0;
u32Len = 0;
u32Len = g_usbd_SetupPacket[7];
u32Len <<= 8;
u32Len += g_usbd_SetupPacket[6];
switch(g_usbd_SetupPacket[3])
{
// Get Device Descriptor
case DESC_DEVICE:
{
u32Len = Minimum(u32Len, LEN_DEVICE);
DBG_PRINTF("Get device desc, %d\n", u32Len);
USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len);
USBD_PrepareCtrlOut(0, 0);
break;
}
// Get Configuration Descriptor
case DESC_CONFIG:
{
uint32_t u32TotalLen;
u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3];
u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
if(u32Len > u32TotalLen)
{
u32Len = u32TotalLen;
if((u32Len % g_usbd_CtrlMaxPktSize) == 0)
{
g_usbd_CtrlInZeroFlag = (uint8_t)1;
}
}
USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len);
USBD_PrepareCtrlOut(0, 0);
break;
}
// Get HID Descriptor
case DESC_HID:
{
/* CV3.0 HID Class Descriptor Test,
Need to indicate index of the HID Descriptor within gu8ConfigDescriptor, specifically HID Composite device. */
uint32_t u32ConfigDescOffset; // u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index)
u32Len = Minimum(u32Len, LEN_HID);
DBG_PRINTF("Get HID desc, %d\n", u32Len);
u32ConfigDescOffset = g_usbd_sInfo->gu32ConfigHidDescIdx[g_usbd_SetupPacket[4]];
USBD_PrepareCtrlIn((uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
USBD_PrepareCtrlOut(0, 0);
break;
}
// Get Report Descriptor
case DESC_HID_RPT:
{
if(u32Len > g_usbd_sInfo->gu32HidReportSize[g_usbd_SetupPacket[4]])
{
u32Len = g_usbd_sInfo->gu32HidReportSize[g_usbd_SetupPacket[4]];
if((u32Len % g_usbd_CtrlMaxPktSize) == 0)
{
g_usbd_CtrlInZeroFlag = (uint8_t)1;
}
}
USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8HidReportDesc[g_usbd_SetupPacket[4]], u32Len);
USBD_PrepareCtrlOut(0, 0);
break;
}
// Get String Descriptor
case DESC_STRING:
{
// Get String Descriptor
if(g_usbd_SetupPacket[2] < 4)
{
if(u32Len > g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0])
{
u32Len = g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0];
if((u32Len % g_usbd_CtrlMaxPktSize) == 0)
{
g_usbd_CtrlInZeroFlag = (uint8_t)1;
}
}
USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]], u32Len);
USBD_PrepareCtrlOut(0, 0);
break;
}
else
{
// Not support. Reply STALL.
USBD_SET_EP_STALL(EP0);
USBD_SET_EP_STALL(EP1);
DBG_PRINTF("Unsupported string desc (%d). Stall ctrl pipe.\n", g_usbd_SetupPacket[2]);
break;
}
}
default:
// Not support. Reply STALL.
USBD_SET_EP_STALL(EP0);
USBD_SET_EP_STALL(EP1);
DBG_PRINTF("Unsupported get desc type. stall ctrl pipe\n");
break;
}
}
/**
* @brief Process standard request
*
* @param None
*
* @return None
*
* @details Parse standard request and perform the corresponding action.
*
*/
void USBD_StandardRequest(void)
{
/* clear global variables for new request */
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
if(g_usbd_SetupPacket[0] & 0x80) /* request data transfer direction */
{
// Device to host
switch(g_usbd_SetupPacket[1])
{
case GET_CONFIGURATION:
{
// Return current configuration setting
/* Data stage */
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbConfig;
USBD_SET_DATA1(EP1);
USBD_SET_PAYLOAD_LEN(EP1, 0);
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 1);
/* Status stage */
USBD_PrepareCtrlOut(0, 0);
DBG_PRINTF("Get configuration\n");
break;
}
case GET_DESCRIPTOR:
{
USBD_GetDescriptor();
/* Status stage */
USBD_PrepareCtrlOut(0, 0);
DBG_PRINTF("Get descriptor\n");
break;
}
case GET_INTERFACE:
{
// Return current interface setting
/* Data stage */
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbAltInterface;
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 1);
/* Status stage */
USBD_PrepareCtrlOut(0, 0);
DBG_PRINTF("Get interface\n");
break;
}
case GET_STATUS:
{
// Device
if(g_usbd_SetupPacket[0] == 0x80)
{
uint8_t u8Tmp;
u8Tmp = 0;
if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x40) u8Tmp |= 1; // Self-Powered/Bus-Powered.
if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x20) u8Tmp |= (g_usbd_RemoteWakeupEn << 1); // Remote wake up
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = u8Tmp;
}
// Interface
else if(g_usbd_SetupPacket[0] == 0x81)
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = 0;
// Endpoint
else if(g_usbd_SetupPacket[0] == 0x82)
{
uint8_t ep = g_usbd_SetupPacket[4] & 0xF;
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = USBD_GetStall(ep) ? 1 : 0;
}
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0) + 1) = 0;
/* Data stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 2);
/* Status stage */
USBD_PrepareCtrlOut(0, 0);
DBG_PRINTF("Get status\n");
break;
}
default:
{
/* Setup error, stall the device */
USBD_SET_EP_STALL(EP0);
USBD_SET_EP_STALL(EP1);
DBG_PRINTF("Unknown request. stall ctrl pipe.\n");
break;
}
}
}
else
{
// Host to device
switch(g_usbd_SetupPacket[1])
{
case CLEAR_FEATURE:
{
if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
{
int32_t epNum, i;
/* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
a flag: g_u32EpStallLock is added to support it */
epNum = g_usbd_SetupPacket[4] & 0xF;
for(i = 0; i < USBD_MAX_EP; i++)
{
if(((USBD->EP[i].CFG & 0xF) == epNum) && ((g_u32EpStallLock & (1 << i)) == 0))
{
USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
USBD->EP[i].CFG &= ~USBD_CFG_DSQ_SYNC_Msk;
DBG_PRINTF("Clr stall ep%d %x\n", i, USBD->EP[i].CFGP);
}
}
}
else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
g_usbd_RemoteWakeupEn = 0;
/* Status stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 0);
DBG_PRINTF("Clear feature op %d\n", g_usbd_SetupPacket[2]);
break;
}
case SET_ADDRESS:
{
g_usbd_UsbAddr = g_usbd_SetupPacket[2];
DBG_PRINTF("Set addr to %d\n", g_usbd_UsbAddr);
// DATA IN for end of setup
/* Status Stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 0);
break;
}
case SET_CONFIGURATION:
{
g_usbd_UsbConfig = g_usbd_SetupPacket[2];
if(g_usbd_pfnSetConfigCallback)
g_usbd_pfnSetConfigCallback();
// DATA IN for end of setup
/* Status stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 0);
DBG_PRINTF("Set config to %d\n", g_usbd_UsbConfig);
break;
}
case SET_FEATURE:
{
if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
{
USBD_SetStall(g_usbd_SetupPacket[4] & 0xF);
DBG_PRINTF("Set feature. stall ep %d\n", g_usbd_SetupPacket[4] & 0xF);
}
else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
{
g_usbd_RemoteWakeupEn = 1;
DBG_PRINTF("Set feature. enable remote wakeup\n");
}
/* Status stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 0);
break;
}
case SET_INTERFACE:
{
g_usbd_UsbAltInterface = g_usbd_SetupPacket[2];
if(g_usbd_pfnSetInterface != NULL)
g_usbd_pfnSetInterface();
/* Status stage */
USBD_SET_DATA1(EP0);
USBD_SET_PAYLOAD_LEN(EP0, 0);
DBG_PRINTF("Set interface to %d\n", g_usbd_UsbAltInterface);
break;
}
default:
{
/* Setup error, stall the device */
USBD_SET_EP_STALL(EP0);
USBD_SET_EP_STALL(EP1);
DBG_PRINTF("Unsupported request. stall ctrl pipe.\n");
break;
}
}
}
}
/**
* @brief Prepare the first Control IN pipe
*
* @param[in] pu8Buf The pointer of data sent to USB host.
* @param[in] u32Size The IN transfer size.
*
* @return None
*
* @details Prepare data for Control IN transfer.
*
*/
void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size)
{
DBG_PRINTF("Prepare Ctrl In %d\n", u32Size);
if(u32Size > g_usbd_CtrlMaxPktSize)
{
// Data size > MXPLD
g_usbd_CtrlInPointer = pu8Buf + g_usbd_CtrlMaxPktSize;
g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
USBD_SET_DATA1(EP0);
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, g_usbd_CtrlMaxPktSize);
USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
}
else
{
// Data size <= MXPLD
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
USBD_SET_DATA1(EP0);
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, u32Size);
USBD_SET_PAYLOAD_LEN(EP0, u32Size);
}
}
/**
* @brief Repeat Control IN pipe
*
* @param None
*
* @return None
*
* @details This function processes the remained data of Control IN transfer.
*
*/
void USBD_CtrlIn(void)
{
if(g_usbd_CtrlInSize)
{
// Process remained data
if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize)
{
// Data size > MXPLD
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
}
else
{
// Data size <= MXPLD
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize);
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
}
}
else // No more data for IN token
{
// In ACK for Set address
if((g_usbd_SetupPacket[0] == REQ_STANDARD) && (g_usbd_SetupPacket[1] == SET_ADDRESS))
{
if((USBD_GET_ADDR() != g_usbd_UsbAddr) && (USBD_GET_ADDR() == 0))
{
USBD_SET_ADDR(g_usbd_UsbAddr);
}
}
/* For the case of data size is integral times maximum packet size */
if(g_usbd_CtrlInZeroFlag)
{
USBD_SET_PAYLOAD_LEN(EP0, 0);
g_usbd_CtrlInZeroFlag = 0;
}
DBG_PRINTF("Ctrl In done.\n");
}
}
/**
* @brief Prepare the first Control OUT pipe
*
* @param[in] pu8Buf The pointer of data received from USB host.
* @param[in] u32Size The OUT transfer size.
*
* @return None
*
* @details This function is used to prepare the first Control OUT transfer.
*
*/
void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
{
g_usbd_CtrlOutPointer = pu8Buf;
g_usbd_CtrlOutSize = 0;
g_usbd_CtrlOutSizeLimit = u32Size;
USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
}
/**
* @brief Repeat Control OUT pipe
*
* @param None
*
* @return None
*
* @details This function processes the successive Control OUT transfer.
*
*/
void USBD_CtrlOut(void)
{
uint32_t u32Size;
DBG_PRINTF("Ctrl Out Ack %d\n", g_usbd_CtrlOutSize);
if(g_usbd_CtrlOutToggle != (USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk))
{
g_usbd_CtrlOutToggle = USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk;
if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
{
u32Size = USBD_GET_PAYLOAD_LEN(EP1);
USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer, (uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP1), u32Size);
g_usbd_CtrlOutPointer += u32Size;
g_usbd_CtrlOutSize += u32Size;
if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
}
}
else
{
USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
}
}
/**
* @brief Reset software flags
*
* @param None
*
* @return None
*
* @details This function resets all variables for protocol and resets USB device address to 0.
*
*/
void USBD_SwReset(void)
{
int i;
// Reset all variables for protocol
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
g_usbd_CtrlOutPointer = 0;
g_usbd_CtrlOutSize = 0;
g_usbd_CtrlOutSizeLimit = 0;
g_u32EpStallLock = 0;
memset(g_usbd_SetupPacket, 0, 8);
/* Reset PID DATA0 */
for(i=0; i<USBD_MAX_EP; i++)
USBD->EP[i].CFG &= ~USBD_CFG_DSQ_SYNC_Msk;
// Reset USB device address
USBD_SET_ADDR(0);
}
/**
* @brief USBD Set Vendor Request
*
* @param[in] pfnVendorReq Vendor Request Callback Function
*
* @return None
*
* @details This function is used to set USBD vendor request callback function
*/
void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)
{
g_usbd_pfnVendorRequest = pfnVendorReq;
}
/**
* @brief The callback function which called when get SET CONFIGURATION request
*
* @param[in] pfnSetConfigCallback Callback function pointer for SET CONFIGURATION request
*
* @return None
*
* @details This function is used to set the callback function which will be called at SET CONFIGURATION request.
*/
void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
{
g_usbd_pfnSetConfigCallback = pfnSetConfigCallback;
}
/**
* @brief EP stall lock function to avoid stall clear by USB SET FEATURE request.
*
* @param[in] u32EpBitmap Use bitmap to select which endpoints will be locked
*
* @return None
*
* @details This function is used to lock relative endpoint to avoid stall clear by SET FEATURE requst.
* If ep stall locked, user needs to reset USB device or re-configure device to clear it.
*/
void USBD_LockEpStall(uint32_t u32EpBitmap)
{
g_u32EpStallLock = u32EpBitmap;
}
/*@}*/ /* end of group USBD_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group USBD_Driver */
/*@}*/ /* end of group Device_Driver */
#ifdef __cplusplus
}
#endif
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

View File

@ -0,0 +1,71 @@
/**************************************************************************//**
* @file wdt.c
* @version V3.00
* $Revision: 4 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series WDT driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup WDT_Driver WDT Driver
@{
*/
/** @addtogroup WDT_EXPORTED_FUNCTIONS WDT Exported Functions
@{
*/
/**
* @brief Initialize WDT counter and start counting
*
* @param[in] u32TimeoutInterval Time-out interval period of WDT module. Valid values are:
* - \ref WDT_TIMEOUT_2POW4
* - \ref WDT_TIMEOUT_2POW6
* - \ref WDT_TIMEOUT_2POW8
* - \ref WDT_TIMEOUT_2POW10
* - \ref WDT_TIMEOUT_2POW12
* - \ref WDT_TIMEOUT_2POW14
* - \ref WDT_TIMEOUT_2POW16
* - \ref WDT_TIMEOUT_2POW18
* @param[in] u32ResetDelay Configure reset delay period while WDT time-out happened. Valid values are:
* - \ref WDT_RESET_DELAY_1026CLK
* - \ref WDT_RESET_DELAY_130CLK
* - \ref WDT_RESET_DELAY_18CLK
* - \ref WDT_RESET_DELAY_3CLK
* @param[in] u32EnableReset Enable WDT reset system function. Valid values are TRUE and FALSE.
* @param[in] u32EnableWakeup Enable WDT wake-up system function. Valid values are TRUE and FALSE.
*
* @return None
*
* @details This function make WDT module start counting with different time-out interval and reset delay period.
* @note Please make sure that Register Write-Protection Function has been disabled before using this function.
*/
void WDT_Open(uint32_t u32TimeoutInterval,
uint32_t u32ResetDelay,
uint32_t u32EnableReset,
uint32_t u32EnableWakeup)
{
WDT->WTCRALT = u32ResetDelay;
WDT->WTCR = u32TimeoutInterval | WDT_WTCR_WTE_Msk |
(u32EnableReset << WDT_WTCR_WTRE_Pos) |
(u32EnableWakeup << WDT_WTCR_WTWKE_Pos);
return;
}
/*@}*/ /* end of group WDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group WDT_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

View File

@ -0,0 +1,72 @@
/**************************************************************************//**
* @file wwdt.c
* @version V3.00
* $Revision: 3 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 series WWDT driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NUC123.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup WWDT_Driver WWDT Driver
@{
*/
/** @addtogroup WWDT_EXPORTED_FUNCTIONS WWDT Exported Functions
@{
*/
/**
* @brief Open WWDT function to start counting
*
* @param[in] u32PreScale Prescale period for the WWDT counter period. Valid values are:
* - \ref WWDT_PRESCALER_1
* - \ref WWDT_PRESCALER_2
* - \ref WWDT_PRESCALER_4
* - \ref WWDT_PRESCALER_8
* - \ref WWDT_PRESCALER_16
* - \ref WWDT_PRESCALER_32
* - \ref WWDT_PRESCALER_64
* - \ref WWDT_PRESCALER_128
* - \ref WWDT_PRESCALER_192
* - \ref WWDT_PRESCALER_256
* - \ref WWDT_PRESCALER_384
* - \ref WWDT_PRESCALER_512
* - \ref WWDT_PRESCALER_768
* - \ref WWDT_PRESCALER_1024
* - \ref WWDT_PRESCALER_1536
* - \ref WWDT_PRESCALER_2048
* @param[in] u32CmpValue Setting the window compared value. Valid values are between 0x0 to 0x3F.
* @param[in] u32EnableInt Enable WWDT interrupt function. Valid values are TRUE and FALSE.
*
* @return None
*
* @details This function make WWDT module start counting with different counter period and compared window value.
* @note Application can call this function valid only once after boot up.
*/
void WWDT_Open(uint32_t u32PreScale,
uint32_t u32CmpValue,
uint32_t u32EnableInt)
{
WWDT->WWDTCR = u32PreScale |
(u32CmpValue << WWDT_WWDTCR_WINCMP_Pos) |
((u32EnableInt == TRUE) ? WWDT_WWDTCR_WWDTIE_Msk : 0) |
WWDT_WWDTCR_WWDTEN_Msk;
return;
}
/*@}*/ /* end of group WWDT_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group WWDT_Driver */
/*@}*/ /* end of group Standard_Driver */
/*** (C) COPYRIGHT 2014~2015 Nuvoton Technology Corp. ***/

1168
NUC123/_syscalls.c Normal file

File diff suppressed because it is too large Load Diff

8763
NUC123/inc/NUC123.h Normal file

File diff suppressed because it is too large Load Diff

1373
NUC123/inc/cmsis_gcc.h Normal file

File diff suppressed because it is too large Load Diff

798
NUC123/inc/core_cm0.h Normal file
View File

@ -0,0 +1,798 @@
/**************************************************************************//**
* @file core_cm0.h
* @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CM0_H_GENERIC
#define __CORE_CM0_H_GENERIC
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
\page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions
CMSIS violates the following MISRA-C:2004 rules:
\li Required Rule 8.5, object/function definition in header file.<br>
Function definitions in header files are used to allow 'inlining'.
\li Required Rule 18.4, declaration of union type or object of union type: '{...}'.<br>
Unions are used for effective representation of core registers.
\li Advisory Rule 19.7, Function-like macro defined.<br>
Function-like macros are used to allow more efficient code.
*/
/*******************************************************************************
* CMSIS definitions
******************************************************************************/
/**
\ingroup Cortex_M0
@{
*/
/* CMSIS CM0 definitions */
#define __CM0_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */
#define __CM0_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */
#define __CM0_CMSIS_VERSION ((__CM0_CMSIS_VERSION_MAIN << 16U) | \
__CM0_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */
#define __CORTEX_M (0x00U) /*!< Cortex-M Core */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */
#define __STATIC_INLINE static inline
#elif defined ( __TMS470__ )
#define __ASM __asm /*!< asm keyword for TI CCS Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __CSMC__ )
#define __packed
#define __ASM _asm /*!< asm keyword for COSMIC Compiler */
#define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */
#define __STATIC_INLINE static inline
#else
#error Unknown compiler
#endif
/** __FPU_USED indicates whether an FPU is used or not.
This core does not support an FPU at all
*/
#define __FPU_USED 0U
#if defined ( __CC_ARM )
#if defined __TARGET_FPU_VFP
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#if defined __ARM_PCS_VFP
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __GNUC__ )
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __ICCARM__ )
#if defined __ARMVFP__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __TMS470__ )
#if defined __TI_VFP_SUPPORT__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __TASKING__ )
#if defined __FPU_VFP__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __CSMC__ )
#if ( __CSMC__ & 0x400U)
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#endif
#include "core_cmInstr.h" /* Core Instruction Access */
#include "core_cmFunc.h" /* Core Function Access */
#ifdef __cplusplus
}
#endif
#endif /* __CORE_CM0_H_GENERIC */
#ifndef __CMSIS_GENERIC
#ifndef __CORE_CM0_H_DEPENDANT
#define __CORE_CM0_H_DEPENDANT
#ifdef __cplusplus
extern "C" {
#endif
/* check device defines and use defaults */
#if defined __CHECK_DEVICE_DEFINES
#ifndef __CM0_REV
#define __CM0_REV 0x0000U
#warning "__CM0_REV not defined in device header file; using default!"
#endif
#ifndef __NVIC_PRIO_BITS
#define __NVIC_PRIO_BITS 2U
#warning "__NVIC_PRIO_BITS not defined in device header file; using default!"
#endif
#ifndef __Vendor_SysTickConfig
#define __Vendor_SysTickConfig 0U
#warning "__Vendor_SysTickConfig not defined in device header file; using default!"
#endif
#endif
/* IO definitions (access restrictions to peripheral registers) */
/**
\defgroup CMSIS_glob_defs CMSIS Global Defines
<strong>IO Type Qualifiers</strong> are used
\li to specify the access to peripheral variables.
\li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
/*@} end of group Cortex_M0 */
/*******************************************************************************
* Register Abstraction
Core Register contain:
- Core Register
- Core NVIC Register
- Core SCB Register
- Core SysTick Register
******************************************************************************/
/**
\defgroup CMSIS_core_register Defines and Type Definitions
\brief Type definitions and defines for Cortex-M processor based devices.
*/
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_CORE Status and Control Registers
\brief Core Register type definitions.
@{
*/
/**
\brief Union type to access the Application Program Status Register (APSR).
*/
typedef union
{
struct
{
uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} APSR_Type;
/* APSR Register Definitions */
#define APSR_N_Pos 31U /*!< APSR: N Position */
#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */
#define APSR_Z_Pos 30U /*!< APSR: Z Position */
#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */
#define APSR_C_Pos 29U /*!< APSR: C Position */
#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */
#define APSR_V_Pos 28U /*!< APSR: V Position */
#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */
/**
\brief Union type to access the Interrupt Program Status Register (IPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} IPSR_Type;
/* IPSR Register Definitions */
#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */
#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */
/**
\brief Union type to access the Special-Purpose Program Status Registers (xPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */
uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */
uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} xPSR_Type;
/* xPSR Register Definitions */
#define xPSR_N_Pos 31U /*!< xPSR: N Position */
#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */
#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */
#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */
#define xPSR_C_Pos 29U /*!< xPSR: C Position */
#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */
#define xPSR_V_Pos 28U /*!< xPSR: V Position */
#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */
#define xPSR_T_Pos 24U /*!< xPSR: T Position */
#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */
#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */
#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */
/**
\brief Union type to access the Control Registers (CONTROL).
*/
typedef union
{
struct
{
uint32_t _reserved0:1; /*!< bit: 0 Reserved */
uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */
uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} CONTROL_Type;
/* CONTROL Register Definitions */
#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */
#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */
/*@} end of group CMSIS_CORE */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
\brief Type definitions for the NVIC Registers
@{
*/
/**
\brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
typedef struct
{
__IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[31U];
__IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[31U];
__IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[31U];
__IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[31U];
uint32_t RESERVED4[64U];
__IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
/*@} end of group CMSIS_NVIC */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_SCB System Control Block (SCB)
\brief Type definitions for the System Control Block Registers
@{
*/
/**
\brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
uint32_t RESERVED0;
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
uint32_t RESERVED1;
__IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
} SCB_Type;
/* SCB CPUID Register Definitions */
#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */
#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */
#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */
#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */
#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */
#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */
#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */
#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */
#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */
#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */
/* SCB Interrupt Control State Register Definitions */
#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */
#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */
#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */
#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */
#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */
#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */
#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */
#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */
#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */
#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */
#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */
#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */
#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */
/* SCB Application Interrupt and Reset Control Register Definitions */
#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */
#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */
#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */
#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */
#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */
#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */
#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */
#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */
#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */
#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */
/* SCB System Control Register Definitions */
#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */
#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */
#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */
#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */
#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */
#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */
/* SCB Configuration Control Register Definitions */
#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */
#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */
#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */
#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */
/* SCB System Handler Control and State Register Definitions */
#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */
#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */
/*@} end of group CMSIS_SCB */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_SysTick System Tick Timer (SysTick)
\brief Type definitions for the System Timer Registers.
@{
*/
/**
\brief Structure type to access the System Timer (SysTick).
*/
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
/*@} end of group CMSIS_SysTick */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug)
\brief 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.
@{
*/
/*@} end of group CMSIS_CoreDebug */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_core_bitfield Core register bit field macros
\brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk).
@{
*/
/**
\brief Mask and shift a bit field value for use in a register bit range.
\param[in] field Name of the register bit field.
\param[in] value Value of the bit field.
\return Masked and shifted value.
*/
#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk)
/**
\brief Mask and shift a register value to extract a bit filed value.
\param[in] field Name of the register bit field.
\param[in] value Value of register.
\return Masked and shifted bit field value.
*/
#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos)
/*@} end of group CMSIS_core_bitfield */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_core_base Core Definitions
\brief Definitions for base addresses, unions, and structures.
@{
*/
/* Memory mapping of Cortex-M0 Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
/*@} */
/*******************************************************************************
* Hardware Abstraction Layer
Core Function Interface contains:
- Core NVIC Functions
- Core SysTick Functions
- Core Register Access Functions
******************************************************************************/
/**
\defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference
*/
/* ########################## NVIC functions #################################### */
/**
\ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_NVICFunctions NVIC Functions
\brief Functions that manage interrupts and exceptions via the NVIC.
@{
*/
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offset and byte masks */
#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL)
#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) )
#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) )
/**
\brief Enable External Interrupt
\details Enables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Disable External Interrupt
\details Disables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Get Pending Interrupt
\details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt.
\param [in] IRQn Interrupt number.
\return 0 Interrupt status is not pending.
\return 1 Interrupt status is pending.
*/
__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
}
/**
\brief Set Pending Interrupt
\details Sets the pending bit of an external interrupt.
\param [in] IRQn Interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Clear Pending Interrupt
\details Clears the pending bit of an external interrupt.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Set Interrupt Priority
\details Sets the priority of an interrupt.
\note The priority cannot be set for every core interrupt.
\param [in] IRQn Interrupt number.
\param [in] priority Priority to set.
*/
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)(IRQn) < 0)
{
SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
else
{
NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
}
/**
\brief Get Interrupt Priority
\details Reads the priority of an interrupt.
The interrupt number can be positive to specify an external (device specific) interrupt,
or negative to specify an internal (core) interrupt.
\param [in] IRQn Interrupt number.
\return Interrupt Priority.
Value is aligned automatically to the implemented priority bits of the microcontroller.
*/
__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) < 0)
{
return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
else
{
return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
}
/**
\brief System Reset
\details Initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
SCB_AIRCR_SYSRESETREQ_Msk);
__DSB(); /* Ensure completion of memory access */
for(;;) /* wait until reset */
{
__NOP();
}
}
/*@} end of CMSIS_Core_NVICFunctions */
/* ################################## SysTick function ############################################ */
/**
\ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_SysTickFunctions SysTick Functions
\brief Functions that configure the System.
@{
*/
#if (__Vendor_SysTickConfig == 0U)
/**
\brief System Tick Configuration
\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
#endif
/*@} end of CMSIS_Core_SysTickFunctions */
#ifdef __cplusplus
}
#endif
#endif /* __CORE_CM0_H_DEPENDANT */
#endif /* __CMSIS_GENERIC */

87
NUC123/inc/core_cmFunc.h Normal file
View File

@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMFUNC_H
#define __CORE_CMFUNC_H
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ TASKING Compiler ------------------*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H */

87
NUC123/inc/core_cmInstr.h Normal file
View File

@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMINSTR_H
#define __CORE_CMINSTR_H
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ TASKING Compiler ------------------*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H */

View File

@ -0,0 +1,66 @@
/**************************************************************************//**
* @file system_NUC123.h
* @version V3.0
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series CMSIS System Header File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#ifndef __SYSTEM_NUC123_H
#define __SYSTEM_NUC123_H
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------------------------------------*/
/* Macro Definition */
/*---------------------------------------------------------------------------------------------------------*/
#ifndef DEBUG_PORT
# define DEBUG_PORT UART0 /*!< Select Debug Port which is used for retarget.c to output debug message to UART */
#endif
/*----------------------------------------------------------------------------
Define SYSCLK
*----------------------------------------------------------------------------*/
#define __HXT (12000000UL) /*!< External Crystal Clock Frequency */
#define __LXT (32768UL) /*!< External Crystal Clock Frequency 32.768KHz */
#define __HIRC (22118400UL) /*!< Internal 22M RC Oscillator Frequency */
#define __LIRC (10000UL) /*!< Internal 10K RC Oscillator Frequency */
#define __HSI (50000000UL) /*!< PLL default output is 50MHz */
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
extern uint32_t CyclesPerUs; /*!< Cycles per micro second */
extern uint32_t PllClock; /*!< PLL Output Clock Frequency */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system
* Initialize GPIO directions and values
*/
extern void SystemInit(void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from CPU registers.
*/
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif

116
NUC123/semihosting.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef ARM_SEMIHOSTING_H_
#define ARM_SEMIHOSTING_H_
// ----------------------------------------------------------------------------
// Semihosting operations.
enum OperationNumber
{
// Regular operations
SEMIHOSTING_EnterSVC = 0x17,
SEMIHOSTING_ReportException = 0x18,
SEMIHOSTING_SYS_CLOSE = 0x02,
SEMIHOSTING_SYS_CLOCK = 0x10,
SEMIHOSTING_SYS_ELAPSED = 0x30,
SEMIHOSTING_SYS_ERRNO = 0x13,
SEMIHOSTING_SYS_FLEN = 0x0C,
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
SEMIHOSTING_SYS_HEAPINFO = 0x16,
SEMIHOSTING_SYS_ISERROR = 0x08,
SEMIHOSTING_SYS_ISTTY = 0x09,
SEMIHOSTING_SYS_OPEN = 0x01,
SEMIHOSTING_SYS_READ = 0x06,
SEMIHOSTING_SYS_READC = 0x07,
SEMIHOSTING_SYS_REMOVE = 0x0E,
SEMIHOSTING_SYS_RENAME = 0x0F,
SEMIHOSTING_SYS_SEEK = 0x0A,
SEMIHOSTING_SYS_SYSTEM = 0x12,
SEMIHOSTING_SYS_TICKFREQ = 0x31,
SEMIHOSTING_SYS_TIME = 0x11,
SEMIHOSTING_SYS_TMPNAM = 0x0D,
SEMIHOSTING_SYS_WRITE = 0x05,
SEMIHOSTING_SYS_WRITEC = 0x03,
SEMIHOSTING_SYS_WRITE0 = 0x04,
// Codes returned by SEMIHOSTING_ReportException
ADP_Stopped_ApplicationExit = ((2 << 16) + 38),
ADP_Stopped_RunTimeError = ((2 << 16) + 35),
};
// ----------------------------------------------------------------------------
// SWI numbers and reason codes for RDI (Angel) monitors.
#define AngelSWI_ARM 0x123456
#ifdef __thumb__
#define AngelSWI 0xAB
#else
#define AngelSWI AngelSWI_ARM
#endif
// For thumb only architectures use the BKPT instruction instead of SWI.
#if defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7EM__) \
|| defined(__ARM_ARCH_6M__)
#define AngelSWIInsn "bkpt"
#define AngelSWIAsm bkpt
#else
#define AngelSWIInsn "swi"
#define AngelSWIAsm swi
#endif
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
// Testing the local semihosting handler cannot use another BKPT, since this
// configuration cannot trigger HaedFault exceptions while the debugger is
// connected, so we use an illegal op code, that will trigger an
// UsageFault exception.
#define AngelSWITestFault "setend be"
#define AngelSWITestFaultOpCode (0xB658)
#endif
static inline int
__attribute__ ((always_inline))
call_host (int reason, void* arg)
{
int value;
asm volatile (
" mov r0, %[rsn] \n"
" mov r1, %[arg] \n"
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
" " AngelSWITestFault " \n"
#else
" " AngelSWIInsn " %[swi] \n"
#endif
" mov %[val], r0"
: [val] "=r" (value) /* Outputs */
: [rsn] "r" (reason), [arg] "r" (arg), [swi] "i" (AngelSWI) /* Inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
// Clobbers r0 and r1, and lr if in supervisor mode
);
// Accordingly to page 13-77 of ARM DUI 0040D other registers
// can also be clobbered. Some memory positions may also be
// changed by a system call, so they should not be kept in
// registers. Note: we are assuming the manual is right and
// Angel is respecting the APCS.
return value;
}
// ----------------------------------------------------------------------------
// Function used in _exit() to return the status code as Angel exception.
static inline void
__attribute__ ((always_inline,noreturn))
report_exception (int reason)
{
call_host (SEMIHOSTING_ReportException, (void*) reason);
for (;;)
;
}
// ----------------------------------------------------------------------------
#endif // ARM_SEMIHOSTING_H_

232
NUC123/startup_NUC123.s Normal file
View File

@ -0,0 +1,232 @@
.syntax unified
.arch armv8 - m.base
.section .stack
.align 3
#ifndef Stack_Size
.equ Stack_Size, 0x00000400
#endif
.global __StackTop
.global __StackLimit
__StackLimit:
.space Stack_Size
.size __StackLimit, . - __StackLimit
__StackTop:
.size __StackTop, . - __StackTop
.section .heap
.align 3
#ifndef Heap_Size
.equ Heap_Size, 0x00000100
#endif
.global __HeapBase
.global __HeapLimit
__HeapBase:
.if Heap_Size
.space Heap_Size
.endif
.size __HeapBase, . - __HeapBase
__HeapLimit:
.size __HeapLimit, . - __HeapLimit
.section .vectors
.align 2
.global __Vectors
__Vectors:
.long __StackTop /* Top of Stack */
.long Reset_Handler /* Reset Handler */
.long NMI_Handler /* NMI Handler */
.long HardFault_Handler /* Hard Fault Handler */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long SVC_Handler /* SVCall Handler */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long PendSV_Handler /* PendSV Handler */
.long SysTick_Handler /* SysTick Handler */
/* External interrupts */
.long BOD_IRQHandler
.long WDT_IRQHandler
.long EINT0_IRQHandler
.long EINT1_IRQHandler
.long GPAB_IRQHandler
.long GPCDF_IRQHandler
.long PWMA_IRQHandler
.long Default_Handler
.long TMR0_IRQHandler
.long TMR1_IRQHandler
.long TMR2_IRQHandler
.long TMR3_IRQHandler
.long UART0_IRQHandler
.long UART1_IRQHandler
.long SPI0_IRQHandler
.long SPI1_IRQHandler
.long SPI2_IRQHandler
.long SPI3_IRQHandler
.long I2C0_IRQHandler
.long I2C1_IRQHandler
.long CAN0_IRQHandler
.long CAN1_IRQHandler
.long SC012_IRQHandler
.long USBD_IRQHandler
.long PS2_IRQHandler
.long ACMP_IRQHandler
.long PDMA_IRQHandler
.long I2S_IRQHandler
.long PWRWU_IRQHandler
.long ADC_IRQHandler
.long Default_Handler
.long RTC_IRQHandler
.size __Vectors, . - __Vectors
.text
.thumb
.thumb_func
.align 2
.global Reset_Handler
.type Reset_Handler, % function
Reset_Handler:
/* Single section scheme.
*
* The ranges of copy from/to are specified by following symbols
* __etext: LMA of start of the section to copy from. Usually end of text
* __data_start__: VMA of start of the section to copy to
* __data_end__: VMA of end of the section to copy to
*
* All addresses must be aligned to 4 bytes boundary.
*/
ldr r1, = __etext
ldr r2, = __data_start__
ldr r3, = __data_end__
subs r3, r2
ble .L_loop1_done
.L_loop1:
subs r3, #4
ldr r0, [r1, r3]
str r0, [r2, r3]
bgt .L_loop1
.L_loop1_done:
/* Single BSS section scheme.
*
* The BSS section is specified by following symbols
* __bss_start__: start of the BSS section.
* __bss_end__: end of the BSS section.
*
* Both addresses must be aligned to 4 bytes boundary.
*/
ldr r1, = __bss_start__
ldr r2, = __bss_end__
movs r0, 0
subs r2, r1
ble .L_loop3_done
.L_loop3:
subs r2, #4
str r0, [r1, r2]
bgt .L_loop3
.L_loop3_done:
/* There's no SystemInit for NUC123, so no point making a pointless call */
// bl SystemInit
#ifndef __ENTRY
#define __ENTRY _entry
#endif
bl __ENTRY
.pool
.size Reset_Handler, . - Reset_Handler
.align 1
.thumb_func
.weak Default_Handler
.type Default_Handler, % function
Default_Handler:
b .
.size Default_Handler, . - Default_Handler
/* Macro to define default handlers. Default handler
* will be weak symbol and just dead loops. They can be
* overwritten by other handlers */
.macro def_irq_handler handler_name
.weak \handler_name
.set \handler_name, Default_Handler
.endm
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler SVC_Handler
def_irq_handler PendSV_Handler
def_irq_handler SysTick_Handler
def_irq_handler BOD_IRQHandler
def_irq_handler WDT_IRQHandler
def_irq_handler EINT0_IRQHandler
def_irq_handler EINT1_IRQHandler
def_irq_handler GPAB_IRQHandler
def_irq_handler GPCDF_IRQHandler
def_irq_handler PWMA_IRQHandler
def_irq_handler TMR0_IRQHandler
def_irq_handler TMR1_IRQHandler
def_irq_handler TMR2_IRQHandler
def_irq_handler TMR3_IRQHandler
def_irq_handler UART0_IRQHandler
def_irq_handler UART1_IRQHandler
def_irq_handler SPI0_IRQHandler
def_irq_handler SPI1_IRQHandler
def_irq_handler SPI2_IRQHandler
def_irq_handler SPI3_IRQHandler
def_irq_handler I2C0_IRQHandler
def_irq_handler I2C1_IRQHandler
def_irq_handler CAN0_IRQHandler
def_irq_handler CAN1_IRQHandler
def_irq_handler SC012_IRQHandler
def_irq_handler USBD_IRQHandler
def_irq_handler PS2_IRQHandler
def_irq_handler ACMP_IRQHandler
def_irq_handler PDMA_IRQHandler
def_irq_handler I2S_IRQHandler
def_irq_handler PWRWU_IRQHandler
def_irq_handler ADC_IRQHandler
def_irq_handler RTC_IRQHandler
/* ;int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0) */
.align 2
.thumb_func
.type SH_DoCommand, % function
SH_DoCommand:
BKPT 0xAB /* ; Wait ICE or HardFault */
//LDR R3, = SH_Return
MOV R4, lr
BLX R3 /* ; Call SH_Return. The return value is in R0 */
BX R4 /* ; Return value = R0 */
.size SH_DoCommand, . - SH_DoCommand
.align 2
.thumb_func
.global __PC
.type __PC, % function
.end

80
NUC123/system_NUC123.c Normal file
View File

@ -0,0 +1,80 @@
/**************************************************************************//**
* @file system_NUC123.c
* @version V3.0
* $Revision: 5 $
* $Date: 15/07/02 11:21a $
* @brief NUC123 Series CMSIS System File
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2014~2015 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdint.h>
#include "NUC123.h"
/*----------------------------------------------------------------------------
Clock Variable definitions
*----------------------------------------------------------------------------*/
uint32_t SystemCoreClock = __HSI; /*!< System Clock Frequency (Core Clock) */
uint32_t CyclesPerUs = (__HSI / 1000000); /* Cycles per micro second */
uint32_t PllClock = __HSI; /*!< PLL Output Clock Frequency */
uint32_t gau32ClkSrcTbl[] = {__HXT, NULL, __HSI, __LIRC, NULL, NULL, NULL, __HIRC};
/*----------------------------------------------------------------------------
Clock functions
This function is used to update the variable SystemCoreClock
and must be called whenever the core clock is changed.
*----------------------------------------------------------------------------*/
void SystemCoreClockUpdate(void) /* Get Core Clock Frequency */
{
uint32_t u32Freq, u32ClkSrc;
uint32_t u32HclkDiv;
/* Update PLL Clock */
PllClock = CLK_GetPLLClockFreq();
u32ClkSrc = CLK->CLKSEL0 & CLK_CLKSEL0_HCLK_S_Msk;
if(u32ClkSrc == CLK_CLKSEL0_HCLK_S_PLL)
{
/* Use PLL clock */
u32Freq = PllClock;
}
else if(u32ClkSrc == CLK_CLKSEL0_HCLK_S_PLL_DIV2)
{
/* Use PLL/2 clock */
u32Freq = PllClock >> 1;
}
else
{
/* Use the clock sources directly */
u32Freq = gau32ClkSrcTbl[u32ClkSrc];
}
u32HclkDiv = (CLK->CLKDIV & CLK_CLKDIV_HCLK_N_Msk) + 1;
/* Update System Core Clock */
SystemCoreClock = u32Freq / u32HclkDiv;
CyclesPerUs = (SystemCoreClock + 500000) / 1000000;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: SystemInit */
/* */
/* Parameters: */
/* None */
/* */
/* Returns: */
/* None */
/* */
/* Description: */
/* The necessary initialization of system. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
void SystemInit(void)
{
}

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# TASOLLER Custom Firmware (Host MCU - Application ROM)
See [Development](./Development.md) for development information.
Yes, the code is a mess. I just wanted to get something onto git y'know :).
## Configuration
Hold FN2 for configuration. It is not the same as stock DAO.
- Pad 1/2 (cell 0): Left wing colour
- Pad 3/4 (cell 1): Ground colour
- Pad 5/6 (cell 2): Ground colour when pressed, and separator colour
- Pad 7/8 (cell 3): Right wing colour
- Pad 9/10 (cell 4): No function
- Pad 11/12 (cell 5): Toggle rainbow effect on/off
- Pad 13/14 (cell 6): Increase/decrease ground brightness
- Pad 15/16 (cell 7): Increase/decrease wing brightness
- Pad 17/18 (cell 8): No function
- Pad 19/20 (cell 9): No function
- Pad 21/22 (cell 10): No function
- Pad 23/24 (cell 11): No function
- Pad 25/26 (cell 12): Increase/decrease sensitivity
- Pad 27/28 (cell 13): No function
- Pad 29/30 (cell 14): Toggle HID keyboard mode
- Pad 31/32 (cell 15): Toggle IO4 emulation mode
## Calibration
Make sure no hands or objects are near the slider before starting calibration.
Hold FN1 for two seconds; the slider will flash red for a few seconds, then fill up with a blue bar.
The slider will then briefly flash green. After this, begin to rub your hands across the slider as much as possible! The cells will turn increasingly green; the greener you can get them the better. Once the dividers have turned green you can save your calibration by pressing FN2.
**Note:** Calibration is a separate process to adjusting the sensor sensitivity. It is recommended to re-calibrate after adjustment of sensitivity. For the best performance, run a re-calibration before every play session to account for changes in your room's temperature and humidity.

17
flash.cmd Normal file
View File

@ -0,0 +1,17 @@
@..\..\openocd-0.12.0-3\bin\openocd.exe -f interface/stlink-v2.cfg -f ..\..\nucxxx.cfg ^
-c "SysReset halt" ^
-c "flash read_bank 1 dataflash.bin" ^
-c "ChipErase" ^
-c "exit"
@..\..\openocd-0.12.0-3\bin\openocd.exe -f interface/stlink-v2.cfg -f ..\..\nucxxx.cfg ^
-c "SysReset halt" ^
-c "WriteConfigRegs 0xFFFFFF7F 0xFFFFFFFF" ^
-c "ReadConfigRegs" ^
-c "program ../bootloader/host_bl.bin 0x100000" ^
-c "program host_aprom.bin 0" ^
-c "program dataflash.bin 0x1F000" ^
-c "SysReset aprom run" ^
-c "exit"
@del dataflash.bin

40
generic.mk Normal file
View File

@ -0,0 +1,40 @@
C_SOURCES = $(wildcard $(SRC_DIR)/*.c)
ASM_SOURCES = $(wildcard $(SRC_DIR)/*.s)
C_OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(C_SOURCES))
ASM_OBJECTS = $(patsubst $(SRC_DIR)/%.s,$(OBJ_DIR)/%.o,$(ASM_SOURCES))
OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) $(DEVICE_OBJECTS)
all: $(BINARY_NAME).bin
.DEFAULT_GOAL=all
# Speed up compiles by not deleting these
.PRECIOUS: $(OBJ_DIR)/%.o
.PRECIOUS: $(OBJ_DIR)/%.elf
%.bin: $(OBJ_DIR)/%.elf
@echo Creating binary $@
@$(OBJCOPY) -O binary $< $@
$(OBJ_DIR)/%.elf: $(OBJECTS)
@echo Linking $@
@$(LD) $(LDFLAGS) -o $@ $^
@echo ==============================================================================
@$(SIZE) $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
@echo Compiling $<
@$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
@echo Compiling $<
@$(AS) $(ASFLAGS) -o $@ $<
clean:
-del $(BINARY_NAME).bin
-rmdir /Q /S $(OBJ_DIR)
$(shell mkdir $(OBJ_DIR))
.PHONY: all clean

0
picolibc/.gitkeep Normal file
View File

4
run.cmd Normal file
View File

@ -0,0 +1,4 @@
@..\..\openocd-0.12.0-3\bin\openocd.exe -f interface/stlink-v2.cfg -f ..\..\nucxxx.cfg ^
-c "SysReset halt" ^
-c "SysReset aprom run" ^
-c "exit"

6
src/delay.s Normal file
View File

@ -0,0 +1,6 @@
.syntax unified
.global DelayCycles
DelayCycles:
subs r0, r0, #1
bcs DelayCycles
bx lr

466
src/descriptors.c Normal file
View File

@ -0,0 +1,466 @@
#include <stddef.h>
#include "tasoller.h"
static const uint8_t IO4_ReportDescriptor[] = {
// Analog input (28 bytes)
HID_USAGE_PAGE(GENERIC_DESKTOP),
HID_USAGE(JOYSTICK),
HID_COLLECTION(APPLICATION),
HID_REPORT_ID(HID_REPORT_ID_IO4),
HID_USAGE(POINTER),
HID_COLLECTION(PHYSICAL),
// 8 ADC channels
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
// 4 Rotary channels
HID_USAGE(RX),
HID_USAGE(RY),
HID_USAGE(RX),
HID_USAGE(RY),
// 2 Coin chutes
HID_USAGE(SLIDER),
HID_USAGE(SLIDER),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(4, 65534),
HID_PHYSICAL_MINIMUM(1, 0),
HID_PHYSICAL_MAXIMUM(4, 65534),
HID_REPORT_COUNT(14),
HID_REPORT_SIZE(16),
HID_INPUT(DATA, VARIABLE, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION),
HID_END_COLLECTION(PHYSICAL),
// Digital input (6 bytes = 48 bits)
// [ 0~15]: Player 1 buttons
// [16~31]: Player 2 buttons
// [32~39]: System status
// -> 01h: ?
// -> 02h: ?
// -> 04h: ?
// -> 08h: ?
// -> 10h: Comm timeout set
// -> 20h: Sampling count set
// [40~47]: USB status
// -> 01h: ?
// -> 02h: ?
// -> 04h: ? (is set on timeout)
HID_USAGE_PAGE(SIMULATION),
HID_USAGE_PAGE(BUTTONS),
HID_USAGE_MINIMUM(1, 1),
HID_USAGE_MAXIMUM(1, 48),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(1, 1),
HID_PHYSICAL_MAXIMUM(1, 1),
HID_REPORT_SIZE(1),
HID_REPORT_COUNT(48),
HID_INPUT(DATA, VARIABLE, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION),
// Reserved for future use. Pad with null. (29 bytes)
HID_USAGE(UNDEFINED),
HID_REPORT_SIZE(8),
HID_REPORT_COUNT(29),
HID_INPUT(CONSTANT, ARRAY, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION),
HID_USAGE_PAGE2(2, 0xFFA0), // Vendor defined FF0A
HID_USAGE(UNDEFINED),
// General-purpose commands to the board. First byte is the command, then 62 data byte
HID_REPORT_ID(HID_REPORT_ID_IO4_CMD),
HID_COLLECTION(APPLICATION),
HID_USAGE(UNDEFINED),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(1, 255),
HID_REPORT_SIZE(8),
HID_REPORT_COUNT(63),
HID_OUTPUT(DATA, VARIABLE, ABSOLUTE, NO_WRAP, LINEAR, PREFERRED_STATE, NO_NULL_POSITION,
NON_VOLATILE),
HID_END_COLLECTION(APPLICATION),
HID_END_COLLECTION(APPLICATION),
};
static const uint8_t Keyboard_ReportDescriptor[] = {
// Keyboard input descriptor
HID_USAGE_PAGE(GENERIC_DESKTOP),
HID_USAGE(KEYBOARD),
HID_COLLECTION(APPLICATION),
HID_REPORT_ID(HID_REPORT_ID_KEYBOARD),
HID_USAGE_PAGE(KEYBOARD),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(1, 231),
HID_USAGE_MINIMUM(1, 0),
HID_USAGE_MAXIMUM(1, 231),
HID_REPORT_SIZE(8),
HID_REPORT_COUNT(NUM_FN + NUM_AIR + NUM_GROUND),
HID_INPUT(DATA, ARRAY, ABSOLUTE),
HID_END_COLLECTION(APPLICATION),
// Debugging reports descriptors (they dump the raw PSoC data)
HID_USAGE_PAGE(GENERIC_DESKTOP),
HID_USAGE(JOYSTICK),
HID_COLLECTION(APPLICATION),
HID_REPORT_ID(HID_REPORT_ID_DEBUG_A),
HID_USAGE(POINTER),
HID_COLLECTION(LOGICAL),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(4, 0xffff),
HID_PHYSICAL_MINIMUM(1, 0),
HID_PHYSICAL_MAXIMUM(4, 0xffff),
HID_REPORT_COUNT(16),
HID_REPORT_SIZE(16),
HID_INPUT(DATA, VARIABLE, ABSOLUTE),
HID_END_COLLECTION(LOGICAL),
HID_REPORT_ID(HID_REPORT_ID_DEBUG_B),
HID_USAGE(POINTER),
HID_COLLECTION(LOGICAL),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(4, 0xffff),
HID_PHYSICAL_MINIMUM(1, 0),
HID_PHYSICAL_MAXIMUM(4, 0xffff),
HID_REPORT_SIZE(16),
HID_REPORT_COUNT(16),
HID_INPUT(DATA, VARIABLE, ABSOLUTE),
HID_END_COLLECTION(LOGICAL),
HID_END_COLLECTION(APPLICATION),
};
static const uint8_t Debug_ReportDescriptor[] = {
HID_USAGE_PAGE(GENERIC_DESKTOP),
HID_USAGE(JOYSTICK),
HID_COLLECTION(APPLICATION),
HID_REPORT_ID(HID_REPORT_ID_DEBUG_A),
HID_USAGE(POINTER),
HID_COLLECTION(LOGICAL),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(4, 0xffff),
HID_PHYSICAL_MINIMUM(1, 0),
HID_PHYSICAL_MAXIMUM(4, 0xffff),
HID_REPORT_COUNT(16),
HID_REPORT_SIZE(16),
HID_INPUT(DATA, VARIABLE, ABSOLUTE),
HID_END_COLLECTION(LOGICAL),
HID_REPORT_ID(HID_REPORT_ID_DEBUG_B),
HID_USAGE(POINTER),
HID_COLLECTION(LOGICAL),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_USAGE(X),
HID_USAGE(Y),
HID_LOGICAL_MINIMUM(1, 0),
HID_LOGICAL_MAXIMUM(4, 0xffff),
HID_PHYSICAL_MINIMUM(1, 0),
HID_PHYSICAL_MAXIMUM(4, 0xffff),
HID_REPORT_SIZE(16),
HID_REPORT_COUNT(16),
HID_INPUT(DATA, VARIABLE, ABSOLUTE),
HID_END_COLLECTION(LOGICAL),
HID_END_COLLECTION(APPLICATION),
};
usb_device_descr_t gIO4DeviceDescriptor = {
sizeof(usb_device_descr_t),
DESC_DEVICE,
0x0200,
USB_CLASS_UNSPECIFIED,
0,
0,
EP0_MAX_PKT_SIZE,
// Unfortunately we're forced to always use this VID if we want IO4 support to work
IO4_VID,
IO4_PID,
0x0100,
USB_STRING_VENDOR,
USB_STRING_PRODUCT,
USB_STRING_SERIAL,
1,
};
// We have a unified descriptor that covers
typedef struct __attribute__((packed)) {
const usb_desc_config_t Config;
const usb_desc_iad_t CDC_IAD;
const usb_desc_interface_t CDC_CMD_Interface;
const usb_desc_cdc_header_t CDC_Header;
const usb_desc_cdc_call_t CDC_Call;
const usb_desc_cdc_acm_t CDC_ACM;
const usb_desc_cdc_union_t CDC_Union;
const usb_desc_endpoint_t CDC_CMD_Endpoint;
const usb_desc_interface_t CDC_Interface;
const usb_desc_endpoint_t CDC_IN_Endpoint;
const usb_desc_endpoint_t CDC_OUT_Endpoint;
const usb_desc_interface_t HID_IO4_Interface;
const usb_desc_hid_t HID_IO4;
const usb_desc_endpoint_t HID_IO4_EndpointIn;
/**
* We're meant to have an OUT endpoint for IO4, but IO4 uses the Win32 WriteFile API, which will
* happily fall back to SET_REPORT calls on the control endpoints if there's no OUT endpoint.
*
* Chunithm never uses the output capability of IO4, so we have no high-frequency data that
* might choke our control endpoints--we just need to support the initial configuration packets.
*/
// const usb_desc_endpoint_t HID_EndpointOut;
const usb_desc_interface_t HID_Misc_Interface;
const usb_desc_hid_t HID_Misc;
const usb_desc_endpoint_t HID_Misc_EndpointIn;
const usb_desc_endpoint_t HID_Misc_EndpointOut;
} config_desc_t;
static const config_desc_t gConfigDescriptor = {
// Config
{
sizeof(usb_desc_config_t),
DESC_CONFIG,
sizeof gConfigDescriptor,
_USBD_ITF_MAX,
0x01,
0x00,
0x80 | (USBD_SELF_POWERED << 6) | (USBD_REMOTE_WAKEUP << 5),
USBD_MAX_POWER,
},
// CDC IAD
{
sizeof(usb_desc_iad_t),
DESC_IAD,
USBD_ITF_CDC_CMD,
2,
USB_CLASS_CDC,
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
CDC_COMM_PROTOCOL_NONE,
USB_STRING_CDC,
},
// CDC Control
{
sizeof(usb_desc_interface_t),
DESC_INTERFACE,
USBD_ITF_CDC_CMD,
0x00,
0x01,
USB_CLASS_CDC,
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
CDC_COMM_PROTOCOL_NONE,
0,
},
{
sizeof(usb_desc_cdc_header_t),
DESC_CS_INTERFACE,
CDC_FUNC_DESC_HEADER,
0x0110,
},
{
sizeof(usb_desc_cdc_call_t),
DESC_CS_INTERFACE,
CDC_FUNC_DESC_CALL_MANAGEMENT,
0,
USBD_ITF_CDC_DAT,
},
{
sizeof(usb_desc_cdc_acm_t),
DESC_CS_INTERFACE,
CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT,
// Supports set line coding
2,
},
{
sizeof(usb_desc_cdc_union_t),
DESC_CS_INTERFACE,
CDC_FUNC_DESC_UNION,
USBD_ITF_CDC_CMD,
USBD_ITF_CDC_DAT,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_CDC_EP_CMD,
EP_INT,
USBD_CDC_CMD_MAX_SIZE,
1,
},
// CDC Data
{
sizeof(usb_desc_interface_t),
DESC_INTERFACE,
USBD_ITF_CDC_DAT,
0,
2,
USB_CLASS_CDC_DATA,
0,
0,
0,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_CDC_EP_IN,
EP_BULK,
USBD_CDC_IN_MAX_SIZE,
0,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_CDC_EP_OUT,
EP_BULK,
USBD_CDC_OUT_MAX_SIZE,
0,
},
// IO4 HID
{
sizeof(usb_desc_interface_t),
DESC_INTERFACE,
USBD_ITF_HID_IO4,
0x00,
0x01,
USB_CLASS_HID,
0,
HID_KEYBOARD,
USB_STRING_HID_IO4,
},
{
sizeof(usb_desc_hid_t),
DESC_HID,
0x0110,
0x00,
0x01,
DESC_HID_RPT,
sizeof IO4_ReportDescriptor,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_HID_IO4_EP_IN,
EP_INT,
USBD_HID_BUF_LEN,
HID_IO4_INT_IN_INTERVAL,
},
// Misc HID
{
sizeof(usb_desc_interface_t),
DESC_INTERFACE,
USBD_ITF_HID_MISC,
0x00,
0x01,
USB_CLASS_HID,
0,
HID_KEYBOARD,
USB_STRING_HID_MISC,
},
{
sizeof(usb_desc_hid_t),
DESC_HID,
0x0110,
0x00,
0x01,
DESC_HID_RPT,
sizeof Keyboard_ReportDescriptor,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_HID_MISC_EP_IN,
EP_INT,
USBD_HID_BUF_LEN,
HID_DEFAULT_INT_IN_INTERVAL,
},
{
sizeof(usb_desc_endpoint_t),
DESC_ENDPOINT,
USBD_HID_MISC_EP_OUT,
EP_INT,
USBD_HID_BUF_LEN,
HID_DEFAULT_INT_IN_INTERVAL,
},
};
const char* gszVendorInitial = "Bottersnike";
const char* gszVendor = IO4_VENDOR;
const char* gszProduct = "TASOLLER";
const usb_device_descr_t *gpDeviceDescriptor = &gIO4DeviceDescriptor;
const usb_desc_config_t *gpConfigDescriptor = &gConfigDescriptor.Config;
const uint32_t gu32HidDescIO4Offset = (offsetof(config_desc_t, HID_IO4));
const uint32_t gu32HidDescMiscOffset = (offsetof(config_desc_t, HID_Misc));
const uint32_t gu32UsbHidIO4ReportLen = sizeof IO4_ReportDescriptor;
const uint32_t gu32UsbHidMiscReportLen = sizeof Keyboard_ReportDescriptor;
const uint8_t* gpu8UsbHidIO4Report = (uint8_t*)IO4_ReportDescriptor;
const uint8_t* gpu8UsbHidMiscReport = (uint8_t*)Keyboard_ReportDescriptor;

99
src/fmc.c Normal file
View File

@ -0,0 +1,99 @@
#include "tasoller.h"
void FMC_Open(void) { FMC->ISPCON |= FMC_ISPCON_ISPEN_Msk; }
void FMC_Close(void) { FMC->ISPCON &= ~FMC_ISPCON_ISPEN_Msk; }
int FMC_Proc(uint32_t u32Cmd, uint32_t addr_start, uint32_t addr_end, uint32_t *pu32Data) {
uint32_t u32Addr, Reg;
for (u32Addr = addr_start; u32Addr < addr_end; pu32Data++) {
FMC->ISPCMD = u32Cmd;
FMC->ISPADR = u32Addr;
if (u32Cmd == FMC_ISPCMD_PROGRAM) FMC->ISPDAT = *pu32Data;
FMC->ISPTRG = 0x1;
__ISB();
while (FMC->ISPTRG & 0x1)
; // Wait for ISP command done.
Reg = FMC->ISPCON;
if (Reg & FMC_ISPCON_ISPFF_Msk) {
FMC->ISPCON = Reg;
return -1;
}
if (u32Cmd == FMC_ISPCMD_READ) *pu32Data = FMC->ISPDAT;
if (u32Cmd == FMC_ISPCMD_PAGE_ERASE) {
u32Addr += FMC_FLASH_PAGE_SIZE;
} else {
u32Addr += 4;
}
}
return 0;
}
#define DATAFLASH_BASE (FMC->DFBADR) // 1F000
// #define DATAFLASH_BASE (0x1F000)
// Dao has his data based at FE0. We're going to base ourself at 000 instead
#define DATAFLASH_EEPROM_BASE (DATAFLASH_BASE + 0x000)
#define DATAFLASH_VERSION (0x02) // Gets merged into the magic number
#define DATAFLASH_MAGIC (0x54617300 | DATAFLASH_VERSION)
flash_t gConfig;
void FMC_EEPROM_Load(void) {
FMC_Open();
FMC_ReadData(DATAFLASH_EEPROM_BASE, DATAFLASH_EEPROM_BASE + sizeof gConfig, (void *)&gConfig);
if (gConfig.u32Magic != DATAFLASH_MAGIC) {
// Zeroing flags first means GCC knows we don't care about the other bits
gConfig.u8Flags = 0;
gConfig.bEnableIO4 = 1;
gConfig.bEnableKeyboard = 0;
gConfig.bEnableRainbow = 1;
gConfig.u8Sens = 8;
gConfig.u16HueWingLeft = 330;
gConfig.u16HueWingRight = 180;
gConfig.u16HueGround = 45;
gConfig.u16HueGroundActive = 330;
gConfig.u8LedGroundBrightness = 255;
gConfig.u8LedWingBrightness = 255;
for (uint8_t i = 0; i < 32; i++) {
gConfig.u16PSoCScaleMin[i] = 0;
gConfig.u16PSoCScaleMax[i] = 2000;
}
bConfigDirty = 1;
}
FMC_Close();
}
uint8_t bConfigDirty = 0;
void FMC_EEPROM_Store(void) {
if (!bConfigDirty) return;
bConfigDirty = 0;
FMC_Open();
FMC->ISPCON |= FMC_ISPCON_LDUEN_Msk;
FMC->ISPCON |= FMC_ISPCON_APUEN_Msk;
FMC_Erase(DATAFLASH_EEPROM_BASE);
gConfig.u32Magic = DATAFLASH_MAGIC;
FMC_WriteData(DATAFLASH_EEPROM_BASE, DATAFLASH_EEPROM_BASE + sizeof gConfig, (void *)&gConfig);
// We don't actually have anything to do if we fail, so there's no point checking for now ig
// // Check if our write succeeded or not
// if (FMC_Read(DATAFLASH_EEPROM_BASE) != DATAFLASH_MAGIC)
// ;
FMC->ISPCON &= ~FMC_ISPCON_APUEN_Msk;
FMC->ISPCON &= ~FMC_ISPCON_LDUEN_Msk;
FMC_Close();
}

60
src/fmc_user.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include <NUC123.h>
#define Config0 FMC_CONFIG_BASE
#define Config1 FMC_CONFIG_BASE + 4
#define ISPGO 0x01
#define _FMC_ENABLE_CFG_UPDATE() \
(FMC->ISPCTL |= FMC_ISPCTL_CFGUEN_Msk) // Enable CONFIG Update Function
#define _FMC_DISABLE_CFG_UPDATE() \
(FMC->ISPCTL &= ~FMC_ISPCTL_CFGUEN_Msk) // Disable CONFIG Update Function
int FMC_Proc(uint32_t u32Cmd, uint32_t addr_start, uint32_t addr_end, uint32_t *data);
#define FMC_EraseAP(u32Start, u32Size) \
FMC_Proc(FMC_ISPCMD_PAGE_ERASE, (u32Start), (u32Start) + (u32Size), NULL)
#define FMC_ReadData(u32Start, u32End, pu32Data) \
FMC_Proc(FMC_ISPCMD_READ, (u32Start), (u32End), (pu32Data))
#define FMC_WriteData(u32Start, u32End, pu32Data) \
FMC_Proc(FMC_ISPCMD_PROGRAM, (u32Start), (u32End), (pu32Data))
#define FMC_ReadU32(u32Addr, pData) FMC_ReadData((u32Addr), (u32Addr) + 4, (pData))
#define FMC_Erase_User(u32Addr) FMC_Proc(FMC_ISPCMD_PAGE_ERASE, (u32Addr), (u32Addr) + 4, 0)
void FMC_Open(void);
void FMC_Close(void);
void FMC_EEPROM_Load(void);
void FMC_EEPROM_Store(void);
#define FMC_EEPROM_VERSION 0x01
typedef struct __attribute__((aligned(4), packed)) {
uint32_t u32Magic;
// Flags
union {
struct __attribute__((packed)) {
uint8_t bEnableIO4 : 1;
uint8_t bEnableKeyboard : 1;
uint8_t bEnableRainbow : 1;
};
uint8_t u8Flags;
};
// Only needs 4 bits but we aren't short atm
uint8_t u8Sens; // [1~16], Higher = more sensitive
uint16_t u16HueWingLeft;
uint16_t u16HueWingRight;
uint16_t u16HueGround;
uint16_t u16HueGroundActive;
uint8_t u8LedGroundBrightness;
uint8_t u8LedWingBrightness;
// Calibration data
uint16_t u16PSoCScaleMin[32];
uint16_t u16PSoCScaleMax[32];
} flash_t;
extern flash_t gConfig;
extern uint8_t bConfigDirty;

11
src/gpio.c Normal file
View File

@ -0,0 +1,11 @@
#include "tasoller.h"
void GPIO_SetMode(GPIO_T *port, uint32_t u32PinMask, uint32_t u32Mode) {
uint32_t i;
for (i = 0; i < GPIO_PIN_MAX; i++) {
if (u32PinMask & (1 << i)) {
port->PMD = (port->PMD & ~(0x3 << (i << 1))) | (u32Mode << (i << 1));
}
}
}

198
src/hid.c Normal file
View File

@ -0,0 +1,198 @@
#include "tasoller.h"
#define HID_IO4_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_IO4_IN)))
#define HID_MISC_BUF ((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_HID_MISC_IN)))
static const uint8_t u8GroundThreshold = 20;
static const uint8_t u8GroundKeymap[32] = {
KEY_I, KEY_COMMA, //
KEY_8, KEY_K, //
KEY_U, KEY_M, //
KEY_7, KEY_J, //
KEY_Y, KEY_N, //
KEY_6, KEY_H, //
KEY_T, KEY_B, //
KEY_5, KEY_G, //
KEY_R, KEY_V, //
KEY_4, KEY_F, //
KEY_E, KEY_C, //
KEY_3, KEY_D, //
KEY_W, KEY_X, //
KEY_2, KEY_S, //
KEY_Q, KEY_Z, //
KEY_1, KEY_A, //
};
static const uint8_t u8AirKeymap[6] = {
HID_KEYBOARD_SLASH_AND_QUESTION_MARK, // VK_OEM_2
HID_KEYBOARD_PERIOD_AND_GREATER_THAN, // VK_OEM_PERIOD
HID_KEYBOARD_QUOTE_AND_DOUBLEQUOTE, // VK_OEM_7
HID_KEYBOARD_SEMICOLON_AND_COLON, // VK_OEM_1
HID_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_CURLY_BRACE, // VK_OEM_6
HID_KEYBOARD_LEFT_BRACKET_AND_LEFT_CURLY_BRACE, // VK_OEM_4
};
static inline void _HID_Keyboard_Tick(uint8_t bReal) {
hid_report_t *buf = (hid_report_t *)HID_MISC_BUF;
memset(buf, 0, sizeof *buf);
buf->bReportId = HID_REPORT_ID_KEYBOARD;
uint8_t kI = 0;
if (bReal) {
if (gu8DigitalButtons & 0x01) buf->bKeyboard[kI++] = HID_KEYBOARD_F1;
if (gu8DigitalButtons & 0x02) buf->bKeyboard[kI++] = HID_KEYBOARD_F2;
if (gu8DigitalButtons & 0x04) buf->bKeyboard[kI++] = u8AirKeymap[0];
if (gu8DigitalButtons & 0x08) buf->bKeyboard[kI++] = u8AirKeymap[1];
if (gu8DigitalButtons & 0x10) buf->bKeyboard[kI++] = u8AirKeymap[2];
if (gu8DigitalButtons & 0x20) buf->bKeyboard[kI++] = u8AirKeymap[3];
if (gu8DigitalButtons & 0x40) buf->bKeyboard[kI++] = u8AirKeymap[4];
if (gu8DigitalButtons & 0x80) buf->bKeyboard[kI++] = u8AirKeymap[5];
for (int i = 0; i < 32; i++) {
if (gu8GroundData[i] > u8GroundThreshold) buf->bKeyboard[kI++] = u8GroundKeymap[i];
}
}
USBD_SET_PAYLOAD_LEN(EP_HID_MISC_IN, sizeof *buf);
}
#define IO4_BUTTON_TEST (1 << 9)
#define IO4_BUTTON_SERVICE (1 << 6)
#define IO4_CMD_SET_COMM_TIMEOUT 0x01
#define IO4_CMD_SET_SAMPLING_COUNT 0x02
#define IO4_CMD_CLEAR_BOARD_STATUS 0x03
#define IO4_CMD_SET_GENERAL_OUTPUT 0x04
#define IO4_CMD_SET_PWM_OUTPUT 0x05
#define IO4_CMD_SET_UNIQUE_OUTPUT 0x41
#define IO4_CMD_UPDATE_FIRMWARE 0x85
volatile uint8_t u8IO4SystemStatus = 0;
volatile uint8_t u8IO4USBStatus = 0;
volatile uint16_t u16IO4CommTimeout = 0;
volatile uint8_t u8IO4SamplingCount = 0;
static void _HID_IO4_Prepare(volatile uint8_t *pu8EpBuf) {
io4_hid_in_t *buf = (io4_hid_in_t *)pu8EpBuf;
memset(buf, 0, sizeof *buf);
buf->bReportId = HID_REPORT_ID_IO4;
// System buttons
if (gu8DigitalButtons & 0x01) buf->wButtons[0] |= IO4_BUTTON_TEST;
if (gu8DigitalButtons & 0x02) buf->wButtons[0] |= IO4_BUTTON_SERVICE;
// Airs
if (!(gu8DigitalButtons & 0x04)) buf->wButtons[0] |= 1 << 13;
if (!(gu8DigitalButtons & 0x08)) buf->wButtons[1] |= 1 << 13;
if (!(gu8DigitalButtons & 0x10)) buf->wButtons[0] |= 1 << 12;
if (!(gu8DigitalButtons & 0x20)) buf->wButtons[1] |= 1 << 12;
if (!(gu8DigitalButtons & 0x40)) buf->wButtons[0] |= 1 << 11;
if (!(gu8DigitalButtons & 0x80)) buf->wButtons[1] |= 1 << 11;
buf->bUsbStatus = u8IO4USBStatus;
buf->bSystemStatus = u8IO4SystemStatus;
}
static void _HID_IO4_Tick() {
_HID_IO4_Prepare(HID_IO4_BUF);
// We must send data every 8ms! None of that "only sending changed keys" stuff
// Trigger a write
gu8HIDIO4Ready = 0;
USBD_SET_PAYLOAD_LEN(EP_HID_IO4_IN, sizeof(io4_hid_in_t));
}
static void _HID_Debug_Tick() {
debug_hid_report_t *buf = (debug_hid_report_t *)HID_MISC_BUF;
memset(buf, 0, sizeof *buf);
static uint8_t bWhich = 0;
if ((bWhich++) & 1) {
buf->bReportId = HID_REPORT_ID_DEBUG_A;
for (uint8_t i = 0; i < 32; i += 2) buf->wData[i / 2] = gu8GroundData[i];
} else {
buf->bReportId = HID_REPORT_ID_DEBUG_B;
for (uint8_t i = 1; i < 32; i += 2) buf->wData[i / 2] = gu8GroundData[i];
}
USBD_SET_PAYLOAD_LEN(EP_HID_MISC_IN, sizeof *buf);
}
static void _HID_Misc_Tick() {
static uint8_t sbLastEnableKeyboard = 0;
if (gConfig.bEnableKeyboard) {
sbLastEnableKeyboard = 1;
_HID_Keyboard_Tick(1);
} else if (sbLastEnableKeyboard) {
// If we've just disabled the keyboard, make sure to send a packet with all keys released!
sbLastEnableKeyboard = 0;
_HID_Keyboard_Tick(0);
}
// TODO: gbEnableDebug (we'll need to use a toggle to alternate)
gu8HIDMiscReady = 0;
}
void USBD_HID_PrepareReport() {
if (gu8HIDIO4Ready) _HID_IO4_Tick();
if (gu8HIDMiscReady) _HID_Misc_Tick();
}
static uint8_t sIO4InBuffer[sizeof(io4_hid_in_t)] = { 0 };
uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size) {
switch (u8ReportId) {
case HID_REPORT_ID_IO4:
if (!gConfig.bEnableIO4) return NULL;
_HID_IO4_Prepare(sIO4InBuffer);
*pu32Size = sizeof sIO4InBuffer;
return sIO4InBuffer;
default:
return NULL;
}
}
void USBD_HID_SetReport(volatile uint8_t *pu8EpBuf, uint32_t u32Size) {
// TODO: is pu8EpBuf[0] the report ID?
// We need to switch on that report ID so we know what we're doing!
if (!gConfig.bEnableIO4) return;
if (u32Size < 2) return;
switch (pu8EpBuf[1]) {
case IO4_CMD_SET_COMM_TIMEOUT:
if (u32Size >= 2 + 1) {
u16IO4CommTimeout = (uint16_t)pu8EpBuf[2] * 200;
u8IO4SystemStatus |= 0x10;
gu8HIDIO4Ready = 1;
_HID_IO4_Tick();
}
break;
case IO4_CMD_SET_SAMPLING_COUNT:
if (u32Size >= 2 + 1) {
u8IO4SamplingCount = pu8EpBuf[2];
u8IO4SystemStatus |= 0x20;
gu8HIDIO4Ready = 1;
_HID_IO4_Tick();
}
break;
case IO4_CMD_CLEAR_BOARD_STATUS:
u8IO4SystemStatus &= 0x0F;
u8IO4USBStatus &= 0x04;
gu8HIDIO4Ready = 1;
_HID_IO4_Tick();
break;
case IO4_CMD_SET_GENERAL_OUTPUT:
if (u32Size >= 2 + 3) {
// 20 bits of data for GPO (+4 of padding)
}
break;
case IO4_CMD_SET_PWM_OUTPUT:
if (u32Size >= 2 + 0) {
// 0 bytes of data for PWM duty cycles (IO4 has no PWM!)
}
break;
case IO4_CMD_SET_UNIQUE_OUTPUT:
if (u32Size >= 2 + 62) {
// 62 bytes of unique output data
}
break;
case IO4_CMD_UPDATE_FIRMWARE:
break;
}
}

412
src/led.c Normal file
View File

@ -0,0 +1,412 @@
#include "tasoller.h"
hsv_t gaControlledIntLedData[LED_NUM_GROUND] = { 0 };
uint8_t gbLedDataIsControlledInt = 0;
uint8_t gu8aControlledExtLedData[32 * 3];
uint8_t gbLedDataIsControlledExt = 0;
volatile uint8_t gu8LEDTx[LED_Tx_BUFFER];
static void (*s_I2C1HandlerFn)(uint32_t u32Status) = NULL;
volatile static uint8_t su8LedTxDataLock = 0;
// Helper definitions
#define SLAVE_RX_ADDR_ACK 0x60
#define SLAVE_RX_ACK 0x80
#define I2C_SLAVE_RX_NACK 0x88
#define I2C_SLAVE_TX_REPEAT_START_STOP 0xA0
#define SLAVE_TX_ACK 0xA8
#define I2C_SLAVE_TX_NACK 0xC0
void I2C1_IRQHandler(void) {
if (I2C_GET_TIMEOUT_FLAG(I2C1)) {
I2C_ClearTimeoutFlag(I2C1);
} else {
if (s_I2C1HandlerFn != NULL) (s_I2C1HandlerFn)(I2C1->I2CSTATUS);
}
}
void I2C1_SlaveTx(uint32_t u32Status) {
static uint8_t su8I2CReadAddr = 0;
switch (u32Status) {
case SLAVE_RX_ACK:
su8I2CReadAddr = I2C1->I2CDAT;
su8LedTxDataLock = 1;
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
break;
case SLAVE_TX_ACK:
I2C_SET_DATA(I2C1, gu8LEDTx[su8I2CReadAddr]);
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
break;
case SLAVE_RX_ADDR_ACK:
case I2C_SLAVE_TX_NACK:
case I2C_SLAVE_RX_NACK:
case I2C_SLAVE_TX_REPEAT_START_STOP:
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
break;
default:
// Hmm?
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
break;
}
}
void LED_I2C1_Init(void) {
I2C_Open(I2C1, 100000);
I2C_SetSlaveAddr(I2C1, 0, 0x18, 0);
I2C_SetSlaveAddr(I2C1, 1, 0x30, 0);
I2C_SetSlaveAddr(I2C1, 2, 0x55, 0);
I2C_SetSlaveAddr(I2C1, 3, 0x18, 0);
I2C_SetSlaveAddrMask(I2C1, 0, 1);
I2C_SetSlaveAddrMask(I2C1, 1, 4);
I2C_SetSlaveAddrMask(I2C1, 2, 1);
I2C_SetSlaveAddrMask(I2C1, 3, 4);
I2C_EnableInt(I2C1);
NVIC_EnableIRQ(I2C1_IRQn);
// I2C1 enter no address SLV mode
I2C_SET_CONTROL_REG(I2C1, I2C_I2CON_SI_AA);
s_I2C1HandlerFn = I2C1_SlaveTx;
}
// static inline void LEDTxLock(void) {
// gu8LEDTx[0] = 0;
// }
// static inline void LEDTxCommit(uint8_t u8Command, uint8_t u8NExpected) {
// gu8LEDTx[0] = u8Command;
// }
/**
* @brief Convert from RGB to HSV
*
* @param pu8aRGB Destination 3-tuple to receive RGB values
* @param u16H Hue, ranging 0~LED_HUE_MAX
* @param u8S Saturation, ranging 0~255
* @param u8V Value, ranging 0~255
*/
void HsvToRgb(uint8_t* pu8aRGB, uint16_t u16H, uint8_t u8S, uint8_t u8V) {
if (u8S == 0) {
pu8aRGB[0] = u8V;
pu8aRGB[1] = u8V;
pu8aRGB[2] = u8V;
return;
}
uint8_t region = u16H / (LED_HUE_MAX / 6);
uint8_t remainder = (u16H - (region * (LED_HUE_MAX / 6))) * (255 / (LED_HUE_MAX / 6));
uint8_t p = (u8V * (255 - u8S)) >> 8;
uint8_t q = (u8V * (255 - ((u8S * remainder) >> 8))) >> 8;
uint8_t t = (u8V * (255 - ((u8S * (255 - remainder)) >> 8))) >> 8;
switch (region) {
case 0:
pu8aRGB[0] = u8V;
pu8aRGB[1] = t;
pu8aRGB[2] = p;
break;
case 1:
pu8aRGB[0] = q;
pu8aRGB[1] = u8V;
pu8aRGB[2] = p;
break;
case 2:
pu8aRGB[0] = p;
pu8aRGB[1] = u8V;
pu8aRGB[2] = t;
break;
case 3:
pu8aRGB[0] = p;
pu8aRGB[1] = q;
pu8aRGB[2] = u8V;
break;
case 4:
pu8aRGB[0] = t;
pu8aRGB[1] = p;
pu8aRGB[2] = u8V;
break;
default:
pu8aRGB[0] = u8V;
pu8aRGB[1] = p;
pu8aRGB[2] = q;
break;
}
return;
}
// 0x00: Normal operation (all other values ignore ground data)
// 0x01: [Stock] Uses colours. Bar 1 full (from right)
// 0x02: [Stock] Uses colours. Bar 2 full (from right)
// 0x03: [Stock] Uses colours. Bar 3 full (from right)
// 0x04: [Stock] Uses colours. Bar 4 full (from right)
// 0x1X: [Stock] All white with black gaps. X bars black (from right)
// 0x1X: [CFW] Rainbow with black gaps. X bars black (from right)
// 0x20: [CFW] Flashes three times
// 0x80: [Stock] Flashes three times
static uint8_t su8LedSpecial = 0x05;
// 0: Separator bar every 4 (4 sections)
// 1: Separator bar every 2 (8 sections)
// 2: Separator bar every 1 (16 sections)
// 3: No separator bars
// 4~7: LEDs off
// For some reason this value can be |8, even though firmware suggests otherwise
static uint8_t su8LedSeparators = 1;
// 0: Invalid, but functions as 1
// 1: 32-key mode
// 2: 16-key mode (same as 32key mode)
// 3: 8-key mode (bars light in pairs)
// 4: 4-key mode (bars light in quads)
static uint8_t su8LedNKey = 1;
// 0x40: Turns off ground LEDs
// 0x80: Turns off wing LEDs
static uint8_t su8LedOff = 0;
// 0x8X: Separator 1~(X+1) lit (ie X ranges from 0~E; F is the same as E)
static uint8_t su8LedCfwRainbow = 0x8F;
void LED_WriteBasicGrounds(void) {
gu8LEDTx[0] = LED_CMD_BASIC;
// 32 bits of grounds
// (01,02)=key1, (04,08)=key2 (10,20)=key3, (40,80)=key4
gu8LEDTx[1] = 0;
gu8LEDTx[2] = 0;
gu8LEDTx[3] = 0;
gu8LEDTx[4] = 0;
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t j = 0; j < 8; j++) {
if (gu8GroundData[i * 8 + j] > PSoC_INTERNAL_DIGITAL_TH) gu8LEDTx[i + 1] |= (1 << j);
}
}
#ifdef LED_FIRMWARE_CFW
gu8LEDTx[5] = 0; // Wing fill
for (uint8_t i = 0; i < 6; i++)
if (gu8DigitalButtons & (1 << (i + 2))) gu8LEDTx[5] |= 1 << i;
gu8LEDTx[6] = su8LedCfwRainbow;
gu8LEDTx[7] = 0; // Unused
#else
// Wings
gu8LEDTx[5] = 0; // Wing fill
for (uint8_t i = 0; i < 6; i++)
if (gu8DigitalButtons & (1 << (i + 2))) gu8LEDTx[5] |= 1 << i;
gu8LEDTx[6] = gConfig.u16HueWingLeft / LED_HUE_SCALE; // Hue left (default 330)
gu8LEDTx[7] = gConfig.u16HueWingRight / LED_HUE_SCALE; // Hue right (default 180)
#endif
// Unused in CFW
gu8LEDTx[8] = gConfig.u16HueGround / LED_HUE_SCALE; // Hue ground inactive (default 45)
gu8LEDTx[9] = gConfig.u16HueGroundActive / LED_HUE_SCALE; // Hue ground active (default 330)
// In CFW only su8LedOff is respected
gu8LEDTx[10] = (su8LedSeparators << 4) | su8LedOff | su8LedNKey;
gu8LEDTx[11] = su8LedSpecial;
}
static const uint8_t su8aWingSensors[LED_NUM_LEFT] = {
DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, DIGITAL_AIR1_Msk, //
DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, DIGITAL_AIR2_Msk, //
DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, DIGITAL_AIR3_Msk, //
DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, DIGITAL_AIR4_Msk, //
DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, DIGITAL_AIR5_Msk, //
DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, DIGITAL_AIR6_Msk, //
};
#define SATURATION_ACTIVE 255
#define SATURATION_INACTIVE 240
#define VALUE_ACTIVE (gConfig.u8LedWingBrightness)
#define VALUE_INACTIVE (gConfig.u8LedWingBrightness / 2)
static void LED_OffGround(void) {
memset((uint8_t*)&gu8LEDTx[LED_DATA_OFFSET], 0, LED_NUM_GROUND * 3);
}
static void LED_OffWings(void) {
memset((uint8_t*)&gu8LEDTx[LED_DATA_OFFSET + LED_NUM_GROUND * 3], 0,
(LED_NUM_LEFT + LED_NUM_RIGHT) * 3);
}
static void LED_AirWings(void) {
uint8_t u8aRgbActive[3];
uint8_t u8aRgbInactive[3];
uint8_t j, i = LED_NUM_GROUND;
// Left wing
HsvToRgb(u8aRgbActive, gConfig.u16HueWingLeft, SATURATION_ACTIVE, VALUE_ACTIVE);
HsvToRgb(u8aRgbInactive, gConfig.u16HueWingLeft, SATURATION_INACTIVE, VALUE_INACTIVE);
for (j = 0; i < LED_NUM_GROUND + LED_NUM_LEFT; i++, j++) {
// GRB
if (gu8DigitalButtons & su8aWingSensors[LED_NUM_LEFT - j - 1]) {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbActive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbActive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbActive[2];
} else {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbInactive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbInactive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbInactive[2];
}
}
// Right wing
HsvToRgb(u8aRgbActive, gConfig.u16HueWingRight, SATURATION_ACTIVE, VALUE_ACTIVE);
HsvToRgb(u8aRgbInactive, gConfig.u16HueWingRight, SATURATION_INACTIVE, VALUE_INACTIVE);
for (j = 0; i < LED_NUM_GROUND + LED_NUM_LEFT + LED_NUM_RIGHT; i++, j++) {
// GRB
if (gu8DigitalButtons & su8aWingSensors[j]) {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbActive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbActive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbActive[2];
} else {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRgbInactive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRgbInactive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRgbInactive[2];
}
}
}
static uint8_t LED_ScaleU8(uint8_t u8V, uint8_t u8Scale) {
return ((uint16_t)u8V * (uint16_t)u8Scale) / 255;
}
static void LED_GroundRainbow(void) {
uint8_t u8aRGB[3];
// 5 ticks * 360 hue = 1800 calls for one cycle (1.8s)
static uint16_t u16Hue = 0;
static uint8_t u8Ticker = 0;
if (++u8Ticker == 5) {
u8Ticker = 0;
u16Hue++;
if (u16Hue == LED_HUE_MAX) u16Hue = 0;
}
/**
* There are 48 LEDs for ground, but we only send 31 values
* They're mapped to the LEDs as follows:
* 00a11b22c33d44f55g66h77i...
*
* That is, we can't split-colour a key :P
*/
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
uint8_t v = 190;
uint8_t h = 0;
uint8_t nCell = i >> 1;
if (i % 2 == 0) {
if (gu16PSoCDigital & (1 << nCell)) {
v = 255;
h = LED_HUE_MAX / 2;
}
} else if (nCell % 4 == 3) {
h = LED_HUE_MAX / 2;
}
// GRB
HsvToRgb(u8aRGB, (u16Hue + h + (i * (LED_HUE_MAX / LED_NUM_GROUND))) % LED_HUE_MAX, v,
LED_ScaleU8(v - 63, gConfig.u8LedGroundBrightness));
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRGB[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRGB[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRGB[2];
}
}
static void LED_GroundStatic(void) {
uint8_t u8aGround[3];
uint8_t u8aGroundActive[3];
HsvToRgb(u8aGround, gConfig.u16HueGround, 255, gConfig.u8LedGroundBrightness);
HsvToRgb(u8aGroundActive, gConfig.u16HueGroundActive, 255, gConfig.u8LedGroundBrightness);
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
const uint8_t nCell = i >> 1;
if (i % 2 == 0) {
// This is a cell. Light it according to the touch input
if (gu16PSoCDigital & (1 << nCell)) {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
} else {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGround[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGround[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGround[2];
}
} else if (nCell % 4 == 3) {
// This is a separating divider. Light it with the active colour
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
} else {
// This is a non-separating divider. Light it based on the two cells either side
if (gu16PSoCDigital & (1 << nCell) && gu16PSoCDigital & (1 << (nCell + 1))) {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGroundActive[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGroundActive[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGroundActive[2];
} else {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aGround[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aGround[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aGround[2];
}
}
}
}
void LED_WriteRGB(void) {
gu8LEDTx[0] = LED_CMD_RGB_FULL;
#ifdef LED_FIRMWARE_CFW
// "CFW" added this byte
gu8LEDTx[1] = su8LedSpecial | su8LedOff;
#endif
// Even when grounds are disabled, internal control overrides that
if (gbLedDataIsControlledInt) {
PIN_LED_GROUND_PWR = 1;
uint8_t u8aRGB[3];
// Convert from HSV to GRB
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
HsvToRgb(u8aRGB, gaControlledIntLedData[LED_NUM_GROUND - i - 1].u16H,
gaControlledIntLedData[LED_NUM_GROUND - i - 1].u8S,
gaControlledIntLedData[LED_NUM_GROUND - i - 1].u8V);
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] = u8aRGB[1];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] = u8aRGB[0];
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] = u8aRGB[2];
}
} else if (gConfig.u8LedGroundBrightness) {
PIN_LED_GROUND_PWR = 1;
if (gbLedDataIsControlledExt) {
// Swap from BRG to GRB
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 0] =
LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 2], gConfig.u8LedGroundBrightness);
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 1] =
LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 1], gConfig.u8LedGroundBrightness);
gu8LEDTx[LED_DATA_OFFSET + i * 3 + 2] =
LED_ScaleU8(gu8aControlledExtLedData[i * 3 + 0], gConfig.u8LedGroundBrightness);
}
} else if (gConfig.bEnableRainbow) {
LED_GroundRainbow();
} else {
LED_GroundStatic();
}
} else {
PIN_LED_GROUND_PWR = 0;
LED_OffGround();
}
if (gConfig.u8LedWingBrightness) {
PIN_LED_WING_PWR = 1;
// TODO: Get data from game when gbLedDataIsControlledExt (HID, probably)
LED_AirWings();
} else {
PIN_LED_WING_PWR = 0;
LED_OffWings();
}
}

73
src/led.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include <stdint.h>
#define LED_FIRMWARE_CFW
#ifndef LED_FIRMWARE_CFW
#define LED_DATA_OFFSET 1
#else
#define LED_DATA_OFFSET 2
#endif
// LED count definitions
#define LED_NUM_GROUND 31
#define LED_NUM_LEFT 24
#define LED_NUM_RIGHT 24
// HSV definitions
#define LED_HUE_SCALE 5 // For transmission to LED board in basic mode
#define LED_HUE_MAX 360
// Host->LED MCU commands
#define LED_CMD_BASIC 0xA5
#define LED_CMD_RGB_FULL 0x5A
// LED index names
#define LED_CELL_0 0
#define LED_CELL_1 2
#define LED_CELL_2 4
#define LED_CELL_3 6
#define LED_CELL_4 8
#define LED_CELL_5 10
#define LED_CELL_6 12
#define LED_CELL_7 14
#define LED_CELL_8 16
#define LED_CELL_9 18
#define LED_CELL_10 20
#define LED_CELL_11 22
#define LED_CELL_12 24
#define LED_CELL_13 26
#define LED_CELL_14 28
#define LED_CELL_15 30
#define LED_DIVIDER_0_1 1
#define LED_DIVIDER_1_2 3
#define LED_DIVIDER_2_3 5
#define LED_DIVIDER_3_4 7
#define LED_DIVIDER_4_5 9
#define LED_DIVIDER_5_6 11
#define LED_DIVIDER_6_7 13
#define LED_DIVIDER_7_8 15
#define LED_DIVIDER_8_9 17
#define LED_DIVIDER_9_10 19
#define LED_DIVIDER_10_11 21
#define LED_DIVIDER_11_12 23
#define LED_DIVIDER_12_13 25
#define LED_DIVIDER_13_14 27
#define LED_DIVIDER_14_15 29
typedef struct {
uint16_t u16H;
uint8_t u8S;
uint8_t u8V;
} hsv_t;
// Internal LED control, from the settings UI (gets priority)
extern hsv_t gaControlledIntLedData[LED_NUM_GROUND];
extern uint8_t gbLedDataIsControlledInt;
// External LED control, from the game
extern uint8_t gu8aControlledExtLedData[32 * 3];
extern uint8_t gbLedDataIsControlledExt;
void LED_I2C1_Init(void);
void LED_WriteBasicGrounds(void);
void LED_WriteRGB(void);

138
src/main.c Normal file
View File

@ -0,0 +1,138 @@
#include "tasoller.h"
uint8_t volatile gu8HIDIO4Ready = 0;
uint8_t volatile gu8HIDMiscReady = 0;
#define DEBOUNCE_COUNT 8
uint8_t TickDebouncer(uint8_t u8Buttons) {
static uint8_t u8Counters[8] = { 0 };
uint8_t debounced = 0;
for (uint8_t i = 0; i < 8; i++) {
if (u8Buttons & (1 << i))
u8Counters[i] = 0;
else if (u8Counters[i] < DEBOUNCE_COUNT)
u8Counters[i]++;
if (u8Counters[i] < DEBOUNCE_COUNT) debounced |= (1 << i);
}
return debounced;
}
uint8_t gu8DigitalButtons;
#define DELAY_FN 2
#define DELAY_AIR 2
void Digital_TickInputs() {
uint8_t u8Buttons = 0;
GPIO_SetMode(_PIN_FN1, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_FN);
GPIO_SetMode(_PIN_FN1, GPIO_PMD_QUASI);
u8Buttons |= PIN_FN1 ? 0 : DIGITAL_FN1_Msk;
GPIO_SetMode(_PIN_FN2, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_FN);
GPIO_SetMode(_PIN_FN2, GPIO_PMD_QUASI);
u8Buttons |= PIN_FN2 ? 0 : DIGITAL_FN2_Msk;
GPIO_SetMode(_PIN_AIR1, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR1, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR1 ? DIGITAL_AIR1_Msk : 0;
GPIO_SetMode(_PIN_AIR2, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR2, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR2 ? DIGITAL_AIR2_Msk : 0;
GPIO_SetMode(_PIN_AIR3, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR3, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR3 ? DIGITAL_AIR3_Msk : 0;
GPIO_SetMode(_PIN_AIR4, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR4, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR4 ? DIGITAL_AIR4_Msk : 0;
GPIO_SetMode(_PIN_AIR5, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR5, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR5 ? DIGITAL_AIR5_Msk : 0;
GPIO_SetMode(_PIN_AIR6, GPIO_PMD_INPUT);
DelayCycles_Small(DELAY_AIR);
GPIO_SetMode(_PIN_AIR6, GPIO_PMD_QUASI);
u8Buttons |= PIN_AIR6 ? DIGITAL_AIR6_Msk : 0;
gu8DigitalButtons = TickDebouncer(u8Buttons);
}
int _entry(void) {
SYS_UnlockReg();
SYS_Init();
#ifdef ENABLE_BOOTLOADER_CHECK
SYS_Bootloader_Check();
#endif
SYS_ModuleInit();
FMC_EEPROM_Load();
gu8VcomReady = 1;
gu8HIDIO4Ready = 1;
gu8HIDMiscReady = 1;
/**
* Unfortunately, everything related to this seems to be a bit broken at the moment
* For some reason, this code gets into infinite loops on cold boots, even with 5 seconds of
* delay added first.
* To make matters worse, if we ever actually call PSoCSetFingerCapacitance it ends up with
* huge asymmetry between the two PSoCs, which is just unworkable.
*/
// uint16_t u16InitialFingerCap = PSoCGetFingerCapacitance();
// if (u16InitialFingerCap != gu16PSoCFingerCap) {
// PSoCSetFingerCapacitance(gu16PSoCFingerCap);
// }
static uint32_t su32NowMs = 0;
su32NowMs++;
while (1) {
USB_VCOM_Tick();
if (bPSoCDirty) {
bPSoCDirty = 0;
PSoC_PostProcessing();
}
Slider_TickSerial();
USBD_HID_PrepareReport();
// Limit this to 250us so our debouncer has a chance to function
// 250us is the resolution of our timer currently, though we could increase it if needed
if (gu8Do250usTick) {
Digital_TickInputs();
}
if (gu8Do1msTick) {
su32NowMs++;
gu8Do1msTick = 0;
Slider_Tick1ms();
PSoC_DigitalCalc();
UI_Tick();
// LED_WriteBasicGrounds();
LED_WriteRGB();
} /* else {
DelayCycles(45);
}*/
// Wait until we know both PSoC are awake and talking before we attempt configure them
if (gu8PSoCSeenData == 0b011) {
PSoC_SetFingerCapacitanceFromConfig();
gu8PSoCSeenData |= 0b100;
}
FMC_EEPROM_Store();
}
}

64
src/pins.h Normal file
View File

@ -0,0 +1,64 @@
#define PIN_SDA PA10
#define PIN_SCL PA11
#define PIN_USB_MUX_EN PB1
#define PIN_USB_MUX_SEL PB0
#define PIN_FN1 PB7
#define PIN_FN2 PB2
#define PIN_EC1 PB3
#define PIN_EC2 PC5
#define PIN_EC3 PC4
#define PIN_RX2 PD9
#define PIN_RX3 PD10
#define PIN_RX4 PD11
#define PIN_LED_WING_PWR PB13
#define PIN_LED_GROUND_PWR PC3
#define _PIN_SDA PA, BIT10
#define _PIN_SCL PA, BIT11
#define _PIN_USB_MUX_EN PB, BIT1
#define _PIN_USB_MUX_SEL PB, BIT0
#define _PIN_FN1 PB, BIT7
#define _PIN_FN2 PB, BIT2
#define _PIN_EC1 PB, BIT3
#define _PIN_EC2 PC, BIT5
#define _PIN_EC3 PC, BIT4
#define _PIN_RX2 PD, BIT9
#define _PIN_RX3 PD, BIT10
#define _PIN_RX4 PD, BIT11
#define _PIN_LED_WING_PWR PB, BIT13
#define _PIN_LED_GROUND_PWR PC, BIT3
#define PIN_AIR1 PIN_RX2
#define PIN_AIR2 PIN_EC1
#define PIN_AIR3 PIN_RX3
#define PIN_AIR4 PIN_EC2
#define PIN_AIR5 PIN_RX4
#define PIN_AIR6 PIN_EC3
#define _PIN_AIR1 _PIN_RX2
#define _PIN_AIR2 _PIN_EC1
#define _PIN_AIR3 _PIN_RX3
#define _PIN_AIR4 _PIN_EC2
#define _PIN_AIR5 _PIN_RX4
#define _PIN_AIR6 _PIN_EC3
#define USB_MUX_ENABLE 0
#define USB_MUX_DISABLE 1
#define USB_MUX_HOST 0
#define USB_MUX_LEDS 1
#define DIGITAL_FN1_Pos 0
#define DIGITAL_FN2_Pos 1
#define DIGITAL_AIR1_Pos 2
#define DIGITAL_AIR2_Pos 3
#define DIGITAL_AIR3_Pos 4
#define DIGITAL_AIR4_Pos 5
#define DIGITAL_AIR5_Pos 6
#define DIGITAL_AIR6_Pos 7
#define DIGITAL_FN1_Msk (1 << DIGITAL_FN1_Pos)
#define DIGITAL_FN2_Msk (1 << DIGITAL_FN2_Pos)
#define DIGITAL_AIR1_Msk (1 << DIGITAL_AIR1_Pos)
#define DIGITAL_AIR2_Msk (1 << DIGITAL_AIR2_Pos)
#define DIGITAL_AIR3_Msk (1 << DIGITAL_AIR3_Pos)
#define DIGITAL_AIR4_Msk (1 << DIGITAL_AIR4_Pos)
#define DIGITAL_AIR5_Msk (1 << DIGITAL_AIR5_Pos)
#define DIGITAL_AIR6_Msk (1 << DIGITAL_AIR6_Pos)

292
src/psoc.c Normal file
View File

@ -0,0 +1,292 @@
#include "tasoller.h"
uint16_t gu16PSoCDiff[32] = { 0 };
uint32_t gu32PSoCDigital = 0;
uint32_t gu32PSoCDigitalPos = 0;
uint32_t gu32PSoCDigitalNeg = 0;
uint32_t gu32PSoCDigitalTrig = 0;
uint16_t gu16PSoCDigital = 0;
uint16_t gu16PSoCDigitalPos = 0;
uint16_t gu16PSoCDigitalNeg = 0;
uint16_t gu16PSoCDigitalTrig = 0;
uint8_t gu8PSoCSeenData = 0;
volatile uint8_t bPSoCDirty = 0;
static void* pu8PsocRxDestination = NULL;
static uint8_t pu8PsocRxDestinationLen = 0;
static volatile uint8_t* pu8PsocGotData = NULL;
static void PSoC_HandleRx(PSoC_CMD_RX eCmd, uint8_t u8Len, uint8_t* u8Data) {
if (eCmd != PSoC_CMD_RX_SLAVE_DIFF && eCmd != PSoC_CMD_RX_MASTER_DIFF &&
eCmd != PSoC_CMD_RX_CS_START) {
static uint8_t debug = 0;
debug++;
}
uint8_t u8PsocDataOffset = 0;
switch (eCmd) {
case PSoC_CMD_RX_REQUEST_FINGER_CAP:
PSoC_SetFingerCapacitanceFromConfig();
return;
// We don't care about these
case PSoC_CMD_RX_CS_START:
case PSoC_CMD_RX_CS_END:
return;
case PSoC_CMD_RX_SLAVE_DIFF:
u8PsocDataOffset = 16;
gu8PSoCSeenData |= 1;
// Falls through
case PSoC_CMD_RX_MASTER_DIFF:
if (eCmd == PSoC_CMD_RX_MASTER_DIFF) gu8PSoCSeenData |= 2;
if (u8Len != 32) return;
for (uint8_t i = 0; i < 16; i++) {
gu16PSoCDiff[u8PsocDataOffset + i] = u8Data[(i * 2)] << 8;
gu16PSoCDiff[u8PsocDataOffset + i] |= u8Data[(i * 2) + 1];
}
bPSoCDirty = 1;
return;
// Arbitrary data reception
case PSoC_CMD_RX_MASTER_TOUCH_TH:
case PSoC_CMD_RX_SLAVE_TOUCH_TH:
case PSoC_CMD_RX_MASTER_FINGER_TH:
case PSoC_CMD_RX_MASTER_HYSTERESIS:
case PSoC_CMD_RX_SLAVE_FINGER_TH:
case PSoC_CMD_RX_SLAVE_HYSTERESIS:
case PSoC_CMD_RX_GET_FINGER_CAP:
case PSoC_CMD_RX_SET_FINGER_CAP:
if (pu8PsocRxDestination) {
if (u8Len > pu8PsocRxDestinationLen) u8Len = pu8PsocRxDestinationLen;
memcpy(pu8PsocRxDestination, u8Data, u8Len);
// Make sure we don't go clobbering stuff later!
pu8PsocRxDestination = NULL;
}
if (pu8PsocGotData) {
*pu8PsocGotData = 1;
// Make sure we don't go clobbering stuff later!
pu8PsocGotData = NULL;
}
return;
}
}
void UART1_IRQHandler(void) {
static uint8_t su8RxData[32] = { 0 };
static uint8_t su8State = 0;
static PSoC_CMD_RX eCmd = 0;
static uint8_t su8Len = 0;
static uint8_t su8Index = 0;
static uint8_t su8Sum = 0;
// We only care about data interrupts
if (!(UART1->ISR & (UART_ISR_RDA_INT_Msk | UART_ISR_TOUT_INT_Msk))) return;
uint8_t u8Data = UART_READ(UART1);
switch (su8State) {
case 0:
eCmd = u8Data; // For debugging
switch (u8Data) {
// Just go away
case PSoC_CMD_RX_CS_START:
case PSoC_CMD_RX_CS_END:
return;
// Commands with no payload
case PSoC_CMD_RX_SET_FINGER_CAP:
PSoC_HandleRx(u8Data, 0, NULL);
return;
// Commands that have a payload we need to receive
case PSoC_CMD_RX_REQUEST_FINGER_CAP:
case PSoC_CMD_RX_MASTER_DIFF:
case PSoC_CMD_RX_SLAVE_DIFF:
case PSoC_CMD_RX_MASTER_TOUCH_TH:
case PSoC_CMD_RX_SLAVE_TOUCH_TH:
case PSoC_CMD_RX_MASTER_FINGER_TH:
case PSoC_CMD_RX_MASTER_HYSTERESIS:
case PSoC_CMD_RX_SLAVE_FINGER_TH:
case PSoC_CMD_RX_SLAVE_HYSTERESIS:
case PSoC_CMD_RX_GET_FINGER_CAP:
eCmd = u8Data;
su8Sum = u8Data;
su8State++;
return;
}
return;
case 1:
su8Len = u8Data;
su8Index = 0;
su8Sum += u8Data;
su8State++;
// If there's no payload to receive, skip that step
if (!su8Len) su8State++;
// Packets too large for reception need dropped
if (su8Len > sizeof su8RxData) su8State = 0;
return;
case 2:
su8Sum += u8Data;
su8RxData[su8Index++] = u8Data;
if (su8Index == su8Len) su8State++;
return;
case 3:
// Only process packets with a valid checksum
if (su8Sum == u8Data) PSoC_HandleRx(eCmd, su8Len, su8RxData);
su8State = 0;
return;
// If we somehow land in an invalid state (should be impossible), make sure we can recover
default:
su8State = 0;
return;
}
}
static inline void PSoC_Cmd(PSoC_CMD_TX eCmd, uint8_t u8D0, uint8_t u8D1, uint8_t u8Blocking) {
static uint8_t su8Ready = 0;
if (u8Blocking) {
su8Ready = 0;
pu8PsocGotData = &su8Ready;
}
static uint8_t u8Packet[5];
u8Packet[0] = eCmd;
u8Packet[1] = 2;
u8Packet[2] = u8D0;
u8Packet[3] = u8D1;
u8Packet[4] = eCmd + 2 + u8D0 + u8D1;
for (uint8_t i = 0; i < 5; i++) {
while (UART_IS_TX_FULL(UART1))
;
UART_WRITE(UART1, u8Packet[i]);
}
if (u8Blocking) {
while (!su8Ready)
;
}
}
uint16_t PSoC_GetFingerCapacitance(void) {
uint16_t u16FingerCap;
pu8PsocRxDestination = &u16FingerCap;
pu8PsocRxDestinationLen = sizeof u16FingerCap;
PSoC_Cmd(PSoC_CMD_TX_GET_FINGER_CAP, 0, 0, 1);
return u16FingerCap;
// Swap endian
// return (u16FingerCap >> 8) | ((u16FingerCap & 0xff) << 8);
}
void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data, volatile uint8_t* pu8Ready) {
pu8PsocGotData = pu8Ready;
pu8PsocRxDestination = pu8Data;
pu8PsocRxDestinationLen = 32;
PSoC_Cmd(PSoC_CMD_TX_GET_DEBUG, 0, u8Cmd, 0);
}
void PSoC_SetFingerCapacitance(uint16_t u16FingerCap) {
if (u16FingerCap > 1023) u16FingerCap = 1023;
// PSoC_Cmd(PSoC_CMD_TX_SET_FINGER_CAP, u16FingerCap >> 8, u16FingerCap & 0xff, 1);
PSoC_Cmd(PSoC_CMD_TX_SET_FINGER_CAP, u16FingerCap >> 8, u16FingerCap & 0xff, 1);
}
void PSoC_SetFingerCapacitanceFromConfig(void) {
PSoC_SetFingerCapacitance(PSoC_FINGER_CAP_MIN + (16 - gConfig.u8Sens) * PSoC_FINGER_CAP_STEP);
}
void PSoC_EnableDebug(uint8_t u8D1, uint8_t u8D2) {
// TODO: Finish figuring out what values these two bytes need
PSoC_Cmd(PSoC_CMD_TX_ENABLE_DEBUG, u8D1, u8D2, 1);
}
uint8_t gu8GroundData[32];
// These are used to uniformly narrow the min/max gap
// #define SCALE_OFFSET_MIN 150
// #define SCALE_OFFSET_MIN 100
// #define SCALE_OFFSET_MAX 450
void PSoC_PostProcessing(void) {
// Process the raw PSoC data to compute our external 0-255 values
for (uint8_t i = 0; i < 32; i++) {
uint8_t j = (15 - (i / 2)) * 2 + (i & 1);
const uint16_t u16Pad = gu16PSoCDiff[i];
const uint16_t u16Min = gConfig.u16PSoCScaleMin[i]; // + SCALE_OFFSET_MIN;
const uint16_t u16Max = gConfig.u16PSoCScaleMax[i]; // - SCALE_OFFSET_MAX;
if (u16Pad < u16Min) {
gu8GroundData[j] = 0;
} else if (u16Pad > u16Max) {
gu8GroundData[j] = 255;
} else {
// Multiply by 255 first to retain precision
// This can overflow u16, hence the u32 cast pre-mult
gu8GroundData[j] = ((uint32_t)(u16Pad - u16Min) * 255) / (u16Max - u16Min);
}
}
}
/**
* @brief Calculate digital input data from PSoC values
*
* Must be called at exactly 1ms intervals
*
* Trigger will activate once, a 200ms delay, then again every 5ms.
*/
void PSoC_DigitalCalc(void) {
// Calculate digital data for 32 pads
uint32_t u32Previous = gu32PSoCDigital;
gu32PSoCDigital = 0;
for (uint8_t i = 0; i < 32; i++) {
if (gu8GroundData[i] > PSoC_INTERNAL_DIGITAL_TH) {
gu32PSoCDigital |= (1 << i);
}
}
gu32PSoCDigitalPos = gu32PSoCDigital & ~u32Previous;
gu32PSoCDigitalNeg = u32Previous & ~gu32PSoCDigital;
gu32PSoCDigitalTrig = gu32PSoCDigitalPos;
// Calculate digital data for 16 cells
uint16_t u16Previous = gu16PSoCDigital;
gu16PSoCDigital = 0;
for (uint8_t i = 0; i < 16; i++) {
if (gu8GroundData[i * 2] > PSoC_INTERNAL_DIGITAL_TH ||
gu8GroundData[i * 2 + 1] > PSoC_INTERNAL_DIGITAL_TH) {
gu16PSoCDigital |= (1 << i);
}
}
gu16PSoCDigitalPos = gu16PSoCDigital & ~u16Previous;
gu16PSoCDigitalNeg = u16Previous & ~gu16PSoCDigital;
gu16PSoCDigitalTrig = gu16PSoCDigitalPos;
static uint8_t u8TriggerCounter = 0;
if (++u8TriggerCounter != 5) return;
u8TriggerCounter = 0;
static uint8_t u8a16TriggerCounter[16] = { 0 };
for (uint8_t i = 0; i < 16; i++) {
if (!(gu16PSoCDigital & (1 << i))) {
u8a16TriggerCounter[i] = 0;
} else if (u8a16TriggerCounter[i] == 200 / 5) {
// High-speed repeat
gu16PSoCDigitalTrig |= (1 << i);
} else {
// Counter up to high-speed
u8a16TriggerCounter[i]++;
}
}
static uint8_t u8a32TriggerCounter[32] = { 0 };
for (uint8_t i = 0; i < 32; i++) {
if (!(gu32PSoCDigital & (1 << i))) {
u8a32TriggerCounter[i] = 0;
} else if (u8a32TriggerCounter[i] == 200 / 5) {
// High-speed repeat
gu32PSoCDigitalTrig |= (1 << i);
} else {
// Counter up to high-speed
u8a32TriggerCounter[i]++;
}
}
}

110
src/psoc.h Normal file
View File

@ -0,0 +1,110 @@
#pragma once
#include <stdint.h>
#define PSoC_DATA_SIZE 32
#define PSoC_PACKET_SIZE (2 + PSoC_DATA_SIZE)
// Used for calculation of PSoC_FINGER_CAP_MIN
// The difference between CAP and MIN must be divisible by 8
#define PSoC_FINGER_CAP_MIN 20 // 0.2pF
#define PSoC_DEFAULT_CAP 340 // 3.2pF
// Maximum is CAP*2-MIN*2 ie 6.0pF
#define PSoC_FINGER_CAP_STEP ((PSoC_DEFAULT_CAP - PSoC_FINGER_CAP_MIN) / 8)
typedef enum {
// Host -> PSoC
PSoC_CMD_TX_GET_FINGER_CAP = 0xB5,
PSoC_CMD_TX_GET_DEBUG = 0xB6,
PSoC_CMD_TX_SET_FINGER_CAP = 0xBD,
PSoC_CMD_TX_ENABLE_DEBUG = 0xDE,
} PSoC_CMD_TX;
typedef enum {
// PSoC -> Host
PSoC_CMD_RX_MASTER_DIFF = 0xAD,
PSoC_CMD_RX_SLAVE_DIFF = 0xAF,
PSoC_CMD_RX_REQUEST_FINGER_CAP = 0xC1,
// PSoC -> Host (Debug)
PSoC_CMD_RX_MASTER_TOUCH_TH = 0xAA,
PSoC_CMD_RX_SLAVE_TOUCH_TH = 0xAB,
PSoC_CMD_RX_MASTER_FINGER_TH = 0xA0,
PSoC_CMD_RX_MASTER_HYSTERESIS = 0xA1,
PSoC_CMD_RX_SLAVE_FINGER_TH = 0xA2,
PSoC_CMD_RX_SLAVE_HYSTERESIS = 0xA3,
PSoC_CMD_RX_CS_START = 0x00,
PSoC_CMD_RX_CS_END = 0xFF,
// Packets that get a direct response
PSoC_CMD_RX_GET_FINGER_CAP = PSoC_CMD_TX_GET_FINGER_CAP,
PSoC_CMD_RX_SET_FINGER_CAP = PSoC_CMD_TX_SET_FINGER_CAP,
} PSoC_CMD_RX;
typedef enum {
PSoC_CMD_DEBUG_MASTER_TOUCH_TH = 0,
PSoC_CMD_DEBUG_SLAVE_TOUCH_TH,
PSoC_CMD_DEBUG_MASTER_FINGER_TH,
PSoC_CMD_DEBUG_SLAVE_FINGER_TH,
PSoC_CMD_DEBUG_MASTER_HYSTERESIS,
PSoC_CMD_DEBUG_SLAVE_HYSTERESIS,
} PSoC_CMD_DEBUG;
// Difference between the raw count value and the baseline, from SmartSense
extern uint16_t gu16PSoCDiff[32];
// Has the difference data changed?
extern volatile uint8_t bPSoCDirty;
// Used for producing gu32PSoCDigital and gu16PSoCDigital
#define PSoC_INTERNAL_DIGITAL_TH 0
// PSoC data, re-interpreted as digital inputs
extern uint32_t gu32PSoCDigital;
extern uint32_t gu32PSoCDigitalPos;
extern uint32_t gu32PSoCDigitalNeg;
extern uint32_t gu32PSoCDigitalTrig;
extern uint16_t gu16PSoCDigital;
extern uint16_t gu16PSoCDigitalPos;
extern uint16_t gu16PSoCDigitalNeg;
extern uint16_t gu16PSoCDigitalTrig;
extern uint8_t gu8PSoCSeenData;
#define PSoC_RAW_T0 34
#define PSoC_RAW_T1 91
#define PSoC_RAW_T2 121
#define PSoC_RAW_MIN 199
#define PSoC_SCALE 5 // ie to scale from [0~4ff] to [0~ff]
#define PSoC_OUT_MIN 20
#define PSoC_OUT_MAX 255
#define PSoC_SCALE_MIN (0 + 128)
#define PSoC_SCALE_MAX (0x4ff - 128 - 256)
#define PSoC_SCALE_RANGE (3) // ie to scale from [min~max] to [0~ff]
void PSoC_PostProcessing(void);
void PSoC_DigitalCalc(void);
// General usage PSoC commands; return instantly
void PSoC_SetFingerCapacitance(uint16_t u16FingerCap);
void PSoC_SetFingerCapacitanceFromConfig(void);
/**
* @brief Get the finger capacitance value currently configured on the Master PSoC
*
* Warning! This function is BLOCKING. Calls are likely to take at least 15ms
*/
uint16_t PSoC_GetFingerCapacitance(void);
/**
* @brief Request a debug array from the PSoC pair
*
* This call is asynchronous. Use pu8Ready to ensure pu8Data is ready.
* Only one call can be in-flight at once.
* **DO NOT** call PSoCGetFingerCapacitance while waiting on this function.
*
* @param u8Cmd The specific debug array to request
* @param pu8Data Pointer to array that will receive the data. Must be 32 bytes.
* @param pu8Ready Optional uint8_t to signal the data is ready
*/
void PSoC_GetDebug(PSoC_CMD_DEBUG u8Cmd, uint8_t* pu8Data, volatile uint8_t* pu8Ready);
void PSoC_EnableDebug(uint8_t u8D1, uint8_t u8D2);

177
src/slider.c Normal file
View File

@ -0,0 +1,177 @@
#include "tasoller.h"
#define SLIDER_SYNC 0xFF
#define SLIDER_MARK 0xFD
static uint8_t su8AutoEnabled = 0;
static uint8_t su8GotLedData = 0;
static uint32_t su32SinceLastControlled = 0;
typedef enum {
SLIDER_PARSE_SYNC_WAIT = 0,
SLIDER_PARSE_CMD,
SLIDER_PARSE_NDATA,
SLIDER_PARSE_DATA,
SLIDER_PARSE_CHECKSUM,
} slider_parse_state;
typedef enum {
SLIDER_CMD_AUTO = 0x01,
SLIDER_CMD_SET_LED = 0x02,
SLIDER_CMD_AUTO_START = 0x03,
SLIDER_CMD_AUTO_STOP = 0x04,
SLIDER_CMD_RESET = 0x10,
SLIDER_CMD_GET_BOARD_INFO = 0xF0,
} slider_cmd;
static const uint8_t su8SliderVersion[32] = {
'1', '5', '3', '3', '0', ' ', ' ', ' ', 0xA0,
'0', '6', '7', '1', '2', 0xFF,
0x90,
};
static inline void Slider_Write(uint8_t u8Byte) {
if (u8Byte == SLIDER_SYNC || u8Byte == SLIDER_MARK) {
USB_VCOM_Write(SLIDER_MARK);
u8Byte--;
}
USB_VCOM_Write(u8Byte);
}
static void Slider_Respond(slider_cmd u8SliderCmd, const uint8_t* pu8Packet, uint8_t u8NPacket) {
uint8_t u8Sum = SLIDER_SYNC + u8SliderCmd + u8NPacket;
USB_VCOM_Write(SLIDER_SYNC); // We don't want to escape sync!
Slider_Write(u8SliderCmd);
Slider_Write(u8NPacket);
for (uint16_t i = 0; i < u8NPacket; i++) {
u8Sum += pu8Packet[i];
Slider_Write(pu8Packet[i]);
}
Slider_Write(-u8Sum);
}
static void Slider_Process(slider_cmd u8SliderCmd, uint8_t* pu8Packet, uint8_t u8NPacket) {
switch (u8SliderCmd) {
case SLIDER_CMD_RESET:
// Hmm? Do we not need to <su8AutoEnabled = 0;> here?
Slider_Respond(SLIDER_CMD_RESET, NULL, 0);
return;
case SLIDER_CMD_GET_BOARD_INFO:
Slider_Respond(SLIDER_CMD_GET_BOARD_INFO, su8SliderVersion, sizeof su8SliderVersion);
return;
case SLIDER_CMD_SET_LED:
// TODO: What is the first byte of data? (00h and 28h observed)
// Why are there 32 triples?
if (u8NPacket == 1 + 0x60) {
gbLedDataIsControlledExt = 1;
su32SinceLastControlled = 0;
memcpy(gu8aControlledExtLedData, &pu8Packet[1], 3 * 32);
}
su8GotLedData = 1;
// No response
return;
case SLIDER_CMD_AUTO_START:
su8AutoEnabled = 1;
su8GotLedData = 1;
// No response
return;
case SLIDER_CMD_AUTO_STOP:
// Purge any Tx buffer from the auto sending
if (su8AutoEnabled) USB_VCOM_PurgeTx();
su8AutoEnabled = 0;
Slider_Respond(SLIDER_CMD_AUTO_STOP, NULL, 0);
return;
// This is an outbound-only command, so we should never see it here!
case SLIDER_CMD_AUTO:
default:
return;
}
}
void Slider_TickSerial(void) {
/**
* Byte 0: FF
* Byte 1: Command
* Byte 2: Length (n)
* Byte [3~2+n]: Data
* Byte [3+n]: Checksum
*
* Byte FD is escape; the next byte should +1'd
*/
static slider_parse_state su8State = SLIDER_PARSE_SYNC_WAIT;
static uint8_t u8Mark = 0;
static uint8_t u8NPacket = 0;
static uint8_t u8NRead = 0;
static uint8_t u8Sum = 0;
static uint8_t u8SliderCmd = 0;
static uint8_t u8Packet[0x61]; // The largest inbound packet expected is to set LEDs
// Make sure we flush the buffer!
while (USB_VCOM_Available()) {
uint8_t u8Byte = USB_VCOM_Read();
if (u8Byte == SLIDER_MARK) {
u8Mark = 1;
continue;
} else if (u8Mark) {
u8Mark = 0;
// TODO: If u8Byte is 0xFD we should technically give up here
u8Byte++;
}
u8Sum += u8Byte;
switch (su8State) {
case SLIDER_PARSE_SYNC_WAIT:
u8Sum = 0xff;
if (u8Byte == SLIDER_SYNC) su8State = SLIDER_PARSE_CMD;
break;
case SLIDER_PARSE_CMD:
u8SliderCmd = u8Byte;
su8State = SLIDER_PARSE_NDATA;
break;
case SLIDER_PARSE_NDATA:
u8NPacket = u8Byte;
u8NRead = 0;
su8State = SLIDER_PARSE_DATA;
// If this is more data than we could handle, just give up
if (u8NPacket > sizeof u8Packet) su8State = SLIDER_PARSE_SYNC_WAIT;
// If there's nothing to do.. do nothing!
if (u8NPacket == 0) su8State = SLIDER_PARSE_CHECKSUM;
break;
case SLIDER_PARSE_DATA:
u8Packet[u8NRead++] = u8Byte;
if (u8NRead == u8NPacket) su8State = SLIDER_PARSE_CHECKSUM;
break;
case SLIDER_PARSE_CHECKSUM:
// Only handle the packet if the sum equaled out
if (u8Sum == 0) Slider_Process(u8SliderCmd, u8Packet, u8NPacket);
su8State = SLIDER_PARSE_SYNC_WAIT;
break;
}
}
}
void Slider_Tick1ms() {
if (gbLedDataIsControlledExt) {
// If we haven't had an LED packet in 5 seconds, call it quits
if (++su32SinceLastControlled == 5 * 1000) gbLedDataIsControlledExt = 0;
}
if (su8AutoEnabled) {
static uint8_t u8Counter = 0;
// Only actually send an update every 8ms
if (++u8Counter != 8) return;
u8Counter = 0;
Slider_Respond(SLIDER_CMD_AUTO, gu8GroundData, sizeof gu8GroundData);
}
}

53
src/slider.h Normal file
View File

@ -0,0 +1,53 @@
// 16 cells (0-15)
#define CELL_0_Msk BIT15
#define CELL_1_Msk BIT14
#define CELL_2_Msk BIT13
#define CELL_3_Msk BIT12
#define CELL_4_Msk BIT11
#define CELL_5_Msk BIT10
#define CELL_6_Msk BIT9
#define CELL_7_Msk BIT8
#define CELL_8_Msk BIT7
#define CELL_9_Msk BIT6
#define CELL_10_Msk BIT5
#define CELL_11_Msk BIT4
#define CELL_12_Msk BIT3
#define CELL_13_Msk BIT2
#define CELL_14_Msk BIT1
#define CELL_15_Msk BIT0
// 32 pads (1-32)
#define PAD_1_Msk BIT30
#define PAD_2_Msk BIT31
#define PAD_3_Msk BIT28
#define PAD_4_Msk BIT29
#define PAD_5_Msk BIT26
#define PAD_6_Msk BIT27
#define PAD_7_Msk BIT24
#define PAD_8_Msk BIT25
#define PAD_9_Msk BIT22
#define PAD_10_Msk BIT23
#define PAD_11_Msk BIT20
#define PAD_12_Msk BIT21
#define PAD_13_Msk BIT18
#define PAD_14_Msk BIT19
#define PAD_15_Msk BIT16
#define PAD_16_Msk BIT17
#define PAD_17_Msk BIT14
#define PAD_18_Msk BIT15
#define PAD_19_Msk BIT12
#define PAD_20_Msk BIT13
#define PAD_21_Msk BIT10
#define PAD_22_Msk BIT11
#define PAD_23_Msk BIT8
#define PAD_24_Msk BIT9
#define PAD_25_Msk BIT6
#define PAD_26_Msk BIT7
#define PAD_27_Msk BIT4
#define PAD_28_Msk BIT5
#define PAD_29_Msk BIT2
#define PAD_30_Msk BIT3
#define PAD_31_Msk BIT0
#define PAD_32_Msk BIT1
void Slider_TickSerial(void);
void Slider_Tick1ms(void);

158
src/sys.c Normal file
View File

@ -0,0 +1,158 @@
#include "tasoller.h"
#ifdef stdout
// Unnecessary for compilation, but clangd can get a bit confused
#undef stdout
#endif
// For picolibc
FILE *const stdout = NULL;
void SYS_ResetModule(uint32_t u32ModuleIndex) {
// Generate reset signal to the corresponding module
*(volatile uint32_t *)((uint32_t)&SYS->IPRSTC1 + (u32ModuleIndex >> 24)) |=
1 << (u32ModuleIndex & 0x00ffffff);
// Release corresponding module from reset state
*(volatile uint32_t *)((uint32_t)&SYS->IPRSTC1 + (u32ModuleIndex >> 24)) &=
~(1 << (u32ModuleIndex & 0x00ffffff));
}
void SYS_Init(void) {
// Enable XT1_OUT (PF.0) and XT1_IN (PF.1)
SYS->GPF_MFP &= ~(SYS_GPF_MFP_PF0_Msk | SYS_GPF_MFP_PF1_Msk);
SYS->GPF_MFP |= SYS_GPF_MFP_PF0_XT1_OUT | SYS_GPF_MFP_PF1_XT1_IN;
// Enable Internal RC 22.1184 MHz clock
CLK_EnableXtalRC(CLK_PWRCON_OSC22M_EN_Msk);
CLK_WaitClockReady(CLK_CLKSTATUS_OSC22M_STB_Msk);
// Switch HCLK clock source to Internal RC and HCLK source divide 1
CLK_SetHCLK(CLK_CLKSEL0_HCLK_S_HIRC, CLK_CLKDIV_HCLK(1));
// Enable external XTAL 12 MHz clock
CLK_EnableXtalRC(CLK_PWRCON_XTL12M_EN_Msk);
CLK_WaitClockReady(CLK_CLKSTATUS_XTL12M_STB_Msk);
// Set core clock
CLK_SetCoreClock(72000000);
// Enable module clocks
CLK_EnableModuleClock(UART1_MODULE);
CLK_EnableModuleClock(USBD_MODULE);
CLK_EnableModuleClock(TMR0_MODULE);
CLK_EnableModuleClock(I2C1_MODULE);
// Select module clock sources
CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_CLKDIV_UART(1));
CLK_SetModuleClock(USBD_MODULE, 0, CLK_CLKDIV_USB(3));
CLK_SetModuleClock(TMR0_MODULE, 0, 0);
CLK_SetModuleClock(I2C1_MODULE, 0, 0);
// Set GPB multi-function pins for UART1 RXD(PB4) and TXD(PB5)
SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB4_Msk | SYS_GPB_MFP_PB5_Msk);
SYS->GPB_MFP |= SYS_GPB_MFP_PB4_UART1_RXD | SYS_GPB_MFP_PB5_UART1_TXD;
GPIO_SetMode(_PIN_SDA, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_SCL, GPIO_PMD_OUTPUT);
PIN_SDA = 1;
PIN_SCL = 1;
// Configure our GPIO pins
GPIO_SetMode(_PIN_EC1, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_RX2, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_RX3, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_RX4, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_EC2, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_EC3, GPIO_PMD_INPUT);
GPIO_SetMode(_PIN_USB_MUX_SEL, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_USB_MUX_EN, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_LED_WING_PWR, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_LED_GROUND_PWR, GPIO_PMD_OUTPUT);
PIN_LED_WING_PWR = 1;
PIN_LED_GROUND_PWR = 1;
GPIO_SetMode(_PIN_FN2, GPIO_PMD_INPUT);
// TODO:
if (PIN_FN2 == 0) {
PIN_USB_MUX_SEL = USB_MUX_LEDS;
PIN_USB_MUX_EN = USB_MUX_ENABLE;
GPIO_SetMode(_PIN_SDA, GPIO_PMD_OUTPUT);
GPIO_SetMode(_PIN_SCL, GPIO_PMD_OUTPUT);
PIN_SDA = 0;
PIN_SCL = 0;
return;
}
// Set GPA multi-function pins for I2C1 SDA and SCL
SYS->GPA_MFP &= ~(SYS_GPA_MFP_PA10_Msk | SYS_GPA_MFP_PA11_Msk);
SYS->GPA_MFP |= (SYS_GPA_MFP_PA10_I2C1_SDA | SYS_GPA_MFP_PA11_I2C1_SCL);
SYS->ALT_MFP &= ~(SYS_ALT_MFP_PA10_Msk | SYS_ALT_MFP_PA11_Msk);
SYS->ALT_MFP |= (SYS_ALT_MFP_PA10_I2C1_SDA | SYS_ALT_MFP_PA11_I2C1_SCL);
PIN_USB_MUX_EN = USB_MUX_ENABLE;
PIN_USB_MUX_SEL = USB_MUX_HOST;
}
void SYS_ModuleInit(void) {
// Setup UART1
SYS_ResetModule(UART1_RST);
UART_Open(UART1, 460800);
/* Enable interrupts for:
* - Receive data available
* - Receive line status
* - RX time-out
*/
UART1->IER = (UART_IER_RDA_IEN_Msk | UART_IER_RLS_IEN_Msk | UART_IER_RTO_IEN_Msk);
NVIC_EnableIRQ(UART1_IRQn);
// Set NVIC priorities
NVIC_SetPriority(USBD_IRQn, 1);
NVIC_SetPriority(TMR0_IRQn, 2);
NVIC_SetPriority(I2S_IRQn, 3);
NVIC_SetPriority(I2C0_IRQn, 4);
CLK_SysTickDelay(10 ms);
// For communication with the LED MCU
LED_I2C1_Init();
// Timer 0: Used for HID, PSoC processing and slider outbound
// This timer runs at 4kHz, but only sets the 1ms flag every 4 calls
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 4 kHz);
TIMER_EnableInt(TIMER0);
NVIC_EnableIRQ(TMR0_IRQn);
TIMER_Start(TIMER0);
// Setup our USB stack
Tas_USBD_Open();
Tas_USBD_Init();
Tas_USBD_Start();
NVIC_EnableIRQ(USBD_IRQn);
}
// Define a dedicated symbol for this, so we can easily trap it with a debugger!
void HardFault_Handler() {
while (1)
;
}
void SYS_Bootloader_Check() {
FMC_Open();
while (FMC_Read(BOOTLOADER_MAGIC_ADDR) != BOOTLOADER_MAGIC)
;
FMC_Close();
}
volatile uint8_t gu8Do250usTick = 0;
volatile uint8_t gu8Do1msTick = 0;
void TMR0_IRQHandler(void) {
static uint32_t su32Counter;
if (TIMER_GetIntFlag(TIMER0)) {
TIMER_ClearIntFlag(TIMER0);
gu8Do250usTick = 1;
if (++su32Counter == 4) {
su32Counter = 0;
gu8Do1msTick = 1;
}
}
}

275
src/tasoller.h Normal file
View File

@ -0,0 +1,275 @@
#pragma once
#include <NUC123.h>
#include <stdio.h>
#include <string.h>
#define ms *1000
#define kHz *1000
/* === LEDs === */
#define LED_Tx_BUFFER 254
// Defined as volatile due to the I2C interrupt reading at random times!
extern volatile uint8_t gu8LEDTx[LED_Tx_BUFFER];
/* === DAO-DRM === */
// * For now the bootloader check is being left enabled.
// * It'll help catch if I break that in my bootloader :P
#define ENABLE_BOOTLOADER_CHECK
#define BOOTLOADER_MAGIC 0x5555A320
#define BOOTLOADER_MAGIC_ADDR 0x100FF8
/* === USB definitions === */
#include "usb_inc/hid.h"
#include "usb_inc/keymap.h"
#include "usb_inc/usb.h"
/* === Local files === */
#include "fmc_user.h"
#include "led.h"
#include "pins.h"
#include "psoc.h"
#include "slider.h"
#define IO4_VENDOR "SEGA INTERACTIVE"
// Product description
#define _IO4_PRODUCT \
"I/O CONTROL BD;" /* Board type */ \
"15257 ;" /* Board number */ \
"01;" /* Mode */ \
"90;" /* Firmware revision */ \
"1831;" /* Firmware checksum */ \
"6679A;" /* Chip number */ \
"00;" /* Config */
// Functional description
#define _IO4_FUNCTION \
"GOUT=14_" /* General purpose output (20) */ \
"ADIN=8,E_" /* ADC input (8) */ \
"ROTIN=4_" /* Rotary input (4) */ \
"COININ=2_" /* Coin input (2) */ \
"SWIN=2,E_" /* Switch inputs (2) */ \
"UQ1=41,6;" /* Unique function 1 (?) */
#define IO4_PRODUCT _IO4_PRODUCT _IO4_FUNCTION
#define IO4_VID 0x0CA3
#define IO4_PID 0x0021
#define INCR(x, y) ((x) = (x) < (y) ? (x) + 1 : (y))
#define DECR(x, y) ((x) = (x) > (y) ? (x) - 1 : (y))
#define MOD_INCR(x, y) ((x) = (x) == ((y)-1) ? 0 : ((x) + 1))
#define MOD_DECR(x, y) ((x) = (x) == 0 ? ((y)-1) : ((x)-1))
#define INV(x) ((x) = 1 - (x))
extern volatile uint8_t gu8VcomReady;
/**
* WARNING: This is both used internally and sent verbatim over serial
* It **MUST** be 32 bytes of ground data
*/
extern uint8_t gu8GroundData[32];
/* === For HID === */
enum {
HID_REPORT_ID_IO4 = 1,
HID_REPORT_ID_KEYBOARD,
HID_REPORT_ID_DEBUG_A,
HID_REPORT_ID_DEBUG_B,
HID_REPORT_ID_IO4_CMD = 16,
};
#define NUM_FN 2
#define NUM_AIR 6
#define NUM_GROUND 32
typedef struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bKeyboard[NUM_FN + NUM_AIR + NUM_GROUND];
} hid_report_t;
typedef struct __attribute__((packed)) {
uint8_t bReportId;
uint16_t wADC[8];
uint16_t wRotary[4];
uint16_t wCoin[2];
uint16_t wButtons[2];
uint8_t bSystemStatus;
uint8_t bUsbStatus;
uint8_t bUnique[29];
} io4_hid_in_t;
typedef struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bCmd;
uint8_t bData[62];
} io4_hid_out_t;
typedef struct __attribute__((packed)) {
uint8_t bReportId;
uint16_t wData[16];
} debug_hid_report_t;
extern uint8_t gu8DigitalButtons;
// void HID_Tick();
void USBD_HID_PrepareReport();
uint8_t *USBD_HID_GetReport(uint8_t u8ReportId, uint32_t *pu32Size);
void USBD_HID_SetReport(volatile uint8_t *pu8EpBuf, uint32_t u32Size);
// For CDC
typedef struct __attribute__((packed)) {
uint32_t u32DTERate; // Baud rate
uint8_t u8CharFormat; // Stop bit
uint8_t u8ParityType; // Parity
uint8_t u8DataBits; // Data bits
} STR_VCOM_LINE_CODING;
extern volatile int8_t gi8BulkOutReady;
extern STR_VCOM_LINE_CODING gLineCoding;
extern uint16_t gCtrlSignal;
extern volatile uint16_t comRbytes;
extern volatile uint16_t comRhead;
extern volatile uint16_t comRtail;
extern volatile uint16_t comTbytes;
extern volatile uint16_t comThead;
extern volatile uint16_t comTtail;
extern volatile uint8_t *gpu8RxBuf;
extern volatile uint32_t gu32RxSize;
extern volatile uint32_t gu32TxSize;
// For HID
extern uint8_t volatile gu8HIDIO4Ready;
extern uint8_t volatile gu8HIDMiscReady;
// General USB control
extern uint8_t volatile g_u8Suspend;
extern uint8_t g_u8Idle;
extern uint8_t g_u8Protocol;
extern const char *gszVendorInitial;
extern const char *gszVendor;
extern const char *gszProduct;
extern const usb_device_descr_t *gpDeviceDescriptor;
extern const usb_desc_config_t *gpConfigDescriptor;
extern const uint32_t gu32HidDescIO4Offset;
extern const uint32_t gu32HidDescMiscOffset;
extern const uint32_t gu32UsbHidIO4ReportLen;
extern const uint32_t gu32UsbHidMiscReportLen;
extern const uint8_t *gpu8UsbHidIO4Report;
extern const uint8_t *gpu8UsbHidMiscReport;
/*-------------------------------------------------------------*/
// Interfaces
enum {
USBD_ITF_CDC_CMD,
USBD_ITF_CDC_DAT,
USBD_ITF_HID_IO4,
USBD_ITF_HID_MISC,
_USBD_ITF_MAX,
};
// Endpoint number mapping
#define EP_CTRL_IN EP0
#define EP_CTRL_OUT EP1
#define EP_CDC_IN EP2
#define EP_CDC_OUT EP3
#define EP_CDC_CMD EP4
#define EP_HID_IO4_IN EP5
#define EP_HID_MISC_IN EP6
#define EP_HID_MISC_OUT EP7
#define _USBD_INTSTS(x) USBD_INTSTS_EP##x
#define USBD_INTSTS(x) _USBD_INTSTS(x)
// Must match the above!!
#define USBD_INTSTS_CTRL_IN USBD_INTSTS(EP_CTRL_IN)
#define USBD_INTSTS_CTRL_OUT USBD_INTSTS(EP_CTRL_OUT)
#define USBD_INTSTS_CDC_IN USBD_INTSTS(EP_CDC_IN)
#define USBD_INTSTS_CDC_OUT USBD_INTSTS(EP_CDC_OUT)
#define USBD_INTSTS_CDC_CMD USBD_INTSTS(EP_CDC_CMD)
#define USBD_INTSTS_HID_IO4_IN USBD_INTSTS(EP_HID_IO4_IN)
#define USBD_INTSTS_HID_MISC_IN USBD_INTSTS(EP_HID_MISC_IN)
#define USBD_INTSTS_HID_MISC_OUT USBD_INTSTS(EP_HID_MISC_OUT)
#define USBD_CDC_EP_IN (1 | EP_INPUT)
#define USBD_CDC_EP_OUT (2 | EP_OUTPUT)
#define USBD_CDC_EP_CMD (3 | EP_INPUT)
#define USBD_HID_IO4_EP_IN (4 | EP_INPUT)
#define USBD_HID_MISC_EP_IN (5 | EP_INPUT)
#define USBD_HID_MISC_EP_OUT (6 | EP_OUTPUT)
#define USBD_SETUP_BUF_LEN (8)
#define USBD_CDC_CMD_MAX_SIZE (16)
#define USBD_CDC_IN_MAX_SIZE (64) // Device -> Host
#define USBD_CDC_OUT_MAX_SIZE (64) // Host -> Device
#define USBD_HID_BUF_LEN (64)
// Endpoint packet max size (cannot total more than 512!)
#define EP0_MAX_PKT_SIZE 64
#define EP1_MAX_PKT_SIZE 64
#define EP2_MAX_PKT_SIZE USBD_CDC_IN_MAX_SIZE
#define EP3_MAX_PKT_SIZE USBD_CDC_OUT_MAX_SIZE
#define EP4_MAX_PKT_SIZE USBD_CDC_CMD_MAX_SIZE
#define EP5_MAX_PKT_SIZE USBD_HID_BUF_LEN
#define EP6_MAX_PKT_SIZE USBD_HID_BUF_LEN
#define EP7_MAX_PKT_SIZE USBD_HID_BUF_LEN
#define SETUP_BUF_BASE 0
#define SETUP_BUF_LEN 8
#if (SETUP_BUF_LEN + EP0_MAX_PKT_SIZE + EP1_MAX_PKT_SIZE + EP2_MAX_PKT_SIZE + EP3_MAX_PKT_SIZE + \
EP4_MAX_PKT_SIZE + EP5_MAX_PKT_SIZE + EP6_MAX_PKT_SIZE + EP7_MAX_PKT_SIZE) > 512
#error USB endpoint packet sizes exceeds 512-byte maximum
#endif
#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
#define EP1_BUF_BASE (EP0_BUF_BASE + EP0_MAX_PKT_SIZE)
#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_MAX_PKT_SIZE)
#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_MAX_PKT_SIZE)
#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_MAX_PKT_SIZE)
#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_MAX_PKT_SIZE)
#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_MAX_PKT_SIZE)
#define EP7_BUF_BASE (EP5_BUF_BASE + EP6_MAX_PKT_SIZE)
// Define Descriptor information
#define HID_IO4_INT_IN_INTERVAL 8
#define HID_DEFAULT_INT_IN_INTERVAL 1
#define HID_DEFAULT_INT_OUT_INTERVAL 1
#define USBD_SELF_POWERED 0
#define USBD_REMOTE_WAKEUP 0
#define USBD_MAX_POWER (500 / 2)
/*-------------------------------------------------------------*/
#define HEX_NIBBLE(x) ("0123456789ABCDEF"[(x)&0xf])
void SYS_Init(void);
void SYS_Bootloader_Check(void);
void SYS_ModuleInit(void);
extern volatile uint8_t gu8Do250usTick;
extern volatile uint8_t gu8Do1msTick;
void EP_CDC_CMD_Handler(void);
void EP_CDC_OUT_Handler(void);
void EP_CDC_IN_Handler(void);
void EP_HID_IO4_IN_Handler(void);
void EP_HID_MISC_IN_Handler(void);
void EP_HID_MISC_OUT_Handler(void);
void USB_VCOM_Write(uint8_t u8Char);
uint16_t USB_VCOM_Available(void);
uint8_t USB_VCOM_Read(void);
void USB_VCOM_Tick(void);
void USB_VCOM_PurgeTx(void);
void UI_Tick(void);
void DelayCycles(uint32_t u32Cycles);
#define DelayCycles_Small(x) \
for (int i = 0; i < (x); i++) __asm__ volatile("" : "+g"(i) : :);
// Custom USBD implementation
void Tas_USBD_Open(void);
void Tas_USBD_Init(void);
void Tas_USBD_Start(void);
void Tas_USBD_ClassRequest(void);
void Tas_USBD_GetSetupPacket(usb_setup_t *buf);
void Tas_USBD_ProcessSetupPacket(void);
void Tas_USBD_PrepareCtrlIn(void *pu8Buf, uint32_t u32Size);
void Tas_USBD_CtrlIn(void);
void Tas_USBD_PrepareCtrlOut(void *pu8Buf, uint32_t u32Size,
void (*pCallback)(volatile uint8_t *, uint32_t));
void Tas_USBD_CtrlOut(void);
void Tas_USBD_SwReset(void);
extern volatile uint8_t *g_usbd_CtrlInPointer;
extern volatile uint32_t g_usbd_CtrlInSize;

249
src/ui.c Normal file
View File

@ -0,0 +1,249 @@
#include "tasoller.h"
#define FN2_HOLD_TIME 250 // ms of FN2 to enter config
#define FN1_HOLD_TIME 2000 // ms of FN1 to enter calibration
// All three of these are scaled based on gConfig.u8Sens
#define CALIB_HANDS_MIN 100 // If we read less than this, ignore it
#define CALIB_HANDS_REQ 700 // All values are required to be greater than this
#define CALIB_HANDS_MAX 1300 // Scale from orange to green between [req] and [max]
#define RED 0
#define GREEN 120
#define BLUE 240
static void UI_TickSensitivity(void) {
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
gaControlledIntLedData[i].u16H = 0;
gaControlledIntLedData[i].u8S = (gConfig.u8Sens - 1) * 16;
gaControlledIntLedData[i].u8V = 0;
}
for (uint8_t i = 0; i < gConfig.u8Sens; i++) gaControlledIntLedData[i * 2].u8V = 255;
// Preferentially allow decreasing of sensitivity, in case it's been taken up too high
if (gu32PSoCDigitalPos & PAD_26_Msk && gConfig.u8Sens > 1) {
gConfig.u8Sens--;
} else if (gu32PSoCDigitalPos & PAD_25_Msk && gConfig.u8Sens < 16) {
gConfig.u8Sens++;
}
}
static void UI_TickSettings(void) {
// If either of the sensitivity settings are being changed, just render that
static uint8_t su8SensTimeout = 0;
if (gu16PSoCDigital & CELL_12_Msk) {
su8SensTimeout = 150;
UI_TickSensitivity();
return;
} else if (su8SensTimeout) {
su8SensTimeout--;
UI_TickSensitivity();
// Save the sensitivity on exit
if (su8SensTimeout == 0) PSoC_SetFingerCapacitanceFromConfig();
return;
}
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
gaControlledIntLedData[i].u16H = 0;
gaControlledIntLedData[i].u8S = 255;
gaControlledIntLedData[i].u8V = 0;
}
{ // LED colour control
gaControlledIntLedData[LED_CELL_0].u16H = gConfig.u16HueWingLeft;
gaControlledIntLedData[LED_CELL_0].u8V = 255;
gaControlledIntLedData[LED_CELL_1].u16H = gConfig.u16HueGround;
gaControlledIntLedData[LED_CELL_1].u8V = 255;
gaControlledIntLedData[LED_DIVIDER_1_2].u16H = gConfig.u16HueGroundActive;
gaControlledIntLedData[LED_DIVIDER_1_2].u8V = 255;
gaControlledIntLedData[LED_CELL_2].u16H = gConfig.u16HueGround;
gaControlledIntLedData[LED_CELL_2].u8V = 255;
gaControlledIntLedData[LED_CELL_3].u16H = gConfig.u16HueWingRight;
gaControlledIntLedData[LED_CELL_3].u8V = 255;
if (gu32PSoCDigitalTrig & PAD_1_Msk) MOD_INCR(gConfig.u16HueWingLeft, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_2_Msk) MOD_DECR(gConfig.u16HueWingLeft, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_3_Msk) MOD_INCR(gConfig.u16HueGround, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_4_Msk) MOD_DECR(gConfig.u16HueGround, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_5_Msk) MOD_INCR(gConfig.u16HueGroundActive, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_6_Msk) MOD_DECR(gConfig.u16HueGroundActive, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_7_Msk) MOD_INCR(gConfig.u16HueWingRight, LED_HUE_MAX);
if (gu32PSoCDigitalTrig & PAD_8_Msk) MOD_DECR(gConfig.u16HueWingRight, LED_HUE_MAX);
}
// [Cell 4 no function]
{ // Lighting toggles
static uint16_t su16Hue = 0;
MOD_INCR(su16Hue, LED_HUE_MAX * 5);
if (gConfig.bEnableRainbow) {
gaControlledIntLedData[LED_CELL_5].u16H = su16Hue / 5;
gaControlledIntLedData[LED_CELL_5].u8V = 255;
} else {
gaControlledIntLedData[LED_CELL_5].u8S = 0;
gaControlledIntLedData[LED_CELL_5].u8V = 255;
}
if (gu16PSoCDigitalPos & CELL_5_Msk) INV(gConfig.bEnableRainbow);
}
{ // Brightness
if (gConfig.u8LedGroundBrightness) {
gaControlledIntLedData[LED_CELL_6].u8S = 0;
gaControlledIntLedData[LED_CELL_6].u8V = gConfig.u8LedGroundBrightness;
} else {
gaControlledIntLedData[LED_CELL_6].u8V = 255;
}
if (gConfig.u8LedWingBrightness) {
gaControlledIntLedData[LED_CELL_7].u8S = 0;
gaControlledIntLedData[LED_CELL_7].u8V = gConfig.u8LedWingBrightness;
} else {
gaControlledIntLedData[LED_CELL_7].u8V = 255;
}
if (gu32PSoCDigitalTrig & PAD_13_Msk) INCR(gConfig.u8LedGroundBrightness, 255);
if (gu32PSoCDigitalTrig & PAD_14_Msk) DECR(gConfig.u8LedGroundBrightness, 0);
if (gu32PSoCDigitalTrig & PAD_15_Msk) INCR(gConfig.u8LedWingBrightness, 255);
if (gu32PSoCDigitalTrig & PAD_16_Msk) DECR(gConfig.u8LedWingBrightness, 0);
}
// [Cell 8,9,10,11 no function]
{ // Sensitivity control (handled in dedicated function)
gaControlledIntLedData[LED_CELL_12].u8S = (gConfig.u8Sens - 1) * 16;
gaControlledIntLedData[LED_CELL_12].u8V = 255;
}
// [Cell 13 no function]
{ // Mode switching
gaControlledIntLedData[LED_CELL_14].u16H = gConfig.bEnableKeyboard ? GREEN : RED;
gaControlledIntLedData[LED_CELL_14].u8V = 255;
gaControlledIntLedData[LED_CELL_15].u16H = gConfig.bEnableIO4 ? GREEN : RED;
gaControlledIntLedData[LED_CELL_15].u8V = 255;
if (gu16PSoCDigitalPos & CELL_14_Msk) INV(gConfig.bEnableKeyboard);
if (gu16PSoCDigitalPos & CELL_15_Msk) INV(gConfig.bEnableIO4);
}
}
static inline void _FillControlled(uint16_t u16H, uint8_t u8Fill) {
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
gaControlledIntLedData[i].u16H = u16H;
gaControlledIntLedData[i].u8S = 255;
gaControlledIntLedData[i].u8V = i < u8Fill ? 255 : 0;
}
}
static uint8_t bCalibrationActive = 0;
static void UI_TickCalibration(void) {
static uint16_t u16Timer = 0;
static uint16_t su16MaxNoHands[32] = { 0 };
static uint16_t su16MaxHands[32] = { 0 };
if (!bCalibrationActive) {
// Calibration start
u16Timer = 0;
bCalibrationActive = 1;
memset(su16MaxNoHands, 0, sizeof su16MaxNoHands);
memset(su16MaxHands, 0, sizeof su16MaxHands);
}
// Only tick the timer when we're using it, to avoid overflow
if (u16Timer < 5000) u16Timer++;
if (u16Timer < 3000) {
// Flash red for the first 3 seconds
_FillControlled(RED, ((u16Timer / 250) & 1) ? 0 : LED_NUM_GROUND);
} else if (u16Timer < 4000) {
// Fill up the cells with blue
_FillControlled(BLUE, (u16Timer - 3000) / (1000 / LED_NUM_GROUND));
for (uint8_t i; i < 32; i++) {
su16MaxNoHands[i] = Maximum(su16MaxNoHands[i], gu16PSoCDiff[i]);
}
} else if (u16Timer < 5000) {
// Flash green for the next second
_FillControlled(GREEN, ((u16Timer / 250) & 1) ? 0 : LED_NUM_GROUND);
} else {
for (uint8_t i = 0; i < 32; i++) {
// As well as the raw minimum, force a small constant threshold minimum too
su16MaxHands[i] = Maximum(su16MaxHands[i], gu16PSoCDiff[i] + (gConfig.u8Sens * 5));
}
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
gaControlledIntLedData[i].u8S = 255;
gaControlledIntLedData[i].u8V = 255;
}
uint16_t u16CalibMin = CALIB_HANDS_MIN + (gConfig.u8Sens * 50);
uint16_t u16CalibReq = CALIB_HANDS_REQ + (gConfig.u8Sens * 50);
uint16_t u16CalibMax = CALIB_HANDS_MAX + (gConfig.u8Sens * 50);
uint8_t bOk = 1;
// Iterate over the cells
for (uint8_t i = 0; i < 16; i++) {
if (su16MaxHands[i * 2] < u16CalibMin || su16MaxHands[i * 2 + 1] < u16CalibMin ||
su16MaxHands[i * 2] < su16MaxNoHands[i * 2] ||
su16MaxHands[i * 2 + 1] < su16MaxNoHands[i * 2 + 1]) {
// Not enough data
gaControlledIntLedData[i * 2].u8V = 0;
bOk = 0;
} else if (su16MaxHands[i * 2] < u16CalibReq || su16MaxHands[i * 2 + 1] < u16CalibReq) {
// Data is too low
gaControlledIntLedData[i * 2].u16H = RED;
bOk = 0;
} else if (su16MaxHands[i * 2] < u16CalibMax || su16MaxHands[i * 2 + 1] < u16CalibMax) {
// We've got enough, but it could be better
uint16_t u16Min = Minimum(su16MaxHands[i * 2], su16MaxHands[i * 2 + 1]);
gaControlledIntLedData[i * 2].u16H =
((u16Min - u16CalibReq) * GREEN) / (u16CalibMax - u16CalibReq);
} else {
// More than enough data
gaControlledIntLedData[i * 2].u16H = GREEN;
}
}
for (uint8_t i = 0; i < LED_NUM_GROUND; i++) {
if (i % 2 == 1) {
gaControlledIntLedData[i].u16H = bOk ? GREEN : RED;
}
}
// Calibration complete
if (gu8DigitalButtons & DIGITAL_FN1_Msk) {
bCalibrationActive = 0;
if (bOk) {
memcpy(gConfig.u16PSoCScaleMin, su16MaxNoHands, sizeof su16MaxNoHands);
memcpy(gConfig.u16PSoCScaleMax, su16MaxHands, sizeof su16MaxHands);
bConfigDirty = 1;
}
}
}
}
void UI_Tick(void) {
static uint8_t u8Fn2Held = 0;
if (gu8DigitalButtons & DIGITAL_FN2_Msk) {
if (u8Fn2Held < FN2_HOLD_TIME) u8Fn2Held++;
} else {
// We released the button after holding it for long enough to be in the configuration UI, so
// assume something changed
if (u8Fn2Held >= FN2_HOLD_TIME) {
bConfigDirty = 1;
}
u8Fn2Held = 0;
}
static uint16_t u16Fn1Held = 0;
if (gu8DigitalButtons & DIGITAL_FN1_Msk) {
if (u16Fn1Held < FN1_HOLD_TIME) u16Fn1Held++;
} else {
u16Fn1Held = 0;
}
if (bCalibrationActive || u16Fn1Held >= FN1_HOLD_TIME) {
gbLedDataIsControlledInt = 1;
UI_TickCalibration();
} else if (u8Fn2Held >= FN2_HOLD_TIME) {
gbLedDataIsControlledInt = 1;
UI_TickSettings();
} else {
gbLedDataIsControlledInt = 0;
}
}

1654
src/usb_inc/hid.h Normal file

File diff suppressed because it is too large Load Diff

69
src/usb_inc/hid_macro.h Normal file
View File

@ -0,0 +1,69 @@
// https://github.com/katyo/hid_def
#pragma once
#define _NONE(...)
#define _UNWR_(...) __VA_ARGS__
#define _UNWR(a) _UNWR_ a
#define _CAT2_(a, b) a##b
#define _CAT2(a, b) _CAT2_(a, b)
#define _CAT3_(a, b, c) a##b##c
#define _CAT3(a, b, c) _CAT3_(a, b, c)
#define _CAT4_(a, b, c, d) a##b##c##d
#define _CAT4(a, b, c, d) _CAT4_(a, b, c, d)
#define _CAT5_(a, b, c, d, e) a##b##c##d##e
#define _CAT5(a, b, c, d, e) _CAT5_(a, b, c, d, e)
#define _NTH0_(a, ...) a
#define _NTH0(...) _NTH0_(__VA_ARGS__)
#define _NTH1_(a, b, ...) b
#define _NTH1(...) _NTH1_(__VA_ARGS__)
#define _NTH2_(a, b, c, ...) c
#define _NTH2(...) _NTH2_(__VA_ARGS__)
#define _NTH3_(a, b, c, d, ...) d
#define _NTH3(...) _NTH3_(__VA_ARGS__)
#define _NTH4_(a, b, c, d, e, ...) e
#define _NTH4(...) _NTH4_(__VA_ARGS__)
#define _MAX2(a, b) ((a) > (b) ? (a) : (b))
#define _MIN2(a, b) ((a) < (b) ? (a) : (b))
#define _CALL_(f, ...) f(__VA_ARGS__)
#define _CALL(f, ...) _CALL_(f, ##__VA_ARGS__)
#define _EVAL0(...) __VA_ARGS__
#define _EVAL1(...) _EVAL0(_EVAL0(_EVAL0(__VA_ARGS__)))
#define _EVAL2(...) _EVAL1(_EVAL1(_EVAL1(__VA_ARGS__)))
#define _EVAL3(...) _EVAL2(_EVAL2(_EVAL2(__VA_ARGS__)))
#define _EVAL4(...) _EVAL3(_EVAL3(_EVAL3(__VA_ARGS__)))
#define _EVAL(...) _EVAL4(_EVAL4(_EVAL4(__VA_ARGS__)))
#define _MAP_END(...)
#define _MAP_OUT
#define _MAP_COMMA ,
#define _MAP_GET_END2() 0, _MAP_END
#define _MAP_GET_END1(...) _MAP_GET_END2
#define _MAP_GET_END(...) _MAP_GET_END1
#define _MAP_NEXT0(test, next, ...) next _MAP_OUT
#define _MAP_NEXT1(test, next) _MAP_NEXT0(test, next, 0)
#define _MAP_NEXT(test, next) _MAP_NEXT1(_MAP_GET_END test, next)
#define _MAP0(f, x, peek, ...) f(x) _MAP_NEXT(peek, _MAP1)(f, peek, __VA_ARGS__)
#define _MAP1(f, x, peek, ...) f(x) _MAP_NEXT(peek, _MAP0)(f, peek, __VA_ARGS__)
/**
* Applies the function macro `f` to each of the remaining parameters.
*/
#define _MAP(f, ...) _EVAL(_MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
#define _ASSERT(x) ((1/(!!(x))) ? (x) : (x))

769
src/usb_inc/keymap.h Normal file
View File

@ -0,0 +1,769 @@
#pragma once
#include <stdint.h>
// Keyboard Modifiers
enum KeyboardMods {
MOD_LEFT_CTRL = (1 << 8),
MOD_LEFT_SHIFT = (1 << 9),
MOD_LEFT_ALT = (1 << 10),
MOD_LEFT_GUI = (1 << 11),
MOD_RIGHT_CTRL = (1 << 12),
MOD_RIGHT_SHIFT = (1 << 13),
MOD_RIGHT_ALT = (1 << 14),
MOD_RIGHT_GUI = (uint16_t)(1 << 15),
};
// Keyboard Leds
enum KeyboardLeds {
LED_NUM_LOCK = (1 << 0),
LED_CAPS_LOCK = (1 << 1),
LED_SCROLL_LOCK = (1 << 2),
LED_COMPOSE = (1 << 3),
LED_KANA = (1 << 4),
LED_POWER = (1 << 5),
LED_SHIFT = (1 << 6),
LED_DO_NOT_DISTURB = (1 << 7),
};
enum KeyboardKeycode {
KEY_RESERVED = 0,
KEY_ERROR_ROLLOVER = 1,
KEY_POST_FAIL = 2,
KEY_ERROR_UNDEFINED = 3,
KEY_A = 4,
KEY_B = 5,
KEY_C = 6,
KEY_D = 7,
KEY_E = 8,
KEY_F = 9,
KEY_G = 10,
KEY_H = 11,
KEY_I = 12,
KEY_J = 13,
KEY_K = 14,
KEY_L = 15,
KEY_M = 16,
KEY_N = 17,
KEY_O = 18,
KEY_P = 19,
KEY_Q = 20,
KEY_R = 21,
KEY_S = 22,
KEY_T = 23,
KEY_U = 24,
KEY_V = 25,
KEY_W = 26,
KEY_X = 27,
KEY_Y = 28,
KEY_Z = 29,
KEY_1 = 30,
KEY_2 = 31,
KEY_3 = 32,
KEY_4 = 33,
KEY_5 = 34,
KEY_6 = 35,
KEY_7 = 36,
KEY_8 = 37,
KEY_9 = 38,
KEY_0 = 39,
KEY_ENTER = 40,
KEY_RETURN = 40, // Alias
KEY_ESC = 41,
KEY_BACKSPACE = 42,
KEY_TAB = 43,
KEY_SPACE = 44,
KEY_MINUS = 45,
KEY_EQUAL = 46,
KEY_LEFT_BRACE = 47,
KEY_RIGHT_BRACE = 48,
KEY_BACKSLASH = 49,
KEY_NON_US_NUM = 50,
KEY_SEMICOLON = 51,
KEY_QUOTE = 52,
KEY_TILDE = 53,
KEY_COMMA = 54,
KEY_PERIOD = 55,
KEY_SLASH = 56,
KEY_CAPS_LOCK = 0x39,
KEY_F1 = 0x3A,
KEY_F2 = 0x3B,
KEY_F3 = 0x3C,
KEY_F4 = 0x3D,
KEY_F5 = 0x3E,
KEY_F6 = 0x3F,
KEY_F7 = 0x40,
KEY_F8 = 0x41,
KEY_F9 = 0x42,
KEY_F10 = 0x43,
KEY_F11 = 0x44,
KEY_F12 = 0x45,
KEY_PRINT = 0x46,
KEY_PRINTSCREEN = 0x46, // Alias
KEY_SCROLL_LOCK = 0x47,
KEY_PAUSE = 0x48,
KEY_INSERT = 0x49,
KEY_HOME = 0x4A,
KEY_PAGE_UP = 0x4B,
KEY_DELETE = 0x4C,
KEY_END = 0x4D,
KEY_PAGE_DOWN = 0x4E,
KEY_RIGHT_ARROW = 0x4F,
KEY_LEFT_ARROW = 0x50,
KEY_DOWN_ARROW = 0x51,
KEY_UP_ARROW = 0x52,
KEY_RIGHT = 0x4F, // Alias
KEY_LEFT = 0x50, // Alias
KEY_DOWN = 0x51, // Alias
KEY_UP = 0x52, // Alias
KEY_NUM_LOCK = 0x53,
KEYPAD_DIVIDE = 0x54,
KEYPAD_MULTIPLY = 0x55,
KEYPAD_SUBTRACT = 0x56,
KEYPAD_ADD = 0x57,
KEYPAD_ENTER = 0x58,
KEYPAD_1 = 0x59,
KEYPAD_2 = 0x5A,
KEYPAD_3 = 0x5B,
KEYPAD_4 = 0x5C,
KEYPAD_5 = 0x5D,
KEYPAD_6 = 0x5E,
KEYPAD_7 = 0x5F,
KEYPAD_8 = 0x60,
KEYPAD_9 = 0x61,
KEYPAD_0 = 0x62,
KEYPAD_DOT = 0x63,
KEY_NON_US = 0x64,
KEY_APPLICATION = 0x65, // Context menu/right click
KEY_MENU = 0x65, // Alias
// Most of the following keys will only work with Linux or not at all.
// F13+ keys are mostly used for laptop functions like ECO key.
KEY_POWER = 0x66, // PowerOff (Ubuntu)
KEY_PAD_EQUALS = 0x67, // Dont confuse with KEYPAD_EQUAL_SIGN
KEY_F13 = 0x68, // Tools (Ubunutu)
KEY_F14 = 0x69, // Launch5 (Ubuntu)
KEY_F15 = 0x6A, // Launch6 (Ubuntu)
KEY_F16 = 0x6B, // Launch7 (Ubuntu)
KEY_F17 = 0x6C, // Launch8 (Ubuntu)
KEY_F18 = 0x6D, // Launch9 (Ubuntu)
KEY_F19 = 0x6E, // Disabled (Ubuntu)
KEY_F20 = 0x6F, // AudioMicMute (Ubuntu)
KEY_F21 = 0x70, // Touchpad toggle (Ubuntu)
KEY_F22 = 0x71, // TouchpadOn (Ubuntu)
KEY_F23 = 0x72, // TouchpadOff Ubuntu)
KEY_F24 = 0x73, // Disabled (Ubuntu)
KEY_EXECUTE = 0x74, // Open (Ubuntu)
KEY_HELP = 0x75, // Help (Ubuntu)
KEY_MENU2 = 0x76, // Disabled (Ubuntu)
KEY_SELECT = 0x77, // Disabled (Ubuntu)
KEY_STOP = 0x78, // Cancel (Ubuntu)
KEY_AGAIN = 0x79, // Redo (Ubuntu)
KEY_UNDO = 0x7A, // Undo (Ubuntu)
KEY_CUT = 0x7B, // Cut (Ubuntu)
KEY_COPY = 0x7C, // Copy (Ubuntu)
KEY_PASTE = 0x7D, // Paste (Ubuntu)
KEY_FIND = 0x7E, // Find (Ubuntu)
KEY_MUTE = 0x7F,
KEY_VOLUME_MUTE = 0x7F, // Alias
KEY_VOLUME_UP = 0x80,
KEY_VOLUME_DOWN = 0x81,
KEY_LOCKING_CAPS_LOCK = 0x82, // Disabled (Ubuntu)
KEY_LOCKING_NUM_LOCK = 0x83, // Disabled (Ubuntu)
KEY_LOCKING_SCROLL_LOCK = 0x84, // Disabled (Ubuntu)
KEYPAD_COMMA = 0x85, // .
KEYPAD_EQUAL_SIGN = 0x86, // Disabled (Ubuntu), Dont confuse with KEYPAD_EQUAL
KEY_INTERNATIONAL1 = 0x87, // Disabled (Ubuntu)
KEY_INTERNATIONAL2 = 0x88, // Hiragana Katakana (Ubuntu)
KEY_INTERNATIONAL3 = 0x89, // Disabled (Ubuntu)
KEY_INTERNATIONAL4 = 0x8A, // Henkan (Ubuntu)
KEY_INTERNATIONAL5 = 0x8B, // Muhenkan (Ubuntu)
KEY_INTERNATIONAL6 = 0x8C, // Disabled (Ubuntu)
KEY_INTERNATIONAL7 = 0x8D, // Disabled (Ubuntu)
KEY_INTERNATIONAL8 = 0x8E, // Disabled (Ubuntu)
KEY_INTERNATIONAL9 = 0x8F, // Disabled (Ubuntu)
KEY_LANG1 = 0x90, // Disabled (Ubuntu)
KEY_LANG2 = 0x91, // Disabled (Ubuntu)
KEY_LANG3 = 0x92, // Katana (Ubuntu)
KEY_LANG4 = 0x93, // Hiragana (Ubuntu)
KEY_LANG5 = 0x94, // Disabled (Ubuntu)
KEY_LANG6 = 0x95, // Disabled (Ubuntu)
KEY_LANG7 = 0x96, // Disabled (Ubuntu)
KEY_LANG8 = 0x97, // Disabled (Ubuntu)
KEY_LANG9 = 0x98, // Disabled (Ubuntu)
KEY_ALTERNATE_ERASE = 0x99, // Disabled (Ubuntu)
KEY_SYSREQ_ATTENTION = 0x9A, // Disabled (Ubuntu)
KEY_CANCEL = 0x9B, // Disabled (Ubuntu)
KEY_CLEAR = 0x9C, // Delete (Ubuntu)
KEY_PRIOR = 0x9D, // Disabled (Ubuntu)
KEY_RETURN2 = 0x9E, // Disabled (Ubuntu), Do not confuse this with KEY_ENTER
KEY_SEPARATOR = 0x9F, // Disabled (Ubuntu)
KEY_OUT = 0xA0, // Disabled (Ubuntu)
KEY_OPER = 0xA1, // Disabled (Ubuntu)
KEY_CLEAR_AGAIN = 0xA2, // Disabled (Ubuntu)
KEY_CRSEL_PROPS = 0xA3, // Disabled (Ubuntu)
KEY_EXSEL = 0xA4, // Disabled (Ubuntu)
KEY_PAD_00 = 0xB0, // Disabled (Ubuntu)
KEY_PAD_000 = 0xB1, // Disabled (Ubuntu)
KEY_THOUSANDS_SEPARATOR = 0xB2, // Disabled (Ubuntu)
KEY_DECIMAL_SEPARATOR = 0xB3, // Disabled (Ubuntu)
KEY_CURRENCY_UNIT = 0xB4, // Disabled (Ubuntu)
KEY_CURRENCY_SUB_UNIT = 0xB5, // Disabled (Ubuntu)
KEYPAD_LEFT_BRACE = 0xB6, // (
KEYPAD_RIGHT_BRACE = 0xB7, // )
KEYPAD_LEFT_CURLY_BRACE = 0xB8, // Disabled (Ubuntu)
KEYPAD_RIGHT_CURLY_BRACE = 0xB9, // Disabled (Ubuntu)
KEYPAD_TAB = 0xBA, // Disabled (Ubuntu)
KEYPAD_BACKSPACE = 0xBB, // Disabled (Ubuntu)
KEYPAD_A = 0xBC, // Disabled (Ubuntu)
KEYPAD_B = 0xBD, // Disabled (Ubuntu)
KEYPAD_C = 0xBE, // Disabled (Ubuntu)
KEYPAD_D = 0xBF, // Disabled (Ubuntu)
KEYPAD_E = 0xC0, // Disabled (Ubuntu)
KEYPAD_F = 0xC1, // Disabled (Ubuntu)
KEYPAD_XOR = 0xC2, // Disabled (Ubuntu)
KEYPAD_CARET = 0xC3, // Disabled (Ubuntu)
KEYPAD_PERCENT = 0xC4, // Disabled (Ubuntu)
KEYPAD_LESS_THAN = 0xC5, // Disabled (Ubuntu)
KEYPAD_GREATER_THAN = 0xC6, // Disabled (Ubuntu)
KEYPAD_AMPERSAND = 0xC7, // Disabled (Ubuntu)
KEYPAD_DOUBLEAMPERSAND = 0xC8, // Disabled (Ubuntu)
KEYPAD_PIPE = 0xC9, // Disabled (Ubuntu)
KEYPAD_DOUBLEPIPE = 0xCA, // Disabled (Ubuntu)
KEYPAD_COLON = 0xCB, // Disabled (Ubuntu)
KEYPAD_POUND_SIGN = 0xCC, // Disabled (Ubuntu)
KEYPAD_SPACE = 0xCD, // Disabled (Ubuntu)
KEYPAD_AT_SIGN = 0xCE, // Disabled (Ubuntu)
KEYPAD_EXCLAMATION_POINT = 0xCF, // Disabled (Ubuntu)
KEYPAD_MEMORY_STORE = 0xD0, // Disabled (Ubuntu)
KEYPAD_MEMORY_RECALL = 0xD1, // Disabled (Ubuntu)
KEYPAD_MEMORY_CLEAR = 0xD2, // Disabled (Ubuntu)
KEYPAD_MEMORY_ADD = 0xD3, // Disabled (Ubuntu)
KEYPAD_MEMORY_SUBTRACT = 0xD4, // Disabled (Ubuntu)
KEYPAD_MEMORY_MULTIPLY = 0xD5, // Disabled (Ubuntu)
KEYPAD_MEMORY_DIVIDE = 0xD6, // Disabled (Ubuntu)
KEYPAD_PLUS_MINUS = 0xD7, // Disabled (Ubuntu)
KEYPAD_CLEAR = 0xD8, // Delete (Ubuntu)
KEYPAD_CLEAR_ENTRY = 0xD9, // Disabled (Ubuntu)
KEYPAD_BINARY = 0xDA, // Disabled (Ubuntu)
KEYPAD_OCTAL = 0xDB, // Disabled (Ubuntu)
KEYPAD_DECIMAL = 0xDC, // Disabled (Ubuntu)
KEYPAD_HEXADECIMAL = 0xDD, // Disabled (Ubuntu)
KEY_LEFT_CTRL = 0xE0,
KEY_LEFT_SHIFT = 0xE1,
KEY_LEFT_ALT = 0xE2,
KEY_LEFT_GUI = 0xE3,
KEY_LEFT_WINDOWS = 0xE3, // Alias
KEY_RIGHT_CTRL = 0xE4,
KEY_RIGHT_SHIFT = 0xE5,
KEY_RIGHT_ALT = 0xE6,
KEY_RIGHT_GUI = 0xE7,
KEY_RIGHT_WINDOWS = 0xE7, // Alias
// Keyboard HID mappings
// Reserved (no_event_indicated)
HID_KEYBOARD_ERROR_ROLLOVER = 0x01,
HID_KEYBOARD_POST_FAIL = 0x02,
HID_KEYBOARD_ERROR_UNDEFINED = 0x03,
HID_KEYBOARD_A_AND_A = 0x04,
HID_KEYBOARD_B_AND_B = 0x05,
HID_KEYBOARD_C_AND_C = 0x06,
HID_KEYBOARD_D_AND_D = 0x07,
HID_KEYBOARD_E_AND_E = 0x08,
HID_KEYBOARD_F_AND_F = 0x09,
HID_KEYBOARD_G_AND_G = 0x0A,
HID_KEYBOARD_H_AND_H = 0x0B,
HID_KEYBOARD_I_AND_I = 0x0C,
HID_KEYBOARD_J_AND_J = 0x0D,
HID_KEYBOARD_K_AND_K = 0x0E,
HID_KEYBOARD_L_AND_L = 0x0F,
HID_KEYBOARD_M_AND_M = 0x10,
HID_KEYBOARD_N_AND_N = 0x11,
HID_KEYBOARD_O_AND_O = 0x12,
HID_KEYBOARD_P_AND_P = 0x13,
HID_KEYBOARD_Q_AND_Q = 0x14,
HID_KEYBOARD_R_AND_R = 0x15,
HID_KEYBOARD_S_AND_S = 0x16,
HID_KEYBOARD_T_AND_T = 0x17,
HID_KEYBOARD_U_AND_U = 0x18,
HID_KEYBOARD_V_AND_V = 0x19,
HID_KEYBOARD_W_AND_W = 0x1A,
HID_KEYBOARD_X_AND_X = 0x1B,
HID_KEYBOARD_Y_AND_Y = 0x1C,
HID_KEYBOARD_Z_AND_Z = 0x1D,
HID_KEYBOARD_1_AND_EXCLAMATION_POINT = 0x1E,
HID_KEYBOARD_2_AND_AT = 0x1F,
HID_KEYBOARD_3_AND_POUND = 0x20,
HID_KEYBOARD_4_AND_DOLLAR = 0x21,
HID_KEYBOARD_5_AND_PERCENT = 0x22,
HID_KEYBOARD_6_AND_CARAT = 0x23,
HID_KEYBOARD_7_AND_AMPERSAND = 0x24,
HID_KEYBOARD_8_AND_ASTERISK = 0x25,
HID_KEYBOARD_9_AND_LEFT_PAREN = 0x26,
HID_KEYBOARD_0_AND_RIGHT_PAREN = 0x27,
HID_KEYBOARD_ENTER = 0x28, // (MARKED AS ENTER_SLASH_RETURN)
HID_KEYBOARD_ESCAPE = 0x29,
HID_KEYBOARD_DELETE = 0x2A, // (BACKSPACE)
HID_KEYBOARD_TAB = 0x2B,
HID_KEYBOARD_SPACEBAR = 0x2C,
HID_KEYBOARD_MINUS_AND_UNDERSCORE = 0x2D, // (UNDERSCORE)
HID_KEYBOARD_EQUALS_AND_PLUS = 0x2E,
HID_KEYBOARD_LEFT_BRACKET_AND_LEFT_CURLY_BRACE = 0x2F,
HID_KEYBOARD_RIGHT_BRACKET_AND_RIGHT_CURLY_BRACE = 0x30,
HID_KEYBOARD_BACKSLASH_AND_PIPE = 0x31,
HID_KEYBOARD_NON_US_POUND_AND_TILDE = 0x32,
HID_KEYBOARD_SEMICOLON_AND_COLON = 0x33,
HID_KEYBOARD_QUOTE_AND_DOUBLEQUOTE = 0x34,
HID_KEYBOARD_GRAVE_ACCENT_AND_TILDE = 0x35,
HID_KEYBOARD_COMMA_AND_LESS_THAN = 0x36,
HID_KEYBOARD_PERIOD_AND_GREATER_THAN = 0x37,
HID_KEYBOARD_SLASH_AND_QUESTION_MARK = 0x38,
HID_KEYBOARD_CAPS_LOCK = 0x39,
HID_KEYBOARD_F1 = 0x3A,
HID_KEYBOARD_F2 = 0x3B,
HID_KEYBOARD_F3 = 0x3C,
HID_KEYBOARD_F4 = 0x3D,
HID_KEYBOARD_F5 = 0x3E,
HID_KEYBOARD_F6 = 0x3F,
HID_KEYBOARD_F7 = 0x40,
HID_KEYBOARD_F8 = 0x41,
HID_KEYBOARD_F9 = 0x42,
HID_KEYBOARD_F10 = 0x43,
HID_KEYBOARD_F11 = 0x44,
HID_KEYBOARD_F12 = 0x45,
HID_KEYBOARD_PRINTSCREEN = 0x46,
HID_KEYBOARD_SCROLL_LOCK = 0x47,
HID_KEYBOARD_PAUSE = 0x48,
HID_KEYBOARD_INSERT = 0x49,
HID_KEYBOARD_HOME = 0x4A,
HID_KEYBOARD_PAGE_UP = 0x4B,
HID_KEYBOARD_DELETE_FORWARD = 0x4C,
HID_KEYBOARD_END = 0x4D,
HID_KEYBOARD_PAGE_DOWN = 0x4E,
HID_KEYBOARD_RIGHTARROW = 0x4F,
HID_KEYBOARD_LEFTARROW = 0x50,
HID_KEYBOARD_DOWNARROW = 0x51,
HID_KEYBOARD_UPARROW = 0x52,
HID_KEYPAD_NUM_LOCK_AND_CLEAR = 0x53,
HID_KEYPAD_DIVIDE = 0x54,
HID_KEYPAD_MULTIPLY = 0x55,
HID_KEYPAD_SUBTRACT = 0x56,
HID_KEYPAD_ADD = 0x57,
HID_KEYPAD_ENTER = 0x58,
HID_KEYPAD_1_AND_END = 0x59,
HID_KEYPAD_2_AND_DOWN_ARROW = 0x5A,
HID_KEYPAD_3_AND_PAGE_DOWN = 0x5B,
HID_KEYPAD_4_AND_LEFT_ARROW = 0x5C,
HID_KEYPAD_5 = 0x5D,
HID_KEYPAD_6_AND_RIGHT_ARROW = 0x5E,
HID_KEYPAD_7_AND_HOME = 0x5F,
HID_KEYPAD_8_AND_UP_ARROW = 0x60,
HID_KEYPAD_9_AND_PAGE_UP = 0x61,
HID_KEYPAD_0_AND_INSERT = 0x62,
HID_KEYPAD_PERIOD_AND_DELETE = 0x63,
HID_KEYBOARD_NON_US_BACKSLASH_AND_PIPE = 0x64,
HID_KEYBOARD_APPLICATION = 0x65,
HID_KEYBOARD_POWER = 0x66,
HID_KEYPAD_EQUALS = 0x67,
HID_KEYBOARD_F13 = 0x68,
HID_KEYBOARD_F14 = 0x69,
HID_KEYBOARD_F15 = 0x6A,
HID_KEYBOARD_F16 = 0x6B,
HID_KEYBOARD_F17 = 0x6C,
HID_KEYBOARD_F18 = 0x6D,
HID_KEYBOARD_F19 = 0x6E,
HID_KEYBOARD_F20 = 0x6F,
HID_KEYBOARD_F21 = 0x70,
HID_KEYBOARD_F22 = 0x71,
HID_KEYBOARD_F23 = 0x72,
HID_KEYBOARD_F24 = 0x73,
HID_KEYBOARD_EXECUTE = 0x74,
HID_KEYBOARD_HELP = 0x75,
HID_KEYBOARD_MENU = 0x76,
HID_KEYBOARD_SELECT = 0x77,
HID_KEYBOARD_STOP = 0x78,
HID_KEYBOARD_AGAIN = 0x79,
HID_KEYBOARD_UNDO = 0x7A,
HID_KEYBOARD_CUT = 0x7B,
HID_KEYBOARD_COPY = 0x7C,
HID_KEYBOARD_PASTE = 0x7D,
HID_KEYBOARD_FIND = 0x7E,
HID_KEYBOARD_MUTE = 0x7F,
HID_KEYBOARD_VOLUME_UP = 0x80,
HID_KEYBOARD_VOLUME_DOWN = 0x81,
HID_KEYBOARD_LOCKING_CAPS_LOCK = 0x82,
HID_KEYBOARD_LOCKING_NUM_LOCK = 0x83,
HID_KEYBOARD_LOCKING_SCROLL_LOCK = 0x84,
HID_KEYPAD_COMMA = 0x85,
HID_KEYPAD_EQUAL_SIGN = 0x86,
HID_KEYBOARD_INTERNATIONAL1 = 0x87,
HID_KEYBOARD_INTERNATIONAL2 = 0x88,
HID_KEYBOARD_INTERNATIONAL3 = 0x89,
HID_KEYBOARD_INTERNATIONAL4 = 0x8A,
HID_KEYBOARD_INTERNATIONAL5 = 0x8B,
HID_KEYBOARD_INTERNATIONAL6 = 0x8C,
HID_KEYBOARD_INTERNATIONAL7 = 0x8D,
HID_KEYBOARD_INTERNATIONAL8 = 0x8E,
HID_KEYBOARD_INTERNATIONAL9 = 0x8F,
HID_KEYBOARD_LANG1 = 0x90,
HID_KEYBOARD_LANG2 = 0x91,
HID_KEYBOARD_LANG3 = 0x92,
HID_KEYBOARD_LANG4 = 0x93,
HID_KEYBOARD_LANG5 = 0x94,
HID_KEYBOARD_LANG6 = 0x95,
HID_KEYBOARD_LANG7 = 0x96,
HID_KEYBOARD_LANG8 = 0x97,
HID_KEYBOARD_LANG9 = 0x98,
HID_KEYBOARD_ALTERNATE_ERASE = 0x99,
HID_KEYBOARD_SYSREQ_SLASH_ATTENTION = 0x9A,
HID_KEYBOARD_CANCEL = 0x9B,
HID_KEYBOARD_CLEAR = 0x9C,
HID_KEYBOARD_PRIOR = 0x9D,
HID_KEYBOARD_RETURN = 0x9E,
HID_KEYBOARD_SEPARATOR = 0x9F,
HID_KEYBOARD_OUT = 0xA0,
HID_KEYBOARD_OPER = 0xA1,
HID_KEYBOARD_CLEAR_SLASH_AGAIN = 0xA2,
HID_KEYBOARD_CRSEL_SLASH_PROPS = 0xA3,
HID_KEYBOARD_EXSEL = 0xA4,
// Reserved 0xA5-AF
HID_KEYPAD_00 = 0xB0,
HID_KEYPAD_000 = 0xB1,
HID_THOUSANDS_SEPARATOR = 0xB2,
HID_DECIMAL_SEPARATOR = 0xB3,
HID_CURRENCY_UNIT = 0xB4,
HID_CURRENCY_SUBUNIT = 0xB5,
HID_KEYPAD_LEFT_PAREN = 0xB6,
HID_KEYPAD_RIGHT_PAREN = 0xB7,
HID_KEYPAD_LEFT_CURLY_BRACE = 0xB8,
HID_KEYPAD_RIGHT_CURLY_BRACE = 0xB9,
HID_KEYPAD_TAB = 0xBA,
HID_KEYPAD_BACKSPACE = 0xBB,
HID_KEYPAD_A = 0xBC,
HID_KEYPAD_B = 0xBD,
HID_KEYPAD_C = 0xBE,
HID_KEYPAD_D = 0xBF,
HID_KEYPAD_E = 0xC0,
HID_KEYPAD_F = 0xC1,
HID_KEYPAD_XOR = 0xC2,
HID_KEYPAD_CARAT = 0xC3,
HID_KEYPAD_PERCENT = 0xC4,
HID_KEYPAD_LESS_THAN = 0xC5,
HID_KEYPAD_GREATER_THAN = 0xC6,
HID_KEYPAD_AMPERSAND = 0xC7,
HID_KEYPAD_DOUBLEAMPERSAND = 0xC8,
HID_KEYPAD_PIPE = 0xC9,
HID_KEYPAD_DOUBLEPIPE = 0xCA,
HID_KEYPAD_COLON = 0xCB,
HID_KEYPAD_POUND_SIGN = 0xCC,
HID_KEYPAD_SPACE = 0xCD,
HID_KEYPAD_AT_SIGN = 0xCE,
HID_KEYPAD_EXCLAMATION_POINT = 0xCF,
HID_KEYPAD_MEMORY_STORE = 0xD0,
HID_KEYPAD_MEMORY_RECALL = 0xD1,
HID_KEYPAD_MEMORY_CLEAR = 0xD2,
HID_KEYPAD_MEMORY_ADD = 0xD3,
HID_KEYPAD_MEMORY_SUBTRACT = 0xD4,
HID_KEYPAD_MEMORY_MULTIPLY = 0xD5,
HID_KEYPAD_MEMORY_DIVIDE = 0xD6,
HID_KEYPAD_PLUS_SLASH_MINUS = 0xD7,
HID_KEYPAD_CLEAR = 0xD8,
HID_KEYPAD_CLEAR_ENTRY = 0xD9,
HID_KEYPAD_BINARY = 0xDA,
HID_KEYPAD_OCTAL = 0xDB,
HID_KEYPAD_DECIMAL = 0xDC,
HID_KEYPAD_HEXADECIMAL = 0xDD,
// 0xDE-0xDF - RESERVED
HID_KEYBOARD_LEFT_CONTROL = 0xE0,
HID_KEYBOARD_LEFT_SHIFT = 0xE1,
HID_KEYBOARD_LEFT_ALT = 0xE2,
HID_KEYBOARD_LEFT_GUI = 0xE3,
HID_KEYBOARD_RIGHT_CONTROL = 0xE4,
HID_KEYBOARD_RIGHT_SHIFT = 0xE5,
HID_KEYBOARD_RIGHT_ALT = 0xE6,
HID_KEYBOARD_RIGHT_GUI = 0xE7,
};
static const uint16_t _asciimap[] = {
KEY_RESERVED, // NUL
KEY_RESERVED, // SOH
KEY_RESERVED, // STX
KEY_RESERVED, // ETX
KEY_RESERVED, // EOT
KEY_RESERVED, // ENQ
KEY_RESERVED, // ACK
KEY_RESERVED, // BEL
KEY_BACKSPACE, // BS Backspace
KEY_TAB, // TAB Tab
KEY_ENTER, // LF Enter
KEY_RESERVED, // VT
KEY_RESERVED, // FF
KEY_RESERVED, // CR
KEY_RESERVED, // SO
KEY_RESERVED, // SI
KEY_RESERVED, // DEL
KEY_RESERVED, // DC1
KEY_RESERVED, // DC2
KEY_RESERVED, // DC3
KEY_RESERVED, // DC4
KEY_RESERVED, // NAK
KEY_RESERVED, // SYN
KEY_RESERVED, // ETB
KEY_RESERVED, // CAN
KEY_RESERVED, // EM
KEY_RESERVED, // SUB
KEY_RESERVED, // ESC
KEY_RESERVED, // FS
KEY_RESERVED, // GS
KEY_RESERVED, // RS
KEY_RESERVED, // US
KEY_SPACE, // ' ' Space
KEY_1 | MOD_LEFT_SHIFT, // !
KEY_QUOTE | MOD_LEFT_SHIFT, // "
KEY_3 | MOD_LEFT_SHIFT, // #
KEY_4 | MOD_LEFT_SHIFT, // $
KEY_5 | MOD_LEFT_SHIFT, // %
KEY_7 | MOD_LEFT_SHIFT, // &
KEY_QUOTE, // '
KEY_9 | MOD_LEFT_SHIFT, // (
KEY_0 | MOD_LEFT_SHIFT, // )
KEY_8 | MOD_LEFT_SHIFT, // *
KEY_EQUAL | MOD_LEFT_SHIFT, // +
KEY_COMMA, // ,
KEY_MINUS, // -
KEY_PERIOD, // .
KEY_SLASH, // /
KEY_0, // 0
KEY_1, // 1
KEY_2, // 2
KEY_3, // 3
KEY_4, // 4
KEY_5, // 5
KEY_6, // 6
KEY_7, // 7
KEY_8, // 8
KEY_9, // 9
KEY_SEMICOLON | MOD_LEFT_SHIFT, // :
KEY_SEMICOLON, // ;
KEY_COMMA | MOD_LEFT_SHIFT, // <
KEY_EQUAL, // =
KEY_PERIOD | MOD_LEFT_SHIFT, // >
KEY_SLASH | MOD_LEFT_SHIFT, // ?
KEY_2 | MOD_LEFT_SHIFT, // @
KEY_A | MOD_LEFT_SHIFT, // A
KEY_B | MOD_LEFT_SHIFT, // B
KEY_C | MOD_LEFT_SHIFT, // C
KEY_D | MOD_LEFT_SHIFT, // D
KEY_E | MOD_LEFT_SHIFT, // E
KEY_F | MOD_LEFT_SHIFT, // F
KEY_G | MOD_LEFT_SHIFT, // G
KEY_H | MOD_LEFT_SHIFT, // H
KEY_I | MOD_LEFT_SHIFT, // I
KEY_J | MOD_LEFT_SHIFT, // J
KEY_K | MOD_LEFT_SHIFT, // K
KEY_L | MOD_LEFT_SHIFT, // L
KEY_M | MOD_LEFT_SHIFT, // M
KEY_N | MOD_LEFT_SHIFT, // N
KEY_O | MOD_LEFT_SHIFT, // O
KEY_P | MOD_LEFT_SHIFT, // P
KEY_Q | MOD_LEFT_SHIFT, // Q
KEY_R | MOD_LEFT_SHIFT, // R
KEY_S | MOD_LEFT_SHIFT, // S
KEY_T | MOD_LEFT_SHIFT, // T
KEY_U | MOD_LEFT_SHIFT, // U
KEY_V | MOD_LEFT_SHIFT, // V
KEY_W | MOD_LEFT_SHIFT, // W
KEY_X | MOD_LEFT_SHIFT, // X
KEY_Y | MOD_LEFT_SHIFT, // Y
KEY_Z | MOD_LEFT_SHIFT, // Z
KEY_LEFT_BRACE, // [
KEY_BACKSLASH, // bslash
KEY_RIGHT_BRACE, // ]
KEY_6 | MOD_LEFT_SHIFT, // ^
KEY_MINUS | MOD_LEFT_SHIFT, // _
KEY_TILDE, // `
KEY_A, // a
KEY_B, // b
KEY_C, // c
KEY_D, // d
KEY_E, // e
KEY_F, // f
KEY_G, // g
KEY_H, // h
KEY_I, // i
KEY_J, // j
KEY_K, // k
KEY_L, // l
KEY_M, // m
KEY_N, // n
KEY_O, // o
KEY_P, // p
KEY_Q, // q
KEY_R, // r
KEY_S, // s
KEY_T, // t
KEY_U, // u
KEY_V, // v
KEY_W, // w
KEY_X, // x
KEY_Y, // y
KEY_Z, // z
KEY_LEFT_BRACE | MOD_LEFT_SHIFT, // {
KEY_BACKSLASH | MOD_LEFT_SHIFT, // |
KEY_RIGHT_BRACE | MOD_LEFT_SHIFT, // }
KEY_TILDE | MOD_LEFT_SHIFT, // ~
KEY_RESERVED, // DEL
// 7-bit ASCII codes end here
// The following characters belong to ISO-8859-15
// ! The first 16 values here are used for the numpad
KEYPAD_0,
KEYPAD_1,
KEYPAD_2,
KEYPAD_3,
KEYPAD_4,
KEYPAD_5,
KEYPAD_6,
KEYPAD_7,
KEYPAD_8,
KEYPAD_9,
KEYPAD_ADD,
KEYPAD_SUBTRACT,
KEYPAD_MULTIPLY,
KEYPAD_DIVIDE,
KEYPAD_ENTER,
KEYPAD_DOT,
// KEY_RESERVED, // 128 - Unused
// KEY_RESERVED, // 129 - Unused
// KEY_RESERVED, // 130 - Unused
// KEY_RESERVED, // 131 - Unused
// KEY_RESERVED, // 132 - Unused
// KEY_RESERVED, // 133 - Unused
// KEY_RESERVED, // 134 - Unused
// KEY_RESERVED, // 135 - Unused
// KEY_RESERVED, // 136 - Unused
// KEY_RESERVED, // 137 - Unused
// KEY_RESERVED, // 138 - Unused
// KEY_RESERVED, // 139 - Unused
// KEY_RESERVED, // 140 - Unused
// KEY_RESERVED, // 141 - Unused
// KEY_RESERVED, // 142 - Unused
// KEY_RESERVED, // 143 - Unused
KEY_RESERVED, // 144 - Unused
KEY_RESERVED, // 145 - Unused
KEY_RESERVED, // 146 - Unused
KEY_RESERVED, // 147 - Unused
KEY_RESERVED, // 148 - Unused
KEY_RESERVED, // 149 - Unused
KEY_RESERVED, // 150 - Unused
KEY_RESERVED, // 151 - Unused
KEY_RESERVED, // 152 - Unused
KEY_RESERVED, // 153 - Unused
KEY_RESERVED, // 154 - Unused
KEY_RESERVED, // 155 - Unused
KEY_RESERVED, // 156 - Unused
KEY_RESERVED, // 157 - Unused
KEY_RESERVED, // 158 - Unused
KEY_RESERVED, // 159 - Unused
KEY_RESERVED, // 160 - Non-breaking Space
KEY_RESERVED, // 161 - Inverted Exclamation Mark
KEY_RESERVED, // 162 - Cent
KEY_RESERVED, // 163 - British Pound Sign
KEY_RESERVED, // 164 - Euro Sign
KEY_RESERVED, // 165 - Yen
KEY_RESERVED, // 166 - Capital 's' Inverted Circumflex
KEY_RESERVED, // 167 - Section Sign
KEY_RESERVED, // 168 - 's' Inverted Circumflex
KEY_RESERVED, // 169 - Copyright Sign
KEY_RESERVED, // 170 - Superscript 'a'
KEY_RESERVED, // 171 - Open Guillemet
KEY_RESERVED, // 172 - Logic Negation
KEY_RESERVED, // 173 - Soft Hypen
KEY_RESERVED, // 174 - Registered Trademark
KEY_RESERVED, // 175 - Macron
KEY_RESERVED, // 176 - Degree Symbol
KEY_RESERVED, // 177 - Plus-Minus
KEY_RESERVED, // 178 - Superscript '2'
KEY_RESERVED, // 179 - Superscript '3'
KEY_RESERVED, // 180 - Capital 'z' Inverted Circumflex
KEY_RESERVED, // 181 - Micro Symbol
KEY_RESERVED, // 182 - Paragraph Mark
KEY_RESERVED, // 183 - Interpunct
KEY_RESERVED, // 184 - 'z' Inverted Circumflex
KEY_RESERVED, // 185 - Superscript '1'
KEY_RESERVED, // 186 - Ordinal Indicator
KEY_RESERVED, // 187 - Closed Guillemet
KEY_RESERVED, // 188 - Capital 'oe'
KEY_RESERVED, // 189 - 'oe'
KEY_RESERVED, // 190 - Capital 'y' Umlaut
KEY_RESERVED, // 191 - Inverted Question Mark
KEY_RESERVED, // 192 - Capital 'a' Grave
KEY_RESERVED, // 193 - Capital 'a' Acute
KEY_RESERVED, // 194 - Capital 'a' Circumflex
KEY_RESERVED, // 195 - Capital 'a' Tilde
KEY_RESERVED, // 196 - Capital 'a' Umlaut
KEY_RESERVED, // 197 - Capital 'a' Circle
KEY_RESERVED, // 198 - Capital 'ae'
KEY_RESERVED, // 199 - Capital 'c' Cedilla
KEY_RESERVED, // 200 - Capital 'e' Grave
KEY_RESERVED, // 201 - Capital 'e' Acute
KEY_RESERVED, // 202 - Capital 'e' Circumflex
KEY_RESERVED, // 203 - Capital 'e' Umlaut
KEY_RESERVED, // 204 - Capital 'i' Grave
KEY_RESERVED, // 205 - Capital 'i' Acute
KEY_RESERVED, // 206 - Capital 'i' Circumflex
KEY_RESERVED, // 207 - Capital 'i' Umlaut
KEY_RESERVED, // 208 - Capital Eth
KEY_RESERVED, // 207 - Capital 'n' Tilde
KEY_RESERVED, // 210 - Capital 'o' Grave
KEY_RESERVED, // 211 - Capital 'o' Acute
KEY_RESERVED, // 212 - Capital 'o' Circumflex
KEY_RESERVED, // 213 - Capital 'o' Tilde
KEY_RESERVED, // 214 - Capital 'o' Umlaut
KEY_RESERVED, // 215 - Multiplication Sign
KEY_RESERVED, // 216 - Capital 'o' Barred
KEY_RESERVED, // 217 - Capital 'u' Grave
KEY_RESERVED, // 218 - Capital 'u' Acute
KEY_RESERVED, // 219 - Capital 'u' Circumflex
KEY_RESERVED, // 220 - Capital 'u' Umlaut
KEY_RESERVED, // 221 - Capital 'y' Acute
KEY_RESERVED, // 222 - Capital Thorn
KEY_RESERVED, // 223 - Eszett
KEY_RESERVED, // 224 - 'a' Grave
KEY_RESERVED, // 225 - 'a' Acute
KEY_RESERVED, // 226 - 'a' Circumflex
KEY_RESERVED, // 227 - 'a' Tilde
KEY_RESERVED, // 228 - 'a' Umlaut
KEY_RESERVED, // 229 - 'a' Circle
KEY_RESERVED, // 230 - 'ae'
KEY_RESERVED, // 231 - 'c' Cedilla
KEY_RESERVED, // 232 - 'e' Grave
KEY_RESERVED, // 233 - 'e' Acute
KEY_RESERVED, // 234 - 'e' Circumflex
KEY_RESERVED, // 235 - 'e' Umlaut
KEY_RESERVED, // 236 - 'i' Grave
KEY_RESERVED, // 237 - 'i' Acute
KEY_RESERVED, // 238 - 'i' Circumflex
KEY_RESERVED, // 239 - 'i' Umlaut
KEY_RESERVED, // 240 - Eth
KEY_RESERVED, // 241 - 'n' Tilde
KEY_RESERVED, // 242 - 'o' Grave
KEY_RESERVED, // 243 - 'o' Acute
KEY_RESERVED, // 244 - 'o' Circumflex
KEY_RESERVED, // 245 - 'o' Tilde
KEY_RESERVED, // 246 - 'o' Umlaut
KEY_RESERVED, // 247 - Multiplication Sign
KEY_RESERVED, // 248 - 'o' Barred
KEY_RESERVED, // 249 - 'u' Grave
KEY_RESERVED, // 250 - 'u' Acute
KEY_RESERVED, // 251 - 'u' Circumflex
KEY_RESERVED, // 252 - 'u' Umlaut
KEY_RESERVED, // 253 - 'y' Acute
KEY_RESERVED, // 254 - Thorn
KEY_RESERVED, // 255 - 'y' Umlaut
};

316
src/usb_inc/usb.h Normal file
View File

@ -0,0 +1,316 @@
#pragma once
#include <stdint.h>
// USB U16 helpers
#define U16(_high, _low) ((uint16_t)(((_high) << 8) | (_low)))
#define U16_HIGH(_u16) ((uint8_t)(((_u16) >> 8) & 0x00ff))
#define U16_LOW(_u16) ((uint8_t)((_u16)&0x00ff))
#define U16_TO_U8S_BE(_u16) U16_HIGH(_u16), U16_LOW(_u16)
#define U16_TO_U8S_LE(_u16) U16_LOW(_u16), U16_HIGH(_u16)
#define U16_TO_U8S_BE_A(_u16) \
{ U16_TO_U8S_BE(_u16) }
#define U16_TO_U8S_LE_A(_u16) \
{ U16_TO_U8S_LE(_u16) }
// USB String helpers
enum {
USB_STRING_LANG = 0,
USB_STRING_VENDOR,
USB_STRING_PRODUCT,
USB_STRING_SERIAL,
USB_STRING_CDC,
USB_STRING_HID_IO4,
USB_STRING_HID_MISC,
};
// USB Spec definitions
#define DESC_IAD 0x0B
#define DESC_CS_DEVICE 0x21
#define DESC_CS_CONFIGURATION 0x22
#define DESC_CS_STRING 0x23
#define DESC_CS_INTERFACE 0x24
#define DESC_CS_ENDPOINT 0x25
#define USB_CLASS_UNSPECIFIED 0
#define USB_CLASS_AUDIO 1
#define USB_CLASS_CDC 2
#define USB_CLASS_HID 3
#define USB_CLASS_RESERVED_4 4
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MSC 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 10
#define USB_CLASS_SMART_CARD 11
#define USB_CLASS_RESERVED_12 12
#define USB_CLASS_CONTENT_SECURITY 13
#define USB_CLASS_VIDEO 14
#define USB_CLASS_PERSONAL_HEALTHCARE 15
#define USB_CLASS_AUDIO_VIDEO 16
#define USB_CLASS_DIAGNOSTIC 0xDC
#define USB_CLASS_WIRELESS_CONTROLLER 0xE0
#define USB_CLASS_MISC 0xEF
#define USB_CLASS_APPLICATION_SPECIFIC 0xFE
#define USB_CLASS_VENDOR_SPECIFIC 0xFF
#define CDC_COMM_SUBCLASS_DIRECT_LINE_CONTROL_MODEL 0x01
#define CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL 0x02
#define CDC_COMM_SUBCLASS_TELEPHONE_CONTROL_MODEL 0x03
#define CDC_COMM_SUBCLASS_MULTICHANNEL_CONTROL_MODEL 0x04
#define CDC_COMM_SUBCLASS_CAPI_CONTROL_MODEL 0x05
#define CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL 0x06
#define CDC_COMM_SUBCLASS_ATM_NETWORKING_CONTROL_MODEL 0x07
#define CDC_COMM_SUBCLASS_WIRELESS_HANDSET_CONTROL_MODEL0x08
#define CDC_COMM_SUBCLASS_DEVICE_MANAGEMENT 0x09
#define CDC_COMM_SUBCLASS_MOBILE_DIRECT_LINE_MODEL 0x0A
#define CDC_COMM_SUBCLASS_OBEX 0x0B
#define CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL 0x0C
#define CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL 0x0D
#define CDC_COMM_PROTOCOL_NONE 0x00
#define CDC_COMM_PROTOCOL_ATCOMMAND 0x01
#define CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101 0x02
#define CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO0x03
#define CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707 0x04
#define CDC_COMM_PROTOCOL_ATCOMMAND_3GPP_27007 0x05
#define CDC_COMM_PROTOCOL_ATCOMMAND_CDMA 0x06
#define CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL 0x07
#define CDC_FUNC_DESC_HEADER 0x00
#define CDC_FUNC_DESC_CALL_MANAGEMENT 0x01
#define CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT 0x02
#define CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT 0x03
#define CDC_FUNC_DESC_TELEPHONE_RINGER 0x04
#define CDC_FUNC_DESC_TELEPHONE_CALL_AND_LINE_STATE_REPORTING_CAPACITY0x05
#define CDC_FUNC_DESC_UNION 0x06
#define CDC_FUNC_DESC_COUNTRY_SELECTION 0x07
#define CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES 0x08
#define CDC_FUNC_DESC_USB_TERMINAL 0x09
#define CDC_FUNC_DESC_NETWORK_CHANNEL_TERMINAL 0x0A
#define CDC_FUNC_DESC_PROTOCOL_UNIT 0x0B
#define CDC_FUNC_DESC_EXTENSION_UNIT 0x0C
#define CDC_FUNC_DESC_MULTICHANEL_MANAGEMENT 0x0D
#define CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT 0x0E
#define CDC_FUNC_DESC_ETHERNET_NETWORKING 0x0F
#define CDC_FUNC_DESC_ATM_NETWORKING 0x10
#define CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL 0x11
#define CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL 0x12
#define CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL 0x13
#define CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL 0x14
#define CDC_FUNC_DESC_OBEX 0x15
#define CDC_FUNC_DESC_COMMAND_SET 0x16
#define CDC_FUNC_DESC_COMMAND_SET_DETAIL 0x17
#define CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL 0x18
#define CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER 0x19
#define CDC_FUNC_DESC_NCM 0x1A
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
typedef struct __attribute__((packed)) {
uint8_t bmRequestType;
uint8_t bRequest;
union {
uint8_t wBytes[6];
struct __attribute__((packed)) {
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
// Core setup packet types
struct __attribute__((packed)) {
uint8_t bIndex;
uint8_t bType;
uint16_t wLanguageId;
uint16_t wDescriptorLength;
} getDescriptor;
struct __attribute__((packed)) {
uint16_t wFeature;
uint16_t wEp;
} clearFeature;
struct __attribute__((packed)) {
uint16_t wAddress;
} setAddress;
struct __attribute__((packed)) {
uint16_t wConfiguration;
} setConfiguration;
struct __attribute__((packed)) {
uint16_t wFeature;
uint16_t wEp;
} setFeature;
struct __attribute__((packed)) {
uint16_t wAlternate;
uint16_t wInterface;
} setInterface;
struct __attribute__((packed)) {
uint16_t wValue;
uint16_t wInterface;
} getStatus;
// USB HID
struct __attribute__((packed)) {
uint8_t bIndex;
uint8_t bType;
uint16_t wInterfaceNum;
uint16_t wDescriptorLength;
} hidGetDescriptor;
struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bReportType;
uint16_t wInterface;
uint16_t wLength;
} hidGetReport;
struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bReportType;
uint16_t wInterface;
uint16_t wLength;
} hidSetReport;
struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bPad;
uint16_t wInterface;
uint16_t wLength;
} hidGetIdle;
struct __attribute__((packed)) {
uint8_t bReportId;
uint8_t bDuration;
uint16_t wInterface;
uint16_t wLength;
} hidSetIdle;
struct __attribute__((packed)) {
uint16_t wPad;
uint16_t wInterface;
uint16_t wLength;
} hidGetProtocol;
struct __attribute__((packed)) {
uint16_t wProtocol;
uint16_t wInterface;
uint16_t wLength;
} hidSetProtocol;
// USB CDC
struct __attribute__((packed)) {
uint16_t wValue;
uint16_t wInterface;
uint16_t wLength;
} getLineCoding;
struct __attribute__((packed)) {
uint16_t wValue;
uint16_t wInterface;
uint16_t wLength;
} setLineCoding;
};
} usb_setup_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacture;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} usb_device_descr_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
} usb_desc_iad_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t MaxPower;
} usb_desc_config_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} usb_desc_interface_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
uint8_t bReportDescriptorType;
uint16_t wDescriptorLength;
} usb_desc_hid_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} usb_desc_endpoint_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint16_t bcdCDC;
} usb_desc_cdc_header_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bControlInterface;
uint8_t bSubordinateInterface0;
} usb_desc_cdc_union_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
uint8_t bDataInterface;
} usb_desc_cdc_call_t;
typedef struct __attribute__((packed)) {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubtype;
uint8_t bmCapabilities;
} usb_desc_cdc_acm_t;
// HID definitions
#define GET_REPORT 0x01
#define GET_IDLE 0x02
#define GET_PROTOCOL 0x03
#define SET_REPORT 0x09
#define SET_IDLE 0x0A
#define SET_PROTOCOL 0x0B
#define HID_NONE 0x00
#define HID_KEYBOARD 0x01
#define HID_MOUSE 0x02
#define HID_RPT_TYPE_INPUT 0x01
#define HID_RPT_TYPE_OUTPUT 0x02
#define HID_RPT_TYPE_FEATURE 0x03

551
src/usbd_driver.c Normal file
View File

@ -0,0 +1,551 @@
#include "tasoller.h"
usb_setup_t g_usbd_SetupPacket;
// uint8_t g_usbd_SetupPacket[8] = { 0 };
// static const usb_setup_t* p_usbd_SetupPacket = (usb_setup_t*)&g_usbd_SetupPacket;
volatile uint8_t g_usbd_RemoteWakeupEn = 0;
volatile uint8_t *g_usbd_CtrlInPointer = 0;
volatile uint32_t g_usbd_CtrlInSize = 0;
static volatile uint8_t *g_usbd_CtrlOutPointer = 0;
static volatile uint32_t g_usbd_CtrlOutSize = 0;
static volatile uint32_t g_usbd_CtrlOutSizeLimit = 0;
static volatile uint32_t g_usbd_UsbAddr = 0;
static volatile uint32_t g_usbd_UsbConfig = 0;
static volatile uint32_t g_usbd_CtrlMaxPktSize = 8;
static volatile uint32_t g_usbd_UsbAltInterface = 0;
static volatile uint32_t g_usbd_CtrlOutToggle = 0;
static volatile uint8_t g_usbd_CtrlInZeroFlag = 0;
static void (*g_usbd_CtrlOutCallback)(volatile uint8_t *, uint32_t);
uint32_t g_u32EpStallLock = 0;
static inline void Tas_USBD_GetDescriptor(void);
static inline void Tas_USBD_StandardRequest(void);
static uint8_t su8VendorCount = 0;
void Tas_USBD_Open(void) {
g_usbd_CtrlMaxPktSize = gpDeviceDescriptor->bMaxPacketSize0;
USBD->ATTR = 0x650; // Disable D+ and USB controller
CLK_SysTickLongDelay(3000 ms);
USBD->ATTR = 0x7D0;
USBD_SET_SE0();
}
void Tas_USBD_Init(void) {
// Buffer range for setup packet -> [0~7]
USBD->STBUFSEG = SETUP_BUF_BASE;
// USB control IN/OUT on EP_CTRL_IN/EP_CTRL_OUT (addr 0)
USBD_CONFIG_EP(EP_CTRL_IN, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
USBD_SET_EP_BUF_ADDR(EP_CTRL_IN, EP0_BUF_BASE);
USBD_CONFIG_EP(EP_CTRL_OUT, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
USBD_SET_EP_BUF_ADDR(EP_CTRL_OUT, EP1_BUF_BASE);
// CDC data IN/OUT on EP2/EP3
USBD_CONFIG_EP(EP_CDC_IN, USBD_CFG_EPMODE_IN | 1);
USBD_SET_EP_BUF_ADDR(EP_CDC_IN, EP2_BUF_BASE);
USBD_CONFIG_EP(EP_CDC_OUT, USBD_CFG_EPMODE_OUT | 2);
USBD_SET_EP_BUF_ADDR(EP_CDC_OUT, EP3_BUF_BASE);
USBD_SET_PAYLOAD_LEN(EP_CDC_OUT, USBD_CDC_OUT_MAX_SIZE);
// CDC command IN on EP4
USBD_CONFIG_EP(EP_CDC_CMD, USBD_CFG_EPMODE_IN | 3);
USBD_SET_EP_BUF_ADDR(EP_CDC_CMD, EP4_BUF_BASE);
// IO4 HID IN on EP5
USBD_CONFIG_EP(EP_HID_IO4_IN, USBD_CFG_EPMODE_IN | 4);
USBD_SET_EP_BUF_ADDR(EP_HID_IO4_IN, EP5_BUF_BASE);
// Misc HID IN/OUT on EP6/EP6
USBD_CONFIG_EP(EP_HID_MISC_IN, USBD_CFG_EPMODE_IN | 5);
USBD_SET_EP_BUF_ADDR(EP_HID_MISC_IN, EP6_BUF_BASE);
USBD_CONFIG_EP(EP_HID_MISC_OUT, USBD_CFG_EPMODE_OUT | 6);
USBD_SET_EP_BUF_ADDR(EP_HID_MISC_OUT, EP7_BUF_BASE);
USBD_SET_PAYLOAD_LEN(EP_HID_MISC_OUT, USBD_HID_BUF_LEN);
}
void Tas_USBD_Start(void) {
// 100ms delay required as part of spec
CLK_SysTickDelay(100 ms);
USBD_CLR_SE0(); // Disable software-disconnect function
// Clear USB-related interrupts before enable interrupt
USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
// Enable USB-related interrupts.
USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
}
void Tas_USBD_GetSetupPacket(usb_setup_t *buf) {
memcpy(buf, &g_usbd_SetupPacket, sizeof g_usbd_SetupPacket);
}
// <static inline> as unused for now
static inline void Tas_USBD_VendorRequest(void) { return; }
void Tas_USBD_ProcessSetupPacket(void) {
g_usbd_CtrlOutToggle = 0;
// Get SETUP packet from USB buffer
USBD_MemCopy((uint8_t *)&g_usbd_SetupPacket, (uint8_t *)USBD_BUF_BASE, 8);
// Check the request type
switch (g_usbd_SetupPacket.bmRequestType & 0x60) {
case REQ_STANDARD:
Tas_USBD_StandardRequest();
break;
case REQ_CLASS:
Tas_USBD_ClassRequest();
break;
case REQ_VENDOR:
Tas_USBD_VendorRequest();
break;
default:
// Setup error, stall the device
USBD_SET_EP_STALL(EP_CTRL_IN);
USBD_SET_EP_STALL(EP_CTRL_OUT);
break;
}
}
static inline void Tas_USBD_GetDescriptor(void) {
uint16_t u16Len;
g_usbd_CtrlInZeroFlag = 0;
u16Len = g_usbd_SetupPacket.wLength;
switch (g_usbd_SetupPacket.getDescriptor.bType) {
// Get Device Descriptor
case DESC_DEVICE:
su8VendorCount = 0;
u16Len = Minimum(u16Len, LEN_DEVICE);
Tas_USBD_PrepareCtrlIn((uint8_t *)gpDeviceDescriptor, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
// Get Configuration Descriptor
case DESC_CONFIG: {
uint32_t u32TotalLen = gpConfigDescriptor->wTotalLength;
if (u16Len > u32TotalLen) {
u16Len = u32TotalLen;
if ((u16Len % g_usbd_CtrlMaxPktSize) == 0) g_usbd_CtrlInZeroFlag = 1;
}
Tas_USBD_PrepareCtrlIn((uint8_t *)gpConfigDescriptor, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
}
// Get HID Descriptor
case DESC_HID:
/* CV3.0 HID Class Descriptor Test,
Need to indicate index of the HID Descriptor within gConfigDescriptor, specifically
HID Composite device. */
uint32_t u32ConfigDescOffset = 0; // u32ConfigDescOffset is configuration descriptor
// offset (HID descriptor start index)
u16Len = Minimum(u16Len, LEN_HID);
if (g_usbd_SetupPacket.hidGetDescriptor.wInterfaceNum == USBD_ITF_HID_IO4)
u32ConfigDescOffset = gu32HidDescIO4Offset;
else if (g_usbd_SetupPacket.hidGetDescriptor.wInterfaceNum == USBD_ITF_HID_MISC)
u32ConfigDescOffset = gu32HidDescMiscOffset;
Tas_USBD_PrepareCtrlIn(((uint8_t *)gpConfigDescriptor) + u32ConfigDescOffset, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
// Get Report Descriptor
case DESC_HID_RPT:
if (g_usbd_SetupPacket.hidGetDescriptor.wInterfaceNum == USBD_ITF_HID_IO4) {
if (u16Len > gu32UsbHidIO4ReportLen) {
u16Len = gu32UsbHidIO4ReportLen;
if ((u16Len % g_usbd_CtrlMaxPktSize) == 0) g_usbd_CtrlInZeroFlag = 1;
}
Tas_USBD_PrepareCtrlIn((uint8_t *)gpu8UsbHidIO4Report, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
} else if (g_usbd_SetupPacket.hidGetDescriptor.wInterfaceNum == USBD_ITF_HID_MISC) {
if (u16Len > gu32UsbHidMiscReportLen) {
u16Len = gu32UsbHidMiscReportLen;
if ((u16Len % g_usbd_CtrlMaxPktSize) == 0) g_usbd_CtrlInZeroFlag = 1;
}
Tas_USBD_PrepareCtrlIn((uint8_t *)gpu8UsbHidMiscReport, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
} else {
Tas_USBD_PrepareCtrlIn(NULL, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
}
break;
// Get String Descriptor
case DESC_STRING: {
uint8_t iString = g_usbd_SetupPacket.getDescriptor.bIndex;
static uint8_t u8Str[256]; // IO4 needs at least 2+(2*96)=194
memset(u8Str, 0, sizeof u8Str);
u8Str[1] = DESC_STRING;
switch (iString) {
case USB_STRING_LANG:
u8Str[0] = 2 + (2 * 2);
u8Str[2] = 0x09;
u8Str[3] = 0x04;
break;
case USB_STRING_VENDOR: {
const char *szVendor;
if (su8VendorCount < 2) {
szVendor = gszVendorInitial;
su8VendorCount++;
} else {
szVendor = gszVendor;
}
uint8_t u8Len = strlen(szVendor);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
u8Str[2 + i * 2] = szVendor[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
}
case USB_STRING_PRODUCT: {
uint8_t u8Len = strlen(gszProduct);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
u8Str[2 + i * 2] = gszProduct[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
}
case USB_STRING_SERIAL: {
// TODO: I think it might be a u16 then two u8s?
// Need to check the TRM
uint32_t u32serial;
FMC_Open();
u8Str[0] = 2 + (2 * 24);
u32serial = FMC_ReadUID(0);
for (int i = 0; i < 8; i++)
u8Str[2 + i * 2] = HEX_NIBBLE((u32serial >> (i * 4)));
u32serial = FMC_ReadUID(1);
for (int i = 0; i < 8; i++)
u8Str[2 + (8 * 2) + i * 2] = HEX_NIBBLE((u32serial >> (i * 4)));
u32serial = FMC_ReadUID(2);
for (int i = 0; i < 8; i++)
u8Str[2 + (16 * 2) + i * 2] = HEX_NIBBLE((u32serial >> (i * 4)));
FMC_Close();
break;
}
case USB_STRING_CDC: {
const char *szCdc = "TASOLLER Slider Serial (COM1)";
uint8_t u8Len = strlen(szCdc);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
u8Str[2 + i * 2] = szCdc[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
}
case USB_STRING_HID_IO4: {
const char *szCdc = IO4_PRODUCT;
uint8_t u8Len = strlen(szCdc);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
u8Str[2 + i * 2] = szCdc[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
}
case USB_STRING_HID_MISC: {
const char *szCdc = "TASOLLER HID";
uint8_t u8Len = strlen(szCdc);
u8Str[0] = 2 + u8Len * 2;
for (uint8_t i = 0; i < u8Len; i++) {
u8Str[2 + i * 2] = szCdc[i];
u8Str[2 + i * 2 + 1] = 0;
}
break;
}
default:
// Not support. Reply STALL.
USBD_SET_EP_STALL(EP_CTRL_IN);
USBD_SET_EP_STALL(EP_CTRL_OUT);
break;
}
if (u8Str[0] != 0) {
if (u16Len > u8Str[0]) u16Len = u8Str[0];
if ((u16Len % g_usbd_CtrlMaxPktSize) == 0) g_usbd_CtrlInZeroFlag = 1;
Tas_USBD_PrepareCtrlIn(u8Str, u16Len);
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
}
break;
}
default:
// Not support. Reply STALL.
USBD_SET_EP_STALL(EP_CTRL_IN);
USBD_SET_EP_STALL(EP_CTRL_OUT);
break;
}
}
static inline void Tas_USBD_StandardRequest(void) {
// Clear global variables for new request
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
// Switch on request data transfer direction
if (g_usbd_SetupPacket.bmRequestType & 0x80) {
// Device to host
switch (g_usbd_SetupPacket.bRequest) {
case GET_CONFIGURATION:
// Return current configuration setting
/* Data stage */
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)) = g_usbd_UsbConfig;
USBD_SET_DATA1(EP_CTRL_OUT);
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, 0);
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 1);
/* Status stage */
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
case GET_DESCRIPTOR:
Tas_USBD_GetDescriptor();
/* Status stage */
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
case GET_INTERFACE:
// Return current interface setting
// Data stage
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)) = g_usbd_UsbAltInterface;
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 1);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
case GET_STATUS:
// Device
if (g_usbd_SetupPacket.bmRequestType == 0x80) {
uint8_t u8Tmp;
u8Tmp = 0;
if (gpConfigDescriptor->bmAttributes & 0x40)
u8Tmp |= 1; // Self-Powered/Bus-Powered.
if (gpConfigDescriptor->bmAttributes & 0x20)
u8Tmp |= (g_usbd_RemoteWakeupEn << 1); // Remote wake up
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)) = u8Tmp;
}
// Interface
else if (g_usbd_SetupPacket.bmRequestType == 0x81)
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)) = 0;
// Endpoint
else if (g_usbd_SetupPacket.bmRequestType == 0x82) {
uint8_t ep = g_usbd_SetupPacket.getStatus.wInterface & 0xF;
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)) =
USBD_GetStall(ep) ? 1 : 0;
}
M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN) + 1) = 0;
// Data stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 2);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
default:
// Setup error, stall the device
USBD_SET_EP_STALL(EP_CTRL_IN);
USBD_SET_EP_STALL(EP_CTRL_OUT);
break;
}
} else {
// Host to device
switch (g_usbd_SetupPacket.bRequest) {
case CLEAR_FEATURE:
if (g_usbd_SetupPacket.clearFeature.wFeature == FEATURE_ENDPOINT_HALT) {
int32_t epNum, i;
/* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
a flag: g_u32EpStallLock is added to support it */
epNum = g_usbd_SetupPacket.clearFeature.wEp & 0xF;
for (i = 0; i < USBD_MAX_EP; i++) {
if (((USBD->EP[i].CFG & 0xF) == epNum) &&
((g_u32EpStallLock & (1 << i)) == 0)) {
USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
USBD->EP[i].CFG &= ~USBD_CFG_DSQ_SYNC_Msk;
}
}
} else if (g_usbd_SetupPacket.clearFeature.wFeature == FEATURE_DEVICE_REMOTE_WAKEUP)
g_usbd_RemoteWakeupEn = 0;
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_ADDRESS:
g_usbd_UsbAddr = g_usbd_SetupPacket.setAddress.wAddress;
// DATA IN for end of setup
// Status Stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_CONFIGURATION:
g_usbd_UsbConfig = g_usbd_SetupPacket.setConfiguration.wConfiguration;
// Callback would be here if we wanted to have one :)
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_FEATURE:
if (g_usbd_SetupPacket.setFeature.wFeature == FEATURE_ENDPOINT_HALT) {
USBD_SetStall(g_usbd_SetupPacket.setFeature.wEp & 0xF);
} else if (g_usbd_SetupPacket.setFeature.wFeature == FEATURE_DEVICE_REMOTE_WAKEUP) {
g_usbd_RemoteWakeupEn = 1;
}
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_INTERFACE:
g_usbd_UsbAltInterface = g_usbd_SetupPacket.setInterface.wAlternate;
// Callback would be here if wanted to have one :)
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
default:
// Setup error, stall the device
USBD_SET_EP_STALL(EP_CTRL_IN);
USBD_SET_EP_STALL(EP_CTRL_OUT);
break;
}
}
}
void Tas_USBD_PrepareCtrlIn(void *pu8Buf, uint32_t u32Size) {
if (u32Size > g_usbd_CtrlMaxPktSize) {
// Data size > MXPLD
g_usbd_CtrlInPointer = (uint8_t *)pu8Buf + g_usbd_CtrlMaxPktSize;
g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
USBD_SET_DATA1(EP_CTRL_IN);
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN), (uint8_t *)pu8Buf,
g_usbd_CtrlMaxPktSize);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, g_usbd_CtrlMaxPktSize);
} else {
// Data size <= MXPLD
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
USBD_SET_DATA1(EP_CTRL_IN);
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN), (uint8_t *)pu8Buf,
u32Size);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, u32Size);
}
}
/**
* @brief Repeat Control IN pipe
* @details This function processes the remained data of Control IN transfer.
*/
void Tas_USBD_CtrlIn(void) {
if (g_usbd_CtrlInSize) {
// Process remained data
if (g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize) {
// Data size > MXPLD
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN),
(uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, g_usbd_CtrlMaxPktSize);
g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
} else {
// Data size <= MXPLD
USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN),
(uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, g_usbd_CtrlInSize);
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
}
} else { // No more data for IN token
// In ACK for Set address
if ((g_usbd_SetupPacket.bmRequestType == REQ_STANDARD) &&
(g_usbd_SetupPacket.bRequest == SET_ADDRESS)) {
if ((USBD_GET_ADDR() != g_usbd_UsbAddr) && (USBD_GET_ADDR() == 0)) {
USBD_SET_ADDR(g_usbd_UsbAddr);
}
}
/* For the case of data size is integral times maximum packet size */
if (g_usbd_CtrlInZeroFlag) {
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
g_usbd_CtrlInZeroFlag = 0;
}
}
}
void Tas_USBD_PrepareCtrlOut(void *pu8Buf, uint32_t u32Size,
void (*pCallback)(volatile uint8_t *, uint32_t)) {
g_usbd_CtrlOutPointer = pu8Buf;
g_usbd_CtrlOutSize = 0;
g_usbd_CtrlOutSizeLimit = u32Size;
g_usbd_CtrlOutCallback = pCallback;
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, g_usbd_CtrlMaxPktSize);
}
/**
* @brief Repeat Control OUT pipe
* @details This function processes the successive Control OUT transfer.
*/
void Tas_USBD_CtrlOut(void) {
uint32_t u32Size;
if (g_usbd_CtrlOutToggle != (USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk)) {
g_usbd_CtrlOutToggle = USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk;
if (g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit) {
u32Size = USBD_GET_PAYLOAD_LEN(EP_CTRL_OUT);
USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer,
(uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_OUT), u32Size);
g_usbd_CtrlOutPointer += u32Size;
g_usbd_CtrlOutSize += u32Size;
if (g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, g_usbd_CtrlMaxPktSize);
}
if (g_usbd_CtrlOutSize >= g_usbd_CtrlOutSizeLimit && g_usbd_CtrlOutCallback) {
g_usbd_CtrlOutCallback(g_usbd_CtrlOutPointer - g_usbd_CtrlOutSize, g_usbd_CtrlOutSize);
}
} else {
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, g_usbd_CtrlMaxPktSize);
}
}
void Tas_USBD_SwReset(void) {
// Reset all variables for protocol
g_usbd_CtrlInPointer = 0;
g_usbd_CtrlInSize = 0;
g_usbd_CtrlOutPointer = 0;
g_usbd_CtrlOutSize = 0;
g_usbd_CtrlOutSizeLimit = 0;
g_u32EpStallLock = 0;
memset(&g_usbd_SetupPacket, 0, 8);
// Reset PID DATA0
for (int i = 0; i < USBD_MAX_EP; i++) USBD->EP[i].CFG &= ~USBD_CFG_DSQ_SYNC_Msk;
// Reset USB device address
USBD_SET_ADDR(0);
}

245
src/usbd_user.c Normal file
View File

@ -0,0 +1,245 @@
#include "tasoller.h"
uint8_t volatile g_u8Suspend = 0;
uint8_t g_u8Idle = 0;
uint8_t g_u8Protocol = 0;
uint8_t gHidSetReport[64];
STR_VCOM_LINE_CODING gLineCoding = { 0, 0, 0, 0 };
uint16_t gCtrlSignal;
uint32_t volatile g_u32OutToggle = 0;
void USBD_IRQHandler(void) {
uint32_t u32IntSts = USBD_GET_INT_FLAG();
uint32_t u32State = USBD_GET_BUS_STATE();
if (u32IntSts & USBD_INTSTS_FLDET) {
// Floating detect
USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);
if (USBD_IS_ATTACHED()) {
USBD_ENABLE_USB();
} else {
USBD_DISABLE_USB();
}
}
if (u32IntSts & USBD_INTSTS_WAKEUP) {
USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
}
if (u32IntSts & USBD_INTSTS_BUS) {
USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);
if (u32State & USBD_STATE_USBRST) {
// Bus reset
USBD_ENABLE_USB();
Tas_USBD_SwReset();
g_u32OutToggle = 0;
g_u8Suspend = 0;
}
if (u32State & USBD_STATE_SUSPEND) {
// Enter power down to wait USB attached; enable USB but disable PHY
g_u8Suspend = 1;
USBD_DISABLE_PHY();
}
if (u32State & USBD_STATE_RESUME) {
// Enable USB and enable PHY
USBD_ENABLE_USB();
g_u8Suspend = 0;
}
}
if (u32IntSts & USBD_INTSTS_USB) {
// USB event
if (u32IntSts & USBD_INTSTS_SETUP) { // Setup packet
USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);
// Clear the data IN/OUT ready flag of control end-points
USBD_STOP_TRANSACTION(EP_CTRL_IN);
USBD_STOP_TRANSACTION(EP_CTRL_OUT);
Tas_USBD_ProcessSetupPacket();
}
// Control endpoints
if (u32IntSts & USBD_INTSTS_CTRL_IN) {
USBD_CLR_INT_FLAG(USBD_INTSTS_CTRL_IN);
Tas_USBD_CtrlIn();
}
if (u32IntSts & USBD_INTSTS_CTRL_OUT) {
USBD_CLR_INT_FLAG(USBD_INTSTS_CTRL_OUT);
Tas_USBD_CtrlOut();
}
// CDC endpoints
if (u32IntSts & USBD_INTSTS_CDC_IN) {
USBD_CLR_INT_FLAG(USBD_INTSTS_CDC_IN);
EP_CDC_IN_Handler();
}
if (u32IntSts & USBD_INTSTS_CDC_OUT) {
USBD_CLR_INT_FLAG(USBD_INTSTS_CDC_OUT);
EP_CDC_OUT_Handler();
}
if (u32IntSts & USBD_INTSTS_CDC_CMD) {
USBD_CLR_INT_FLAG(USBD_INTSTS_CDC_CMD);
// TODO: ACM packets have connect/disconnect?
}
// IO4 HID endpoints
if (u32IntSts & USBD_INTSTS_HID_IO4_IN) {
USBD_CLR_INT_FLAG(USBD_INTSTS_HID_IO4_IN);
EP_HID_IO4_IN_Handler();
}
// IO4 Misc endpoints
if (u32IntSts & USBD_INTSTS_HID_MISC_IN) {
USBD_CLR_INT_FLAG(USBD_INTSTS_HID_MISC_IN);
EP_HID_MISC_IN_Handler();
}
if (u32IntSts & USBD_INTSTS_HID_MISC_OUT) {
USBD_CLR_INT_FLAG(USBD_INTSTS_HID_MISC_OUT);
EP_HID_MISC_OUT_Handler();
}
}
}
void EP_HID_IO4_IN_Handler(void) { gu8HIDIO4Ready = 1; }
void EP_HID_MISC_IN_Handler(void) { gu8HIDMiscReady = 1; }
void EP_HID_MISC_OUT_Handler(void) {
// TODO: Handle anything we need to here
}
void EP_CDC_OUT_Handler(void) {
// Bulk OUT
if (g_u32OutToggle == (USBD->EPSTS & USBD_EPSTS_EPSTS3_Msk)) {
USBD_SET_PAYLOAD_LEN(EP_CDC_OUT, USBD_CDC_OUT_MAX_SIZE);
} else {
gu32RxSize = USBD_GET_PAYLOAD_LEN(EP_CDC_OUT);
gpu8RxBuf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CDC_OUT));
g_u32OutToggle = USBD->EPSTS & USBD_EPSTS_EPSTS3_Msk;
// Set a flag to indicate bulk out ready
gi8BulkOutReady = 1;
}
}
void EP_CDC_IN_Handler(void) { gu32TxSize = 0; }
void Tas_USBD_ClassRequest(void) {
usb_setup_t setup;
Tas_USBD_GetSetupPacket(&setup);
if (setup.bmRequestType & 0x80) {
// Device to host
switch (setup.bRequest) {
case GET_LINE_CODING:
if (setup.getLineCoding.wInterface == USBD_ITF_CDC_CMD)
USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_IN)),
(uint8_t *)&gLineCoding, setup.getLineCoding.wLength);
// Data stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, setup.getLineCoding.wLength);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
case GET_REPORT: {
uint32_t u32Size = 0;
uint8_t *pu8Data = NULL;
pu8Data = USBD_HID_GetReport(setup.hidGetReport.bReportId, &u32Size);
Tas_USBD_PrepareCtrlIn(pu8Data, u32Size);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
}
case GET_IDLE:
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, setup.hidGetIdle.wLength);
// Data stage
Tas_USBD_PrepareCtrlIn(&g_u8Idle, setup.hidGetIdle.wLength);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
case GET_PROTOCOL:
USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, setup.hidGetProtocol.wLength);
// Data stage
Tas_USBD_PrepareCtrlIn(&g_u8Protocol, setup.hidGetProtocol.wLength);
// Status stage
Tas_USBD_PrepareCtrlOut(NULL, 0, NULL);
break;
default:
// Setup error, stall the device
USBD_SetStall(EP_CTRL_IN);
USBD_SetStall(EP_CTRL_OUT);
break;
}
} else {
// Host to device
switch (setup.bRequest) {
case SET_CONTROL_LINE_STATE:
// TODO: Use bit[0] (DTR) to identify connection state
// Is RTS worth using?
if (setup.wIndex == USBD_ITF_CDC_CMD) gCtrlSignal = setup.wValue;
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_LINE_CODING:
if (setup.setLineCoding.wInterface == USBD_ITF_CDC_CMD)
Tas_USBD_PrepareCtrlOut(&gLineCoding, sizeof gLineCoding, NULL);
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_REPORT:
// Report Type = Output
if (setup.hidSetReport.bReportType == 2) {
Tas_USBD_PrepareCtrlOut(&gHidSetReport, sizeof gHidSetReport,
USBD_HID_SetReport);
// USBD_SET_DATA1(EP_CTRL_OUT);
// USBD_SET_PAYLOAD_LEN(EP_CTRL_OUT, setup.wLength);
// USBD_HID_RecvData(
// setup.hidSetReport.bReportId,
// (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CTRL_OUT)),
// setup.hidSetReport.wLength);
// // Status stage
// Tas_USBD_PrepareCtrlIn(NULL, 0);
}
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_IDLE:
g_u8Idle = setup.hidSetIdle.bDuration;
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
case SET_PROTOCOL:
g_u8Protocol = setup.hidSetProtocol.wProtocol;
// Status stage
USBD_SET_DATA1(EP_CTRL_IN);
USBD_SET_PAYLOAD_LEN(EP_CTRL_IN, 0);
break;
default:
// Setup error, stall the device
USBD_SetStall(EP_CTRL_IN);
USBD_SetStall(EP_CTRL_OUT);
break;
}
}
}

102
src/vcom.c Normal file
View File

@ -0,0 +1,102 @@
#include "tasoller.h"
#define BUF_SIZE_RX 512
#define BUF_SIZE_TX 512
volatile uint8_t gu8VcomReady = 0;
static volatile uint8_t gau8ComRbuf[BUF_SIZE_RX];
static volatile uint16_t gu16ComRbytes = 0;
static volatile uint16_t gu16ComRhead = 0;
static volatile uint16_t gu16ComRtail = 0;
static volatile uint8_t gau8ComTbuf[BUF_SIZE_TX];
static volatile uint16_t gu16ComTbytes = 0;
static volatile uint16_t gu16ComThead = 0;
static volatile uint16_t gu16ComTtail = 0;
uint8_t gau8RxBuf[64] = { 0 };
volatile uint8_t *gpu8RxBuf = 0;
volatile uint32_t gu32RxSize = 0;
volatile uint32_t gu32TxSize = 0;
volatile int8_t gi8BulkOutReady = 0;
void _USB_VCOM_Tick_Tx(void) {
uint32_t u32Len;
if (gu32TxSize != 0) return;
// Check wether we have new COM Rx data to send to USB or not
if (!gu16ComRbytes) {
// Prepare a zero packet if previous packet size is USBD_CDC_IN_MAX_SIZE and
// no more data to send at this moment to note Host the transfer has been done
u32Len = USBD_GET_PAYLOAD_LEN(EP_CDC_IN);
if (u32Len == USBD_CDC_IN_MAX_SIZE) USBD_SET_PAYLOAD_LEN(EP_CDC_IN, 0);
return;
}
u32Len = gu16ComRbytes;
if (u32Len > USBD_CDC_IN_MAX_SIZE) u32Len = USBD_CDC_IN_MAX_SIZE;
for (uint32_t i = 0; i < u32Len; i++) {
if (gu16ComRhead >= BUF_SIZE_RX) gu16ComRhead = 0;
gau8RxBuf[i] = gau8ComRbuf[gu16ComRhead++];
}
// __set_PRIMASK(1);
gu16ComRbytes -= u32Len;
// __set_PRIMASK(0);
gu32TxSize = u32Len;
USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP_CDC_IN)), (uint8_t *)gau8RxBuf,
u32Len);
USBD_SET_PAYLOAD_LEN(EP_CDC_IN, u32Len);
}
void _USB_VCOM_Tick_Rx(void) {
// Process the Bulk out data when bulk out data is ready.
if (!gi8BulkOutReady) return;
if (gu32RxSize > BUF_SIZE_TX - gu16ComTbytes) return;
for (uint32_t i = 0; i < gu32RxSize; i++) {
gau8ComTbuf[gu16ComTtail++] = gpu8RxBuf[i];
if (gu16ComTtail >= BUF_SIZE_TX) gu16ComTtail = 0;
}
// __set_PRIMASK(1);
gu16ComTbytes += gu32RxSize;
// __set_PRIMASK(0);
gu32RxSize = 0;
gi8BulkOutReady = 0; // Clear bulk out ready flag
// Ready to get next BULK out
USBD_SET_PAYLOAD_LEN(EP_CDC_OUT, USBD_CDC_OUT_MAX_SIZE);
}
void USB_VCOM_Tick(void) {
_USB_VCOM_Tick_Tx();
_USB_VCOM_Tick_Rx();
}
uint8_t USB_VCOM_Read() {
if (!gu16ComTbytes) return 0xff;
gu16ComTbytes--;
if (gu16ComThead >= BUF_SIZE_TX) gu16ComThead = 0;
return gau8ComTbuf[gu16ComThead++];
}
void USB_VCOM_Write(uint8_t u8Data) {
if (gu16ComRbytes < BUF_SIZE_RX) {
// Enqueue the character
gau8ComRbuf[gu16ComRtail++] = u8Data;
if (gu16ComRtail >= BUF_SIZE_RX) gu16ComRtail = 0;
gu16ComRbytes++;
} else {
// FIFO over run
}
}
uint16_t USB_VCOM_Available(void) { return gu16ComTbytes; }
void USB_VCOM_PurgeTx(void) {
gu16ComRbytes = 0;
gu16ComRhead = 0;
gu16ComRtail = 0;
}