Refactored the included files from the ch32fun project.
+ updated as of 2025-12-23
This commit is contained in:
parent
56e38aeeae
commit
7e0b1e3244
58 changed files with 90369 additions and 56430 deletions
1493
inc/ch32fun.h
1493
inc/ch32fun.h
File diff suppressed because it is too large
Load diff
18083
inc/ch32h41xhw.h
Normal file
18083
inc/ch32h41xhw.h
Normal file
File diff suppressed because it is too large
Load diff
9094
inc/ch32l103hw.h
Normal file
9094
inc/ch32l103hw.h
Normal file
File diff suppressed because it is too large
Load diff
6484
inc/ch32v003hw.h
6484
inc/ch32v003hw.h
File diff suppressed because it is too large
Load diff
6237
inc/ch32v10xhw.h
Normal file
6237
inc/ch32v10xhw.h
Normal file
File diff suppressed because it is too large
Load diff
8450
inc/ch32v20xhw.h
Normal file
8450
inc/ch32v20xhw.h
Normal file
File diff suppressed because it is too large
Load diff
10625
inc/ch32v30xhw.h
Normal file
10625
inc/ch32v30xhw.h
Normal file
File diff suppressed because it is too large
Load diff
5002
inc/ch32x00xhw.h
Normal file
5002
inc/ch32x00xhw.h
Normal file
File diff suppressed because it is too large
Load diff
6245
inc/ch32x03xhw.h
Normal file
6245
inc/ch32x03xhw.h
Normal file
File diff suppressed because it is too large
Load diff
2645
inc/ch5xxhw.h
Normal file
2645
inc/ch5xxhw.h
Normal file
File diff suppressed because it is too large
Load diff
5187
inc/ch641hw.h
Normal file
5187
inc/ch641hw.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,22 +1,26 @@
|
|||
// 2023-06-26 recallmenot
|
||||
|
||||
// ######## necessities
|
||||
//######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_GPIO_BR_H
|
||||
#define CH32V003_GPIO_BR_H
|
||||
|
||||
// includes
|
||||
#include <stdint.h> //uintN_t support
|
||||
#include "../ch32fun/ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
|
||||
|
||||
/*######## library description
|
||||
This is a speedy and light GPIO library due to
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
||||
first, enable the desired port.
|
||||
|
|
@ -94,81 +98,78 @@ Writing `TIMx->SWEVGR |= TIM_UG` will immediately update the shadow register and
|
|||
|
||||
*/
|
||||
|
||||
// ######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin)
|
||||
|
||||
enum GPIO_port_n
|
||||
{
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
//######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||
|
||||
enum GPIO_port_n {
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
};
|
||||
|
||||
enum GPIO_pinModes
|
||||
{
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
enum GPIO_pinModes {
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
};
|
||||
|
||||
enum lowhigh
|
||||
{
|
||||
low,
|
||||
high,
|
||||
enum lowhigh {
|
||||
low,
|
||||
high,
|
||||
};
|
||||
|
||||
// analog inputs
|
||||
enum GPIO_analog_inputs
|
||||
{
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
enum GPIO_analog_inputs {
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
};
|
||||
|
||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||
enum GPIO_ADC_sampletimes
|
||||
{
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
enum GPIO_ADC_sampletimes {
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
};
|
||||
|
||||
enum GPIO_tim1_output_sets
|
||||
{
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
enum GPIO_tim1_output_sets {
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
};
|
||||
|
||||
enum GPIO_tim2_output_sets
|
||||
{
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
enum GPIO_tim2_output_sets {
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
};
|
||||
|
||||
// ######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
|
||||
//######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
// setup
|
||||
#define GPIO_port_enable(GPIO_port_n)
|
||||
|
|
@ -201,66 +202,72 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_tim1_analogWrite(channel, value)
|
||||
#define GPIO_tim2_analogWrite(channel, value)
|
||||
|
||||
// ######## internal function declarations
|
||||
|
||||
// ######## internal variables
|
||||
|
||||
// ######## preprocessor macros
|
||||
//######## internal function declarations
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
|
||||
|
||||
//######## internal variables
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
|
||||
#define CONCAT(a, b) a ## b
|
||||
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
||||
|
||||
#undef GPIOv_from_PORT_PIN
|
||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (pin))
|
||||
#define GPIOv_to_PORT(GPIOv) (GPIOv >> 4)
|
||||
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin ) ((GPIO_port_n << 4 ) | (pin))
|
||||
#define GPIOv_to_PORT( GPIOv ) (GPIOv >> 4 )
|
||||
#define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase( GPIOv ) ((GPIO_TypeDef*)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIOv)
|
||||
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n)
|
||||
|
|
@ -280,74 +287,91 @@ static inline void GPIO_tim2_init();
|
|||
#endif
|
||||
|
||||
#if !defined(GPIO_timer_prescaler)
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#endif
|
||||
|
||||
// ######## define requirements / maintenance defines
|
||||
//######## define requirements / maintenance defines
|
||||
|
||||
|
||||
|
||||
//######## small function definitions, static inline
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
|
||||
#undef GPIO_port_enable
|
||||
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
||||
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
})
|
||||
|
||||
#undef GPIO_port_digitalWrite
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
|
||||
#undef GPIO_port_digitalRead
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
|
||||
#undef GPIO_pinMode
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
})
|
||||
|
||||
#undef GPIO_digitalWrite_hi
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#undef GPIO_digitalWrite_lo
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
|
||||
#undef GPIO_digitalWrite
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
|
||||
#undef GPIO_digitalWrite_branching
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? (GPIO_digitalWrite_hi(GPIOv)) : (GPIO_digitalWrite_lo(GPIOv)))
|
||||
|
||||
#undef GPIO_digitalRead
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
|
||||
#undef GPIO_ADC_set_sampletime
|
||||
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_sampletimes_all
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3); \
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3) \
|
||||
| GPIO_ADC_sampletime << (6 * 3) \
|
||||
| GPIO_ADC_sampletime << (7 * 3) \
|
||||
| GPIO_ADC_sampletime << (8 * 3) \
|
||||
| GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_power
|
||||
|
|
@ -357,137 +381,133 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
||||
|
||||
#undef GPIO_ADC_calibrate
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
||||
; \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while (ADC1->CTLR2 & ADC_CAL) \
|
||||
; \
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while(ADC1->CTLR2 & ADC_CAL); \
|
||||
})
|
||||
|
||||
// large but will likely only ever be called once
|
||||
static inline void GPIO_ADCinit()
|
||||
{
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
static inline void GPIO_ADCinit() {
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
}
|
||||
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
||||
{
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while (!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while(!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef GPIO_tim1_map
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
})
|
||||
|
||||
#undef GPIO_tim2_map
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
})
|
||||
|
||||
static inline void GPIO_tim1_init()
|
||||
{
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim1_init() {
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
static inline void GPIO_tim2_init()
|
||||
{
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim2_init() {
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
|
||||
#undef GPIO_tim1_enableCH
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
})
|
||||
#undef GPIO_tim2_enableCH
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \
|
||||
})
|
||||
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
|
||||
#undef GPIO_tim1_analogWrite
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#undef GPIO_tim2_analogWrite
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
|
||||
#endif // CH32V003_GPIO_BR_H
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// ######## necessities
|
||||
//######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_SPI_H
|
||||
#define CH32V003_SPI_H
|
||||
|
||||
// includes
|
||||
#include<stdint.h> //uintN_t support
|
||||
#include "ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
|
@ -20,7 +20,7 @@ SYSTEM_CORE_CLOCK and APB_CLOCK should be defined already as APB_CLOCK is used b
|
|||
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
to enable using the functions of this library:
|
||||
|
|
@ -47,8 +47,10 @@ then pick the desired setting of each group:
|
|||
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
||||
*/
|
||||
|
||||
// ######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
|
||||
|
||||
//######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
static inline void SPI_init();
|
||||
|
||||
// establish / end a connection to the SPI device
|
||||
|
|
@ -65,14 +67,14 @@ static inline void SPI_NSS_software_high();
|
|||
|
||||
// read / write the SPI device
|
||||
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint16_t SPI_read_16();
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
|
||||
// send a command and get a response from the SPI device
|
||||
// you'll use this for most devices
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data);
|
||||
|
||||
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
||||
|
|
@ -85,25 +87,31 @@ static inline void SPI_poweron();
|
|||
static inline void kill_interrrupts();
|
||||
static inline void restore_interrupts();
|
||||
|
||||
// ######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
static inline uint8_t SPI_is_RX_empty();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
// ######## internal variables
|
||||
|
||||
//######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
static inline uint8_t SPI_is_RX_empty();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
static uint16_t EXT1_INTENR_backup;
|
||||
|
||||
// ######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
// stringify for displaying what #defines evaluated to at preprocessor stage
|
||||
#define VALUE_TO_STRING(x) #x
|
||||
#define VALUE(x) VALUE_TO_STRING(x)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
|
||||
// compile-time log2
|
||||
//compile-time log2
|
||||
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
||||
|
||||
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
||||
|
|
@ -112,249 +120,233 @@ static uint16_t EXT1_INTENR_backup;
|
|||
|
||||
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
||||
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
||||
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
#pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
|
||||
// ######## preprocessor #define requirements
|
||||
|
||||
|
||||
//######## preprocessor #define requirements
|
||||
|
||||
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
static inline void SPI_init()
|
||||
{
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
|
||||
//######## small function definitions, static inline
|
||||
static inline void SPI_init() {
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
|
||||
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
|
||||
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
|
||||
// MISO on PC7, 10MHz input, floating
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*7));
|
||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
|
||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
|
||||
// MISO on PC7, 10MHz input, floating
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 7));
|
||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 7);
|
||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
#endif
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void SPI_begin_8()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_8() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_begin_16()
|
||||
{
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_16() {
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_end()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
static inline void SPI_end() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
}
|
||||
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 3);
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<3);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
}
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<4);
|
||||
}
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t SPI_read_8()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
static inline uint8_t SPI_read_8() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline uint16_t SPI_read_16()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
static inline uint16_t SPI_read_16() {
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline void SPI_write_8(uint8_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_8(uint8_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline void SPI_write_16(uint16_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_16(uint16_t data) {
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
}
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
}
|
||||
|
||||
static inline void SPI_poweroff()
|
||||
{
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweroff() {
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
}
|
||||
static inline void SPI_poweron()
|
||||
{
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweron() {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
}
|
||||
|
||||
static inline void kill_interrrupts()
|
||||
{
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
static inline void kill_interrrupts() {
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
}
|
||||
static inline void restore_interrupts()
|
||||
{
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
static inline void restore_interrupts() {
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
}
|
||||
|
||||
// ######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
|
||||
|
||||
//######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete() {
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
}
|
||||
static inline uint8_t SPI_is_RX_empty()
|
||||
{
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
static inline uint8_t SPI_is_RX_empty() {
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
}
|
||||
static inline void SPI_wait_RX_available()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
static inline void SPI_wait_RX_available() {
|
||||
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
}
|
||||
static inline void SPI_wait_not_busy()
|
||||
{
|
||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
static inline void SPI_wait_not_busy() {
|
||||
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
}
|
||||
static inline void SPI_wait_transmit_finished()
|
||||
{
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
static inline void SPI_wait_transmit_finished() {
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
}
|
||||
|
||||
// ######## implementation block
|
||||
// #define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
|
||||
//######## implementation block
|
||||
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
||||
|
||||
// no functions here because I think all of the functions are small enough to static inline
|
||||
//no functions here because I think all of the functions are small enough to static inline
|
||||
|
||||
#endif // CH32V003_SPI_IMPLEMENTATION
|
||||
#endif // CH32V003_SPI_H
|
||||
|
|
|
|||
|
|
@ -3,42 +3,44 @@
|
|||
|
||||
/** ADC-based Capactive Touch Control.
|
||||
|
||||
see cap_touch_adc.c for an example.
|
||||
see cap_touch_adc.c for an example.
|
||||
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
|
||||
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
*/
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
// Can either be 0 or 1.
|
||||
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
||||
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
||||
#define TOUCH_SLOPE 1
|
||||
#define TOUCH_SLOPE 1
|
||||
|
||||
// If you set this to 1, it will glitch the line, so it will only read
|
||||
// anything reasonable if the capacitance can overcome that initial spike.
|
||||
// Typically, it seems if you use this you probbly don't need to do
|
||||
// any pre-use calibration.
|
||||
#define TOUCH_FLAT 0
|
||||
#define TOUCH_FLAT 0
|
||||
|
||||
// Macro used for force-alingining ADC timing
|
||||
#define FORCEALIGNADC \
|
||||
asm volatile( \
|
||||
"\n\
|
||||
asm volatile( \
|
||||
"\n\
|
||||
.balign 4\n\
|
||||
andi a2, %[cyccnt], 3\n\
|
||||
c.slli a2, 1\n\
|
||||
|
|
@ -48,172 +50,169 @@
|
|||
jalr a2, 1\n\
|
||||
.long 0x00010001\n\
|
||||
.long 0x00010001\n\
|
||||
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2");
|
||||
"\
|
||||
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||
);
|
||||
|
||||
static void InitTouchADC();
|
||||
void InitTouchADC()
|
||||
|
||||
static void InitTouchADC( );
|
||||
void InitTouchADC( )
|
||||
{
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
||||
;
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while (ADC1->CTLR2 & ADC_CAL)
|
||||
;
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while(ADC1->CTLR2 & ADC_CAL);
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
__enable_irq();
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
__enable_irq();
|
||||
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | CFGBASE;
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#if TOUCH_FLAT == 1
|
||||
#define RELEASEIO \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
io->CFGLR = CFGFLOAT;
|
||||
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||
#else
|
||||
#define RELEASEIO \
|
||||
io->CFGLR = CFGFLOAT; \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
||||
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||
#endif
|
||||
|
||||
#define INNER_LOOP(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP(0);
|
||||
INNER_LOOP(2);
|
||||
INNER_LOOP(4);
|
||||
}
|
||||
INNER_LOOP( 0 );
|
||||
INNER_LOOP( 2 );
|
||||
INNER_LOOP( 4 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#define INNER_LOOP_SAFE(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP_SAFE( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP_SAFE(0);
|
||||
INNER_LOOP_SAFE(2);
|
||||
INNER_LOOP_SAFE(4);
|
||||
}
|
||||
INNER_LOOP_SAFE( 0 );
|
||||
INNER_LOOP_SAFE( 2 );
|
||||
INNER_LOOP_SAFE( 4 );
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2023 Valve Corporation
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
|
@ -222,3 +221,4 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
|
|
|||
944
inc/extralibs/ch32v208_eth.h
Normal file
944
inc/extralibs/ch32v208_eth.h
Normal file
|
|
@ -0,0 +1,944 @@
|
|||
/*
|
||||
* Single-File-Header for the CH32V208 (and CH579?) built-in 10BASE-T MAC/PHY.
|
||||
*
|
||||
* This peripheral uses POINTER-BASED DMA, not descriptor-based DMA:
|
||||
*
|
||||
* Hardware:
|
||||
* - ERXST register: Points to buffer for next RX packet
|
||||
* - ETXST register: Points to buffer for current TX packet
|
||||
* - Hardware DMAs directly to/from these addresses
|
||||
* - Software must manually update pointers after each packet
|
||||
*
|
||||
* Software (this driver):
|
||||
* - Creates descriptor ring for bookkeeping
|
||||
* - Descriptors are NEVER accessed by hardware
|
||||
* - OWN bit is pure software: 1=empty, 0=filled
|
||||
* - Provides ring-buffer API on top of simple pointers
|
||||
*
|
||||
* USAGE
|
||||
*
|
||||
* Include once with implementation:
|
||||
*
|
||||
* #define CH32V208_ETH_IMPLEMENTATION
|
||||
* #include "ch32v208_eth.h"
|
||||
*
|
||||
* Init:
|
||||
*
|
||||
* eth_config_t config = {
|
||||
* .mac_addr = my_mac, // NULL = use chip default
|
||||
* .rx_callback = eth_rx_cb, // NULL if using manual polling
|
||||
* .link_callback = link_cb, // optional
|
||||
* .activity_callback = led_cb, // optional
|
||||
* .broadcast_filter = true,
|
||||
* };
|
||||
* eth_init(&config);
|
||||
*
|
||||
* Main loop:
|
||||
*
|
||||
* while (1) {
|
||||
* eth_poll_link(); // call every 50-100ms
|
||||
* eth_process_rx(); // IF using callback mode
|
||||
* }
|
||||
*
|
||||
* RECEIVING PACKETS
|
||||
*
|
||||
* Callback mode:
|
||||
*
|
||||
* void eth_rx_cb(const uint8_t *packet, uint16_t length) {
|
||||
* // process packet (called from eth_process_rx)
|
||||
* }
|
||||
*
|
||||
* Manual polling (zero-copy, for sfhip, lwIP etc):
|
||||
*
|
||||
* uint16_t length;
|
||||
* const uint8_t *packet;
|
||||
* while ((packet = eth_get_rx_packet(&length)) != NULL) {
|
||||
* // process packet directly from DMA buffer
|
||||
* eth_release_rx_packet(); // must call when done
|
||||
* }
|
||||
*
|
||||
* SENDING PACKETS
|
||||
*
|
||||
* Simple (with memcpy):
|
||||
*
|
||||
* uint8_t packet[64];
|
||||
* // ... fill packet ...
|
||||
* int ret = eth_send_packet(packet, 64);
|
||||
* // ret: 0=success, -1=queue full
|
||||
*
|
||||
* Zero-copy mode (build directly in DMA buffer):
|
||||
*
|
||||
* uint16_t max_len;
|
||||
* uint8_t *buf = eth_get_tx_buffer(&max_len);
|
||||
* if (buf) {
|
||||
* // build packet directly in DMA buffer
|
||||
* eth_send_packet_zerocopy(actual_length);
|
||||
* }
|
||||
*
|
||||
* CONFIGURATION
|
||||
*
|
||||
* Define before including header to customize:
|
||||
*
|
||||
* ETH_RX_BUF_COUNT RX descriptor ring size (default: 4)
|
||||
* ETH_TX_BUF_COUNT TX queue depth (default: 2)
|
||||
* ETH_MAX_PACKET_SIZE MAC MTU (default: 1536)
|
||||
* ETH_RX_BUF_SIZE RX buffer size (default: ETH_MAX_PACKET_SIZE)
|
||||
* ETH_TX_BUF_SIZE TX buffer size (default: ETH_MAX_PACKET_SIZE)
|
||||
* ETH_ENABLE_STATS Enable eth_get_stats() and eth_reset_stats()
|
||||
*/
|
||||
|
||||
#ifndef _CH32V208_ETH_H
|
||||
#define _CH32V208_ETH_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef ETH_RX_BUF_COUNT
|
||||
#define ETH_RX_BUF_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifndef ETH_TX_BUF_COUNT
|
||||
#define ETH_TX_BUF_COUNT 2
|
||||
#endif
|
||||
|
||||
#ifndef ETH_MAX_PACKET_SIZE
|
||||
#define ETH_MAX_PACKET_SIZE 1536
|
||||
#endif
|
||||
|
||||
#ifndef ETH_RX_BUF_SIZE
|
||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef ETH_TX_BUF_SIZE
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
||||
#endif
|
||||
|
||||
#define ETH_MAC_ADDR_LEN 6
|
||||
|
||||
// Define ETH_ENABLE_STATS before including this header to enable stats collection
|
||||
// #define ETH_ENABLE_STATS
|
||||
|
||||
// Callback types
|
||||
typedef void ( *eth_rx_callback_t )( const uint8_t *packet, uint16_t length );
|
||||
typedef void ( *eth_link_callback_t )( bool link_up );
|
||||
typedef void ( *eth_activity_callback_t )( void );
|
||||
|
||||
// Ethernet configuration
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *mac_addr; // MAC address (can be NULL to use chip default)
|
||||
eth_rx_callback_t rx_callback; // Called when packet received
|
||||
eth_link_callback_t link_callback; // Called when link status changes
|
||||
eth_activity_callback_t activity_callback; // Called on TX/RX activity, can be used for LED
|
||||
bool promiscuous_mode; // Enable promiscuous mode
|
||||
bool broadcast_filter; // Accept broadcast packets
|
||||
bool multicast_filter; // Accept multicast packets
|
||||
} eth_config_t;
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
// Ethernet statistics
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rx_packets;
|
||||
uint32_t tx_packets;
|
||||
uint32_t rx_errors;
|
||||
uint32_t tx_errors;
|
||||
uint32_t rx_dropped;
|
||||
uint32_t tx_dropped;
|
||||
} eth_stats_t;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Init the Ethernet peripheral
|
||||
* @param config Ptr to config struct
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int eth_init( const eth_config_t *config );
|
||||
|
||||
/**
|
||||
* Send an Ethernet packet
|
||||
* @param packet Ptr to packet data (incl. Ethernet header)
|
||||
* @param length Length of pkt in bytes
|
||||
* @return 0: success, -1: queue full
|
||||
*/
|
||||
int eth_send_packet( const uint8_t *packet, uint16_t length );
|
||||
|
||||
/**
|
||||
* Get pointer to next available TX buffer for zero-copy transmission
|
||||
* @param length max length available in buffer
|
||||
* @return pointer to TX buffer, or NULL if queue full
|
||||
* @note After writing packet data, call eth_send_packet_zerocopy() with actual length
|
||||
*/
|
||||
uint8_t *eth_get_tx_buffer( uint16_t *max_length );
|
||||
|
||||
/**
|
||||
* Commit a zero-copy TX buffer for transmission
|
||||
* @param length packet length written to buffer from eth_get_tx_buffer()
|
||||
* @return 0 on success
|
||||
*/
|
||||
int eth_send_packet_zerocopy( uint16_t length );
|
||||
|
||||
/**
|
||||
* Process received packets (call from main loop)
|
||||
* This will invoke the rx_callback for each received pkt
|
||||
*/
|
||||
void eth_process_rx( void );
|
||||
|
||||
/**
|
||||
* Get pointer to next received packet (alternative to eth_process_rx with callback)
|
||||
* @param length Pointer to store packet length
|
||||
* @return Pointer to packet data, or NULL if no packet ready
|
||||
* @note Caller MUST call eth_release_rx_packet() when done with the packet
|
||||
* @note Packet data is valid only until eth_release_rx_packet() is called
|
||||
*/
|
||||
const uint8_t *eth_get_rx_packet( uint16_t *length );
|
||||
|
||||
/**
|
||||
* Release currently held RX packet back to DMA
|
||||
* @note Must be called after eth_get_rx_packet() to free the descriptor
|
||||
*/
|
||||
void eth_release_rx_packet( void );
|
||||
|
||||
/**
|
||||
* Poll link status and handle auto-negotiation
|
||||
* this is based on WCHNET_LinkProcess
|
||||
* https://github.com/openwch/ch32v20x/blob/main/EVT/EXAM/ETH/NetLib/eth_driver.c#L131
|
||||
* TODO: cable polarity reversal is untested
|
||||
*
|
||||
* call this periodically from main loop (i.e. every 50-100ms)
|
||||
*/
|
||||
void eth_poll_link( void );
|
||||
|
||||
/**
|
||||
* Get current MAC
|
||||
* @param mac_addr Buffer to store MAC address (6 bytes)
|
||||
*/
|
||||
void eth_get_mac_address( uint8_t *mac_addr );
|
||||
|
||||
/**
|
||||
* Check if link is up
|
||||
* @return true if link is up
|
||||
*/
|
||||
bool eth_is_link_up( void );
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
/**
|
||||
* Get stats
|
||||
* @param stats Pointer to statistics structure to fill
|
||||
*/
|
||||
void eth_get_stats( eth_stats_t *stats );
|
||||
|
||||
/**
|
||||
* Reset stat counters
|
||||
*/
|
||||
void eth_reset_stats( void );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _CH32V208_ETH_H
|
||||
|
||||
|
||||
#ifdef CH32V208_ETH_IMPLEMENTATION
|
||||
|
||||
#include "ch32fun.h"
|
||||
#include <string.h>
|
||||
|
||||
// DMA descriptor
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t Status;
|
||||
volatile uint32_t Buffer1Addr;
|
||||
} ETH_DMADESCTypeDef;
|
||||
|
||||
// TX queue management
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t head;
|
||||
volatile uint32_t tail;
|
||||
volatile bool is_full; // this is only really needed if ETH_TX_BUF_COUNT == 1
|
||||
} tx_queue_t;
|
||||
|
||||
// driver state
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rx_head_idx;
|
||||
uint32_t rx_tail_idx;
|
||||
tx_queue_t tx_q;
|
||||
uint8_t mac_addr[ETH_MAC_ADDR_LEN];
|
||||
eth_rx_callback_t rx_callback;
|
||||
eth_link_callback_t link_callback;
|
||||
eth_activity_callback_t activity_callback;
|
||||
volatile bool link_irq_flag;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
eth_stats_t stats;
|
||||
#endif
|
||||
// autoneg & polarity state
|
||||
uint8_t phy_mdix_mode; // current MDI/MDIX setting
|
||||
uint8_t crc_error_count; // CRC errors since link up
|
||||
bool polarity_detect_active;
|
||||
uint8_t negotiation_poll_count;
|
||||
enum
|
||||
{
|
||||
LINK_STATE_DOWN,
|
||||
LINK_STATE_NEGOTIATING,
|
||||
LINK_STATE_UP
|
||||
} link_state;
|
||||
} eth_driver_state_t;
|
||||
|
||||
__attribute__( ( aligned( 4 ) ) ) static ETH_DMADESCTypeDef g_dma_rx_descs[ETH_RX_BUF_COUNT];
|
||||
__attribute__( ( aligned( 4 ) ) ) static ETH_DMADESCTypeDef g_dma_tx_descs[ETH_TX_BUF_COUNT];
|
||||
__attribute__( ( aligned( 4 ) ) ) static uint8_t g_mac_rx_bufs[ETH_RX_BUF_COUNT * ETH_RX_BUF_SIZE];
|
||||
__attribute__( ( aligned( 4 ) ) ) static uint8_t g_mac_tx_bufs[ETH_TX_BUF_COUNT * ETH_TX_BUF_SIZE];
|
||||
|
||||
static eth_driver_state_t g_eth_state = { 0 };
|
||||
|
||||
static void phy_write_reg( uint8_t reg_add, uint16_t reg_val )
|
||||
{
|
||||
R32_ETH_MIWR = ( reg_add & RB_ETH_MIREGADR_MASK ) | RB_ETH_MIWR_MIIWR | ( reg_val << RB_ETH_MIWR_DATA_SHIFT );
|
||||
}
|
||||
|
||||
static uint16_t phy_read_reg( uint8_t reg_add )
|
||||
{
|
||||
ETH10M->MIERGADR = reg_add;
|
||||
return ETH10M->MIRD;
|
||||
}
|
||||
|
||||
static inline void tx_queue_init( tx_queue_t *q )
|
||||
{
|
||||
q->head = 0;
|
||||
q->tail = 0;
|
||||
q->is_full = false;
|
||||
}
|
||||
|
||||
static inline bool tx_queue_is_empty( const tx_queue_t *q )
|
||||
{
|
||||
return !q->is_full && ( q->head == q->tail );
|
||||
}
|
||||
|
||||
static inline bool tx_queue_is_full( const tx_queue_t *q )
|
||||
{
|
||||
return q->is_full;
|
||||
}
|
||||
|
||||
static inline void tx_queue_produce( tx_queue_t *q )
|
||||
{
|
||||
q->head = ( q->head + 1 ) % ETH_TX_BUF_COUNT;
|
||||
if ( q->head == q->tail )
|
||||
{
|
||||
q->is_full = true; // head caught up to tail = full
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tx_queue_consume( tx_queue_t *q )
|
||||
{
|
||||
q->tail = ( q->tail + 1 ) % ETH_TX_BUF_COUNT;
|
||||
q->is_full = false; // after consuming, definitely not full
|
||||
}
|
||||
|
||||
static void eth_get_chip_mac_addr( uint8_t *mac )
|
||||
{
|
||||
const uint8_t *macaddr_src = (const uint8_t *)( ROM_CFG_USERADR_ID + 5 );
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
mac[i] = *( macaddr_src-- );
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_start_if_possible( void )
|
||||
{
|
||||
if ( ETH10M->ECON1 & RB_ETH_ECON1_TXRTS )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t idx = g_eth_state.tx_q.tail;
|
||||
ETH_DMADESCTypeDef *desc = &g_dma_tx_descs[idx];
|
||||
uint16_t len = desc->Status;
|
||||
|
||||
ETH10M->ETXLN = len; // set tx packet len
|
||||
ETH10M->ETXST = desc->Buffer1Addr; // set tx buf start address (DMA source)
|
||||
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS; // set tx req flag to start DMA transmission
|
||||
}
|
||||
|
||||
/**
|
||||
* Start PHY auto-negotiation with specific MDI/MDIX mode
|
||||
*/
|
||||
static void phy_start_autoneg( uint8_t mdix_mode )
|
||||
{
|
||||
// reset and restart auto-negotiation
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
// configure MDI/MDIX mode
|
||||
phy_write_reg( PHY_MDIX, ( mdix_mode & MDIX_MODE_MASK ) | MDIX_PN_POLARITY_NORMAL );
|
||||
// enable auto-negotiation
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_AN_ENABLE | PHY_BMCR_AN_RESTART );
|
||||
|
||||
g_eth_state.phy_mdix_mode = mdix_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try next MDI/MDIX mode in sequence: AUTO -> MDIX -> MDI -> AUTO
|
||||
*/
|
||||
static void phy_try_next_mdix_mode( void )
|
||||
{
|
||||
uint8_t next_mode;
|
||||
|
||||
switch ( g_eth_state.phy_mdix_mode & MDIX_MODE_MASK )
|
||||
{
|
||||
case MDIX_MODE_AUTO:
|
||||
next_mode = MDIX_MODE_MDIX; // try forced MDIX
|
||||
break;
|
||||
case MDIX_MODE_MDIX:
|
||||
next_mode = MDIX_MODE_MDI; // try forced MDI
|
||||
break;
|
||||
default:
|
||||
next_mode = MDIX_MODE_AUTO; // back to auto
|
||||
break;
|
||||
}
|
||||
|
||||
phy_start_autoneg( next_mode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cable polarity issue (P/N reversal)
|
||||
*/
|
||||
static void phy_fix_polarity( void )
|
||||
{
|
||||
uint16_t mdix_reg = phy_read_reg( PHY_MDIX );
|
||||
|
||||
// toggle P/N polarity between NORMAL and REVERSED
|
||||
mdix_reg ^= MDIX_PN_POLARITY_REVERSED;
|
||||
|
||||
phy_write_reg( PHY_MDIX, mdix_reg );
|
||||
g_eth_state.crc_error_count = 0;
|
||||
}
|
||||
|
||||
static void eth_link_up_handler( void )
|
||||
{
|
||||
// read auto-negotiation registers
|
||||
uint16_t anar = phy_read_reg( PHY_ANAR ); // what we advertised
|
||||
uint16_t anlpar = phy_read_reg( PHY_ANLPAR ); // what partner advertised
|
||||
uint16_t common = anar & anlpar;
|
||||
|
||||
// check if both sides support full-duplex
|
||||
bool is_full_duplex = ( common & PHY_ANLPAR_10BASE_TFD ) != 0;
|
||||
// configure MAC to match negotiated duplex mode
|
||||
if ( is_full_duplex )
|
||||
{
|
||||
ETH10M->MACON2 |= RB_ETH_MACON2_FULDPX;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETH10M->MACON2 &= ~RB_ETH_MACON2_FULDPX;
|
||||
}
|
||||
// enable CRC error packet reception for polarity detection
|
||||
ETH10M->ERXFCON |= RB_ETH_ERXFCON_CRCEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_UP;
|
||||
g_eth_state.crc_error_count = 0;
|
||||
g_eth_state.polarity_detect_active = true;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
|
||||
if ( g_eth_state.link_callback )
|
||||
{
|
||||
g_eth_state.link_callback( true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure MAC for link down
|
||||
*/
|
||||
static void eth_link_down_handler( void )
|
||||
{
|
||||
// Disable polarity detection
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
ETH10M->ERXFCON &= ~RB_ETH_ERXFCON_CRCEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
|
||||
if ( g_eth_state.link_callback )
|
||||
{
|
||||
g_eth_state.link_callback( false );
|
||||
}
|
||||
}
|
||||
|
||||
int eth_init( const eth_config_t *config )
|
||||
{
|
||||
if ( !config )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset( &g_eth_state, 0, sizeof( g_eth_state ) );
|
||||
|
||||
g_eth_state.rx_callback = config->rx_callback;
|
||||
g_eth_state.link_callback = config->link_callback;
|
||||
g_eth_state.activity_callback = config->activity_callback;
|
||||
|
||||
if ( config->mac_addr )
|
||||
{
|
||||
memcpy( g_eth_state.mac_addr, config->mac_addr, ETH_MAC_ADDR_LEN );
|
||||
}
|
||||
else
|
||||
{
|
||||
eth_get_chip_mac_addr( g_eth_state.mac_addr );
|
||||
}
|
||||
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
RCC->CFGR0 |= RCC_ETHPRE; // Ethernet clock prescaler
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_10M_EN; // Extended Control Register, 10M Ethernet enable and clock enable
|
||||
|
||||
// Transmit/Receive module reset
|
||||
ETH10M->ECON1 = RB_ETH_ECON1_TXRST | RB_ETH_ECON1_RXRST;
|
||||
ETH10M->ECON1 = 0;
|
||||
|
||||
uint32_t rx_filter;
|
||||
|
||||
if ( config->promiscuous_mode )
|
||||
{
|
||||
// Promiscuous: disable filtering (ERXFCON=0 *probably* receives everything)
|
||||
rx_filter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal mode: enable filtering and ALWAYS receive unicast to our MAC
|
||||
rx_filter = RB_ETH_ERXFCON_EN | RB_ETH_ERXFCON_UCEN;
|
||||
|
||||
// broadcast packet reception
|
||||
if ( config->broadcast_filter )
|
||||
{
|
||||
rx_filter |= RB_ETH_ERXFCON_BCEN;
|
||||
}
|
||||
// multicast packet reception
|
||||
if ( config->multicast_filter )
|
||||
{
|
||||
rx_filter |= RB_ETH_ERXFCON_MCEN;
|
||||
}
|
||||
}
|
||||
|
||||
ETH10M->ERXFCON = rx_filter;
|
||||
// MAC layer receive enable
|
||||
ETH10M->MACON1 = RB_ETH_MACON1_MARXEN;
|
||||
|
||||
// Pad short packets with 0x00 to 60 bytes, then append 4-byte CRC
|
||||
// Hardware pads CRC
|
||||
ETH10M->MACON2 = PADCFG_AUTO_3 | RB_ETH_MACON2_TXCRCEN;
|
||||
// Set maximum frame length (MTU)
|
||||
ETH10M->MAMXFL = ETH_MAX_PACKET_SIZE;
|
||||
|
||||
// MAC is reversed
|
||||
R8_ETH_MAADRL1 = g_eth_state.mac_addr[5];
|
||||
R8_ETH_MAADRL2 = g_eth_state.mac_addr[4];
|
||||
R8_ETH_MAADRL3 = g_eth_state.mac_addr[3];
|
||||
R8_ETH_MAADRL4 = g_eth_state.mac_addr[2];
|
||||
R8_ETH_MAADRL5 = g_eth_state.mac_addr[1];
|
||||
R8_ETH_MAADRL6 = g_eth_state.mac_addr[0];
|
||||
|
||||
// PHY Analog Parameter Setting, default value and "Rated driver"
|
||||
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
||||
|
||||
tx_queue_init( &g_eth_state.tx_q );
|
||||
for ( int i = 0; i < ETH_TX_BUF_COUNT; i++ )
|
||||
{
|
||||
g_dma_tx_descs[i].Status = 0;
|
||||
g_dma_tx_descs[i].Buffer1Addr = (uint32_t)&g_mac_tx_bufs[i * ETH_TX_BUF_SIZE];
|
||||
}
|
||||
|
||||
// init RX descriptor ring (DMA reads from these)
|
||||
g_eth_state.rx_head_idx = 0;
|
||||
g_eth_state.rx_tail_idx = 0;
|
||||
for ( int i = 0; i < ETH_RX_BUF_COUNT; i++ )
|
||||
{
|
||||
g_dma_rx_descs[i].Status = ETH_DMARxDesc_OWN; // DMA owns all initially
|
||||
g_dma_rx_descs[i].Buffer1Addr = (uint32_t)&g_mac_rx_bufs[i * ETH_RX_BUF_SIZE];
|
||||
}
|
||||
|
||||
// start RX
|
||||
ETH10M->ERXST = g_dma_rx_descs[0].Buffer1Addr;
|
||||
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
||||
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
g_eth_state.crc_error_count = 0;
|
||||
|
||||
// start auto-negotiation with AUTO MDI/MDIX
|
||||
phy_start_autoneg( MDIX_MODE_AUTO );
|
||||
Delay_Ms( 100 ); // Give PHY time to initialize
|
||||
|
||||
// clear all pending interrupt flags
|
||||
ETH10M->EIR = 0xFF;
|
||||
ETH10M->ESTAT |= RB_ETH_ESTAT_INT | RB_ETH_ESTAT_BUFER;
|
||||
|
||||
ETH10M->EIE = RB_ETH_EIE_INTIE | // Ethernet interrupt enable (master enable)
|
||||
RB_ETH_EIE_RXIE | // RX complete interrupt
|
||||
RB_ETH_EIE_TXIE | // TX complete interrupt
|
||||
RB_ETH_EIE_LINKIE | // Link status change interrupt
|
||||
RB_ETH_EIE_TXERIE | // TX error interrupt (collision, underrun, etc.)
|
||||
RB_ETH_EIE_RXERIE | // RX error interrupt (CRC error, overrun, etc.)
|
||||
RB_ETH_EIE_R_EN50; // Built-in 50ohm impedance matching resistor enable
|
||||
|
||||
NVIC_EnableIRQ( ETH_IRQn );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_send_packet( const uint8_t *packet, uint16_t length )
|
||||
{
|
||||
if ( tx_queue_is_full( &g_eth_state.tx_q ) )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_dropped++;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reserve our slot in the queue
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
tx_queue_produce( &g_eth_state.tx_q );
|
||||
|
||||
uint8_t *tx_buf = (uint8_t *)g_dma_tx_descs[idx].Buffer1Addr;
|
||||
memcpy( tx_buf, packet, length );
|
||||
g_dma_tx_descs[idx].Status = length;
|
||||
|
||||
tx_start_if_possible();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *eth_get_tx_buffer( uint16_t *max_length )
|
||||
{
|
||||
if ( tx_queue_is_full( &g_eth_state.tx_q ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( max_length )
|
||||
{
|
||||
*max_length = ETH_TX_BUF_SIZE;
|
||||
}
|
||||
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
return (uint8_t *)g_dma_tx_descs[idx].Buffer1Addr;
|
||||
}
|
||||
|
||||
|
||||
int eth_send_packet_zerocopy( uint16_t length )
|
||||
{
|
||||
uint32_t idx = g_eth_state.tx_q.head;
|
||||
g_dma_tx_descs[idx].Status = length;
|
||||
|
||||
tx_queue_produce( &g_eth_state.tx_q );
|
||||
tx_start_if_possible();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *eth_get_rx_packet( uint16_t *length )
|
||||
{
|
||||
if ( !length )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t tail_idx = g_eth_state.rx_tail_idx;
|
||||
|
||||
if ( g_dma_rx_descs[tail_idx].Status & ETH_DMARxDesc_OWN )
|
||||
{
|
||||
return NULL; // no packet ready
|
||||
}
|
||||
|
||||
// extract packet length from descriptor status field
|
||||
*length = ( g_dma_rx_descs[tail_idx].Status & ETH_DMARxDesc_FL ) >> ETH_DMARxDesc_FrameLengthShift;
|
||||
|
||||
// return pointer to packet buffer
|
||||
return (const uint8_t *)g_dma_rx_descs[tail_idx].Buffer1Addr;
|
||||
}
|
||||
|
||||
void eth_release_rx_packet( void )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_packets++;
|
||||
#endif
|
||||
uint32_t tail_idx = g_eth_state.rx_tail_idx;
|
||||
|
||||
// give descriptor back to DMA
|
||||
g_dma_rx_descs[tail_idx].Status = ETH_DMARxDesc_OWN;
|
||||
|
||||
// advance to next descriptor in ring
|
||||
g_eth_state.rx_tail_idx = ( tail_idx + 1 ) % ETH_RX_BUF_COUNT;
|
||||
}
|
||||
|
||||
|
||||
void eth_process_rx( void )
|
||||
{
|
||||
uint16_t length;
|
||||
const uint8_t *packet;
|
||||
|
||||
// process all packets that DMA has released
|
||||
while ( ( packet = eth_get_rx_packet( &length ) ) != NULL )
|
||||
{
|
||||
// deliver to user callback if registered
|
||||
if ( g_eth_state.rx_callback )
|
||||
{
|
||||
g_eth_state.rx_callback( packet, length );
|
||||
}
|
||||
|
||||
eth_release_rx_packet();
|
||||
}
|
||||
}
|
||||
|
||||
void eth_poll_link( void )
|
||||
{
|
||||
if ( g_eth_state.link_irq_flag )
|
||||
{
|
||||
g_eth_state.link_irq_flag = false;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
}
|
||||
|
||||
uint16_t bmsr = phy_read_reg( PHY_BMSR );
|
||||
uint16_t anlpar = phy_read_reg( PHY_ANLPAR );
|
||||
|
||||
bool phy_link = ( bmsr & PHY_BMSR_LINK_STATUS ) != 0;
|
||||
bool an_complete = ( bmsr & PHY_BMSR_AN_COMPLETE ) != 0;
|
||||
|
||||
switch ( g_eth_state.link_state )
|
||||
{
|
||||
|
||||
case LINK_STATE_DOWN:
|
||||
if ( phy_link && an_complete && ( anlpar != 0 ) )
|
||||
{
|
||||
// valid link with successful negotiation
|
||||
eth_link_up_handler();
|
||||
}
|
||||
else if ( phy_link && an_complete && ( anlpar == 0 ) )
|
||||
{
|
||||
// false auto-negotiation completion (ANLPAR=0)
|
||||
// reset PHY and try different mode
|
||||
g_eth_state.link_state = LINK_STATE_NEGOTIATING;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
phy_try_next_mdix_mode();
|
||||
}
|
||||
break;
|
||||
|
||||
case LINK_STATE_NEGOTIATING:
|
||||
if ( phy_link && an_complete && ( anlpar != 0 ) )
|
||||
{
|
||||
// negotiation succeeded
|
||||
eth_link_up_handler();
|
||||
}
|
||||
else if ( phy_link && an_complete && ( anlpar == 0 ) )
|
||||
{
|
||||
// still no valid partner response after negotiation
|
||||
g_eth_state.negotiation_poll_count++;
|
||||
|
||||
if ( g_eth_state.negotiation_poll_count >= 10 )
|
||||
{
|
||||
// try next MDI/MDIX mode after 10 polls
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
phy_write_reg( PHY_BMCR, PHY_BMCR_RESET );
|
||||
Delay_Us( 100 );
|
||||
phy_try_next_mdix_mode();
|
||||
}
|
||||
}
|
||||
else if ( !phy_link )
|
||||
{
|
||||
// link went down during negotiation
|
||||
g_eth_state.link_state = LINK_STATE_DOWN;
|
||||
g_eth_state.negotiation_poll_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case LINK_STATE_UP:
|
||||
if ( !phy_link )
|
||||
{
|
||||
// link went down
|
||||
eth_link_down_handler();
|
||||
phy_start_autoneg( MDIX_MODE_AUTO );
|
||||
}
|
||||
else if ( g_eth_state.polarity_detect_active )
|
||||
{
|
||||
// monitor for polarity issues
|
||||
if ( g_eth_state.crc_error_count >= 3 )
|
||||
{
|
||||
phy_fix_polarity();
|
||||
g_eth_state.polarity_detect_active = false;
|
||||
ETH10M->ERXFCON &= ~RB_ETH_ERXFCON_CRCEN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void eth_get_mac_address( uint8_t *mac_addr )
|
||||
{
|
||||
if ( mac_addr )
|
||||
{
|
||||
memcpy( mac_addr, g_eth_state.mac_addr, ETH_MAC_ADDR_LEN );
|
||||
}
|
||||
}
|
||||
|
||||
bool eth_is_link_up( void )
|
||||
{
|
||||
return g_eth_state.link_state == LINK_STATE_UP;
|
||||
}
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
void eth_get_stats( eth_stats_t *stats )
|
||||
{
|
||||
if ( stats )
|
||||
{
|
||||
*stats = g_eth_state.stats;
|
||||
}
|
||||
}
|
||||
|
||||
void eth_reset_stats( void )
|
||||
{
|
||||
memset( &g_eth_state.stats, 0, sizeof( eth_stats_t ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
void ETH_IRQHandler( void ) __attribute__( ( interrupt ) ) __attribute__( ( used ) );
|
||||
void ETH_IRQHandler( void )
|
||||
{
|
||||
uint32_t flags = ETH10M->EIR;
|
||||
|
||||
uint32_t head_idx = g_eth_state.rx_head_idx;
|
||||
|
||||
if ( flags & RB_ETH_EIR_RXIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_RXIF; // clear interrupt flag
|
||||
|
||||
// check if DMA still owns the current head descriptor
|
||||
if ( g_dma_rx_descs[head_idx].Status & ETH_DMARxDesc_OWN )
|
||||
{
|
||||
uint16_t rx_len = ETH10M->ERXLN;
|
||||
|
||||
if ( rx_len == 0 || rx_len > ETH_RX_BUF_SIZE )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// check for RX errors
|
||||
uint8_t estat = ETH10M->ESTAT;
|
||||
const uint8_t error_mask =
|
||||
RB_ETH_ESTAT_BUFER | RB_ETH_ESTAT_RXCRCER | RB_ETH_ESTAT_RXNIBBLE | RB_ETH_ESTAT_RXMORE;
|
||||
|
||||
if ( estat & error_mask )
|
||||
{
|
||||
// track CRC errors specifically for polarity detection
|
||||
if ( ( estat & RB_ETH_ESTAT_RXCRCER ) && g_eth_state.polarity_detect_active )
|
||||
{
|
||||
g_eth_state.crc_error_count++;
|
||||
}
|
||||
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
return; // discard
|
||||
}
|
||||
|
||||
// check if next descriptor is available
|
||||
uint32_t next_idx = ( head_idx + 1 ) % ETH_RX_BUF_COUNT;
|
||||
|
||||
if ( !( g_dma_rx_descs[next_idx].Status & ETH_DMARxDesc_OWN ) )
|
||||
{
|
||||
// ring full
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_dropped++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// packet is ready and we have space
|
||||
// mark current descriptor as ready for CPU processing
|
||||
g_dma_rx_descs[head_idx].Status &= ~ETH_DMARxDesc_OWN;
|
||||
|
||||
// add frame metadata
|
||||
g_dma_rx_descs[head_idx].Status |= ( ETH_DMARxDesc_FS | ETH_DMARxDesc_LS | // Single segment frame
|
||||
( ETH10M->ERXLN << ETH_DMARxDesc_FrameLengthShift ) );
|
||||
|
||||
// advance head to next descriptor for DMA
|
||||
g_eth_state.rx_head_idx = next_idx;
|
||||
|
||||
// tell MAC where to write next packet
|
||||
ETH10M->ERXST = g_dma_rx_descs[next_idx].Buffer1Addr;
|
||||
|
||||
// signal activity
|
||||
if ( g_eth_state.activity_callback )
|
||||
{
|
||||
g_eth_state.activity_callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_TXIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
||||
|
||||
if ( !tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_packets++;
|
||||
#endif
|
||||
tx_queue_consume( &g_eth_state.tx_q );
|
||||
}
|
||||
|
||||
tx_start_if_possible();
|
||||
|
||||
// signal activity
|
||||
if ( g_eth_state.activity_callback )
|
||||
{
|
||||
g_eth_state.activity_callback();
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_TXERIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.tx_errors++;
|
||||
#endif
|
||||
|
||||
if ( !tx_queue_is_empty( &g_eth_state.tx_q ) )
|
||||
{
|
||||
tx_queue_consume( &g_eth_state.tx_q );
|
||||
}
|
||||
tx_start_if_possible();
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_RXERIF )
|
||||
{
|
||||
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
||||
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
||||
#ifdef ETH_ENABLE_STATS
|
||||
g_eth_state.stats.rx_errors++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( flags & RB_ETH_EIR_LINKIF )
|
||||
{
|
||||
g_eth_state.link_irq_flag = true;
|
||||
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CH32V208_ETH_IMPLEMENTATION
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#define _CH32V307GIGABIT_H
|
||||
|
||||
/* This file is written against the RTL8211E
|
||||
*/
|
||||
*/
|
||||
|
||||
// #define CH32V307GIGABIT_MCO25 1
|
||||
// #define CH32V307GIGABIT_PHYADDRESS 0
|
||||
|
|
@ -34,515 +34,515 @@
|
|||
// ETH DMA structure definition (From ch32v30x_eth.c
|
||||
typedef struct
|
||||
{
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
} ETH_DMADESCTypeDef;
|
||||
|
||||
// You must provide:
|
||||
|
||||
void ch32v307ethHandleReconfig(int link, int speed, int duplex);
|
||||
void ch32v307ethHandleReconfig( int link, int speed, int duplex );
|
||||
|
||||
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
|
||||
int ch32v307ethInitHandlePacket(uint8_t *data, int frame_length, ETH_DMADESCTypeDef *dmadesc);
|
||||
int ch32v307ethInitHandlePacket( uint8_t * data, int frame_length, ETH_DMADESCTypeDef * dmadesc );
|
||||
|
||||
void ch32v307ethInitHandleTXC(void);
|
||||
void ch32v307ethInitHandleTXC( void );
|
||||
|
||||
// This library provides:
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac);
|
||||
static int ch32v307ethInit(void);
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy(void);
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac );
|
||||
static int ch32v307ethInit( void );
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy( void );
|
||||
|
||||
// Data pursuent to ethernet.
|
||||
uint8_t ch32v307eth_mac[6] = {0};
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef *pDMARxGet;
|
||||
ETH_DMADESCTypeDef *pDMATxSet;
|
||||
uint8_t ch32v307eth_mac[6] = { 0 };
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef * pDMARxGet;
|
||||
ETH_DMADESCTypeDef * pDMATxSet;
|
||||
|
||||
|
||||
// Internal functions
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val);
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value);
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg);
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg );
|
||||
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value)
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value )
|
||||
{
|
||||
static uint8_t reg_request_count = 0;
|
||||
static uint8_t reg_request_count = 0;
|
||||
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if (miiar & ETH_MACMIIAR_MB)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2)
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if( miiar & ETH_MACMIIAR_MB )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ch32v307ethTickPhy(void)
|
||||
{
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1;
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if( ch32v307ethPHYRegAsyncRead( reg, &miidr ) ) return -1;
|
||||
|
||||
printf("REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid);
|
||||
printf( "REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid );
|
||||
|
||||
if (reg == 0x1a)
|
||||
{
|
||||
speed = ((miidr >> 4) & 3);
|
||||
linked = ((miidr >> 2) & 1);
|
||||
duplex = ((miidr >> 3) & 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr >> 14) & 3);
|
||||
linked = ((miidr >> 10) & 1);
|
||||
duplex = ((miidr >> 13) & 1);
|
||||
}
|
||||
if( reg == 0x1a )
|
||||
{
|
||||
speed = ((miidr>>4)&3);
|
||||
linked = ((miidr>>2)&1);
|
||||
duplex = ((miidr>>3)&1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr>>14)&3);
|
||||
linked = ((miidr>>10)&1);
|
||||
duplex = ((miidr>>13)&1);
|
||||
}
|
||||
|
||||
printf("LINK INFO: %d %d %d\n", speed, linked, duplex);
|
||||
if (linked)
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11);
|
||||
if (newmaccr != oldmaccr)
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig(linked, speed, duplex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
|
||||
if( linked )
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
|
||||
if( newmaccr != oldmaccr )
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig( linked, speed, duplex );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Based on ETH_WritePHYRegister
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
|
||||
{
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg)
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg )
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
}
|
||||
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac)
|
||||
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||
{
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
}
|
||||
|
||||
static int ch32v307ethInit(void)
|
||||
static int ch32v307ethInit( void )
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset)
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW);
|
||||
funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
|
||||
#endif
|
||||
|
||||
// Configure strapping.
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funDigitalWrite(PA1, FUN_HIGH);
|
||||
funDigitalWrite(PA0, FUN_HIGH);
|
||||
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay
|
||||
funDigitalWrite(PC2, FUN_HIGH);
|
||||
// Configure strapping.
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funDigitalWrite( PA1, FUN_HIGH );
|
||||
funDigitalWrite( PA0, FUN_HIGH );
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
|
||||
funDigitalWrite( PC2, FUN_HIGH );
|
||||
|
||||
// Pull-up MDIO
|
||||
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite(PD9, FUN_HIGH);
|
||||
// Pull-up MDIO
|
||||
funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite( PD9, FUN_HIGH );
|
||||
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII
|
||||
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
|
||||
(7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if (timeout == 0) return -5;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if (timeout == 0) return -6;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if( timeout == 0 ) return -5;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if( timeout == 0 ) return -6;
|
||||
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if (timeout == 0) return -7;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if( timeout == 0 ) return -7;
|
||||
|
||||
// Switch to PLL.
|
||||
// Switch to PLL.
|
||||
#ifdef CH32V307GIGABIT_MCO25
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9 << 24); // And output clock on PA8
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9<<24); // And output clock on PA8
|
||||
#else
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
#endif
|
||||
|
||||
// For clock in.
|
||||
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125
|
||||
// For clock in.
|
||||
funPinMode( PB1, GPIO_CFGLR_IN_FLOAT ); //GMII_CLK125
|
||||
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &= ~RCC_ETHMACRST;
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &=~RCC_ETHMACRST;
|
||||
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
|
||||
// Wait for reset to complete.
|
||||
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--)
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
// Wait for reset to complete.
|
||||
for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL;
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
|
||||
|
||||
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO
|
||||
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC
|
||||
funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
|
||||
funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
|
||||
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
|
||||
|
||||
// Release PHY from reset.
|
||||
// Release PHY from reset.
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH);
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
|
||||
#endif
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
|
||||
funPinMode(PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD3
|
||||
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2
|
||||
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1
|
||||
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0
|
||||
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL
|
||||
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL
|
||||
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC
|
||||
funPinMode( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
|
||||
funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
|
||||
funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
|
||||
funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
|
||||
funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
|
||||
funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
|
||||
funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
|
||||
|
||||
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V
|
||||
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1
|
||||
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1
|
||||
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1
|
||||
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0]
|
||||
funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
|
||||
funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
|
||||
funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
|
||||
funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
|
||||
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay
|
||||
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 22) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 21) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
(0 << 17) | // IFG = 0, 96-bit guard time.
|
||||
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
(0 << 12) | // Self Loop = 0
|
||||
(0 << 11) | // Full-Duplex Mode (UNSET TO START)
|
||||
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
(1 << 7) | // APCS (automatically strip frames)
|
||||
(1 << 3) | // TE (Transmit enable!)
|
||||
(1 << 2) | // RE (Receive Enable)
|
||||
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
|
||||
( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 22 ) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
( 0 << 17 ) | // IFG = 0, 96-bit guard time.
|
||||
( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
( 0 << 12 ) | // Self Loop = 0
|
||||
( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
|
||||
( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
( 1 << 7 ) | // APCS (automatically strip frames)
|
||||
( 1 << 3 ) | // TE (Transmit enable!)
|
||||
( 1 << 2 ) | // RE (Receive Enable)
|
||||
( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
PHY_Reset |
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
PHY_Reset |
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
|
||||
ch32v307ethPHYRegRead(0x03);
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe.
|
||||
if (ch32v307eth_phyid == 0xc916)
|
||||
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select.
|
||||
ch32v307ethPHYRegRead( 0x03 );
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
|
||||
if( ch32v307eth_phyid == 0xc916 )
|
||||
ch32v307ethPHYRegWrite( 0x1F, 0x0a43 ); // RTL8211FS needs page select.
|
||||
|
||||
ch32v307ethGetMacInUC(ch32v307eth_mac);
|
||||
ch32v307ethGetMacInUC( ch32v307eth_mac );
|
||||
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5] << 8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1] << 8) | (ch32v307eth_mac[2] << 16) | (ch32v307eth_mac[3] << 24));
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5]<<8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1]<<8) | (ch32v307eth_mac[2]<<16) | (ch32v307eth_mac[3]<<24));
|
||||
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
|
||||
NVIC_EnableIRQ(ETH_IRQn);
|
||||
NVIC_EnableIRQ( ETH_IRQn );
|
||||
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ETH_IRQHandler(void) __attribute__((interrupt));
|
||||
void ETH_IRQHandler(void)
|
||||
void ETH_IRQHandler( void ) __attribute__((interrupt));
|
||||
void ETH_IRQHandler( void )
|
||||
{
|
||||
uint32_t int_sta;
|
||||
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if ((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
|
||||
// Nominal interrupts.
|
||||
if (int_sta & ETH_DMA_IT_NIS)
|
||||
{
|
||||
if (int_sta & ETH_DMA_IT_R)
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
// Nominal interrupts.
|
||||
if( int_sta & ETH_DMA_IT_NIS )
|
||||
{
|
||||
if( int_sta & ETH_DMA_IT_R )
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if (status & ETH_DMARxDesc_OWN) break;
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if( status & ETH_DMARxDesc_OWN ) break;
|
||||
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
|
||||
int suppress_own = 0;
|
||||
int suppress_own = 0;
|
||||
|
||||
if ((status & mask) == eq)
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if (frame_length > 0)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet);
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
if( ( status & mask ) == eq )
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if( frame_length > 0 )
|
||||
{
|
||||
uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
|
||||
// Relinquish control back to underlying hardware.
|
||||
if (!suppress_own)
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
// Relinquish control back to underlying hardware.
|
||||
if( !suppress_own )
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
if (int_sta & ETH_DMA_IT_T)
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while (1);
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while( 1 );
|
||||
}
|
||||
if( int_sta & ETH_DMA_IT_T )
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while( 1 );
|
||||
}
|
||||
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc)
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc)
|
||||
{
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
|
||||
if (pDMATxSet->Status & ETH_DMATxDesc_OWN)
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
|
||||
pDMATxSet = (ETH_DMADESCTypeDef *)pDMATxSet->Buffer2NextDescAddr;
|
||||
pDMATxSet = (ETH_DMADESCTypeDef*)pDMATxSet->Buffer2NextDescAddr;
|
||||
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1036
inc/extralibs/fsusb.c
Normal file
1036
inc/extralibs/fsusb.c
Normal file
File diff suppressed because it is too large
Load diff
419
inc/extralibs/fsusb.h
Normal file
419
inc/extralibs/fsusb.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
#ifndef _FSUSB_H
|
||||
#define _FSUSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#if defined(FUSB_FROM_RAM) && (FUSB_FROM_RAM)
|
||||
#if defined(CH5xx)
|
||||
#define __USBFS_FUN_ATTRIBUTE __attribute__((section(".srodata"), used))
|
||||
#else
|
||||
#define __USBFS_FUN_ATTRIBUTE
|
||||
#endif
|
||||
#else
|
||||
#define __USBFS_FUN_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
#if defined(CH5xx) || defined(CH32X03x) || defined(CH32V10x)
|
||||
#if !defined (CH32X03x) && !defined(CH32V10x)
|
||||
#define USBFS_BASE USB_BASE_ADDR
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t UDEV_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t USB_STATUS;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t RX_LEN;
|
||||
__IO uint8_t Reserved0;
|
||||
__IO uint16_t Reserved1;
|
||||
__IO uint8_t UEP4_1_MOD;
|
||||
__IO uint8_t UEP2_3_MOD;
|
||||
__IO uint8_t UEP567_MOD;
|
||||
__IO uint8_t Reserved2;
|
||||
__IO uint16_t UEP0_DMA;
|
||||
__IO uint16_t Reserved3;
|
||||
__IO uint16_t UEP1_DMA;
|
||||
__IO uint16_t Reserved4;
|
||||
__IO uint16_t UEP2_DMA;
|
||||
__IO uint16_t Reserved5;
|
||||
__IO uint16_t UEP3_DMA;
|
||||
__IO uint16_t Reserved6;
|
||||
__IO uint8_t UEP0_TX_LEN;
|
||||
__IO uint8_t Reserved7;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t Reserved8;
|
||||
__IO uint8_t UEP1_TX_LEN;
|
||||
__IO uint8_t Reserved9;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t Reserved10;
|
||||
__IO uint8_t UEP2_TX_LEN;
|
||||
__IO uint8_t Reserved11;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t Reserved12;
|
||||
__IO uint8_t UEP3_TX_LEN;
|
||||
__IO uint8_t Reserved13;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t Reserved14;
|
||||
__IO uint8_t UEP4_TX_LEN;
|
||||
__IO uint8_t Reserved15;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t Reserved16;
|
||||
__IO uint32_t Reserved17;
|
||||
__IO uint32_t Reserved18;
|
||||
__IO uint32_t Reserved19;
|
||||
__IO uint32_t Reserved20;
|
||||
__IO uint32_t Reserved21;
|
||||
__IO uint32_t Reserved22;
|
||||
__IO uint32_t Reserved23;
|
||||
__IO uint32_t Reserved24;
|
||||
__IO uint16_t UEP5_DMA;
|
||||
__IO uint16_t UEP6_DMA;
|
||||
__IO uint16_t UEP7_DMA;
|
||||
__IO uint32_t Reserved25;
|
||||
__IO uint8_t UEP5_TX_LEN;
|
||||
__IO uint8_t Reserved26;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t Reserved27;
|
||||
__IO uint8_t UEP6_TX_LEN;
|
||||
__IO uint8_t Reserved28;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t Reserved29;
|
||||
__IO uint8_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t Reserved30;
|
||||
__IO uint32_t EPX_MODE;
|
||||
} USBFS_TypeDef;
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((uint8_t*)&USBFS->UEP0_TX_LEN)[n*4])
|
||||
#define UEP_CTRL_TX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((uint16_t*)&USBFS->UEP0_DMA)[n*2])
|
||||
#endif
|
||||
|
||||
#if defined(CH32V10x)
|
||||
#define USBFS_BASE 0x40023400
|
||||
#define USB_IRQn USBFS_IRQn
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t UDEV_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_ADDR;
|
||||
__IO uint8_t USB_STATUS;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t RX_LEN;
|
||||
__IO uint8_t Reserved0;
|
||||
__IO uint16_t Reserved1;
|
||||
__IO uint8_t UEP4_1_MOD;
|
||||
__IO uint8_t UEP2_3_MOD;
|
||||
__IO uint8_t UEP5_6_MOD;
|
||||
__IO uint8_t UEP7_MOD;
|
||||
__IO uint16_t UEP0_DMA;
|
||||
__IO uint16_t Reserved3;
|
||||
__IO uint16_t UEP1_DMA;
|
||||
__IO uint16_t Reserved4;
|
||||
__IO uint16_t UEP2_DMA;
|
||||
__IO uint16_t Reserved5;
|
||||
__IO uint16_t UEP3_DMA;
|
||||
__IO uint16_t Reserved6;
|
||||
__IO uint16_t UEP4_DMA;
|
||||
__IO uint16_t Reserved7;
|
||||
__IO uint16_t UEP5_DMA;
|
||||
__IO uint16_t Reserved8;
|
||||
__IO uint16_t UEP6_DMA;
|
||||
__IO uint16_t Reserved9;
|
||||
__IO uint16_t UEP7_DMA;
|
||||
__IO uint16_t Reserved10;
|
||||
__IO uint16_t UEP0_TX_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t Reserved11;
|
||||
__IO uint16_t UEP1_TX_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t Reserved12;
|
||||
__IO uint16_t UEP2_TX_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t Reserved13;
|
||||
__IO uint16_t UEP3_TX_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t Reserved14;
|
||||
__IO uint16_t UEP4_TX_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t Reserved15;
|
||||
__IO uint16_t UEP5_TX_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t Reserved16;
|
||||
__IO uint16_t UEP6_TX_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t Reserved17;
|
||||
__IO uint16_t UEP7_TX_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t Reserved18;
|
||||
} USBFS_TypeDef;
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((volatile uint16_t*)&USBFS->UEP0_DMA)[n*2])
|
||||
#endif
|
||||
|
||||
#if !defined (CH32X03x)
|
||||
#define DEBUG_PIN PA8
|
||||
|
||||
#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */
|
||||
#define UEP_SIZE 64
|
||||
|
||||
#define DEF_UEP_IN 0x80
|
||||
#define DEF_UEP_OUT 0x00
|
||||
#define DEF_UEP_BUSY 0x01
|
||||
#define DEF_UEP_FREE 0x00
|
||||
|
||||
#define DEF_UEP0 0
|
||||
#define DEF_UEP1 1
|
||||
#define DEF_UEP2 2
|
||||
#define DEF_UEP3 3
|
||||
#define DEF_UEP4 4
|
||||
#define DEF_UEP5 5
|
||||
#define DEF_UEP6 6
|
||||
#define DEF_UEP7 7
|
||||
#define UNUM_EP 8
|
||||
|
||||
#define USBFS_UEP_T_RES_MASK MASK_UEP_T_RES
|
||||
#define USBFS_UEP_T_RES_ACK UEP_T_RES_ACK
|
||||
#define USBFS_UEP_T_RES_NAK UEP_T_RES_NAK
|
||||
#define USBFS_UEP_T_TOG RB_UEP_T_TOG
|
||||
#define USBFS_UEP_T_RES_STALL UEP_T_RES_STALL
|
||||
|
||||
#define USBFS_UEP_R_RES_MASK MASK_UEP_R_RES
|
||||
#define USBFS_UEP_R_RES_ACK UEP_R_RES_ACK
|
||||
#define USBFS_UEP_R_RES_NAK UEP_R_RES_NAK
|
||||
#define USBFS_UEP_R_TOG RB_UEP_R_TOG
|
||||
#define USBFS_UEP_R_RES_STALL UEP_R_RES_STALL
|
||||
|
||||
#define USBFS_UDA_GP_BIT RB_UDA_GP_BIT
|
||||
#define USBFS_UMS_SUSPEND RB_UMS_SUSPEND
|
||||
|
||||
#define USBFS_UC_RESET_SIE RB_UC_RESET_SIE
|
||||
#define USBFS_UC_CLR_ALL RB_UC_CLR_ALL
|
||||
#define USBFS_UIE_SUSPEND RB_UIE_SUSPEND
|
||||
#define USBFS_UIE_TRANSFER RB_UIE_TRANSFER
|
||||
#define USBFS_UIE_BUS_RST RB_UIE_BUS_RST
|
||||
#define USBFS_UC_INT_BUSY RB_UC_INT_BUSY
|
||||
#define USBFS_UC_DMA_EN RB_UC_DMA_EN
|
||||
#define USBFS_UC_DEV_PU_EN RB_UC_DEV_PU_EN
|
||||
|
||||
#endif
|
||||
|
||||
#define USBFS_UD_PORT_EN RB_UD_PORT_EN
|
||||
#define USBFS_UD_PD_DIS RB_UD_PD_DIS
|
||||
|
||||
#define USBFS_UEP1_RX_EN RB_UEP1_RX_EN
|
||||
#define USBFS_UEP2_RX_EN RB_UEP2_RX_EN
|
||||
#define USBFS_UEP3_RX_EN RB_UEP3_RX_EN
|
||||
#define USBFS_UEP4_RX_EN RB_UEP4_RX_EN
|
||||
|
||||
#define USBFS_UEP1_TX_EN RB_UEP1_TX_EN
|
||||
#define USBFS_UEP2_TX_EN RB_UEP2_TX_EN
|
||||
#define USBFS_UEP3_TX_EN RB_UEP3_TX_EN
|
||||
#define USBFS_UEP4_TX_EN RB_UEP4_TX_EN
|
||||
|
||||
#define CHECK_USBFS_UEP_AUTO_TOG RB_UEP_AUTO_TOG
|
||||
#define CHECK_USBFS_UEP_T_AUTO_TOG RB_UEP_AUTO_TOG
|
||||
// #define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
||||
|
||||
#define USBFS ((USBFS_TypeDef *)USBFS_BASE)
|
||||
|
||||
#ifdef CH32X03x
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
||||
#define DEBUG_PIN PB12
|
||||
#define USB_IRQn USBFS_IRQn
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_PIN PB0
|
||||
|
||||
#define USBFS ((USBOTG_FS_TypeDef *)USBFS_BASE)
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_RX_CTRL)[n*4])
|
||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
||||
|
||||
#define CHECK_USBFS_UEP_T_AUTO_TOG USBOTG_UEP_T_AUTO_TOG
|
||||
#define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
||||
|
||||
#define USBFS_UEP_T_RES_MASK USBOTG_UEP_T_RES_MASK
|
||||
#define USBFS_UEP_T_RES_ACK USBOTG_UEP_T_RES_ACK
|
||||
#define USBFS_UEP_T_RES_NAK USBOTG_UEP_T_RES_NAK
|
||||
#define USBFS_UEP_T_TOG USBOTG_UEP_T_TOG
|
||||
#define USBFS_UEP_T_RES_STALL USBOTG_UEP_T_RES_STALL
|
||||
|
||||
#define USBFS_UEP_R_RES_MASK USBOTG_UEP_R_RES_MASK
|
||||
#define USBFS_UEP_R_RES_ACK USBOTG_UEP_R_RES_ACK
|
||||
#define USBFS_UEP_R_RES_NAK USBOTG_UEP_R_RES_NAK
|
||||
#define USBFS_UEP_R_TOG USBOTG_UEP_R_TOG
|
||||
#define USBFS_UEP_R_RES_STALL USBOTG_UEP_R_RES_STALL
|
||||
|
||||
// #define USBFS_UDA_GP_BIT USBOTG_UDA_GP_BIT
|
||||
#define USBFS_UMS_SUSPEND USBOTG_UMS_SUSPEND
|
||||
#define USBFS_UEP1_RX_EN USBOTG_UEP1_RX_EN
|
||||
#define USBFS_UEP2_RX_EN USBOTG_UEP2_RX_EN
|
||||
#define USBFS_UEP3_RX_EN USBOTG_UEP3_RX_EN
|
||||
#define USBFS_UEP4_RX_EN USBOTG_UEP4_RX_EN
|
||||
|
||||
#define USBFS_UEP1_TX_EN USBOTG_UEP1_TX_EN
|
||||
#define USBFS_UEP2_TX_EN USBOTG_UEP2_TX_EN
|
||||
#define USBFS_UEP3_TX_EN USBOTG_UEP3_TX_EN
|
||||
#define USBFS_UEP4_TX_EN USBOTG_UEP4_TX_EN
|
||||
|
||||
#define USBFS_UC_RESET_SIE USBOTG_UC_RESET_SIE
|
||||
#define USBFS_UC_CLR_ALL USBOTG_UC_CLR_ALL
|
||||
#define USBFS_UIE_SUSPEND USBOTG_UIE_SUSPEND
|
||||
#define USBFS_UIE_TRANSFER USBOTG_UIE_TRANSFER
|
||||
#define USBFS_UIE_BUS_RST USBOTG_UIE_BUS_RST
|
||||
#define USBFS_UC_INT_BUSY USBOTG_UC_INT_BUSY
|
||||
#define USBFS_UC_DMA_EN USBOTG_UC_DMA_EN
|
||||
#define USBFS_UC_DEV_PU_EN USBOTG_UC_DEV_PU_EN
|
||||
#define USBFS_UD_PD_DIS USBOTG_UD_PD_DIS
|
||||
#define USBFS_UD_PORT_EN USBOTG_UD_PORT_EN
|
||||
|
||||
#ifdef CH32V30x_D8C
|
||||
#define USB_IRQn OTG_FS_IRQn
|
||||
#else
|
||||
#define USB_IRQn USBHD_IRQn
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// Mask for the combined USBFS->INT_FG + USBFS->INT_ST
|
||||
#define CRB_UIS_IS_NAK (1<<7)
|
||||
#define CRB_U_TOG_OK (1<<6)
|
||||
#define CRB_U_SIE_FREE (1<<5)
|
||||
#define CRB_UIF_FIFO_OV (1<<4)
|
||||
#define CRB_UIF_HST_SOF (1<<3)
|
||||
#define CRB_UIF_SUSPEND (1<<2)
|
||||
#define CRB_UIF_TRANSFER (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
|
||||
#if defined(CH5xx) || defined(CH32X03x) || defined(CH32V10x)
|
||||
#define CRB_UIF_SETUP_ACT (1<<15)
|
||||
#endif
|
||||
#define CRB_UIS_TOG_OK (1<<14)
|
||||
#define CMASK_UIS_TOKEN (3<<12)
|
||||
#define CMASK_UIS_ENDP (0xf<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_SOF 0x1
|
||||
#define CUIS_TOKEN_IN 0x2
|
||||
#define CUIS_TOKEN_SETUP 0x3
|
||||
|
||||
#define USBFS_PACKET_SIZE 64
|
||||
|
||||
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
||||
|
||||
struct _USBState;
|
||||
|
||||
// Provided functions:
|
||||
int USBFSSetup();
|
||||
uint8_t USBFS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||
static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
|
||||
static inline int USBFS_SendEndpoint( int endp, int len );
|
||||
static inline int USBFS_SendACK( int endp, int tx );
|
||||
static inline int USBFS_SendNAK( int endp, int tx );
|
||||
|
||||
#if FUSB_USE_DMA7_COPY
|
||||
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len );
|
||||
static inline void copyBufferComplete();
|
||||
#endif
|
||||
|
||||
// Implement the following:
|
||||
#if FUSB_HID_USER_REPORTS
|
||||
__USBFS_FUN_ATTRIBUTE int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
__USBFS_FUN_ATTRIBUTE int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
#if FUSB_USER_HANDLERS
|
||||
__USBFS_FUN_ATTRIBUTE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__USBFS_FUN_ATTRIBUTE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__USBFS_FUN_ATTRIBUTE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBFS_EP_OFF = 0,
|
||||
USBFS_EP_RX = -1,
|
||||
USBFS_EP_TX = 1,
|
||||
} USBFS_EP_mode;
|
||||
|
||||
#ifndef FUSB_EP1_MODE
|
||||
#define FUSB_EP1_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP2_MODE
|
||||
#define FUSB_EP2_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP3_MODE
|
||||
#define FUSB_EP3_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP4_MODE
|
||||
#define FUSB_EP4_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP5_MODE
|
||||
#define FUSB_EP5_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP6_MODE
|
||||
#define FUSB_EP6_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP7_MODE
|
||||
#define FUSB_EP7_MODE 0
|
||||
#endif
|
||||
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
// Setup Request
|
||||
uint8_t USBFS_SetupReqCode;
|
||||
uint8_t USBFS_SetupReqType;
|
||||
uint16_t USBFS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBFS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint8_t USBFS_DevConfig;
|
||||
uint8_t USBFS_DevAddr;
|
||||
uint8_t USBFS_DevSleepStatus;
|
||||
uint8_t USBFS_DevEnumStatus;
|
||||
|
||||
uint8_t* pCtrlPayloadPtr;
|
||||
|
||||
uint8_t ENDPOINTS[FUSB_CONFIG_EPS][64];
|
||||
USBFS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
||||
|
||||
#define CTRL0BUFF (USBFSCTX.ENDPOINTS[0])
|
||||
#define pUSBFS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||
|
||||
#if FUSB_HID_INTERFACES > 0
|
||||
uint8_t USBFS_HidIdle[FUSB_HID_INTERFACES];
|
||||
uint8_t USBFS_HidProtocol[FUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBFS_Endp_Busy[FUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBFS_errata_dont_send_endpoint_in_window;
|
||||
};
|
||||
|
||||
extern struct _USBState USBFSCTX;
|
||||
|
||||
#include "fsusb.c"
|
||||
|
||||
#endif
|
||||
|
||||
1022
inc/extralibs/hsusb.c
Normal file
1022
inc/extralibs/hsusb.c
Normal file
File diff suppressed because it is too large
Load diff
475
inc/extralibs/hsusb.h
Normal file
475
inc/extralibs/hsusb.h
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
#ifndef _HSUSB_H
|
||||
#define _HSUSB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#if !defined(CH584_CH585) && !defined(CH32V205) && !defined(CH32H4xx) && !defined(CH32V30x) && !defined(CH565_CH569)
|
||||
#error "This lib doesn't work on this MCU"
|
||||
#endif
|
||||
|
||||
#if defined(CH32V30x) || defined(CH565_CH569)
|
||||
#define USBHS_IMPL 1
|
||||
// #elif defined(CH584_CH585) || defined(CH32V205) || defined(CH32H4xx)
|
||||
#else
|
||||
#define USBHS_IMPL 2
|
||||
#endif
|
||||
|
||||
#ifndef __HIGH_CODE
|
||||
#define __HIGH_CODE
|
||||
#endif
|
||||
|
||||
#ifndef USBHS_BASE
|
||||
#if defined(CH32V30x) || defined(CH32V205)
|
||||
#define USBHS_BASE (0x40023400)
|
||||
#elif defined(CH32H4xx)
|
||||
#define USBHS_BASE (0x40030000)
|
||||
#else
|
||||
#define USBHS_BASE (0x40009000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (USBHS_IMPL==1)
|
||||
#if (FUNCONF_USE_HSI) && !defined(FUSB_SOF_HSITRIM)
|
||||
#define FUSB_SOF_HSITRIM 1
|
||||
#endif
|
||||
#define TICKS_PER_HSITRIM (FUNCONF_PLL_MULTIPLIER * 20000 * 125) / 1000000 // SOF is sent every 125uS, each HSITRIM changes HSI by 20kHz
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t HOST_CTRL;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint8_t SUSPEND;
|
||||
__IO uint8_t RESERVED0;
|
||||
__IO uint8_t SPEED_TYPE;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint8_t INT_FG;
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint16_t RX_LEN;
|
||||
__IO uint16_t RESERVED1;
|
||||
__IO uint32_t UEP_CONFIG;
|
||||
__IO uint32_t UEP_TYPE;
|
||||
__IO uint32_t UEP_BUF_MODE;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_RX_DMA;
|
||||
__IO uint32_t UEP2_RX_DMA;
|
||||
__IO uint32_t UEP3_RX_DMA;
|
||||
__IO uint32_t UEP4_RX_DMA;
|
||||
__IO uint32_t UEP5_RX_DMA;
|
||||
__IO uint32_t UEP6_RX_DMA;
|
||||
__IO uint32_t UEP7_RX_DMA;
|
||||
__IO uint32_t UEP8_RX_DMA;
|
||||
__IO uint32_t UEP9_RX_DMA;
|
||||
__IO uint32_t UEP10_RX_DMA;
|
||||
__IO uint32_t UEP11_RX_DMA;
|
||||
__IO uint32_t UEP12_RX_DMA;
|
||||
__IO uint32_t UEP13_RX_DMA;
|
||||
__IO uint32_t UEP14_RX_DMA;
|
||||
__IO uint32_t UEP15_RX_DMA;
|
||||
__IO uint32_t UEP1_TX_DMA;
|
||||
__IO uint32_t UEP2_TX_DMA;
|
||||
__IO uint32_t UEP3_TX_DMA;
|
||||
__IO uint32_t UEP4_TX_DMA;
|
||||
__IO uint32_t UEP5_TX_DMA;
|
||||
__IO uint32_t UEP6_TX_DMA;
|
||||
__IO uint32_t UEP7_TX_DMA;
|
||||
__IO uint32_t UEP8_TX_DMA;
|
||||
__IO uint32_t UEP9_TX_DMA;
|
||||
__IO uint32_t UEP10_TX_DMA;
|
||||
__IO uint32_t UEP11_TX_DMA;
|
||||
__IO uint32_t UEP12_TX_DMA;
|
||||
__IO uint32_t UEP13_TX_DMA;
|
||||
__IO uint32_t UEP14_TX_DMA;
|
||||
__IO uint32_t UEP15_TX_DMA;
|
||||
__IO uint16_t UEP0_MAX_LEN;
|
||||
__IO uint16_t RESERVED2;
|
||||
__IO uint16_t UEP1_MAX_LEN;
|
||||
__IO uint16_t RESERVED3;
|
||||
__IO uint16_t UEP2_MAX_LEN;
|
||||
__IO uint16_t RESERVED4;
|
||||
__IO uint16_t UEP3_MAX_LEN;
|
||||
__IO uint16_t RESERVED5;
|
||||
__IO uint16_t UEP4_MAX_LEN;
|
||||
__IO uint16_t RESERVED6;
|
||||
__IO uint16_t UEP5_MAX_LEN;
|
||||
__IO uint16_t RESERVED7;
|
||||
__IO uint16_t UEP6_MAX_LEN;
|
||||
__IO uint16_t RESERVED8;
|
||||
__IO uint16_t UEP7_MAX_LEN;
|
||||
__IO uint16_t RESERVED9;
|
||||
__IO uint16_t UEP8_MAX_LEN;
|
||||
__IO uint16_t RESERVED10;
|
||||
__IO uint16_t UEP9_MAX_LEN;
|
||||
__IO uint16_t RESERVED11;
|
||||
__IO uint16_t UEP10_MAX_LEN;
|
||||
__IO uint16_t RESERVED12;
|
||||
__IO uint16_t UEP11_MAX_LEN;
|
||||
__IO uint16_t RESERVED13;
|
||||
__IO uint16_t UEP12_MAX_LEN;
|
||||
__IO uint16_t RESERVED14;
|
||||
__IO uint16_t UEP13_MAX_LEN;
|
||||
__IO uint16_t RESERVED15;
|
||||
__IO uint16_t UEP14_MAX_LEN;
|
||||
__IO uint16_t RESERVED16;
|
||||
__IO uint16_t UEP15_MAX_LEN;
|
||||
__IO uint16_t RESERVED17;
|
||||
__IO uint16_t UEP0_T_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_T_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_T_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_T_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_T_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_T_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_T_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_T_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint16_t UEP8_T_LEN;
|
||||
__IO uint8_t UEP8_TX_CTRL;
|
||||
__IO uint8_t UEP8_RX_CTRL;
|
||||
__IO uint16_t UEP9_T_LEN;
|
||||
__IO uint8_t UEP9_TX_CTRL;
|
||||
__IO uint8_t UEP9_RX_CTRL;
|
||||
__IO uint16_t UEP10_T_LEN;
|
||||
__IO uint8_t UEP10_TX_CTRL;
|
||||
__IO uint8_t UEP10_RX_CTRL;
|
||||
__IO uint16_t UEP11_T_LEN;
|
||||
__IO uint8_t UEP11_TX_CTRL;
|
||||
__IO uint8_t UEP11_RX_CTRL;
|
||||
__IO uint16_t UEP12_T_LEN;
|
||||
__IO uint8_t UEP12_TX_CTRL;
|
||||
__IO uint8_t UEP12_RX_CTRL;
|
||||
__IO uint16_t UEP13_T_LEN;
|
||||
__IO uint8_t UEP13_TX_CTRL;
|
||||
__IO uint8_t UEP13_RX_CTRL;
|
||||
__IO uint16_t UEP14_T_LEN;
|
||||
__IO uint8_t UEP14_TX_CTRL;
|
||||
__IO uint8_t UEP14_RX_CTRL;
|
||||
__IO uint16_t UEP15_T_LEN;
|
||||
__IO uint8_t UEP15_TX_CTRL;
|
||||
__IO uint8_t UEP15_RX_CTRL;
|
||||
} USBHS_TypeDef;
|
||||
|
||||
#define USBHS_CHECK_NAK_RX (USBHS->INT_ST & 0x80)
|
||||
|
||||
#define CRB_U_IS_NAK (1<<7)
|
||||
#define CTOG_MATCH_SYNC (1<<6)
|
||||
#define CRB_UIF_SETUP_ACT (1<<5) // CRB_U_SIE_FREE on USBFS
|
||||
#define CRB_UIF_FIFO_OV (1<<4)
|
||||
#define CRB_UIF_HST_SOF (1<<3)
|
||||
#define CRB_UIF_SUSPEND (1<<2)
|
||||
#define CRB_UIF_TRANSFER (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
#define CSETUP_ACT (1<<15)
|
||||
#define CRB_UIS_TOG_OK (1<<14)
|
||||
#define CMASK_UIS_TOKEN (3<<12)
|
||||
#define CMASK_UIS_ENDP (0xf<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_SOF 0x1
|
||||
#define CUIS_TOKEN_IN 0x2
|
||||
#define CUIS_TOKEN_SETUP 0x3
|
||||
|
||||
#define UEP_TX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<n))
|
||||
#define UEP_RX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<(n+16)))
|
||||
|
||||
#define USBHS_DONE_TX(n)
|
||||
#define USBHS_DONE_RX(n)
|
||||
|
||||
#elif (USBHS_IMPL==2)
|
||||
typedef struct
|
||||
{
|
||||
__IO uint8_t BASE_CTRL;
|
||||
__IO uint8_t BASE_MODE;
|
||||
__IO uint8_t INT_EN;
|
||||
__IO uint8_t DEV_AD;
|
||||
__IO uint8_t WAKE_CTRL;
|
||||
__IO uint8_t TEST_MODE;
|
||||
__IO uint16_t LPM_DATA;
|
||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||
__IO uint8_t INT_ST;
|
||||
__IO uint8_t MIS_ST;
|
||||
__IO uint16_t FRAME_NO;
|
||||
__IO uint16_t BUS;
|
||||
__IO uint16_t UEP_TX_EN;
|
||||
__IO uint16_t UEP_RX_EN;
|
||||
__IO uint16_t UEP_T_TOG_AUTO;
|
||||
__IO uint16_t UEP_R_TOG_AUTO;
|
||||
__IO uint8_t UEP_T_BURST;
|
||||
__IO uint8_t UEP_T_BURST_MODE;
|
||||
__IO uint8_t UEP_R_BURST;
|
||||
__IO uint8_t UEP_R_RES_MODE;
|
||||
__IO uint32_t UEP_AF_MODE;
|
||||
__IO uint32_t UEP0_DMA;
|
||||
__IO uint32_t UEP1_RX_DMA;
|
||||
__IO uint32_t UEP2_RX_DMA;
|
||||
__IO uint32_t UEP3_RX_DMA;
|
||||
__IO uint32_t UEP4_RX_DMA;
|
||||
__IO uint32_t UEP5_RX_DMA;
|
||||
__IO uint32_t UEP6_RX_DMA;
|
||||
__IO uint32_t UEP7_RX_DMA;
|
||||
__IO uint32_t UEP1_TX_DMA;
|
||||
__IO uint32_t UEP2_TX_DMA;
|
||||
__IO uint32_t UEP3_TX_DMA;
|
||||
__IO uint32_t UEP4_TX_DMA;
|
||||
__IO uint32_t UEP5_TX_DMA;
|
||||
__IO uint32_t UEP6_TX_DMA;
|
||||
__IO uint32_t UEP7_TX_DMA;
|
||||
__IO uint32_t UEP0_MAX_LEN;
|
||||
__IO uint32_t UEP1_MAX_LEN;
|
||||
__IO uint32_t UEP2_MAX_LEN;
|
||||
__IO uint32_t UEP3_MAX_LEN;
|
||||
__IO uint32_t UEP4_MAX_LEN;
|
||||
__IO uint32_t UEP5_MAX_LEN;
|
||||
__IO uint32_t UEP6_MAX_LEN;
|
||||
__IO uint32_t UEP7_MAX_LEN;
|
||||
__IO uint16_t UEP0_RX_LEN;
|
||||
__IO uint16_t reserved;
|
||||
__IO uint16_t UEP1_RX_LEN;
|
||||
__IO uint16_t UEP1_R_SIZE;
|
||||
__IO uint16_t UEP2_RX_LEN;
|
||||
__IO uint16_t UEP2_R_SIZE;
|
||||
__IO uint16_t UEP3_RX_LEN;
|
||||
__IO uint16_t UEP3_R_SIZE;
|
||||
__IO uint16_t UEP4_RX_LEN;
|
||||
__IO uint16_t UEP4_R_SIZE;
|
||||
__IO uint16_t UEP5_RX_LEN;
|
||||
__IO uint16_t UEP5_R_SIZE;
|
||||
__IO uint16_t UEP6_RX_LEN;
|
||||
__IO uint16_t UEP6_R_SIZE;
|
||||
__IO uint16_t UEP7_RX_LEN;
|
||||
__IO uint16_t UEP7_R_SIZE;
|
||||
__IO uint16_t UEP0_T_LEN;
|
||||
__IO uint8_t UEP0_TX_CTRL;
|
||||
__IO uint8_t UEP0_RX_CTRL;
|
||||
__IO uint16_t UEP1_T_LEN;
|
||||
__IO uint8_t UEP1_TX_CTRL;
|
||||
__IO uint8_t UEP1_RX_CTRL;
|
||||
__IO uint16_t UEP2_T_LEN;
|
||||
__IO uint8_t UEP2_TX_CTRL;
|
||||
__IO uint8_t UEP2_RX_CTRL;
|
||||
__IO uint16_t UEP3_T_LEN;
|
||||
__IO uint8_t UEP3_TX_CTRL;
|
||||
__IO uint8_t UEP3_RX_CTRL;
|
||||
__IO uint16_t UEP4_T_LEN;
|
||||
__IO uint8_t UEP4_TX_CTRL;
|
||||
__IO uint8_t UEP4_RX_CTRL;
|
||||
__IO uint16_t UEP5_T_LEN;
|
||||
__IO uint8_t UEP5_TX_CTRL;
|
||||
__IO uint8_t UEP5_RX_CTRL;
|
||||
__IO uint16_t UEP6_T_LEN;
|
||||
__IO uint8_t UEP6_TX_CTRL;
|
||||
__IO uint8_t UEP6_RX_CTRL;
|
||||
__IO uint16_t UEP7_T_LEN;
|
||||
__IO uint8_t UEP7_TX_CTRL;
|
||||
__IO uint8_t UEP7_RX_CTRL;
|
||||
__IO uint16_t UEP_T_ISO;
|
||||
__IO uint16_t UEP_R_ISO;
|
||||
} USBHS_TypeDef;
|
||||
|
||||
#define USBHS_CHECK_NAK_RX (USBHS->UEP0_RX_CTRL & (1<<6))
|
||||
|
||||
#define UEP_RX_LEN(n) (((volatile uint16_t*)&USBHS->UEP1_RX_LEN)[(n-1)*2])
|
||||
#define UEP_TX_EN(n) USBHS->UEP_TX_EN |= ((uint16_t)(1<<n))
|
||||
#define UEP_RX_EN(n) USBHS->UEP_RX_EN |= ((uint16_t)(1<<n))
|
||||
|
||||
#define DEBUG_PIN PB17
|
||||
|
||||
#define TEST_ENABLE 0x01
|
||||
#define TEST_MASK 0x0F
|
||||
|
||||
#define USBHS_UMS_SUSPEND (1<<1)
|
||||
|
||||
#define USBHS_UC_RESET_SIE (1<<1)
|
||||
#define USBHS_UC_CLR_ALL (1<<2)
|
||||
#define USBHS_UC_DMA_EN (1<<4)
|
||||
#define USBHS_UC_PORT_EN (1<<5)
|
||||
|
||||
#define USBHS_UIE_SUSPEND (1<<1)
|
||||
#define USBHS_UIE_TRANSFER (1<<4)
|
||||
#define USBHS_UIE_BUS_RST (1<<0)
|
||||
|
||||
// Mask for the combined USBHS->INT_FG + USBHS->INT_ST
|
||||
#define CRB_UIF_FIFO_OV (1<<7)
|
||||
#define CRB_UIF_LINK_RDY (1<<6)
|
||||
#define CRB_UIF_RX_SOF (1<<5)
|
||||
#define CRB_UIF_TRANSFER (1<<4)
|
||||
#define CRB_UIF_LPM_ACT (1<<3)
|
||||
#define CRB_UIF_BUS_SLEEP (1<<2)
|
||||
#define CRB_UIF_SUSPEND (1<<1)
|
||||
#define CRB_UIF_BUS_RST (1<<0)
|
||||
|
||||
#define CMASK_UIS_TOKEN (1<<12)
|
||||
#define CMASK_UIS_ENDP (7<<8)
|
||||
|
||||
#define CUIS_TOKEN_OUT 0x0
|
||||
#define CUIS_TOKEN_IN 0x1
|
||||
|
||||
#define USBHS_DONE_TX(n) UEP_CTRL_TX(n) &= ~(USBHS_UEP_T_DONE)
|
||||
#define USBHS_DONE_RX(n) UEP_CTRL_RX(n) &= ~(USBHS_UEP_R_DONE)
|
||||
|
||||
#endif
|
||||
|
||||
#define USBHS_SPEED_TYPE_MASK ((uint8_t)(0x03))
|
||||
|
||||
#define USBHS_DEF_UEP_IN 0x80
|
||||
#define USBHS_DEF_UEP_OUT 0x00
|
||||
#define USBHS_DEF_UEP_BUSY 0x01
|
||||
#define USBHS_DEF_UEP_FREE 0x00
|
||||
|
||||
#define USBHS_NUM_EP 8
|
||||
#define USBHS_DEF_UEP0 0
|
||||
#define USBHS_DEF_UEP1 1
|
||||
#define USBHS_DEF_UEP2 2
|
||||
#define USBHS_DEF_UEP3 3
|
||||
#define USBHS_DEF_UEP4 4
|
||||
#define USBHS_DEF_UEP5 5
|
||||
#define USBHS_DEF_UEP6 6
|
||||
#define USBHS_DEF_UEP7 7
|
||||
#define USBHS_DEF_UEP8 8
|
||||
#define USBHS_DEF_UEP9 9
|
||||
#define USBHS_DEF_UEP10 10
|
||||
#define USBHS_DEF_UEP11 11
|
||||
#define USBHS_DEF_UEP12 12
|
||||
#define USBHS_DEF_UEP13 13
|
||||
#define USBHS_DEF_UEP14 14
|
||||
#define USBHS_DEF_UEP15 15
|
||||
|
||||
#define USBHS_DEF_UEP0_SIZE 64
|
||||
|
||||
#ifndef FUSB_EP_SIZE
|
||||
#define USBHS_UEP_SIZE 64
|
||||
#else
|
||||
#define USBHS_UEP_SIZE FUSB_EP_SIZE
|
||||
#endif
|
||||
|
||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBHS->UEP0_T_LEN)[n*2])
|
||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBHS->UEP0_TX_CTRL)[n*4])
|
||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBHS->UEP0_RX_CTRL)[n*4])
|
||||
#define UEP_DMA_RX(n) (((volatile uint32_t*)&USBHS->UEP0_DMA)[n])
|
||||
#define UEP_DMA_TX(n) (((volatile uint32_t*)&USBHS->UEP1_TX_DMA)[n-1])
|
||||
|
||||
#define USBHS ((USBHS_TypeDef *)USBHS_BASE)
|
||||
|
||||
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
||||
|
||||
struct _USBState;
|
||||
|
||||
// Provided functions:
|
||||
int USBHSSetup();
|
||||
static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len, int copy);
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp );
|
||||
static inline int USBHS_SendEndpoint( int endp, int len );
|
||||
static inline int USBHS_SendACK( int endp, int tx );
|
||||
static inline int USBHS_SendNAK( int endp, int tx );
|
||||
|
||||
// Implement the following:
|
||||
#if FUSB_HID_USER_REPORTS
|
||||
__HIGH_CODE int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
__HIGH_CODE int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
|
||||
#if FUSB_USER_HANDLERS
|
||||
__HIGH_CODE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__HIGH_CODE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||
__HIGH_CODE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||
#endif
|
||||
|
||||
#if FUSB_OUT_FLOW_CONTROL > 0
|
||||
void USBHS_RxReady(int endp);
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_SPEED_FULL = 0,
|
||||
USB_SPEED_HIGH = 1,
|
||||
USB_SPEED_LOW = 2,
|
||||
} USB_SPEED_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBHS_EP_OFF = 0,
|
||||
USBHS_EP_RX = -1,
|
||||
USBHS_EP_TX = 1,
|
||||
} USBHS_EP_mode;
|
||||
|
||||
#ifndef FUSB_EP1_MODE
|
||||
#define FUSB_EP1_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP2_MODE
|
||||
#define FUSB_EP2_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP3_MODE
|
||||
#define FUSB_EP3_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP4_MODE
|
||||
#define FUSB_EP4_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP5_MODE
|
||||
#define FUSB_EP5_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP6_MODE
|
||||
#define FUSB_EP6_MODE 0
|
||||
#endif
|
||||
#ifndef FUSB_EP7_MODE
|
||||
#define FUSB_EP7_MODE 0
|
||||
#endif
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
__attribute__ ((aligned(4))) uint8_t CTRL0BUFF[64];
|
||||
__attribute__ ((aligned(4))) uint8_t ENDPOINTS[FUSB_CONFIG_EPS-1][FUSB_EP_SIZE];
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint8_t USBHS_DevConfig;
|
||||
uint8_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
|
||||
uint8_t* pCtrlPayloadPtr;
|
||||
|
||||
|
||||
USBHS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
||||
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)USBHSCTX.CTRL0BUFF)
|
||||
|
||||
#if FUSB_HID_INTERFACES > 0
|
||||
uint8_t USBHS_HidIdle[FUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[FUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBHS_Endp_Busy[FUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBHS_errata_dont_send_endpoint_in_window;
|
||||
volatile uint64_t USBHS_sof_timestamp;
|
||||
};
|
||||
|
||||
extern struct _USBState USBHSCTX;
|
||||
|
||||
#include "hsusb.c"
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,74 +7,75 @@
|
|||
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
|
||||
*/
|
||||
|
||||
#include "ch32fun.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_defines.h"
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
|
||||
uint8_t *pCtrlPayloadPtr;
|
||||
uint8_t * pCtrlPayloadPtr;
|
||||
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF)
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||
|
||||
#if HUSB_HID_INTERFACES > 0
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
};
|
||||
|
||||
// Provided functions:
|
||||
int HSUSBSetup();
|
||||
int HSUSBSetup();
|
||||
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||
|
||||
// Implement the following:
|
||||
#if HUSB_HID_USER_REPORTS
|
||||
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
int HandleHidUserSetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
void HandleHidUserReportDataOut(struct _USBState *ctx, uint8_t *data, int len);
|
||||
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len);
|
||||
void HandleHidUserReportOutComplete(struct _USBState *ctx);
|
||||
int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
#endif
|
||||
|
||||
#if HUSB_BULK_USER_REPORTS
|
||||
void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
||||
void HandleGotEPComplete( struct _USBState * ctx, int ep );
|
||||
#endif
|
||||
|
||||
extern struct _USBState HSUSBCTX;
|
||||
|
||||
|
||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
||||
|
||||
static inline uint8_t *USBHS_GetEPBufferIfAvailable(int endp)
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||
{
|
||||
if (HSUSBCTX.USBHS_Endp_Busy[endp]) return 0;
|
||||
return USBHSD_UEP_TXBUF(endp);
|
||||
if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
|
||||
return USBHSD_UEP_TXBUF( endp );
|
||||
}
|
||||
|
||||
static inline void USBHS_SendEndpoint(int endp, int len, const uint8_t *data)
|
||||
static inline void USBHS_SendEndpoint( int endp, int len, const uint8_t * data )
|
||||
{
|
||||
if (endp)
|
||||
{
|
||||
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN(endp) = len;
|
||||
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01;
|
||||
if( endp )
|
||||
{
|
||||
(((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN( endp ) = len;
|
||||
USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
852
inc/extralibs/iSLER.h
Normal file
852
inc/extralibs/iSLER.h
Normal file
|
|
@ -0,0 +1,852 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CH570_CH572
|
||||
#define CRCPOLY1 BB2
|
||||
#define ACCESSADDRESS1 BB3
|
||||
#define RSSI BB12 // ? couldn't find it, not sure
|
||||
#define CTRL_TX BB13
|
||||
#define CRCINIT2 BB22
|
||||
#define CRCPOLY2 BB23
|
||||
#define ACCESSADDRESS2 BB24
|
||||
#define TMR LL25
|
||||
#define TXBUF LL30
|
||||
#define RXBUF LL31
|
||||
#define CTRL_MOD_RFSTOP 0xfffff8ff
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffcffff) | 0x20000)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffcffff) | 0x10000)
|
||||
#define DEVSETMODE_TUNE 0x0558
|
||||
#define DEVSETMODE_TX 0x0258
|
||||
#define DEVSETMODE_RX 0x0158
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xfffffcff) | 0x100)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xfffffcff)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX 0x1000000
|
||||
#elif defined(CH571_CH573)
|
||||
#define TXBUF DMA4
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12 // ? couldn't find it, not sure
|
||||
#define TMR LL24
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x180000
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_TUNE 0x5d
|
||||
#define DEVSETMODE_TX 0x5a
|
||||
#define DEVSETMODE_RX 0x59
|
||||
#define CTRL_CFG_PHY_1M (BB->CTRL_CFG | 0x10000000)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX (BB->CTRL_CFG & 0xefffffff)
|
||||
#elif defined(CH582_CH583)
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x880000
|
||||
#define CTRL_TX_TXPOWER 0x80010e78
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffe7f) | 0x100)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffe7f) | 0x80)
|
||||
#define DEVSETMODE_TUNE 0x00dd
|
||||
#define DEVSETMODE_TX 0x00da
|
||||
#define DEVSETMODE_RX 0x00d9
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xffff0fff) | 0x1000)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xffff0fff)
|
||||
#define CTRL_CFG_PHY_CODED ((BB->CTRL_CFG & 0xffff0fff) | 0x2000)
|
||||
#define LL_STATUS_TX 0x2000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#elif (defined(CH584_CH585) || defined(CH591_CH592))
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL30
|
||||
#define RXBUF LL31
|
||||
#define CTRL_MOD_RFSTOP 0xfffff8ff
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffcff) | 0x280)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffcff) | 0x100)
|
||||
#define DEVSETMODE_TUNE 0x0558
|
||||
#define DEVSETMODE_TX 0x0258
|
||||
#define DEVSETMODE_RX 0x0158
|
||||
#define CTRL_CFG_PHY_1M (BB->CTRL_CFG & 0xffffff7f)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG | 0x80)
|
||||
#define LL_STATUS_TX 0x20000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#elif defined(CH32V20x)
|
||||
#define CH32V208
|
||||
#define ACCESSADDRESS1 BB2
|
||||
#define CTRL_TX BB11
|
||||
#define RSSI BB12
|
||||
#define TMR LL25
|
||||
#define TXBUF LL28
|
||||
#define RXBUF LL29
|
||||
#define RFEND_TXCTUNE_INIT 0x100000
|
||||
#define CTRL_TX_TXPOWER 0x80010ec8
|
||||
#define CTRL_MOD_RFSTOP 0xfffffff8
|
||||
#define DEVSETMODE_ON ((BB->CTRL_CFG & 0xfffffe7f) | 0x100)
|
||||
#define DEVSETMODE_OFF ((BB->CTRL_CFG & 0xfffffe7f) | 0x80)
|
||||
#define DEVSETMODE_TUNE 0x5d
|
||||
#define DEVSETMODE_TX 0x5a
|
||||
#define DEVSETMODE_RX 0x59
|
||||
#define CTRL_CFG_PHY_1M ((BB->CTRL_CFG & 0xffff0fff) | 0x1000)
|
||||
#define CTRL_CFG_PHY_2M (BB->CTRL_CFG & 0xffff0fff)
|
||||
#define CTRL_CFG_PHY_CODED ((BB->CTRL_CFG & 0xffff0fff) | 0x2000)
|
||||
#define LL_STATUS_TX 0x2000
|
||||
#define CTRL_CFG_START_TX 0x800000
|
||||
#else
|
||||
#error "MCU_TARGET selected in Makefile is not supported"
|
||||
#endif
|
||||
|
||||
#ifdef CH32V208
|
||||
#define BB_BASE (0x40024100) // Baseband, digital part of the PHY
|
||||
#define LL_BASE (0x40024200) // Link Layer, MAC
|
||||
#define RF_BASE (0x40025000) // Radio frontend, analog part of the PHY
|
||||
#else
|
||||
#define DMA_BASE (0x4000c000)
|
||||
#define BB_BASE (0x4000c100)
|
||||
#define LL_BASE (0x4000c200)
|
||||
#define RF_BASE (0x4000d000)
|
||||
#endif
|
||||
|
||||
#define DMA ((DMA_Type *) DMA_BASE)
|
||||
#define BB ((BB_Type *) BB_BASE)
|
||||
#define LL ((LL_Type *) LL_BASE)
|
||||
#define RF ((RF_Type *) RF_BASE)
|
||||
|
||||
#ifdef CH571_CH573
|
||||
typedef struct {
|
||||
volatile uint32_t DMA0;
|
||||
volatile uint32_t DMA1;
|
||||
volatile uint32_t DMA2;
|
||||
volatile uint32_t DMA3;
|
||||
volatile uint32_t DMA4;
|
||||
volatile uint32_t DMA5;
|
||||
volatile uint32_t DMA6;
|
||||
volatile uint32_t DMA7;
|
||||
} DMA_Type;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// bits 0..5 = Channel
|
||||
// bit 6 = disable whitening.
|
||||
// bit 8 = 1 during normal TX/operation, but clearing does not affect TX. Note: 0 at reset, set in software.
|
||||
// bit 9 = settable, but unknown effect.
|
||||
// bit 10 = 1 during normal TX/operation, but clearing does not affect TX. Note: 1 at reset, not touched in software.
|
||||
// bit 16 = cleared by firmware upon TX, but does not seem to have an effect on the TX.
|
||||
// bit 17 = settable, but unknown effect
|
||||
// bit 20 = settable, but unknown effect.
|
||||
// bit 24 = set at end of tx routine
|
||||
// bit 29-31 = settable, but unknown effect.
|
||||
volatile uint32_t CTRL_CFG;
|
||||
|
||||
volatile uint32_t CRCINIT1;
|
||||
volatile uint32_t BB2; // ch570/2: CRCPOLY1, [ch582/3 ch591/2]: ACCESSADDRESS1
|
||||
volatile uint32_t BB3; // ch570/2 ACCESSADDRESS1
|
||||
volatile uint32_t BB4;
|
||||
volatile uint32_t BB5;
|
||||
volatile uint32_t BB6;
|
||||
volatile uint32_t BB7;
|
||||
volatile uint32_t BB8;
|
||||
volatile uint32_t BB9;
|
||||
volatile uint32_t BB10;
|
||||
volatile uint32_t BB11; // ch582/3, ch584/5, ch591/2: CTRL_TX
|
||||
volatile uint32_t BB12;
|
||||
|
||||
// default, pre TX is a4000009
|
||||
// bit 0: Set normally, but cleared in software when TXing (maybe a ready bit?)
|
||||
// bit 1: Unset normally, but cleared anyway by software when TXing (maybe a fault bit?)
|
||||
// bit 2: Disables TX.
|
||||
// bit 4: Normally 0, but, if set to 1, seems to increase preamble length.
|
||||
// bit 8: Normally 0, but, if set, no clear effect.
|
||||
// bit 9: Normally 0, but, if set, no clear effect.
|
||||
// bits 24-30: TX Power. Normally 0xA4
|
||||
// Oddly, bit 31 seems to maybe be always set.
|
||||
volatile uint32_t BB13; // ch570/2: CTRL_TX
|
||||
volatile uint32_t BB14;
|
||||
volatile uint32_t BB15;
|
||||
volatile uint32_t BB16;
|
||||
volatile uint32_t BB17;
|
||||
volatile uint32_t BB18;
|
||||
volatile uint32_t BB19;
|
||||
volatile uint32_t BB20;
|
||||
volatile uint32_t BB21;
|
||||
volatile uint32_t BB22; // ch570/2: CRCINIT2
|
||||
volatile uint32_t BB23; // ch570/2: CRCPOLY2
|
||||
volatile uint32_t BB24; // ch570/2: ACCESSADDRESS2
|
||||
} BB_Type;
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t LL0;
|
||||
volatile uint32_t LL1;
|
||||
volatile uint32_t STATUS;
|
||||
volatile uint32_t INT_EN;
|
||||
volatile uint32_t LL4;
|
||||
volatile uint32_t LL5;
|
||||
volatile uint32_t LL6;
|
||||
volatile uint32_t LL7;
|
||||
volatile uint32_t LL8;
|
||||
volatile uint32_t LL9;
|
||||
volatile uint32_t LL10;
|
||||
volatile uint32_t LL11;
|
||||
volatile uint32_t LL12;
|
||||
volatile uint32_t LL13;
|
||||
volatile uint32_t LL14;
|
||||
volatile uint32_t LL15;
|
||||
volatile uint32_t LL16;
|
||||
volatile uint32_t LL17;
|
||||
volatile uint32_t LL18;
|
||||
volatile uint32_t LL19;
|
||||
|
||||
// Controls a lot of higher-level functions.
|
||||
// For Tuning: 0x30558
|
||||
// For Idle: 0x30000
|
||||
// For Sending:0x30258
|
||||
// Bit 3: Somehow, enables BB
|
||||
// Bit 4: Normally 1, controls length/send times of BB, if unset, BB will double-send part of signals.
|
||||
// Bit 6: Normally 1, Unknown effect.
|
||||
// Bit 9: If 0, no output.
|
||||
// Bit 10: Somehow required for TX?
|
||||
// Bit 16-17: Normally 1, unknown effect. Seems to suppress odd carrier burst after message.
|
||||
volatile uint32_t CTRL_MOD;
|
||||
volatile uint32_t LL21;
|
||||
volatile uint32_t LL22;
|
||||
volatile uint32_t LL23;
|
||||
volatile uint32_t LL24; // ch571/3: TMR
|
||||
volatile uint32_t LL25; // ch570/2, ch582/3, ch591/2: TMR
|
||||
volatile uint32_t LL26;
|
||||
volatile uint32_t LL27;
|
||||
volatile uint32_t LL28; // ch582/3: TXBUF
|
||||
volatile uint32_t LL29; // ch582/3: RXBUF
|
||||
volatile uint32_t LL30; // ch570/2, ch591/2: TXBUF
|
||||
volatile uint32_t LL31; // ch570/2, ch591/2: RXBUF
|
||||
} LL_Type;
|
||||
|
||||
typedef struct {
|
||||
volatile uint32_t RF0;
|
||||
volatile uint32_t RF1;
|
||||
volatile uint32_t RF2;
|
||||
volatile uint32_t RF3;
|
||||
volatile uint32_t RF4;
|
||||
volatile uint32_t RF5;
|
||||
volatile uint32_t RF6;
|
||||
volatile uint32_t RF7;
|
||||
volatile uint32_t RF8;
|
||||
volatile uint32_t RF9;
|
||||
volatile uint32_t RF10;
|
||||
volatile uint32_t RF11;
|
||||
volatile uint32_t RF12;
|
||||
volatile uint32_t RF13;
|
||||
volatile uint32_t TXTUNE_CTRL;
|
||||
volatile uint32_t RF15;
|
||||
volatile uint32_t RF16;
|
||||
volatile uint32_t RF17;
|
||||
volatile uint32_t RF18;
|
||||
volatile uint32_t RF19;
|
||||
volatile uint32_t RF20;
|
||||
volatile uint32_t RF21;
|
||||
volatile uint32_t RF22;
|
||||
volatile uint32_t RF23;
|
||||
volatile uint32_t RF24;
|
||||
volatile uint32_t RF25;
|
||||
volatile uint32_t RF26;
|
||||
volatile uint32_t RF27;
|
||||
volatile uint32_t RF28;
|
||||
volatile uint32_t RF29;
|
||||
volatile uint32_t RF30;
|
||||
volatile uint32_t RF31;
|
||||
volatile uint32_t RF32;
|
||||
volatile uint32_t RF33;
|
||||
volatile uint32_t RF34;
|
||||
volatile uint32_t RF35;
|
||||
volatile uint32_t TXCTUNE_CO_CTRL;
|
||||
volatile uint32_t TXCTUNE_GA_CTRL;
|
||||
volatile uint32_t RF38;
|
||||
volatile uint32_t RXTUNE;
|
||||
volatile uint32_t TXCTUNE_CO[10];
|
||||
volatile uint32_t TXCTUNE_GA[3];
|
||||
} RF_Type;
|
||||
|
||||
uint8_t channel_map[] = {1,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,0,11,39};
|
||||
#define CO_MID (uint8_t)(RF->TXTUNE_CTRL & ~0xffffffc0)
|
||||
#define GA_MID (uint8_t)((RF->TXTUNE_CTRL & ~0x80ffffff) >> 24)
|
||||
|
||||
#define PHY_1M 1
|
||||
#define PHY_2M 2
|
||||
#define PHY_S2 4
|
||||
#define PHY_S8 8
|
||||
|
||||
void DevSetMode(uint16_t mode);
|
||||
__attribute__((aligned(4))) uint32_t LLE_BUF[0x110];
|
||||
#ifdef CH571_CH573
|
||||
__attribute__((aligned(4))) uint32_t LLE_BUF2[0x110];
|
||||
#endif
|
||||
volatile uint32_t tuneFilter;
|
||||
volatile uint32_t tuneFilter2M;
|
||||
volatile uint32_t rx_ready;
|
||||
|
||||
|
||||
|
||||
#ifdef CH571_CH573
|
||||
__attribute__((interrupt))
|
||||
void BB_IRQHandler() {
|
||||
// printf("BB\n");
|
||||
if(BB->BB14 & (1<<6)) {
|
||||
BB->BB14 &= 0xffffff9f;
|
||||
}
|
||||
if(BB->BB14 & (1<<1)) {
|
||||
BB->BB14 = 0xfffffffd;
|
||||
BB->BB20 = 0x45;
|
||||
}
|
||||
if(BB->BB14 & (1<<4)) {
|
||||
BB->BB14 = 0xffffffef;
|
||||
BB->BB20 = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((interrupt))
|
||||
void LLE_IRQHandler() {
|
||||
// printf("LL\n");
|
||||
#ifdef CH571_CH573
|
||||
if(LL->STATUS & (1<<9)) {
|
||||
LL->TMR = 400;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 2;
|
||||
BB->CTRL_CFG |= 0x10000000;
|
||||
}
|
||||
LL->STATUS = 0;
|
||||
#elif defined(CH582_CH583)
|
||||
if((LL->STATUS & (1<<14)) && (LL->INT_EN & (1<<14))) {
|
||||
LL->LL26 = 0xffffffff;
|
||||
LL->STATUS = 0x4000;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LL->STATUS &= LL->INT_EN;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 1;
|
||||
}
|
||||
DevSetMode(0);
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
|
||||
#ifdef ISLER_CALLBACK
|
||||
ISLER_CALLBACK();
|
||||
#else
|
||||
rx_ready = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RFEND_Reset() {
|
||||
#ifdef CH571_CH573
|
||||
RF->RF3 |= 0x1000;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xffffefff;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x1000;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 1;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xfffffffe;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 1;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x100;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 &= 0xfffffeff;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 |= 0x100;
|
||||
ADD_N_NOPS(20);
|
||||
#elif defined(CH32V208)
|
||||
RF->RF3 = 0x1101;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 = 0;
|
||||
ADD_N_NOPS(20);
|
||||
RF->RF3 = 0x1101;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DevInit(uint8_t TxPower) {
|
||||
#ifdef CH571_CH573
|
||||
DMA->DMA4 = (uint32_t)LLE_BUF;
|
||||
DMA->DMA5 = (uint32_t)LLE_BUF;
|
||||
DMA->DMA6 = (uint32_t)LLE_BUF2;
|
||||
DMA->DMA7 = (uint32_t)LLE_BUF2;
|
||||
DMA->DMA2 |= 0x2000;
|
||||
DMA->DMA3 |= 0x2000;
|
||||
DMA->DMA2 |= 0x1000;
|
||||
DMA->DMA3 |= 0x1000;
|
||||
DMA->DMA0 |= 2;
|
||||
DMA->DMA0 |= 0x20;
|
||||
|
||||
LL->LL5 = 0x50;
|
||||
LL->LL7 = 10;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x50;
|
||||
LL->LL19 = 10;
|
||||
#elif defined(CH570_CH572) || defined(CH582_CH583) || defined(CH584_CH585) || defined(CH591_CH592)
|
||||
LL->LL5 = 0x8c;
|
||||
LL->LL7 = 0x76;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x8c;
|
||||
LL->LL19 = 0x76;
|
||||
#elif defined(CH32V208)
|
||||
LL->LL5 = 0x8c;
|
||||
LL->LL7 = 0x6c;
|
||||
LL->LL9 = 0x8c;
|
||||
LL->LL13 = 0x8c;
|
||||
LL->LL17 = 0x8c;
|
||||
LL->LL19 = 0x6c;
|
||||
#endif
|
||||
|
||||
#ifdef CH570_CH572
|
||||
LL->LL11 = 0x6c;
|
||||
LL->LL15 = 0x6c;
|
||||
LL->LL1 = 0x78;
|
||||
LL->LL21 = 0;
|
||||
LL->INT_EN = 0x16000f;
|
||||
#elif defined(CH571_CH573)
|
||||
LL->LL11 = 0x3c;
|
||||
LL->LL15 = 0x3c;
|
||||
LL->LL22 = 0xf6;
|
||||
LL->INT_EN = 0xc303;
|
||||
NVIC->FIBADDRR = 0x20000000;
|
||||
NVIC->VTFADDR[2] = (uint32_t)LLE_IRQHandler -NVIC->FIBADDRR;
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
LL->LL11 = 0x3c;
|
||||
LL->LL15 = 0x3c;
|
||||
LL->INT_EN = 0xf00f;
|
||||
#elif defined(CH584_CH585)
|
||||
LL->LL11 = 0x6e;
|
||||
LL->LL15 = 0x6e;
|
||||
LL->LL1 &= 0xffffffe1;
|
||||
LL->LL21 = 0;
|
||||
LL->INT_EN = 0x1f000f;
|
||||
#elif defined(CH591_CH592)
|
||||
LL->LL6 = 0x78;
|
||||
LL->LL8 = 0xffffffff;
|
||||
LL->LL11 = 0x6e;
|
||||
LL->LL21 = 0x14;
|
||||
LL->INT_EN = 0x1f000f;
|
||||
#endif
|
||||
|
||||
LL->RXBUF = (uint32_t)LLE_BUF;
|
||||
LL->STATUS = 0xffffffff;
|
||||
RF->RF10 = 0x480;
|
||||
|
||||
#ifdef CH570_CH572
|
||||
RF->RF12 &= 0xfff9ffff;
|
||||
RF->RF12 |= 0x70000000;
|
||||
RF->RF15 = (RF->RF15 & 0xf8ffffff) | 0x2000000;
|
||||
RF->RF15 = (RF->RF15 & 0x1fffffff) | 0x40000000;
|
||||
RF->RF18 &= 0xfff8ffff;
|
||||
RF->RF20 = (RF->RF20 & 0xfffff8ff) | 0x300;
|
||||
RF->RF23 |= 0x70000;
|
||||
RF->RF23 |= 0x700000;
|
||||
|
||||
BB->BB14 = 0x2020c;
|
||||
BB->BB15 = 0x50;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x1ffffff) | (TxPower | 0x40) << 0x19;
|
||||
BB->CTRL_CFG &= 0xfffffcff;
|
||||
#elif defined(CH571_CH573) || defined(CH582_CH583) || defined(CH32V208)
|
||||
RFEND_Reset();
|
||||
RF->RF18 = (RF->RF18 & 0x8fffffff) | 0x20000000;
|
||||
RF->RF18 = (RF->RF18 & 0xf8ffffff) | 0x4000000;
|
||||
RF->RF18 = (RF->RF18 & 0xfffffff0) | 9;
|
||||
RF->RF18 &= 0xfff8ffff;
|
||||
RF->RF18 |= 0x80000000;
|
||||
RF->RF19 = (RF->RF19 & 0xfffffff8) | 3;
|
||||
RF->RF19 = (RF->RF19 & 0xffffff8f) | 0x30;
|
||||
RF->RF19 = (RF->RF19 & 0xfffff8ff) | 0x300;
|
||||
RF->RF19 &= 0xfeffffff;
|
||||
RF->RF19 |= 0x2000000;
|
||||
RF->RF20 = (RF->RF20 & 0xffff0fff) | 0x4000;
|
||||
RF->RF21 = (RF->RF21 & 0xfffffff0) | 0xc;
|
||||
RF->RF21 |= 0x80;
|
||||
RF->RF21 &= 0xffffefff;
|
||||
RF->RF15 = (RF->RF15 & 0xffff0fff) | 0x8000;
|
||||
RF->RF15 = (RF->RF15 & 0xf8ffffff) | 0x2000000;
|
||||
RF->RF15 = (RF->RF15 & 0x1fffffff) | 0x40000000;
|
||||
RF->RF11 |= 0x700000;
|
||||
RF->RF11 &= 0xf8ffffff;
|
||||
RF->RF11 = (RF->RF11 & 0xffffcfff) | 0x2000;
|
||||
RF->RF11 = (RF->RF11 & 0xfffcffff) | 0x20000;
|
||||
RF->RF12 &= 0xfffffff0;
|
||||
RF->RF12 &= 0xffffff0f;
|
||||
RF->RF12 &= 0xfffff8ff;
|
||||
RF->RF12 |= 0x700000;
|
||||
RF->RF12 = (RF->RF12 & 0x8fffffff) | 0x50000000;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xff07ffff) | RFEND_TXCTUNE_INIT;
|
||||
RF->TXTUNE_CTRL |= 0x80000000;
|
||||
|
||||
#ifdef CH571_CH573
|
||||
BB->CTRL_CFG = (TxPower << 8) | BB->CTRL_CFG | 0x1008000;
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffffc0ff) | (TxPower & 0x3f) << 8;
|
||||
SYS_SAFE_ACCESS(
|
||||
R16_AUX_POWER_ADJ = (TxPower < 0x15) ? (R16_AUX_POWER_ADJ & 0xffef):
|
||||
(R16_AUX_POWER_ADJ | 0x10);
|
||||
);
|
||||
BB->CTRL_TX = 0x10e78;
|
||||
BB->BB6 |= 0x8000;
|
||||
BB->BB6 = (BB->BB6 & 0xffff807f) | 0x3500;
|
||||
BB->BB13 = 0x152;
|
||||
|
||||
// NVIC->VTFADDR[3] = (uint32_t)BB_IRQHandler +0x14000000; // why 14000000?
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG |= 0x800000;
|
||||
BB->CTRL_CFG |= 0x10000000;
|
||||
BB->BB13 = 0x1d0;
|
||||
BB->CTRL_TX = TxPower << 0x19 | CTRL_TX_TXPOWER;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x81ffffff) | (TxPower & 0x3f) << 0x19;
|
||||
BB->BB8 = 0x90083;
|
||||
|
||||
// NVIC->VTFADDR[3] = (uint32_t)BB_IRQHandler +0x20000000; // why 20000000?
|
||||
#endif
|
||||
#elif defined(CH584_CH585) || defined(CH591_CH592)
|
||||
RF->RF12 = (RF->RF12 & 0x8fffffff) | 0x10077700;
|
||||
RF->RF15 = (RF->RF15 & 0x18ff0fff) | 0x42005000;
|
||||
RF->RF19 &= 0xfffcff88;
|
||||
RF->RF21 = (RF->RF21 & 0xfffffff0) | 9;
|
||||
RF->RF23 &= 0xff88ffff;
|
||||
|
||||
BB->CTRL_CFG |= 0x800000;
|
||||
BB->BB14 = 0x3ff; // ch584/5
|
||||
BB->BB13 = 0x50;
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0x81ffffff) | (TxPower & 0x3f) << 0x19;
|
||||
uint32_t uVar3 = 0x1000000;
|
||||
uint32_t uVar4 = RF->RF23 & 0xf8ffffff;
|
||||
if(TxPower < 29) { // ch585: 27
|
||||
/* uVar3 and uVar4 are initialized properly already */
|
||||
}
|
||||
else if(TxPower < 35) {
|
||||
uVar3 = 0x3000000;
|
||||
}
|
||||
else if(TxPower < 59) {
|
||||
uVar3 = 0x5000000;
|
||||
}
|
||||
else {
|
||||
uVar4 = RF->RF23;
|
||||
uVar3 = 0x7000000;
|
||||
}
|
||||
RF->RF23 = uVar4 | uVar3;
|
||||
BB->BB15 = 0x2020c; // ch584/5
|
||||
BB->BB4 = (BB->BB4 & 0xffffffc0) | 0xe;
|
||||
#endif
|
||||
|
||||
NVIC->VTFIDR[3] = 0x14;
|
||||
}
|
||||
|
||||
void DevSetMode(uint16_t mode) {
|
||||
#if !defined(CH571_CH573)
|
||||
if(mode) {
|
||||
BB->CTRL_CFG = DEVSETMODE_ON;
|
||||
RF->RF2 |= 0x330000;
|
||||
}
|
||||
else {
|
||||
BB->CTRL_CFG = DEVSETMODE_OFF;
|
||||
RF->RF2 &= 0xffcdffff;
|
||||
}
|
||||
#ifdef CH582_CH583
|
||||
mode = (mode == 0) ? 0x80 : mode;
|
||||
#elif !defined(CH32V208)
|
||||
mode |= 0x30000;
|
||||
#endif
|
||||
#endif // ! CH571_CH573
|
||||
LL->CTRL_MOD = mode;
|
||||
}
|
||||
|
||||
uint32_t RFEND_TXCTune(uint8_t channel) {
|
||||
// 0xbf = 2401 MHz
|
||||
RF->RF1 &= 0xfffffffe;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xfffe00ff) | (0xbf00 + (channel_map[channel] << 8));
|
||||
RF->RF1 |= 1;
|
||||
|
||||
LL->TMR = 8000;
|
||||
while(!(RF->TXCTUNE_CO_CTRL & (1 << 25)) || !(RF->TXCTUNE_CO_CTRL & (1 << 26))) {
|
||||
if(LL->TMR == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t nCO = (uint8_t)RF->TXCTUNE_CO_CTRL & 0x3f;
|
||||
uint8_t nGA = (uint8_t)(RF->TXCTUNE_GA_CTRL >> 10) & 0x7f;
|
||||
|
||||
// printf("nCO,nGA ch:%u idx:%u %u,%u\n", channel, channel_map[channel], nCO,nGA);
|
||||
|
||||
return (nGA << 24) | nCO;
|
||||
}
|
||||
|
||||
void RFEND_TXTune() {
|
||||
RF->RF1 &= 0xfffffeff;
|
||||
RF->RF10 &= 0xffffefff;
|
||||
RF->RF11 &= 0xffffffef;
|
||||
RF->RF2 |= 0x20000;
|
||||
RF->RF1 |= 0x10;
|
||||
|
||||
// 2401 MHz
|
||||
uint32_t tune2401 = RFEND_TXCTune(37);
|
||||
uint8_t nCO2401 = (uint8_t)(tune2401 & 0x3f);
|
||||
uint8_t nGA2401 = (uint8_t)(tune2401 >> 24) & 0x7f;
|
||||
|
||||
// 2480 MHz
|
||||
uint32_t tune2480 = RFEND_TXCTune(39);
|
||||
uint8_t nCO2480 = (uint8_t)(tune2480 & 0x3f);
|
||||
uint8_t nGA2480 = (uint8_t)(tune2480 >> 24) & 0x7f;
|
||||
|
||||
// 2440 MHz
|
||||
uint32_t tune2440 = RFEND_TXCTune(18);
|
||||
uint8_t nCO2440 = (uint8_t)(tune2440 & 0x3f);
|
||||
uint8_t nGA2440 = (uint8_t)(tune2440 >> 24) & 0x7f;
|
||||
|
||||
uint32_t dCO0140 = nCO2401 - nCO2440;
|
||||
uint32_t dCO4080 = nCO2440 - nCO2480;
|
||||
uint8_t tune = 0;
|
||||
uint8_t int_points = sizeof(RF->TXCTUNE_CO) /2;
|
||||
uint8_t txctune_co[sizeof(RF->TXCTUNE_CO)] = {0};
|
||||
for(int f = 0; f < int_points; f++) {
|
||||
tune = (dCO0140 * (int_points -f)) / int_points;
|
||||
txctune_co[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int f = int_points; f < sizeof(RF->TXCTUNE_CO); f++) {
|
||||
tune = (dCO4080 * (f -int_points)) / int_points;
|
||||
txctune_co[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int i = 0; i < sizeof(txctune_co) /4; i++) {
|
||||
RF->TXCTUNE_CO[i] = ((uint32_t*)txctune_co)[i];
|
||||
}
|
||||
|
||||
// This GA interpolating is not exactly what is done in EVT
|
||||
// Actually the reception on a BLE monitor is better when this is left out completely
|
||||
// This will need some proper experimentation by people with 2.4GHz SDRs
|
||||
uint32_t dGA0140 = nGA2401 - nGA2440;
|
||||
uint32_t dGA4080 = nGA2440 - nGA2480;
|
||||
int_points = sizeof(RF->TXCTUNE_GA) /2;
|
||||
uint8_t txctune_ga[sizeof(RF->TXCTUNE_GA)] = {0};
|
||||
for(int f = 1; f < int_points; f++) {
|
||||
tune = (dGA0140 * (int_points -f)) / int_points;
|
||||
txctune_ga[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int f = int_points; f < sizeof(RF->TXCTUNE_GA) -1; f++) {
|
||||
tune = (dGA4080 * (f -int_points)) / int_points;
|
||||
txctune_ga[f] = tune | (tune << 4);
|
||||
}
|
||||
for(int i = 0; i < (sizeof(txctune_ga) /4); i++) {
|
||||
RF->TXCTUNE_GA[i] = ((uint32_t*)txctune_ga)[i];
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
printf("2401 2440 2480 CO: %u %u %u, GA: %u %u %u\n", nCO2401, nCO2440, nCO2480, nGA2401, nGA2440, nGA2480);
|
||||
for(int i = 0; i < 10; i++ ) {
|
||||
printf( "%d: %08lx\n", i, RF->TXCTUNE_CO[i] );
|
||||
}
|
||||
for(int i = 0; i < 3; i++ ) {
|
||||
printf( "%d: %08lx\n", i, RF->TXCTUNE_GA[i] );
|
||||
}
|
||||
#endif
|
||||
|
||||
RF->RF1 &= 0xffffffef;
|
||||
RF->RF1 &= 0xfffffffe;
|
||||
RF->RF10 |= 0x1000;
|
||||
RF->RF11 |= 0x10;
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0xffffffc0) | (tune2440 & 0x3f);
|
||||
RF->TXTUNE_CTRL = (RF->TXTUNE_CTRL & 0x80ffffff) | (tune2440 & 0x7f000000);
|
||||
|
||||
// FTune
|
||||
RF->RF1 |= 0x100;
|
||||
}
|
||||
|
||||
void RFEND_RXTune() {
|
||||
RF->RF20 &= 0xfffeffff;
|
||||
RF->RF2 |= 0x200000;
|
||||
RF->RF3 = (RF->RF3 & 0xffffffef) | 0x10;
|
||||
RF->RF1 |= 0x1000;
|
||||
|
||||
LL->TMR = 100;
|
||||
while(LL->TMR && ((RF->RXTUNE >> 8) & 1));
|
||||
|
||||
tuneFilter = RF->RXTUNE & 0x1f;
|
||||
RF->RF20 |= 0x10000;
|
||||
RF->RF20 = (RF->RF20 & 0xffffffe0) | tuneFilter;
|
||||
RF->RF2 &= 0xffdfffff;
|
||||
tuneFilter2M = (tuneFilter +2 < 0x1f) ? (tuneFilter +2) : 0x1f;
|
||||
|
||||
// RXADC
|
||||
RF->RF22 &= 0xfffeffff;
|
||||
RF->RF2 |= 0x10000;
|
||||
RF->RF3 = (RF->RF3 & 0xfffffeff) | 0x100;
|
||||
RF->RF1 = (RF->RF1 & 0xfffeffff) | 0x100000;
|
||||
}
|
||||
|
||||
void RegInit() {
|
||||
DevSetMode(DEVSETMODE_TUNE);
|
||||
RFEND_TXTune();
|
||||
RFEND_RXTune();
|
||||
DevSetMode(0);
|
||||
}
|
||||
|
||||
void RFCoreInit(uint8_t TxPower) {
|
||||
#if defined(CH571_CH573) || defined(CH584_CH585) // maybe all?
|
||||
NVIC->IENR[0] = 0x1000;
|
||||
NVIC->IRER[0] = 0x1000;
|
||||
#endif
|
||||
DevInit(TxPower);
|
||||
RegInit();
|
||||
NVIC->IPRIOR[0x15] |= 0x80;
|
||||
NVIC_EnableIRQ(LLE_IRQn);
|
||||
}
|
||||
|
||||
void DevSetChannel(uint8_t channel) {
|
||||
#ifdef CH571_CH573
|
||||
BB->BB6 = (BB->BB6 & 0xf8ffffff) | 0x4000000;
|
||||
BB->BB6 = (BB->BB6 & 0xffffff83) | 0x1c;
|
||||
#endif
|
||||
RF->RF11 &= 0xfffffffd;
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffffff80) | (channel & 0x7f);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
int8_t ReadRSSI() {
|
||||
return (int8_t)(BB->RSSI >> 0xf);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void Frame_TX(uint32_t access_address, uint8_t adv[], size_t len, uint8_t channel, uint8_t phy_mode) {
|
||||
BB->CTRL_TX = (BB->CTRL_TX & 0xfffffffc) | 1;
|
||||
|
||||
DevSetChannel(channel);
|
||||
|
||||
// Uncomment to disable whitening to debug RF.
|
||||
//BB->CTRL_CFG |= (1<<6);
|
||||
DevSetMode(DEVSETMODE_TX);
|
||||
|
||||
BB->ACCESSADDRESS1 = access_address; // access address
|
||||
BB->CRCINIT1 = 0x555555; // crc init
|
||||
#ifdef CH570_CH572
|
||||
BB->ACCESSADDRESS2 = access_address;
|
||||
BB->CRCINIT2 = 0x555555;
|
||||
BB->CRCPOLY1 = (BB->CRCPOLY1 & 0xff000000) | 0x80032d; // crc poly
|
||||
BB->CRCPOLY2 = (BB->CRCPOLY2 & 0xff000000) | 0x80032d;
|
||||
#endif
|
||||
|
||||
#if defined(CH571_CH573)
|
||||
DMA->TXBUF = (uint32_t)adv;
|
||||
#else
|
||||
LL->TXBUF = (uint32_t)adv;
|
||||
#endif
|
||||
|
||||
// Wait for tuning bit to clear.
|
||||
for( int timeout = 3000; !(RF->RF26 & 0x1000000) && timeout >= 0; timeout-- );
|
||||
|
||||
#if defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
(phy_mode == PHY_S2) ? CTRL_CFG_PHY_CODED:
|
||||
(phy_mode == PHY_S8) ? CTRL_CFG_PHY_CODED:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
if(phy_mode > PHY_2M) { // coded phy
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffff3fff) | ((phy_mode == PHY_S2) ? 0x4000 : 0);
|
||||
}
|
||||
#elif defined(CH571_CH573)
|
||||
BB->CTRL_CFG = CTRL_CFG_PHY_1M; // no 2M PHY on ch571/3
|
||||
#else
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
#endif
|
||||
|
||||
#if defined(CH570_CH572)
|
||||
BB->BB9 = (BB->BB9 & 0xf9ffffff) | ((phy_mode == PHY_2M) ? 0 : 0x2000000);
|
||||
#endif
|
||||
|
||||
#if defined(CH571_CH573)
|
||||
BB->BB11 = (BB->BB11 & 0xfffffffc); // |2 for RX
|
||||
#endif
|
||||
|
||||
// This clears bit 17 (If set, seems to have no impact.)
|
||||
LL->LL4 &= 0xfffdffff;
|
||||
|
||||
#if !defined(CH571_CH573)
|
||||
LL->STATUS = LL_STATUS_TX;
|
||||
#endif
|
||||
LL->TMR = (uint32_t)(len *512); // needs optimisation, per phy mode
|
||||
|
||||
BB->CTRL_CFG |= CTRL_CFG_START_TX;
|
||||
BB->CTRL_TX &= 0xfffffffc;
|
||||
|
||||
LL->LL0 = 2; // Not sure what this does, but on RX it's 1
|
||||
|
||||
while(LL->TMR); // wait for tx buffer to empty
|
||||
DevSetMode(0);
|
||||
if(LL->LL0 & 3) {
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void Frame_RX(uint32_t access_address, uint8_t channel, uint8_t phy_mode) {
|
||||
DevSetMode(0);
|
||||
if(LL->LL0 & 3) {
|
||||
LL->CTRL_MOD &= CTRL_MOD_RFSTOP;
|
||||
LL->LL0 |= 0x08;
|
||||
}
|
||||
LL->TMR = 0;
|
||||
|
||||
DevSetChannel(channel);
|
||||
DevSetMode(DEVSETMODE_RX);
|
||||
|
||||
#if defined(CH582_CH583) || defined(CH32V208)
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
(phy_mode == PHY_S2) ? CTRL_CFG_PHY_CODED:
|
||||
(phy_mode == PHY_S8) ? CTRL_CFG_PHY_CODED:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
if(phy_mode > PHY_2M) { // coded phy
|
||||
BB->CTRL_CFG = (BB->CTRL_CFG & 0xffff3fff) | ((phy_mode == PHY_S2) ? 0x4000 : 0);
|
||||
}
|
||||
#elif defined(CH571_CH573)
|
||||
BB->CTRL_CFG = CTRL_CFG_PHY_1M; // no 2M PHY on ch571/3
|
||||
#else
|
||||
BB->CTRL_CFG = (phy_mode == PHY_2M) ? CTRL_CFG_PHY_2M:
|
||||
CTRL_CFG_PHY_1M; // default 1M for now
|
||||
#endif
|
||||
|
||||
#ifdef CH570_CH572
|
||||
BB->BB9 = (BB->BB9 & 0xf9ffffff) | ((phy_mode == PHY_2M) ? 0 : 0x2000000);
|
||||
RF->RF20 = (RF->RF20 & 0xffffffe0) | ((phy_mode == PHY_2M) ? (tuneFilter2M & 0x1f) : (tuneFilter & 0x1f));
|
||||
BB->BB5 = (BB->BB5 & 0xffffffc0) | ((phy_mode == PHY_2M) ? 0xd : 0xb);
|
||||
BB->BB7 = (BB->BB7 & 0xff00fc00) | ((phy_mode == PHY_2M) ? 0x7f00a0 : 0x79009c);
|
||||
#elif defined(CH571_CH573)
|
||||
BB->BB11 = (BB->BB11 & 0xfffffffc) | 2; // no |2 for TX
|
||||
#elif defined(CH582_CH583) || defined(CH32V208)
|
||||
#if defined(CH582_CH583)
|
||||
BB->BB4 = (phy_mode < PHY_S2) ? 0x3722d0 : 0x3722df;
|
||||
#elif defined(CH32V208)
|
||||
BB->BB4 = (phy_mode < PHY_S2) ? 0x3222d0 : 0x34a4df;
|
||||
#endif
|
||||
BB->BB5 = (phy_mode < PHY_S2) ? 0x8101901 : 0x8301ff1;
|
||||
BB->BB6 = (phy_mode < PHY_S2) ? 0x31624 : 0x31619;
|
||||
BB->BB8 = (phy_mode < PHY_S2) ? 0x90083 : 0x90086;
|
||||
BB->BB9 = 0x1006310;
|
||||
BB->BB10 = (phy_mode < PHY_S2) ? 0x28be : 0x28de;
|
||||
#elif defined(CH584_CH585) || defined(CH591_CH592)
|
||||
BB->BB6 = (BB->BB6 & 0xfffffc00) | ((phy_mode == PHY_2M) ? 0x13a : 0x132);
|
||||
BB->BB4 = (BB->BB4 & 0x00ffffff) | ((phy_mode == PHY_2M) ? 0x78000000 : 0x7f000000);
|
||||
#endif
|
||||
|
||||
BB->ACCESSADDRESS1 = access_address; // access address
|
||||
BB->CRCINIT1 = 0x555555; // crc init
|
||||
#ifdef CH570_CH572
|
||||
BB->ACCESSADDRESS2 = access_address;
|
||||
BB->CRCINIT2 = 0x555555;
|
||||
BB->CRCPOLY1 = (BB->CRCPOLY1 & 0xff000000) | 0x80032d; // crc poly
|
||||
BB->CRCPOLY2 = (BB->CRCPOLY2 & 0xff000000) | 0x80032d;
|
||||
#endif
|
||||
|
||||
LL->LL0 = 1; // Not sure what this does, but on TX it's 2
|
||||
rx_ready = 0;
|
||||
}
|
||||
36
inc/extralibs/lib_crc.h
Normal file
36
inc/extralibs/lib_crc.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// should work for CH32v10x, CH32v20x, and CH32v30x
|
||||
// Although has only been tested on CH32v303
|
||||
|
||||
static void CRC_init(void) {
|
||||
// Enable CRC clock
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_CRC;
|
||||
}
|
||||
|
||||
// Calculate CRC for a single 32-bit value
|
||||
static u32 CRC_calculate32(u32 data) {
|
||||
// Reset CRC unit
|
||||
CRC->CTLR = CRC_CTLR_RESET;
|
||||
|
||||
// Write data to trigger CRC calculation
|
||||
CRC->DATAR = data;
|
||||
|
||||
// Wait for CRC calculation
|
||||
u32 timeout = 10000;
|
||||
while (CRC->DATAR == 0 && --timeout);
|
||||
|
||||
// read the CRC result
|
||||
return CRC->DATAR;
|
||||
}
|
||||
|
||||
// Calculate CRC for an array of 32-bit values
|
||||
static u32 CRC_calculateArray32(u32 *data, u32 length) {
|
||||
CRC->CTLR = CRC_CTLR_RESET;
|
||||
|
||||
// Process each 32-bit word
|
||||
for(u32 i = 0; i < length; i++) {
|
||||
CRC->DATAR = data[i];
|
||||
}
|
||||
|
||||
// Return final CRC
|
||||
return CRC->DATAR;
|
||||
}
|
||||
26
inc/extralibs/lib_pvd.h
Normal file
26
inc/extralibs/lib_pvd.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Tested with CH32V002, CH32V006, and CH32V303
|
||||
|
||||
#include "ch32fun.h"
|
||||
|
||||
static void PVD_init(u8 threshold) {
|
||||
if (threshold > PVD_MAX_THRESHOLD_LVL) threshold = PVD_MAX_THRESHOLD_LVL;
|
||||
|
||||
// Enable PWR clock
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_PWR;
|
||||
|
||||
// Enable PVD
|
||||
PWR->CTLR |= PWR_CTLR_PVDE;
|
||||
|
||||
// Clear the existing PLS bits and set new threshold
|
||||
PWR->CTLR = (PWR->CTLR & ~PWR_CTLR_PLS) | (threshold << 5);
|
||||
}
|
||||
|
||||
// Get threshold setting: the PLS[1:0] bits
|
||||
static int PVD_getThreshold() {
|
||||
return (PWR->CTLR & PWR_CTLR_PLS) >> 5;
|
||||
}
|
||||
|
||||
// return PVD flag: 1 if VDD below threshold
|
||||
static int PVD_getAlert() {
|
||||
return PWR->CSR & PWR_CSR_PVDO;
|
||||
}
|
||||
|
|
@ -1,30 +1,30 @@
|
|||
/******************************************************************************
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
#ifndef CH32V003_LIB_RAND
|
||||
#define CH32V003_LIB_RAND
|
||||
|
||||
|
|
@ -34,13 +34,14 @@
|
|||
// Strength 3: Genetate two 32bit values using the LFSR, then XOR them together
|
||||
// Example: #define RANDOM_STRENGTH 2
|
||||
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#endif
|
||||
|
||||
// @brief set the random LFSR values seed by default to a known-good value
|
||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||
|
||||
|
||||
/*** Library specific Functions - Do Not Use *********************************/
|
||||
/****************************************************************************/
|
||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
||||
|
|
@ -50,59 +51,63 @@ static uint32_t _rand_lfsr = 0x747AA32F;
|
|||
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
||||
uint8_t _rand_lfsr_update(void)
|
||||
{
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, 32 times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random 32-bit value
|
||||
uint32_t _rand_gen_32b(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, n times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random n-bit value
|
||||
uint32_t _rand_gen_nb(int bits)
|
||||
uint32_t _rand_gen_nb( int bits)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
/*** API Functions ***********************************************************/
|
||||
/*****************************************************************************/
|
||||
/// @brief seeds the Random LFSR to the value passed
|
||||
|
|
@ -110,39 +115,40 @@ uint32_t _rand_gen_nb(int bits)
|
|||
/// @return None
|
||||
void seed(const uint32_t seed_val)
|
||||
{
|
||||
_rand_lfsr = seed_val;
|
||||
_rand_lfsr = seed_val;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||
/// you have selected
|
||||
/// you have selected
|
||||
/// @param None
|
||||
/// @return 32bit Random value
|
||||
uint32_t rand(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
142
inc/extralibs/register_debug_utilities.h
Normal file
142
inc/extralibs/register_debug_utilities.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include <stdio.h>
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BITS(reg, 32, 16);
|
||||
void UTIL_PRINT_BITS(u32 val, u8 len, u8 divider_len) {
|
||||
const char* separator = "\n";
|
||||
|
||||
for (int i = (len)-1; i >= 0; i--) {
|
||||
printf("%d| ", i);
|
||||
if (i > 0) printf(i % divider_len ? "" : "%s", separator);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (int i = (len)-1; i >= 0; i--) {
|
||||
printf(i < 10 ? "%2d" : "%3d", ((val) >> i) & 1);
|
||||
if (i > 0) printf(i % divider_len ? " " : " %s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS VALUES
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BITS_VALUES(
|
||||
// reg,
|
||||
// "a", 0,
|
||||
// "b", 1,
|
||||
// "c", 2,
|
||||
// );
|
||||
|
||||
void UTIL_PRINT_BITS_VALUES(u32 reg, ...) {
|
||||
struct BitPair { const char* name; int pos; };
|
||||
va_list args;
|
||||
va_start(args, reg);
|
||||
|
||||
// Count how many pairs were passed (until NULL name)
|
||||
int pair_count = 0;
|
||||
va_list count_args;
|
||||
va_copy(count_args, args);
|
||||
|
||||
while (1) {
|
||||
const char* name = va_arg(count_args, const char*);
|
||||
if (name == NULL) break;
|
||||
int pos = va_arg(count_args, int);
|
||||
(void)pos;
|
||||
pair_count++;
|
||||
}
|
||||
va_end(count_args);
|
||||
|
||||
// Read all the pairs
|
||||
struct BitPair pairs[pair_count];
|
||||
for (int i = 0; i < pair_count; i++) {
|
||||
pairs[i].name = va_arg(args, const char*);
|
||||
pairs[i].pos = va_arg(args, int);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Print the pairs
|
||||
for (int i = 0; i < pair_count; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
printf("%s=%d", pairs[i].name, (unsigned int)((reg >> pairs[i].pos) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
//! ####################################
|
||||
//! PRINT BITS RANGE
|
||||
//! ####################################
|
||||
|
||||
// eg: UTIL_PRINT_BIT_RANGE(
|
||||
// reg,
|
||||
// "FIELD3", 5, 3,
|
||||
// "FIELD2", 2, 1,
|
||||
// "FIELD1", 0, 0,
|
||||
// NULL
|
||||
// );
|
||||
|
||||
// NOTE: NULL terminated REQUIRED
|
||||
void UTIL_PRINT_BIT_RANGE(u32 reg, ...) {
|
||||
// Define the struct
|
||||
typedef struct { const char* name; int end; int start; } BitField;
|
||||
|
||||
va_list args;
|
||||
va_start(args, reg);
|
||||
|
||||
// Count how many fields were passed (until NULL name)
|
||||
int field_count = 0;
|
||||
va_list count_args;
|
||||
va_copy(count_args, args);
|
||||
|
||||
while (1) {
|
||||
const char* name = va_arg(count_args, const char*);
|
||||
if (name == NULL) break;
|
||||
int start = va_arg(count_args, int);
|
||||
(void)start;
|
||||
int end = va_arg(count_args, int);
|
||||
(void)end;
|
||||
field_count++;
|
||||
}
|
||||
va_end(count_args);
|
||||
|
||||
// Read all the fields
|
||||
BitField fields[field_count];
|
||||
for (int i = 0; i < field_count; i++) {
|
||||
fields[i].name = va_arg(args, const char*);
|
||||
fields[i].end = va_arg(args, int); // get end first
|
||||
fields[i].start = va_arg(args, int); // then get start
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Print the fields
|
||||
for (int i = 0; i < field_count; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
int start = fields[i].start;
|
||||
int end = fields[i].end;
|
||||
|
||||
if (end == start) {
|
||||
// Single bit
|
||||
printf("%s = %d [%d]", fields[i].name, (reg >> start) & 1, start);
|
||||
} else {
|
||||
// Multiple bits
|
||||
int mask = ((1 << (end - start + 1)) - 1);
|
||||
printf("%s = 0x%02X [%d:%d]", fields[i].name, (reg >> start) & mask, end, start);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//! ####################################
|
||||
//! PRINT REGS
|
||||
//! ####################################
|
||||
|
||||
#define UTIL_PRINT_REG8(reg, label) printf("%s: 0x%02X\n", label, (unsigned int)(reg));
|
||||
#define UTIL_PRINT_REG16(reg, label) printf("%s: 0x%04X\n", label, (unsigned int)(reg));
|
||||
#define UTIL_PRINT_REG32(reg, label) printf("%s: 0x%08X\n", label, (unsigned int)(reg));
|
||||
|
||||
|
||||
127
inc/extralibs/rtc_helper.h
Normal file
127
inc/extralibs/rtc_helper.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// MIT License
|
||||
// Copyright (c) 2025 UniTheCat
|
||||
|
||||
#define RTC_TICKS_PER_SECOND 32768
|
||||
|
||||
#define SECONDS_PER_MINUTE 60
|
||||
#define SECONDS_PER_HOUR 3600
|
||||
#define SECONDS_PER_DAY 86400
|
||||
|
||||
#define IS_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
|
||||
|
||||
// Array of days in each month (non-leap year)
|
||||
const u8 DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
typedef struct {
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
} rtc_date_t;
|
||||
|
||||
typedef struct {
|
||||
u8 hr;
|
||||
u8 min;
|
||||
u8 sec;
|
||||
u16 ms;
|
||||
} rtc_time_t;
|
||||
|
||||
typedef struct {
|
||||
rtc_date_t date;
|
||||
rtc_time_t time;
|
||||
} rtc_datetime_t;
|
||||
|
||||
// calculate days of the current year. eg. 2020-02-05 is 36 day
|
||||
u32 RTC_days_of_year(u16 year, u8 month, u8 day) {
|
||||
u32 day_of_year = 0;
|
||||
|
||||
// Add days from January to month-1
|
||||
for (u8 m = 0; m < month - 1; m++) {
|
||||
day_of_year += DAYS_IN_MONTH[m];
|
||||
}
|
||||
|
||||
// Add extra day for February (full month) if it's a leap year
|
||||
if (month > 2 && IS_LEAP_YEAR(year)) {
|
||||
day_of_year += 1;
|
||||
}
|
||||
|
||||
// Add days in the current month
|
||||
day_of_year += day;
|
||||
|
||||
return day_of_year;
|
||||
}
|
||||
|
||||
u32 RTC_get_seconds(u16 year, u8 month, u8 day, u8 hr, u8 min, u8 sec) {
|
||||
//# Validate input
|
||||
if (month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hr > 23 || min > 59 || sec > 59 || year < 1970) { return 0; }
|
||||
|
||||
// calculate days of the current year, -1 for 0-based days
|
||||
u32 days = RTC_days_of_year(year, month, day) - 1;
|
||||
|
||||
// add the days count excluding the current year
|
||||
// (start from epoch time 1970-01-01 00:00:00)
|
||||
for (int y=1970; y < year; y++) {
|
||||
days += IS_LEAP_YEAR(y) ? 366 : 365;
|
||||
}
|
||||
|
||||
// calculate total seconds
|
||||
return days * SECONDS_PER_DAY +
|
||||
hr * SECONDS_PER_HOUR +
|
||||
min * SECONDS_PER_MINUTE + sec;
|
||||
}
|
||||
|
||||
rtc_time_t RTC_get_time(u32 total_seconds, u32 ms) {
|
||||
u32 minutes = total_seconds / 60;
|
||||
|
||||
return (rtc_time_t) {
|
||||
.sec = total_seconds % 60,
|
||||
.min = minutes % 60,
|
||||
.hr = (minutes / 60) % 24,
|
||||
.ms = ms
|
||||
};
|
||||
}
|
||||
|
||||
rtc_date_t RTC_get_date(u32 total_seconds, u16 year_base) {
|
||||
rtc_date_t output = {
|
||||
.year = year_base,
|
||||
.month = 1,
|
||||
.day = 1
|
||||
};
|
||||
|
||||
// Days since epoch
|
||||
u32 days_remaining = total_seconds / SECONDS_PER_DAY;
|
||||
|
||||
// Find the year
|
||||
while(1) {
|
||||
u32 days_in_year = IS_LEAP_YEAR(output.year) ? 366 : 365;
|
||||
if (days_remaining < days_in_year) break;
|
||||
days_remaining -= days_in_year;
|
||||
output.year++;
|
||||
}
|
||||
|
||||
// find the month
|
||||
for (u8 m = 0; m < 12; m++) {
|
||||
u8 days_in_month = DAYS_IN_MONTH[m];
|
||||
if (m == 1 && IS_LEAP_YEAR(output.year)) days_in_month = 29;
|
||||
if (days_remaining < days_in_month) break;
|
||||
|
||||
days_remaining -= days_in_month;
|
||||
output.month++;
|
||||
}
|
||||
|
||||
// add 1 because days_remaining is 0-based
|
||||
output.day = days_remaining + 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void RTC_print_date(rtc_date_t date, char *delimiter) {
|
||||
printf("%04d", date.year);
|
||||
printf("%s%02d", delimiter, date.month);
|
||||
printf("%s%02d", delimiter, date.day);
|
||||
}
|
||||
|
||||
void RTC_print_time(rtc_time_t time) {
|
||||
printf("%02d:%02d:%02d.%03d",
|
||||
time.hr, time.min, time.sec, time.ms);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,14 +27,14 @@
|
|||
#define TIMEOUT_MAX 100000
|
||||
|
||||
// uncomment this to enable IRQ-driven operation
|
||||
// #define SSD1306_I2C_IRQ
|
||||
//#define SSD1306_I2C_IRQ
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// some stuff that IRQ mode needs
|
||||
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
|
||||
|
||||
// uncomment this to enable time diags in IRQ
|
||||
// #define IRQ_DIAG
|
||||
//#define IRQ_DIAG
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -42,62 +42,62 @@ volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
#if (SSD1306_I2C_CLKRATE <= 100000)
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// fast mode over 100kHz
|
||||
// fast mode over 100kHz
|
||||
#ifndef SSD1306_I2C_DUTY
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
#endif
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
#endif
|
||||
I2C1->CKCFGR = tempreg;
|
||||
I2C1->CKCFGR = tempreg;
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
#endif
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
}
|
||||
|
||||
/*
|
||||
* error descriptions
|
||||
*/
|
||||
char *errstr[] =
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -105,28 +105,28 @@ char *errstr[] =
|
|||
*/
|
||||
uint8_t ssd1306_i2c_error(uint8_t err)
|
||||
{
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// event codes we use
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
|
||||
/*
|
||||
* check for 32-bit event codes
|
||||
*/
|
||||
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||
{
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
||||
return (status & event_mask) == event_mask;
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
|
||||
return (status & event_mask) == event_mask;
|
||||
}
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
|
|
@ -135,67 +135,63 @@ uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
int32_t timeout;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(3));
|
||||
#endif
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while(ssd1306_i2c_irq_state);
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (3));
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while (ssd1306_i2c_irq_state)
|
||||
;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
#endif
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -204,43 +200,42 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
|
||||
void I2C1_EV_IRQHandler(void)
|
||||
{
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
#endif
|
||||
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
|
||||
/* check for TXE */
|
||||
if(STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if(ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
|
||||
/* check for TXE */
|
||||
if (STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if (ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
/* was that the last byte? */
|
||||
if(!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||
|
||||
/* was that the last byte? */
|
||||
if (!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
;
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
|
@ -249,61 +244,56 @@ void I2C1_EV_IRQHandler(void)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
int32_t timeout;
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
// send data one byte at a time
|
||||
while(sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// send data one byte at a time
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -312,20 +302,20 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if (cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1);
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if(cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -333,51 +323,51 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_init(void)
|
||||
{
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
|
||||
#ifdef CH32V20x
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
|
||||
#ifdef SSD1306_REMAP_I2C
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
#else
|
||||
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
#endif
|
||||
|
||||
#else
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2);
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
|
||||
#endif
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
#endif
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
#if 0
|
||||
// test if SSD1306 is on the bus by sending display off command
|
||||
uint8_t command = 0xAF;
|
||||
return ssd1306_pkt_send(&command, 1, 1);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,115 +26,120 @@
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
}
|
||||
|
||||
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0);
|
||||
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0);
|
||||
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA);
|
||||
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||
#define SDA_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 I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1)
|
||||
// Delay_Us(x*1);
|
||||
#endif
|
||||
#ifndef I2CDELAY_FUNC
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||
#endif
|
||||
|
||||
static void ssd1306_i2c_sendstart()
|
||||
{
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
}
|
||||
|
||||
void ssd1306_i2c_sendstop()
|
||||
{
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
}
|
||||
|
||||
// Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
||||
//Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
if (data & 0x80)
|
||||
{
|
||||
SDA_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDA_LOW;
|
||||
}
|
||||
data <<= 1;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(2 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
}
|
||||
unsigned int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
if( data & 0x80 )
|
||||
{ SDA_HIGH; }
|
||||
else
|
||||
{ SDA_LOW; }
|
||||
data<<=1;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
}
|
||||
|
||||
// Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH // Maybe?
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
return !!i;
|
||||
//Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH
|
||||
SDA_RELEASE
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_DRIVE
|
||||
SDA_HIGH
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
return !!i;
|
||||
}
|
||||
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1);
|
||||
if (r) return r;
|
||||
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if (cmd)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x00))
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x40))
|
||||
return 1; // Data
|
||||
}
|
||||
for (int i = 0; i < sz; i++)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(data[i]))
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
|
||||
if( r ) return r;
|
||||
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if(cmd)
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x00 ) )
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x40 ) )
|
||||
return 1; // Data
|
||||
}
|
||||
for( int i = 0; i < sz; i++ )
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( data[i] ) )
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 0);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 1);
|
||||
Delay_Us(10);
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_RST_PIN, 0 );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, 1 );
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,43 +24,66 @@
|
|||
#endif
|
||||
|
||||
#ifndef SSD1306_SCK_PIN
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
||||
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_SOFT_SPI
|
||||
#define SSD1306_SOFT_SPI 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* init SPI and GPIO for SSD1306 OLED
|
||||
*/
|
||||
uint8_t ssd1306_spi_init(void)
|
||||
{
|
||||
// Enable GPIOC and SPI
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
// Enable GPIOC and SPI
|
||||
#ifdef CH5xx
|
||||
#else
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
#endif
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
#if defined( CH5xx ) || SSD1306_SOFT_SPI
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
#else
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
#endif
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
// Configure SPI
|
||||
#if SSD1306_SOFT_SPI
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH );
|
||||
#elif defined( CH5xx )
|
||||
R8_SPI0_CLOCK_DIV = FUNCONF_SYSTEM_CORE_CLOCK / 12000000; // 16MHz is the fastest I want to go - though it does seem to work up to ~60MHz.
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
|
||||
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_2WIRE_MOD | RB_SPI_SCK_OE;
|
||||
R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
|
||||
// | RB_SPI_MST_SCK_MOD; // Mode 3 / mode 0
|
||||
R8_SPI0_CTRL_CFG = RB_MST_CLK_SEL;
|
||||
#else
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
#endif
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -68,9 +91,9 @@ uint8_t ssd1306_spi_init(void)
|
|||
*/
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -78,35 +101,56 @@ void ssd1306_rst(void)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
if (cmd)
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
|
||||
}
|
||||
if(cmd)
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||
}
|
||||
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||
|
||||
// send data
|
||||
while(sz--)
|
||||
{
|
||||
#if SSD1306_SOFT_SPI
|
||||
uint8_t c = *data++;
|
||||
int i = 8;
|
||||
do
|
||||
{
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
|
||||
funDigitalWrite( SSD1306_MOSI_PIN, !!(c & 0x80) ); ADD_N_NOPS(1)
|
||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH ); ADD_N_NOPS(1)
|
||||
c<<=1;
|
||||
} while( --i );
|
||||
|
||||
// send data
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TXE
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
||||
;
|
||||
#elif defined( CH5xx )
|
||||
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
||||
R8_SPI0_BUFFER = *data++;
|
||||
#else
|
||||
// wait for TXE
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
#endif
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
#if SSD1306_SOFT_SPI
|
||||
// Nothing needed here.
|
||||
#elif defined( CH5xx )
|
||||
while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE)) { }
|
||||
#else
|
||||
while(SPI1->STATR & SPI_STATR_BSY) { }
|
||||
#endif
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
while (SPI1->STATR & SPI_STATR_BSY) {}
|
||||
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
203
inc/extralibs/static_i2c.h
Normal file
203
inc/extralibs/static_i2c.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Copyright 2012-2025 <>< Charles Lohr
|
||||
This file may be used for any purposes (commercial or private) just please
|
||||
leave this copyright notice in there somewhere. You may cross license
|
||||
this as MIT or NewBSD.
|
||||
|
||||
Now, generic I2C library for any GPIO-based system.
|
||||
|
||||
Include this in your .c file only!!!
|
||||
Include it after the following are defined:
|
||||
|
||||
I2CDELAY_FUNC -> If you wish to override the internal delay functions.
|
||||
I2CSPEEDBASE -> define speed base multiplier 1 = normal, 10 = slow, .1 =
|
||||
fast; failure to define this will result in the clock being as fast as
|
||||
possible. I2CNEEDGETBYTE -> Do we need to be able to read data?
|
||||
|
||||
I2CPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigI2C
|
||||
to be generated.
|
||||
I2CNOSTATIC -> #define if you want the functions to be generated as
|
||||
not-static code.
|
||||
|
||||
NOTE: You must initially configure the port to be outputs on both DSDA
|
||||
and DSCL and set them both to be driven high.
|
||||
*/
|
||||
/* Example:
|
||||
|
||||
#define DELAY1 Delay_Us(1);
|
||||
#define DELAY2 Delay_Us(2);
|
||||
#define DSCL_IHIGH { funPinMode( PIN_SCL, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SCL, 1 ); }
|
||||
#define DSDA_IHIGH { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); }
|
||||
#define DSDA_INPUT { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); }
|
||||
#define DSCL_OUTPUT { funDigitalWrite( PIN_SCL, 0 ); funPinMode( PIN_SCL, GPIO_CFGLR_OUT_2Mhz_PP ); }
|
||||
#define DSDA_OUTPUT { funDigitalWrite( PIN_SDA, 0 ); funPinMode( PIN_SDA, GPIO_CFGLR_OUT_2Mhz_PP ); }
|
||||
#define READ_DSDA funDigitalRead( PIN_SDA )
|
||||
#define I2CNEEDGETBYTE 1
|
||||
#define I2CNEEDSCAN 1
|
||||
|
||||
#include "static_i2c.h"
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef I2CPREFIX
|
||||
#define I2CPREFIX
|
||||
#endif
|
||||
|
||||
#ifndef I2CNOSTATIC
|
||||
#define I2CSTATICODE
|
||||
#else
|
||||
#define I2CSTATICODE static
|
||||
#endif
|
||||
|
||||
#ifndef I2CFNCOLLAPSE
|
||||
#define INTI2CFNCOLLAPSE(PFX, name) PFX##name
|
||||
#define I2CFNCOLLAPSE(PFX, name) INTI2CFNCOLLAPSE(PFX, name)
|
||||
#endif
|
||||
|
||||
#ifndef I2CNEEDGETBYTE
|
||||
#define I2CNEEDGETBYTE 1
|
||||
#endif
|
||||
|
||||
#ifndef DSCL_IHIGH
|
||||
#define DSCL_IHIGH DSCL_INPUT
|
||||
#endif
|
||||
|
||||
#ifndef DSDA_IHIGH
|
||||
#define DSDA_IHIGH DSDA_INPUT
|
||||
#endif
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, ConfigI2C)()
|
||||
{
|
||||
DSDA_IHIGH
|
||||
DSCL_IHIGH
|
||||
}
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)()
|
||||
{
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
DSDA_OUTPUT
|
||||
DELAY1
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
}
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)()
|
||||
{
|
||||
DELAY1
|
||||
DSDA_OUTPUT
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
DSDA_IHIGH
|
||||
DELAY1
|
||||
}
|
||||
|
||||
// Return nonzero on failure.
|
||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data)
|
||||
{
|
||||
unsigned int i;
|
||||
// Assume we are in a started state (DSCL = 0 & DSDA = 0)
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
DELAY1
|
||||
if (data & 0x80)
|
||||
{
|
||||
DSDA_IHIGH
|
||||
}
|
||||
else
|
||||
{
|
||||
DSDA_OUTPUT
|
||||
}
|
||||
data <<= 1;
|
||||
DELAY2
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
DSCL_OUTPUT
|
||||
}
|
||||
|
||||
// Immediately after sending last bit, open up DDDR for control.
|
||||
DELAY1
|
||||
DSDA_INPUT
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY1
|
||||
i = READ_DSDA;
|
||||
DELAY1
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
return !!i;
|
||||
}
|
||||
|
||||
#if I2CNEEDGETBYTE
|
||||
|
||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char ret = 0;
|
||||
|
||||
DSDA_INPUT
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
ret <<= 1;
|
||||
if (READ_DSDA)
|
||||
ret |= 1;
|
||||
DSCL_OUTPUT
|
||||
}
|
||||
|
||||
// Send ack.
|
||||
if (send_nak)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
DSDA_OUTPUT
|
||||
}
|
||||
|
||||
DELAY1
|
||||
DSCL_IHIGH
|
||||
DELAY2
|
||||
DSCL_OUTPUT
|
||||
DELAY1
|
||||
DSDA_IHIGH
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// In case you want SCAN code
|
||||
|
||||
#if I2CNEEDSCAN
|
||||
|
||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, Scan)()
|
||||
{
|
||||
int i;
|
||||
printf( " " );
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
printf( " %x", i );
|
||||
}
|
||||
for( i = 0; i < 128; i++ )
|
||||
{
|
||||
if( ( i & 0xf ) == 0 )
|
||||
{
|
||||
printf( "\n%02x ", i );
|
||||
}
|
||||
SendStart();
|
||||
int b = SendByte( i<<1 );
|
||||
SendStop();
|
||||
printf( "%c ", b?'.':'#' );
|
||||
}
|
||||
printf( "\n" );
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,28 +2,30 @@
|
|||
I may write another version of this to use DMA to timer ports, but, the SPI port can be used
|
||||
to generate outputs very efficiently. So, for now, SPI Port. Additionally, it uses FAR less
|
||||
internal bus resources than to do the same thing with timers.
|
||||
|
||||
|
||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
||||
**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!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
|
||||
Other defines inclue:
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
|
||||
You will need to implement the following two functions, as callbacks from the ISR.
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
|
||||
You willalso need to call
|
||||
WS2812BDMAInit();
|
||||
WS2812BDMAInit();
|
||||
|
||||
Then, whenyou want to update the LEDs, call:
|
||||
WS2812BDMAStart( int num_leds );
|
||||
WS2812BDMAStart( int num_leds );
|
||||
*/
|
||||
|
||||
#ifndef _WS2812_LED_DRIVER_H
|
||||
|
|
@ -32,11 +34,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
||||
void WS2812BDMAInit();
|
||||
void WS2812BDMAStart(int leds);
|
||||
void WS2812BDMAInit( );
|
||||
void WS2812BDMAStart( int leds );
|
||||
|
||||
// Callbacks that you must implement.
|
||||
uint32_t WS2812BLEDCallback(int ledno);
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
|
||||
#ifdef WS2812DMA_IMPLEMENTATION
|
||||
|
||||
|
|
@ -46,241 +48,293 @@ uint32_t WS2812BLEDCallback(int ledno);
|
|||
#endif
|
||||
|
||||
// Note first n LEDs of DMA Buffer are 0's as a "break"
|
||||
// Need one extra LED at end to leave line high.
|
||||
// Need one extra LED at end to leave line high.
|
||||
// This must be greater than WS2812B_RESET_PERIOD.
|
||||
#define WS2812B_RESET_PERIOD 2
|
||||
|
||||
#ifdef WSRAW
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
|
||||
#else
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
|
||||
#endif
|
||||
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static volatile int WS2812LEDs;
|
||||
static volatile int WS2812LEDPlace;
|
||||
static volatile int WS2812BLEDInUse;
|
||||
|
||||
#ifdef CH5xx
|
||||
#ifdef CH570_CH572
|
||||
#define bMOSI PA7
|
||||
#else
|
||||
#define bMOSI PA14
|
||||
#endif
|
||||
#endif
|
||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||
// This effectively creates the bitstream that outputs to the LEDs.
|
||||
static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
||||
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
|
||||
{
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000,
|
||||
0b1000100010001110,
|
||||
0b1000100011101000,
|
||||
0b1000100011101110,
|
||||
0b1000111010001000,
|
||||
0b1000111010001110,
|
||||
0b1000111011101000,
|
||||
0b1000111011101110,
|
||||
0b1110100010001000,
|
||||
0b1110100010001110,
|
||||
0b1110100011101000,
|
||||
0b1110100011101110,
|
||||
0b1110111010001000,
|
||||
0b1110111010001110,
|
||||
0b1110111011101000,
|
||||
0b1110111011101110,
|
||||
};
|
||||
|
||||
int i;
|
||||
uint16_t *end = ptr + numhalfwords;
|
||||
int ledcount = WS2812LEDs;
|
||||
int place = WS2812LEDPlace;
|
||||
|
||||
#ifdef WSRAW
|
||||
while (place < 0 && ptr != end)
|
||||
{
|
||||
uint32_t *lptr = (uint32_t *)ptr;
|
||||
lptr[0] = 0;
|
||||
lptr[1] = 0;
|
||||
lptr[2] = 0;
|
||||
lptr[3] = 0;
|
||||
ptr += 8;
|
||||
place++;
|
||||
}
|
||||
|
||||
#ifdef CH5xx
|
||||
// Reversing bit order because CH5xx SPI FIFO is only half of what CH32 have
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b0001000100010001, 0b0111000100010001, 0b0001011100010001, 0b0111011100010001,
|
||||
0b0001000101110001, 0b0111000101110001, 0b0001011101110001, 0b0111011101110001,
|
||||
0b0001000100010111, 0b0111000100010111, 0b0001011100010111, 0b0111011100010111,
|
||||
0b0001000101110111, 0b0111000101110111, 0b0001011101110111, 0b0111011101110111, };
|
||||
#else
|
||||
while (place < 0 && ptr != end)
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||
#endif
|
||||
|
||||
while (ptr != end)
|
||||
{
|
||||
if (place >= ledcount)
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while (ptr != end)
|
||||
(*ptr++) = 0; // 0xffff;
|
||||
|
||||
// Only safe to do this when we're on the second leg.
|
||||
if (tce)
|
||||
{
|
||||
if (place == ledcount)
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
int i;
|
||||
uint16_t * end = ptr + numhalfwords;
|
||||
int ledcount = WS2812LEDs;
|
||||
int place = WS2812LEDPlace;
|
||||
|
||||
#ifdef WSRAW
|
||||
uint32_t ledval32bit = WS2812BLEDCallback(place++);
|
||||
|
||||
ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf];
|
||||
ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf];
|
||||
|
||||
ptr += 8;
|
||||
i += 8;
|
||||
while( place < 0 && ptr != end )
|
||||
{
|
||||
uint32_t * lptr = (uint32_t *)ptr;
|
||||
lptr[0] = 0;
|
||||
lptr[1] = 0;
|
||||
lptr[2] = 0;
|
||||
lptr[3] = 0;
|
||||
ptr += 8;
|
||||
place++;
|
||||
}
|
||||
|
||||
#else
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback(place++);
|
||||
while( place < 0 && ptr != end )
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
#endif
|
||||
|
||||
while( ptr != end )
|
||||
{
|
||||
if( place >= ledcount )
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while( ptr != end )
|
||||
(*ptr++) = 0;//0xffff;
|
||||
|
||||
// Only safe to do this when we're on the second leg.
|
||||
if( tce )
|
||||
{
|
||||
if( place == ledcount )
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
#ifdef CH5xx
|
||||
R8_SPI0_INTER_EN &= ~RB_SPI_IE_DMA_END; // Disable DMA end interrupt
|
||||
#else
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
#endif
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WSRAW
|
||||
uint32_t ledval32bit = WS2812BLEDCallback( place++ );
|
||||
|
||||
ptr[6] = bitquartets[(ledval32bit>>28)&0xf];
|
||||
ptr[7] = bitquartets[(ledval32bit>>24)&0xf];
|
||||
ptr[4] = bitquartets[(ledval32bit>>20)&0xf];
|
||||
ptr[5] = bitquartets[(ledval32bit>>16)&0xf];
|
||||
ptr[2] = bitquartets[(ledval32bit>>12)&0xf];
|
||||
ptr[3] = bitquartets[(ledval32bit>>8)&0xf];
|
||||
ptr[0] = bitquartets[(ledval32bit>>4)&0xf];
|
||||
ptr[1] = bitquartets[(ledval32bit>>0)&0xf];
|
||||
|
||||
ptr += 8;
|
||||
i += 8;
|
||||
|
||||
#else
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback( place++ );
|
||||
|
||||
#ifdef WSRBG
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
#elif defined(WSGRB)
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
#elif defined( WSGRB )
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
#else
|
||||
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
#endif
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
#endif
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
}
|
||||
|
||||
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler(void)
|
||||
#ifdef CH5xx
|
||||
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.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
// Backup flags.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
|
||||
if (intfr & DMA1_IT_HT3)
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
|
||||
}
|
||||
if (intfr & DMA1_IT_TC3)
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while (intfr & DMA1_IT_GL3);
|
||||
if( intfr & DMA1_IT_HT3 )
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
|
||||
}
|
||||
if( intfr & DMA1_IT_TC3 )
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while( intfr & DMA1_IT_GL3 );
|
||||
|
||||
// GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
}
|
||||
#endif
|
||||
|
||||
void WS2812BDMAStart( int leds )
|
||||
{
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
#ifdef CH5xx
|
||||
R8_SPI0_INTER_EN &= ~RB_SPI_IE_DMA_END;
|
||||
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
|
||||
R16_SPI0_TOTAL_CNT = 0;
|
||||
#else
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
#endif
|
||||
__enable_irq();
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
|
||||
|
||||
#ifdef CH5xx
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
R16_SPI0_TOTAL_CNT = DMA_BUFFER_LEN * 2;
|
||||
R16_SPI0_DMA_BEG = (uint32_t)WS2812dmabuff;
|
||||
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
|
||||
R8_SPI0_INTER_EN = RB_SPI_IE_DMA_END;
|
||||
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
|
||||
#else
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WS2812BDMAStart(int leds)
|
||||
void WS2812BDMAInit( )
|
||||
{
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
// 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;
|
||||
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN, 0);
|
||||
NVIC_EnableIRQ( SPI0_IRQn );
|
||||
#else
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
}
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
|
||||
void WS2812BDMAInit()
|
||||
{
|
||||
// Enable DMA + Peripherals
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; // Enable Tx buffer DMA
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3 << 3; // Divisior = 16 (48/16 = 3MHz)
|
||||
#if defined(CH32V003)
|
||||
SPI1->HSCR = 1; // Enable high-speed read mode
|
||||
#endif
|
||||
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set; // Enable SPI
|
||||
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
//DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
|
||||
// DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ( DMA1_Channel3_IRQn );
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
|
||||
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
You may also want to define
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes);
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes );
|
||||
|
||||
#ifdef WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
|
|
@ -25,58 +25,59 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
|
|||
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
||||
#endif
|
||||
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes)
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes )
|
||||
{
|
||||
int port_id = (((intptr_t)port - (intptr_t)GPIOA) >> 10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled.
|
||||
int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
|
||||
|
||||
int poffset = (pin * 4);
|
||||
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset));
|
||||
int poffset = (pin*4);
|
||||
port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
|
||||
|
||||
int maskon = 1 << pin;
|
||||
int maskoff = 1 << (16 + pin);
|
||||
int maskon = 1<<pin;
|
||||
int maskoff = 1<<(16+pin);
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
|
||||
uint8_t *end = data + len_in_bytes;
|
||||
while (data != end)
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
uint8_t * end = data + len_in_bytes;
|
||||
while( data != end )
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (byte & 0x80)
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
if( byte & 0x80 )
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__disable_irq();
|
||||
__disable_irq();
|
||||
#endif
|
||||
port->BSHR = maskon;
|
||||
asm volatile("nop\nnop\nnop\nnop");
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskon;
|
||||
asm volatile( "nop\nnop\nnop\nnop" );
|
||||
port->BSHR = maskoff;
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__enable_irq();
|
||||
__enable_irq();
|
||||
#endif
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
data++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"DisableFormat": true,
|
||||
"SortIncludes": "Never"
|
||||
}
|
||||
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_blink.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_blink.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_blink.o ch5xx_blink.bin
|
||||
riscv64-unknown-elf-as ch5xx_blink.asm -march=rv32imac -mabi=ilp32 -o ch5xx_blink.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_blink.o ch5xx_blink.bin
|
||||
xxd -i ch5xx_blink.bin > ch5xx_blink.h
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_verify.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_verify.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_verify.o ch5xx_verify.bin
|
||||
riscv64-unknown-elf-as ch5xx_verify.asm -march=rv32imac_zicsr -o ch5xx_verify.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_verify.o ch5xx_verify.bin
|
||||
xxd -i ch5xx_verify.bin > ch5xx_verify.h
|
||||
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_write_block.sh
Executable file
5
inc/misc/attic/ch5xx_blobs_for_minichlink/build_write_block.sh
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -f ch5xx_write_block.o ch5xx_write_block.bin
|
||||
riscv64-unknown-elf-as ch5xx_write_block.asm -march=rv32imac_zicsr -o ch5xx_write_block.o
|
||||
riscv64-unknown-elf-objcopy -O binary ch5xx_write_block.o ch5xx_write_block.bin
|
||||
xxd -i ch5xx_write_block.bin > ch5xx_write_block.h
|
||||
23
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_blink.asm
Normal file
23
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_blink.asm
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# The simplest blink fuction that can fit into PROGBUF.
|
||||
# This is the version suitable for CH5xx series of chips by WCH.
|
||||
# You need to preload respective registers with values for port, pin and delay.
|
||||
# Copyright 2025 monte-monte
|
||||
#
|
||||
#a2 = GPIO port (0 - A, 1 - B...)
|
||||
#a3 = value to count down from for a delay between blinks
|
||||
#a4 = pin mask
|
||||
BEGIN:
|
||||
c.sw a4, 0(a2);
|
||||
c.mv a5, a3;
|
||||
sw zero, 8(a2);
|
||||
LOOP1:
|
||||
c.addi a5, -1;
|
||||
c.bnez a5, LOOP1;
|
||||
c.mv a5, a3;
|
||||
c.sw a4, 8(a2);
|
||||
LOOP2:
|
||||
c.addi a5, -1;
|
||||
c.bnez a5, LOOP2;
|
||||
c.j BEGIN;
|
||||
c.ebreak
|
||||
10
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_verify.asm
Normal file
10
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_verify.asm
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
c.nop;
|
||||
li a5,4;
|
||||
LOOP:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,LOOP;
|
||||
lb a4,4(a3);
|
||||
c.addi a5,-1;
|
||||
c.bnez a5,LOOP;
|
||||
c.lw a1,0(a3);
|
||||
c.sw a1,0(a0);
|
||||
116
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_write_block.asm
Normal file
116
inc/misc/attic/ch5xx_blobs_for_minichlink/ch5xx_write_block.asm
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#
|
||||
# A procedure to write data to flash on CH5xx series of chips by WCH.
|
||||
# This should be compiled into a binary blob and placed into RAM.
|
||||
# Then you will be able to run it and send data via a programmer by writing it to DMDATA0/1
|
||||
# Copyright 2025 monte-monte
|
||||
#
|
||||
#s0 = incomming data from dmdata0
|
||||
#s1 = incomming data from dmdata1
|
||||
#t0 = general reg
|
||||
#t1 = address global
|
||||
#a0 = address in loop
|
||||
#a1 = dmdata0 offset
|
||||
#a2 = general reg
|
||||
#a3 = R32_FLASH_DATA
|
||||
#a4 = general operational
|
||||
#a5 = len counter
|
||||
PREAMBLE:
|
||||
#c.li t0,0;
|
||||
#c.li a2,0;
|
||||
#c.li a4,0;
|
||||
#c.li a5,0;
|
||||
lw s0,0(a1);
|
||||
lw s1,4(a1);
|
||||
bne s1,s0,PREAMBLE;#Wait for DMDATA0/1 to be cleared;
|
||||
c.bnez s0,PREAMBLE;
|
||||
START:
|
||||
#BEGIN
|
||||
addi a0,t1,0;
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
c.li a4,6;
|
||||
sb a4,4(a3);
|
||||
END:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,END;
|
||||
sb zero,6(a3);
|
||||
#BEGIN with CMD = 2
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
c.li a4,2;
|
||||
sb a4,4(a3);
|
||||
c.li a2,3;
|
||||
OUT:
|
||||
srli t0,a0,16;
|
||||
andi t0,t0,0xff;
|
||||
OUT_LOOP:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,OUT_LOOP;
|
||||
sb t0,4(a3);
|
||||
c.slli a0,8;
|
||||
c.addi a2,-1;
|
||||
c.bnez a2,OUT;
|
||||
ADDRES_IS_SET:
|
||||
sw zero,0(a1);#Clear DMDATA0 to indicate we are ready to write again
|
||||
addi a5,zero,64;#Load up the byte counter
|
||||
DATA_RETRIEVER:
|
||||
c.lw s0,0(a1);
|
||||
c.lw s1,4(a1);
|
||||
c.bnez s1, WRITE_ZERO
|
||||
c.beqz s0, DATA_RETRIEVER;
|
||||
WRITE:
|
||||
c.sw s0,0(a3);
|
||||
c.li a4,0x4;
|
||||
WRITE_LOOP1:
|
||||
lb a2,6(a3);
|
||||
blt a2,zero,WRITE_LOOP1;
|
||||
c.li a2,21;
|
||||
sb a2,6(a3);
|
||||
c.addi a4,-1;
|
||||
c.bnez a4,WRITE_LOOP1;
|
||||
c.addi a5,-1;
|
||||
sw zero,0(a1);
|
||||
c.bnez a5,DATA_RETRIEVER;
|
||||
addi t1,t1,256;
|
||||
sw t1,0(a1);#Write current address to DMDATA0 to indicate that we are in wait loop
|
||||
lui t0,0x80;
|
||||
WAIT:
|
||||
#END
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,WAIT;
|
||||
sb zero,6(a3)
|
||||
#BEGIN with CMD = 5
|
||||
WAIT_LOOP:
|
||||
sb zero,6(a3);
|
||||
c.li a4,5;
|
||||
sb a4,6(a3);
|
||||
sb a4,4(a3)
|
||||
IN_LOOP1:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,IN_LOOP1;
|
||||
lbu a2,4(a3);
|
||||
IN_LOOP2:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,IN_LOOP2;
|
||||
lb a2,4(a3);
|
||||
WAIT_END:
|
||||
lb a4,6(a3);
|
||||
blt a4,zero,WAIT_END;
|
||||
sb zero,6(a3)
|
||||
#IF
|
||||
andi a4,a2,1;
|
||||
c.bnez a4,WAIT_LOOP_BACK;
|
||||
j START;
|
||||
WAIT_LOOP_BACK:
|
||||
c.addi t0,-1;
|
||||
bne t0,zero,WAIT_LOOP;
|
||||
EXIT:
|
||||
c.ebreak;
|
||||
WRITE_ZERO:
|
||||
sw zero,4(a1);
|
||||
beq s1,a1,WAIT;
|
||||
sw zero,0(a3);
|
||||
c.li a4,0x4;
|
||||
c.j WRITE_LOOP1;
|
||||
|
|
@ -20,7 +20,7 @@ typedef enum IRQn
|
|||
Ecall_U_Mode_IRQn = 8, /* 8 Ecall U Mode Interrupt */
|
||||
Break_Point_IRQn = 9, /* 9 Break Point Interrupt */
|
||||
#endif
|
||||
SysTicK_IRQn = 12, /* 12 System timer Interrupt */
|
||||
SysTick_IRQn = 12, /* 12 System timer Interrupt */
|
||||
Software_IRQn = 14, /* 14 software Interrupt */
|
||||
|
||||
#if defined(CH32V003) || defined(CH32X03x)
|
||||
|
|
@ -1864,8 +1864,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
#define USB_PHY_V33 (1<<6)
|
||||
#define USB_IOEN (1<<7)
|
||||
|
||||
|
||||
#define USBFSD_UEP_MOD_BASE 0x4002340C
|
||||
|
|
@ -2266,11 +2264,7 @@ typedef struct
|
|||
#define ESIG_BASE ((uint32_t)0x1FFFF7E0)
|
||||
#define INFO_BASE ((uint32_t)0x1FFFF704)
|
||||
|
||||
#if defined(CH32V003) || defined(CH32V10x)
|
||||
#define EXTEN_BASE ((uint32_t)0x40023800)
|
||||
#elif defined(CH32V20x) || defined(CH32V30x)
|
||||
#define EXTEN_BASE (AHBPERIPH_BASE + 0x3800)
|
||||
#endif
|
||||
|
||||
#define PFIC_BASE (CORE_PERIPH_BASE + 0xE000)
|
||||
#define SysTick_BASE (CORE_PERIPH_BASE + 0xF000)
|
||||
|
|
@ -2283,118 +2277,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
// AFIO CTLR Bits
|
||||
#define PB6_FILT_EN (1<<27)
|
||||
#define PB5_FILT_EN (1<<26)
|
||||
#define PA4_FILT_EN (1<<25)
|
||||
#define PA3_FILT_EN (1<<24)
|
||||
#define UDM_BC_CMPO (1<<19)
|
||||
#define UDP_BC_CMPO (1<<17)
|
||||
#define UDM_BC_VSRC (1<<17)
|
||||
#define UDP_BC_VSRC (1<<16)
|
||||
#define USBPD_IN_HVT (1<<9)
|
||||
#define USBPD_PHY_V33 (1<<8)
|
||||
#define USB_IOEN (1<<7)
|
||||
#define USB_PHY_V33 (1<<6)
|
||||
#define UDP_PUE_00 (0b00<<2)
|
||||
#define UDP_PUE_01 (0b01<<2)
|
||||
#define UDP_PUE_10 (0b10<<2)
|
||||
#define UDP_PUE_11 (0b11<<2)
|
||||
#define UDM_PUE_00 (0b00<<0)
|
||||
#define UDM_PUE_01 (0b01<<0)
|
||||
#define UDM_PUE_10 (0b10<<0)
|
||||
#define UDM_PUE_11 (0b11<<0)
|
||||
#define UDP_PUE_MASK 0x0000000C
|
||||
#define UDP_PUE_DISABLE 0x00000000
|
||||
#define UDP_PUE_35UA 0x00000004
|
||||
#define UDP_PUE_10K 0x00000008
|
||||
#define UDP_PUE_1K5 0x0000000C
|
||||
#define UDM_PUE_MASK 0x00000003
|
||||
#define UDM_PUE_DISABLE 0x00000000
|
||||
#define UDM_PUE_35UA 0x00000001
|
||||
#define UDM_PUE_10K 0x00000002
|
||||
#define UDM_PUE_1K5 0x00000003
|
||||
|
||||
|
||||
// USB PD Bits
|
||||
#define IE_TX_END (1<<15)
|
||||
#define IE_RX_RESET (1<<14)
|
||||
#define IE_RX_ACT (1<<13)
|
||||
#define IE_RX_BYTE (1<<12)
|
||||
#define IE_RX_BIT (1<<11)
|
||||
#define IE_PD_IO (1<<10)
|
||||
#define WAKE_POLAR (1<<5)
|
||||
#define PD_RST_EN (1<<4)
|
||||
#define PD_DMA_EN (1<<3)
|
||||
#define CC_SEL (1<<2)
|
||||
#define PD_ALL_CLR (1<<1)
|
||||
#define PD_FILT_EN (1<<0)
|
||||
#define BMC_CLK_CNT_MASK (0xff)
|
||||
|
||||
//R8_CONTROL
|
||||
#define BMC_BYTE_HI (1<<7)
|
||||
#define TX_BIT_BACK (1<<6)
|
||||
#define DATA_FLAG (1<<5)
|
||||
#define RX_STATE_MASK (0x7<<2)
|
||||
#define RX_STATE_0 (1<<2)
|
||||
#define RX_STATE_1 (1<<3)
|
||||
#define RX_STATE_2 (1<<4)
|
||||
#define BMC_START (1<<1)
|
||||
#define PD_TX_EN (1<<0)
|
||||
|
||||
#define TX_SEL4_MASK (3<<6)
|
||||
#define TX_SEL4_0 (1<<6)
|
||||
#define TX_SEL4_1 (1<<7)
|
||||
|
||||
#define TX_SEL3_MASK (3<<4)
|
||||
#define TX_SEL3_0 (1<<4)
|
||||
#define TX_SEL3_1 (1<<5)
|
||||
|
||||
#define TX_SEL2_MASK (3<<2)
|
||||
#define TX_SEL2_0 (1<<2)
|
||||
#define TX_SEL2_1 (1<<3)
|
||||
|
||||
#define TX_SEL1 (1<<0)
|
||||
|
||||
#define BMC_TX_SZ_MASK (0x1ff)
|
||||
|
||||
//R8_STATUS
|
||||
#define IF_TX_END (1<<7)
|
||||
#define IF_RX_RESET (1<<6)
|
||||
#define IF_RX_ACT (1<<5)
|
||||
#define IF_RX_BYTE (1<<4)
|
||||
#define IF_RX_BIT (1<<3)
|
||||
#define IFBUF_ERR (1<<2)
|
||||
#define BMC_AUX_MASK (3<<0)
|
||||
#define BMC_AUX_1 (1<<1)
|
||||
#define BMC_AUX_0 (1<<0)
|
||||
|
||||
// PORT CC1
|
||||
#define CC1_CE_MASK (7<<5)
|
||||
#define CC1_CE_0 (1<<5)
|
||||
#define CC1_CE_1 (2<<5)
|
||||
#define CC1_CE_2 (4<<5)
|
||||
|
||||
#define CC1_LVE (1<<4)
|
||||
#define CC1_PU_MASK (3<<2)
|
||||
#define CC1_PU_DISABLE (0<<2)
|
||||
#define CC1_PU_330uA (1<<2)
|
||||
#define CC1_PU_180uA (2<<2)
|
||||
#define CC1_PU_80uA (3<<2)
|
||||
#define PA_CC1_AI (1<<0)
|
||||
|
||||
#define CC2_CE_MASK (7<<5)
|
||||
#define CC2_CE_0 (1<<5)
|
||||
#define CC2_CE_1 (2<<5)
|
||||
#define CC2_CE_2 (4<<5)
|
||||
|
||||
#define CC2_LVE (1<<4)
|
||||
#define CC2_PU_MASK (3<<2)
|
||||
#define CC2_PU_DISABLE (0<<2)
|
||||
#define CC2_PU_330uA (1<<2)
|
||||
#define CC2_PU_180uA (2<<2)
|
||||
#define CC2_PU_80uA (3<<2)
|
||||
#define PA_CC2_AI (1<<0)
|
||||
|
||||
|
||||
|
||||
|
|
@ -5356,33 +5238,33 @@ typedef struct
|
|||
|
||||
#if defined(CH32V003)
|
||||
/***************** Bit definition for AFIO_EXTICR register *****************/
|
||||
#define AFIO_EXTICR_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
||||
#define AFIO_EXTICR_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
||||
#define AFIO_EXTICR_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
||||
#define AFIO_EXTICR_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
||||
#define AFIO_EXTICR_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
||||
#define AFIO_EXTICR_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
||||
#define AFIO_EXTICR_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
||||
#define AFIO_EXTICR_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
||||
#define AFIO_EXTICR1_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
||||
#define AFIO_EXTICR1_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
||||
#define AFIO_EXTICR1_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
||||
#define AFIO_EXTICR1_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
||||
#define AFIO_EXTICR1_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
||||
#define AFIO_EXTICR1_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
||||
#define AFIO_EXTICR1_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
||||
#define AFIO_EXTICR1_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
||||
|
||||
#define AFIO_EXTICR_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
||||
#define AFIO_EXTICR_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
||||
#define AFIO_EXTICR_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
||||
#define AFIO_EXTICR_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
||||
#define AFIO_EXTICR_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
||||
#define AFIO_EXTICR_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
||||
#define AFIO_EXTICR_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
||||
#define AFIO_EXTICR_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
||||
#define AFIO_EXTICR_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
||||
#define AFIO_EXTICR_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
||||
#define AFIO_EXTICR_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
||||
#define AFIO_EXTICR_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
||||
#define AFIO_EXTICR_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
||||
#define AFIO_EXTICR_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
||||
#define AFIO_EXTICR1_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
||||
#define AFIO_EXTICR1_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
||||
#define AFIO_EXTICR1_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
||||
#define AFIO_EXTICR1_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
||||
#define AFIO_EXTICR1_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
||||
#define AFIO_EXTICR1_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
||||
#define AFIO_EXTICR1_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
||||
#define AFIO_EXTICR1_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
||||
#define AFIO_EXTICR1_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
||||
#define AFIO_EXTICR1_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
||||
#define AFIO_EXTICR1_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
||||
#define AFIO_EXTICR1_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
||||
#endif
|
||||
|
||||
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
|
||||
|
|
@ -9507,7 +9389,7 @@ typedef enum
|
|||
#define OB_RST_NoEN ((uint16_t)0x0018) /* Reset IO disable (PD7)*/
|
||||
#define OB_RST_EN_DT12ms ((uint16_t)0x0010) /* Reset IO enable (PD7) and Ignore delay time 12ms */
|
||||
#define OB_RST_EN_DT1ms ((uint16_t)0x0008) /* Reset IO enable (PD7) and Ignore delay time 1ms */
|
||||
#define OB_RST_EN_DT128ms ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128ms */
|
||||
#define OB_RST_EN_DT128us ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128us */
|
||||
|
||||
#define OB_STARTMODE_BOOT ((uint16_t)0x0020) /* Start in BOOT area */
|
||||
#define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */
|
||||
|
|
@ -12586,6 +12468,349 @@ typedef volatile unsigned long *PUINT32V;
|
|||
|
||||
#endif
|
||||
|
||||
/* ch32x035_usbpd.h ----------------------------------------------------------*/
|
||||
|
||||
/* Register Bit Definition */
|
||||
/* USBPD->CONFIG */
|
||||
#define PD_FILT_ED (1<<0) /* PD pin input filter enable */
|
||||
#define PD_ALL_CLR (1<<1) /* Clear all interrupt flags */
|
||||
#if defined(CH32X03x)
|
||||
#define CC_SEL (1<<2) /* Select PD communication port */
|
||||
#define PD_DMA_EN (1<<3) /* Enable DMA for USBPD */
|
||||
#define PD_RST_EN (1<<4) /* PD mode reset command enable */
|
||||
#define WAKE_POLAR (1<<5) /* PD port wake-up level */
|
||||
#elif defined(CH641)
|
||||
#define CC_ALL_SEL (3<<2) /* Select PD communication port ALL*/
|
||||
#define CC_SEL_Mask (3<<2) /* Clear PD communication port */
|
||||
#define CC_SEL_1 (0<<2) /* Select PD communication port1 */
|
||||
#define CC_SEL_2 (1<<2) /* Select PD communication port2 */
|
||||
#define CC_SEL_3 (2<<2) /* Select PD communication port3 */
|
||||
#define PD_DMA_EN (1<<4) /* Enable DMA for USBPD */
|
||||
#define PD_RST_EN (1<<5) /* PD mode reset command enable */
|
||||
#define WAKE_POLAR (1<<6) /* PD port wake-up level */
|
||||
#endif
|
||||
#define IE_PD_IO (1<<10) /* PD IO interrupt enable */
|
||||
#define IE_RX_BIT (1<<11) /* Receive bit interrupt enable */
|
||||
#define IE_RX_BYTE (1<<12) /* Receive byte interrupt enable */
|
||||
#define IE_RX_ACT (1<<13) /* Receive completion interrupt enable */
|
||||
#define IE_RX_RESET (1<<14) /* Reset interrupt enable */
|
||||
#define IE_TX_END (1<<15) /* Transfer completion interrupt enable */
|
||||
|
||||
/* USBPD->CONTROL */
|
||||
#define PD_TX_EN (1<<0) /* USBPD transceiver mode and transmit enable */
|
||||
#define BMC_START (1<<1) /* BMC send start signal */
|
||||
#define RX_STATE_0 (1<<2) /* PD received state bit 0 */
|
||||
#define RX_STATE_1 (1<<3) /* PD received state bit 1 */
|
||||
#define RX_STATE_2 (1<<4) /* PD received state bit 2 */
|
||||
#define DATA_FLAG (1<<5) /* Cache data valid flag bit */
|
||||
#define TX_BIT_BACK (1<<6) /* Indicates the current bit status of the BMC when sending the code */
|
||||
#define BMC_BYTE_HI (1<<7) /* Indicates the current half-byte status of the PD data being sent and received */
|
||||
|
||||
/* USBPD->TX_SEL */
|
||||
#define TX_SEL1 (0<<0)
|
||||
#define TX_SEL1_SYNC1 (0<<0) /* 0-SYNC1 */
|
||||
#define TX_SEL1_RST1 (1<<0) /* 1-RST1 */
|
||||
#define TX_SEL2_Mask (3<<2)
|
||||
#define TX_SEL2_SYNC1 (0<<2) /* 00-SYNC1 */
|
||||
#define TX_SEL2_SYNC3 (1<<2) /* 01-SYNC3 */
|
||||
#define TX_SEL2_RST1 (2<<2) /* 1x-RST1 */
|
||||
#define TX_SEL3_Mask (3<<4)
|
||||
#define TX_SEL3_SYNC1 (0<<4) /* 00-SYNC1 */
|
||||
#define TX_SEL3_SYNC3 (1<<4) /* 01-SYNC3 */
|
||||
#define TX_SEL3_RST1 (2<<4) /* 1x-RST1 */
|
||||
#define TX_SEL4_Mask (3<<6)
|
||||
#define TX_SEL4_SYNC2 (0<<6) /* 00-SYNC2 */
|
||||
#define TX_SEL4_SYNC3 (1<<6) /* 01-SYNC3 */
|
||||
#define TX_SEL4_RST2 (2<<6) /* 1x-RST2 */
|
||||
|
||||
/* USBPD->STATUS */
|
||||
#define BMC_AUX_Mask (3<<0) /* Clear BMC auxiliary information */
|
||||
#define BMC_AUX_INVALID (0<<0) /* 00-Invalid */
|
||||
#define BMC_AUX_SOP0 (1<<0) /* 01-SOP0 */
|
||||
#define BMC_AUX_SOP1_HRST (2<<0) /* 10-SOP1 hard reset */
|
||||
#define BMC_AUX_SOP2_CRST (3<<0) /* 11-SOP2 cable reset */
|
||||
#define BUF_ERR (1<<2) /* BUFFER or DMA error interrupt flag */
|
||||
#define IF_RX_BIT (1<<3) /* Receive bit or 5bit interrupt flag */
|
||||
#define IF_RX_BYTE (1<<4) /* Receive byte or SOP interrupt flag */
|
||||
#define IF_RX_ACT (1<<5) /* Receive completion interrupt flag */
|
||||
#define IF_RX_RESET (1<<6) /* Receive reset interrupt flag */
|
||||
#define IF_TX_END (1<<7) /* Transfer completion interrupt flag */
|
||||
|
||||
/* USBPD->PORT_CC1 */
|
||||
/* USBPD->PORT_CC2 */
|
||||
#if defined(CH641)
|
||||
/* USBPD->PORT_CC3 */
|
||||
#define CC_CMPO (1<<0) /* CC port comparator analog input */
|
||||
#elif defined(CH32X03x)
|
||||
#define PA_CC_AI (1<<0) /* CC port comparator analogue input */
|
||||
#endif
|
||||
#define CC_PD (1<<1) /* CC port pull-down resistor enable */
|
||||
#define CC_PU_Mask (3<<2) /* Clear CC port pull-up current */
|
||||
#define CC_NO_PU (0<<2) /* 00-Prohibit pull-up current */
|
||||
#define CC_PU_330 (1<<2) /* 01-330uA */
|
||||
#define CC_PU_180 (2<<2) /* 10-180uA */
|
||||
#define CC_PU_80 (3<<2) /* 11-80uA */
|
||||
#define CC_LVE (1<<4) /* CC port output low voltage enable */
|
||||
#if defined(CH32X03x)
|
||||
#define CC_CMP_Mask (7<<5) /* Clear CC_CMP*/
|
||||
#define CC_NO_CMP (0<<5) /* 000-closed */
|
||||
#define CC_CMP_22 (2<<5) /* 010-0.22V */
|
||||
#define CC_CMP_45 (3<<5) /* 011-0.45V */
|
||||
#define CC_CMP_55 (4<<5) /* 100-0.55V */
|
||||
#define CC_CMP_66 (5<<5) /* 101-0.66V */
|
||||
#define CC_CMP_95 (6<<5) /* 110-0.95V */
|
||||
#define CC_CMP_123 (7<<5) /* 111-1.23V */
|
||||
#define USBPD_IN_HVT (1<<9)
|
||||
#elif defined(CH641)
|
||||
#define CC_CVS_Mask (3<<5) /* clear CC_CVS*/
|
||||
#define CC_CVS_55 (0<<5) /* 00-0.55V */
|
||||
#define CC_CVS_22 (1<<5) /* 01-0.22V */
|
||||
#define CC_CVS_66 (2<<5) /* 10-0.66V */
|
||||
#define CC_CVS_123 (3<<5) /* 11-1.23V */
|
||||
#define CC_CE (1<<7) /* Enable the voltage comparator on port CC */
|
||||
#endif
|
||||
|
||||
#if defined(CH32X03x)
|
||||
|
||||
/*********************************************************
|
||||
* PD pin PC14/PC15 high threshold input mode:
|
||||
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||
* 0-Normal GPIO threshold input
|
||||
* *******************************************************/
|
||||
#define USBPD_PHY_V33 (1<<8)
|
||||
/**********************************************************
|
||||
* PD transceiver PHY pull-up limit configuration bits:
|
||||
* 1-Direct use of VDD for GPIO applications or PD applications with VDD voltage of 3.3V
|
||||
* 0-LDO buck enabled, limited to approx 3.3V, for PD applications with VDD more than 4V
|
||||
* ********************************************************/
|
||||
|
||||
#elif defined(CH641)
|
||||
|
||||
/*********************************************************
|
||||
* PD pin PB0/PB1/PB9 high threshold input mode:
|
||||
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||
* 0-Normal GPIO threshold input
|
||||
* *******************************************************/
|
||||
#define USBPD_HVT (1<<19)
|
||||
|
||||
#endif
|
||||
|
||||
/* Control Message Types */
|
||||
#define DEF_TYPE_RESERVED 0x00
|
||||
#define DEF_TYPE_GOODCRC 0x01 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_GOTOMIN 0x02 /* Send By: Source */
|
||||
#define DEF_TYPE_ACCEPT 0x03 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_REJECT 0x04 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_PING 0x05 /* Send By: Source */
|
||||
#define DEF_TYPE_PS_RDY 0x06 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_SRC_CAP 0x07 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_SNK_CAP 0x08 /* Send By: Source,DRP */
|
||||
#define DEF_TYPE_DR_SWAP 0x09 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_PR_SWAP 0x0A /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_VCONN_SWAP 0x0B /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_WAIT 0x0C /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_SOFT_RESET 0x0D /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_DATA_RESET 0x0E /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_DATA_RESET_CMP 0x0F /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_NOT_SUPPORT 0x10 /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_GET_SRC_CAP_EX 0x11 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_STATUS 0x12 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_STATUS_R 0X02 /* ext=1 */
|
||||
#define DEF_TYPE_FR_SWAP 0x13 /* Send By: Sink */
|
||||
#define DEF_TYPE_GET_PPS_STATUS 0x14 /* Send By: Sink */
|
||||
#define DEF_TYPE_GET_CTY_CODES 0x15 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_SNK_CAP_EX 0x16 /* Send By: Source,DRP */
|
||||
#define DEF_TYPE_GET_SRC_INFO 0x17 /* Send By: Sink,DRP */
|
||||
#define DEF_TYPE_GET_REVISION 0x18 /* Send By: Source,Sink */
|
||||
|
||||
/* Data Message Types */
|
||||
#define DEF_TYPE_SRC_CAP 0x01 /* Send By: Source,Dual-Role Power */
|
||||
#define DEF_TYPE_REQUEST 0x02 /* Send By: Sink */
|
||||
#define DEF_TYPE_BIST 0x03 /* Send By: Tester,Source,Sink */
|
||||
#define DEF_TYPE_SNK_CAP 0x04 /* Send By: Sink,Dual-Role Power */
|
||||
#define DEF_TYPE_BAT_STATUS 0x05 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_ALERT 0x06 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_GET_CTY_INFO 0x07 /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_ENTER_USB 0x08 /* Send By: DFP */
|
||||
#define DEF_TYPE_EPR_REQUEST 0x09 /* Send By: Sink */
|
||||
#define DEF_TYPE_EPR_MODE 0x0A /* Send By: Source,Sink */
|
||||
#define DEF_TYPE_SRC_INFO 0x0B /* Send By: Source */
|
||||
#define DEF_TYPE_REVISION 0x0C /* Send By: Source,Sink,Cable Plug */
|
||||
#define DEF_TYPE_VENDOR_DEFINED 0x0F /* Send By: Source,Sink,Cable Plug */
|
||||
|
||||
/* Vendor Define Message Command */
|
||||
#define DEF_VDM_DISC_IDENT 0x01
|
||||
#define DEF_VDM_DISC_SVID 0x02
|
||||
#define DEF_VDM_DISC_MODE 0x03
|
||||
#define DEF_VDM_ENTER_MODE 0x04
|
||||
#define DEF_VDM_EXIT_MODE 0x05
|
||||
#define DEF_VDM_ATTENTION 0x06
|
||||
#define DEF_VDM_DP_S_UPDATE 0x10
|
||||
#define DEF_VDM_DP_CONFIG 0x11
|
||||
|
||||
/* PD Revision */
|
||||
#define DEF_PD_REVISION_10 0x00
|
||||
#define DEF_PD_REVISION_20 0x01
|
||||
#define DEF_PD_REVISION_30 0x02
|
||||
|
||||
|
||||
/* PD PHY Channel */
|
||||
#if defined(CH32X03x)
|
||||
|
||||
#define DEF_PD_CC1 0x00
|
||||
#define DEF_PD_CC2 0x01
|
||||
|
||||
#define PIN_CC1 GPIO_Pin_14
|
||||
#define PIN_CC2 GPIO_Pin_15
|
||||
|
||||
#elif defined(CH641)
|
||||
#define PIN_CC1 GPIO_Pin_0
|
||||
#define PIN_CC2 GPIO_Pin_1
|
||||
#define PIN_CC3 GPIO_Pin_9
|
||||
#endif
|
||||
|
||||
/* PD Tx Status */
|
||||
#define DEF_PD_TX_OK 0x00
|
||||
#define DEF_PD_TX_FAIL 0x01
|
||||
|
||||
/* PDO INDEX */
|
||||
#define PDO_INDEX_1 1
|
||||
#define PDO_INDEX_2 2
|
||||
#define PDO_INDEX_3 3
|
||||
#define PDO_INDEX_4 4
|
||||
#define PDO_INDEX_5 5
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define UPD_TMR_TX_48M (80-1) /* timer value for USB PD BMC transmittal @Fsys=48MHz */
|
||||
#define UPD_TMR_RX_48M (120-1) /* timer value for USB PD BMC receiving @Fsys=48MHz */
|
||||
#define UPD_TMR_TX_24M (40-1) /* timer value for USB PD BMC transmittal @Fsys=24MHz */
|
||||
#define UPD_TMR_RX_24M (60-1) /* timer value for USB PD BMC receiving @Fsys=24MHz */
|
||||
#define UPD_TMR_TX_12M (20-1) /* timer value for USB PD BMC transmittal @Fsys=12MHz */
|
||||
#define UPD_TMR_RX_12M (30-1) /* timer value for USB PD BMC receiving @Fsys=12MHz */
|
||||
|
||||
#define MASK_PD_STAT 0x03 /* Bit mask for current PD status */
|
||||
#define PD_RX_SOP0 0x01 /* SOP0 received */
|
||||
#define PD_RX_SOP1_HRST 0x02 /* SOP1 or Hard Reset received */
|
||||
#define PD_RX_SOP2_CRST 0x03 /* SOP2 or Cable Reset received */
|
||||
|
||||
#define UPD_SOP0 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC1 | TX_SEL4_SYNC2 ) /* SOP1 */
|
||||
#define UPD_SOP1 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC3 | TX_SEL4_SYNC3 ) /* SOP2 */
|
||||
#define UPD_SOP2 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC3 | TX_SEL3_SYNC1 | TX_SEL4_SYNC3 ) /* SOP3 */
|
||||
#define UPD_HARD_RESET ( TX_SEL1_RST1 | TX_SEL2_RST1 | TX_SEL3_RST1 | TX_SEL4_RST2 ) /* Hard Reset*/
|
||||
#define UPD_CABLE_RESET ( TX_SEL1_RST1 | TX_SEL2_SYNC1 | TX_SEL3_RST1 | TX_SEL4_SYNC3 ) /* Cable Reset*/
|
||||
|
||||
|
||||
#define bCC_CMP_22 0X01
|
||||
#define bCC_CMP_45 0X02
|
||||
#define bCC_CMP_55 0X04
|
||||
#define bCC_CMP_66 0X08
|
||||
#define bCC_CMP_95 0X10
|
||||
#define bCC_CMP_123 0X20
|
||||
#define bCC_CMP_220 0X40
|
||||
|
||||
/******************************************************************************/
|
||||
/* PD State Machine */
|
||||
typedef enum
|
||||
{
|
||||
STA_IDLE = 0, /* 0: No task status */
|
||||
STA_DISCONNECT, /* 1: Disconnection */
|
||||
STA_SRC_CONNECT, /* 2: SRC connect */
|
||||
STA_RX_SRC_CAP_WAIT, /* 3: Waiting to receive SRC_CAP */
|
||||
STA_RX_SRC_CAP, /* 4: SRC_CAP received */
|
||||
STA_TX_REQ, /* 5: Send REQUEST */
|
||||
STA_RX_ACCEPT_WAIT, /* 6: Waiting to receive ACCEPT */
|
||||
STA_RX_ACCEPT, /* 7: ACCEPT received */
|
||||
STA_RX_REJECT, /* 8: REJECT received */
|
||||
STA_RX_PS_RDY_WAIT, /* 9: Waiting to receive PS_RDY */
|
||||
STA_RX_PS_RDY, /* 10: PS_RDY received */
|
||||
STA_SINK_CONNECT, /* 11: SNK access */
|
||||
STA_TX_SRC_CAP, /* 12: Send SRC_CAP */
|
||||
STA_RX_REQ_WAIT, /* 13: Waiting to receive REQUEST */
|
||||
STA_RX_REQ, /* 14: REQUEST received */
|
||||
STA_TX_ACCEPT, /* 15: Send ACCEPT */
|
||||
STA_TX_REJECT, /* 16: Send REJECT */
|
||||
STA_ADJ_VOL, /* 17: Adjustment of output voltage and current */
|
||||
STA_TX_PS_RDY, /* 18: Send PS_RDY */
|
||||
STA_TX_DR_SWAP, /* 19: Send DR_SWAP */
|
||||
STA_RX_DR_SWAP_ACCEPT, /* 20: Waiting to receive the answer ACCEPT from DR_SWAP */
|
||||
STA_TX_PR_SWAP, /* 21: Send PR_SWAP */
|
||||
STA_RX_PR_SWAP_ACCEPT, /* 22: Waiting to receive the answer ACCEPT from PR_SWAP */
|
||||
STA_RX_PR_SWAP_PS_RDY, /* 23: Waiting to receive the answer PS_RDY from PR_SWAP */
|
||||
STA_TX_PR_SWAP_PS_RDY, /* 24: Send answer PS_RDY for PR_SWAP */
|
||||
STA_PR_SWAP_RECON_WAIT, /* 25: Wait for PR_SWAP before reconnecting */
|
||||
STA_SRC_RECON_WAIT, /* 26: Waiting for SRC to reconnect */
|
||||
STA_SINK_RECON_WAIT, /* 27: Waiting for SNK to reconnect */
|
||||
STA_RX_APD_PS_RDY_WAIT, /* 28: Waiting for PS_RDY from the receiving adapter */
|
||||
STA_RX_APD_PS_RDY, /* 29: PS_RDY received from the adapter */
|
||||
STA_MODE_SWITCH, /* 30: Mode switching */
|
||||
STA_TX_SOFTRST, /* 31: Sending a software reset */
|
||||
STA_TX_HRST, /* 32: Send hardware reset */
|
||||
STA_PHY_RST, /* 33: PHY reset */
|
||||
STA_APD_IDLE_WAIT, /* 34: Waiting for the adapter to become idle */
|
||||
} CC_STATUS;
|
||||
|
||||
/******************************************************************************/
|
||||
/* PD Message Header Struct */
|
||||
typedef union
|
||||
{
|
||||
struct _Message_Header
|
||||
{
|
||||
UINT8 MsgType: 5; /* Message Type */
|
||||
UINT8 PDRole: 1; /* 0-UFP; 1-DFP */
|
||||
UINT8 SpecRev: 2; /* 00-Rev1.0; 01-Rev2.0; 10-Rev3.0; */
|
||||
UINT8 PRRole: 1; /* 0-Sink; 1-Source */
|
||||
UINT8 MsgID: 3;
|
||||
UINT8 NumDO: 3;
|
||||
UINT8 Ext: 1;
|
||||
}Message_Header;
|
||||
UINT16 Data;
|
||||
}_Message_Header;
|
||||
|
||||
/******************************************************************************/
|
||||
/* Bit definition */
|
||||
typedef union
|
||||
{
|
||||
struct _BITS_
|
||||
{
|
||||
UINT8 Msg_Recvd: 1; /* Notify the main program of the receipt of a PD packet */
|
||||
UINT8 Connected: 1; /* PD Physical Layer Connected Flag */
|
||||
UINT8 Stop_Det_Chk: 1; /* 0-Enable detection; 1-Disable disconnection detection */
|
||||
UINT8 PD_Role: 1; /* 0-UFP; 1-DFP */
|
||||
UINT8 PR_Role: 1; /* 0-Sink; 1-Source */
|
||||
UINT8 Auto_Ack_PRRole: 1; /* Role used by auto-responder 0:SINK; 1:SOURCE */
|
||||
UINT8 PD_Version: 1; /* PD version 0-PD2.0; 1-PD3.0 */
|
||||
UINT8 VDM_Version: 1; /* VDM Version 0-1.0 1-2.0 */
|
||||
UINT8 HPD_Connected: 1; /* HPD Physical Layer Connected Flag */
|
||||
UINT8 HPD_Det_Chk: 1; /* 0-turn off HPD connection detection; 1-turn on HPD connection detection */
|
||||
UINT8 CC_Sel_En: 1; /* 0-CC channel selection toggle enable; 1-CC channel selection toggle disable */
|
||||
UINT8 CC_Sel_State: 1; /* 0-CC channel selection switches to 0; 1-CC channel selection switches to 1 */
|
||||
UINT8 PD_Comm_Succ: 1; /* 0-PD communication unsuccessful; 1-PD communication successful; */
|
||||
UINT8 Recv: 3;
|
||||
}Bit;
|
||||
UINT16 Bit_Flag;
|
||||
}_BIT_FLAG;
|
||||
|
||||
/* PD control-related structures */
|
||||
typedef struct _PD_CONTROL
|
||||
{
|
||||
CC_STATUS PD_State; /* PD communication status machine */
|
||||
CC_STATUS PD_State_Last; /* PD communication status machine (last value) */
|
||||
UINT8 Msg_ID; /* ID of the message sent */
|
||||
UINT8 Det_Timer; /* PD connection status detection timing */
|
||||
UINT8 Det_Cnt; /* Number of PD connection status detections */
|
||||
UINT8 Det_Sel_Cnt; /* Number of SEL toggles for PD connection status detection */
|
||||
UINT8 HPD_Det_Timer; /* HPD connection detection timing */
|
||||
UINT8 HPD_Det_Cnt; /* HPD pin connection status detection count */
|
||||
UINT16 PD_Comm_Timer; /* PD shared timing variables */
|
||||
UINT8 ReqPDO_Idx; /* Index of the requested PDO, valid values 1-7 */
|
||||
UINT16 PD_BusIdle_Timer; /* Bus Idle Time Timer */
|
||||
UINT8 Mode_Try_Cnt; /* Number of retries for current mode, highest bit marks mode */
|
||||
UINT8 Err_Op_Cnt; /* Exception operation count */
|
||||
UINT8 Adapter_Idle_Cnt; /* Adapter communication idle timing */
|
||||
_BIT_FLAG Flag; /* Flag byte bit definition */
|
||||
}PD_CONTROL, *pPD_CONTROL;
|
||||
|
||||
/* ch32v00x_wwdg.h -----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,244 +1,226 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char *yes[] = {"SENTINEL_WILL_BE_REPLACED_BY_CMDLINE"}; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char *no[] = {"CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003"};
|
||||
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||
|
||||
char *WhitePull(const char **sti)
|
||||
char * WhitePull( const char ** sti )
|
||||
{
|
||||
const char *st = *sti;
|
||||
int len = 0;
|
||||
while ((*st == ' ' || *st == '\t' || *st == '(') && *st)
|
||||
{
|
||||
st++;
|
||||
}
|
||||
const char *sts = st;
|
||||
while (*st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0)
|
||||
{
|
||||
st++;
|
||||
len++;
|
||||
}
|
||||
if (*st == ')') { st++; }
|
||||
char *ret = malloc(len + 1);
|
||||
memcpy(ret, sts, len);
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
const char * st = *sti;
|
||||
int len = 0;
|
||||
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||
const char * sts = st;
|
||||
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||
if( *st == ')' ) { st++; }
|
||||
char * ret = malloc( len + 1 );
|
||||
memcpy( ret, sts, len );
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NYI(const char *s)
|
||||
int NYI( const char * s )
|
||||
{
|
||||
int ret = 2;
|
||||
char *wp = WhitePull(&s);
|
||||
int i;
|
||||
for (i = 0; i < sizeof(yes) / sizeof(yes[0]); i++)
|
||||
if (strcmp(yes[i], wp) == 0) ret = 1;
|
||||
if (ret != 1)
|
||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
||||
if (strcmp(no[i], wp) == 0) ret = 0;
|
||||
free(wp);
|
||||
return ret;
|
||||
int ret = 2;
|
||||
char * wp = WhitePull( &s );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
|
||||
if( strcmp( yes[i], wp ) == 0 ) ret = 1;
|
||||
if( ret != 1 )
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
if( strcmp( no[i], wp ) == 0 ) ret = 0;
|
||||
free( wp );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EvalSpec(const char *spl)
|
||||
int EvalSpec( const char * spl )
|
||||
{
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
cont:
|
||||
char *wp = WhitePull(&spl);
|
||||
int def = -1;
|
||||
if (strcmp(wp, "defined") == 0) def = 1;
|
||||
if (strcmp(wp, "!defined") == 0) def = 2;
|
||||
if (def < 0) return 2;
|
||||
char *wpn = WhitePull(&spl);
|
||||
i = NYI(wpn);
|
||||
// printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if (i == 2) return 2;
|
||||
char * wp = WhitePull( &spl );
|
||||
int def = -1;
|
||||
if( strcmp( wp, "defined" ) == 0 ) def = 1;
|
||||
if( strcmp( wp, "!defined" ) == 0 ) def = 2;
|
||||
if( def < 0 ) return 2;
|
||||
char * wpn = WhitePull( &spl );
|
||||
i = NYI( wpn );
|
||||
//printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if( i == 2 ) return 2;
|
||||
|
||||
if (def == 2) i = !i;
|
||||
if( def == 2 ) i = !i;
|
||||
|
||||
if (lasto == 1)
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if (lasto == 2)
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
if( lasto == 1 )
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if( lasto == 2 )
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
|
||||
char *wpa = WhitePull(&spl);
|
||||
// printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
// printf( "RET: %d\n", ret );
|
||||
if (strcmp(wpa, "||") == 0)
|
||||
{
|
||||
lasto = 1;
|
||||
goto cont;
|
||||
}
|
||||
else if (strcmp(wpa, "&&") == 0)
|
||||
{
|
||||
lasto = 2;
|
||||
goto cont;
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
char * wpa = WhitePull( &spl );
|
||||
//printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
//printf( "RET: %d\n", ret );
|
||||
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||
else return ret;
|
||||
}
|
||||
|
||||
// 0 for no
|
||||
// 1 for yes
|
||||
// 2 for indeterminate
|
||||
int NoYesInd(const char *preprocc)
|
||||
int NoYesInd( const char * preprocc )
|
||||
{
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if (strncmp(preprocc, "#if ", 4) == 0) ofs = 4;
|
||||
if (strncmp(preprocc, "#elif ", 6) == 0) ofs = 6;
|
||||
if (ofs)
|
||||
{
|
||||
ret = EvalSpec(preprocc + ofs);
|
||||
// printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if (strncmp(preprocc, "#ifdef ", 7) == 0)
|
||||
{
|
||||
const char *ep = preprocc + 6;
|
||||
char *wp = WhitePull(&ep);
|
||||
ret = NYI(wp);
|
||||
free(wp);
|
||||
}
|
||||
else if (strncmp(preprocc, "#ifndef ", 8) == 0)
|
||||
{
|
||||
const char *ep = preprocc + 6;
|
||||
char *wp = WhitePull(&ep);
|
||||
ret = NYI(wp);
|
||||
if (ret < 2) ret = !ret;
|
||||
free(wp);
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
// printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
|
||||
if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
|
||||
if( ofs )
|
||||
{
|
||||
ret = EvalSpec( preprocc + ofs );
|
||||
//printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
free( wp );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
if( ret < 2 ) ret = !ret;
|
||||
free( wp );
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
//printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *sslineis(const char *line, const char *match)
|
||||
const char * sslineis( const char * line, const char * match )
|
||||
{
|
||||
while (*line == ' ' || *line == '\t')
|
||||
line++;
|
||||
const char *linestart = line;
|
||||
while (*line && *match == *line)
|
||||
{
|
||||
line++;
|
||||
match++;
|
||||
}
|
||||
if (*match == 0)
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
while( *line == ' ' || *line == '\t' ) line++;
|
||||
const char * linestart = line;
|
||||
while( *line && *match == *line ) { line++; match++; }
|
||||
if( *match == 0 )
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n");
|
||||
int i;
|
||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
||||
{
|
||||
fprintf(stderr, "\t%s\n", no[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if( argc != 3 )
|
||||
{
|
||||
fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
{
|
||||
fprintf( stderr, "\t%s\n", no[i] );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
yes[0] = argv[1];
|
||||
yes[0] = argv[1];
|
||||
|
||||
FILE *f = fopen(argv[2], "r");
|
||||
if (!f)
|
||||
{
|
||||
fprintf(stderr, "Error: Could not open \"%s\"\n", argv[2]);
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char *l;
|
||||
FILE * f = fopen( argv[2], "r" );
|
||||
if( !f )
|
||||
{
|
||||
fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char * l;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
// 0 = no
|
||||
// 1 = yes
|
||||
// 2 = indeterminate
|
||||
// 3 = super no. (I.e. after a true #if clause)
|
||||
int yesnoind[1024];
|
||||
yesnoind[0] = 1;
|
||||
int depth = 0;
|
||||
|
||||
while (l = fgets(line, sizeof(line) - 1, f))
|
||||
{
|
||||
const char *ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
// 0 = no
|
||||
// 1 = yes
|
||||
// 2 = indeterminate
|
||||
// 3 = super no. (I.e. after a true #if clause)
|
||||
int yesnoind[1024];
|
||||
yesnoind[0] = 1;
|
||||
|
||||
if ((ss = sslineis(line, "#if ")) || (ss = sslineis(line, "#ifdef ")) || (ss = sslineis(line, "#ifndef ")))
|
||||
{
|
||||
waspre = 1;
|
||||
// printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd(ss);
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if ((ss = sslineis(line, "#elif ")))
|
||||
{
|
||||
if (nyi != 2)
|
||||
{
|
||||
waspre = 1;
|
||||
if (nyi == 1)
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd(ss);
|
||||
}
|
||||
// printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if ((ss = sslineis(line, "#else")))
|
||||
{
|
||||
if (nyi != 2)
|
||||
{
|
||||
waspre = 1;
|
||||
if (yesnoind[depth] == 1)
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if ((ss = sslineis(line, "#endif")))
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if (depth < 0)
|
||||
{
|
||||
fprintf(stderr, "UNTERMD IF\n");
|
||||
}
|
||||
}
|
||||
while( l = fgets( line, sizeof(line)-1, f ) )
|
||||
{
|
||||
const char * ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for (i = 0; i <= depth; i++)
|
||||
{
|
||||
// printf( "%d", yesnoind[i] );
|
||||
if (yesnoind[i] == 0 || yesnoind[i] == 3) thisv = 0;
|
||||
}
|
||||
// printf( ">>%s", l );
|
||||
if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
//printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd( ss );
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if( (ss = sslineis( line, "#elif " ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( nyi == 1 )
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd( ss );
|
||||
}
|
||||
//printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#else" ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( yesnoind[depth] == 1 )
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#endif" ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if( depth < 0 )
|
||||
{
|
||||
fprintf( stderr, "UNTERMD IF\n" );
|
||||
}
|
||||
}
|
||||
|
||||
if (thisv != 0 && thisv != 3 && (thisv != 1 || !waspre))
|
||||
{
|
||||
printf("%s", l);
|
||||
}
|
||||
}
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for( i = 0; i <= depth; i++ )
|
||||
{
|
||||
//printf( "%d", yesnoind[i] );
|
||||
if( yesnoind[i] == 0 || yesnoind[i] == 3 ) thisv = 0;
|
||||
}
|
||||
//printf( ">>%s", l );
|
||||
|
||||
if( thisv != 0 && thisv != 3 && ( thisv != 1 || !waspre ) )
|
||||
{
|
||||
printf( "%s", l );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
11
inc/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
11
inc/misc/drivers_for_WCH-LinkE/R0-1v3/README.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
This only works for the WCH LinkE in RISC-V mode. If your programmer has the BLUE light ON shortly after boot your programmer is in ARM mode.
|
||||
|
||||
Please follow instructions here to convert your programmer to RISC-V mode from ARM mode.
|
||||
|
||||
Basically press-and-hold the ModeS button while plugging in the USB.
|
||||
|
||||
Once powered, it will store that to default.
|
||||
|
||||
The blue light should be OFF.
|
||||
|
||||
Once you are in RISC-V mode, you can install this driver by right-clicking on the driver and saying install.
|
||||
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).cat
Normal file
Binary file not shown.
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
BIN
inc/misc/drivers_for_WCH-LinkE/R0-1v3/WCH-Link_(Interface_0).inf
Normal file
Binary file not shown.
44121
inc/misc/dumped_libgcc.S
44121
inc/misc/dumped_libgcc.S
File diff suppressed because it is too large
Load diff
190
inc/misc/install_xpack_gcc.ps1
Normal file
190
inc/misc/install_xpack_gcc.ps1
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
using namespace System.IO;
|
||||
using namespace System.IO.Compression.FileSystem;
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = 'DestPreset')]
|
||||
param (
|
||||
# Uses one of the preset locations to install to
|
||||
[Parameter(ParameterSetName = 'DestPreset', Position = 0)]
|
||||
[ValidateSet('User', 'System')]
|
||||
[string]$Destination = 'User',
|
||||
|
||||
# If a preset location is not used, then the user must specify a path to install to
|
||||
[Parameter(ParameterSetName = 'DestPath', Position = 0, Mandatory = $true)]
|
||||
[string]$Path,
|
||||
|
||||
# If enabled, will prevent modification of your PATH environment variable
|
||||
[switch]$NoPath,
|
||||
|
||||
# If enabled, will not install our make
|
||||
[switch]$NoMake,
|
||||
|
||||
# Skips all prompts and just installs, mainly intended for use if we need to re-run as admin.
|
||||
[switch]$SkipPrompts
|
||||
);
|
||||
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
[string] $XpackVersion = '14.2.0-3';
|
||||
[string] $XpackEdition = 'riscv-none-elf-gcc';
|
||||
[string] $XpackArch = 'win32-x64';
|
||||
[string] $XpackNameEd = "xpack-$XpackEdition";
|
||||
[string] $XpackNameEdVer = "$XpackNameEd-$XpackVersion";
|
||||
[string] $XpackNameEdVerArch = "$XpackNameEdVer-$XpackArch"
|
||||
[string] $XpackDownloadFilename = "$XpackNameEdVerArch.zip";
|
||||
[string] $XpackDownloadURL = "https://github.com/xpack-dev-tools/$XpackEdition-xpack/releases/download/v$XpackVersion/$XpackDownloadFilename";
|
||||
|
||||
[string] $MakeVersion = '4.4.1';
|
||||
[string] $MakeEdition = 'without-guile';
|
||||
[string] $MakeArch = 'w32';
|
||||
[string] $MakeName = "make-$MakeVersion-$MakeEdition"
|
||||
[string] $MakeNameFull = "$MakeName-$MakeArch";
|
||||
[string] $MakeDownloadFilename = "$MakeNameFull-bin.zip";
|
||||
[string] $MakeDownloadURL = "https://sourceforge.net/projects/ezwinports/files/$MakeDownloadFilename/download";
|
||||
|
||||
[EnvironmentVariableTarget] $PathScope = [EnvironmentVariableTarget]::User;
|
||||
[string] $TempFolder = [Path]::GetTempPath();
|
||||
[bool] $NoClearTemp = $false;
|
||||
|
||||
if ($PSCmdlet.ParameterSetName -EQ 'DestPreset')
|
||||
{
|
||||
if ($Destination -EQ 'User') { $Path = Join-Path $ENV:LocalAppData $XpackNameEd; }
|
||||
elseif ($Destination -EQ 'System')
|
||||
{
|
||||
$Path = Join-Path $ENV:ProgramFiles $XpackNameEd;
|
||||
$PathScope = [EnvironmentVariableTarget]::Machine;
|
||||
}
|
||||
else { throw 'Unknown Preset Destination'; }
|
||||
}
|
||||
if ([string]::IsNullOrEmpty($Path)) { throw 'Destination path must be provided'; }
|
||||
|
||||
[string] $TempFolder = Join-Path $TempFolder 'ch32fun';
|
||||
[string] $XpackDownloadFilePath = Join-Path $TempFolder $XpackDownloadFilename;
|
||||
[string] $XpackPath = Join-Path $Path $XpackVersion;
|
||||
[string] $XpackBinPath = Join-Path $XpackPath 'bin';
|
||||
[string] $MakeDownloadFilePath = Join-Path $TempFolder $MakeDownloadFilename;
|
||||
|
||||
Write-Host "${XpackNameEdVer}:";
|
||||
Write-Host " will be downloaded from " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackDownloadURL -ForegroundColor 'DarkGreen';
|
||||
Write-Host " to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackDownloadFilePath -ForegroundColor 'DarkGreen';
|
||||
Write-Host " then installed to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackPath -ForegroundColor 'DarkGreen';
|
||||
Write-Host;
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
Write-Host "${MakeName}:"
|
||||
Write-Host " will be downloaded from " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $MakeDownloadURL -ForegroundColor 'DarkGreen';
|
||||
Write-Host " to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $MakeDownloadFilePath -ForegroundColor 'DarkGreen';
|
||||
Write-Host " then installed to " -NoNewline -ForegroundColor 'DarkGray';
|
||||
Write-Host $XpackBinPath -ForegroundColor 'DarkGreen';
|
||||
Write-Host;
|
||||
}
|
||||
if ($NoPath) { Write-Host "Your environment variables will not be edited.`n"; }
|
||||
else
|
||||
{
|
||||
Write-Host "xpack will be added to your " -NoNewline;
|
||||
Write-Host $PathScope.ToString().ToLower() -ForegroundColor 'DarkGreen' -NoNewline;
|
||||
Write-Host " PATH environment variable.`n";
|
||||
}
|
||||
if (-NOT $SkipPrompts)
|
||||
{
|
||||
[string] $Answer = Read-Host -Prompt "Is this correct? (y/n)";
|
||||
if ($Answer -NE 'y') { Exit; }
|
||||
}
|
||||
|
||||
try
|
||||
{ # Check if we need elevation
|
||||
[bool] $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator');
|
||||
if ((-NOT $NoPath) -AND ($PathScope -EQ [EnvironmentVariableTarget]::Machine) -AND (-NOT $IsAdmin)) { throw; } # If we want to set the system PATH variable, we need to elevate
|
||||
if (-NOT (Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -ErrorAction SilentlyContinue -ErrorVariable PermissionError | Out-Null; }
|
||||
if ($PermissionError) { throw; }
|
||||
[string] $TestFile = Join-Path $Path 'TestingFile.txt';
|
||||
Set-Content -Path $TestFile -Value 'Checking permissions.' -ErrorAction SilentlyContinue -ErrorVariable PermissionError;
|
||||
if ($PermissionError) { throw; }
|
||||
Remove-Item -Path $TestFile -ErrorAction SilentlyContinue -ErrorVariable PermissionError;
|
||||
if ($PermissionError) { throw; }
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Host 'Administrator permissions are required, requesting elevation...';
|
||||
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator'))
|
||||
{
|
||||
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -GE 6000)
|
||||
{
|
||||
$CommandLine = "-File `"$($MyInvocation.MyCommand.Path)`" -SkipPrompts";
|
||||
if ($PSCmdlet.ParameterSetName -EQ 'DestPreset') { $CommandLine += " -Destination `"$Destination`""; }
|
||||
else { $CommandLine += " -Path `"$Path`""; }
|
||||
if ($NoPath) { $CommandLine += ' -NoPath'; }
|
||||
if ($NoMake) { $CommandLine += ' -NoMake'; }
|
||||
try { Start-Process -FilePath 'PowerShell.exe' -Verb RunAs -ArgumentList $CommandLine; }
|
||||
catch { Write-Error 'Failed to elevate to administrator.'; Exit; }
|
||||
}
|
||||
}
|
||||
else { Write-Error 'Could not access folder, but am already administrator!'; Exit; }
|
||||
if (-NOT $NoPath) { Write-Host 'You may need to restart your terminal before changes apply.'; }
|
||||
Exit;
|
||||
}
|
||||
|
||||
[void](New-Item -Path $TempFolder -ItemType Directory -Force);
|
||||
[void](New-Item -Path $Path -ItemType Directory -Force);
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -LT 7) { $ProgressPreference = 'SilentlyContinue'; } # Showing progress makes it download very slowly on old PowerShell https://github.com/PowerShell/PowerShell/issues/2138
|
||||
|
||||
Write-Host "Downloading $XpackDownloadFilename" -NoNewline;
|
||||
try { Write-Host $(' ({0:F2} MB)...' -F ([long]::Parse((Invoke-WebRequest -UseBasicParsing -Uri $XpackDownloadURL -Method Head).Headers['Content-Length']) / (1024.0 * 1024.0))); }
|
||||
catch { Write-Host '...'; }
|
||||
Invoke-WebRequest -UseBasicParsing -Uri $XpackDownloadURL -OutFile $XpackDownloadFilePath;
|
||||
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
Write-Host "Downloading $MakeDownloadFilename...";
|
||||
Invoke-WebRequest -UseBasicParsing -UserAgent 'Wget' -Uri $MakeDownloadURL -OutFile $MakeDownloadFilePath;
|
||||
}
|
||||
|
||||
Write-Host "Extracting $XpackDownloadFilename...";
|
||||
[string] $XpackTempPath = Join-Path $TempFolder 'xpath';
|
||||
if (Test-Path $XpackTempPath) { Remove-Item -Recurse -Force $XpackTempPath; }
|
||||
Expand-Archive $XpackDownloadFilePath -DestinationPath $XpackTempPath;
|
||||
if (-NOT (Test-Path $XpackPath)) { [void](New-Item -Path $XpackPath -ItemType Directory -Force); }
|
||||
Copy-Item -Path $(Join-Path $(Join-Path $XpackTempPath $XpackNameEdVer) '*') -Destination $XpackPath -Recurse -Force;
|
||||
|
||||
if (-NOT $NoMake)
|
||||
{
|
||||
[string] $MakeTempPath = Join-Path $TempFolder 'make';
|
||||
Write-Host "Extracting $MakeDownloadFilename...";
|
||||
Expand-Archive -Force $MakeDownloadFilePath -DestinationPath $MakeTempPath;
|
||||
Move-Item -Force -Path $(Join-Path $MakeTempPath 'bin/make.exe') -Destination $XpackBinPath;
|
||||
}
|
||||
|
||||
if (-NOT $NoClearTemp)
|
||||
{
|
||||
Write-Host "Deleting $TempFolder...";
|
||||
Remove-Item $TempFolder -Force -Recurse;
|
||||
}
|
||||
|
||||
if (-NOT $NoPath)
|
||||
{
|
||||
Write-Host "Adding to $PathScope PATH environment variable...";
|
||||
$CurrentPATH = [Environment]::GetEnvironmentVariable('PATH', $PathScope);
|
||||
if ([string]::IsNullOrWhitespace($CurrentPATH)) { Write-Error 'Could not retrieve the current PATH, not editing'; Exit; }
|
||||
|
||||
if ($CurrentPATH.Contains($XpackBinPath.TrimEnd(('\', '/')))) # If the install dir is on the path, regardless of trailing slash or not
|
||||
{
|
||||
Write-Host ' It looks like this xpack installation is already in your user PATH, so it will not be edited.';
|
||||
}
|
||||
else {
|
||||
$NewPATH = "$CurrentPATH;$XpackBinPath";
|
||||
[Environment]::SetEnvironmentVariable('PATH', $NewPATH, $PathScope);
|
||||
Write-Host ' You may need to restart your terminal before you can use xpack gcc.';
|
||||
}
|
||||
# Detect GitHub Actions runner and export for future steps
|
||||
if ($env:GITHUB_ACTIONS -eq 'true') {
|
||||
Write-Host "Detected GitHub Actions runner. Prepending xPack bin to PATH for workflow steps..."
|
||||
Add-Content -Path $env:GITHUB_ENV -Value "PATH=$XpackBinPath`:$env:PATH"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host 'Finished!';
|
||||
37
inc/misc/minichlink-live/README.md
Normal file
37
inc/misc/minichlink-live/README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Minichlink live command server
|
||||
|
||||
Minichlink now supports a command server on port 4444.
|
||||
Currently, there are only two commands implemented:
|
||||
- `-s` Set/Write command
|
||||
- `-m` Read command
|
||||
|
||||
The format of these commands is the same as the command line interface commands with the same name:
|
||||
```sh
|
||||
-s [debug register] [value]
|
||||
-m [debug register]
|
||||
```
|
||||
> [!WARNING]
|
||||
> All values MUST be expressed in hexadecimal:
|
||||
```sh
|
||||
-s 0x20 0xc02a717d
|
||||
```
|
||||
|
||||
Multiple commands can be chained together, the results of the read operations will be returned as a key value pair with the key being the register address:
|
||||
```sh
|
||||
04: 1234bees5
|
||||
04: f00cac1a
|
||||
```
|
||||
|
||||
The QingKe V4 Processor manual describes how to build these commands, but there are also 4 example scripts that you can use:
|
||||
```sh
|
||||
./read.sh dma_count # reads contents of memory of `debug_count` symbol
|
||||
|
||||
./write.sh dma_count 123 # writes the value 123 at `dma_count` symbol address
|
||||
|
||||
./batch_read.sh dma_buffer # reads the contents of the symbol `dma_buffer`
|
||||
# size is deduced automatically, but can also be specified with a second argument
|
||||
|
||||
./plot.py dma_count # continuously read a value an plot it
|
||||
```
|
||||
> [!WARNING]
|
||||
> All of these scripts are examples, not tools, treat appropriately
|
||||
64
inc/misc/minichlink-live/batch_read.sh
Executable file
64
inc/misc/minichlink-live/batch_read.sh
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
COUNT=$2
|
||||
if [ -z "$SYMBOL" ]; then
|
||||
echo "Usage: $0 <symbol> [<count>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR="$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print "0x"$1}')"
|
||||
if [ -z "$COUNT" ]; then
|
||||
WORDS=$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print int(("0x"$5 + 3) / 4)}')
|
||||
else
|
||||
WORDS=$COUNT
|
||||
fi
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Reading $WORDS words from $SYMBOL@$ADDR"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
# Prelude
|
||||
commands+=" -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands+=" -s 0x21 0x9002c22e" # sw a1,4(sp); ebreak
|
||||
commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
|
||||
# Batch Read
|
||||
commands+=" -s 0x20 0x05914188" # lw a0,0(a1); add a1,a1,4
|
||||
commands+=" -s 0x21 0x90029002" # ebreak
|
||||
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x0027100b" # Abstract cmd data0->x11 and exec progbuf
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
|
||||
for i in $(seq 0 $((WORDS - 2))); do
|
||||
commands+=" -s 0x17 0x0026100a" # Abstract exec and x10->data0
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
done
|
||||
|
||||
commands+=" -s 0x17 0x0022100a" # Abstract cmd x10->data0
|
||||
# commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
|
||||
# Postlude
|
||||
commands+=" -s 0x20 0x45924502" # lw a0,0(sp); lw a1,4(sp)
|
||||
commands+=" -s 0x21 0x90026141" # add sp,sp,16; ebreak
|
||||
# commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
102
inc/misc/minichlink-live/plot.py
Executable file
102
inc/misc/minichlink-live/plot.py
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.animation import FuncAnimation
|
||||
import sys
|
||||
import subprocess
|
||||
import socket
|
||||
|
||||
|
||||
PERIOD_MS = 1000 / 30
|
||||
SAMPLES = 200
|
||||
symbol = sys.argv[1]
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
xdata, ydata = range(SAMPLES), [0] * SAMPLES
|
||||
(ln,) = plt.plot([], [])
|
||||
|
||||
# find elf in current directory
|
||||
result = subprocess.run(["find", ".", "-name", "*.elf"], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr.strip()}")
|
||||
sys.exit(1)
|
||||
|
||||
elf = result.stdout.splitlines()[0]
|
||||
print(f"Using ELF file: {elf}")
|
||||
|
||||
result = subprocess.run(
|
||||
["riscv64-unknown-elf-objdump", "-t", elf], capture_output=True, text=True
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr.strip()}")
|
||||
sys.exit(1)
|
||||
|
||||
symbol_address = -1
|
||||
for line in result.stdout.splitlines()[4:]:
|
||||
name = line.split()[-1]
|
||||
if symbol == name:
|
||||
symbol_address = int(line.split()[0], 16)
|
||||
break
|
||||
|
||||
if symbol_address == -1:
|
||||
print(f"Error: Symbol '{symbol}' not found in ELF file.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Symbol '{symbol}' found at address: {symbol_address:#x}")
|
||||
|
||||
commands = " -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
commands += " -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands += " -s 0x21 0xc432c22e" # sw a1,4(sp); sw a2,8(sp)
|
||||
commands += " -s 0x22 0xe0000637" # lui a2,0xe0000
|
||||
commands += " -s 0x23 0x0f460613" # add a2,a2,244 # e00000f4 <data0>
|
||||
commands += " -s 0x24 0x410c4208" # lw a0,0(a2); lw a1,0(a0)
|
||||
commands += " -s 0x25 0x4502c20c" # sw a1,0(a2); lw a0,0(sp)
|
||||
commands += " -s 0x26 0x46224592" # lw a1,4(sp); lw a2,8(sp)
|
||||
commands += " -s 0x27 0x90026141" # add sp,sp,16; ebreak
|
||||
|
||||
commands += f" -s 0x04 {symbol_address:#x}" # Write address 0x20000000 to DATA0
|
||||
commands += " -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
commands += " -m 0x16" # Read ABSTRACTCS
|
||||
commands += " -m 0x04" # Read DATA0
|
||||
|
||||
commands += " -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
command = commands.encode()
|
||||
|
||||
|
||||
def read_memory():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(("127.0.0.1", 4444))
|
||||
s.send(command)
|
||||
|
||||
data = s.recv(1024).decode()
|
||||
s.close()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_value():
|
||||
value = int(read_memory().splitlines()[-1].split()[-1], 16)
|
||||
print(f"Received value: {value}")
|
||||
return value
|
||||
|
||||
|
||||
def init():
|
||||
ax.set_xlim(0, SAMPLES)
|
||||
ax.set_ylim(0, 1024)
|
||||
return (ln,)
|
||||
|
||||
|
||||
def update(frame):
|
||||
global ydata
|
||||
value = get_value()
|
||||
ydata = ydata[1:] + [value]
|
||||
ln.set_data(xdata, ydata)
|
||||
return (ln,)
|
||||
|
||||
|
||||
ani = FuncAnimation(
|
||||
fig, update, frames=SAMPLES, init_func=init, blit=True, interval=PERIOD_MS
|
||||
)
|
||||
plt.show()
|
||||
43
inc/misc/minichlink-live/read.sh
Executable file
43
inc/misc/minichlink-live/read.sh
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
if [ -z "$SYMBOL" ]; then
|
||||
echo "Usage: $0 <symbol>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR=$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print "0x"$1}')
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Reading $SYMBOL@$ADDR"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
|
||||
commands+=" -s 0x20 0xc02a717d" # add sp,sp,-16; sw a0,0(sp)
|
||||
commands+=" -s 0x21 0xc432c22e" # sw a1,4(sp); sw a2,8(sp)
|
||||
commands+=" -s 0x22 0xe0000637" # lui a2,0xe0000
|
||||
commands+=" -s 0x23 0x0f460613" # add a2,a2,244 # e00000f4 <data0>
|
||||
commands+=" -s 0x24 0x410c4208" # lw a0,0(a2); lw a1,0(a0)
|
||||
commands+=" -s 0x25 0x4502c20c" # sw a1,0(a2); lw a0,0(sp)
|
||||
commands+=" -s 0x26 0x46224592" # lw a1,4(sp); lw a2,8(sp)
|
||||
commands+=" -s 0x27 0x90026141" # add sp,sp,16; ebreak
|
||||
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x00270000" # Abstact cmd exec progbuf
|
||||
commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -m 0x04" # Read DATA0
|
||||
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
41
inc/misc/minichlink-live/write.sh
Executable file
41
inc/misc/minichlink-live/write.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SYMBOL=$1
|
||||
VAL=$2
|
||||
if [ -z "$SYMBOL" ] || [ -z "$VAL" ]; then
|
||||
echo "Usage: $0 <symbol> <value>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for symbol: '$SYMBOL'"
|
||||
|
||||
ADDR="0x$(riscv64-unknown-elf-objdump -t *.elf | grep $SYMBOL | awk '{print $1}')"
|
||||
|
||||
if [ -z "$ADDR" ]; then
|
||||
echo "Error: Symbol '$SYMBOL' not found in the object file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $ADDR =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
echo "Error: Address must be in hexadecimal format (e.g., 0x20000000)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert the value to hexadecimal format
|
||||
if ! [[ $VAL =~ ^0x[0-9a-fA-F]+$ ]]; then
|
||||
VAL="0x$(printf '%x' "$VAL")"
|
||||
fi
|
||||
|
||||
echo "Setting $SYMBOL@$ADDR -> $VAL"
|
||||
|
||||
commands=" -s 0x10 0x80000001" # Make the debug module work properly.
|
||||
commands+=" -s 0x20 0x0072a023" # Write wcode of sw x7,0(x5)
|
||||
commands+=" -s 0x21 0x00100073" # Write wcode of ebreak
|
||||
commands+=" -s 0x04 $ADDR" # Write address 0x20000000 to DATA0
|
||||
commands+=" -s 0x17 0x00271005" # Abstract cmd data0->x5 and exec progbuf
|
||||
commands+=" -s 0x04 $VAL" # Write value to DATA0
|
||||
commands+=" -s 0x17 0x00271007" # Abstract cmd data0->x7
|
||||
commands+=" -m 0x16" # Read ABSTRACTCS
|
||||
commands+=" -s 0x10 0x40000001" # Resume(1<<30) without reset(1<<0)
|
||||
|
||||
echo $commands | nc localhost 4444
|
||||
23
inc/misc/tests/Makefile
Normal file
23
inc/misc/tests/Makefile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
all : ci
|
||||
|
||||
EXAMPLES := $(wildcard ../../examples/*/.) $(wildcard ../../examples_v10x/*/.) $(wildcard ../../examples_v20x/*/.) $(wildcard ../../examples_v30x/*/.) $(wildcard ../../examples_x035/*/.)
|
||||
|
||||
.PHONY: ci tests all $(EXAMPLES) clean
|
||||
|
||||
results :
|
||||
mkdir -p results
|
||||
|
||||
$(EXAMPLES) : results
|
||||
echo $(shell basename $(realpath $(lastword $@)))
|
||||
($(MAKE) -C $@ build > results/$(subst .,,$(subst /,_,$@)).txt 2> results/$(subst .,,$(subst /,_,$@)).warning && echo "success" > results/$(subst .,,$(subst /,_,$@)).result) || echo "failure" > results/$(subst .,,$(subst /,_,$@)).result
|
||||
echo $(shell basename $(realpath $(lastword $@))).bin > results/$(subst .,,$(subst /,_,$@)).stat
|
||||
sha1sum $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
wc --bytes $@/$(shell basename $(realpath $(lastword $@))).bin | cut -d' ' -f 1 >> results/$(subst .,,$(subst /,_,$@)).stat
|
||||
|
||||
tests : $(EXAMPLES)
|
||||
|
||||
ci : install tests
|
||||
|
||||
clean :
|
||||
rm -rf results
|
||||
|
||||
2757
src/ch32fun.c
2757
src/ch32fun.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue