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}
|
add_executable(${PROJECT_NAME}
|
||||||
main.c
|
main.c
|
||||||
|
ch32fun.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
${CMAKE_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/extralibs
|
${CMAKE_SOURCE_DIR}/extralibs
|
||||||
${CMAKE_SOURCE_DIR}/ch32fun
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
ch32fun
|
#ch32fun
|
||||||
#libgcc
|
|
||||||
#${CMAKE_SOURCE_DIR}/libgcc.a
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE
|
target_compile_options(${PROJECT_NAME} PUBLIC
|
||||||
-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
|
|
||||||
-g
|
-g
|
||||||
-Os
|
-Os
|
||||||
-flto
|
-flto
|
||||||
|
|
@ -35,7 +26,31 @@ target_compile_options(${PROJECT_NAME} PRIVATE
|
||||||
-DCH32V003=1
|
-DCH32V003=1
|
||||||
-static-libgcc
|
-static-libgcc
|
||||||
-nostdlib
|
-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)
|
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
|
// 2023-06-26 recallmenot
|
||||||
|
|
||||||
// ######## necessities
|
//######## necessities
|
||||||
|
|
||||||
// include guards
|
// include guards
|
||||||
#ifndef CH32V003_GPIO_BR_H
|
#ifndef CH32V003_GPIO_BR_H
|
||||||
#define CH32V003_GPIO_BR_H
|
#define CH32V003_GPIO_BR_H
|
||||||
|
|
||||||
// includes
|
// includes
|
||||||
|
#include <stdint.h> //uintN_t support
|
||||||
#include "../ch32fun/ch32fun.h"
|
#include "../ch32fun/ch32fun.h"
|
||||||
#include <stdint.h> //uintN_t support
|
|
||||||
|
|
||||||
|
|
||||||
/*######## library description
|
/*######## library description
|
||||||
This is a speedy and light GPIO library due to
|
This is a speedy and light GPIO library due to
|
||||||
static inlining of most functions
|
static inlining of most functions
|
||||||
compile-time abstraction
|
compile-time abstraction
|
||||||
branchless where it counts
|
branchless where it counts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*######## library usage and configuration
|
/*######## library usage and configuration
|
||||||
|
|
||||||
first, enable the desired port.
|
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
|
//######## ports, pins and states: use these for the functions below!
|
||||||
{
|
|
||||||
GPIO_port_A = 0b00,
|
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||||
GPIO_port_C = 0b10,
|
|
||||||
GPIO_port_D = 0b11,
|
enum GPIO_port_n {
|
||||||
|
GPIO_port_A = 0b00,
|
||||||
|
GPIO_port_C = 0b10,
|
||||||
|
GPIO_port_D = 0b11,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_pinModes
|
enum GPIO_pinModes {
|
||||||
{
|
GPIO_pinMode_I_floating,
|
||||||
GPIO_pinMode_I_floating,
|
GPIO_pinMode_I_pullUp,
|
||||||
GPIO_pinMode_I_pullUp,
|
GPIO_pinMode_I_pullDown,
|
||||||
GPIO_pinMode_I_pullDown,
|
GPIO_pinMode_I_analog,
|
||||||
GPIO_pinMode_I_analog,
|
GPIO_pinMode_O_pushPull,
|
||||||
GPIO_pinMode_O_pushPull,
|
GPIO_pinMode_O_openDrain,
|
||||||
GPIO_pinMode_O_openDrain,
|
GPIO_pinMode_O_pushPullMux,
|
||||||
GPIO_pinMode_O_pushPullMux,
|
GPIO_pinMode_O_openDrainMux,
|
||||||
GPIO_pinMode_O_openDrainMux,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lowhigh
|
enum lowhigh {
|
||||||
{
|
low,
|
||||||
low,
|
high,
|
||||||
high,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// analog inputs
|
// analog inputs
|
||||||
enum GPIO_analog_inputs
|
enum GPIO_analog_inputs {
|
||||||
{
|
GPIO_Ain0_A2,
|
||||||
GPIO_Ain0_A2,
|
GPIO_Ain1_A1,
|
||||||
GPIO_Ain1_A1,
|
GPIO_Ain2_C4,
|
||||||
GPIO_Ain2_C4,
|
GPIO_Ain3_D2,
|
||||||
GPIO_Ain3_D2,
|
GPIO_Ain4_D3,
|
||||||
GPIO_Ain4_D3,
|
GPIO_Ain5_D5,
|
||||||
GPIO_Ain5_D5,
|
GPIO_Ain6_D6,
|
||||||
GPIO_Ain6_D6,
|
GPIO_Ain7_D4,
|
||||||
GPIO_Ain7_D4,
|
GPIO_AinVref,
|
||||||
GPIO_AinVref,
|
GPIO_AinVcal,
|
||||||
GPIO_AinVcal,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||||
enum GPIO_ADC_sampletimes
|
enum GPIO_ADC_sampletimes {
|
||||||
{
|
GPIO_ADC_sampletime_3cy,
|
||||||
GPIO_ADC_sampletime_3cy,
|
GPIO_ADC_sampletime_9cy,
|
||||||
GPIO_ADC_sampletime_9cy,
|
GPIO_ADC_sampletime_15cy,
|
||||||
GPIO_ADC_sampletime_15cy,
|
GPIO_ADC_sampletime_30cy,
|
||||||
GPIO_ADC_sampletime_30cy,
|
GPIO_ADC_sampletime_43cy,
|
||||||
GPIO_ADC_sampletime_43cy,
|
GPIO_ADC_sampletime_57cy,
|
||||||
GPIO_ADC_sampletime_57cy,
|
GPIO_ADC_sampletime_73cy,
|
||||||
GPIO_ADC_sampletime_73cy,
|
GPIO_ADC_sampletime_241cy_default,
|
||||||
GPIO_ADC_sampletime_241cy_default,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_tim1_output_sets
|
enum GPIO_tim1_output_sets {
|
||||||
{
|
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||||
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_1__C6_C7_C0_D3__C3_C4_D1,
|
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_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,
|
||||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_tim2_output_sets
|
enum GPIO_tim2_output_sets {
|
||||||
{
|
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||||
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
|
// setup
|
||||||
#define GPIO_port_enable(GPIO_port_n)
|
#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_tim1_analogWrite(channel, value)
|
||||||
#define GPIO_tim2_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)
|
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
||||||
|
|
||||||
#undef GPIOv_from_PORT_PIN
|
#undef GPIOv_from_PORT_PIN
|
||||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (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_PORT( GPIOv ) (GPIOv >> 4 )
|
||||||
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111)
|
#define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
|
||||||
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
#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_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(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_A 0b00
|
||||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
#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_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_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_A GPIOA
|
||||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
#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_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_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_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_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_C RCC_APB2Periph_GPIOC
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
#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_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, 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_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_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_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_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_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_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_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_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_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, 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_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_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_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_I_analog(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(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_openDrain(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(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_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, 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_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_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_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_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_pushPull(GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(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
|
#endif
|
||||||
|
|
||||||
#if !defined(GPIO_timer_prescaler)
|
#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
|
#endif
|
||||||
|
|
||||||
// ######## define requirements / maintenance defines
|
//######## define requirements / maintenance defines
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//######## small function definitions, static inline
|
||||||
|
|
||||||
// ######## small function definitions, static inline
|
|
||||||
|
|
||||||
#undef GPIO_port_enable
|
#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_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) ({ \
|
#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_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 * 1)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
(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 * 3)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
(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 * 5)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_port_digitalWrite
|
#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
|
#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
|
#undef GPIO_pinMode
|
||||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
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))); \
|
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_digitalWrite_hi
|
#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
|
#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
|
#undef GPIO_digitalWrite
|
||||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||||
#define GPIO_digitalWrite_0(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_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||||
|
|
||||||
#undef GPIO_digitalWrite_branching
|
#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
|
#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
|
#undef GPIO_ADC_set_sampletime
|
||||||
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
||||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_ADC_set_sampletimes_all
|
#undef GPIO_ADC_set_sampletimes_all
|
||||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||||
ADC1->SAMPTR2 &= 0; \
|
ADC1->SAMPTR2 &= 0; \
|
||||||
ADC1->SAMPTR2 |= \
|
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); \
|
GPIO_ADC_sampletime << (0 * 3) \
|
||||||
ADC1->SAMPTR1 &= 0; \
|
| GPIO_ADC_sampletime << (1 * 3) \
|
||||||
ADC1->SAMPTR1 |= \
|
| GPIO_ADC_sampletime << (2 * 3) \
|
||||||
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 << (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
|
#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)
|
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
||||||
|
|
||||||
#undef GPIO_ADC_calibrate
|
#undef GPIO_ADC_calibrate
|
||||||
#define GPIO_ADC_calibrate() ({ \
|
#define GPIO_ADC_calibrate() ({ \
|
||||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||||
; \
|
ADC1->CTLR2 |= ADC_CAL; \
|
||||||
ADC1->CTLR2 |= ADC_CAL; \
|
while(ADC1->CTLR2 & ADC_CAL); \
|
||||||
while (ADC1->CTLR2 & ADC_CAL) \
|
|
||||||
; \
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// large but will likely only ever be called once
|
// large but will likely only ever be called once
|
||||||
static inline void GPIO_ADCinit()
|
static inline void GPIO_ADCinit() {
|
||||||
{
|
// select ADC clock source
|
||||||
// select ADC clock source
|
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
RCC->CFGR0 &= ~(0x1F<<11);
|
||||||
RCC->CFGR0 &= ~(0x1F << 11);
|
|
||||||
|
|
||||||
// enable clock to the ADC
|
// enable clock to the ADC
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||||
|
|
||||||
// Reset the ADC to init all regs
|
// Reset the ADC to init all regs
|
||||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||||
|
|
||||||
// set sampling time for all inputs to 241 cycles
|
// set sampling time for all inputs to 241 cycles
|
||||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||||
|
|
||||||
// set trigger to software
|
// set trigger to software
|
||||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||||
|
|
||||||
// pre-clear conversion queue
|
// pre-clear conversion queue
|
||||||
ADC1->RSQR1 = 0;
|
ADC1->RSQR1 = 0;
|
||||||
ADC1->RSQR2 = 0;
|
ADC1->RSQR2 = 0;
|
||||||
ADC1->RSQR3 = 0;
|
ADC1->RSQR3 = 0;
|
||||||
|
|
||||||
// power the ADC
|
// power the ADC
|
||||||
GPIO_ADC_set_power(1);
|
GPIO_ADC_set_power(1);
|
||||||
GPIO_ADC_calibrate();
|
GPIO_ADC_calibrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||||
{
|
// set mux to selected input
|
||||||
// set mux to selected input
|
ADC1->RSQR3 = input;
|
||||||
ADC1->RSQR3 = input;
|
// allow everything to precharge
|
||||||
// allow everything to precharge
|
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
// start sw conversion (auto clears)
|
||||||
// start sw conversion (auto clears)
|
ADC1->CTLR2 |= ADC_SWSTART;
|
||||||
ADC1->CTLR2 |= ADC_SWSTART;
|
// wait for conversion complete
|
||||||
// wait for conversion complete
|
while(!(ADC1->STATR & ADC_EOC)) {}
|
||||||
while (!(ADC1->STATR & ADC_EOC)) {}
|
// get result
|
||||||
// get result
|
return ADC1->RDATAR;
|
||||||
return ADC1->RDATAR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef GPIO_tim1_map
|
#undef GPIO_tim1_map
|
||||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_tim2_map
|
#undef GPIO_tim2_map
|
||||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||||
})
|
})
|
||||||
|
|
||||||
static inline void GPIO_tim1_init()
|
static inline void GPIO_tim1_init() {
|
||||||
{
|
// enable TIM1
|
||||||
// enable TIM1
|
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
// reset TIM1 to init all regs
|
||||||
// reset TIM1 to init all regs
|
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
// SMCFGR: default clk input is CK_INT
|
||||||
// SMCFGR: default clk input is CK_INT
|
// set clock prescaler divider
|
||||||
// set clock prescaler divider
|
TIM1->PSC = GPIO_timer_prescaler;
|
||||||
TIM1->PSC = GPIO_timer_prescaler;
|
// set PWM total cycle width
|
||||||
// set PWM total cycle width
|
TIM1->ATRLR = GPIO_timer_resolution;
|
||||||
TIM1->ATRLR = GPIO_timer_resolution;
|
// CTLR1: default is up, events generated, edge align
|
||||||
// CTLR1: default is up, events generated, edge align
|
// enable auto-reload of preload
|
||||||
// enable auto-reload of preload
|
TIM1->CTLR1 |= TIM_ARPE;
|
||||||
TIM1->CTLR1 |= TIM_ARPE;
|
// initialize counter
|
||||||
// initialize counter
|
TIM1->SWEVGR |= TIM_UG;
|
||||||
TIM1->SWEVGR |= TIM_UG;
|
// disengage brake
|
||||||
// disengage brake
|
TIM1->BDTR |= TIM_MOE;
|
||||||
TIM1->BDTR |= TIM_MOE;
|
// Enable TIM1
|
||||||
// Enable TIM1
|
TIM1->CTLR1 |= TIM_CEN;
|
||||||
TIM1->CTLR1 |= TIM_CEN;
|
|
||||||
}
|
}
|
||||||
static inline void GPIO_tim2_init()
|
static inline void GPIO_tim2_init() {
|
||||||
{
|
// enable TIM2
|
||||||
// enable TIM2
|
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
// reset TIM2 to init all regs
|
||||||
// reset TIM2 to init all regs
|
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
// SMCFGR: default clk input is CK_INT
|
||||||
// SMCFGR: default clk input is CK_INT
|
// set clock prescaler divider
|
||||||
// set clock prescaler divider
|
TIM2->PSC = GPIO_timer_prescaler;
|
||||||
TIM2->PSC = GPIO_timer_prescaler;
|
// set PWM total cycle width
|
||||||
// set PWM total cycle width
|
TIM2->ATRLR = GPIO_timer_resolution;
|
||||||
TIM2->ATRLR = GPIO_timer_resolution;
|
// CTLR1: default is up, events generated, edge align
|
||||||
// CTLR1: default is up, events generated, edge align
|
// enable auto-reload of preload
|
||||||
// enable auto-reload of preload
|
TIM2->CTLR1 |= TIM_ARPE;
|
||||||
TIM2->CTLR1 |= TIM_ARPE;
|
// initialize counter
|
||||||
// initialize counter
|
TIM2->SWEVGR |= TIM_UG;
|
||||||
TIM2->SWEVGR |= TIM_UG;
|
// Enable TIM2
|
||||||
// Enable TIM2
|
TIM2->CTLR1 |= TIM_CEN;
|
||||||
TIM2->CTLR1 |= TIM_CEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
#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(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_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_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_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_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||||
|
|
||||||
#undef GPIO_tim1_enableCH
|
#undef GPIO_tim1_enableCH
|
||||||
#define GPIO_tim1_enableCH(channel) ({ \
|
#define GPIO_tim1_enableCH(channel) ({ \
|
||||||
GPIO_timer_channel_set(TIM1, channel); \
|
GPIO_timer_channel_set(TIM1, channel); \
|
||||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||||
})
|
})
|
||||||
#undef GPIO_tim2_enableCH
|
#undef GPIO_tim2_enableCH
|
||||||
#define GPIO_tim2_enableCH(channel) ({ \
|
#define GPIO_tim2_enableCH(channel) ({ \
|
||||||
GPIO_timer_channel_set(TIM2, channel); \
|
GPIO_timer_channel_set(TIM2, channel); \
|
||||||
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
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
|
#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
|
#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
|
#endif // CH32V003_GPIO_BR_H
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
// ######## necessities
|
//######## necessities
|
||||||
|
|
||||||
// include guards
|
// include guards
|
||||||
#ifndef CH32V003_SPI_H
|
#ifndef CH32V003_SPI_H
|
||||||
#define CH32V003_SPI_H
|
#define CH32V003_SPI_H
|
||||||
|
|
||||||
// includes
|
// includes
|
||||||
|
#include<stdint.h> //uintN_t support
|
||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include <stdint.h> //uintN_t support
|
|
||||||
|
|
||||||
#ifndef APB_CLOCK
|
#ifndef APB_CLOCK
|
||||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*######## library usage and configuration
|
/*######## 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
|
#ifndef APB_CLOCK
|
||||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
to enable using the functions of this library:
|
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!
|
#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();
|
static inline void SPI_init();
|
||||||
|
|
||||||
// establish / end a connection to the SPI device
|
// establish / end a connection to the SPI device
|
||||||
|
|
@ -65,14 +67,14 @@ static inline void SPI_NSS_software_high();
|
||||||
|
|
||||||
// read / write the SPI device
|
// read / write the SPI device
|
||||||
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
// 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 uint16_t SPI_read_16();
|
||||||
static inline void SPI_write_8(uint8_t data);
|
static inline void SPI_write_8(uint8_t data);
|
||||||
static inline void SPI_write_16(uint16_t data);
|
static inline void SPI_write_16(uint16_t data);
|
||||||
|
|
||||||
// send a command and get a response from the SPI device
|
// send a command and get a response from the SPI device
|
||||||
// you'll use this for most devices
|
// 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);
|
static inline uint16_t SPI_transfer_16(uint16_t data);
|
||||||
|
|
||||||
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
// 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 kill_interrrupts();
|
||||||
static inline void restore_interrupts();
|
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;
|
static uint16_t EXT1_INTENR_backup;
|
||||||
|
|
||||||
// ######## preprocessor macros
|
|
||||||
// min and max helper macros
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
//######## preprocessor macros
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
// 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
|
// stringify for displaying what #defines evaluated to at preprocessor stage
|
||||||
#define VALUE_TO_STRING(x) #x
|
#define VALUE_TO_STRING(x) #x
|
||||||
#define VALUE(x) VALUE_TO_STRING(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))
|
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
||||||
|
|
||||||
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
// 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
|
// 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)");
|
_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)
|
#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
|
#endif
|
||||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
#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
|
#endif
|
||||||
|
|
||||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 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_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 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_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ######## small function definitions, static inline
|
|
||||||
static inline void SPI_init()
|
|
||||||
{
|
|
||||||
SPI_poweron();
|
|
||||||
|
|
||||||
// reset control register
|
|
||||||
SPI1->CTLR1 = 0;
|
|
||||||
|
|
||||||
// set prescaler
|
//######## small function definitions, static inline
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
|
static inline void SPI_init() {
|
||||||
|
SPI_poweron();
|
||||||
|
|
||||||
|
// reset control register
|
||||||
|
SPI1->CTLR1 = 0;
|
||||||
|
|
||||||
// set clock polarity and phase
|
// set prescaler
|
||||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
|
||||||
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
|
// set clock polarity and phase
|
||||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
#elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0);
|
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
#endif
|
||||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
// configure NSS pin, master mode
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1);
|
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
GPIOC->CFGLR &= ~(0xf<<(4*0));
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3);
|
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
|
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
|
||||||
#endif
|
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
|
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 5));
|
GPIOC->CFGLR &= ~(0xf<<(4*5));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
|
||||||
|
|
||||||
// CH32V003 is master
|
// CH32V003 is master
|
||||||
SPI1->CTLR1 |= SPI_Mode_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
|
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
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
|
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||||
|
#endif
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SPI_begin_8()
|
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_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_begin_16()
|
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_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_end()
|
static inline void SPI_end() {
|
||||||
{
|
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||||
static inline void SPI_NSS_software_high()
|
static inline void SPI_NSS_software_high() {
|
||||||
{
|
GPIOC->BSHR = (1<<3);
|
||||||
GPIOC->BSHR = (1 << 3);
|
|
||||||
}
|
}
|
||||||
static inline void SPI_NSS_software_low()
|
static inline void SPI_NSS_software_low() {
|
||||||
{
|
GPIOC->BSHR = (1<<(16+3));
|
||||||
GPIOC->BSHR = (1 << (16 + 3));
|
|
||||||
}
|
}
|
||||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
static inline void SPI_NSS_software_high()
|
static inline void SPI_NSS_software_high() {
|
||||||
{
|
GPIOC->BSHR = (1<<4);
|
||||||
GPIOC->BSHR = (1 << 4);
|
|
||||||
}
|
}
|
||||||
static inline void SPI_NSS_software_low()
|
static inline void SPI_NSS_software_low() {
|
||||||
{
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint8_t SPI_read_8()
|
static inline uint8_t SPI_read_8() {
|
||||||
{
|
return SPI1->DATAR;
|
||||||
return SPI1->DATAR;
|
|
||||||
}
|
}
|
||||||
static inline uint16_t SPI_read_16()
|
static inline uint16_t SPI_read_16() {
|
||||||
{
|
return SPI1->DATAR;
|
||||||
return SPI1->DATAR;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_write_8(uint8_t data)
|
static inline void SPI_write_8(uint8_t data) {
|
||||||
{
|
SPI1->DATAR = data;
|
||||||
SPI1->DATAR = data;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_write_16(uint16_t data)
|
static inline void SPI_write_16(uint16_t data) {
|
||||||
{
|
SPI1->DATAR = data;
|
||||||
SPI1->DATAR = data;
|
|
||||||
}
|
}
|
||||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||||
{
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_high();
|
||||||
SPI_NSS_software_high();
|
#endif
|
||||||
#endif
|
SPI_write_8(data);
|
||||||
SPI_write_8(data);
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
asm volatile("nop");
|
||||||
asm volatile("nop");
|
SPI_wait_RX_available();
|
||||||
SPI_wait_RX_available();
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_low();
|
||||||
SPI_NSS_software_low();
|
#endif
|
||||||
#endif
|
return SPI_read_8();
|
||||||
return SPI_read_8();
|
|
||||||
}
|
}
|
||||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||||
{
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_high();
|
||||||
SPI_NSS_software_high();
|
#endif
|
||||||
#endif
|
SPI_write_16(data);
|
||||||
SPI_write_16(data);
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
asm volatile("nop");
|
||||||
asm volatile("nop");
|
SPI_wait_RX_available();
|
||||||
SPI_wait_RX_available();
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_low();
|
||||||
SPI_NSS_software_low();
|
#endif
|
||||||
#endif
|
return SPI_read_16();
|
||||||
return SPI_read_16();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SPI_poweroff()
|
static inline void SPI_poweroff() {
|
||||||
{
|
SPI_end();
|
||||||
SPI_end();
|
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_poweron()
|
static inline void SPI_poweron() {
|
||||||
{
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kill_interrrupts()
|
static inline void kill_interrrupts() {
|
||||||
{
|
EXT1_INTENR_backup = EXTI->INTENR;
|
||||||
EXT1_INTENR_backup = EXTI->INTENR;
|
// zero the interrupt enable register to disable all interrupts
|
||||||
// zero the interrupt enable register to disable all interrupts
|
EXTI->INTENR = 0;
|
||||||
EXTI->INTENR = 0;
|
|
||||||
}
|
}
|
||||||
static inline void restore_interrupts()
|
static inline void restore_interrupts() {
|
||||||
{
|
EXTI->INTENR = EXT1_INTENR_backup;
|
||||||
EXTI->INTENR = EXT1_INTENR_backup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######## small internal function definitions, static inline
|
|
||||||
static inline void SPI_wait_TX_complete()
|
|
||||||
{
|
//######## small internal function definitions, static inline
|
||||||
while (!(SPI1->STATR & SPI_STATR_TXE)) {}
|
static inline void SPI_wait_TX_complete() {
|
||||||
|
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||||
}
|
}
|
||||||
static inline uint8_t SPI_is_RX_empty()
|
static inline uint8_t SPI_is_RX_empty() {
|
||||||
{
|
return SPI1->STATR & SPI_STATR_RXNE;
|
||||||
return SPI1->STATR & SPI_STATR_RXNE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_RX_available()
|
static inline void SPI_wait_RX_available() {
|
||||||
{
|
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||||
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_not_busy()
|
static inline void SPI_wait_not_busy() {
|
||||||
{
|
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_transmit_finished()
|
static inline void SPI_wait_transmit_finished() {
|
||||||
{
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
SPI_wait_not_busy();
|
||||||
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)
|
#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_IMPLEMENTATION
|
||||||
#endif // CH32V003_SPI_H
|
#endif // CH32V003_SPI_H
|
||||||
|
|
|
||||||
|
|
@ -3,42 +3,44 @@
|
||||||
|
|
||||||
/** ADC-based Capactive Touch Control.
|
/** 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
|
// Enable GPIOD, C and ADC
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||||
InitTouchADC();
|
InitTouchADC();
|
||||||
|
|
||||||
|
|
||||||
// Then do this any time you want to read some touches.
|
// Then do this any time you want to read some touches.
|
||||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, 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.
|
// Can either be 0 or 1.
|
||||||
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
// 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 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||||
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
// 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
|
// 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.
|
// anything reasonable if the capacitance can overcome that initial spike.
|
||||||
// Typically, it seems if you use this you probbly don't need to do
|
// Typically, it seems if you use this you probbly don't need to do
|
||||||
// any pre-use calibration.
|
// any pre-use calibration.
|
||||||
#define TOUCH_FLAT 0
|
#define TOUCH_FLAT 0
|
||||||
|
|
||||||
// Macro used for force-alingining ADC timing
|
// Macro used for force-alingining ADC timing
|
||||||
#define FORCEALIGNADC \
|
#define FORCEALIGNADC \
|
||||||
asm volatile( \
|
asm volatile( \
|
||||||
"\n\
|
"\n\
|
||||||
.balign 4\n\
|
.balign 4\n\
|
||||||
andi a2, %[cyccnt], 3\n\
|
andi a2, %[cyccnt], 3\n\
|
||||||
c.slli a2, 1\n\
|
c.slli a2, 1\n\
|
||||||
|
|
@ -48,172 +50,169 @@
|
||||||
jalr a2, 1\n\
|
jalr a2, 1\n\
|
||||||
.long 0x00010001\n\
|
.long 0x00010001\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
|
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||||
RCC->CFGR0 &= ~(0x1F << 11);
|
RCC->CFGR0 &= ~(0x1F<<11);
|
||||||
|
|
||||||
// Set up single conversion on chl 2
|
// Set up single conversion on chl 2
|
||||||
ADC1->RSQR1 = 0;
|
ADC1->RSQR1 = 0;
|
||||||
ADC1->RSQR2 = 0;
|
ADC1->RSQR2 = 0;
|
||||||
|
|
||||||
// turn on ADC and set rule group to sw trig
|
// turn on ADC and set rule group to sw trig
|
||||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||||
|
|
||||||
// Reset calibration
|
// Reset calibration
|
||||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||||
;
|
|
||||||
|
// Calibrate
|
||||||
// Calibrate
|
ADC1->CTLR2 |= ADC_CAL;
|
||||||
ADC1->CTLR2 |= ADC_CAL;
|
while(ADC1->CTLR2 & ADC_CAL);
|
||||||
while (ADC1->CTLR2 & ADC_CAL)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run from RAM to get even more stable timing.
|
// Run from RAM to get even more stable timing.
|
||||||
// This function call takes about 8.1uS to execute.
|
// 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")));
|
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 ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
FORCEALIGNADC
|
FORCEALIGNADC
|
||||||
ADC1->RSQR3 = adcno;
|
ADC1->RSQR3 = adcno;
|
||||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
||||||
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin)));
|
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE;
|
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (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
|
#if TOUCH_FLAT == 1
|
||||||
#define RELEASEIO \
|
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
|
||||||
io->CFGLR = CFGFLOAT;
|
|
||||||
#else
|
#else
|
||||||
#define RELEASEIO \
|
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||||
io->CFGLR = CFGFLOAT; \
|
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INNER_LOOP(n) \
|
#define INNER_LOOP( n ) \
|
||||||
{ \
|
{ \
|
||||||
/* Only lock IRQ for a very narrow window. */ \
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
__disable_irq(); \
|
__disable_irq(); \
|
||||||
FORCEALIGNADC \
|
FORCEALIGNADC \
|
||||||
\
|
\
|
||||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
this We are catching it onthe slope much more effectively. */ \
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
\
|
\
|
||||||
ADD_N_NOPS(n) \
|
ADD_N_NOPS( n ) \
|
||||||
\
|
\
|
||||||
RELEASEIO \
|
RELEASEIO \
|
||||||
\
|
\
|
||||||
/* Sampling actually starts here, somewhere, so we can let other \
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
interrupts run */ \
|
interrupts run */ \
|
||||||
__enable_irq(); \
|
__enable_irq(); \
|
||||||
while (!(ADC1->STATR & ADC_EOC)) \
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
; \
|
io->CFGLR = CFGDRIVE; \
|
||||||
io->CFGLR = CFGDRIVE; \
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
ret += ADC1->RDATAR; \
|
||||||
ret += ADC1->RDATAR; \
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < iterations; i++)
|
for( i = 0; i < iterations; i++ )
|
||||||
{
|
{
|
||||||
// Wait a variable amount of time based on loop iteration, in order
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
// to get a variety of RC points and minimize DNL.
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
INNER_LOOP(0);
|
INNER_LOOP( 0 );
|
||||||
INNER_LOOP(2);
|
INNER_LOOP( 2 );
|
||||||
INNER_LOOP(4);
|
INNER_LOOP( 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run from RAM to get even more stable timing.
|
// Run from RAM to get even more stable timing.
|
||||||
// This function call takes about 8.1uS to execute.
|
// 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")));
|
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 ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
|
|
||||||
ADC1->RSQR3 = adcno;
|
ADC1->RSQR3 = adcno;
|
||||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
|
|
||||||
// If we run multiple times with slightly different wait times, we can
|
// If we run multiple times with slightly different wait times, we can
|
||||||
// reduce the impact of the ADC's DNL.
|
// reduce the impact of the ADC's DNL.
|
||||||
|
|
||||||
#define INNER_LOOP_SAFE(n) \
|
#define INNER_LOOP_SAFE( n ) \
|
||||||
{ \
|
{ \
|
||||||
/* Only lock IRQ for a very narrow window. */ \
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
__disable_irq(); \
|
__disable_irq(); \
|
||||||
\
|
\
|
||||||
FORCEALIGNADC \
|
FORCEALIGNADC \
|
||||||
\
|
\
|
||||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
this We are catching it onthe slope much more effectively. */ \
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
\
|
\
|
||||||
ADD_N_NOPS(n) \
|
ADD_N_NOPS( n ) \
|
||||||
\
|
\
|
||||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||||
\
|
\
|
||||||
/* Sampling actually starts here, somewhere, so we can let other \
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
interrupts run */ \
|
interrupts run */ \
|
||||||
__enable_irq(); \
|
__enable_irq(); \
|
||||||
while (!(ADC1->STATR & ADC_EOC)) \
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
; \
|
__disable_irq(); \
|
||||||
__disable_irq(); \
|
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
__enable_irq(); \
|
||||||
__enable_irq(); \
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
ret += ADC1->RDATAR; \
|
||||||
ret += ADC1->RDATAR; \
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < iterations; i++)
|
for( i = 0; i < iterations; i++ )
|
||||||
{
|
{
|
||||||
// Wait a variable amount of time based on loop iteration, in order
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
// to get a variety of RC points and minimize DNL.
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
INNER_LOOP_SAFE(0);
|
INNER_LOOP_SAFE( 0 );
|
||||||
INNER_LOOP_SAFE(2);
|
INNER_LOOP_SAFE( 2 );
|
||||||
INNER_LOOP_SAFE(4);
|
INNER_LOOP_SAFE( 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MIT License
|
* MIT License
|
||||||
*
|
*
|
||||||
* Copyright (c) 2023 Valve Corporation
|
* Copyright (c) 2023 Valve Corporation
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
* copies or substantial portions of the Software.
|
* copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* 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
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define _CH32V307GIGABIT_H
|
#define _CH32V307GIGABIT_H
|
||||||
|
|
||||||
/* This file is written against the RTL8211E
|
/* This file is written against the RTL8211E
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// #define CH32V307GIGABIT_MCO25 1
|
// #define CH32V307GIGABIT_MCO25 1
|
||||||
// #define CH32V307GIGABIT_PHYADDRESS 0
|
// #define CH32V307GIGABIT_PHYADDRESS 0
|
||||||
|
|
@ -34,515 +34,515 @@
|
||||||
// ETH DMA structure definition (From ch32v30x_eth.c
|
// ETH DMA structure definition (From ch32v30x_eth.c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t volatile Status; /* Status */
|
uint32_t volatile Status; /* Status */
|
||||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||||
} ETH_DMADESCTypeDef;
|
} ETH_DMADESCTypeDef;
|
||||||
|
|
||||||
// You must provide:
|
// 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)
|
// 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:
|
// This library provides:
|
||||||
static void ch32v307ethGetMacInUC(uint8_t *mac);
|
static void ch32v307ethGetMacInUC( uint8_t * mac );
|
||||||
static int ch32v307ethInit(void);
|
static int ch32v307ethInit( void );
|
||||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy.
|
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||||
static int ch32v307ethTickPhy(void);
|
static int ch32v307ethTickPhy( void );
|
||||||
|
|
||||||
// Data pursuent to ethernet.
|
// Data pursuent to ethernet.
|
||||||
uint8_t ch32v307eth_mac[6] = {0};
|
uint8_t ch32v307eth_mac[6] = { 0 };
|
||||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
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_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
|
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
|
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||||
ETH_DMADESCTypeDef *pDMARxGet;
|
ETH_DMADESCTypeDef * pDMARxGet;
|
||||||
ETH_DMADESCTypeDef *pDMATxSet;
|
ETH_DMADESCTypeDef * pDMATxSet;
|
||||||
|
|
||||||
|
|
||||||
// Internal functions
|
// Internal functions
|
||||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val);
|
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value);
|
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||||
static int ch32v307ethPHYRegRead(uint32_t reg);
|
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;
|
uint32_t miiar = ETH->MACMIIAR;
|
||||||
if (miiar & ETH_MACMIIAR_MB)
|
if( miiar & ETH_MACMIIAR_MB )
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2)
|
if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
|
||||||
{
|
{
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||||
reg_request_count++;
|
reg_request_count++;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
reg_request_count = 0;
|
reg_request_count = 0;
|
||||||
*value = ETH->MACMIIDR;
|
*value = ETH->MACMIIDR;
|
||||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethTickPhy(void)
|
static int ch32v307ethTickPhy(void)
|
||||||
{
|
{
|
||||||
int speed, linked, duplex;
|
int speed, linked, duplex;
|
||||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||||
int miidr;
|
int miidr;
|
||||||
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1;
|
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)
|
if( reg == 0x1a )
|
||||||
{
|
{
|
||||||
speed = ((miidr >> 4) & 3);
|
speed = ((miidr>>4)&3);
|
||||||
linked = ((miidr >> 2) & 1);
|
linked = ((miidr>>2)&1);
|
||||||
duplex = ((miidr >> 3) & 1);
|
duplex = ((miidr>>3)&1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
speed = ((miidr >> 14) & 3);
|
speed = ((miidr>>14)&3);
|
||||||
linked = ((miidr >> 10) & 1);
|
linked = ((miidr>>10)&1);
|
||||||
duplex = ((miidr >> 13) & 1);
|
duplex = ((miidr>>13)&1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("LINK INFO: %d %d %d\n", speed, linked, duplex);
|
printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
|
||||||
if (linked)
|
if( linked )
|
||||||
{
|
{
|
||||||
uint32_t oldmaccr = ETH->MACCR;
|
uint32_t oldmaccr = ETH->MACCR;
|
||||||
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11);
|
uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
|
||||||
if (newmaccr != oldmaccr)
|
if( newmaccr != oldmaccr )
|
||||||
{
|
{
|
||||||
ETH->MACCR = newmaccr;
|
ETH->MACCR = newmaccr;
|
||||||
ch32v307ethHandleReconfig(linked, speed, duplex);
|
ch32v307ethHandleReconfig( linked, speed, duplex );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Based on ETH_WritePHYRegister
|
// 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->MACMIIDR = val;
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||||
|
|
||||||
uint32_t timeout = 0x100000;
|
uint32_t timeout = 0x100000;
|
||||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||||
;
|
|
||||||
|
|
||||||
// If timeout = 0, is an error.
|
// If timeout = 0, is an error.
|
||||||
return timeout ? 0 : -1;
|
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 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||||
|
|
||||||
uint32_t timeout = 0x100000;
|
uint32_t timeout = 0x100000;
|
||||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||||
;
|
|
||||||
|
|
||||||
// If timeout = 0, is an error.
|
// If timeout = 0, is an error.
|
||||||
return timeout ? ETH->MACMIIDR : -1;
|
return timeout ? ETH->MACMIIDR : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ch32v307ethGetMacInUC(uint8_t *mac)
|
|
||||||
|
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||||
{
|
{
|
||||||
// Mac is backwards.
|
// Mac is backwards.
|
||||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5);
|
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
|
||||||
for (int i = 0; i < 6; i++)
|
for( int i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
mac[i] = *(macaddr--);
|
mac[i] = *(macaddr--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethInit(void)
|
static int ch32v307ethInit( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||||
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset)
|
funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
|
||||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW);
|
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Configure strapping.
|
// Configure strapping.
|
||||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||||
funDigitalWrite(PA1, FUN_HIGH);
|
funDigitalWrite( PA1, FUN_HIGH );
|
||||||
funDigitalWrite(PA0, FUN_HIGH);
|
funDigitalWrite( PA0, FUN_HIGH );
|
||||||
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay
|
funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
|
||||||
funDigitalWrite(PC2, FUN_HIGH);
|
funDigitalWrite( PC2, FUN_HIGH );
|
||||||
|
|
||||||
// Pull-up MDIO
|
// Pull-up MDIO
|
||||||
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||||
funDigitalWrite(PD9, FUN_HIGH);
|
funDigitalWrite( PD9, FUN_HIGH );
|
||||||
|
|
||||||
// Will be required later.
|
// Will be required later.
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
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&
|
// 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:
|
// Clock Tree:
|
||||||
// 8MHz Input
|
// 8MHz Input
|
||||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||||
// PREDIV1 = 2 (1 in register).
|
// PREDIV1 = 2 (1 in register).
|
||||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||||
// PLL = 18 (0 in register) = 72MHz
|
// PLL = 18 (0 in register) = 72MHz
|
||||||
// PLLVCO = 144MHz
|
// PLLVCO = 144MHz
|
||||||
// SYSCLK = PLLVCO = 144MHz
|
// SYSCLK = PLLVCO = 144MHz
|
||||||
// Use EXT_125M (ETH1G_SRC)
|
// Use EXT_125M (ETH1G_SRC)
|
||||||
|
|
||||||
// Switch processor back to HSI so we don't eat dirt.
|
// Switch processor back to HSI so we don't eat dirt.
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||||
|
|
||||||
// Setup clock tree.
|
// Setup clock tree.
|
||||||
RCC->CFGR2 |=
|
RCC->CFGR2 |=
|
||||||
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
(1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||||
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
(1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||||
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII
|
(2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
|
||||||
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
(7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||||
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
(1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||||
0;
|
0;
|
||||||
|
|
||||||
// Power on PLLs
|
// Power on PLLs
|
||||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
if( timeout == 0 ) return -5;
|
||||||
if (timeout == 0) return -5;
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
if( timeout == 0 ) return -6;
|
||||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
|
||||||
if (timeout == 0) return -6;
|
|
||||||
|
|
||||||
// PLL = x18 (0 in register)
|
// PLL = x18 (0 in register)
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0;
|
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||||
RCC->CTLR |= RCC_PLLON;
|
RCC->CTLR |= RCC_PLLON;
|
||||||
|
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
if( timeout == 0 ) return -7;
|
||||||
if (timeout == 0) return -7;
|
|
||||||
|
|
||||||
// Switch to PLL.
|
// Switch to PLL.
|
||||||
#ifdef CH32V307GIGABIT_MCO25
|
#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
|
#else
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For clock in.
|
// For clock in.
|
||||||
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125
|
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.
|
// Power on and reset.
|
||||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||||
RCC->AHBRSTR &= ~RCC_ETHMACRST;
|
RCC->AHBRSTR &=~RCC_ETHMACRST;
|
||||||
|
|
||||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||||
|
|
||||||
// Wait for reset to complete.
|
// Wait for reset to complete.
|
||||||
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--)
|
for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
|
||||||
{
|
{
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use RGMII
|
// Use RGMII
|
||||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL;
|
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
|
||||||
|
|
||||||
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO
|
funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
|
||||||
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC
|
funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
|
||||||
|
|
||||||
// For clock output to Ethernet module.
|
// For clock output to Ethernet module.
|
||||||
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL
|
funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
|
||||||
|
|
||||||
// Release PHY from reset.
|
// Release PHY from reset.
|
||||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH);
|
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
|
||||||
#endif
|
#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( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
|
||||||
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2
|
funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
|
||||||
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1
|
funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
|
||||||
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0
|
funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
|
||||||
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL
|
funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
|
||||||
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC
|
funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
|
||||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||||
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL
|
funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
|
||||||
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC
|
funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
|
||||||
|
|
||||||
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V
|
funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
|
||||||
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1
|
funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
|
||||||
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1
|
funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
|
||||||
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1
|
funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
|
||||||
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0]
|
funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
|
||||||
|
|
||||||
// Configure MDC/MDIO
|
// Configure MDC/MDIO
|
||||||
// Conflicting notes - some say /42, others don't.
|
// Conflicting notes - some say /42, others don't.
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||||
|
|
||||||
// Update MACCR
|
// Update MACCR
|
||||||
ETH->MACCR =
|
ETH->MACCR =
|
||||||
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay
|
( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
|
||||||
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||||
(0 << 22) | // Max TX = 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)
|
( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||||
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||||
(0 << 17) | // IFG = 0, 96-bit guard time.
|
( 0 << 17 ) | // IFG = 0, 96-bit guard time.
|
||||||
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||||
(0 << 12) | // Self Loop = 0
|
( 0 << 12 ) | // Self Loop = 0
|
||||||
(0 << 11) | // Full-Duplex Mode (UNSET TO START)
|
( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
|
||||||
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||||
(1 << 7) | // APCS (automatically strip frames)
|
( 1 << 7 ) | // APCS (automatically strip frames)
|
||||||
(1 << 3) | // TE (Transmit enable!)
|
( 1 << 3 ) | // TE (Transmit enable!)
|
||||||
(1 << 2) | // RE (Receive Enable)
|
( 1 << 2 ) | // RE (Receive Enable)
|
||||||
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong)
|
( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||||
0;
|
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
|
// Reset the physical layer
|
||||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||||
PHY_Reset |
|
PHY_Reset |
|
||||||
1 << 12 | // Auto negotiate
|
1<<12 | // Auto negotiate
|
||||||
1 << 8 | // Duplex
|
1<<8 | // Duplex
|
||||||
1 << 6 | // Speed Bit.
|
1<<6 | // Speed Bit.
|
||||||
0);
|
0 );
|
||||||
|
|
||||||
// De-assert reset.
|
// De-assert reset.
|
||||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||||
1 << 12 | // Auto negotiate
|
1<<12 | // Auto negotiate
|
||||||
1 << 8 | // Duplex
|
1<<8 | // Duplex
|
||||||
1 << 6 | // Speed Bit.
|
1<<6 | // Speed Bit.
|
||||||
0);
|
0 );
|
||||||
|
|
||||||
ch32v307ethPHYRegRead(0x03);
|
ch32v307ethPHYRegRead( 0x03 );
|
||||||
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe.
|
ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
|
||||||
if (ch32v307eth_phyid == 0xc916)
|
if( ch32v307eth_phyid == 0xc916 )
|
||||||
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select.
|
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->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->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->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||||
ETH_SourceAddrFilter_Disable |
|
ETH_SourceAddrFilter_Disable |
|
||||||
ETH_PassControlFrames_BlockAll |
|
ETH_PassControlFrames_BlockAll |
|
||||||
ETH_BroadcastFramesReception_Enable |
|
ETH_BroadcastFramesReception_Enable |
|
||||||
ETH_DestinationAddrFilter_Normal |
|
ETH_DestinationAddrFilter_Normal |
|
||||||
ETH_PromiscuousMode_Disable |
|
ETH_PromiscuousMode_Disable |
|
||||||
ETH_MulticastFramesFilter_Perfect |
|
ETH_MulticastFramesFilter_Perfect |
|
||||||
ETH_UnicastFramesFilter_Perfect);
|
ETH_UnicastFramesFilter_Perfect);
|
||||||
|
|
||||||
ETH->MACHTHR = (uint32_t)0;
|
ETH->MACHTHR = (uint32_t)0;
|
||||||
ETH->MACHTLR = (uint32_t)0;
|
ETH->MACHTLR = (uint32_t)0;
|
||||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||||
|
|
||||||
ETH->MACFCR = 0; // No pause frames.
|
ETH->MACFCR = 0; // No pause frames.
|
||||||
|
|
||||||
// Configure RX/TX chains.
|
// Configure RX/TX chains.
|
||||||
ETH_DMADESCTypeDef *tdesc;
|
ETH_DMADESCTypeDef *tdesc;
|
||||||
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||||
{
|
{
|
||||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||||
tdesc->ControlBufferSize = 0;
|
tdesc->ControlBufferSize = 0;
|
||||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||||
}
|
}
|
||||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||||
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||||
{
|
{
|
||||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * 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);
|
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||||
}
|
}
|
||||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||||
|
|
||||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||||
|
|
||||||
// Receive a good frame half interrupt mask.
|
// Receive a good frame half interrupt mask.
|
||||||
// Receive CRC error frame half interrupt mask.
|
// Receive CRC error frame half interrupt mask.
|
||||||
// For the future: Why do we want this?
|
// For the future: Why do we want this?
|
||||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||||
|
|
||||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||||
ETH_DMA_IT_R | // Receive
|
ETH_DMA_IT_R | // Receive
|
||||||
ETH_DMA_IT_T | // Transmit
|
ETH_DMA_IT_T | // Transmit
|
||||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||||
|
|
||||||
NVIC_EnableIRQ(ETH_IRQn);
|
NVIC_EnableIRQ( ETH_IRQn );
|
||||||
|
|
||||||
// Actually enable receiving process.
|
// Actually enable receiving process.
|
||||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
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 ) __attribute__((interrupt));
|
||||||
void ETH_IRQHandler(void)
|
void ETH_IRQHandler( void )
|
||||||
{
|
{
|
||||||
uint32_t int_sta;
|
uint32_t int_sta;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int_sta = ETH->DMASR;
|
int_sta = ETH->DMASR;
|
||||||
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0)
|
if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off nominal situations.
|
// Off nominal situations.
|
||||||
if (int_sta & ETH_DMA_IT_AIS)
|
if (int_sta & ETH_DMA_IT_AIS)
|
||||||
{
|
{
|
||||||
// Receive buffer unavailable interrupt enable.
|
// Receive buffer unavailable interrupt enable.
|
||||||
if (int_sta & ETH_DMA_IT_RBU)
|
if (int_sta & ETH_DMA_IT_RBU)
|
||||||
{
|
{
|
||||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||||
if ((INFO->CHIPID & 0xf0) == 0x10)
|
if((INFO->CHIPID & 0xf0) == 0x10)
|
||||||
{
|
{
|
||||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||||
ETH->DMARPDR = 0;
|
ETH->DMARPDR = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nominal interrupts.
|
// Nominal interrupts.
|
||||||
if (int_sta & ETH_DMA_IT_NIS)
|
if( int_sta & ETH_DMA_IT_NIS )
|
||||||
{
|
{
|
||||||
if (int_sta & ETH_DMA_IT_R)
|
if( int_sta & ETH_DMA_IT_R )
|
||||||
{
|
{
|
||||||
// Received a packet, normally.
|
// Received a packet, normally.
|
||||||
// Status is in Table 27-17 Definitions of RDes0
|
// Status is in Table 27-17 Definitions of RDes0
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||||
// XXX TODO: Restructure this to allow for
|
// XXX TODO: Restructure this to allow for
|
||||||
ETH->DMASR = ETH_DMA_IT_R;
|
ETH->DMASR = ETH_DMA_IT_R;
|
||||||
|
|
||||||
uint32_t status = pDMARxGet->Status;
|
uint32_t status = pDMARxGet->Status;
|
||||||
if (status & ETH_DMARxDesc_OWN) break;
|
if( status & ETH_DMARxDesc_OWN ) break;
|
||||||
|
|
||||||
// We only have a valid packet in a specific situation.
|
// We only have a valid packet in a specific situation.
|
||||||
// So, we take the status, then mask off the bits we care about
|
// 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.
|
// And see if they're equal to the ones that need to be set/unset.
|
||||||
const uint32_t mask =
|
const uint32_t mask =
|
||||||
ETH_DMARxDesc_OWN |
|
ETH_DMARxDesc_OWN |
|
||||||
ETH_DMARxDesc_LS |
|
ETH_DMARxDesc_LS |
|
||||||
ETH_DMARxDesc_ES |
|
ETH_DMARxDesc_ES |
|
||||||
ETH_DMARxDesc_FS;
|
ETH_DMARxDesc_FS;
|
||||||
const uint32_t eq =
|
const uint32_t eq =
|
||||||
0 |
|
0 |
|
||||||
ETH_DMARxDesc_LS |
|
ETH_DMARxDesc_LS |
|
||||||
0 |
|
0 |
|
||||||
ETH_DMARxDesc_FS;
|
ETH_DMARxDesc_FS;
|
||||||
|
|
||||||
int suppress_own = 0;
|
int suppress_own = 0;
|
||||||
|
|
||||||
if ((status & mask) == eq)
|
if( ( status & mask ) == eq )
|
||||||
{
|
{
|
||||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||||
if (frame_length > 0)
|
if( frame_length > 0 )
|
||||||
{
|
{
|
||||||
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr;
|
uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
|
||||||
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet);
|
suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, Invalid Packet
|
// Otherwise, Invalid Packet
|
||||||
|
|
||||||
// Relinquish control back to underlying hardware.
|
// Relinquish control back to underlying hardware.
|
||||||
if (!suppress_own)
|
if( !suppress_own )
|
||||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||||
|
|
||||||
// Tricky logic for figuring out the next packet. Originally
|
// Tricky logic for figuring out the next packet. Originally
|
||||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||||
else
|
else
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||||
}
|
}
|
||||||
} while (1);
|
} while( 1 );
|
||||||
}
|
}
|
||||||
if (int_sta & ETH_DMA_IT_T)
|
if( int_sta & ETH_DMA_IT_T )
|
||||||
{
|
{
|
||||||
ch32v307ethInitHandleTXC();
|
ch32v307ethInitHandleTXC();
|
||||||
ETH->DMASR = ETH_DMA_IT_T;
|
ETH->DMASR = ETH_DMA_IT_T;
|
||||||
}
|
}
|
||||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||||
}
|
}
|
||||||
} while (1);
|
} 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.
|
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||||
// This also provides a transmit timestamp, which could be
|
// This also provides a transmit timestamp, which could be
|
||||||
// used for PTP.
|
// used for PTP.
|
||||||
// But we don't want to do that.
|
// But we don't want to do that.
|
||||||
// We just want to go. If anyone cares, they can check later.
|
// We just want to go. If anyone cares, they can check later.
|
||||||
|
|
||||||
if (pDMATxSet->Status & ETH_DMATxDesc_OWN)
|
if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
|
||||||
{
|
{
|
||||||
ETH->DMATPDR = 0;
|
ETH->DMATPDR = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
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"
|
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||||
pDMATxSet->Status =
|
pDMATxSet->Status =
|
||||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||||
enable_txc | // Interrupt when complete
|
enable_txc | // Interrupt when complete
|
||||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
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->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||||
ETH->DMATPDR = 0;
|
ETH->DMATPDR = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#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
|
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 <stdint.h>
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "usb_defines.h"
|
||||||
|
#include "usb_config.h"
|
||||||
|
|
||||||
struct _USBState
|
struct _USBState
|
||||||
{
|
{
|
||||||
// Setup Request
|
// Setup Request
|
||||||
uint8_t USBHS_SetupReqCode;
|
uint8_t USBHS_SetupReqCode;
|
||||||
uint8_t USBHS_SetupReqType;
|
uint8_t USBHS_SetupReqType;
|
||||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||||
uint32_t USBHS_IndexValue;
|
uint32_t USBHS_IndexValue;
|
||||||
|
|
||||||
// USB Device Status
|
// USB Device Status
|
||||||
uint16_t USBHS_DevConfig;
|
uint16_t USBHS_DevConfig;
|
||||||
uint16_t USBHS_DevAddr;
|
uint16_t USBHS_DevAddr;
|
||||||
uint8_t USBHS_DevSleepStatus;
|
uint8_t USBHS_DevSleepStatus;
|
||||||
uint8_t USBHS_DevEnumStatus;
|
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 CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF)
|
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||||
|
|
||||||
#if HUSB_HID_INTERFACES > 0
|
#if HUSB_HID_INTERFACES > 0
|
||||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||||
#endif
|
#endif
|
||||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Provided functions:
|
// Provided functions:
|
||||||
int HSUSBSetup();
|
int HSUSBSetup();
|
||||||
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||||
|
|
||||||
// Implement the following:
|
// Implement the following:
|
||||||
#if HUSB_HID_USER_REPORTS
|
#if HUSB_HID_USER_REPORTS
|
||||||
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||||
int HandleHidUserSetReportSetup(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);
|
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||||
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len);
|
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||||
void HandleHidUserReportOutComplete(struct _USBState *ctx);
|
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HUSB_BULK_USER_REPORTS
|
#if HUSB_BULK_USER_REPORTS
|
||||||
void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
void HandleGotEPComplete( struct _USBState * ctx, int ep );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct _USBState HSUSBCTX;
|
extern struct _USBState HSUSBCTX;
|
||||||
|
|
||||||
|
|
||||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
// 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;
|
if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
|
||||||
return USBHSD_UEP_TXBUF(endp);
|
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)
|
if( endp )
|
||||||
{
|
{
|
||||||
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data;
|
(((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
|
||||||
}
|
}
|
||||||
USBHSD_UEP_TLEN(endp) = len;
|
USBHSD_UEP_TLEN( endp ) = len;
|
||||||
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
|
USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||||
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01;
|
HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,30 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||||
* See the GitHub for more information:
|
* See the GitHub for more information:
|
||||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||||
*
|
*
|
||||||
* Ver 1.1 09 Sep 2024
|
* Ver 1.1 09 Sep 2024
|
||||||
*
|
*
|
||||||
* Released under the MIT Licence
|
* Released under the MIT Licence
|
||||||
* Copyright ADBeta (c) 2024
|
* Copyright ADBeta (c) 2024
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
* deal in the Software without restriction, including without limitation the
|
* deal in the Software without restriction, including without limitation the
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
* 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
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
* 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
|
* 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
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#ifndef CH32V003_LIB_RAND
|
#ifndef CH32V003_LIB_RAND
|
||||||
#define CH32V003_LIB_RAND
|
#define CH32V003_LIB_RAND
|
||||||
|
|
||||||
|
|
@ -34,13 +34,14 @@
|
||||||
// Strength 3: Genetate two 32bit values using the LFSR, then XOR them together
|
// Strength 3: Genetate two 32bit values using the LFSR, then XOR them together
|
||||||
// Example: #define RANDOM_STRENGTH 2
|
// Example: #define RANDOM_STRENGTH 2
|
||||||
|
|
||||||
#ifndef RANDOM_STRENGTH
|
#ifndef RANDOM_STRENGTH
|
||||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// @brief set the random LFSR values seed by default to a known-good value
|
// @brief set the random LFSR values seed by default to a known-good value
|
||||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||||
|
|
||||||
|
|
||||||
/*** Library specific Functions - Do Not Use *********************************/
|
/*** Library specific Functions - Do Not Use *********************************/
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
/// @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
|
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
||||||
uint8_t _rand_lfsr_update(void)
|
uint8_t _rand_lfsr_update(void)
|
||||||
{
|
{
|
||||||
// Shifting to MSB to make calculations more efficient later
|
// Shifting to MSB to make calculations more efficient later
|
||||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||||
|
|
||||||
// Calculate the MSB to be put into the LFSR
|
// Calculate the MSB to be put into the LFSR
|
||||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||||
// Shift the lfsr and append the MSB to it
|
// Shift the lfsr and append the MSB to it
|
||||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||||
// Return the LSB instead of MSB
|
// Return the LSB instead of MSB
|
||||||
return msb >> 31;
|
return msb >> 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||||
/// a random bit from LFSR taps, 32 times.
|
/// a random bit from LFSR taps, 32 times.
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return a (psuedo)random 32-bit value
|
/// @return a (psuedo)random 32-bit value
|
||||||
uint32_t _rand_gen_32b(void)
|
uint32_t _rand_gen_32b(void)
|
||||||
{
|
{
|
||||||
uint32_t rand_out = 0;
|
uint32_t rand_out = 0;
|
||||||
|
|
||||||
uint8_t bits = 32;
|
uint8_t bits = 32;
|
||||||
while (bits--)
|
while(bits--)
|
||||||
{
|
{
|
||||||
// Shift the current rand value for the new LSB
|
// Shift the current rand value for the new LSB
|
||||||
rand_out = rand_out << 1;
|
rand_out = rand_out << 1;
|
||||||
// Append the LSB
|
// Append the LSB
|
||||||
rand_out |= _rand_lfsr_update();
|
rand_out |= _rand_lfsr_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||||
/// a random bit from LFSR taps, n times.
|
/// a random bit from LFSR taps, n times.
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return a (psuedo)random n-bit value
|
/// @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--)
|
while(bits--)
|
||||||
{
|
{
|
||||||
// Shift the current rand value for the new LSB
|
// Shift the current rand value for the new LSB
|
||||||
rand_out = rand_out << 1;
|
rand_out = rand_out << 1;
|
||||||
// Append the LSB
|
// Append the LSB
|
||||||
rand_out |= _rand_lfsr_update();
|
rand_out |= _rand_lfsr_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*** API Functions ***********************************************************/
|
/*** API Functions ***********************************************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/// @brief seeds the Random LFSR to the value passed
|
/// @brief seeds the Random LFSR to the value passed
|
||||||
|
|
@ -110,39 +115,40 @@ uint32_t _rand_gen_nb(int bits)
|
||||||
/// @return None
|
/// @return None
|
||||||
void seed(const uint32_t seed_val)
|
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
|
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||||
/// you have selected
|
/// you have selected
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return 32bit Random value
|
/// @return 32bit Random value
|
||||||
uint32_t rand(void)
|
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 is level 1, Update LFSR Once, then return it
|
||||||
#if RANDOM_STRENGTH == 1
|
#if RANDOM_STRENGTH == 1
|
||||||
// Update the LFSR, discard result, and return _lsfr raw
|
// Update the LFSR, discard result, and return _lsfr raw
|
||||||
(void)_rand_lfsr_update();
|
(void)_rand_lfsr_update();
|
||||||
rand_out = _rand_lfsr;
|
rand_out = _rand_lfsr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||||
// bits from the LFSR
|
// bits from the LFSR
|
||||||
#if RANDOM_STRENGTH == 2
|
#if RANDOM_STRENGTH == 2
|
||||||
rand_out = _rand_gen_32b();
|
rand_out = _rand_gen_32b();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||||
// together
|
// together
|
||||||
#if RANDOM_STRENGTH == 3
|
#if RANDOM_STRENGTH == 3
|
||||||
uint32_t rand_a = _rand_gen_32b();
|
uint32_t rand_a = _rand_gen_32b();
|
||||||
uint32_t rand_b = _rand_gen_32b();
|
uint32_t rand_b = _rand_gen_32b();
|
||||||
rand_out = rand_a ^ rand_b;
|
rand_out = rand_a ^ rand_b;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,14 +27,14 @@
|
||||||
#define TIMEOUT_MAX 100000
|
#define TIMEOUT_MAX 100000
|
||||||
|
|
||||||
// uncomment this to enable IRQ-driven operation
|
// uncomment this to enable IRQ-driven operation
|
||||||
// #define SSD1306_I2C_IRQ
|
//#define SSD1306_I2C_IRQ
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#ifdef SSD1306_I2C_IRQ
|
||||||
// some stuff that IRQ mode needs
|
// 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;
|
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
|
// uncomment this to enable time diags in IRQ
|
||||||
// #define IRQ_DIAG
|
//#define IRQ_DIAG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -42,62 +42,62 @@ volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c
|
||||||
*/
|
*/
|
||||||
void ssd1306_i2c_setup(void)
|
void ssd1306_i2c_setup(void)
|
||||||
{
|
{
|
||||||
uint16_t tempreg;
|
uint16_t tempreg;
|
||||||
|
|
||||||
// Reset I2C1 to init all regs
|
// Reset I2C1 to init all regs
|
||||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
// set freq
|
// set freq
|
||||||
tempreg = I2C1->CTLR2;
|
tempreg = I2C1->CTLR2;
|
||||||
tempreg &= ~I2C_CTLR2_FREQ;
|
tempreg &= ~I2C_CTLR2_FREQ;
|
||||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
|
||||||
I2C1->CTLR2 = tempreg;
|
I2C1->CTLR2 = tempreg;
|
||||||
|
|
||||||
// Set clock config
|
// Set clock config
|
||||||
tempreg = 0;
|
tempreg = 0;
|
||||||
#if (SSD1306_I2C_CLKRATE <= 100000)
|
#if (SSD1306_I2C_CLKRATE <= 100000)
|
||||||
// standard mode good to 100kHz
|
// standard mode good to 100kHz
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
#else
|
#else
|
||||||
// fast mode over 100kHz
|
// fast mode over 100kHz
|
||||||
#ifndef SSD1306_I2C_DUTY
|
#ifndef SSD1306_I2C_DUTY
|
||||||
// 33% duty cycle
|
// 33% duty cycle
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
#else
|
#else
|
||||||
// 36% duty cycle
|
// 36% duty cycle
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
tempreg |= I2C_CKCFGR_DUTY;
|
tempreg |= I2C_CKCFGR_DUTY;
|
||||||
#endif
|
#endif
|
||||||
tempreg |= I2C_CKCFGR_FS;
|
tempreg |= I2C_CKCFGR_FS;
|
||||||
#endif
|
#endif
|
||||||
I2C1->CKCFGR = tempreg;
|
I2C1->CKCFGR = tempreg;
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#ifdef SSD1306_I2C_IRQ
|
||||||
// enable IRQ driven operation
|
// enable IRQ driven operation
|
||||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||||
|
|
||||||
// initialize the state
|
// initialize the state
|
||||||
ssd1306_i2c_irq_state = 0;
|
ssd1306_i2c_irq_state = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enable I2C
|
||||||
|
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||||
|
|
||||||
// Enable I2C
|
// set ACK mode
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||||
|
|
||||||
// set ACK mode
|
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* error descriptions
|
* error descriptions
|
||||||
*/
|
*/
|
||||||
char *errstr[] =
|
char *errstr[] =
|
||||||
{
|
{
|
||||||
"not busy",
|
"not busy",
|
||||||
"master mode",
|
"master mode",
|
||||||
"transmit mode",
|
"transmit mode",
|
||||||
"tx empty",
|
"tx empty",
|
||||||
"transmit complete",
|
"transmit complete",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -105,28 +105,28 @@ char *errstr[] =
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_error(uint8_t err)
|
uint8_t ssd1306_i2c_error(uint8_t err)
|
||||||
{
|
{
|
||||||
// report error
|
// report error
|
||||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||||
|
|
||||||
|
// reset & initialize I2C
|
||||||
|
ssd1306_i2c_setup();
|
||||||
|
|
||||||
// reset & initialize I2C
|
return 1;
|
||||||
ssd1306_i2c_setup();
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// event codes we use
|
// event codes we use
|
||||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
#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_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_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for 32-bit event codes
|
* check for 32-bit event codes
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||||
{
|
{
|
||||||
/* read order matters here! STAR1 before STAR2!! */
|
/* read order matters here! STAR1 before STAR2!! */
|
||||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
|
||||||
return (status & event_mask) == event_mask;
|
return (status & event_mask) == event_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#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)
|
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
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (3));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// error out if buffer under/overflow
|
// exit
|
||||||
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
return 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -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) __attribute__((interrupt));
|
||||||
void I2C1_EV_IRQHandler(void)
|
void I2C1_EV_IRQHandler(void)
|
||||||
{
|
{
|
||||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (4));
|
GPIOC->BSHR = (1<<(4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// read status, clear any events
|
// read status, clear any events
|
||||||
STAR1 = I2C1->STAR1;
|
STAR1 = I2C1->STAR1;
|
||||||
STAR2 = I2C1->STAR2;
|
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 */
|
/* was that the last byte? */
|
||||||
if (STAR1 & I2C_STAR1_TXE)
|
if(!ssd1306_i2c_send_sz)
|
||||||
{
|
{
|
||||||
/* check for remaining data */
|
// disable TXE interrupt
|
||||||
if (ssd1306_i2c_send_sz--)
|
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
|
||||||
|
// 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? */
|
// set STOP condition
|
||||||
if (!ssd1306_i2c_send_sz)
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
{
|
}
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
@ -249,61 +244,56 @@ void I2C1_EV_IRQHandler(void)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
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
|
// Set START condition
|
||||||
timeout = TIMEOUT_MAX;
|
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
|
||||||
;
|
// wait for master mode select
|
||||||
if (timeout == -1)
|
timeout = TIMEOUT_MAX;
|
||||||
return ssd1306_i2c_error(0);
|
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
|
// wait for transmit condition
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
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
|
// send data one byte at a time
|
||||||
timeout = TIMEOUT_MAX;
|
while(sz--)
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
{
|
||||||
;
|
// wait for TX Empty
|
||||||
if (timeout == -1)
|
timeout = TIMEOUT_MAX;
|
||||||
return ssd1306_i2c_error(1);
|
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
|
// wait for tx complete
|
||||||
I2C1->DATAR = addr << 1;
|
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
|
// set STOP condition
|
||||||
timeout = TIMEOUT_MAX;
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
|
||||||
;
|
// we're happy
|
||||||
if (timeout == -1)
|
return 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif
|
#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 ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
uint8_t pkt[33];
|
uint8_t pkt[33];
|
||||||
|
|
||||||
/* build command or data packets */
|
/* build command or data packets */
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
pkt[0] = 0;
|
pkt[0] = 0;
|
||||||
pkt[1] = *data;
|
pkt[1] = *data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pkt[0] = 0x40;
|
pkt[0] = 0x40;
|
||||||
memcpy(&pkt[1], data, sz);
|
memcpy(&pkt[1], data, sz);
|
||||||
}
|
}
|
||||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1);
|
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)
|
uint8_t ssd1306_i2c_init(void)
|
||||||
{
|
{
|
||||||
// Enable GPIOC and I2C
|
// Enable GPIOC and I2C
|
||||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
#ifdef CH32V20x
|
#ifdef CH32V20x
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||||
|
|
||||||
#ifdef SSD1306_REMAP_I2C
|
#ifdef SSD1306_REMAP_I2C
|
||||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||||
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
#else
|
#else
|
||||||
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
|
||||||
|
|
||||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 2));
|
GPIOC->CFGLR &= ~(0xf<<(4*2));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
// GPIO diags on PC3/PC4
|
// GPIO diags on PC3/PC4
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
|
||||||
GPIOC->BSHR = (1 << (16 + 3));
|
GPIOC->BSHR = (1<<(16+3));
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// load I2C regs
|
// load I2C regs
|
||||||
ssd1306_i2c_setup();
|
ssd1306_i2c_setup();
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// test if SSD1306 is on the bus by sending display off command
|
// test if SSD1306 is on the bus by sending display off command
|
||||||
uint8_t command = 0xAF;
|
uint8_t command = 0xAF;
|
||||||
return ssd1306_pkt_send(&command, 1, 1);
|
return ssd1306_pkt_send(&command, 1, 1);
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,115 +26,111 @@
|
||||||
*/
|
*/
|
||||||
void ssd1306_i2c_setup(void)
|
void ssd1306_i2c_setup(void)
|
||||||
{
|
{
|
||||||
funGpioInitAll();
|
funGpioInitAll();
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||||
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||||
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0);
|
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||||
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0);
|
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||||
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA);
|
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
|
||||||
#define I2CSPEEDBASE 1
|
#define I2CSPEEDBASE 1
|
||||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1)
|
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||||
// Delay_Us(x*1);
|
//Delay_Us(x*1);
|
||||||
|
|
||||||
static void ssd1306_i2c_sendstart()
|
static void ssd1306_i2c_sendstart()
|
||||||
{
|
{
|
||||||
SCL_HIGH
|
SCL_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_LOW
|
SDA_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_LOW
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssd1306_i2c_sendstop()
|
void ssd1306_i2c_sendstop()
|
||||||
{
|
{
|
||||||
SDA_LOW
|
SDA_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_LOW
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_HIGH
|
SCL_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_HIGH
|
SDA_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return nonzero on failure.
|
//Return nonzero on failure.
|
||||||
unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < 8; i++)
|
for( i = 0; i < 8; i++ )
|
||||||
{
|
{
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
if (data & 0x80)
|
if( data & 0x80 )
|
||||||
{
|
{ SDA_HIGH; }
|
||||||
SDA_HIGH;
|
else
|
||||||
}
|
{ SDA_LOW; }
|
||||||
else
|
data<<=1;
|
||||||
{
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_LOW;
|
SCL_HIGH
|
||||||
}
|
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
|
||||||
data <<= 1;
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
}
|
||||||
SCL_HIGH
|
|
||||||
I2CDELAY_FUNC(2 * I2CSPEEDBASE);
|
|
||||||
SCL_LOW
|
|
||||||
}
|
|
||||||
|
|
||||||
// Immediately after sending last bit, open up DDDR for control.
|
//Immediately after sending last bit, open up DDDR for control.
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD );
|
||||||
SDA_HIGH
|
SDA_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_HIGH
|
SCL_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
i = SDA_IN;
|
i = SDA_IN;
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_LOW
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_HIGH // Maybe?
|
SDA_HIGH // Maybe?
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
return !!i;
|
return !!i;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
ssd1306_i2c_sendstart();
|
ssd1306_i2c_sendstart();
|
||||||
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1);
|
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
|
||||||
if (r) return r;
|
if( r ) return r;
|
||||||
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(0x00))
|
if( ssd1306_i2c_sendbyte( 0x00 ) )
|
||||||
return 1; // Control
|
return 1; // Control
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(0x40))
|
if( ssd1306_i2c_sendbyte( 0x40 ) )
|
||||||
return 1; // Data
|
return 1; // Data
|
||||||
}
|
}
|
||||||
for (int i = 0; i < sz; i++)
|
for( int i = 0; i < sz; i++ )
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(data[i]))
|
if( ssd1306_i2c_sendbyte( data[i] ) )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ssd1306_i2c_sendstop();
|
ssd1306_i2c_sendstop();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssd1306_rst(void)
|
void ssd1306_rst(void)
|
||||||
{
|
{
|
||||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_RST_PIN, 0);
|
funDigitalWrite( SSD1306_RST_PIN, 0 );
|
||||||
Delay_Ms(10);
|
Delay_Ms(10);
|
||||||
funDigitalWrite(SSD1306_RST_PIN, 1);
|
funDigitalWrite( SSD1306_RST_PIN, 1 );
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SSD1306_SCK_PIN
|
#ifndef SSD1306_SCK_PIN
|
||||||
#define SSD1306_SCK_PIN PC5
|
#define SSD1306_SCK_PIN PC5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
||||||
|
|
@ -36,31 +36,31 @@
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_spi_init(void)
|
uint8_t ssd1306_spi_init(void)
|
||||||
{
|
{
|
||||||
// Enable GPIOC and SPI
|
// Enable GPIOC and SPI
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
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();
|
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||||
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||||
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);
|
// Configure SPI
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
SPI1->CTLR1 =
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
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
|
// enable SPI port
|
||||||
SPI1->CTLR1 =
|
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
|
||||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
// always succeed
|
||||||
SSD1306_BAUD_RATE_PRESCALER;
|
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)
|
void ssd1306_rst(void)
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
|
||||||
Delay_Ms(10);
|
Delay_Ms(10);
|
||||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
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)
|
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||||
}
|
}
|
||||||
|
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
while (sz--)
|
while(sz--)
|
||||||
{
|
{
|
||||||
// wait for TXE
|
// wait for TXE
|
||||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||||
;
|
|
||||||
|
// Send byte
|
||||||
// Send byte
|
SPI1->DATAR = *data++;
|
||||||
SPI1->DATAR = *data++;
|
}
|
||||||
}
|
|
||||||
|
// wait for not busy before exiting
|
||||||
// wait for not busy before exiting
|
while(SPI1->STATR & SPI_STATR_BSY) { }
|
||||||
while (SPI1->STATR & SPI_STATR_BSY) {}
|
|
||||||
|
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
|
||||||
|
// we're happy
|
||||||
// we're happy
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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
|
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
|
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.
|
internal bus resources than to do the same thing with timers.
|
||||||
|
|
||||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
**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!
|
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||||
|
|
||||||
If you are including this in main, simply
|
If you are including this in main, simply
|
||||||
#define WS2812DMA_IMPLEMENTATION
|
#define WS2812DMA_IMPLEMENTATION
|
||||||
|
|
||||||
Other defines inclue:
|
Other defines inclue:
|
||||||
#define WSRAW
|
#define WSRAW
|
||||||
#define WSRBG
|
#define WSRBG
|
||||||
#define WSGRB
|
#define WSGRB
|
||||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||||
|
|
||||||
You will need to implement the following two functions, as callbacks from the ISR.
|
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
|
You willalso need to call
|
||||||
WS2812BDMAInit();
|
WS2812BDMAInit();
|
||||||
|
|
||||||
Then, whenyou want to update the LEDs, call:
|
Then, whenyou want to update the LEDs, call:
|
||||||
WS2812BDMAStart( int num_leds );
|
WS2812BDMAStart( int num_leds );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WS2812_LED_DRIVER_H
|
#ifndef _WS2812_LED_DRIVER_H
|
||||||
|
|
@ -32,11 +32,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
||||||
void WS2812BDMAInit();
|
void WS2812BDMAInit( );
|
||||||
void WS2812BDMAStart(int leds);
|
void WS2812BDMAStart( int leds );
|
||||||
|
|
||||||
// Callbacks that you must implement.
|
// Callbacks that you must implement.
|
||||||
uint32_t WS2812BLEDCallback(int ledno);
|
uint32_t WS2812BLEDCallback( int ledno );
|
||||||
|
|
||||||
#ifdef WS2812DMA_IMPLEMENTATION
|
#ifdef WS2812DMA_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
@ -46,241 +46,230 @@ uint32_t WS2812BLEDCallback(int ledno);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Note first n LEDs of DMA Buffer are 0's as a "break"
|
// 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.
|
// This must be greater than WS2812B_RESET_PERIOD.
|
||||||
#define WS2812B_RESET_PERIOD 2
|
#define WS2812B_RESET_PERIOD 2
|
||||||
|
|
||||||
#ifdef WSRAW
|
#ifdef WSRAW
|
||||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
|
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
|
||||||
#else
|
#else
|
||||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
|
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||||
static volatile int WS2812LEDs;
|
static volatile int WS2812LEDs;
|
||||||
static volatile int WS2812LEDPlace;
|
static volatile int WS2812LEDPlace;
|
||||||
static volatile int WS2812BLEDInUse;
|
static volatile int WS2812BLEDInUse;
|
||||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||||
// This effectively creates the bitstream that outputs to the LEDs.
|
// 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] = {
|
const static uint16_t bitquartets[16] = {
|
||||||
0b1000100010001000,
|
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||||
0b1000100010001110,
|
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||||
0b1000100011101000,
|
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||||
0b1000100011101110,
|
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||||
0b1000111010001000,
|
|
||||||
0b1000111010001110,
|
|
||||||
0b1000111011101000,
|
|
||||||
0b1000111011101110,
|
|
||||||
0b1110100010001000,
|
|
||||||
0b1110100010001110,
|
|
||||||
0b1110100011101000,
|
|
||||||
0b1110100011101110,
|
|
||||||
0b1110111010001000,
|
|
||||||
0b1110111010001110,
|
|
||||||
0b1110111011101000,
|
|
||||||
0b1110111011101110,
|
|
||||||
};
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
uint16_t *end = ptr + numhalfwords;
|
uint16_t * end = ptr + numhalfwords;
|
||||||
int ledcount = WS2812LEDs;
|
int ledcount = WS2812LEDs;
|
||||||
int place = WS2812LEDPlace;
|
int place = WS2812LEDPlace;
|
||||||
|
|
||||||
#ifdef WSRAW
|
#ifdef WSRAW
|
||||||
while (place < 0 && ptr != end)
|
while( place < 0 && ptr != end )
|
||||||
{
|
{
|
||||||
uint32_t *lptr = (uint32_t *)ptr;
|
uint32_t * lptr = (uint32_t *)ptr;
|
||||||
lptr[0] = 0;
|
lptr[0] = 0;
|
||||||
lptr[1] = 0;
|
lptr[1] = 0;
|
||||||
lptr[2] = 0;
|
lptr[2] = 0;
|
||||||
lptr[3] = 0;
|
lptr[3] = 0;
|
||||||
ptr += 8;
|
ptr += 8;
|
||||||
place++;
|
place++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
while (place < 0 && ptr != end)
|
while( place < 0 && ptr != end )
|
||||||
{
|
{
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
(*ptr++) = 0;
|
(*ptr++) = 0;
|
||||||
place++;
|
place++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (ptr != end)
|
while( ptr != end )
|
||||||
{
|
{
|
||||||
if (place >= ledcount)
|
if( place >= ledcount )
|
||||||
{
|
{
|
||||||
// Optionally, leave line high.
|
// Optionally, leave line high.
|
||||||
while (ptr != end)
|
while( ptr != end )
|
||||||
(*ptr++) = 0; // 0xffff;
|
(*ptr++) = 0;//0xffff;
|
||||||
|
|
||||||
// Only safe to do this when we're on the second leg.
|
// Only safe to do this when we're on the second leg.
|
||||||
if (tce)
|
if( tce )
|
||||||
{
|
{
|
||||||
if (place == ledcount)
|
if( place == ledcount )
|
||||||
{
|
{
|
||||||
// Take the DMA out of circular mode and let it expire.
|
// Take the DMA out of circular mode and let it expire.
|
||||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||||
WS2812BLEDInUse = 0;
|
WS2812BLEDInUse = 0;
|
||||||
}
|
}
|
||||||
place++;
|
place++;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WSRAW
|
#ifdef WSRAW
|
||||||
uint32_t ledval32bit = WS2812BLEDCallback(place++);
|
uint32_t ledval32bit = WS2812BLEDCallback( place++ );
|
||||||
|
|
||||||
ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf];
|
ptr[6] = bitquartets[(ledval32bit>>28)&0xf];
|
||||||
ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf];
|
ptr[7] = bitquartets[(ledval32bit>>24)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf];
|
ptr[4] = bitquartets[(ledval32bit>>20)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf];
|
ptr[5] = bitquartets[(ledval32bit>>16)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf];
|
ptr[2] = bitquartets[(ledval32bit>>12)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf];
|
ptr[3] = bitquartets[(ledval32bit>>8)&0xf];
|
||||||
ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf];
|
ptr[0] = bitquartets[(ledval32bit>>4)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf];
|
ptr[1] = bitquartets[(ledval32bit>>0)&0xf];
|
||||||
|
|
||||||
ptr += 8;
|
ptr += 8;
|
||||||
i += 8;
|
i += 8;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Use a LUT to figure out how we should set the SPI line.
|
// Use a LUT to figure out how we should set the SPI line.
|
||||||
uint32_t ledval24bit = WS2812BLEDCallback(place++);
|
uint32_t ledval24bit = WS2812BLEDCallback( place++ );
|
||||||
|
|
||||||
#ifdef WSRBG
|
#ifdef WSRBG
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
#elif defined(WSGRB)
|
#elif defined( WSGRB )
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
#else
|
#else
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
#endif
|
#endif
|
||||||
ptr += 6;
|
ptr += 6;
|
||||||
i += 6;
|
i += 6;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
WS2812LEDPlace = place;
|
}
|
||||||
|
WS2812LEDPlace = place;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
|
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
|
||||||
void DMA1_Channel3_IRQHandler(void)
|
void DMA1_Channel3_IRQHandler( void )
|
||||||
{
|
{
|
||||||
// GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||||
|
|
||||||
// Backup flags.
|
// Backup flags.
|
||||||
volatile int intfr = DMA1->INTFR;
|
volatile int intfr = DMA1->INTFR;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Clear all possible flags.
|
// Clear all possible flags.
|
||||||
DMA1->INTFCR = DMA1_IT_GL3;
|
DMA1->INTFCR = DMA1_IT_GL3;
|
||||||
|
|
||||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
// 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
|
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||||
// LED jitter. I am henseforth flipping the order.
|
// LED jitter. I am henseforth flipping the order.
|
||||||
|
|
||||||
if (intfr & DMA1_IT_HT3)
|
if( intfr & DMA1_IT_HT3 )
|
||||||
{
|
{
|
||||||
// Halfwaay (Fill in first part)
|
// Halfwaay (Fill in first part)
|
||||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
|
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
|
||||||
}
|
}
|
||||||
if (intfr & DMA1_IT_TC3)
|
if( intfr & DMA1_IT_TC3 )
|
||||||
{
|
{
|
||||||
// Complete (Fill in second part)
|
// Complete (Fill in second part)
|
||||||
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
|
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
|
||||||
}
|
}
|
||||||
intfr = DMA1->INTFR;
|
intfr = DMA1->INTFR;
|
||||||
} while (intfr & DMA1_IT_GL3);
|
} 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.
|
// Enter critical section.
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
WS2812BLEDInUse = 1;
|
WS2812BLEDInUse = 1;
|
||||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||||
DMA1_Channel3->CNTR = 0;
|
DMA1_Channel3->CNTR = 0;
|
||||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||||
WS2812LEDs = leds;
|
WS2812LEDs = leds;
|
||||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||||
__enable_irq();
|
__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->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WS2812BDMAInit()
|
void WS2812BDMAInit( )
|
||||||
{
|
{
|
||||||
// Enable DMA + Peripherals
|
// Enable DMA + Peripherals
|
||||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||||
|
|
||||||
// MOSI, Configure GPIO Pin
|
// MOSI, Configure GPIO Pin
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||||
|
|
||||||
// Configure SPI
|
// Configure SPI
|
||||||
SPI1->CTLR1 =
|
SPI1->CTLR1 =
|
||||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||||
3 << 3; // Divisior = 16 (48/16 = 3MHz)
|
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||||
|
|
||||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||||
SPI1->HSCR = 1;
|
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 is for SPI1TX
|
||||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||||
DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||||
DMA1_Channel3->CFGR =
|
DMA1_Channel3->CFGR =
|
||||||
DMA_M2M_Disable |
|
DMA_M2M_Disable |
|
||||||
DMA_Priority_VeryHigh |
|
DMA_Priority_VeryHigh |
|
||||||
DMA_MemoryDataSize_HalfWord |
|
DMA_MemoryDataSize_HalfWord |
|
||||||
DMA_PeripheralDataSize_HalfWord |
|
DMA_PeripheralDataSize_HalfWord |
|
||||||
DMA_MemoryInc_Enable |
|
DMA_MemoryInc_Enable |
|
||||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||||
DMA_DIR_PeripheralDST |
|
DMA_DIR_PeripheralDST |
|
||||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
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_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||||
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
NVIC_EnableIRQ( DMA1_Channel3_IRQn );
|
||||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||||
|
|
||||||
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
||||||
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
|
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||||
|
|
||||||
If you are including this in main, simply
|
If you are including this in main, simply
|
||||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||||
|
|
||||||
You may also want to define
|
You may also want to define
|
||||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#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
|
#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
|
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
||||||
#endif
|
#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);
|
int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
|
||||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled.
|
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
|
||||||
|
|
||||||
int poffset = (pin * 4);
|
int poffset = (pin*4);
|
||||||
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset));
|
port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
|
||||||
|
|
||||||
int maskon = 1 << pin;
|
int maskon = 1<<pin;
|
||||||
int maskoff = 1 << (16 + pin);
|
int maskoff = 1<<(16+pin);
|
||||||
|
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
|
|
||||||
uint8_t *end = data + len_in_bytes;
|
uint8_t * end = data + len_in_bytes;
|
||||||
while (data != end)
|
while( data != end )
|
||||||
{
|
{
|
||||||
uint8_t byte = *data;
|
uint8_t byte = *data;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; i++)
|
for( i = 0; i < 8; i++ )
|
||||||
{
|
{
|
||||||
if (byte & 0x80)
|
if( byte & 0x80 )
|
||||||
{
|
{
|
||||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||||
port->BSHR = maskon;
|
port->BSHR = maskon;
|
||||||
DelaySysTick(25);
|
DelaySysTick(25);
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
DelaySysTick(1);
|
DelaySysTick(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
#endif
|
#endif
|
||||||
port->BSHR = maskon;
|
port->BSHR = maskon;
|
||||||
asm volatile("nop\nnop\nnop\nnop");
|
asm volatile( "nop\nnop\nnop\nnop" );
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
#endif
|
#endif
|
||||||
DelaySysTick(15);
|
DelaySysTick(15);
|
||||||
}
|
}
|
||||||
byte <<= 1;
|
byte <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
data++;
|
data++;
|
||||||
}
|
}
|
||||||
|
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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