Refactored the included files from the ch32fun project.
+ updated as of 2025-12-23
This commit is contained in:
parent
56e38aeeae
commit
7e0b1e3244
58 changed files with 90369 additions and 56430 deletions
337
inc/ch32fun.h
337
inc/ch32fun.h
|
|
@ -59,6 +59,8 @@
|
|||
by setting FUNCONF_DEBUG_HARDFAULT to 0.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* CH32V003 Fun Configs; please define any non-default options in funconfig.h *
|
||||
|
||||
|
|
@ -75,15 +77,18 @@
|
|||
#define FUNCONF_SYSTICK_USE_HCLK 0 // Should systick be at 48 MHz (1) or 6MHz (0) on an '003. Typically set to 0 to divide HCLK by 8.
|
||||
#define FUNCONF_TINYVECTOR 0 // If enabled, Does not allow normal interrupts.
|
||||
#define FUNCONF_UART_PRINTF_BAUD 115200 // Only used if FUNCONF_USE_UARTPRINTF is set.
|
||||
#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x80000 // Arbitrary time units, this is around 120ms.
|
||||
#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x100000 // Arbitrary time units, this is around 200ms.
|
||||
#define FUNCONF_ENABLE_HPE 1 // Enable hardware interrupt stack. Very good on QingKeV4, i.e. x035, v10x, v20x, v30x, but questionable on 003.
|
||||
// If you are using that, consider using INTERRUPT_DECORATOR as an attribute to your interrupt handlers.
|
||||
#define FUNCONF_USE_5V_VDD 0 // Enable this if you plan to use your part at 5V - affects USB and PD configration on the x035.
|
||||
#define FUNCONF_DEBUG_HARDFAULT 1 // Log fatal errors with "printf"
|
||||
#define FUNCONF_ISR_IN_RAM 0 // Put the interrupt vector in RAM.
|
||||
#define FUNCONF_SUPPORT_CONSTRUCTORS 0 // Call functions with __attribute__((constructor)) in SystemInit()
|
||||
#define FUNCONF_ICACHE_EN 1 // Enables ICache on cores that support it, may require power-down + power up to work properly at flash time.
|
||||
*/
|
||||
|
||||
// Sanity check for when porting old code.
|
||||
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x)
|
||||
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x) || defined(CH32L103) || defined(CH32H41x)
|
||||
#if defined(CH32V003)
|
||||
#error Cannot define CH32V003 and another arch.
|
||||
#endif
|
||||
|
|
@ -98,7 +103,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(FUNCONF_USE_DEBUGPRINTF) && FUNCONF_USE_DEBUGPRINTF && !defined(FUNCONF_DEBUGPRINTF_TIMEOUT)
|
||||
#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x80000
|
||||
#define FUNCONF_DEBUGPRINTF_TIMEOUT 0x100000
|
||||
#endif
|
||||
|
||||
#if defined(FUNCONF_USE_HSI) && defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSI && FUNCONF_USE_HSE
|
||||
|
|
@ -140,6 +145,7 @@
|
|||
#define INTERRUPT_DECORATOR __attribute__((interrupt))
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined( FUNCONF_USE_CLK_SEC )
|
||||
#define FUNCONF_USE_CLK_SEC 1// use clock security system by default
|
||||
#endif
|
||||
|
|
@ -149,7 +155,7 @@
|
|||
#define HSE_VALUE (24000000) // Value of the External oscillator in Hz, default
|
||||
#elif defined(CH32V10x)
|
||||
#define HSE_VALUE (8000000)
|
||||
#elif defined(CH32V20x)
|
||||
#elif defined(CH32V20x) || defined(CH32L103)
|
||||
#if defined(CH32V20x_D8) || defined(CH32V20x_D8W)
|
||||
#define HSE_VALUE (32000000)
|
||||
#else
|
||||
|
|
@ -157,20 +163,27 @@
|
|||
#endif
|
||||
#elif defined(CH32V30x)
|
||||
#define HSE_VALUE (8000000)
|
||||
#elif defined(CH57x) || defined(CH58x) || defined(CH59x)
|
||||
#define HSE_VALUE (32000000)
|
||||
#elif defined(CH32H41x)
|
||||
#define HSE_VALUE (25000000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Value of the Internal oscillator in Hz, default.
|
||||
#ifndef HSI_VALUE
|
||||
#if defined(CH32V003)
|
||||
#define HSI_VALUE (24000000) // Value of the Internal oscillator in Hz, default.
|
||||
#if defined(CH32V003) || defined(CH32V00x)
|
||||
#define HSI_VALUE (24000000)
|
||||
#elif defined(CH32X03x)
|
||||
#define HSI_VALUE (48000000)
|
||||
#elif defined(CH32V10x)
|
||||
#define HSI_VALUE (8000000)
|
||||
#elif defined(CH32V20x)
|
||||
#elif defined(CH32V20x) || defined(CH32L103)
|
||||
#define HSI_VALUE (8000000)
|
||||
#elif defined(CH32V30x)
|
||||
#define HSI_VALUE (8000000)
|
||||
#elif defined(CH32H41x)
|
||||
#define HSI_VALUE (25000000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -186,10 +199,15 @@
|
|||
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
|
||||
#if defined(CH32V10x)
|
||||
#define FUNCONF_PLL_MULTIPLIER 10 // Default: 8 * 10 = 80 MHz
|
||||
#elif defined(CH32L103)
|
||||
#define FUNCONF_PLL_MULTIPLIER 12 // Default: 8 * 12 = 96 MHz
|
||||
// Note: Can be overclocked to 144 MHz
|
||||
#elif defined(CH32V20x)
|
||||
#define FUNCONF_PLL_MULTIPLIER 18 // Default: 8 * 18 = 144 MHz
|
||||
#elif defined(CH32V30x)
|
||||
#define FUNCONF_PLL_MULTIPLIER 18 // Default: 8 * 18 = 144 MHz
|
||||
#elif defined(CH32H41x)
|
||||
#define FUNCONF_PLL_MULTIPLIER 16 // Default: 25 * 16 = 400 MHz
|
||||
#else // CH32V003
|
||||
#define FUNCONF_PLL_MULTIPLIER 2 // Default: 24 * 2 = 48 MHz
|
||||
#endif
|
||||
|
|
@ -199,10 +217,33 @@
|
|||
#endif
|
||||
|
||||
#ifndef FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#if defined(CH57x) || defined(CH58x) || defined(CH59x) // no PLL multiplier, but a divider from the 480 MHz clock
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK 60000000 // default in ch32fun.c using CLK_SOURCE_PLL_60MHz
|
||||
#if defined(CLK_SOURCE_CH5XX)
|
||||
#error Must define FUNCONF_SYSTEM_CORE_CLOCK too if CLK_SOURCE_CH5XX is defined
|
||||
#endif
|
||||
#elif defined(CH32H41x)
|
||||
#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
|
||||
#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE / 4)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE / 4)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#endif
|
||||
#else
|
||||
#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
|
||||
#if defined(CH32V20x_D8) || defined(CH32V20x_D8W)
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE/4)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#else
|
||||
#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE)*(FUNCONF_PLL_MULTIPLIER))
|
||||
#endif
|
||||
#else
|
||||
#error Must define either FUNCONF_USE_HSI or FUNCONF_USE_HSE to be 1.
|
||||
#endif
|
||||
|
|
@ -212,6 +253,14 @@
|
|||
#define FUNCONF_USE_5V_VDD 0
|
||||
#endif
|
||||
|
||||
#ifndef FUNCONF_ISR_IN_RAM
|
||||
#define FUNCONF_ISR_IN_RAM 0
|
||||
#endif
|
||||
|
||||
#ifndef FUNCONF_ICACHE_EN
|
||||
#define FUNCONF_ICACHE_EN 1
|
||||
#endif
|
||||
|
||||
// Default package for CH32V20x
|
||||
#if defined(CH32V20x)
|
||||
#if !defined(CH32V20x_D8W) && !defined(CH32V20x_D8) && !defined(CH32V20x_D6)
|
||||
|
|
@ -275,9 +324,12 @@
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef WEAK
|
||||
#define WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
|
@ -324,39 +376,45 @@ extern "C"
|
|||
typedef __IO int64_t vs64;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NoREADY = 0,
|
||||
READY = !NoREADY
|
||||
} ErrorStatus;
|
||||
typedef enum {NoREADY = 0, READY = !NoREADY} ErrorStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DISABLE = 0,
|
||||
ENABLE = !DISABLE
|
||||
} FunctionalState;
|
||||
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RESET = 0,
|
||||
SET = !RESET
|
||||
} FlagStatus, ITStatus;
|
||||
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
|
||||
|
||||
#define RV_STATIC_INLINE static inline
|
||||
#endif // __ASSEMBLER__
|
||||
|
||||
#include <string.h> // for memcpy in ch5xx hw.h files
|
||||
#endif // ifndef __ASSEMBLER__
|
||||
|
||||
#if FUNCONF_ISR_IN_RAM
|
||||
#define VECTOR_HANDLER_SECTION ".data.vector_handler"
|
||||
#define ISR_HANDLER_INITIAL_JUMP ".word 0x00000000\n"
|
||||
#else
|
||||
#define VECTOR_HANDLER_SECTION ".text.vector_handler"
|
||||
#define ISR_HANDLER_INITIAL_JUMP "j handle_reset\n"
|
||||
#endif
|
||||
|
||||
#ifdef CH32V003
|
||||
#include "ch32v003hw.h"
|
||||
#elif defined( CH32V002 ) || defined( CH32V00x )
|
||||
#include "ch32x00xhw.h"
|
||||
#elif defined( CH32X03x )
|
||||
#include "ch32x03xhw.h"
|
||||
#elif defined( CH32X03x )
|
||||
#include "ch32x03xhw.h"
|
||||
#elif defined( CH32V10x )
|
||||
#include "ch32v10xhw.h"
|
||||
#elif defined( CH32L103 )
|
||||
#include "ch32l103hw.h"
|
||||
#elif defined( CH32V20x )
|
||||
#include "ch32v20xhw.h"
|
||||
#elif defined( CH32V30x )
|
||||
#include "ch32v30xhw.h"
|
||||
#elif defined( CH57x ) || defined( CH58x ) || defined( CH59x )
|
||||
#include "ch5xxhw.h"
|
||||
#elif defined( CH32H41x )
|
||||
#include "ch32h41xhw.h"
|
||||
#endif
|
||||
|
||||
#if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )
|
||||
|
|
@ -372,37 +430,28 @@ extern "C"
|
|||
// Enable Global Interrupt
|
||||
RV_STATIC_INLINE void __enable_irq()
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mstatus" : "=r"(result));
|
||||
result |= 0x88;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r"(result));
|
||||
uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
|
||||
result |= 0x88; __ASM volatile( ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r" (result) );
|
||||
}
|
||||
|
||||
// Disable Global Interrupt
|
||||
RV_STATIC_INLINE void __disable_irq()
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mstatus" : "=r"(result));
|
||||
result &= ~0x88;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r"(result));
|
||||
uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
|
||||
result &= ~0x88; __ASM volatile( ADD_ARCH_ZICSR "csrw mstatus, %0" : : "r" (result) );
|
||||
}
|
||||
|
||||
// Is Global Interrupt enabled (1 = yes, 0 = no)
|
||||
RV_STATIC_INLINE uint8_t __isenabled_irq(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mstatus" : "=r"(result));
|
||||
uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mstatus": "=r"(result) );
|
||||
return (result & 0x08) != 0u;
|
||||
}
|
||||
|
||||
// Get stack pointer (returns the stack pointer)
|
||||
RV_STATIC_INLINE uint32_t __get_cpu_sp(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "mv %0, sp" : "=r"(result));
|
||||
uint32_t result; __ASM volatile( ADD_ARCH_ZICSR "mv %0, sp" : "=r"(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -484,13 +533,11 @@ extern "C"
|
|||
|
||||
RV_STATIC_INLINE void NVIC_clear_all_IRQs_except(uint8_t IRQn_to_keep)
|
||||
{
|
||||
if (!(IRQn_to_keep >> 5))
|
||||
{ // IRQn_to_keep < 32
|
||||
if (!(IRQn_to_keep >> 5)) { // IRQn_to_keep < 32
|
||||
NVIC->IRER[0] = (~0) & (~(1 << IRQn_to_keep));
|
||||
NVIC->IRER[1] = (~0);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
IRQn_to_keep = IRQn_to_keep >> 5;
|
||||
NVIC->IRER[0] = (~0);
|
||||
NVIC->IRER[1] = (~0) & (~(1 << IRQn_to_keep));
|
||||
|
|
@ -532,8 +579,7 @@ extern "C"
|
|||
*
|
||||
* @return none
|
||||
*/
|
||||
RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState)
|
||||
{
|
||||
RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){
|
||||
if(num > 1) return ;
|
||||
|
||||
if (NewState != DISABLE)
|
||||
|
|
@ -541,8 +587,7 @@ extern "C"
|
|||
NVIC->VTFIDR[num] = IRQn;
|
||||
NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1);
|
||||
}
|
||||
else
|
||||
{
|
||||
else{
|
||||
NVIC->VTFIDR[num] = IRQn;
|
||||
NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1));
|
||||
}
|
||||
|
|
@ -574,8 +619,7 @@ extern "C"
|
|||
static inline uint32_t __get_FFLAGS(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"fflags" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "fflags" : "=r" (result) );
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -589,8 +633,7 @@ extern "C"
|
|||
static inline uint32_t __get_FRM(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"frm" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "frm" : "=r" (result) );
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -604,8 +647,7 @@ extern "C"
|
|||
static inline uint32_t __get_FCSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"fcsr" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "fcsr" : "=r" (result) );
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -649,8 +691,7 @@ extern "C"
|
|||
static inline uint32_t __get_MTVEC(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mtvec" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mtvec": "=r"(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -664,8 +705,7 @@ extern "C"
|
|||
static inline uint32_t __get_MSCRATCH(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mscratch" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mscratch" : "=r"(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -679,8 +719,7 @@ extern "C"
|
|||
static inline uint32_t __get_MEPC(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mepc" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mepc" : "=r"(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -694,8 +733,7 @@ extern "C"
|
|||
static inline uint32_t __get_MCAUSE(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mcause" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mcause": "=r"(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -709,8 +747,7 @@ extern "C"
|
|||
static inline uint32_t __get_MTVAL(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile(ADD_ARCH_ZICSR "csrr %0,"
|
||||
"mtval" : "=r"(result));
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrr %0," "mtval" : "=r" (result) );
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -752,6 +789,14 @@ extern "C"
|
|||
return (result);
|
||||
}
|
||||
|
||||
// Return stack pointer register (SP)
|
||||
static inline uint32_t __get_SP(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile( "mv %0,""sp": "=r"(result):);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined(CH32V003) && CH32V003
|
||||
|
||||
// Return DBGMCU_CR Register value
|
||||
|
|
@ -762,20 +807,13 @@ extern "C"
|
|||
return (result);
|
||||
}
|
||||
|
||||
|
||||
// Set the DBGMCU_CR Register value
|
||||
static inline void __set_DEBUG_CR(uint32_t value)
|
||||
{
|
||||
__ASM volatile( ADD_ARCH_ZICSR "csrw 0x7C0, %0" : : "r" (value) );
|
||||
}
|
||||
|
||||
// Return stack pointer register (SP)
|
||||
static inline uint32_t __get_SP(void)
|
||||
{
|
||||
uint32_t result;
|
||||
__ASM volatile("mv %0,"
|
||||
"sp" : "=r"(result) :);
|
||||
return (result);
|
||||
}
|
||||
#endif // CH32V003
|
||||
|
||||
#endif // !assembler
|
||||
|
|
@ -814,13 +852,13 @@ extern "C"
|
|||
|
||||
#endif/* __CORE_RISCV_H__ */
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SYSTICK info
|
||||
|
|
@ -837,78 +875,112 @@ extern "C"
|
|||
#define DELAY_MS_TIME ((FUNCONF_SYSTEM_CORE_CLOCK)/8000)
|
||||
#endif
|
||||
|
||||
#define DELAY_MSEC_COUNT(n) (DELAY_MS_TIME * n)
|
||||
#define DELAY_SEC_COUNT(n) (DELAY_MS_TIME * 1000 * n)
|
||||
|
||||
#define Delay_Us(n) DelaySysTick( (n) * DELAY_US_TIME )
|
||||
#define Delay_Ms(n) DelaySysTick( (n) * DELAY_MS_TIME )
|
||||
|
||||
#define Ticks_from_Us(n) (n * DELAY_US_TIME)
|
||||
#define Ticks_from_Ms(n) (n * DELAY_MS_TIME)
|
||||
#define Ticks_from_Us(n) ((n) * DELAY_US_TIME)
|
||||
#define Ticks_from_Ms(n) ((n) * DELAY_MS_TIME)
|
||||
|
||||
#define TimeElapsed32(now,start) ((uint32_t)((uint32_t)(now)-(uint32_t)(start)))
|
||||
|
||||
// Add a certain number of nops. Note: These are usually executed in pairs
|
||||
// and take two cycles, so you typically would use 0, 2, 4, etc.
|
||||
#define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
|
||||
|
||||
#define FUN_HIGH 0x1
|
||||
#define FUN_LOW 0x0
|
||||
#if defined(CH57x) || defined(CH58x) || defined(CH59x)
|
||||
#if defined( PB ) && defined( R32_PB_PIN )
|
||||
#define OFFSET_FOR_GPIOB(pin) (((pin & PB) >> 31) * (&R32_PB_PIN - &R32_PA_PIN)) // 0 if GPIOA, 0x20 if GPIOB
|
||||
#else
|
||||
#define PB 0
|
||||
#define OFFSET_FOR_GPIOB(pin) 0
|
||||
#endif
|
||||
#define GPIO_ResetBits(pin) (*(&R32_PA_CLR + OFFSET_FOR_GPIOB(pin)) = (pin & ~PB))
|
||||
#define GPIO_SetBits(pin) (*(&R32_PA_SET + OFFSET_FOR_GPIOB(pin)) = (pin & ~PB))
|
||||
#define GPIO_InverseBits(pin) (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) ^= (pin & ~PB))
|
||||
#define GPIO_ReadPortPin(pin) (*(&R32_PA_PIN + OFFSET_FOR_GPIOB(pin)) & (pin & ~PB))
|
||||
#define funDigitalRead(pin) GPIO_ReadPortPin(pin)
|
||||
#define funDigitalWrite( pin, value ) do{ if((value)==FUN_HIGH){GPIO_SetBits(pin);} else if((value)==FUN_LOW){GPIO_ResetBits(pin);} }while(0)
|
||||
#define funGpioInitAll() // funGpioInitAll() does not do anything on ch5xx, put here for consistency
|
||||
|
||||
RV_STATIC_INLINE void funPinMode(u32 pin, GPIOModeTypeDef mode)
|
||||
{
|
||||
switch(mode) {
|
||||
case GPIO_ModeIN_Floating:
|
||||
*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
break;
|
||||
case GPIO_ModeIN_PU:
|
||||
*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
|
||||
*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
break;
|
||||
case GPIO_ModeIN_PD:
|
||||
*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
|
||||
*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
break;
|
||||
case GPIO_ModeOut_PP_5mA:
|
||||
*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
|
||||
*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
|
||||
break;
|
||||
case GPIO_ModeOut_PP_20mA:
|
||||
*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
|
||||
*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Arduino-like GPIO Functionality
|
||||
#define GpioOf( pin ) ((GPIO_TypeDef *)(GPIOA_BASE + 0x400 * ((pin)>>4)))
|
||||
|
||||
#define FUN_HIGH 0x1
|
||||
#define FUN_LOW 0x0
|
||||
#define FUN_OUTPUT (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)
|
||||
#define FUN_INPUT (GPIO_CNF_IN_FLOATING)
|
||||
|
||||
// For pins, use things like PA8, PB15
|
||||
// For configuration, use things like GPIO_CFGLR_OUT_10Mhz_PP
|
||||
|
||||
#define funDigitalWrite(pin, value) \
|
||||
{ \
|
||||
GpioOf(pin)->BSHR = 1 << ((!(value)) * 16 + ((pin) & 0xf)); \
|
||||
}
|
||||
#define funDigitalWrite( pin, value ) do{ GpioOf( pin )->BSHR = 1<<((!(value))*16 + ((pin) & 0xf)); }while(0)
|
||||
|
||||
#if defined(CH32X03x)
|
||||
#define funGpioInitAll() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC); \
|
||||
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ); }
|
||||
#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
|
||||
#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32L103)
|
||||
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }
|
||||
#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }
|
||||
#define funGpioInitB() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB ); }
|
||||
#elif defined(CH32H41x)
|
||||
#define funGpioInitAll() { RCC->HB2PCENR |= ( RCC_HB2Periph_AFIO | RCC_HB2Periph_GPIOA | RCC_HB2Periph_GPIOB | RCC_HB2Periph_GPIOC | RCC_HB2Periph_GPIOD | RCC_HB2Periph_GPIOE | RCC_HB2Periph_GPIOF ); }
|
||||
|
||||
RV_STATIC_INLINE void funPinMode(u32 pin, GPIOMode_TypeDef mode, GPIOSpeed_TypeDef speed)
|
||||
{
|
||||
*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7)));
|
||||
GpioOf(pin)->SPEED = (GpioOf(pin)->SPEED & ~(0x3 << (2 * (pin & 0xF)))) | (speed << (2 * (pin & 0xF)));
|
||||
}
|
||||
#define funPinMode(pin, mode) \
|
||||
{ \
|
||||
*((&GpioOf(pin)->CFGLR) + ((pin & 0x8) >> 3)) = ((*((&GpioOf(pin)->CFGLR) + ((pin & 0x8) >> 3))) & (~(0xf << (4 * ((pin) & 0x7))))) | ((mode) << (4 * ((pin) & 0x7))); \
|
||||
}
|
||||
#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
|
||||
#define funGpioInitAll() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD); \
|
||||
}
|
||||
#define funPinMode(pin, mode) \
|
||||
{ \
|
||||
*((&GpioOf(pin)->CFGLR) + ((pin & 0x8) >> 3)) = ((*((&GpioOf(pin)->CFGLR) + ((pin & 0x8) >> 3))) & (~(0xf << (4 * ((pin) & 0x7))))) | ((mode) << (4 * ((pin) & 0x7))); \
|
||||
}
|
||||
#define funGpioInitB() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB); \
|
||||
|
||||
/* Helper for AF */
|
||||
RV_STATIC_INLINE void funPinAF(u32 pin, u32 af)
|
||||
{
|
||||
volatile uint32_t* afio = (uint32_t*)(AFIO_BASE + 4U + 4U * (pin >> 3));
|
||||
*afio = (*afio & ~(0xf << (4U * (pin & 0x7)))) | (af << (4U * (pin & 0x7)));
|
||||
}
|
||||
|
||||
#else
|
||||
#define funGpioInitAll() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD); \
|
||||
}
|
||||
#define funPinMode(pin, mode) \
|
||||
{ \
|
||||
GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf << (4 * ((pin) & 0xf))))) | ((mode) << (4 * ((pin) & 0xf))); \
|
||||
}
|
||||
#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }
|
||||
#define funPinMode( pin, mode ) { GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf<<(4*((pin)&0xf))))) | ((mode)<<(4*((pin)&0xf))); }
|
||||
#endif
|
||||
|
||||
#define funGpioInitA() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA); \
|
||||
}
|
||||
#define funGpioInitC() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC); \
|
||||
}
|
||||
#define funGpioInitD() \
|
||||
{ \
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD); \
|
||||
}
|
||||
#define funGpioInitA() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA ); }
|
||||
#define funGpioInitC() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); }
|
||||
#define funGpioInitD() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); }
|
||||
#define funDigitalRead( pin ) ((int)((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1))
|
||||
#endif
|
||||
|
||||
|
||||
#define ANALOG_0 0
|
||||
#define ANALOG_1 1
|
||||
|
|
@ -927,6 +999,7 @@ extern "C"
|
|||
|
||||
#if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )
|
||||
|
||||
|
||||
// Stuff that can only be compiled on device (not for the programmer, or other host programs)
|
||||
|
||||
// Initialize the ADC calibrate it and set some sane defaults.
|
||||
|
|
@ -937,21 +1010,21 @@ extern "C"
|
|||
int funAnalogRead( int nAnalogNumber );
|
||||
|
||||
void handle_reset() __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used));
|
||||
void DefaultIRQHandler(void) __attribute__((section(".text.vector_handler"))) __attribute__((naked)) __attribute__((used));
|
||||
void DefaultIRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used));
|
||||
// used to clear the CSS flag in case of clock fail switch
|
||||
#if defined(FUNCONF_USE_CLK_SEC) && FUNCONF_USE_CLK_SEC
|
||||
void NMI_RCC_CSS_IRQHandler(void) __attribute__((section(".text.vector_handler"))) __attribute__((naked)) __attribute__((used));
|
||||
void NMI_RCC_CSS_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used));
|
||||
#endif
|
||||
|
||||
void DelaySysTick( uint32_t n );
|
||||
|
||||
|
||||
// Depending on a LOT of factors, it's about 6 cycles per n.
|
||||
// **DO NOT send it zero or less.**
|
||||
#ifndef __MACOSX__
|
||||
#ifndef __DELAY_TINY_DEFINED__
|
||||
#define __DELAY_TINY_DEFINED__
|
||||
static inline void Delay_Tiny(int n)
|
||||
{
|
||||
static inline void Delay_Tiny( int n ) {
|
||||
__ASM volatile( "\
|
||||
mv a5, %[n]\n\
|
||||
1: \
|
||||
|
|
@ -963,7 +1036,11 @@ extern "C"
|
|||
#endif //defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )
|
||||
|
||||
// Tricky: We need to make sure main and SystemInit() are preserved.
|
||||
#ifdef MINICHLINK
|
||||
int main( int argc, char ** argv) __attribute__((used));
|
||||
#else
|
||||
int main() __attribute__((used));
|
||||
#endif
|
||||
void SystemInit(void);
|
||||
|
||||
#ifdef FUNCONF_UART_PRINTF_BAUD
|
||||
|
|
@ -993,12 +1070,18 @@ extern "C"
|
|||
// Just a definition to the internal _write function.
|
||||
int _write(int fd, const char *buf, int size);
|
||||
|
||||
// Print a hexadecimal value to the debug (or UART) depending on configuration.
|
||||
void PrintHex( uint32_t n );
|
||||
|
||||
// Call this to busy-wait the polling of input.
|
||||
void poll_input( void );
|
||||
|
||||
// Receiving bytes from host. Override if you wish.
|
||||
void handle_debug_input( int numbytes, uint8_t * data );
|
||||
|
||||
// Call functions with __attribute__((constructor)). Defining FUNCONF_SUPPORT_CONSTRUCTORS 1 will do it for you
|
||||
void CallConstructors( void );
|
||||
|
||||
// Functions from ch32fun.c
|
||||
#include <stdarg.h>
|
||||
|
||||
|
|
@ -1006,9 +1089,11 @@ extern "C"
|
|||
int mini_vpprintf( int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va );
|
||||
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
|
||||
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
|
||||
int mini_itoa(long value, unsigned int radix, int uppercase, int unsig, char *buffer);
|
||||
|
||||
#endif // __ASSEMBLER__
|
||||
|
||||
|
||||
/*
|
||||
* This file contains various parts of the official WCH EVT Headers which
|
||||
* were originally under a restrictive license.
|
||||
|
|
@ -1049,4 +1134,6 @@ extern "C"
|
|||
};
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __CH32FUN_H
|
||||
|
||||
|
|
|
|||
18083
inc/ch32h41xhw.h
Normal file
18083
inc/ch32h41xhw.h
Normal file
File diff suppressed because it is too large
Load diff
9094
inc/ch32l103hw.h
Normal file
9094
inc/ch32l103hw.h
Normal file
File diff suppressed because it is too large
Load diff
1196
inc/ch32v003hw.h
1196
inc/ch32v003hw.h
File diff suppressed because it is too large
Load diff
6237
inc/ch32v10xhw.h
Normal file
6237
inc/ch32v10xhw.h
Normal file
File diff suppressed because it is too large
Load diff
8450
inc/ch32v20xhw.h
Normal file
8450
inc/ch32v20xhw.h
Normal file
File diff suppressed because it is too large
Load diff
10625
inc/ch32v30xhw.h
Normal file
10625
inc/ch32v30xhw.h
Normal file
File diff suppressed because it is too large
Load diff
5002
inc/ch32x00xhw.h
Normal file
5002
inc/ch32x00xhw.h
Normal file
File diff suppressed because it is too large
Load diff
6245
inc/ch32x03xhw.h
Normal file
6245
inc/ch32x03xhw.h
Normal file
File diff suppressed because it is too large
Load diff
2645
inc/ch5xxhw.h
Normal file
2645
inc/ch5xxhw.h
Normal file
File diff suppressed because it is too large
Load diff
5187
inc/ch641hw.h
Normal file
5187
inc/ch641hw.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -7,8 +7,10 @@
|
|||
#define CH32V003_GPIO_BR_H
|
||||
|
||||
// includes
|
||||
#include "../ch32fun/ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
#include "../ch32fun/ch32fun.h"
|
||||
|
||||
|
||||
|
||||
/*######## library description
|
||||
This is a speedy and light GPIO library due to
|
||||
|
|
@ -17,6 +19,8 @@ This is a speedy and light GPIO library due to
|
|||
branchless where it counts
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
||||
first, enable the desired port.
|
||||
|
|
@ -94,19 +98,19 @@ Writing `TIMx->SWEVGR |= TIM_UG` will immediately update the shadow register and
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||
|
||||
enum GPIO_port_n
|
||||
{
|
||||
enum GPIO_port_n {
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
};
|
||||
|
||||
enum GPIO_pinModes
|
||||
{
|
||||
enum GPIO_pinModes {
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
|
|
@ -117,15 +121,13 @@ enum GPIO_pinModes
|
|||
GPIO_pinMode_O_openDrainMux,
|
||||
};
|
||||
|
||||
enum lowhigh
|
||||
{
|
||||
enum lowhigh {
|
||||
low,
|
||||
high,
|
||||
};
|
||||
|
||||
// analog inputs
|
||||
enum GPIO_analog_inputs
|
||||
{
|
||||
enum GPIO_analog_inputs {
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
|
|
@ -139,8 +141,7 @@ enum GPIO_analog_inputs
|
|||
};
|
||||
|
||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||
enum GPIO_ADC_sampletimes
|
||||
{
|
||||
enum GPIO_ADC_sampletimes {
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
|
|
@ -151,22 +152,22 @@ enum GPIO_ADC_sampletimes
|
|||
GPIO_ADC_sampletime_241cy_default,
|
||||
};
|
||||
|
||||
enum GPIO_tim1_output_sets
|
||||
{
|
||||
enum GPIO_tim1_output_sets {
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
};
|
||||
|
||||
enum GPIO_tim2_output_sets
|
||||
{
|
||||
enum GPIO_tim2_output_sets {
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
|
|
@ -201,10 +202,16 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_tim1_analogWrite(channel, value)
|
||||
#define GPIO_tim2_analogWrite(channel, value)
|
||||
|
||||
|
||||
|
||||
//######## internal function declarations
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
|
||||
#define CONCAT(a, b) a ## b
|
||||
|
|
@ -285,8 +292,11 @@ static inline void GPIO_tim2_init();
|
|||
|
||||
//######## define requirements / maintenance defines
|
||||
|
||||
|
||||
|
||||
//######## small function definitions, static inline
|
||||
|
||||
|
||||
#undef GPIO_port_enable
|
||||
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
||||
|
||||
|
|
@ -328,7 +338,7 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
|
||||
#undef GPIO_digitalWrite_branching
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? (GPIO_digitalWrite_hi(GPIOv)) : (GPIO_digitalWrite_lo(GPIOv)))
|
||||
|
||||
#undef GPIO_digitalRead
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
|
|
@ -344,10 +354,24 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3) \
|
||||
| GPIO_ADC_sampletime << (6 * 3) \
|
||||
| GPIO_ADC_sampletime << (7 * 3) \
|
||||
| GPIO_ADC_sampletime << (8 * 3) \
|
||||
| GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3); \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_power
|
||||
|
|
@ -359,16 +383,13 @@ static inline void GPIO_tim2_init();
|
|||
#undef GPIO_ADC_calibrate
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
||||
; \
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while (ADC1->CTLR2 & ADC_CAL) \
|
||||
; \
|
||||
while(ADC1->CTLR2 & ADC_CAL); \
|
||||
})
|
||||
|
||||
// large but will likely only ever be called once
|
||||
static inline void GPIO_ADCinit()
|
||||
{
|
||||
static inline void GPIO_ADCinit() {
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
|
|
@ -396,8 +417,7 @@ static inline void GPIO_ADCinit()
|
|||
GPIO_ADC_calibrate();
|
||||
}
|
||||
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
||||
{
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
|
|
@ -410,6 +430,8 @@ static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
|||
return ADC1->RDATAR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef GPIO_tim1_map
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
|
|
@ -422,8 +444,7 @@ static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
|||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
})
|
||||
|
||||
static inline void GPIO_tim1_init()
|
||||
{
|
||||
static inline void GPIO_tim1_init() {
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
|
|
@ -444,8 +465,7 @@ static inline void GPIO_tim1_init()
|
|||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
static inline void GPIO_tim2_init()
|
||||
{
|
||||
static inline void GPIO_tim2_init() {
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
#define CH32V003_SPI_H
|
||||
|
||||
// includes
|
||||
#include "ch32fun.h"
|
||||
#include<stdint.h> //uintN_t support
|
||||
#include "ch32fun.h"
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
|
|
@ -47,6 +47,8 @@ then pick the desired setting of each group:
|
|||
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
static inline void SPI_init();
|
||||
|
|
@ -85,14 +87,20 @@ static inline void SPI_poweron();
|
|||
static inline void kill_interrrupts();
|
||||
static inline void restore_interrupts();
|
||||
|
||||
|
||||
|
||||
//######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
static inline uint8_t SPI_is_RX_empty();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
static uint16_t EXT1_INTENR_backup;
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
|
@ -112,7 +120,9 @@ static uint16_t EXT1_INTENR_backup;
|
|||
|
||||
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
||||
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
||||
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
#pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
|
||||
|
||||
|
||||
//######## preprocessor #define requirements
|
||||
|
||||
|
|
@ -151,9 +161,10 @@ _Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCA
|
|||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//######## small function definitions, static inline
|
||||
static inline void SPI_init()
|
||||
{
|
||||
static inline void SPI_init() {
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
|
|
@ -226,59 +237,47 @@ static inline void SPI_init()
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void SPI_begin_8()
|
||||
{
|
||||
static inline void SPI_begin_8() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_begin_16()
|
||||
{
|
||||
static inline void SPI_begin_16() {
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_end()
|
||||
{
|
||||
static inline void SPI_end() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
}
|
||||
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<3);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
}
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<4);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t SPI_read_8()
|
||||
{
|
||||
static inline uint8_t SPI_read_8() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline uint16_t SPI_read_16()
|
||||
{
|
||||
static inline uint16_t SPI_read_16() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline void SPI_write_8(uint8_t data)
|
||||
{
|
||||
static inline void SPI_write_8(uint8_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline void SPI_write_16(uint16_t data)
|
||||
{
|
||||
static inline void SPI_write_16(uint16_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
||||
{
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
|
|
@ -291,8 +290,7 @@ static inline uint8_t SPI_transfer_8(uint8_t data)
|
|||
#endif
|
||||
return SPI_read_8();
|
||||
}
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
||||
{
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
|
|
@ -306,50 +304,44 @@ static inline uint16_t SPI_transfer_16(uint16_t data)
|
|||
return SPI_read_16();
|
||||
}
|
||||
|
||||
static inline void SPI_poweroff()
|
||||
{
|
||||
static inline void SPI_poweroff() {
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
}
|
||||
static inline void SPI_poweron()
|
||||
{
|
||||
static inline void SPI_poweron() {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
}
|
||||
|
||||
static inline void kill_interrrupts()
|
||||
{
|
||||
static inline void kill_interrrupts() {
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
}
|
||||
static inline void restore_interrupts()
|
||||
{
|
||||
static inline void restore_interrupts() {
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete()
|
||||
{
|
||||
static inline void SPI_wait_TX_complete() {
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
}
|
||||
static inline uint8_t SPI_is_RX_empty()
|
||||
{
|
||||
static inline uint8_t SPI_is_RX_empty() {
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
}
|
||||
static inline void SPI_wait_RX_available()
|
||||
{
|
||||
static inline void SPI_wait_RX_available() {
|
||||
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
}
|
||||
static inline void SPI_wait_not_busy()
|
||||
{
|
||||
static inline void SPI_wait_not_busy() {
|
||||
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
}
|
||||
static inline void SPI_wait_transmit_finished()
|
||||
{
|
||||
static inline void SPI_wait_transmit_finished() {
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
}
|
||||
|
||||
|
||||
//######## implementation block
|
||||
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
// Can either be 0 or 1.
|
||||
|
|
@ -48,7 +50,10 @@
|
|||
jalr a2, 1\n\
|
||||
.long 0x00010001\n\
|
||||
.long 0x00010001\n\
|
||||
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2");
|
||||
"\
|
||||
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||
);
|
||||
|
||||
|
||||
static void InitTouchADC( );
|
||||
void InitTouchADC( )
|
||||
|
|
@ -65,13 +70,11 @@ void InitTouchADC()
|
|||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
||||
;
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while (ADC1->CTLR2 & ADC_CAL)
|
||||
;
|
||||
while(ADC1->CTLR2 & ADC_CAL);
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
|
|
@ -94,14 +97,11 @@ uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int itera
|
|||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
|
||||
#if TOUCH_FLAT == 1
|
||||
#define RELEASEIO \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
io->CFGLR = CFGFLOAT;
|
||||
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||
#else
|
||||
#define RELEASEIO \
|
||||
io->CFGLR = CFGFLOAT; \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
||||
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||
#endif
|
||||
|
||||
#define INNER_LOOP( n ) \
|
||||
|
|
@ -121,8 +121,7 @@ uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int itera
|
|||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
|
|
@ -174,8 +173,7 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
|||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
__enable_irq(); \
|
||||
|
|
@ -197,6 +195,7 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -222,3 +221,4 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
|
|
|||
944
inc/extralibs/ch32v208_eth.h
Normal file
944
inc/extralibs/ch32v208_eth.h
Normal file
|
|
@ -0,0 +1,944 @@
|
|||
/*
|
||||
* Single-File-Header for the CH32V208 (and CH579?) built-in 10BASE-T MAC/PHY.
|
||||
*
|
||||
* This peripheral uses POINTER-BASED DMA, not descriptor-based DMA:
|
||||
*
|
||||
* Hardware:
|
||||
* - ERXST register: Points to buffer for next RX packet
|
||||
* - ETXST register: Points to buffer for current TX packet
|
||||
* - Hardware DMAs directly to/from these addresses
|
||||
* - Software must manually update pointers after each packet
|
||||
*
|
||||
* Software (this driver):
|
||||
* - Creates descriptor ring for bookkeeping
|
||||
* - Descriptors are NEVER accessed by hardware
|
||||
* - OWN bit is pure software: 1=empty, 0=filled
|
||||
* - Provides ring-buffer API on top of simple pointers
|
||||
*
|
||||
* USAGE
|
||||
*
|
||||
* Include once with implementation:
|
||||
*
|
||||
* #define CH32V208_ETH_IMPLEMENTATION
|
||||
* #include "ch32v208_eth.h"
|
||||
*
|
||||
* Init:
|
||||
*
|
||||
* eth_config_t config = {
|
||||
* .mac_addr = my_mac, // NULL = use chip default
|
||||
* .rx_callback = eth_rx_cb, // NULL if using manual polling
|
||||
* .link_callback = link_cb, // optional
|
||||
* .activity_callback = led_cb, // optional
|
||||
* .broadcast_filter = true,
|
||||
* };
|
||||
* eth_init(&config);
|
||||
*
|
||||
* Main loop:
|
||||
*
|
||||
* while (1) {
|
||||
* eth_poll_link(); // call every 50-100ms
|
||||
* eth_process_rx(); // IF using callback mode
|
||||
* }
|
||||
*
|
||||
* RECEIVING PACKETS
|
||||
*
|
||||
* Callback mode:
|
||||
*
|
||||
* void eth_rx_cb(const uint8_t *packet, uint16_t length) {
|
||||
* // process packet (called from eth_process_rx)
|
||||
* }
|
||||
*
|
||||
* Manual polling (zero-copy, for sfhip, lwIP etc):
|
||||
*
|
||||
* uint16_t length;
|
||||
* const uint8_t *packet;
|
||||
* while ((packet = eth_get_rx_packet(&length)) != NULL) {
|
||||
* // process packet directly from DMA buffer
|
||||
* eth_release_rx_packet(); // must call when done
|
||||
* }
|
||||
*
|
||||
* SENDING PACKETS
|
||||
*
|
||||
* Simple (with memcpy):
|
||||
*
|
||||
* uint8_t packet[64];
|
||||
* // ... fill packet ...
|
||||
* int ret = eth_send_packet(packet, 64);
|
||||
* // ret: 0=success, -1=queue full
|
||||
*
|
||||
* Zero-copy mode (build directly in DMA buffer):
|
||||
*
|
||||
* uint16_t max_len;
|
||||
* uint8_t *buf = eth_get_tx_buffer(&max_len);
|
||||
* if (buf) {
|
||||
* // build packet directly in DMA buffer
|
||||
* eth_send_packet_zerocopy(actual_length);
|
||||
* }
|
||||
*
|
||||
* CONFIGURATION
|
||||
*
|
||||
* Define before including header to customize:
|
||||
*
|
||||
* ETH_RX_BUF_COUNT RX descriptor ring size (default: 4)
|
||||
* ETH_TX_BUF_COUNT TX queue depth (default: 2)
|
||||
* ETH_MAX_PACKET_SIZE MAC MTU (default: 1536)
|
||||
* ETH_RX_BUF_SIZE RX buffer size (default: ETH_MAX_PACKET_SIZE)
|
||||
* ETH_TX_BUF_SIZE TX buffer size (default: ETH_MAX_PACKET_SIZE)
|
||||
* ETH_ENABLE_STATS Enable eth_get_stats() and eth_reset_stats()
|
||||
*/
|
||||
|
||||
#ifndef _CH32V208_ETH_H
|
||||
#define _CH32V208_ETH_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ETH_RX_BUF_COUNT
|
||||
#define ETH_RX_BUF_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifndef ETH_TX_BUF_COUNT
|
||||
#define ETH_TX_BUF_COUNT 2
|
||||
#endif
|
||||
|
||||
#ifndef ETH_MAX_PACKET_SIZE
|
||||
#define ETH_MAX_PACKET_SIZE 1536
|
||||
#endif
|
||||
|
||||
#ifndef ETH_RX_BUF_SIZE
|
||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef ETH_TX_BUF_SIZE
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||
#endif
|
||||
|
||||
#define ETH_MAC_ADDR_LEN 6
|
||||
|
||||
// Define ETH_ENABLE_STATS before including this header to enable stats collection
|
||||
// #define ETH_ENABLE_STATS
|
||||
|
||||
// Callback types
|
||||
typedef void ( *eth_rx_callback_t )( const uint8_t *packet, uint16_t length );
|
||||
typedef void ( *eth_link_callback_t )( bool link_up );
|
||||
typedef void ( *eth_activity_callback_t )( void );
|
||||
|
||||
// Ethernet configuration
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *mac_addr; // MAC address (can be NULL to use chip default)
|
||||
eth_rx_callback_t rx_callback; // Called when packet received
|
||||
eth_link_callback_t link_callback; // Called when link status changes
|
||||
eth_activity_callback_t activity_callback; // Called on TX/RX activity, can be used for LED
|
||||
bool promiscuous_mode; // Enable promiscuous mode
|
||||
bool broadcast_filter; // Accept broadcast packets
|
||||
bool multicast_filter; // Accept multicast packets
|
||||
} eth_config_t;
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
// Ethernet statistics
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rx_packets;
|
||||
uint32_t tx_packets;
|
||||
uint32_t rx_errors;
|
||||
uint32_t tx_errors;
|
||||
uint32_t rx_dropped;
|
||||
uint32_t tx_dropped;
|
||||
} eth_stats_t;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Init the Ethernet peripheral
|
||||
* @param config Ptr to config struct
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int eth_init( const eth_config_t *config );
|
||||
|
||||
/**
|
||||
* Send an Ethernet packet
|
||||
* @param packet Ptr to packet data (incl. Ethernet header)
|
||||
* @param length Length of pkt in bytes
|
||||
* @return 0: success, -1: queue full
|
||||
*/
|
||||
int eth_send_packet( const uint8_t *packet, uint16_t length );
|
||||
|
||||
/**
|
||||
* Get pointer to next available TX buffer for zero-copy transmission
|
||||
* @param length max length available in buffer
|
||||
* @return pointer to TX buffer, or NULL if queue full
|
||||
* @note After writing packet data, call eth_send_packet_zerocopy() with actual length
|
||||
*/
|
||||
uint8_t *eth_get_tx_buffer( uint16_t *max_length );
|
||||
|
||||
/**
|
||||
* Commit a zero-copy TX buffer for transmission
|
||||
* @param length packet length written to buffer from eth_get_tx_buffer()
|
||||
* @return 0 on success
|
||||
*/
|
||||
int eth_send_packet_zerocopy( uint16_t length );
|
||||
|
||||
/**
|
||||
* Process received packets (call from main loop)
|
||||
* This will invoke the rx_callback for each received pkt
|
||||
*/
|
||||
void eth_process_rx( void );
|
||||
|
||||
/**
|
||||
* Get pointer to next received packet (alternative to eth_process_rx with callback)
|
||||
* @param length Pointer to store packet length
|
||||
* @return Pointer to packet data, or NULL if no packet ready
|
||||
* @note Caller MUST call eth_release_rx_packet() when done with the packet
|
||||
* @note Packet data is valid only until eth_release_rx_packet() is called
|
||||
*/
|
||||
const uint8_t *eth_get_rx_packet( uint16_t *length );
|
||||
|
||||
/**
|
||||
* Release currently held RX packet back to DMA
|
||||
* @note Must be called after eth_get_rx_packet() to free the descriptor
|
||||
*/
|
||||
void eth_release_rx_packet( void );
|
||||
|
||||
/**
|
||||
* Poll link status and handle auto-negotiation
|
||||
* this is based on WCHNET_LinkProcess
|
||||
* https://github.com/openwch/ch32v20x/blob/main/EVT/EXAM/ETH/NetLib/eth_driver.c#L131
|
||||
* TODO: cable polarity reversal is untested
|
||||
*
|
||||
* call this periodically from main loop (i.e. every 50-100ms)
|
||||
*/
|
||||
void eth_poll_link( void );
|
||||
|
||||
/**
|
||||
* Get current MAC
|
||||
* @param mac_addr Buffer to store MAC address (6 bytes)
|
||||
*/
|
||||
void eth_get_mac_address( uint8_t *mac_addr );
|
||||
|
||||
/**
|
||||
* Check if link is up
|
||||
* @return true if link is up
|
||||
*/
|
||||
bool eth_is_link_up( void );
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
/**
|
||||
* Get stats
|
||||
* @param stats Pointer to statistics structure to fill
|
||||
*/
|
||||
void eth_get_stats( eth_stats_t *stats );
|
||||
|
||||
/**
|
||||
* Reset stat counters
|
||||
*/
|
||||
void eth_reset_stats( void );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CH32V208_ETH_H
|
||||
|
||||
|
||||
#ifdef CH32V208_ETH_IMPLEMENTATION
|
||||
|
||||
#include "ch32fun.h"
|
||||
#include <string.h>
|
||||
|
||||
// DMA descriptor
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t Status;
|
||||
volatile uint32_t Buffer1Addr;
|
||||
} ETH_DMADESCTypeDef;
|
||||
|
||||
// TX queue management
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t head;
|
||||
volatile uint32_t tail;
|
||||
volatile bool is_full; // this is only really needed if ETH_TX_BUF_COUNT == 1
|
||||
} tx_queue_t;
|
||||
|
||||
// driver state
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rx_head_idx;
|
||||
uint32_t rx_tail_idx;
|
||||
tx_queue_t tx_q;
|
||||
uint8_t mac_addr[ETH_MAC_ADDR_LEN];
|
||||
eth_rx_callback_t rx_callback;
|
||||
eth_link_callback_t link_callback;
|
||||
eth_activity_callback_t activity_callback;
|
||||
volatile bool link_irq_flag;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
eth_stats_t stats;
|
||||
#endif
|
||||
// autoneg & polarity state
|
||||
uint8_t phy_mdix_mode; // current MDI/MDIX setting
|
||||
uint8_t crc_error_count; // CRC errors since link up
|
||||
bool polarity_detect_active;
|
||||
uint8_t negotiation_poll_count;
|
||||
enum
|
||||
{
|
||||
LINK_STATE_DOWN,
|
||||
LINK_STATE_NEGOTIATING,
|
||||
LINK_STATE_UP
|
||||
} link_state;
|
||||
} eth_driver_state_t;
|
||||
|
||||
__attribute__( ( aligned( 4 ) ) ) static ETH_DMADESCTypeDef g_dma_rx_descs[ETH_RX_BUF_COUNT];
|
||||
__attribute__( ( aligned( 4 ) ) ) static ETH_DMADESCTypeDef g_dma_tx_descs[ETH_TX_BUF_COUNT];
|
||||
__attribute__( ( aligned( 4 ) ) ) static uint8_t g_mac_rx_bufs[ETH_RX_BUF_COUNT * ETH_RX_BUF_SIZE];
|
||||
__attribute__( ( aligned( 4 ) ) ) static uint8_t g_mac_tx_bufs[ETH_TX_BUF_COUNT * ETH_TX_BUF_SIZE];
|
||||
|
||||
static eth_driver_state_t g_eth_state = { 0 };
|
||||
|
||||
static void phy_write_reg( uint8_t reg_add, uint16_t reg_val )
|
||||
{
|
||||
R32_ETH_MIWR = ( reg_add & RB_ETH_MIREGADR_MASK ) | RB_ETH_MIWR_MIIWR | ( reg_val << RB_ETH_MIWR_DATA_SHIFT );
|
||||
}
|
||||
|
||||
static uint16_t phy_read_reg( uint8_t reg_add )
|
||||
{
|
||||
ETH10M->MIERGADR = reg_add;
|
||||
return ETH10M->MIRD;
|
||||
}
|
||||
|
||||
static inline void tx_queue_init( tx_queue_t *q )
|
||||
{
|
||||
q->head = 0;
|
||||
q->tail = 0;
|
||||
q->is_full = false;
|
||||
}
|
||||
|
||||
static inline bool tx_queue_is_empty( const tx_queue_t *q )
|
||||
{
|
||||
return !q->is_full && ( q->head == q->tail );
|
||||
}
|
||||
|
||||
static inline bool tx_queue_is_full( const tx_queue_t *q )
|
||||
{
|
||||
return q->is_full;
|
||||
}
|
||||
|
||||
static inline void tx_queue_produce( tx_queue_t *q )
|
||||
{
|
||||
q->head = ( q->head + 1 ) % ETH_TX_BUF_COUNT;
|
||||
if ( q->head == q->tail )
|
||||
{
|
||||
q->is_full = true; // head caught up to tail = full
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tx_queue_consume( tx_queue_t *q )
|
||||
{
|
||||
q->tail = ( q->tail + 1 ) % ETH_TX_BUF_COUNT;
|
||||
q->is_full = false; // after consuming, definitely not full
|
||||
}
|
||||
|
||||
static void eth_get_chip_mac_addr( uint8_t *mac )
|
||||
{
|
||||
const uint8_t *macaddr_src = (const uint8_t *)( ROM_CFG_USERADR_ID + 5 );
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
mac[i] = *( macaddr_src-- );
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_start_if_possible( void )
|
||||
{
|
||||
if ( ETH10M->ECON1 & RB_ETH_ECON1_TXRTS )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t idx = g_eth_state.tx_q.tail;
|
||||
ETH_DMADESCTypeDef *desc = &g_dma_tx_descs[idx];
|
||||
uint16_t len = desc->Status;
|
||||
|
||||
ETH10M->ETXLN = len; // set tx packet len
|
||||
ETH10M->ETXST = desc->Buffer1Addr; // set tx buf start address (DMA source)
|
||||
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS; // set tx req flag to start DMA transmission
|
||||
}
|
||||
|
||||
/**
|
||||
* Start PHY auto-negotiation with specific MDI/MDIX mode
|
||||
*/
|
||||
static void phy_start_autoneg( uint8_t mdix_mode )
|
||||
{
|
||||
// reset and restart auto-negotiation
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
// configure MDI/MDIX mode
|
||||
phy_write_reg( PHY_MDIX, ( mdix_mode & MDIX_MODE_MASK ) | MDIX_PN_POLARITY_NORMAL );
|
||||
// enable auto-negotiation
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_AN_ENABLE | PHY_BMCR_AN_RESTART );
|
||||
|
||||
g_eth_state.phy_mdix_mode = mdix_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try next MDI/MDIX mode in sequence: AUTO -> MDIX -> MDI -> AUTO
|
||||
*/
|
||||
static void phy_try_next_mdix_mode( void )
|
||||
{
|
||||
uint8_t next_mode;
|
||||
|
||||
switch ( g_eth_state.phy_mdix_mode & MDIX_MODE_MASK )
|
||||
{
|
||||
case MDIX_MODE_AUTO:
|
||||
next_mode = MDIX_MODE_MDIX; // try forced MDIX
|
||||
break;
|
||||
case MDIX_MODE_MDIX:
|
||||
next_mode = MDIX_MODE_MDI; // try forced MDI
|
||||
break;
|
||||
default:
|
||||
next_mode = MDIX_MODE_AUTO; // back to auto
|
||||
break;
|
||||
}
|
||||
|
||||
phy_start_autoneg( next_mode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cable polarity issue (P/N reversal)
|
||||
*/
|
||||
static void phy_fix_polarity( void )
|
||||
{
|
||||
uint16_t mdix_reg = phy_read_reg( PHY_MDIX );
|
||||
|
||||
// toggle P/N polarity between NORMAL and REVERSED
|
||||
mdix_reg ^= MDIX_PN_POLARITY_REVERSED;
|
||||
|
||||
phy_write_reg( PHY_MDIX, mdix_reg );
|
||||
g_eth_state.crc_error_count = 0;
|
||||
}
|
||||
|
||||
static void eth_link_up_handler( void )
|
||||
{
|
||||
// read auto-negotiation registers
|
||||
uint16_t anar = phy_read_reg( PHY_ANAR ); // what we advertised
|
||||
uint16_t anlpar = phy_read_reg( PHY_ANLPAR ); // what partner advertised
|
||||
uint16_t common = anar & anlpar;
|
||||
|
||||
// check if both sides support full-duplex
|
||||
bool is_full_duplex = ( common & PHY_ANLPAR_10BASE_TFD ) != 0;
|
||||
// configure MAC to match negotiated duplex mode
|
||||
if ( is_full_duplex )
|
||||
{
|
||||
ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETH10M->MACON2 &= ~RB_ETH_MACON2_FULDPX;
|
||||
}
|
||||
// enable CRC error packet reception for polarity detection
|
||||
ETH10M->ERXFCON |= RB_ETH_ERXFCON_CRCEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_UP;
|
||||
g_eth_state.crc_error_count = 0;
|
||||
g_eth_state.polarity_detect_active = true;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
|
||||
if ( g_eth_state.link_callback )
|
||||
{
|
||||
g_eth_state.link_callback( true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure MAC for link down
|
||||
*/
|
||||
static void eth_link_down_handler( void )
|
||||
{
|
||||
// Disable polarity detection
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
ETH10M->ERXFCON &= ~RB_ETH_ERXFCON_CRCEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
|
||||
if ( g_eth_state.link_callback )
|
||||
{
|
||||
g_eth_state.link_callback( false );
|
||||
}
|
||||
}
|
||||
|
||||
int eth_init( const eth_config_t *config )
|
||||
{
|
||||
if ( !config )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset( &g_eth_state, 0, sizeof( g_eth_state ) );
|
||||
|
||||
g_eth_state.rx_callback = config->rx_callback;
|
||||
g_eth_state.link_callback = config->link_callback;
|
||||
g_eth_state.activity_callback = config->activity_callback;
|
||||
|
||||
if ( config->mac_addr )
|
||||
{
|
||||
memcpy( g_eth_state.mac_addr, config->mac_addr, ETH_MAC_ADDR_LEN );
|
||||
}
|
||||
else
|
||||
{
|
||||
eth_get_chip_mac_addr( g_eth_state.mac_addr );
|
||||
}
|
||||
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
RCC->CFGR0 |= RCC_ETHPRE; // Ethernet clock prescaler
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; // Extended Control Register, 10M Ethernet enable and clock enable
|
||||
|
||||
// Transmit/Receive module reset
|
||||
ETH10M->ECON1 = RB_ETH_ECON1_TXRST | RB_ETH_ECON1_RXRST;
|
||||
ETH10M->ECON1 = 0;
|
||||
|
||||
uint32_t rx_filter;
|
||||
|
||||
if ( config->promiscuous_mode )
|
||||
{
|
||||
// Promiscuous: disable filtering (ERXFCON=0 *probably* receives everything)
|
||||
rx_filter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal mode: enable filtering and ALWAYS receive unicast to our MAC
|
||||
rx_filter = RB_ETH_ERXFCON_EN | RB_ETH_ERXFCON_UCEN;
|
||||
|
||||
// broadcast packet reception
|
||||
if ( config->broadcast_filter )
|
||||
{
|
||||
rx_filter |= RB_ETH_ERXFCON_BCEN;
|
||||
}
|
||||
// multicast packet reception
|
||||
if ( config->multicast_filter )
|
||||
{
|
||||
rx_filter |= RB_ETH_ERXFCON_MCEN;
|
||||
}
|
||||
}
|
||||
|
||||
ETH10M->ERXFCON = rx_filter;
|
||||
// MAC layer receive enable
|
||||
ETH10M->MACON1 = RB_ETH_MACON1_MARXEN;
|
||||
|
||||
// Pad short packets with 0x00 to 60 bytes, then append 4-byte CRC
|
||||
// Hardware pads CRC
|
||||
ETH10M->MACON2 = PADCFG_AUTO_3 | RB_ETH_MACON2_TXCRCEN;
|
||||
// Set maximum frame length (MTU)
|
||||
ETH10M->MAMXFL = ETH_MAX_PACKET_SIZE;
|
||||
|
||||
// MAC is reversed
|
||||
R8_ETH_MAADRL1 = g_eth_state.mac_addr[5];
|
||||
R8_ETH_MAADRL2 = g_eth_state.mac_addr[4];
|
||||
R8_ETH_MAADRL3 = g_eth_state.mac_addr[3];
|
||||
R8_ETH_MAADRL4 = g_eth_state.mac_addr[2];
|
||||
R8_ETH_MAADRL5 = g_eth_state.mac_addr[1];
|
||||
R8_ETH_MAADRL6 = g_eth_state.mac_addr[0];
|
||||
|
||||
// PHY Analog Parameter Setting, default value and "Rated driver"
|
||||
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
||||
|
||||
tx_queue_init( &g_eth_state.tx_q );
|
||||
for ( int i = 0; i < ETH_TX_BUF_COUNT; i++ )
|
||||
{
|
||||
g_dma_tx_descs[i].Status = 0;
|
||||
g_dma_tx_descs[i].Buffer1Addr = (uint32_t)&g_mac_tx_bufs[i * ETH_TX_BUF_SIZE];
|
||||
}
|
||||
|
||||
// init RX descriptor ring (DMA reads from these)
|
||||
g_eth_state.rx_head_idx = 0;
|
||||
g_eth_state.rx_tail_idx = 0;
|
||||
for ( int i = 0; i < ETH_RX_BUF_COUNT; i++ )
|
||||
{
|
||||
g_dma_rx_descs[i].Status = ETH_DMARxDesc_OWN; // DMA owns all initially
|
||||
g_dma_rx_descs[i].Buffer1Addr = (uint32_t)&g_mac_rx_bufs[i * ETH_RX_BUF_SIZE];
|
||||
}
|
||||
|
||||
// start RX
|
||||
ETH10M->ERXST = g_dma_rx_descs[0].Buffer1Addr;
|
||||
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
g_eth_state.crc_error_count = 0;
|
||||
|
||||
// start auto-negotiation with AUTO MDI/MDIX
|
||||
phy_start_autoneg( MDIX_MODE_AUTO );
|
||||
Delay_Ms( 100 ); // Give PHY time to initialize
|
||||
|
||||
// clear all pending interrupt flags
|
||||
ETH10M->EIR = 0xFF;
|
||||
ETH10M->ESTAT |= RB_ETH_ESTAT_INT | RB_ETH_ESTAT_BUFER;
|
||||
|
||||
ETH10M->EIE = RB_ETH_EIE_INTIE | // Ethernet interrupt enable (master enable)
|
||||
RB_ETH_EIE_RXIE | // RX complete interrupt
|
||||
RB_ETH_EIE_TXIE | // TX complete interrupt
|
||||
RB_ETH_EIE_LINKIE | // Link status change interrupt
|
||||
RB_ETH_EIE_TXERIE | // TX error interrupt (collision, underrun, etc.)
|
||||
RB_ETH_EIE_RXERIE | // RX error interrupt (CRC error, overrun, etc.)
|
||||
RB_ETH_EIE_R_EN50; // Built-in 50ohm impedance matching resistor enable
|
||||
|
||||
NVIC_EnableIRQ( ETH_IRQn );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_send_packet( const uint8_t *packet, uint16_t length )
|
||||
{
|
||||
if ( tx_queue_is_full( &g_eth_state.tx_q ) )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_dropped++;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reserve our slot in the queue
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
tx_queue_produce( &g_eth_state.tx_q );
|
||||
|
||||
uint8_t *tx_buf = (uint8_t *)g_dma_tx_descs[idx].Buffer1Addr;
|
||||
memcpy( tx_buf, packet, length );
|
||||
g_dma_tx_descs[idx].Status = length;
|
||||
|
||||
tx_start_if_possible();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *eth_get_tx_buffer( uint16_t *max_length )
|
||||
{
|
||||
if ( tx_queue_is_full( &g_eth_state.tx_q ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( max_length )
|
||||
{
|
||||
*max_length = ETH_TX_BUF_SIZE;
|
||||
}
|
||||
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
return (uint8_t *)g_dma_tx_descs[idx].Buffer1Addr;
|
||||
}
|
||||
|
||||
|
||||
int eth_send_packet_zerocopy( uint16_t length )
|
||||
{
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
g_dma_tx_descs[idx].Status = length;
|
||||
|
||||
tx_queue_produce( &g_eth_state.tx_q );
|
||||
tx_start_if_possible();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *eth_get_rx_packet( uint16_t *length )
|
||||
{
|
||||
if ( !length )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t tail_idx = g_eth_state.rx_tail_idx;
|
||||
|
||||
if ( g_dma_rx_descs[tail_idx].Status & ETH_DMARxDesc_OWN )
|
||||
{
|
||||
return NULL; // no packet ready
|
||||
}
|
||||
|
||||
// extract packet length from descriptor status field
|
||||
*length = ( g_dma_rx_descs[tail_idx].Status & ETH_DMARxDesc_FL ) >> ETH_DMARxDesc_FrameLengthShift;
|
||||
|
||||
// return pointer to packet buffer
|
||||
return (const uint8_t *)g_dma_rx_descs[tail_idx].Buffer1Addr;
|
||||
}
|
||||
|
||||
void eth_release_rx_packet( void )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_packets++;
|
||||
#endif
|
||||
uint32_t tail_idx = g_eth_state.rx_tail_idx;
|
||||
|
||||
// give descriptor back to DMA
|
||||
g_dma_rx_descs[tail_idx].Status = ETH_DMARxDesc_OWN;
|
||||
|
||||
// advance to next descriptor in ring
|
||||
g_eth_state.rx_tail_idx = ( tail_idx + 1 ) % ETH_RX_BUF_COUNT;
|
||||
}
|
||||
|
||||
|
||||
void eth_process_rx( void )
|
||||
{
|
||||
uint16_t length;
|
||||
const uint8_t *packet;
|
||||
|
||||
// process all packets that DMA has released
|
||||
while ( ( packet = eth_get_rx_packet( &length ) ) != NULL )
|
||||
{
|
||||
// deliver to user callback if registered
|
||||
if ( g_eth_state.rx_callback )
|
||||
{
|
||||
g_eth_state.rx_callback( packet, length );
|
||||
}
|
||||
|
||||
eth_release_rx_packet();
|
||||
}
|
||||
}
|
||||
|
||||
void eth_poll_link( void )
|
||||
{
|
||||
if ( g_eth_state.link_irq_flag )
|
||||
{
|
||||
g_eth_state.link_irq_flag = false;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
}
|
||||
|
||||
uint16_t bmsr = phy_read_reg( PHY_BMSR );
|
||||
uint16_t anlpar = phy_read_reg( PHY_ANLPAR );
|
||||
|
||||
bool phy_link = ( bmsr & PHY_BMSR_LINK_STATUS ) != 0;
|
||||
bool an_complete = ( bmsr & PHY_BMSR_AN_COMPLETE ) != 0;
|
||||
|
||||
switch ( g_eth_state.link_state )
|
||||
{
|
||||
|
||||
case LINK_STATE_DOWN:
|
||||
if ( phy_link && an_complete && ( anlpar != 0 ) )
|
||||
{
|
||||
// valid link with successful negotiation
|
||||
eth_link_up_handler();
|
||||
}
|
||||
else if ( phy_link && an_complete && ( anlpar == 0 ) )
|
||||
{
|
||||
// false auto-negotiation completion (ANLPAR=0)
|
||||
// reset PHY and try different mode
|
||||
g_eth_state.link_state = LINK_STATE_NEGOTIATING;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
phy_try_next_mdix_mode();
|
||||
}
|
||||
break;
|
||||
|
||||
case LINK_STATE_NEGOTIATING:
|
||||
if ( phy_link && an_complete && ( anlpar != 0 ) )
|
||||
{
|
||||
// negotiation succeeded
|
||||
eth_link_up_handler();
|
||||
}
|
||||
else if ( phy_link && an_complete && ( anlpar == 0 ) )
|
||||
{
|
||||
// still no valid partner response after negotiation
|
||||
g_eth_state.negotiation_poll_count++;
|
||||
|
||||
if ( g_eth_state.negotiation_poll_count >= 10 )
|
||||
{
|
||||
// try next MDI/MDIX mode after 10 polls
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
phy_try_next_mdix_mode();
|
||||
}
|
||||
}
|
||||
else if ( !phy_link )
|
||||
{
|
||||
// link went down during negotiation
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case LINK_STATE_UP:
|
||||
if ( !phy_link )
|
||||
{
|
||||
// link went down
|
||||
eth_link_down_handler();
|
||||
phy_start_autoneg( MDIX_MODE_AUTO );
|
||||
}
|
||||
else if ( g_eth_state.polarity_detect_active )
|
||||
{
|
||||
// monitor for polarity issues
|
||||
if ( g_eth_state.crc_error_count >= 3 )
|
||||
{
|
||||
phy_fix_polarity();
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
ETH10M->ERXFCON &= ~RB_ETH_ERXFCON_CRCEN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void eth_get_mac_address( uint8_t *mac_addr )
|
||||
{
|
||||
if ( mac_addr )
|
||||
{
|
||||
memcpy( mac_addr, g_eth_state.mac_addr, ETH_MAC_ADDR_LEN );
|
||||
}
|
||||
}
|
||||
|
||||
bool eth_is_link_up( void )
|
||||
{
|
||||
return g_eth_state.link_state == LINK_STATE_UP;
|
||||
}
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
void eth_get_stats( eth_stats_t *stats )
|
||||
{
|
||||
if ( stats )
|
||||
{
|
||||
*stats = g_eth_state.stats;
|
||||
}
|
||||
}
|
||||
|
||||
void eth_reset_stats( void )
|
||||
{
|
||||
memset( &g_eth_state.stats, 0, sizeof( eth_stats_t ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
void ETH_IRQHandler( void ) __attribute__( ( interrupt ) ) __attribute__( ( used ) );
|
||||
void ETH_IRQHandler( void )
|
||||
{
|
||||
uint32_t flags = ETH10M->EIR;
|
||||
|
||||
uint32_t head_idx = g_eth_state.rx_head_idx;
|
||||
|
||||
if ( flags & RB_ETH_EIR_RXIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_RXIF; // clear interrupt flag
|
||||
|
||||
// check if DMA still owns the current head descriptor
|
||||
if ( g_dma_rx_descs[head_idx].Status & ETH_DMARxDesc_OWN )
|
||||
{
|
||||
uint16_t rx_len = ETH10M->ERXLN;
|
||||
|
||||
if ( rx_len == 0 || rx_len > ETH_RX_BUF_SIZE )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// check for RX errors
|
||||
uint8_t estat = ETH10M->ESTAT;
|
||||
const uint8_t error_mask =
|
||||
RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER | RB_ETH_ESTAT_RXNIBBLE | RB_ETH_ESTAT_RXMORE;
|
||||
|
||||
if ( estat & error_mask )
|
||||
{
|
||||
// track CRC errors specifically for polarity detection
|
||||
if ( ( estat & RB_ETH_ESTAT_RXCRCER ) && g_eth_state.polarity_detect_active )
|
||||
{
|
||||
g_eth_state.crc_error_count++;
|
||||
}
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
return; // discard
|
||||
}
|
||||
|
||||
// check if next descriptor is available
|
||||
uint32_t next_idx = ( head_idx + 1 ) % ETH_RX_BUF_COUNT;
|
||||
|
||||
if ( !( g_dma_rx_descs[next_idx].Status & ETH_DMARxDesc_OWN ) )
|
||||
{
|
||||
// ring full
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_dropped++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// packet is ready and we have space
|
||||
// mark current descriptor as ready for CPU processing
|
||||
g_dma_rx_descs[head_idx].Status &= ~ETH_DMARxDesc_OWN;
|
||||
|
||||
// add frame metadata
|
||||
g_dma_rx_descs[head_idx].Status |= ( ETH_DMARxDesc_FS | ETH_DMARxDesc_LS | // Single segment frame
|
||||
( ETH10M->ERXLN << ETH_DMARxDesc_FrameLengthShift ) );
|
||||
|
||||
// advance head to next descriptor for DMA
|
||||
g_eth_state.rx_head_idx = next_idx;
|
||||
|
||||
// tell MAC where to write next packet
|
||||
ETH10M->ERXST = g_dma_rx_descs[next_idx].Buffer1Addr;
|
||||
|
||||
// signal activity
|
||||
if ( g_eth_state.activity_callback )
|
||||
{
|
||||
g_eth_state.activity_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_TXIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
||||
|
||||
if ( !tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_packets++;
|
||||
#endif
|
||||
tx_queue_consume( &g_eth_state.tx_q );
|
||||
}
|
||||
|
||||
tx_start_if_possible();
|
||||
|
||||
// signal activity
|
||||
if ( g_eth_state.activity_callback )
|
||||
{
|
||||
g_eth_state.activity_callback();
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_TXERIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_errors++;
|
||||
#endif
|
||||
|
||||
if ( !tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
tx_queue_consume( &g_eth_state.tx_q );
|
||||
}
|
||||
tx_start_if_possible();
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_RXERIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
||||
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_LINKIF )
|
||||
{
|
||||
g_eth_state.link_irq_flag = true;
|
||||
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CH32V208_ETH_IMPLEMENTATION
|
||||
|
|
@ -64,6 +64,7 @@ uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGAB
|
|||
ETH_DMADESCTypeDef * pDMARxGet;
|
||||
ETH_DMADESCTypeDef * pDMATxSet;
|
||||
|
||||
|
||||
// Internal functions
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||
|
|
@ -130,6 +131,7 @@ static int ch32v307ethTickPhy(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Based on ETH_WritePHYRegister
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
|
||||
{
|
||||
|
|
@ -140,8 +142,7 @@ static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
|
|||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
|
|
@ -155,13 +156,13 @@ static int ch32v307ethPHYRegRead(uint32_t reg)
|
|||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
}
|
||||
|
||||
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||
{
|
||||
// Mac is backwards.
|
||||
|
|
@ -228,19 +229,16 @@ static int ch32v307ethInit(void)
|
|||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if( timeout == 0 ) return -5;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if( timeout == 0 ) return -6;
|
||||
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if( timeout == 0 ) return -7;
|
||||
|
||||
// Switch to PLL.
|
||||
|
|
@ -545,4 +543,6 @@ static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enabl
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
1036
inc/extralibs/fsusb.c
Normal file
1036
inc/extralibs/fsusb.c
Normal file
File diff suppressed because it is too large
Load diff
419
inc/extralibs/fsusb.h
Normal file
419
inc/extralibs/fsusb.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
#ifndef _FSUSB_H
|
||||
#define _FSUSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#if defined(FUSB_FROM_RAM) && (FUSB_FROM_RAM)
|
||||
#if defined(CH5xx)
|
||||
#define __USBFS_FUN_ATTRIBUTE __attribute__((section(".srodata"), used))
|
||||
#else
|
||||
#define __USBFS_FUN_ATTRIBUTE
|
||||
#endif
|
||||
#else
|
||||
#define __USBFS_FUN_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
#if defined(CH5xx) || defined(CH32X03x) || defined(CH32V10x)
|
||||
#if !defined (CH32X03x) && !defined(CH32V10x)
|
||||
#define USBFS_BASE USB_BASE_ADDR
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t UDEV_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t USB_STATUS;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t RX_LEN;
|
||||
__IO uint8_t Reserved0;
|
||||
__IO uint16_t Reserved1;
|
||||
__IO uint8_t UEP4_1_MOD;
|
||||
__IO uint8_t UEP2_3_MOD;
|
||||
__IO uint8_t UEP567_MOD;
|
||||
__IO uint8_t Reserved2;
|
||||
__IO uint16_t UEP0_DMA;
|
||||
__IO uint16_t Reserved3;
|
||||
__IO uint16_t UEP1_DMA;
|
||||
__IO uint16_t Reserved4;
|
||||
__IO uint16_t UEP2_DMA;
|
||||
__IO uint16_t Reserved5;
|
||||
__IO uint16_t UEP3_DMA;
|
||||
__IO uint16_t Reserved6;
|
||||
__IO uint8_t UEP0_TX_LEN;
|
||||
__IO uint8_t Reserved7;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t Reserved8;
|
||||
__IO uint8_t UEP1_TX_LEN;
|
||||
__IO uint8_t Reserved9;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t Reserved10;
|
||||
__IO uint8_t UEP2_TX_LEN;
|
||||
__IO uint8_t Reserved11;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t Reserved12;
|
||||
__IO uint8_t UEP3_TX_LEN;
|
||||
__IO uint8_t Reserved13;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t Reserved14;
|
||||
__IO uint8_t UEP4_TX_LEN;
|
||||
__IO uint8_t Reserved15;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t Reserved16;
|
||||
__IO uint32_t Reserved17;
|
||||
__IO uint32_t Reserved18;
|
||||
__IO uint32_t Reserved19;
|
||||
__IO uint32_t Reserved20;
|
||||
__IO uint32_t Reserved21;
|
||||
__IO uint32_t Reserved22;
|
||||
__IO uint32_t Reserved23;
|
||||
__IO uint32_t Reserved24;
|
||||
__IO uint16_t UEP5_DMA;
|
||||
__IO uint16_t UEP6_DMA;
|
||||
__IO uint16_t UEP7_DMA;
|
||||
__IO uint32_t Reserved25;
|
||||
__IO uint8_t UEP5_TX_LEN;
|
||||
__IO uint8_t Reserved26;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t Reserved27;
|
||||
__IO uint8_t UEP6_TX_LEN;
|
||||
__IO uint8_t Reserved28;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t Reserved29;
|
||||
__IO uint8_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t Reserved30;
|
||||
__IO uint32_t EPX_MODE;
|
||||
} USBFS_TypeDef;
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((uint8_t*)&USBFS->UEP0_TX_LEN)[n*4])
|
||||
#define UEP_CTRL_TX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((uint16_t*)&USBFS->UEP0_DMA)[n*2])
|
||||
#endif
|
||||
|
||||
#if defined(CH32V10x)
|
||||
#define USBFS_BASE 0x40023400
|
||||
#define USB_IRQn USBFS_IRQn
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t UDEV_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t USB_STATUS;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t RX_LEN;
|
||||
__IO uint8_t Reserved0;
|
||||
__IO uint16_t Reserved1;
|
||||
__IO uint8_t UEP4_1_MOD;
|
||||
__IO uint8_t UEP2_3_MOD;
|
||||
__IO uint8_t UEP5_6_MOD;
|
||||
__IO uint8_t UEP7_MOD;
|
||||
__IO uint16_t UEP0_DMA;
|
||||
__IO uint16_t Reserved3;
|
||||
__IO uint16_t UEP1_DMA;
|
||||
__IO uint16_t Reserved4;
|
||||
__IO uint16_t UEP2_DMA;
|
||||
__IO uint16_t Reserved5;
|
||||
__IO uint16_t UEP3_DMA;
|
||||
__IO uint16_t Reserved6;
|
||||
__IO uint16_t UEP4_DMA;
|
||||
__IO uint16_t Reserved7;
|
||||
__IO uint16_t UEP5_DMA;
|
||||
__IO uint16_t Reserved8;
|
||||
__IO uint16_t UEP6_DMA;
|
||||
__IO uint16_t Reserved9;
|
||||
__IO uint16_t UEP7_DMA;
|
||||
__IO uint16_t Reserved10;
|
||||
__IO uint16_t UEP0_TX_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t Reserved11;
|
||||
__IO uint16_t UEP1_TX_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t Reserved12;
|
||||
__IO uint16_t UEP2_TX_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t Reserved13;
|
||||
__IO uint16_t UEP3_TX_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t Reserved14;
|
||||
__IO uint16_t UEP4_TX_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t Reserved15;
|
||||
__IO uint16_t UEP5_TX_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t Reserved16;
|
||||
__IO uint16_t UEP6_TX_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t Reserved17;
|
||||
__IO uint16_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t Reserved18;
|
||||
} USBFS_TypeDef;
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((volatile uint16_t*)&USBFS->UEP0_DMA)[n*2])
|
||||
#endif
|
||||
|
||||
#if !defined (CH32X03x)
|
||||
#define DEBUG_PIN PA8
|
||||
|
||||
#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */
|
||||
#define UEP_SIZE 64
|
||||
|
||||
#define DEF_UEP_IN 0x80
|
||||
#define DEF_UEP_OUT 0x00
|
||||
#define DEF_UEP_BUSY 0x01
|
||||
#define DEF_UEP_FREE 0x00
|
||||
|
||||
#define DEF_UEP0 0
|
||||
#define DEF_UEP1 1
|
||||
#define DEF_UEP2 2
|
||||
#define DEF_UEP3 3
|
||||
#define DEF_UEP4 4
|
||||
#define DEF_UEP5 5
|
||||
#define DEF_UEP6 6
|
||||
#define DEF_UEP7 7
|
||||
#define UNUM_EP 8
|
||||
|
||||
#define USBFS_UEP_T_RES_MASK MASK_UEP_T_RES
|
||||
#define USBFS_UEP_T_RES_ACK UEP_T_RES_ACK
|
||||
#define USBFS_UEP_T_RES_NAK UEP_T_RES_NAK
|
||||
#define USBFS_UEP_T_TOG RB_UEP_T_TOG
|
||||
#define USBFS_UEP_T_RES_STALL UEP_T_RES_STALL
|
||||
|
||||
#define USBFS_UEP_R_RES_MASK MASK_UEP_R_RES
|
||||
#define USBFS_UEP_R_RES_ACK UEP_R_RES_ACK
|
||||
#define USBFS_UEP_R_RES_NAK UEP_R_RES_NAK
|
||||
#define USBFS_UEP_R_TOG RB_UEP_R_TOG
|
||||
#define USBFS_UEP_R_RES_STALL UEP_R_RES_STALL
|
||||
|
||||
#define USBFS_UDA_GP_BIT RB_UDA_GP_BIT
|
||||
#define USBFS_UMS_SUSPEND RB_UMS_SUSPEND
|
||||
|
||||
#define USBFS_UC_RESET_SIE RB_UC_RESET_SIE
|
||||
#define USBFS_UC_CLR_ALL RB_UC_CLR_ALL
|
||||
#define USBFS_UIE_SUSPEND RB_UIE_SUSPEND
|
||||
#define USBFS_UIE_TRANSFER RB_UIE_TRANSFER
|
||||
#define USBFS_UIE_BUS_RST RB_UIE_BUS_RST
|
||||
#define USBFS_UC_INT_BUSY RB_UC_INT_BUSY
|
||||
#define USBFS_UC_DMA_EN RB_UC_DMA_EN
|
||||
#define USBFS_UC_DEV_PU_EN RB_UC_DEV_PU_EN
|
||||
|
||||
#endif
|
||||
|
||||
#define USBFS_UD_PORT_EN RB_UD_PORT_EN
|
||||
#define USBFS_UD_PD_DIS RB_UD_PD_DIS
|
||||
|
||||
#define USBFS_UEP1_RX_EN RB_UEP1_RX_EN
|
||||
#define USBFS_UEP2_RX_EN RB_UEP2_RX_EN
|
||||
#define USBFS_UEP3_RX_EN RB_UEP3_RX_EN
|
||||
#define USBFS_UEP4_RX_EN RB_UEP4_RX_EN
|
||||
|
||||
#define USBFS_UEP1_TX_EN RB_UEP1_TX_EN
|
||||
#define USBFS_UEP2_TX_EN RB_UEP2_TX_EN
|
||||
#define USBFS_UEP3_TX_EN RB_UEP3_TX_EN
|
||||
#define USBFS_UEP4_TX_EN RB_UEP4_TX_EN
|
||||
|
||||
#define CHECK_USBFS_UEP_AUTO_TOG RB_UEP_AUTO_TOG
|
||||
#define CHECK_USBFS_UEP_T_AUTO_TOG RB_UEP_AUTO_TOG
|
||||
// #define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
||||
|
||||
#define USBFS ((USBFS_TypeDef *)USBFS_BASE)
|
||||
|
||||
#ifdef CH32X03x
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
||||
#define DEBUG_PIN PB12
|
||||
#define USB_IRQn USBFS_IRQn
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_PIN PB0
|
||||
|
||||
#define USBFS ((USBOTG_FS_TypeDef *)USBFS_BASE)
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_RX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
||||
|
||||
#define CHECK_USBFS_UEP_T_AUTO_TOG USBOTG_UEP_T_AUTO_TOG
|
||||
#define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
||||
|
||||
#define USBFS_UEP_T_RES_MASK USBOTG_UEP_T_RES_MASK
|
||||
#define USBFS_UEP_T_RES_ACK USBOTG_UEP_T_RES_ACK
|
||||
#define USBFS_UEP_T_RES_NAK USBOTG_UEP_T_RES_NAK
|
||||
#define USBFS_UEP_T_TOG USBOTG_UEP_T_TOG
|
||||
#define USBFS_UEP_T_RES_STALL USBOTG_UEP_T_RES_STALL
|
||||
|
||||
#define USBFS_UEP_R_RES_MASK USBOTG_UEP_R_RES_MASK
|
||||
#define USBFS_UEP_R_RES_ACK USBOTG_UEP_R_RES_ACK
|
||||
#define USBFS_UEP_R_RES_NAK USBOTG_UEP_R_RES_NAK
|
||||
#define USBFS_UEP_R_TOG USBOTG_UEP_R_TOG
|
||||
#define USBFS_UEP_R_RES_STALL USBOTG_UEP_R_RES_STALL
|
||||
|
||||
// #define USBFS_UDA_GP_BIT USBOTG_UDA_GP_BIT
|
||||
#define USBFS_UMS_SUSPEND USBOTG_UMS_SUSPEND
|
||||
#define USBFS_UEP1_RX_EN USBOTG_UEP1_RX_EN
|
||||
#define USBFS_UEP2_RX_EN USBOTG_UEP2_RX_EN
|
||||
#define USBFS_UEP3_RX_EN USBOTG_UEP3_RX_EN
|
||||
#define USBFS_UEP4_RX_EN USBOTG_UEP4_RX_EN
|
||||
|
||||
#define USBFS_UEP1_TX_EN USBOTG_UEP1_TX_EN
|
||||
#define USBFS_UEP2_TX_EN USBOTG_UEP2_TX_EN
|
||||
#define USBFS_UEP3_TX_EN USBOTG_UEP3_TX_EN
|
||||
#define USBFS_UEP4_TX_EN USBOTG_UEP4_TX_EN
|
||||
|
||||
#define USBFS_UC_RESET_SIE USBOTG_UC_RESET_SIE
|
||||
#define USBFS_UC_CLR_ALL USBOTG_UC_CLR_ALL
|
||||
#define USBFS_UIE_SUSPEND USBOTG_UIE_SUSPEND
|
||||
#define USBFS_UIE_TRANSFER USBOTG_UIE_TRANSFER
|
||||
#define USBFS_UIE_BUS_RST USBOTG_UIE_BUS_RST
|
||||
#define USBFS_UC_INT_BUSY USBOTG_UC_INT_BUSY
|
||||
#define USBFS_UC_DMA_EN USBOTG_UC_DMA_EN
|
||||
#define USBFS_UC_DEV_PU_EN USBOTG_UC_DEV_PU_EN
|
||||
#define USBFS_UD_PD_DIS USBOTG_UD_PD_DIS
|
||||
#define USBFS_UD_PORT_EN USBOTG_UD_PORT_EN
|
||||
|
||||
#ifdef CH32V30x_D8C
|
||||
#define USB_IRQn OTG_FS_IRQn
|
||||
#else
|
||||
#define USB_IRQn USBHD_IRQn
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Mask for the combined USBFS->INT_FG + USBFS->INT_ST
|
||||
#define CRB_UIS_IS_NAK (1<<7)
|
||||
#define CRB_U_TOG_OK (1<<6)
|
||||
#define CRB_U_SIE_FREE (1<<5)
|
||||
#define CRB_UIF_FIFO_OV (1<<4)
|
||||
#define CRB_UIF_HST_SOF (1<<3)
|
||||
#define CRB_UIF_SUSPEND (1<<2)
|
||||
#define CRB_UIF_TRANSFER (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
|
||||
#if defined(CH5xx) || defined(CH32X03x) || defined(CH32V10x)
|
||||
#define CRB_UIF_SETUP_ACT (1<<15)
|
||||
#endif
|
||||
#define CRB_UIS_TOG_OK (1<<14)
|
||||
#define CMASK_UIS_TOKEN (3<<12)
|
||||
#define CMASK_UIS_ENDP (0xf<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_SOF 0x1
|
||||
#define CUIS_TOKEN_IN 0x2
|
||||
#define CUIS_TOKEN_SETUP 0x3
|
||||
|
||||
#define USBFS_PACKET_SIZE 64
|
||||
|
||||
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
||||
|
||||
struct _USBState;
|
||||
|
||||
// Provided functions:
|
||||
int USBFSSetup();
|
||||
uint8_t USBFS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||
static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
|
||||
static inline int USBFS_SendEndpoint( int endp, int len );
|
||||
static inline int USBFS_SendACK( int endp, int tx );
|
||||
static inline int USBFS_SendNAK( int endp, int tx );
|
||||
|
||||
#if FUSB_USE_DMA7_COPY
|
||||
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len );
|
||||
static inline void copyBufferComplete();
|
||||
#endif
|
||||
|
||||
// Implement the following:
|
||||
#if FUSB_HID_USER_REPORTS
|
||||
__USBFS_FUN_ATTRIBUTE int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
__USBFS_FUN_ATTRIBUTE int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
#if FUSB_USER_HANDLERS
|
||||
__USBFS_FUN_ATTRIBUTE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__USBFS_FUN_ATTRIBUTE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__USBFS_FUN_ATTRIBUTE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBFS_EP_OFF = 0,
|
||||
USBFS_EP_RX = -1,
|
||||
USBFS_EP_TX = 1,
|
||||
} USBFS_EP_mode;
|
||||
|
||||
#ifndef FUSB_EP1_MODE
|
||||
#define FUSB_EP1_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP2_MODE
|
||||
#define FUSB_EP2_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP3_MODE
|
||||
#define FUSB_EP3_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP4_MODE
|
||||
#define FUSB_EP4_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP5_MODE
|
||||
#define FUSB_EP5_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP6_MODE
|
||||
#define FUSB_EP6_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP7_MODE
|
||||
#define FUSB_EP7_MODE 0
|
||||
#endif
|
||||
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
// Setup Request
|
||||
uint8_t USBFS_SetupReqCode;
|
||||
uint8_t USBFS_SetupReqType;
|
||||
uint16_t USBFS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBFS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint8_t USBFS_DevConfig;
|
||||
uint8_t USBFS_DevAddr;
|
||||
uint8_t USBFS_DevSleepStatus;
|
||||
uint8_t USBFS_DevEnumStatus;
|
||||
|
||||
uint8_t* pCtrlPayloadPtr;
|
||||
|
||||
uint8_t ENDPOINTS[FUSB_CONFIG_EPS][64];
|
||||
USBFS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
||||
|
||||
#define CTRL0BUFF (USBFSCTX.ENDPOINTS[0])
|
||||
#define pUSBFS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||
|
||||
#if FUSB_HID_INTERFACES > 0
|
||||
uint8_t USBFS_HidIdle[FUSB_HID_INTERFACES];
|
||||
uint8_t USBFS_HidProtocol[FUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBFS_Endp_Busy[FUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBFS_errata_dont_send_endpoint_in_window;
|
||||
};
|
||||
|
||||
extern struct _USBState USBFSCTX;
|
||||
|
||||
#include "fsusb.c"
|
||||
|
||||
#endif
|
||||
|
||||
1022
inc/extralibs/hsusb.c
Normal file
1022
inc/extralibs/hsusb.c
Normal file
File diff suppressed because it is too large
Load diff
475
inc/extralibs/hsusb.h
Normal file
475
inc/extralibs/hsusb.h
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
#ifndef _HSUSB_H
|
||||
#define _HSUSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#if !defined(CH584_CH585) && !defined(CH32V205) && !defined(CH32H4xx) && !defined(CH32V30x) && !defined(CH565_CH569)
|
||||
#error "This lib doesn't work on this MCU"
|
||||
#endif
|
||||
|
||||
#if defined(CH32V30x) || defined(CH565_CH569)
|
||||
#define USBHS_IMPL 1
|
||||
// #elif defined(CH584_CH585) || defined(CH32V205) || defined(CH32H4xx)
|
||||
#else
|
||||
#define USBHS_IMPL 2
|
||||
#endif
|
||||
|
||||
#ifndef __HIGH_CODE
|
||||
#define __HIGH_CODE
|
||||
#endif
|
||||
|
||||
#ifndef USBHS_BASE
|
||||
#if defined(CH32V30x) || defined(CH32V205)
|
||||
#define USBHS_BASE (0x40023400)
|
||||
#elif defined(CH32H4xx)
|
||||
#define USBHS_BASE (0x40030000)
|
||||
#else
|
||||
#define USBHS_BASE (0x40009000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (USBHS_IMPL==1)
|
||||
#if (FUNCONF_USE_HSI) && !defined(FUSB_SOF_HSITRIM)
|
||||
#define FUSB_SOF_HSITRIM 1
|
||||
#endif
|
||||
#define TICKS_PER_HSITRIM (FUNCONF_PLL_MULTIPLIER * 20000 * 125) / 1000000 // SOF is sent every 125uS, each HSITRIM changes HSI by 20kHz
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t HOST_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint8_t SUSPEND;
|
||||
__IO uint8_t RESERVED0;
|
||||
__IO uint8_t SPEED_TYPE;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t RESERVED1;
|
||||
__IO uint32_t UEP_CONFIG;
|
||||
__IO uint32_t UEP_TYPE;
|
||||
__IO uint32_t UEP_BUF_MODE;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_RX_DMA;
|
||||
__IO uint32_t UEP2_RX_DMA;
|
||||
__IO uint32_t UEP3_RX_DMA;
|
||||
__IO uint32_t UEP4_RX_DMA;
|
||||
__IO uint32_t UEP5_RX_DMA;
|
||||
__IO uint32_t UEP6_RX_DMA;
|
||||
__IO uint32_t UEP7_RX_DMA;
|
||||
__IO uint32_t UEP8_RX_DMA;
|
||||
__IO uint32_t UEP9_RX_DMA;
|
||||
__IO uint32_t UEP10_RX_DMA;
|
||||
__IO uint32_t UEP11_RX_DMA;
|
||||
__IO uint32_t UEP12_RX_DMA;
|
||||
__IO uint32_t UEP13_RX_DMA;
|
||||
__IO uint32_t UEP14_RX_DMA;
|
||||
__IO uint32_t UEP15_RX_DMA;
|
||||
__IO uint32_t UEP1_TX_DMA;
|
||||
__IO uint32_t UEP2_TX_DMA;
|
||||
__IO uint32_t UEP3_TX_DMA;
|
||||
__IO uint32_t UEP4_TX_DMA;
|
||||
__IO uint32_t UEP5_TX_DMA;
|
||||
__IO uint32_t UEP6_TX_DMA;
|
||||
__IO uint32_t UEP7_TX_DMA;
|
||||
__IO uint32_t UEP8_TX_DMA;
|
||||
__IO uint32_t UEP9_TX_DMA;
|
||||
__IO uint32_t UEP10_TX_DMA;
|
||||
__IO uint32_t UEP11_TX_DMA;
|
||||
__IO uint32_t UEP12_TX_DMA;
|
||||
__IO uint32_t UEP13_TX_DMA;
|
||||
__IO uint32_t UEP14_TX_DMA;
|
||||
__IO uint32_t UEP15_TX_DMA;
|
||||
__IO uint16_t UEP0_MAX_LEN;
|
||||
__IO uint16_t RESERVED2;
|
||||
__IO uint16_t UEP1_MAX_LEN;
|
||||
__IO uint16_t RESERVED3;
|
||||
__IO uint16_t UEP2_MAX_LEN;
|
||||
__IO uint16_t RESERVED4;
|
||||
__IO uint16_t UEP3_MAX_LEN;
|
||||
__IO uint16_t RESERVED5;
|
||||
__IO uint16_t UEP4_MAX_LEN;
|
||||
__IO uint16_t RESERVED6;
|
||||
__IO uint16_t UEP5_MAX_LEN;
|
||||
__IO uint16_t RESERVED7;
|
||||
__IO uint16_t UEP6_MAX_LEN;
|
||||
__IO uint16_t RESERVED8;
|
||||
__IO uint16_t UEP7_MAX_LEN;
|
||||
__IO uint16_t RESERVED9;
|
||||
__IO uint16_t UEP8_MAX_LEN;
|
||||
__IO uint16_t RESERVED10;
|
||||
__IO uint16_t UEP9_MAX_LEN;
|
||||
__IO uint16_t RESERVED11;
|
||||
__IO uint16_t UEP10_MAX_LEN;
|
||||
__IO uint16_t RESERVED12;
|
||||
__IO uint16_t UEP11_MAX_LEN;
|
||||
__IO uint16_t RESERVED13;
|
||||
__IO uint16_t UEP12_MAX_LEN;
|
||||
__IO uint16_t RESERVED14;
|
||||
__IO uint16_t UEP13_MAX_LEN;
|
||||
__IO uint16_t RESERVED15;
|
||||
__IO uint16_t UEP14_MAX_LEN;
|
||||
__IO uint16_t RESERVED16;
|
||||
__IO uint16_t UEP15_MAX_LEN;
|
||||
__IO uint16_t RESERVED17;
|
||||
__IO uint16_t UEP0_T_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_T_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_T_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_T_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_T_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_T_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_T_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_T_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint16_t UEP8_T_LEN;
|
||||
__IO uint8_t UEP8_TX_CTRL;
|
||||
__IO uint8_t UEP8_RX_CTRL;
|
||||
__IO uint16_t UEP9_T_LEN;
|
||||
__IO uint8_t UEP9_TX_CTRL;
|
||||
__IO uint8_t UEP9_RX_CTRL;
|
||||
__IO uint16_t UEP10_T_LEN;
|
||||
__IO uint8_t UEP10_TX_CTRL;
|
||||
__IO uint8_t UEP10_RX_CTRL;
|
||||
__IO uint16_t UEP11_T_LEN;
|
||||
__IO uint8_t UEP11_TX_CTRL;
|
||||
__IO uint8_t UEP11_RX_CTRL;
|
||||
__IO uint16_t UEP12_T_LEN;
|
||||
__IO uint8_t UEP12_TX_CTRL;
|
||||
__IO uint8_t UEP12_RX_CTRL;
|
||||
__IO uint16_t UEP13_T_LEN;
|
||||
__IO uint8_t UEP13_TX_CTRL;
|
||||
__IO uint8_t UEP13_RX_CTRL;
|
||||
__IO uint16_t UEP14_T_LEN;
|
||||
__IO uint8_t UEP14_TX_CTRL;
|
||||
__IO uint8_t UEP14_RX_CTRL;
|
||||
__IO uint16_t UEP15_T_LEN;
|
||||
__IO uint8_t UEP15_TX_CTRL;
|
||||
__IO uint8_t UEP15_RX_CTRL;
|
||||
} USBHS_TypeDef;
|
||||
|
||||
#define USBHS_CHECK_NAK_RX (USBHS->INT_ST & 0x80)
|
||||
|
||||
#define CRB_U_IS_NAK (1<<7)
|
||||
#define CTOG_MATCH_SYNC (1<<6)
|
||||
#define CRB_UIF_SETUP_ACT (1<<5) // CRB_U_SIE_FREE on USBFS
|
||||
#define CRB_UIF_FIFO_OV (1<<4)
|
||||
#define CRB_UIF_HST_SOF (1<<3)
|
||||
#define CRB_UIF_SUSPEND (1<<2)
|
||||
#define CRB_UIF_TRANSFER (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
#define CSETUP_ACT (1<<15)
|
||||
#define CRB_UIS_TOG_OK (1<<14)
|
||||
#define CMASK_UIS_TOKEN (3<<12)
|
||||
#define CMASK_UIS_ENDP (0xf<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_SOF 0x1
|
||||
#define CUIS_TOKEN_IN 0x2
|
||||
#define CUIS_TOKEN_SETUP 0x3
|
||||
|
||||
#define UEP_TX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<n))
|
||||
#define UEP_RX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<(n+16)))
|
||||
|
||||
#define USBHS_DONE_TX(n)
|
||||
#define USBHS_DONE_RX(n)
|
||||
|
||||
#elif (USBHS_IMPL==2)
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t BASE_MODE;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint8_t WAKE_CTRL;
|
||||
__IO uint8_t TEST_MODE;
|
||||
__IO uint16_t LPM_DATA;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint16_t BUS;
|
||||
__IO uint16_t UEP_TX_EN;
|
||||
__IO uint16_t UEP_RX_EN;
|
||||
__IO uint16_t UEP_T_TOG_AUTO;
|
||||
__IO uint16_t UEP_R_TOG_AUTO;
|
||||
__IO uint8_t UEP_T_BURST;
|
||||
__IO uint8_t UEP_T_BURST_MODE;
|
||||
__IO uint8_t UEP_R_BURST;
|
||||
__IO uint8_t UEP_R_RES_MODE;
|
||||
__IO uint32_t UEP_AF_MODE;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_RX_DMA;
|
||||
__IO uint32_t UEP2_RX_DMA;
|
||||
__IO uint32_t UEP3_RX_DMA;
|
||||
__IO uint32_t UEP4_RX_DMA;
|
||||
__IO uint32_t UEP5_RX_DMA;
|
||||
__IO uint32_t UEP6_RX_DMA;
|
||||
__IO uint32_t UEP7_RX_DMA;
|
||||
__IO uint32_t UEP1_TX_DMA;
|
||||
__IO uint32_t UEP2_TX_DMA;
|
||||
__IO uint32_t UEP3_TX_DMA;
|
||||
__IO uint32_t UEP4_TX_DMA;
|
||||
__IO uint32_t UEP5_TX_DMA;
|
||||
__IO uint32_t UEP6_TX_DMA;
|
||||
__IO uint32_t UEP7_TX_DMA;
|
||||
__IO uint32_t UEP0_MAX_LEN;
|
||||
__IO uint32_t UEP1_MAX_LEN;
|
||||
__IO uint32_t UEP2_MAX_LEN;
|
||||
__IO uint32_t UEP3_MAX_LEN;
|
||||
__IO uint32_t UEP4_MAX_LEN;
|
||||
__IO uint32_t UEP5_MAX_LEN;
|
||||
__IO uint32_t UEP6_MAX_LEN;
|
||||
__IO uint32_t UEP7_MAX_LEN;
|
||||
__IO uint16_t UEP0_RX_LEN;
|
||||
__IO uint16_t reserved;
|
||||
__IO uint16_t UEP1_RX_LEN;
|
||||
__IO uint16_t UEP1_R_SIZE;
|
||||
__IO uint16_t UEP2_RX_LEN;
|
||||
__IO uint16_t UEP2_R_SIZE;
|
||||
__IO uint16_t UEP3_RX_LEN;
|
||||
__IO uint16_t UEP3_R_SIZE;
|
||||
__IO uint16_t UEP4_RX_LEN;
|
||||
__IO uint16_t UEP4_R_SIZE;
|
||||
__IO uint16_t UEP5_RX_LEN;
|
||||
__IO uint16_t UEP5_R_SIZE;
|
||||
__IO uint16_t UEP6_RX_LEN;
|
||||
__IO uint16_t UEP6_R_SIZE;
|
||||
__IO uint16_t UEP7_RX_LEN;
|
||||
__IO uint16_t UEP7_R_SIZE;
|
||||
__IO uint16_t UEP0_T_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_T_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_T_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_T_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_T_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_T_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_T_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_T_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint16_t UEP_T_ISO;
|
||||
__IO uint16_t UEP_R_ISO;
|
||||
} USBHS_TypeDef;
|
||||
|
||||
#define USBHS_CHECK_NAK_RX (USBHS->UEP0_RX_CTRL & (1<<6))
|
||||
|
||||
#define UEP_RX_LEN(n) (((volatile uint16_t*)&USBHS->UEP1_RX_LEN)[(n-1)*2])
|
||||
#define UEP_TX_EN(n) USBHS->UEP_TX_EN |= ((uint16_t)(1<<n))
|
||||
#define UEP_RX_EN(n) USBHS->UEP_RX_EN |= ((uint16_t)(1<<n))
|
||||
|
||||
#define DEBUG_PIN PB17
|
||||
|
||||
#define TEST_ENABLE 0x01
|
||||
#define TEST_MASK 0x0F
|
||||
|
||||
#define USBHS_UMS_SUSPEND (1<<1)
|
||||
|
||||
#define USBHS_UC_RESET_SIE (1<<1)
|
||||
#define USBHS_UC_CLR_ALL (1<<2)
|
||||
#define USBHS_UC_DMA_EN (1<<4)
|
||||
#define USBHS_UC_PORT_EN (1<<5)
|
||||
|
||||
#define USBHS_UIE_SUSPEND (1<<1)
|
||||
#define USBHS_UIE_TRANSFER (1<<4)
|
||||
#define USBHS_UIE_BUS_RST (1<<0)
|
||||
|
||||
// Mask for the combined USBHS->INT_FG + USBHS->INT_ST
|
||||
#define CRB_UIF_FIFO_OV (1<<7)
|
||||
#define CRB_UIF_LINK_RDY (1<<6)
|
||||
#define CRB_UIF_RX_SOF (1<<5)
|
||||
#define CRB_UIF_TRANSFER (1<<4)
|
||||
#define CRB_UIF_LPM_ACT (1<<3)
|
||||
#define CRB_UIF_BUS_SLEEP (1<<2)
|
||||
#define CRB_UIF_SUSPEND (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
|
||||
#define CMASK_UIS_TOKEN (1<<12)
|
||||
#define CMASK_UIS_ENDP (7<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_IN 0x1
|
||||
|
||||
#define USBHS_DONE_TX(n) UEP_CTRL_TX(n) &= ~(USBHS_UEP_T_DONE)
|
||||
#define USBHS_DONE_RX(n) UEP_CTRL_RX(n) &= ~(USBHS_UEP_R_DONE)
|
||||
|
||||
#endif
|
||||
|
||||
#define USBHS_SPEED_TYPE_MASK ((uint8_t)(0x03))
|
||||
|
||||
#define USBHS_DEF_UEP_IN 0x80
|
||||
#define USBHS_DEF_UEP_OUT 0x00
|
||||
#define USBHS_DEF_UEP_BUSY 0x01
|
||||
#define USBHS_DEF_UEP_FREE 0x00
|
||||
|
||||
#define USBHS_NUM_EP 8
|
||||
#define USBHS_DEF_UEP0 0
|
||||
#define USBHS_DEF_UEP1 1
|
||||
#define USBHS_DEF_UEP2 2
|
||||
#define USBHS_DEF_UEP3 3
|
||||
#define USBHS_DEF_UEP4 4
|
||||
#define USBHS_DEF_UEP5 5
|
||||
#define USBHS_DEF_UEP6 6
|
||||
#define USBHS_DEF_UEP7 7
|
||||
#define USBHS_DEF_UEP8 8
|
||||
#define USBHS_DEF_UEP9 9
|
||||
#define USBHS_DEF_UEP10 10
|
||||
#define USBHS_DEF_UEP11 11
|
||||
#define USBHS_DEF_UEP12 12
|
||||
#define USBHS_DEF_UEP13 13
|
||||
#define USBHS_DEF_UEP14 14
|
||||
#define USBHS_DEF_UEP15 15
|
||||
|
||||
#define USBHS_DEF_UEP0_SIZE 64
|
||||
|
||||
#ifndef FUSB_EP_SIZE
|
||||
#define USBHS_UEP_SIZE 64
|
||||
#else
|
||||
#define USBHS_UEP_SIZE FUSB_EP_SIZE
|
||||
#endif
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBHS->UEP0_T_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBHS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBHS->UEP0_RX_CTRL)[n*4])
|
||||
#define UEP_DMA_RX(n) (((volatile uint32_t*)&USBHS->UEP0_DMA)[n])
|
||||
#define UEP_DMA_TX(n) (((volatile uint32_t*)&USBHS->UEP1_TX_DMA)[n-1])
|
||||
|
||||
#define USBHS ((USBHS_TypeDef *)USBHS_BASE)
|
||||
|
||||
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
||||
|
||||
struct _USBState;
|
||||
|
||||
// Provided functions:
|
||||
int USBHSSetup();
|
||||
static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len, int copy);
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp );
|
||||
static inline int USBHS_SendEndpoint( int endp, int len );
|
||||
static inline int USBHS_SendACK( int endp, int tx );
|
||||
static inline int USBHS_SendNAK( int endp, int tx );
|
||||
|
||||
// Implement the following:
|
||||
#if FUSB_HID_USER_REPORTS
|
||||
__HIGH_CODE int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
__HIGH_CODE int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
|
||||
#if FUSB_USER_HANDLERS
|
||||
__HIGH_CODE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__HIGH_CODE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__HIGH_CODE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||
#endif
|
||||
|
||||
#if FUSB_OUT_FLOW_CONTROL > 0
|
||||
void USBHS_RxReady(int endp);
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_SPEED_FULL = 0,
|
||||
USB_SPEED_HIGH = 1,
|
||||
USB_SPEED_LOW = 2,
|
||||
} USB_SPEED_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBHS_EP_OFF = 0,
|
||||
USBHS_EP_RX = -1,
|
||||
USBHS_EP_TX = 1,
|
||||
} USBHS_EP_mode;
|
||||
|
||||
#ifndef FUSB_EP1_MODE
|
||||
#define FUSB_EP1_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP2_MODE
|
||||
#define FUSB_EP2_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP3_MODE
|
||||
#define FUSB_EP3_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP4_MODE
|
||||
#define FUSB_EP4_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP5_MODE
|
||||
#define FUSB_EP5_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP6_MODE
|
||||
#define FUSB_EP6_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP7_MODE
|
||||
#define FUSB_EP7_MODE 0
|
||||
#endif
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
__attribute__ ((aligned(4))) uint8_t CTRL0BUFF[64];
|
||||
__attribute__ ((aligned(4))) uint8_t ENDPOINTS[FUSB_CONFIG_EPS-1][FUSB_EP_SIZE];
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint8_t USBHS_DevConfig;
|
||||
uint8_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
|
||||
uint8_t* pCtrlPayloadPtr;
|
||||
|
||||
|
||||
USBHS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
||||
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)USBHSCTX.CTRL0BUFF)
|
||||
|
||||
#if FUSB_HID_INTERFACES > 0
|
||||
uint8_t USBHS_HidIdle[FUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[FUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBHS_Endp_Busy[FUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBHS_errata_dont_send_endpoint_in_window;
|
||||
volatile uint64_t USBHS_sof_timestamp;
|
||||
};
|
||||
|
||||
extern struct _USBState USBHSCTX;
|
||||
|
||||
#include "hsusb.c"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -131,6 +131,7 @@ void USBHS_IRQHandler(void)
|
|||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case HID_SET_IDLE:
|
||||
if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
|
||||
HSUSBCTX.USBHS_HidIdle[ USBHS_SetupReqIndex ] = (uint8_t)( USBHS_IndexValue >> 8 );
|
||||
|
|
@ -189,6 +190,7 @@ void USBHS_IRQHandler(void)
|
|||
goto sendstall;
|
||||
}
|
||||
|
||||
|
||||
/* Copy Descriptors to Endp0 DMA buffer */
|
||||
int totalLen = USBHS_SetupReqLen;
|
||||
if( totalLen > len )
|
||||
|
|
@ -341,6 +343,7 @@ void USBHS_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/* end-point 0 data Tx/Rx */
|
||||
if( USBHS_SetupReqType & DEF_UEP_IN )
|
||||
|
|
@ -372,7 +375,8 @@ void USBHS_IRQHandler(void)
|
|||
// if one request not support, return stall. Stall means permanent error.
|
||||
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_STALL;
|
||||
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_STALL;
|
||||
replycomplete:;
|
||||
replycomplete:
|
||||
;
|
||||
}
|
||||
if( intfgst & ( CRB_UIF_TRANSFER ) )
|
||||
{
|
||||
|
|
@ -417,6 +421,7 @@ void USBHS_IRQHandler(void)
|
|||
}
|
||||
else if ( ( ctx->USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
||||
{
|
||||
|
||||
#if HUSB_HID_USER_REPORTS
|
||||
len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen;
|
||||
if( len && HSUSBCTX.USBHS_SetupReqCode == HID_GET_REPORT )
|
||||
|
|
@ -550,16 +555,21 @@ void USBHS_IRQHandler(void)
|
|||
|
||||
void USBHS_InternalFinishSetup()
|
||||
{
|
||||
|
||||
// To reconfigure your endpoints for TX/RX do it here.
|
||||
|
||||
#if HUSB_CONFIG_EPS > 5
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN | USBHS_UEP5_R_EN;
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
||||
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN | USBHS_UEP5_R_EN;
|
||||
#elif HUSB_CONFIG_EPS > 4
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN;
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
||||
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN;
|
||||
#elif HUSB_CONFIG_EPS > 3
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN;
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
||||
| USBHS_UEP2_T_EN | USBHS_UEP3_T_EN;
|
||||
#elif HUSB_CONFIG_EPS > 2
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN;
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN
|
||||
| USBHS_UEP2_T_EN;
|
||||
#elif HUSB_CONFIG_EPS > 1
|
||||
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN;
|
||||
#else
|
||||
|
|
@ -649,3 +659,5 @@ int HSUSBSetup()
|
|||
// Go on-bus.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
|
||||
*/
|
||||
|
||||
#include "ch32fun.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_defines.h"
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
|
|
@ -59,6 +59,7 @@ void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
|||
|
||||
extern struct _USBState HSUSBCTX;
|
||||
|
||||
|
||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
||||
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||
|
|
|
|||
852
inc/extralibs/iSLER.h
Normal file
852
inc/extralibs/iSLER.h
Normal file
|
|
@ -0,0 +1,852 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CH570_CH572
|
||||
#define CRCPOLY1 BB2
|
||||
#define ACCESSADDRESS1 BB3
|
||||
#define RSSI BB12 // ? couldn't find it, not sure
|
||||
#define CTRL_TX BB13
|
||||
#define CRCINIT2 BB22
|
||||
#define CRCPOLY2 BB23
|
||||
#define ACCESSADDRESS2 BB24
|
||||
#define TMR LL25
|
||||
#define TXBUF LL30
|
||||
#define RXBUF LL31
|
||||
#define CTRL_MOD_RFSTOP 0xfffff8ff
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffcffff) | 0x20000)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffcffff) | 0x10000)
|
||||
#define DEVSETMODE_TUNE 0x0558
|
||||
#define DEVSETMODE_TX 0x0258
|
||||
#define DEVSETMODE_RX 0x0158
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xfffffcff) | 0x100)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xfffffcff)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX 0x1000000
|
||||
#elif defined(CH571_CH573)
|
||||
#define TXBUF DMA4
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12 // ? couldn't find it, not sure
|
||||
#define TMR LL24
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x180000
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_TUNE 0x5d
|
||||
#define DEVSETMODE_TX 0x5a
|
||||
#define DEVSETMODE_RX 0x59
|
||||
#define CTRL_CFG_PHY_1M (BB->CTRL_CFG | 0x10000000)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX (BB->CTRL_CFG & 0xefffffff)
|
||||
#elif defined(CH582_CH583)
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x880000
|
||||
#define CTRL_TX_TXPOWER 0x80010e78
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffe7f) | 0x100)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffe7f) | 0x80)
|
||||
#define DEVSETMODE_TUNE 0x00dd
|
||||
#define DEVSETMODE_TX 0x00da
|
||||
#define DEVSETMODE_RX 0x00d9
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xffff0fff) | 0x1000)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xffff0fff)
|
||||
#define CTRL_CFG_PHY_CODED ((BB->CTRL_CFG & 0xffff0fff) | 0x2000)
|
||||
#define LL_STATUS_TX 0x2000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#elif (defined(CH584_CH585) || defined(CH591_CH592))
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL30
|
||||
#define RXBUF LL31
|
||||
#define CTRL_MOD_RFSTOP 0xfffff8ff
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffcff) | 0x280)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffcff) | 0x100)
|
||||
#define DEVSETMODE_TUNE 0x0558
|
||||
#define DEVSETMODE_TX 0x0258
|
||||
#define DEVSETMODE_RX 0x0158
|
||||
#define CTRL_CFG_PHY_1M (BB->CTRL_CFG & 0xffffff7f)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG | 0x80)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#elif defined(CH32V20x)
|
||||
#define CH32V208
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x100000
|
||||
#define CTRL_TX_TXPOWER 0x80010ec8
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffe7f) | 0x100)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffe7f) | 0x80)
|
||||
#define DEVSETMODE_TUNE 0x5d
|
||||
#define DEVSETMODE_TX 0x5a
|
||||
#define DEVSETMODE_RX 0x59
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xffff0fff) | 0x1000)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xffff0fff)
|
||||
#define CTRL_CFG_PHY_CODED ((BB->CTRL_CFG & 0xffff0fff) | 0x2000)
|
||||
#define LL_STATUS_TX 0x2000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#else
|
||||
#error "MCU_TARGET selected in Makefile is not supported"
|
||||
#endif
|
||||
|
||||
#ifdef CH32V208
|
||||
#define BB_BASE (0x40024100) // Baseband, digital part of the PHY
|
||||
#define LL_BASE (0x40024200) // Link Layer, MAC
|
||||
#define RF_BASE (0x40025000) // Radio frontend, analog part of the PHY
|
||||
#else
|
||||
#define DMA_BASE (0x4000c000)
|
||||
#define BB_BASE (0x4000c100)
|
||||
#define LL_BASE (0x4000c200)
|
||||
#define RF_BASE (0x4000d000)
|
||||
#endif
|
||||
|
||||
#define DMA ((DMA_Type *) DMA_BASE)
|
||||
#define BB ((BB_Type *) BB_BASE)
|
||||
#define LL ((LL_Type *) LL_BASE)
|
||||
#define RF ((RF_Type *) RF_BASE)
|
||||
|
||||
#ifdef CH571_CH573
|
||||
typedef struct {
|
||||
volatile uint32_t DMA0;
|
||||
volatile uint32_t DMA1;
|
||||
volatile uint32_t DMA2;
|
||||
volatile uint32_t DMA3;
|
||||
volatile uint32_t DMA4;
|
||||
volatile uint32_t DMA5;
|
||||
volatile uint32_t DMA6;
|
||||
volatile uint32_t DMA7;
|
||||
} DMA_Type;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// bits 0..5 = Channel
|
||||
// bit 6 = disable whitening.
|
||||
// bit 8 = 1 during normal TX/operation, but clearing does not affect TX. Note: 0 at reset, set in software.
|
||||
// bit 9 = settable, but unknown effect.
|
||||
// bit 10 = 1 during normal TX/operation, but clearing does not affect TX. Note: 1 at reset, not touched in software.
|
||||
// bit 16 = cleared by firmware upon TX, but does not seem to have an effect on the TX.
|
||||
// bit 17 = settable, but unknown effect
|
||||
// bit 20 = settable, but unknown effect.
|
||||
// bit 24 = set at end of tx routine
|
||||
// bit 29-31 = settable, but unknown effect.
|
||||
volatile uint32_t CTRL_CFG;
|
||||
|
||||
volatile uint32_t CRCINIT1;
|
||||
volatile uint32_t BB2; // ch570/2: CRCPOLY1, [ch582/3 ch591/2]: ACCESSADDRESS1
|
||||
volatile uint32_t BB3; // ch570/2 ACCESSADDRESS1
|
||||
volatile uint32_t BB4;
|
||||
volatile uint32_t BB5;
|
||||
volatile uint32_t BB6;
|
||||
volatile uint32_t BB7;
|
||||
volatile uint32_t BB8;
|
||||
volatile uint32_t BB9;
|
||||
volatile uint32_t BB10;
|
||||
volatile uint32_t BB11; // ch582/3, ch584/5, ch591/2: CTRL_TX
|
||||
volatile uint32_t BB12;
|
||||
|
||||
// default, pre TX is a4000009
|
||||
// bit 0: Set normally, but cleared in software when TXing (maybe a ready bit?)
|
||||
// bit 1: Unset normally, but cleared anyway by software when TXing (maybe a fault bit?)
|
||||
// bit 2: Disables TX.
|
||||
// bit 4: Normally 0, but, if set to 1, seems to increase preamble length.
|
||||
// bit 8: Normally 0, but, if set, no clear effect.
|
||||
// bit 9: Normally 0, but, if set, no clear effect.
|
||||
// bits 24-30: TX Power. Normally 0xA4
|
||||
// Oddly, bit 31 seems to maybe be always set.
|
||||
volatile uint32_t BB13; // ch570/2: CTRL_TX
|
||||
volatile uint32_t BB14;
|
||||
volatile uint32_t BB15;
|
||||
volatile uint32_t BB16;
|
||||
volatile uint32_t BB17;
|
||||
volatile uint32_t BB18;
|
||||
volatile uint32_t BB19;
|
||||
volatile uint32_t BB20;
|
||||
volatile uint32_t BB21;
|
||||
volatile uint32_t BB22; // ch570/2: CRCINIT2
|
||||
volatile uint32_t BB23; // ch570/2: CRCPOLY2
|
||||
volatile uint32_t BB24; // ch570/2: ACCESSADDRESS2
|
||||
} BB_Type;
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t LL0;
|
||||
volatile uint32_t LL1;
|
||||
volatile uint32_t STATUS;
|
||||
volatile uint32_t INT_EN;
|
||||
volatile uint32_t LL4;
|
||||
volatile uint32_t LL5;
|
||||
volatile uint32_t LL6;
|
||||
volatile uint32_t LL7;
|
||||
volatile uint32_t LL8;
|
||||
volatile uint32_t LL9;
|
||||
volatile uint32_t LL10;
|
||||
volatile uint32_t LL11;
|
||||
volatile uint32_t LL12;
|
||||
volatile uint32_t LL13;
|
||||
volatile uint32_t LL14;
|
||||
volatile uint32_t LL15;
|
||||
volatile uint32_t LL16;
|
||||
volatile uint32_t LL17;
|
||||
volatile uint32_t LL18;
|
||||
volatile uint32_t LL19;
|
||||
|
||||
// Controls a lot of higher-level functions.
|
||||
// For Tuning: 0x30558
|
||||
// For Idle: 0x30000
|
||||
// For Sending:0x30258
|
||||
// Bit 3: Somehow, enables BB
|
||||
// Bit 4: Normally 1, controls length/send times of BB, if unset, BB will double-send part of signals.
|
||||
// Bit 6: Normally 1, Unknown effect.
|
||||
// Bit 9: If 0, no output.
|
||||
// Bit 10: Somehow required for TX?
|
||||
// Bit 16-17: Normally 1, unknown effect. Seems to suppress odd carrier burst after message.
|
||||
volatile uint32_t CTRL_MOD;
|
||||
volatile uint32_t LL21;
|
||||
volatile uint32_t LL22;
|
||||
volatile uint32_t LL23;
|
||||
volatile uint32_t LL24; // ch571/3: TMR
|
||||
volatile uint32_t LL25; // ch570/2, ch582/3, ch591/2: TMR
|
||||
volatile uint32_t LL26;
|
||||
volatile uint32_t LL27;
|
||||
volatile uint32_t LL28; // ch582/3: TXBUF
|
||||
volatile uint32_t LL29; // ch582/3: RXBUF
|
||||
volatile uint32_t LL30; // ch570/2, ch591/2: TXBUF
|
||||
volatile uint32_t LL31; // ch570/2, ch591/2: RXBUF
|
||||
} LL_Type;
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t RF0;
|
||||
volatile uint32_t RF1;
|
||||
volatile uint32_t RF2;
|
||||
volatile uint32_t RF3;
|
||||
volatile uint32_t RF4;
|
||||
volatile uint32_t RF5;
|
||||
volatile uint32_t RF6;
|
||||
volatile uint32_t RF7;
|
||||
volatile uint32_t RF8;
|
||||
volatile uint32_t RF9;
|
||||
volatile uint32_t RF10;
|
||||
volatile uint32_t RF11;
|
||||
volatile uint32_t RF12;
|
||||
volatile uint32_t RF13;
|
||||
volatile uint32_t TXTUNE_CTRL;
|
||||
volatile uint32_t RF15;
|
||||
volatile uint32_t RF16;
|
||||
volatile uint32_t RF17;
|
||||
volatile uint32_t RF18;
|
||||
volatile uint32_t RF19;
|
||||
volatile uint32_t RF20;
|
||||
volatile uint32_t RF21;
|
||||
volatile uint32_t RF22;
|
||||
volatile uint32_t RF23;
|
||||
volatile uint32_t RF24;
|
||||
volatile uint32_t RF25;
|
||||
volatile uint32_t RF26;
|
||||
volatile uint32_t RF27;
|
||||
volatile uint32_t RF28;
|
||||
volatile uint32_t RF29;
|
||||
volatile uint32_t RF30;
|
||||
volatile uint32_t RF31;
|
||||
volatile uint32_t RF32;
|
||||
volatile uint32_t RF33;
|
||||
volatile uint32_t RF34;
|
||||
volatile uint32_t RF35;
|
||||
volatile uint32_t TXCTUNE_CO_CTRL;
|
||||
volatile uint32_t TXCTUNE_GA_CTRL;
|
||||
volatile uint32_t RF38;
|
||||
volatile uint32_t RXTUNE;
|
||||
volatile uint32_t TXCTUNE_CO[10];
|
||||
volatile uint32_t TXCTUNE_GA[3];
|
||||
} RF_Type;
|
||||
|
||||
uint8_t channel_map[] = {1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,0,11,39};
|
||||
#define CO_MID (uint8_t)(RF->TXTUNE_CTRL & ~0xffffffc0)
|
||||
#define GA_MID (uint8_t)((RF->TXTUNE_CTRL & ~0x80ffffff) >> 24)
|
||||
|
||||
#define PHY_1M 1
|
||||
#define PHY_2M 2
|
||||
#define PHY_S2 4
|
||||
#define PHY_S8 8
|
||||
|
||||
void DevSetMode(uint16_t mode);
|
||||
__attribute__((aligned(4))) uint32_t LLE_BUF[0x110];
|
||||
#ifdef CH571_CH573
|
||||
__attribute__((aligned(4))) uint32_t LLE_BUF2[0x110];
|
||||
#endif
|
||||
volatile uint32_t tuneFilter;
|
||||
volatile uint32_t tuneFilter2M;
|
||||
volatile uint32_t rx_ready;
|
||||
|
||||
|
||||
|
||||
#ifdef CH571_CH573
|
||||
__attribute__((interrupt))
|
||||
void BB_IRQHandler() {
|
||||
// printf("BB\n");
|
||||
if(BB->BB14 & (1<<6)) {
|
||||
BB->BB14 &= 0xffffff9f;
|
||||
}
|
||||
if(BB->BB14 & (1<<1)) {
|
||||
BB->BB14 = 0xfffffffd;
|
||||
BB->BB20 = 0x45;
|
||||
}
|
||||
if(BB->BB14 & (1<<4)) {
|
||||
BB->BB14 = 0xffffffef;
|
||||
BB->BB20 = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((interrupt))
|
||||
void LLE_IRQHandler() {
|
||||
// printf("LL\n");
|
||||
#ifdef CH571_CH573
|
||||
if(LL->STATUS & (1<<9)) {
|
||||
LL->TMR = 400;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 2;
|
||||
BB->CTRL_CFG |= 0x10000000;
|
||||
}
|
||||
LL->STATUS = 0;
|
||||
#elif defined(CH582_CH583)
|
||||
if((LL->STATUS & (1<<14)) && (LL->INT_EN & (1<<14))) {
|
||||
LL->LL26 = 0xffffffff;
|
||||
LL->STATUS = 0x4000;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LL->STATUS &= LL->INT_EN;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 1;
|
||||
}
|
||||
DevSetMode(0);
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
|
||||
#ifdef ISLER_CALLBACK
|
||||
ISLER_CALLBACK();
|
||||
#else
|
||||
rx_ready = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RFEND_Reset() {
|
||||
#ifdef CH571_CH573
|
||||
RF->RF3 |= 0x1000;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xffffefff;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x1000;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 1;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xfffffffe;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 1;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x100;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xfffffeff;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x100;
|
||||
ADD_N_NOPS(20);
|
||||
#elif defined(CH32V208)
|
||||
RF->RF3 = 0x1101;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 = 0;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 = 0x1101;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DevInit(uint8_t TxPower) {
|
||||
#ifdef CH571_CH573
|
||||
DMA->DMA4 = (uint32_t)LLE_BUF;
|
||||
DMA->DMA5 = (uint32_t)LLE_BUF;
|
||||
DMA->DMA6 = (uint32_t)LLE_BUF2;
|
||||
DMA->DMA7 = (uint32_t)LLE_BUF2;
|
||||
DMA->DMA2 |= 0x2000;
|
||||
DMA->DMA3 |= 0x2000;
|
||||
DMA->DMA2 |= 0x1000;
|
||||
DMA->DMA3 |= 0x1000;
|
||||
DMA->DMA0 |= 2;
|
||||
DMA->DMA0 |= 0x20;
|
||||
|
||||
LL->LL5 = 0x50;
|
||||
LL->LL7 = 10;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x50;
|
||||
LL->LL19 = 10;
|
||||
#elif defined(CH570_CH572) || defined(CH582_CH583) || defined(CH584_CH585) || defined(CH591_CH592)
|
||||
LL->LL5 = 0x8c;
|
||||
LL->LL7 = 0x76;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x8c;
|
||||
LL->LL19 = 0x76;
|
||||
#elif defined(CH32V208)
|
||||
LL->LL5 = 0x8c;
|
||||
LL->LL7 = 0x6c;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x8c;
|
||||
LL->LL19 = 0x6c;
|
||||
#endif
|
||||
|
||||
#ifdef CH570_CH572
|
||||
LL->LL11 = 0x6c;
|
||||
LL->LL15 = 0x6c;
|
||||
LL->LL1 = 0x78;
|
||||
LL->LL21 = 0;
|
||||
LL->INT_EN = 0x16000f;
|
||||
#elif defined(CH571_CH573)
|
||||
LL->LL11 = 0x3c;
|
||||
LL->LL15 = 0x3c;
|
||||
LL->LL22 = 0xf6;
|
||||
LL->INT_EN = 0xc303;
|
||||
NVIC->FIBADDRR = 0x20000000;
|
||||
NVIC->VTFADDR[2] = (uint32_t)LLE_IRQHandler -NVIC->FIBADDRR;
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
LL->LL11 = 0x3c;
|
||||
LL->LL15 = 0x3c;
|
||||
LL->INT_EN = 0xf00f;
|
||||
#elif defined(CH584_CH585)
|
||||
LL->LL11 = 0x6e;
|
||||
LL->LL15 = 0x6e;
|
||||
LL->LL1 &= 0xffffffe1;
|
||||
LL->LL21 = 0;
|
||||
LL->INT_EN = 0x1f000f;
|
||||
#elif defined(CH591_CH592)
|
||||
LL->LL6 = 0x78;
|
||||
LL->LL8 = 0xffffffff;
|
||||
LL->LL11 = 0x6e;
|
||||
LL->LL21 = 0x14;
|
||||
LL->INT_EN = 0x1f000f;
|
||||
#endif
|
||||
|
||||
LL->RXBUF = (uint32_t)LLE_BUF;
|
||||
LL->STATUS = 0xffffffff;
|
||||
RF->RF10 = 0x480;
|
||||
|
||||
#ifdef CH570_CH572
|
||||
RF->RF12 &= 0xfff9ffff;
|
||||
RF->RF12 |= 0x70000000;
|
||||
RF->RF15 = (RF->RF15 & 0xf8ffffff) | 0x2000000;
|
||||
RF->RF15 = (RF->RF15 & 0x1fffffff) | 0x40000000;
|
||||
RF->RF18 &= 0xfff8ffff;
|
||||
RF->RF20 = (RF->RF20 & 0xfffff8ff) | 0x300;
|
||||
RF->RF23 |= 0x70000;
|
||||
RF->RF23 |= 0x700000;
|
||||
|
||||
BB->BB14 = 0x2020c;
|
||||
BB->BB15 = 0x50;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x1ffffff) | (TxPower | 0x40) << 0x19;
|
||||
BB->CTRL_CFG &= 0xfffffcff;
|
||||
#elif defined(CH571_CH573) || defined(CH582_CH583) || defined(CH32V208)
|
||||
RFEND_Reset();
|
||||
RF->RF18 = (RF->RF18 & 0x8fffffff) | 0x20000000;
|
||||
RF->RF18 = (RF->RF18 & 0xf8ffffff) | 0x4000000;
|
||||
RF->RF18 = (RF->RF18 & 0xfffffff0) | 9;
|
||||
RF->RF18 &= 0xfff8ffff;
|
||||
RF->RF18 |= 0x80000000;
|
||||
RF->RF19 = (RF->RF19 & 0xfffffff8) | 3;
|
||||
RF->RF19 = (RF->RF19 & 0xffffff8f) | 0x30;
|
||||
RF->RF19 = (RF->RF19 & 0xfffff8ff) | 0x300;
|
||||
RF->RF19 &= 0xfeffffff;
|
||||
RF->RF19 |= 0x2000000;
|
||||
RF->RF20 = (RF->RF20 & 0xffff0fff) | 0x4000;
|
||||
RF->RF21 = (RF->RF21 & 0xfffffff0) | 0xc;
|
||||
RF->RF21 |= 0x80;
|
||||
RF->RF21 &= 0xffffefff;
|
||||
RF->RF15 = (RF->RF15 & 0xffff0fff) | 0x8000;
|
||||
RF->RF15 = (RF->RF15 & 0xf8ffffff) | 0x2000000;
|
||||
RF->RF15 = (RF->RF15 & 0x1fffffff) | 0x40000000;
|
||||
RF->RF11 |= 0x700000;
|
||||
RF->RF11 &= 0xf8ffffff;
|
||||
RF->RF11 = (RF->RF11 & 0xffffcfff) | 0x2000;
|
||||
RF->RF11 = (RF->RF11 & 0xfffcffff) | 0x20000;
|
||||
RF->RF12 &= 0xfffffff0;
|
||||
RF->RF12 &= 0xffffff0f;
|
||||
RF->RF12 &= 0xfffff8ff;
|
||||
RF->RF12 |= 0x700000;
|
||||
RF->RF12 = (RF->RF12 & 0x8fffffff) | 0x50000000;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xff07ffff) | RFEND_TXCTUNE_INIT;
|
||||
RF->TXTUNE_CTRL |= 0x80000000;
|
||||
|
||||
#ifdef CH571_CH573
|
||||
BB->CTRL_CFG = (TxPower << 8) | BB->CTRL_CFG | 0x1008000;
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffffc0ff) | (TxPower & 0x3f) << 8;
|
||||
SYS_SAFE_ACCESS(
|
||||
R16_AUX_POWER_ADJ = (TxPower < 0x15) ? (R16_AUX_POWER_ADJ & 0xffef):
|
||||
(R16_AUX_POWER_ADJ | 0x10);
|
||||
);
|
||||
BB->CTRL_TX = 0x10e78;
|
||||
BB->BB6 |= 0x8000;
|
||||
BB->BB6 = (BB->BB6 & 0xffff807f) | 0x3500;
|
||||
BB->BB13 = 0x152;
|
||||
|
||||
// NVIC->VTFADDR[3] = (uint32_t)BB_IRQHandler +0x14000000; // why 14000000?
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG |= 0x800000;
|
||||
BB->CTRL_CFG |= 0x10000000;
|
||||
BB->BB13 = 0x1d0;
|
||||
BB->CTRL_TX = TxPower << 0x19 | CTRL_TX_TXPOWER;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x81ffffff) | (TxPower & 0x3f) << 0x19;
|
||||
BB->BB8 = 0x90083;
|
||||
|
||||
// NVIC->VTFADDR[3] = (uint32_t)BB_IRQHandler +0x20000000; // why 20000000?
|
||||
#endif
|
||||
#elif defined(CH584_CH585) || defined(CH591_CH592)
|
||||
RF->RF12 = (RF->RF12 & 0x8fffffff) | 0x10077700;
|
||||
RF->RF15 = (RF->RF15 & 0x18ff0fff) | 0x42005000;
|
||||
RF->RF19 &= 0xfffcff88;
|
||||
RF->RF21 = (RF->RF21 & 0xfffffff0) | 9;
|
||||
RF->RF23 &= 0xff88ffff;
|
||||
|
||||
BB->CTRL_CFG |= 0x800000;
|
||||
BB->BB14 = 0x3ff; // ch584/5
|
||||
BB->BB13 = 0x50;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x81ffffff) | (TxPower & 0x3f) << 0x19;
|
||||
uint32_t uVar3 = 0x1000000;
|
||||
uint32_t uVar4 = RF->RF23 & 0xf8ffffff;
|
||||
if(TxPower < 29) { // ch585: 27
|
||||
/* uVar3 and uVar4 are initialized properly already */
|
||||
}
|
||||
else if(TxPower < 35) {
|
||||
uVar3 = 0x3000000;
|
||||
}
|
||||
else if(TxPower < 59) {
|
||||
uVar3 = 0x5000000;
|
||||
}
|
||||
else {
|
||||
uVar4 = RF->RF23;
|
||||
uVar3 = 0x7000000;
|
||||
}
|
||||
RF->RF23 = uVar4 | uVar3;
|
||||
BB->BB15 = 0x2020c; // ch584/5
|
||||
BB->BB4 = (BB->BB4 & 0xffffffc0) | 0xe;
|
||||
#endif
|
||||
|
||||
NVIC->VTFIDR[3] = 0x14;
|
||||
}
|
||||
|
||||
void DevSetMode(uint16_t mode) {
|
||||
#if !defined(CH571_CH573)
|
||||
if(mode) {
|
||||
BB->CTRL_CFG = DEVSETMODE_ON;
|
||||
RF->RF2 |= 0x330000;
|
||||
}
|
||||
else {
|
||||
BB->CTRL_CFG = DEVSETMODE_OFF;
|
||||
RF->RF2 &= 0xffcdffff;
|
||||
}
|
||||
#ifdef CH582_CH583
|
||||
mode = (mode == 0) ? 0x80 : mode;
|
||||
#elif !defined(CH32V208)
|
||||
mode |= 0x30000;
|
||||
#endif
|
||||
#endif // ! CH571_CH573
|
||||
LL->CTRL_MOD = mode;
|
||||
}
|
||||
|
||||
uint32_t RFEND_TXCTune(uint8_t channel) {
|
||||
// 0xbf = 2401 MHz
|
||||
RF->RF1 &= 0xfffffffe;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xfffe00ff) | (0xbf00 + (channel_map[channel] << 8));
|
||||
RF->RF1 |= 1;
|
||||
|
||||
LL->TMR = 8000;
|
||||
while(!(RF->TXCTUNE_CO_CTRL & (1 << 25)) || !(RF->TXCTUNE_CO_CTRL & (1 << 26))) {
|
||||
if(LL->TMR == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t nCO = (uint8_t)RF->TXCTUNE_CO_CTRL & 0x3f;
|
||||
uint8_t nGA = (uint8_t)(RF->TXCTUNE_GA_CTRL >> 10) & 0x7f;
|
||||
|
||||
// printf("nCO,nGA ch:%u idx:%u %u,%u\n", channel, channel_map[channel], nCO,nGA);
|
||||
|
||||
return (nGA << 24) | nCO;
|
||||
}
|
||||
|
||||
void RFEND_TXTune() {
|
||||
RF->RF1 &= 0xfffffeff;
|
||||
RF->RF10 &= 0xffffefff;
|
||||
RF->RF11 &= 0xffffffef;
|
||||
RF->RF2 |= 0x20000;
|
||||
RF->RF1 |= 0x10;
|
||||
|
||||
// 2401 MHz
|
||||
uint32_t tune2401 = RFEND_TXCTune(37);
|
||||
uint8_t nCO2401 = (uint8_t)(tune2401 & 0x3f);
|
||||
uint8_t nGA2401 = (uint8_t)(tune2401 >> 24) & 0x7f;
|
||||
|
||||
// 2480 MHz
|
||||
uint32_t tune2480 = RFEND_TXCTune(39);
|
||||
uint8_t nCO2480 = (uint8_t)(tune2480 & 0x3f);
|
||||
uint8_t nGA2480 = (uint8_t)(tune2480 >> 24) & 0x7f;
|
||||
|
||||
// 2440 MHz
|
||||
uint32_t tune2440 = RFEND_TXCTune(18);
|
||||
uint8_t nCO2440 = (uint8_t)(tune2440 & 0x3f);
|
||||
uint8_t nGA2440 = (uint8_t)(tune2440 >> 24) & 0x7f;
|
||||
|
||||
uint32_t dCO0140 = nCO2401 - nCO2440;
|
||||
uint32_t dCO4080 = nCO2440 - nCO2480;
|
||||
uint8_t tune = 0;
|
||||
uint8_t int_points = sizeof(RF->TXCTUNE_CO) /2;
|
||||
uint8_t txctune_co[sizeof(RF->TXCTUNE_CO)] = {0};
|
||||
for(int f = 0; f < int_points; f++) {
|
||||
tune = (dCO0140 * (int_points -f)) / int_points;
|
||||
txctune_co[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int f = int_points; f < sizeof(RF->TXCTUNE_CO); f++) {
|
||||
tune = (dCO4080 * (f -int_points)) / int_points;
|
||||
txctune_co[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int i = 0; i < sizeof(txctune_co) /4; i++) {
|
||||
RF->TXCTUNE_CO[i] = ((uint32_t*)txctune_co)[i];
|
||||
}
|
||||
|
||||
// This GA interpolating is not exactly what is done in EVT
|
||||
// Actually the reception on a BLE monitor is better when this is left out completely
|
||||
// This will need some proper experimentation by people with 2.4GHz SDRs
|
||||
uint32_t dGA0140 = nGA2401 - nGA2440;
|
||||
uint32_t dGA4080 = nGA2440 - nGA2480;
|
||||
int_points = sizeof(RF->TXCTUNE_GA) /2;
|
||||
uint8_t txctune_ga[sizeof(RF->TXCTUNE_GA)] = {0};
|
||||
for(int f = 1; f < int_points; f++) {
|
||||
tune = (dGA0140 * (int_points -f)) / int_points;
|
||||
txctune_ga[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int f = int_points; f < sizeof(RF->TXCTUNE_GA) -1; f++) {
|
||||
tune = (dGA4080 * (f -int_points)) / int_points;
|
||||
txctune_ga[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int i = 0; i < (sizeof(txctune_ga) /4); i++) {
|
||||
RF->TXCTUNE_GA[i] = ((uint32_t*)txctune_ga)[i];
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
printf("2401 2440 2480 CO: %u %u %u, GA: %u %u %u\n", nCO2401, nCO2440, nCO2480, nGA2401, nGA2440, nGA2480);
|
||||
for(int i = 0; i < 10; i++ ) {
|
||||
printf( "%d: %08lx\n", i, RF->TXCTUNE_CO[i] );
|
||||
}
|
||||
for(int i = 0; i < 3; i++ ) {
|
||||
printf( "%d: %08lx\n", i, RF->TXCTUNE_GA[i] );
|
||||
}
|
||||
#endif
|
||||
|
||||
RF->RF1 &= 0xffffffef;
|
||||
RF->RF1 &= 0xfffffffe;
|
||||
RF->RF10 |= 0x1000;
|
||||
RF->RF11 |= 0x10;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xffffffc0) | (tune2440 & 0x3f);
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0x80ffffff) | (tune2440 & 0x7f000000);
|
||||
|
||||
// FTune
|
||||
RF->RF1 |= 0x100;
|
||||
}
|
||||
|
||||
void RFEND_RXTune() {
|
||||
RF->RF20 &= 0xfffeffff;
|
||||
RF->RF2 |= 0x200000;
|
||||
RF->RF3 = (RF->RF3 & 0xffffffef) | 0x10;
|
||||
RF->RF1 |= 0x1000;
|
||||
|
||||
LL->TMR = 100;
|
||||
while(LL->TMR && ((RF->RXTUNE >> 8) & 1));
|
||||
|
||||
tuneFilter = RF->RXTUNE & 0x1f;
|
||||
RF->RF20 |= 0x10000;
|
||||
RF->RF20 = (RF->RF20 & 0xffffffe0) | tuneFilter;
|
||||
RF->RF2 &= 0xffdfffff;
|
||||
tuneFilter2M = (tuneFilter +2 < 0x1f) ? (tuneFilter +2) : 0x1f;
|
||||
|
||||
// RXADC
|
||||
RF->RF22 &= 0xfffeffff;
|
||||
RF->RF2 |= 0x10000;
|
||||
RF->RF3 = (RF->RF3 & 0xfffffeff) | 0x100;
|
||||
RF->RF1 = (RF->RF1 & 0xfffeffff) | 0x100000;
|
||||
}
|
||||
|
||||
void RegInit() {
|
||||
DevSetMode(DEVSETMODE_TUNE);
|
||||
RFEND_TXTune();
|
||||
RFEND_RXTune();
|
||||
DevSetMode(0);
|
||||
}
|
||||
|
||||
void RFCoreInit(uint8_t TxPower) {
|
||||
#if defined(CH571_CH573) || defined(CH584_CH585) // maybe all?
|
||||
NVIC->IENR[0] = 0x1000;
|
||||
NVIC->IRER[0] = 0x1000;
|
||||
#endif
|
||||
DevInit(TxPower);
|
||||
RegInit();
|
||||
NVIC->IPRIOR[0x15] |= 0x80;
|
||||
NVIC_EnableIRQ(LLE_IRQn);
|
||||
}
|
||||
|
||||
void DevSetChannel(uint8_t channel) {
|
||||
#ifdef CH571_CH573
|
||||
BB->BB6 = (BB->BB6 & 0xf8ffffff) | 0x4000000;
|
||||
BB->BB6 = (BB->BB6 & 0xffffff83) | 0x1c;
|
||||
#endif
|
||||
RF->RF11 &= 0xfffffffd;
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffffff80) | (channel & 0x7f);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
int8_t ReadRSSI() {
|
||||
return (int8_t)(BB->RSSI >> 0xf);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void Frame_TX(uint32_t access_address, uint8_t adv[], size_t len, uint8_t channel, uint8_t phy_mode) {
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 1;
|
||||
|
||||
DevSetChannel(channel);
|
||||
|
||||
// Uncomment to disable whitening to debug RF.
|
||||
//BB->CTRL_CFG |= (1<<6);
|
||||
DevSetMode(DEVSETMODE_TX);
|
||||
|
||||
BB->ACCESSADDRESS1 = access_address; // access address
|
||||
BB->CRCINIT1 = 0x555555; // crc init
|
||||
#ifdef CH570_CH572
|
||||
BB->ACCESSADDRESS2 = access_address;
|
||||
BB->CRCINIT2 = 0x555555;
|
||||
BB->CRCPOLY1 = (BB->CRCPOLY1 & 0xff000000) | 0x80032d; // crc poly
|
||||
BB->CRCPOLY2 = (BB->CRCPOLY2 & 0xff000000) | 0x80032d;
|
||||
#endif
|
||||
|
||||
#if defined(CH571_CH573)
|
||||
DMA->TXBUF = (uint32_t)adv;
|
||||
#else
|
||||
LL->TXBUF = (uint32_t)adv;
|
||||
#endif
|
||||
|
||||
// Wait for tuning bit to clear.
|
||||
for( int timeout = 3000; !(RF->RF26 & 0x1000000) && timeout >= 0; timeout-- );
|
||||
|
||||
#if defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
(phy_mode == PHY_S2) ? CTRL_CFG_PHY_CODED:
|
||||
(phy_mode == PHY_S8) ? CTRL_CFG_PHY_CODED:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
if(phy_mode > PHY_2M) { // coded phy
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffff3fff) | ((phy_mode == PHY_S2) ? 0x4000 : 0);
|
||||
}
|
||||
#elif defined(CH571_CH573)
|
||||
BB->CTRL_CFG = CTRL_CFG_PHY_1M; // no 2M PHY on ch571/3
|
||||
#else
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
#endif
|
||||
|
||||
#if defined(CH570_CH572)
|
||||
BB->BB9 = (BB->BB9 & 0xf9ffffff) | ((phy_mode == PHY_2M) ? 0 : 0x2000000);
|
||||
#endif
|
||||
|
||||
#if defined(CH571_CH573)
|
||||
BB->BB11 = (BB->BB11 & 0xfffffffc); // |2 for RX
|
||||
#endif
|
||||
|
||||
// This clears bit 17 (If set, seems to have no impact.)
|
||||
LL->LL4 &= 0xfffdffff;
|
||||
|
||||
#if !defined(CH571_CH573)
|
||||
LL->STATUS = LL_STATUS_TX;
|
||||
#endif
|
||||
LL->TMR = (uint32_t)(len *512); // needs optimisation, per phy mode
|
||||
|
||||
BB->CTRL_CFG |= CTRL_CFG_START_TX;
|
||||
BB->CTRL_TX &= 0xfffffffc;
|
||||
|
||||
LL->LL0 = 2; // Not sure what this does, but on RX it's 1
|
||||
|
||||
while(LL->TMR); // wait for tx buffer to empty
|
||||
DevSetMode(0);
|
||||
if(LL->LL0 & 3) {
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void Frame_RX(uint32_t access_address, uint8_t channel, uint8_t phy_mode) {
|
||||
DevSetMode(0);
|
||||
if(LL->LL0 & 3) {
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
}
|
||||
LL->TMR = 0;
|
||||
|
||||
DevSetChannel(channel);
|
||||
DevSetMode(DEVSETMODE_RX);
|
||||
|
||||
#if defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
(phy_mode == PHY_S2) ? CTRL_CFG_PHY_CODED:
|
||||
(phy_mode == PHY_S8) ? CTRL_CFG_PHY_CODED:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
if(phy_mode > PHY_2M) { // coded phy
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffff3fff) | ((phy_mode == PHY_S2) ? 0x4000 : 0);
|
||||
}
|
||||
#elif defined(CH571_CH573)
|
||||
BB->CTRL_CFG = CTRL_CFG_PHY_1M; // no 2M PHY on ch571/3
|
||||
#else
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
#endif
|
||||
|
||||
#ifdef CH570_CH572
|
||||
BB->BB9 = (BB->BB9 & 0xf9ffffff) | ((phy_mode == PHY_2M) ? 0 : 0x2000000);
|
||||
RF->RF20 = (RF->RF20 & 0xffffffe0) | ((phy_mode == PHY_2M) ? (tuneFilter2M & 0x1f) : (tuneFilter & 0x1f));
|
||||
BB->BB5 = (BB->BB5 & 0xffffffc0) | ((phy_mode == PHY_2M) ? 0xd : 0xb);
|
||||
BB->BB7 = (BB->BB7 & 0xff00fc00) | ((phy_mode == PHY_2M) ? 0x7f00a0 : 0x79009c);
|
||||
#elif defined(CH571_CH573)
|
||||
BB->BB11 = (BB->BB11 & 0xfffffffc) | 2; // no |2 for TX
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
#if defined(CH582_CH583)
|
||||
BB->BB4 = (phy_mode < PHY_S2) ? 0x3722d0 : 0x3722df;
|
||||
#elif defined(CH32V208)
|
||||
BB->BB4 = (phy_mode < PHY_S2) ? 0x3222d0 : 0x34a4df;
|
||||
#endif
|
||||
BB->BB5 = (phy_mode < PHY_S2) ? 0x8101901 : 0x8301ff1;
|
||||
BB->BB6 = (phy_mode < PHY_S2) ? 0x31624 : 0x31619;
|
||||
BB->BB8 = (phy_mode < PHY_S2) ? 0x90083 : 0x90086;
|
||||
BB->BB9 = 0x1006310;
|
||||
BB->BB10 = (phy_mode < PHY_S2) ? 0x28be : 0x28de;
|
||||
#elif defined(CH584_CH585) || defined(CH591_CH592)
|
||||
BB->BB6 = (BB->BB6 & 0xfffffc00) | ((phy_mode == PHY_2M) ? 0x13a : 0x132);
|
||||
BB->BB4 = (BB->BB4 & 0x00ffffff) | ((phy_mode == PHY_2M) ? 0x78000000 : 0x7f000000);
|
||||
#endif
|
||||
|
||||
BB->ACCESSADDRESS1 = access_address; // access address
|
||||
BB->CRCINIT1 = 0x555555; // crc init
|
||||
#ifdef CH570_CH572
|
||||
BB->ACCESSADDRESS2 = access_address;
|
||||
BB->CRCINIT2 = 0x555555;
|
||||
BB->CRCPOLY1 = (BB->CRCPOLY1 & 0xff000000) | 0x80032d; // crc poly
|
||||
BB->CRCPOLY2 = (BB->CRCPOLY2 & 0xff000000) | 0x80032d;
|
||||
#endif
|
||||
|
||||
LL->LL0 = 1; // Not sure what this does, but on TX it's 2
|
||||
rx_ready = 0;
|
||||
}
|
||||
36
inc/extralibs/lib_crc.h
Normal file
36
inc/extralibs/lib_crc.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// should work for CH32v10x, CH32v20x, and CH32v30x
|
||||
// Although has only been tested on CH32v303
|
||||
|
||||
static void CRC_init(void) {
|
||||
// Enable CRC clock
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_CRC;
|
||||
}
|
||||
|
||||
// Calculate CRC for a single 32-bit value
|
||||
static u32 CRC_calculate32(u32 data) {
|
||||
// Reset CRC unit
|
||||
CRC->CTLR = CRC_CTLR_RESET;
|
||||
|
||||
// Write data to trigger CRC calculation
|
||||
CRC->DATAR = data;
|
||||
|
||||
// Wait for CRC calculation
|
||||
u32 timeout = 10000;
|
||||
while (CRC->DATAR == 0 && --timeout);
|
||||
|
||||
// read the CRC result
|
||||
return CRC->DATAR;
|
||||
}
|
||||
|
||||
// Calculate CRC for an array of 32-bit values
|
||||
static u32 CRC_calculateArray32(u32 *data, u32 length) {
|
||||
CRC->CTLR = CRC_CTLR_RESET;
|
||||
|
||||
// Process each 32-bit word
|
||||
for(u32 i = 0; i < length; i++) {
|
||||
CRC->DATAR = data[i];
|
||||
}
|
||||
|
||||
// Return final CRC
|
||||
return CRC->DATAR;
|
||||
}
|
||||
26
inc/extralibs/lib_pvd.h
Normal file
26
inc/extralibs/lib_pvd.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Tested with CH32V002, CH32V006, and CH32V303
|
||||
|
||||
#include "ch32fun.h"
|
||||
|
||||
static void PVD_init(u8 threshold) {
|
||||
if (threshold > PVD_MAX_THRESHOLD_LVL) threshold = PVD_MAX_THRESHOLD_LVL;
|
||||
|
||||
// Enable PWR clock
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_PWR;
|
||||
|
||||
// Enable PVD
|
||||
PWR->CTLR |= PWR_CTLR_PVDE;
|
||||
|
||||
// Clear the existing PLS bits and set new threshold
|
||||
PWR->CTLR = (PWR->CTLR & ~PWR_CTLR_PLS) | (threshold << 5);
|
||||
}
|
||||
|
||||
// Get threshold setting: the PLS[1:0] bits
|
||||
static int PVD_getThreshold() {
|
||||
return (PWR->CTLR & PWR_CTLR_PLS) >> 5;
|
||||
}
|
||||
|
||||
// return PVD flag: 1 if VDD below threshold
|
||||
static int PVD_getAlert() {
|
||||
return PWR->CSR & PWR_CSR_PVDO;
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
// @brief set the random LFSR values seed by default to a known-good value
|
||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||
|
||||
|
||||
/*** Library specific Functions - Do Not Use *********************************/
|
||||
/****************************************************************************/
|
||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
||||
|
|
@ -64,6 +65,7 @@ uint8_t _rand_lfsr_update(void)
|
|||
return msb >> 31;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, 32 times.
|
||||
/// @param None
|
||||
|
|
@ -84,6 +86,8 @@ uint32_t _rand_gen_32b(void)
|
|||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, n times.
|
||||
/// @param None
|
||||
|
|
@ -103,6 +107,7 @@ uint32_t _rand_gen_nb(int bits)
|
|||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
/*** API Functions ***********************************************************/
|
||||
/*****************************************************************************/
|
||||
/// @brief seeds the Random LFSR to the value passed
|
||||
|
|
@ -113,6 +118,7 @@ void seed(const uint32_t seed_val)
|
|||
_rand_lfsr = seed_val;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||
/// you have selected
|
||||
/// @param None
|
||||
|
|
|
|||
142
inc/extralibs/register_debug_utilities.h
Normal file
142
inc/extralibs/register_debug_utilities.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include <stdio.h>
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BITS(reg, 32, 16);
|
||||
void UTIL_PRINT_BITS(u32 val, u8 len, u8 divider_len) {
|
||||
const char* separator = "\n";
|
||||
|
||||
for (int i = (len)-1; i >= 0; i--) {
|
||||
printf("%d| ", i);
|
||||
if (i > 0) printf(i % divider_len ? "" : "%s", separator);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (int i = (len)-1; i >= 0; i--) {
|
||||
printf(i < 10 ? "%2d" : "%3d", ((val) >> i) & 1);
|
||||
if (i > 0) printf(i % divider_len ? " " : " %s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS VALUES
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BITS_VALUES(
|
||||
// reg,
|
||||
// "a", 0,
|
||||
// "b", 1,
|
||||
// "c", 2,
|
||||
// );
|
||||
|
||||
void UTIL_PRINT_BITS_VALUES(u32 reg, ...) {
|
||||
struct BitPair { const char* name; int pos; };
|
||||
va_list args;
|
||||
va_start(args, reg);
|
||||
|
||||
// Count how many pairs were passed (until NULL name)
|
||||
int pair_count = 0;
|
||||
va_list count_args;
|
||||
va_copy(count_args, args);
|
||||
|
||||
while (1) {
|
||||
const char* name = va_arg(count_args, const char*);
|
||||
if (name == NULL) break;
|
||||
int pos = va_arg(count_args, int);
|
||||
(void)pos;
|
||||
pair_count++;
|
||||
}
|
||||
va_end(count_args);
|
||||
|
||||
// Read all the pairs
|
||||
struct BitPair pairs[pair_count];
|
||||
for (int i = 0; i < pair_count; i++) {
|
||||
pairs[i].name = va_arg(args, const char*);
|
||||
pairs[i].pos = va_arg(args, int);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Print the pairs
|
||||
for (int i = 0; i < pair_count; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
printf("%s=%d", pairs[i].name, (unsigned int)((reg >> pairs[i].pos) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS RANGE
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BIT_RANGE(
|
||||
// reg,
|
||||
// "FIELD3", 5, 3,
|
||||
// "FIELD2", 2, 1,
|
||||
// "FIELD1", 0, 0,
|
||||
// NULL
|
||||
// );
|
||||
|
||||
// NOTE: NULL terminated REQUIRED
|
||||
void UTIL_PRINT_BIT_RANGE(u32 reg, ...) {
|
||||
// Define the struct
|
||||
typedef struct { const char* name; int end; int start; } BitField;
|
||||
|
||||
va_list args;
|
||||
va_start(args, reg);
|
||||
|
||||
// Count how many fields were passed (until NULL name)
|
||||
int field_count = 0;
|
||||
va_list count_args;
|
||||
va_copy(count_args, args);
|
||||
|
||||
while (1) {
|
||||
const char* name = va_arg(count_args, const char*);
|
||||
if (name == NULL) break;
|
||||
int start = va_arg(count_args, int);
|
||||
(void)start;
|
||||
int end = va_arg(count_args, int);
|
||||
(void)end;
|
||||
field_count++;
|
||||
}
|
||||
va_end(count_args);
|
||||
|
||||
// Read all the fields
|
||||
BitField fields[field_count];
|
||||
for (int i = 0; i < field_count; i++) {
|
||||
fields[i].name = va_arg(args, const char*);
|
||||
fields[i].end = va_arg(args, int); // get end first
|
||||
fields[i].start = va_arg(args, int); // then get start
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Print the fields
|
||||
for (int i = 0; i < field_count; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
int start = fields[i].start;
|
||||
int end = fields[i].end;
|
||||
|
||||
if (end == start) {
|
||||
// Single bit
|
||||
printf("%s = %d [%d]", fields[i].name, (reg >> start) & 1, start);
|
||||
} else {
|
||||
// Multiple bits
|
||||
int mask = ((1 << (end - start + 1)) - 1);
|
||||
printf("%s = 0x%02X [%d:%d]", fields[i].name, (reg >> start) & mask, end, start);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//! ####################################
|
||||
//! PRINT REGS
|
||||
//! ####################################
|
||||
|
||||
#define UTIL_PRINT_REG8(reg, label) printf("%s: 0x%02X\n", label, (unsigned int)(reg));
|
||||
#define UTIL_PRINT_REG16(reg, label) printf("%s: 0x%04X\n", label, (unsigned int)(reg));
|
||||
#define UTIL_PRINT_REG32(reg, label) printf("%s: 0x%08X\n", label, (unsigned int)(reg));
|
||||
|
||||
|
||||
127
inc/extralibs/rtc_helper.h
Normal file
127
inc/extralibs/rtc_helper.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// MIT License
|
||||
// Copyright (c) 2025 UniTheCat
|
||||
|
||||
#define RTC_TICKS_PER_SECOND 32768
|
||||
|
||||
#define SECONDS_PER_MINUTE 60
|
||||
#define SECONDS_PER_HOUR 3600
|
||||
#define SECONDS_PER_DAY 86400
|
||||
|
||||
#define IS_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
|
||||
|
||||
// Array of days in each month (non-leap year)
|
||||
const u8 DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
typedef struct {
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
} rtc_date_t;
|
||||
|
||||
typedef struct {
|
||||
u8 hr;
|
||||
u8 min;
|
||||
u8 sec;
|
||||
u16 ms;
|
||||
} rtc_time_t;
|
||||
|
||||
typedef struct {
|
||||
rtc_date_t date;
|
||||
rtc_time_t time;
|
||||
} rtc_datetime_t;
|
||||
|
||||
// calculate days of the current year. eg. 2020-02-05 is 36 day
|
||||
u32 RTC_days_of_year(u16 year, u8 month, u8 day) {
|
||||
u32 day_of_year = 0;
|
||||
|
||||
// Add days from January to month-1
|
||||
for (u8 m = 0; m < month - 1; m++) {
|
||||
day_of_year += DAYS_IN_MONTH[m];
|
||||
}
|
||||
|
||||
// Add extra day for February (full month) if it's a leap year
|
||||
if (month > 2 && IS_LEAP_YEAR(year)) {
|
||||
day_of_year += 1;
|
||||
}
|
||||
|
||||
// Add days in the current month
|
||||
day_of_year += day;
|
||||
|
||||
return day_of_year;
|
||||
}
|
||||
|
||||
u32 RTC_get_seconds(u16 year, u8 month, u8 day, u8 hr, u8 min, u8 sec) {
|
||||
//# Validate input
|
||||
if (month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hr > 23 || min > 59 || sec > 59 || year < 1970) { return 0; }
|
||||
|
||||
// calculate days of the current year, -1 for 0-based days
|
||||
u32 days = RTC_days_of_year(year, month, day) - 1;
|
||||
|
||||
// add the days count excluding the current year
|
||||
// (start from epoch time 1970-01-01 00:00:00)
|
||||
for (int y=1970; y < year; y++) {
|
||||
days += IS_LEAP_YEAR(y) ? 366 : 365;
|
||||
}
|
||||
|
||||
// calculate total seconds
|
||||
return days * SECONDS_PER_DAY +
|
||||
hr * SECONDS_PER_HOUR +
|
||||
min * SECONDS_PER_MINUTE + sec;
|
||||
}
|
||||
|
||||
rtc_time_t RTC_get_time(u32 total_seconds, u32 ms) {
|
||||
u32 minutes = total_seconds / 60;
|
||||
|
||||
return (rtc_time_t) {
|
||||
.sec = total_seconds % 60,
|
||||
.min = minutes % 60,
|
||||
.hr = (minutes / 60) % 24,
|
||||
.ms = ms
|
||||
};
|
||||
}
|
||||
|
||||
rtc_date_t RTC_get_date(u32 total_seconds, u16 year_base) {
|
||||
rtc_date_t output = {
|
||||
.year = year_base,
|
||||
.month = 1,
|
||||
.day = 1
|
||||
};
|
||||
|
||||
// Days since epoch
|
||||
u32 days_remaining = total_seconds / SECONDS_PER_DAY;
|
||||
|
||||
// Find the year
|
||||
while(1) {
|
||||
u32 days_in_year = IS_LEAP_YEAR(output.year) ? 366 : 365;
|
||||
if (days_remaining < days_in_year) break;
|
||||
days_remaining -= days_in_year;
|
||||
output.year++;
|
||||
}
|
||||
|
||||
// find the month
|
||||
for (u8 m = 0; m < 12; m++) {
|
||||
u8 days_in_month = DAYS_IN_MONTH[m];
|
||||
if (m == 1 && IS_LEAP_YEAR(output.year)) days_in_month = 29;
|
||||
if (days_remaining < days_in_month) break;
|
||||
|
||||
days_remaining -= days_in_month;
|
||||
output.month++;
|
||||
}
|
||||
|
||||
// add 1 because days_remaining is 0-based
|
||||
output.day = days_remaining + 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void RTC_print_date(rtc_date_t date, char *delimiter) {
|
||||
printf("%04d", date.year);
|
||||
printf("%s%02d", delimiter, date.month);
|
||||
printf("%s%02d", delimiter, date.day);
|
||||
}
|
||||
|
||||
void RTC_print_time(rtc_time_t time) {
|
||||
printf("%02d:%02d:%02d.%03d",
|
||||
time.hr, time.min, time.sec, time.ms);
|
||||
}
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
#ifndef _SSD1306_H
|
||||
#define _SSD1306_H
|
||||
|
||||
#include "font_8x8.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "font_8x8.h"
|
||||
|
||||
// comfortable packet size for this OLED
|
||||
#define SSD1306_PSZ 32
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
// Let the caller configure the OLED.
|
||||
#else
|
||||
// characteristics of each type
|
||||
#if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64) && !defined(SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET))
|
||||
#if !defined (SSD1306_64X32) && !defined (SSD1306_72X40) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET) )
|
||||
#error "Please define the SSD1306_WXH resolution used in your application"
|
||||
#endif
|
||||
|
||||
|
|
@ -28,6 +28,13 @@
|
|||
#define SSD1306_OFFSET 32
|
||||
#endif
|
||||
|
||||
#ifdef SSD1306_72X40
|
||||
#define SSD1306_W 72
|
||||
#define SSD1306_H 40
|
||||
#define SSD1306_FULLUSE
|
||||
#define SSD1306_OFFSET 28
|
||||
#endif
|
||||
|
||||
#ifdef SSD1306_128X32
|
||||
#define SSD1306_W 128
|
||||
#define SSD1306_H 32
|
||||
|
|
@ -132,8 +139,10 @@ const uint8_t ssd1306_init_array[] =
|
|||
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
|
||||
0x80, // the suggested ratio 0x80
|
||||
SSD1306_SETMULTIPLEX, // 0xA8
|
||||
#ifdef SSD1306_64X32
|
||||
#if defined(SSD1306_64X32)
|
||||
0x1F, // for 64-wide displays
|
||||
#elif defined(SSD1306_72X40)
|
||||
0x27,
|
||||
#else
|
||||
0x3F, // for 128-wide displays
|
||||
#endif
|
||||
|
|
@ -147,9 +156,17 @@ const uint8_t ssd1306_init_array[] =
|
|||
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
|
||||
SSD1306_COMSCANDEC,
|
||||
SSD1306_SETCOMPINS, // 0xDA
|
||||
#if defined(SSD1306_FULLUSE)
|
||||
0x12, //
|
||||
#else
|
||||
0x22, //
|
||||
#endif
|
||||
SSD1306_SETCONTRAST, // 0x81
|
||||
#ifdef SSD1306_72X40
|
||||
0xAF,
|
||||
#else
|
||||
0x8F,
|
||||
#endif
|
||||
SSD1306_SETPRECHARGE, // 0xd9
|
||||
0xF1,
|
||||
SSD1306_SETVCOMDETECT, // 0xDB
|
||||
|
|
@ -175,31 +192,6 @@ void ssd1306_setbuf(uint8_t color)
|
|||
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
|
||||
}
|
||||
|
||||
#ifndef SSD1306_FULLUSE
|
||||
/*
|
||||
* expansion array for OLED with every other row unused
|
||||
*/
|
||||
const uint8_t expand[16] =
|
||||
{
|
||||
0x00,
|
||||
0x02,
|
||||
0x08,
|
||||
0x0a,
|
||||
0x20,
|
||||
0x22,
|
||||
0x28,
|
||||
0x2a,
|
||||
0x80,
|
||||
0x82,
|
||||
0x88,
|
||||
0x8a,
|
||||
0xa0,
|
||||
0xa2,
|
||||
0xa8,
|
||||
0xaa,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Send the frame buffer
|
||||
*/
|
||||
|
|
@ -230,40 +222,13 @@ void ssd1306_refresh(void)
|
|||
ssd1306_cmd(0); // Page start address (0 = reset)
|
||||
ssd1306_cmd(7); // Page end address
|
||||
|
||||
#ifdef SSD1306_FULLUSE
|
||||
/* for fully used rows just plow thru everything */
|
||||
for(i=0;i<sizeof(ssd1306_buffer);i+=SSD1306_PSZ)
|
||||
{
|
||||
/* send PSZ block of data */
|
||||
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
|
||||
}
|
||||
#else
|
||||
/* for displays with odd rows unused expand bytes */
|
||||
uint8_t tbuf[SSD1306_PSZ], j, k;
|
||||
for (i = 0; i < sizeof(ssd1306_buffer); i += 128)
|
||||
{
|
||||
/* low nybble */
|
||||
for (j = 0; j < 128; j += SSD1306_PSZ)
|
||||
{
|
||||
for (k = 0; k < SSD1306_PSZ; k++)
|
||||
tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf];
|
||||
|
||||
/* send PSZ block of data */
|
||||
ssd1306_data(tbuf, SSD1306_PSZ);
|
||||
}
|
||||
|
||||
/* high nybble */
|
||||
for (j = 0; j < 128; j += SSD1306_PSZ)
|
||||
{
|
||||
for (k = 0; k < SSD1306_PSZ; k++)
|
||||
tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf];
|
||||
|
||||
/* send PSZ block of data */
|
||||
ssd1306_data(tbuf, SSD1306_PSZ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -312,19 +277,16 @@ void ssd1306_xorPixel(uint32_t x, uint32_t y)
|
|||
* draw a an image from an array, directly into to the display buffer
|
||||
* the color modes allow for overwriting and even layering (sprites!)
|
||||
*/
|
||||
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint32_t width, uint32_t height, uint32_t color_mode)
|
||||
{
|
||||
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint32_t width, uint32_t height, uint32_t color_mode) {
|
||||
uint32_t x_absolute;
|
||||
uint32_t y_absolute;
|
||||
uint32_t pixel;
|
||||
uint32_t bytes_to_draw = width / 8;
|
||||
uint32_t buffer_addr;
|
||||
|
||||
for (uint32_t line = 0; line < height; line++)
|
||||
{
|
||||
for (uint32_t line = 0; line < height; line++) {
|
||||
y_absolute = y + line;
|
||||
if (y_absolute >= SSD1306_H)
|
||||
{
|
||||
if (y_absolute >= SSD1306_H) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -332,15 +294,12 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint3
|
|||
// bitmask for current pixel in vertical (output) byte
|
||||
uint32_t v_mask = 1 << (y_absolute & 7);
|
||||
|
||||
for (uint32_t byte = 0; byte < bytes_to_draw; byte++)
|
||||
{
|
||||
for (uint32_t byte = 0; byte < bytes_to_draw; byte++) {
|
||||
uint32_t input_byte = input[byte + line * bytes_to_draw];
|
||||
|
||||
for (pixel = 0; pixel < 8; pixel++)
|
||||
{
|
||||
for (pixel = 0; pixel < 8; pixel++) {
|
||||
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
|
||||
if (x_absolute >= SSD1306_W)
|
||||
{
|
||||
if (x_absolute >= SSD1306_W) {
|
||||
break;
|
||||
}
|
||||
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
|
||||
|
|
@ -348,8 +307,7 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint3
|
|||
// state of current pixel
|
||||
uint8_t input_pixel = input_byte & (1 << pixel);
|
||||
|
||||
switch (color_mode)
|
||||
{
|
||||
switch (color_mode) {
|
||||
case 0:
|
||||
// write pixels as they are
|
||||
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
|
||||
|
|
@ -501,23 +459,19 @@ void ssd1306_drawCircle(int x, int y, int radius, int color)
|
|||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
||||
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
||||
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
||||
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
|
||||
e2 = err;
|
||||
if (e2 <= y_pos)
|
||||
{
|
||||
if (e2 <= y_pos) {
|
||||
err += ++y_pos * 2 + 1;
|
||||
if (-x_pos == y_pos && e2 <= x_pos)
|
||||
{
|
||||
if(-x_pos == y_pos && e2 <= x_pos) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > x_pos)
|
||||
{
|
||||
if (e2 > x_pos) {
|
||||
err += ++x_pos * 2 + 1;
|
||||
}
|
||||
} while (x_pos <= 0);
|
||||
|
|
@ -534,8 +488,7 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
|
|||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
||||
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
||||
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
||||
|
|
@ -543,16 +496,13 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
|
|||
ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color);
|
||||
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
|
||||
e2 = err;
|
||||
if (e2 <= y_pos)
|
||||
{
|
||||
if (e2 <= y_pos) {
|
||||
err += ++y_pos * 2 + 1;
|
||||
if (-x_pos == y_pos && e2 <= x_pos)
|
||||
{
|
||||
if(-x_pos == y_pos && e2 <= x_pos) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > x_pos)
|
||||
{
|
||||
if(e2 > x_pos) {
|
||||
err += ++x_pos * 2 + 1;
|
||||
}
|
||||
} while(x_pos <= 0);
|
||||
|
|
@ -658,8 +608,7 @@ void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
|
|||
/*
|
||||
* enum for font size
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
fontsize_8x8 = 1,
|
||||
fontsize_16x16 = 2,
|
||||
fontsize_32x32 = 4,
|
||||
|
|
@ -693,10 +642,8 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
|
|||
col = (~color) & 1;
|
||||
|
||||
// Draw the pixel at the original size and scaled size using nested for-loops
|
||||
for (uint8_t k = 0; k < font_scale; k++)
|
||||
{
|
||||
for (uint8_t l = 0; l < font_scale; l++)
|
||||
{
|
||||
for (uint8_t k = 0; k < font_scale; k++) {
|
||||
for (uint8_t l = 0; l < font_scale; l++) {
|
||||
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
|
||||
}
|
||||
}
|
||||
|
|
@ -742,7 +689,6 @@ uint8_t ssd1306_init(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// clear display
|
||||
ssd1306_refresh();
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -146,8 +146,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while (ssd1306_i2c_irq_state)
|
||||
;
|
||||
while(ssd1306_i2c_irq_state);
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
|
|
@ -161,8 +160,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
|
|
@ -171,8 +169,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
|
|
@ -181,8 +178,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
|
|
@ -231,8 +227,7 @@ void I2C1_EV_IRQHandler(void)
|
|||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
;
|
||||
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
|
@ -253,8 +248,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
|
|
@ -263,8 +257,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
|
|
@ -273,8 +266,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
|
|
@ -283,8 +275,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
|
||||
;
|
||||
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
|
|
@ -294,8 +285,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--))
|
||||
;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,13 +37,20 @@ void ssd1306_i2c_setup(void)
|
|||
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||
#define SDA_RELEASE { funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 ); }
|
||||
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
|
||||
#define SDA_DRIVE { funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 ); funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP ); }
|
||||
|
||||
#ifndef I2CSPEEDBASE
|
||||
#define I2CSPEEDBASE 1
|
||||
#endif
|
||||
#ifndef I2CDELAY_FUNC
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||
// Delay_Us(x*1);
|
||||
#endif
|
||||
|
||||
static void ssd1306_i2c_sendstart()
|
||||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
|
|
@ -54,6 +61,7 @@ static void ssd1306_i2c_sendstart()
|
|||
|
||||
void ssd1306_i2c_sendstop()
|
||||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
|
|
@ -72,13 +80,9 @@ unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
|||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
if( data & 0x80 )
|
||||
{
|
||||
SDA_HIGH;
|
||||
}
|
||||
{ SDA_HIGH; }
|
||||
else
|
||||
{
|
||||
SDA_LOW;
|
||||
}
|
||||
{ SDA_LOW; }
|
||||
data<<=1;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
|
|
@ -88,8 +92,8 @@ unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
|||
|
||||
//Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
||||
SDA_HIGH
|
||||
SDA_RELEASE
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
|
|
@ -97,7 +101,8 @@ unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
|||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH // Maybe?
|
||||
SDA_DRIVE
|
||||
SDA_HIGH
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
return !!i;
|
||||
|
|
|
|||
|
|
@ -31,26 +31,48 @@
|
|||
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_SOFT_SPI
|
||||
#define SSD1306_SOFT_SPI 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* init SPI and GPIO for SSD1306 OLED
|
||||
*/
|
||||
uint8_t ssd1306_spi_init(void)
|
||||
{
|
||||
// Enable GPIOC and SPI
|
||||
#ifdef CH5xx
|
||||
#else
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
#endif
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
#if defined( CH5xx ) || SSD1306_SOFT_SPI
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
#else
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
#endif
|
||||
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
|
||||
// Configure SPI
|
||||
#if SSD1306_SOFT_SPI
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH );
|
||||
#elif defined( CH5xx )
|
||||
R8_SPI0_CLOCK_DIV = FUNCONF_SYSTEM_CORE_CLOCK / 12000000; // 16MHz is the fastest I want to go - though it does seem to work up to ~60MHz.
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_2WIRE_MOD | RB_SPI_SCK_OE;
|
||||
R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
|
||||
// | RB_SPI_MST_SCK_MOD; // Mode 3 / mode 0
|
||||
R8_SPI0_CTRL_CFG = RB_MST_CLK_SEL;
|
||||
#else
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
|
|
@ -58,6 +80,7 @@ uint8_t ssd1306_spi_init(void)
|
|||
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
#endif
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
|
|
@ -92,16 +115,37 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
|||
// send data
|
||||
while(sz--)
|
||||
{
|
||||
#if SSD1306_SOFT_SPI
|
||||
uint8_t c = *data++;
|
||||
int i = 8;
|
||||
do
|
||||
{
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
|
||||
funDigitalWrite( SSD1306_MOSI_PIN, !!(c & 0x80) ); ADD_N_NOPS(1)
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH ); ADD_N_NOPS(1)
|
||||
c<<=1;
|
||||
} while( --i );
|
||||
|
||||
#elif defined( CH5xx )
|
||||
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
||||
R8_SPI0_BUFFER = *data++;
|
||||
#else
|
||||
// wait for TXE
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
||||
;
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
#endif
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
#if SSD1306_SOFT_SPI
|
||||
// Nothing needed here.
|
||||
#elif defined( CH5xx )
|
||||
while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE)) { }
|
||||
#else
|
||||
while(SPI1->STATR & SPI_STATR_BSY) { }
|
||||
#endif
|
||||
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
|
||||
|
|
|
|||
203
inc/extralibs/static_i2c.h
Normal file
203
inc/extralibs/static_i2c.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Copyright 2012-2025 <>< Charles Lohr
|
||||
This file may be used for any purposes (commercial or private) just please
|
||||
leave this copyright notice in there somewhere. You may cross license
|
||||
this as MIT or NewBSD.
|
||||
|
||||
Now, generic I2C library for any GPIO-based system.
|
||||
|
||||
Include this in your .c file only!!!
|
||||
Include it after the following are defined:
|
||||
|
||||
I2CDELAY_FUNC -> If you wish to override the internal delay functions.
|
||||
I2CSPEEDBASE -> define speed base multiplier 1 = normal, 10 = slow, .1 =
|
||||
fast; failure to define this will result in the clock being as fast as
|
||||
possible. I2CNEEDGETBYTE -> Do we need to be able to read data?
|
||||
|
||||
I2CPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigI2C
|
||||
to be generated.
|
||||
I2CNOSTATIC -> #define if you want the functions to be generated as
|
||||
not-static code.
|
||||
|
||||
NOTE: You must initially configure the port to be outputs on both DSDA
|
||||
and DSCL and set them both to be driven high.
|
||||
*/
|
||||
/* Example:
|
||||
|
||||
#define DELAY1 Delay_Us(1);
|
||||
#define DELAY2 Delay_Us(2);
|
||||
#define DSCL_IHIGH { funPinMode( PIN_SCL, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SCL, 1 ); }
|
||||
#define DSDA_IHIGH { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); }
|
||||
#define DSDA_INPUT { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); }
|
||||
#define DSCL_OUTPUT { funDigitalWrite( PIN_SCL, 0 ); funPinMode( PIN_SCL, GPIO_CFGLR_OUT_2Mhz_PP ); }
|
||||
#define DSDA_OUTPUT { funDigitalWrite( PIN_SDA, 0 ); funPinMode( PIN_SDA, GPIO_CFGLR_OUT_2Mhz_PP ); }
|
||||
#define READ_DSDA funDigitalRead( PIN_SDA )
|
||||
#define I2CNEEDGETBYTE 1
|
||||
#define I2CNEEDSCAN 1
|
||||
|
||||
#include "static_i2c.h"
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef I2CPREFIX
|
||||
#define I2CPREFIX
|
||||
#endif
|
||||
|
||||
#ifndef I2CNOSTATIC
|
||||
#define I2CSTATICODE
|
||||
#else
|
||||
#define I2CSTATICODE static
|
||||
#endif
|
||||
|
||||
#ifndef I2CFNCOLLAPSE
|
||||
#define INTI2CFNCOLLAPSE(PFX, name) PFX##name
|
||||
#define I2CFNCOLLAPSE(PFX, name) INTI2CFNCOLLAPSE(PFX, name)
|
||||
#endif
|
||||
|
||||
#ifndef I2CNEEDGETBYTE
|
||||
#define I2CNEEDGETBYTE 1
|
||||
#endif
|
||||
|
||||
#ifndef DSCL_IHIGH
|
||||
#define DSCL_IHIGH DSCL_INPUT
|
||||
#endif
|
||||
|
||||
#ifndef DSDA_IHIGH
|
||||
#define DSDA_IHIGH DSDA_INPUT
|
||||
#endif
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, ConfigI2C)()
|
||||
{
|
||||
DSDA_IHIGH
|
||||
DSCL_IHIGH
|
||||
}
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)()
|
||||
{
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
DSDA_OUTPUT
|
||||
DELAY1
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
}
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)()
|
||||
{
|
||||
DELAY1
|
||||
DSDA_OUTPUT
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
DSDA_IHIGH
|
||||
DELAY1
|
||||
}
|
||||
|
||||
// Return nonzero on failure.
|
||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data)
|
||||
{
|
||||
unsigned int i;
|
||||
// Assume we are in a started state (DSCL = 0 & DSDA = 0)
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
DELAY1
|
||||
if (data & 0x80)
|
||||
{
|
||||
DSDA_IHIGH
|
||||
}
|
||||
else
|
||||
{
|
||||
DSDA_OUTPUT
|
||||
}
|
||||
data <<= 1;
|
||||
DELAY2
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
DSCL_OUTPUT
|
||||
}
|
||||
|
||||
// Immediately after sending last bit, open up DDDR for control.
|
||||
DELAY1
|
||||
DSDA_INPUT
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
i = READ_DSDA;
|
||||
DELAY1
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
return !!i;
|
||||
}
|
||||
|
||||
#if I2CNEEDGETBYTE
|
||||
|
||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char ret = 0;
|
||||
|
||||
DSDA_INPUT
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
ret <<= 1;
|
||||
if (READ_DSDA)
|
||||
ret |= 1;
|
||||
DSCL_OUTPUT
|
||||
}
|
||||
|
||||
// Send ack.
|
||||
if (send_nak)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
DSDA_OUTPUT
|
||||
}
|
||||
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
DSDA_IHIGH
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// In case you want SCAN code
|
||||
|
||||
#if I2CNEEDSCAN
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, Scan)()
|
||||
{
|
||||
int i;
|
||||
printf( " " );
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
printf( " %x", i );
|
||||
}
|
||||
for( i = 0; i < 128; i++ )
|
||||
{
|
||||
if( ( i & 0xf ) == 0 )
|
||||
{
|
||||
printf( "\n%02x ", i );
|
||||
}
|
||||
SendStart();
|
||||
int b = SendByte( i<<1 );
|
||||
SendStop();
|
||||
printf( "%c ", b?'.':'#' );
|
||||
}
|
||||
printf( "\n" );
|
||||
}
|
||||
#endif
|
||||
|
|
@ -37,10 +37,12 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* From Linux
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#define USB_DIR_OUT 0 /* to device */
|
||||
#define USB_DIR_IN 0x80 /* to host */
|
||||
|
||||
|
|
@ -50,6 +52,7 @@
|
|||
#define USB_TYPE_VENDOR (0x02 << 5)
|
||||
#define USB_TYPE_RESERVED (0x03 << 5)
|
||||
|
||||
|
||||
/*
|
||||
* USB recipients, the third of three bRequestType fields
|
||||
*/
|
||||
|
|
@ -85,16 +88,11 @@
|
|||
#elif defined (__cplusplus) && __cplusplus >= 201103L
|
||||
#define TU_VERIFY_STATIC static_assert
|
||||
#else
|
||||
#define TU_VERIFY_STATIC(const_expr, _mess) \
|
||||
enum \
|
||||
{ \
|
||||
TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1 / (!!(const_expr)) \
|
||||
}
|
||||
#define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
|
@ -262,8 +260,7 @@ extern "C"
|
|||
DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10
|
||||
}device_capability_type_t;
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6),
|
||||
};
|
||||
|
|
@ -296,6 +293,7 @@ extern "C"
|
|||
INTERFACE_INVALID_NUMBER = 0xff
|
||||
};
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00,
|
||||
|
|
@ -390,16 +388,14 @@ extern "C"
|
|||
|
||||
uint8_t bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
|
||||
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t xfer : 2;
|
||||
uint8_t sync : 2;
|
||||
uint8_t usage : 2;
|
||||
uint8_t : 2;
|
||||
} bmAttributes ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
|
||||
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
|
||||
uint16_t hs_period_mult : 2;
|
||||
uint16_t TU_RESERVED : 3;
|
||||
|
|
@ -484,12 +480,9 @@ extern "C"
|
|||
/*------------------------------------------------------------------*/
|
||||
/* Types
|
||||
*------------------------------------------------------------------*/
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
union
|
||||
{
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
union {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
|
||||
uint8_t type : 2; ///< Request type tusb_request_type_t.
|
||||
uint8_t direction : 1; ///< Direction type. tusb_dir_t
|
||||
|
|
@ -556,11 +549,11 @@ extern "C"
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
// from tinyusb_hid.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TU_U16_HIGH(u16) ((uint8_t) (((u16) >> 8) & 0x00ff))
|
||||
|
|
@ -759,6 +752,7 @@ extern "C"
|
|||
#define DEF_STRING_DESC_PROD 0x02
|
||||
#define DEF_STRING_DESC_SERN 0x03
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Common Definitions
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -1244,6 +1238,7 @@ extern "C"
|
|||
#define HID_KEY_ALT_RIGHT 0xE6
|
||||
#define HID_KEY_GUI_RIGHT 0xE7
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// REPORT DESCRIPTOR
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -1296,8 +1291,7 @@ extern "C"
|
|||
#define HID_BUFFERED_BYTES (1<<8)
|
||||
|
||||
//------------- COLLECTION ITEM 6.2.2.6 -------------//
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
HID_COLLECTION_PHYSICAL = 0,
|
||||
HID_COLLECTION_APPLICATION,
|
||||
HID_COLLECTION_LOGICAL,
|
||||
|
|
@ -1356,8 +1350,7 @@ extern "C"
|
|||
//--------------------------------------------------------------------+
|
||||
|
||||
/// HID Usage Table - Table 1: Usage Page Summary
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
HID_USAGE_PAGE_DESKTOP = 0x01,
|
||||
HID_USAGE_PAGE_SIMULATE = 0x02,
|
||||
HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
|
||||
|
|
@ -1386,8 +1379,7 @@ extern "C"
|
|||
};
|
||||
|
||||
/// HID Usage Table - Table 6: Generic Desktop Page
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
HID_USAGE_DESKTOP_POINTER = 0x01,
|
||||
HID_USAGE_DESKTOP_MOUSE = 0x02,
|
||||
HID_USAGE_DESKTOP_JOYSTICK = 0x04,
|
||||
|
|
@ -1459,6 +1451,7 @@ extern "C"
|
|||
HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7
|
||||
};
|
||||
|
||||
|
||||
/// HID Usage Table: Consumer Page (0x0C)
|
||||
/// Only contains controls that supported by Windows (whole list is too long)
|
||||
enum
|
||||
|
|
@ -1665,9 +1658,7 @@ extern "C"
|
|||
{1, HID_KEY_BACKSLASH }, /* 0x7C | */ \
|
||||
{1, HID_KEY_BRACKET_RIGHT }, /* 0x7D } */ \
|
||||
{1, HID_KEY_GRAVE }, /* 0x7E ~ */ \
|
||||
{ \
|
||||
0, HID_KEY_DELETE \
|
||||
} /* 0x7F Delete */
|
||||
{0, HID_KEY_DELETE } /* 0x7F Delete */ \
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* KEYCODE to Ascii Conversion
|
||||
|
|
@ -1783,10 +1774,17 @@ extern "C"
|
|||
{'9' , 0 }, /* 0x61 */ \
|
||||
{'0' , 0 }, /* 0x62 */ \
|
||||
{'0' , 0 }, /* 0x63 */ \
|
||||
{'=', '='}, /* 0x67 */
|
||||
{'=' , '=' }, /* 0x67 */ \
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _TUSB_TYPES_H_ */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
internal bus resources than to do the same thing with timers.
|
||||
|
||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
||||
**For the CH570/2 - PORTA Pin 7**
|
||||
**For the CH582/3 or CH591/2 PORTA Pin 14**
|
||||
|
||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
|
|
@ -60,28 +62,32 @@ static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
|||
static volatile int WS2812LEDs;
|
||||
static volatile int WS2812LEDPlace;
|
||||
static volatile int WS2812BLEDInUse;
|
||||
|
||||
#ifdef CH5xx
|
||||
#ifdef CH570_CH572
|
||||
#define bMOSI PA7
|
||||
#else
|
||||
#define bMOSI PA14
|
||||
#endif
|
||||
#endif
|
||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||
// This effectively creates the bitstream that outputs to the LEDs.
|
||||
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
|
||||
{
|
||||
#ifdef CH5xx
|
||||
// Reversing bit order because CH5xx SPI FIFO is only half of what CH32 have
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000,
|
||||
0b1000100010001110,
|
||||
0b1000100011101000,
|
||||
0b1000100011101110,
|
||||
0b1000111010001000,
|
||||
0b1000111010001110,
|
||||
0b1000111011101000,
|
||||
0b1000111011101110,
|
||||
0b1110100010001000,
|
||||
0b1110100010001110,
|
||||
0b1110100011101000,
|
||||
0b1110100011101110,
|
||||
0b1110111010001000,
|
||||
0b1110111010001110,
|
||||
0b1110111011101000,
|
||||
0b1110111011101110,
|
||||
};
|
||||
0b0001000100010001, 0b0111000100010001, 0b0001011100010001, 0b0111011100010001,
|
||||
0b0001000101110001, 0b0111000101110001, 0b0001011101110001, 0b0111011101110001,
|
||||
0b0001000100010111, 0b0111000100010111, 0b0001011100010111, 0b0111011100010111,
|
||||
0b0001000101110111, 0b0111000101110111, 0b0001011101110111, 0b0111011101110111, };
|
||||
#else
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||
#endif
|
||||
|
||||
int i;
|
||||
uint16_t * end = ptr + numhalfwords;
|
||||
|
|
@ -127,7 +133,11 @@ static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
|||
if( place == ledcount )
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
#ifdef CH5xx
|
||||
R8_SPI0_INTER_EN &= ~RB_SPI_IE_DMA_END; // Disable DMA end interrupt
|
||||
#else
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
#endif
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
|
|
@ -180,10 +190,23 @@ static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
|||
ptr += 6;
|
||||
i += 6;
|
||||
#endif
|
||||
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
}
|
||||
|
||||
#ifdef CH5xx
|
||||
void SPI0_IRQHandler( void ) __attribute__((interrupt));
|
||||
void SPI0_IRQHandler( void )
|
||||
{
|
||||
uint8_t intf = R8_SPI0_INT_FLAG;
|
||||
if( (intf & RB_SPI_IF_DMA_END) )
|
||||
{
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 1 );
|
||||
R16_SPI0_TOTAL_CNT = DMA_BUFFER_LEN * 2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler( void )
|
||||
{
|
||||
|
|
@ -215,28 +238,54 @@ void DMA1_Channel3_IRQHandler(void)
|
|||
|
||||
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
}
|
||||
#endif
|
||||
|
||||
void WS2812BDMAStart( int leds )
|
||||
{
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
#ifdef CH5xx
|
||||
R8_SPI0_INTER_EN &= ~RB_SPI_IE_DMA_END;
|
||||
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
|
||||
R16_SPI0_TOTAL_CNT = 0;
|
||||
#else
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
#endif
|
||||
__enable_irq();
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
|
||||
|
||||
#ifdef CH5xx
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
R16_SPI0_TOTAL_CNT = DMA_BUFFER_LEN * 2;
|
||||
R16_SPI0_DMA_BEG = (uint32_t)WS2812dmabuff;
|
||||
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
|
||||
R8_SPI0_INTER_EN = RB_SPI_IE_DMA_END;
|
||||
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
|
||||
#else
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812BDMAInit( )
|
||||
{
|
||||
// Enable DMA + Peripherals
|
||||
#ifdef CH5xx
|
||||
funPinMode( bMOSI, GPIO_CFGLR_OUT_2Mhz_PP );
|
||||
R8_SPI0_CLOCK_DIV = FUNCONF_SYSTEM_CORE_CLOCK / 3000000; // div = Fsys/3MHz
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_2WIRE_MOD;
|
||||
R16_SPI0_DMA_END = ( (uint32_t)WS2812dmabuff + (DMA_BUFFER_LEN * 2) );
|
||||
R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
|
||||
|
||||
NVIC_EnableIRQ( SPI0_IRQn );
|
||||
#else
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
|
||||
|
|
@ -250,10 +299,13 @@ void WS2812BDMAInit()
|
|||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; // Enable Tx buffer DMA
|
||||
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
#if defined(CH32V003)
|
||||
SPI1->HSCR = 1; // Enable high-speed read mode
|
||||
#endif
|
||||
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set; // Enable SPI
|
||||
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
|
||||
|
|
@ -279,8 +331,10 @@ void WS2812BDMAInit()
|
|||
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -80,3 +80,4 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
|
|||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"DisableFormat": true,
|
||||
"SortIncludes": "Never"
|
||||
}
|
||||
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_blink.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_blink.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_blink.o ch5xx_blink.bin
|
||||
riscv64-unknown-elf-as ch5xx_blink.asm -march=rv32imac -mabi=ilp32 -o ch5xx_blink.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_blink.o ch5xx_blink.bin
|
||||
xxd -i ch5xx_blink.bin > ch5xx_blink.h
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_verify.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_verify.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_verify.o ch5xx_verify.bin
|
||||
riscv64-unknown-elf-as ch5xx_verify.asm -march=rv32imac_zicsr -o ch5xx_verify.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_verify.o ch5xx_verify.bin
|
||||
xxd -i ch5xx_verify.bin > ch5xx_verify.h
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_write_block.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_write_block.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_write_block.o ch5xx_write_block.bin
|
||||
riscv64-unknown-elf-as ch5xx_write_block.asm -march=rv32imac_zicsr -o ch5xx_write_block.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_write_block.o ch5xx_write_block.bin
|
||||
xxd -i ch5xx_write_block.bin > ch5xx_write_block.h
|
||||
23
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_blink.asm
Normal file
23
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_blink.asm
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# The simplest blink fuction that can fit into PROGBUF.
|
||||
# This is the version suitable for CH5xx series of chips by WCH.
|
||||
# You need to preload respective registers with values for port, pin and delay.
|
||||
# Copyright 2025 monte-monte
|
||||
#
|
||||
#a2 = GPIO port (0 - A, 1 - B...)
|
||||
#a3 = value to count down from for a delay between blinks
|
||||
#a4 = pin mask
|
||||
BEGIN:
|
||||
c.sw a4, 0(a2);
|
||||
c.mv a5, a3;
|
||||
sw zero, 8(a2);
|
||||
LOOP1:
|
||||
c.addi a5, -1;
|
||||
c.bnez a5, LOOP1;
|
||||
c.mv a5, a3;
|
||||
c.sw a4, 8(a2);
|
||||
LOOP2:
|
||||
c.addi a5, -1;
|
||||
c.bnez a5, LOOP2;
|
||||
c.j BEGIN;
|
||||
c.ebreak
|
||||
10
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_verify.asm
Normal file
10
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_verify.asm
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
c.nop;
|
||||
li a5,4;
|
||||
LOOP:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,LOOP;
|
||||
lb a4,4(a3);
|
||||
c.addi a5,-1;
|
||||
c.bnez a5,LOOP;
|
||||
c.lw a1,0(a3);
|
||||
c.sw a1,0(a0);
|
||||
116
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_write_block.asm
Normal file
116
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_write_block.asm
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#
|
||||
# A procedure to write data to flash on CH5xx series of chips by WCH.
|
||||
# This should be compiled into a binary blob and placed into RAM.
|
||||
# Then you will be able to run it and send data via a programmer by writing it to DMDATA0/1
|
||||
# Copyright 2025 monte-monte
|
||||
#
|
||||
#s0 = incomming data from dmdata0
|
||||
#s1 = incomming data from dmdata1
|
||||
#t0 = general reg
|
||||
#t1 = address global
|
||||
#a0 = address in loop
|
||||
#a1 = dmdata0 offset
|
||||
#a2 = general reg
|
||||
#a3 = R32_FLASH_DATA
|
||||
#a4 = general operational
|
||||
#a5 = len counter
|
||||
PREAMBLE:
|
||||
#c.li t0,0;
|
||||
#c.li a2,0;
|
||||
#c.li a4,0;
|
||||
#c.li a5,0;
|
||||
lw s0,0(a1);
|
||||
lw s1,4(a1);
|
||||
bne s1,s0,PREAMBLE;#Wait for DMDATA0/1 to be cleared;
|
||||
c.bnez s0,PREAMBLE;
|
||||
START:
|
||||
#BEGIN
|
||||
addi a0,t1,0;
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
c.li a4,6;
|
||||
sb a4,4(a3);
|
||||
END:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,END;
|
||||
sb zero,6(a3);
|
||||
#BEGIN with CMD = 2
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
c.li a4,2;
|
||||
sb a4,4(a3);
|
||||
c.li a2,3;
|
||||
OUT:
|
||||
srli t0,a0,16;
|
||||
andi t0,t0,0xff;
|
||||
OUT_LOOP:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,OUT_LOOP;
|
||||
sb t0,4(a3);
|
||||
c.slli a0,8;
|
||||
c.addi a2,-1;
|
||||
c.bnez a2,OUT;
|
||||
ADDRES_IS_SET:
|
||||
sw zero,0(a1);#Clear DMDATA0 to indicate we are ready to write again
|
||||
addi a5,zero,64;#Load up the byte counter
|
||||
DATA_RETRIEVER:
|
||||
c.lw s0,0(a1);
|
||||
c.lw s1,4(a1);
|
||||
c.bnez s1, WRITE_ZERO
|
||||
c.beqz s0, DATA_RETRIEVER;
|
||||
WRITE:
|
||||
c.sw s0,0(a3);
|
||||
c.li a4,0x4;
|
||||
WRITE_LOOP1:
|
||||
lb a2,6(a3);
|
||||
blt a2,zero,WRITE_LOOP1;
|
||||
c.li a2,21;
|
||||
sb a2,6(a3);
|
||||
c.addi a4,-1;
|
||||
c.bnez a4,WRITE_LOOP1;
|
||||
c.addi a5,-1;
|
||||
sw zero,0(a1);
|
||||
c.bnez a5,DATA_RETRIEVER;
|
||||
addi t1,t1,256;
|
||||
sw t1,0(a1);#Write current address to DMDATA0 to indicate that we are in wait loop
|
||||
lui t0,0x80;
|
||||
WAIT:
|
||||
#END
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,WAIT;
|
||||
sb zero,6(a3)
|
||||
#BEGIN with CMD = 5
|
||||
WAIT_LOOP:
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
sb a4,4(a3)
|
||||
IN_LOOP1:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,IN_LOOP1;
|
||||
lbu a2,4(a3);
|
||||
IN_LOOP2:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,IN_LOOP2;
|
||||
lb a2,4(a3);
|
||||
WAIT_END:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,WAIT_END;
|
||||
sb zero,6(a3)
|
||||
#IF
|
||||
andi a4,a2,1;
|
||||
c.bnez a4,WAIT_LOOP_BACK;
|
||||
j START;
|
||||
WAIT_LOOP_BACK:
|
||||
c.addi t0,-1;
|
||||
bne t0,zero,WAIT_LOOP;
|
||||
EXIT:
|
||||
c.ebreak;
|
||||
WRITE_ZERO:
|
||||
sw zero,4(a1);
|
||||
beq s1,a1,WAIT;
|
||||
sw zero,0(a3);
|
||||
c.li a4,0x4;
|
||||
c.j WRITE_LOOP1;
|
||||
|
|
@ -20,7 +20,7 @@ typedef enum IRQn
|
|||
Ecall_U_Mode_IRQn = 8, /* 8 Ecall U Mode Interrupt */
|
||||
Break_Point_IRQn = 9, /* 9 Break Point Interrupt */
|
||||
#endif
|
||||
SysTicK_IRQn = 12, /* 12 System timer Interrupt */
|
||||
SysTick_IRQn = 12, /* 12 System timer Interrupt */
|
||||
Software_IRQn = 14, /* 14 software Interrupt */
|
||||
|
||||
#if defined(CH32V003) || defined(CH32X03x)
|
||||
|
|
@ -1864,8 +1864,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
#define USB_PHY_V33 (1<<6)
|
||||
#define USB_IOEN (1<<7)
|
||||
|
||||
|
||||
#define USBFSD_UEP_MOD_BASE 0x4002340C
|
||||
|
|
@ -2266,11 +2264,7 @@ typedef struct
|
|||
#define ESIG_BASE ((uint32_t)0x1FFFF7E0)
|
||||
#define INFO_BASE ((uint32_t)0x1FFFF704)
|
||||
|
||||
#if defined(CH32V003) || defined(CH32V10x)
|
||||
#define EXTEN_BASE ((uint32_t)0x40023800)
|
||||
#elif defined(CH32V20x) || defined(CH32V30x)
|
||||
#define EXTEN_BASE (AHBPERIPH_BASE + 0x3800)
|
||||
#endif
|
||||
|
||||
#define PFIC_BASE (CORE_PERIPH_BASE + 0xE000)
|
||||
#define SysTick_BASE (CORE_PERIPH_BASE + 0xF000)
|
||||
|
|
@ -2283,118 +2277,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
// AFIO CTLR Bits
|
||||
#define PB6_FILT_EN (1<<27)
|
||||
#define PB5_FILT_EN (1<<26)
|
||||
#define PA4_FILT_EN (1<<25)
|
||||
#define PA3_FILT_EN (1<<24)
|
||||
#define UDM_BC_CMPO (1<<19)
|
||||
#define UDP_BC_CMPO (1<<17)
|
||||
#define UDM_BC_VSRC (1<<17)
|
||||
#define UDP_BC_VSRC (1<<16)
|
||||
#define USBPD_IN_HVT (1<<9)
|
||||
#define USBPD_PHY_V33 (1<<8)
|
||||
#define USB_IOEN (1<<7)
|
||||
#define USB_PHY_V33 (1<<6)
|
||||
#define UDP_PUE_00 (0b00<<2)
|
||||
#define UDP_PUE_01 (0b01<<2)
|
||||
#define UDP_PUE_10 (0b10<<2)
|
||||
#define UDP_PUE_11 (0b11<<2)
|
||||
#define UDM_PUE_00 (0b00<<0)
|
||||
#define UDM_PUE_01 (0b01<<0)
|
||||
#define UDM_PUE_10 (0b10<<0)
|
||||
#define UDM_PUE_11 (0b11<<0)
|
||||
#define UDP_PUE_MASK 0x0000000C
|
||||
#define UDP_PUE_DISABLE 0x00000000
|
||||
#define UDP_PUE_35UA 0x00000004
|
||||
#define UDP_PUE_10K 0x00000008
|
||||
#define UDP_PUE_1K5 0x0000000C
|
||||
#define UDM_PUE_MASK 0x00000003
|
||||
#define UDM_PUE_DISABLE 0x00000000
|
||||
#define UDM_PUE_35UA 0x00000001
|
||||
#define UDM_PUE_10K 0x00000002
|
||||
#define UDM_PUE_1K5 0x00000003
|
||||
|
||||
|
||||
// USB PD Bits
|
||||
#define IE_TX_END (1<<15)
|
||||
#define IE_RX_RESET (1<<14)
|
||||
#define IE_RX_ACT (1<<13)
|
||||
#define IE_RX_BYTE (1<<12)
|
||||
#define IE_RX_BIT (1<<11)
|
||||
#define IE_PD_IO (1<<10)
|
||||
#define WAKE_POLAR (1<<5)
|
||||
#define PD_RST_EN (1<<4)
|
||||
#define PD_DMA_EN (1<<3)
|
||||
#define CC_SEL (1<<2)
|
||||
#define PD_ALL_CLR (1<<1)
|
||||
#define PD_FILT_EN (1<<0)
|
||||
#define BMC_CLK_CNT_MASK (0xff)
|
||||
|
||||
//R8_CONTROL
|
||||
#define BMC_BYTE_HI (1<<7)
|
||||
#define TX_BIT_BACK (1<<6)
|
||||
#define DATA_FLAG (1<<5)
|
||||
#define RX_STATE_MASK (0x7<<2)
|
||||
#define RX_STATE_0 (1<<2)
|
||||
#define RX_STATE_1 (1<<3)
|
||||
#define RX_STATE_2 (1<<4)
|
||||
#define BMC_START (1<<1)
|
||||
#define PD_TX_EN (1<<0)
|
||||
|
||||
#define TX_SEL4_MASK (3<<6)
|
||||
#define TX_SEL4_0 (1<<6)
|
||||
#define TX_SEL4_1 (1<<7)
|
||||
|
||||
#define TX_SEL3_MASK (3<<4)
|
||||
#define TX_SEL3_0 (1<<4)
|
||||
#define TX_SEL3_1 (1<<5)
|
||||
|
||||
#define TX_SEL2_MASK (3<<2)
|
||||
#define TX_SEL2_0 (1<<2)
|
||||
#define TX_SEL2_1 (1<<3)
|
||||
|
||||
#define TX_SEL1 (1<<0)
|
||||
|
||||
#define BMC_TX_SZ_MASK (0x1ff)
|
||||
|
||||
//R8_STATUS
|
||||
#define IF_TX_END (1<<7)
|
||||
#define IF_RX_RESET (1<<6)
|
||||
#define IF_RX_ACT (1<<5)
|
||||
#define IF_RX_BYTE (1<<4)
|
||||
#define IF_RX_BIT (1<<3)
|
||||
#define IFBUF_ERR (1<<2)
|
||||
#define BMC_AUX_MASK (3<<0)
|
||||
#define BMC_AUX_1 (1<<1)
|
||||
#define BMC_AUX_0 (1<<0)
|
||||
|
||||
// PORT CC1
|
||||
#define CC1_CE_MASK (7<<5)
|
||||
#define CC1_CE_0 (1<<5)
|
||||
#define CC1_CE_1 (2<<5)
|
||||
#define CC1_CE_2 (4<<5)
|
||||
|
||||
#define CC1_LVE (1<<4)
|
||||
#define CC1_PU_MASK (3<<2)
|
||||
#define CC1_PU_DISABLE (0<<2)
|
||||
#define CC1_PU_330uA (1<<2)
|
||||
#define CC1_PU_180uA (2<<2)
|
||||
#define CC1_PU_80uA (3<<2)
|
||||
#define PA_CC1_AI (1<<0)
|
||||
|
||||
#define CC2_CE_MASK (7<<5)
|
||||
#define CC2_CE_0 (1<<5)
|
||||
#define CC2_CE_1 (2<<5)
|
||||
#define CC2_CE_2 (4<<5)
|
||||
|
||||
#define CC2_LVE (1<<4)
|
||||
#define CC2_PU_MASK (3<<2)
|
||||
#define CC2_PU_DISABLE (0<<2)
|
||||
#define CC2_PU_330uA (1<<2)
|
||||
#define CC2_PU_180uA (2<<2)
|
||||
#define CC2_PU_80uA (3<<2)
|
||||
#define PA_CC2_AI (1<<0)
|
||||
|
||||
|
||||
|
||||
|
|
@ -5356,33 +5238,33 @@ typedef struct
|
|||
|
||||
#if defined(CH32V003)
|
||||
/***************** Bit definition for AFIO_EXTICR register *****************/
|
||||
#define AFIO_EXTICR_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
||||
#define AFIO_EXTICR_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
||||
#define AFIO_EXTICR_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
||||
#define AFIO_EXTICR_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
||||
#define AFIO_EXTICR_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
||||
#define AFIO_EXTICR_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
||||
#define AFIO_EXTICR_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
||||
#define AFIO_EXTICR_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
||||
#define AFIO_EXTICR1_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
||||
#define AFIO_EXTICR1_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
||||
#define AFIO_EXTICR1_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
||||
#define AFIO_EXTICR1_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
||||
#define AFIO_EXTICR1_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
||||
#define AFIO_EXTICR1_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
||||
#define AFIO_EXTICR1_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
||||
#define AFIO_EXTICR1_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
||||
|
||||
#define AFIO_EXTICR_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
||||
#define AFIO_EXTICR_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
||||
#define AFIO_EXTICR_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
||||
#define AFIO_EXTICR_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
||||
#define AFIO_EXTICR_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
||||
#define AFIO_EXTICR_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
||||
#define AFIO_EXTICR_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
||||
#define AFIO_EXTICR_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
||||
#define AFIO_EXTICR_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
||||
#define AFIO_EXTICR_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
||||
#define AFIO_EXTICR_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
||||
#define AFIO_EXTICR_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
||||
#define AFIO_EXTICR1_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
||||
#define AFIO_EXTICR1_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
||||
#define AFIO_EXTICR1_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
||||
#define AFIO_EXTICR1_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
||||
#define AFIO_EXTICR1_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
||||
#define AFIO_EXTICR1_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
||||
#define AFIO_EXTICR1_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
||||
#define AFIO_EXTICR1_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
||||
#define AFIO_EXTICR1_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
||||
#define AFIO_EXTICR1_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
||||
#define AFIO_EXTICR1_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
||||
#endif
|
||||
|
||||
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
|
||||
|
|
@ -9507,7 +9389,7 @@ typedef enum
|
|||
#define OB_RST_NoEN ((uint16_t)0x0018) /* Reset IO disable (PD7)*/
|
||||
#define OB_RST_EN_DT12ms ((uint16_t)0x0010) /* Reset IO enable (PD7) and Ignore delay time 12ms */
|
||||
#define OB_RST_EN_DT1ms ((uint16_t)0x0008) /* Reset IO enable (PD7) and Ignore delay time 1ms */
|
||||
#define OB_RST_EN_DT128ms ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128ms */
|
||||
#define OB_RST_EN_DT128us ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128us */
|
||||
|
||||
#define OB_STARTMODE_BOOT ((uint16_t)0x0020) /* Start in BOOT area */
|
||||
#define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */
|
||||
|
|
@ -12586,6 +12468,349 @@ typedef volatile unsigned long *PUINT32V;
|
|||
|
||||
#endif
|
||||
|
||||
/* ch32x035_usbpd.h ----------------------------------------------------------*/
|
||||
|
||||
/* Register Bit Definition */
|
||||
/* USBPD->CONFIG */
|
||||
#define PD_FILT_ED (1<<0) /* PD pin input filter enable */
|
||||
#define PD_ALL_CLR (1<<1) /* Clear all interrupt flags */
|
||||
#if defined(CH32X03x)
|
||||
#define CC_SEL (1<<2) /* Select PD communication port */
|
||||
#define PD_DMA_EN (1<<3) /* Enable DMA for USBPD */
|
||||
#define PD_RST_EN (1<<4) /* PD mode reset command enable */
|
||||
#define WAKE_POLAR (1<<5) /* PD port wake-up level */
|
||||
#elif defined(CH641)
|
||||
#define CC_ALL_SEL (3<<2) /* Select PD communication port ALL*/
|
||||
#define CC_SEL_Mask (3<<2) /* Clear PD communication port */
|
||||
#define CC_SEL_1 (0<<2) /* Select PD communication port1 */
|
||||
#define CC_SEL_2 (1<<2) /* Select PD communication port2 */
|
||||
#define CC_SEL_3 (2<<2) /* Select PD communication port3 */
|
||||
#define PD_DMA_EN (1<<4) /* Enable DMA for USBPD */
|
||||
#define PD_RST_EN (1<<5) /* PD mode reset command enable */
|
||||
#define WAKE_POLAR (1<<6) /* PD port wake-up level */
|
||||
#endif
|
||||
#define IE_PD_IO (1<<10) /* PD IO interrupt enable */
|
||||
#define IE_RX_BIT (1<<11) /* Receive bit interrupt enable */
|
||||
#define IE_RX_BYTE (1<<12) /* Receive byte interrupt enable */
|
||||
#define IE_RX_ACT (1<<13) /* Receive completion interrupt enable */
|
||||
#define IE_RX_RESET (1<<14) /* Reset interrupt enable */
|
||||
#define IE_TX_END (1<<15) /* Transfer completion interrupt enable */
|
||||
|
||||
/* USBPD->CONTROL */
|
||||
#define PD_TX_EN (1<<0) /* USBPD transceiver mode and transmit enable */
|
||||
#define BMC_START (1<<1) /* BMC send start signal */
|
||||
#define RX_STATE_0 (1<<2) /* PD received state bit 0 */
|
||||
#define RX_STATE_1 (1<<3) /* PD received state bit 1 */
|
||||
#define RX_STATE_2 (1<<4) /* PD received state bit 2 */
|
||||
#define DATA_FLAG (1<<5) /* Cache data valid flag bit */
|
||||
#define TX_BIT_BACK (1<<6) /* Indicates the current bit status of the BMC when sending the code */
|
||||
#define BMC_BYTE_HI (1<<7) /* Indicates the current half-byte status of the PD data being sent and received */
|
||||
|
||||
/* USBPD->TX_SEL */
|
||||
#define TX_SEL1 (0<<0)
|
||||
#define TX_SEL1_SYNC1 (0<<0) /* 0-SYNC1 */
|
||||
#define TX_SEL1_RST1 (1<<0) /* 1-RST1 */
|
||||
#define TX_SEL2_Mask (3<<2)
|
||||
#define TX_SEL2_SYNC1 (0<<2) /* 00-SYNC1 */
|
||||
#define TX_SEL2_SYNC3 (1<<2) /* 01-SYNC3 */
|
||||
#define TX_SEL2_RST1 (2<<2) /* 1x-RST1 */
|
||||
#define TX_SEL3_Mask (3<<4)
|
||||
#define TX_SEL3_SYNC1 (0<<4) /* 00-SYNC1 */
|
||||
#define TX_SEL3_SYNC3 (1<<4) /* 01-SYNC3 */
|
||||
#define TX_SEL3_RST1 (2<<4) /* 1x-RST1 */
|
||||
#define TX_SEL4_Mask (3<<6)
|
||||
#define TX_SEL4_SYNC2 (0<<6) /* 00-SYNC2 */
|
||||
#define TX_SEL4_SYNC3 (1<<6) /* 01-SYNC3 */
|
||||
#define TX_SEL4_RST2 (2<<6) /* 1x-RST2 */
|
||||
|
||||
/* USBPD->STATUS */
|
||||
#define BMC_AUX_Mask (3<<0) /* Clear BMC auxiliary information */
|
||||
#define BMC_AUX_INVALID (0<<0) /* 00-Invalid */
|
||||
#define BMC_AUX_SOP0 (1<<0) /* 01-SOP0 */
|
||||
#define BMC_AUX_SOP1_HRST (2<<0) /* 10-SOP1 hard reset */
|
||||
#define BMC_AUX_SOP2_CRST (3<<0) /* 11-SOP2 cable reset */
|
||||
#define BUF_ERR (1<<2) /* BUFFER or DMA error interrupt flag */
|
||||
#define IF_RX_BIT (1<<3) /* Receive bit or 5bit interrupt flag */
|
||||
#define IF_RX_BYTE (1<<4) /* Receive byte or SOP interrupt flag */
|
||||
#define IF_RX_ACT (1<<5) /* Receive completion interrupt flag */
|
||||
#define IF_RX_RESET (1<<6) /* Receive reset interrupt flag */
|
||||
#define IF_TX_END (1<<7) /* Transfer completion interrupt flag */
|
||||
|
||||
/* USBPD->PORT_CC1 */
|
||||
/* USBPD->PORT_CC2 */
|
||||
#if defined(CH641)
|
||||
/* USBPD->PORT_CC3 */
|
||||
#define CC_CMPO (1<<0) /* CC port comparator analog input */
|
||||
#elif defined(CH32X03x)
|
||||
#define PA_CC_AI (1<<0) /* CC port comparator analogue input */
|
||||
#endif
|
||||
#define CC_PD (1<<1) /* CC port pull-down resistor enable */
|
||||
#define CC_PU_Mask (3<<2) /* Clear CC port pull-up current */
|
||||
#define CC_NO_PU (0<<2) /* 00-Prohibit pull-up current */
|
||||
#define CC_PU_330 (1<<2) /* 01-330uA */
|
||||
#define CC_PU_180 (2<<2) /* 10-180uA */
|
||||
#define CC_PU_80 (3<<2) /* 11-80uA */
|
||||
#define CC_LVE (1<<4) /* CC port output low voltage enable */
|
||||
#if defined(CH32X03x)
|
||||
#define CC_CMP_Mask (7<<5) /* Clear CC_CMP*/
|
||||
#define CC_NO_CMP (0<<5) /* 000-closed */
|
||||
#define CC_CMP_22 (2<<5) /* 010-0.22V */
|
||||
#define CC_CMP_45 (3<<5) /* 011-0.45V */
|
||||
#define CC_CMP_55 (4<<5) /* 100-0.55V */
|
||||
#define CC_CMP_66 (5<<5) /* 101-0.66V */
|
||||
#define CC_CMP_95 (6<<5) /* 110-0.95V */
|
||||
#define CC_CMP_123 (7<<5) /* 111-1.23V */
|
||||
#define USBPD_IN_HVT (1<<9)
|
||||
#elif defined(CH641)
|
||||
#define CC_CVS_Mask (3<<5) /* clear CC_CVS*/
|
||||
#define CC_CVS_55 (0<<5) /* 00-0.55V */
|
||||
#define CC_CVS_22 (1<<5) /* 01-0.22V */
|
||||
#define CC_CVS_66 (2<<5) /* 10-0.66V */
|
||||
#define CC_CVS_123 (3<<5) /* 11-1.23V */
|
||||
#define CC_CE (1<<7) /* Enable the voltage comparator on port CC */
|
||||
#endif
|
||||
|
||||
#if defined(CH32X03x)
|
||||
|
||||
/*********************************************************
|
||||
* PD pin PC14/PC15 high threshold input mode:
|
||||
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||
* 0-Normal GPIO threshold input
|
||||
* *******************************************************/
|
||||
#define USBPD_PHY_V33 (1<<8)
|
||||
/**********************************************************
|
||||
* PD transceiver PHY pull-up limit configuration bits:
|
||||
* 1-Direct use of VDD for GPIO applications or PD applications with VDD voltage of 3.3V
|
||||
* 0-LDO buck enabled, limited to approx 3.3V, for PD applications with VDD more than 4V
|
||||
* ********************************************************/
|
||||
|
||||
#elif defined(CH641)
|
||||
|
||||
/*********************************************************
|
||||
* PD pin PB0/PB1/PB9 high threshold input mode:
|
||||
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||
* 0-Normal GPIO threshold input
|
||||
* *******************************************************/
|
||||
#define USBPD_HVT (1<<19)
|
||||
|
||||
#endif
|
||||
|
||||
/* Control Message Types */
|
||||
#define DEF_TYPE_RESERVED 0x00
|
||||
#define DEF_TYPE_GOODCRC 0x01 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_GOTOMIN 0x02 /* Send By: Source */
|
||||
#define DEF_TYPE_ACCEPT 0x03 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_REJECT 0x04 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_PING 0x05 /* Send By: Source */
|
||||
#define DEF_TYPE_PS_RDY 0x06 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_SRC_CAP 0x07 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_SNK_CAP 0x08 /* Send By: Source,DRP */
|
||||
#define DEF_TYPE_DR_SWAP 0x09 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_PR_SWAP 0x0A /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_VCONN_SWAP 0x0B /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_WAIT 0x0C /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_SOFT_RESET 0x0D /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_DATA_RESET 0x0E /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_DATA_RESET_CMP 0x0F /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_NOT_SUPPORT 0x10 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_GET_SRC_CAP_EX 0x11 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_STATUS 0x12 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_STATUS_R 0X02 /* ext=1 */
|
||||
#define DEF_TYPE_FR_SWAP 0x13 /* Send By: Sink */
|
||||
#define DEF_TYPE_GET_PPS_STATUS 0x14 /* Send By: Sink */
|
||||
#define DEF_TYPE_GET_CTY_CODES 0x15 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_SNK_CAP_EX 0x16 /* Send By: Source,DRP */
|
||||
#define DEF_TYPE_GET_SRC_INFO 0x17 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_REVISION 0x18 /* Send By: Source,Sink */
|
||||
|
||||
/* Data Message Types */
|
||||
#define DEF_TYPE_SRC_CAP 0x01 /* Send By: Source,Dual-Role Power */
|
||||
#define DEF_TYPE_REQUEST 0x02 /* Send By: Sink */
|
||||
#define DEF_TYPE_BIST 0x03 /* Send By: Tester,Source,Sink */
|
||||
#define DEF_TYPE_SNK_CAP 0x04 /* Send By: Sink,Dual-Role Power */
|
||||
#define DEF_TYPE_BAT_STATUS 0x05 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_ALERT 0x06 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_CTY_INFO 0x07 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_ENTER_USB 0x08 /* Send By: DFP */
|
||||
#define DEF_TYPE_EPR_REQUEST 0x09 /* Send By: Sink */
|
||||
#define DEF_TYPE_EPR_MODE 0x0A /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_SRC_INFO 0x0B /* Send By: Source */
|
||||
#define DEF_TYPE_REVISION 0x0C /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_VENDOR_DEFINED 0x0F /* Send By: Source,Sink,Cable Plug */
|
||||
|
||||
/* Vendor Define Message Command */
|
||||
#define DEF_VDM_DISC_IDENT 0x01
|
||||
#define DEF_VDM_DISC_SVID 0x02
|
||||
#define DEF_VDM_DISC_MODE 0x03
|
||||
#define DEF_VDM_ENTER_MODE 0x04
|
||||
#define DEF_VDM_EXIT_MODE 0x05
|
||||
#define DEF_VDM_ATTENTION 0x06
|
||||
#define DEF_VDM_DP_S_UPDATE 0x10
|
||||
#define DEF_VDM_DP_CONFIG 0x11
|
||||
|
||||
/* PD Revision */
|
||||
#define DEF_PD_REVISION_10 0x00
|
||||
#define DEF_PD_REVISION_20 0x01
|
||||
#define DEF_PD_REVISION_30 0x02
|
||||
|
||||
|
||||
/* PD PHY Channel */
|
||||
#if defined(CH32X03x)
|
||||
|
||||
#define DEF_PD_CC1 0x00
|
||||
#define DEF_PD_CC2 0x01
|
||||
|
||||
#define PIN_CC1 GPIO_Pin_14
|
||||
#define PIN_CC2 GPIO_Pin_15
|
||||
|
||||
#elif defined(CH641)
|
||||
#define PIN_CC1 GPIO_Pin_0
|
||||
#define PIN_CC2 GPIO_Pin_1
|
||||
#define PIN_CC3 GPIO_Pin_9
|
||||
#endif
|
||||
|
||||
/* PD Tx Status */
|
||||
#define DEF_PD_TX_OK 0x00
|
||||
#define DEF_PD_TX_FAIL 0x01
|
||||
|
||||
/* PDO INDEX */
|
||||
#define PDO_INDEX_1 1
|
||||
#define PDO_INDEX_2 2
|
||||
#define PDO_INDEX_3 3
|
||||
#define PDO_INDEX_4 4
|
||||
#define PDO_INDEX_5 5
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define UPD_TMR_TX_48M (80-1) /* timer value for USB PD BMC transmittal @Fsys=48MHz */
|
||||
#define UPD_TMR_RX_48M (120-1) /* timer value for USB PD BMC receiving @Fsys=48MHz */
|
||||
#define UPD_TMR_TX_24M (40-1) /* timer value for USB PD BMC transmittal @Fsys=24MHz */
|
||||
#define UPD_TMR_RX_24M (60-1) /* timer value for USB PD BMC receiving @Fsys=24MHz */
|
||||
#define UPD_TMR_TX_12M (20-1) /* timer value for USB PD BMC transmittal @Fsys=12MHz */
|
||||
#define UPD_TMR_RX_12M (30-1) /* timer value for USB PD BMC receiving @Fsys=12MHz */
|
||||
|
||||
#define MASK_PD_STAT 0x03 /* Bit mask for current PD status */
|
||||
#define PD_RX_SOP0 0x01 /* SOP0 received */
|
||||
#define PD_RX_SOP1_HRST 0x02 /* SOP1 or Hard Reset received */
|
||||
#define PD_RX_SOP2_CRST 0x03 /* SOP2 or Cable Reset received */
|
||||
|
||||
#define UPD_SOP0 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC1 | TX_SEL4_SYNC2 ) /* SOP1 */
|
||||
#define UPD_SOP1 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC3 | TX_SEL4_SYNC3 ) /* SOP2 */
|
||||
#define UPD_SOP2 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC3 | TX_SEL3_SYNC1 | TX_SEL4_SYNC3 ) /* SOP3 */
|
||||
#define UPD_HARD_RESET ( TX_SEL1_RST1 | TX_SEL2_RST1 | TX_SEL3_RST1 | TX_SEL4_RST2 ) /* Hard Reset*/
|
||||
#define UPD_CABLE_RESET ( TX_SEL1_RST1 | TX_SEL2_SYNC1 | TX_SEL3_RST1 | TX_SEL4_SYNC3 ) /* Cable Reset*/
|
||||
|
||||
|
||||
#define bCC_CMP_22 0X01
|
||||
#define bCC_CMP_45 0X02
|
||||
#define bCC_CMP_55 0X04
|
||||
#define bCC_CMP_66 0X08
|
||||
#define bCC_CMP_95 0X10
|
||||
#define bCC_CMP_123 0X20
|
||||
#define bCC_CMP_220 0X40
|
||||
|
||||
/******************************************************************************/
|
||||
/* PD State Machine */
|
||||
typedef enum
|
||||
{
|
||||
STA_IDLE = 0, /* 0: No task status */
|
||||
STA_DISCONNECT, /* 1: Disconnection */
|
||||
STA_SRC_CONNECT, /* 2: SRC connect */
|
||||
STA_RX_SRC_CAP_WAIT, /* 3: Waiting to receive SRC_CAP */
|
||||
STA_RX_SRC_CAP, /* 4: SRC_CAP received */
|
||||
STA_TX_REQ, /* 5: Send REQUEST */
|
||||
STA_RX_ACCEPT_WAIT, /* 6: Waiting to receive ACCEPT */
|
||||
STA_RX_ACCEPT, /* 7: ACCEPT received */
|
||||
STA_RX_REJECT, /* 8: REJECT received */
|
||||
STA_RX_PS_RDY_WAIT, /* 9: Waiting to receive PS_RDY */
|
||||
STA_RX_PS_RDY, /* 10: PS_RDY received */
|
||||
STA_SINK_CONNECT, /* 11: SNK access */
|
||||
STA_TX_SRC_CAP, /* 12: Send SRC_CAP */
|
||||
STA_RX_REQ_WAIT, /* 13: Waiting to receive REQUEST */
|
||||
STA_RX_REQ, /* 14: REQUEST received */
|
||||
STA_TX_ACCEPT, /* 15: Send ACCEPT */
|
||||
STA_TX_REJECT, /* 16: Send REJECT */
|
||||
STA_ADJ_VOL, /* 17: Adjustment of output voltage and current */
|
||||
STA_TX_PS_RDY, /* 18: Send PS_RDY */
|
||||
STA_TX_DR_SWAP, /* 19: Send DR_SWAP */
|
||||
STA_RX_DR_SWAP_ACCEPT, /* 20: Waiting to receive the answer ACCEPT from DR_SWAP */
|
||||
STA_TX_PR_SWAP, /* 21: Send PR_SWAP */
|
||||
STA_RX_PR_SWAP_ACCEPT, /* 22: Waiting to receive the answer ACCEPT from PR_SWAP */
|
||||
STA_RX_PR_SWAP_PS_RDY, /* 23: Waiting to receive the answer PS_RDY from PR_SWAP */
|
||||
STA_TX_PR_SWAP_PS_RDY, /* 24: Send answer PS_RDY for PR_SWAP */
|
||||
STA_PR_SWAP_RECON_WAIT, /* 25: Wait for PR_SWAP before reconnecting */
|
||||
STA_SRC_RECON_WAIT, /* 26: Waiting for SRC to reconnect */
|
||||
STA_SINK_RECON_WAIT, /* 27: Waiting for SNK to reconnect */
|
||||
STA_RX_APD_PS_RDY_WAIT, /* 28: Waiting for PS_RDY from the receiving adapter */
|
||||
STA_RX_APD_PS_RDY, /* 29: PS_RDY received from the adapter */
|
||||
STA_MODE_SWITCH, /* 30: Mode switching */
|
||||
STA_TX_SOFTRST, /* 31: Sending a software reset */
|
||||
STA_TX_HRST, /* 32: Send hardware reset */
|
||||
STA_PHY_RST, /* 33: PHY reset */
|
||||
STA_APD_IDLE_WAIT, /* 34: Waiting for the adapter to become idle */
|
||||
} CC_STATUS;
|
||||
|
||||
/******************************************************************************/
|
||||
/* PD Message Header Struct */
|
||||
typedef union
|
||||
{
|
||||
struct _Message_Header
|
||||
{
|
||||
UINT8 MsgType: 5; /* Message Type */
|
||||
UINT8 PDRole: 1; /* 0-UFP; 1-DFP */
|
||||
UINT8 SpecRev: 2; /* 00-Rev1.0; 01-Rev2.0; 10-Rev3.0; */
|
||||
UINT8 PRRole: 1; /* 0-Sink; 1-Source */
|
||||
UINT8 MsgID: 3;
|
||||
UINT8 NumDO: 3;
|
||||
UINT8 Ext: 1;
|
||||
}Message_Header;
|
||||
UINT16 Data;
|
||||
}_Message_Header;
|
||||
|
||||
/******************************************************************************/
|
||||
/* Bit definition */
|
||||
typedef union
|
||||
{
|
||||
struct _BITS_
|
||||
{
|
||||
UINT8 Msg_Recvd: 1; /* Notify the main program of the receipt of a PD packet */
|
||||
UINT8 Connected: 1; /* PD Physical Layer Connected Flag */
|
||||
UINT8 Stop_Det_Chk: 1; /* 0-Enable detection; 1-Disable disconnection detection */
|
||||
UINT8 PD_Role: 1; /* 0-UFP; 1-DFP */
|
||||
UINT8 PR_Role: 1; /* 0-Sink; 1-Source */
|
||||
UINT8 Auto_Ack_PRRole: 1; /* Role used by auto-responder 0:SINK; 1:SOURCE */
|
||||
UINT8 PD_Version: 1; /* PD version 0-PD2.0; 1-PD3.0 */
|
||||
UINT8 VDM_Version: 1; /* VDM Version 0-1.0 1-2.0 */
|
||||
UINT8 HPD_Connected: 1; /* HPD Physical Layer Connected Flag */
|
||||
UINT8 HPD_Det_Chk: 1; /* 0-turn off HPD connection detection; 1-turn on HPD connection detection */
|
||||
UINT8 CC_Sel_En: 1; /* 0-CC channel selection toggle enable; 1-CC channel selection toggle disable */
|
||||
UINT8 CC_Sel_State: 1; /* 0-CC channel selection switches to 0; 1-CC channel selection switches to 1 */
|
||||
UINT8 PD_Comm_Succ: 1; /* 0-PD communication unsuccessful; 1-PD communication successful; */
|
||||
UINT8 Recv: 3;
|
||||
}Bit;
|
||||
UINT16 Bit_Flag;
|
||||
}_BIT_FLAG;
|
||||
|
||||
/* PD control-related structures */
|
||||
typedef struct _PD_CONTROL
|
||||
{
|
||||
CC_STATUS PD_State; /* PD communication status machine */
|
||||
CC_STATUS PD_State_Last; /* PD communication status machine (last value) */
|
||||
UINT8 Msg_ID; /* ID of the message sent */
|
||||
UINT8 Det_Timer; /* PD connection status detection timing */
|
||||
UINT8 Det_Cnt; /* Number of PD connection status detections */
|
||||
UINT8 Det_Sel_Cnt; /* Number of SEL toggles for PD connection status detection */
|
||||
UINT8 HPD_Det_Timer; /* HPD connection detection timing */
|
||||
UINT8 HPD_Det_Cnt; /* HPD pin connection status detection count */
|
||||
UINT16 PD_Comm_Timer; /* PD shared timing variables */
|
||||
UINT8 ReqPDO_Idx; /* Index of the requested PDO, valid values 1-7 */
|
||||
UINT16 PD_BusIdle_Timer; /* Bus Idle Time Timer */
|
||||
UINT8 Mode_Try_Cnt; /* Number of retries for current mode, highest bit marks mode */
|
||||
UINT8 Err_Op_Cnt; /* Exception operation count */
|
||||
UINT8 Adapter_Idle_Cnt; /* Adapter communication idle timing */
|
||||
_BIT_FLAG Flag; /* Flag byte bit definition */
|
||||
}PD_CONTROL, *pPD_CONTROL;
|
||||
|
||||
/* ch32v00x_wwdg.h -----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||
|
|
@ -10,16 +10,9 @@ char *WhitePull(const char **sti)
|
|||
{
|
||||
const char * st = *sti;
|
||||
int len = 0;
|
||||
while ((*st == ' ' || *st == '\t' || *st == '(') && *st)
|
||||
{
|
||||
st++;
|
||||
}
|
||||
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||
const char * sts = st;
|
||||
while (*st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0)
|
||||
{
|
||||
st++;
|
||||
len++;
|
||||
}
|
||||
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||
if( *st == ')' ) { st++; }
|
||||
char * ret = malloc( len + 1 );
|
||||
memcpy( ret, sts, len );
|
||||
|
|
@ -76,18 +69,9 @@ cont:
|
|||
lastv = ret;
|
||||
lasto = -1;
|
||||
//printf( "RET: %d\n", ret );
|
||||
if (strcmp(wpa, "||") == 0)
|
||||
{
|
||||
lasto = 1;
|
||||
goto cont;
|
||||
}
|
||||
else if (strcmp(wpa, "&&") == 0)
|
||||
{
|
||||
lasto = 2;
|
||||
goto cont;
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||
else return ret;
|
||||
}
|
||||
|
||||
// 0 for no
|
||||
|
|
@ -127,14 +111,9 @@ int NoYesInd(const char *preprocc)
|
|||
|
||||
const char * sslineis( const char * line, const char * match )
|
||||
{
|
||||
while (*line == ' ' || *line == '\t')
|
||||
line++;
|
||||
while( *line == ' ' || *line == '\t' ) line++;
|
||||
const char * linestart = line;
|
||||
while (*line && *match == *line)
|
||||
{
|
||||
line++;
|
||||
match++;
|
||||
}
|
||||
while( *line && *match == *line ) { line++; match++; }
|
||||
if( *match == 0 )
|
||||
return linestart;
|
||||
else
|
||||
|
|
@ -165,6 +144,7 @@ int main(int argc, char **argv)
|
|||
char line[1024];
|
||||
char * l;
|
||||
|
||||
|
||||
int depth = 0;
|
||||
|
||||
// 0 = no
|
||||
|
|
@ -242,3 +222,5 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
11
inc/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
11
inc/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
This only works for the WCH LinkE in RISC-V mode. If your programmer has the BLUE light ON shortly after boot your programmer is in ARM mode.
|
||||
|
||||
Please follow instructions here to convert your programmer to RISC-V mode from ARM mode.
|
||||
|
||||
Basically press-and-hold the ModeS button while plugging in the USB.
|
||||
|
||||
Once powered, it will store that to default.
|
||||
|
||||
The blue light should be OFF.
|
||||
|
||||
Once you are in RISC-V mode, you can install this driver by right-clicking on the driver and saying install.
|
||||
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
Binary file not shown.
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
Binary file not shown.
44121
inc/misc/dumped_libgcc.S
44121
inc/misc/dumped_libgcc.S
File diff suppressed because it is too large
Load diff
190
inc/misc/install_xpack_gcc.ps1
Normal file
190
inc/misc/install_xpack_gcc.ps1
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
using namespace System.IO;
|
||||
using namespace System.IO.Compression.FileSystem;
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = 'DestPreset')]
|
||||
param (
|
||||
# Uses one of the preset locations to install to
|
||||
[Parameter(ParameterSetName = 'DestPreset', Position = 0)]
|
||||
[ValidateSet('User', 'System')]
|
||||
[string]$Destination = 'User',
|
||||
|
||||
# If a preset location is not used, then the user must specify a path to install to
|
||||
[Parameter(ParameterSetName = 'DestPath', Position = 0, Mandatory = $true)]
|
||||
[string]$Path,
|
||||
|
||||
# If enabled, will prevent modification of your PATH environment variable
|
||||
[switch]$NoPath,
|
||||
|
||||
# If enabled, will not install our make
|
||||
[switch]$NoMake,
|
||||
|
||||
# Skips all prompts and just installs, mainly intended for use if we need to re-run as admin.
|
||||
[switch]$SkipPrompts
|
||||
);
|
||||
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
[string] $XpackVersion = '14.2.0-3';
|
||||
[string] $XpackEdition = 'riscv-none-elf-gcc';
|
||||
[string] $XpackArch = 'win32-x64';
|
||||
[string] $XpackNameEd = "xpack-$XpackEdition";
|
||||
[string] $XpackNameEdVer = "$XpackNameEd-$XpackVersion";
|
||||
[string] $XpackNameEdVerArch = "$XpackNameEdVer-$XpackArch"
|
||||
[string] $XpackDownloadFilename = "$XpackNameEdVerArch.zip";
|
||||
[string] $XpackDownloadURL = "https://github.com/xpack-dev-tools/$XpackEdition-xpack/releases/download/v$XpackVersion/$XpackDownloadFilename";
|
||||
|
||||
[string] $MakeVersion = '4.4.1';
|
||||
[string] $MakeEdition = 'without-guile';
|
||||
[string] $MakeArch = 'w32';
|
||||
[string] $MakeName = "make-$MakeVersion-$MakeEdition"
|
||||
[string] $MakeNameFull = "$MakeName-$MakeArch";
|
||||
[string] $MakeDownloadFilename = "$MakeNameFull-bin.zip";
|
||||
[string] $MakeDownloadURL = "https://sourceforge.net/projects/ezwinports/files/$MakeDownloadFilename/download";
|
||||
|
||||
[EnvironmentVariableTarget] $PathScope = [EnvironmentVariableTarget]::User;
|
||||
[string] $TempFolder = [Path]::GetTempPath();
|
||||
[bool] $NoClearTemp = $false;
|
||||
|
||||
if ($PSCmdlet.ParameterSetName -EQ 'DestPreset')
|
||||
{
|
||||
if ($Destination -EQ 'User') { $Path = Join-Path $ENV:LocalAppData $XpackNameEd; }
|
||||
elseif ($Destination -EQ 'System')
|
||||
{
|
||||
$Path = Join-Path $ENV:ProgramFiles $XpackNameEd;
|
||||
$PathScope = [EnvironmentVariableTarget]::Machine;
|
||||
}
|
||||
else { throw 'Unknown Preset Destination'; }
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($Path)) { throw 'Destination path must be provided'; }
|
||||
|
||||
[string] $TempFolder = Join-Path $TempFolder 'ch32fun';
|
||||
[string] $XpackDownloadFilePath = Join-Path $TempFolder $XpackDownloadFilename;
|
||||
[string] $XpackPath = Join-Path $Path $XpackVersion;
|
||||
[string] $XpackBinPath = Join-Path $XpackPath 'bin';
|
||||
[string] $MakeDownloadFilePath = Join-Path $TempFolder $MakeDownloadFilename;
|
||||
|
||||
Write-Host "${XpackNameEdVer}:";
|
||||
Write-Host " will be downloaded from " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackDownloadURL -ForegroundColor 'DarkGreen';
|
||||
Write-Host " to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackDownloadFilePath -ForegroundColor 'DarkGreen';
|
||||
Write-Host " then installed to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackPath -ForegroundColor 'DarkGreen';
|
||||
Write-Host;
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
Write-Host "${MakeName}:"
|
||||
Write-Host " will be downloaded from " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $MakeDownloadURL -ForegroundColor 'DarkGreen';
|
||||
Write-Host " to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $MakeDownloadFilePath -ForegroundColor 'DarkGreen';
|
||||
Write-Host " then installed to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackBinPath -ForegroundColor 'DarkGreen';
|
||||
Write-Host;
|
||||
}
|
||||
if ($NoPath) { Write-Host "Your environment variables will not be edited.`n"; }
|
||||
else
|
||||
{
|
||||
Write-Host "xpack will be added to your " -NoNewline;
|
||||
Write-Host $PathScope.ToString().ToLower() -ForegroundColor 'DarkGreen' -NoNewline;
|
||||
Write-Host " PATH environment variable.`n";
|
||||
}
|
||||
if (-NOT $SkipPrompts)
|
||||
{
|
||||
[string] $Answer = Read-Host -Prompt "Is this correct? (y/n)";
|
||||
if ($Answer -NE 'y') { Exit; }
|
||||
}
|
||||
|
||||
try
|
||||
{ # Check if we need elevation
|
||||
[bool] $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator');
|
||||
if ((-NOT $NoPath) -AND ($PathScope -EQ [EnvironmentVariableTarget]::Machine) -AND (-NOT $IsAdmin)) { throw; } # If we want to set the system PATH variable, we need to elevate
|
||||
if (-NOT (Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -ErrorAction SilentlyContinue -ErrorVariable PermissionError | Out-Null; }
|
||||
if ($PermissionError) { throw; }
|
||||
[string] $TestFile = Join-Path $Path 'TestingFile.txt';
|
||||
Set-Content -Path $TestFile -Value 'Checking permissions.' -ErrorAction SilentlyContinue -ErrorVariable PermissionError;
|
||||
if ($PermissionError) { throw; }
|
||||
Remove-Item -Path $TestFile -ErrorAction SilentlyContinue -ErrorVariable PermissionError;
|
||||
if ($PermissionError) { throw; }
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Host 'Administrator permissions are required, requesting elevation...';
|
||||
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator'))
|
||||
{
|
||||
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -GE 6000)
|
||||
{
|
||||
$CommandLine = "-File `"$($MyInvocation.MyCommand.Path)`" -SkipPrompts";
|
||||
if ($PSCmdlet.ParameterSetName -EQ 'DestPreset') { $CommandLine += " -Destination `"$Destination`""; }
|
||||
else { $CommandLine += " -Path `"$Path`""; }
|
||||
if ($NoPath) { $CommandLine += ' -NoPath'; }
|
||||
if ($NoMake) { $CommandLine += ' -NoMake'; }
|
||||
try { Start-Process -FilePath 'PowerShell.exe' -Verb RunAs -ArgumentList $CommandLine; }
|
||||
catch { Write-Error 'Failed to elevate to administrator.'; Exit; }
|
||||
}
|
||||
}
|
||||
else { Write-Error 'Could not access folder, but am already administrator!'; Exit; }
|
||||
if (-NOT $NoPath) { Write-Host 'You may need to restart your terminal before changes apply.'; }
|
||||
Exit;
|
||||
}
|
||||
|
||||
[void](New-Item -Path $TempFolder -ItemType Directory -Force);
|
||||
[void](New-Item -Path $Path -ItemType Directory -Force);
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -LT 7) { $ProgressPreference = 'SilentlyContinue'; } # Showing progress makes it download very slowly on old PowerShell https://github.com/PowerShell/PowerShell/issues/2138
|
||||
|
||||
Write-Host "Downloading $XpackDownloadFilename" -NoNewline;
|
||||
try { Write-Host $(' ({0:F2} MB)...' -F ([long]::Parse((Invoke-WebRequest -UseBasicParsing -Uri $XpackDownloadURL -Method Head).Headers['Content-Length']) / (1024.0 * 1024.0))); }
|
||||
catch { Write-Host '...'; }
|
||||
Invoke-WebRequest -UseBasicParsing -Uri $XpackDownloadURL -OutFile $XpackDownloadFilePath;
|
||||
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
Write-Host "Downloading $MakeDownloadFilename...";
|
||||
Invoke-WebRequest -UseBasicParsing -UserAgent 'Wget' -Uri $MakeDownloadURL -OutFile $MakeDownloadFilePath;
|
||||
}
|
||||
|
||||
Write-Host "Extracting $XpackDownloadFilename...";
|
||||
[string] $XpackTempPath = Join-Path $TempFolder 'xpath';
|
||||
if (Test-Path $XpackTempPath) { Remove-Item -Recurse -Force $XpackTempPath; }
|
||||
Expand-Archive $XpackDownloadFilePath -DestinationPath $XpackTempPath;
|
||||
if (-NOT (Test-Path $XpackPath)) { [void](New-Item -Path $XpackPath -ItemType Directory -Force); }
|
||||
Copy-Item -Path $(Join-Path $(Join-Path $XpackTempPath $XpackNameEdVer) '*') -Destination $XpackPath -Recurse -Force;
|
||||
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
[string] $MakeTempPath = Join-Path $TempFolder 'make';
|
||||
Write-Host "Extracting $MakeDownloadFilename...";
|
||||
Expand-Archive -Force $MakeDownloadFilePath -DestinationPath $MakeTempPath;
|
||||
Move-Item -Force -Path $(Join-Path $MakeTempPath 'bin/make.exe') -Destination $XpackBinPath;
|
||||
}
|
||||
|
||||
if (-NOT $NoClearTemp)
|
||||
{
|
||||
Write-Host "Deleting $TempFolder...";
|
||||
Remove-Item $TempFolder -Force -Recurse;
|
||||
}
|
||||
|
||||
if (-NOT $NoPath)
|
||||
{
|
||||
Write-Host "Adding to $PathScope PATH environment variable...";
|
||||
$CurrentPATH = [Environment]::GetEnvironmentVariable('PATH', $PathScope);
|
||||
if ([string]::IsNullOrWhitespace($CurrentPATH)) { Write-Error 'Could not retrieve the current PATH, not editing'; Exit; }
|
||||
|
||||
if ($CurrentPATH.Contains($XpackBinPath.TrimEnd(('\', '/')))) # If the install dir is on the path, regardless of trailing slash or not
|
||||
{
|
||||
Write-Host ' It looks like this xpack installation is already in your user PATH, so it will not be edited.';
|
||||
}
|
||||
else {
|
||||
$NewPATH = "$CurrentPATH;$XpackBinPath";
|
||||
[Environment]::SetEnvironmentVariable('PATH', $NewPATH, $PathScope);
|
||||
Write-Host ' You may need to restart your terminal before you can use xpack gcc.';
|
||||
}
|
||||
# Detect GitHub Actions runner and export for future steps
|
||||
if ($env:GITHUB_ACTIONS -eq 'true') {
|
||||
Write-Host "Detected GitHub Actions runner. Prepending xPack bin to PATH for workflow steps..."
|
||||
Add-Content -Path $env:GITHUB_ENV -Value "PATH=$XpackBinPath`:$env:PATH"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host 'Finished!';
|
||||
37
inc/misc/minichlink-live/README.md
Normal file
37
inc/misc/minichlink-live/README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Minichlink live command server
|
||||
|
||||
Minichlink now supports a command server on port 4444.
|
||||
Currently, there are only two commands implemented:
|
||||
- `-s` Set/Write command
|
||||
- `-m` Read command
|
||||
|
||||
The format of these commands is the same as the command line interface commands with the same name:
|
||||
```sh
|
||||
-s [debug register] [value]
|
||||
-m [debug register]
|
||||
```
|
||||
> [!WARNING]
|
||||
> All values MUST be expressed in hexadecimal:
|
||||
```sh
|
||||
-s 0x20 0xc02a717d
|
||||
```
|
||||
|
||||
Multiple commands can be chained together, the results of the read operations will be returned as a key value pair with the key being the register address:
|
||||
```sh
|
||||
04: 1234bees5
|
||||
04: f00cac1a
|
||||
```
|
||||
|
||||
The QingKe V4 Processor manual describes how to build these commands, but there are also 4 example scripts that you can use:
|
||||
```sh
|
||||
./read.sh dma_count # reads contents of memory of `debug_count` symbol
|
||||
|
||||
./write.sh dma_count 123 # writes the value 123 at `dma_count` symbol address
|
||||
|
||||
./batch_read.sh dma_buffer # reads the contents of the symbol `dma_buffer`
|
||||
# size is deduced automatically, but can also be specified with a second argument
|
||||
|
||||
./plot.py dma_count # continuously read a value an plot it
|
||||
```
|
||||
> [!WARNING]
|
||||
> All of these scripts are examples, not tools, treat appropriately
|
||||
64
inc/misc/minichlink-live/batch_read.sh
Executable file
64
inc/misc/minichlink-live/batch_read.sh
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
COUNT=$2
|
||||
if [ -z "$SYMBOL" ]; then
|
||||
echo "Usage: $0 <symbol> [<count>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR="$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print "0x"$1}')"
|
||||
if [ -z "$COUNT" ]; then
|
||||
WORDS=$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print int(("0x"$5 + 3) / 4)}')
|
||||
else
|
||||
WORDS=$COUNT
|
||||
fi
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Reading $WORDS words from $SYMBOL@$ADDR"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
# Prelude
|
||||
commands+=" -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands+=" -s 0x21 0x9002c22e" # sw a1,4(sp); ebreak
|
||||
commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
|
||||
# Batch Read
|
||||
commands+=" -s 0x20 0x05914188" # lw a0,0(a1); add a1,a1,4
|
||||
commands+=" -s 0x21 0x90029002" # ebreak
|
||||
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x0027100b" # Abstract cmd data0->x11 and exec progbuf
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
|
||||
for i in $(seq 0 $((WORDS - 2))); do
|
||||
commands+=" -s 0x17 0x0026100a" # Abstract exec and x10->data0
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
done
|
||||
|
||||
commands+=" -s 0x17 0x0022100a" # Abstract cmd x10->data0
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
|
||||
# Postlude
|
||||
commands+=" -s 0x20 0x45924502" # lw a0,0(sp); lw a1,4(sp)
|
||||
commands+=" -s 0x21 0x90026141" # add sp,sp,16; ebreak
|
||||
# commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
102
inc/misc/minichlink-live/plot.py
Executable file
102
inc/misc/minichlink-live/plot.py
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.animation import FuncAnimation
|
||||
import sys
|
||||
import subprocess
|
||||
import socket
|
||||
|
||||
|
||||
PERIOD_MS = 1000 / 30
|
||||
SAMPLES = 200
|
||||
symbol = sys.argv[1]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
xdata, ydata = range(SAMPLES), [0] * SAMPLES
|
||||
(ln,) = plt.plot([], [])
|
||||
|
||||
# find elf in current directory
|
||||
result = subprocess.run(["find", ".", "-name", "*.elf"], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr.strip()}")
|
||||
sys.exit(1)
|
||||
|
||||
elf = result.stdout.splitlines()[0]
|
||||
print(f"Using ELF file: {elf}")
|
||||
|
||||
result = subprocess.run(
|
||||
["riscv64-unknown-elf-objdump", "-t", elf], capture_output=True, text=True
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr.strip()}")
|
||||
sys.exit(1)
|
||||
|
||||
symbol_address = -1
|
||||
for line in result.stdout.splitlines()[4:]:
|
||||
name = line.split()[-1]
|
||||
if symbol == name:
|
||||
symbol_address = int(line.split()[0], 16)
|
||||
break
|
||||
|
||||
if symbol_address == -1:
|
||||
print(f"Error: Symbol '{symbol}' not found in ELF file.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Symbol '{symbol}' found at address: {symbol_address:#x}")
|
||||
|
||||
commands = " -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
commands += " -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands += " -s 0x21 0xc432c22e" # sw a1,4(sp); sw a2,8(sp)
|
||||
commands += " -s 0x22 0xe0000637" # lui a2,0xe0000
|
||||
commands += " -s 0x23 0x0f460613" # add a2,a2,244 # e00000f4 <data0>
|
||||
commands += " -s 0x24 0x410c4208" # lw a0,0(a2); lw a1,0(a0)
|
||||
commands += " -s 0x25 0x4502c20c" # sw a1,0(a2); lw a0,0(sp)
|
||||
commands += " -s 0x26 0x46224592" # lw a1,4(sp); lw a2,8(sp)
|
||||
commands += " -s 0x27 0x90026141" # add sp,sp,16; ebreak
|
||||
|
||||
commands += f" -s 0x04 {symbol_address:#x}" # Write address 0x20000000 to DATA0
|
||||
commands += " -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
commands += " -m 0x16" # Read ABSTRACTCS
|
||||
commands += " -m 0x04" # Read DATA0
|
||||
|
||||
commands += " -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
command = commands.encode()
|
||||
|
||||
|
||||
def read_memory():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(("127.0.0.1", 4444))
|
||||
s.send(command)
|
||||
|
||||
data = s.recv(1024).decode()
|
||||
s.close()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_value():
|
||||
value = int(read_memory().splitlines()[-1].split()[-1], 16)
|
||||
print(f"Received value: {value}")
|
||||
return value
|
||||
|
||||
|
||||
def init():
|
||||
ax.set_xlim(0, SAMPLES)
|
||||
ax.set_ylim(0, 1024)
|
||||
return (ln,)
|
||||
|
||||
|
||||
def update(frame):
|
||||
global ydata
|
||||
value = get_value()
|
||||
ydata = ydata[1:] + [value]
|
||||
ln.set_data(xdata, ydata)
|
||||
return (ln,)
|
||||
|
||||
|
||||
ani = FuncAnimation(
|
||||
fig, update, frames=SAMPLES, init_func=init, blit=True, interval=PERIOD_MS
|
||||
)
|
||||
plt.show()
|
||||
43
inc/misc/minichlink-live/read.sh
Executable file
43
inc/misc/minichlink-live/read.sh
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
if [ -z "$SYMBOL" ]; then
|
||||
echo "Usage: $0 <symbol>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR=$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print "0x"$1}')
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Reading $SYMBOL@$ADDR"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
commands+=" -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands+=" -s 0x21 0xc432c22e" # sw a1,4(sp); sw a2,8(sp)
|
||||
commands+=" -s 0x22 0xe0000637" # lui a2,0xe0000
|
||||
commands+=" -s 0x23 0x0f460613" # add a2,a2,244 # e00000f4 <data0>
|
||||
commands+=" -s 0x24 0x410c4208" # lw a0,0(a2); lw a1,0(a0)
|
||||
commands+=" -s 0x25 0x4502c20c" # sw a1,0(a2); lw a0,0(sp)
|
||||
commands+=" -s 0x26 0x46224592" # lw a1,4(sp); lw a2,8(sp)
|
||||
commands+=" -s 0x27 0x90026141" # add sp,sp,16; ebreak
|
||||
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
41
inc/misc/minichlink-live/write.sh
Executable file
41
inc/misc/minichlink-live/write.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
VAL=$2
|
||||
if [ -z "$SYMBOL" ] || [ -z "$VAL" ]; then
|
||||
echo "Usage: $0 <symbol> <value>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR="0x$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print $1}')"
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert the value to hexadecimal format
|
||||
if ! [[ $VAL =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
VAL="0x$(printf '%x' "$VAL")"
|
||||
fi
|
||||
|
||||
echo "Setting $SYMBOL@$ADDR -> $VAL"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
commands+=" -s 0x20 0x0072a023" # Write wcode of sw x7,0(x5)
|
||||
commands+=" -s 0x21 0x00100073" # Write wcode of ebreak
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x00271005" # Abstract cmd data0->x5 and exec progbuf
|
||||
commands+=" -s 0x04 $VAL" # Write value to DATA0
|
||||
commands+=" -s 0x17 0x00271007" # Abstract cmd data0->x7
|
||||
commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
23
inc/misc/tests/Makefile
Normal file
23
inc/misc/tests/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
all : ci
|
||||
|
||||
EXAMPLES := $(wildcard ../../examples/*/.) $(wildcard ../../examples_v10x/*/.) $(wildcard ../../examples_v20x/*/.) $(wildcard ../../examples_v30x/*/.) $(wildcard ../../examples_x035/*/.)
|
||||
|
||||
.PHONY: ci tests all $(EXAMPLES) clean
|
||||
|
||||
results :
|
||||
mkdir -p results
|
||||
|
||||
$(EXAMPLES) : results
|
||||
echo $(shell basename $(realpath $(lastword $@)))
|
||||
($(MAKE) -C $@ build > results/$(subst .,,$(subst /,_,$@)).txt 2> results/$(subst .,,$(subst /,_,$@)).warning && echo "success" > results/$(subst .,,$(subst /,_,$@)).result) || echo "failure" > results/$(subst .,,$(subst /,_,$@)).result
|
||||
echo $(shell basename $(realpath $(lastword $@))).bin > results/$(subst .,,$(subst /,_,$@)).stat
|
||||
sha1sum $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
wc --bytes $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
|
||||
tests : $(EXAMPLES)
|
||||
|
||||
ci : install tests
|
||||
|
||||
clean :
|
||||
rm -rf results
|
||||
|
||||
1235
src/ch32fun.c
1235
src/ch32fun.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue