Refactored the included files from the ch32fun project.

+ updated as of 2025-12-23
This commit is contained in:
Jake Goodwin 2025-12-23 14:33:54 -08:00
parent 56e38aeeae
commit 7e0b1e3244
58 changed files with 90369 additions and 56430 deletions

File diff suppressed because it is too large Load diff

18083
inc/ch32h41xhw.h Normal file

File diff suppressed because it is too large Load diff

9094
inc/ch32l103hw.h Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

6237
inc/ch32v10xhw.h Normal file

File diff suppressed because it is too large Load diff

8450
inc/ch32v20xhw.h Normal file

File diff suppressed because it is too large Load diff

10625
inc/ch32v30xhw.h Normal file

File diff suppressed because it is too large Load diff

5002
inc/ch32x00xhw.h Normal file

File diff suppressed because it is too large Load diff

6245
inc/ch32x03xhw.h Normal file

File diff suppressed because it is too large Load diff

2645
inc/ch5xxhw.h Normal file

File diff suppressed because it is too large Load diff

5187
inc/ch641hw.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,16 @@
// 2023-06-26 recallmenot // 2023-06-26 recallmenot
// ######## necessities //######## necessities
// include guards // include guards
#ifndef CH32V003_GPIO_BR_H #ifndef CH32V003_GPIO_BR_H
#define CH32V003_GPIO_BR_H #define CH32V003_GPIO_BR_H
// includes // includes
#include "../ch32fun/ch32fun.h"
#include <stdint.h> //uintN_t support #include <stdint.h> //uintN_t support
#include "../ch32fun/ch32fun.h"
/*######## library description /*######## library description
This is a speedy and light GPIO library due to 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 branchless where it counts
*/ */
/*######## library usage and configuration /*######## library usage and configuration
first, enable the desired port. 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 //######## ports, pins and states: use these for the functions below!
{
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
enum GPIO_port_n {
GPIO_port_A = 0b00, GPIO_port_A = 0b00,
GPIO_port_C = 0b10, GPIO_port_C = 0b10,
GPIO_port_D = 0b11, GPIO_port_D = 0b11,
}; };
enum GPIO_pinModes enum GPIO_pinModes {
{
GPIO_pinMode_I_floating, GPIO_pinMode_I_floating,
GPIO_pinMode_I_pullUp, GPIO_pinMode_I_pullUp,
GPIO_pinMode_I_pullDown, GPIO_pinMode_I_pullDown,
@ -117,15 +121,13 @@ enum GPIO_pinModes
GPIO_pinMode_O_openDrainMux, GPIO_pinMode_O_openDrainMux,
}; };
enum lowhigh enum lowhigh {
{
low, low,
high, high,
}; };
// analog inputs // analog inputs
enum GPIO_analog_inputs enum GPIO_analog_inputs {
{
GPIO_Ain0_A2, GPIO_Ain0_A2,
GPIO_Ain1_A1, GPIO_Ain1_A1,
GPIO_Ain2_C4, GPIO_Ain2_C4,
@ -139,8 +141,7 @@ enum GPIO_analog_inputs
}; };
// how many cycles the ADC shall sample the input for (speed vs precision) // how many cycles the ADC shall sample the input for (speed vs precision)
enum GPIO_ADC_sampletimes enum GPIO_ADC_sampletimes {
{
GPIO_ADC_sampletime_3cy, GPIO_ADC_sampletime_3cy,
GPIO_ADC_sampletime_9cy, GPIO_ADC_sampletime_9cy,
GPIO_ADC_sampletime_15cy, GPIO_ADC_sampletime_15cy,
@ -151,23 +152,23 @@ enum GPIO_ADC_sampletimes
GPIO_ADC_sampletime_241cy_default, GPIO_ADC_sampletime_241cy_default,
}; };
enum GPIO_tim1_output_sets enum GPIO_tim1_output_sets {
{
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1, GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1, GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1, GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6, GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
}; };
enum GPIO_tim2_output_sets enum GPIO_tim2_output_sets {
{
GPIO_tim2_output_set_0__D4_D3_C0_D7, GPIO_tim2_output_set_0__D4_D3_C0_D7,
GPIO_tim2_output_set_1__C5_C2_D2_C1, GPIO_tim2_output_set_1__C5_C2_D2_C1,
GPIO_tim2_output_set_2__C1_D3_C0_D7, GPIO_tim2_output_set_2__C1_D3_C0_D7,
GPIO_tim2_output_set_3__C1_C7_D6_D5, GPIO_tim2_output_set_3__C1_C7_D6_D5,
}; };
// ######## interface function overview: use these!
//######## interface function overview: use these!
// most functions have been reduced to function-like macros, actual definitions downstairs // most functions have been reduced to function-like macros, actual definitions downstairs
// setup // setup
@ -201,20 +202,26 @@ static inline void GPIO_tim2_init();
#define GPIO_tim1_analogWrite(channel, value) #define GPIO_tim1_analogWrite(channel, value)
#define GPIO_tim2_analogWrite(channel, value) #define GPIO_tim2_analogWrite(channel, value)
// ######## internal function declarations
// ######## internal variables
// ######## preprocessor macros //######## internal function declarations
#define CONCAT(a, b) a##b
//######## internal variables
//######## preprocessor macros
#define CONCAT(a, b) a ## b
#define CONCAT_INDIRECT(a, b) CONCAT(a, b) #define CONCAT_INDIRECT(a, b) CONCAT(a, b)
#undef GPIOv_from_PORT_PIN #undef GPIOv_from_PORT_PIN
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (pin)) #define GPIOv_from_PORT_PIN( GPIO_port_n, pin ) ((GPIO_port_n << 4 ) | (pin))
#define GPIOv_to_PORT(GPIOv) (GPIOv >> 4) #define GPIOv_to_PORT( GPIOv ) (GPIOv >> 4 )
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111) #define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4))))) #define GPIOv_to_GPIObase( GPIOv ) ((GPIO_TypeDef*)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx #define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx) #define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
@ -283,9 +290,12 @@ static inline void GPIO_tim2_init();
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz #define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
#endif #endif
// ######## define requirements / maintenance defines //######## define requirements / maintenance defines
//######## small function definitions, static inline
// ######## small function definitions, static inline
#undef GPIO_port_enable #undef GPIO_port_enable
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n); #define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
@ -328,7 +338,7 @@ static inline void GPIO_tim2_init();
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv) #define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
#undef GPIO_digitalWrite_branching #undef GPIO_digitalWrite_branching
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv)) #define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? (GPIO_digitalWrite_hi(GPIOv)) : (GPIO_digitalWrite_lo(GPIOv)))
#undef GPIO_digitalRead #undef GPIO_digitalRead
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1) #define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
@ -344,10 +354,24 @@ static inline void GPIO_tim2_init();
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \ #define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
ADC1->SAMPTR2 &= 0; \ ADC1->SAMPTR2 &= 0; \
ADC1->SAMPTR2 |= \ ADC1->SAMPTR2 |= \
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \ GPIO_ADC_sampletime << (0 * 3) \
| 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 &= 0; \
ADC1->SAMPTR1 |= \ 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 #undef GPIO_ADC_set_power
@ -359,19 +383,16 @@ static inline void GPIO_tim2_init();
#undef GPIO_ADC_calibrate #undef GPIO_ADC_calibrate
#define GPIO_ADC_calibrate() ({ \ #define GPIO_ADC_calibrate() ({ \
ADC1->CTLR2 |= ADC_RSTCAL; \ ADC1->CTLR2 |= ADC_RSTCAL; \
while (ADC1->CTLR2 & ADC_RSTCAL) \ while(ADC1->CTLR2 & ADC_RSTCAL); \
; \
ADC1->CTLR2 |= ADC_CAL; \ ADC1->CTLR2 |= ADC_CAL; \
while (ADC1->CTLR2 & ADC_CAL) \ while(ADC1->CTLR2 & ADC_CAL); \
; \
}) })
// large but will likely only ever be called once // large but will likely only ever be called once
static inline void GPIO_ADCinit() static inline void GPIO_ADCinit() {
{
// select ADC clock source // select ADC clock source
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
RCC->CFGR0 &= ~(0x1F << 11); RCC->CFGR0 &= ~(0x1F<<11);
// enable clock to the ADC // enable clock to the ADC
RCC->APB2PCENR |= RCC_APB2Periph_ADC1; RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
@ -396,8 +417,7 @@ static inline void GPIO_ADCinit()
GPIO_ADC_calibrate(); GPIO_ADC_calibrate();
} }
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
{
// set mux to selected input // set mux to selected input
ADC1->RSQR3 = input; ADC1->RSQR3 = input;
// allow everything to precharge // allow everything to precharge
@ -405,11 +425,13 @@ static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
// start sw conversion (auto clears) // start sw conversion (auto clears)
ADC1->CTLR2 |= ADC_SWSTART; ADC1->CTLR2 |= ADC_SWSTART;
// wait for conversion complete // wait for conversion complete
while (!(ADC1->STATR & ADC_EOC)) {} while(!(ADC1->STATR & ADC_EOC)) {}
// get result // get result
return ADC1->RDATAR; return ADC1->RDATAR;
} }
#undef GPIO_tim1_map #undef GPIO_tim1_map
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \ #define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \ RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
@ -422,8 +444,7 @@ static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \ AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
}) })
static inline void GPIO_tim1_init() static inline void GPIO_tim1_init() {
{
// enable TIM1 // enable TIM1
RCC->APB2PCENR |= RCC_APB2Periph_TIM1; RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
// reset TIM1 to init all regs // reset TIM1 to init all regs
@ -444,8 +465,7 @@ static inline void GPIO_tim1_init()
// Enable TIM1 // Enable TIM1
TIM1->CTLR1 |= TIM_CEN; TIM1->CTLR1 |= TIM_CEN;
} }
static inline void GPIO_tim2_init() static inline void GPIO_tim2_init() {
{
// enable TIM2 // enable TIM2
RCC->APB1PCENR |= RCC_APB1Periph_TIM2; RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
// reset TIM2 to init all regs // reset TIM2 to init all regs
@ -480,7 +500,7 @@ static inline void GPIO_tim2_init()
#undef GPIO_tim2_enableCH #undef GPIO_tim2_enableCH
#define GPIO_tim2_enableCH(channel) ({ \ #define GPIO_tim2_enableCH(channel) ({ \
GPIO_timer_channel_set(TIM2, channel); \ GPIO_timer_channel_set(TIM2, channel); \
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \ TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \
}) })
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR)) #define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))

View file

@ -1,15 +1,15 @@
// ######## necessities //######## necessities
// include guards // include guards
#ifndef CH32V003_SPI_H #ifndef CH32V003_SPI_H
#define CH32V003_SPI_H #define CH32V003_SPI_H
// includes // includes
#include<stdint.h> //uintN_t support
#include "ch32fun.h" #include "ch32fun.h"
#include <stdint.h> //uintN_t support
#ifndef APB_CLOCK #ifndef APB_CLOCK
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK #define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
#endif #endif
/*######## library usage and configuration /*######## library usage and configuration
@ -47,7 +47,9 @@ then pick the desired setting of each group:
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually! #define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
*/ */
// ######## function overview (declarations): use these!
//######## function overview (declarations): use these!
// initialize and configure the SPI peripheral // initialize and configure the SPI peripheral
static inline void SPI_init(); static inline void SPI_init();
@ -85,25 +87,31 @@ static inline void SPI_poweron();
static inline void kill_interrrupts(); static inline void kill_interrrupts();
static inline void restore_interrupts(); static inline void restore_interrupts();
// ######## internal function declarations
//######## internal function declarations
static inline void SPI_wait_TX_complete(); static inline void SPI_wait_TX_complete();
static inline uint8_t SPI_is_RX_empty(); static inline uint8_t SPI_is_RX_empty();
static inline void SPI_wait_RX_available(); static inline void SPI_wait_RX_available();
// ######## internal variables
//######## internal variables
static uint16_t EXT1_INTENR_backup; static uint16_t EXT1_INTENR_backup;
// ######## preprocessor macros
//######## preprocessor macros
// min and max helper macros // min and max helper macros
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MAX(a,b) (((a)>(b))?(a):(b))
// stringify for displaying what #defines evaluated to at preprocessor stage // stringify for displaying what #defines evaluated to at preprocessor stage
#define VALUE_TO_STRING(x) #x #define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x) #define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "=" VALUE(var) #define VAR_NAME_VALUE(var) #var "=" VALUE(var)
// compile-time log2 //compile-time log2
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x)) #define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS) // compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
@ -112,28 +120,30 @@ static uint16_t EXT1_INTENR_backup;
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7 // ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)"); _Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER)) #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
// ######## preprocessor #define requirements
//######## preprocessor #define requirements
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX) #if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!" #warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
#endif #endif
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX) #if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
#warning "both CH32V003_SPI_DIRECTION_ options were defined!" #warning "both CH32V003_SPI_DIRECTION_ options were defined!"
#endif #endif
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \ #if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \ (defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \ (defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1 (defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!" #warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
#endif #endif
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \ #if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \ (defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \ (defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0 (defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!" #warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
#endif #endif
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \ #if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
@ -141,220 +151,202 @@ _Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCA
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \ (defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \ (defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1 (defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!" #warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
#endif #endif
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \ #if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \ (defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \ (defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \ (defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0 (defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
#warning "none of the CH32V003_SPI_NSS_ options were defined!" #warning "none of the CH32V003_SPI_NSS_ options were defined!"
#endif #endif
// ######## small function definitions, static inline
static inline void SPI_init()
{ //######## small function definitions, static inline
static inline void SPI_init() {
SPI_poweron(); SPI_poweron();
// reset control register // reset control register
SPI1->CTLR1 = 0; SPI1->CTLR1 = 0;
// set prescaler // set prescaler
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3); SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
// set clock polarity and phase // set clock polarity and phase
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) #if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge); SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) #elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge); SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) #elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge); SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) #elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge); SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
#endif #endif
// configure NSS pin, master mode // configure NSS pin, master mode
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0) #if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1 // _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
GPIOC->CFGLR &= ~(0xf << (4 * 0)); GPIOC->CFGLR &= ~(0xf<<(4*0));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0) AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1) #elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1 // NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
GPIOC->CFGLR &= ~(0xf << (4 * 1)); GPIOC->CFGLR &= ~(0xf<<(4*1));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3) #elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
GPIOC->CFGLR &= ~(0xf << (4 * 3)); GPIOC->CFGLR &= ~(0xf<<(4*3));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4) #elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
GPIOC->CFGLR &= ~(0xf << (4 * 4)); GPIOC->CFGLR &= ~(0xf<<(4*4));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) #elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
#endif #endif
// SCK on PC5, 10MHz Output, alt func, push-pull // SCK on PC5, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf << (4 * 5)); GPIOC->CFGLR &= ~(0xf<<(4*5));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5); GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
// CH32V003 is master // CH32V003 is master
SPI1->CTLR1 |= SPI_Mode_Master; SPI1->CTLR1 |= SPI_Mode_Master;
// set data direction and configure data pins // set data direction and configure data pins
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) #if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex; SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
// MOSI on PC6, 10MHz Output, alt func, push-pull // MOSI on PC6, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf << (4 * 6)); GPIOC->CFGLR &= ~(0xf<<(4*6));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6); GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
// MISO on PC7, 10MHz input, floating // MISO on PC7, 10MHz input, floating
GPIOC->CFGLR &= ~(0xf << (4 * 7)); GPIOC->CFGLR &= ~(0xf<<(4*7));
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 7); GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX) #elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
SPI1->CTLR1 |= SPI_Direction_1Line_Tx; SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
// MOSI on PC6, 10MHz Output, alt func, push-pull // MOSI on PC6, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf << (4 * 6)); GPIOC->CFGLR &= ~(0xf<<(4*6));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6); GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
#endif #endif
} }
static inline void SPI_begin_8() static inline void SPI_begin_8() {
{
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE; SPI1->CTLR1 |= SPI_CTLR1_SPE;
} }
static inline void SPI_begin_16() static inline void SPI_begin_16() {
{
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0 SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE; SPI1->CTLR1 |= SPI_CTLR1_SPE;
} }
static inline void SPI_end() static inline void SPI_end() {
{
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE); SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
} }
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) #if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
static inline void SPI_NSS_software_high() static inline void SPI_NSS_software_high() {
{ GPIOC->BSHR = (1<<3);
GPIOC->BSHR = (1 << 3);
} }
static inline void SPI_NSS_software_low() static inline void SPI_NSS_software_low() {
{ GPIOC->BSHR = (1<<(16+3));
GPIOC->BSHR = (1 << (16 + 3));
} }
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4) #elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
static inline void SPI_NSS_software_high() static inline void SPI_NSS_software_high() {
{ GPIOC->BSHR = (1<<4);
GPIOC->BSHR = (1 << 4);
} }
static inline void SPI_NSS_software_low() static inline void SPI_NSS_software_low() {
{ GPIOC->BSHR = (1<<(16+4));
GPIOC->BSHR = (1 << (16 + 4));
} }
#endif #endif
static inline uint8_t SPI_read_8() static inline uint8_t SPI_read_8() {
{
return SPI1->DATAR; return SPI1->DATAR;
} }
static inline uint16_t SPI_read_16() static inline uint16_t SPI_read_16() {
{
return SPI1->DATAR; return SPI1->DATAR;
} }
static inline void SPI_write_8(uint8_t data) static inline void SPI_write_8(uint8_t data) {
{
SPI1->DATAR = data; SPI1->DATAR = data;
} }
static inline void SPI_write_16(uint16_t data) static inline void SPI_write_16(uint16_t data) {
{
SPI1->DATAR = data; SPI1->DATAR = data;
} }
static inline uint8_t SPI_transfer_8(uint8_t data) static inline uint8_t SPI_transfer_8(uint8_t data) {
{ #if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI_NSS_software_high(); SPI_NSS_software_high();
#endif #endif
SPI_write_8(data); SPI_write_8(data);
SPI_wait_TX_complete(); SPI_wait_TX_complete();
asm volatile("nop"); asm volatile("nop");
SPI_wait_RX_available(); SPI_wait_RX_available();
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4) #if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI_NSS_software_low(); SPI_NSS_software_low();
#endif #endif
return SPI_read_8(); return SPI_read_8();
} }
static inline uint16_t SPI_transfer_16(uint16_t data) static inline uint16_t SPI_transfer_16(uint16_t data) {
{ #if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI_NSS_software_high(); SPI_NSS_software_high();
#endif #endif
SPI_write_16(data); SPI_write_16(data);
SPI_wait_TX_complete(); SPI_wait_TX_complete();
asm volatile("nop"); asm volatile("nop");
SPI_wait_RX_available(); SPI_wait_RX_available();
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4) #if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI_NSS_software_low(); SPI_NSS_software_low();
#endif #endif
return SPI_read_16(); return SPI_read_16();
} }
static inline void SPI_poweroff() static inline void SPI_poweroff() {
{
SPI_end(); SPI_end();
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1; RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
} }
static inline void SPI_poweron() static inline void SPI_poweron() {
{
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
} }
static inline void kill_interrrupts() static inline void kill_interrrupts() {
{
EXT1_INTENR_backup = EXTI->INTENR; EXT1_INTENR_backup = EXTI->INTENR;
// zero the interrupt enable register to disable all interrupts // zero the interrupt enable register to disable all interrupts
EXTI->INTENR = 0; EXTI->INTENR = 0;
} }
static inline void restore_interrupts() static inline void restore_interrupts() {
{
EXTI->INTENR = EXT1_INTENR_backup; EXTI->INTENR = EXT1_INTENR_backup;
} }
// ######## small internal function definitions, static inline
static inline void SPI_wait_TX_complete()
{ //######## small internal function definitions, static inline
while (!(SPI1->STATR & SPI_STATR_TXE)) {} static inline void SPI_wait_TX_complete() {
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
} }
static inline uint8_t SPI_is_RX_empty() static inline uint8_t SPI_is_RX_empty() {
{
return SPI1->STATR & SPI_STATR_RXNE; return SPI1->STATR & SPI_STATR_RXNE;
} }
static inline void SPI_wait_RX_available() static inline void SPI_wait_RX_available() {
{ while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
} }
static inline void SPI_wait_not_busy() static inline void SPI_wait_not_busy() {
{ while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
} }
static inline void SPI_wait_transmit_finished() static inline void SPI_wait_transmit_finished() {
{
SPI_wait_TX_complete(); SPI_wait_TX_complete();
SPI_wait_not_busy(); SPI_wait_not_busy();
} }
// ######## implementation block
// #define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library //######## implementation block
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
#if defined(CH32V003_SPI_IMPLEMENTATION) #if defined(CH32V003_SPI_IMPLEMENTATION)
// no functions here because I think all of the functions are small enough to static inline //no functions here because I think all of the functions are small enough to static inline
#endif // CH32V003_SPI_IMPLEMENTATION #endif // CH32V003_SPI_IMPLEMENTATION
#endif // CH32V003_SPI_H #endif // CH32V003_SPI_H

View file

@ -21,6 +21,8 @@
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations ); sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
*/ */
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation. #define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
// Can either be 0 or 1. // Can either be 0 or 1.
@ -48,13 +50,16 @@
jalr a2, 1\n\ jalr a2, 1\n\
.long 0x00010001\n\ .long 0x00010001\n\
.long 0x00010001\n\ .long 0x00010001\n\
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2"); "\
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
);
static void InitTouchADC();
void InitTouchADC() static void InitTouchADC( );
void InitTouchADC( )
{ {
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2 // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
RCC->CFGR0 &= ~(0x1F << 11); RCC->CFGR0 &= ~(0x1F<<11);
// Set up single conversion on chl 2 // Set up single conversion on chl 2
ADC1->RSQR1 = 0; ADC1->RSQR1 = 0;
@ -65,46 +70,41 @@ void InitTouchADC()
// Reset calibration // Reset calibration
ADC1->CTLR2 |= ADC_RSTCAL; ADC1->CTLR2 |= ADC_RSTCAL;
while (ADC1->CTLR2 & ADC_RSTCAL) while(ADC1->CTLR2 & ADC_RSTCAL);
;
// Calibrate // Calibrate
ADC1->CTLR2 |= ADC_CAL; ADC1->CTLR2 |= ADC_CAL;
while (ADC1->CTLR2 & ADC_CAL) while(ADC1->CTLR2 & ADC_CAL);
;
} }
// Run from RAM to get even more stable timing. // Run from RAM to get even more stable timing.
// This function call takes about 8.1uS to execute. // This function call takes about 8.1uS to execute.
static uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata"))); static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
{ {
uint32_t ret = 0; uint32_t ret = 0;
__disable_irq(); __disable_irq();
FORCEALIGNADC FORCEALIGNADC
ADC1->RSQR3 = adcno; ADC1->RSQR3 = adcno;
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno); ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
__enable_irq(); __enable_irq();
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin))); uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE; uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | CFGBASE; uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
// If we run multiple times with slightly different wait times, we can // If we run multiple times with slightly different wait times, we can
// reduce the impact of the ADC's DNL. // reduce the impact of the ADC's DNL.
#if TOUCH_FLAT == 1 #if TOUCH_FLAT == 1
#define RELEASEIO \ #define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
io->CFGLR = CFGFLOAT;
#else #else
#define RELEASEIO \ #define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
io->CFGLR = CFGFLOAT; \
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
#endif #endif
#define INNER_LOOP(n) \ #define INNER_LOOP( n ) \
{ \ { \
/* Only lock IRQ for a very narrow window. */ \ /* Only lock IRQ for a very narrow window. */ \
__disable_irq(); \ __disable_irq(); \
@ -114,29 +114,28 @@ uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int itera
this We are catching it onthe slope much more effectively. */ \ this We are catching it onthe slope much more effectively. */ \
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \ ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
\ \
ADD_N_NOPS(n) \ ADD_N_NOPS( n ) \
\ \
RELEASEIO \ RELEASEIO \
\ \
/* Sampling actually starts here, somewhere, so we can let other \ /* Sampling actually starts here, somewhere, so we can let other \
interrupts run */ \ interrupts run */ \
__enable_irq(); \ __enable_irq(); \
while (!(ADC1->STATR & ADC_EOC)) \ while(!(ADC1->STATR & ADC_EOC)); \
; \
io->CFGLR = CFGDRIVE; \ io->CFGLR = CFGDRIVE; \
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \ io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
ret += ADC1->RDATAR; \ ret += ADC1->RDATAR; \
} }
int i; int i;
for (i = 0; i < iterations; i++) for( i = 0; i < iterations; i++ )
{ {
// Wait a variable amount of time based on loop iteration, in order // Wait a variable amount of time based on loop iteration, in order
// to get a variety of RC points and minimize DNL. // to get a variety of RC points and minimize DNL.
INNER_LOOP(0); INNER_LOOP( 0 );
INNER_LOOP(2); INNER_LOOP( 2 );
INNER_LOOP(4); INNER_LOOP( 4 );
} }
return ret; return ret;
@ -144,18 +143,18 @@ uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int itera
// Run from RAM to get even more stable timing. // Run from RAM to get even more stable timing.
// This function call takes about 8.1uS to execute. // This function call takes about 8.1uS to execute.
static uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata"))); static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
{ {
uint32_t ret = 0; uint32_t ret = 0;
ADC1->RSQR3 = adcno; ADC1->RSQR3 = adcno;
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno); ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
// If we run multiple times with slightly different wait times, we can // If we run multiple times with slightly different wait times, we can
// reduce the impact of the ADC's DNL. // reduce the impact of the ADC's DNL.
#define INNER_LOOP_SAFE(n) \ #define INNER_LOOP_SAFE( n ) \
{ \ { \
/* Only lock IRQ for a very narrow window. */ \ /* Only lock IRQ for a very narrow window. */ \
__disable_irq(); \ __disable_irq(); \
@ -166,37 +165,37 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
this We are catching it onthe slope much more effectively. */ \ this We are catching it onthe slope much more effectively. */ \
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \ ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
\ \
ADD_N_NOPS(n) \ ADD_N_NOPS( n ) \
\ \
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \ io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \ io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
\ \
/* Sampling actually starts here, somewhere, so we can let other \ /* Sampling actually starts here, somewhere, so we can let other \
interrupts run */ \ interrupts run */ \
__enable_irq(); \ __enable_irq(); \
while (!(ADC1->STATR & ADC_EOC)) \ while(!(ADC1->STATR & ADC_EOC)); \
; \
__disable_irq(); \ __disable_irq(); \
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \ io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
__enable_irq(); \ __enable_irq(); \
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \ io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
ret += ADC1->RDATAR; \ ret += ADC1->RDATAR; \
} }
int i; int i;
for (i = 0; i < iterations; i++) for( i = 0; i < iterations; i++ )
{ {
// Wait a variable amount of time based on loop iteration, in order // Wait a variable amount of time based on loop iteration, in order
// to get a variety of RC points and minimize DNL. // to get a variety of RC points and minimize DNL.
INNER_LOOP_SAFE(0); INNER_LOOP_SAFE( 0 );
INNER_LOOP_SAFE(2); INNER_LOOP_SAFE( 2 );
INNER_LOOP_SAFE(4); INNER_LOOP_SAFE( 4 );
} }
return ret; return ret;
} }
#endif #endif
/* /*
@ -222,3 +221,4 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */

View 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

View file

@ -2,7 +2,7 @@
#define _CH32V307GIGABIT_H #define _CH32V307GIGABIT_H
/* This file is written against the RTL8211E /* This file is written against the RTL8211E
*/ */
// #define CH32V307GIGABIT_MCO25 1 // #define CH32V307GIGABIT_MCO25 1
// #define CH32V307GIGABIT_PHYADDRESS 0 // #define CH32V307GIGABIT_PHYADDRESS 0
@ -42,43 +42,44 @@ typedef struct
// You must provide: // You must provide:
void ch32v307ethHandleReconfig(int link, int speed, int duplex); void ch32v307ethHandleReconfig( int link, int speed, int duplex );
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer) // Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
int ch32v307ethInitHandlePacket(uint8_t *data, int frame_length, ETH_DMADESCTypeDef *dmadesc); int ch32v307ethInitHandlePacket( uint8_t * data, int frame_length, ETH_DMADESCTypeDef * dmadesc );
void ch32v307ethInitHandleTXC(void); void ch32v307ethInitHandleTXC( void );
// This library provides: // This library provides:
static void ch32v307ethGetMacInUC(uint8_t *mac); static void ch32v307ethGetMacInUC( uint8_t * mac );
static int ch32v307ethInit(void); static int ch32v307ethInit( void );
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy. static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
static int ch32v307ethTickPhy(void); static int ch32v307ethTickPhy( void );
// Data pursuent to ethernet. // Data pursuent to ethernet.
uint8_t ch32v307eth_mac[6] = {0}; uint8_t ch32v307eth_mac[6] = { 0 };
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
ETH_DMADESCTypeDef *pDMARxGet; ETH_DMADESCTypeDef * pDMARxGet;
ETH_DMADESCTypeDef *pDMATxSet; ETH_DMADESCTypeDef * pDMATxSet;
// Internal functions // Internal functions
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val); static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
static int ch32v307ethPHYRegAsyncRead(int reg, int *value); static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
static int ch32v307ethPHYRegRead(uint32_t reg); static int ch32v307ethPHYRegRead( uint32_t reg );
static int ch32v307ethPHYRegAsyncRead(int reg, int *value) static int ch32v307ethPHYRegAsyncRead( int reg, int * value )
{ {
static uint8_t reg_request_count = 0; static uint8_t reg_request_count = 0;
uint32_t miiar = ETH->MACMIIAR; uint32_t miiar = ETH->MACMIIAR;
if (miiar & ETH_MACMIIAR_MB) if( miiar & ETH_MACMIIAR_MB )
{ {
return -1; return -1;
} }
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2) if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
{ {
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ | ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA ((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
@ -98,40 +99,41 @@ static int ch32v307ethTickPhy(void)
int speed, linked, duplex; int speed, linked, duplex;
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part) const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
int miidr; int miidr;
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1; if( ch32v307ethPHYRegAsyncRead( reg, &miidr ) ) return -1;
printf("REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid); printf( "REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid );
if (reg == 0x1a) if( reg == 0x1a )
{ {
speed = ((miidr >> 4) & 3); speed = ((miidr>>4)&3);
linked = ((miidr >> 2) & 1); linked = ((miidr>>2)&1);
duplex = ((miidr >> 3) & 1); duplex = ((miidr>>3)&1);
} }
else else
{ {
speed = ((miidr >> 14) & 3); speed = ((miidr>>14)&3);
linked = ((miidr >> 10) & 1); linked = ((miidr>>10)&1);
duplex = ((miidr >> 13) & 1); duplex = ((miidr>>13)&1);
} }
printf("LINK INFO: %d %d %d\n", speed, linked, duplex); printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
if (linked) if( linked )
{ {
uint32_t oldmaccr = ETH->MACCR; uint32_t oldmaccr = ETH->MACCR;
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11); uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
if (newmaccr != oldmaccr) if( newmaccr != oldmaccr )
{ {
ETH->MACCR = newmaccr; ETH->MACCR = newmaccr;
ch32v307ethHandleReconfig(linked, speed, duplex); ch32v307ethHandleReconfig( linked, speed, duplex );
return 1; return 1;
} }
} }
return 0; return 0;
} }
// Based on ETH_WritePHYRegister // Based on ETH_WritePHYRegister
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val) static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
{ {
ETH->MACMIIDR = val; ETH->MACMIIDR = val;
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ | ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
@ -140,14 +142,13 @@ static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB; ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
uint32_t timeout = 0x100000; uint32_t timeout = 0x100000;
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout) while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
;
// If timeout = 0, is an error. // If timeout = 0, is an error.
return timeout ? 0 : -1; return timeout ? 0 : -1;
} }
static int ch32v307ethPHYRegRead(uint32_t reg) static int ch32v307ethPHYRegRead( uint32_t reg )
{ {
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ | ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA ((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
@ -155,45 +156,45 @@ static int ch32v307ethPHYRegRead(uint32_t reg)
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB; (0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
uint32_t timeout = 0x100000; uint32_t timeout = 0x100000;
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout) while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
;
// If timeout = 0, is an error. // If timeout = 0, is an error.
return timeout ? ETH->MACMIIDR : -1; return timeout ? ETH->MACMIIDR : -1;
} }
static void ch32v307ethGetMacInUC(uint8_t *mac)
static void ch32v307ethGetMacInUC( uint8_t * mac )
{ {
// Mac is backwards. // Mac is backwards.
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5); const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
for (int i = 0; i < 6; i++) for( int i = 0; i < 6; i++ )
{ {
mac[i] = *(macaddr--); mac[i] = *(macaddr--);
} }
} }
static int ch32v307ethInit(void) static int ch32v307ethInit( void )
{ {
int i; int i;
#ifdef CH32V307GIGABIT_PHY_RSTB #ifdef CH32V307GIGABIT_PHY_RSTB
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset) funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW); funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
#endif #endif
// Configure strapping. // Configure strapping.
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3 funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2 funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1 funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0 funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
funDigitalWrite(PA1, FUN_HIGH); funDigitalWrite( PA1, FUN_HIGH );
funDigitalWrite(PA0, FUN_HIGH); funDigitalWrite( PA0, FUN_HIGH );
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
funDigitalWrite(PC2, FUN_HIGH); funDigitalWrite( PC2, FUN_HIGH );
// Pull-up MDIO // Pull-up MDIO
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR) funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
funDigitalWrite(PD9, FUN_HIGH); funDigitalWrite( PD9, FUN_HIGH );
// Will be required later. // Will be required later.
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
@ -217,91 +218,88 @@ static int ch32v307ethInit(void)
// Setup clock tree. // Setup clock tree.
RCC->CFGR2 |= RCC->CFGR2 |=
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz (1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz) (1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII (2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz) (7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz (1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
0; 0;
// Power on PLLs // Power on PLLs
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON; RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
int timeout; int timeout;
for (timeout = 10000; timeout > 0; timeout--) for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
if (RCC->CTLR & RCC_PLL3RDY) break; if( timeout == 0 ) return -5;
if (timeout == 0) return -5; for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
for (timeout = 10000; timeout > 0; timeout--) if( timeout == 0 ) return -6;
if (RCC->CTLR & RCC_PLL2RDY) break;
if (timeout == 0) return -6;
// PLL = x18 (0 in register) // PLL = x18 (0 in register)
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0; RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
RCC->CTLR |= RCC_PLLON; RCC->CTLR |= RCC_PLLON;
for (timeout = 10000; timeout > 0; timeout--) for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
if (RCC->CTLR & RCC_PLLRDY) break; if( timeout == 0 ) return -7;
if (timeout == 0) return -7;
// Switch to PLL. // Switch to PLL.
#ifdef CH32V307GIGABIT_MCO25 #ifdef CH32V307GIGABIT_MCO25
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9 << 24); // And output clock on PA8 RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9<<24); // And output clock on PA8
#else #else
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL; RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
#endif #endif
// For clock in. // For clock in.
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125 funPinMode( PB1, GPIO_CFGLR_IN_FLOAT ); //GMII_CLK125
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock. RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
// Power on and reset. // Power on and reset.
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN; RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
RCC->AHBRSTR |= RCC_ETHMACRST; RCC->AHBRSTR |= RCC_ETHMACRST;
RCC->AHBRSTR &= ~RCC_ETHMACRST; RCC->AHBRSTR &=~RCC_ETHMACRST;
ETH->DMABMR |= ETH_DMABMR_SR; ETH->DMABMR |= ETH_DMABMR_SR;
// Wait for reset to complete. // Wait for reset to complete.
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--) for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
{ {
Delay_Us(10); Delay_Us(10);
} }
// Use RGMII // Use RGMII
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL; EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
// For clock output to Ethernet module. // For clock output to Ethernet module.
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
// Release PHY from reset. // Release PHY from reset.
#ifdef CH32V307GIGABIT_PHY_RSTB #ifdef CH32V307GIGABIT_PHY_RSTB
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH); funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
#endif #endif
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
funPinMode(PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD3 funPinMode( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2 funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1 funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0 funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3 funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2 funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1 funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0 funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1 funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1 funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1 funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0] funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
// Configure MDC/MDIO // Configure MDC/MDIO
// Conflicting notes - some say /42, others don't. // Conflicting notes - some say /42, others don't.
@ -309,48 +307,48 @@ static int ch32v307ethInit(void)
// Update MACCR // Update MACCR
ETH->MACCR = ETH->MACCR =
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay ( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames) ( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
(0 << 22) | // Max TX = 2kB (Revisit if looking into jumbo frames) ( 0 << 22 ) | // Max TX = 2kB (Revisit if looking into jumbo frames)
(0 << 21) | // Rated Drive (instead of energy savings mode) (10M PHY only) ( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only) ( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
(0 << 17) | // IFG = 0, 96-bit guard time. ( 0 << 17 ) | // IFG = 0, 96-bit guard time.
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START) ( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
(0 << 12) | // Self Loop = 0 ( 0 << 12 ) | // Self Loop = 0
(0 << 11) | // Full-Duplex Mode (UNSET TO START) ( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums. ( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
(1 << 7) | // APCS (automatically strip frames) ( 1 << 7 ) | // APCS (automatically strip frames)
(1 << 3) | // TE (Transmit enable!) ( 1 << 3 ) | // TE (Transmit enable!)
(1 << 2) | // RE (Receive Enable) ( 1 << 2 ) | // RE (Receive Enable)
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong) ( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
0; 0;
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms. Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
// Reset the physical layer // Reset the physical layer
ch32v307ethPHYRegWrite(PHY_BCR, ch32v307ethPHYRegWrite( PHY_BCR,
PHY_Reset | PHY_Reset |
1 << 12 | // Auto negotiate 1<<12 | // Auto negotiate
1 << 8 | // Duplex 1<<8 | // Duplex
1 << 6 | // Speed Bit. 1<<6 | // Speed Bit.
0); 0 );
// De-assert reset. // De-assert reset.
ch32v307ethPHYRegWrite(PHY_BCR, ch32v307ethPHYRegWrite( PHY_BCR,
1 << 12 | // Auto negotiate 1<<12 | // Auto negotiate
1 << 8 | // Duplex 1<<8 | // Duplex
1 << 6 | // Speed Bit. 1<<6 | // Speed Bit.
0); 0 );
ch32v307ethPHYRegRead(0x03); ch32v307ethPHYRegRead( 0x03 );
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe. ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
if (ch32v307eth_phyid == 0xc916) if( ch32v307eth_phyid == 0xc916 )
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select. ch32v307ethPHYRegWrite( 0x1F, 0x0a43 ); // RTL8211FS needs page select.
ch32v307ethGetMacInUC(ch32v307eth_mac); ch32v307ethGetMacInUC( ch32v307eth_mac );
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5] << 8) | ch32v307eth_mac[4]); ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5]<<8) | ch32v307eth_mac[4]);
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1] << 8) | (ch32v307eth_mac[2] << 16) | (ch32v307eth_mac[3] << 24)); ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1]<<8) | (ch32v307eth_mac[2]<<16) | (ch32v307eth_mac[3]<<24));
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable | ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
ETH_SourceAddrFilter_Disable | ETH_SourceAddrFilter_Disable |
@ -369,7 +367,7 @@ static int ch32v307ethInit(void)
// Configure RX/TX chains. // Configure RX/TX chains.
ETH_DMADESCTypeDef *tdesc; ETH_DMADESCTypeDef *tdesc;
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++) for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
{ {
tdesc = ch32v307eth_DMATxDscrTab + i; tdesc = ch32v307eth_DMATxDscrTab + i;
tdesc->ControlBufferSize = 0; tdesc->ControlBufferSize = 0;
@ -378,7 +376,7 @@ static int ch32v307ethInit(void)
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab; tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
} }
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab; ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++) for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
{ {
tdesc = ch32v307eth_DMARxDscrTab + i; tdesc = ch32v307eth_DMARxDscrTab + i;
tdesc->Status = ETH_DMARxDesc_OWN; tdesc->Status = ETH_DMARxDesc_OWN;
@ -403,7 +401,7 @@ static int ch32v307ethInit(void)
ETH_DMA_IT_AIS | // Abnormal interrupt ETH_DMA_IT_AIS | // Abnormal interrupt
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
NVIC_EnableIRQ(ETH_IRQn); NVIC_EnableIRQ( ETH_IRQn );
// Actually enable receiving process. // Actually enable receiving process.
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF; ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
@ -411,15 +409,15 @@ static int ch32v307ethInit(void)
return 0; return 0;
} }
void ETH_IRQHandler(void) __attribute__((interrupt)); void ETH_IRQHandler( void ) __attribute__((interrupt));
void ETH_IRQHandler(void) void ETH_IRQHandler( void )
{ {
uint32_t int_sta; uint32_t int_sta;
do do
{ {
int_sta = ETH->DMASR; int_sta = ETH->DMASR;
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0) if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
{ {
break; break;
} }
@ -431,7 +429,7 @@ void ETH_IRQHandler(void)
if (int_sta & ETH_DMA_IT_RBU) if (int_sta & ETH_DMA_IT_RBU)
{ {
ETH->DMASR = ETH_DMA_IT_RBU; ETH->DMASR = ETH_DMA_IT_RBU;
if ((INFO->CHIPID & 0xf0) == 0x10) if((INFO->CHIPID & 0xf0) == 0x10)
{ {
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN; ((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
ETH->DMARPDR = 0; ETH->DMARPDR = 0;
@ -441,9 +439,9 @@ void ETH_IRQHandler(void)
} }
// Nominal interrupts. // Nominal interrupts.
if (int_sta & ETH_DMA_IT_NIS) if( int_sta & ETH_DMA_IT_NIS )
{ {
if (int_sta & ETH_DMA_IT_R) if( int_sta & ETH_DMA_IT_R )
{ {
// Received a packet, normally. // Received a packet, normally.
// Status is in Table 27-17 Definitions of RDes0 // Status is in Table 27-17 Definitions of RDes0
@ -454,7 +452,7 @@ void ETH_IRQHandler(void)
ETH->DMASR = ETH_DMA_IT_R; ETH->DMASR = ETH_DMA_IT_R;
uint32_t status = pDMARxGet->Status; uint32_t status = pDMARxGet->Status;
if (status & ETH_DMARxDesc_OWN) break; if( status & ETH_DMARxDesc_OWN ) break;
// We only have a valid packet in a specific situation. // We only have a valid packet in a specific situation.
// So, we take the status, then mask off the bits we care about // So, we take the status, then mask off the bits we care about
@ -472,45 +470,45 @@ void ETH_IRQHandler(void)
int suppress_own = 0; int suppress_own = 0;
if ((status & mask) == eq) if( ( status & mask ) == eq )
{ {
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4; int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
if (frame_length > 0) if( frame_length > 0 )
{ {
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr; uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet); suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
} }
} }
// Otherwise, Invalid Packet // Otherwise, Invalid Packet
// Relinquish control back to underlying hardware. // Relinquish control back to underlying hardware.
if (!suppress_own) if( !suppress_own )
pDMARxGet->Status = ETH_DMARxDesc_OWN; pDMARxGet->Status = ETH_DMARxDesc_OWN;
// Tricky logic for figuring out the next packet. Originally // Tricky logic for figuring out the next packet. Originally
// discussed in ch32v30x_eth.c in ETH_DropRxPkt // discussed in ch32v30x_eth.c in ETH_DropRxPkt
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET) if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr); pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
else else
{ {
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET) if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR); pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
else else
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2)); pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
} }
} while (1); } while( 1 );
} }
if (int_sta & ETH_DMA_IT_T) if( int_sta & ETH_DMA_IT_T )
{ {
ch32v307ethInitHandleTXC(); ch32v307ethInitHandleTXC();
ETH->DMASR = ETH_DMA_IT_T; ETH->DMASR = ETH_DMA_IT_T;
} }
ETH->DMASR = ETH_DMA_IT_NIS; ETH->DMASR = ETH_DMA_IT_NIS;
} }
} while (1); } while( 1 );
} }
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc) static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc)
{ {
// The official SDK waits until ETH_DMATxDesc_TTSS is set. // The official SDK waits until ETH_DMATxDesc_TTSS is set.
// This also provides a transmit timestamp, which could be // This also provides a transmit timestamp, which could be
@ -518,7 +516,7 @@ static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enabl
// But we don't want to do that. // But we don't want to do that.
// We just want to go. If anyone cares, they can check later. // We just want to go. If anyone cares, they can check later.
if (pDMATxSet->Status & ETH_DMATxDesc_OWN) if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
{ {
ETH->DMATPDR = 0; ETH->DMATPDR = 0;
return -1; return -1;
@ -537,7 +535,7 @@ static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enabl
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums. ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
ETH_DMATxDesc_OWN; // Own back to hardware ETH_DMATxDesc_OWN; // Own back to hardware
pDMATxSet = (ETH_DMADESCTypeDef *)pDMATxSet->Buffer2NextDescAddr; pDMATxSet = (ETH_DMADESCTypeDef*)pDMATxSet->Buffer2NextDescAddr;
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it) ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
ETH->DMATPDR = 0; ETH->DMATPDR = 0;
@ -545,4 +543,6 @@ static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enabl
return 0; return 0;
} }
#endif #endif

1036
inc/extralibs/fsusb.c Normal file

File diff suppressed because it is too large Load diff

419
inc/extralibs/fsusb.h Normal file
View 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

File diff suppressed because it is too large Load diff

475
inc/extralibs/hsusb.h Normal file
View 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

View file

@ -2,25 +2,25 @@
#include "ch32fun.h" #include "ch32fun.h"
#include <string.h> #include <string.h>
#define UEP_CTRL_H(n) (((uint16_t *)&USBHSD->UEP0_TX_CTRL)[n * 2]) #define UEP_CTRL_H(n) (((uint16_t*)&USBHSD->UEP0_TX_CTRL)[n*2])
struct _USBState HSUSBCTX; struct _USBState HSUSBCTX;
// based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM // based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM
// Mask for the combined USBHSD->INT_FG + USBHSD->INT_ST // Mask for the combined USBHSD->INT_FG + USBHSD->INT_ST
#define CRB_U_IS_NAK (1 << 7) #define CRB_U_IS_NAK (1<<7)
#define CTOG_MATCH_SYNC (1 << 6) #define CTOG_MATCH_SYNC (1<<6)
#define CRB_UIF_SETUP_ACT (1 << 5) // CRB_U_SIE_FREE on USBFS #define CRB_UIF_SETUP_ACT (1<<5) // CRB_U_SIE_FREE on USBFS
#define CRB_UIF_FIFO_OV (1 << 4) #define CRB_UIF_FIFO_OV (1<<4)
#define CRB_UIF_HST_SOF (1 << 3) #define CRB_UIF_HST_SOF (1<<3)
#define CRB_UIF_SUSPEND (1 << 2) #define CRB_UIF_SUSPEND (1<<2)
#define CRB_UIF_TRANSFER (1 << 1) #define CRB_UIF_TRANSFER (1<<1)
#define CRB_UIF_BUS_RST (1 << 0) #define CRB_UIF_BUS_RST (1<<0)
#define CSETUP_ACT (1 << 15) #define CSETUP_ACT (1<<15)
#define CRB_UIS_TOG_OK (1 << 14) #define CRB_UIS_TOG_OK (1<<14)
#define CMASK_UIS_TOKEN (3 << 12) #define CMASK_UIS_TOKEN (3<<12)
#define CMASK_UIS_ENDP (0xf << 8) #define CMASK_UIS_ENDP (0xf<<8)
#define CUIS_TOKEN_OUT 0x0 #define CUIS_TOKEN_OUT 0x0
#define CUIS_TOKEN_SOF 0x1 #define CUIS_TOKEN_SOF 0x1
@ -44,7 +44,7 @@ static inline void DMA7FastCopy( uint8_t * dest, const uint8_t * src, int len )
DMA_MemoryInc_Enable | DMA_MemoryInc_Enable |
DMA_PeripheralInc_Enable | DMA_PeripheralInc_Enable |
DMA_Mode_Normal | DMA_CFGR1_EN; DMA_Mode_Normal | DMA_CFGR1_EN;
#if !(FUSB_CURSED_TURBO_DMA == 1) #if !( FUSB_CURSED_TURBO_DMA == 1 )
// Somehow, it seems to work (unsafely) without this. // Somehow, it seems to work (unsafely) without this.
// Really, though, it's probably fine. // Really, though, it's probably fine.
while( DMA1_Channel7->CNTR ); while( DMA1_Channel7->CNTR );
@ -57,11 +57,11 @@ static inline void DMA7FastCopyComplete() { while( DMA1_Channel7->CNTR ); }
void USBHS_InternalFinishSetup(); void USBHS_InternalFinishSetup();
// void USBHSWakeUp_IRQHandler(void) __attribute((interrupt)); //void USBHSWakeUp_IRQHandler(void) __attribute((interrupt));
// void USBHSWakeUp_IRQHandler(void) //void USBHSWakeUp_IRQHandler(void)
//{ //{
// printf( "USBHSWakeUp MSTATUS:%08x MTVAL:%08x MCAUSE:%08x MEPC:%08x\n", (int)__get_MSTATUS(), (int)__get_MTVAL(), (int)__get_MCAUSE(), (int)__get_MEPC() ); // printf( "USBHSWakeUp MSTATUS:%08x MTVAL:%08x MCAUSE:%08x MEPC:%08x\n", (int)__get_MSTATUS(), (int)__get_MTVAL(), (int)__get_MCAUSE(), (int)__get_MEPC() );
// } //}
extern uint8_t scratchpad[]; extern uint8_t scratchpad[];
void USBHS_IRQHandler(void) __attribute((interrupt)); void USBHS_IRQHandler(void) __attribute((interrupt));
@ -69,12 +69,12 @@ void USBHS_IRQHandler(void)
{ {
// Based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM/User/ch32v30x_usbhs_device.c // Based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM/User/ch32v30x_usbhs_device.c
// Combined FG + ST flag // Combined FG + ST flag
uint16_t intfgst = *(uint16_t *)(&USBHSD->INT_FG); uint16_t intfgst = *(uint16_t*)(&USBHSD->INT_FG);
int len = 0; int len = 0;
struct _USBState *ctx = &HSUSBCTX; struct _USBState * ctx = &HSUSBCTX;
uint8_t *ctrl0buff = CTRL0BUFF; uint8_t * ctrl0buff = CTRL0BUFF;
if (intfgst & (CRB_UIF_SETUP_ACT)) if( intfgst & ( CRB_UIF_SETUP_ACT ) )
{ {
// On the Chapter 22 USB, SETUP Requests are handled here instead of in UIF_TRANSFER, with TOKEN_SETUP. // On the Chapter 22 USB, SETUP Requests are handled here instead of in UIF_TRANSFER, with TOKEN_SETUP.
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
@ -85,43 +85,43 @@ void USBHS_IRQHandler(void)
int USBHS_SetupReqCode = HSUSBCTX.USBHS_SetupReqCode = pUSBHS_SetupReqPak->bRequest; int USBHS_SetupReqCode = HSUSBCTX.USBHS_SetupReqCode = pUSBHS_SetupReqPak->bRequest;
int USBHS_SetupReqLen = HSUSBCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength; int USBHS_SetupReqLen = HSUSBCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength;
int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex; int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex;
int USBHS_IndexValue = HSUSBCTX.USBHS_IndexValue = (pUSBHS_SetupReqPak->wIndex << 16) | pUSBHS_SetupReqPak->wValue; int USBHS_IndexValue = HSUSBCTX.USBHS_IndexValue = ( pUSBHS_SetupReqPak->wIndex << 16 ) | pUSBHS_SetupReqPak->wValue;
len = 0; len = 0;
// printf( "Setup: %d %d %d %d %d\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen, //printf( "Setup: %d %d %d %d %d\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen,
// USBHS_SetupReqIndex, USBHS_IndexValue ); // USBHS_SetupReqIndex, USBHS_IndexValue );
if ((USBHS_SetupReqType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
{ {
#if HUSB_HID_INTERFACES > 0 #if HUSB_HID_INTERFACES > 0
if ((USBHS_SetupReqType & USB_REQ_TYP_MASK) == USB_REQ_TYP_CLASS) if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS )
{ {
/* Class Request */ /* Class Request */
// printf( "REQ: %d [%02x %02x %04x %04x]\n", USBHS_SetupReqCode, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest, pUSBHS_SetupReqPak->wValue, pUSBHS_SetupReqPak->wLength ); //printf( "REQ: %d [%02x %02x %04x %04x]\n", USBHS_SetupReqCode, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest, pUSBHS_SetupReqPak->wValue, pUSBHS_SetupReqPak->wLength );
switch (USBHS_SetupReqCode) switch( USBHS_SetupReqCode )
{ {
case HID_SET_REPORT: case HID_SET_REPORT:
#if HUSB_HID_USER_REPORTS #if HUSB_HID_USER_REPORTS
len = HandleHidUserSetReportSetup(ctx, pUSBHS_SetupReqPak); len = HandleHidUserSetReportSetup( ctx, pUSBHS_SetupReqPak );
if (len < 0) goto sendstall; if( len < 0 ) goto sendstall;
ctx->USBHS_SetupReqLen = len; ctx->USBHS_SetupReqLen = len;
USBHSD->UEP0_TX_LEN = 0; USBHSD->UEP0_TX_LEN = 0;
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1;
goto replycomplete; goto replycomplete;
case HID_GET_REPORT: case HID_GET_REPORT:
len = HandleHidUserGetReportSetup(ctx, pUSBHS_SetupReqPak); len = HandleHidUserGetReportSetup( ctx, pUSBHS_SetupReqPak );
if (len < 0) goto sendstall; if( len < 0 ) goto sendstall;
ctx->USBHS_SetupReqLen = len; ctx->USBHS_SetupReqLen = len;
len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len; len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len;
if (!ctx->pCtrlPayloadPtr) if( !ctx->pCtrlPayloadPtr )
{ {
len = HandleHidUserReportDataIn(ctx, ctrl0buff, len); len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
} }
else else
{ {
// DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
ctx->pCtrlPayloadPtr += len; ctx->pCtrlPayloadPtr += len;
} }
USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_LEN = len;
@ -131,27 +131,28 @@ void USBHS_IRQHandler(void)
#endif #endif
break; break;
case HID_SET_IDLE: case HID_SET_IDLE:
if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
HSUSBCTX.USBHS_HidIdle[USBHS_SetupReqIndex] = (uint8_t)(USBHS_IndexValue >> 8); HSUSBCTX.USBHS_HidIdle[ USBHS_SetupReqIndex ] = (uint8_t)( USBHS_IndexValue >> 8 );
break; break;
case HID_SET_PROTOCOL: case HID_SET_PROTOCOL:
if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) if ( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex] = (uint8_t)USBHS_IndexValue; HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex] = (uint8_t)USBHS_IndexValue;
break; break;
case HID_GET_IDLE: case HID_GET_IDLE:
if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
{ {
ctrl0buff[0] = HSUSBCTX.USBHS_HidIdle[USBHS_SetupReqIndex]; ctrl0buff[0] = HSUSBCTX.USBHS_HidIdle[ USBHS_SetupReqIndex ];
len = 1; len = 1;
} }
break; break;
case HID_GET_PROTOCOL: case HID_GET_PROTOCOL:
if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) if( USBHS_SetupReqIndex < HUSB_HID_INTERFACES )
{ {
ctrl0buff[0] = HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex]; ctrl0buff[0] = HSUSBCTX.USBHS_HidProtocol[ USBHS_SetupReqIndex ];
len = 1; len = 1;
} }
break; break;
@ -168,36 +169,37 @@ void USBHS_IRQHandler(void)
else else
{ {
/* usb standard request processing */ /* usb standard request processing */
switch (USBHS_SetupReqCode) switch( USBHS_SetupReqCode )
{ {
/* get device/configuration/string/report/... descriptors */ /* get device/configuration/string/report/... descriptors */
case USB_GET_DESCRIPTOR: case USB_GET_DESCRIPTOR:
{ {
const struct descriptor_list_struct *e = descriptor_list; const struct descriptor_list_struct * e = descriptor_list;
const struct descriptor_list_struct *e_end = e + DESCRIPTOR_LIST_ENTRIES; const struct descriptor_list_struct * e_end = e + DESCRIPTOR_LIST_ENTRIES;
for (; e != e_end; e++) for( ; e != e_end; e++ )
{ {
if (e->lIndexValue == USBHS_IndexValue) if( e->lIndexValue == USBHS_IndexValue )
{ {
ctx->pCtrlPayloadPtr = (uint8_t *)e->addr; ctx->pCtrlPayloadPtr = (uint8_t*)e->addr;
len = e->length; len = e->length;
break; break;
} }
} }
if (e == e_end) if( e == e_end )
{ {
goto sendstall; goto sendstall;
} }
/* Copy Descriptors to Endp0 DMA buffer */ /* Copy Descriptors to Endp0 DMA buffer */
int totalLen = USBHS_SetupReqLen; int totalLen = USBHS_SetupReqLen;
if (totalLen > len) if( totalLen > len )
{ {
totalLen = len; totalLen = len;
} }
len = (totalLen >= DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : totalLen; len = ( totalLen >= DEF_USBD_UEP0_SIZE ) ? DEF_USBD_UEP0_SIZE : totalLen;
// DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //memcpy( CTRL0BUFF, ctx->pCtrlPayloadPtr, len ); //DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //memcpy( CTRL0BUFF, ctx->pCtrlPayloadPtr, len );
memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
ctx->USBHS_SetupReqLen = totalLen - len; ctx->USBHS_SetupReqLen = totalLen - len;
ctx->pCtrlPayloadPtr += len; ctx->pCtrlPayloadPtr += len;
USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_LEN = len;
@ -207,29 +209,29 @@ void USBHS_IRQHandler(void)
/* Set usb address */ /* Set usb address */
case USB_SET_ADDRESS: case USB_SET_ADDRESS:
ctx->USBHS_DevAddr = (uint16_t)(ctx->USBHS_IndexValue & 0xFF); ctx->USBHS_DevAddr = (uint16_t)( ctx->USBHS_IndexValue & 0xFF );
break; break;
/* Get usb configuration now set */ /* Get usb configuration now set */
case USB_GET_CONFIGURATION: case USB_GET_CONFIGURATION:
ctrl0buff[0] = ctx->USBHS_DevConfig; ctrl0buff[0] = ctx->USBHS_DevConfig;
if (ctx->USBHS_SetupReqLen > 1) if( ctx->USBHS_SetupReqLen > 1 )
ctx->USBHS_SetupReqLen = 1; ctx->USBHS_SetupReqLen = 1;
break; break;
/* Set usb configuration to use */ /* Set usb configuration to use */
case USB_SET_CONFIGURATION: case USB_SET_CONFIGURATION:
ctx->USBHS_DevConfig = (uint8_t)(ctx->USBHS_IndexValue & 0xFF); ctx->USBHS_DevConfig = (uint8_t)( ctx->USBHS_IndexValue & 0xFF );
ctx->USBHS_DevEnumStatus = 0x01; ctx->USBHS_DevEnumStatus = 0x01;
break; break;
/* Clear or disable one usb feature */ /* Clear or disable one usb feature */
case USB_CLEAR_FEATURE: case USB_CLEAR_FEATURE:
#if HUSB_SUPPORTS_SLEEP #if HUSB_SUPPORTS_SLEEP
if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
{ {
/* clear one device feature */ /* clear one device feature */
if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_REMOTE_WAKEUP) if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
{ {
/* clear usb sleep status, device not prepare to sleep */ /* clear usb sleep status, device not prepare to sleep */
ctx->USBHS_DevSleepStatus &= ~0x01; ctx->USBHS_DevSleepStatus &= ~0x01;
@ -241,13 +243,13 @@ void USBHS_IRQHandler(void)
} }
else else
#endif #endif
if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
{ {
if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_ENDP_HALT) if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
{ {
/* Clear End-point Feature */ /* Clear End-point Feature */
int ep = USBHS_SetupReqIndex & 0xf; int ep = USBHS_SetupReqIndex & 0xf;
if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
{ {
UEP_CTRL_H(ep) = USBHS_UEP_T_TOG_DATA0 | USBHS_UEP_T_RES_NAK; UEP_CTRL_H(ep) = USBHS_UEP_T_TOG_DATA0 | USBHS_UEP_T_RES_NAK;
} }
@ -269,11 +271,11 @@ void USBHS_IRQHandler(void)
/* set or enable one usb feature */ /* set or enable one usb feature */
case USB_SET_FEATURE: case USB_SET_FEATURE:
if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
{ {
#if HUSB_SUPPORTS_SLEEP #if HUSB_SUPPORTS_SLEEP
/* Set Device Feature */ /* Set Device Feature */
if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_REMOTE_WAKEUP) if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
{ {
/* Set Wake-up flag, device prepare to sleep */ /* Set Wake-up flag, device prepare to sleep */
USBHS_DevSleepStatus |= 0x01; USBHS_DevSleepStatus |= 0x01;
@ -284,14 +286,14 @@ void USBHS_IRQHandler(void)
goto sendstall; goto sendstall;
} }
} }
else if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) else if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
{ {
/* Set Endpoint Feature */ /* Set Endpoint Feature */
if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_ENDP_HALT) if( (uint8_t)( USBHS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
{ {
int ep = USBHS_SetupReqIndex & 0xf; int ep = USBHS_SetupReqIndex & 0xf;
if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
UEP_CTRL_H(ep) = (UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_STALL; UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_STALL;
} }
else else
goto sendstall; goto sendstall;
@ -303,7 +305,7 @@ void USBHS_IRQHandler(void)
/* This request allows the host to select another setting for the specified interface */ /* This request allows the host to select another setting for the specified interface */
case USB_GET_INTERFACE: case USB_GET_INTERFACE:
ctrl0buff[0] = 0x00; ctrl0buff[0] = 0x00;
if (USBHS_SetupReqLen > 1) USBHS_SetupReqLen = 1; if( USBHS_SetupReqLen > 1 ) USBHS_SetupReqLen = 1;
break; break;
case USB_SET_INTERFACE: case USB_SET_INTERFACE:
@ -313,25 +315,25 @@ void USBHS_IRQHandler(void)
case USB_GET_STATUS: case USB_GET_STATUS:
ctrl0buff[0] = 0x00; ctrl0buff[0] = 0x00;
ctrl0buff[1] = 0x00; ctrl0buff[1] = 0x00;
if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
{ {
#if FUSB_SUPPORTS_SLEEP #if FUSB_SUPPORTS_SLEEP
ctrl0buff[0] = (ctx->USBHS_DevSleepStatus & 0x01) << 1; ctrl0buff[0] = (ctx->USBHS_DevSleepStatus & 0x01)<<1;
#else #else
ctrl0buff[0] = 0x00; ctrl0buff[0] = 0x00;
#endif #endif
} }
else if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) else if( ( USBHS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
{ {
int ep = USBHS_SetupReqIndex & 0xf; int ep = USBHS_SetupReqIndex & 0xf;
if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) if( ( USBHS_SetupReqIndex & DEF_UEP_IN ) && ep < HUSB_CONFIG_EPS )
ctrl0buff[0] = (UEP_CTRL_H(ep) & USBHS_UEP_T_RES_MASK) == USBHS_UEP_T_RES_STALL; ctrl0buff[0] = ( UEP_CTRL_H(ep) & USBHS_UEP_T_RES_MASK ) == USBHS_UEP_T_RES_STALL;
else else
goto sendstall; goto sendstall;
} }
else else
goto sendstall; goto sendstall;
if (USBHS_SetupReqLen > 2) if( USBHS_SetupReqLen > 2 )
USBHS_SetupReqLen = 2; USBHS_SetupReqLen = 2;
break; break;
@ -341,18 +343,19 @@ void USBHS_IRQHandler(void)
} }
} }
{ {
/* end-point 0 data Tx/Rx */ /* end-point 0 data Tx/Rx */
if (USBHS_SetupReqType & DEF_UEP_IN) if( USBHS_SetupReqType & DEF_UEP_IN )
{ {
len = (USBHS_SetupReqLen > DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : USBHS_SetupReqLen; len = ( USBHS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBHS_SetupReqLen;
USBHS_SetupReqLen -= len; USBHS_SetupReqLen -= len;
USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_LEN = len;
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
} }
else else
{ {
if (USBHS_SetupReqLen == 0) if( USBHS_SetupReqLen == 0 )
{ {
USBHSD->UEP0_TX_LEN = 0; USBHSD->UEP0_TX_LEN = 0;
USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK;
@ -372,22 +375,23 @@ void USBHS_IRQHandler(void)
// if one request not support, return stall. Stall means permanent error. // 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_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; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_STALL;
replycomplete:; replycomplete:
;
} }
if (intfgst & (CRB_UIF_TRANSFER)) if( intfgst & ( CRB_UIF_TRANSFER ) )
{ {
int token = (intfgst & CMASK_UIS_TOKEN) >> 12; int token = ( intfgst & CMASK_UIS_TOKEN) >> 12;
int ep = (intfgst & CMASK_UIS_ENDP) >> 8; int ep = ( intfgst & CMASK_UIS_ENDP ) >> 8;
switch (token) switch ( token )
{ {
case CUIS_TOKEN_IN: case CUIS_TOKEN_IN:
if (ep) if( ep )
{ {
if (ep < HUSB_CONFIG_EPS) if( ep < HUSB_CONFIG_EPS )
{ {
UEP_CTRL_H(ep) = (UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK; UEP_CTRL_H(ep) = ( UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_NAK;
UEP_CTRL_H(ep) ^= USBHS_UEP_T_TOG_DATA1; UEP_CTRL_H(ep) ^= USBHS_UEP_T_TOG_DATA1;
ctx->USBHS_Endp_Busy[ep] = 0; ctx->USBHS_Endp_Busy[ ep ] = 0;
// Don't set EP in here. Wait for out. // Don't set EP in here. Wait for out.
// Optimization: Could we set EP here? // Optimization: Could we set EP here?
} }
@ -395,19 +399,19 @@ void USBHS_IRQHandler(void)
else else
{ {
/* end-point 0 data in interrupt */ /* end-point 0 data in interrupt */
if (ctx->USBHS_SetupReqLen == 0) if( ctx->USBHS_SetupReqLen == 0 )
{ {
USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK;
} }
if (ctx->pCtrlPayloadPtr) if( ctx->pCtrlPayloadPtr )
{ {
// Shortcut mechanism, for descriptors or if the user wants it. // Shortcut mechanism, for descriptors or if the user wants it.
len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen; len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen;
// DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA //DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA
memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); memcpy( ctrl0buff, ctx->pCtrlPayloadPtr, len );
ctx->USBHS_SetupReqLen -= len; ctx->USBHS_SetupReqLen -= len;
if (ctx->USBHS_SetupReqLen > 0) if( ctx->USBHS_SetupReqLen > 0 )
ctx->pCtrlPayloadPtr += len; ctx->pCtrlPayloadPtr += len;
else else
ctx->pCtrlPayloadPtr = 0; ctx->pCtrlPayloadPtr = 0;
@ -415,13 +419,14 @@ void USBHS_IRQHandler(void)
USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_LEN = len;
USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1; USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
} }
else if ((ctx->USBHS_SetupReqType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) else if ( ( ctx->USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
{ {
#if HUSB_HID_USER_REPORTS #if HUSB_HID_USER_REPORTS
len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen; len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen;
if (len && HSUSBCTX.USBHS_SetupReqCode == HID_GET_REPORT) if( len && HSUSBCTX.USBHS_SetupReqCode == HID_GET_REPORT )
{ {
len = HandleHidUserReportDataIn(ctx, ctrl0buff, len); len = HandleHidUserReportDataIn( ctx, ctrl0buff, len );
USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_LEN = len;
USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1; USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
ctx->USBHS_SetupReqLen -= len; ctx->USBHS_SetupReqLen -= len;
@ -431,7 +436,7 @@ void USBHS_IRQHandler(void)
} }
else else
{ {
switch (HSUSBCTX.USBHS_SetupReqCode) switch( HSUSBCTX.USBHS_SetupReqCode )
{ {
case USB_GET_DESCRIPTOR: case USB_GET_DESCRIPTOR:
break; break;
@ -448,7 +453,7 @@ void USBHS_IRQHandler(void)
/* data-out stage processing */ /* data-out stage processing */
case CUIS_TOKEN_OUT: case CUIS_TOKEN_OUT:
switch (ep) switch( ep )
{ {
/* end-point 0 data out interrupt */ /* end-point 0 data out interrupt */
case DEF_UEP0: case DEF_UEP0:
@ -456,38 +461,38 @@ void USBHS_IRQHandler(void)
// XXX WARNINGS: // XXX WARNINGS:
// 1. intfgst & CRB_UIS_TOG_OK is not set for non-odd transactions, i.e. first, third, etc, are all fine. // 1. intfgst & CRB_UIS_TOG_OK is not set for non-odd transactions, i.e. first, third, etc, are all fine.
// 2. HandleHidUserReportOutComplete doesn't seem to work. // 2. HandleHidUserReportOutComplete doesn't seem to work.
// if( intfgst & CRB_UIS_TOG_OK ) //if( intfgst & CRB_UIS_TOG_OK )
#if HUSB_HID_USER_REPORTS #if HUSB_HID_USER_REPORTS
int len = USBHSD->RX_LEN; int len = USBHSD->RX_LEN;
uint8_t *cptr = ctx->pCtrlPayloadPtr; uint8_t * cptr = ctx->pCtrlPayloadPtr;
if (!cptr) if( !cptr )
{ {
HandleHidUserReportDataOut(ctx, ctrl0buff, len); HandleHidUserReportDataOut( ctx, ctrl0buff, len );
} }
else else
{ {
int remain = ctx->USBHS_SetupReqLen - len; int remain = ctx->USBHS_SetupReqLen - len;
if (remain < 0) if( remain < 0 )
{ {
len += remain; len += remain;
remain = 0; remain = 0;
} }
// DMA7FastCopy( cptr, ctrl0buff, len ); //DMA7FastCopy( cptr, ctrl0buff, len );
memcpy(cptr, ctrl0buff, len); memcpy( cptr, ctrl0buff, len );
ctx->USBHS_SetupReqLen = remain; ctx->USBHS_SetupReqLen = remain;
if (remain > 0) if( remain > 0 )
ctx->pCtrlPayloadPtr = cptr + len; ctx->pCtrlPayloadPtr = cptr + len;
else else
ctx->pCtrlPayloadPtr = 0; ctx->pCtrlPayloadPtr = 0;
} }
#endif #endif
if (ctx->USBHS_SetupReqLen == 0) if( ctx->USBHS_SetupReqLen == 0 )
{ {
#if HUSB_HID_USER_REPORTS #if HUSB_HID_USER_REPORTS
// DMA7FastCopyComplete(); //DMA7FastCopyComplete();
HandleHidUserReportOutComplete(ctx); HandleHidUserReportOutComplete( ctx );
#endif #endif
} }
@ -498,10 +503,10 @@ void USBHS_IRQHandler(void)
} }
default: default:
// Any other out. (also happens with In) // Any other out. (also happens with In)
HSUSBCTX.USBHS_Endp_Busy[ep] = 0x02; HSUSBCTX.USBHS_Endp_Busy[ ep ] = 0x02;
USBHSD_UEP_RXCTRL(ep) = ((USBHSD_UEP_RXCTRL(ep)) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK; USBHSD_UEP_RXCTRL( ep ) = ((USBHSD_UEP_RXCTRL( ep )) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
#if HUSB_BULK_USER_REPORTS #if HUSB_BULK_USER_REPORTS
HandleGotEPComplete(ctx, ep); HandleGotEPComplete( ctx, ep );
#endif #endif
break; break;
} }
@ -510,11 +515,11 @@ void USBHS_IRQHandler(void)
case CUIS_TOKEN_SOF: // Sof pack processing case CUIS_TOKEN_SOF: // Sof pack processing
break; break;
default: default :
break; break;
} }
} }
if (intfgst & USBHS_UIF_BUS_RST) if(intfgst & USBHS_UIF_BUS_RST)
{ {
/* usb reset interrupt processing */ /* usb reset interrupt processing */
ctx->USBHS_DevConfig = 0; ctx->USBHS_DevConfig = 0;
@ -523,18 +528,18 @@ void USBHS_IRQHandler(void)
ctx->USBHS_DevEnumStatus = 0; ctx->USBHS_DevEnumStatus = 0;
USBHSD->DEV_AD = 0; USBHSD->DEV_AD = 0;
USBHS_InternalFinishSetup(); USBHS_InternalFinishSetup( );
} }
if (intfgst & USBHS_UIF_SUSPEND) if(intfgst & USBHS_UIF_SUSPEND)
{ {
USBHSD->INT_FG = USBHS_UIF_SUSPEND; USBHSD->INT_FG = USBHS_UIF_SUSPEND;
Delay_Us(10); Delay_Us(10);
// USB suspend interrupt processing // USB suspend interrupt processing
if (USBHSD->MIS_ST & USBHS_UMS_SUSPEND) if(USBHSD->MIS_ST & USBHS_UMS_SUSPEND)
{ {
HSUSBCTX.USBHS_DevSleepStatus |= 0x02; HSUSBCTX.USBHS_DevSleepStatus |= 0x02;
if (HSUSBCTX.USBHS_DevSleepStatus == 0x03) if(HSUSBCTX.USBHS_DevSleepStatus == 0x03)
{ {
// TODO: Handle usb sleep here // TODO: Handle usb sleep here
} }
@ -550,16 +555,21 @@ void USBHS_IRQHandler(void)
void USBHS_InternalFinishSetup() void USBHS_InternalFinishSetup()
{ {
// To reconfigure your endpoints for TX/RX do it here. // To reconfigure your endpoints for TX/RX do it here.
#if HUSB_CONFIG_EPS > 5 #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 #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 #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 #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 #elif HUSB_CONFIG_EPS > 1
USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN; USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN;
#else #else
@ -600,12 +610,12 @@ void USBHS_InternalFinishSetup()
UEP_CTRL_H(0) = USBHS_UEP_R_RES_ACK | USBHS_UEP_T_RES_NAK; UEP_CTRL_H(0) = USBHS_UEP_R_RES_ACK | USBHS_UEP_T_RES_NAK;
int i; int i;
for (i = 1; i < HUSB_CONFIG_EPS; i++) for( i = 1; i < HUSB_CONFIG_EPS; i++ )
UEP_CTRL_H(i) = USBFS_UEP_T_RES_NAK; UEP_CTRL_H(i) = USBFS_UEP_T_RES_NAK;
for (uint8_t i = 0; i < sizeof(HSUSBCTX.USBHS_Endp_Busy) / sizeof(HSUSBCTX.USBHS_Endp_Busy[0]); i++) for(uint8_t i=0; i< sizeof(HSUSBCTX.USBHS_Endp_Busy)/sizeof(HSUSBCTX.USBHS_Endp_Busy[0]); i++ )
{ {
HSUSBCTX.USBHS_Endp_Busy[i] = 0; HSUSBCTX.USBHS_Endp_Busy[ i ] = 0;
} }
} }
@ -649,3 +659,5 @@ int HSUSBSetup()
// Go on-bus. // Go on-bus.
return 0; return 0;
} }

View file

@ -7,10 +7,10 @@
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
*/ */
#include "ch32fun.h"
#include "usb_config.h"
#include "usb_defines.h"
#include <stdint.h> #include <stdint.h>
#include "ch32fun.h"
#include "usb_defines.h"
#include "usb_config.h"
struct _USBState struct _USBState
{ {
@ -26,12 +26,12 @@ struct _USBState
uint8_t USBHS_DevSleepStatus; uint8_t USBHS_DevSleepStatus;
uint8_t USBHS_DevEnumStatus; uint8_t USBHS_DevEnumStatus;
uint8_t *pCtrlPayloadPtr; uint8_t * pCtrlPayloadPtr;
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64]; uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0]) #define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF) #define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
#if HUSB_HID_INTERFACES > 0 #if HUSB_HID_INTERFACES > 0
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES]; uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
@ -46,35 +46,36 @@ uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8
// Implement the following: // Implement the following:
#if HUSB_HID_USER_REPORTS #if HUSB_HID_USER_REPORTS
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req); int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
int HandleHidUserSetReportSetup(struct _USBState *ctx, tusb_control_request_t *req); int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
void HandleHidUserReportDataOut(struct _USBState *ctx, uint8_t *data, int len); void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len); int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
void HandleHidUserReportOutComplete(struct _USBState *ctx); void HandleHidUserReportOutComplete( struct _USBState * ctx );
#endif #endif
#if HUSB_BULK_USER_REPORTS #if HUSB_BULK_USER_REPORTS
void HandleGotEPComplete(struct _USBState *ctx, int ep); void HandleGotEPComplete( struct _USBState * ctx, int ep );
#endif #endif
extern struct _USBState HSUSBCTX; extern struct _USBState HSUSBCTX;
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp ) // To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
static inline uint8_t *USBHS_GetEPBufferIfAvailable(int endp) static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
{ {
if (HSUSBCTX.USBHS_Endp_Busy[endp]) return 0; if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
return USBHSD_UEP_TXBUF(endp); return USBHSD_UEP_TXBUF( endp );
} }
static inline void USBHS_SendEndpoint(int endp, int len, const uint8_t *data) static inline void USBHS_SendEndpoint( int endp, int len, const uint8_t * data )
{ {
if (endp) if( endp )
{ {
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data; (((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
} }
USBHSD_UEP_TLEN(endp) = len; USBHSD_UEP_TLEN( endp ) = len;
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK; USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01; HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
} }
#endif #endif

852
inc/extralibs/iSLER.h Normal file
View 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
View 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
View 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;
}

View file

@ -1,30 +1,30 @@
/****************************************************************************** /******************************************************************************
* Psuedo Random Number Generator using a Linear Feedback Shift Register * Psuedo Random Number Generator using a Linear Feedback Shift Register
* See the GitHub for more information: * See the GitHub for more information:
* https://github.com/ADBeta/CH32V003_lib_rand * https://github.com/ADBeta/CH32V003_lib_rand
* *
* Ver 1.1 09 Sep 2024 * Ver 1.1 09 Sep 2024
* *
* Released under the MIT Licence * Released under the MIT Licence
* Copyright ADBeta (c) 2024 * Copyright ADBeta (c) 2024
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to * of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the * deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is * sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE. * USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/ ******************************************************************************/
#ifndef CH32V003_LIB_RAND #ifndef CH32V003_LIB_RAND
#define CH32V003_LIB_RAND #define CH32V003_LIB_RAND
@ -35,12 +35,13 @@
// Example: #define RANDOM_STRENGTH 2 // Example: #define RANDOM_STRENGTH 2
#ifndef RANDOM_STRENGTH #ifndef RANDOM_STRENGTH
#error "Error in lib_rand. Must define RANDOM_STRENGTH" #error "Error in lib_rand. Must define RANDOM_STRENGTH"
#endif #endif
// @brief set the random LFSR values seed by default to a known-good value // @brief set the random LFSR values seed by default to a known-good value
static uint32_t _rand_lfsr = 0x747AA32F; static uint32_t _rand_lfsr = 0x747AA32F;
/*** Library specific Functions - Do Not Use *********************************/ /*** Library specific Functions - Do Not Use *********************************/
/****************************************************************************/ /****************************************************************************/
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting /// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
@ -64,6 +65,7 @@ uint8_t _rand_lfsr_update(void)
return msb >> 31; return msb >> 31;
} }
/// @brief Generates a Random 32-bit number, using the LFSR - by generating /// @brief Generates a Random 32-bit number, using the LFSR - by generating
/// a random bit from LFSR taps, 32 times. /// a random bit from LFSR taps, 32 times.
/// @param None /// @param None
@ -73,7 +75,7 @@ uint32_t _rand_gen_32b(void)
uint32_t rand_out = 0; uint32_t rand_out = 0;
uint8_t bits = 32; uint8_t bits = 32;
while (bits--) while(bits--)
{ {
// Shift the current rand value for the new LSB // Shift the current rand value for the new LSB
rand_out = rand_out << 1; rand_out = rand_out << 1;
@ -84,15 +86,17 @@ uint32_t _rand_gen_32b(void)
return rand_out; return rand_out;
} }
/// @brief Generates a Random n-bit number, using the LFSR - by generating /// @brief Generates a Random n-bit number, using the LFSR - by generating
/// a random bit from LFSR taps, n times. /// a random bit from LFSR taps, n times.
/// @param None /// @param None
/// @return a (psuedo)random n-bit value /// @return a (psuedo)random n-bit value
uint32_t _rand_gen_nb(int bits) uint32_t _rand_gen_nb( int bits)
{ {
uint32_t rand_out = 0; uint32_t rand_out = 0;
while (bits--) while(bits--)
{ {
// Shift the current rand value for the new LSB // Shift the current rand value for the new LSB
rand_out = rand_out << 1; rand_out = rand_out << 1;
@ -103,6 +107,7 @@ uint32_t _rand_gen_nb(int bits)
return rand_out; return rand_out;
} }
/*** API Functions ***********************************************************/ /*** API Functions ***********************************************************/
/*****************************************************************************/ /*****************************************************************************/
/// @brief seeds the Random LFSR to the value passed /// @brief seeds the Random LFSR to the value passed
@ -113,6 +118,7 @@ void seed(const uint32_t seed_val)
_rand_lfsr = seed_val; _rand_lfsr = seed_val;
} }
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH /// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
/// you have selected /// you have selected
/// @param None /// @param None
@ -121,26 +127,26 @@ uint32_t rand(void)
{ {
uint32_t rand_out = 0; uint32_t rand_out = 0;
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it // If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
#if RANDOM_STRENGTH == 1 #if RANDOM_STRENGTH == 1
// Update the LFSR, discard result, and return _lsfr raw // Update the LFSR, discard result, and return _lsfr raw
(void)_rand_lfsr_update(); (void)_rand_lfsr_update();
rand_out = _rand_lfsr; rand_out = _rand_lfsr;
#endif #endif
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random // If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
// bits from the LFSR // bits from the LFSR
#if RANDOM_STRENGTH == 2 #if RANDOM_STRENGTH == 2
rand_out = _rand_gen_32b(); rand_out = _rand_gen_32b();
#endif #endif
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them // If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
// together // together
#if RANDOM_STRENGTH == 3 #if RANDOM_STRENGTH == 3
uint32_t rand_a = _rand_gen_32b(); uint32_t rand_a = _rand_gen_32b();
uint32_t rand_b = _rand_gen_32b(); uint32_t rand_b = _rand_gen_32b();
rand_out = rand_a ^ rand_b; rand_out = rand_a ^ rand_b;
#endif #endif
return rand_out; return rand_out;
} }

View 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
View 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);
}

View file

@ -6,19 +6,19 @@
#ifndef _SSD1306_H #ifndef _SSD1306_H
#define _SSD1306_H #define _SSD1306_H
#include "font_8x8.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "font_8x8.h"
// comfortable packet size for this OLED // comfortable packet size for this OLED
#define SSD1306_PSZ 32 #define SSD1306_PSZ 32
#if defined(SSD1306_CUSTOM) #if defined (SSD1306_CUSTOM)
// Let the caller configure the OLED. // Let the caller configure the OLED.
#else #else
// characteristics of each type // 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" #error "Please define the SSD1306_WXH resolution used in your application"
#endif #endif
#ifdef SSD1306_64X32 #ifdef SSD1306_64X32
@ -28,6 +28,13 @@
#define SSD1306_OFFSET 32 #define SSD1306_OFFSET 32
#endif #endif
#ifdef SSD1306_72X40
#define SSD1306_W 72
#define SSD1306_H 40
#define SSD1306_FULLUSE
#define SSD1306_OFFSET 28
#endif
#ifdef SSD1306_128X32 #ifdef SSD1306_128X32
#define SSD1306_W 128 #define SSD1306_W 128
#define SSD1306_H 32 #define SSD1306_H 32
@ -98,13 +105,13 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
/* choose VCC mode */ /* choose VCC mode */
#define SSD1306_EXTERNALVCC 0x1 #define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2 #define SSD1306_SWITCHCAPVCC 0x2
// #define vccstate SSD1306_EXTERNALVCC //#define vccstate SSD1306_EXTERNALVCC
#define vccstate SSD1306_SWITCHCAPVCC #define vccstate SSD1306_SWITCHCAPVCC
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY #if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
// OLED initialization commands for 128x32 // OLED initialization commands for 128x32
const uint8_t ssd1306_init_array[] = const uint8_t ssd1306_init_array[] =
{ {
#ifdef SH1107 #ifdef SH1107
SSD1306_DISPLAYOFF, // Turn OLED off SSD1306_DISPLAYOFF, // Turn OLED off
0x00, // Low column 0x00, // Low column
@ -114,7 +121,7 @@ const uint8_t ssd1306_init_array[] =
SSD1306_SETCONTRAST, 0x6f, // Set constrast SSD1306_SETCONTRAST, 0x6f, // Set constrast
SSD1306_COLUMNADDR, // Set memory addressing mode SSD1306_COLUMNADDR, // Set memory addressing mode
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.) SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // Iterate over all 128 rows (Multiplex Ratio) SSD1306_SETMULTIPLEX, (SSD1306_H-1), // Iterate over all 128 rows (Multiplex Ratio)
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different) SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness) SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
@ -125,15 +132,17 @@ const uint8_t ssd1306_init_array[] =
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best. SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
SSD1306_SETCONTRAST, 0xfe, // Set constrast SSD1306_SETCONTRAST, 0xfe, // Set constrast
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // 128-wide. SSD1306_SETMULTIPLEX, (SSD1306_H-1), // 128-wide.
SSD1306_DISPLAYON, // Display on. SSD1306_DISPLAYON, // Display on.
#else #else
SSD1306_DISPLAYOFF, // 0xAE SSD1306_DISPLAYOFF, // 0xAE
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5 SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
0x80, // the suggested ratio 0x80 0x80, // the suggested ratio 0x80
SSD1306_SETMULTIPLEX, // 0xA8 SSD1306_SETMULTIPLEX, // 0xA8
#ifdef SSD1306_64X32 #if defined(SSD1306_64X32)
0x1F, // for 64-wide displays 0x1F, // for 64-wide displays
#elif defined(SSD1306_72X40)
0x27,
#else #else
0x3F, // for 128-wide displays 0x3F, // for 128-wide displays
#endif #endif
@ -147,9 +156,17 @@ const uint8_t ssd1306_init_array[] =
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
SSD1306_COMSCANDEC, SSD1306_COMSCANDEC,
SSD1306_SETCOMPINS, // 0xDA SSD1306_SETCOMPINS, // 0xDA
#if defined(SSD1306_FULLUSE)
0x12, // 0x12, //
#else
0x22, //
#endif
SSD1306_SETCONTRAST, // 0x81 SSD1306_SETCONTRAST, // 0x81
#ifdef SSD1306_72X40
0xAF,
#else
0x8F, 0x8F,
#endif
SSD1306_SETPRECHARGE, // 0xd9 SSD1306_SETPRECHARGE, // 0xd9
0xF1, 0xF1,
SSD1306_SETVCOMDETECT, // 0xDB SSD1306_SETVCOMDETECT, // 0xDB
@ -165,7 +182,7 @@ const uint8_t ssd1306_init_array[] =
#endif #endif
// the display buffer // the display buffer
uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8]; uint8_t ssd1306_buffer[SSD1306_W*SSD1306_H/8];
/* /*
* set the buffer to a color * set the buffer to a color
@ -175,31 +192,6 @@ void ssd1306_setbuf(uint8_t color)
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer)); 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 * Send the frame buffer
*/ */
@ -211,59 +203,32 @@ void ssd1306_refresh(void)
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode. ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
for (i = 0; i < SSD1306_H / 8; i++) for(i=0;i<SSD1306_H/8;i++)
{ {
ssd1306_cmd(0xb0 | i); ssd1306_cmd(0xb0 | i);
ssd1306_cmd(0x00 | (0 & 0xf)); ssd1306_cmd( 0x00 | (0&0xf) );
ssd1306_cmd(0x10 | (0 >> 4)); ssd1306_cmd( 0x10 | (0>>4) );
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 0 * SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+0*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 1 * SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+1*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 2 * SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+2*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 3 * SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+3*SSD1306_PSZ], SSD1306_PSZ);
} }
#else #else
ssd1306_cmd(SSD1306_COLUMNADDR); ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset) ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset) ssd1306_cmd(SSD1306_OFFSET+SSD1306_W-1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR); ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset) ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address ssd1306_cmd(7); // Page end address
#ifdef SSD1306_FULLUSE for(i=0;i<sizeof(ssd1306_buffer);i+=SSD1306_PSZ)
/* for fully used rows just plow thru everything */
for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ)
{ {
/* send PSZ block of data */ /* send PSZ block of data */
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ); 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 #endif
} }
/* /*
@ -274,19 +239,19 @@ void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
uint32_t addr; uint32_t addr;
/* clip */ /* clip */
if (x >= SSD1306_W) if(x >= SSD1306_W)
return; return;
if (y >= SSD1306_H) if(y >= SSD1306_H)
return; return;
/* compute buffer address */ /* compute buffer address */
addr = x + SSD1306_W * (y / 8); addr = x + SSD1306_W*(y/8);
/* set/clear bit in buffer */ /* set/clear bit in buffer */
if (color) if(color)
ssd1306_buffer[addr] |= (1 << (y & 7)); ssd1306_buffer[addr] |= (1<<(y&7));
else else
ssd1306_buffer[addr] &= ~(1 << (y & 7)); ssd1306_buffer[addr] &= ~(1<<(y&7));
} }
/* /*
@ -297,34 +262,31 @@ void ssd1306_xorPixel(uint32_t x, uint32_t y)
uint32_t addr; uint32_t addr;
/* clip */ /* clip */
if (x >= SSD1306_W) if(x >= SSD1306_W)
return; return;
if (y >= SSD1306_H) if(y >= SSD1306_H)
return; return;
/* compute buffer address */ /* compute buffer address */
addr = x + SSD1306_W * (y / 8); addr = x + SSD1306_W*(y/8);
ssd1306_buffer[addr] ^= (1 << (y & 7)); ssd1306_buffer[addr] ^= (1<<(y&7));
} }
/* /*
* draw a an image from an array, directly into to the display buffer * draw a an image from an array, directly into to the display buffer
* the color modes allow for overwriting and even layering (sprites!) * 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 x_absolute;
uint32_t y_absolute; uint32_t y_absolute;
uint32_t pixel; uint32_t pixel;
uint32_t bytes_to_draw = width / 8; uint32_t bytes_to_draw = width / 8;
uint32_t buffer_addr; uint32_t buffer_addr;
for (uint32_t line = 0; line < height; line++) for (uint32_t line = 0; line < height; line++) {
{
y_absolute = y + line; y_absolute = y + line;
if (y_absolute >= SSD1306_H) if (y_absolute >= SSD1306_H) {
{
break; 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 // bitmask for current pixel in vertical (output) byte
uint32_t v_mask = 1 << (y_absolute & 7); 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]; 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; x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W) if (x_absolute >= SSD1306_W) {
{
break; break;
} }
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8 // 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 // state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel); uint8_t input_pixel = input_byte & (1 << pixel);
switch (color_mode) switch (color_mode) {
{
case 0: case 0:
// write pixels as they are // write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0); ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
@ -376,13 +334,13 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint3
break; break;
} }
} }
#if SSD1306_LOG_IMAGE == 1 #if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte); printf("%02x ", input_byte);
#endif #endif
} }
#if SSD1306_LOG_IMAGE == 1 #if SSD1306_LOG_IMAGE == 1
printf("\n\r"); printf("\n\r");
#endif #endif
} }
} }
@ -392,9 +350,9 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint3
void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{ {
// clipping // clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return; if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if ((y + h - 1) >= SSD1306_H) h = SSD1306_H - y; if((y+h-1) >= SSD1306_H) h = SSD1306_H-y;
while (h--) while(h--)
{ {
ssd1306_drawPixel(x, y++, color); ssd1306_drawPixel(x, y++, color);
} }
@ -406,8 +364,8 @@ void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color) void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
{ {
// clipping // clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return; if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if ((x + w - 1) >= SSD1306_W) w = SSD1306_W - x; if((x+w-1) >= SSD1306_W) w = SSD1306_W-x;
while (w--) while (w--)
{ {
@ -420,7 +378,7 @@ void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
*/ */
int gfx_abs(int x) int gfx_abs(int x)
{ {
return (x < 0) ? -x : x; return (x<0) ? -x : x;
} }
/* /*
@ -444,14 +402,14 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
/* flip sense 45deg to keep error calc in range */ /* flip sense 45deg to keep error calc in range */
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0)); steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
if (steep) if(steep)
{ {
gfx_swap(&x0, &y0); gfx_swap(&x0, &y0);
gfx_swap(&x1, &y1); gfx_swap(&x1, &y1);
} }
/* run low->high */ /* run low->high */
if (x0 > x1) if(x0 > x1)
{ {
gfx_swap(&x0, &x1); gfx_swap(&x0, &x1);
gfx_swap(&y0, &y1); gfx_swap(&y0, &y1);
@ -460,18 +418,18 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
/* set up loop initial conditions */ /* set up loop initial conditions */
deltax = x1 - x0; deltax = x1 - x0;
deltay = gfx_abs(y1 - y0); deltay = gfx_abs(y1 - y0);
error = deltax / 2; error = deltax/2;
y = y0; y = y0;
if (y0 < y1) if(y0 < y1)
ystep = 1; ystep = 1;
else else
ystep = -1; ystep = -1;
/* loop x */ /* loop x */
for (x = x0; x <= x1; x++) for(x=x0;x<=x1;x++)
{ {
/* plot point */ /* plot point */
if (steep) if(steep)
/* flip point & plot */ /* flip point & plot */
ssd1306_drawPixel(y, x, color); ssd1306_drawPixel(y, x, color);
else else
@ -482,7 +440,7 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
error = error - deltay; error = error - deltay;
/* update y */ /* update y */
if (error < 0) if(error < 0)
{ {
y = y + ystep; y = y + ystep;
error = error + deltax; error = error + deltax;
@ -501,23 +459,19 @@ void ssd1306_drawCircle(int x, int y, int radius, int color)
int err = 2 - 2 * radius; int err = 2 - 2 * radius;
int e2; 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);
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; e2 = err;
if (e2 <= y_pos) if (e2 <= y_pos) {
{
err += ++y_pos * 2 + 1; err += ++y_pos * 2 + 1;
if (-x_pos == y_pos && e2 <= x_pos) if(-x_pos == y_pos && e2 <= x_pos) {
{
e2 = 0; e2 = 0;
} }
} }
if (e2 > x_pos) if (e2 > x_pos) {
{
err += ++x_pos * 2 + 1; err += ++x_pos * 2 + 1;
} }
} while (x_pos <= 0); } 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 err = 2 - 2 * radius;
int e2; 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);
ssd1306_drawPixel(x + x_pos, y - y_pos, color); ssd1306_drawPixel(x + x_pos, y - y_pos, color);
@ -543,19 +496,16 @@ 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);
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; e2 = err;
if (e2 <= y_pos) if (e2 <= y_pos) {
{
err += ++y_pos * 2 + 1; err += ++y_pos * 2 + 1;
if (-x_pos == y_pos && e2 <= x_pos) if(-x_pos == y_pos && e2 <= x_pos) {
{
e2 = 0; e2 = 0;
} }
} }
if (e2 > x_pos) if(e2 > x_pos) {
{
err += ++x_pos * 2 + 1; err += ++x_pos * 2 + 1;
} }
} while (x_pos <= 0); } while(x_pos <= 0);
} }
/* /*
@ -564,9 +514,9 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color) void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color)
{ {
ssd1306_drawFastVLine(x, y, h, color); ssd1306_drawFastVLine(x, y, h, color);
ssd1306_drawFastVLine(x + w - 1, y, h, color); ssd1306_drawFastVLine(x+w-1, y, h, color);
ssd1306_drawFastHLine(x, y, w, color); ssd1306_drawFastHLine(x, y, w, color);
ssd1306_drawFastHLine(x, y + h - 1, w, color); ssd1306_drawFastHLine(x, y+h-1, w, color);
} }
/* /*
@ -574,15 +524,15 @@ void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t col
*/ */
void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color) void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color)
{ {
uint32_t m, n = y, iw = w; uint32_t m, n=y, iw = w;
/* scan vertical */ /* scan vertical */
while (h--) while(h--)
{ {
m = x; m=x;
w = iw; w=iw;
/* scan horizontal */ /* scan horizontal */
while (w--) while(w--)
{ {
/* invert pixels */ /* invert pixels */
ssd1306_drawPixel(m++, n, color); ssd1306_drawPixel(m++, n, color);
@ -596,15 +546,15 @@ void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t co
*/ */
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h) void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{ {
uint8_t m, n = y, iw = w; uint8_t m, n=y, iw = w;
/* scan vertical */ /* scan vertical */
while (h--) while(h--)
{ {
m = x; m=x;
w = iw; w=iw;
/* scan horizontal */ /* scan horizontal */
while (w--) while(w--)
{ {
/* invert pixels */ /* invert pixels */
ssd1306_xorPixel(m++, n); ssd1306_xorPixel(m++, n);
@ -621,17 +571,17 @@ void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
uint16_t i, j, col; uint16_t i, j, col;
uint8_t d; uint8_t d;
for (i = 0; i < 8; i++) for(i=0;i<8;i++)
{ {
d = fontdata[(chr << 3) + i]; d = fontdata[(chr<<3)+i];
for (j = 0; j < 8; j++) for(j=0;j<8;j++)
{ {
if (d & 0x80) if(d&0x80)
col = color; col = color;
else else
col = (~color) & 1; col = (~color)&1;
ssd1306_drawPixel(x + j, y + i, col); ssd1306_drawPixel(x+j, y+i, col);
// next bit // next bit
d <<= 1; d <<= 1;
@ -646,11 +596,11 @@ void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
{ {
uint8_t c; uint8_t c;
while ((c = *str++)) while((c=*str++))
{ {
ssd1306_drawchar(x, y, c, color); ssd1306_drawchar(x, y, c, color);
x += 8; x += 8;
if (x > 120) if(x>120)
break; break;
} }
} }
@ -658,8 +608,7 @@ void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
/* /*
* enum for font size * enum for font size
*/ */
typedef enum typedef enum {
{
fontsize_8x8 = 1, fontsize_8x8 = 1,
fontsize_16x16 = 2, fontsize_16x16 = 2,
fontsize_32x32 = 4, 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; col = (~color) & 1;
// Draw the pixel at the original size and scaled size using nested for-loops // 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 k = 0; k < font_scale; k++) {
{ for (uint8_t l = 0; l < font_scale; l++) {
for (uint8_t l = 0; l < font_scale; l++)
{
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col); ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
} }
} }
@ -714,11 +661,11 @@ void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_siz
{ {
uint8_t c; uint8_t c;
while ((c = *str++)) while((c=*str++))
{ {
ssd1306_drawchar_sz(x, y, c, color, font_size); ssd1306_drawchar_sz(x, y, c, color, font_size);
x += 8 * font_size; x += 8 * font_size;
if (x > 128 - 8 * font_size) if(x>128 - 8 * font_size)
break; break;
} }
} }
@ -736,13 +683,12 @@ uint8_t ssd1306_init(void)
// initialize OLED // initialize OLED
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY #if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array; uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while (*cmd_list != SSD1306_TERMINATE_CMDS) while(*cmd_list != SSD1306_TERMINATE_CMDS)
{ {
if (ssd1306_cmd(*cmd_list++)) if(ssd1306_cmd(*cmd_list++))
return 1; return 1;
} }
// clear display
ssd1306_refresh(); ssd1306_refresh();
#endif #endif

View file

@ -27,14 +27,14 @@
#define TIMEOUT_MAX 100000 #define TIMEOUT_MAX 100000
// uncomment this to enable IRQ-driven operation // uncomment this to enable IRQ-driven operation
// #define SSD1306_I2C_IRQ //#define SSD1306_I2C_IRQ
#ifdef SSD1306_I2C_IRQ #ifdef SSD1306_I2C_IRQ
// some stuff that IRQ mode needs // some stuff that IRQ mode needs
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state; volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
// uncomment this to enable time diags in IRQ // uncomment this to enable time diags in IRQ
// #define IRQ_DIAG //#define IRQ_DIAG
#endif #endif
/* /*
@ -51,22 +51,22 @@ void ssd1306_i2c_setup(void)
// set freq // set freq
tempreg = I2C1->CTLR2; tempreg = I2C1->CTLR2;
tempreg &= ~I2C_CTLR2_FREQ; tempreg &= ~I2C_CTLR2_FREQ;
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ; tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
I2C1->CTLR2 = tempreg; I2C1->CTLR2 = tempreg;
// Set clock config // Set clock config
tempreg = 0; tempreg = 0;
#if (SSD1306_I2C_CLKRATE <= 100000) #if (SSD1306_I2C_CLKRATE <= 100000)
// standard mode good to 100kHz // standard mode good to 100kHz
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR; tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
#else #else
// fast mode over 100kHz // fast mode over 100kHz
#ifndef SSD1306_I2C_DUTY #ifndef SSD1306_I2C_DUTY
// 33% duty cycle // 33% duty cycle
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR; tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
#else #else
// 36% duty cycle // 36% duty cycle
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR; tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
tempreg |= I2C_CKCFGR_DUTY; tempreg |= I2C_CKCFGR_DUTY;
#endif #endif
tempreg |= I2C_CKCFGR_FS; tempreg |= I2C_CKCFGR_FS;
@ -92,7 +92,7 @@ void ssd1306_i2c_setup(void)
* error descriptions * error descriptions
*/ */
char *errstr[] = char *errstr[] =
{ {
"not busy", "not busy",
"master mode", "master mode",
"transmit mode", "transmit mode",
@ -125,7 +125,7 @@ uint8_t ssd1306_i2c_error(uint8_t err)
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask) uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
{ {
/* read order matters here! STAR1 before STAR2!! */ /* read order matters here! STAR1 before STAR2!! */
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16); uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
return (status & event_mask) == event_mask; return (status & event_mask) == event_mask;
} }
@ -138,20 +138,19 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
int32_t timeout; int32_t timeout;
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
GPIOC->BSHR = (1 << (3)); GPIOC->BSHR = (1<<(3));
#endif #endif
// error out if buffer under/overflow // error out if buffer under/overflow
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz) if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
return 2; return 2;
// wait for previous packet to finish // wait for previous packet to finish
while (ssd1306_i2c_irq_state) while(ssd1306_i2c_irq_state);
;
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
GPIOC->BSHR = (1 << (16 + 3)); GPIOC->BSHR = (1<<(16+3));
GPIOC->BSHR = (1 << (4)); GPIOC->BSHR = (1<<(4));
#endif #endif
// init buffer for sending // init buffer for sending
@ -161,9 +160,8 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
// wait for not busy // wait for not busy
timeout = TIMEOUT_MAX; timeout = TIMEOUT_MAX;
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--)) while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
; if(timeout==-1)
if (timeout == -1)
return ssd1306_i2c_error(0); return ssd1306_i2c_error(0);
// Set START condition // Set START condition
@ -171,19 +169,17 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
// wait for master mode select // wait for master mode select
timeout = TIMEOUT_MAX; 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)
if (timeout == -1)
return ssd1306_i2c_error(1); return ssd1306_i2c_error(1);
// send 7-bit address + write flag // send 7-bit address + write flag
I2C1->DATAR = addr << 1; I2C1->DATAR = addr<<1;
// wait for transmit condition // wait for transmit condition
timeout = TIMEOUT_MAX; 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)
if (timeout == -1)
return ssd1306_i2c_error(2); return ssd1306_i2c_error(2);
// Enable TXE interrupt // Enable TXE interrupt
@ -191,7 +187,7 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
ssd1306_i2c_irq_state = 1; ssd1306_i2c_irq_state = 1;
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
GPIOC->BSHR = (1 << (16 + 4)); GPIOC->BSHR = (1<<(16+4));
#endif #endif
// exit // exit
@ -207,7 +203,7 @@ void I2C1_EV_IRQHandler(void)
uint16_t STAR1, STAR2 __attribute__((unused)); uint16_t STAR1, STAR2 __attribute__((unused));
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
GPIOC->BSHR = (1 << (4)); GPIOC->BSHR = (1<<(4));
#endif #endif
// read status, clear any events // read status, clear any events
@ -215,14 +211,14 @@ void I2C1_EV_IRQHandler(void)
STAR2 = I2C1->STAR2; STAR2 = I2C1->STAR2;
/* check for TXE */ /* check for TXE */
if (STAR1 & I2C_STAR1_TXE) if(STAR1 & I2C_STAR1_TXE)
{ {
/* check for remaining data */ /* check for remaining data */
if (ssd1306_i2c_send_sz--) if(ssd1306_i2c_send_sz--)
I2C1->DATAR = *ssd1306_i2c_send_ptr++; I2C1->DATAR = *ssd1306_i2c_send_ptr++;
/* was that the last byte? */ /* was that the last byte? */
if (!ssd1306_i2c_send_sz) if(!ssd1306_i2c_send_sz)
{ {
// disable TXE interrupt // disable TXE interrupt
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN); I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
@ -231,8 +227,7 @@ void I2C1_EV_IRQHandler(void)
ssd1306_i2c_irq_state = 0; ssd1306_i2c_irq_state = 0;
// wait for tx complete // 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 // set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP; I2C1->CTLR1 |= I2C_CTLR1_STOP;
@ -240,7 +235,7 @@ void I2C1_EV_IRQHandler(void)
} }
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
GPIOC->BSHR = (1 << (16 + 4)); GPIOC->BSHR = (1<<(16+4));
#endif #endif
} }
#else #else
@ -253,9 +248,8 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
// wait for not busy // wait for not busy
timeout = TIMEOUT_MAX; timeout = TIMEOUT_MAX;
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--)) while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
; if(timeout==-1)
if (timeout == -1)
return ssd1306_i2c_error(0); return ssd1306_i2c_error(0);
// Set START condition // Set START condition
@ -263,29 +257,26 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
// wait for master mode select // wait for master mode select
timeout = TIMEOUT_MAX; 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)
if (timeout == -1)
return ssd1306_i2c_error(1); return ssd1306_i2c_error(1);
// send 7-bit address + write flag // send 7-bit address + write flag
I2C1->DATAR = addr << 1; I2C1->DATAR = addr<<1;
// wait for transmit condition // wait for transmit condition
timeout = TIMEOUT_MAX; 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)
if (timeout == -1)
return ssd1306_i2c_error(2); return ssd1306_i2c_error(2);
// send data one byte at a time // send data one byte at a time
while (sz--) while(sz--)
{ {
// wait for TX Empty // wait for TX Empty
timeout = TIMEOUT_MAX; timeout = TIMEOUT_MAX;
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--)) while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
; if(timeout==-1)
if (timeout == -1)
return ssd1306_i2c_error(3); return ssd1306_i2c_error(3);
// send command // send command
@ -294,9 +285,8 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
// wait for tx complete // wait for tx complete
timeout = TIMEOUT_MAX; 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)
if (timeout == -1)
return ssd1306_i2c_error(4); return ssd1306_i2c_error(4);
// set STOP condition // set STOP condition
@ -315,7 +305,7 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
uint8_t pkt[33]; uint8_t pkt[33];
/* build command or data packets */ /* build command or data packets */
if (cmd) if(cmd)
{ {
pkt[0] = 0; pkt[0] = 0;
pkt[1] = *data; pkt[1] = *data;
@ -325,7 +315,7 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
pkt[0] = 0x40; pkt[0] = 0x40;
memcpy(&pkt[1], data, sz); memcpy(&pkt[1], data, sz);
} }
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1); return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
} }
/* /*
@ -341,32 +331,32 @@ uint8_t ssd1306_i2c_init(void)
#ifdef SSD1306_REMAP_I2C #ifdef SSD1306_REMAP_I2C
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP; AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD); funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD); funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
#else #else
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD); funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD); funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
#endif #endif
#else #else
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO; RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
// PC1 is SDA, 10MHz Output, alt func, open-drain // PC1 is SDA, 10MHz Output, alt func, open-drain
GPIOC->CFGLR &= ~(0xf << (4 * 1)); GPIOC->CFGLR &= ~(0xf<<(4*1));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
// PC2 is SCL, 10MHz Output, alt func, open-drain // PC2 is SCL, 10MHz Output, alt func, open-drain
GPIOC->CFGLR &= ~(0xf << (4 * 2)); GPIOC->CFGLR &= ~(0xf<<(4*2));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
#endif #endif
#ifdef IRQ_DIAG #ifdef IRQ_DIAG
// GPIO diags on PC3/PC4 // GPIO diags on PC3/PC4
GPIOC->CFGLR &= ~(0xf << (4 * 3)); GPIOC->CFGLR &= ~(0xf<<(4*3));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
GPIOC->BSHR = (1 << (16 + 3)); GPIOC->BSHR = (1<<(16+3));
GPIOC->CFGLR &= ~(0xf << (4 * 4)); GPIOC->CFGLR &= ~(0xf<<(4*4));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
GPIOC->BSHR = (1 << (16 + 4)); GPIOC->BSHR = (1<<(16+4));
#endif #endif
// load I2C regs // load I2C regs

View file

@ -27,101 +27,106 @@
void ssd1306_i2c_setup(void) void ssd1306_i2c_setup(void)
{ {
funGpioInitAll(); funGpioInitAll();
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP); funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1); funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP); funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1); funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
} }
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1); #define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1); #define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0); #define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0); #define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA); #define SDA_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 #define I2CSPEEDBASE 1
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1) #endif
// Delay_Us(x*1); #ifndef I2CDELAY_FUNC
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
#endif
static void ssd1306_i2c_sendstart() static void ssd1306_i2c_sendstart()
{ {
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH SCL_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_LOW SDA_LOW
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW SCL_LOW
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
} }
void ssd1306_i2c_sendstop() void ssd1306_i2c_sendstop()
{ {
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_LOW SDA_LOW
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW SCL_LOW
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH SCL_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_HIGH SDA_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
} }
// Return nonzero on failure. //Return nonzero on failure.
unsigned char ssd1306_i2c_sendbyte(unsigned char data) unsigned char ssd1306_i2c_sendbyte( unsigned char data )
{ {
unsigned int i; unsigned int i;
for (i = 0; i < 8; i++) for( i = 0; i < 8; i++ )
{ {
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
if (data & 0x80) if( data & 0x80 )
{ { SDA_HIGH; }
SDA_HIGH;
}
else else
{ { SDA_LOW; }
SDA_LOW; data<<=1;
} I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
data <<= 1;
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
SCL_HIGH SCL_HIGH
I2CDELAY_FUNC(2 * I2CSPEEDBASE); I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
SCL_LOW SCL_LOW
} }
// Immediately after sending last bit, open up DDDR for control. //Immediately after sending last bit, open up DDDR for control.
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
SDA_HIGH SDA_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); SDA_RELEASE
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH SCL_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
i = SDA_IN; i = SDA_IN;
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW SCL_LOW
I2CDELAY_FUNC(1 * I2CSPEEDBASE); I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_HIGH // Maybe? SDA_DRIVE
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP); SDA_HIGH
I2CDELAY_FUNC(1 * I2CSPEEDBASE); funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
return !!i; return !!i;
} }
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd) uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
{ {
ssd1306_i2c_sendstart(); ssd1306_i2c_sendstart();
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1); int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
if (r) return r; if( r ) return r;
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start //ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
if (cmd) if(cmd)
{ {
if (ssd1306_i2c_sendbyte(0x00)) if( ssd1306_i2c_sendbyte( 0x00 ) )
return 1; // Control return 1; // Control
} }
else else
{ {
if (ssd1306_i2c_sendbyte(0x40)) if( ssd1306_i2c_sendbyte( 0x40 ) )
return 1; // Data return 1; // Data
} }
for (int i = 0; i < sz; i++) for( int i = 0; i < sz; i++ )
{ {
if (ssd1306_i2c_sendbyte(data[i])) if( ssd1306_i2c_sendbyte( data[i] ) )
return 1; return 1;
} }
ssd1306_i2c_sendstop(); ssd1306_i2c_sendstop();
@ -130,10 +135,10 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
void ssd1306_rst(void) void ssd1306_rst(void)
{ {
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP); funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite(SSD1306_RST_PIN, 0); funDigitalWrite( SSD1306_RST_PIN, 0 );
Delay_Ms(10); Delay_Ms(10);
funDigitalWrite(SSD1306_RST_PIN, 1); funDigitalWrite( SSD1306_RST_PIN, 1 );
Delay_Us(10); Delay_Us(10);
} }

View file

@ -31,26 +31,48 @@
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2 #define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
#endif #endif
#ifndef SSD1306_SOFT_SPI
#define SSD1306_SOFT_SPI 0
#endif
/* /*
* init SPI and GPIO for SSD1306 OLED * init SPI and GPIO for SSD1306 OLED
*/ */
uint8_t ssd1306_spi_init(void) uint8_t ssd1306_spi_init(void)
{ {
// Enable GPIOC and SPI // Enable GPIOC and SPI
#ifdef CH5xx
#else
RCC->APB2PCENR |= RCC_APB2Periph_SPI1; RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
#endif
funGpioInitAll(); funGpioInitAll();
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP); funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP); funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP); funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP); #if defined( CH5xx ) || SSD1306_SOFT_SPI
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP); 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_RST_PIN, FUN_HIGH );
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH); funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW); funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
// Configure SPI // 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 = SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b | SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
SPI_Mode_Master | SPI_Direction_1Line_Tx | SPI_Mode_Master | SPI_Direction_1Line_Tx |
@ -58,6 +80,7 @@ uint8_t ssd1306_spi_init(void)
// enable SPI port // enable SPI port
SPI1->CTLR1 |= CTLR1_SPE_Set; SPI1->CTLR1 |= CTLR1_SPE_Set;
#endif
// always succeed // always succeed
return 0; return 0;
@ -68,9 +91,9 @@ uint8_t ssd1306_spi_init(void)
*/ */
void ssd1306_rst(void) void ssd1306_rst(void)
{ {
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW); funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
Delay_Ms(10); Delay_Ms(10);
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH); funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
} }
/* /*
@ -78,32 +101,53 @@ void ssd1306_rst(void)
*/ */
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd) uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
{ {
if (cmd) if(cmd)
{ {
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW); funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
} }
else else
{ {
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH); funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
} }
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW); funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
// send data // send data
while (sz--) while(sz--)
{ {
#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 // wait for TXE
while (!(SPI1->STATR & SPI_STATR_TXE)) while(!(SPI1->STATR & SPI_STATR_TXE));
;
// Send byte // Send byte
SPI1->DATAR = *data++; SPI1->DATAR = *data++;
#endif
} }
// wait for not busy before exiting // wait for not busy before exiting
while (SPI1->STATR & SPI_STATR_BSY) {} #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); funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
// we're happy // we're happy
return 0; return 0;

203
inc/extralibs/static_i2c.h Normal file
View 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

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,8 @@
internal bus resources than to do the same thing with timers. internal bus resources than to do the same thing with timers.
**For the CH32V003 this means output will be on PORTC Pin 6** **For the CH32V003 this means output will be on PORTC Pin 6**
**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! Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
@ -32,11 +34,11 @@
#include <stdint.h> #include <stdint.h>
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin. // Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
void WS2812BDMAInit(); void WS2812BDMAInit( );
void WS2812BDMAStart(int leds); void WS2812BDMAStart( int leds );
// Callbacks that you must implement. // Callbacks that you must implement.
uint32_t WS2812BLEDCallback(int ledno); uint32_t WS2812BLEDCallback( int ledno );
#ifdef WS2812DMA_IMPLEMENTATION #ifdef WS2812DMA_IMPLEMENTATION
@ -51,47 +53,51 @@ uint32_t WS2812BLEDCallback(int ledno);
#define WS2812B_RESET_PERIOD 2 #define WS2812B_RESET_PERIOD 2
#ifdef WSRAW #ifdef WSRAW
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8) #define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
#else #else
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6) #define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
#endif #endif
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN]; static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
static volatile int WS2812LEDs; static volatile int WS2812LEDs;
static volatile int WS2812LEDPlace; static volatile int WS2812LEDPlace;
static volatile int WS2812BLEDInUse; static volatile int WS2812BLEDInUse;
#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 is the code that updates a portion of the WS2812dmabuff with new data.
// This effectively creates the bitstream that outputs to the LEDs. // This effectively creates the bitstream that outputs to the LEDs.
static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce) static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
{ {
#ifdef CH5xx
// Reversing bit order because CH5xx SPI FIFO is only half of what CH32 have
const static uint16_t bitquartets[16] = { const static uint16_t bitquartets[16] = {
0b1000100010001000, 0b0001000100010001, 0b0111000100010001, 0b0001011100010001, 0b0111011100010001,
0b1000100010001110, 0b0001000101110001, 0b0111000101110001, 0b0001011101110001, 0b0111011101110001,
0b1000100011101000, 0b0001000100010111, 0b0111000100010111, 0b0001011100010111, 0b0111011100010111,
0b1000100011101110, 0b0001000101110111, 0b0111000101110111, 0b0001011101110111, 0b0111011101110111, };
0b1000111010001000, #else
0b1000111010001110, const static uint16_t bitquartets[16] = {
0b1000111011101000, 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
0b1000111011101110, 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
0b1110100010001000, 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
0b1110100010001110, 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
0b1110100011101000, #endif
0b1110100011101110,
0b1110111010001000,
0b1110111010001110,
0b1110111011101000,
0b1110111011101110,
};
int i; int i;
uint16_t *end = ptr + numhalfwords; uint16_t * end = ptr + numhalfwords;
int ledcount = WS2812LEDs; int ledcount = WS2812LEDs;
int place = WS2812LEDPlace; int place = WS2812LEDPlace;
#ifdef WSRAW #ifdef WSRAW
while (place < 0 && ptr != end) while( place < 0 && ptr != end )
{ {
uint32_t *lptr = (uint32_t *)ptr; uint32_t * lptr = (uint32_t *)ptr;
lptr[0] = 0; lptr[0] = 0;
lptr[1] = 0; lptr[1] = 0;
lptr[2] = 0; lptr[2] = 0;
@ -101,7 +107,7 @@ static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
} }
#else #else
while (place < 0 && ptr != end) while( place < 0 && ptr != end )
{ {
(*ptr++) = 0; (*ptr++) = 0;
(*ptr++) = 0; (*ptr++) = 0;
@ -113,21 +119,25 @@ static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
} }
#endif #endif
while (ptr != end) while( ptr != end )
{ {
if (place >= ledcount) if( place >= ledcount )
{ {
// Optionally, leave line high. // Optionally, leave line high.
while (ptr != end) while( ptr != end )
(*ptr++) = 0; // 0xffff; (*ptr++) = 0;//0xffff;
// Only safe to do this when we're on the second leg. // Only safe to do this when we're on the second leg.
if (tce) if( tce )
{ {
if (place == ledcount) if( place == ledcount )
{ {
// Take the DMA out of circular mode and let it expire. // Take the DMA out of circular mode and let it expire.
#ifdef CH5xx
R8_SPI0_INTER_EN &= ~RB_SPI_IE_DMA_END; // Disable DMA end interrupt
#else
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular; DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
#endif
WS2812BLEDInUse = 0; WS2812BLEDInUse = 0;
} }
place++; place++;
@ -137,57 +147,70 @@ static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
} }
#ifdef WSRAW #ifdef WSRAW
uint32_t ledval32bit = WS2812BLEDCallback(place++); uint32_t ledval32bit = WS2812BLEDCallback( place++ );
ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf]; ptr[6] = bitquartets[(ledval32bit>>28)&0xf];
ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf]; ptr[7] = bitquartets[(ledval32bit>>24)&0xf];
ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf]; ptr[4] = bitquartets[(ledval32bit>>20)&0xf];
ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf]; ptr[5] = bitquartets[(ledval32bit>>16)&0xf];
ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf]; ptr[2] = bitquartets[(ledval32bit>>12)&0xf];
ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf]; ptr[3] = bitquartets[(ledval32bit>>8)&0xf];
ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf]; ptr[0] = bitquartets[(ledval32bit>>4)&0xf];
ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf]; ptr[1] = bitquartets[(ledval32bit>>0)&0xf];
ptr += 8; ptr += 8;
i += 8; i += 8;
#else #else
// Use a LUT to figure out how we should set the SPI line. // Use a LUT to figure out how we should set the SPI line.
uint32_t ledval24bit = WS2812BLEDCallback(place++); uint32_t ledval24bit = WS2812BLEDCallback( place++ );
#ifdef WSRBG #ifdef WSRBG
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf]; ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf]; ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf]; ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf]; ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf]; ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf]; ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
#elif defined(WSGRB) #elif defined( WSGRB )
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf]; ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf]; ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf]; ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf]; ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf]; ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf]; ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
#else #else
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf]; ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf]; ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf]; ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf]; ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf]; ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf]; ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
#endif #endif
ptr += 6; ptr += 6;
i += 6; i += 6;
#endif #endif
} }
WS2812LEDPlace = place; WS2812LEDPlace = place;
} }
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt)); #ifdef CH5xx
void DMA1_Channel3_IRQHandler(void) void SPI0_IRQHandler( void ) __attribute__((interrupt));
void SPI0_IRQHandler( void )
{ {
// GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling 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 )
{
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
// Backup flags. // Backup flags.
volatile int intfr = DMA1->INTFR; volatile int intfr = DMA1->INTFR;
@ -200,67 +223,96 @@ void DMA1_Channel3_IRQHandler(void)
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes // DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
// LED jitter. I am henseforth flipping the order. // LED jitter. I am henseforth flipping the order.
if (intfr & DMA1_IT_HT3) if( intfr & DMA1_IT_HT3 )
{ {
// Halfwaay (Fill in first part) // Halfwaay (Fill in first part)
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1); WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
} }
if (intfr & DMA1_IT_TC3) if( intfr & DMA1_IT_TC3 )
{ {
// Complete (Fill in second part) // Complete (Fill in second part)
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0); WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
} }
intfr = DMA1->INTFR; intfr = DMA1->INTFR;
} while (intfr & DMA1_IT_GL3); } while( intfr & DMA1_IT_GL3 );
// GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling //GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
} }
#endif
void WS2812BDMAStart(int leds) void WS2812BDMAStart( int leds )
{ {
// Enter critical section. // Enter critical section.
__disable_irq(); __disable_irq();
WS2812BLEDInUse = 1; 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->CFGR &= ~DMA_Mode_Circular;
DMA1_Channel3->CNTR = 0; DMA1_Channel3->CNTR = 0;
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff; DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
#endif
__enable_irq();
WS2812LEDs = leds; WS2812LEDs = leds;
WS2812LEDPlace = -WS2812B_RESET_PERIOD; WS2812LEDPlace = -WS2812B_RESET_PERIOD;
__enable_irq();
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN, 0);
#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->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
DMA1_Channel3->CFGR |= DMA_Mode_Circular; DMA1_Channel3->CFGR |= DMA_Mode_Circular;
#endif
} }
void WS2812BDMAInit() void WS2812BDMAInit( )
{ {
// Enable DMA + Peripherals // 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->AHBPCENR |= RCC_AHBPeriph_DMA1;
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
// MOSI, Configure GPIO Pin // MOSI, Configure GPIO Pin
GPIOC->CFGLR &= ~(0xf << (4 * 6)); GPIOC->CFGLR &= ~(0xf<<(4*6));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
// Configure SPI // Configure SPI
SPI1->CTLR1 = SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b | SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
SPI_Mode_Master | SPI_Direction_1Line_Tx | SPI_Mode_Master | SPI_Direction_1Line_Tx |
3 << 3; // Divisior = 16 (48/16 = 3MHz) 3<<3; // Divisior = 16 (48/16 = 3MHz)
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; // Enable Tx buffer DMA
SPI1->HSCR = 1;
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. SPI1->DATAR = 0; // Set SPI line Low.
// DMA1_Channel3 is for SPI1TX //DMA1_Channel3 is for SPI1TX
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR; DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff; DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!) DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
DMA1_Channel3->CFGR = DMA1_Channel3->CFGR =
DMA_M2M_Disable | DMA_M2M_Disable |
DMA_Priority_VeryHigh | DMA_Priority_VeryHigh |
@ -271,16 +323,18 @@ void WS2812BDMAInit()
DMA_DIR_PeripheralDST | DMA_DIR_PeripheralDST |
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts. DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority. // NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
NVIC_EnableIRQ(DMA1_Channel3_IRQn); NVIC_EnableIRQ( DMA1_Channel3_IRQn );
DMA1_Channel3->CFGR |= DMA_CFGR1_EN; DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING #ifdef WS2812B_ALLOW_INTERRUPT_NESTING
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting. __set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3 PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
#endif #endif
#endif
} }
#endif #endif
#endif #endif

View file

@ -15,7 +15,7 @@
#include <stdint.h> #include <stdint.h>
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes); void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes );
#ifdef WS2812BSIMPLE_IMPLEMENTATION #ifdef WS2812BSIMPLE_IMPLEMENTATION
@ -25,28 +25,28 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK #error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
#endif #endif
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes) void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes )
{ {
int port_id = (((intptr_t)port - (intptr_t)GPIOA) >> 10); int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled. RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
int poffset = (pin * 4); int poffset = (pin*4);
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset)); port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
int maskon = 1 << pin; int maskon = 1<<pin;
int maskoff = 1 << (16 + pin); int maskoff = 1<<(16+pin);
port->BSHR = maskoff; port->BSHR = maskoff;
uint8_t *end = data + len_in_bytes; uint8_t * end = data + len_in_bytes;
while (data != end) while( data != end )
{ {
uint8_t byte = *data; uint8_t byte = *data;
int i; int i;
for (i = 0; i < 8; i++) for( i = 0; i < 8; i++ )
{ {
if (byte & 0x80) if( byte & 0x80 )
{ {
// WS2812B's need AT LEAST 625ns for a logical "1" // WS2812B's need AT LEAST 625ns for a logical "1"
port->BSHR = maskon; port->BSHR = maskon;
@ -61,7 +61,7 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
__disable_irq(); __disable_irq();
#endif #endif
port->BSHR = maskon; port->BSHR = maskon;
asm volatile("nop\nnop\nnop\nnop"); asm volatile( "nop\nnop\nnop\nnop" );
port->BSHR = maskoff; port->BSHR = maskoff;
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING #ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
__enable_irq(); __enable_irq();
@ -80,3 +80,4 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
#endif #endif
#endif #endif

View file

@ -1,5 +0,0 @@
{
"DisableFormat": true,
"SortIncludes": "Never"
}

View 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

View 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

View 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

View 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

View 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);

View 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;

View file

@ -20,7 +20,7 @@ typedef enum IRQn
Ecall_U_Mode_IRQn = 8, /* 8 Ecall U Mode Interrupt */ Ecall_U_Mode_IRQn = 8, /* 8 Ecall U Mode Interrupt */
Break_Point_IRQn = 9, /* 9 Break Point Interrupt */ Break_Point_IRQn = 9, /* 9 Break Point Interrupt */
#endif #endif
SysTicK_IRQn = 12, /* 12 System timer Interrupt */ SysTick_IRQn = 12, /* 12 System timer Interrupt */
Software_IRQn = 14, /* 14 software Interrupt */ Software_IRQn = 14, /* 14 software Interrupt */
#if defined(CH32V003) || defined(CH32X03x) #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 #define USBFSD_UEP_MOD_BASE 0x4002340C
@ -2266,11 +2264,7 @@ typedef struct
#define ESIG_BASE ((uint32_t)0x1FFFF7E0) #define ESIG_BASE ((uint32_t)0x1FFFF7E0)
#define INFO_BASE ((uint32_t)0x1FFFF704) #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) #define EXTEN_BASE (AHBPERIPH_BASE + 0x3800)
#endif
#define PFIC_BASE (CORE_PERIPH_BASE + 0xE000) #define PFIC_BASE (CORE_PERIPH_BASE + 0xE000)
#define SysTick_BASE (CORE_PERIPH_BASE + 0xF000) #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) #if defined(CH32V003)
/***************** Bit definition for AFIO_EXTICR register *****************/ /***************** Bit definition for AFIO_EXTICR register *****************/
#define AFIO_EXTICR_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */ #define AFIO_EXTICR1_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
#define AFIO_EXTICR_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */ #define AFIO_EXTICR1_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
#define AFIO_EXTICR_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */ #define AFIO_EXTICR1_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
#define AFIO_EXTICR_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */ #define AFIO_EXTICR1_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
#define AFIO_EXTICR_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */ #define AFIO_EXTICR1_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
#define AFIO_EXTICR_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */ #define AFIO_EXTICR1_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
#define AFIO_EXTICR_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */ #define AFIO_EXTICR1_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
#define AFIO_EXTICR_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */ #define AFIO_EXTICR1_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
#define AFIO_EXTICR_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */ #define AFIO_EXTICR1_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
#define AFIO_EXTICR_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */ #define AFIO_EXTICR1_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
#define AFIO_EXTICR_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */ #define AFIO_EXTICR1_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
#define AFIO_EXTICR_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */ #define AFIO_EXTICR1_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
#define AFIO_EXTICR_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */ #define AFIO_EXTICR1_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
#define AFIO_EXTICR_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */ #define AFIO_EXTICR1_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
#define AFIO_EXTICR_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */ #define AFIO_EXTICR1_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
#define AFIO_EXTICR_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */ #define AFIO_EXTICR1_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
#define AFIO_EXTICR_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */ #define AFIO_EXTICR1_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
#define AFIO_EXTICR_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */ #define AFIO_EXTICR1_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
#define AFIO_EXTICR_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */ #define AFIO_EXTICR1_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
#define AFIO_EXTICR_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */ #define AFIO_EXTICR1_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
#define AFIO_EXTICR_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */ #define AFIO_EXTICR1_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
#define AFIO_EXTICR_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */ #define AFIO_EXTICR1_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
#define AFIO_EXTICR_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */ #define AFIO_EXTICR1_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
#define AFIO_EXTICR_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */ #define AFIO_EXTICR1_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
#define AFIO_EXTICR_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */ #define AFIO_EXTICR1_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
#define AFIO_EXTICR_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */ #define AFIO_EXTICR1_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
#endif #endif
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) #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_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_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_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_BOOT ((uint16_t)0x0020) /* Start in BOOT area */
#define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */ #define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */
@ -12586,6 +12468,349 @@ typedef volatile unsigned long *PUINT32V;
#endif #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 -----------------------------------------------------------*/ /* ch32v00x_wwdg.h -----------------------------------------------------------*/

View file

@ -1,48 +1,41 @@
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdint.h>
#include <string.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 * 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"}; const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
char *WhitePull(const char **sti) char * WhitePull( const char ** sti )
{ {
const char *st = *sti; const char * st = *sti;
int len = 0; int len = 0;
while ((*st == ' ' || *st == '\t' || *st == '(') && *st) while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
{ const char * sts = st;
st++; while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
} if( *st == ')' ) { st++; }
const char *sts = st; char * ret = malloc( len + 1 );
while (*st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0) memcpy( ret, sts, len );
{
st++;
len++;
}
if (*st == ')') { st++; }
char *ret = malloc(len + 1);
memcpy(ret, sts, len);
ret[len] = 0; ret[len] = 0;
*sti = st; *sti = st;
return ret; return ret;
} }
int NYI(const char *s) int NYI( const char * s )
{ {
int ret = 2; int ret = 2;
char *wp = WhitePull(&s); char * wp = WhitePull( &s );
int i; int i;
for (i = 0; i < sizeof(yes) / sizeof(yes[0]); i++) for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
if (strcmp(yes[i], wp) == 0) ret = 1; if( strcmp( yes[i], wp ) == 0 ) ret = 1;
if (ret != 1) if( ret != 1 )
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++) for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
if (strcmp(no[i], wp) == 0) ret = 0; if( strcmp( no[i], wp ) == 0 ) ret = 0;
free(wp); free( wp );
return ret; return ret;
} }
int EvalSpec(const char *spl) int EvalSpec( const char * spl )
{ {
int rsofar = 0; int rsofar = 0;
int i; int i;
@ -50,120 +43,107 @@ int EvalSpec(const char *spl)
int lasto = -1; int lasto = -1;
int ret = 0; int ret = 0;
cont: cont:
char *wp = WhitePull(&spl); char * wp = WhitePull( &spl );
int def = -1; int def = -1;
if (strcmp(wp, "defined") == 0) def = 1; if( strcmp( wp, "defined" ) == 0 ) def = 1;
if (strcmp(wp, "!defined") == 0) def = 2; if( strcmp( wp, "!defined" ) == 0 ) def = 2;
if (def < 0) return 2; if( def < 0 ) return 2;
char *wpn = WhitePull(&spl); char * wpn = WhitePull( &spl );
i = NYI(wpn); i = NYI( wpn );
// printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto ); //printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
if (i == 2) return 2; if( i == 2 ) return 2;
if (def == 2) i = !i; if( def == 2 ) i = !i;
if (lasto == 1) if( lasto == 1 )
{ {
ret = lastv || i; ret = lastv || i;
} }
else if (lasto == 2) else if( lasto == 2 )
ret = lastv && i; ret = lastv && i;
else else
ret = i; ret = i;
char *wpa = WhitePull(&spl); char * wpa = WhitePull( &spl );
// printf( "WPA: \"%s\"\n", wpa ); //printf( "WPA: \"%s\"\n", wpa );
lastv = ret; lastv = ret;
lasto = -1; lasto = -1;
// printf( "RET: %d\n", ret ); //printf( "RET: %d\n", ret );
if (strcmp(wpa, "||") == 0) if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
{ else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
lasto = 1; else return ret;
goto cont;
}
else if (strcmp(wpa, "&&") == 0)
{
lasto = 2;
goto cont;
}
else
return ret;
} }
// 0 for no // 0 for no
// 1 for yes // 1 for yes
// 2 for indeterminate // 2 for indeterminate
int NoYesInd(const char *preprocc) int NoYesInd( const char * preprocc )
{ {
int ret; int ret;
int ofs = 0; int ofs = 0;
if (strncmp(preprocc, "#if ", 4) == 0) ofs = 4; if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
if (strncmp(preprocc, "#elif ", 6) == 0) ofs = 6; if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
if (ofs) if( ofs )
{ {
ret = EvalSpec(preprocc + ofs); ret = EvalSpec( preprocc + ofs );
// printf( "SPEC: %d\n", ret ); //printf( "SPEC: %d\n", ret );
} }
else if (strncmp(preprocc, "#ifdef ", 7) == 0) else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
{ {
const char *ep = preprocc + 6; const char * ep = preprocc + 6;
char *wp = WhitePull(&ep); char * wp = WhitePull( &ep );
ret = NYI(wp); ret = NYI( wp );
free(wp); free( wp );
} }
else if (strncmp(preprocc, "#ifndef ", 8) == 0) else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
{ {
const char *ep = preprocc + 6; const char * ep = preprocc + 6;
char *wp = WhitePull(&ep); char * wp = WhitePull( &ep );
ret = NYI(wp); ret = NYI( wp );
if (ret < 2) ret = !ret; if( ret < 2 ) ret = !ret;
free(wp); free( wp );
} }
else else
ret = 2; ret = 2;
// printf( "%d-> %s\n", ret, preprocc ); //printf( "%d-> %s\n", ret, preprocc );
return ret; return ret;
} }
const char *sslineis(const char *line, const char *match) const char * sslineis( const char * line, const char * match )
{ {
while (*line == ' ' || *line == '\t') while( *line == ' ' || *line == '\t' ) line++;
line++; const char * linestart = line;
const char *linestart = line; while( *line && *match == *line ) { line++; match++; }
while (*line && *match == *line) if( *match == 0 )
{
line++;
match++;
}
if (*match == 0)
return linestart; return linestart;
else else
return 0; return 0;
} }
int main(int argc, char **argv) int main( int argc, char ** argv )
{ {
if (argc != 3) if( argc != 3 )
{ {
fprintf(stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n"); fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
int i; int i;
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++) for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
{ {
fprintf(stderr, "\t%s\n", no[i]); fprintf( stderr, "\t%s\n", no[i] );
} }
return -1; return -1;
} }
yes[0] = argv[1]; yes[0] = argv[1];
FILE *f = fopen(argv[2], "r"); FILE * f = fopen( argv[2], "r" );
if (!f) if( !f )
{ {
fprintf(stderr, "Error: Could not open \"%s\"\n", argv[2]); fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
return -2; return -2;
} }
char line[1024]; char line[1024];
char *l; char * l;
int depth = 0; int depth = 0;
@ -174,71 +154,73 @@ int main(int argc, char **argv)
int yesnoind[1024]; int yesnoind[1024];
yesnoind[0] = 1; yesnoind[0] = 1;
while (l = fgets(line, sizeof(line) - 1, f)) while( l = fgets( line, sizeof(line)-1, f ) )
{ {
const char *ss = 0; const char * ss = 0;
int nyi = yesnoind[depth]; int nyi = yesnoind[depth];
int waspre = 0; int waspre = 0;
if ((ss = sslineis(line, "#if ")) || (ss = sslineis(line, "#ifdef ")) || (ss = sslineis(line, "#ifndef "))) if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
{ {
waspre = 1; waspre = 1;
// printf( "CHECK: %d/%s\n", depth, l ); //printf( "CHECK: %d/%s\n", depth, l );
nyi = NoYesInd(ss); nyi = NoYesInd( ss );
depth++; depth++;
yesnoind[depth] = nyi; yesnoind[depth] = nyi;
} }
else if ((ss = sslineis(line, "#elif "))) else if( (ss = sslineis( line, "#elif " ) ) )
{ {
if (nyi != 2) if( nyi != 2 )
{ {
waspre = 1; waspre = 1;
if (nyi == 1) if( nyi == 1 )
{ {
nyi = 3; nyi = 3;
} }
else else
{ {
nyi = NoYesInd(ss); nyi = NoYesInd( ss );
} }
// printf( "ELIF check: %s %d\n", ss, nyi ); //printf( "ELIF check: %s %d\n", ss, nyi );
yesnoind[depth] = nyi; yesnoind[depth] = nyi;
} }
} }
else if ((ss = sslineis(line, "#else"))) else if( (ss = sslineis( line, "#else" ) ) )
{ {
if (nyi != 2) if( nyi != 2 )
{ {
waspre = 1; waspre = 1;
if (yesnoind[depth] == 1) if( yesnoind[depth] == 1 )
nyi = 3; nyi = 3;
else else
nyi = !yesnoind[depth]; nyi = !yesnoind[depth];
yesnoind[depth] = nyi; yesnoind[depth] = nyi;
} }
} }
else if ((ss = sslineis(line, "#endif"))) else if( (ss = sslineis( line, "#endif" ) ) )
{ {
waspre = 1; waspre = 1;
depth--; depth--;
if (depth < 0) if( depth < 0 )
{ {
fprintf(stderr, "UNTERMD IF\n"); fprintf( stderr, "UNTERMD IF\n" );
} }
} }
int thisv = nyi; int thisv = nyi;
int i; int i;
for (i = 0; i <= depth; i++) for( i = 0; i <= depth; i++ )
{ {
// printf( "%d", yesnoind[i] ); //printf( "%d", yesnoind[i] );
if (yesnoind[i] == 0 || yesnoind[i] == 3) thisv = 0; if( yesnoind[i] == 0 || yesnoind[i] == 3 ) thisv = 0;
} }
// printf( ">>%s", l ); //printf( ">>%s", l );
if (thisv != 0 && thisv != 3 && (thisv != 1 || !waspre)) if( thisv != 0 && thisv != 3 && ( thisv != 1 || !waspre ) )
{ {
printf("%s", l); printf( "%s", l );
} }
} }
} }

View 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.

File diff suppressed because it is too large Load diff

View 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!';

View 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

View 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
View 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()

View 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

View 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
View 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

File diff suppressed because it is too large Load diff