Modified after discovering issues with ch32fun being a seperate lib.
This commit is contained in:
parent
a80c0f1360
commit
6771cbadf6
38 changed files with 74191 additions and 20976 deletions
4700
inc/ch32v003hw.h
4700
inc/ch32v003hw.h
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef _FUNCONFIG_H
|
||||
#define _FUNCONFIG_H
|
||||
|
||||
#define CH32V003 1
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,28 +1,19 @@
|
|||
|
||||
add_executable(${PROJECT_NAME}
|
||||
main.c
|
||||
main.c
|
||||
ch32fun.c
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/extralibs
|
||||
${CMAKE_SOURCE_DIR}/ch32fun
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
ch32fun
|
||||
#libgcc
|
||||
#${CMAKE_SOURCE_DIR}/libgcc.a
|
||||
#ch32fun
|
||||
)
|
||||
|
||||
target_link_options(${PROJECT_NAME} PRIVATE
|
||||
-Wl,--print-memory-usage
|
||||
-Wl,-Map=${PROJECT_NAME}.map
|
||||
-lgcc
|
||||
-Wl,--gc-sections
|
||||
-T ${CMAKE_SOURCE_DIR}/src/linker_script.ld
|
||||
)
|
||||
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC
|
||||
-g
|
||||
-Os
|
||||
-flto
|
||||
|
|
@ -35,7 +26,31 @@ target_compile_options(${PROJECT_NAME} PRIVATE
|
|||
-DCH32V003=1
|
||||
-static-libgcc
|
||||
-nostdlib
|
||||
-Wall
|
||||
-Wl,--print-memory-usage
|
||||
-Wl,-Map=${PROJECT_NAME}.map
|
||||
-lgcc
|
||||
-Wl,--gc-sections
|
||||
-T${CMAKE_SOURCE_DIR}/src/linker_script.ld
|
||||
)
|
||||
|
||||
target_link_options(${PROJECT_NAME} PUBLIC
|
||||
-g
|
||||
-Os
|
||||
-flto
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-fmessage-length=0
|
||||
-msmall-data-limit=8
|
||||
-march=rv32ec
|
||||
-mabi=ilp32e
|
||||
-DCH32V003=1
|
||||
-static-libgcc
|
||||
-nostdlib
|
||||
-Wl,--print-memory-usage
|
||||
-Wl,-Map=${PROJECT_NAME}.map
|
||||
-lgcc
|
||||
-Wl,--gc-sections
|
||||
-T${CMAKE_SOURCE_DIR}/src/linker_script.ld
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -57,11 +72,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".elf")
|
|||
|
||||
|
||||
|
||||
#add_library(libgcc STATIC IMPORTED)
|
||||
#set_target_properties(libgcc PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libgcc.a)
|
||||
|
||||
|
||||
|
||||
add_subdirectory(ch32fun)
|
||||
#add_subdirectory(extralibs)
|
||||
add_subdirectory(attic)
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
|
||||
add_library(ch32fun OBJECT
|
||||
ch32fun.c
|
||||
)
|
||||
|
||||
target_include_directories(ch32fun PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_SOURCE_DIR}/inc
|
||||
${CMAKE_SOURCE_DIR}/src/extralibs
|
||||
${CMAKE_SOURCE_DIR}/src/ch32fun
|
||||
)
|
||||
|
||||
target_compile_options(ch32fun PRIVATE
|
||||
-g
|
||||
-Os
|
||||
-flto
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-fmessage-length=0
|
||||
-msmall-data-limit=8
|
||||
-march=rv32ec
|
||||
-mabi=ilp32e
|
||||
-DCH32V003=1
|
||||
-static-libgcc
|
||||
-nostdlib
|
||||
-Wall
|
||||
)
|
||||
|
||||
#target_link_libraries(ch32fun PRIVATE
|
||||
# ${CMAKE_SOURCE_DIR}/libgcc.a
|
||||
#)
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
## Update Status Overview
|
||||
|PERIPHERAL |V003|V00x|V10x|V20x|V30x|X035|L103|M030|
|
||||
|:-------------|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|
||||
|DPAL Header\* |2.0 | x |2.7 | x | x | √ | × | × |
|
||||
|ADC |1.9 | x |2.1 | x | x |1.3 | × | × |
|
||||
|AWU |N/A |N/A |N/A |N/A |N/A | √ |N/A |N/A |
|
||||
|BKP |N/A |N/A |2.1 | x | x |N/A | × |N/A |
|
||||
|CAN |N/A |N/A |N/A | x | x |N/A | × |N/A |
|
||||
|CRC |N/A |N/A |2.1 | x | x |N/A | × |N/A |
|
||||
|DAC |N/A |N/A |N/A |N/A | x |N/A |N/A |N/A |
|
||||
|DBGMCU |1.5 | x |2.1 | x | x | √ | × | × |
|
||||
|DMA | √ | x | √ | x | x | √ | × | × |
|
||||
|DVP |N/A |N/A |N/A |N/A | x |N/A |N/A |N/A |
|
||||
|ETH |N/A |N/A |N/A |N/A | x |N/A |N/A |N/A |
|
||||
|EXIT | √ | x |2.4 | x | x | √ | × | × |
|
||||
|FLASH | √ | x |2.7 | x | x |1.4 | × | × |
|
||||
|FSMC |N/A |N/A |N/A |N/A | x |N/A |N/A |N/A |
|
||||
|GPIO |2.0 | x |2.7 | x | x |1.6 | × | × |
|
||||
|I2C | √ | x | √ | x | x |1.7 | × | × |
|
||||
|IWDG | √ | x | √ | x | x | √ | × |N/A |
|
||||
|LPTIM |N/A |N/A |N/A |N/A |N/A |N/A | × |N/A |
|
||||
|MISC | √ | x |2.4 | x | x |1.6 | × |N/A |
|
||||
|OPA | √ | x |N/A | x | x |1.3 | × | × |
|
||||
|PWR |1.9 | x |2.6 | x | x |1.7 | × | × |
|
||||
|RCC |1.8 | x |2.7 | x | x | √ | × | × |
|
||||
|RNG |N/A |N/A |N/A |N/A | x |N/A |N/A |N/A |
|
||||
|RTC |N/A |N/A | √ | x | x |N/A | × |N/A |
|
||||
|SPI |1.9 | x |2.7 | x | x |1.7 | × | × |
|
||||
|TIM |1.6 | x | √ | x | x | √ | × | × |
|
||||
|USART | √ | x |2.4 | x | x | √ | × | × |
|
||||
|USB |N/A |N/A | √ | x | x |1.8 | × | × |
|
||||
|USB_HOST |N/A |N/A | √ |N/A |N/A |N/A |N/A |N/A |
|
||||
|USBPD |N/A |N/A |N/A |N/A |N/A | x | × | × |
|
||||
|WWWDG | √ | x | √ | x | x | √ | × | × |
|
||||
|**chxxxhw.h** | √ | x | √ | √ | √ | √ | x | x |
|
||||
|**minichlink**| √ | x | √ | √ | √ | √ | x | x |
|
||||
|
||||
* n.m: Last commit message of the header file in ch32xxx/EVT/EXAM/SRC/Peripheral/inc
|
||||
* √: Merged in , version unspecified
|
||||
* ×: Not merged / Unchecked
|
||||
* +: Work in progress
|
||||
* N/A: No header file with this suffix in EVT, does not mean that the feature is not supported
|
||||
|
||||
\* DPAL Header: Device Peripheral Access Layer Header File, normally named as ch32xxx.h
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,222 +0,0 @@
|
|||
ENTRY( InterruptVector )
|
||||
|
||||
MEMORY
|
||||
{
|
||||
#if TARGET_MCU_LD == 0
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
|
||||
#elif TARGET_MCU_LD == 1
|
||||
#if MCU_PACKAGE == 1
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
#elif MCU_PACKAGE == 2
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 10K
|
||||
#else
|
||||
#error "Unknown MCU package"
|
||||
#endif
|
||||
#elif TARGET_MCU_LD == 2
|
||||
#if MCU_PACKAGE == 1
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
#elif MCU_PACKAGE == 2
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 10K
|
||||
#elif MCU_PACKAGE == 3
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
#else
|
||||
#error "Unknown MCU package"
|
||||
#endif
|
||||
#elif TARGET_MCU_LD == 3
|
||||
#if MCU_PACKAGE == 1
|
||||
#if TARGET_MCU_MEMORY_SPLIT == 1
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 224K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
|
||||
#elif TARGET_MCU_MEMORY_SPLIT == 2
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
#elif TARGET_MCU_MEMORY_SPLIT == 3
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 288K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||
#else
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
#endif
|
||||
#elif MCU_PACKAGE == 2
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||
#else
|
||||
#error "Unknown MCU package"
|
||||
#endif
|
||||
#elif TARGET_MCU_LD == 4
|
||||
#if MCU_PACKAGE == 1
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
#else
|
||||
#error "Unknown MCU package"
|
||||
#endif
|
||||
#elif TARGET_MCU_LD == 5
|
||||
/* CH32V002 */
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
|
||||
#elif TARGET_MCU_LD == 6
|
||||
/* CH32V004 */
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
|
||||
#elif TARGET_MCU_LD == 7
|
||||
/* CH32V005, CH32V006, CH32V007 */
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
|
||||
#else
|
||||
#error "Unknown MCU target"
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
_sinit = .;
|
||||
. = ALIGN(4);
|
||||
KEEP(*(SORT_NONE(.init)))
|
||||
. = ALIGN(4);
|
||||
_einit = .;
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP(*(SORT_NONE(.fini)))
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
PROVIDE( _etext = . );
|
||||
PROVIDE( _eitcm = . );
|
||||
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dalign :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_vma = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.dlalign :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_lma = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__global_pointer$ = . + 0x3fc; /* This gets set in the startup code. This allows -mrelax'd code to be smaller by acting as a sort of quick reference in the gp register. */
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.data .data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
. = ALIGN(8);
|
||||
*(.sdata .sdata.*)
|
||||
*(.sdata2*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
. = ALIGN(8);
|
||||
*(.srodata.cst16)
|
||||
*(.srodata.cst8)
|
||||
*(.srodata.cst4)
|
||||
*(.srodata.cst2)
|
||||
*(.srodata .srodata.*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _edata = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _sbss = .);
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _ebss = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
PROVIDE( _end = _ebss);
|
||||
PROVIDE( end = . );
|
||||
|
||||
PROVIDE( _eusrstack = ORIGIN(RAM) + LENGTH(RAM));
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.note .note.*)
|
||||
*(.eh_frame .eh_frame.*)
|
||||
*(.comment .comment.*)
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
*(.ARM.exidx*)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
# Default prefix for Windows
|
||||
ifeq ($(OS),Windows_NT)
|
||||
PREFIX?=riscv64-unknown-elf
|
||||
# Check if riscv64-unknown-elf-gcc exists
|
||||
else ifneq ($(shell which riscv64-unknown-elf-gcc),)
|
||||
PREFIX?=riscv64-unknown-elf
|
||||
# We used to check if riscv64-linux-gnu-gcc exists, because it would still produce valid output with -ffreestanding.
|
||||
# It was different enough that we decided not to automatically fallback to it.
|
||||
# Default prefix
|
||||
else
|
||||
PREFIX?=riscv64-elf
|
||||
endif
|
||||
|
||||
# Fedora places newlib in a different location
|
||||
ifneq ($(wildcard /etc/fedora-release),)
|
||||
NEWLIB?=/usr/arm-none-eabi/include
|
||||
else
|
||||
NEWLIB?=/usr/include/newlib
|
||||
endif
|
||||
|
||||
CH32FUN?=$(shell dirname $(lastword $(MAKEFILE_LIST)))
|
||||
#TARGET_MCU?=CH32V003 # Because we are now opening up to more processors, don't assume this.
|
||||
|
||||
TARGET_EXT?=c
|
||||
|
||||
CH32FUN?=$(dir $(lastword $(MAKEFILE_LIST)))
|
||||
MINICHLINK?=$(CH32FUN)/../minichlink
|
||||
|
||||
WRITE_SECTION?=flash
|
||||
SYSTEM_C?=$(CH32FUN)/ch32fun.c
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
EXTRA_CFLAGS+=-DFUNCONF_DEBUG=1
|
||||
endif
|
||||
|
||||
CFLAGS?=-g -Os -flto -ffunction-sections -fdata-sections -fmessage-length=0 -msmall-data-limit=8
|
||||
LDFLAGS+=-Wl,--print-memory-usage -Wl,-Map=$(TARGET).map
|
||||
|
||||
ifeq ($(TARGET_MCU),CH32V003)
|
||||
CFLAGS_ARCH+=-march=rv32ec -mabi=ilp32e -DCH32V003=1
|
||||
GENERATED_LD_FILE?=$(CH32FUN)/generated_ch32v003.ld
|
||||
TARGET_MCU_LD:=0
|
||||
LINKER_SCRIPT?=$(GENERATED_LD_FILE)
|
||||
LDFLAGS+=-L$(CH32FUN)/../misc -lgcc
|
||||
else
|
||||
MCU_PACKAGE?=1
|
||||
ifeq ($(findstring CH32V00,$(TARGET_MCU)),CH32V00) # CH32V002, 4, 5, 6, 7
|
||||
# Note: The CH32V003 is not a CH32V00x.
|
||||
CFLAGS_ARCH+=-march=rv32eczmmul -mabi=ilp32e -DCH32V00x=1
|
||||
ifeq ($(findstring CH32V002, $(TARGET_MCU)), CH32V002)
|
||||
TARGET_MCU_LD:=5
|
||||
else ifeq ($(findstring CH32V004, $(TARGET_MCU)), CH32V004)
|
||||
TARGET_MCU_LD:=6
|
||||
else ifeq ($(findstring CH32V005, $(TARGET_MCU)), CH32V005)
|
||||
TARGET_MCU_LD:=7
|
||||
else ifeq ($(findstring CH32V006, $(TARGET_MCU)), CH32V006)
|
||||
TARGET_MCU_LD:=7
|
||||
else ifeq ($(findstring CH32V007, $(TARGET_MCU)), CH32V007)
|
||||
TARGET_MCU_LD:=7
|
||||
else
|
||||
ERROR:=$(error Unknown MCU $(TARGET_MCU))
|
||||
endif
|
||||
else ifeq ($(findstring CH32V10,$(TARGET_MCU)),CH32V10) # CH32V103
|
||||
TARGET_MCU_PACKAGE?=CH32V103R8T6
|
||||
CFLAGS_ARCH+= -march=rv32imac \
|
||||
-mabi=ilp32 \
|
||||
-DCH32V10x=1
|
||||
|
||||
# MCU Flash/RAM split
|
||||
ifeq ($(findstring R8, $(TARGET_MCU_PACKAGE)), R8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring C8, $(TARGET_MCU_PACKAGE)), C8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring C6, $(TARGET_MCU_PACKAGE)), C6)
|
||||
MCU_PACKAGE:=2
|
||||
endif
|
||||
|
||||
TARGET_MCU_LD:=1
|
||||
else ifeq ($(findstring CH32X03,$(TARGET_MCU)),CH32X03) # CH32X033, X035
|
||||
TARGET_MCU_PACKAGE?=CH32X035F8U6
|
||||
CFLAGS_ARCH+=-march=rv32imac \
|
||||
-mabi=ilp32 \
|
||||
-DCH32X03x=1
|
||||
|
||||
# MCU Flash/RAM split
|
||||
ifeq ($(findstring F8, $(TARGET_MCU_PACKAGE)), F8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring R8, $(TARGET_MCU_PACKAGE)), R8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring K8, $(TARGET_MCU_PACKAGE)), K8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring C8, $(TARGET_MCU_PACKAGE)), C8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring G8, $(TARGET_MCU_PACKAGE)), G8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring G6, $(TARGET_MCU_PACKAGE)), G6)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring F7, $(TARGET_MCU_PACKAGE)), F7)
|
||||
MCU_PACKAGE:=1
|
||||
endif
|
||||
|
||||
TARGET_MCU_LD:=4
|
||||
else ifeq ($(findstring CH32V20,$(TARGET_MCU)),CH32V20) # CH32V203
|
||||
TARGET_MCU_PACKAGE?=CH32V203F6P6
|
||||
CFLAGS_ARCH+= -march=rv32imac \
|
||||
-mabi=ilp32 \
|
||||
-DCH32V20x=1
|
||||
|
||||
# MCU Flash/RAM split
|
||||
|
||||
|
||||
# Package
|
||||
ifeq ($(findstring 203RB, $(TARGET_MCU_PACKAGE)), 203RB)
|
||||
CFLAGS+=-DCH32V20x_D8
|
||||
else ifeq ($(findstring 208, $(TARGET_MCU_PACKAGE)), 208)
|
||||
CFLAGS+=-DCH32V20x_D8W
|
||||
MCU_PACKAGE:=3
|
||||
else ifeq ($(findstring F8, $(TARGET_MCU_PACKAGE)), F8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring G8, $(TARGET_MCU_PACKAGE)), G8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring K8, $(TARGET_MCU_PACKAGE)), K8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring C8, $(TARGET_MCU_PACKAGE)), C8)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring F6, $(TARGET_MCU_PACKAGE)), F6)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring G6, $(TARGET_MCU_PACKAGE)), G6)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring K6, $(TARGET_MCU_PACKAGE)), K6)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring C6, $(TARGET_MCU_PACKAGE)), C6)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring RB, $(TARGET_MCU_PACKAGE)), RB)
|
||||
MCU_PACKAGE:=3
|
||||
else ifeq ($(findstring GB, $(TARGET_MCU_PACKAGE)), GB)
|
||||
MCU_PACKAGE:=3
|
||||
else ifeq ($(findstring CB, $(TARGET_MCU_PACKAGE)), CB)
|
||||
MCU_PACKAGE:=3
|
||||
else ifeq ($(findstring WB, $(TARGET_MCU_PACKAGE)), WB)
|
||||
MCU_PACKAGE:=3
|
||||
else
|
||||
CFLAGS+=-DCH32V20x_D6
|
||||
endif
|
||||
|
||||
TARGET_MCU_LD:=2
|
||||
else ifeq ($(findstring CH32V30,$(TARGET_MCU)),CH32V30) #CH32V307
|
||||
TARGET_MCU_PACKAGE?=CH32V307VCT6
|
||||
MCU_PACKAGE?=1
|
||||
TARGET_MCU_MEMORY_SPLIT?=3
|
||||
ENABLE_FPU?=1
|
||||
|
||||
ifeq ($(ENABLE_FPU), 1)
|
||||
CFLAGS_ARCH+= -march=rv32imafc -mabi=ilp32f
|
||||
else
|
||||
CFLAGS_ARCH+= -march=rv32imac -mabi=ilp32 -DDISABLED_FLOAT
|
||||
endif
|
||||
|
||||
CFLAGS_ARCH+= \
|
||||
-DCH32V30x=1 \
|
||||
-DTARGET_MCU_MEMORY_SPLIT=$(TARGET_MCU_MEMORY_SPLIT)
|
||||
|
||||
# MCU Flash/RAM split
|
||||
ifeq ($(findstring RC, $(TARGET_MCU_PACKAGE)), RC)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring VC, $(TARGET_MCU_PACKAGE)), VC)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring WC, $(TARGET_MCU_PACKAGE)), WC)
|
||||
MCU_PACKAGE:=1
|
||||
else ifeq ($(findstring CB, $(TARGET_MCU_PACKAGE)), CB)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring FB, $(TARGET_MCU_PACKAGE)), FB)
|
||||
MCU_PACKAGE:=2
|
||||
else ifeq ($(findstring RB, $(TARGET_MCU_PACKAGE)), RB)
|
||||
MCU_PACKAGE:=2
|
||||
endif
|
||||
|
||||
# Package
|
||||
ifeq ($(findstring 303, $(TARGET_MCU_PACKAGE)), 303)
|
||||
CFLAGS+=-DCH32V30x_D8
|
||||
else
|
||||
CFLAGS+=-DCH32V30x_D8C
|
||||
endif
|
||||
|
||||
TARGET_MCU_LD:=3
|
||||
else
|
||||
ERROR:=$(error Unknown MCU $(TARGET_MCU))
|
||||
endif
|
||||
|
||||
LDFLAGS+=-lgcc
|
||||
GENERATED_LD_FILE:=$(CH32FUN)/generated_$(TARGET_MCU_PACKAGE)_$(TARGET_MCU_MEMORY_SPLIT).ld
|
||||
LINKER_SCRIPT:=$(GENERATED_LD_FILE)
|
||||
endif
|
||||
|
||||
CFLAGS+= \
|
||||
$(CFLAGS_ARCH) -static-libgcc \
|
||||
-I$(NEWLIB) \
|
||||
-I$(CH32FUN)/../extralibs \
|
||||
-I$(CH32FUN) \
|
||||
-nostdlib \
|
||||
-I. -Wall $(EXTRA_CFLAGS)
|
||||
|
||||
LDFLAGS+=-T $(LINKER_SCRIPT) -Wl,--gc-sections
|
||||
FILES_TO_COMPILE:=$(SYSTEM_C) $(TARGET).$(TARGET_EXT) $(ADDITIONAL_C_FILES)
|
||||
|
||||
$(TARGET).bin : $(TARGET).elf
|
||||
$(PREFIX)-objdump -S $^ > $(TARGET).lst
|
||||
$(PREFIX)-objcopy -O binary $< $(TARGET).bin
|
||||
$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
closechlink :
|
||||
-taskkill /F /IM minichlink.exe /T
|
||||
else
|
||||
closechlink :
|
||||
-killall minichlink
|
||||
endif
|
||||
|
||||
terminal : monitor
|
||||
|
||||
monitor :
|
||||
$(MINICHLINK)/minichlink -T
|
||||
|
||||
unbrick :
|
||||
$(MINICHLINK)/minichlink -u
|
||||
|
||||
gdbserver :
|
||||
-$(MINICHLINK)/minichlink -baG
|
||||
|
||||
gdbclient :
|
||||
gdb-multiarch $(TARGET).elf -ex "target remote :3333"
|
||||
|
||||
clangd :
|
||||
make clean
|
||||
bear -- make build
|
||||
|
||||
clangd_clean :
|
||||
rm -f compile_commands.json
|
||||
rm -rf .cache
|
||||
|
||||
FLASH_COMMAND?=$(MINICHLINK)/minichlink -w $< $(WRITE_SECTION) -b
|
||||
|
||||
.PHONY : $(GENERATED_LD_FILE)
|
||||
$(GENERATED_LD_FILE) :
|
||||
$(PREFIX)-gcc -E -P -x c -DTARGET_MCU=$(TARGET_MCU) -DMCU_PACKAGE=$(MCU_PACKAGE) -DTARGET_MCU_LD=$(TARGET_MCU_LD) -DTARGET_MCU_MEMORY_SPLIT=$(TARGET_MCU_MEMORY_SPLIT) $(CH32FUN)/ch32fun.ld > $(GENERATED_LD_FILE)
|
||||
|
||||
$(TARGET).elf : $(FILES_TO_COMPILE) $(LINKER_SCRIPT) $(EXTRA_ELF_DEPENDENCIES)
|
||||
$(PREFIX)-gcc -o $@ $(FILES_TO_COMPILE) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
# Rule for independently building ch32fun.o indirectly, instead of recompiling it from source every time.
|
||||
# Not used in the default 003fun toolchain, but used in more sophisticated toolchains.
|
||||
ch32fun.o : $(SYSTEM_C)
|
||||
$(PREFIX)-gcc -c -o $@ $(SYSTEM_C) $(CFLAGS)
|
||||
|
||||
cv_flash : $(TARGET).bin
|
||||
make -C $(MINICHLINK) all
|
||||
$(FLASH_COMMAND)
|
||||
|
||||
cv_clean :
|
||||
rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex $(GENERATED_LD_FILE) || true
|
||||
|
||||
build : $(TARGET).bin
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
ENTRY( InterruptVector )
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* Actually at 0x1FFFF000 but the system maps it to 0x00000000 */
|
||||
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1920
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.init :
|
||||
{
|
||||
_sinit = .;
|
||||
. = ALIGN(4);
|
||||
KEEP(*(SORT_NONE(.init)))
|
||||
. = ALIGN(4);
|
||||
_einit = .;
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP(*(SORT_NONE(.fini)))
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
PROVIDE( _etext = . );
|
||||
PROVIDE( _eitcm = . );
|
||||
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.dalign :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_vma = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.dlalign :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_data_lma = .);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.data .data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE( __global_pointer$ = . + 0x800 );
|
||||
*(.sdata .sdata.*)
|
||||
*(.sdata2*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
. = ALIGN(8);
|
||||
*(.srodata.cst16)
|
||||
*(.srodata.cst8)
|
||||
*(.srodata.cst4)
|
||||
*(.srodata.cst2)
|
||||
*(.srodata .srodata.*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _edata = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _sbss = .);
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON*)
|
||||
. = ALIGN(4);
|
||||
PROVIDE( _ebss = .);
|
||||
} >RAM AT>FLASH
|
||||
|
||||
PROVIDE( _end = _ebss);
|
||||
PROVIDE( end = . );
|
||||
|
||||
PROVIDE( _eusrstack = ORIGIN(RAM) + LENGTH(RAM));
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,22 +1,26 @@
|
|||
// 2023-06-26 recallmenot
|
||||
|
||||
// ######## necessities
|
||||
//######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_GPIO_BR_H
|
||||
#define CH32V003_GPIO_BR_H
|
||||
|
||||
// includes
|
||||
#include <stdint.h> //uintN_t support
|
||||
#include "../ch32fun/ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
|
||||
|
||||
/*######## library description
|
||||
This is a speedy and light GPIO library due to
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
||||
first, enable the desired port.
|
||||
|
|
@ -94,81 +98,78 @@ Writing `TIMx->SWEVGR |= TIM_UG` will immediately update the shadow register and
|
|||
|
||||
*/
|
||||
|
||||
// ######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin)
|
||||
|
||||
enum GPIO_port_n
|
||||
{
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
//######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||
|
||||
enum GPIO_port_n {
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
};
|
||||
|
||||
enum GPIO_pinModes
|
||||
{
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
enum GPIO_pinModes {
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
};
|
||||
|
||||
enum lowhigh
|
||||
{
|
||||
low,
|
||||
high,
|
||||
enum lowhigh {
|
||||
low,
|
||||
high,
|
||||
};
|
||||
|
||||
// analog inputs
|
||||
enum GPIO_analog_inputs
|
||||
{
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
enum GPIO_analog_inputs {
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
};
|
||||
|
||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||
enum GPIO_ADC_sampletimes
|
||||
{
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
enum GPIO_ADC_sampletimes {
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
};
|
||||
|
||||
enum GPIO_tim1_output_sets
|
||||
{
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
enum GPIO_tim1_output_sets {
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
};
|
||||
|
||||
enum GPIO_tim2_output_sets
|
||||
{
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
enum GPIO_tim2_output_sets {
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
};
|
||||
|
||||
// ######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
|
||||
//######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
// setup
|
||||
#define GPIO_port_enable(GPIO_port_n)
|
||||
|
|
@ -201,66 +202,72 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_tim1_analogWrite(channel, value)
|
||||
#define GPIO_tim2_analogWrite(channel, value)
|
||||
|
||||
// ######## internal function declarations
|
||||
|
||||
// ######## internal variables
|
||||
|
||||
// ######## preprocessor macros
|
||||
//######## internal function declarations
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
|
||||
|
||||
//######## internal variables
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
|
||||
#define CONCAT(a, b) a ## b
|
||||
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
||||
|
||||
#undef GPIOv_from_PORT_PIN
|
||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (pin))
|
||||
#define GPIOv_to_PORT(GPIOv) (GPIOv >> 4)
|
||||
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin ) ((GPIO_port_n << 4 ) | (pin))
|
||||
#define GPIOv_to_PORT( GPIOv ) (GPIOv >> 4 )
|
||||
#define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase( GPIOv ) ((GPIO_TypeDef*)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIOv)
|
||||
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n)
|
||||
|
|
@ -280,74 +287,91 @@ static inline void GPIO_tim2_init();
|
|||
#endif
|
||||
|
||||
#if !defined(GPIO_timer_prescaler)
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#endif
|
||||
|
||||
// ######## define requirements / maintenance defines
|
||||
//######## define requirements / maintenance defines
|
||||
|
||||
|
||||
|
||||
//######## small function definitions, static inline
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
|
||||
#undef GPIO_port_enable
|
||||
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
||||
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
})
|
||||
|
||||
#undef GPIO_port_digitalWrite
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
|
||||
#undef GPIO_port_digitalRead
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
|
||||
#undef GPIO_pinMode
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
})
|
||||
|
||||
#undef GPIO_digitalWrite_hi
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#undef GPIO_digitalWrite_lo
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
|
||||
#undef GPIO_digitalWrite
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
|
||||
#undef GPIO_digitalWrite_branching
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
|
||||
#undef GPIO_digitalRead
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
|
||||
#undef GPIO_ADC_set_sampletime
|
||||
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_sampletimes_all
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3); \
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3) \
|
||||
| GPIO_ADC_sampletime << (6 * 3) \
|
||||
| GPIO_ADC_sampletime << (7 * 3) \
|
||||
| GPIO_ADC_sampletime << (8 * 3) \
|
||||
| GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_power
|
||||
|
|
@ -357,137 +381,133 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
||||
|
||||
#undef GPIO_ADC_calibrate
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
||||
; \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while (ADC1->CTLR2 & ADC_CAL) \
|
||||
; \
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while(ADC1->CTLR2 & ADC_CAL); \
|
||||
})
|
||||
|
||||
// large but will likely only ever be called once
|
||||
static inline void GPIO_ADCinit()
|
||||
{
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
static inline void GPIO_ADCinit() {
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
}
|
||||
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
||||
{
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while (!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while(!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef GPIO_tim1_map
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
})
|
||||
|
||||
#undef GPIO_tim2_map
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
})
|
||||
|
||||
static inline void GPIO_tim1_init()
|
||||
{
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim1_init() {
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
static inline void GPIO_tim2_init()
|
||||
{
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim2_init() {
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
|
||||
#undef GPIO_tim1_enableCH
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
})
|
||||
#undef GPIO_tim2_enableCH
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \
|
||||
})
|
||||
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
|
||||
#undef GPIO_tim1_analogWrite
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#undef GPIO_tim2_analogWrite
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
|
||||
#endif // CH32V003_GPIO_BR_H
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// ######## necessities
|
||||
//######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_SPI_H
|
||||
#define CH32V003_SPI_H
|
||||
|
||||
// includes
|
||||
#include<stdint.h> //uintN_t support
|
||||
#include "ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
|
@ -20,7 +20,7 @@ SYSTEM_CORE_CLOCK and APB_CLOCK should be defined already as APB_CLOCK is used b
|
|||
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
to enable using the functions of this library:
|
||||
|
|
@ -47,8 +47,10 @@ then pick the desired setting of each group:
|
|||
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
||||
*/
|
||||
|
||||
// ######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
|
||||
|
||||
//######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
static inline void SPI_init();
|
||||
|
||||
// establish / end a connection to the SPI device
|
||||
|
|
@ -65,14 +67,14 @@ static inline void SPI_NSS_software_high();
|
|||
|
||||
// read / write the SPI device
|
||||
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint16_t SPI_read_16();
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
|
||||
// send a command and get a response from the SPI device
|
||||
// you'll use this for most devices
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data);
|
||||
|
||||
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
||||
|
|
@ -85,25 +87,31 @@ static inline void SPI_poweron();
|
|||
static inline void kill_interrrupts();
|
||||
static inline void restore_interrupts();
|
||||
|
||||
// ######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
static inline uint8_t SPI_is_RX_empty();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
// ######## internal variables
|
||||
|
||||
//######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
static inline uint8_t SPI_is_RX_empty();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
static uint16_t EXT1_INTENR_backup;
|
||||
|
||||
// ######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
// stringify for displaying what #defines evaluated to at preprocessor stage
|
||||
#define VALUE_TO_STRING(x) #x
|
||||
#define VALUE(x) VALUE_TO_STRING(x)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
|
||||
// compile-time log2
|
||||
//compile-time log2
|
||||
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
||||
|
||||
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
||||
|
|
@ -112,249 +120,233 @@ static uint16_t EXT1_INTENR_backup;
|
|||
|
||||
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
||||
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
||||
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
//#pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
|
||||
// ######## preprocessor #define requirements
|
||||
|
||||
|
||||
//######## preprocessor #define requirements
|
||||
|
||||
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
static inline void SPI_init()
|
||||
{
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
|
||||
//######## small function definitions, static inline
|
||||
static inline void SPI_init() {
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
|
||||
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
|
||||
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
|
||||
// MISO on PC7, 10MHz input, floating
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*7));
|
||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
|
||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
|
||||
// MISO on PC7, 10MHz input, floating
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 7));
|
||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 7);
|
||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
#endif
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void SPI_begin_8()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_8() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_begin_16()
|
||||
{
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_16() {
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_end()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
static inline void SPI_end() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
}
|
||||
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 3);
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<3);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
}
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<4);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t SPI_read_8()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
static inline uint8_t SPI_read_8() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline uint16_t SPI_read_16()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
static inline uint16_t SPI_read_16() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline void SPI_write_8(uint8_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_8(uint8_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline void SPI_write_16(uint16_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_16(uint16_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
}
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
}
|
||||
|
||||
static inline void SPI_poweroff()
|
||||
{
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweroff() {
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
}
|
||||
static inline void SPI_poweron()
|
||||
{
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweron() {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
}
|
||||
|
||||
static inline void kill_interrrupts()
|
||||
{
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
static inline void kill_interrrupts() {
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
}
|
||||
static inline void restore_interrupts()
|
||||
{
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
static inline void restore_interrupts() {
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
}
|
||||
|
||||
// ######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
|
||||
|
||||
//######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete() {
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
}
|
||||
static inline uint8_t SPI_is_RX_empty()
|
||||
{
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
static inline uint8_t SPI_is_RX_empty() {
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
}
|
||||
static inline void SPI_wait_RX_available()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
static inline void SPI_wait_RX_available() {
|
||||
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
}
|
||||
static inline void SPI_wait_not_busy()
|
||||
{
|
||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
static inline void SPI_wait_not_busy() {
|
||||
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
}
|
||||
static inline void SPI_wait_transmit_finished()
|
||||
{
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
static inline void SPI_wait_transmit_finished() {
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
}
|
||||
|
||||
// ######## implementation block
|
||||
// #define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
|
||||
//######## implementation block
|
||||
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
||||
|
||||
// no functions here because I think all of the functions are small enough to static inline
|
||||
//no functions here because I think all of the functions are small enough to static inline
|
||||
|
||||
#endif // CH32V003_SPI_IMPLEMENTATION
|
||||
#endif // CH32V003_SPI_H
|
||||
|
|
|
|||
|
|
@ -3,42 +3,44 @@
|
|||
|
||||
/** ADC-based Capactive Touch Control.
|
||||
|
||||
see cap_touch_adc.c for an example.
|
||||
see cap_touch_adc.c for an example.
|
||||
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
|
||||
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
*/
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
// Can either be 0 or 1.
|
||||
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
||||
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
||||
#define TOUCH_SLOPE 1
|
||||
#define TOUCH_SLOPE 1
|
||||
|
||||
// If you set this to 1, it will glitch the line, so it will only read
|
||||
// anything reasonable if the capacitance can overcome that initial spike.
|
||||
// Typically, it seems if you use this you probbly don't need to do
|
||||
// any pre-use calibration.
|
||||
#define TOUCH_FLAT 0
|
||||
#define TOUCH_FLAT 0
|
||||
|
||||
// Macro used for force-alingining ADC timing
|
||||
#define FORCEALIGNADC \
|
||||
asm volatile( \
|
||||
"\n\
|
||||
asm volatile( \
|
||||
"\n\
|
||||
.balign 4\n\
|
||||
andi a2, %[cyccnt], 3\n\
|
||||
c.slli a2, 1\n\
|
||||
|
|
@ -48,172 +50,169 @@
|
|||
jalr a2, 1\n\
|
||||
.long 0x00010001\n\
|
||||
.long 0x00010001\n\
|
||||
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2");
|
||||
"\
|
||||
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||
);
|
||||
|
||||
static void InitTouchADC();
|
||||
void InitTouchADC()
|
||||
|
||||
static void InitTouchADC( );
|
||||
void InitTouchADC( )
|
||||
{
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
||||
;
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while (ADC1->CTLR2 & ADC_CAL)
|
||||
;
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while(ADC1->CTLR2 & ADC_CAL);
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
__enable_irq();
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
__enable_irq();
|
||||
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | CFGBASE;
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#if TOUCH_FLAT == 1
|
||||
#define RELEASEIO \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
io->CFGLR = CFGFLOAT;
|
||||
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||
#else
|
||||
#define RELEASEIO \
|
||||
io->CFGLR = CFGFLOAT; \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
||||
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||
#endif
|
||||
|
||||
#define INNER_LOOP(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP(0);
|
||||
INNER_LOOP(2);
|
||||
INNER_LOOP(4);
|
||||
}
|
||||
INNER_LOOP( 0 );
|
||||
INNER_LOOP( 2 );
|
||||
INNER_LOOP( 4 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#define INNER_LOOP_SAFE(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP_SAFE( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP_SAFE(0);
|
||||
INNER_LOOP_SAFE(2);
|
||||
INNER_LOOP_SAFE(4);
|
||||
}
|
||||
INNER_LOOP_SAFE( 0 );
|
||||
INNER_LOOP_SAFE( 2 );
|
||||
INNER_LOOP_SAFE( 4 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2023 Valve Corporation
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
|
@ -222,3 +221,4 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define _CH32V307GIGABIT_H
|
||||
|
||||
/* This file is written against the RTL8211E
|
||||
*/
|
||||
*/
|
||||
|
||||
// #define CH32V307GIGABIT_MCO25 1
|
||||
// #define CH32V307GIGABIT_PHYADDRESS 0
|
||||
|
|
@ -34,515 +34,515 @@
|
|||
// ETH DMA structure definition (From ch32v30x_eth.c
|
||||
typedef struct
|
||||
{
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
} ETH_DMADESCTypeDef;
|
||||
|
||||
// You must provide:
|
||||
|
||||
void ch32v307ethHandleReconfig(int link, int speed, int duplex);
|
||||
void ch32v307ethHandleReconfig( int link, int speed, int duplex );
|
||||
|
||||
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
|
||||
int ch32v307ethInitHandlePacket(uint8_t *data, int frame_length, ETH_DMADESCTypeDef *dmadesc);
|
||||
int ch32v307ethInitHandlePacket( uint8_t * data, int frame_length, ETH_DMADESCTypeDef * dmadesc );
|
||||
|
||||
void ch32v307ethInitHandleTXC(void);
|
||||
void ch32v307ethInitHandleTXC( void );
|
||||
|
||||
// This library provides:
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac);
|
||||
static int ch32v307ethInit(void);
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy(void);
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac );
|
||||
static int ch32v307ethInit( void );
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy( void );
|
||||
|
||||
// Data pursuent to ethernet.
|
||||
uint8_t ch32v307eth_mac[6] = {0};
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef *pDMARxGet;
|
||||
ETH_DMADESCTypeDef *pDMATxSet;
|
||||
uint8_t ch32v307eth_mac[6] = { 0 };
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef * pDMARxGet;
|
||||
ETH_DMADESCTypeDef * pDMATxSet;
|
||||
|
||||
|
||||
// Internal functions
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val);
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value);
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg);
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg );
|
||||
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value)
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value )
|
||||
{
|
||||
static uint8_t reg_request_count = 0;
|
||||
static uint8_t reg_request_count = 0;
|
||||
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if (miiar & ETH_MACMIIAR_MB)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2)
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if( miiar & ETH_MACMIIAR_MB )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ch32v307ethTickPhy(void)
|
||||
{
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1;
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if( ch32v307ethPHYRegAsyncRead( reg, &miidr ) ) return -1;
|
||||
|
||||
printf("REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid);
|
||||
printf( "REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid );
|
||||
|
||||
if (reg == 0x1a)
|
||||
{
|
||||
speed = ((miidr >> 4) & 3);
|
||||
linked = ((miidr >> 2) & 1);
|
||||
duplex = ((miidr >> 3) & 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr >> 14) & 3);
|
||||
linked = ((miidr >> 10) & 1);
|
||||
duplex = ((miidr >> 13) & 1);
|
||||
}
|
||||
if( reg == 0x1a )
|
||||
{
|
||||
speed = ((miidr>>4)&3);
|
||||
linked = ((miidr>>2)&1);
|
||||
duplex = ((miidr>>3)&1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr>>14)&3);
|
||||
linked = ((miidr>>10)&1);
|
||||
duplex = ((miidr>>13)&1);
|
||||
}
|
||||
|
||||
printf("LINK INFO: %d %d %d\n", speed, linked, duplex);
|
||||
if (linked)
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11);
|
||||
if (newmaccr != oldmaccr)
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig(linked, speed, duplex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
|
||||
if( linked )
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
|
||||
if( newmaccr != oldmaccr )
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig( linked, speed, duplex );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Based on ETH_WritePHYRegister
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
|
||||
{
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg)
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg )
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
}
|
||||
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac)
|
||||
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||
{
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
}
|
||||
|
||||
static int ch32v307ethInit(void)
|
||||
static int ch32v307ethInit( void )
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset)
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW);
|
||||
funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
|
||||
#endif
|
||||
|
||||
// Configure strapping.
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funDigitalWrite(PA1, FUN_HIGH);
|
||||
funDigitalWrite(PA0, FUN_HIGH);
|
||||
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay
|
||||
funDigitalWrite(PC2, FUN_HIGH);
|
||||
// Configure strapping.
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funDigitalWrite( PA1, FUN_HIGH );
|
||||
funDigitalWrite( PA0, FUN_HIGH );
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
|
||||
funDigitalWrite( PC2, FUN_HIGH );
|
||||
|
||||
// Pull-up MDIO
|
||||
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite(PD9, FUN_HIGH);
|
||||
// Pull-up MDIO
|
||||
funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite( PD9, FUN_HIGH );
|
||||
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII
|
||||
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
|
||||
(7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if (timeout == 0) return -5;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if (timeout == 0) return -6;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if( timeout == 0 ) return -5;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if( timeout == 0 ) return -6;
|
||||
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if (timeout == 0) return -7;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if( timeout == 0 ) return -7;
|
||||
|
||||
// Switch to PLL.
|
||||
// Switch to PLL.
|
||||
#ifdef CH32V307GIGABIT_MCO25
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9 << 24); // And output clock on PA8
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9<<24); // And output clock on PA8
|
||||
#else
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
#endif
|
||||
|
||||
// For clock in.
|
||||
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125
|
||||
// For clock in.
|
||||
funPinMode( PB1, GPIO_CFGLR_IN_FLOAT ); //GMII_CLK125
|
||||
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &= ~RCC_ETHMACRST;
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &=~RCC_ETHMACRST;
|
||||
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
|
||||
// Wait for reset to complete.
|
||||
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--)
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
// Wait for reset to complete.
|
||||
for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL;
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
|
||||
|
||||
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO
|
||||
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC
|
||||
funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
|
||||
funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
|
||||
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
|
||||
|
||||
// Release PHY from reset.
|
||||
// Release PHY from reset.
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH);
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
|
||||
#endif
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
|
||||
funPinMode(PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD3
|
||||
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2
|
||||
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1
|
||||
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0
|
||||
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL
|
||||
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL
|
||||
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC
|
||||
funPinMode( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
|
||||
funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
|
||||
funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
|
||||
funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
|
||||
funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
|
||||
funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
|
||||
funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
|
||||
|
||||
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V
|
||||
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1
|
||||
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1
|
||||
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1
|
||||
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0]
|
||||
funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
|
||||
funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
|
||||
funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
|
||||
funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
|
||||
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay
|
||||
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 22) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 21) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
(0 << 17) | // IFG = 0, 96-bit guard time.
|
||||
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
(0 << 12) | // Self Loop = 0
|
||||
(0 << 11) | // Full-Duplex Mode (UNSET TO START)
|
||||
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
(1 << 7) | // APCS (automatically strip frames)
|
||||
(1 << 3) | // TE (Transmit enable!)
|
||||
(1 << 2) | // RE (Receive Enable)
|
||||
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
|
||||
( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 22 ) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
( 0 << 17 ) | // IFG = 0, 96-bit guard time.
|
||||
( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
( 0 << 12 ) | // Self Loop = 0
|
||||
( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
|
||||
( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
( 1 << 7 ) | // APCS (automatically strip frames)
|
||||
( 1 << 3 ) | // TE (Transmit enable!)
|
||||
( 1 << 2 ) | // RE (Receive Enable)
|
||||
( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
PHY_Reset |
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
PHY_Reset |
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
|
||||
ch32v307ethPHYRegRead(0x03);
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe.
|
||||
if (ch32v307eth_phyid == 0xc916)
|
||||
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select.
|
||||
ch32v307ethPHYRegRead( 0x03 );
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
|
||||
if( ch32v307eth_phyid == 0xc916 )
|
||||
ch32v307ethPHYRegWrite( 0x1F, 0x0a43 ); // RTL8211FS needs page select.
|
||||
|
||||
ch32v307ethGetMacInUC(ch32v307eth_mac);
|
||||
ch32v307ethGetMacInUC( ch32v307eth_mac );
|
||||
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5] << 8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1] << 8) | (ch32v307eth_mac[2] << 16) | (ch32v307eth_mac[3] << 24));
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5]<<8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1]<<8) | (ch32v307eth_mac[2]<<16) | (ch32v307eth_mac[3]<<24));
|
||||
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
|
||||
NVIC_EnableIRQ(ETH_IRQn);
|
||||
NVIC_EnableIRQ( ETH_IRQn );
|
||||
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ETH_IRQHandler(void) __attribute__((interrupt));
|
||||
void ETH_IRQHandler(void)
|
||||
void ETH_IRQHandler( void ) __attribute__((interrupt));
|
||||
void ETH_IRQHandler( void )
|
||||
{
|
||||
uint32_t int_sta;
|
||||
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if ((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
|
||||
// Nominal interrupts.
|
||||
if (int_sta & ETH_DMA_IT_NIS)
|
||||
{
|
||||
if (int_sta & ETH_DMA_IT_R)
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
// Nominal interrupts.
|
||||
if( int_sta & ETH_DMA_IT_NIS )
|
||||
{
|
||||
if( int_sta & ETH_DMA_IT_R )
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if (status & ETH_DMARxDesc_OWN) break;
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if( status & ETH_DMARxDesc_OWN ) break;
|
||||
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
|
||||
int suppress_own = 0;
|
||||
int suppress_own = 0;
|
||||
|
||||
if ((status & mask) == eq)
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if (frame_length > 0)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet);
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
if( ( status & mask ) == eq )
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if( frame_length > 0 )
|
||||
{
|
||||
uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
|
||||
// Relinquish control back to underlying hardware.
|
||||
if (!suppress_own)
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
// Relinquish control back to underlying hardware.
|
||||
if( !suppress_own )
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
if (int_sta & ETH_DMA_IT_T)
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while (1);
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while( 1 );
|
||||
}
|
||||
if( int_sta & ETH_DMA_IT_T )
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while( 1 );
|
||||
}
|
||||
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc)
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc)
|
||||
{
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
|
||||
if (pDMATxSet->Status & ETH_DMATxDesc_OWN)
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
|
||||
pDMATxSet = (ETH_DMADESCTypeDef *)pDMATxSet->Buffer2NextDescAddr;
|
||||
pDMATxSet = (ETH_DMADESCTypeDef*)pDMATxSet->Buffer2NextDescAddr;
|
||||
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -7,74 +7,75 @@
|
|||
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
|
||||
*/
|
||||
|
||||
#include "ch32fun.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_defines.h"
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
|
||||
uint8_t *pCtrlPayloadPtr;
|
||||
uint8_t * pCtrlPayloadPtr;
|
||||
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF)
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||
|
||||
#if HUSB_HID_INTERFACES > 0
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
};
|
||||
|
||||
// Provided functions:
|
||||
int HSUSBSetup();
|
||||
int HSUSBSetup();
|
||||
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||
|
||||
// Implement the following:
|
||||
#if HUSB_HID_USER_REPORTS
|
||||
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
int HandleHidUserSetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
void HandleHidUserReportDataOut(struct _USBState *ctx, uint8_t *data, int len);
|
||||
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len);
|
||||
void HandleHidUserReportOutComplete(struct _USBState *ctx);
|
||||
int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
|
||||
#if HUSB_BULK_USER_REPORTS
|
||||
void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
||||
void HandleGotEPComplete( struct _USBState * ctx, int ep );
|
||||
#endif
|
||||
|
||||
extern struct _USBState HSUSBCTX;
|
||||
|
||||
|
||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
||||
|
||||
static inline uint8_t *USBHS_GetEPBufferIfAvailable(int endp)
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||
{
|
||||
if (HSUSBCTX.USBHS_Endp_Busy[endp]) return 0;
|
||||
return USBHSD_UEP_TXBUF(endp);
|
||||
if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
|
||||
return USBHSD_UEP_TXBUF( endp );
|
||||
}
|
||||
|
||||
static inline void USBHS_SendEndpoint(int endp, int len, const uint8_t *data)
|
||||
static inline void USBHS_SendEndpoint( int endp, int len, const uint8_t * data )
|
||||
{
|
||||
if (endp)
|
||||
{
|
||||
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN(endp) = len;
|
||||
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01;
|
||||
if( endp )
|
||||
{
|
||||
(((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN( endp ) = len;
|
||||
USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
/******************************************************************************
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
#ifndef CH32V003_LIB_RAND
|
||||
#define CH32V003_LIB_RAND
|
||||
|
||||
|
|
@ -34,13 +34,14 @@
|
|||
// Strength 3: Genetate two 32bit values using the LFSR, then XOR them together
|
||||
// Example: #define RANDOM_STRENGTH 2
|
||||
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#endif
|
||||
|
||||
// @brief set the random LFSR values seed by default to a known-good value
|
||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||
|
||||
|
||||
/*** Library specific Functions - Do Not Use *********************************/
|
||||
/****************************************************************************/
|
||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
||||
|
|
@ -50,59 +51,63 @@ static uint32_t _rand_lfsr = 0x747AA32F;
|
|||
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
||||
uint8_t _rand_lfsr_update(void)
|
||||
{
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, 32 times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random 32-bit value
|
||||
uint32_t _rand_gen_32b(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, n times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random n-bit value
|
||||
uint32_t _rand_gen_nb(int bits)
|
||||
uint32_t _rand_gen_nb( int bits)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
/*** API Functions ***********************************************************/
|
||||
/*****************************************************************************/
|
||||
/// @brief seeds the Random LFSR to the value passed
|
||||
|
|
@ -110,39 +115,40 @@ uint32_t _rand_gen_nb(int bits)
|
|||
/// @return None
|
||||
void seed(const uint32_t seed_val)
|
||||
{
|
||||
_rand_lfsr = seed_val;
|
||||
_rand_lfsr = seed_val;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||
/// you have selected
|
||||
/// you have selected
|
||||
/// @param None
|
||||
/// @return 32bit Random value
|
||||
uint32_t rand(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,14 +27,14 @@
|
|||
#define TIMEOUT_MAX 100000
|
||||
|
||||
// uncomment this to enable IRQ-driven operation
|
||||
// #define SSD1306_I2C_IRQ
|
||||
//#define SSD1306_I2C_IRQ
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// some stuff that IRQ mode needs
|
||||
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
|
||||
|
||||
// uncomment this to enable time diags in IRQ
|
||||
// #define IRQ_DIAG
|
||||
//#define IRQ_DIAG
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -42,62 +42,62 @@ volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
#if (SSD1306_I2C_CLKRATE <= 100000)
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// fast mode over 100kHz
|
||||
// fast mode over 100kHz
|
||||
#ifndef SSD1306_I2C_DUTY
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
#endif
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
#endif
|
||||
I2C1->CKCFGR = tempreg;
|
||||
I2C1->CKCFGR = tempreg;
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
#endif
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
}
|
||||
|
||||
/*
|
||||
* error descriptions
|
||||
*/
|
||||
char *errstr[] =
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -105,28 +105,28 @@ char *errstr[] =
|
|||
*/
|
||||
uint8_t ssd1306_i2c_error(uint8_t err)
|
||||
{
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// event codes we use
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
|
||||
/*
|
||||
* check for 32-bit event codes
|
||||
*/
|
||||
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||
{
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
||||
return (status & event_mask) == event_mask;
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
|
||||
return (status & event_mask) == event_mask;
|
||||
}
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
|
|
@ -135,67 +135,63 @@ uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
int32_t timeout;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(3));
|
||||
#endif
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while(ssd1306_i2c_irq_state);
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (3));
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while (ssd1306_i2c_irq_state)
|
||||
;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
#endif
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -204,43 +200,42 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
|
||||
void I2C1_EV_IRQHandler(void)
|
||||
{
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
#endif
|
||||
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
|
||||
/* check for TXE */
|
||||
if(STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if(ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
|
||||
/* check for TXE */
|
||||
if (STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if (ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
/* was that the last byte? */
|
||||
if(!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||
|
||||
/* was that the last byte? */
|
||||
if (!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
;
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
|
@ -249,61 +244,56 @@ void I2C1_EV_IRQHandler(void)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
int32_t timeout;
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
// send data one byte at a time
|
||||
while(sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// send data one byte at a time
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -312,20 +302,20 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if (cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1);
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if(cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -333,51 +323,51 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_init(void)
|
||||
{
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
|
||||
#ifdef CH32V20x
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
|
||||
#ifdef SSD1306_REMAP_I2C
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
#else
|
||||
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
#endif
|
||||
|
||||
#else
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2);
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
|
||||
#endif
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
#if 0
|
||||
// test if SSD1306 is on the bus by sending display off command
|
||||
uint8_t command = 0xAF;
|
||||
return ssd1306_pkt_send(&command, 1, 1);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,115 +26,111 @@
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
}
|
||||
|
||||
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0);
|
||||
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0);
|
||||
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA);
|
||||
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
|
||||
#define I2CSPEEDBASE 1
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1)
|
||||
// Delay_Us(x*1);
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||
//Delay_Us(x*1);
|
||||
|
||||
static void ssd1306_i2c_sendstart()
|
||||
{
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
}
|
||||
|
||||
void ssd1306_i2c_sendstop()
|
||||
{
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
}
|
||||
|
||||
// Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
||||
//Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
if (data & 0x80)
|
||||
{
|
||||
SDA_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDA_LOW;
|
||||
}
|
||||
data <<= 1;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(2 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
}
|
||||
unsigned int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
if( data & 0x80 )
|
||||
{ SDA_HIGH; }
|
||||
else
|
||||
{ SDA_LOW; }
|
||||
data<<=1;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
}
|
||||
|
||||
// Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH // Maybe?
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
return !!i;
|
||||
//Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD );
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH // Maybe?
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
return !!i;
|
||||
}
|
||||
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1);
|
||||
if (r) return r;
|
||||
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if (cmd)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x00))
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x40))
|
||||
return 1; // Data
|
||||
}
|
||||
for (int i = 0; i < sz; i++)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(data[i]))
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
|
||||
if( r ) return r;
|
||||
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if(cmd)
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x00 ) )
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x40 ) )
|
||||
return 1; // Data
|
||||
}
|
||||
for( int i = 0; i < sz; i++ )
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( data[i] ) )
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 0);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 1);
|
||||
Delay_Us(10);
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_RST_PIN, 0 );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, 1 );
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef SSD1306_SCK_PIN
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
||||
|
|
@ -36,31 +36,31 @@
|
|||
*/
|
||||
uint8_t ssd1306_spi_init(void)
|
||||
{
|
||||
// Enable GPIOC and SPI
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
// Enable GPIOC and SPI
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -68,9 +68,9 @@ uint8_t ssd1306_spi_init(void)
|
|||
*/
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -78,35 +78,34 @@ void ssd1306_rst(void)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
if (cmd)
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
|
||||
}
|
||||
if(cmd)
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||
}
|
||||
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
|
||||
|
||||
// send data
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TXE
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
||||
;
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
while (SPI1->STATR & SPI_STATR_BSY) {}
|
||||
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||
|
||||
// send data
|
||||
while(sz--)
|
||||
{
|
||||
// wait for TXE
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
while(SPI1->STATR & SPI_STATR_BSY) { }
|
||||
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,28 +2,28 @@
|
|||
I may write another version of this to use DMA to timer ports, but, the SPI port can be used
|
||||
to generate outputs very efficiently. So, for now, SPI Port. Additionally, it uses FAR less
|
||||
internal bus resources than to do the same thing with timers.
|
||||
|
||||
|
||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
||||
|
||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
|
||||
Other defines inclue:
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
|
||||
You will need to implement the following two functions, as callbacks from the ISR.
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
|
||||
You willalso need to call
|
||||
WS2812BDMAInit();
|
||||
WS2812BDMAInit();
|
||||
|
||||
Then, whenyou want to update the LEDs, call:
|
||||
WS2812BDMAStart( int num_leds );
|
||||
WS2812BDMAStart( int num_leds );
|
||||
*/
|
||||
|
||||
#ifndef _WS2812_LED_DRIVER_H
|
||||
|
|
@ -32,11 +32,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
||||
void WS2812BDMAInit();
|
||||
void WS2812BDMAStart(int leds);
|
||||
void WS2812BDMAInit( );
|
||||
void WS2812BDMAStart( int leds );
|
||||
|
||||
// Callbacks that you must implement.
|
||||
uint32_t WS2812BLEDCallback(int ledno);
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
|
||||
#ifdef WS2812DMA_IMPLEMENTATION
|
||||
|
||||
|
|
@ -46,241 +46,230 @@ uint32_t WS2812BLEDCallback(int ledno);
|
|||
#endif
|
||||
|
||||
// Note first n LEDs of DMA Buffer are 0's as a "break"
|
||||
// Need one extra LED at end to leave line high.
|
||||
// Need one extra LED at end to leave line high.
|
||||
// This must be greater than WS2812B_RESET_PERIOD.
|
||||
#define WS2812B_RESET_PERIOD 2
|
||||
|
||||
#ifdef WSRAW
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
|
||||
#else
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
|
||||
#endif
|
||||
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static volatile int WS2812LEDs;
|
||||
static volatile int WS2812LEDPlace;
|
||||
static volatile int WS2812BLEDInUse;
|
||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||
// This effectively creates the bitstream that outputs to the LEDs.
|
||||
static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
||||
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
|
||||
{
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000,
|
||||
0b1000100010001110,
|
||||
0b1000100011101000,
|
||||
0b1000100011101110,
|
||||
0b1000111010001000,
|
||||
0b1000111010001110,
|
||||
0b1000111011101000,
|
||||
0b1000111011101110,
|
||||
0b1110100010001000,
|
||||
0b1110100010001110,
|
||||
0b1110100011101000,
|
||||
0b1110100011101110,
|
||||
0b1110111010001000,
|
||||
0b1110111010001110,
|
||||
0b1110111011101000,
|
||||
0b1110111011101110,
|
||||
};
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||
|
||||
int i;
|
||||
uint16_t *end = ptr + numhalfwords;
|
||||
int ledcount = WS2812LEDs;
|
||||
int place = WS2812LEDPlace;
|
||||
int i;
|
||||
uint16_t * end = ptr + numhalfwords;
|
||||
int ledcount = WS2812LEDs;
|
||||
int place = WS2812LEDPlace;
|
||||
|
||||
#ifdef WSRAW
|
||||
while (place < 0 && ptr != end)
|
||||
{
|
||||
uint32_t *lptr = (uint32_t *)ptr;
|
||||
lptr[0] = 0;
|
||||
lptr[1] = 0;
|
||||
lptr[2] = 0;
|
||||
lptr[3] = 0;
|
||||
ptr += 8;
|
||||
place++;
|
||||
}
|
||||
while( place < 0 && ptr != end )
|
||||
{
|
||||
uint32_t * lptr = (uint32_t *)ptr;
|
||||
lptr[0] = 0;
|
||||
lptr[1] = 0;
|
||||
lptr[2] = 0;
|
||||
lptr[3] = 0;
|
||||
ptr += 8;
|
||||
place++;
|
||||
}
|
||||
|
||||
#else
|
||||
while (place < 0 && ptr != end)
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
while( place < 0 && ptr != end )
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (ptr != end)
|
||||
{
|
||||
if (place >= ledcount)
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while (ptr != end)
|
||||
(*ptr++) = 0; // 0xffff;
|
||||
while( ptr != end )
|
||||
{
|
||||
if( place >= ledcount )
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while( ptr != end )
|
||||
(*ptr++) = 0;//0xffff;
|
||||
|
||||
// Only safe to do this when we're on the second leg.
|
||||
if (tce)
|
||||
{
|
||||
if (place == ledcount)
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
}
|
||||
// Only safe to do this when we're on the second leg.
|
||||
if( tce )
|
||||
{
|
||||
if( place == ledcount )
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WSRAW
|
||||
uint32_t ledval32bit = WS2812BLEDCallback(place++);
|
||||
uint32_t ledval32bit = WS2812BLEDCallback( place++ );
|
||||
|
||||
ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf];
|
||||
ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf];
|
||||
ptr[6] = bitquartets[(ledval32bit>>28)&0xf];
|
||||
ptr[7] = bitquartets[(ledval32bit>>24)&0xf];
|
||||
ptr[4] = bitquartets[(ledval32bit>>20)&0xf];
|
||||
ptr[5] = bitquartets[(ledval32bit>>16)&0xf];
|
||||
ptr[2] = bitquartets[(ledval32bit>>12)&0xf];
|
||||
ptr[3] = bitquartets[(ledval32bit>>8)&0xf];
|
||||
ptr[0] = bitquartets[(ledval32bit>>4)&0xf];
|
||||
ptr[1] = bitquartets[(ledval32bit>>0)&0xf];
|
||||
|
||||
ptr += 8;
|
||||
i += 8;
|
||||
ptr += 8;
|
||||
i += 8;
|
||||
|
||||
#else
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback(place++);
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback( place++ );
|
||||
|
||||
#ifdef WSRBG
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
#elif defined(WSGRB)
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
#elif defined( WSGRB )
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
#else
|
||||
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
#endif
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
#endif
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
}
|
||||
|
||||
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler(void)
|
||||
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler( void )
|
||||
{
|
||||
// GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||
|
||||
// Backup flags.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
// Backup flags.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
|
||||
if (intfr & DMA1_IT_HT3)
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
|
||||
}
|
||||
if (intfr & DMA1_IT_TC3)
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while (intfr & DMA1_IT_GL3);
|
||||
if( intfr & DMA1_IT_HT3 )
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
|
||||
}
|
||||
if( intfr & DMA1_IT_TC3 )
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while( intfr & DMA1_IT_GL3 );
|
||||
|
||||
// GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
}
|
||||
|
||||
void WS2812BDMAStart(int leds)
|
||||
void WS2812BDMAStart( int leds )
|
||||
{
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN, 0);
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
}
|
||||
|
||||
void WS2812BDMAInit()
|
||||
void WS2812BDMAInit( )
|
||||
{
|
||||
// Enable DMA + Peripherals
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
// Enable DMA + Peripherals
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3 << 3; // Divisior = 16 (48/16 = 3MHz)
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
|
||||
// DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
//DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ( DMA1_Channel3_IRQn );
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
|
||||
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
You may also want to define
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes);
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes );
|
||||
|
||||
#ifdef WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
|
|
@ -25,58 +25,59 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
|
|||
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
||||
#endif
|
||||
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes)
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes )
|
||||
{
|
||||
int port_id = (((intptr_t)port - (intptr_t)GPIOA) >> 10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled.
|
||||
int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
|
||||
|
||||
int poffset = (pin * 4);
|
||||
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset));
|
||||
int poffset = (pin*4);
|
||||
port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
|
||||
|
||||
int maskon = 1 << pin;
|
||||
int maskoff = 1 << (16 + pin);
|
||||
int maskon = 1<<pin;
|
||||
int maskoff = 1<<(16+pin);
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
|
||||
uint8_t *end = data + len_in_bytes;
|
||||
while (data != end)
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
uint8_t * end = data + len_in_bytes;
|
||||
while( data != end )
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (byte & 0x80)
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
if( byte & 0x80 )
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__disable_irq();
|
||||
__disable_irq();
|
||||
#endif
|
||||
port->BSHR = maskon;
|
||||
asm volatile("nop\nnop\nnop\nnop");
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskon;
|
||||
asm volatile( "nop\nnop\nnop\nnop" );
|
||||
port->BSHR = maskoff;
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__enable_irq();
|
||||
__enable_irq();
|
||||
#endif
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
data++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
9235
src/misc/CH32V003xx.svd
Normal file
9235
src/misc/CH32V003xx.svd
Normal file
File diff suppressed because it is too large
Load diff
773
src/misc/LIBGCC_LICENSE
Normal file
773
src/misc/LIBGCC_LICENSE
Normal file
|
|
@ -0,0 +1,773 @@
|
|||
The software in the directory newlib and the files configure.ac, Makefile.in,
|
||||
and patches/newlib, is licensed as follows:
|
||||
|
||||
Copyright (c) 2016, The Regents of the University of California (Regents).
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
3. Neither the name of the Regents nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
||||
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
||||
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
||||
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
||||
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
The software in the directories binutils, gcc, and linux-headers, and the
|
||||
files patches/binutils and patches/gcc, is licensed as follows:
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
The software in the directory glibc and the file patches/glibc is licensed as
|
||||
follows:
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
189
src/misc/README.md
Normal file
189
src/misc/README.md
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
# Supplementary non-official material
|
||||
|
||||
This is a copy of libgcc.a that I know works well with the part. Below are the instructions on how to get the source code and how to build it.
|
||||
|
||||
# Extra totally non-official info
|
||||
|
||||
## GPIO Drive Currents
|
||||
|
||||
At 3.3v, it seems that for all speed configurations, the short drive current is 50mA both for emitter and colletor. But the current falls off rather quickly with some voltage.
|
||||
|
||||
At 5v the peak current power application is 90-100mA for emitter and collector.
|
||||
|
||||
## General notes about the CH32V003.
|
||||
|
||||
CPI/Processor Speed:
|
||||
|
||||
Ignoring branches and load/stores, compressed instructions run at 1 CPI. Non-compressed instructions run at 1 CPI for the first 2 instructions, then further ones take 2 CPI regardless of how many more you have. Running from RAM and running from FLASH have slightly different performance characteristics depending on wait states that should be measured in-situation.
|
||||
|
||||
## Building libgcc.a from source.
|
||||
|
||||
1. Install prerequisites (for Debian-based systems; similar steps for other systems):
|
||||
|
||||
```
|
||||
sudo apt-get install build-essential autoconf automake autotools-dev curl \
|
||||
libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo \
|
||||
gperf libtool patchutils bc zlib1g-dev git
|
||||
```
|
||||
|
||||
2. Checkout sources:
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/riscv/riscv-gnu-toolchain.git
|
||||
cd riscv-gnu-toolchain
|
||||
```
|
||||
|
||||
3. Configure and build:
|
||||
|
||||
```
|
||||
./configure --prefix $(pwd)/build-ch32v003 --with-arch=rv32ec --with-abi=ilp32e
|
||||
make -j8
|
||||
```
|
||||
|
||||
4. Enjoy the built libgcc.a at ./build-ch32v003/lib/gcc/riscv32-unknown-elf/12.2.0/libgcc.a
|
||||
|
||||
|
||||
## The vendor bytes section
|
||||
|
||||
```sh
|
||||
../../ch32v003fun//../minichlink/minichlink -a -r + 0x1ffff700 36 -r + 0x1ffff7e0 20
|
||||
```
|
||||
|
||||
For a ch32v307 CH32V307WCU6:
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 18 05 73 30 29 c6 6a 09 85 c5 9f ff
|
||||
1ffff710: 55 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 62 05 1a 00
|
||||
Read 16 bytes
|
||||
1ffff7e0: 20 01 ff ff ff ff ff ff db 4a aa 7b 54 50 d9 16
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
|
||||
Another V307 CH32V307WCU6 (from the same lot)
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 18 05 73 30 2a c6 8c 09 85 c5 9f ff
|
||||
1ffff710: 55 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 5c 05 1a 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 20 01 ff ff ff ff ff ff ed 4a aa 7b 54 50 eb 16
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
A CH32V307VCT6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 28 05 70 30 29 c6 8f 09 85 45 ff ff
|
||||
1ffff710: 55 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 7c 05 19 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 20 01 ff ff ff ff ff ff 99 65 1a 7b 54 50 07 31
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
CH32V305FBP6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 38 05 52 30 2a c6 a9 09 45 c5 9b 32
|
||||
1ffff710: 55 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 81 05 19 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 80 00 ff ff ff ff ff ff cd ab bd 08 7b bc 05 71
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
A CH32V208
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 1c 05 80 20 29 86 51 09 55 00 3f c0
|
||||
1ffff710: 24 01 11 10 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 71 05 1d 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: a0 00 ff ff ff ff ff ff 7a 8b d3 7b 54 50 a1 57
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
A Ch32v203 GBU6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 38 05 5b 30 2d c6 86 09 45 c5 9f 3e
|
||||
1ffff710: 15 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 75 05 1b 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 80 00 ff ff ff ff ff ff cd ab de b7 78 bc 23 20
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
Another CH32v203GBU6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 38 05 5b 30 2d c6 72 09 45 c5 9f 3e
|
||||
1ffff710: 15 a1 05 00 00 00 00 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 7c 05 1b 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 80 00 ff ff ff ff ff ff cd ab c9 b7 78 bc 0e 20
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
A ch32v203c8t6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 00 05 31 20 29 86 6d 09 05 00 3e c1
|
||||
1ffff710: ff ff ff ff 00 00 08 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 7e 05 18 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 40 00 ff ff ff ff ff ff cd ab 09 db 6a bc 40 43
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
A ch32v203c8t6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 00 05 31 20 29 86 62 09 05 00 3e c1
|
||||
1ffff710: ff ff ff ff 00 00 08 86 81 31 15 38 05 fa aa 55
|
||||
1ffff720: 88 05 18 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 40 00 ff ff ff ff ff ff cd ab e5 d6 6a bc 1c 3f
|
||||
1ffff7f0: 39 e3 39 e3
|
||||
```
|
||||
|
||||
CH32X035F8U6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 11 06 5e 03 08 10 69 74 03 5a 00 00
|
||||
1ffff710: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
1ffff720: ff ff ff ff
|
||||
Read 20 bytes
|
||||
1ffff7e0: 3e 00 ff ff ff ff ff ff cd ab 31 28 45 bc 43 90
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
|
||||
CH32X035C8T6
|
||||
```
|
||||
1ffff700: 34 fe 78 dc 01 06 51 03 08 10 41 05 03 5a 00 00
|
||||
1ffff710: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
||||
1ffff720: ff ff ff ff
|
||||
Read 20 bytes
|
||||
1ffff7e0: 3e 00 ff ff ff ff ff ff cd ab bc 1f 48 bc d1 87
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
|
||||
For a ch32v003 (QFN)
|
||||
```
|
||||
1ffff700: 07 f8 98 a3 91 bb 13 07 10 0f 4d b1 13 07 e0 0f
|
||||
1ffff710: 71 b9 33 86 e4 00 08 22 36 c6 3a c4 32 c2 b9 34
|
||||
1ffff720: 12 46 b2 46
|
||||
...
|
||||
1ffff7e0: 10 00 ff ff ff ff ff ff cd ab 0c 78 0c bc e5 df
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
|
||||
Another ch32v003 (QFN)
|
||||
```
|
||||
1ffff700: 12 00 00 00 03 03 09 04 88 06 00 00 0a 00 00 00
|
||||
1ffff710: 05 01 09 ff a1 01 75 08 95 7f 85 aa 09 ff b1 00
|
||||
1ffff720: c0 00 00 00
|
||||
Read 20 bytes
|
||||
1ffff7e0: 10 00 ff ff ff ff ff ff cd ab 2d 6f 3d bc 37 d7
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
For a ch32v003 (SOIC-8) (Different Lot)
|
||||
```
|
||||
1ffff700: 07 f8 98 a3 91 bb 13 07 10 0f 4d b1 13 07 e0 0f
|
||||
1ffff710: 71 b9 33 86 e4 00 08 22 36 c6 3a c4 32 c2 b9 34
|
||||
1ffff720: 12 46 b2 46
|
||||
Read 20 bytes
|
||||
1ffff7e0: 10 00 ff ff ff ff ff ff cd ab 8d 3f c6 bc 20 a8
|
||||
1ffff7f0: ff ff ff ff
|
||||
```
|
||||
12914
src/misc/attic/hardware_header_all_combined.h
Normal file
12914
src/misc/attic/hardware_header_all_combined.h
Normal file
File diff suppressed because it is too large
Load diff
226
src/misc/attic/temp_transition_helper.c
Normal file
226
src/misc/attic/temp_transition_helper.c
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||
|
||||
char * WhitePull( const char ** sti )
|
||||
{
|
||||
const char * st = *sti;
|
||||
int len = 0;
|
||||
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||
const char * sts = st;
|
||||
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||
if( *st == ')' ) { st++; }
|
||||
char * ret = malloc( len + 1 );
|
||||
memcpy( ret, sts, len );
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NYI( const char * s )
|
||||
{
|
||||
int ret = 2;
|
||||
char * wp = WhitePull( &s );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
|
||||
if( strcmp( yes[i], wp ) == 0 ) ret = 1;
|
||||
if( ret != 1 )
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
if( strcmp( no[i], wp ) == 0 ) ret = 0;
|
||||
free( wp );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EvalSpec( const char * spl )
|
||||
{
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
cont:
|
||||
char * wp = WhitePull( &spl );
|
||||
int def = -1;
|
||||
if( strcmp( wp, "defined" ) == 0 ) def = 1;
|
||||
if( strcmp( wp, "!defined" ) == 0 ) def = 2;
|
||||
if( def < 0 ) return 2;
|
||||
char * wpn = WhitePull( &spl );
|
||||
i = NYI( wpn );
|
||||
//printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if( i == 2 ) return 2;
|
||||
|
||||
if( def == 2 ) i = !i;
|
||||
|
||||
if( lasto == 1 )
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if( lasto == 2 )
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
|
||||
char * wpa = WhitePull( &spl );
|
||||
//printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
//printf( "RET: %d\n", ret );
|
||||
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||
else return ret;
|
||||
}
|
||||
|
||||
// 0 for no
|
||||
// 1 for yes
|
||||
// 2 for indeterminate
|
||||
int NoYesInd( const char * preprocc )
|
||||
{
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
|
||||
if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
|
||||
if( ofs )
|
||||
{
|
||||
ret = EvalSpec( preprocc + ofs );
|
||||
//printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
free( wp );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
if( ret < 2 ) ret = !ret;
|
||||
free( wp );
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
//printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * sslineis( const char * line, const char * match )
|
||||
{
|
||||
while( *line == ' ' || *line == '\t' ) line++;
|
||||
const char * linestart = line;
|
||||
while( *line && *match == *line ) { line++; match++; }
|
||||
if( *match == 0 )
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
if( argc != 3 )
|
||||
{
|
||||
fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
{
|
||||
fprintf( stderr, "\t%s\n", no[i] );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
yes[0] = argv[1];
|
||||
|
||||
FILE * f = fopen( argv[2], "r" );
|
||||
if( !f )
|
||||
{
|
||||
fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char * l;
|
||||
|
||||
|
||||
int depth = 0;
|
||||
|
||||
// 0 = no
|
||||
// 1 = yes
|
||||
// 2 = indeterminate
|
||||
// 3 = super no. (I.e. after a true #if clause)
|
||||
int yesnoind[1024];
|
||||
yesnoind[0] = 1;
|
||||
|
||||
while( l = fgets( line, sizeof(line)-1, f ) )
|
||||
{
|
||||
const char * ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
|
||||
if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
//printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd( ss );
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if( (ss = sslineis( line, "#elif " ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( nyi == 1 )
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd( ss );
|
||||
}
|
||||
//printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#else" ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( yesnoind[depth] == 1 )
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#endif" ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if( depth < 0 )
|
||||
{
|
||||
fprintf( stderr, "UNTERMD IF\n" );
|
||||
}
|
||||
}
|
||||
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for( i = 0; i <= depth; i++ )
|
||||
{
|
||||
//printf( "%d", yesnoind[i] );
|
||||
if( yesnoind[i] == 0 || yesnoind[i] == 3 ) thisv = 0;
|
||||
}
|
||||
//printf( ">>%s", l );
|
||||
|
||||
if( thisv != 0 && thisv != 3 && ( thisv != 1 || !waspre ) )
|
||||
{
|
||||
printf( "%s", l );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
src/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
11
src/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
This only works for the WCH LinkE in RISC-V mode. If your programmer has the BLUE light ON shortly after boot your programmer is in ARM mode.
|
||||
|
||||
Please follow instructions here to convert your programmer to RISC-V mode from ARM mode.
|
||||
|
||||
Basically press-and-hold the ModeS button while plugging in the USB.
|
||||
|
||||
Once powered, it will store that to default.
|
||||
|
||||
The blue light should be OFF.
|
||||
|
||||
Once you are in RISC-V mode, you can install this driver by right-clicking on the driver and saying install.
|
||||
BIN
src/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
BIN
src/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
Binary file not shown.
BIN
src/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
BIN
src/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
Binary file not shown.
44121
src/misc/dumped_libgcc.S
Normal file
44121
src/misc/dumped_libgcc.S
Normal file
File diff suppressed because it is too large
Load diff
BIN
src/misc/factory_bootloader.bin
Normal file
BIN
src/misc/factory_bootloader.bin
Normal file
Binary file not shown.
BIN
src/misc/libgcc.a
Normal file
BIN
src/misc/libgcc.a
Normal file
Binary file not shown.
23
src/misc/tests/Makefile
Normal file
23
src/misc/tests/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
all : ci
|
||||
|
||||
EXAMPLES := $(wildcard ../../examples/*/.) $(wildcard ../../examples_v10x/*/.) $(wildcard ../../examples_v20x/*/.) $(wildcard ../../examples_v30x/*/.) $(wildcard ../../examples_x035/*/.)
|
||||
|
||||
.PHONY: ci tests all $(EXAMPLES) clean
|
||||
|
||||
results :
|
||||
mkdir -p results
|
||||
|
||||
$(EXAMPLES) : results
|
||||
echo $(shell basename $(realpath $(lastword $@)))
|
||||
($(MAKE) -C $@ build > results/$(subst .,,$(subst /,_,$@)).txt 2> results/$(subst .,,$(subst /,_,$@)).warning && echo "success" > results/$(subst .,,$(subst /,_,$@)).result) || echo "failure" > results/$(subst .,,$(subst /,_,$@)).result
|
||||
echo $(shell basename $(realpath $(lastword $@))).bin > results/$(subst .,,$(subst /,_,$@)).stat
|
||||
sha1sum $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
wc --bytes $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
|
||||
tests : $(EXAMPLES)
|
||||
|
||||
ci : install tests
|
||||
|
||||
clean :
|
||||
rm -rf results
|
||||
|
||||
Loading…
Add table
Reference in a new issue