Merge pull request #10 from kienvo/led-scan

Add basic Charlieplexing scan
This commit is contained in:
François Cartegnie
2024-06-06 11:22:09 +07:00
committed by GitHub
49 changed files with 14398 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
ENTRY( _start )
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K
RAM (xrw) : ORIGIN = 0x20003800, LENGTH = 32K
}
SECTIONS
{
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
/* .vector :
{
*(.vector);
} >FLASH AT>FLASH */
.highcodelalign :
{
. = ALIGN(4);
PROVIDE(_highcode_lma = .);
} >FLASH AT>FLASH
.highcode :
{
. = ALIGN(4);
PROVIDE(_highcode_vma_start = .);
*(.vector);
KEEP(*(SORT_NONE(.vector_handler)))
*(.highcode);
*(.highcode.*);
. = ALIGN(4);
PROVIDE(_highcode_vma_end = .);
} >RAM AT>FLASH
.text :
{
. = ALIGN(4);
KEEP(*(SORT_NONE(.handle_reset)))
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.sdata2.*)
*(.glue_7)
*(.glue_7t)
*(.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 :
{
. = ORIGIN(RAM) + MAX(0x800 , SIZEOF(.highcode));
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.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 = . );
.stack ORIGIN(RAM)+LENGTH(RAM) :
{
. = ALIGN(4);
PROVIDE(_eusrstack = . );
} >RAM
}

View File

@@ -0,0 +1,306 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : core_riscv.c
* Author : WCH
* Version : V1.1.0
* Date : 2021/06/06
* Description : RISC-V Core Peripheral Access Layer Source File
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include <stdint.h>
/* define compiler specific symbols */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#endif
/*********************************************************************
* @fn __get_MSTATUS
*
* @brief Return the Machine Status Register
*
* @return mstatus value
*/
uint32_t __get_MSTATUS(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mstatus" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MSTATUS
*
* @brief Set the Machine Status Register
*
* @param value - set mstatus value
*
* @return none
*/
void __set_MSTATUS(uint32_t value)
{
__ASM volatile ("csrw mstatus, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MISA
*
* @brief Return the Machine ISA Register
*
* @return misa value
*/
uint32_t __get_MISA(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "misa" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MISA
*
* @brief Set the Machine ISA Register
*
* @param value - set misa value
*
* @return none
*/
void __set_MISA(uint32_t value)
{
__ASM volatile ("csrw misa, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MTVEC
*
* @brief Return the Machine Trap-Vector Base-Address Register
*
* @return mtvec value
*/
uint32_t __get_MTVEC(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mtvec" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MTVEC
*
* @brief Set the Machine Trap-Vector Base-Address Register
*
* @param value - set mtvec value
*
* @return none
*/
void __set_MTVEC(uint32_t value)
{
__ASM volatile ("csrw mtvec, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MSCRATCH
*
* @brief Return the Machine Seratch Register
*
* @return mscratch value
*/
uint32_t __get_MSCRATCH(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mscratch" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MSCRATCH
*
* @brief Set the Machine Seratch Register
*
* @param value - set mscratch value
*
* @return none
*/
void __set_MSCRATCH(uint32_t value)
{
__ASM volatile ("csrw mscratch, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MEPC
*
* @brief Return the Machine Exception Program Register
*
* @return mepc value
*/
uint32_t __get_MEPC(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mepc" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MEPC
*
* @brief Set the Machine Exception Program Register
*
* @return mepc value
*/
void __set_MEPC(uint32_t value)
{
__ASM volatile ("csrw mepc, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MCAUSE
*
* @brief Return the Machine Cause Register
*
* @return mcause value
*/
uint32_t __get_MCAUSE(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mcause" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MEPC
*
* @brief Set the Machine Cause Register
*
* @return mcause value
*/
void __set_MCAUSE(uint32_t value)
{
__ASM volatile ("csrw mcause, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MTVAL
*
* @brief Return the Machine Trap Value Register
*
* @return mtval value
*/
uint32_t __get_MTVAL(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mtval" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __set_MTVAL
*
* @brief Set the Machine Trap Value Register
*
* @return mtval value
*/
void __set_MTVAL(uint32_t value)
{
__ASM volatile ("csrw mtval, %0" : : "r" (value) );
}
/*********************************************************************
* @fn __get_MVENDORID
*
* @brief Return Vendor ID Register
*
* @return mvendorid value
*/
uint32_t __get_MVENDORID(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mvendorid" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __get_MARCHID
*
* @brief Return Machine Architecture ID Register
*
* @return marchid value
*/
uint32_t __get_MARCHID(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "marchid" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __get_MIMPID
*
* @brief Return Machine Implementation ID Register
*
* @return mimpid value
*/
uint32_t __get_MIMPID(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mimpid" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __get_MHARTID
*
* @brief Return Hart ID Register
*
* @return mhartid value
*/
uint32_t __get_MHARTID(void)
{
uint32_t result;
__ASM volatile ( "csrr %0," "mhartid" : "=r" (result) );
return (result);
}
/*********************************************************************
* @fn __get_SP
*
* @brief Return SP Register
*
* @return SP value
*/
uint32_t __get_SP(void)
{
uint32_t result;
__ASM volatile ( "mv %0," "sp" : "=r"(result) : );
return (result);
}

View File

@@ -0,0 +1,381 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : core_riscv.h
* Author : WCH
* Version : V1.0.1
* Date : 2021/10/28
* Description : CH583 RISC-V Core Peripheral Access Layer Header File
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CORE_RV3A_H__
#define __CORE_RV3A_H__
#ifdef __cplusplus
extern "C" {
#endif
/* IO definitions */
#ifdef __cplusplus
#define __I volatile /*!< defines 'read only' permissions */
#else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
#define RV_STATIC_INLINE static inline
//typedef enum {SUCCESS = 0, ERROR = !SUCCESS} ErrorStatus;
typedef enum
{
DISABLE = 0,
ENABLE = !DISABLE
} FunctionalState;
typedef enum
{
RESET = 0,
SET = !RESET
} FlagStatus, ITStatus;
/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
typedef struct
{
__I uint32_t ISR[8]; // 0
__I uint32_t IPR[8]; // 20H
__IO uint32_t ITHRESDR; // 40H
uint8_t RESERVED[4]; // 44H
__O uint32_t CFGR; // 48H
__I uint32_t GISR; // 4CH
__IO uint8_t IDCFGR[4]; // 50H
uint8_t RESERVED0[0x0C]; // 54H
__IO uint32_t FIADDRR[4]; // 60H
uint8_t RESERVED1[0x90]; // 70H
__O uint32_t IENR[8]; // 100H
uint8_t RESERVED2[0x60]; // 120H
__O uint32_t IRER[8]; // 180H
uint8_t RESERVED3[0x60]; // 1A0H
__O uint32_t IPSR[8]; // 200H
uint8_t RESERVED4[0x60]; // 220H
__O uint32_t IPRR[8]; // 280H
uint8_t RESERVED5[0x60]; // 2A0H
__IO uint32_t IACTR[8]; // 300H
uint8_t RESERVED6[0xE0]; // 320H
__IO uint8_t IPRIOR[256]; // 400H
uint8_t RESERVED7[0x810]; // 500H
__IO uint32_t SCTLR; // D10H
} PFIC_Type;
/* memory mapped structure for SysTick */
typedef struct
{
__IO uint32_t CTLR;
__IO uint32_t SR;
__IO uint64_t CNT;
__IO uint64_t CMP;
} SysTick_Type;
#define PFIC ((PFIC_Type *)0xE000E000)
#define SysTick ((SysTick_Type *)0xE000F000)
#define PFIC_KEY1 ((uint32_t)0xFA050000)
#define PFIC_KEY2 ((uint32_t)0xBCAF0000)
#define PFIC_KEY3 ((uint32_t)0xBEEF0000)
/* ########################## define #################################### */
#define __nop() __asm__ volatile("nop")
#define read_csr(reg) ({unsigned long __tmp; \
__asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define write_csr(reg, val) ({ \
if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
__asm__ volatile ("csrw " #reg ", %0" :: "i"(val)); \
else \
__asm__ volatile ("csrw " #reg ", %0" :: "r"(val)); })
#define PFIC_EnableAllIRQ() write_csr(0x800, 0x88)
#define PFIC_DisableAllIRQ() write_csr(0x800, 0x80)
/* ########################## PFIC functions #################################### */
/*******************************************************************************
* @fn PFIC_EnableIRQ
*
* @brief Enable Interrupt
*
* @param IRQn - Interrupt Numbers
*/
RV_STATIC_INLINE void PFIC_EnableIRQ(IRQn_Type IRQn)
{
PFIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn)&0x1F));
}
/*******************************************************************************
* @fn PFIC_DisableIRQ
*
* @brief Disable Interrupt
*
* @param IRQn - Interrupt Numbers
*/
RV_STATIC_INLINE void PFIC_DisableIRQ(IRQn_Type IRQn)
{
PFIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn)&0x1F));
__nop();
__nop();
}
/*******************************************************************************
* @fn PFIC_GetStatusIRQ
*
* @brief Get Interrupt Enable State
*
* @param IRQn - Interrupt Numbers
*
* @return 1: Interrupt Enable
* 0: Interrupt Disable
*/
RV_STATIC_INLINE uint32_t PFIC_GetStatusIRQ(IRQn_Type IRQn)
{
return ((uint32_t)((PFIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn)&0x1F))) ? 1 : 0));
}
/*******************************************************************************
* @fn PFIC_GetPendingIRQ
*
* @brief Get Interrupt Pending State
*
* @param IRQn - Interrupt Numbers
*
* @return 1: Interrupt Pending Enable
* 0: Interrupt Pending Disable
*/
RV_STATIC_INLINE uint32_t PFIC_GetPendingIRQ(IRQn_Type IRQn)
{
return ((uint32_t)((PFIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn)&0x1F))) ? 1 : 0));
}
/*******************************************************************************
* @fn PFIC_SetPendingIRQ
*
* @brief Set Interrupt Pending
*
* @param IRQn - Interrupt Numbers
*/
RV_STATIC_INLINE void PFIC_SetPendingIRQ(IRQn_Type IRQn)
{
PFIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn)&0x1F));
}
/*******************************************************************************
* @fn PFIC_ClearPendingIRQ
*
* @brief Clear Interrupt Pending
*
* @param IRQn - Interrupt Numbers
*/
RV_STATIC_INLINE void PFIC_ClearPendingIRQ(IRQn_Type IRQn)
{
PFIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn)&0x1F));
}
/*******************************************************************************
* @fn PFIC_GetActive
*
* @brief Get Interrupt Active State
*
* @param IRQn - Interrupt Numbers
*
* @return 1: Interrupt Active
* 0: Interrupt No Active.
*/
RV_STATIC_INLINE uint32_t PFIC_GetActive(IRQn_Type IRQn)
{
return ((uint32_t)((PFIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn)&0x1F))) ? 1 : 0));
}
/*******************************************************************************
* @fn PFIC_SetPriority
*
* @brief Set Interrupt Priority
*
* @param IRQn - Interrupt Numbers
* @param priority - bit7: pre-emption priority
* bit6-bit4: subpriority
*/
RV_STATIC_INLINE void PFIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
{
PFIC->IPRIOR[(uint32_t)(IRQn)] = priority;
}
/*********************************************************************
* @fn PFIC_EnableFastINT0
*
* @brief Set fast Interrupt 0
*
* @param IRQn - Interrupt Numbers
* @param addr - interrupt service addr
*/
RV_STATIC_INLINE void PFIC_EnableFastINT0(IRQn_Type IRQn, uint32_t addr)
{
PFIC->IDCFGR[0] = IRQn;
PFIC->FIADDRR[0] = (addr & 0xFFFFFFFE) | 1;
}
/*********************************************************************
* @fn PFIC_EnableFastINT1
*
* @brief Set fast Interrupt 1
*
* @param IRQn - Interrupt Numbers
* @param addr - interrupt service addr
*/
RV_STATIC_INLINE void PFIC_EnableFastINT1(IRQn_Type IRQn, uint32_t addr)
{
PFIC->IDCFGR[1] = IRQn;
PFIC->FIADDRR[1] = (addr & 0xFFFFFFFE) | 1;
}
/*********************************************************************
* @fn PFIC_EnableFastINT2
*
* @brief Set fast Interrupt 2
*
* @param IRQn - Interrupt Numbers
* @param addr - interrupt service addr
*/
RV_STATIC_INLINE void PFIC_EnableFastINT2(IRQn_Type IRQn, uint32_t addr)
{
PFIC->IDCFGR[2] = IRQn;
PFIC->FIADDRR[2] = (addr & 0xFFFFFFFE) | 1;
}
/*********************************************************************
* @fn PFIC_EnableFastINT3
*
* @brief Set fast Interrupt 3
*
* @param IRQn - Interrupt Numbers
* @param addr - interrupt service addr
*/
RV_STATIC_INLINE void PFIC_EnableFastINT3(IRQn_Type IRQn, uint32_t addr)
{
PFIC->IDCFGR[3] = IRQn;
PFIC->FIADDRR[3] = (addr & 0xFFFFFFFE) | 1;
}
/*********************************************************************
* @fn PFIC_DisableFastINT0
*
* @brief Disable fast Interrupt 0
*/
RV_STATIC_INLINE void PFIC_DisableFastINT0(void)
{
PFIC->FIADDRR[0] = PFIC->FIADDRR[0] & 0xFFFFFFFE;
}
/*********************************************************************
* @fn PFIC_DisableFastINT1
*
* @brief Disable fast Interrupt 1
*/
RV_STATIC_INLINE void PFIC_DisableFastINT1(void)
{
PFIC->FIADDRR[1] = PFIC->FIADDRR[1] & 0xFFFFFFFE;
}
/*********************************************************************
* @fn PFIC_DisableFastINT2
*
* @brief Disable fast Interrupt 2
*/
RV_STATIC_INLINE void PFIC_DisableFastINT2(void)
{
PFIC->FIADDRR[2] = PFIC->FIADDRR[2] & 0xFFFFFFFE;
}
/*********************************************************************
* @fn PFIC_DisableFastINT3
*
* @brief Disable fast Interrupt 3
*/
RV_STATIC_INLINE void PFIC_DisableFastINT3(void)
{
PFIC->FIADDRR[3] = PFIC->FIADDRR[3] & 0xFFFFFFFE;
}
/*********************************************************************
* @fn __SEV
*
* @brief Wait for Events
*/
__attribute__((always_inline)) RV_STATIC_INLINE void __SEV(void)
{
PFIC->SCTLR |= (1 << 3);
}
/*********************************************************************
* @fn __WFI
*
* @brief Wait for Interrupt
*/
__attribute__((always_inline)) RV_STATIC_INLINE void __WFI(void)
{
PFIC->SCTLR &= ~(1 << 3); // wfi
__asm__ volatile("wfi");
}
/*********************************************************************
* @fn __WFE
*
* @brief Wait for Events
*/
__attribute__((always_inline)) RV_STATIC_INLINE void __WFE(void)
{
PFIC->SCTLR |= (1 << 3) | (1 << 5); // (wfi->wfe)+(__sev)
__asm__ volatile("wfi");
PFIC->SCTLR |= (1 << 3);
__asm__ volatile("wfi");
}
/*********************************************************************
* @fn PFIC_SystemReset
*
* @brief Initiate a system reset request
*/
RV_STATIC_INLINE void PFIC_SystemReset(void)
{
PFIC->CFGR = PFIC_KEY3 | (1 << 7);
}
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFFFFFFFFFFF)
#define SysTick_CTLR_INIT (1 << 5)
#define SysTick_CTLR_MODE (1 << 4)
#define SysTick_CTLR_STRE (1 << 3)
#define SysTick_CTLR_STCLK (1 << 2)
#define SysTick_CTLR_STIE (1 << 1)
#define SysTick_CTLR_STE (1 << 0)
#define SysTick_SR_CNTIF (1 << 0)
RV_STATIC_INLINE uint32_t SysTick_Config(uint64_t ticks)
{
if((ticks - 1) > SysTick_LOAD_RELOAD_Msk)
return (1); /* Reload value impossible */
SysTick->CMP = ticks - 1; /* set reload register */
PFIC_EnableIRQ(SysTick_IRQn);
SysTick->CTLR = SysTick_CTLR_INIT |
SysTick_CTLR_STRE |
SysTick_CTLR_STCLK |
SysTick_CTLR_STIE |
SysTick_CTLR_STE; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
#ifdef __cplusplus
}
#endif
#endif /* __CORE_RV3A_H__ */

View File

@@ -0,0 +1,188 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : startup_ch58x.s
* Author : WCH
* Version : V1.0.0
* Date : 2021/02/25
* Description :
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
.section .init,"ax",@progbits
.global _start
.align 1
_start:
j handle_reset
.section .vector,"ax",@progbits
.align 1
_vector_base:
.option norvc;
.word 0
.word 0
.word NMI_Handler /* NMI Handler */
.word HardFault_Handler /* Hard Fault Handler */
.word 0xF5F9BDA9
.word Ecall_M_Mode_Handler /* 5 */
.word 0
.word 0
.word Ecall_U_Mode_Handler /* 8 */
.word Break_Point_Handler /* 9 */
.word 0
.word 0
.word SysTick_Handler /* SysTick Handler */
.word 0
.word SW_Handler /* SW Handler */
.word 0
/* External Interrupts */
.word TMR0_IRQHandler /* 0: TMR0 */
.word GPIOA_IRQHandler /* GPIOA */
.word GPIOB_IRQHandler /* GPIOB */
.word SPI0_IRQHandler /* SPI0 */
.word BB_IRQHandler /* BLEB */
.word LLE_IRQHandler /* BLEL */
.word USB_IRQHandler /* USB */
.word USB2_IRQHandler /* USB2 */
.word TMR1_IRQHandler /* TMR1 */
.word TMR2_IRQHandler /* TMR2 */
.word UART0_IRQHandler /* UART0 */
.word UART1_IRQHandler /* UART1 */
.word RTC_IRQHandler /* RTC */
.word ADC_IRQHandler /* ADC */
.word I2C_IRQHandler /* I2C */
.word PWMX_IRQHandler /* PWMX */
.word TMR3_IRQHandler /* TMR3 */
.word UART2_IRQHandler /* UART2 */
.word UART3_IRQHandler /* UART3 */
.word WDOG_BAT_IRQHandler /* WDOG_BAT */
.option rvc;
.section .vector_handler, "ax", @progbits
.weak NMI_Handler
.weak HardFault_Handler
.weak Ecall_M_Mode_Handler
.weak Ecall_U_Mode_Handler
.weak Break_Point_Handler
.weak SysTick_Handler
.weak SW_Handler
.weak TMR0_IRQHandler
.weak GPIOA_IRQHandler
.weak GPIOB_IRQHandler
.weak SPI0_IRQHandler
.weak BB_IRQHandler
.weak LLE_IRQHandler
.weak USB_IRQHandler
.weak USB2_IRQHandler
.weak TMR1_IRQHandler
.weak TMR2_IRQHandler
.weak UART0_IRQHandler
.weak UART1_IRQHandler
.weak RTC_IRQHandler
.weak ADC_IRQHandler
.weak I2C_IRQHandler
.weak PWMX_IRQHandler
.weak TMR3_IRQHandler
.weak UART2_IRQHandler
.weak UART3_IRQHandler
.weak WDOG_BAT_IRQHandler
NMI_Handler: 1: j 1b
HardFault_Handler: 1: j 1b
Ecall_M_Mode_Handler: 1: j 1b
Ecall_U_Mode_Handler: 1: j 1b
Break_Point_Handler: 1: j 1b
SysTick_Handler: 1: j 1b
SW_Handler: 1: j 1b
TMR0_IRQHandler: 1: j 1b
GPIOA_IRQHandler: 1: j 1b
GPIOB_IRQHandler: 1: j 1b
SPI0_IRQHandler: 1: j 1b
BB_IRQHandler: 1: j 1b
LLE_IRQHandler: 1: j 1b
USB_IRQHandler: 1: j 1b
USB2_IRQHandler: 1: j 1b
TMR1_IRQHandler: 1: j 1b
TMR2_IRQHandler: 1: j 1b
UART0_IRQHandler: 1: j 1b
UART1_IRQHandler: 1: j 1b
RTC_IRQHandler: 1: j 1b
ADC_IRQHandler: 1: j 1b
I2C_IRQHandler: 1: j 1b
PWMX_IRQHandler: 1: j 1b
TMR3_IRQHandler: 1: j 1b
UART2_IRQHandler: 1: j 1b
UART3_IRQHandler: 1: j 1b
WDOG_BAT_IRQHandler: 1: j 1b
.section .handle_reset,"ax",@progbits
.weak handle_reset
.align 1
handle_reset:
.option push
.option norelax
la gp, __global_pointer$
.option pop
1:
la sp, _eusrstack
/* Load highcode code section from flash to RAM */
2:
la a0, _highcode_lma
la a1, _highcode_vma_start
la a2, _highcode_vma_end
bgeu a1, a2, 2f
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
/* Load data section from flash to RAM */
2:
la a0, _data_lma
la a1, _data_vma
la a2, _edata
bgeu a1, a2, 2f
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
/* clear bss section */
la a0, _sbss
la a1, _ebss
bgeu a0, a1, 2f
1:
sw zero, (a0)
addi a0, a0, 4
bltu a0, a1, 1b
2:
/* 流水线控制位 & 动态预测控制位 */
li t0, 0x1f
csrw 0xbc0, t0
/* 打开嵌套中断、硬件压栈功能 */
li t0, 0x3
csrw 0x804, t0
li t0, 0x88
csrs mstatus, t0
la t0, _vector_base
/* 配置向量表模式为绝对地址模式 */
ori t0, t0, 3
csrw mtvec, t0
la t0, main
csrw mepc, t0
mret

View File

@@ -0,0 +1,235 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_adc.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn ADC_DataCalib_Rough
*
* @brief 采样数据粗调,获取偏差值,必须先配置ADC后调用此函数获取校准值
*
* @param none
*
* @return 偏差
*/
signed short ADC_DataCalib_Rough(void) // 采样数据粗调,获取偏差值
{
uint16_t i;
uint32_t sum = 0;
uint8_t ch = 0; // 备份通道
ch = R8_ADC_CHANNEL;
ADC_ChannelCfg(1); // ADC校准通道请选择通道1
R8_ADC_CFG |= RB_ADC_OFS_TEST; // 进入测试模式
R8_ADC_CONVERT = RB_ADC_START;
while(R8_ADC_CONVERT & RB_ADC_START);
for(i = 0; i < 16; i++)
{
R8_ADC_CONVERT = RB_ADC_START;
while(R8_ADC_CONVERT & RB_ADC_START);
sum += (~R16_ADC_DATA) & RB_ADC_DATA;
}
sum = (sum + 8) >> 4;
R8_ADC_CFG &= ~RB_ADC_OFS_TEST; // 关闭测试模式
R8_ADC_CHANNEL = ch;
return (2048 - sum);
}
/*********************************************************************
* @fn ADC_ExtSingleChSampInit
*
* @brief 外部信号单通道采样初始化
*
* @param sp - refer to ADC_SampClkTypeDef
* @param ga - refer to ADC_SignalPGATypeDef
*
* @return none
*/
void ADC_ExtSingleChSampInit(ADC_SampClkTypeDef sp, ADC_SignalPGATypeDef ga)
{
R8_TKEY_CFG &= ~RB_TKEY_PWR_ON;
R8_ADC_CFG = RB_ADC_POWER_ON | RB_ADC_BUF_EN | (sp << 6) | (ga << 4);
}
/*********************************************************************
* @fn ADC_ExtDiffChSampInit
*
* @brief 外部信号差分通道采样初始化
*
* @param sp - refer to ADC_SampClkTypeDef
* @param ga - refer to ADC_SignalPGATypeDef
*
* @return none
*/
void ADC_ExtDiffChSampInit(ADC_SampClkTypeDef sp, ADC_SignalPGATypeDef ga)
{
R8_TKEY_CFG &= ~RB_TKEY_PWR_ON;
R8_ADC_CFG = RB_ADC_POWER_ON | RB_ADC_DIFF_EN | (sp << 6) | (ga << 4);
}
/*********************************************************************
* @fn ADC_InterTSSampInit
*
* @brief 内置温度传感器采样初始化
*
* @param none
*
* @return none
*/
void ADC_InterTSSampInit(void)
{
R8_TKEY_CFG &= ~RB_TKEY_PWR_ON;
R8_TEM_SENSOR = RB_TEM_SEN_PWR_ON;
R8_ADC_CHANNEL = CH_INTE_VTEMP;
R8_ADC_CFG = RB_ADC_POWER_ON | RB_ADC_DIFF_EN | (3 << 4);
}
/*********************************************************************
* @fn ADC_InterBATSampInit
*
* @brief 内置电池电压采样初始化
*
* @param none
*
* @return none
*/
void ADC_InterBATSampInit(void)
{
R8_TKEY_CFG &= ~RB_TKEY_PWR_ON;
R8_ADC_CHANNEL = CH_INTE_VBAT;
R8_ADC_CFG = RB_ADC_POWER_ON | RB_ADC_BUF_EN | (0 << 4); // 使用-12dB模式
}
/*********************************************************************
* @fn TouchKey_ChSampInit
*
* @brief 触摸按键通道采样初始化
*
* @param none
*
* @return none
*/
void TouchKey_ChSampInit(void)
{
R8_ADC_CFG = RB_ADC_POWER_ON | RB_ADC_BUF_EN | (2 << 4);
R8_TKEY_CFG |= RB_TKEY_PWR_ON;
}
/*********************************************************************
* @fn ADC_ExcutSingleConver
*
* @brief ADC执行单次转换
*
* @param none
*
* @return ADC转换后的数据
*/
uint16_t ADC_ExcutSingleConver(void)
{
R8_ADC_CONVERT = RB_ADC_START;
while(R8_ADC_CONVERT & RB_ADC_START);
return (R16_ADC_DATA & RB_ADC_DATA);
}
/*********************************************************************
* @fn TouchKey_ExcutSingleConver
*
* @brief TouchKey转换后数据
*
* @param charg - Touchkey充电时间,5bits有效, t=charg*Tadc
* @param disch - Touchkey放电时间,3bits有效, t=disch*Tadc
*
* @return 当前TouchKey等效数据
*/
uint16_t TouchKey_ExcutSingleConver(uint8_t charg, uint8_t disch)
{
R8_TKEY_COUNT = (disch << 5) | (charg & 0x1f);
R8_TKEY_CONVERT = RB_TKEY_START;
while(R8_TKEY_CONVERT & RB_TKEY_START);
return (R16_ADC_DATA & RB_ADC_DATA);
}
/*********************************************************************
* @fn ADC_AutoConverCycle
*
* @brief 设置连续 ADC的周期
*
* @param cycle - 采样周期计算方法为(256-cycle)*16*Tsys
*
* @return none
*/
void ADC_AutoConverCycle(uint8_t cycle)
{
R8_ADC_AUTO_CYCLE = cycle;
}
/*********************************************************************
* @fn ADC_DMACfg
*
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*
* @return none
*/
void ADC_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, ADC_DMAModeTypeDef m)
{
if(s == DISABLE)
{
R8_ADC_CTRL_DMA &= ~(RB_ADC_DMA_ENABLE | RB_ADC_IE_DMA_END);
}
else
{
R16_ADC_DMA_BEG = startAddr;
R16_ADC_DMA_END = endAddr;
if(m)
{
R8_ADC_CTRL_DMA |= RB_ADC_DMA_LOOP | RB_ADC_IE_DMA_END | RB_ADC_DMA_ENABLE;
}
else
{
R8_ADC_CTRL_DMA &= ~RB_ADC_DMA_LOOP;
R8_ADC_CTRL_DMA |= RB_ADC_IE_DMA_END | RB_ADC_DMA_ENABLE;
}
}
}
/*********************************************************************
* @fn adc_to_temperature_celsius
*
* @brief Convert ADC value to temperature(Celsius)
*
* @param adc_val - adc value
*
* @return temperature (Celsius)
*/
int adc_to_temperature_celsius(uint16_t adc_val)
{
uint32_t C25 = 0;
int temp;
C25 = (*((PUINT32)ROM_CFG_TMP_25C));
/* current temperature = standard temperature + (adc deviation * adc linearity coefficient) */
temp = (((C25 >> 16) & 0xFFFF) ? ((C25 >> 16) & 0xFFFF) : 25) + \
(adc_val - ((int)(C25 & 0xFFFF))) * 10 / 27;
return (temp);
}

View File

@@ -0,0 +1,477 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_clk.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn LClk32K_Select
*
* @brief 32K 低频时钟来源
*
* @param hc - 选择32K使用内部还是外部
*
* @return none
*/
void LClk32K_Select(LClk32KTypeDef hc)
{
uint8_t cfg = R8_CK32K_CONFIG;
if(hc == Clk32K_LSI)
{
cfg &= ~RB_CLK_OSC32K_XT;
}
else
{
cfg |= RB_CLK_OSC32K_XT;
}
sys_safe_access_enable();
R8_CK32K_CONFIG = cfg;
sys_safe_access_disable();
}
/*********************************************************************
* @fn HSECFG_Current
*
* @brief HSE晶体 偏置电流配置
*
* @param c - 75%,100%,125%,150%
*
* @return none
*/
void HSECFG_Current(HSECurrentTypeDef c)
{
uint8_t x32M_c;
x32M_c = R8_XT32M_TUNE;
x32M_c = (x32M_c & 0xfc) | (c & 0x03);
sys_safe_access_enable();
R8_XT32M_TUNE = x32M_c;
sys_safe_access_disable();
}
/*********************************************************************
* @fn HSECFG_Capacitance
*
* @brief HSE晶体 负载电容配置
*
* @param c - refer to HSECapTypeDef
*
* @return none
*/
void HSECFG_Capacitance(HSECapTypeDef c)
{
uint8_t x32M_c;
x32M_c = R8_XT32M_TUNE;
x32M_c = (x32M_c & 0x8f) | (c << 4);
sys_safe_access_enable();
R8_XT32M_TUNE = x32M_c;
sys_safe_access_disable();
}
/*********************************************************************
* @fn LSECFG_Current
*
* @brief LSE晶体 偏置电流配置
*
* @param c - 70%,100%,140%,200%
*
* @return none
*/
void LSECFG_Current(LSECurrentTypeDef c)
{
uint8_t x32K_c;
x32K_c = R8_XT32K_TUNE;
x32K_c = (x32K_c & 0xfc) | (c & 0x03);
sys_safe_access_enable();
R8_XT32K_TUNE = x32K_c;
sys_safe_access_disable();
}
/*********************************************************************
* @fn LSECFG_Capacitance
*
* @brief LSE晶体 负载电容配置
*
* @param c - refer to LSECapTypeDef
*
* @return none
*/
void LSECFG_Capacitance(LSECapTypeDef c)
{
uint8_t x32K_c;
x32K_c = R8_XT32K_TUNE;
x32K_c = (x32K_c & 0x0f) | (c << 4);
sys_safe_access_enable();
R8_XT32K_TUNE = x32K_c;
sys_safe_access_disable();
}
/*********************************************************************
* @fn Calibration_LSI
*
* @brief 校准内部32K时钟
*
* @param cali_Lv - 校准等级选择 Level_32 - 用时 1.2ms 1000ppm (32M 主频) 1100ppm (60M 主频)
* Level_64 - 用时 2.2ms 800ppm (32M 主频) 1000ppm (60M 主频)
* Level_128 - 用时 4.2ms 600ppm (32M 主频) 800ppm (60M 主频)
*
* @return none
*/
void Calibration_LSI(Cali_LevelTypeDef cali_Lv)
{
UINT32 i;
INT32 cnt_offset;
UINT8 retry = 0;
INT32 freq_sys;
freq_sys = GetSysClock();
sys_safe_access_enable();
R8_CK32K_CONFIG |= RB_CLK_OSC32K_FILT;
R8_CK32K_CONFIG &= ~RB_CLK_OSC32K_FILT;
sys_safe_access_enable();
R8_XT32K_TUNE &= ~3;
R8_XT32K_TUNE |= 1;
// 粗调
sys_safe_access_enable();
R8_OSC_CAL_CTRL &= ~RB_OSC_CNT_TOTAL;
R8_OSC_CAL_CTRL |= 1;
sys_safe_access_enable();
R8_OSC_CAL_CTRL |= RB_OSC_CNT_EN;
R16_OSC_CAL_CNT |= RB_OSC_CAL_OV_CLR;
while( (R8_OSC_CAL_CTRL &RB_OSC_CNT_EN) == 0 )
{
sys_safe_access_enable();
R8_OSC_CAL_CTRL |= RB_OSC_CNT_EN;
}
while(1)
{
while(!(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT));
i = R16_OSC_CAL_CNT; // 用于丢弃
while(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT);
R16_OSC_CAL_CNT |= RB_OSC_CAL_OV_CLR;
while(!(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT));
i = R16_OSC_CAL_CNT; // 实时校准后采样值
cnt_offset = (i & 0x3FFF) + R8_OSC_CAL_OV_CNT * 0x3FFF - 2000 * (freq_sys / 1000) / CAB_LSIFQ;
if(((cnt_offset > -37 * (freq_sys / 1000) / CAB_LSIFQ) && (cnt_offset < 37 * (freq_sys / 1000) / CAB_LSIFQ)) || retry > 2)
{
if(retry)
break;
}
retry++;
cnt_offset = (cnt_offset > 0) ? (((cnt_offset * 2) / (74 * (freq_sys/1000) / 60000)) + 1) / 2 : (((cnt_offset * 2) / (74 * (freq_sys/1000) / 60000 )) - 1) / 2;
sys_safe_access_enable();
R16_INT32K_TUNE += cnt_offset;
}
// 细调
// 配置细调参数后丢弃2次捕获值软件行为上判断已有一次这里只留一次
while(!(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT));
i = R16_OSC_CAL_CNT; // 用于丢弃
R16_OSC_CAL_CNT |= RB_OSC_CAL_OV_CLR;
sys_safe_access_enable();
R8_OSC_CAL_CTRL &= ~RB_OSC_CNT_TOTAL;
R8_OSC_CAL_CTRL |= cali_Lv;
while( (R8_OSC_CAL_CTRL&0x07) != cali_Lv )
{
sys_safe_access_enable();
R8_OSC_CAL_CTRL |= cali_Lv;
}
while(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT);
while(!(R8_OSC_CAL_CTRL & RB_OSC_CNT_HALT));
i = R16_OSC_CAL_CNT; // 实时校准后采样值
cnt_offset = (i & 0x3FFF) + R8_OSC_CAL_OV_CNT * 0x3FFF - 4000 * (1 << cali_Lv) * (freq_sys / 1000000) / 256 * 1000/(CAB_LSIFQ/256) ;
cnt_offset = (cnt_offset > 0) ? ((((cnt_offset * 2*(100 )) / (1366 * ((1 << cali_Lv)/8) * (freq_sys/1000) / 60000)) + 1) / 2)<<5 : ((((cnt_offset * 2*(100)) / (1366 * ((1 << cali_Lv)/8) * (freq_sys/1000) / 60000)) - 1) / 2)<<5;
sys_safe_access_enable();
R16_INT32K_TUNE += cnt_offset;
R8_OSC_CAL_CTRL &= ~RB_OSC_CNT_EN;
}
/*********************************************************************
* @fn RTCInitTime
*
* @brief RTC时钟初始化当前时间
*
* @param y - 配置年MAX_Y = BEGYEAR + 44
* @param mon - 配置月MAX_MON = 12
* @param d - 配置日MAX_D = 31
* @param h - 配置小时MAX_H = 23
* @param m - 配置分钟MAX_M = 59
* @param s - 配置秒MAX_S = 59
*
* @return none
*/
void RTC_InitTime(uint16_t y, uint16_t mon, uint16_t d, uint16_t h, uint16_t m, uint16_t s)
{
uint32_t t;
uint16_t year, month, day, sec2, t32k;
volatile uint8_t clk_pin;
year = y;
month = mon;
day = 0;
while(year > BEGYEAR)
{
day += YearLength(year - 1);
year--;
}
while(month > 1)
{
day += monthLength(IsLeapYear(y), month - 2);
month--;
}
day += d - 1;
sec2 = (h % 24) * 1800 + m * 30 + s / 2;
t32k = (s & 1) ? (0x8000) : (0);
t = sec2;
t = t << 16 | t32k;
do
{
clk_pin = (R8_CK32K_CONFIG & RB_32K_CLK_PIN);
} while(clk_pin != (R8_CK32K_CONFIG & RB_32K_CLK_PIN));
if(!clk_pin)
{
while(!clk_pin)
{
do
{
clk_pin = (R8_CK32K_CONFIG & RB_32K_CLK_PIN);
} while(clk_pin != (R8_CK32K_CONFIG & RB_32K_CLK_PIN));
}
}
sys_safe_access_enable();
R32_RTC_TRIG = day;
R8_RTC_MODE_CTRL |= RB_RTC_LOAD_HI;
while((R32_RTC_TRIG & 0x3FFF) != (R32_RTC_CNT_DAY & 0x3FFF));
sys_safe_access_enable();
R32_RTC_TRIG = t;
R8_RTC_MODE_CTRL |= RB_RTC_LOAD_LO;
sys_safe_access_disable();
}
/*********************************************************************
* @fn RTC_GetTime
*
* @brief 获取当前时间
*
* @param py - 获取到的年MAX_Y = BEGYEAR + 44
* @param pmon - 获取到的月MAX_MON = 12
* @param pd - 获取到的日MAX_D = 31
* @param ph - 获取到的小时MAX_H = 23
* @param pm - 获取到的分钟MAX_M = 59
* @param ps - 获取到的秒MAX_S = 59
*
* @return none
*/
void RTC_GetTime(uint16_t *py, uint16_t *pmon, uint16_t *pd, uint16_t *ph, uint16_t *pm, uint16_t *ps)
{
uint32_t t;
uint16_t day, sec2, t32k;
day = R32_RTC_CNT_DAY & 0x3FFF;
sec2 = R16_RTC_CNT_2S;
t32k = R16_RTC_CNT_32K;
t = sec2 * 2 + ((t32k < 0x8000) ? 0 : 1);
*py = BEGYEAR;
while(day >= YearLength(*py))
{
day -= YearLength(*py);
(*py)++;
}
*pmon = 0;
while(day >= monthLength(IsLeapYear(*py), *pmon))
{
day -= monthLength(IsLeapYear(*py), *pmon);
(*pmon)++;
}
(*pmon)++;
*pd = day + 1;
*ph = t / 3600;
*pm = t % 3600 / 60;
*ps = t % 60;
}
/*********************************************************************
* @fn RTC_SetCycle32k
*
* @brief 基于LSE/LSI时钟配置当前RTC 周期数
*
* @param cyc - 配置周期计数初值MAX_CYC = 0xA8BFFFFF = 2831155199
*
* @return none
*/
void RTC_SetCycle32k(uint32_t cyc)
{
volatile uint8_t clk_pin;
do
{
clk_pin = (R8_CK32K_CONFIG & RB_32K_CLK_PIN);
} while((clk_pin != (R8_CK32K_CONFIG & RB_32K_CLK_PIN)) || (!clk_pin));
sys_safe_access_enable();
R32_RTC_TRIG = cyc;
R8_RTC_MODE_CTRL |= RB_RTC_LOAD_LO;
sys_safe_access_disable();
}
/*********************************************************************
* @fn RTC_GetCycle32k
*
* @brief 基于LSE/LSI时钟获取当前RTC 周期数
*
* @param none
*
* @return 当前周期数MAX_CYC = 0xA8BFFFFF = 2831155199
*/
uint32_t RTC_GetCycle32k(void)
{
volatile uint32_t i;
do
{
i = R32_RTC_CNT_32K;
} while(i != R32_RTC_CNT_32K);
return (i);
}
/*********************************************************************
* @fn RTC_TMRFunCfg
*
* @brief RTC定时模式配置注意定时基准固定为32768Hz
*
* @param t - refer to RTC_TMRCycTypeDef
*
* @return none
*/
void RTC_TMRFunCfg(RTC_TMRCycTypeDef t)
{
sys_safe_access_enable();
R8_RTC_MODE_CTRL &= ~(RB_RTC_TMR_EN | RB_RTC_TMR_MODE);
sys_safe_access_enable();
R8_RTC_MODE_CTRL |= RB_RTC_TMR_EN | (t);
sys_safe_access_disable();
}
/*********************************************************************
* @fn RTC_TRIGFunCfg
*
* @brief RTC时间触发模式配置
*
* @param cyc - 相对当前时间的触发间隔时间基于LSE/LSI时钟周期数
*
* @return none
*/
void RTC_TRIGFunCfg(uint32_t cyc)
{
uint32_t t;
t = RTC_GetCycle32k() + cyc;
if(t > 0xA8C00000)
{
t -= 0xA8C00000;
}
sys_safe_access_enable();
R32_RTC_TRIG = t;
R8_RTC_MODE_CTRL |= RB_RTC_TRIG_EN;
sys_safe_access_disable();
}
/*********************************************************************
* @fn RTC_ModeFunDisable
*
* @brief RTC 模式功能关闭
*
* @param m - 需要关闭的当前模式
*
* @return none
*/
void RTC_ModeFunDisable(RTC_MODETypeDef m)
{
uint8_t i = 0;
if(m == RTC_TRIG_MODE)
{
i |= RB_RTC_TRIG_EN;
}
else if(m == RTC_TMR_MODE)
{
i |= RB_RTC_TMR_EN;
}
sys_safe_access_enable();
R8_RTC_MODE_CTRL &= ~(i);
sys_safe_access_disable();
}
/*********************************************************************
* @fn RTC_GetITFlag
*
* @brief 获取RTC中断标志
*
* @param f - refer to RTC_EVENTTypeDef
*
* @return 中断标志状态
*/
uint8_t RTC_GetITFlag(RTC_EVENTTypeDef f)
{
if(f == RTC_TRIG_EVENT)
{
return (R8_RTC_FLAG_CTRL & RB_RTC_TRIG_FLAG);
}
else
{
return (R8_RTC_FLAG_CTRL & RB_RTC_TMR_FLAG);
}
}
/*********************************************************************
* @fn RTC_ClearITFlag
*
* @brief 清除RTC中断标志
*
* @param f - refer to RTC_EVENTTypeDef
*
* @return none
*/
void RTC_ClearITFlag(RTC_EVENTTypeDef f)
{
switch(f)
{
case RTC_TRIG_EVENT:
R8_RTC_FLAG_CTRL = RB_RTC_TRIG_CLR;
break;
case RTC_TMR_EVENT:
R8_RTC_FLAG_CTRL = RB_RTC_TMR_CLR;
break;
default:
break;
}
}

View File

@@ -0,0 +1,166 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_flash.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/* RESET_EN */
#define RESET_Enable 0x00000008
#define RESET_Disable 0xFFFFFFF7
/* LOCKUP_RST_EN */
#define UART_NO_KEY_Enable 0x00000100
#define UART_NO_KEY_Disable 0xFFFFFEFF
/* BOOT_PIN */
#define BOOT_PIN_PB22 0x00000200
#define BOOT_PIN_PB11 0xFFFFFDFF
/* FLASH_WRProt */
#define FLASH_WRProt 0xFFF003FF
/*********************************************************************
* @fn FLASH_ROM_READ
*
* @brief Read Flash
*
* @param StartAddr - read address
* @param Buffer - read buffer
* @param len - read len
*
* @return none
*/
void FLASH_ROM_READ(uint32_t StartAddr, void *Buffer, uint32_t len)
{
uint32_t i, Length = (len + 3) >> 2;
uint32_t *pCode = (uint32_t *)StartAddr;
uint32_t *pBuf = (uint32_t *)Buffer;
for(i = 0; i < Length; i++)
{
*pBuf++ = *pCode++;
}
}
/*********************************************************************
* @fn UserOptionByteConfig
*
* @brief Configure User Option Byte.需在调用用户配置字生效函数后生效,且每次烧录后只能修改一次
* (使用该函数,必须使用官方提供的.S文件同时调用该函数后两次上电后两线调试接口默认关闭)
*
* @param RESET_EN - 外部复位引脚使能
* @param BOOT_PIN - ENABLE-使用默认boot脚-PB22,DISABLE-使用boot脚-PB11
* @param UART_NO_KEY_EN - 串口免按键下载使能
* @param FLASHProt_Size - 写保护大小(单位4K)
*
* @return 0-Success, 1-Err
*/
uint8_t UserOptionByteConfig(FunctionalState RESET_EN, FunctionalState BOOT_PIN, FunctionalState UART_NO_KEY_EN,
uint32_t FLASHProt_Size)
{
uint32_t s, t;
FLASH_ROM_READ(0x14, &s, 4);
if(s == 0xF5F9BDA9)
{
s = 0;
FLASH_EEPROM_CMD(CMD_GET_ROM_INFO, 0x7EFFC, &s, 4);
s &= 0xFF;
if(RESET_EN == ENABLE)
s |= RESET_Enable;
else
s &= RESET_Disable;
/* bit[7:0]-bit[31-24] */
s |= ((~(s << 24)) & 0xFF000000); //高8位 配置信息取反;
if(BOOT_PIN == ENABLE)
s |= BOOT_PIN_PB22;
if(UART_NO_KEY_EN == ENABLE)
s |= UART_NO_KEY_Enable;
/* bit[23-10] */
s &= 0xFF0003FF;
s |= ((FLASHProt_Size << 10) | (5 << 20)) & 0x00FFFC00;
/*Write user option byte*/
FLASH_ROM_WRITE(0x14, &s, 4);
/* Verify user option byte */
FLASH_ROM_READ(0x14, &t, 4);
if(s == t)
return 0;
else
return 1;
}
return 1;
}
/*********************************************************************
* @fn UserOptionByteClose_SWD
*
* @brief 关两线调试接口,其余配置值保持不变.需在调用用户配置字生效函数后生效,且每次烧录后只能修改一次
* (使用该函数,必须使用官方提供的.S文件同时调用该函数后两次上电后两线调试接口默认关闭)
*
* @return 0-Success, 1-Err
*/
uint8_t UserOptionByteClose_SWD(void)
{
uint32_t s, t;
FLASH_ROM_READ(0x14, &s, 4);
if(s == 0xF5F9BDA9)
{
FLASH_EEPROM_CMD(CMD_GET_ROM_INFO, 0x7EFFC, &s, 4);
s &= ~((1 << 4) | (1 << 7)); //禁用调试功能, 禁用SPI读写FLASH
/* bit[7:0]-bit[31-24] */
s &= 0x00FFFFFF;
s |= ((~(s << 24)) & 0xFF000000); //高8位 配置信息取反;
/*Write user option byte*/
FLASH_ROM_WRITE(0x14, &s, 4);
/* Verify user option byte */
FLASH_ROM_READ(0x14, &t, 4);
if(s == t)
return 0;
else
return 1;
}
return 1;
}
/*********************************************************************
* @fn UserOptionByte_Active
*
* @brief 用户配置字生效函数,执行后自动复位
*
* @return 0-Success, 1-Err
*/
void UserOptionByte_Active(void)
{
FLASH_ROM_SW_RESET();
sys_safe_access_enable();
R16_INT32K_TUNE = 0xFFFF;
sys_safe_access_enable();
R8_RST_WDOG_CTRL |= RB_SOFTWARE_RESET;
sys_safe_access_disable();
while(1);
}

View File

@@ -0,0 +1,263 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_gpio.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn GPIOA_ModeCfg
*
* @brief GPIOA端口引脚模式配置
*
* @param pin - PA0-PA15
* @param mode - 输入输出类型
*
* @return none
*/
void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
{
switch(mode)
{
case GPIO_ModeIN_Floating:
R32_PA_PD_DRV &= ~pin;
R32_PA_PU &= ~pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeIN_PU:
R32_PA_PD_DRV &= ~pin;
R32_PA_PU |= pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeIN_PD:
R32_PA_PD_DRV |= pin;
R32_PA_PU &= ~pin;
R32_PA_DIR &= ~pin;
break;
case GPIO_ModeOut_PP_5mA:
R32_PA_PD_DRV &= ~pin;
R32_PA_DIR |= pin;
break;
case GPIO_ModeOut_PP_20mA:
R32_PA_PD_DRV |= pin;
R32_PA_DIR |= pin;
break;
default:
break;
}
}
/*********************************************************************
* @fn GPIOB_ModeCfg
*
* @brief GPIOB端口引脚模式配置
*
* @param pin - PB0-PB23
* @param mode - 输入输出类型
*
* @return none
*/
void GPIOB_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
{
switch(mode)
{
case GPIO_ModeIN_Floating:
R32_PB_PD_DRV &= ~pin;
R32_PB_PU &= ~pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeIN_PU:
R32_PB_PD_DRV &= ~pin;
R32_PB_PU |= pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeIN_PD:
R32_PB_PD_DRV |= pin;
R32_PB_PU &= ~pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeOut_PP_5mA:
R32_PB_PD_DRV &= ~pin;
R32_PB_DIR |= pin;
break;
case GPIO_ModeOut_PP_20mA:
R32_PB_PD_DRV |= pin;
R32_PB_DIR |= pin;
break;
default:
break;
}
}
/*********************************************************************
* @fn GPIOA_ITModeCfg
*
* @brief GPIOA引脚中断模式配置
*
* @param pin - PA0-PA15
* @param mode - 触发类型
*
* @return none
*/
void GPIOA_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode)
{
switch(mode)
{
case GPIO_ITMode_LowLevel: // 低电平触发
R16_PA_INT_MODE &= ~pin;
R32_PA_CLR |= pin;
break;
case GPIO_ITMode_HighLevel: // 高电平触发
R16_PA_INT_MODE &= ~pin;
R32_PA_OUT |= pin;
break;
case GPIO_ITMode_FallEdge: // 下降沿触发
R16_PA_INT_MODE |= pin;
R32_PA_CLR |= pin;
break;
case GPIO_ITMode_RiseEdge: // 上升沿触发
R16_PA_INT_MODE |= pin;
R32_PA_OUT |= pin;
break;
default:
break;
}
R16_PA_INT_IF = pin;
R16_PA_INT_EN |= pin;
}
/*********************************************************************
* @fn GPIOB_ITModeCfg
*
* @brief GPIOB引脚中断模式配置
*
* @param pin - PB0-PB23
* @param mode - 触发类型
*
* @return none
*/
void GPIOB_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode)
{
uint32_t Pin = pin | ((pin & (GPIO_Pin_22 | GPIO_Pin_23)) >> 14);
switch(mode)
{
case GPIO_ITMode_LowLevel: // 低电平触发
R16_PB_INT_MODE &= ~Pin;
R32_PB_CLR |= pin;
break;
case GPIO_ITMode_HighLevel: // 高电平触发
R16_PB_INT_MODE &= ~Pin;
R32_PB_OUT |= pin;
break;
case GPIO_ITMode_FallEdge: // 下降沿触发
R16_PB_INT_MODE |= Pin;
R32_PB_CLR |= pin;
break;
case GPIO_ITMode_RiseEdge: // 上升沿触发
R16_PB_INT_MODE |= Pin;
R32_PB_OUT |= pin;
break;
default:
break;
}
R16_PB_INT_IF = Pin;
R16_PB_INT_EN |= Pin;
}
/*********************************************************************
* @fn GPIOPinRemap
*
* @brief 外设功能引脚映射
*
* @param s - 是否使能映射
* @param perph - RB_RF_ANT_SW_EN - RF antenna switch control output on PB16/PB17/PB18/PB19/PB20/PB21
* RB_PIN_U0_INV - RXD0/RXD0_/TXD0/TXD0_ invert input/output
* RB_PIN_INTX - INTX: INT24/INT25 PB8/PB9 -> INT24_/INT25_ PB22/PB23
* RB_PIN_MODEM - MODEM: PB1/PB5 -> PB14/PB15
* RB_PIN_I2C - I2C: PB13/PB12 -> PB21/PB20
* RB_PIN_PWMX - PWMX: PA12/PA13/PB4/PB6/PB7 -> PA6/PA7/PB1/PB2/PB3
* RB_PIN_SPI0 - SPI0: PA12/PA13/PA14/PA15 -> PB12/PB13/PB14/PB15
* RB_PIN_UART3 - UART3: PA4/PA5 -> PB20/PB21
* RB_PIN_UART2 - UART2: PA6/PA7 -> PB22/PB23
* RB_PIN_UART1 - UART1: PA8/PA9 -> PB12/PB13
* RB_PIN_UART0 - UART0: PB4/PB7 -> PA15/PA14
* RB_PIN_TMR3 - TMR2: PA9 -> PB23
* RB_PIN_TMR2 - TMR2: PA11 -> PB11
* RB_PIN_TMR1 - TMR1: PA10 -> PB10
* RB_PIN_TMR0 - TMR0: PA9 -> PB23
*
* @return none
*/
void GPIOPinRemap(FunctionalState s, uint16_t perph)
{
if(s)
{
R16_PIN_ALTERNATE |= perph;
}
else
{
R16_PIN_ALTERNATE &= ~perph;
}
}
/*********************************************************************
* @fn GPIOAGPPCfg
*
* @brief 模拟外设GPIO引脚功能控制
*
* @param s - ENABLE - 打开模拟外设功能,关闭数字功能
* DISABLE - 启用数字功能,关闭模拟外设功能
* @param perph - RB_PIN_ADC8_9_IE - ADC/TKEY 9/8通道
* RB_PIN_ADC6_7_IE - ADC/TKEY 7/6通道
* RB_PIN_ADC10_IE - ADC/TKEY 10通道
* RB_PIN_ADC11_IE - ADC/TKEY 11 通道
* RB_PIN_USB2_DP_PU - USB2 U2D+引脚内部上拉电阻
* RB_PIN_USB2_IE - USB2引脚
* RB_PIN_USB_DP_PU - USB UD+引脚内部上拉电阻
* RB_PIN_USB_IE - USB 引脚
* RB_PIN_ADC0_IE - ADC/TKEY 0 通道
* RB_PIN_ADC1_IE - ADC/TKEY 1 通道
* RB_PIN_ADC12_IE - ADC/TKEY 12 通道
* RB_PIN_ADC13_IE - ADC/TKEY 13 通道
* RB_PIN_XT32K_IE - 32KHz晶振LSE引脚
* RB_PIN_ADC2_3_IE - ADC/TKEY 2/3 通道
* RB_PIN_ADC4_5_IE - ADC/TKEY 4/5 通道
*
* @return none
*/
void GPIOAGPPCfg(FunctionalState s, uint16_t perph)
{
if(s)
{
R16_PIN_ANALOG_IE |= perph;
}
else
{
R16_PIN_ANALOG_IE &= ~perph;
}
}

View File

@@ -0,0 +1,672 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_i2c.c
* Author : WCH
* Version : V1.0
* Date : 2021/03/15
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn I2C_Init
*
* @brief Initializes the I2Cx peripheral according to the specified
* parameters in the I2C_InitStruct.
*
* @param I2C_Mode - refer to I2C_ModeTypeDef
* @param I2C_ClockSpeed - Specifies the clock frequency(Hz).
* This parameter must be set to a value lower than 400kHz
* @param I2C_DutyCycle - Specifies the I2C fast mode duty cycle.refer to I2C_DutyTypeDef
* @param I2C_Ack - Enables or disables the acknowledgement.refer to I2C_AckTypeDef
* @param I2C_AckAddr - Specifies if 7-bit or 10-bit address is acknowledged.refer to I2C_AckAddrTypeDef
* @param I2C_OwnAddress1 - Specifies the first device own address.
* This parameter can be a 7-bit or 10-bit address.
*
* @return none
*/
void I2C_Init(I2C_ModeTypeDef I2C_Mode, UINT32 I2C_ClockSpeed, I2C_DutyTypeDef I2C_DutyCycle,
I2C_AckTypeDef I2C_Ack, I2C_AckAddrTypeDef I2C_AckAddr, UINT16 I2C_OwnAddress1)
{
uint32_t sysClock;
uint16_t tmpreg;
I2C_SoftwareResetCmd(ENABLE);
I2C_SoftwareResetCmd(DISABLE);
sysClock = GetSysClock();
R16_I2C_CTRL2 &= ~RB_I2C_FREQ;
R16_I2C_CTRL2 |= (sysClock / 1000000);
R16_I2C_CTRL1 &= ~RB_I2C_PE;
if(I2C_ClockSpeed <= 100000)
{
tmpreg = (sysClock / (I2C_ClockSpeed << 1)) & RB_I2C_CCR;
if(tmpreg < 0x04)
tmpreg = 0x04;
R16_I2C_RTR = (((sysClock / 1000000) + 1) > 0x3F) ? 0x3F : ((sysClock / 1000000) + 1);
}
else
{
if(I2C_DutyCycle == I2C_DutyCycle_2)
{
tmpreg = (sysClock / (I2C_ClockSpeed * 3)) & RB_I2C_CCR;
}
else
{
tmpreg = (sysClock / (I2C_ClockSpeed * 25)) & RB_I2C_CCR;
tmpreg |= I2C_DutyCycle_16_9;
}
if(tmpreg == 0)
{
tmpreg |= (uint16_t)0x0001;
}
tmpreg |= RB_I2C_F_S;
R16_I2C_RTR = (uint16_t)((((sysClock / 1000000) * (uint16_t)300) / (uint16_t)1000) + (uint16_t)1);
}
R16_I2C_CKCFGR = tmpreg;
R16_I2C_CTRL1 |= RB_I2C_PE;
R16_I2C_CTRL1 &= ~(RB_I2C_SMBUS | RB_I2C_SMBTYPE | RB_I2C_ACK);
R16_I2C_CTRL1 |= I2C_Mode | I2C_Ack;
R16_I2C_OADDR1 &= ~0xFFFF;
R16_I2C_OADDR1 |= I2C_AckAddr | I2C_OwnAddress1;
}
/*********************************************************************
* @fn I2C_Cmd
*
* @brief Enables or disables the specified I2C peripheral.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_Cmd(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_PE;
else
R16_I2C_CTRL1 &= ~RB_I2C_PE;
}
/*********************************************************************
* @fn I2C_GenerateSTART
*
* @brief Generates I2Cx communication START condition.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_GenerateSTART(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_START;
else
R16_I2C_CTRL1 &= ~RB_I2C_START;
}
/*********************************************************************
* @fn I2C_GenerateSTOP
*
* @brief Generates I2Cx communication STOP condition.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_GenerateSTOP(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_STOP;
else
R16_I2C_CTRL1 &= ~RB_I2C_STOP;
}
/*********************************************************************
* @fn I2C_AcknowledgeConfig
*
* @brief Enables or disables the specified I2C acknowledge feature.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_AcknowledgeConfig(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_ACK;
else
R16_I2C_CTRL1 &= ~RB_I2C_ACK;
}
/*********************************************************************
* @fn I2C_OwnAddress2Config
*
* @brief Configures the specified I2C own address2.
*
* @param Address - specifies the 7bit I2C own address2.
*
* @return none
*/
void I2C_OwnAddress2Config(uint8_t Address)
{
R16_I2C_OADDR2 &= ~RB_I2C_ADD2;
R16_I2C_OADDR2 |= (uint16_t)(Address & RB_I2C_ADD2);
}
/*********************************************************************
* @fn I2C_DualAddressCmd
*
* @brief Enables or disables the specified I2C dual addressing mode.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_DualAddressCmd(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_OADDR2 |= RB_I2C_ENDUAL;
else
R16_I2C_OADDR2 &= ~RB_I2C_ENDUAL;
}
/*********************************************************************
* @fn I2C_GeneralCallCmd
*
* @brief Enables or disables the specified I2C general call feature.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_GeneralCallCmd(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_ENGC;
else
R16_I2C_CTRL1 &= ~RB_I2C_ENGC;
}
/*********************************************************************
* @fn I2C_ITConfig
*
* @brief Enables or disables the specified I2C interrupts.
*
* @param I2C_IT - specifies the I2C interrupts sources to be enabled or disabled.
* I2C_IT_BUF - Buffer interrupt mask.
* I2C_IT_EVT - Event interrupt mask.
* I2C_IT_ERR - Error interrupt mask.
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_ITConfig(I2C_ITTypeDef I2C_IT, FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL2 |= I2C_IT;
else
R16_I2C_CTRL2 &= (uint16_t)~I2C_IT;
}
/*********************************************************************
* @fn I2C_SendData
*
* @brief Sends a data byte through the I2Cx peripheral.
*
* @param Data - Byte to be transmitted.
*
* @return none
*/
void I2C_SendData(uint8_t Data)
{
R16_I2C_DATAR = Data;
}
/*********************************************************************
* @fn I2C_ReceiveData
*
* @brief Returns the most recent received data by the I2Cx peripheral.
*
* @return The value of the received data.
*/
uint8_t I2C_ReceiveData(void)
{
return (uint8_t)R16_I2C_DATAR;
}
/*********************************************************************
* @fn I2C_Send7bitAddress
*
* @brief Transmits the address byte to select the slave device.
*
* @param Address - specifies the slave address which will be transmitted.
* @param I2C_Direction - specifies whether the I2C device will be a Transmitter or a Receiver.
* I2C_Direction_Transmitter - Transmitter mode.
* I2C_Direction_Receiver - Receiver mode.
*
* @return none
*/
void I2C_Send7bitAddress(uint8_t Address, uint8_t I2C_Direction)
{
if(I2C_Direction != I2C_Direction_Transmitter)
Address |= OADDR1_ADD0_Set;
else
Address &= OADDR1_ADD0_Reset;
R16_I2C_DATAR = Address;
}
/*********************************************************************
* @fn I2C_SoftwareResetCmd
*
* @brief Enables or disables the specified I2C software reset.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_SoftwareResetCmd(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_SWRST;
else
R16_I2C_CTRL1 &= ~RB_I2C_SWRST;
}
/*********************************************************************
* @fn I2C_NACKPositionConfig
*
* @brief Selects the specified I2C NACK position in master receiver mode.
*
* @param I2C_NACKPosition - specifies the NACK position.
* I2C_NACKPosition_Next - indicates that the next byte will be the last received byte.
* I2C_NACKPosition_Current - indicates that current byte is the last received byte.
*
* @return none
*/
void I2C_NACKPositionConfig(uint16_t I2C_NACKPosition)
{
if(I2C_NACKPosition == I2C_NACKPosition_Next)
R16_I2C_CTRL1 |= I2C_NACKPosition_Next;
else
R16_I2C_CTRL1 &= I2C_NACKPosition_Current;
}
/*********************************************************************
* @fn I2C_SMBusAlertConfig
*
* @brief Drives the SMBusAlert pin high or low for the specified I2C.
*
* @param I2C_SMBusAlert - specifies SMBAlert pin level.
* I2C_SMBusAlert_Low - SMBAlert pin driven low.
* I2C_SMBusAlert_High - SMBAlert pin driven high.
*
* @return none
*/
void I2C_SMBusAlertConfig(uint16_t I2C_SMBusAlert)
{
if(I2C_SMBusAlert == I2C_SMBusAlert_Low)
R16_I2C_CTRL1 |= I2C_SMBusAlert_Low;
else
R16_I2C_CTRL1 &= I2C_SMBusAlert_High;
}
/*********************************************************************
* @fn I2C_TransmitPEC
*
* @brief Enables or disables the specified I2C PEC transfer.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_TransmitPEC(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_PEC;
else
R16_I2C_CTRL1 &= ~RB_I2C_PEC;
}
/*********************************************************************
* @fn I2C_PECPositionConfig
*
* @brief Selects the specified I2C PEC position.
*
* @param I2C_PECPosition - specifies the PEC position.
* I2C_PECPosition_Next - indicates that the next byte is PEC.
* I2C_PECPosition_Current - indicates that current byte is PEC.
*
* @return none
*/
void I2C_PECPositionConfig(uint16_t I2C_PECPosition)
{
if(I2C_PECPosition == I2C_PECPosition_Next)
R16_I2C_CTRL1 |= I2C_PECPosition_Next;
else
R16_I2C_CTRL1 &= I2C_PECPosition_Current;
}
/*********************************************************************
* @fn I2C_CalculatePEC
*
* @brief Enables or disables the PEC value calculation of the transferred bytes.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_CalculatePEC(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_ENPEC;
else
R16_I2C_CTRL1 &= ~RB_I2C_ENPEC;
}
/*********************************************************************
* @fn I2C_GetPEC
*
* @brief Returns the PEC value for the specified I2C.
*
* @return The PEC value.
*/
uint8_t I2C_GetPEC(void)
{
return (R16_I2C_STAR2 >> 8);
}
/*********************************************************************
* @fn I2C_ARPCmd
*
* @brief Enables or disables the specified I2C ARP.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_ARPCmd(FunctionalState NewState)
{
if(NewState != DISABLE)
R16_I2C_CTRL1 |= RB_I2C_EBARP;
else
R16_I2C_CTRL1 &= ~RB_I2C_EBARP;
}
/*********************************************************************
* @fn I2C_StretchClockCmd
*
* @brief Enables or disables the specified I2C Clock stretching.
*
* @param NewState - ENABLE or DISABLE.
*
* @return none
*/
void I2C_StretchClockCmd(FunctionalState NewState)
{
if(NewState == DISABLE)
R16_I2C_CTRL1 |= RB_I2C_NOSTRETCH;
else
R16_I2C_CTRL1 &= ~RB_I2C_NOSTRETCH;
}
/*********************************************************************
* @fn I2C_FastModeDutyCycleConfig
*
* @brief Selects the specified I2C fast mode duty cycle.
*
* @param I2C_DutyCycle - specifies the fast mode duty cycle.
* I2C_DutyCycle_2 - I2C fast mode Tlow/Thigh = 2.
* I2C_DutyCycle_16_9 - I2C fast mode Tlow/Thigh = 16/9.
*
* @return none
*/
void I2C_FastModeDutyCycleConfig(uint16_t I2C_DutyCycle)
{
if(I2C_DutyCycle != I2C_DutyCycle_16_9)
R16_I2C_CKCFGR &= ~I2C_DutyCycle_16_9;
else
R16_I2C_CKCFGR |= I2C_DutyCycle_16_9;
}
/*********************************************************************
* @fn I2C_CheckEvent
*
* @brief Checks whether the last I2Cx Event is equal to the one passed as parameter.
*
* @param I2C_EVENT - specifies the event to be checked.
* I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED : EV1.
* I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED : EV1.
* I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED : EV1.
* I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED : EV1.
* I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED : EV1.
* I2C_EVENT_SLAVE_BYTE_RECEIVED : EV2.
* (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_DUALF) : EV2.
* (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_GENCALL) : EV2.
* I2C_EVENT_SLAVE_BYTE_TRANSMITTED : EV3.
* (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_DUALF) : EV3.
* (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | I2C_FLAG_GENCALL) : EV3.
* I2C_EVENT_SLAVE_ACK_FAILURE : EV3_2.
* I2C_EVENT_SLAVE_STOP_DETECTED : EV4.
* I2C_EVENT_MASTER_MODE_SELECT : EV5.
* I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED : EV6.
* I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED : EV6.
* I2C_EVENT_MASTER_BYTE_RECEIVED : EV7.
* I2C_EVENT_MASTER_BYTE_TRANSMITTING : EV8.
* I2C_EVENT_MASTER_BYTE_TRANSMITTED : EV8_2.
* I2C_EVENT_MASTER_MODE_ADDRESS10 : EV9.
*
* @return 1 - SUCCESS or 0 - ERROR.
*/
uint8_t I2C_CheckEvent(uint32_t I2C_EVENT)
{
uint32_t lastevent = 0;
uint32_t flag1 = 0, flag2 = 0;
uint8_t status = 0;
flag1 = R16_I2C_STAR1;
flag2 = R16_I2C_STAR2;
flag2 = flag2 << 16;
lastevent = (flag1 | flag2) & FLAG_Mask;
if((lastevent & I2C_EVENT) == I2C_EVENT)
{
status = !0;
}
else
{
status = 0;
}
return status;
}
/*********************************************************************
* @fn I2C_GetLastEvent
*
* @brief Returns the last I2Cx Event.
*
* @return The last event.
*/
uint32_t I2C_GetLastEvent(void)
{
uint32_t lastevent = 0;
uint32_t flag1 = 0, flag2 = 0;
flag1 = R16_I2C_STAR1;
flag2 = R16_I2C_STAR2;
flag2 = flag2 << 16;
lastevent = (flag1 | flag2) & FLAG_Mask;
return lastevent;
}
/*********************************************************************
* @fn I2C_GetFlagStatus
*
* @brief Checks whether the last I2Cx Event is equal to the one passed as parameter.
*
* @param I2C_FLAG - specifies the flag to check.
* I2C_FLAG_DUALF - Dual flag (Slave mode).
* I2C_FLAG_SMBHOST - SMBus host header (Slave mode).
* I2C_FLAG_SMBDEFAULT - SMBus default header (Slave mode).
* I2C_FLAG_GENCALL - General call header flag (Slave mode).
* I2C_FLAG_TRA - Transmitter/Receiver flag.
* I2C_FLAG_BUSY - Bus busy flag.
* I2C_FLAG_MSL - Master/Slave flag.
* I2C_FLAG_SMBALERT - SMBus Alert flag.
* I2C_FLAG_TIMEOUT - Timeout or Tlow error flag.
* I2C_FLAG_PECERR - PEC error in reception flag.
* I2C_FLAG_OVR - Overrun/Underrun flag (Slave mode).
* I2C_FLAG_AF - Acknowledge failure flag.
* I2C_FLAG_ARLO - Arbitration lost flag (Master mode).
* I2C_FLAG_BERR - Bus error flag.
* I2C_FLAG_TXE - Data register empty flag (Transmitter).
* I2C_FLAG_RXNE - Data register not empty (Receiver) flag.
* I2C_FLAG_STOPF - Stop detection flag (Slave mode).
* I2C_FLAG_ADD10 - 10-bit header sent flag (Master mode).
* I2C_FLAG_BTF - Byte transfer finished flag.
* I2C_FLAG_ADDR - Address sent flag (Master mode) "ADSL"
* Address matched flag (Slave mode)"ENDA".
* I2C_FLAG_SB - Start bit flag (Master mode).
*
* @return FlagStatus - SET or RESET.
*/
FlagStatus I2C_GetFlagStatus(uint32_t I2C_FLAG)
{
FlagStatus bitstatus = RESET;
__IO uint32_t i2creg = 0, i2cxbase = 0;
i2cxbase = (uint32_t)BA_I2C;
i2creg = I2C_FLAG >> 28;
I2C_FLAG &= FLAG_Mask;
if(i2creg != 0)
{
i2cxbase += 0x14;
}
else
{
I2C_FLAG = (uint32_t)(I2C_FLAG >> 16);
i2cxbase += 0x18;
}
if(((*(__IO uint32_t *)i2cxbase) & I2C_FLAG) != (uint32_t)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
/*********************************************************************
* @fn I2C_ClearFlag
*
* @brief Clears the I2Cx's pending flags.
*
* @param I2C_FLAG - specifies the flag to clear.
* I2C_FLAG_SMBALERT - SMBus Alert flag.
* I2C_FLAG_TIMEOUT - Timeout or Tlow error flag.
* I2C_FLAG_PECERR - PEC error in reception flag.
* I2C_FLAG_OVR - Overrun/Underrun flag (Slave mode).
* I2C_FLAG_AF - Acknowledge failure flag.
* I2C_FLAG_ARLO - Arbitration lost flag (Master mode).
* I2C_FLAG_BERR - Bus error flag.
*
* @return none
*/
void I2C_ClearFlag(uint32_t I2C_FLAG)
{
uint32_t flagpos = 0;
flagpos = I2C_FLAG & FLAG_Mask;
R16_I2C_STAR1 = (uint16_t)~flagpos;
}
/*********************************************************************
* @fn I2C_GetITStatus
*
* @brief Checks whether the specified I2C interrupt has occurred or not.
*
* @param II2C_IT - specifies the interrupt source to check.
* I2C_FLAG_SMBALERT - SMBus Alert flag.
* I2C_FLAG_TIMEOUT - Timeout or Tlow error flag.
* I2C_FLAG_PECERR - PEC error in reception flag.
* I2C_FLAG_OVR - Overrun/Underrun flag (Slave mode).
* I2C_FLAG_AF - Acknowledge failure flag.
* I2C_FLAG_ARLO - Arbitration lost flag (Master mode).
* I2C_FLAG_BERR - Bus error flag.
* I2C_FLAG_TXE - Data register empty flag (Transmitter).
* I2C_FLAG_RXNE - Data register not empty (Receiver) flag.
* I2C_FLAG_STOPF - Stop detection flag (Slave mode).
* I2C_FLAG_ADD10 - 10-bit header sent flag (Master mode).
* I2C_FLAG_BTF - Byte transfer finished flag.
* I2C_FLAG_ADDR - Address sent flag (Master mode) "ADSL"
* Address matched flag (Slave mode)"ENDA".
* I2C_FLAG_SB - Start bit flag (Master mode).
*
* @return none
*/
ITStatus I2C_GetITStatus(uint32_t I2C_IT)
{
ITStatus bitstatus = RESET;
uint32_t enablestatus = 0;
enablestatus = (uint32_t)(((I2C_IT & ITEN_Mask) >> 16) & (R16_I2C_CTRL2));
I2C_IT &= FLAG_Mask;
if(((R16_I2C_STAR1 & I2C_IT) != (uint32_t)RESET) && enablestatus)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
/*********************************************************************
* @fn I2C_ClearITPendingBit
*
* @brief Clears the I2Cx interrupt pending bits.
*
* @param I2C_IT - specifies the interrupt pending bit to clear.
* I2C_IT_SMBALERT - SMBus Alert interrupt.
* I2C_IT_TIMEOUT - Timeout or Tlow error interrupt.
* I2C_IT_PECERR - PEC error in reception interrupt.
* I2C_IT_OVR - Overrun/Underrun interrupt (Slave mode).
* I2C_IT_AF - Acknowledge failure interrupt.
* I2C_IT_ARLO - Arbitration lost interrupt (Master mode).
* I2C_IT_BERR - Bus error interrupt.
*
* @return none
*/
void I2C_ClearITPendingBit(uint32_t I2C_IT)
{
uint32_t flagpos = 0;
flagpos = I2C_IT & FLAG_Mask;
R16_I2C_STAR1 = (uint16_t)~flagpos;
}

View File

@@ -0,0 +1,123 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_pwm.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn PWMX_CycleCfg
*
* @brief PWM4-PWM11基准时钟配置
*
* @param cyc - refer to PWMX_CycleTypeDef
*
* @return none
*/
void PWMX_CycleCfg(PWMX_CycleTypeDef cyc)
{
switch(cyc)
{
case PWMX_Cycle_256:
R8_PWM_CONFIG = R8_PWM_CONFIG & 0xf0;
break;
case PWMX_Cycle_255:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | 0x01;
break;
case PWMX_Cycle_128:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (1 << 2);
break;
case PWMX_Cycle_127:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (1 << 2) | 0x01;
break;
case PWMX_Cycle_64:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (2 << 2);
break;
case PWMX_Cycle_63:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (2 << 2) | 0x01;
break;
case PWMX_Cycle_32:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (3 << 2);
break;
case PWMX_Cycle_31:
R8_PWM_CONFIG = (R8_PWM_CONFIG & 0xf0) | (3 << 2) | 0x01;
break;
default:
break;
}
}
/*********************************************************************
* @fn PWMX_ACTOUT
*
* @brief PWM4-PWM11通道输出波形配置
*
* @param ch - select channel of pwm, refer to channel of PWM define
* @param da - effective pulse width
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param s - control pwmx function, ENABLE or DISABLE
*
* @return none
*/
void PWMX_ACTOUT(uint8_t ch, uint8_t da, PWMX_PolarTypeDef pr, FunctionalState s)
{
uint8_t i;
if(s == DISABLE)
{
R8_PWM_OUT_EN &= ~(ch);
}
else
{
(pr) ? (R8_PWM_POLAR |= (ch)) : (R8_PWM_POLAR &= ~(ch));
for(i = 0; i < 8; i++)
{
if((ch >> i) & 1)
{
*((volatile uint8_t *)((&R8_PWM4_DATA) + i)) = da;
}
}
R8_PWM_OUT_EN |= (ch);
}
}
/*********************************************************************
* @fn PWMX_AlterOutCfg
*
* @brief PWM 交替输出模式配置
*
* @param ch - select group of PWM alternate output
* RB_PWM4_5_STAG_EN - PWM4 和 PWM5 通道交替输出
* RB_PWM6_7_STAG_EN - PWM6 和 PWM7 通道交替输出
* RB_PWM8_9_STAG_EN - PWM8 和 PWM9 通道交替输出
* RB_PWM10_11_STAG_EN - PWM10 和 PWM11 通道交替输出
* @param s - control pwmx function, ENABLE or DISABLE
*
* @return none
*/
void PWMX_AlterOutCfg(uint8_t ch, FunctionalState s)
{
if(s == DISABLE)
{
R8_PWM_CONFIG &= ~(ch);
}
else
{
R8_PWM_CONFIG |= (ch);
}
}

View File

@@ -0,0 +1,384 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_pwr.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn PWR_DCDCCfg
*
* @brief 启用内部DC/DC电源用于节约系统功耗
*
* @param s - 是否打开DCDC电源
*
* @return none
*/
void PWR_DCDCCfg(FunctionalState s)
{
uint16_t adj = R16_AUX_POWER_ADJ;
uint16_t plan = R16_POWER_PLAN;
if(s == DISABLE)
{
adj &= ~RB_DCDC_CHARGE;
plan &= ~(RB_PWR_DCDC_EN | RB_PWR_DCDC_PRE); // 旁路 DC/DC
sys_safe_access_enable();
R16_AUX_POWER_ADJ = adj;
R16_POWER_PLAN = plan;
sys_safe_access_disable();
}
else
{
adj |= RB_DCDC_CHARGE;
plan |= RB_PWR_DCDC_PRE;
sys_safe_access_enable();
R16_AUX_POWER_ADJ = adj;
R16_POWER_PLAN = plan;
DelayUs(10);
sys_safe_access_enable();
R16_POWER_PLAN |= RB_PWR_DCDC_EN;
sys_safe_access_disable();
}
}
/*********************************************************************
* @fn PWR_UnitModCfg
*
* @brief 可控单元模块的电源控制
*
* @param s - 是否打开电源
* @param unit - please refer to unit of controllable power supply
*
* @return none
*/
void PWR_UnitModCfg(FunctionalState s, uint8_t unit)
{
uint8_t pwr_ctrl = R8_HFCK_PWR_CTRL;
uint8_t ck32k_cfg = R8_CK32K_CONFIG;
if(s == DISABLE) //关闭
{
pwr_ctrl &= ~(unit & 0x1c);
ck32k_cfg &= ~(unit & 0x03);
}
else //打开
{
pwr_ctrl |= (unit & 0x1c);
ck32k_cfg |= (unit & 0x03);
}
sys_safe_access_enable();
R8_HFCK_PWR_CTRL = pwr_ctrl;
R8_CK32K_CONFIG = ck32k_cfg;
sys_safe_access_disable();
}
/*********************************************************************
* @fn PWR_PeriphClkCfg
*
* @brief 外设时钟控制位
*
* @param s - 是否打开对应外设时钟
* @param perph - please refer to Peripher CLK control bit define
*
* @return none
*/
void PWR_PeriphClkCfg(FunctionalState s, uint16_t perph)
{
uint32_t sleep_ctrl = R32_SLEEP_CONTROL;
if(s == DISABLE)
{
sleep_ctrl |= perph;
}
else
{
sleep_ctrl &= ~perph;
}
sys_safe_access_enable();
R32_SLEEP_CONTROL = sleep_ctrl;
sys_safe_access_disable();
}
/*********************************************************************
* @fn PWR_PeriphWakeUpCfg
*
* @brief 睡眠唤醒源配置
*
* @param s - 是否打开此外设睡眠唤醒功能
* @param perph - 需要设置的唤醒源
* RB_SLP_USB_WAKE - USB 为唤醒源
* RB_SLP_RTC_WAKE - RTC 为唤醒源
* RB_SLP_GPIO_WAKE - GPIO 为唤醒源
* RB_SLP_BAT_WAKE - BAT 为唤醒源
* @param mode - refer to WakeUP_ModeypeDef
*
* @return none
*/
void PWR_PeriphWakeUpCfg(FunctionalState s, uint8_t perph, WakeUP_ModeypeDef mode)
{
uint8_t m;
if(s == DISABLE)
{
sys_safe_access_enable();
R8_SLP_WAKE_CTRL &= ~perph;
}
else
{
switch(mode)
{
case Short_Delay:
m = 0x01;
break;
case Long_Delay:
m = 0x00;
break;
default:
m = 0x01;
break;
}
sys_safe_access_enable();
R8_SLP_WAKE_CTRL |= RB_WAKE_EV_MODE | perph;
sys_safe_access_enable();
R8_SLP_POWER_CTRL &= ~(RB_WAKE_DLY_MOD);
sys_safe_access_enable();
R8_SLP_POWER_CTRL |= m;
}
sys_safe_access_disable();
}
/*********************************************************************
* @fn PowerMonitor
*
* @brief 电源监控
*
* @param s - 是否打开此功能
* @param vl - refer to VolM_LevelypeDef
*
* @return none
*/
void PowerMonitor(FunctionalState s, VolM_LevelypeDef vl)
{
uint8_t ctrl = R8_BAT_DET_CTRL;
uint8_t cfg = R8_BAT_DET_CFG;
if(s == DISABLE)
{
sys_safe_access_enable();
R8_BAT_DET_CTRL = 0;
sys_safe_access_disable();
}
else
{
if(vl & 0x80)
{
cfg = vl & 0x03;
ctrl = RB_BAT_MON_EN | ((vl >> 2) & 1);
}
else
{
cfg = vl & 0x03;
ctrl = RB_BAT_DET_EN;
}
sys_safe_access_enable();
R8_BAT_DET_CTRL = ctrl;
R8_BAT_DET_CFG = cfg;
sys_safe_access_disable();
mDelayuS(1);
sys_safe_access_enable();
R8_BAT_DET_CTRL |= RB_BAT_LOW_IE | RB_BAT_LOWER_IE;
sys_safe_access_disable();
}
}
/*********************************************************************
* @fn LowPower_Idle
*
* @brief 低功耗-Idle模式
*
* @param none
*
* @return none
*/
__HIGH_CODE
void LowPower_Idle(void)
{
FLASH_ROM_SW_RESET();
R8_FLASH_CTRL = 0x04; //flash关闭
PFIC->SCTLR &= ~(1 << 2); // sleep
__WFI();
__nop();
__nop();
}
/*********************************************************************
* @fn LowPower_Halt
*
* @brief 低功耗-Halt模式此低功耗切到HSI/5时钟运行唤醒后需要用户自己重新选择系统时钟源
*
* @param none
*
* @return none
*/
__HIGH_CODE
void LowPower_Halt(void)
{
uint8_t x32Kpw, x32Mpw;
FLASH_ROM_SW_RESET();
R8_FLASH_CTRL = 0x04; //flash关闭
x32Kpw = R8_XT32K_TUNE;
x32Mpw = R8_XT32M_TUNE;
x32Mpw = (x32Mpw & 0xfc) | 0x03; // 150%额定电流
if(R16_RTC_CNT_32K > 0x3fff)
{ // 超过500ms
x32Kpw = (x32Kpw & 0xfc) | 0x01; // LSE驱动电流降低到额定电流
}
sys_safe_access_enable();
R8_BAT_DET_CTRL = 0; // 关闭电压监控
sys_safe_access_enable();
R8_XT32K_TUNE = x32Kpw;
R8_XT32M_TUNE = x32Mpw;
sys_safe_access_enable();
R8_PLL_CONFIG |= (1 << 5);
sys_safe_access_disable();
PFIC->SCTLR |= (1 << 2); //deep sleep
__WFI();
__nop();
__nop();
sys_safe_access_enable();
R8_PLL_CONFIG &= ~(1 << 5);
sys_safe_access_disable();
}
/*******************************************************************************
* Function Name : LowPower_Sleep
* Description : 低功耗-Sleep模式。
注意当主频为80M时睡眠唤醒中断不可调用flash内代码且退出此函数前需要加上30us延迟。
* Input : rm:
RB_PWR_RAM2K - 2K retention SRAM 供电
RB_PWR_RAM30K - 30K main SRAM 供电
RB_PWR_EXTEND - USB 和 BLE 单元保留区域供电
RB_PWR_XROM - FlashROM 供电
NULL - 以上单元都断电
* Return : None
*******************************************************************************/
__HIGH_CODE
void LowPower_Sleep(uint8_t rm)
{
uint8_t x32Kpw, x32Mpw;
uint16_t power_plan;
x32Kpw = R8_XT32K_TUNE;
x32Mpw = R8_XT32M_TUNE;
x32Mpw = (x32Mpw & 0xfc) | 0x03; // 150%额定电流
if(R16_RTC_CNT_32K > 0x3fff)
{ // 超过500ms
x32Kpw = (x32Kpw & 0xfc) | 0x01; // LSE驱动电流降低到额定电流
}
sys_safe_access_enable();
R8_BAT_DET_CTRL = 0; // 关闭电压监控
sys_safe_access_enable();
R8_XT32K_TUNE = x32Kpw;
R8_XT32M_TUNE = x32Mpw;
sys_safe_access_disable();
PFIC->SCTLR |= (1 << 2); //deep sleep
power_plan = R16_POWER_PLAN & (RB_PWR_DCDC_EN | RB_PWR_DCDC_PRE);
power_plan |= RB_PWR_PLAN_EN | RB_PWR_MUST_0010 | RB_PWR_CORE | rm;
__nop();
sys_safe_access_enable();
R8_SLP_POWER_CTRL |= RB_RAM_RET_LV;
R8_PLL_CONFIG |= (1 << 5);
R16_POWER_PLAN = power_plan;
do{
__WFI();
__nop();
__nop();
DelayUs(70);
uint8_t mac[6] = {0};
GetMACAddress(mac);
if(mac[5] != 0xff)
break;
}while(1);
sys_safe_access_enable();
R8_PLL_CONFIG &= ~(1 << 5);
sys_safe_access_disable();
}
/*********************************************************************
* @fn LowPower_Shutdown
*
* @brief 低功耗-Shutdown模式此低功耗切到HSI/5时钟运行唤醒后需要用户自己重新选择系统时钟源
* @note 注意调用此函数DCDC功能强制关闭唤醒后可以手动再次打开
*
* @param rm - 供电模块选择
* RB_PWR_RAM2K - 2K retention SRAM 供电
* RB_PWR_RAM16K - 16K main SRAM 供电
* NULL - 以上单元都断电
*
* @return none
*/
__HIGH_CODE
void LowPower_Shutdown(uint8_t rm)
{
uint8_t x32Kpw, x32Mpw;
FLASH_ROM_SW_RESET();
x32Kpw = R8_XT32K_TUNE;
x32Mpw = R8_XT32M_TUNE;
x32Mpw = (x32Mpw & 0xfc) | 0x03; // 150%额定电流
if(R16_RTC_CNT_32K > 0x3fff)
{ // 超过500ms
x32Kpw = (x32Kpw & 0xfc) | 0x01; // LSE驱动电流降低到额定电流
}
sys_safe_access_enable();
R8_BAT_DET_CTRL = 0; // 关闭电压监控
sys_safe_access_enable();
R8_XT32K_TUNE = x32Kpw;
R8_XT32M_TUNE = x32Mpw;
sys_safe_access_disable();
SetSysClock(CLK_SOURCE_HSE_6_4MHz);
PFIC->SCTLR |= (1 << 2); //deep sleep
sys_safe_access_enable();
R8_SLP_POWER_CTRL |= RB_RAM_RET_LV;
sys_safe_access_enable();
R16_POWER_PLAN = RB_PWR_PLAN_EN | RB_PWR_MUST_0010 | rm;
__WFI();
__nop();
__nop();
FLASH_ROM_SW_RESET();
sys_safe_access_enable();
R8_RST_WDOG_CTRL |= RB_SOFTWARE_RESET;
sys_safe_access_disable();
}

View File

@@ -0,0 +1,368 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_SPI0.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn SPI0_MasterDefInit
*
* @brief 主机模式默认初始化模式0+3线全双工+8MHz
*
* @param none
*
* @return none
*/
void SPI0_MasterDefInit(void)
{
R8_SPI0_CLOCK_DIV = 4; // 主频时钟4分频
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_SCK_OE;
R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF; // 访问BUFFER/FIFO自动清除IF_BYTE_END标志
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE; // 不启动DMA方式
}
/*********************************************************************
* @fn SPI0_CLKCfg
*
* @brief SPI0 基准时钟配置,= d*Tsys
*
* @param c - 时钟分频系数
*
* @return none
*/
void SPI0_CLKCfg(uint8_t c)
{
if(c == 2)
{
R8_SPI0_CTRL_CFG |= RB_SPI_MST_DLY_EN;
}
else
{
R8_SPI0_CTRL_CFG &= ~RB_SPI_MST_DLY_EN;
}
R8_SPI0_CLOCK_DIV = c;
}
/*********************************************************************
* @fn SPI0_DataMode
*
* @brief 设置数据流模式
*
* @param m - 数据流模式 refer to ModeBitOrderTypeDef
*
* @return none
*/
void SPI0_DataMode(ModeBitOrderTypeDef m)
{
switch(m)
{
case Mode0_LowBitINFront:
R8_SPI0_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
break;
case Mode0_HighBitINFront:
R8_SPI0_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
R8_SPI0_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
break;
case Mode3_LowBitINFront:
R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
break;
case Mode3_HighBitINFront:
R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
R8_SPI0_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
break;
default:
break;
}
}
/*********************************************************************
* @fn SPI0_MasterSendByte
*
* @brief 发送单字节 (buffer)
*
* @param d - 发送字节
*
* @return none
*/
void SPI0_MasterSendByte(uint8_t d)
{
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI0_BUFFER = d;
while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));
}
/*********************************************************************
* @fn SPI0_MasterRecvByte
*
* @brief 接收单字节 (buffer)
*
* @param none
*
* @return 接收到的字节
*/
uint8_t SPI0_MasterRecvByte(void)
{
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI0_BUFFER = 0xFF; // 启动传输
while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE));
return (R8_SPI0_BUFFER);
}
/*********************************************************************
* @fn SPI0_MasterTrans
*
* @brief 使用FIFO连续发送多字节
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度最大4095
*
* @return none
*/
void SPI0_MasterTrans(uint8_t *pbuf, uint16_t len)
{
uint16_t sendlen;
sendlen = len;
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; // 设置数据方向为输出
R16_SPI0_TOTAL_CNT = sendlen; // 设置要发送的数据长度
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
while(sendlen)
{
if(R8_SPI0_FIFO_COUNT < SPI_FIFO_SIZE)
{
R8_SPI0_FIFO = *pbuf;
pbuf++;
sendlen--;
}
}
while(R8_SPI0_FIFO_COUNT != 0); // 等待FIFO中的数据全部发送完成
}
/*********************************************************************
* @fn SPI0_MasterRecv
*
* @brief 使用FIFO连续接收多字节
*
* @param pbuf - 待接收的数据首地址
* @param len - 待接收的数据长度最大4095
*
* @return none
*/
void SPI0_MasterRecv(uint8_t *pbuf, uint16_t len)
{
uint16_t readlen;
readlen = len;
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR; // 设置数据方向为输入
R16_SPI0_TOTAL_CNT = len; // 设置需要接收的数据长度FIFO方向为输入长度不为0则会启动传输 */
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
while(readlen)
{
if(R8_SPI0_FIFO_COUNT)
{
*pbuf = R8_SPI0_FIFO;
pbuf++;
readlen--;
}
}
}
/*********************************************************************
* @fn SPI0_MasterDMATrans
*
* @brief DMA方式连续发送数据
*
* @param pbuf - 待发送数据起始地址,需要四字节对其
* @param len - 待发送数据长度
*
* @return none
*/
void SPI0_MasterDMATrans(uint8_t *pbuf, uint16_t len)
{
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (uint32_t)pbuf;
R16_SPI0_DMA_END = (uint32_t)(pbuf + len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}
/*********************************************************************
* @fn SPI0_MasterDMARecv
*
* @brief DMA方式连续接收数据
*
* @param pbuf - 待接收数据存放起始地址,需要四字节对其
* @param len - 待接收数据长度
*
* @return none
*/
void SPI0_MasterDMARecv(uint8_t *pbuf, uint16_t len)
{
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (uint32_t)pbuf;
R16_SPI0_DMA_END = (uint32_t)(pbuf + len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}
/*********************************************************************
* @fn SPI0_SlaveInit
*
* @brief 设备模式默认初始化建议设置MISO的GPIO对应为输入模式
*
* @return none
*/
void SPI0_SlaveInit(void)
{
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MISO_OE | RB_SPI_MODE_SLAVE;
R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF;
}
/*********************************************************************
* @fn SPI0_SlaveRecvByte
*
* @brief 从机模式,接收一字节数据
*
* @return 接收到数据
*/
uint8_t SPI0_SlaveRecvByte(void)
{
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
while(R8_SPI0_FIFO_COUNT == 0);
return R8_SPI0_FIFO;
}
/*********************************************************************
* @fn SPI0_SlaveSendByte
*
* @brief 从机模式,发送一字节数据
*
* @param d - 待发送数据
*
* @return none
*/
void SPI0_SlaveSendByte(uint8_t d)
{
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI0_FIFO = d;
while(R8_SPI0_FIFO_COUNT != 0); // 等待发送完成
}
/*********************************************************************
* @fn SPI0_SlaveRecv
*
* @brief 从机模式,接收多字节数据
*
* @param pbuf - 接收收数据存放起始地址
* @param len - 请求接收数据长度
*
* @return none
*/
void SPI0_SlaveRecv(uint8_t *pbuf, uint16_t len)
{
uint16_t revlen;
revlen = len;
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
while(revlen)
{
if(R8_SPI0_FIFO_COUNT)
{
*pbuf = R8_SPI0_FIFO;
pbuf++;
revlen--;
}
}
}
/*********************************************************************
* @fn SPI0_SlaveTrans
*
* @brief 从机模式,发送多字节数据
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度最大4095
*
* @return none
*/
void SPI0_SlaveTrans(uint8_t *pbuf, uint16_t len)
{
uint16_t sendlen;
sendlen = len;
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; // 设置数据方向为输出
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
while(sendlen)
{
if(R8_SPI0_FIFO_COUNT < SPI_FIFO_SIZE)
{
R8_SPI0_FIFO = *pbuf;
pbuf++;
sendlen--;
}
}
while(R8_SPI0_FIFO_COUNT != 0); // 等待FIFO中的数据全部发送完成
}
/*********************************************************************
* @fn SPI0_SlaveDMARecv
*
* @brief DMA方式连续接收数据
*
* @param pbuf - 待接收数据存放起始地址,需要四字节对其
* @param len - 待接收数据长度
*
* @return none
*/
void SPI0_SlaveDMARecv(uint8_t *pbuf, uint16_t len)
{
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (uint32_t)pbuf;
R16_SPI0_DMA_END = (uint32_t)(pbuf + len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}
/*********************************************************************
* @fn SPI0_SlaveDMATrans
*
* @brief DMA方式连续发送数据
*
* @param pbuf - 待发送数据起始地址,需要四字节对其
* @param len - 待发送数据长度
*
* @return none
*/
void SPI0_SlaveDMATrans(uint8_t *pbuf, uint16_t len)
{
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (uint32_t)pbuf;
R16_SPI0_DMA_END = (uint32_t)(pbuf + len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}

View File

@@ -0,0 +1,178 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_SPI1.c
* Author : WCH
* Version : V1.0
* Date : 2018/12/15
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn SPI1_MasterDefInit
*
* @brief 主机模式默认初始化模式0+3线全双工+8MHz
*
* @param none
*
* @return none
*/
void SPI1_MasterDefInit(void)
{
R8_SPI1_CLOCK_DIV = 4; // 主频时钟4分频
R8_SPI1_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI1_CTRL_MOD = RB_SPI1_SDO_OE | RB_SPI_SCK_OE;
R8_SPI1_CTRL_CFG |= RB_SPI_AUTO_IF; // 访问BUFFER/FIFO自动清除IF_BYTE_END标志
}
/*********************************************************************
* @fn SPI1_CLKCfg
*
* @brief SPI1 基准时钟配置,= d*Tsys
*
* @param c - 时钟分频系数
*
* @return none
*/
void SPI1_CLKCfg(uint8_t c)
{
if(c == 2)
{
R8_SPI1_CTRL_CFG |= RB_SPI_MST_DLY_EN;
}
else
{
R8_SPI1_CTRL_CFG &= ~RB_SPI_MST_DLY_EN;
}
R8_SPI1_CLOCK_DIV = c;
}
/*********************************************************************
* @fn SPI1_DataMode
*
* @brief 设置数据流模式
*
* @param m - 数据流模式 refer to ModeBitOrderTypeDef
*
* @return none
*/
void SPI1_DataMode(ModeBitOrderTypeDef m)
{
switch(m)
{
case Mode0_LowBitINFront:
R8_SPI1_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
R8_SPI1_CTRL_CFG |= RB_SPI_BIT_ORDER;
break;
case Mode0_HighBitINFront:
R8_SPI1_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
R8_SPI1_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
break;
case Mode3_LowBitINFront:
R8_SPI1_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
R8_SPI1_CTRL_CFG |= RB_SPI_BIT_ORDER;
break;
case Mode3_HighBitINFront:
R8_SPI1_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
R8_SPI1_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
break;
default:
break;
}
}
/*********************************************************************
* @fn SPI1_MasterSendByte
*
* @brief 发送单字节 (buffer)
*
* @param d - 发送字节
*
* @return none
*/
void SPI1_MasterSendByte(uint8_t d)
{
R8_SPI1_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI1_BUFFER = d;
while(!(R8_SPI1_INT_FLAG & RB_SPI_FREE));
}
/*********************************************************************
* @fn SPI1_MasterRecvByte
*
* @brief 接收单字节 (buffer)
*
* @param none
*
* @return 接收到的字节
*/
uint8_t SPI1_MasterRecvByte(void)
{
R8_SPI1_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI1_BUFFER = 0xFF; // 启动传输
while(!(R8_SPI1_INT_FLAG & RB_SPI_FREE));
return (R8_SPI1_BUFFER);
}
/*********************************************************************
* @fn SPI1_MasterTrans
*
* @brief 使用FIFO连续发送多字节
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度最大4095
*
* @return none
*/
void SPI1_MasterTrans(uint8_t *pbuf, uint16_t len)
{
uint16_t sendlen;
sendlen = len;
R8_SPI1_CTRL_MOD &= ~RB_SPI_FIFO_DIR; // 设置数据方向为输出
R16_SPI1_TOTAL_CNT = sendlen; // 设置要发送的数据长度
R8_SPI1_INT_FLAG = RB_SPI_IF_CNT_END;
while(sendlen)
{
if(R8_SPI1_FIFO_COUNT < SPI_FIFO_SIZE)
{
R8_SPI1_FIFO = *pbuf;
pbuf++;
sendlen--;
}
}
while(R8_SPI1_FIFO_COUNT != 0); // 等待FIFO中的数据全部发送完成
}
/*********************************************************************
* @fn SPI1_MasterRecv
*
* @brief 使用FIFO连续接收多字节
*
* @param pbuf - 待接收的数据首地址
* @param len - 待接收的数据长度最大4095
*
* @return none
*/
void SPI1_MasterRecv(uint8_t *pbuf, uint16_t len)
{
uint16_t readlen;
readlen = len;
R8_SPI1_CTRL_MOD |= RB_SPI_FIFO_DIR; // 设置数据方向为输入
R16_SPI1_TOTAL_CNT = len; // 设置需要接收的数据长度FIFO方向为输入长度不为0则会启动传输 */
R8_SPI1_INT_FLAG = RB_SPI_IF_CNT_END;
while(readlen)
{
if(R8_SPI1_FIFO_COUNT)
{
*pbuf = R8_SPI1_FIFO;
pbuf++;
readlen--;
}
}
}

View File

@@ -0,0 +1,396 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_SYS.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn SetSysClock
*
* @brief 配置系统运行时钟
*
* @param sc - 系统时钟源选择 refer to SYS_CLKTypeDef
*
* @return none
*/
__HIGH_CODE
void SetSysClock(SYS_CLKTypeDef sc)
{
uint32_t i;
sys_safe_access_enable();
R8_PLL_CONFIG &= ~(1 << 5); //
sys_safe_access_disable();
if(sc & 0x20)
{ // HSE div
if(!(R8_HFCK_PWR_CTRL & RB_CLK_XT32M_PON))
{
sys_safe_access_enable();
R8_HFCK_PWR_CTRL |= RB_CLK_XT32M_PON; // HSE power on
for(i = 0; i < 1200; i++)
{
__nop();
__nop();
}
}
sys_safe_access_enable();
R16_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f);
__nop();
__nop();
__nop();
__nop();
sys_safe_access_disable();
sys_safe_access_enable();
SAFEOPERATE;
R8_FLASH_CFG = 0X51;
sys_safe_access_disable();
}
else if(sc & 0x40)
{ // PLL div
if(!(R8_HFCK_PWR_CTRL & RB_CLK_PLL_PON))
{
sys_safe_access_enable();
R8_HFCK_PWR_CTRL |= RB_CLK_PLL_PON; // PLL power on
for(i = 0; i < 2000; i++)
{
__nop();
__nop();
}
}
sys_safe_access_enable();
R16_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f);
__nop();
__nop();
__nop();
__nop();
sys_safe_access_disable();
if(sc == CLK_SOURCE_PLL_80MHz)
{
sys_safe_access_enable();
R8_FLASH_CFG = 0X02;
sys_safe_access_disable();
}
else
{
sys_safe_access_enable();
R8_FLASH_CFG = 0X52;
sys_safe_access_disable();
}
}
else
{
sys_safe_access_enable();
R16_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
}
//更改FLASH clk的驱动能力
sys_safe_access_enable();
R8_PLL_CONFIG |= 1 << 7;
sys_safe_access_disable();
}
/*********************************************************************
* @fn GetSysClock
*
* @brief 获取当前系统时钟
*
* @param none
*
* @return Hz
*/
uint32_t GetSysClock(void)
{
uint16_t rev;
rev = R16_CLK_SYS_CFG & 0xff;
if((rev & 0x40) == (0 << 6))
{ // 32M进行分频
return (32000000 / (rev & 0x1f));
}
else if((rev & RB_CLK_SYS_MOD) == (1 << 6))
{ // PLL进行分频
return (480000000 / (rev & 0x1f));
}
else
{ // 32K做主频
return (32000);
}
}
/*********************************************************************
* @fn SYS_GetInfoSta
*
* @brief 获取当前系统信息状态
*
* @param i - refer to SYS_InfoStaTypeDef
*
* @return 是否开启
*/
uint8_t SYS_GetInfoSta(SYS_InfoStaTypeDef i)
{
if(i == STA_SAFEACC_ACT)
{
return (R8_SAFE_ACCESS_SIG & RB_SAFE_ACC_ACT);
}
else
{
return (R8_GLOB_CFG_INFO & (1 << i));
}
}
/*********************************************************************
* @fn SYS_ResetExecute
*
* @brief 执行系统软件复位
*
* @param none
*
* @return none
*/
__HIGH_CODE
void SYS_ResetExecute(void)
{
FLASH_ROM_SW_RESET();
sys_safe_access_enable();
R8_RST_WDOG_CTRL |= RB_SOFTWARE_RESET;
sys_safe_access_disable();
}
/*********************************************************************
* @fn SYS_DisableAllIrq
*
* @brief 关闭所有中断,并保留当前中断值
*
* @param pirqv - 当前保留中断值
*
* @return none
*/
void SYS_DisableAllIrq(uint32_t *pirqv)
{
*pirqv = (PFIC->ISR[0] >> 8) | (PFIC->ISR[1] << 24);
PFIC->IRER[0] = 0xffffffff;
PFIC->IRER[1] = 0xffffffff;
}
/*********************************************************************
* @fn SYS_RecoverIrq
*
* @brief 恢复之前关闭的中断值
*
* @param irq_status - 当前保留中断值
*
* @return none
*/
void SYS_RecoverIrq(uint32_t irq_status)
{
PFIC->IENR[0] = (irq_status << 8);
PFIC->IENR[1] = (irq_status >> 24);
}
/*********************************************************************
* @fn SYS_GetSysTickCnt
*
* @brief 获取当前系统(SYSTICK)计数值
*
* @param none
*
* @return 当前计数值
*/
uint32_t SYS_GetSysTickCnt(void)
{
uint32_t val;
val = SysTick->CNT;
return (val);
}
/*********************************************************************
* @fn WWDG_ITCfg
*
* @brief 看门狗定时器溢出中断使能
*
* @param s - 溢出是否中断
*
* @return none
*/
void WWDG_ITCfg(FunctionalState s)
{
uint8_t ctrl = R8_RST_WDOG_CTRL;
if(s == DISABLE)
{
ctrl &= ~RB_WDOG_INT_EN;
}
else
{
ctrl |= RB_WDOG_INT_EN;
}
sys_safe_access_enable();
R8_RST_WDOG_CTRL = ctrl;
sys_safe_access_disable();
}
/*********************************************************************
* @fn WWDG_ResetCfg
*
* @brief 看门狗定时器复位功能
*
* @param s - 溢出是否复位
*
* @return none
*/
void WWDG_ResetCfg(FunctionalState s)
{
uint8_t ctrl = R8_RST_WDOG_CTRL;
if(s == DISABLE)
{
ctrl &= ~RB_WDOG_RST_EN;
}
else
{
ctrl |= RB_WDOG_RST_EN;
}
sys_safe_access_enable();
R8_RST_WDOG_CTRL = ctrl;
sys_safe_access_disable();
}
/*********************************************************************
* @fn WWDG_ClearFlag
*
* @brief 清除看门狗中断标志,重新加载计数值也可清除
*
* @param none
*
* @return none
*/
void WWDG_ClearFlag(void)
{
sys_safe_access_enable();
R8_RST_WDOG_CTRL |= RB_WDOG_INT_FLAG;
sys_safe_access_disable();
}
/*********************************************************************
* @fn HardFault_Handler
*
* @brief 硬件错误中断,进入后执行复位,复位类型为上电复位
*
* @param none
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
__attribute__((weak))
void HardFault_Handler(void)
{
FLASH_ROM_SW_RESET();
sys_safe_access_enable();
R16_INT32K_TUNE = 0xFFFF;
sys_safe_access_enable();
R8_RST_WDOG_CTRL |= RB_SOFTWARE_RESET;
sys_safe_access_disable();
while(1);
}
/*********************************************************************
* @fn mDelayuS
*
* @brief uS 延时
*
* @param t - 时间参数
*
* @return none
*/
__HIGH_CODE
void mDelayuS(uint16_t t)
{
uint32_t i;
#if(FREQ_SYS == 80000000)
i = t * 20;
#elif(FREQ_SYS == 60000000)
i = t * 15;
#elif(FREQ_SYS == 48000000)
i = t * 12;
#elif(FREQ_SYS == 40000000)
i = t * 10;
#elif(FREQ_SYS == 32000000)
i = t << 3;
#elif(FREQ_SYS == 24000000)
i = t * 6;
#elif(FREQ_SYS == 16000000)
i = t << 2;
#elif(FREQ_SYS == 8000000)
i = t << 1;
#elif(FREQ_SYS == 4000000)
i = t;
#elif(FREQ_SYS == 2000000)
i = t >> 1;
#elif(FREQ_SYS == 1000000)
i = t >> 2;
#else
i = t << 1;
#endif
do
{
__nop();
} while(--i);
}
/*********************************************************************
* @fn mDelaymS
*
* @brief mS 延时
*
* @param t - 时间参数
*
* @return none
*/
__HIGH_CODE
void mDelaymS(uint16_t t)
{
uint16_t i;
for(i = 0; i < t; i++)
{
mDelayuS(1000);
}
}
#ifdef DEBUG
int _write(int fd, char *buf, int size)
{
int i;
for(i = 0; i < size; i++)
{
#if DEBUG == Debug_UART0
while(R8_UART0_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
R8_UART0_THR = *buf++; /* 发送数据 */
#elif DEBUG == Debug_UART1
while(R8_UART1_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
R8_UART1_THR = *buf++; /* 发送数据 */
#elif DEBUG == Debug_UART2
while(R8_UART2_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
R8_UART2_THR = *buf++; /* 发送数据 */
#elif DEBUG == Debug_UART3
while(R8_UART3_TFC == UART_FIFO_SIZE); /* 等待数据发送 */
R8_UART3_THR = *buf++; /* 发送数据 */
#endif
}
return size;
}
#endif

View File

@@ -0,0 +1,75 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_timer0.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn TMR0_TimerInit
*
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*
* @return none
*/
void TMR0_TimerInit(uint32_t t)
{
R32_TMR0_CNT_END = t;
R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR0_CTRL_MOD = RB_TMR_COUNT_EN;
}
/*********************************************************************
* @fn TMR0_EXTSingleCounterInit
*
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*
* @return none
*/
void TMR0_EXTSingleCounterInit(CapModeTypeDef cap)
{
R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR0_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_CAP_COUNT | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR0_PWMInit
*
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*
* @return none
*/
void TMR0_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts)
{
// R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR0_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_OUT_EN | (pr << 4) | (ts << 6);
}
/*********************************************************************
* @fn TMR0_CapInit
*
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*
* @return none
*/
void TMR0_CapInit(CapModeTypeDef cap)
{
R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR0_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_MODE_IN | (cap << 6);
}

View File

@@ -0,0 +1,104 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_timer1.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn TMR1_TimerInit
*
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*
* @return none
*/
void TMR1_TimerInit(uint32_t t)
{
R32_TMR1_CNT_END = t;
R8_TMR1_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR1_CTRL_MOD = RB_TMR_COUNT_EN;
}
/*********************************************************************
* @fn TMR1_EXTSingleCounterInit
*
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*
* @return none
*/
void TMR1_EXTSingleCounterInit(CapModeTypeDef cap)
{
R8_TMR1_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR1_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_CAP_COUNT | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR1_PWMInit
*
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*
* @return none
*/
void TMR1_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts)
{
// R8_TMR1_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR1_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_OUT_EN | (pr << 4) | (ts << 6);
}
/*********************************************************************
* @fn TMR1_CapInit
*
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*
* @return none
*/
void TMR1_CapInit(CapModeTypeDef cap)
{
R8_TMR1_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR1_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR1_DMACfg
*
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*
* @return none
*/
void TMR1_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, DMAModeTypeDef m)
{
if(s == DISABLE)
{
R8_TMR1_CTRL_DMA = 0;
}
else
{
R16_TMR1_DMA_BEG = startAddr;
R16_TMR1_DMA_END = endAddr;
if(m)
R8_TMR1_CTRL_DMA = RB_TMR_DMA_LOOP | RB_TMR_DMA_ENABLE;
else
R8_TMR1_CTRL_DMA = RB_TMR_DMA_ENABLE;
}
}

View File

@@ -0,0 +1,104 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_timer2.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn TMR2_TimerInit
*
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*
* @return none
*/
void TMR2_TimerInit(uint32_t t)
{
R32_TMR2_CNT_END = t;
R8_TMR2_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR2_CTRL_MOD = RB_TMR_COUNT_EN;
}
/*********************************************************************
* @fn TMR2_EXTSingleCounterInit
*
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*
* @return none
*/
void TMR2_EXTSingleCounterInit(CapModeTypeDef cap)
{
R8_TMR2_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR2_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_CAP_COUNT | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR2_PWMInit
*
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*
* @return none
*/
void TMR2_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts)
{
// R8_TMR2_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR2_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_OUT_EN | (pr << 4) | (ts << 6);
}
/*********************************************************************
* @fn TMR2_CapInit
*
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*
* @return none
*/
void TMR2_CapInit(CapModeTypeDef cap)
{
R8_TMR2_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR2_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR2_DMACfg
*
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*
* @return none
*/
void TMR2_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, DMAModeTypeDef m)
{
if(s == DISABLE)
{
R8_TMR2_CTRL_DMA = 0;
}
else
{
R16_TMR2_DMA_BEG = startAddr;
R16_TMR2_DMA_END = endAddr;
if(m)
R8_TMR2_CTRL_DMA = RB_TMR_DMA_LOOP | RB_TMR_DMA_ENABLE;
else
R8_TMR2_CTRL_DMA = RB_TMR_DMA_ENABLE;
}
}

View File

@@ -0,0 +1,75 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_timer3.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn TMR3_TimerInit
*
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*
* @return none
*/
void TMR3_TimerInit(uint32_t t)
{
R32_TMR3_CNT_END = t;
R8_TMR3_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR3_CTRL_MOD = RB_TMR_COUNT_EN;
}
/*********************************************************************
* @fn TMR3_EXTSingleCounterInit
*
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*
* @return none
*/
void TMR3_EXTSingleCounterInit(CapModeTypeDef cap)
{
R8_TMR3_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR3_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_CAP_COUNT | RB_TMR_MODE_IN | (cap << 6);
}
/*********************************************************************
* @fn TMR3_PWMInit
*
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*
* @return none
*/
void TMR3_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts)
{
// R8_TMR3_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR3_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_OUT_EN | (pr << 4) | (ts << 6);
}
/*********************************************************************
* @fn TMR3_CapInit
*
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*
* @return none
*/
void TMR3_CapInit(CapModeTypeDef cap)
{
R8_TMR3_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR3_CTRL_MOD = RB_TMR_COUNT_EN | RB_TMR_MODE_IN | (cap << 6);
}

View File

@@ -0,0 +1,151 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_uart0.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn UART0_DefInit
*
* @brief 串口默认初始化配置
*
* @param none
*
* @return none
*/
void UART0_DefInit(void)
{
UART0_BaudRateCfg(115200);
R8_UART0_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; // FIFO打开触发点4字节
R8_UART0_LCR = RB_LCR_WORD_SZ;
R8_UART0_IER = RB_IER_TXD_EN;
R8_UART0_DIV = 1;
}
/*********************************************************************
* @fn UART0_BaudRateCfg
*
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*
* @return none
*/
void UART0_BaudRateCfg(uint32_t baudrate)
{
uint32_t x;
x = 10 * GetSysClock() / 8 / baudrate;
x = (x + 5) / 10;
R16_UART0_DL = (uint16_t)x;
}
/*********************************************************************
* @fn UART0_ByteTrigCfg
*
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*
* @return none
*/
void UART0_ByteTrigCfg(UARTByteTRIGTypeDef b)
{
R8_UART0_FCR = (R8_UART0_FCR & ~RB_FCR_FIFO_TRIG) | (b << 6);
}
/*********************************************************************
* @fn UART0_INTCfg
*
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*
* @return none
*/
void UART0_INTCfg(FunctionalState s, uint8_t i)
{
if(s)
{
R8_UART0_IER |= i;
R8_UART0_MCR |= RB_MCR_INT_OE;
}
else
{
R8_UART0_IER &= ~i;
}
}
/*********************************************************************
* @fn UART0_Reset
*
* @brief 串口软件复位
*
* @param none
*
* @return none
*/
void UART0_Reset(void)
{
R8_UART0_IER = RB_IER_RESET;
}
/*********************************************************************
* @fn UART0_SendString
*
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*
* @return none
*/
void UART0_SendString(uint8_t *buf, uint16_t l)
{
uint16_t len = l;
while(len)
{
if(R8_UART0_TFC != UART_FIFO_SIZE)
{
R8_UART0_THR = *buf++;
len--;
}
}
}
/*********************************************************************
* @fn UART0_RecvString
*
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART0_RecvString(uint8_t *buf)
{
uint16_t len = 0;
while(R8_UART0_RFC)
{
*buf++ = R8_UART0_RBR;
len++;
}
return (len);
}

View File

@@ -0,0 +1,150 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_uart1.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn UART1_DefInit
*
* @brief 串口默认初始化配置
*
* @param none
*
* @return none
*/
void UART1_DefInit(void)
{
UART1_BaudRateCfg(115200);
R8_UART1_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; // FIFO打开触发点4字节
R8_UART1_LCR = RB_LCR_WORD_SZ;
R8_UART1_IER = RB_IER_TXD_EN;
R8_UART1_DIV = 1;
}
/*********************************************************************
* @fn UART1_BaudRateCfg
*
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*
* @return none
*/
void UART1_BaudRateCfg(uint32_t baudrate)
{
uint32_t x;
x = 10 * GetSysClock() / 8 / baudrate;
x = (x + 5) / 10;
R16_UART1_DL = (uint16_t)x;
}
/*********************************************************************
* @fn UART1_ByteTrigCfg
*
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*
* @return none
*/
void UART1_ByteTrigCfg(UARTByteTRIGTypeDef b)
{
R8_UART1_FCR = (R8_UART1_FCR & ~RB_FCR_FIFO_TRIG) | (b << 6);
}
/*********************************************************************
* @fn UART1_INTCfg
*
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*
* @return none
*/
void UART1_INTCfg(FunctionalState s, uint8_t i)
{
if(s)
{
R8_UART1_IER |= i;
R8_UART1_MCR |= RB_MCR_INT_OE;
}
else
{
R8_UART1_IER &= ~i;
}
}
/*********************************************************************
* @fn UART1_Reset
*
* @brief 串口软件复位
*
* @param none
*
* @return none
*/
void UART1_Reset(void)
{
R8_UART1_IER = RB_IER_RESET;
}
/*********************************************************************
* @fn UART1_SendString
*
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*
* @return none
*/
void UART1_SendString(uint8_t *buf, uint16_t l)
{
uint16_t len = l;
while(len)
{
if(R8_UART1_TFC != UART_FIFO_SIZE)
{
R8_UART1_THR = *buf++;
len--;
}
}
}
/*********************************************************************
* @fn UART1_RecvString
*
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART1_RecvString(uint8_t *buf)
{
uint16_t len = 0;
while(R8_UART1_RFC)
{
*buf++ = R8_UART1_RBR;
len++;
}
return (len);
}

View File

@@ -0,0 +1,151 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_uart2.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn UART2_DefInit
*
* @brief 串口默认初始化配置
*
* @param none
*
* @return none
*/
void UART2_DefInit(void)
{
UART2_BaudRateCfg(115200);
R8_UART2_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; // FIFO打开触发点4字节
R8_UART2_LCR = RB_LCR_WORD_SZ;
R8_UART2_IER = RB_IER_TXD_EN;
R8_UART2_DIV = 1;
}
/*********************************************************************
* @fn UART2_BaudRateCfg
*
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*
* @return none
*/
void UART2_BaudRateCfg(uint32_t baudrate)
{
uint32_t x;
x = 10 * GetSysClock() / 8 / baudrate;
x = (x + 5) / 10;
R16_UART2_DL = (uint16_t)x;
}
/*********************************************************************
* @fn UART2_ByteTrigCfg
*
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*
* @return none
*/
void UART2_ByteTrigCfg(UARTByteTRIGTypeDef b)
{
R8_UART2_FCR = (R8_UART2_FCR & ~RB_FCR_FIFO_TRIG) | (b << 6);
}
/*********************************************************************
* @fn UART2_INTCfg
*
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*
* @return none
*/
void UART2_INTCfg(FunctionalState s, uint8_t i)
{
if(s)
{
R8_UART2_IER |= i;
R8_UART2_MCR |= RB_MCR_INT_OE;
}
else
{
R8_UART2_IER &= ~i;
}
}
/*********************************************************************
* @fn UART2_Reset
*
* @brief 串口软件复位
*
* @param none
*
* @return none
*/
void UART2_Reset(void)
{
R8_UART2_IER = RB_IER_RESET;
}
/*********************************************************************
* @fn UART2_SendString
*
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*
* @return none
*/
void UART2_SendString(uint8_t *buf, uint16_t l)
{
uint16_t len = l;
while(len)
{
if(R8_UART2_TFC != UART_FIFO_SIZE)
{
R8_UART2_THR = *buf++;
len--;
}
}
}
/*********************************************************************
* @fn UART2_RecvString
*
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART2_RecvString(uint8_t *buf)
{
uint16_t len = 0;
while(R8_UART2_RFC)
{
*buf++ = R8_UART2_RBR;
len++;
}
return (len);
}

View File

@@ -0,0 +1,151 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_uart3.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
/*********************************************************************
* @fn UART3_DefInit
*
* @brief 串口默认初始化配置
*
* @param none
*
* @return none
*/
void UART3_DefInit(void)
{
UART3_BaudRateCfg(115200);
R8_UART3_FCR = (2 << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; // FIFO打开触发点4字节
R8_UART3_LCR = RB_LCR_WORD_SZ;
R8_UART3_IER = RB_IER_TXD_EN;
R8_UART3_DIV = 1;
}
/*********************************************************************
* @fn UART3_BaudRateCfg
*
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*
* @return none
*/
void UART3_BaudRateCfg(uint32_t baudrate)
{
uint32_t x;
x = 10 * GetSysClock() / 8 / baudrate;
x = (x + 5) / 10;
R16_UART3_DL = (uint16_t)x;
}
/*********************************************************************
* @fn UART3_ByteTrigCfg
*
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*
* @return none
*/
void UART3_ByteTrigCfg(UARTByteTRIGTypeDef b)
{
R8_UART3_FCR = (R8_UART3_FCR & ~RB_FCR_FIFO_TRIG) | (b << 6);
}
/*********************************************************************
* @fn UART3_INTCfg
*
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*
* @return none
*/
void UART3_INTCfg(FunctionalState s, uint8_t i)
{
if(s)
{
R8_UART3_IER |= i;
R8_UART3_MCR |= RB_MCR_INT_OE;
}
else
{
R8_UART3_IER &= ~i;
}
}
/*********************************************************************
* @fn UART3_Reset
*
* @brief 串口软件复位
*
* @param none
*
* @return none
*/
void UART3_Reset(void)
{
R8_UART3_IER = RB_IER_RESET;
}
/*********************************************************************
* @fn UART3_SendString
*
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*
* @return none
*/
void UART3_SendString(uint8_t *buf, uint16_t l)
{
uint16_t len = l;
while(len)
{
if(R8_UART3_TFC != UART_FIFO_SIZE)
{
R8_UART3_THR = *buf++;
len--;
}
}
}
/*********************************************************************
* @fn UART3_RecvString
*
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART3_RecvString(uint8_t *buf)
{
uint16_t len = 0;
while(R8_UART3_RFC)
{
*buf++ = R8_UART3_RBR;
len++;
}
return (len);
}

View File

@@ -0,0 +1,113 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usb2dev.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
uint8_t *pU2EP0_RAM_Addr;
uint8_t *pU2EP1_RAM_Addr;
uint8_t *pU2EP2_RAM_Addr;
uint8_t *pU2EP3_RAM_Addr;
/*********************************************************************
* @fn USB2_DeviceInit
*
* @brief USB2设备功能初始化4个端点8个通道。
*
* @param none
*
* @return none
*/
void USB2_DeviceInit(void)
{
R8_USB2_CTRL = 0x00; // 先设定模式,取消 RB_UC_CLR_ALL
R8_U2EP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN | RB_UEP1_RX_EN | RB_UEP1_TX_EN; // 端点4 OUT+IN,端点1 OUT+IN
R8_U2EP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN | RB_UEP3_RX_EN | RB_UEP3_TX_EN; // 端点2 OUT+IN,端点3 OUT+IN
R16_U2EP0_DMA = (uint16_t)(uint32_t)pU2EP0_RAM_Addr;
R16_U2EP1_DMA = (uint16_t)(uint32_t)pU2EP1_RAM_Addr;
R16_U2EP2_DMA = (uint16_t)(uint32_t)pU2EP2_RAM_Addr;
R16_U2EP3_DMA = (uint16_t)(uint32_t)pU2EP3_RAM_Addr;
R8_U2EP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_U2EP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_U2EP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_U2EP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_U2EP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_USB2_DEV_AD = 0x00;
R8_USB2_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
R16_PIN_ANALOG_IE |= RB_PIN_USB2_IE | RB_PIN_USB2_DP_PU; // 防止USB端口浮空及上拉电阻
R8_USB2_INT_FG = 0xFF; // 清中断标志
R8_U2DEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN; // 允许USB端口
R8_USB2_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
}
/*********************************************************************
* @fn U2DevEP1_IN_Deal
*
* @brief U2端点1数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void U2DevEP1_IN_Deal(uint8_t l)
{
R8_U2EP1_T_LEN = l;
R8_U2EP1_CTRL = (R8_U2EP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn U2DevEP2_IN_Deal
*
* @brief U2端点2数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void U2DevEP2_IN_Deal(uint8_t l)
{
R8_U2EP2_T_LEN = l;
R8_U2EP2_CTRL = (R8_U2EP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn U2DevEP3_IN_Deal
*
* @brief U2端点3数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void U2DevEP3_IN_Deal(uint8_t l)
{
R8_U2EP3_T_LEN = l;
R8_U2EP3_CTRL = (R8_U2EP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn U2DevEP4_IN_Deal
*
* @brief U2端点4数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void U2DevEP4_IN_Deal(uint8_t l)
{
R8_U2EP4_T_LEN = l;
R8_U2EP4_CTRL = (R8_U2EP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}

View File

@@ -0,0 +1,652 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbhost.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
#if DISK_LIB_ENABLE
#include "CHRV3UFI.H"
#endif
uint8_t Usb2DevEndp0Size; // USB2设备的端点0的最大包尺寸
uint8_t FoundNewU2Dev;
_RootHubDev ThisUsb2Dev; //ROOT口
_DevOnHubPort DevOnU2HubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
uint8_t *pU2HOST_RX_RAM_Addr;
uint8_t *pU2HOST_TX_RAM_Addr;
/*获取设备描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetU2DevDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof(USB_DEV_DESCR), 0x00};
/*获取配置描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetU2CfgDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00};
/*设置USB地址*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Addr[] = {USB_REQ_TYP_OUT, USB_SET_ADDRESS, USB_DEVICE_ADDR,
0x00, 0x00, 0x00, 0x00, 0x00};
/*设置USB配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Config[] = {USB_REQ_TYP_OUT, USB_SET_CONFIGURATION,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*设置USB接口配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Interface[] = {USB_REQ_RECIP_INTERF, USB_SET_INTERFACE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*清除端点STALL*/
__attribute__((aligned(4))) const uint8_t SetupClrU2EndpStall[] = {USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*********************************************************************
* @fn DisableRootU2HubPort
*
* @brief 关闭ROOT-HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
*
* @param none
*
* @return none
*/
void DisableRootU2HubPort(void)
{
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_DISCONNECT;
#endif
#ifndef DISK_BASE_BUF_LEN
ThisUsb2Dev.DeviceStatus = ROOT_DEV_DISCONNECT;
ThisUsb2Dev.DeviceAddress = 0x00;
#endif
}
/*********************************************************************
* @fn AnalyzeRootU2Hub
*
* @brief 分析ROOT-HUB状态,处理ROOT-HUB端口的设备插拔事件
* 如果设备拔出,函数中调用DisableRootHubPort()函数,将端口关闭,插入事件,置相应端口的状态位
*
* @param none
*
* @return 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
*/
uint8_t AnalyzeRootU2Hub(void)
{
uint8_t s;
s = ERR_SUCCESS;
if(R8_USB2_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 设备存在
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT
#else
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_DISCONNECT // 检测到有设备插入
#endif
|| (R8_U2HOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 检测到有设备插入,但尚未允许,说明是刚插入
DisableRootU2HubPort(); // 关闭端口
#ifdef DISK_BASE_BUF_LEN
CHRV3DiskStatus = DISK_CONNECT;
#else
ThisUsb2Dev.DeviceSpeed = R8_USB2_MIS_ST & RB_UMS_DM_LEVEL ? 0 : 1;
ThisUsb2Dev.DeviceStatus = ROOT_DEV_CONNECTED; //置连接标志
#endif
PRINT("USB2 dev in\n");
s = ERR_USB_CONNECT;
}
}
#ifdef DISK_BASE_BUF_LEN
else if(CHRV3DiskStatus >= DISK_CONNECT)
{
#else
else if(ThisUsb2Dev.DeviceStatus >= ROOT_DEV_CONNECTED)
{ //检测到设备拔出
#endif
DisableRootU2HubPort(); // 关闭端口
PRINT("USB2 dev out\n");
if(s == ERR_SUCCESS)
s = ERR_USB_DISCON;
}
// R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
return (s);
}
/*********************************************************************
* @fn SetHostUsb2Addr
*
* @brief 设置USB主机当前操作的USB设备地址
*
* @param addr - USB设备地址
*
* @return none
*/
void SetHostUsb2Addr(uint8_t addr)
{
R8_USB2_DEV_AD = (R8_USB2_DEV_AD & RB_UDA_GP_BIT) | (addr & MASK_USB_ADDR);
}
/*********************************************************************
* @fn SetUsb2Speed
*
* @brief 设置当前USB速度
*
* @param FullSpeed - USB速度
*
* @return none
*/
void SetUsb2Speed(uint8_t FullSpeed)
{
#ifndef DISK_BASE_BUF_LEN
if(FullSpeed) // 全速
{
R8_USB2_CTRL &= ~RB_UC_LOW_SPEED; // 全速
R8_U2H_SETUP &= ~RB_UH_PRE_PID_EN; // 禁止PRE PID
}
else
{
R8_USB2_CTRL |= RB_UC_LOW_SPEED; // 低速
}
#endif
(void)FullSpeed;
}
/*********************************************************************
* @fn ResetRootU2HubPort
*
* @brief 检测到设备后,复位总线,为枚举设备准备,设置为默认为全速
*
* @param none
*
* @return none
*/
void ResetRootU2HubPort(void)
{
Usb2DevEndp0Size = DEFAULT_ENDP0_SIZE; //USB2设备的端点0的最大包尺寸
SetHostUsb2Addr(0x00);
R8_U2HOST_CTRL &= ~RB_UH_PORT_EN; // 关掉端口
SetUsb2Speed(1); // 默认为全速
R8_U2HOST_CTRL = (R8_U2HOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为全速,开始复位
mDelaymS(15); // 复位时间10mS到20mS
R8_U2HOST_CTRL = R8_U2HOST_CTRL & ~RB_UH_BUS_RESET; // 结束复位
mDelayuS(250);
R8_USB2_INT_FG = RB_UIF_DETECT; // 清中断标志
}
/*********************************************************************
* @fn EnableRootU2HubPort
*
* @brief 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
*
* @param none
*
* @return 返回ERR_SUCCESS为检测到新连接,返回ERR_USB_DISCON为无连接
*/
uint8_t EnableRootU2HubPort(void)
{
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus < DISK_CONNECT)
CHRV3DiskStatus = DISK_CONNECT;
#else
if(ThisUsb2Dev.DeviceStatus < ROOT_DEV_CONNECTED)
ThisUsb2Dev.DeviceStatus = ROOT_DEV_CONNECTED;
#endif
if(R8_USB2_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 有设备
#ifndef DISK_BASE_BUF_LEN
if((R8_U2HOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 尚未使能
ThisUsb2Dev.DeviceSpeed = (R8_USB2_MIS_ST & RB_UMS_DM_LEVEL) ? 0 : 1;
if(ThisUsb2Dev.DeviceSpeed == 0)
R8_U2HOST_CTRL |= RB_UH_LOW_SPEED; // 低速
}
#endif
R8_U2HOST_CTRL |= RB_UH_PORT_EN; //使能HUB端口
return (ERR_SUCCESS);
}
return (ERR_USB_DISCON);
}
#ifndef DISK_BASE_BUF_LEN
/*********************************************************************
* @fn SelectU2HubPort
*
* @brief 选定需要操作的HUB口
*
* @param HubPortIndex - 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
*
* @return None
*/
void SelectU2HubPort(uint8_t HubPortIndex)
{
if(HubPortIndex) // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
{
SetHostUsb2Addr(DevOnU2HubPort[HubPortIndex - 1].DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsb2Speed(DevOnU2HubPort[HubPortIndex - 1].DeviceSpeed); // 设置当前USB速度
if(DevOnU2HubPort[HubPortIndex - 1].DeviceSpeed == 0) // 通过外部HUB与低速USB设备通讯需要前置ID
{
R8_U2EP1_CTRL |= RB_UH_PRE_PID_EN; // 启用PRE PID
mDelayuS(100);
}
}
else
{
SetHostUsb2Addr(ThisUsb2Dev.DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsb2Speed(ThisUsb2Dev.DeviceSpeed); // 设置USB设备的速度
}
}
#endif
/*********************************************************************
* @fn WaitUSB2_Interrupt
*
* @brief 等待USB中断
*
* @param none
*
* @return 返回ERR_SUCCESS 数据接收或者发送成功,返回ERR_USB_UNKNOWN 数据接收或者发送失败
*/
uint8_t WaitUSB2_Interrupt(void)
{
uint16_t i;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0; i--)
{
;
}
return ((R8_USB2_INT_FG & RB_UIF_TRANSFER) ? ERR_SUCCESS : ERR_USB_UNKNOWN);
}
/*********************************************************************
* @fn USB2HostTransact
*
* @brief 传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
* 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化
*
* @param endp_pid - 令牌和地址, 高4位是token_pid令牌, 低4位是端点地址
* @param tog - 同步标志
* @param timeout - 超时时间
*
* @return ERR_USB_UNKNOWN 超时,可能硬件异常
* ERR_USB_DISCON 设备断开
* ERR_USB_CONNECT 设备连接
* ERR_SUCCESS 传输完成
*/
uint8_t USB2HostTransact(uint8_t endp_pid, uint8_t tog, uint32_t timeout)
{
uint8_t TransRetry;
uint8_t s, r;
uint16_t i;
R8_U2H_RX_CTRL = R8_U2H_TX_CTRL = tog;
TransRetry = 0;
do
{
R8_U2H_EP_PID = endp_pid; // 指定令牌PID和目的端点号
R8_USB2_INT_FG = RB_UIF_TRANSFER;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0; i--)
;
R8_U2H_EP_PID = 0x00; // 停止USB传输
if((R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0)
{
return (ERR_USB_UNKNOWN);
}
if(R8_USB2_INT_FG & RB_UIF_DETECT)
{ // USB设备插拔事件
// mDelayuS( 200 ); // 等待传输完成
R8_USB2_INT_FG = RB_UIF_DETECT;
s = AnalyzeRootU2Hub(); // 分析ROOT-U2HUB状态
if(s == ERR_USB_CONNECT)
FoundNewU2Dev = 1;
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(CHRV3DiskStatus == DISK_CONNECT)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#else
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_CONNECTED)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#endif
mDelayuS(200); // 等待传输完成
}
if(R8_USB2_INT_FG & RB_UIF_TRANSFER) // 传输完成事件
{
if(R8_USB2_INT_ST & RB_UIS_TOG_OK)
{
return (ERR_SUCCESS);
}
r = R8_USB2_INT_ST & MASK_UIS_H_RES; // USB设备应答状态
if(r == USB_PID_STALL)
{
return (r | ERR_USB_TRANSFER);
}
if(r == USB_PID_NAK)
{
if(timeout == 0)
{
return (r | ERR_USB_TRANSFER);
}
if(timeout < 0xFFFFFFFF)
timeout--;
--TransRetry;
}
else
switch(endp_pid >> 4)
{
case USB_PID_SETUP:
case USB_PID_OUT:
if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
case USB_PID_IN:
if(r == USB_PID_DATA0 || r == USB_PID_DATA1)
{ // 不同步则需丢弃后重试
} // 不同步重试
else if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
default:
return (ERR_USB_UNKNOWN); // 不可能的情况
break;
}
}
else
{ // 其它中断,不应该发生的情况
R8_USB2_INT_FG = 0xFF; /* 清中断标志 */
}
mDelayuS(15);
} while(++TransRetry < 3);
return (ERR_USB_TRANSFER); // 应答超时
}
/*********************************************************************
* @fn U2HostCtrlTransfer
*
* @brief 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
*
* @param DataBuf - 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据
* @param RetLen - 实际成功收发的总长度保存在RetLen指向的字节变量中
*
* @return ERR_USB_BUF_OVER IN状态阶段出错
* ERR_SUCCESS 数据交换成功
*/
uint8_t U2HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen)
{
uint16_t RemLen = 0;
uint8_t s, RxLen, RxCnt, TxCnt;
uint8_t *pBuf;
uint8_t *pLen;
pBuf = DataBuf;
pLen = RetLen;
mDelayuS(200);
if(pLen)
*pLen = 0; // 实际成功收发的总长度
R8_U2H_TX_LEN = sizeof(USB_SETUP_REQ);
s = USB2HostTransact(USB_PID_SETUP << 4 | 0x00, 0x00, 200000 / 20); // SETUP阶段,200mS超时
if(s != ERR_SUCCESS)
return (s);
R8_U2H_RX_CTRL = R8_U2H_TX_CTRL = RB_UH_R_TOG | RB_UH_R_AUTO_TOG | RB_UH_T_TOG | RB_UH_T_AUTO_TOG; // 默认DATA1
R8_U2H_TX_LEN = 0x01; // 默认无数据故状态阶段为IN
RemLen = pU2SetupReq->wLength;
if(RemLen && pBuf) // 需要收发数据
{
if(pU2SetupReq->bRequestType & USB_REQ_TYP_IN) // 收
{
while(RemLen)
{
mDelayuS(200);
s = USB2HostTransact(USB_PID_IN << 4 | 0x00, R8_U2H_RX_CTRL, 200000 / 20); // IN数据
if(s != ERR_SUCCESS)
return (s);
RxLen = R8_USB2_RX_LEN < RemLen ? R8_USB2_RX_LEN : RemLen;
RemLen -= RxLen;
if(pLen)
*pLen += RxLen; // 实际成功收发的总长度
for(RxCnt = 0; RxCnt != RxLen; RxCnt++)
{
*pBuf = pU2HOST_RX_RAM_Addr[RxCnt];
pBuf++;
}
if(R8_USB2_RX_LEN == 0 || (R8_USB2_RX_LEN & (Usb2DevEndp0Size - 1)))
break; // 短包
}
R8_U2H_TX_LEN = 0x00; // 状态阶段为OUT
}
else // 发
{
while(RemLen)
{
mDelayuS(200);
R8_U2H_TX_LEN = RemLen >= Usb2DevEndp0Size ? Usb2DevEndp0Size : RemLen;
for(TxCnt = 0; TxCnt != R8_U2H_TX_LEN; TxCnt++)
{
pU2HOST_TX_RAM_Addr[TxCnt] = *pBuf;
pBuf++;
}
s = USB2HostTransact(USB_PID_OUT << 4 | 0x00, R8_U2H_TX_CTRL, 200000 / 20); // OUT数据
if(s != ERR_SUCCESS)
return (s);
RemLen -= R8_U2H_TX_LEN;
if(pLen)
*pLen += R8_U2H_TX_LEN; // 实际成功收发的总长度
}
// R8_U2H_TX_LEN = 0x01; // 状态阶段为IN
}
}
mDelayuS(200);
s = USB2HostTransact((R8_U2H_TX_LEN ? USB_PID_IN << 4 | 0x00 : USB_PID_OUT << 4 | 0x00), RB_UH_R_TOG | RB_UH_T_TOG, 200000 / 20); // STATUS阶段
if(s != ERR_SUCCESS)
return (s);
if(R8_U2H_TX_LEN == 0)
return (ERR_SUCCESS); // 状态OUT
if(R8_USB2_RX_LEN == 0)
return (ERR_SUCCESS); // 状态IN,检查IN状态返回数据长度
return (ERR_USB_BUF_OVER); // IN状态阶段错误
}
/*********************************************************************
* @fn CopyU2SetupReqPkg
*
* @brief 复制控制传输的请求包
*
* @param pReqPkt - 控制请求包地址
*
* @return none
*/
void CopyU2SetupReqPkg(const uint8_t *pReqPkt) // 复制控制传输的请求包
{
uint8_t i;
for(i = 0; i != sizeof(USB_SETUP_REQ); i++)
{
((uint8_t *)pU2SetupReq)[i] = *pReqPkt;
pReqPkt++;
}
}
/*********************************************************************
* @fn CtrlGetU2DeviceDescr
*
* @brief 获取设备描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @param none
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetU2DeviceDescr(void)
{
uint8_t s;
uint8_t len;
Usb2DevEndp0Size = DEFAULT_ENDP0_SIZE;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2DevDescr);
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
Usb2DevEndp0Size = ((PUSB_DEV_DESCR)U2Com_Buffer)->bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndp0Size再继续
if(len < ((PUSB_SETUP_REQ)SetupGetU2DevDescr)->wLength)
return (ERR_USB_BUF_OVER); // 描述符长度错误
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetU2ConfigDescr
*
* @brief 获取配置描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @param none
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetU2ConfigDescr(void)
{
uint8_t s;
uint8_t len;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2CfgDescr);
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
if(len < ((PUSB_SETUP_REQ)SetupGetU2CfgDescr)->wLength)
return (ERR_USB_BUF_OVER); // 返回长度错误
len = ((PUSB_CFG_DESCR)U2Com_Buffer)->wTotalLength;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2CfgDescr);
pU2SetupReq->wLength = len; // 完整配置描述符的总长度
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
#ifdef DISK_BASE_BUF_LEN
if(len > 64)
len = 64;
memcpy(TxBuffer, U2Com_Buffer, len); //U盘操作时需要拷贝到TxBuffer
#endif
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsb2Address
*
* @brief 设置USB设备地址
*
* @param addr - 设备地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsb2Address(uint8_t addr)
{
uint8_t s;
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Addr);
pU2SetupReq->wValue = addr; // USB设备地址
s = U2HostCtrlTransfer(NULL, NULL); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
SetHostUsb2Addr(addr); // 设置USB主机当前操作的USB设备地址
mDelaymS(10); // 等待USB设备完成操作
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsb2Config
*
* @brief 设置USB设备配置
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsb2Config(uint8_t cfg)
{
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Config);
pU2SetupReq->wValue = cfg; // USB设备配置
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlClearU2EndpStall
*
* @brief 清除端点STALL
*
* @param endp - 端点地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlClearU2EndpStall(uint8_t endp)
{
CopyU2SetupReqPkg((uint8_t *)SetupClrU2EndpStall); // 清除端点的错误
pU2SetupReq->wIndex = endp; // 端点地址
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlSetUsb2Intercace
*
* @brief 设置USB设备接口
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsb2Intercace(uint8_t cfg)
{
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Interface);
pU2SetupReq->wValue = cfg; // USB设备配置
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn USB2_HostInit
*
* @brief USB主机功能初始化
*
* @param none
*
* @return none
*/
void USB2_HostInit(void)
{
R8_USB2_CTRL = RB_UC_HOST_MODE;
R8_U2HOST_CTRL = 0;
R8_USB2_DEV_AD = 0x00;
R8_U2H_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
R16_U2H_RX_DMA = (uint16_t)(uint32_t)pU2HOST_RX_RAM_Addr;
R16_U2H_TX_DMA = (uint16_t)(uint32_t)pU2HOST_TX_RAM_Addr;
R8_U2H_RX_CTRL = 0x00;
R8_U2H_TX_CTRL = 0x00;
R8_USB2_CTRL = RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
R8_U2H_SETUP = RB_UH_SOF_EN;
R8_USB2_INT_FG = 0xFF;
DisableRootU2HubPort();
R8_USB2_INT_EN = RB_UIE_TRANSFER | RB_UIE_DETECT;
FoundNewU2Dev = 0;
}

View File

@@ -0,0 +1,826 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbhost.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
#if DISK_LIB_ENABLE
#include "CHRV3UFI.H"
#endif
/* 设置HID上传速率 */
__attribute__((aligned(4))) const uint8_t SetupSetU2HIDIdle[] = {0x21, HID_SET_IDLE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* 获取HID设备报表描述符 */
__attribute__((aligned(4))) const uint8_t SetupGetU2HIDDevReport[] = {0x81, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_REPORT, 0x00, 0x00, 0x41, 0x00};
/* 获取HUB描述符 */
__attribute__((aligned(4))) const uint8_t SetupGetU2HubDescr[] = {HUB_GET_HUB_DESCRIPTOR, HUB_GET_DESCRIPTOR,
0x00, USB_DESCR_TYP_HUB, 0x00, 0x00, sizeof(USB_HUB_DESCR), 0x00};
__attribute__((aligned(4))) uint8_t U2Com_Buffer[128]; // 定义用户临时缓冲区,枚举时用于处理描述符,枚举结束也可以用作普通临时缓冲区
/*********************************************************************
* @fn AnalyzeU2HidIntEndp
*
* @brief 从描述符中分析出HID中断端点的地址,如果HubPortIndex是0保存到ROOTHUB如果是非零值则保存到HUB下结构体
*
* @param buf - 待分析数据缓冲区地址 HubPortIndex0表示根HUB非0表示外部HUB下的端口号
*
* @return 端点数
*/
uint8_t AnalyzeU2HidIntEndp(uint8_t *buf, uint8_t HubPortIndex)
{
uint8_t i, s, l;
s = 0;
if(HubPortIndex)
{
memset(DevOnU2HubPort[HubPortIndex - 1].GpVar, 0, sizeof(DevOnU2HubPort[HubPortIndex - 1].GpVar)); //清空数组
}
else
{
memset(ThisUsb2Dev.GpVar, 0, sizeof(ThisUsb2Dev.GpVar)); //清空数组
}
for(i = 0; i < ((PUSB_CFG_DESCR)buf)->wTotalLength; i += l) // 搜索中断端点描述符,跳过配置描述符和接口描述符
{
if(((PUSB_ENDP_DESCR)(buf + i))->bDescriptorType == USB_DESCR_TYP_ENDP // 是端点描述符
&& (((PUSB_ENDP_DESCR)(buf + i))->bmAttributes & USB_ENDP_TYPE_MASK) == USB_ENDP_TYPE_INTER // 是中断端点
&& (((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)) // 是IN端点
{ // 保存中断端点的地址,位7用于同步标志位,清0
if(HubPortIndex)
{
DevOnU2HubPort[HubPortIndex - 1].GpVar[s] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
ThisUsb2Dev.GpVar[s] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK; // 中断端点的地址可以根据需要保存wMaxPacketSize和bInterval
}
PRINT("%02x ", (uint16_t)ThisUsb2Dev.GpVar[s]);
s++;
if(s >= 4)
{
break; //只分析4个端点
}
}
l = ((PUSB_ENDP_DESCR)(buf + i))->bLength; // 当前描述符长度,跳过
if(l > 16)
{
break;
}
}
PRINT("\n");
return (s);
}
/*********************************************************************
* @fn AnalyzeU2BulkEndp
*
* @brief 分析出批量端点,GpVar[0]、GpVar[1]存放上传端点。GpVar[2]、GpVar[3]存放下传端点
*
* @param buf - 待分析数据缓冲区地址 HubPortIndex0表示根HUB非0表示外部HUB下的端口号
*
* @return 0
*/
uint8_t AnalyzeU2BulkEndp(uint8_t *buf, uint8_t HubPortIndex)
{
uint8_t i, s1, s2, l;
s1 = 0;
s2 = 2;
if(HubPortIndex)
{
memset(DevOnU2HubPort[HubPortIndex - 1].GpVar, 0, sizeof(DevOnU2HubPort[HubPortIndex - 1].GpVar)); //清空数组
}
else
{
memset(ThisUsb2Dev.GpVar, 0, sizeof(ThisUsb2Dev.GpVar)); //清空数组
}
for(i = 0; i < ((PUSB_CFG_DESCR)buf)->wTotalLength; i += l) // 搜索中断端点描述符,跳过配置描述符和接口描述符
{
if((((PUSB_ENDP_DESCR)(buf + i))->bDescriptorType == USB_DESCR_TYP_ENDP) // 是端点描述符
&& ((((PUSB_ENDP_DESCR)(buf + i))->bmAttributes & USB_ENDP_TYPE_MASK) == USB_ENDP_TYPE_BULK)) // 是中断端点
{
if(HubPortIndex)
{
if(((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)
{
DevOnU2HubPort[HubPortIndex - 1].GpVar[s1++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
DevOnU2HubPort[HubPortIndex - 1].GpVar[s2++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
}
else
{
if(((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)
{
ThisUsb2Dev.GpVar[s1++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
ThisUsb2Dev.GpVar[s2++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
}
if(s1 == 2)
{
s1 = 1;
}
if(s2 == 4)
{
s2 = 3;
}
}
l = ((PUSB_ENDP_DESCR)(buf + i))->bLength; // 当前描述符长度,跳过
if(l > 16)
{
break;
}
}
return (0);
}
/*********************************************************************
* @fn InitRootU2Device
*
* @brief 初始化指定ROOT-HUB端口的USB设备
*
* @param none
*
* @return 错误码
*/
uint8_t InitRootU2Device(void)
{
uint8_t i, s;
uint8_t cfg, dv_cls, if_cls;
PRINT("Reset U2 host port\n");
ResetRootU2HubPort(); // 检测到设备后,复位相应端口的USB总线
for(i = 0, s = 0; i < 100; i++)
{ // 等待USB设备复位后重新连接,100mS超时
mDelaymS(1);
if(EnableRootU2HubPort() == ERR_SUCCESS)
{ // 使能端口
i = 0;
s++;
if(s > 100)
break; // 已经稳定连接100mS
}
}
if(i)
{ // 复位后设备没有连接
DisableRootU2HubPort();
PRINT("Disable U2 host port because of disconnect\n");
return (ERR_USB_DISCON);
}
SetUsb2Speed(ThisUsb2Dev.DeviceSpeed); // 设置当前USB速度
PRINT("GetU2DevDescr: ");
s = CtrlGetU2DeviceDescr(); // 获取设备描述符
if(s == ERR_SUCCESS)
{
for(i = 0; i < ((PUSB_SETUP_REQ)SetupGetU2DevDescr)->wLength; i++)
PRINT("x%02X ", (uint16_t)(U2Com_Buffer[i]));
PRINT("\n");
ThisUsb2Dev.DeviceVID = ((PUSB_DEV_DESCR)U2Com_Buffer)->idVendor; //保存VID PID信息
ThisUsb2Dev.DevicePID = ((PUSB_DEV_DESCR)U2Com_Buffer)->idProduct;
dv_cls = ((PUSB_DEV_DESCR)U2Com_Buffer)->bDeviceClass;
s = CtrlSetUsb2Address(((PUSB_SETUP_REQ)SetupSetUsb2Addr)->wValue);
if(s == ERR_SUCCESS)
{
ThisUsb2Dev.DeviceAddress = ((PUSB_SETUP_REQ)SetupSetUsb2Addr)->wValue; // 保存USB地址
PRINT("GetU2CfgDescr: ");
s = CtrlGetU2ConfigDescr();
if(s == ERR_SUCCESS)
{
for(i = 0; i < ((PUSB_CFG_DESCR)U2Com_Buffer)->wTotalLength; i++)
{
PRINT("x%02X ", (uint16_t)(U2Com_Buffer[i]));
}
PRINT("\n");
/* 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等 */
cfg = ((PUSB_CFG_DESCR)U2Com_Buffer)->bConfigurationValue;
if_cls = ((PUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceClass; // 接口类代码
if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_STORAGE))
{ // 是USB存储类设备,基本上确认是U盘
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_USB_ADDR;
return (ERR_SUCCESS);
}
else
return (ERR_USB_UNSUPPORT);
#else
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
ThisUsb2Dev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsb2Dev.DeviceType = USB_DEV_CLASS_STORAGE;
PRINT("U2 USB-Disk Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_PRINTER) && ((PUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceSubClass == 0x01)
{ // 是打印机类设备
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// 需保存端点信息以便主程序进行USB传输
ThisUsb2Dev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsb2Dev.DeviceType = USB_DEV_CLASS_PRINTER;
PRINT("U2 USB-Print Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_HID) && ((PUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceSubClass <= 0x01)
{ // 是HID类设备,键盘/鼠标等
// 从描述符中分析出HID中断端点的地址
s = AnalyzeU2HidIntEndp(U2Com_Buffer, 0); // 从描述符中分析出HID中断端点的地址
PRINT("AnalyzeU2HidIntEndp %02x\n", (uint16_t)s);
// 保存中断端点的地址,位7用于同步标志位,清0
if_cls = ((PUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceProtocol;
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// Set_Idle( );
// 需保存端点信息以便主程序进行USB传输
ThisUsb2Dev.DeviceStatus = ROOT_DEV_SUCCESS;
if(if_cls == 1)
{
ThisUsb2Dev.DeviceType = DEV_TYPE_KEYBOARD;
// 进一步初始化,例如设备键盘指示灯LED等
PRINT("U2 USB-Keyboard Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
else if(if_cls == 2)
{
ThisUsb2Dev.DeviceType = DEV_TYPE_MOUSE;
// 为了以后查询鼠标状态,应该分析描述符,取得中断端口的地址,长度等信息
PRINT("U2 USB-Mouse Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
s = ERR_USB_UNSUPPORT;
}
}
else if(dv_cls == USB_DEV_CLASS_HUB)
{ // 是HUB类设备,集线器等
s = CtrlGetU2HubDescr();
if(s == ERR_SUCCESS)
{
PRINT("Max Port:%02X ", (((PXUSB_HUB_DESCR)U2Com_Buffer)->bNbrPorts));
ThisUsb2Dev.GpHUBPortNum = ((PXUSB_HUB_DESCR)U2Com_Buffer)->bNbrPorts; // 保存HUB的端口数量
if(ThisUsb2Dev.GpHUBPortNum > HUB_MAX_PORTS)
{
ThisUsb2Dev.GpHUBPortNum = HUB_MAX_PORTS; // 因为定义结构DevOnHubPort时人为假定每个HUB不超过HUB_MAX_PORTS个端口
}
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
ThisUsb2Dev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsb2Dev.DeviceType = USB_DEV_CLASS_HUB;
//需保存端点信息以便主程序进行USB传输,本来中断端点可用于HUB事件通知,但本程序使用查询状态控制传输代替
//给HUB各端口上电,查询各端口状态,初始化有设备连接的HUB端口,初始化设备
for(i = 1; i <= ThisUsb2Dev.GpHUBPortNum; i++) // 给HUB各端口都上电
{
DevOnU2HubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 清外部HUB端口上设备的状态
s = U2HubSetPortFeature(i, HUB_PORT_POWER);
if(s != ERR_SUCCESS)
{
PRINT("Ext-HUB Port_%1d# power on error\n", (uint16_t)i); // 端口上电失败
}
}
PRINT("U2 USB-HUB Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
}
else
{ // 可以进一步分析
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// 需保存端点信息以便主程序进行USB传输
ThisUsb2Dev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsb2Dev.DeviceType = DEV_TYPE_UNKNOW;
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS); /* 未知设备初始化成功 */
}
}
#endif
}
}
}
PRINT("InitRootU2Dev Err = %02X\n", (uint16_t)s);
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_CONNECT;
#else
ThisUsb2Dev.DeviceStatus = ROOT_DEV_FAILED;
#endif
SetUsb2Speed(1); // 默认为全速
return (s);
}
/*********************************************************************
* @fn InitU2DevOnHub
*
* @brief 初始化枚举外部HUB后的二级USB设备
*
* @param HubPortIndex - 指定外部HUB
*
* @return 错误码
*/
uint8_t InitU2DevOnHub(uint8_t HubPortIndex)
{
uint8_t i, s, cfg, dv_cls, if_cls;
uint8_t ifc;
PRINT("Init dev @ExtHub-port_%1d ", (uint16_t)HubPortIndex);
if(HubPortIndex == 0)
{
return (ERR_USB_UNKNOWN);
}
SelectU2HubPort(HubPortIndex); // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口,选择速度
PRINT("GetDevDescr: ");
s = CtrlGetU2DeviceDescr(); // 获取设备描述符
if(s != ERR_SUCCESS)
{
return (s);
}
DevOnU2HubPort[HubPortIndex - 1].DeviceVID = ((uint16_t)((PUSB_DEV_DESCR)U2Com_Buffer)->idVendor); //保存VID PID信息
DevOnU2HubPort[HubPortIndex - 1].DevicePID = ((uint16_t)((PUSB_DEV_DESCR)U2Com_Buffer)->idProduct);
dv_cls = ((PUSB_DEV_DESCR)U2Com_Buffer)->bDeviceClass; // 设备类代码
cfg = (1 << 4) + HubPortIndex; // 计算出一个USB地址,避免地址重叠
s = CtrlSetUsb2Address(cfg); // 设置USB设备地址
if(s != ERR_SUCCESS)
{
return (s);
}
DevOnU2HubPort[HubPortIndex - 1].DeviceAddress = cfg; // 保存分配的USB地址
PRINT("GetCfgDescr: ");
s = CtrlGetU2ConfigDescr(); // 获取配置描述符
if(s != ERR_SUCCESS)
{
return (s);
}
cfg = ((PUSB_CFG_DESCR)U2Com_Buffer)->bConfigurationValue;
for(i = 0; i < ((PUSB_CFG_DESCR)U2Com_Buffer)->wTotalLength; i++)
{
PRINT("x%02X ", (uint16_t)(U2Com_Buffer[i]));
}
PRINT("\n");
/* 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等 */
if_cls = ((PXUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceClass; // 接口类代码
if(dv_cls == 0x00 && if_cls == USB_DEV_CLASS_STORAGE) // 是USB存储类设备,基本上确认是U盘
{
AnalyzeU2BulkEndp(U2Com_Buffer, HubPortIndex);
for(i = 0; i != 4; i++)
{
PRINT("%02x ", (uint16_t)DevOnU2HubPort[HubPortIndex - 1].GpVar[i]);
}
PRINT("\n");
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
DevOnU2HubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
DevOnU2HubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_STORAGE;
PRINT("USB-Disk Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_HID) && (((PXUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceSubClass <= 0x01)) // 是HID类设备,键盘/鼠标等
{
ifc = ((PXUSB_CFG_DESCR_LONG)U2Com_Buffer)->cfg_descr.bNumInterfaces;
s = AnalyzeU2HidIntEndp(U2Com_Buffer, HubPortIndex); // 从描述符中分析出HID中断端点的地址
PRINT("AnalyzeU2HidIntEndp %02x\n", (uint16_t)s);
if_cls = ((PXUSB_CFG_DESCR_LONG)U2Com_Buffer)->itf_descr.bInterfaceProtocol;
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
for(dv_cls = 0; dv_cls < ifc; dv_cls++)
{
s = CtrlGetU2HIDDeviceReport(dv_cls); //获取报表描述符
if(s == ERR_SUCCESS)
{
for(i = 0; i < 64; i++)
{
PRINT("x%02X ", (uint16_t)(U2Com_Buffer[i]));
}
PRINT("\n");
}
}
//需保存端点信息以便主程序进行USB传输
DevOnU2HubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
if(if_cls == 1)
{
DevOnU2HubPort[HubPortIndex - 1].DeviceType = DEV_TYPE_KEYBOARD;
//进一步初始化,例如设备键盘指示灯LED等
if(ifc > 1)
{
PRINT("USB_DEV_CLASS_HID Ready\n");
// DevOnU2HubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HID; //复合HID设备
}
PRINT("USB-Keyboard Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
else if(if_cls == 2)
{
DevOnU2HubPort[HubPortIndex - 1].DeviceType = DEV_TYPE_MOUSE;
//为了以后查询鼠标状态,应该分析描述符,取得中断端口的地址,长度等信息
if(ifc > 1)
{
PRINT("USB_DEV_CLASS_HID Ready\n");
// DevOnU2HubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HID; //复合HID设备
}
PRINT("USB-Mouse Ready\n");
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS);
}
s = ERR_USB_UNSUPPORT;
}
}
else if(dv_cls == USB_DEV_CLASS_HUB) // 是HUB类设备,集线器等
{
DevOnU2HubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HUB;
PRINT("This program don't support Level 2 HUB\n"); // 需要支持多级HUB级联请参考本程序进行扩展
s = U2HubClearPortFeature(i, HUB_PORT_ENABLE); // 禁止HUB端口
if(s != ERR_SUCCESS)
{
return (s);
}
s = ERR_USB_UNSUPPORT;
}
else //其他设备
{
AnalyzeU2BulkEndp(U2Com_Buffer, HubPortIndex); //分析出批量端点
for(i = 0; i != 4; i++)
{
PRINT("%02x ", (uint16_t)DevOnU2HubPort[HubPortIndex - 1].GpVar[i]);
}
PRINT("\n");
s = CtrlSetUsb2Config(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
//需保存端点信息以便主程序进行USB传输
DevOnU2HubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
DevOnU2HubPort[HubPortIndex - 1].DeviceType = dv_cls ? dv_cls : if_cls;
SetUsb2Speed(1); // 默认为全速
return (ERR_SUCCESS); //未知设备初始化成功
}
}
PRINT("InitDevOnHub Err = %02X\n", (uint16_t)s);
DevOnU2HubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_FAILED;
SetUsb2Speed(1); // 默认为全速
return (s);
}
/*********************************************************************
* @fn EnumU2HubPort
*
* @brief 枚举指定ROOT-HUB端口上的外部HUB集线器的各个端口,检查各端口有无连接或移除事件并初始化二级USB设备
*
* @param RootHubIndex - ROOT_HUB0和ROOT_HUB1
*
* @return 错误码
*/
uint8_t EnumU2HubPort()
{
uint8_t i, s;
for(i = 1; i <= ThisUsb2Dev.GpHUBPortNum; i++) // 查询集线器的端口是否有变化
{
SelectU2HubPort(0); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
s = U2HubGetPortStatus(i); // 获取端口状态
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
if(((U2Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) && (U2Com_Buffer[2] & (1 << (HUB_C_PORT_CONNECTION & 0x07)))) || (U2Com_Buffer[2] == 0x10))
{ // 发现有设备连接
DevOnU2HubPort[i - 1].DeviceStatus = ROOT_DEV_CONNECTED; // 有设备连接
DevOnU2HubPort[i - 1].DeviceAddress = 0x00;
s = U2HubGetPortStatus(i); // 获取端口状态
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
DevOnU2HubPort[i - 1].DeviceSpeed = U2Com_Buffer[1] & (1 << (HUB_PORT_LOW_SPEED & 0x07)) ? 0 : 1; // 低速还是全速
if(DevOnU2HubPort[i - 1].DeviceSpeed)
{
PRINT("Found full speed device on port %1d\n", (uint16_t)i);
}
else
{
PRINT("Found low speed device on port %1d\n", (uint16_t)i);
}
mDelaymS(200); // 等待设备上电稳定
s = U2HubSetPortFeature(i, HUB_PORT_RESET); // 对有设备连接的端口复位
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
PRINT("Reset port and then wait in\n");
do // 查询复位端口,直到复位完成,把完成后的状态显示出来
{
mDelaymS(1);
s = U2HubGetPortStatus(i);
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
} while(U2Com_Buffer[0] & (1 << (HUB_PORT_RESET & 0x07))); // 端口正在复位则等待
mDelaymS(100);
s = U2HubClearPortFeature(i, HUB_C_PORT_RESET); // 清除复位完成标志
// s = U2HubSetPortFeature( i, HUB_PORT_ENABLE ); // 启用HUB端口
s = U2HubClearPortFeature(i, HUB_C_PORT_CONNECTION); // 清除连接或移除变化标志
if(s != ERR_SUCCESS)
{
return (s);
}
s = U2HubGetPortStatus(i); // 再读取状态,复查设备是否还在
if(s != ERR_SUCCESS)
{
return (s);
}
if((U2Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) == 0)
{
DevOnU2HubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 设备不在了
}
s = InitU2DevOnHub(i); // 初始化二级USB设备
if(s != ERR_SUCCESS)
{
return (s);
}
SetUsb2Speed(1); // 默认为全速
}
else if(U2Com_Buffer[2] & (1 << (HUB_C_PORT_ENABLE & 0x07))) // 设备连接出错
{
U2HubClearPortFeature(i, HUB_C_PORT_ENABLE); // 清除连接错误标志
PRINT("Device on port error\n");
s = U2HubSetPortFeature(i, HUB_PORT_RESET); // 对有设备连接的端口复位
if(s != ERR_SUCCESS)
return (s); // 可能是该HUB断开了
do // 查询复位端口,直到复位完成,把完成后的状态显示出来
{
mDelaymS(1);
s = U2HubGetPortStatus(i);
if(s != ERR_SUCCESS)
return (s); // 可能是该HUB断开了
} while(U2Com_Buffer[0] & (1 << (HUB_PORT_RESET & 0x07))); // 端口正在复位则等待
}
else if((U2Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) == 0) // 设备已经断开
{
if(DevOnU2HubPort[i - 1].DeviceStatus >= ROOT_DEV_CONNECTED)
{
PRINT("Device on port %1d removed\n", (uint16_t)i);
}
DevOnU2HubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 有设备连接
if(U2Com_Buffer[2] & (1 << (HUB_C_PORT_CONNECTION & 0x07)))
{
U2HubClearPortFeature(i, HUB_C_PORT_CONNECTION); // 清除移除变化标志
}
}
}
return (ERR_SUCCESS); // 返回操作成功
}
/*********************************************************************
* @fn EnumAllU2HubPort
*
* @brief 枚举所有ROOT-HUB端口下外部HUB后的二级USB设备
*
* @return 错误码
*/
uint8_t EnumAllU2HubPort(void)
{
uint8_t s;
if((ThisUsb2Dev.DeviceStatus >= ROOT_DEV_SUCCESS) && (ThisUsb2Dev.DeviceType == USB_DEV_CLASS_HUB)) // HUB枚举成功
{
SelectU2HubPort(0); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
s = EnumU2HubPort(); // 枚举指定ROOT-HUB端口上的外部HUB集线器的各个端口,检查各端口有无连接或移除事件
if(s != ERR_SUCCESS) // 可能是HUB断开了
{
PRINT("EnumAllHubPort err = %02X\n", (uint16_t)s);
}
SetUsb2Speed(1); // 默认为全速
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn U2SearchTypeDevice
*
* @brief 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号,输出端口号为0xFFFF则未搜索到.
* 当然也可以根据USB的厂商VID产品PID进行搜索(事先要记录各设备的VID和PID),以及指定搜索序号
*
* @param type - 搜索的设备类型
*
* @return 输出高8位为ROOT-HUB端口号,低8位为外部HUB的端口号,低8位为0则设备直接在ROOT-HUB端口上
*/
uint16_t U2SearchTypeDevice(uint8_t type)
{
uint8_t RootHubIndex; //CH554只有一个USB口,RootHubIndex = 0,只需看返回值的低八位即可
uint8_t HubPortIndex;
RootHubIndex = 0;
if((ThisUsb2Dev.DeviceType == USB_DEV_CLASS_HUB) && (ThisUsb2Dev.DeviceStatus >= ROOT_DEV_SUCCESS)) // 外部集线器HUB且枚举成功
{
for(HubPortIndex = 1; HubPortIndex <= ThisUsb2Dev.GpHUBPortNum; HubPortIndex++) // 搜索外部HUB的各个端口
{
if(DevOnU2HubPort[HubPortIndex - 1].DeviceType == type && DevOnU2HubPort[HubPortIndex - 1].DeviceStatus >= ROOT_DEV_SUCCESS)
{
return (((uint16_t)RootHubIndex << 8) | HubPortIndex); // 类型匹配且枚举成功
}
}
}
if((ThisUsb2Dev.DeviceType == type) && (ThisUsb2Dev.DeviceStatus >= ROOT_DEV_SUCCESS))
{
return ((uint16_t)RootHubIndex << 8); // 类型匹配且枚举成功,在ROOT-HUB端口上
}
return (0xFFFF);
}
/*********************************************************************
* @fn U2SETorOFFNumLock
*
* @brief NumLock的点灯判断
*
* @param buf - 点灯键值
*
* @return 错误码
*/
uint8_t U2SETorOFFNumLock(uint8_t *buf)
{
uint8_t tmp[] = {0x21, 0x09, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00};
uint8_t len, s;
if((buf[2] == 0x53) & ((buf[0] | buf[1] | buf[3] | buf[4] | buf[5] | buf[6] | buf[7]) == 0))
{
for(s = 0; s != sizeof(tmp); s++)
{
((uint8_t *)pU2SetupReq)[s] = tmp[s];
}
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetU2HIDDeviceReport
*
* @brief 获取HID设备报表描述符,返回在TxBuffer中
*
* @param none
*
* @return 错误码
*/
uint8_t CtrlGetU2HIDDeviceReport(uint8_t infc)
{
uint8_t s;
uint8_t len;
CopyU2SetupReqPkg((uint8_t *)SetupSetU2HIDIdle);
pU2SetupReq->wIndex = infc;
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
CopyU2SetupReqPkg((uint8_t *)SetupGetU2HIDDevReport);
pU2SetupReq->wIndex = infc;
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetU2HubDescr
*
* @brief 获取HUB描述符,返回在Com_Buffer中
*
* @param none
*
* @return 错误码
*/
uint8_t CtrlGetU2HubDescr(void)
{
uint8_t s;
uint8_t len;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2HubDescr);
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
if(len < ((PUSB_SETUP_REQ)SetupGetU2HubDescr)->wLength)
{
return (ERR_USB_BUF_OVER); // 描述符长度错误
}
// if ( len < 4 ) return( ERR_USB_BUF_OVER ); // 描述符长度错误
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn U2HubGetPortStatus
*
* @brief 查询HUB端口状态,返回在Com_Buffer中
*
* @param HubPortIndex - 端口号
*
* @return 错误码
*/
uint8_t U2HubGetPortStatus(uint8_t HubPortIndex)
{
uint8_t s;
uint8_t len;
pU2SetupReq->bRequestType = HUB_GET_PORT_STATUS;
pU2SetupReq->bRequest = HUB_GET_STATUS;
pU2SetupReq->wValue = 0x0000;
pU2SetupReq->wIndex = 0x0000 | HubPortIndex;
pU2SetupReq->wLength = 0x0004;
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
if(len < 4)
{
return (ERR_USB_BUF_OVER); // 描述符长度错误
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn U2HubSetPortFeature
*
* @brief 设置HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t U2HubSetPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt)
{
pU2SetupReq->bRequestType = HUB_SET_PORT_FEATURE;
pU2SetupReq->bRequest = HUB_SET_FEATURE;
pU2SetupReq->wValue = 0x0000 | FeatureSelt;
pU2SetupReq->wIndex = 0x0000 | HubPortIndex;
pU2SetupReq->wLength = 0x0000;
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn U2HubClearPortFeature
*
* @brief 清除HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t U2HubClearPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt)
{
pU2SetupReq->bRequestType = HUB_CLEAR_PORT_FEATURE;
pU2SetupReq->bRequest = HUB_CLEAR_FEATURE;
pU2SetupReq->wValue = 0x0000 | FeatureSelt;
pU2SetupReq->wIndex = 0x0000 | HubPortIndex;
pU2SetupReq->wLength = 0x0000;
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}

View File

@@ -0,0 +1,113 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbdev.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
uint8_t *pEP0_RAM_Addr;
uint8_t *pEP1_RAM_Addr;
uint8_t *pEP2_RAM_Addr;
uint8_t *pEP3_RAM_Addr;
/*********************************************************************
* @fn USB_DeviceInit
*
* @brief USB设备功能初始化4个端点8个通道。
*
* @param none
*
* @return none
*/
void USB_DeviceInit(void)
{
R8_USB_CTRL = 0x00; // 先设定模式,取消 RB_UC_CLR_ALL
R8_UEP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN | RB_UEP1_RX_EN | RB_UEP1_TX_EN; // 端点4 OUT+IN,端点1 OUT+IN
R8_UEP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN | RB_UEP3_RX_EN | RB_UEP3_TX_EN; // 端点2 OUT+IN,端点3 OUT+IN
R16_UEP0_DMA = (uint16_t)(uint32_t)pEP0_RAM_Addr;
R16_UEP1_DMA = (uint16_t)(uint32_t)pEP1_RAM_Addr;
R16_UEP2_DMA = (uint16_t)(uint32_t)pEP2_RAM_Addr;
R16_UEP3_DMA = (uint16_t)(uint32_t)pEP3_RAM_Addr;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_UEP4_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_USB_DEV_AD = 0x00;
R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN; // 启动USB设备及DMA在中断期间中断标志未清除前自动返回NAK
R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU; // 防止USB端口浮空及上拉电阻
R8_USB_INT_FG = 0xFF; // 清中断标志
R8_UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN; // 允许USB端口
R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
}
/*********************************************************************
* @fn DevEP1_IN_Deal
*
* @brief 端点1数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void DevEP1_IN_Deal(uint8_t l)
{
R8_UEP1_T_LEN = l;
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn DevEP2_IN_Deal
*
* @brief 端点2数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void DevEP2_IN_Deal(uint8_t l)
{
R8_UEP2_T_LEN = l;
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn DevEP3_IN_Deal
*
* @brief 端点3数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void DevEP3_IN_Deal(uint8_t l)
{
R8_UEP3_T_LEN = l;
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}
/*********************************************************************
* @fn DevEP4_IN_Deal
*
* @brief 端点4数据上传
*
* @param l - 上传数据长度(<64B)
*
* @return none
*/
void DevEP4_IN_Deal(uint8_t l)
{
R8_UEP4_T_LEN = l;
R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
}

View File

@@ -0,0 +1,692 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbhost.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
#if DISK_LIB_ENABLE
#include "CHRV3UFI.H"
#endif
uint8_t UsbDevEndp0Size; // USB设备的端点0的最大包尺寸
uint8_t FoundNewDev;
_RootHubDev ThisUsbDev; //ROOT口
_DevOnHubPort DevOnHubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
uint8_t *pHOST_RX_RAM_Addr;
uint8_t *pHOST_TX_RAM_Addr;
/*获取设备描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetDevDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof(USB_DEV_DESCR), 0x00};
/*获取配置描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetCfgDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00};
/*设置USB地址*/
__attribute__((aligned(4))) const uint8_t SetupSetUsbAddr[] = {USB_REQ_TYP_OUT, USB_SET_ADDRESS, USB_DEVICE_ADDR, 0x00,
0x00, 0x00, 0x00, 0x00};
/*设置USB配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsbConfig[] = {USB_REQ_TYP_OUT, USB_SET_CONFIGURATION, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00};
/*设置USB接口配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsbInterface[] = {USB_REQ_RECIP_INTERF, USB_SET_INTERFACE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
/*清除端点STALL*/
__attribute__((aligned(4))) const uint8_t SetupClrEndpStall[] = {USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*********************************************************************
* @fn DisableRootHubPort
*
* @brief 关闭ROOT-HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
*
* @param none
*
* @return none
*/
void DisableRootHubPort(void)
{
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_DISCONNECT;
#endif
#ifndef DISK_BASE_BUF_LEN
ThisUsbDev.DeviceStatus = ROOT_DEV_DISCONNECT;
ThisUsbDev.DeviceAddress = 0x00;
#endif
}
/*********************************************************************
* @fn AnalyzeRootHub
*
* @brief 分析ROOT-HUB状态,处理ROOT-HUB端口的设备插拔事件
* 如果设备拔出,函数中调用DisableRootHubPort()函数,将端口关闭,插入事件,置相应端口的状态位
*
* @param none
*
* @return 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
*/
uint8_t AnalyzeRootHub(void)
{
uint8_t s;
s = ERR_SUCCESS;
if(R8_USB_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 设备存在
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT
#else
if(ThisUsbDev.DeviceStatus == ROOT_DEV_DISCONNECT // 检测到有设备插入
#endif
|| (R8_UHOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 检测到有设备插入,但尚未允许,说明是刚插入
DisableRootHubPort(); // 关闭端口
#ifdef DISK_BASE_BUF_LEN
CHRV3DiskStatus = DISK_CONNECT;
#else
ThisUsbDev.DeviceSpeed = R8_USB_MIS_ST & RB_UMS_DM_LEVEL ? 0 : 1;
ThisUsbDev.DeviceStatus = ROOT_DEV_CONNECTED; //置连接标志
#endif
PRINT("USB dev in\n");
s = ERR_USB_CONNECT;
}
}
#ifdef DISK_BASE_BUF_LEN
else if(CHRV3DiskStatus >= DISK_CONNECT)
{
#else
else if(ThisUsbDev.DeviceStatus >= ROOT_DEV_CONNECTED)
{ //检测到设备拔出
#endif
DisableRootHubPort(); // 关闭端口
PRINT("USB dev out\n");
if(s == ERR_SUCCESS)
{
s = ERR_USB_DISCON;
}
}
// R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
return (s);
}
/*********************************************************************
* @fn SetHostUsbAddr
*
* @brief 设置USB主机当前操作的USB设备地址
*
* @param addr - USB设备地址
*
* @return none
*/
void SetHostUsbAddr(uint8_t addr)
{
R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | (addr & MASK_USB_ADDR);
}
/*********************************************************************
* @fn SetUsbSpeed
*
* @brief 设置当前USB速度
*
* @param FullSpeed - USB速度
*
* @return none
*/
void SetUsbSpeed(uint8_t FullSpeed)
{
#ifndef DISK_BASE_BUF_LEN
if(FullSpeed) // 全速
{
R8_USB_CTRL &= ~RB_UC_LOW_SPEED; // 全速
R8_UH_SETUP &= ~RB_UH_PRE_PID_EN; // 禁止PRE PID
}
else
{
R8_USB_CTRL |= RB_UC_LOW_SPEED; // 低速
}
#endif
(void)FullSpeed;
}
/*********************************************************************
* @fn ResetRootHubPort
*
* @brief 检测到设备后,复位总线,为枚举设备准备,设置为默认为全速
*
* @param none
*
* @return none
*/
void ResetRootHubPort(void)
{
UsbDevEndp0Size = DEFAULT_ENDP0_SIZE; //USB设备的端点0的最大包尺寸
SetHostUsbAddr(0x00);
R8_UHOST_CTRL &= ~RB_UH_PORT_EN; // 关掉端口
SetUsbSpeed(1); // 默认为全速
R8_UHOST_CTRL = (R8_UHOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为全速,开始复位
mDelaymS(15); // 复位时间10mS到20mS
R8_UHOST_CTRL = R8_UHOST_CTRL & ~RB_UH_BUS_RESET; // 结束复位
mDelayuS(250);
R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
}
/*********************************************************************
* @fn EnableRootHubPort
*
* @brief 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
*
* @param none
*
* @return 返回ERR_SUCCESS为检测到新连接,返回ERR_USB_DISCON为无连接
*/
uint8_t EnableRootHubPort(void)
{
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus < DISK_CONNECT)
CHRV3DiskStatus = DISK_CONNECT;
#else
if(ThisUsbDev.DeviceStatus < ROOT_DEV_CONNECTED)
ThisUsbDev.DeviceStatus = ROOT_DEV_CONNECTED;
#endif
if(R8_USB_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 有设备
#ifndef DISK_BASE_BUF_LEN
if((R8_UHOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 尚未使能
ThisUsbDev.DeviceSpeed = (R8_USB_MIS_ST & RB_UMS_DM_LEVEL) ? 0 : 1;
if(ThisUsbDev.DeviceSpeed == 0)
{
R8_UHOST_CTRL |= RB_UH_LOW_SPEED; // 低速
}
}
#endif
R8_UHOST_CTRL |= RB_UH_PORT_EN; //使能HUB端口
return (ERR_SUCCESS);
}
return (ERR_USB_DISCON);
}
#ifndef DISK_BASE_BUF_LEN
/*********************************************************************
* @fn SelectHubPort
*
* @brief 选定需要操作的HUB口
*
* @param HubPortIndex - 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
*
* @return None
*/
void SelectHubPort(uint8_t HubPortIndex)
{
if(HubPortIndex) // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
{
SetHostUsbAddr(DevOnHubPort[HubPortIndex - 1].DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsbSpeed(DevOnHubPort[HubPortIndex - 1].DeviceSpeed); // 设置当前USB速度
if(DevOnHubPort[HubPortIndex - 1].DeviceSpeed == 0) // 通过外部HUB与低速USB设备通讯需要前置ID
{
R8_UEP1_CTRL |= RB_UH_PRE_PID_EN; // 启用PRE PID
mDelayuS(100);
}
}
else
{
SetHostUsbAddr(ThisUsbDev.DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsbSpeed(ThisUsbDev.DeviceSpeed); // 设置USB设备的速度
}
}
#endif
/*********************************************************************
* @fn WaitUSB_Interrupt
*
* @brief 等待USB中断
*
* @param none
*
* @return 返回ERR_SUCCESS 数据接收或者发送成功,返回ERR_USB_UNKNOWN 数据接收或者发送失败
*/
uint8_t WaitUSB_Interrupt(void)
{
uint16_t i;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB_INT_FG & RB_UIF_TRANSFER) == 0; i--)
{
;
}
return ((R8_USB_INT_FG & RB_UIF_TRANSFER) ? ERR_SUCCESS : ERR_USB_UNKNOWN);
}
/*********************************************************************
* @fn USBHostTransact
*
* @brief 传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
* 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化
*
* @param endp_pid - 令牌和地址, 高4位是token_pid令牌, 低4位是端点地址
* @param tog - 同步标志
* @param timeout - 超时时间
*
* @return ERR_USB_UNKNOWN 超时,可能硬件异常
* ERR_USB_DISCON 设备断开
* ERR_USB_CONNECT 设备连接
* ERR_SUCCESS 传输完成
*/
uint8_t USBHostTransact(uint8_t endp_pid, uint8_t tog, uint32_t timeout)
{
uint8_t TransRetry;
uint8_t s, r;
uint16_t i;
R8_UH_RX_CTRL = R8_UH_TX_CTRL = tog;
TransRetry = 0;
do
{
R8_UH_EP_PID = endp_pid; // 指定令牌PID和目的端点号
R8_USB_INT_FG = RB_UIF_TRANSFER;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB_INT_FG & RB_UIF_TRANSFER) == 0; i--)
{
;
}
R8_UH_EP_PID = 0x00; // 停止USB传输
if((R8_USB_INT_FG & RB_UIF_TRANSFER) == 0)
{
return (ERR_USB_UNKNOWN);
}
if(R8_USB_INT_FG & RB_UIF_DETECT)
{ // USB设备插拔事件
// mDelayuS( 200 ); // 等待传输完成
R8_USB_INT_FG = RB_UIF_DETECT;
s = AnalyzeRootHub(); // 分析ROOT-HUB状态
if(s == ERR_USB_CONNECT)
FoundNewDev = 1;
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(CHRV3DiskStatus == DISK_CONNECT)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#else
if(ThisUsbDev.DeviceStatus == ROOT_DEV_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(ThisUsbDev.DeviceStatus == ROOT_DEV_CONNECTED)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#endif
mDelayuS(200); // 等待传输完成
}
if(R8_USB_INT_FG & RB_UIF_TRANSFER) // 传输完成事件
{
if(R8_USB_INT_ST & RB_UIS_TOG_OK)
{
return (ERR_SUCCESS);
}
r = R8_USB_INT_ST & MASK_UIS_H_RES; // USB设备应答状态
if(r == USB_PID_STALL)
{
return (r | ERR_USB_TRANSFER);
}
if(r == USB_PID_NAK)
{
if(timeout == 0)
{
return (r | ERR_USB_TRANSFER);
}
if(timeout < 0xFFFFFFFF)
{
timeout--;
}
--TransRetry;
}
else
switch(endp_pid >> 4)
{
case USB_PID_SETUP:
case USB_PID_OUT:
if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
case USB_PID_IN:
if(r == USB_PID_DATA0 || r == USB_PID_DATA1)
{ // 不同步则需丢弃后重试
} // 不同步重试
else if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
default:
return (ERR_USB_UNKNOWN); // 不可能的情况
break;
}
}
else
{ // 其它中断,不应该发生的情况
R8_USB_INT_FG = 0xFF; /* 清中断标志 */
}
mDelayuS(15);
} while(++TransRetry < 3);
return (ERR_USB_TRANSFER); // 应答超时
}
/*********************************************************************
* @fn HostCtrlTransfer
*
* @brief 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
*
* @param DataBuf - 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据
* @param RetLen - 实际成功收发的总长度保存在RetLen指向的字节变量中
*
* @return ERR_USB_BUF_OVER IN状态阶段出错
* ERR_SUCCESS 数据交换成功
*/
uint8_t HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen)
{
uint16_t RemLen = 0;
uint8_t s, RxLen, RxCnt, TxCnt;
uint8_t *pBuf;
uint8_t *pLen;
pBuf = DataBuf;
pLen = RetLen;
mDelayuS(200);
if(pLen)
{
*pLen = 0; // 实际成功收发的总长度
}
R8_UH_TX_LEN = sizeof(USB_SETUP_REQ);
s = USBHostTransact(USB_PID_SETUP << 4 | 0x00, 0x00, 200000 / 20); // SETUP阶段,200mS超时
if(s != ERR_SUCCESS)
{
return (s);
}
R8_UH_RX_CTRL = R8_UH_TX_CTRL = RB_UH_R_TOG | RB_UH_R_AUTO_TOG | RB_UH_T_TOG | RB_UH_T_AUTO_TOG; // 默认DATA1
R8_UH_TX_LEN = 0x01; // 默认无数据故状态阶段为IN
RemLen = pSetupReq->wLength;
if(RemLen && pBuf) // 需要收发数据
{
if(pSetupReq->bRequestType & USB_REQ_TYP_IN) // 收
{
while(RemLen)
{
mDelayuS(200);
s = USBHostTransact(USB_PID_IN << 4 | 0x00, R8_UH_RX_CTRL, 200000 / 20); // IN数据
if(s != ERR_SUCCESS)
{
return (s);
}
RxLen = R8_USB_RX_LEN < RemLen ? R8_USB_RX_LEN : RemLen;
RemLen -= RxLen;
if(pLen)
{
*pLen += RxLen; // 实际成功收发的总长度
}
for(RxCnt = 0; RxCnt != RxLen; RxCnt++)
{
*pBuf = pHOST_RX_RAM_Addr[RxCnt];
pBuf++;
}
if(R8_USB_RX_LEN == 0 || (R8_USB_RX_LEN & (UsbDevEndp0Size - 1)))
{
break; // 短包
}
}
R8_UH_TX_LEN = 0x00; // 状态阶段为OUT
}
else // 发
{
while(RemLen)
{
mDelayuS(200);
R8_UH_TX_LEN = RemLen >= UsbDevEndp0Size ? UsbDevEndp0Size : RemLen;
for(TxCnt = 0; TxCnt != R8_UH_TX_LEN; TxCnt++)
{
pHOST_TX_RAM_Addr[TxCnt] = *pBuf;
pBuf++;
}
s = USBHostTransact(USB_PID_OUT << 4 | 0x00, R8_UH_TX_CTRL, 200000 / 20); // OUT数据
if(s != ERR_SUCCESS)
{
return (s);
}
RemLen -= R8_UH_TX_LEN;
if(pLen)
{
*pLen += R8_UH_TX_LEN; // 实际成功收发的总长度
}
}
// R8_UH_TX_LEN = 0x01; // 状态阶段为IN
}
}
mDelayuS(200);
s = USBHostTransact((R8_UH_TX_LEN ? USB_PID_IN << 4 | 0x00 : USB_PID_OUT << 4 | 0x00), RB_UH_R_TOG | RB_UH_T_TOG, 200000 / 20); // STATUS阶段
if(s != ERR_SUCCESS)
{
return (s);
}
if(R8_UH_TX_LEN == 0)
{
return (ERR_SUCCESS); // 状态OUT
}
if(R8_USB_RX_LEN == 0)
{
return (ERR_SUCCESS); // 状态IN,检查IN状态返回数据长度
}
return (ERR_USB_BUF_OVER); // IN状态阶段错误
}
/*********************************************************************
* @fn CopySetupReqPkg
*
* @brief 复制控制传输的请求包
*
* @param pReqPkt - 控制请求包地址
*
* @return none
*/
void CopySetupReqPkg(const uint8_t *pReqPkt) // 复制控制传输的请求包
{
uint8_t i;
for(i = 0; i != sizeof(USB_SETUP_REQ); i++)
{
((uint8_t *)pSetupReq)[i] = *pReqPkt;
pReqPkt++;
}
}
/*********************************************************************
* @fn CtrlGetDeviceDescr
*
* @brief 获取设备描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @param none
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetDeviceDescr(void)
{
uint8_t s;
uint8_t len;
UsbDevEndp0Size = DEFAULT_ENDP0_SIZE;
CopySetupReqPkg(SetupGetDevDescr);
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
UsbDevEndp0Size = ((PUSB_DEV_DESCR)Com_Buffer)->bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndp0Size再继续
if(len < ((PUSB_SETUP_REQ)SetupGetDevDescr)->wLength)
{
return (ERR_USB_BUF_OVER); // 描述符长度错误
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetConfigDescr
*
* @brief 获取配置描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @param none
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetConfigDescr(void)
{
uint8_t s;
uint8_t len;
CopySetupReqPkg(SetupGetCfgDescr);
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
if(len < ((PUSB_SETUP_REQ)SetupGetCfgDescr)->wLength)
{
return (ERR_USB_BUF_OVER); // 返回长度错误
}
len = ((PUSB_CFG_DESCR)Com_Buffer)->wTotalLength;
CopySetupReqPkg(SetupGetCfgDescr);
pSetupReq->wLength = len; // 完整配置描述符的总长度
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
#ifdef DISK_BASE_BUF_LEN
if(len > 64)
len = 64;
memcpy(TxBuffer, Com_Buffer, len); //U盘操作时需要拷贝到TxBuffer
#endif
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsbAddress
*
* @brief 设置USB设备地址
*
* @param addr - 设备地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbAddress(uint8_t addr)
{
uint8_t s;
CopySetupReqPkg(SetupSetUsbAddr);
pSetupReq->wValue = addr; // USB设备地址
s = HostCtrlTransfer(NULL, NULL); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
SetHostUsbAddr(addr); // 设置USB主机当前操作的USB设备地址
mDelaymS(10); // 等待USB设备完成操作
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsbConfig
*
* @brief 设置USB设备配置
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbConfig(uint8_t cfg)
{
CopySetupReqPkg(SetupSetUsbConfig);
pSetupReq->wValue = cfg; // USB设备配置
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlClearEndpStall
*
* @brief 清除端点STALL
*
* @param endp - 端点地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlClearEndpStall(uint8_t endp)
{
CopySetupReqPkg(SetupClrEndpStall); // 清除端点的错误
pSetupReq->wIndex = endp; // 端点地址
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlSetUsbIntercace
*
* @brief 设置USB设备接口
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbIntercace(uint8_t cfg)
{
CopySetupReqPkg(SetupSetUsbInterface);
pSetupReq->wValue = cfg; // USB设备配置
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn USB_HostInit
*
* @brief USB主机功能初始化
*
* @param none
*
* @return none
*/
void USB_HostInit(void)
{
R8_USB_CTRL = RB_UC_HOST_MODE;
R8_UHOST_CTRL = 0;
R8_USB_DEV_AD = 0x00;
R8_UH_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
R16_UH_RX_DMA = (uint16_t)(uint32_t)pHOST_RX_RAM_Addr;
R16_UH_TX_DMA = (uint16_t)(uint32_t)pHOST_TX_RAM_Addr;
R8_UH_RX_CTRL = 0x00;
R8_UH_TX_CTRL = 0x00;
R8_USB_CTRL = RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
R8_UH_SETUP = RB_UH_SOF_EN;
R8_USB_INT_FG = 0xFF;
DisableRootHubPort();
R8_USB_INT_EN = RB_UIE_TRANSFER | RB_UIE_DETECT;
FoundNewDev = 0;
}

View File

@@ -0,0 +1,832 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbhost.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "CH58x_common.h"
#if DISK_LIB_ENABLE
#include "CHRV3UFI.H"
#endif
/* 设置HID上传速率 */
__attribute__((aligned(4))) const uint8_t SetupSetHIDIdle[] = {0x21, HID_SET_IDLE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* 获取HID设备报表描述符 */
__attribute__((aligned(4))) const uint8_t SetupGetHIDDevReport[] = {0x81, USB_GET_DESCRIPTOR, 0x00, USB_DESCR_TYP_REPORT,
0x00, 0x00, 0x41, 0x00};
/* 获取HUB描述符 */
__attribute__((aligned(4))) const uint8_t SetupGetHubDescr[] = {HUB_GET_HUB_DESCRIPTOR, HUB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_HUB, 0x00, 0x00, sizeof(USB_HUB_DESCR), 0x00};
__attribute__((aligned(4))) uint8_t Com_Buffer[128]; // 定义用户临时缓冲区,枚举时用于处理描述符,枚举结束也可以用作普通临时缓冲区
/*********************************************************************
* @fn AnalyzeHidIntEndp
*
* @brief 从描述符中分析出HID中断端点的地址,如果HubPortIndex是0保存到ROOTHUB如果是非零值则保存到HUB下结构体
*
* @param buf - 待分析数据缓冲区地址 HubPortIndex0表示根HUB非0表示外部HUB下的端口号
*
* @return 端点数
*/
uint8_t AnalyzeHidIntEndp(uint8_t *buf, uint8_t HubPortIndex)
{
uint8_t i, s, l;
s = 0;
if(HubPortIndex)
{
memset(DevOnHubPort[HubPortIndex - 1].GpVar, 0, sizeof(DevOnHubPort[HubPortIndex - 1].GpVar)); //清空数组
}
else
{
memset(ThisUsbDev.GpVar, 0, sizeof(ThisUsbDev.GpVar)); //清空数组
}
for(i = 0; i < ((PUSB_CFG_DESCR)buf)->wTotalLength; i += l) // 搜索中断端点描述符,跳过配置描述符和接口描述符
{
if(((PUSB_ENDP_DESCR)(buf + i))->bDescriptorType == USB_DESCR_TYP_ENDP // 是端点描述符
&& (((PUSB_ENDP_DESCR)(buf + i))->bmAttributes & USB_ENDP_TYPE_MASK) == USB_ENDP_TYPE_INTER // 是中断端点
&& (((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)) // 是IN端点
{ // 保存中断端点的地址,位7用于同步标志位,清0
if(HubPortIndex)
{
DevOnHubPort[HubPortIndex - 1].GpVar[s] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
ThisUsbDev.GpVar[s] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK; // 中断端点的地址可以根据需要保存wMaxPacketSize和bInterval
}
PRINT("%02x ", (uint16_t)ThisUsbDev.GpVar[s]);
s++;
if(s >= 4)
{
break; //只分析4个端点
}
}
l = ((PUSB_ENDP_DESCR)(buf + i))->bLength; // 当前描述符长度,跳过
if(l > 16)
{
break;
}
}
PRINT("\n");
return (s);
}
/*********************************************************************
* @fn AnalyzeBulkEndp
*
* @brief 分析出批量端点,GpVar[0]、GpVar[1]存放上传端点。GpVar[2]、GpVar[3]存放下传端点
*
* @param buf - 待分析数据缓冲区地址 HubPortIndex0表示根HUB非0表示外部HUB下的端口号
*
* @return 0
*/
uint8_t AnalyzeBulkEndp(uint8_t *buf, uint8_t HubPortIndex)
{
uint8_t i, s1, s2, l;
s1 = 0;
s2 = 2;
if(HubPortIndex)
{
memset(DevOnHubPort[HubPortIndex - 1].GpVar, 0, sizeof(DevOnHubPort[HubPortIndex - 1].GpVar)); //清空数组
}
else
{
memset(ThisUsbDev.GpVar, 0, sizeof(ThisUsbDev.GpVar)); //清空数组
}
for(i = 0; i < ((PUSB_CFG_DESCR)buf)->wTotalLength; i += l) // 搜索中断端点描述符,跳过配置描述符和接口描述符
{
if((((PUSB_ENDP_DESCR)(buf + i))->bDescriptorType == USB_DESCR_TYP_ENDP) // 是端点描述符
&& ((((PUSB_ENDP_DESCR)(buf + i))->bmAttributes & USB_ENDP_TYPE_MASK) == USB_ENDP_TYPE_BULK)) // 是中断端点
{
if(HubPortIndex)
{
if(((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)
{
DevOnHubPort[HubPortIndex - 1].GpVar[s1++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
DevOnHubPort[HubPortIndex - 1].GpVar[s2++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
}
else
{
if(((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_DIR_MASK)
{
ThisUsbDev.GpVar[s1++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
else
{
ThisUsbDev.GpVar[s2++] = ((PUSB_ENDP_DESCR)(buf + i))->bEndpointAddress & USB_ENDP_ADDR_MASK;
}
}
if(s1 == 2)
{
s1 = 1;
}
if(s2 == 4)
{
s2 = 3;
}
}
l = ((PUSB_ENDP_DESCR)(buf + i))->bLength; // 当前描述符长度,跳过
if(l > 16)
{
break;
}
}
return (0);
}
/*********************************************************************
* @fn InitRootDevice
*
* @brief 初始化指定ROOT-HUB端口的USB设备
*
* @param none
*
* @return 错误码
*/
uint8_t InitRootDevice(void)
{
uint8_t i, s;
uint8_t cfg, dv_cls, if_cls;
PRINT("Reset host port\n");
ResetRootHubPort(); // 检测到设备后,复位相应端口的USB总线
for(i = 0, s = 0; i < 100; i++)
{ // 等待USB设备复位后重新连接,100mS超时
mDelaymS(1);
if(EnableRootHubPort() == ERR_SUCCESS)
{ // 使能端口
i = 0;
s++;
if(s > 100)
{
break; // 已经稳定连接100mS
}
}
}
if(i)
{ // 复位后设备没有连接
DisableRootHubPort();
PRINT("Disable host port because of disconnect\n");
return (ERR_USB_DISCON);
}
SetUsbSpeed(ThisUsbDev.DeviceSpeed); // 设置当前USB速度
PRINT("GetDevDescr: ");
s = CtrlGetDeviceDescr(); // 获取设备描述符
if(s == ERR_SUCCESS)
{
for(i = 0; i < ((PUSB_SETUP_REQ)SetupGetDevDescr)->wLength; i++)
{
PRINT("x%02X ", (uint16_t)(Com_Buffer[i]));
}
PRINT("\n");
ThisUsbDev.DeviceVID = ((PUSB_DEV_DESCR)Com_Buffer)->idVendor; //保存VID PID信息
ThisUsbDev.DevicePID = ((PUSB_DEV_DESCR)Com_Buffer)->idProduct;
dv_cls = ((PUSB_DEV_DESCR)Com_Buffer)->bDeviceClass;
s = CtrlSetUsbAddress(((PUSB_SETUP_REQ)SetupSetUsbAddr)->wValue);
if(s == ERR_SUCCESS)
{
ThisUsbDev.DeviceAddress = ((PUSB_SETUP_REQ)SetupSetUsbAddr)->wValue; // 保存USB地址
PRINT("GetCfgDescr: ");
s = CtrlGetConfigDescr();
if(s == ERR_SUCCESS)
{
for(i = 0; i < ((PUSB_CFG_DESCR)Com_Buffer)->wTotalLength; i++)
{
PRINT("x%02X ", (uint16_t)(Com_Buffer[i]));
}
PRINT("\n");
/* 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等 */
cfg = ((PUSB_CFG_DESCR)Com_Buffer)->bConfigurationValue;
if_cls = ((PUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceClass; // 接口类代码
if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_STORAGE))
{ // 是USB存储类设备,基本上确认是U盘
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_USB_ADDR;
return (ERR_SUCCESS);
}
else
{
return (ERR_USB_UNSUPPORT);
}
#else
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
ThisUsbDev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsbDev.DeviceType = USB_DEV_CLASS_STORAGE;
PRINT("USB-Disk Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_PRINTER) && ((PUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceSubClass == 0x01)
{ // 是打印机类设备
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// 需保存端点信息以便主程序进行USB传输
ThisUsbDev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsbDev.DeviceType = USB_DEV_CLASS_PRINTER;
PRINT("USB-Print Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_HID) && ((PUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceSubClass <= 0x01)
{ // 是HID类设备,键盘/鼠标等
// 从描述符中分析出HID中断端点的地址
s = AnalyzeHidIntEndp(Com_Buffer, 0); // 从描述符中分析出HID中断端点的地址
PRINT("AnalyzeHidIntEndp %02x\n", (uint16_t)s);
// 保存中断端点的地址,位7用于同步标志位,清0
if_cls = ((PUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceProtocol;
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// Set_Idle( );
// 需保存端点信息以便主程序进行USB传输
ThisUsbDev.DeviceStatus = ROOT_DEV_SUCCESS;
if(if_cls == 1)
{
ThisUsbDev.DeviceType = DEV_TYPE_KEYBOARD;
// 进一步初始化,例如设备键盘指示灯LED等
PRINT("USB-Keyboard Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
else if(if_cls == 2)
{
ThisUsbDev.DeviceType = DEV_TYPE_MOUSE;
// 为了以后查询鼠标状态,应该分析描述符,取得中断端口的地址,长度等信息
PRINT("USB-Mouse Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
s = ERR_USB_UNSUPPORT;
}
}
else if(dv_cls == USB_DEV_CLASS_HUB)
{ // 是HUB类设备,集线器等
s = CtrlGetHubDescr();
if(s == ERR_SUCCESS)
{
PRINT("Max Port:%02X ", (((PXUSB_HUB_DESCR)Com_Buffer)->bNbrPorts));
ThisUsbDev.GpHUBPortNum = ((PXUSB_HUB_DESCR)Com_Buffer)->bNbrPorts; // 保存HUB的端口数量
if(ThisUsbDev.GpHUBPortNum > HUB_MAX_PORTS)
{
ThisUsbDev.GpHUBPortNum = HUB_MAX_PORTS; // 因为定义结构DevOnHubPort时人为假定每个HUB不超过HUB_MAX_PORTS个端口
}
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
ThisUsbDev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsbDev.DeviceType = USB_DEV_CLASS_HUB;
//需保存端点信息以便主程序进行USB传输,本来中断端点可用于HUB事件通知,但本程序使用查询状态控制传输代替
//给HUB各端口上电,查询各端口状态,初始化有设备连接的HUB端口,初始化设备
for(i = 1; i <= ThisUsbDev.GpHUBPortNum; i++) // 给HUB各端口都上电
{
DevOnHubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 清外部HUB端口上设备的状态
s = HubSetPortFeature(i, HUB_PORT_POWER);
if(s != ERR_SUCCESS)
{
PRINT("Ext-HUB Port_%1d# power on error\n", (uint16_t)i); // 端口上电失败
}
}
PRINT("USB-HUB Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
}
else
{ // 可以进一步分析
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
// 需保存端点信息以便主程序进行USB传输
ThisUsbDev.DeviceStatus = ROOT_DEV_SUCCESS;
ThisUsbDev.DeviceType = DEV_TYPE_UNKNOW;
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS); /* 未知设备初始化成功 */
}
}
#endif
}
}
}
PRINT("InitRootDev Err = %02X\n", (uint16_t)s);
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_CONNECT;
#else
ThisUsbDev.DeviceStatus = ROOT_DEV_FAILED;
#endif
SetUsbSpeed(1); // 默认为全速
return (s);
}
/*********************************************************************
* @fn InitDevOnHub
*
* @brief 初始化枚举外部HUB后的二级USB设备
*
* @param HubPortIndex - 指定外部HUB
*
* @return 错误码
*/
uint8_t InitDevOnHub(uint8_t HubPortIndex)
{
uint8_t i, s, cfg, dv_cls, if_cls;
uint8_t ifc;
PRINT("Init dev @ExtHub-port_%1d ", (uint16_t)HubPortIndex);
if(HubPortIndex == 0)
{
return (ERR_USB_UNKNOWN);
}
SelectHubPort(HubPortIndex); // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口,选择速度
PRINT("GetDevDescr: ");
s = CtrlGetDeviceDescr(); // 获取设备描述符
if(s != ERR_SUCCESS)
{
return (s);
}
DevOnHubPort[HubPortIndex - 1].DeviceVID = ((uint16_t)((PUSB_DEV_DESCR)Com_Buffer)->idVendor); //保存VID PID信息
DevOnHubPort[HubPortIndex - 1].DevicePID = ((uint16_t)((PUSB_DEV_DESCR)Com_Buffer)->idProduct);
dv_cls = ((PUSB_DEV_DESCR)Com_Buffer)->bDeviceClass; // 设备类代码
cfg = (1 << 4) + HubPortIndex; // 计算出一个USB地址,避免地址重叠
s = CtrlSetUsbAddress(cfg); // 设置USB设备地址
if(s != ERR_SUCCESS)
{
return (s);
}
DevOnHubPort[HubPortIndex - 1].DeviceAddress = cfg; // 保存分配的USB地址
PRINT("GetCfgDescr: ");
s = CtrlGetConfigDescr(); // 获取配置描述符
if(s != ERR_SUCCESS)
{
return (s);
}
cfg = ((PUSB_CFG_DESCR)Com_Buffer)->bConfigurationValue;
for(i = 0; i < ((PUSB_CFG_DESCR)Com_Buffer)->wTotalLength; i++)
{
PRINT("x%02X ", (uint16_t)(Com_Buffer[i]));
}
PRINT("\n");
/* 分析配置描述符,获取端点数据/各端点地址/各端点大小等,更新变量endp_addr和endp_size等 */
if_cls = ((PXUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceClass; // 接口类代码
if(dv_cls == 0x00 && if_cls == USB_DEV_CLASS_STORAGE) // 是USB存储类设备,基本上确认是U盘
{
AnalyzeBulkEndp(Com_Buffer, HubPortIndex);
for(i = 0; i != 4; i++)
{
PRINT("%02x ", (uint16_t)DevOnHubPort[HubPortIndex - 1].GpVar[i]);
}
PRINT("\n");
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
DevOnHubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
DevOnHubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_STORAGE;
PRINT("USB-Disk Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
}
else if((dv_cls == 0x00) && (if_cls == USB_DEV_CLASS_HID) && (((PXUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceSubClass <= 0x01)) // 是HID类设备,键盘/鼠标等
{
ifc = ((PXUSB_CFG_DESCR_LONG)Com_Buffer)->cfg_descr.bNumInterfaces;
s = AnalyzeHidIntEndp(Com_Buffer, HubPortIndex); // 从描述符中分析出HID中断端点的地址
PRINT("AnalyzeHidIntEndp %02x\n", (uint16_t)s);
if_cls = ((PXUSB_CFG_DESCR_LONG)Com_Buffer)->itf_descr.bInterfaceProtocol;
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
for(dv_cls = 0; dv_cls < ifc; dv_cls++)
{
s = CtrlGetHIDDeviceReport(dv_cls); //获取报表描述符
if(s == ERR_SUCCESS)
{
for(i = 0; i < 64; i++)
{
PRINT("x%02X ", (uint16_t)(Com_Buffer[i]));
}
PRINT("\n");
}
}
//需保存端点信息以便主程序进行USB传输
DevOnHubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
if(if_cls == 1)
{
DevOnHubPort[HubPortIndex - 1].DeviceType = DEV_TYPE_KEYBOARD;
//进一步初始化,例如设备键盘指示灯LED等
if(ifc > 1)
{
PRINT("USB_DEV_CLASS_HID Ready\n");
DevOnHubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HID; //复合HID设备
}
PRINT("USB-Keyboard Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
else if(if_cls == 2)
{
DevOnHubPort[HubPortIndex - 1].DeviceType = DEV_TYPE_MOUSE;
//为了以后查询鼠标状态,应该分析描述符,取得中断端口的地址,长度等信息
if(ifc > 1)
{
PRINT("USB_DEV_CLASS_HID Ready\n");
DevOnHubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HID; //复合HID设备
}
PRINT("USB-Mouse Ready\n");
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS);
}
s = ERR_USB_UNSUPPORT;
}
}
else if(dv_cls == USB_DEV_CLASS_HUB) // 是HUB类设备,集线器等
{
DevOnHubPort[HubPortIndex - 1].DeviceType = USB_DEV_CLASS_HUB;
PRINT("This program don't support Level 2 HUB\n"); // 需要支持多级HUB级联请参考本程序进行扩展
s = HubClearPortFeature(i, HUB_PORT_ENABLE); // 禁止HUB端口
if(s != ERR_SUCCESS)
{
return (s);
}
s = ERR_USB_UNSUPPORT;
}
else //其他设备
{
AnalyzeBulkEndp(Com_Buffer, HubPortIndex); //分析出批量端点
for(i = 0; i != 4; i++)
{
PRINT("%02x ", (uint16_t)DevOnHubPort[HubPortIndex - 1].GpVar[i]);
}
PRINT("\n");
s = CtrlSetUsbConfig(cfg); // 设置USB设备配置
if(s == ERR_SUCCESS)
{
//需保存端点信息以便主程序进行USB传输
DevOnHubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_SUCCESS;
DevOnHubPort[HubPortIndex - 1].DeviceType = dv_cls ? dv_cls : if_cls;
SetUsbSpeed(1); // 默认为全速
return (ERR_SUCCESS); //未知设备初始化成功
}
}
PRINT("InitDevOnHub Err = %02X\n", (uint16_t)s);
DevOnHubPort[HubPortIndex - 1].DeviceStatus = ROOT_DEV_FAILED;
SetUsbSpeed(1); // 默认为全速
return (s);
}
/*********************************************************************
* @fn EnumHubPort
*
* @brief 枚举指定ROOT-HUB端口上的外部HUB集线器的各个端口,检查各端口有无连接或移除事件并初始化二级USB设备
*
* @param RootHubIndex - ROOT_HUB0和ROOT_HUB1
*
* @return 错误码
*/
uint8_t EnumHubPort()
{
uint8_t i, s;
for(i = 1; i <= ThisUsbDev.GpHUBPortNum; i++) // 查询集线器的端口是否有变化
{
SelectHubPort(0); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
s = HubGetPortStatus(i); // 获取端口状态
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
if(((Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) && (Com_Buffer[2] & (1 << (HUB_C_PORT_CONNECTION & 0x07)))) || (Com_Buffer[2] == 0x10))
{ // 发现有设备连接
DevOnHubPort[i - 1].DeviceStatus = ROOT_DEV_CONNECTED; // 有设备连接
DevOnHubPort[i - 1].DeviceAddress = 0x00;
s = HubGetPortStatus(i); // 获取端口状态
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
DevOnHubPort[i - 1].DeviceSpeed = Com_Buffer[1] & (1 << (HUB_PORT_LOW_SPEED & 0x07)) ? 0 : 1; // 低速还是全速
if(DevOnHubPort[i - 1].DeviceSpeed)
{
PRINT("Found full speed device on port %1d\n", (uint16_t)i);
}
else
{
PRINT("Found low speed device on port %1d\n", (uint16_t)i);
}
mDelaymS(200); // 等待设备上电稳定
s = HubSetPortFeature(i, HUB_PORT_RESET); // 对有设备连接的端口复位
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
PRINT("Reset port and then wait in\n");
do // 查询复位端口,直到复位完成,把完成后的状态显示出来
{
mDelaymS(1);
s = HubGetPortStatus(i);
if(s != ERR_SUCCESS)
{
return (s); // 可能是该HUB断开了
}
} while(Com_Buffer[0] & (1 << (HUB_PORT_RESET & 0x07))); // 端口正在复位则等待
mDelaymS(100);
s = HubClearPortFeature(i, HUB_C_PORT_RESET); // 清除复位完成标志
// s = HubSetPortFeature( i, HUB_PORT_ENABLE ); // 启用HUB端口
s = HubClearPortFeature(i, HUB_C_PORT_CONNECTION); // 清除连接或移除变化标志
if(s != ERR_SUCCESS)
{
return (s);
}
s = HubGetPortStatus(i); // 再读取状态,复查设备是否还在
if(s != ERR_SUCCESS)
{
return (s);
}
if((Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) == 0)
{
DevOnHubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 设备不在了
}
s = InitDevOnHub(i); // 初始化二级USB设备
if(s != ERR_SUCCESS)
{
return (s);
}
SetUsbSpeed(1); // 默认为全速
}
else if(Com_Buffer[2] & (1 << (HUB_C_PORT_ENABLE & 0x07))) // 设备连接出错
{
HubClearPortFeature(i, HUB_C_PORT_ENABLE); // 清除连接错误标志
PRINT("Device on port error\n");
s = HubSetPortFeature(i, HUB_PORT_RESET); // 对有设备连接的端口复位
if(s != ERR_SUCCESS)
return (s); // 可能是该HUB断开了
do // 查询复位端口,直到复位完成,把完成后的状态显示出来
{
mDelaymS(1);
s = HubGetPortStatus(i);
if(s != ERR_SUCCESS)
return (s); // 可能是该HUB断开了
} while(Com_Buffer[0] & (1 << (HUB_PORT_RESET & 0x07))); // 端口正在复位则等待
}
else if((Com_Buffer[0] & (1 << (HUB_PORT_CONNECTION & 0x07))) == 0) // 设备已经断开
{
if(DevOnHubPort[i - 1].DeviceStatus >= ROOT_DEV_CONNECTED)
{
PRINT("Device on port %1d removed\n", (uint16_t)i);
}
DevOnHubPort[i - 1].DeviceStatus = ROOT_DEV_DISCONNECT; // 有设备连接
if(Com_Buffer[2] & (1 << (HUB_C_PORT_CONNECTION & 0x07)))
{
HubClearPortFeature(i, HUB_C_PORT_CONNECTION); // 清除移除变化标志
}
}
}
return (ERR_SUCCESS); // 返回操作成功
}
/*********************************************************************
* @fn EnumAllHubPort
*
* @brief 枚举所有ROOT-HUB端口下外部HUB后的二级USB设备
*
* @return 错误码
*/
uint8_t EnumAllHubPort(void)
{
uint8_t s;
if((ThisUsbDev.DeviceStatus >= ROOT_DEV_SUCCESS) && (ThisUsbDev.DeviceType == USB_DEV_CLASS_HUB)) // HUB枚举成功
{
SelectHubPort(0); // 选择操作指定的ROOT-HUB端口,设置当前USB速度以及被操作设备的USB地址
s = EnumHubPort(); // 枚举指定ROOT-HUB端口上的外部HUB集线器的各个端口,检查各端口有无连接或移除事件
if(s != ERR_SUCCESS) // 可能是HUB断开了
{
PRINT("EnumAllHubPort err = %02X\n", (uint16_t)s);
}
SetUsbSpeed(1); // 默认为全速
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn SearchTypeDevice
*
* @brief 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号,输出端口号为0xFFFF则未搜索到.
* 当然也可以根据USB的厂商VID产品PID进行搜索(事先要记录各设备的VID和PID),以及指定搜索序号
*
* @param type - 搜索的设备类型
*
* @return 输出高8位为ROOT-HUB端口号,低8位为外部HUB的端口号,低8位为0则设备直接在ROOT-HUB端口上
*/
uint16_t SearchTypeDevice(uint8_t type)
{
uint8_t RootHubIndex; //CH554只有一个USB口,RootHubIndex = 0,只需看返回值的低八位即可
uint8_t HubPortIndex;
RootHubIndex = 0;
if((ThisUsbDev.DeviceType == USB_DEV_CLASS_HUB) && (ThisUsbDev.DeviceStatus >= ROOT_DEV_SUCCESS)) // 外部集线器HUB且枚举成功
{
for(HubPortIndex = 1; HubPortIndex <= ThisUsbDev.GpHUBPortNum; HubPortIndex++) // 搜索外部HUB的各个端口
{
if(DevOnHubPort[HubPortIndex - 1].DeviceType == type && DevOnHubPort[HubPortIndex - 1].DeviceStatus >= ROOT_DEV_SUCCESS)
{
return (((uint16_t)RootHubIndex << 8) | HubPortIndex); // 类型匹配且枚举成功
}
}
}
if((ThisUsbDev.DeviceType == type) && (ThisUsbDev.DeviceStatus >= ROOT_DEV_SUCCESS))
{
return ((uint16_t)RootHubIndex << 8); // 类型匹配且枚举成功,在ROOT-HUB端口上
}
return (0xFFFF);
}
/*********************************************************************
* @fn SETorOFFNumLock
*
* @brief NumLock的点灯判断
*
* @param buf - 点灯键值
*
* @return 错误码
*/
uint8_t SETorOFFNumLock(uint8_t *buf)
{
uint8_t tmp[] = {0x21, 0x09, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00};
uint8_t len, s;
if((buf[2] == 0x53) & ((buf[0] | buf[1] | buf[3] | buf[4] | buf[5] | buf[6] | buf[7]) == 0))
{
for(s = 0; s != sizeof(tmp); s++)
{
((uint8_t *)pSetupReq)[s] = tmp[s];
}
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetHIDDeviceReport
*
* @brief 获取HID设备报表描述符,返回在TxBuffer中
*
* @param none
*
* @return 错误码
*/
uint8_t CtrlGetHIDDeviceReport(uint8_t infc)
{
uint8_t s;
uint8_t len;
CopySetupReqPkg(SetupSetHIDIdle);
pSetupReq->wIndex = infc;
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
CopySetupReqPkg(SetupGetHIDDevReport);
pSetupReq->wIndex = infc;
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetHubDescr
*
* @brief 获取HUB描述符,返回在Com_Buffer中
*
* @param none
*
* @return 错误码
*/
uint8_t CtrlGetHubDescr(void)
{
uint8_t s;
uint8_t len;
CopySetupReqPkg(SetupGetHubDescr);
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
if(len < ((PUSB_SETUP_REQ)SetupGetHubDescr)->wLength)
{
return (ERR_USB_BUF_OVER); // 描述符长度错误
}
// if ( len < 4 ) return( ERR_USB_BUF_OVER ); // 描述符长度错误
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn HubGetPortStatus
*
* @brief 查询HUB端口状态,返回在Com_Buffer中
*
* @param HubPortIndex - 端口号
*
* @return 错误码
*/
uint8_t HubGetPortStatus(uint8_t HubPortIndex)
{
uint8_t s;
uint8_t len;
pSetupReq->bRequestType = HUB_GET_PORT_STATUS;
pSetupReq->bRequest = HUB_GET_STATUS;
pSetupReq->wValue = 0x0000;
pSetupReq->wIndex = 0x0000 | HubPortIndex;
pSetupReq->wLength = 0x0004;
s = HostCtrlTransfer(Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
{
return (s);
}
if(len < 4)
{
return (ERR_USB_BUF_OVER); // 描述符长度错误
}
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn HubSetPortFeature
*
* @brief 设置HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t HubSetPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt)
{
pSetupReq->bRequestType = HUB_SET_PORT_FEATURE;
pSetupReq->bRequest = HUB_SET_FEATURE;
pSetupReq->wValue = 0x0000 | FeatureSelt;
pSetupReq->wIndex = 0x0000 | HubPortIndex;
pSetupReq->wLength = 0x0000;
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn HubClearPortFeature
*
* @brief 清除HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t HubClearPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt)
{
pSetupReq->bRequestType = HUB_CLEAR_PORT_FEATURE;
pSetupReq->bRequest = HUB_CLEAR_FEATURE;
pSetupReq->wValue = 0x0000 | FeatureSelt;
pSetupReq->wIndex = 0x0000 | HubPortIndex;
pSetupReq->wLength = 0x0000;
return (HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,265 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_adc.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_ADC_H__
#define __CH58x_ADC_H__
#ifdef __cplusplus
extern "C" {
#endif
#define ROM_CFG_TMP_25C 0x7F014
/**
* @brief adc single channel define
*/
typedef enum
{
CH_EXTIN_0 = 0, // ADC 外部模拟通道 0
CH_EXTIN_1, // ADC 外部模拟通道 1
CH_EXTIN_2, // ADC 外部模拟通道 2
CH_EXTIN_3, // ADC 外部模拟通道 3
CH_EXTIN_4, // ADC 外部模拟通道 4
CH_EXTIN_5, // ADC 外部模拟通道 5
CH_EXTIN_6, // ADC 外部模拟通道 6
CH_EXTIN_7, // ADC 外部模拟通道 7
CH_EXTIN_8, // ADC 外部模拟通道 8
CH_EXTIN_9, // ADC 外部模拟通道 9
CH_EXTIN_10, // ADC 外部模拟通道 10
CH_EXTIN_11, // ADC 外部模拟通道 11
CH_EXTIN_12, // ADC 外部模拟通道 12
CH_EXTIN_13, // ADC 外部模拟通道 13
CH_INTE_VBAT = 14, // ADC 内部电池检测通道
CH_INTE_VTEMP = 15, // ADC 内部温度传感器检测通道
} ADC_SingleChannelTypeDef;
/**
* @brief adc differential channel define
*/
typedef enum
{
CH_DIFF_0_2 = 0, // ADC 差分通道 #0-#2
CH_DIFF_1_3, // ADC 差分通道 #1-#3
} ADC_DiffChannelTypeDef;
/**
* @brief adc sampling clock
*/
typedef enum
{
SampleFreq_3_2 = 0, // 3.2M 采样频率
SampleFreq_8, // 8M 采样频率
SampleFreq_5_33, // 5.33M 采样频率
SampleFreq_4, // 4M 采样频率
} ADC_SampClkTypeDef;
/**
* @brief adc signal PGA
*/
typedef enum
{
ADC_PGA_1_4 = 0, // -12dB, 1/4倍
ADC_PGA_1_2, // -6dB, 1/2倍
ADC_PGA_0, // 0dB, 1倍无增益
ADC_PGA_2, // 6dB, 2倍
} ADC_SignalPGATypeDef;
/**
* @brief Configuration DMA mode
*/
typedef enum
{
ADC_Mode_Single = 0, // 单次模式
ADC_Mode_LOOP, // 循环模式
} ADC_DMAModeTypeDef;
/**
* @brief 设置 ADC 采样通道
*
* @param d - refer to ADC_SingleChannelTypeDef
*/
#define ADC_ChannelCfg(d) (R8_ADC_CHANNEL = d)
/**
* @brief 设置 ADC 采样时钟
*
* @param d - refer to ADC_SampClkTypeDef
*/
#define ADC_SampClkCfg(d) (R8_ADC_CFG = R8_ADC_CFG & (~RB_ADC_CLK_DIV) | (d << 6))
/**
* @brief 设置 ADC 信号增益
*
* @param d - refer to ADC_SignalPGATypeDef
*/
#define ADC_PGACfg(d) (R8_ADC_CFG = R8_ADC_CFG & (~RB_ADC_PGA_GAIN) | (d << 4))
/**
* @brief 设置内部温度传感器校准值
*
* @param d - 校准值
*/
#define ADC_TempCalibCfg(d) (R8_TEM_SENSOR = R8_TEM_SENSOR & (~RB_TEM_SEN_CALIB) | d)
/**
* @brief 外部信号单通道采样初始化
*
* @param sp - refer to ADC_SampClkTypeDef
* @param ga - refer to ADC_SignalPGATypeDef
*/
void ADC_ExtSingleChSampInit(ADC_SampClkTypeDef sp, ADC_SignalPGATypeDef ga);
/**
* @brief 外部信号差分通道采样初始化
*
* @param sp - refer to ADC_SampClkTypeDef
* @param ga - refer to ADC_SignalPGATypeDef
*/
void ADC_ExtDiffChSampInit(ADC_SampClkTypeDef sp, ADC_SignalPGATypeDef ga);
/**
* @brief 触摸按键通道采样初始化
*/
void TouchKey_ChSampInit(void);
/**
* @brief 关闭TouchKey电源
*/
#define TouchKey_DisableTSPower() (R8_TKEY_CFG &= ~RB_TKEY_PWR_ON)
/**
* @brief 内置温度传感器采样初始化
*/
void ADC_InterTSSampInit(void);
/**
* @brief 关闭温度传感器电源
*/
#define ADC_DisableTSPower() (R8_TEM_SENSOR = 0)
/**
* @brief 内置电池电压采样初始化
*/
void ADC_InterBATSampInit(void);
/**
* @brief ADC执行单次转换
*
* @return ADC转换后的数据
*/
uint16_t ADC_ExcutSingleConver(void);
/**
* @brief 采样数据粗调,获取偏差值,必须先配置ADC后调用此函数获取校准值
*
* @return 偏差
*/
signed short ADC_DataCalib_Rough(void);
/**
* @brief TouchKey转换后数据
*
* @param charg - Touchkey充电时间,5bits有效, t=charg*Tadc
* @param disch - Touchkey放电时间,3bits有效, t=disch*Tadc
*
* @return 当前TouchKey等效数据
*/
uint16_t TouchKey_ExcutSingleConver(uint8_t charg, uint8_t disch);
/**
* @brief 设置连续 ADC的周期
*
* @param cycle - 单位为 16个系统时钟
*/
void ADC_AutoConverCycle(uint8_t cycle);
/**
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*/
void ADC_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, ADC_DMAModeTypeDef m);
/**
* @brief Convert ADC value to temperature(Celsius)
*
* @param adc_val - adc value
*
* @return temperature (Celsius)
*/
int adc_to_temperature_celsius(uint16_t adc_val);
/**
* @brief 获取ADC转换值
*
* @return ADC转换值
*/
#define ADC_ReadConverValue() (R16_ADC_DATA)
/**
* @brief ADC执行单次转换
*/
#define ADC_StartUp() (R8_ADC_CONVERT = RB_ADC_START)
/**
* @brief 获取ADC中断状态
*/
#define ADC_GetITStatus() (R8_ADC_INT_FLAG & RB_ADC_IF_EOC)
/**
* @brief 清除ADC中断标志
*/
#define ADC_ClearITFlag() (R8_ADC_CONVERT = 0)
/**
* @brief 获取ADC DMA完成状态
*/
#define ADC_GetDMAStatus() (R8_ADC_DMA_IF & RB_ADC_IF_DMA_END)
/**
* @brief 清除ADC DMA完成标志
*/
#define ADC_ClearDMAFlag() (R8_ADC_DMA_IF |= RB_ADC_IF_DMA_END)
/**
* @brief 开启自动连续 ADC
*/
#define ADC_StartDMA() (R8_ADC_CTRL_DMA |= RB_ADC_AUTO_EN)
/**
* @brief 停止自动连续 ADC
*/
#define ADC_StopDMA() (R8_ADC_CTRL_DMA &= ~RB_ADC_AUTO_EN)
/**
* @brief 获取TouchKey中断状态
*/
#define TouchKey_GetITStatus() (R8_ADC_INT_FLAG & RB_ADC_IF_EOC)
/**
* @brief 清除TouchKey中断标志
*/
#define TouchKey_ClearITFlag() (R8_TKEY_CTRL |= RB_TKEY_PWR_ON)
#ifdef __cplusplus
}
#endif
#endif // __CH58x_ADC_H__

View File

@@ -0,0 +1,290 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_clk.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_CLK_H__
#define __CH58x_CLK_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief 系统主频定义
*/
typedef enum
{
CLK_SOURCE_LSI = 0x00,
CLK_SOURCE_LSE,
CLK_SOURCE_HSE_16MHz = 0x22,
CLK_SOURCE_HSE_8MHz = 0x24,
CLK_SOURCE_HSE_6_4MHz = 0x25,
CLK_SOURCE_HSE_4MHz = 0x28,
CLK_SOURCE_HSE_2MHz = (0x20 | 16),
CLK_SOURCE_HSE_1MHz = (0x20 | 0),
CLK_SOURCE_PLL_80MHz = 0x46,
CLK_SOURCE_PLL_60MHz = 0x48,
CLK_SOURCE_PLL_48MHz = (0x40 | 10),
CLK_SOURCE_PLL_40MHz = (0x40 | 12),
CLK_SOURCE_PLL_36_9MHz = (0x40 | 13),
CLK_SOURCE_PLL_32MHz = (0x40 | 15),
CLK_SOURCE_PLL_30MHz = (0x40 | 16),
CLK_SOURCE_PLL_24MHz = (0x40 | 20),
CLK_SOURCE_PLL_20MHz = (0x40 | 24),
CLK_SOURCE_PLL_15MHz = (0x40 | 0),
} SYS_CLKTypeDef;
/**
* @brief 32K时钟选择
*/
typedef enum
{
Clk32K_LSI = 0,
Clk32K_LSE,
} LClk32KTypeDef;
/**
* @brief 32M晶振电流挡位
*/
typedef enum
{
HSE_RCur_75 = 0,
HSE_RCur_100,
HSE_RCur_125,
HSE_RCur_150
} HSECurrentTypeDef;
/**
* @brief 32M晶振内部电容挡位
*/
typedef enum
{
HSECap_10p = 0,
HSECap_12p,
HSECap_14p,
HSECap_16p,
HSECap_18p,
HSECap_20p,
HSECap_22p,
HSECap_24p
} HSECapTypeDef;
/**
* @brief 32K晶振电流挡位
*/
typedef enum
{
LSE_RCur_70 = 0,
LSE_RCur_100,
LSE_RCur_140,
LSE_RCur_200
} LSECurrentTypeDef;
/**
* @brief 32K晶振内部电容挡位
*/
typedef enum
{
LSECap_2p = 0,
LSECap_13p,
LSECap_14p,
LSECap_15p,
LSECap_16p,
LSECap_17p,
LSECap_18p,
LSECap_19p,
LSECap_20p,
LSECap_21p,
LSECap_22p,
LSECap_23p,
LSECap_24p,
LSECap_25p,
LSECap_26p,
LSECap_27p
} LSECapTypeDef;
#define MAX_DAY 0x00004000
#define MAX_2_SEC 0x0000A8C0
//#define MAX_SEC 0x545FFFFF
#define BEGYEAR 2020
#define IsLeapYear(yr) (!((yr) % 400) || (((yr) % 100) && !((yr) % 4)))
#define YearLength(yr) (IsLeapYear(yr) ? 366 : 365)
#define monthLength(lpyr, mon) (((mon) == 1) ? (28 + (lpyr)) : (((mon) > 6) ? (((mon) & 1) ? 31 : 30) : (((mon) & 1) ? 30 : 31)))
/**
* @brief rtc timer mode period define
*/
typedef enum
{
Period_0_125_S = 0, // 0.125s 周期
Period_0_25_S, // 0.25s 周期
Period_0_5_S, // 0.5s 周期
Period_1_S, // 1s 周期
Period_2_S, // 2s 周期
Period_4_S, // 4s 周期
Period_8_S, // 8s 周期
Period_16_S, // 16s 周期
} RTC_TMRCycTypeDef;
/**
* @brief rtc interrupt event define
*/
typedef enum
{
RTC_TRIG_EVENT = 0, // RTC 触发事件
RTC_TMR_EVENT, // RTC 周期定时事件
} RTC_EVENTTypeDef;
/**
* @brief rtc interrupt event define
*/
typedef enum
{
RTC_TRIG_MODE = 0, // RTC 触发模式
RTC_TMR_MODE, // RTC 周期定时模式
} RTC_MODETypeDef;
typedef enum
{
/* 校准精度越高,耗时越长 */
Level_32 = 3, // 用时 1.2ms 1000ppm (32M 主频) 1100ppm (60M 主频)
Level_64, // 用时 2.2ms 800ppm (32M 主频) 1000ppm (60M 主频)
Level_128, // 用时 4.2ms 600ppm (32M 主频) 800ppm (60M 主频)
} Cali_LevelTypeDef;
/**
* @brief 32K 低频时钟来源
*
* @param hc - 选择32K使用内部还是外部
*/
void LClk32K_Select(LClk32KTypeDef hc);
/**
* @brief HSE晶体 偏置电流配置
*
* @param c - 75%,100%,125%,150%
*/
void HSECFG_Current(HSECurrentTypeDef c);
/**
* @brief HSE晶体 负载电容配置
*
* @param c - refer to HSECapTypeDef
*/
void HSECFG_Capacitance(HSECapTypeDef c);
/**
* @brief LSE晶体 偏置电流配置
*
* @param c - 70%,100%,140%,200%
*/
void LSECFG_Current(LSECurrentTypeDef c);
/**
* @brief LSE晶体 负载电容配置
*
* @param c - refer to LSECapTypeDef
*/
void LSECFG_Capacitance(LSECapTypeDef c);
void Calibration_LSI(Cali_LevelTypeDef cali_Lv); /* 用主频校准内部32K时钟 */
/**
* @brief RTC时钟初始化当前时间
*
* @param y - 配置年MAX_Y = BEGYEAR + 44
* @param mon - 配置月MAX_MON = 12
* @param d - 配置日MAX_D = 31
* @param h - 配置小时MAX_H = 23
* @param m - 配置分钟MAX_M = 59
* @param s - 配置秒MAX_S = 59
*/
void RTC_InitTime(uint16_t y, uint16_t mon, uint16_t d, uint16_t h, uint16_t m, uint16_t s);
/**
* @brief 获取当前时间
*
* @param py - 获取到的年MAX_Y = BEGYEAR + 44
* @param pmon - 获取到的月MAX_MON = 12
* @param pd - 获取到的日MAX_D = 31
* @param ph - 获取到的小时MAX_H = 23
* @param pm - 获取到的分钟MAX_M = 59
* @param ps - 获取到的秒MAX_S = 59
*/
void RTC_GetTime(uint16_t *py, uint16_t *pmon, uint16_t *pd, uint16_t *ph, uint16_t *pm, uint16_t *ps);
/**
* @brief 基于LSE/LSI时钟配置当前RTC 周期数
*
* @param cyc - 配置周期计数初值MAX_CYC = 0xA8BFFFFF = 2831155199
*/
void RTC_SetCycle32k(uint32_t cyc);
/**
* @brief 基于LSE/LSI时钟获取当前RTC 周期数
*
* @return 当前周期数MAX_CYC = 0xA8BFFFFF = 2831155199
*/
uint32_t RTC_GetCycle32k(void);
/**
* @brief RTC定时模式配置注意定时基准固定为32768Hz
*
* @param t - refer to RTC_TMRCycTypeDef
*/
void RTC_TRIGFunCfg(uint32_t cyc);
/**
* @brief RTC定时模式配置注意定时基准固定为32768Hz
*
* @param t - refer to RTC_TMRCycTypeDef
*/
void RTC_TMRFunCfg(RTC_TMRCycTypeDef t);
/**
* @brief RTC 模式功能关闭
*
* @param m - 需要关闭的当前模式
*/
void RTC_ModeFunDisable(RTC_MODETypeDef m);
/**
* @brief 获取RTC中断标志
*
* @param f - refer to RTC_EVENTTypeDef
*
* @return 中断标志状态
*/
uint8_t RTC_GetITFlag(RTC_EVENTTypeDef f);
/**
* @brief 清除RTC中断标志
*
* @param f - refer to RTC_EVENTTypeDef
*/
void RTC_ClearITFlag(RTC_EVENTTypeDef f);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_CLK_H__

View File

@@ -0,0 +1,101 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_common.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_COMM_H__
#define __CH58x_COMM_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef NULL
#define NULL 0
#endif
#define ALL 0xFFFF
#ifndef __HIGH_CODE
#define __HIGH_CODE __attribute__((section(".highcode")))
#endif
#ifndef __INTERRUPT
#ifdef INT_SOFT
#define __INTERRUPT __attribute__((interrupt()))
#else
#define __INTERRUPT __attribute__((interrupt("WCH-Interrupt-fast")))
#endif
#endif
#define Debug_UART0 0
#define Debug_UART1 1
#define Debug_UART2 2
#define Debug_UART3 3
#ifdef DEBUG
#include <stdio.h>
#endif
/**
* @brief 系统主频时钟Hz
*/
#ifndef FREQ_SYS
#define FREQ_SYS 60000000
#endif
#ifndef SAFEOPERATE
#define SAFEOPERATE __nop();__nop()
#endif
/**
* @brief 32K时钟Hz
*/
#ifdef CLK_OSC32K
#if ( CLK_OSC32K == 1 )
#define CAB_LSIFQ 32000
#else
#define CAB_LSIFQ 32768
#endif
#else
#define CAB_LSIFQ 32000
#endif
#include <string.h>
#include <stdint.h>
#include "CH583SFR.h"
#include "core_riscv.h"
#include "CH58x_clk.h"
#include "CH58x_uart.h"
#include "CH58x_gpio.h"
#include "CH58x_i2c.h"
#include "CH58x_flash.h"
#include "CH58x_pwr.h"
#include "CH58x_pwm.h"
#include "CH58x_adc.h"
#include "CH58x_sys.h"
#include "CH58x_timer.h"
#include "CH58x_spi.h"
#include "CH58x_usbdev.h"
#include "CH58x_usbhost.h"
#include "ISP583.h"
#define DelayMs(x) mDelaymS(x)
#define DelayUs(x) mDelayuS(x)
#ifdef __cplusplus
}
#endif
#endif // __CH58x_COMM_H__

View File

@@ -0,0 +1,42 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_flash.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_FLASH_H__
#define __CH58x_FLASH_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ¶ÁÈ¡Flash-ROM
*
* @param StartAddr - read address
* @param Buffer - read buffer
* @param len - read len
*/
void FLASH_ROM_READ(uint32_t StartAddr, void *Buffer, uint32_t len);
void FLASH_ROM_READ(UINT32 StartAddr, PVOID Buffer, UINT32 len); /* ¶ÁÈ¡Flash-ROM */
UINT8 UserOptionByteConfig(FunctionalState RESET_EN, FunctionalState BOOT_PIN, FunctionalState UART_NO_KEY_EN,
UINT32 FLASHProt_Size);
UINT8 UserOptionByteClose_SWD(void);
void UserOptionByte_Active(void);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_FLASH_H__

View File

@@ -0,0 +1,274 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_gpio.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_GPIO_H__
#define __CH58x_GPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief GPIO_pins_define
*/
#define GPIO_Pin_0 (0x00000001) /*!< Pin 0 selected */
#define GPIO_Pin_1 (0x00000002) /*!< Pin 1 selected */
#define GPIO_Pin_2 (0x00000004) /*!< Pin 2 selected */
#define GPIO_Pin_3 (0x00000008) /*!< Pin 3 selected */
#define GPIO_Pin_4 (0x00000010) /*!< Pin 4 selected */
#define GPIO_Pin_5 (0x00000020) /*!< Pin 5 selected */
#define GPIO_Pin_6 (0x00000040) /*!< Pin 6 selected */
#define GPIO_Pin_7 (0x00000080) /*!< Pin 7 selected */
#define GPIO_Pin_8 (0x00000100) /*!< Pin 8 selected */
#define GPIO_Pin_9 (0x00000200) /*!< Pin 9 selected */
#define GPIO_Pin_10 (0x00000400) /*!< Pin 10 selected */
#define GPIO_Pin_11 (0x00000800) /*!< Pin 11 selected */
#define GPIO_Pin_12 (0x00001000) /*!< Pin 12 selected */
#define GPIO_Pin_13 (0x00002000) /*!< Pin 13 selected */
#define GPIO_Pin_14 (0x00004000) /*!< Pin 14 selected */
#define GPIO_Pin_15 (0x00008000) /*!< Pin 15 selected */
#define GPIO_Pin_16 (0x00010000) /*!< Pin 16 selected */
#define GPIO_Pin_17 (0x00020000) /*!< Pin 17 selected */
#define GPIO_Pin_18 (0x00040000) /*!< Pin 18 selected */
#define GPIO_Pin_19 (0x00080000) /*!< Pin 19 selected */
#define GPIO_Pin_20 (0x00100000) /*!< Pin 20 selected */
#define GPIO_Pin_21 (0x00200000) /*!< Pin 21 selected */
#define GPIO_Pin_22 (0x00400000) /*!< Pin 22 selected */
#define GPIO_Pin_23 (0x00800000) /*!< Pin 23 selected */
#define GPIO_Pin_All (0xFFFFFFFF) /*!< All pins selected */
/**
* @brief Configuration GPIO Mode
*/
typedef enum
{
GPIO_ModeIN_Floating, //浮空输入
GPIO_ModeIN_PU, //上拉输入
GPIO_ModeIN_PD, //下拉输入
GPIO_ModeOut_PP_5mA, //推挽输出最大5mA
GPIO_ModeOut_PP_20mA, //推挽输出最大20mA
} GPIOModeTypeDef;
/**
* @brief Configuration GPIO IT Mode
*/
typedef enum
{
GPIO_ITMode_LowLevel, //低电平触发
GPIO_ITMode_HighLevel, //高电平触发
GPIO_ITMode_FallEdge, //下降沿触发
GPIO_ITMode_RiseEdge, //上升沿触发
} GPIOITModeTpDef;
/**
* @brief GPIOA端口引脚模式配置
*
* @param pin - PA0-PA15
* @param mode - 输入输出类型
*/
void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode);
/**
* @brief GPIOB端口引脚模式配置
*
* @param pin - PB0-PB23
* @param mode - 输入输出类型
*/
void GPIOB_ModeCfg(uint32_t pin, GPIOModeTypeDef mode);
/**
* @brief GPIOA端口引脚输出置低
*
* @param pin - PA0-PA15
*/
#define GPIOA_ResetBits(pin) (R32_PA_CLR |= pin)
/**
* @brief GPIOA端口引脚输出置高
*
* @param pin - PA0-PA15
*/
#define GPIOA_SetBits(pin) (R32_PA_OUT |= pin)
/**
* @brief GPIOB端口引脚输出置低
*
* @param pin - PB0-PB23
*/
#define GPIOB_ResetBits(pin) (R32_PB_CLR |= pin)
/**
* @brief GPIOB端口引脚输出置高
*
* @param pin - PB0-PB23
*/
#define GPIOB_SetBits(pin) (R32_PB_OUT |= pin)
/**
* @brief GPIOA端口引脚输出电平翻转
*
* @param pin - PA0-PA15
*/
#define GPIOA_InverseBits(pin) (R32_PA_OUT ^= pin)
/**
* @brief GPIOB端口引脚输出电平翻转
*
* @param pin - PB0-PB23
*/
#define GPIOB_InverseBits(pin) (R32_PB_OUT ^= pin)
/**
* @brief GPIOA端口32位数据返回低16位有效
*
* @return GPIOA端口32位数据
*/
#define GPIOA_ReadPort() (R32_PA_PIN)
/**
* @brief GPIOB端口32位数据返回低24位有效
*
* @return GPIOB端口32位数据
*/
#define GPIOB_ReadPort() (R32_PB_PIN)
/**
* @brief GPIOA端口引脚状态0-引脚低电平,(!0)-引脚高电平
*
* @param pin - PA0-PA15
*
* @return GPIOA端口引脚状态
*/
#define GPIOA_ReadPortPin(pin) (R32_PA_PIN & (pin))
/**
* @brief GPIOB端口引脚状态0-引脚低电平,(!0)-引脚高电平
*
* @param pin - PB0-PB23
*
* @return GPIOB端口引脚状态
*/
#define GPIOB_ReadPortPin(pin) (R32_PB_PIN & (pin))
/**
* @brief GPIOA引脚中断模式配置
*
* @param pin - PA0-PA15
* @param mode - 触发类型
*/
void GPIOA_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode);
/**
* @brief GPIOB引脚中断模式配置
*
* @param pin - PB0-PB23
* @param mode - 触发类型
*/
void GPIOB_ITModeCfg(uint32_t pin, GPIOITModeTpDef mode);
/**
* @brief 读取GPIOA端口中断标志状态
*
* @return GPIOA端口中断标志状态
*/
#define GPIOA_ReadITFlagPort() (R16_PA_INT_IF)
/**
* @brief 读取GPIOB端口中断标志状态
*
* @return GPIOB端口中断标志状态
*/
#define GPIOB_ReadITFlagPort() ((R16_PB_INT_IF & (~((GPIO_Pin_22 | GPIO_Pin_23) >> 14))) | ((R16_PB_INT_IF << 14) & (GPIO_Pin_22 | GPIO_Pin_23)))
/**
* @brief 读取GPIOA端口引脚中断标志状态
*
* @param pin - PA0-PA15
*
* @return GPIOA端口引脚中断标志状态
*/
#define GPIOA_ReadITFlagBit(pin) (R16_PA_INT_IF & (pin))
/**
* @brief 读取GPIOB端口引脚中断标志状态
*
* @param pin - PB0-PB23
*
* @return GPIOB端口引脚中断标志状态
*/
#define GPIOB_ReadITFlagBit(pin) (R16_PB_INT_IF & ((pin) | (((pin) & (GPIO_Pin_22 | GPIO_Pin_23)) >> 14)))
/**
* @brief 清除GPIOA端口引脚中断标志状态
*
* @param pin - PA0-PA15
*/
#define GPIOA_ClearITFlagBit(pin) (R16_PA_INT_IF = pin)
/**
* @brief 清除GPIOB端口引脚中断标志状态
*
* @param pin - PB0-PB23
*/
#define GPIOB_ClearITFlagBit(pin) (R16_PB_INT_IF = ((pin) | (((pin) & (GPIO_Pin_22 | GPIO_Pin_23)) >> 14)))
/**
* @brief 外设功能引脚映射
*
* @param s - 是否使能映射
* @param perph - RB_RF_ANT_SW_EN - RF antenna switch control output on PB16/PB17/PB18/PB19/PB20/PB21
* RB_PIN_U0_INV - RXD0/RXD0_/TXD0/TXD0_ invert input/output
* RB_PIN_INTX - INTX: INT24/INT25 PB8/PB9 -> INT24_/INT25_ PB22/PB23
* RB_PIN_MODEM - MODEM: PB1/PB5 -> PB14/PB15
* RB_PIN_I2C - I2C: PB13/PB12 -> PB21/PB20
* RB_PIN_PWMX - PWMX: PA12/PA13/PB4/PB6/PB7 -> PA6/PA7/PB1/PB2/PB3
* RB_PIN_SPI0 - SPI0: PA12/PA13/PA14/PA15 -> PB12/PB13/PB14/PB15
* RB_PIN_UART3 - UART3: PA4/PA5 -> PB20/PB21
* RB_PIN_UART2 - UART2: PA6/PA7 -> PB22/PB23
* RB_PIN_UART1 - UART1: PA8/PA9 -> PB12/PB13
* RB_PIN_UART0 - UART0: PB4/PB7 -> PA15/PA14
* RB_PIN_TMR3 - TMR2: PA9 -> PB23
* RB_PIN_TMR2 - TMR2: PA11 -> PB11
* RB_PIN_TMR1 - TMR1: PA10 -> PB10
* RB_PIN_TMR0 - TMR0: PA9 -> PB23
*/
void GPIOPinRemap(FunctionalState s, uint16_t perph);
/**
* @brief 模拟外设GPIO引脚功能控制
*
* @param s - 是否启用模拟外设功能
* @param perph - RB_PIN_ADC8_9_IE - ADC/TKEY 9/8通道
* RB_PIN_ADC6_7_IE - ADC/TKEY 7/6通道
* RB_PIN_ADC10_IE - ADC/TKEY 10通道
* RB_PIN_ADC11_IE - ADC/TKEY 11 通道
* RB_PIN_USB2_DP_PU - USB2 U2D+引脚内部上拉电阻
* RB_PIN_USB2_IE - USB2引脚
* RB_PIN_USB_DP_PU - USB UD+引脚内部上拉电阻
* RB_PIN_USB_IE - USB 引脚
* RB_PIN_ADC0_IE - ADC/TKEY 0 通道
* RB_PIN_ADC1_IE - ADC/TKEY 1 通道
* RB_PIN_ADC12_IE - ADC/TKEY 12 通道
* RB_PIN_ADC13_IE - ADC/TKEY 13 通道
* RB_PIN_XT32K_IE - 32KHz晶振LSE引脚
* RB_PIN_ADC2_3_IE - ADC/TKEY 2/3 通道
* RB_PIN_ADC4_5_IE - ADC/TKEY 4/5 通道
*/
void GPIOAGPPCfg(FunctionalState s, uint16_t perph);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_GPIO_H__

View File

@@ -0,0 +1,180 @@
#ifndef __CH58x_I2C_H__
#define __CH58x_I2C_H__
#ifdef __cplusplus
extern "C" {
#endif
/* I2C_transfer_direction */
#define I2C_Direction_Transmitter ((uint8_t)0x00)
#define I2C_Direction_Receiver ((uint8_t)0x01)
/* I2C ADD0 mask */
#define OADDR1_ADD0_Set ((uint16_t)0x0001)
#define OADDR1_ADD0_Reset ((uint16_t)0xFFFE)
/* I2C_NACK_position */
#define I2C_NACKPosition_Next ((uint16_t)RB_I2C_POS)
#define I2C_NACKPosition_Current ((uint16_t)~RB_I2C_POS)
/* I2C_PEC_position */
#define I2C_PECPosition_Next ((uint16_t)RB_I2C_POS)
#define I2C_PECPosition_Current ((uint16_t)~RB_I2C_POS)
/* I2C_SMBus_alert_pin_level */
#define I2C_SMBusAlert_Low ((uint16_t)RB_I2C_ALERT)
#define I2C_SMBusAlert_High ((uint16_t)~RB_I2C_ALERT)
/* I2C FLAG mask */
#define FLAG_Mask ((uint32_t)0x00FFFFFF)
/* I2C Interrupt Enable mask */
#define ITEN_Mask ((uint32_t)0x07000000)
/* I2C_mode */
typedef enum
{
I2C_Mode_I2C = 0x0000,
I2C_Mode_SMBusDevice = 0x0002,
I2C_Mode_SMBusHost = 0x000A,
} I2C_ModeTypeDef;
/* I2C_duty_cycle_in_fast_mode */
typedef enum
{
I2C_DutyCycle_16_9 = RB_I2C_DUTY, /* I2C fast mode Tlow/Thigh = 16/9 */
I2C_DutyCycle_2 = 0x0000, /* I2C fast mode Tlow/Thigh = 2 */
} I2C_DutyTypeDef;
/* I2C_acknowledgement - Enables or disables the acknowledgement.*/
typedef enum
{
I2C_Ack_Enable = RB_I2C_ACK,
I2C_Ack_Disable = 0x0000,
} I2C_AckTypeDef;
/* I2C_acknowledged_address - Specifies if 7-bit or 10-bit address is acknowledged. */
typedef enum
{
I2C_AckAddr_7bit = 0x4000,
I2C_AckAddr_10bit = 0xC000,
} I2C_AckAddrTypeDef;
/* I2C_interrupts_definition */
typedef enum
{
I2C_IT_BUF = 0x0400, /* Buffer interrupt mask. */
I2C_IT_EVT = 0x0200, /* Event interrupt mask. */
I2C_IT_ERR = 0x0100, /* Error interrupt mask. */
} I2C_ITTypeDef;
/* I2C_interrupts_definition */
#define I2C_IT_SMBALERT ((uint32_t)0x01008000)
#define I2C_IT_TIMEOUT ((uint32_t)0x01004000)
#define I2C_IT_PECERR ((uint32_t)0x01001000)
#define I2C_IT_OVR ((uint32_t)0x01000800)
#define I2C_IT_AF ((uint32_t)0x01000400)
#define I2C_IT_ARLO ((uint32_t)0x01000200)
#define I2C_IT_BERR ((uint32_t)0x01000100)
#define I2C_IT_TXE ((uint32_t)0x06000080)
#define I2C_IT_RXNE ((uint32_t)0x06000040)
#define I2C_IT_STOPF ((uint32_t)0x02000010)
#define I2C_IT_ADD10 ((uint32_t)0x02000008)
#define I2C_IT_BTF ((uint32_t)0x02000004)
#define I2C_IT_ADDR ((uint32_t)0x02000002)
#define I2C_IT_SB ((uint32_t)0x02000001)
/* SR2 register flags */
#define I2C_FLAG_DUALF ((uint32_t)0x00800000)
#define I2C_FLAG_SMBHOST ((uint32_t)0x00400000)
#define I2C_FLAG_SMBDEFAULT ((uint32_t)0x00200000)
#define I2C_FLAG_GENCALL ((uint32_t)0x00100000)
#define I2C_FLAG_TRA ((uint32_t)0x00040000)
#define I2C_FLAG_BUSY ((uint32_t)0x00020000)
#define I2C_FLAG_MSL ((uint32_t)0x00010000)
/* SR1 register flags */
#define I2C_FLAG_SMBALERT ((uint32_t)0x10008000)
#define I2C_FLAG_TIMEOUT ((uint32_t)0x10004000)
#define I2C_FLAG_PECERR ((uint32_t)0x10001000)
#define I2C_FLAG_OVR ((uint32_t)0x10000800)
#define I2C_FLAG_AF ((uint32_t)0x10000400)
#define I2C_FLAG_ARLO ((uint32_t)0x10000200)
#define I2C_FLAG_BERR ((uint32_t)0x10000100)
#define I2C_FLAG_TXE ((uint32_t)0x10000080)
#define I2C_FLAG_RXNE ((uint32_t)0x10000040)
#define I2C_FLAG_STOPF ((uint32_t)0x10000010)
#define I2C_FLAG_ADD10 ((uint32_t)0x10000008)
#define I2C_FLAG_BTF ((uint32_t)0x10000004)
#define I2C_FLAG_ADDR ((uint32_t)0x10000002)
#define I2C_FLAG_SB ((uint32_t)0x10000001)
/****************I2C Master Events (Events grouped in order of communication)********************/
#define I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
#define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
#define I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ((uint32_t)0x00030002) /* BUSY, MSL and ADDR flags */
#define I2C_EVENT_MASTER_MODE_ADDRESS10 ((uint32_t)0x00030008) /* BUSY, MSL and ADD10 flags */
#define I2C_EVENT_MASTER_BYTE_RECEIVED ((uint32_t)0x00030040) /* BUSY, MSL and RXNE flags */
#define I2C_EVENT_MASTER_BYTE_TRANSMITTING ((uint32_t)0x00070080) /* TRA, BUSY, MSL, TXE flags */
#define I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
/******************I2C Slave Events (Events grouped in order of communication)******************/
#define I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED ((uint32_t)0x00020002) /* BUSY and ADDR flags */
#define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060082) /* TRA, BUSY, TXE and ADDR flags */
#define I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED ((uint32_t)0x00820000) /* DUALF and BUSY flags */
#define I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED ((uint32_t)0x00860080) /* DUALF, TRA, BUSY and TXE flags */
#define I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED ((uint32_t)0x00120000) /* GENCALL and BUSY flags */
#define I2C_EVENT_SLAVE_BYTE_RECEIVED ((uint32_t)0x00020040) /* BUSY and RXNE flags */
#define I2C_EVENT_SLAVE_STOP_DETECTED ((uint32_t)0x00000010) /* STOPF flag */
#define I2C_EVENT_SLAVE_BYTE_TRANSMITTED ((uint32_t)0x00060084) /* TRA, BUSY, TXE and BTF flags */
#define I2C_EVENT_SLAVE_BYTE_TRANSMITTING ((uint32_t)0x00060080) /* TRA, BUSY and TXE flags */
#define I2C_EVENT_SLAVE_ACK_FAILURE ((uint32_t)0x00000400) /* AF flag */
void I2C_Init(I2C_ModeTypeDef I2C_Mode, UINT32 I2C_ClockSpeed, I2C_DutyTypeDef I2C_DutyCycle,
I2C_AckTypeDef I2C_Ack, I2C_AckAddrTypeDef I2C_AckAddr, UINT16 I2C_OwnAddress1);
void I2C_Cmd(FunctionalState NewState);
void I2C_GenerateSTART(FunctionalState NewState);
void I2C_GenerateSTOP(FunctionalState NewState);
void I2C_AcknowledgeConfig(FunctionalState NewState);
void I2C_OwnAddress2Config(uint8_t Address);
void I2C_DualAddressCmd(FunctionalState NewState);
void I2C_GeneralCallCmd(FunctionalState NewState);
void I2C_ITConfig(I2C_ITTypeDef I2C_IT, FunctionalState NewState);
void I2C_SendData(uint8_t Data);
uint8_t I2C_ReceiveData(void);
void I2C_Send7bitAddress(uint8_t Address, uint8_t I2C_Direction);
void I2C_SoftwareResetCmd(FunctionalState NewState);
void I2C_NACKPositionConfig(uint16_t I2C_NACKPosition);
void I2C_SMBusAlertConfig(uint16_t I2C_SMBusAlert);
void I2C_TransmitPEC(FunctionalState NewState);
void I2C_PECPositionConfig(uint16_t I2C_PECPosition);
void I2C_CalculatePEC(FunctionalState NewState);
uint8_t I2C_GetPEC(void);
void I2C_ARPCmd(FunctionalState NewState);
void I2C_StretchClockCmd(FunctionalState NewState);
void I2C_FastModeDutyCycleConfig(uint16_t I2C_DutyCycle);
/****************************************************************************************
* I2C State Monitoring Functions
****************************************************************************************/
uint8_t I2C_CheckEvent(uint32_t I2C_EVENT);
uint32_t I2C_GetLastEvent(void);
FlagStatus I2C_GetFlagStatus(uint32_t I2C_FLAG);
void I2C_ClearFlag(uint32_t I2C_FLAG);
ITStatus I2C_GetITStatus(uint32_t I2C_IT);
void I2C_ClearITPendingBit(uint32_t I2C_IT);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_I2C_H__

View File

@@ -0,0 +1,152 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_pwm.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_PWM_H__
#define __CH58x_PWM_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief channel of PWM define
*/
#define CH_PWM4 0x01 // PWM4 通道
#define CH_PWM5 0x02 // PWM5 通道
#define CH_PWM6 0x04 // PWM6 通道
#define CH_PWM7 0x08 // PWM7 通道
#define CH_PWM8 0x10 // PWM8 通道
#define CH_PWM9 0x20 // PWM9 通道
#define CH_PWM10 0x40 // PWM10 通道
#define CH_PWM11 0x80 // PWM11 通道
/**
* @brief channel of PWM define
*/
typedef enum
{
High_Level = 0, // 默认低电平,高电平有效
Low_Level, // 默认高电平,低电平有效
} PWMX_PolarTypeDef;
/**
* @brief Configuration PWM4_11 Cycle size
*/
typedef enum
{
PWMX_Cycle_256 = 0, // 256 个PWMX周期
PWMX_Cycle_255, // 255 个PWMX周期
PWMX_Cycle_128, // 128 个PWMX周期
PWMX_Cycle_127, // 127 个PWMX周期
PWMX_Cycle_64, // 64 个PWMX周期
PWMX_Cycle_63, // 63 个PWMX周期
PWMX_Cycle_32, // 32 个PWMX周期
PWMX_Cycle_31, // 31 个PWMX周期
} PWMX_CycleTypeDef;
/**
* @brief PWM4-PWM11 通道基准时钟配置
*
* @param d - 通道基准时钟 = d*Tsys
*/
#define PWMX_CLKCfg(d) (R8_PWM_CLOCK_DIV = d)
/**
* @brief PWM4-PWM11基准时钟配置
*
* @param cyc - refer to PWMX_CycleTypeDef
*/
void PWMX_CycleCfg(PWMX_CycleTypeDef cyc);
/**
* @brief 设置 PWM4 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM4_ActDataWidth(d) (R8_PWM4_DATA = d)
/**
* @brief 设置 PWM5 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM5_ActDataWidth(d) (R8_PWM5_DATA = d)
/**
* @brief 设置 PWM6 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM6_ActDataWidth(d) (R8_PWM6_DATA = d)
/**
* @brief 设置 PWM7 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM7_ActDataWidth(d) (R8_PWM7_DATA = d)
/**
* @brief 设置 PWM8 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM8_ActDataWidth(d) (R8_PWM8_DATA = d)
/**
* @brief 设置 PWM9 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM9_ActDataWidth(d) (R8_PWM9_DATA = d)
/**
* @brief 设置 PWM10 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM10_ActDataWidth(d) (R8_PWM10_DATA = d)
/**
* @brief 设置 PWM11 有效数据脉宽
*
* @param d - 有效数据脉宽
*/
#define PWM11_ActDataWidth(d) (R8_PWM11_DATA = d)
/**
* @brief PWM4-PWM11通道输出波形配置
*
* @param ch - select channel of pwm, refer to channel of PWM define
* @param da - effective pulse width
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param s - control pwmx function, ENABLE or DISABLE
*/
void PWMX_ACTOUT(uint8_t ch, uint8_t da, PWMX_PolarTypeDef pr, FunctionalState s);
/**
* @brief PWM 交替输出模式配置
*
* @param ch - select group of PWM alternate output
* RB_PWM4_5_STAG_EN - PWM4 和 PWM5 通道交替输出
* RB_PWM6_7_STAG_EN - PWM6 和 PWM7 通道交替输出
* RB_PWM8_9_STAG_EN - PWM8 和 PWM9 通道交替输出
* RB_PWM10_11_STAG_EN - PWM10 和 PWM11 通道交替输出
* @param s - control pwmx function, ENABLE or DISABLE
*/
void PWMX_AlterOutCfg(uint8_t ch, FunctionalState s);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_PWM_H__

View File

@@ -0,0 +1,167 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_pwr.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_PWR_H__
#define __CH58x_PWR_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Peripher CLK control bit define
*/
#define BIT_SLP_CLK_TMR0 (0x00000001) /*!< TMR0 peripher clk bit */
#define BIT_SLP_CLK_TMR1 (0x00000002) /*!< TMR1 peripher clk bit */
#define BIT_SLP_CLK_TMR2 (0x00000004) /*!< TMR2 peripher clk bit */
#define BIT_SLP_CLK_TMR3 (0x00000008) /*!< TMR3 peripher clk bit */
#define BIT_SLP_CLK_UART0 (0x00000010) /*!< UART0 peripher clk bit */
#define BIT_SLP_CLK_UART1 (0x00000020) /*!< UART1 peripher clk bit */
#define BIT_SLP_CLK_UART2 (0x00000040) /*!< UART2 peripher clk bit */
#define BIT_SLP_CLK_UART3 (0x00000080) /*!< UART3 peripher clk bit */
#define BIT_SLP_CLK_SPI0 (0x00000100) /*!< SPI0 peripher clk bit */
//#define BIT_SLP_CLK_SPI1 (0x00000200) /*!< SPI1 peripher clk bit */
#define BIT_SLP_CLK_PWMX (0x00000400) /*!< PWMX peripher clk bit */
//#define BIT_SLP_CLK_LCD (0x00000800) /*!< LCD peripher clk bit */
#define BIT_SLP_CLK_USB (0x00001000) /*!< USB peripher clk bit */
//#define BIT_SLP_CLK_ETH (0x00002000) /*!< ETH peripher clk bit */
//#define BIT_SLP_CLK_LED (0x00004000) /*!< LED peripher clk bit */
#define BIT_SLP_CLK_BLE (0x00008000) /*!< BLE peripher clk bit */
#define BIT_SLP_CLK_RAMX (0x10000000) /*!< main SRAM RAM16K peripher clk bit */
#define BIT_SLP_CLK_RAM2K (0x20000000) /*!< RAM2K peripher clk bit */
#define BIT_SLP_CLK_ALL (0x3000FFFF) /*!< All peripher clk bit */
/**
* @brief unit of controllable power supply
*/
#define UNIT_SYS_LSE RB_CLK_XT32K_PON // 外部32K 时钟振荡
#define UNIT_SYS_LSI RB_CLK_INT32K_PON // 内部32K 时钟振荡
#define UNIT_SYS_HSE RB_CLK_XT32M_PON // 外部32M 时钟振荡
#define UNIT_SYS_PLL RB_CLK_PLL_PON // PLL 时钟振荡
/**
* @brief wakeup mode define
*/
typedef enum
{
Short_Delay = 0,
Long_Delay,
} WakeUP_ModeypeDef;
/**
* @brief wakeup mode define
*/
typedef enum
{
/* 下面等级将使用高精度监控210uA消耗 */
HALevel_1V9 = 0, // 1.7-1.9
HALevel_2V1, // 1.9-2.1
HALevel_2V3, // 2.1-2.3
HALevel_2V5, // 2.3-2.5
/* 下面等级将使用低功耗监控1uA消耗 */
LPLevel_1V8 = 0x80,
LPLevel_1V9,
LPLevel_2V0,
LPLevel_2V1,
LPLevel_2V2,
LPLevel_2V3,
LPLevel_2V4,
LPLevel_2V5,
} VolM_LevelypeDef;
/**
* @brief 启用内部DC/DC电源用于节约系统功耗
*
* @param s - 是否打开DCDC电源
*/
void PWR_DCDCCfg(FunctionalState s);
/**
* @brief 可控单元模块的电源控制
*
* @param s - 是否打开电源
* @param unit - please refer to unit of controllable power supply
*/
void PWR_UnitModCfg(FunctionalState s, uint8_t unit);
/**
* @brief 外设时钟控制位
*
* @param s - 是否打开对应外设时钟
* @param perph - please refer to Peripher CLK control bit define
*/
void PWR_PeriphClkCfg(FunctionalState s, uint16_t perph);
/**
* @brief 睡眠唤醒源配置
*
* @param s - 是否打开此外设睡眠唤醒功能
* @param perph - 需要设置的唤醒源
* RB_SLP_USB_WAKE - USB 为唤醒源
* RB_SLP_RTC_WAKE - RTC 为唤醒源
* RB_SLP_GPIO_WAKE - GPIO 为唤醒源
* RB_SLP_BAT_WAKE - BAT 为唤醒源
* @param mode - refer to WakeUP_ModeypeDef
*/
void PWR_PeriphWakeUpCfg(FunctionalState s, uint8_t perph, WakeUP_ModeypeDef mode);
/**
* @brief 电源监控
*
* @param s - 是否打开此功能
* @param vl - refer to VolM_LevelypeDef
*/
void PowerMonitor(FunctionalState s, VolM_LevelypeDef vl);
/**
* @brief 低功耗-Idle模式
*/
void LowPower_Idle(void);
/**
* @brief 低功耗-Halt模式此低功耗切到HSI/5时钟运行唤醒后需要用户自己重新选择系统时钟源
*/
void LowPower_Halt(void);
/**
* @brief 低功耗-Sleep模式此低功耗切到HSI/5时钟运行唤醒后需要用户自己重新选择系统时钟源
* @note 注意调用此函数DCDC功能强制关闭唤醒后可以手动再次打开
*
* @param rm - 供电模块选择
* RB_PWR_RAM2K - 2K retention SRAM 供电
* RB_PWR_RAM16K - 16K main SRAM 供电
* RB_PWR_EXTEND - USB 和 BLE 单元保留区域供电
* RB_PWR_XROM - FlashROM 供电
* NULL - 以上单元都断电
*/
void LowPower_Sleep(uint8_t rm);
/**
* @brief 低功耗-Shutdown模式此低功耗切到HSI/5时钟运行唤醒后需要用户自己重新选择系统时钟源
* @note 注意调用此函数DCDC功能强制关闭唤醒后可以手动再次打开
*
* @param rm - 供电模块选择
* RB_PWR_RAM2K - 2K retention SRAM 供电
* RB_PWR_RAM16K - 16K main SRAM 供电
* NULL - 以上单元都断电
*/
void LowPower_Shutdown(uint8_t rm);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_PWR_H__

View File

@@ -0,0 +1,209 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_SPI.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_SPI_H__
#define __CH58x_SPI_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SPI0 interrupt bit define
*/
#define SPI0_IT_FST_BYTE RB_SPI_IE_FST_BYTE // 从机模式的首字节命令模式下,接收到首字节中断
#define SPI0_IT_FIFO_OV RB_SPI_IE_FIFO_OV // FIFO 溢出
#define SPI0_IT_DMA_END RB_SPI_IE_DMA_END // DMA 传输结束
#define SPI0_IT_FIFO_HF RB_SPI_IE_FIFO_HF // FIFO 使用过半
#define SPI0_IT_BYTE_END RB_SPI_IE_BYTE_END // 单字节传输完成
#define SPI0_IT_CNT_END RB_SPI_IE_CNT_END // 全部字节传输完成
/**
* @brief Configuration data mode
*/
typedef enum
{
Mode0_LowBitINFront = 0, // 模式0低位在前
Mode0_HighBitINFront, // 模式0高位在前
Mode3_LowBitINFront, // 模式3低位在前
Mode3_HighBitINFront, // 模式3高位在前
} ModeBitOrderTypeDef;
/**
* @brief Configuration SPI0 slave mode
*/
typedef enum
{
Mode_DataStream = 0, // 数据流模式
Mose_FirstCmd, // 首字节命令模式
} Slave_ModeTypeDef;
/**
* @brief 主机模式默认初始化模式0+3线全双工+8MHz
*/
void SPI0_MasterDefInit(void);
/**
* @brief SPI0 基准时钟配置,= d*Tsys
*
* @param c - 时钟分频系数
*/
void SPI0_CLKCfg(uint8_t c);
/**
* @brief 设置数据流模式
*
* @param m - 数据流模式 refer to ModeBitOrderTypeDef
*/
void SPI0_DataMode(ModeBitOrderTypeDef m);
/**
* @brief 发送单字节 (buffer)
*
* @param d - 发送字节
*/
void SPI0_MasterSendByte(uint8_t d);
/**
* @brief 接收单字节 (buffer)
*
* @param none
*/
uint8_t SPI0_MasterRecvByte(void);
/**
* @brief 使用FIFO连续发送多字节
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度最大4095
*/
void SPI0_MasterTrans(uint8_t *pbuf, uint16_t len);
/**
* @brief 使用FIFO连续接收多字节
*
* @param pbuf - 待接收的数据首地址
* @param len - 待接收的数据长度最大4095
*/
void SPI0_MasterRecv(uint8_t *pbuf, uint16_t len);
/**
* @brief DMA方式连续发送数据
*
* @param pbuf - 待发送数据起始地址,需要四字节对其
* @param len - 待发送数据长度
*/
void SPI0_MasterDMATrans(uint8_t *pbuf, uint16_t len);
/**
* @brief DMA方式连续接收数据
*
* @param pbuf - 待接收数据存放起始地址,需要四字节对其
* @param len - 待接收数据长度
*/
void SPI0_MasterDMARecv(uint8_t *pbuf, uint16_t len);
void SPI1_MasterDefInit(void); /* 主机模式默认初始化模式0+3线全双工+8MHz */
void SPI1_CLKCfg(UINT8 c); /* SPI1 基准时钟配置,= d*Tsys */
void SPI1_DataMode(ModeBitOrderTypeDef m); /* 设置数据流模式 */
void SPI1_MasterSendByte(UINT8 d); /* 发送单字节 (buffer) */
UINT8 SPI1_MasterRecvByte(void); /* 接收单字节 (buffer) */
void SPI1_MasterTrans(UINT8 *pbuf, UINT16 len); /* 使用FIFO连续发送多字节 */
void SPI1_MasterRecv(UINT8 *pbuf, UINT16 len); /* 使用FIFO连续接收多字节 */
/**
* @brief 设备模式默认初始化建议设置MISO的GPIO对应为输入模式
*/
void SPI0_SlaveInit(void);
/**
* @brief 加载首字节数据内容
*
* @param d - 首字节数据内容
*/
#define SetFirstData(d) (R8_SPI0_SLAVE_PRE = d)
/**
* @brief 从机模式,发送一字节数据
*
* @param d - 待发送数据
*/
void SPI0_SlaveSendByte(uint8_t d);
/**
* @brief 从机模式,接收一字节数据
*
* @return 接收到数据
*/
uint8_t SPI0_SlaveRecvByte(void);
/**
* @brief 从机模式,发送多字节数据
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度最大4095
*/
void SPI0_SlaveTrans(uint8_t *pbuf, uint16_t len);
/**
* @brief 从机模式,接收多字节数据
*
* @param pbuf - 接收收数据存放起始地址
* @param len - 请求接收数据长度
*/
void SPI0_SlaveRecv(uint8_t *pbuf, uint16_t len);
/**
* @brief DMA方式连续发送数据
*
* @param pbuf - 待发送数据起始地址,需要四字节对其
* @param len - 待发送数据长度
*/
void SPI0_SlaveDMATrans(uint8_t *pbuf, uint16_t len);
/**
* @brief DMA方式连续接收数据
*
* @param pbuf - 待接收数据存放起始地址,需要四字节对其
* @param len - 待接收数据长度
*/
void SPI0_SlaveDMARecv(uint8_t *pbuf, uint16_t len);
/**
* @brief 配置SPI0中断
*
* @param s - 使能/关闭
* @param f - refer to SPI0 interrupt bit define
*/
#define SPI0_ITCfg(s, f) ((s) ? (R8_SPI0_INTER_EN |= f) : (R8_SPI0_INTER_EN &= ~f))
/**
* @brief 获取中断标志状态0-未置位,(!0)-触发
*
* @param f - refer to SPI0 interrupt bit define
*/
#define SPI0_GetITFlag(f) (R8_SPI0_INT_FLAG & f)
/**
* @brief 清除当前中断标志
*
* @param f - refer to SPI0 interrupt bit define
*/
#define SPI0_ClearITFlag(f) (R8_SPI0_INT_FLAG = f)
#ifdef __cplusplus
}
#endif
#endif // __CH58x_SPI_H__

View File

@@ -0,0 +1,194 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_SYS.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_SYS_H__
#define __CH58x_SYS_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief rtc interrupt event define
*/
typedef enum
{
RST_STATUS_SW = 0, // 软件复位
RST_STATUS_RPOR, // 上电复位
RST_STATUS_WTR, // 看门狗超时复位
RST_STATUS_MR, // 外部手动复位
RST_STATUS_LRM0, // 唤醒复位-软复位引起
RST_STATUS_GPWSM, // 下电模式唤醒复位
RST_STATUS_LRM1, // 唤醒复位-看门狗引起
RST_STATUS_LRM2, // 唤醒复位-手动复位引起
} SYS_ResetStaTypeDef;
/**
* @brief rtc interrupt event define
*/
typedef enum
{
INFO_ROM_READ = 0, // FlashROM 代码和数据区 是否可读
INFO_RESET_EN = 2, // RST#外部手动复位输入功能是否开启
INFO_BOOT_EN, // 系统引导程序 BootLoader 是否开启
INFO_DEBUG_EN, // 系统仿真调试接口是否开启
INFO_LOADER, // 当前系统是否处于Bootloader 区
STA_SAFEACC_ACT, // 当前系统是否处于安全访问状态否则RWA属性区域不可访问
} SYS_InfoStaTypeDef;
/**
* @brief 获取芯片ID类一般为固定值
*/
#define SYS_GetChipID() R8_CHIP_ID
/**
* @brief 获取安全访问ID一般为固定值
*/
#define SYS_GetAccessID() R8_SAFE_ACCESS_ID
/**
* @brief 配置系统运行时钟
*
* @param sc - 系统时钟源选择 refer to SYS_CLKTypeDef
*/
void SetSysClock(SYS_CLKTypeDef sc);
/**
* @brief 获取当前系统时钟
*
* @return Hz
*/
uint32_t GetSysClock(void);
/**
* @brief 获取当前系统信息状态
*
* @param i - refer to SYS_InfoStaTypeDef
*
* @return 是否开启
*/
uint8_t SYS_GetInfoSta(SYS_InfoStaTypeDef i);
/**
* @brief 获取系统上次复位状态
*
* @return refer to SYS_ResetStaTypeDef
*/
#define SYS_GetLastResetSta() (R8_RESET_STATUS & RB_RESET_FLAG)
/**
* @brief 执行系统软件复位
*/
void SYS_ResetExecute(void);
/**
* @brief 设置复位保存寄存器的值,不受手动复位、 软件复位、 看门狗复位或者普通唤醒复位的影响
*
* @param i - refer to SYS_InfoStaTypeDef
*/
#define SYS_ResetKeepBuf(d) (R8_GLOB_RESET_KEEP = d)
/**
* @brief 关闭所有中断,并保留当前中断值
*
* @param pirqv - 当前保留中断值
*/
void SYS_DisableAllIrq(uint32_t *pirqv);
/**
* @brief 恢复之前关闭的中断值
*
* @param irq_status - 当前保留中断值
*/
void SYS_RecoverIrq(uint32_t irq_status);
/**
* @brief 获取当前系统(SYSTICK)计数值
*
* @return 当前计数值
*/
uint32_t SYS_GetSysTickCnt(void);
/**
* @brief 加载看门狗计数初值,递增型
*
* @param c - 看门狗计数初值
*/
#define WWDG_SetCounter(c) (R8_WDOG_COUNT = c)
/**
* @brief 看门狗定时器溢出中断使能
*
* @param s - 溢出是否中断
*/
void WWDG_ITCfg(FunctionalState s);
/**
* @brief 看门狗定时器复位功能
*
* @param s - 溢出是否复位
*/
void WWDG_ResetCfg(FunctionalState s);
/**
* @brief 获取当前看门狗定时器溢出标志
*
* @return 看门狗定时器溢出标志
*/
#define WWDG_GetFlowFlag() (R8_RST_WDOG_CTRL & RB_WDOG_INT_FLAG)
/**
* @brief 清除看门狗中断标志,重新加载计数值也可清除
*/
void WWDG_ClearFlag(void);
/**
* @brief uS 延时
*
* @param t - 时间参数
*/
void mDelayuS(uint16_t t);
/**
* @brief mS 延时
*
* @param t - 时间参数
*/
void mDelaymS(uint16_t t);
/**
* @brief Enter safe access mode.
*
* @NOTE: After enter safe access mode, about 16 system frequency cycles
* are in safe mode, and one or more secure registers can be rewritten
* within the valid period. The safe mode will be automatically
* terminated after the above validity period is exceeded.
*/
__attribute__((always_inline)) static inline void sys_safe_access_enable(void)
{
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
SAFEOPERATE;
}
__attribute__((always_inline)) static inline void sys_safe_access_disable(void)
{
R8_SAFE_ACCESS_SIG = 0;
}
#ifdef __cplusplus
}
#endif
#endif // __CH58x_SYS_H__

View File

@@ -0,0 +1,555 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_timer.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_TIMER_H__
#define __CH58x_TIMER_H__
#ifdef __cplusplus
extern "C" {
#endif
#define DataBit_25 (1 << 25)
/**
* @brief TMR0 interrupt bit define
*/
#define TMR0_3_IT_CYC_END 0x01 // 周期结束标志:捕捉-超时,定时-周期结束PWM-周期结束
#define TMR0_3_IT_DATA_ACT 0x02 // 数据有效标志:捕捉-新数据PWM-有效电平结束
#define TMR0_3_IT_FIFO_HF 0x04 // FIFO 使用过半:捕捉- FIFO>=4 PWM- FIFO<4
#define TMR1_2_IT_DMA_END 0x08 // DMA 结束支持TMR1和TMR2
#define TMR0_3_IT_FIFO_OV 0x10 // FIFO 溢出:捕捉- FIFO满 PWM- FIFO空
/**
* @brief Configuration PWM effective level repeat times
*/
typedef enum
{
PWM_Times_1 = 0, // PWM 有效输出重复1次数
PWM_Times_4, // PWM 有效输出重复4次数
PWM_Times_8, // PWM 有效输出重复8次数
PWM_Times_16, // PWM 有效输出重复16次数
} PWM_RepeatTsTypeDef;
/**
* @brief Configuration Cap mode
*/
typedef enum
{
CAP_NULL = 0, // 不捕捉 & 不计数
Edge_To_Edge, // 任意边沿之间 & 计数任意边沿
FallEdge_To_FallEdge, // 下降沿到下降沿 & 计数下降沿
RiseEdge_To_RiseEdge, // 上升沿到上升沿 & 计数上升沿
} CapModeTypeDef;
/**
* @brief Configuration DMA mode
*/
typedef enum
{
Mode_Single = 0, // 单次模式
Mode_LOOP, // 循环模式
} DMAModeTypeDef;
/**
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*/
void TMR0_TimerInit(uint32_t t);
/**
* @brief 获取当前定时器值最大67108864
*
* @return 当前定时器值
*/
#define TMR0_GetCurrentTimer() R32_TMR0_COUNT
/**
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*/
void TMR0_EXTSingleCounterInit(CapModeTypeDef cap);
/**
* @brief 设置计数统计溢出大小最大67108862
*
* @param cyc - 计数统计溢出大小
*/
#define TMR0_CountOverflowCfg(cyc) (R32_TMR0_CNT_END = (cyc + 2))
/**
* @brief 获取当前计数值最大67108862
*
* @return 当前计数值
*/
#define TMR0_GetCurrentCount() R32_TMR0_COUNT
/**
* @brief PWM0 通道输出波形周期配置, 最大67108864
*
* @param cyc - 输出波形周期
*/
#define TMR0_PWMCycleCfg(cyc) (R32_TMR0_CNT_END = cyc)
/**
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*/
void TMR0_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts);
/**
* @brief PWM0 有效数据脉宽, 最大67108864
*
* @param d - 有效数据脉宽
*/
#define TMR0_PWMActDataWidth(d) (R32_TMR0_FIFO = d)
/**
* @brief CAP0 捕捉电平超时配置, 最大33554432
*
* @param cyc - 捕捉电平超时
*/
#define TMR0_CAPTimeoutCfg(cyc) (R32_TMR0_CNT_END = cyc)
/**
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*/
void TMR0_CapInit(CapModeTypeDef cap);
/**
* @brief 获取脉冲数据
*
* @return 脉冲数据
*/
#define TMR0_CAPGetData() R32_TMR0_FIFO
/**
* @brief 获取当前已捕获数据个数
*
* @return 当前已捕获数据个数
*/
#define TMR0_CAPDataCounter() R8_TMR0_FIFO_COUNT
/**
* @brief 关闭 TMR0
*/
#define TMR0_Disable() (R8_TMR0_CTRL_MOD &= ~RB_TMR_COUNT_EN)
/**
* @brief 开启 TMR0
*/
#define TMR0_Enable() (R8_TMR0_CTRL_MOD |= RB_TMR_COUNT_EN)
/**
* @brief 中断配置
*
* @param s - 使能/关闭
* @param f - refer to TMR interrupt bit define
*/
#define TMR0_ITCfg(s, f) ((s) ? (R8_TMR0_INTER_EN |= f) : (R8_TMR0_INTER_EN &= ~f))
/**
* @brief 清除中断标志
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR0_ClearITFlag(f) (R8_TMR0_INT_FLAG = f)
/**
* @brief 查询中断标志状态
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR0_GetITFlag(f) (R8_TMR0_INT_FLAG & f)
/**
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*/
void TMR1_TimerInit(uint32_t t);
/**
* @brief 获取当前定时器值最大67108864
*
* @return 当前定时器值
*/
#define TMR1_GetCurrentTimer() R32_TMR1_COUNT
/**
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*/
void TMR1_EXTSingleCounterInit(CapModeTypeDef cap);
/**
* @brief 设置计数统计溢出大小最大67108862
*
* @param cyc - 计数统计溢出大小
*/
#define TMR1_CountOverflowCfg(cyc) (R32_TMR1_CNT_END = (cyc + 2))
/**
* @brief 获取当前计数值最大67108862
*
* @return 当前计数值
*/
#define TMR1_GetCurrentCount() R32_TMR1_COUNT
/**
* @brief PWM1 通道输出波形周期配置, 最大67108864
*
* @param cyc - 输出波形周期
*/
#define TMR1_PWMCycleCfg(cyc) (R32_TMR1_CNT_END = cyc)
/**
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*/
void TMR1_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts);
/**
* @brief PWM1 有效数据脉宽, 最大67108864
*
* @param d - 有效数据脉宽
*/
#define TMR1_PWMActDataWidth(d) (R32_TMR1_FIFO = d)
/**
* @brief CAP1 捕捉电平超时配置, 最大33554432
*
* @param cyc - 捕捉电平超时
*/
#define TMR1_CAPTimeoutCfg(cyc) (R32_TMR1_CNT_END = cyc)
/**
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*/
void TMR1_CapInit(CapModeTypeDef cap);
/**
* @brief 获取脉冲数据
*
* @return 脉冲数据
*/
#define TMR1_CAPGetData() R32_TMR1_FIFO
/**
* @brief 获取当前已捕获数据个数
*
* @return 当前已捕获数据个数
*/
#define TMR1_CAPDataCounter() R8_TMR1_FIFO_COUNT
/**
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*/
void TMR1_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, DMAModeTypeDef m);
/**
* @brief 关闭 TMR1
*/
#define TMR1_Disable() (R8_TMR1_CTRL_MOD &= ~RB_TMR_COUNT_EN)
/**
* @brief 开启 TMR1
*/
#define TMR1_Enable() (R8_TMR1_CTRL_MOD |= RB_TMR_COUNT_EN)
/**
* @brief 中断配置
*
* @param s - 使能/关闭
* @param f - refer to TMR interrupt bit define
*/
#define TMR1_ITCfg(s, f) ((s) ? (R8_TMR1_INTER_EN |= f) : (R8_TMR1_INTER_EN &= ~f))
/**
* @brief 清除中断标志
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR1_ClearITFlag(f) (R8_TMR1_INT_FLAG = f)
/**
* @brief 查询中断标志状态
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR1_GetITFlag(f) (R8_TMR1_INT_FLAG & f)
/**
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*/
void TMR2_TimerInit(uint32_t t);
/**
* @brief 获取当前定时器值最大67108864
*
* @return 当前定时器值
*/
#define TMR2_GetCurrentTimer() R32_TMR2_COUNT
/**
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*/
void TMR2_EXTSingleCounterInit(CapModeTypeDef cap);
/**
* @brief 设置计数统计溢出大小最大67108862
*
* @param cyc - 计数统计溢出大小
*/
#define TMR2_CountOverflowCfg(cyc) (R32_TMR2_CNT_END = (cyc + 2))
/**
* @brief 获取当前计数值最大67108862
*
* @return 当前计数值
*/
#define TMR2_GetCurrentCount() R32_TMR2_COUNT
/**
* @brief PWM2 通道输出波形周期配置, 最大67108864
*
* @param cyc - 输出波形周期
*/
#define TMR2_PWMCycleCfg(cyc) (R32_TMR2_CNT_END = cyc)
/**
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*/
void TMR2_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts);
/**
* @brief PWM2 有效数据脉宽, 最大67108864
*
* @param d - 有效数据脉宽
*/
#define TMR2_PWMActDataWidth(d) (R32_TMR2_FIFO = d)
/**
* @brief CAP2 捕捉电平超时配置, 最大33554432
*
* @param cyc - 捕捉电平超时
*/
#define TMR2_CAPTimeoutCfg(cyc) (R32_TMR2_CNT_END = cyc)
/**
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*/
void TMR2_CapInit(CapModeTypeDef cap);
/**
* @brief 获取脉冲数据
*
* @return 脉冲数据
*/
#define TMR2_CAPGetData() R32_TMR2_FIFO
/**
* @brief 获取当前已捕获数据个数
*
* @return 当前已捕获数据个数
*/
#define TMR2_CAPDataCounter() R8_TMR2_FIFO_COUNT
/**
* @brief 配置DMA功能
*
* @param s - 是否打开DMA功能
* @param startAddr - DMA 起始地址
* @param endAddr - DMA 结束地址
* @param m - 配置DMA模式
*/
void TMR2_DMACfg(uint8_t s, uint16_t startAddr, uint16_t endAddr, DMAModeTypeDef m);
/**
* @brief 关闭 TMR2
*/
#define TMR2_Disable() (R8_TMR2_CTRL_MOD &= ~RB_TMR_COUNT_EN)
/**
* @brief 开启 TMR2
*/
#define TMR2_Enable() (R8_TMR2_CTRL_MOD |= RB_TMR_COUNT_EN)
/**
* @brief 中断配置
*
* @param s - 使能/关闭
* @param f - refer to TMR interrupt bit define
*/
#define TMR2_ITCfg(s, f) ((s) ? (R8_TMR2_INTER_EN |= f) : (R8_TMR2_INTER_EN &= ~f))
/**
* @brief 清除中断标志
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR2_ClearITFlag(f) (R8_TMR2_INT_FLAG = f)
/**
* @brief 查询中断标志状态
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR2_GetITFlag(f) (R8_TMR2_INT_FLAG & f)
/**
* @brief 定时功能初始化
*
* @param t - 定时时间基于当前系统时钟Tsys, 最长定时周期 67108864
*/
void TMR3_TimerInit(uint32_t t);
/**
* @brief 获取当前定时器值最大67108864
*
* @return 当前定时器值
*/
#define TMR3_GetCurrentTimer() R32_TMR3_COUNT
/**
* @brief 边沿计数功能初始化
*
* @param cap - 采集计数类型
*/
void TMR3_EXTSingleCounterInit(CapModeTypeDef cap);
/**
* @brief 设置计数统计溢出大小最大67108862
*
* @param cyc - 计数统计溢出大小
*/
#define TMR3_CountOverflowCfg(cyc) (R32_TMR3_CNT_END = (cyc + 2))
/**
* @brief 获取当前计数值最大67108862
*
* @return 当前计数值
*/
#define TMR3_GetCurrentCount() R32_TMR3_COUNT
/**
* @brief PWM3 通道输出波形周期配置, 最大67108864
*
* @param cyc - 输出波形周期
*/
#define TMR3_PWMCycleCfg(cyc) (R32_TMR3_CNT_END = cyc)
/**
* @brief PWM 输出初始化
*
* @param pr - select wave polar, refer to PWMX_PolarTypeDef
* @param ts - set pwm repeat times, refer to PWM_RepeatTsTypeDef
*/
void TMR3_PWMInit(PWMX_PolarTypeDef pr, PWM_RepeatTsTypeDef ts);
/**
* @brief PWM3 有效数据脉宽, 最大67108864
*
* @param d - 有效数据脉宽
*/
#define TMR3_PWMActDataWidth(d) (R32_TMR3_FIFO = d)
/**
* @brief CAP3 捕捉电平超时配置, 最大33554432
*
* @param cyc - 捕捉电平超时
*/
#define TMR3_CAPTimeoutCfg(cyc) (R32_TMR3_CNT_END = cyc)
/**
* @brief 外部信号捕捉功能初始化
*
* @param cap - select capture mode, refer to CapModeTypeDef
*/
void TMR3_CapInit(CapModeTypeDef cap);
/**
* @brief 获取脉冲数据
*
* @return 脉冲数据
*/
#define TMR3_CAPGetData() R32_TMR3_FIFO
/**
* @brief 获取当前已捕获数据个数
*
* @return 当前已捕获数据个数
*/
#define TMR3_CAPDataCounter() R8_TMR3_FIFO_COUNT
/**
* @brief 关闭 TMR3
*/
#define TMR3_Disable() (R8_TMR3_CTRL_MOD &= ~RB_TMR_COUNT_EN)
/**
* @brief 开启 TMR3
*/
#define TMR3_Enable() (R8_TMR3_CTRL_MOD |= RB_TMR_COUNT_EN)
/**
* @brief 中断配置
*
* @param s - 使能/关闭
* @param f - refer to TMR interrupt bit define
*/
#define TMR3_ITCfg(s, f) ((s) ? (R8_TMR3_INTER_EN |= f) : (R8_TMR3_INTER_EN &= ~f))
/**
* @brief 清除中断标志
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR3_ClearITFlag(f) (R8_TMR3_INT_FLAG = f)
/**
* @brief 查询中断标志状态
*
* @param f - refer to TMR interrupt bit define
*/
#define TMR3_GetITFlag(f) (R8_TMR3_INT_FLAG & f)
#ifdef __cplusplus
}
#endif
#endif // __CH58x_TIMER_H__

View File

@@ -0,0 +1,412 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_uart.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_UART_H__
#define __CH58x_UART_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LINE error and status define
*/
#define STA_ERR_BREAK RB_LSR_BREAK_ERR // 数据间隔错误
#define STA_ERR_FRAME RB_LSR_FRAME_ERR // 数据帧错误
#define STA_ERR_PAR RB_LSR_PAR_ERR // 奇偶校验位出错
#define STA_ERR_FIFOOV RB_LSR_OVER_ERR // 接收数据溢出
#define STA_TXFIFO_EMP RB_LSR_TX_FIFO_EMP // 当前发送FIFO空可以继续填充发送数据
#define STA_TXALL_EMP RB_LSR_TX_ALL_EMP // 当前所有发送数据都发送完成
#define STA_RECV_DATA RB_LSR_DATA_RDY // 当前有接收到数据
/**
* @brief Configuration UART TrigByte num
*/
typedef enum
{
UART_1BYTE_TRIG = 0, // 1字节触发
UART_2BYTE_TRIG, // 2字节触发
UART_4BYTE_TRIG, // 4字节触发
UART_7BYTE_TRIG, // 7字节触发
} UARTByteTRIGTypeDef;
/**
* @brief 串口默认初始化配置
*/
void UART0_DefInit(void);
/**
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*/
void UART0_BaudRateCfg(uint32_t baudrate);
/**
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*/
void UART0_ByteTrigCfg(UARTByteTRIGTypeDef b);
/**
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*/
void UART0_INTCfg(FunctionalState s, uint8_t i);
/**
* @brief 串口软件复位
*/
void UART0_Reset(void);
/**
* @brief 清除当前接收FIFO
*/
#define UART0_CLR_RXFIFO() (R8_UART0_FCR |= RB_FCR_RX_FIFO_CLR)
/**
* @brief 清除当前发送FIFO
*/
#define UART0_CLR_TXFIFO() (R8_UART0_FCR |= RB_FCR_TX_FIFO_CLR)
/**
* @brief 获取当前中断标志
*
* @return 当前中断标志
*/
#define UART0_GetITFlag() (R8_UART0_IIR & RB_IIR_INT_MASK)
/**
* @brief 获取当前通讯状态
*
* @return refer to LINE error and status define
*/
#define UART0_GetLinSTA() (R8_UART0_LSR)
/**
* @brief 串口单字节发送
*
* @param b 待发送的字节
*/
#define UART0_SendByte(b) (R8_UART0_THR = b)
/**
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*/
void UART0_SendString(uint8_t *buf, uint16_t l);
/**
* @brief 串口读取单字节
*
* @return 读取到的单字节
*/
#define UART0_RecvByte() (R8_UART0_RBR)
/**
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART0_RecvString(uint8_t *buf);
/**
* @brief 串口默认初始化配置
*/
void UART1_DefInit(void);
/**
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*/
void UART1_BaudRateCfg(uint32_t baudrate);
/**
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*/
void UART1_ByteTrigCfg(UARTByteTRIGTypeDef b);
/**
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*/
void UART1_INTCfg(FunctionalState s, uint8_t i);
/**
* @brief 串口软件复位
*/
void UART1_Reset(void);
/**
* @brief 清除当前接收FIFO
*/
#define UART1_CLR_RXFIFO() (R8_UART1_FCR |= RB_FCR_RX_FIFO_CLR)
/**
* @brief 清除当前发送FIFO
*/
#define UART1_CLR_TXFIFO() (R8_UART1_FCR |= RB_FCR_TX_FIFO_CLR)
/**
* @brief 获取当前中断标志
*
* @return 当前中断标志
*/
#define UART1_GetITFlag() (R8_UART1_IIR & RB_IIR_INT_MASK)
/**
* @brief 获取当前通讯状态
*
* @return refer to LINE error and status define
*/
#define UART1_GetLinSTA() (R8_UART1_LSR)
/**
* @brief 串口单字节发送
*
* @param b 待发送的字节
*/
#define UART1_SendByte(b) (R8_UART1_THR = b)
/**
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*/
void UART1_SendString(uint8_t *buf, uint16_t l);
/**
* @brief 串口读取单字节
*
* @return 读取到的单字节
*/
#define UART1_RecvByte() (R8_UART1_RBR)
/**
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART1_RecvString(uint8_t *buf);
/**
* @brief 串口默认初始化配置
*/
void UART2_DefInit(void);
/**
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*/
void UART2_BaudRateCfg(uint32_t baudrate);
/**
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*/
void UART2_ByteTrigCfg(UARTByteTRIGTypeDef b);
/**
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*/
void UART2_INTCfg(FunctionalState s, uint8_t i);
/**
* @brief 串口软件复位
*/
void UART2_Reset(void);
/**
* @brief 清除当前接收FIFO
*/
#define UART2_CLR_RXFIFO() (R8_UART2_FCR |= RB_FCR_RX_FIFO_CLR)
/**
* @brief 清除当前发送FIFO
*/
#define UART2_CLR_TXFIFO() (R8_UART2_FCR |= RB_FCR_TX_FIFO_CLR)
/**
* @brief 获取当前中断标志
*
* @return 当前中断标志
*/
#define UART2_GetITFlag() (R8_UART2_IIR & RB_IIR_INT_MASK)
/**
* @brief 获取当前通讯状态
*
* @return refer to LINE error and status define
*/
#define UART2_GetLinSTA() (R8_UART2_LSR)
/**
* @brief 串口单字节发送
*
* @param b 待发送的字节
*/
#define UART2_SendByte(b) (R8_UART2_THR = b)
/**
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*/
void UART2_SendString(uint8_t *buf, uint16_t l);
/**
* @brief 串口读取单字节
*
* @return 读取到的单字节
*/
#define UART2_RecvByte() (R8_UART2_RBR)
/**
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART2_RecvString(uint8_t *buf);
/**
* @brief 串口默认初始化配置
*/
void UART3_DefInit(void);
/**
* @brief 串口波特率配置
*
* @param baudrate - 波特率
*/
void UART3_BaudRateCfg(uint32_t baudrate);
/**
* @brief 串口字节触发中断配置
*
* @param b - 触发字节数 refer to UARTByteTRIGTypeDef
*/
void UART3_ByteTrigCfg(UARTByteTRIGTypeDef b);
/**
* @brief 串口中断配置
*
* @param s - 中断控制状态,是否使能相应中断
* @param i - 中断类型
* RB_IER_MODEM_CHG - 调制解调器输入状态变化中断使能位(仅 UART0 支持)
* RB_IER_LINE_STAT - 接收线路状态中断
* RB_IER_THR_EMPTY - 发送保持寄存器空中断
* RB_IER_RECV_RDY - 接收数据中断
*/
void UART3_INTCfg(FunctionalState s, uint8_t i);
/**
* @brief 串口软件复位
*/
void UART3_Reset(void);
/**
* @brief 清除当前接收FIFO
*/
#define UART3_CLR_RXFIFO() (R8_UART3_FCR |= RB_FCR_RX_FIFO_CLR)
/**
* @brief 清除当前发送FIFO
*/
#define UART3_CLR_TXFIFO() (R8_UART3_FCR |= RB_FCR_TX_FIFO_CLR)
/**
* @brief 获取当前中断标志
*
* @return 当前中断标志
*/
#define UART3_GetITFlag() (R8_UART3_IIR & RB_IIR_INT_MASK)
/**
* @brief 获取当前通讯状态
*
* @return refer to LINE error and status define
*/
#define UART3_GetLinSTA() (R8_UART3_LSR)
/**
* @brief 串口单字节发送
*
* @param b 待发送的字节
*/
#define UART3_SendByte(b) (R8_UART3_THR = b)
/**
* @brief 串口多字节发送
*
* @param buf - 待发送的数据内容首地址
* @param l - 待发送的数据长度
*/
void UART3_SendString(uint8_t *buf, uint16_t l);
/**
* @brief 串口读取单字节
*
* @return 读取到的单字节
*/
#define UART3_RecvByte() (R8_UART3_RBR)
/**
* @brief 串口读取多字节
*
* @param buf - 读取数据存放缓存区首地址
*
* @return 读取数据长度
*/
uint16_t UART3_RecvString(uint8_t *buf);
#ifdef __cplusplus
}
#endif
#endif // __CH58x_UART_H__

View File

@@ -0,0 +1,177 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_usbdev.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_USBDEV_H__
#define __CH58x_USBDEV_H__
#ifdef __cplusplus
extern "C" {
#endif
/* HID类请求 */
#define DEF_USB_GET_IDLE 0x02 /* get idle for key or mouse */
#define DEF_USB_GET_PROTOCOL 0x03 /* get protocol for bios type */
#define DEF_USB_SET_REPORT 0x09 /* set report for key */
#define DEF_USB_SET_IDLE 0x0A /* set idle for key or mouse */
#define DEF_USB_SET_PROTOCOL 0x0B /* set protocol for bios type */
/* 以下缓存区是USB模块收发使用的数据缓冲区总共9个通道9块缓存用户可根据实际使用的通道数定义相应缓存区 */
extern uint8_t *pEP0_RAM_Addr; //ep0(64)+ep4_out(64)+ep4_in(64)
extern uint8_t *pEP1_RAM_Addr; //ep1_out(64)+ep1_in(64)
extern uint8_t *pEP2_RAM_Addr; //ep2_out(64)+ep2_in(64)
extern uint8_t *pEP3_RAM_Addr; //ep3_out(64)+ep3_in(64)
extern uint8_t *pU2EP0_RAM_Addr; //ep0(64)+ep4_out(64)+ep4_in(64)
extern uint8_t *pU2EP1_RAM_Addr; //ep1_out(64)+ep1_in(64)
extern uint8_t *pU2EP2_RAM_Addr; //ep2_out(64)+ep2_in(64)
extern uint8_t *pU2EP3_RAM_Addr; //ep3_out(64)+ep3_in(64)
#define pSetupReqPak ((PUSB_SETUP_REQ)pEP0_RAM_Addr)
#define pEP0_DataBuf (pEP0_RAM_Addr)
#define pEP1_OUT_DataBuf (pEP1_RAM_Addr)
#define pEP1_IN_DataBuf (pEP1_RAM_Addr + 64)
#define pEP2_OUT_DataBuf (pEP2_RAM_Addr)
#define pEP2_IN_DataBuf (pEP2_RAM_Addr + 64)
#define pEP3_OUT_DataBuf (pEP3_RAM_Addr)
#define pEP3_IN_DataBuf (pEP3_RAM_Addr + 64)
#define pEP4_OUT_DataBuf (pEP0_RAM_Addr + 64)
#define pEP4_IN_DataBuf (pEP0_RAM_Addr + 128)
#define pU2SetupReqPak ((PUSB_SETUP_REQ)pU2EP0_RAM_Addr)
#define pU2EP0_DataBuf (pU2EP0_RAM_Addr)
#define pU2EP1_OUT_DataBuf (pU2EP1_RAM_Addr)
#define pU2EP1_IN_DataBuf (pU2EP1_RAM_Addr + 64)
#define pU2EP2_OUT_DataBuf (pU2EP2_RAM_Addr)
#define pU2EP2_IN_DataBuf (pU2EP2_RAM_Addr + 64)
#define pU2EP3_OUT_DataBuf (pU2EP3_RAM_Addr)
#define pU2EP3_IN_DataBuf (pU2EP3_RAM_Addr + 64)
#define pU2EP4_OUT_DataBuf (pU2EP0_RAM_Addr + 64)
#define pU2EP4_IN_DataBuf (pU2EP0_RAM_Addr + 128)
/**
* @brief USB设备功能初始化4个端点8个通道。
*/
void USB_DeviceInit(void);
/**
* @brief USB设备应答传输处理
*/
void USB_DevTransProcess(void);
/**
* @brief 端点1下传数据处理
*
* @param l - 待处理数据长度(<64B)
*/
void DevEP1_OUT_Deal(uint8_t l);
/**
* @brief 端点2下传数据处理
*
* @param l - 待处理数据长度(<64B)
*/
void DevEP2_OUT_Deal(uint8_t l);
/**
* @brief 端点3下传数据处理
*
* @param l - 待处理数据长度(<64B)
*/
void DevEP3_OUT_Deal(uint8_t l);
/**
* @brief 端点4下传数据处理
*
* @param l - 待处理数据长度(<64B)
*/
void DevEP4_OUT_Deal(uint8_t l);
/**
* @brief 端点1数据上传
*
* @param l - 上传数据长度(<64B)
*/
void DevEP1_IN_Deal(uint8_t l);
/**
* @brief 端点2数据上传
*
* @param l - 上传数据长度(<64B)
*/
void DevEP2_IN_Deal(uint8_t l);
/**
* @brief 端点3数据上传
*
* @param l - 上传数据长度(<64B)
*/
void DevEP3_IN_Deal(uint8_t l);
/**
* @brief 端点4数据上传
*
* @param l - 上传数据长度(<64B)
*/
void DevEP4_IN_Deal(uint8_t l);
/**
* @brief 查询端点1是否上传完成
*
* @return 0-未完成 (!0)-已完成
*/
#define EP1_GetINSta() (R8_UEP1_CTRL & UEP_T_RES_NAK)
/**
* @brief 查询端点2是否上传完成
*
* @return 0-未完成 (!0)-已完成
*/
#define EP2_GetINSta() (R8_UEP2_CTRL & UEP_T_RES_NAK)
/**
* @brief 查询端点3是否上传完成
*
* @return 0-未完成 (!0)-已完成
*/
#define EP3_GetINSta() (R8_UEP3_CTRL & UEP_T_RES_NAK)
/**
* @brief 查询端点4是否上传完成
*
* @return 0-未完成 (!0)-已完成
*/
#define EP4_GetINSta() (R8_UEP4_CTRL & UEP_T_RES_NAK)
void USB2_DeviceInit(void); /* USB2设备功能初始化4个端点8个通道 */
void USB2_DevTransProcess(void); /* USB2设备应答传输处理 */
void U2DevEP1_OUT_Deal(uint8_t l); /* 设备端点1下传通道处理 */
void U2DevEP2_OUT_Deal(uint8_t l); /* 设备端点2下传通道处理 */
void U2DevEP3_OUT_Deal(uint8_t l); /* 设备端点3下传通道处理 */
void U2DevEP4_OUT_Deal(uint8_t l); /* 设备端点4下传通道处理 */
void U2DevEP1_IN_Deal(uint8_t l); /* 设备端点1上传通道处理 */
void U2DevEP2_IN_Deal(uint8_t l); /* 设备端点2上传通道处理 */
void U2DevEP3_IN_Deal(uint8_t l); /* 设备端点3上传通道处理 */
void U2DevEP4_IN_Deal(uint8_t l); /* 设备端点4上传通道处理 */
// 0-未完成 (!0)-已完成
#define U2EP1_GetINSta() (R8_U2EP1_CTRL & UEP_T_RES_NAK) /* 查询端点1是否上传完成 */
#define U2EP2_GetINSta() (R8_U2EP2_CTRL & UEP_T_RES_NAK) /* 查询端点2是否上传完成 */
#define U2EP3_GetINSta() (R8_U2EP3_CTRL & UEP_T_RES_NAK) /* 查询端点3是否上传完成 */
#define U2EP4_GetINSta() (R8_U2EP4_CTRL & UEP_T_RES_NAK) /* 查询端点4是否上传完成 */
#ifdef __cplusplus
}
#endif
#endif // __CH58x_USBDEV_H__

View File

@@ -0,0 +1,349 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : CH57x_usbhost.h
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH58x_USBHOST_H__
#define __CH58x_USBHOST_H__
#ifdef __cplusplus
extern "C" {
#endif
#if DISK_LIB_ENABLE
#if DISK_WITHOUT_USB_HUB
/* 不使用U盘文件系统库或者U盘挂载USBhub下面需要关闭下面定义 */
#define FOR_ROOT_UDISK_ONLY
#endif
/* 使用U盘文件系统库需要开启下面定义, 不使用请关闭 */
#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节,建议选择为2048甚至4096以支持某些大扇区的U盘,为0则禁止在.H文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */
#endif
// 各子程序返回状态码
#define ERR_SUCCESS 0x00 // 操作成功
#define ERR_USB_CONNECT 0x15 /* 检测到USB设备连接事件,已经连接 */
#define ERR_USB_DISCON 0x16 /* 检测到USB设备断开事件,已经断开 */
#define ERR_USB_BUF_OVER 0x17 /* USB传输的数据有误或者数据太多缓冲区溢出 */
#define ERR_USB_DISK_ERR 0x1F /* USB存储器操作失败,在初始化时可能是USB存储器不支持,在读写操作中可能是磁盘损坏或者已经断开 */
#define ERR_USB_TRANSFER 0x20 /* NAK/STALL等更多错误码在0x20~0x2F */
#define ERR_USB_UNSUPPORT 0xFB /* 不支持的USB设备*/
#define ERR_USB_UNKNOWN 0xFE /* 设备操作出错*/
#define ERR_AOA_PROTOCOL 0x41 /* 协议版本出错 */
/*USB设备相关信息表,最多支持1个设备*/
#define ROOT_DEV_DISCONNECT 0
#define ROOT_DEV_CONNECTED 1
#define ROOT_DEV_FAILED 2
#define ROOT_DEV_SUCCESS 3
#define DEV_TYPE_KEYBOARD (USB_DEV_CLASS_HID | 0x20)
#define DEV_TYPE_MOUSE (USB_DEV_CLASS_HID | 0x30)
#define DEF_AOA_DEVICE 0xF0
#define DEV_TYPE_UNKNOW 0xFF
/*
约定: USB设备地址分配规则(参考USB_DEVICE_ADDR)
地址值 设备位置
0x02 内置Root-HUB下的USB设备或外部HUB
0x1x 内置Root-HUB下的外部HUB的端口x下的USB设备,x为1~n
*/
#define HUB_MAX_PORTS 4
#define WAIT_USB_TOUT_200US 800 // 等待USB中断超时时间
typedef struct
{
uint8_t DeviceStatus; // 设备状态,0-无设备,1-有设备但尚未初始化,2-有设备但初始化枚举失败,3-有设备且初始化枚举成功
uint8_t DeviceAddress; // 设备被分配的USB地址
uint8_t DeviceSpeed; // 0为低速,非0为全速
uint8_t DeviceType; // 设备类型
uint16_t DeviceVID;
uint16_t DevicePID;
uint8_t GpVar[4]; // 通用变量,存放端点
uint8_t GpHUBPortNum; // 通用变量,如果是HUB表示HUB端口数
} _RootHubDev;
typedef struct
{
UINT8 DeviceStatus; // 设备状态,0-无设备,1-有设备但尚未初始化,2-有设备但初始化枚举失败,3-有设备且初始化枚举成功
UINT8 DeviceAddress; // 设备被分配的USB地址
UINT8 DeviceSpeed; // 0为低速,非0为全速
UINT8 DeviceType; // 设备类型
UINT16 DeviceVID;
UINT16 DevicePID;
UINT8 GpVar[4]; // 通用变量
} _DevOnHubPort; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
extern _RootHubDev ThisUsbDev;
extern _DevOnHubPort DevOnHubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
extern uint8_t UsbDevEndp0Size; // USB设备的端点0的最大包尺寸 */
extern uint8_t FoundNewDev;
extern uint8_t *pHOST_RX_RAM_Addr;
extern uint8_t *pHOST_TX_RAM_Addr;
extern _RootHubDev ThisUsb2Dev;
extern _DevOnHubPort DevOnU2HubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
extern uint8_t Usb2DevEndp0Size; // USB设备的端点0的最大包尺寸 */
extern uint8_t FoundNewU2Dev;
extern uint8_t *pU2HOST_RX_RAM_Addr;
extern uint8_t *pU2HOST_TX_RAM_Addr;
#define pSetupReq ((PUSB_SETUP_REQ)pHOST_TX_RAM_Addr)
#define pU2SetupReq ((PUSB_SETUP_REQ)pU2HOST_TX_RAM_Addr)
extern uint8_t Com_Buffer[];
extern uint8_t U2Com_Buffer[];
/* 以下为USB主机请求包 */
extern const uint8_t SetupGetDevDescr[]; // 获取设备描述符*/
extern const uint8_t SetupGetCfgDescr[]; // 获取配置描述符*/
extern const uint8_t SetupSetUsbAddr[]; // 设置USB地址*/
extern const uint8_t SetupSetUsbConfig[]; // 设置USB配置*/
extern const uint8_t SetupSetUsbInterface[]; // 设置USB接口配置*/
extern const uint8_t SetupClrEndpStall[]; // 清除端点STALL*/
extern const uint8_t SetupGetU2DevDescr[]; // 获取设备描述符*/
extern const uint8_t SetupGetU2CfgDescr[]; // 获取配置描述符*/
extern const uint8_t SetupSetUsb2Addr[]; // 设置USB地址*/
extern const uint8_t SetupSetUsb2Config[]; // 设置USB配置*/
extern const uint8_t SetupSetUsb2Interface[]; // 设置USB接口配置*/
extern const uint8_t SetupClrU2EndpStall[]; // 清除端点STALL*/
/**
* @brief 关闭ROOT-HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
*/
void DisableRootHubPort(void);
/**
* @brief 分析ROOT-HUB状态,处理ROOT-HUB端口的设备插拔事件
* 如果设备拔出,函数中调用DisableRootHubPort()函数,将端口关闭,插入事件,置相应端口的状态位
*
* @return 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
*/
uint8_t AnalyzeRootHub(void);
/**
* @brief 设置USB主机当前操作的USB设备地址
*
* @param addr - USB设备地址
*/
void SetHostUsbAddr(uint8_t addr);
/**
* @brief 设置当前USB速度
*
* @param FullSpeed - USB速度
*/
void SetUsbSpeed(uint8_t FullSpeed);
/**
* @brief 检测到设备后,复位总线,为枚举设备准备,设置为默认为全速
*/
void ResetRootHubPort(void);
/**
* @brief 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
*
* @return 返回ERR_SUCCESS为检测到新连接,返回ERR_USB_DISCON为无连接
*/
uint8_t EnableRootHubPort(void);
/**
* @brief 等待USB中断
*
* @return 返回ERR_SUCCESS 数据接收或者发送成功,返回ERR_USB_UNKNOWN 数据接收或者发送失败
*/
uint8_t WaitUSB_Interrupt(void);
/**
* @brief 传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
* 本子程序着重于易理解,而在实际应用中,为了提供运行速度,应该对本子程序代码进行优化
*
* @param endp_pid - 令牌和地址, 高4位是token_pid令牌, 低4位是端点地址
* @param tog - 同步标志
* @param timeout - 超时时间
*
* @return ERR_USB_UNKNOWN 超时,可能硬件异常
* ERR_USB_DISCON 设备断开
* ERR_USB_CONNECT 设备连接
* ERR_SUCCESS 传输完成
*/
uint8_t USBHostTransact(uint8_t endp_pid, uint8_t tog, uint32_t timeout);
/**
* @brief 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
*
* @param DataBuf - 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据
* @param RetLen - 实际成功收发的总长度保存在RetLen指向的字节变量中
*
* @return ERR_USB_BUF_OVER IN状态阶段出错
* ERR_SUCCESS 数据交换成功
*/
uint8_t HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen);
/**
* @brief 复制控制传输的请求包
*
* @param pReqPkt - 控制请求包地址
*/
void CopySetupReqPkg(const uint8_t *pReqPkt);
/**
* @brief 获取设备描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetDeviceDescr(void);
/**
* @brief 获取配置描述符,返回在 pHOST_TX_RAM_Addr 中
*
* @return ERR_USB_BUF_OVER 描述符长度错误
* ERR_SUCCESS 成功
*/
uint8_t CtrlGetConfigDescr(void);
/**
* @brief 设置USB设备地址
*
* @param addr - 设备地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbAddress(uint8_t addr);
/**
* @brief 设置USB设备配置
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbConfig(uint8_t cfg);
/**
* @brief 清除端点STALL
*
* @param endp - 端点地址
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlClearEndpStall(uint8_t endp);
/**
* @brief 设置USB设备接口
*
* @param cfg - 配置值
*
* @return ERR_SUCCESS 成功
*/
uint8_t CtrlSetUsbIntercace(uint8_t cfg);
/**
* @brief USB主机功能初始化
*/
void USB_HostInit(void);
uint8_t EnumAllHubPort(void);// 枚举所有ROOT-HUB端口下外部HUB后的二级USB设备
void SelectHubPort(uint8_t HubPortIndex); // HubPortIndex=0选择操作指定的ROOT-HUB端口,否则选择操作指定的ROOT-HUB端口的外部HUB的指定端口
uint16_t SearchTypeDevice(uint8_t type); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号,输出端口号为0xFFFF则未搜索到.
uint8_t SETorOFFNumLock(uint8_t *buf); // NumLock的点灯判断
void DisableRootU2HubPort(void); // 关闭ROOT-U2HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
uint8_t AnalyzeRootU2Hub(void); // 分析ROOT-U2HUB状态,处理ROOT-U2HUB端口的设备插拔事件
// 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
void SetHostUsb2Addr(uint8_t addr); // 设置USB主机当前操作的USB设备地址
void SetUsb2Speed(uint8_t FullSpeed); // 设置当前USB速度
void ResetRootU2HubPort(void); // 检测到设备后,复位相应端口的总线,为枚举设备准备,设置为默认为全速
uint8_t EnableRootU2HubPort(void); // 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
void SelectU2HubPort(uint8_t HubPortIndex); // HubPortIndex=0选择操作指定的ROOT-HUB端口,否则选择操作指定的ROOT-HUB端口的外部HUB的指定端口
uint8_t WaitUSB2_Interrupt(void); // 等待USB中断
// 传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
uint8_t USB2HostTransact(uint8_t endp_pid, uint8_t tog, UINT32 timeout); // endp_pid: 高4位是token_pid令牌, 低4位是端点地址
uint8_t U2HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen); // 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
// 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度返回保存在ReqLen指向的字节变量中
void CopyU2SetupReqPkg(const uint8_t *pReqPkt); // 复制控制传输的请求包
uint8_t CtrlGetU2DeviceDescr(void); // 获取设备描述符,返回在 pHOST_TX_RAM_Addr 中
uint8_t CtrlGetU2ConfigDescr(void); // 获取配置描述符,返回在 pHOST_TX_RAM_Addr 中
uint8_t CtrlSetUsb2Address(uint8_t addr); // 设置USB设备地址
uint8_t CtrlSetUsb2Config(uint8_t cfg); // 设置USB设备配置
uint8_t CtrlClearU2EndpStall(uint8_t endp); // 清除端点STALL
uint8_t CtrlSetUsb2Intercace(uint8_t cfg); // 设置USB设备接口
void USB2_HostInit(void); // 初始化USB主机
/*************************************************************/
/**
* @brief 初始化指定ROOT-HUB端口的USB设备
*
* @return 错误码
*/
uint8_t InitRootDevice(void);
/**
* @brief 获取HID设备报表描述符,返回在TxBuffer中
*
* @return 错误码
*/
uint8_t CtrlGetHIDDeviceReport(uint8_t infc);
/**
* @brief 获取HUB描述符,返回在Com_Buffer中
*
* @return 错误码
*/
uint8_t CtrlGetHubDescr(void);
/**
* @brief 查询HUB端口状态,返回在Com_Buffer中
*
* @param HubPortIndex - 端口号
*
* @return 错误码
*/
uint8_t HubGetPortStatus(uint8_t HubPortIndex);
/**
* @brief 设置HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t HubSetPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt);
/**
* @brief 清除HUB端口特性
*
* @param HubPortIndex - 端口号
* @param FeatureSelt - 端口特性
*
* @return 错误码
*/
uint8_t HubClearPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt);
uint8_t InitRootU2Device(void);
uint8_t EnumAllU2HubPort(void);
uint16_t U2SearchTypeDevice(uint8_t type);
uint8_t U2SETorOFFNumLock(uint8_t *buf);
uint8_t CtrlGetU2HIDDeviceReport(uint8_t infc); // HID类命令SET_IDLE和GET_REPORT
uint8_t CtrlGetU2HubDescr(void); // 获取HUB描述符,返回在TxBuffer中
uint8_t U2HubGetPortStatus(uint8_t HubPortIndex); // 查询HUB端口状态,返回在TxBuffer中
uint8_t U2HubSetPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt); // 设置HUB端口特性
uint8_t U2HubClearPortFeature(uint8_t HubPortIndex, uint8_t FeatureSelt); // 清除HUB端口特性
#ifdef __cplusplus
}
#endif
#endif // __CH58x_USBHOST_H__

View File

@@ -0,0 +1,190 @@
/* CH583 Flash-ROM & Data-Flash */
/* Website: http://wch.cn */
/* Email: tech@wch.cn */
/* Author: W.ch 2020.06 */
/* V1.0 FlashROM library for USER/BOOT */
/* for the target in USER code area on the chip divided into USER code area and BOOT area */
/* 用于具有用户代码区和引导区的芯片、操作目标为用户代码区的情况,
可以在用户代码中被调用IAP擦写自身也可以在引导代码中被调用更新用户代码 */
/* Flash-ROM feature:
for store program code, support block erasing, dword and page writing, dword verifying, unit for Length is byte,
minimal quantity for write or verify is one dword (4-bytes),
256 bytes/page for writing, FLASH_ROM_WRITE support one dword or more dword writing, but multiple of 256 is the best,
4KB (4096 bytes) bytes/block for erasing, so multiple of 4096 is the best */
/* Data-Flash(EEPROM) feature:
for store data, support block erasing, byte and page writing, byte reading,
minimal quantity for write or read is one byte,
256 bytes/page for writing, EEPROM_WRITE support one byte or more byte writing, but multiple of 256 is the best,
0.25KB/4KB (256/4096 bytes) bytes/block for erasing, so multiple of 256 or 4096 is the best */
#ifndef EEPROM_PAGE_SIZE
#define EEPROM_PAGE_SIZE 256 // Flash-ROM & Data-Flash page size for writing
#define EEPROM_BLOCK_SIZE 4096 // Flash-ROM & Data-Flash block size for erasing
#define EEPROM_MIN_ER_SIZE EEPROM_PAGE_SIZE // Data-Flash minimal size for erasing
//#define EEPROM_MIN_ER_SIZE EEPROM_BLOCK_SIZE // Flash-ROM minimal size for erasing
#define EEPROM_MIN_WR_SIZE 1 // Data-Flash minimal size for writing
#define EEPROM_MAX_SIZE 0x8000 // Data-Flash maximum size, 32KB
#endif
#ifndef FLASH_MIN_WR_SIZE
#define FLASH_MIN_WR_SIZE 4 // Flash-ROM minimal size for writing
#endif
#ifndef FLASH_ROM_MAX_SIZE
#define FLASH_ROM_MAX_SIZE 0x070000 // Flash-ROM maximum program size, 448KB
#endif
#ifndef CMD_FLASH_ROM_SW_RESET
// CMD_* for caller from FlashROM or RAM, auto execute CMD_FLASH_ROM_SW_RESET before command
#define CMD_FLASH_ROM_START_IO 0x00 // start FlashROM I/O, without parameter
#define CMD_FLASH_ROM_SW_RESET 0x04 // software reset FlashROM, without parameter
#define CMD_GET_ROM_INFO 0x06 // get information from FlashROM, parameter @Address,Buffer
#define CMD_GET_UNIQUE_ID 0x07 // get 64 bit unique ID, parameter @Buffer
#define CMD_FLASH_ROM_PWR_DOWN 0x0D // power-down FlashROM, without parameter
#define CMD_FLASH_ROM_PWR_UP 0x0C // power-up FlashROM, without parameter
#define CMD_FLASH_ROM_LOCK 0x08 // lock(protect)/unlock FlashROM data block, return 0 if success, parameter @StartAddr
// StartAddr: 0=unlock all, 1=lock boot code, 3=lock all code and data
#define CMD_EEPROM_ERASE 0x09 // erase Data-Flash block, return 0 if success, parameter @StartAddr,Length
#define CMD_EEPROM_WRITE 0x0A // write Data-Flash data block, return 0 if success, parameter @StartAddr,Buffer,Length
#define CMD_EEPROM_READ 0x0B // read Data-Flash data block, parameter @StartAddr,Buffer,Length
#define CMD_FLASH_ROM_ERASE 0x01 // erase FlashROM block, return 0 if success, parameter @StartAddr,Length
#define CMD_FLASH_ROM_WRITE 0x02 // write FlashROM data block, minimal block is dword, return 0 if success, parameter @StartAddr,Buffer,Length
#define CMD_FLASH_ROM_VERIFY 0x03 // read FlashROM data block, minimal block is dword, return 0 if success, parameter @StartAddr,Buffer,Length
#endif
#define ROM_CFG_MAC_ADDR 0x7F018 // address for MAC address information
#define ROM_CFG_BOOT_INFO 0x7DFF8 // address for BOOT information
/**
* @brief execute Flash/EEPROM command, caller from FlashROM or RAM
*
* @param cmd - CMD_* for caller from FlashROM or RAM.
* @param StartAddr - Address of the data to be process.
* @param Buffer - Pointer to the buffer where data should be process, Must be aligned to 4 bytes.
* @param Length - Size of data to be process, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
extern uint32_t FLASH_EEPROM_CMD( uint8_t cmd, uint32_t StartAddr, void *Buffer, uint32_t Length );
/**
* @brief start FlashROM I/O
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_START_IO( ) FLASH_EEPROM_CMD( CMD_FLASH_ROM_START_IO, 0, NULL, 0 )
/**
* @brief software reset FlashROM
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_SW_RESET( ) FLASH_EEPROM_CMD( CMD_FLASH_ROM_SW_RESET, 0, NULL, 0 )
/**
* @brief get 6 bytes MAC address
*
* @param Buffer - Pointer to the buffer where data should be stored, Must be aligned to 4 bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define GetMACAddress(Buffer) FLASH_EEPROM_CMD( CMD_GET_ROM_INFO, ROM_CFG_MAC_ADDR, Buffer, 0 )
/**
* @brief get 8 bytes BOOT information
*
* @param Buffer - Pointer to the buffer where data should be stored, Must be aligned to 4 bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define GET_BOOT_INFO(Buffer) FLASH_EEPROM_CMD( CMD_GET_ROM_INFO, ROM_CFG_BOOT_INFO, Buffer, 0 )
/**
* @brief get 64 bit unique ID
*
* @param Buffer - Pointer to the buffer where data should be stored, Must be aligned to 4 bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define GET_UNIQUE_ID(Buffer) FLASH_EEPROM_CMD( CMD_GET_UNIQUE_ID, 0, Buffer, 0 )
/**
* @brief power-down FlashROM
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_PWR_DOWN( ) FLASH_EEPROM_CMD( CMD_FLASH_ROM_PWR_DOWN, 0, NULL, 0 )
/**
* @brief power-up FlashROM
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_PWR_UP( ) FLASH_EEPROM_CMD( CMD_FLASH_ROM_PWR_UP, 0, NULL, 0 )
/**
* @brief read Data-Flash data block
*
* @param StartAddr - Address of the data to be read.
* @param Buffer - Pointer to the buffer where data should be stored, Must be aligned to 4 bytes.
* @param Length - Size of data to be read, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define EEPROM_READ(StartAddr,Buffer,Length) FLASH_EEPROM_CMD( CMD_EEPROM_READ, StartAddr, Buffer, Length )
/**
*
* @param StartAddr - Address of the data to be erased.
* @param Length - Size of data to be erased, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define EEPROM_ERASE(StartAddr,Length) FLASH_EEPROM_CMD( CMD_EEPROM_ERASE, StartAddr, NULL, Length )
/**
* @brief write Data-Flash data block
*
* @param StartAddr - Address of the data to be written.
* @param Buffer - Pointer to the source buffer, Must be aligned to 4 bytes.
* @param Length - Size of data to be written, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define EEPROM_WRITE(StartAddr,Buffer,Length) FLASH_EEPROM_CMD( CMD_EEPROM_WRITE, StartAddr, Buffer, Length )
/**
* @brief erase FlashROM block
*
* @param StartAddr - Address of the data to be erased.
* @param Length - Size of data to be erased, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_ERASE(StartAddr,Length) FLASH_EEPROM_CMD( CMD_FLASH_ROM_ERASE, StartAddr, NULL, Length )
/**
* @brief write FlashROM data block, minimal block is dword.
*
* @param StartAddr - Address of the data to be written.
* @param Buffer - Pointer to the source buffer, Must be aligned to 4 bytes.
* @param Length - Size of data to be written, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_WRITE(StartAddr,Buffer,Length) FLASH_EEPROM_CMD( CMD_FLASH_ROM_WRITE, StartAddr, Buffer, Length )
/**
* @brief verify FlashROM data block, minimal block is dword.
*
* @param StartAddr - Address of the data to verify.
* @param Buffer - Pointer to the source buffer, Must be aligned to 4 bytes.
* @param Length - Size of data to verify, in bytes.
*
* @return 0-SUCCESS (!0)-FAILURE
*/
#define FLASH_ROM_VERIFY(StartAddr,Buffer,Length) FLASH_EEPROM_CMD( CMD_FLASH_ROM_VERIFY, StartAddr, Buffer, Length )

Binary file not shown.

181
Makefile Normal file
View File

@@ -0,0 +1,181 @@
######################################
# target
######################################
TARGET = badgemagic-ch582
######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization for size
OPT = -Os
#######################################
# paths
#######################################
# Build path
BUILD_DIR ?= build
######################################
# source
######################################
# C sources
C_SOURCES = \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_i2c.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer2.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_spi0.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_gpio.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_pwr.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart3.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart2.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_sys.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_clk.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart0.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer1.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_pwm.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostClass.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbdev.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_adc.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usbhostBase.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer3.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer0.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2hostClass.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_flash.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_uart1.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2dev.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_usb2hostBase.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_spi1.c \
CH5xx_ble_firmware_library/RVMSIS/core_riscv.c \
src/main.c \
src/leddrv.c
# ASM sources
ASM_SOURCES = \
CH5xx_ble_firmware_library/Startup/startup_CH583.S
#######################################
# binaries
#######################################
PREFIX ?= riscv-none-embed-
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
#######################################
# CFLAGS
#######################################
# cpu
CPU = -march=rv32imac -mabi=ilp32 -msmall-data-limit=8
# fpu
FPU =
# float-abi
FLOAT-ABI =
# mcu
MCU = $(CPU) $(FPU) $(FLOAT-ABI)
# AS includes
AS_INCLUDES =
# C includes
C_INCLUDES = \
-ICH5xx_ble_firmware_library/StdPeriphDriver/inc \
-ICH5xx_ble_firmware_library/RVMSIS \
-ICH5xx_ble_firmware_library/Core \
-IUser
# compile gcc flags
ASFLAGS = $(MCU) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $(MCU) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
# Generate dependency information
CFLAGS += -MMD -MP
#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = CH5xx_ble_firmware_library/Ld/Link.ld
# libraries
LIBS = -lc -lm -lnosys ./CH5xx_ble_firmware_library/StdPeriphDriver/libISP583.a
LIBDIR =
LDFLAGS = $(MCU) -mno-save-restore -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -Wunused -Wuninitialized -T $(LDSCRIPT) -nostartfiles -Xlinker --gc-sections -Wl,-Map=$(BUILD_DIR)/$(TARGET).map --specs=nano.specs $(LIBS)
# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/, $(C_SOURCES:.c=.o))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/, $(ASM_SOURCES:.S=.o))
$(BUILD_DIR)/%.o: %.c Makefile
@mkdir -pv $(dir $@)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(@:.o=.lst) $< -o $@
$(BUILD_DIR)/%.o: %.S Makefile
@mkdir -pv $(dir $@)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
@mkdir -pv $(dir $@)
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf
@mkdir -pv $(dir $@)
$(HEX) $< $@
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf
@mkdir -pv $(dir $@)
$(BIN) $< $@
#######################################
# Program
#######################################
program: $(BUILD_DIR)/$(TARGET).elf
sudo wch-openocd -f /usr/share/wch-openocd/openocd/scripts/interface/wch-riscv.cfg -c 'init; halt; program $(BUILD_DIR)/$(TARGET).elf; reset; wlink_reset_resume; exit;'
isp: $(BUILD_DIR)/$(TARGET).bin
wchisp flash $(BUILD_DIR)/$(TARGET).bin
#######################################
# clean up
#######################################
clean:
rm -f $(OBJECTS)
rm -f $(OBJECTS:%.o=%.d)
rm -f $(OBJECTS:%.o=%.lst)
rm -f $(BUILD_DIR)/$(TARGET).*
find $(BUILD_DIR) -type d -empty -delete
#######################################
# dependencies
#######################################
-include $(OBJECTS:%.o=%.d)
# *** EOF ***

150
src/leddrv.c Normal file
View File

@@ -0,0 +1,150 @@
#include "leddrv.h"
#define LED_DRIVE_STRENTH 0
#define LED_PINCOUNT (23)
typedef enum {
FLOATING,
LOW,
HIGH,
} tristate_t;
typedef struct {
uint32_t *port_buf;
uint32_t *cfg_buf;
uint32_t pin;
} pinctrl_t;
static void gpio_buf_set(pinctrl_t pinctl, tristate_t state)
{
if (state == FLOATING) {
*(pinctl.cfg_buf) &= ~pinctl.pin;
} else {
if (state == HIGH)
*(pinctl.port_buf) |= pinctl.pin;
else
*(pinctl.port_buf) &= ~pinctl.pin;
*(pinctl.cfg_buf) |= pinctl.pin;
}
}
static void gpio_buf_apply(
volatile uint8_t *gpio_base,
uint32_t *port, uint32_t *cfg,
uint32_t *mask)
{
#if LED_DRIVE_STRENTH != 0
uint32_t *drv = (uint32_t *)(gpio_base + GPIO_PD_DRV);
*drv = (*drv & ~*mask) | (*cfg & *mask);
#endif
uint32_t *dir = (uint32_t *)(gpio_base + GPIO_DIR);
*dir = (*dir & ~*mask) | (*cfg & *mask);
uint32_t *out = (uint32_t *)(gpio_base + GPIO_OUT);
*out = (*out & ~*mask) | (*port & *mask);
}
static uint32_t PA_buf;
static uint32_t PB_buf;
static uint32_t PAcfg_buf;
static uint32_t PBcfg_buf;
static uint32_t PA_mask;
static uint32_t PB_mask;
#define GPIO_APPLY_ALL() \
gpio_buf_apply(BA_PA, &PA_buf, &PAcfg_buf, &PA_mask); \
gpio_buf_apply(BA_PB, &PB_buf, &PBcfg_buf, &PB_mask)
#define PINCTRL(x, pin) { \
&P##x##_buf, \
&P##x##cfg_buf, \
GPIO_Pin_##pin \
}
static const pinctrl_t led_pins[LED_PINCOUNT] = {
PINCTRL(A, 15), // A
PINCTRL(B, 18), // B
PINCTRL(B, 0), // C
PINCTRL(B, 7), // D
PINCTRL(A, 12), // E
PINCTRL(A, 10), // F
PINCTRL(A, 11), // G
PINCTRL(B, 9), // H
PINCTRL(B, 8), // I
PINCTRL(B, 15), // J
PINCTRL(B, 14), // K
PINCTRL(B, 13), // L
PINCTRL(B, 12), // M
PINCTRL(B, 5), // N
PINCTRL(A, 4), // O
PINCTRL(B, 3), // P
PINCTRL(B, 4), // Q
PINCTRL(B, 2), // R
PINCTRL(B, 1), // S
PINCTRL(B, 23), // T
PINCTRL(B, 21), // U
PINCTRL(B, 20), // V
PINCTRL(B, 19), // W
};
void led_init()
{
for (int i=0; i<LED_PINCOUNT; i++) {
if (led_pins[i].port_buf == &PA_buf)
PA_mask |= led_pins[i].pin;
else
PB_mask |= led_pins[i].pin;
}
}
void leds_releaseall() {
for (int i=0; i<LED_PINCOUNT; i++)
gpio_buf_set(led_pins[i], FLOATING);
GPIO_APPLY_ALL();
}
static void led_write2dcol_raw(int dcol, uint32_t val)
{
// TODO: assert params
gpio_buf_set(led_pins[dcol], HIGH);
for (int i=0; i<LED_PINCOUNT; i++) {
if (i == dcol) continue;
gpio_buf_set(led_pins[i], (val & 0x01) ? LOW : FLOATING); // danger: floating=0 (led off) or low=1 (led on)
val >>= 1;
}
GPIO_APPLY_ALL();
}
static uint32_t combine_cols(uint16_t col1_val, uint16_t col2_val)
{
uint32_t dval = 0;
dval |= ((col1_val & 0x01) << (LED_ROWS*2));
dval |= ((col2_val & 0x01) << (LED_ROWS*2+1));
for (int i=0; i<LED_ROWS; i++) {
col1_val >>= 1;
col2_val >>= 1;
dval >>= 2;
dval |= ((col1_val & 0x01) << (LED_ROWS*2));
dval |= ((col2_val & 0x01) << (LED_ROWS*2+1));
}
return dval;
}
void led_write2dcol(int dcol, uint16_t col1_val, uint16_t col2_val)
{
led_write2dcol_raw(dcol, combine_cols(col1_val, col2_val));
}
void led_write2row_raw(int row, int which_half, uint32_t val)
{
row = row*2 + (which_half != 0);
gpio_buf_set(led_pins[row], LOW);
for (int i=0; i<LED_PINCOUNT; i++) {
if (i == row) continue;
gpio_buf_set(led_pins[i], (val & 0x01) ? HIGH : FLOATING);
val >>= 1;
}
GPIO_APPLY_ALL();
}

14
src/leddrv.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __LEDDRV_H__
#define __LEDDRV_H__
#include "CH58x_common.h"
#define LED_COLS 44
#define LED_ROWS 11
void led_init();
void leds_releaseall();
void led_write2dcol(int dcol, uint16_t col1_val, uint16_t col2_val);
void led_write2row_raw(int row, int which_half, uint32_t val);
#endif /* __LEDDRV_H__ */

88
src/main.c Normal file
View File

@@ -0,0 +1,88 @@
#include "CH58x_common.h"
#include "CH58x_sys.h"
#include "leddrv.h"
#define FB_WIDTH LED_COLS*4
#define SCROLL_IRATIO 3
uint16_t fb[2][FB_WIDTH];
uint8_t test_font[][11] = {
0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xF0, 0x00, // F
0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, // O
0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, // A
0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // I
0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, // A
};
void draw2fb(uint16_t *fb, int c, int col)
{
uint16_t tmpfb[8] = {0};
for (int i=0; i<8; i++) {
for (int j=0; j<11; j++) {
tmpfb[i] |= ((test_font[c][j] >> (8-i)) & 0x01) << j;
}
}
for (int i=0; i<8; i++) {
fb[col+i] = tmpfb[i];
}
}
volatile int fb_sel = 0;
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
led_init();
draw2fb(fb[0], 0, 8*5);
draw2fb(fb[0], 1, 8*6);
draw2fb(fb[0], 2, 8*7);
draw2fb(fb[0], 3, 8*8);
draw2fb(fb[0], 4, 8*9);
draw2fb(fb[0], 5, 8*10);
draw2fb(fb[0], 6, 8*11);
draw2fb(fb[0], 7, 8*12);
draw2fb(fb[1], 4, 8*5);
draw2fb(fb[1], 5, 8*6);
draw2fb(fb[1], 6, 8*7);
draw2fb(fb[1], 7, 8*8);
draw2fb(fb[1], 0, 8*9);
draw2fb(fb[1], 1, 8*10);
draw2fb(fb[1], 2, 8*11);
draw2fb(fb[1], 3, 8*12);
TMR0_TimerInit(1500);
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
PFIC_EnableIRQ(TMR0_IRQn);
while (1) {
}
}
__attribute__((interrupt))
void TMR0_IRQHandler(void)
{
static int i, scroll;
if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) {
i += 2;
if (i >= LED_COLS) {
i = 0;
scroll++;
if (scroll >= (FB_WIDTH-LED_COLS)*SCROLL_IRATIO) {
scroll = 0;
fb_sel = fb_sel == 0;
}
}
// This is a mess
led_write2dcol(i/2, fb[fb_sel][i+scroll/SCROLL_IRATIO], fb[fb_sel][i+scroll/SCROLL_IRATIO+1]);
TMR0_ClearITFlag(TMR0_3_IT_CYC_END);
}
}