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
1483
inc/ch32fun.h
1483
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
6458
inc/ch32v003hw.h
6458
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
|
// 2023-06-26 recallmenot
|
||||||
|
|
||||||
// ######## necessities
|
//######## necessities
|
||||||
|
|
||||||
// include guards
|
// include guards
|
||||||
#ifndef CH32V003_GPIO_BR_H
|
#ifndef CH32V003_GPIO_BR_H
|
||||||
#define CH32V003_GPIO_BR_H
|
#define CH32V003_GPIO_BR_H
|
||||||
|
|
||||||
// includes
|
// includes
|
||||||
|
#include <stdint.h> //uintN_t support
|
||||||
#include "../ch32fun/ch32fun.h"
|
#include "../ch32fun/ch32fun.h"
|
||||||
#include <stdint.h> //uintN_t support
|
|
||||||
|
|
||||||
|
|
||||||
/*######## library description
|
/*######## library description
|
||||||
This is a speedy and light GPIO library due to
|
This is a speedy and light GPIO library due to
|
||||||
static inlining of most functions
|
static inlining of most functions
|
||||||
compile-time abstraction
|
compile-time abstraction
|
||||||
branchless where it counts
|
branchless where it counts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*######## library usage and configuration
|
/*######## library usage and configuration
|
||||||
|
|
||||||
first, enable the desired port.
|
first, enable the desired port.
|
||||||
|
|
@ -94,81 +98,78 @@ Writing `TIMx->SWEVGR |= TIM_UG` will immediately update the shadow register and
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ######## ports, pins and states: use these for the functions below!
|
|
||||||
|
|
||||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin)
|
|
||||||
|
|
||||||
enum GPIO_port_n
|
//######## ports, pins and states: use these for the functions below!
|
||||||
{
|
|
||||||
GPIO_port_A = 0b00,
|
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||||
GPIO_port_C = 0b10,
|
|
||||||
GPIO_port_D = 0b11,
|
enum GPIO_port_n {
|
||||||
|
GPIO_port_A = 0b00,
|
||||||
|
GPIO_port_C = 0b10,
|
||||||
|
GPIO_port_D = 0b11,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_pinModes
|
enum GPIO_pinModes {
|
||||||
{
|
GPIO_pinMode_I_floating,
|
||||||
GPIO_pinMode_I_floating,
|
GPIO_pinMode_I_pullUp,
|
||||||
GPIO_pinMode_I_pullUp,
|
GPIO_pinMode_I_pullDown,
|
||||||
GPIO_pinMode_I_pullDown,
|
GPIO_pinMode_I_analog,
|
||||||
GPIO_pinMode_I_analog,
|
GPIO_pinMode_O_pushPull,
|
||||||
GPIO_pinMode_O_pushPull,
|
GPIO_pinMode_O_openDrain,
|
||||||
GPIO_pinMode_O_openDrain,
|
GPIO_pinMode_O_pushPullMux,
|
||||||
GPIO_pinMode_O_pushPullMux,
|
GPIO_pinMode_O_openDrainMux,
|
||||||
GPIO_pinMode_O_openDrainMux,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lowhigh
|
enum lowhigh {
|
||||||
{
|
low,
|
||||||
low,
|
high,
|
||||||
high,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// analog inputs
|
// analog inputs
|
||||||
enum GPIO_analog_inputs
|
enum GPIO_analog_inputs {
|
||||||
{
|
GPIO_Ain0_A2,
|
||||||
GPIO_Ain0_A2,
|
GPIO_Ain1_A1,
|
||||||
GPIO_Ain1_A1,
|
GPIO_Ain2_C4,
|
||||||
GPIO_Ain2_C4,
|
GPIO_Ain3_D2,
|
||||||
GPIO_Ain3_D2,
|
GPIO_Ain4_D3,
|
||||||
GPIO_Ain4_D3,
|
GPIO_Ain5_D5,
|
||||||
GPIO_Ain5_D5,
|
GPIO_Ain6_D6,
|
||||||
GPIO_Ain6_D6,
|
GPIO_Ain7_D4,
|
||||||
GPIO_Ain7_D4,
|
GPIO_AinVref,
|
||||||
GPIO_AinVref,
|
GPIO_AinVcal,
|
||||||
GPIO_AinVcal,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||||
enum GPIO_ADC_sampletimes
|
enum GPIO_ADC_sampletimes {
|
||||||
{
|
GPIO_ADC_sampletime_3cy,
|
||||||
GPIO_ADC_sampletime_3cy,
|
GPIO_ADC_sampletime_9cy,
|
||||||
GPIO_ADC_sampletime_9cy,
|
GPIO_ADC_sampletime_15cy,
|
||||||
GPIO_ADC_sampletime_15cy,
|
GPIO_ADC_sampletime_30cy,
|
||||||
GPIO_ADC_sampletime_30cy,
|
GPIO_ADC_sampletime_43cy,
|
||||||
GPIO_ADC_sampletime_43cy,
|
GPIO_ADC_sampletime_57cy,
|
||||||
GPIO_ADC_sampletime_57cy,
|
GPIO_ADC_sampletime_73cy,
|
||||||
GPIO_ADC_sampletime_73cy,
|
GPIO_ADC_sampletime_241cy_default,
|
||||||
GPIO_ADC_sampletime_241cy_default,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_tim1_output_sets
|
enum GPIO_tim1_output_sets {
|
||||||
{
|
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPIO_tim2_output_sets
|
enum GPIO_tim2_output_sets {
|
||||||
{
|
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ######## interface function overview: use these!
|
|
||||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
|
||||||
|
//######## interface function overview: use these!
|
||||||
|
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||||
|
|
||||||
// setup
|
// setup
|
||||||
#define GPIO_port_enable(GPIO_port_n)
|
#define GPIO_port_enable(GPIO_port_n)
|
||||||
|
|
@ -201,66 +202,72 @@ static inline void GPIO_tim2_init();
|
||||||
#define GPIO_tim1_analogWrite(channel, value)
|
#define GPIO_tim1_analogWrite(channel, value)
|
||||||
#define GPIO_tim2_analogWrite(channel, value)
|
#define GPIO_tim2_analogWrite(channel, value)
|
||||||
|
|
||||||
// ######## internal function declarations
|
|
||||||
|
|
||||||
// ######## internal variables
|
|
||||||
|
|
||||||
// ######## preprocessor macros
|
//######## internal function declarations
|
||||||
|
|
||||||
#define CONCAT(a, b) a##b
|
|
||||||
|
|
||||||
|
//######## internal variables
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//######## preprocessor macros
|
||||||
|
|
||||||
|
#define CONCAT(a, b) a ## b
|
||||||
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
||||||
|
|
||||||
#undef GPIOv_from_PORT_PIN
|
#undef GPIOv_from_PORT_PIN
|
||||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (pin))
|
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin ) ((GPIO_port_n << 4 ) | (pin))
|
||||||
#define GPIOv_to_PORT(GPIOv) (GPIOv >> 4)
|
#define GPIOv_to_PORT( GPIOv ) (GPIOv >> 4 )
|
||||||
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111)
|
#define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
|
||||||
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
#define GPIOv_to_GPIObase( GPIOv ) ((GPIO_TypeDef*)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||||
|
|
||||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||||
|
|
||||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||||
|
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||||
|
|
||||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||||
|
|
||||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
||||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIOv)
|
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIOv)
|
||||||
|
|
||||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n)
|
||||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n)
|
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n)
|
||||||
|
|
@ -280,74 +287,91 @@ static inline void GPIO_tim2_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(GPIO_timer_prescaler)
|
#if !defined(GPIO_timer_prescaler)
|
||||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ######## define requirements / maintenance defines
|
//######## define requirements / maintenance defines
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//######## small function definitions, static inline
|
||||||
|
|
||||||
// ######## small function definitions, static inline
|
|
||||||
|
|
||||||
#undef GPIO_port_enable
|
#undef GPIO_port_enable
|
||||||
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
||||||
|
|
||||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_port_digitalWrite
|
#undef GPIO_port_digitalWrite
|
||||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||||
|
|
||||||
#undef GPIO_port_digitalRead
|
#undef GPIO_port_digitalRead
|
||||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||||
|
|
||||||
#undef GPIO_pinMode
|
#undef GPIO_pinMode
|
||||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_digitalWrite_hi
|
#undef GPIO_digitalWrite_hi
|
||||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||||
#undef GPIO_digitalWrite_lo
|
#undef GPIO_digitalWrite_lo
|
||||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||||
|
|
||||||
#undef GPIO_digitalWrite
|
#undef GPIO_digitalWrite
|
||||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||||
|
|
||||||
#undef GPIO_digitalWrite_branching
|
#undef GPIO_digitalWrite_branching
|
||||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? (GPIO_digitalWrite_hi(GPIOv)) : (GPIO_digitalWrite_lo(GPIOv)))
|
||||||
|
|
||||||
#undef GPIO_digitalRead
|
#undef GPIO_digitalRead
|
||||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||||
|
|
||||||
#undef GPIO_ADC_set_sampletime
|
#undef GPIO_ADC_set_sampletime
|
||||||
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
||||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_ADC_set_sampletimes_all
|
#undef GPIO_ADC_set_sampletimes_all
|
||||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||||
ADC1->SAMPTR2 &= 0; \
|
ADC1->SAMPTR2 &= 0; \
|
||||||
ADC1->SAMPTR2 |= \
|
ADC1->SAMPTR2 |= \
|
||||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \
|
GPIO_ADC_sampletime << (0 * 3) \
|
||||||
ADC1->SAMPTR1 &= 0; \
|
| GPIO_ADC_sampletime << (1 * 3) \
|
||||||
ADC1->SAMPTR1 |= \
|
| GPIO_ADC_sampletime << (2 * 3) \
|
||||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3); \
|
| GPIO_ADC_sampletime << (3 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (4 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (5 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (6 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (7 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (8 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (9 * 3); \
|
||||||
|
ADC1->SAMPTR1 &= 0; \
|
||||||
|
ADC1->SAMPTR1 |= \
|
||||||
|
GPIO_ADC_sampletime << (0 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (1 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (2 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (3 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (4 * 3) \
|
||||||
|
| GPIO_ADC_sampletime << (5 * 3); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_ADC_set_power
|
#undef GPIO_ADC_set_power
|
||||||
|
|
@ -357,137 +381,133 @@ static inline void GPIO_tim2_init();
|
||||||
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
||||||
|
|
||||||
#undef GPIO_ADC_calibrate
|
#undef GPIO_ADC_calibrate
|
||||||
#define GPIO_ADC_calibrate() ({ \
|
#define GPIO_ADC_calibrate() ({ \
|
||||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||||
; \
|
ADC1->CTLR2 |= ADC_CAL; \
|
||||||
ADC1->CTLR2 |= ADC_CAL; \
|
while(ADC1->CTLR2 & ADC_CAL); \
|
||||||
while (ADC1->CTLR2 & ADC_CAL) \
|
|
||||||
; \
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// large but will likely only ever be called once
|
// large but will likely only ever be called once
|
||||||
static inline void GPIO_ADCinit()
|
static inline void GPIO_ADCinit() {
|
||||||
{
|
// select ADC clock source
|
||||||
// select ADC clock source
|
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
RCC->CFGR0 &= ~(0x1F<<11);
|
||||||
RCC->CFGR0 &= ~(0x1F << 11);
|
|
||||||
|
|
||||||
// enable clock to the ADC
|
// enable clock to the ADC
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||||
|
|
||||||
// Reset the ADC to init all regs
|
// Reset the ADC to init all regs
|
||||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||||
|
|
||||||
// set sampling time for all inputs to 241 cycles
|
// set sampling time for all inputs to 241 cycles
|
||||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||||
|
|
||||||
// set trigger to software
|
// set trigger to software
|
||||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||||
|
|
||||||
// pre-clear conversion queue
|
// pre-clear conversion queue
|
||||||
ADC1->RSQR1 = 0;
|
ADC1->RSQR1 = 0;
|
||||||
ADC1->RSQR2 = 0;
|
ADC1->RSQR2 = 0;
|
||||||
ADC1->RSQR3 = 0;
|
ADC1->RSQR3 = 0;
|
||||||
|
|
||||||
// power the ADC
|
// power the ADC
|
||||||
GPIO_ADC_set_power(1);
|
GPIO_ADC_set_power(1);
|
||||||
GPIO_ADC_calibrate();
|
GPIO_ADC_calibrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||||
{
|
// set mux to selected input
|
||||||
// set mux to selected input
|
ADC1->RSQR3 = input;
|
||||||
ADC1->RSQR3 = input;
|
// allow everything to precharge
|
||||||
// allow everything to precharge
|
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
// start sw conversion (auto clears)
|
||||||
// start sw conversion (auto clears)
|
ADC1->CTLR2 |= ADC_SWSTART;
|
||||||
ADC1->CTLR2 |= ADC_SWSTART;
|
// wait for conversion complete
|
||||||
// wait for conversion complete
|
while(!(ADC1->STATR & ADC_EOC)) {}
|
||||||
while (!(ADC1->STATR & ADC_EOC)) {}
|
// get result
|
||||||
// get result
|
return ADC1->RDATAR;
|
||||||
return ADC1->RDATAR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef GPIO_tim1_map
|
#undef GPIO_tim1_map
|
||||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#undef GPIO_tim2_map
|
#undef GPIO_tim2_map
|
||||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||||
})
|
})
|
||||||
|
|
||||||
static inline void GPIO_tim1_init()
|
static inline void GPIO_tim1_init() {
|
||||||
{
|
// enable TIM1
|
||||||
// enable TIM1
|
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
// reset TIM1 to init all regs
|
||||||
// reset TIM1 to init all regs
|
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
// SMCFGR: default clk input is CK_INT
|
||||||
// SMCFGR: default clk input is CK_INT
|
// set clock prescaler divider
|
||||||
// set clock prescaler divider
|
TIM1->PSC = GPIO_timer_prescaler;
|
||||||
TIM1->PSC = GPIO_timer_prescaler;
|
// set PWM total cycle width
|
||||||
// set PWM total cycle width
|
TIM1->ATRLR = GPIO_timer_resolution;
|
||||||
TIM1->ATRLR = GPIO_timer_resolution;
|
// CTLR1: default is up, events generated, edge align
|
||||||
// CTLR1: default is up, events generated, edge align
|
// enable auto-reload of preload
|
||||||
// enable auto-reload of preload
|
TIM1->CTLR1 |= TIM_ARPE;
|
||||||
TIM1->CTLR1 |= TIM_ARPE;
|
// initialize counter
|
||||||
// initialize counter
|
TIM1->SWEVGR |= TIM_UG;
|
||||||
TIM1->SWEVGR |= TIM_UG;
|
// disengage brake
|
||||||
// disengage brake
|
TIM1->BDTR |= TIM_MOE;
|
||||||
TIM1->BDTR |= TIM_MOE;
|
// Enable TIM1
|
||||||
// Enable TIM1
|
TIM1->CTLR1 |= TIM_CEN;
|
||||||
TIM1->CTLR1 |= TIM_CEN;
|
|
||||||
}
|
}
|
||||||
static inline void GPIO_tim2_init()
|
static inline void GPIO_tim2_init() {
|
||||||
{
|
// enable TIM2
|
||||||
// enable TIM2
|
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
// reset TIM2 to init all regs
|
||||||
// reset TIM2 to init all regs
|
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
// SMCFGR: default clk input is CK_INT
|
||||||
// SMCFGR: default clk input is CK_INT
|
// set clock prescaler divider
|
||||||
// set clock prescaler divider
|
TIM2->PSC = GPIO_timer_prescaler;
|
||||||
TIM2->PSC = GPIO_timer_prescaler;
|
// set PWM total cycle width
|
||||||
// set PWM total cycle width
|
TIM2->ATRLR = GPIO_timer_resolution;
|
||||||
TIM2->ATRLR = GPIO_timer_resolution;
|
// CTLR1: default is up, events generated, edge align
|
||||||
// CTLR1: default is up, events generated, edge align
|
// enable auto-reload of preload
|
||||||
// enable auto-reload of preload
|
TIM2->CTLR1 |= TIM_ARPE;
|
||||||
TIM2->CTLR1 |= TIM_ARPE;
|
// initialize counter
|
||||||
// initialize counter
|
TIM2->SWEVGR |= TIM_UG;
|
||||||
TIM2->SWEVGR |= TIM_UG;
|
// Enable TIM2
|
||||||
// Enable TIM2
|
TIM2->CTLR1 |= TIM_CEN;
|
||||||
TIM2->CTLR1 |= TIM_CEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||||
|
|
||||||
#undef GPIO_tim1_enableCH
|
#undef GPIO_tim1_enableCH
|
||||||
#define GPIO_tim1_enableCH(channel) ({ \
|
#define GPIO_tim1_enableCH(channel) ({ \
|
||||||
GPIO_timer_channel_set(TIM1, channel); \
|
GPIO_timer_channel_set(TIM1, channel); \
|
||||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||||
})
|
})
|
||||||
#undef GPIO_tim2_enableCH
|
#undef GPIO_tim2_enableCH
|
||||||
#define GPIO_tim2_enableCH(channel) ({ \
|
#define GPIO_tim2_enableCH(channel) ({ \
|
||||||
GPIO_timer_channel_set(TIM2, channel); \
|
GPIO_timer_channel_set(TIM2, channel); \
|
||||||
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||||
|
|
||||||
#undef GPIO_tim1_analogWrite
|
#undef GPIO_tim1_analogWrite
|
||||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||||
#undef GPIO_tim2_analogWrite
|
#undef GPIO_tim2_analogWrite
|
||||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||||
|
|
||||||
#endif // CH32V003_GPIO_BR_H
|
#endif // CH32V003_GPIO_BR_H
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
// ######## necessities
|
//######## necessities
|
||||||
|
|
||||||
// include guards
|
// include guards
|
||||||
#ifndef CH32V003_SPI_H
|
#ifndef CH32V003_SPI_H
|
||||||
#define CH32V003_SPI_H
|
#define CH32V003_SPI_H
|
||||||
|
|
||||||
// includes
|
// includes
|
||||||
|
#include<stdint.h> //uintN_t support
|
||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include <stdint.h> //uintN_t support
|
|
||||||
|
|
||||||
#ifndef APB_CLOCK
|
#ifndef APB_CLOCK
|
||||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*######## library usage and configuration
|
/*######## library usage and configuration
|
||||||
|
|
@ -20,7 +20,7 @@ SYSTEM_CORE_CLOCK and APB_CLOCK should be defined already as APB_CLOCK is used b
|
||||||
|
|
||||||
|
|
||||||
#ifndef APB_CLOCK
|
#ifndef APB_CLOCK
|
||||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
to enable using the functions of this library:
|
to enable using the functions of this library:
|
||||||
|
|
@ -47,8 +47,10 @@ then pick the desired setting of each group:
|
||||||
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ######## function overview (declarations): use these!
|
|
||||||
// initialize and configure the SPI peripheral
|
|
||||||
|
//######## function overview (declarations): use these!
|
||||||
|
// initialize and configure the SPI peripheral
|
||||||
static inline void SPI_init();
|
static inline void SPI_init();
|
||||||
|
|
||||||
// establish / end a connection to the SPI device
|
// establish / end a connection to the SPI device
|
||||||
|
|
@ -65,14 +67,14 @@ static inline void SPI_NSS_software_high();
|
||||||
|
|
||||||
// read / write the SPI device
|
// read / write the SPI device
|
||||||
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
||||||
static inline uint8_t SPI_read_8();
|
static inline uint8_t SPI_read_8();
|
||||||
static inline uint16_t SPI_read_16();
|
static inline uint16_t SPI_read_16();
|
||||||
static inline void SPI_write_8(uint8_t data);
|
static inline void SPI_write_8(uint8_t data);
|
||||||
static inline void SPI_write_16(uint16_t data);
|
static inline void SPI_write_16(uint16_t data);
|
||||||
|
|
||||||
// send a command and get a response from the SPI device
|
// send a command and get a response from the SPI device
|
||||||
// you'll use this for most devices
|
// you'll use this for most devices
|
||||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||||
static inline uint16_t SPI_transfer_16(uint16_t data);
|
static inline uint16_t SPI_transfer_16(uint16_t data);
|
||||||
|
|
||||||
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
||||||
|
|
@ -85,25 +87,31 @@ static inline void SPI_poweron();
|
||||||
static inline void kill_interrrupts();
|
static inline void kill_interrrupts();
|
||||||
static inline void restore_interrupts();
|
static inline void restore_interrupts();
|
||||||
|
|
||||||
// ######## internal function declarations
|
|
||||||
static inline void SPI_wait_TX_complete();
|
|
||||||
static inline uint8_t SPI_is_RX_empty();
|
|
||||||
static inline void SPI_wait_RX_available();
|
|
||||||
|
|
||||||
// ######## internal variables
|
|
||||||
|
//######## internal function declarations
|
||||||
|
static inline void SPI_wait_TX_complete();
|
||||||
|
static inline uint8_t SPI_is_RX_empty();
|
||||||
|
static inline void SPI_wait_RX_available();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//######## internal variables
|
||||||
static uint16_t EXT1_INTENR_backup;
|
static uint16_t EXT1_INTENR_backup;
|
||||||
|
|
||||||
// ######## preprocessor macros
|
|
||||||
// min and max helper macros
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
//######## preprocessor macros
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
// min and max helper macros
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
|
||||||
// stringify for displaying what #defines evaluated to at preprocessor stage
|
// stringify for displaying what #defines evaluated to at preprocessor stage
|
||||||
#define VALUE_TO_STRING(x) #x
|
#define VALUE_TO_STRING(x) #x
|
||||||
#define VALUE(x) VALUE_TO_STRING(x)
|
#define VALUE(x) VALUE_TO_STRING(x)
|
||||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||||
|
|
||||||
// compile-time log2
|
//compile-time log2
|
||||||
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
||||||
|
|
||||||
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
||||||
|
|
@ -112,249 +120,233 @@ static uint16_t EXT1_INTENR_backup;
|
||||||
|
|
||||||
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
||||||
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
||||||
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
#pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||||
|
|
||||||
// ######## preprocessor #define requirements
|
|
||||||
|
|
||||||
|
//######## preprocessor #define requirements
|
||||||
|
|
||||||
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ######## small function definitions, static inline
|
|
||||||
static inline void SPI_init()
|
|
||||||
{
|
|
||||||
SPI_poweron();
|
|
||||||
|
|
||||||
// reset control register
|
|
||||||
SPI1->CTLR1 = 0;
|
|
||||||
|
|
||||||
// set prescaler
|
//######## small function definitions, static inline
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
|
static inline void SPI_init() {
|
||||||
|
SPI_poweron();
|
||||||
|
|
||||||
// set clock polarity and phase
|
// reset control register
|
||||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
SPI1->CTLR1 = 0;
|
||||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
|
||||||
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
|
||||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
|
||||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
|
||||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
|
||||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
|
||||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// configure NSS pin, master mode
|
// set prescaler
|
||||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
|
||||||
// _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
|
// set clock polarity and phase
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 5));
|
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
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
|
||||||
|
|
||||||
// CH32V003 is master
|
// configure NSS pin, master mode
|
||||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
#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 data direction and configure data pins
|
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
GPIOC->CFGLR &= ~(0xf<<(4*5));
|
||||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
|
||||||
|
|
||||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
// CH32V003 is master
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
|
||||||
|
|
||||||
// MISO on PC7, 10MHz input, floating
|
// set data direction and configure data pins
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 7));
|
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 7);
|
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
|
||||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
|
||||||
|
|
||||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||||
#endif
|
|
||||||
|
// MISO on PC7, 10MHz input, floating
|
||||||
|
GPIOC->CFGLR &= ~(0xf<<(4*7));
|
||||||
|
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
|
||||||
|
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||||
|
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||||
|
|
||||||
|
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||||
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
|
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SPI_begin_8()
|
static inline void SPI_begin_8() {
|
||||||
{
|
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_begin_16()
|
static inline void SPI_begin_16() {
|
||||||
{
|
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_end()
|
static inline void SPI_end() {
|
||||||
{
|
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||||
static inline void SPI_NSS_software_high()
|
static inline void SPI_NSS_software_high() {
|
||||||
{
|
GPIOC->BSHR = (1<<3);
|
||||||
GPIOC->BSHR = (1 << 3);
|
|
||||||
}
|
}
|
||||||
static inline void SPI_NSS_software_low()
|
static inline void SPI_NSS_software_low() {
|
||||||
{
|
GPIOC->BSHR = (1<<(16+3));
|
||||||
GPIOC->BSHR = (1 << (16 + 3));
|
|
||||||
}
|
}
|
||||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
static inline void SPI_NSS_software_high()
|
static inline void SPI_NSS_software_high() {
|
||||||
{
|
GPIOC->BSHR = (1<<4);
|
||||||
GPIOC->BSHR = (1 << 4);
|
|
||||||
}
|
}
|
||||||
static inline void SPI_NSS_software_low()
|
static inline void SPI_NSS_software_low() {
|
||||||
{
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint8_t SPI_read_8()
|
static inline uint8_t SPI_read_8() {
|
||||||
{
|
return SPI1->DATAR;
|
||||||
return SPI1->DATAR;
|
|
||||||
}
|
}
|
||||||
static inline uint16_t SPI_read_16()
|
static inline uint16_t SPI_read_16() {
|
||||||
{
|
return SPI1->DATAR;
|
||||||
return SPI1->DATAR;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_write_8(uint8_t data)
|
static inline void SPI_write_8(uint8_t data) {
|
||||||
{
|
SPI1->DATAR = data;
|
||||||
SPI1->DATAR = data;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_write_16(uint16_t data)
|
static inline void SPI_write_16(uint16_t data) {
|
||||||
{
|
SPI1->DATAR = data;
|
||||||
SPI1->DATAR = data;
|
|
||||||
}
|
}
|
||||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||||
{
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_high();
|
||||||
SPI_NSS_software_high();
|
#endif
|
||||||
#endif
|
SPI_write_8(data);
|
||||||
SPI_write_8(data);
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
asm volatile("nop");
|
||||||
asm volatile("nop");
|
SPI_wait_RX_available();
|
||||||
SPI_wait_RX_available();
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_low();
|
||||||
SPI_NSS_software_low();
|
#endif
|
||||||
#endif
|
return SPI_read_8();
|
||||||
return SPI_read_8();
|
|
||||||
}
|
}
|
||||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||||
{
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_high();
|
||||||
SPI_NSS_software_high();
|
#endif
|
||||||
#endif
|
SPI_write_16(data);
|
||||||
SPI_write_16(data);
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
asm volatile("nop");
|
||||||
asm volatile("nop");
|
SPI_wait_RX_available();
|
||||||
SPI_wait_RX_available();
|
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
SPI_NSS_software_low();
|
||||||
SPI_NSS_software_low();
|
#endif
|
||||||
#endif
|
return SPI_read_16();
|
||||||
return SPI_read_16();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SPI_poweroff()
|
static inline void SPI_poweroff() {
|
||||||
{
|
SPI_end();
|
||||||
SPI_end();
|
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_poweron()
|
static inline void SPI_poweron() {
|
||||||
{
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kill_interrrupts()
|
static inline void kill_interrrupts() {
|
||||||
{
|
EXT1_INTENR_backup = EXTI->INTENR;
|
||||||
EXT1_INTENR_backup = EXTI->INTENR;
|
// zero the interrupt enable register to disable all interrupts
|
||||||
// zero the interrupt enable register to disable all interrupts
|
EXTI->INTENR = 0;
|
||||||
EXTI->INTENR = 0;
|
|
||||||
}
|
}
|
||||||
static inline void restore_interrupts()
|
static inline void restore_interrupts() {
|
||||||
{
|
EXTI->INTENR = EXT1_INTENR_backup;
|
||||||
EXTI->INTENR = EXT1_INTENR_backup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######## small internal function definitions, static inline
|
|
||||||
static inline void SPI_wait_TX_complete()
|
|
||||||
{
|
//######## small internal function definitions, static inline
|
||||||
while (!(SPI1->STATR & SPI_STATR_TXE)) {}
|
static inline void SPI_wait_TX_complete() {
|
||||||
|
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||||
}
|
}
|
||||||
static inline uint8_t SPI_is_RX_empty()
|
static inline uint8_t SPI_is_RX_empty() {
|
||||||
{
|
return SPI1->STATR & SPI_STATR_RXNE;
|
||||||
return SPI1->STATR & SPI_STATR_RXNE;
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_RX_available()
|
static inline void SPI_wait_RX_available() {
|
||||||
{
|
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||||
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_not_busy()
|
static inline void SPI_wait_not_busy() {
|
||||||
{
|
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
|
||||||
}
|
}
|
||||||
static inline void SPI_wait_transmit_finished()
|
static inline void SPI_wait_transmit_finished() {
|
||||||
{
|
SPI_wait_TX_complete();
|
||||||
SPI_wait_TX_complete();
|
SPI_wait_not_busy();
|
||||||
SPI_wait_not_busy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######## implementation block
|
|
||||||
// #define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
//######## implementation block
|
||||||
|
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||||
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
||||||
|
|
||||||
// no functions here because I think all of the functions are small enough to static inline
|
//no functions here because I think all of the functions are small enough to static inline
|
||||||
|
|
||||||
#endif // CH32V003_SPI_IMPLEMENTATION
|
#endif // CH32V003_SPI_IMPLEMENTATION
|
||||||
#endif // CH32V003_SPI_H
|
#endif // CH32V003_SPI_H
|
||||||
|
|
|
||||||
|
|
@ -3,42 +3,44 @@
|
||||||
|
|
||||||
/** ADC-based Capactive Touch Control.
|
/** ADC-based Capactive Touch Control.
|
||||||
|
|
||||||
see cap_touch_adc.c for an example.
|
see cap_touch_adc.c for an example.
|
||||||
|
|
||||||
// Enable GPIOD, C and ADC
|
// Enable GPIOD, C and ADC
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||||
InitTouchADC();
|
InitTouchADC();
|
||||||
|
|
||||||
|
|
||||||
// Then do this any time you want to read some touches.
|
// Then do this any time you want to read some touches.
|
||||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
|
||||||
|
|
||||||
|
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||||
|
|
||||||
// Can either be 0 or 1.
|
// Can either be 0 or 1.
|
||||||
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
||||||
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||||
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
||||||
#define TOUCH_SLOPE 1
|
#define TOUCH_SLOPE 1
|
||||||
|
|
||||||
// If you set this to 1, it will glitch the line, so it will only read
|
// If you set this to 1, it will glitch the line, so it will only read
|
||||||
// anything reasonable if the capacitance can overcome that initial spike.
|
// anything reasonable if the capacitance can overcome that initial spike.
|
||||||
// Typically, it seems if you use this you probbly don't need to do
|
// Typically, it seems if you use this you probbly don't need to do
|
||||||
// any pre-use calibration.
|
// any pre-use calibration.
|
||||||
#define TOUCH_FLAT 0
|
#define TOUCH_FLAT 0
|
||||||
|
|
||||||
// Macro used for force-alingining ADC timing
|
// Macro used for force-alingining ADC timing
|
||||||
#define FORCEALIGNADC \
|
#define FORCEALIGNADC \
|
||||||
asm volatile( \
|
asm volatile( \
|
||||||
"\n\
|
"\n\
|
||||||
.balign 4\n\
|
.balign 4\n\
|
||||||
andi a2, %[cyccnt], 3\n\
|
andi a2, %[cyccnt], 3\n\
|
||||||
c.slli a2, 1\n\
|
c.slli a2, 1\n\
|
||||||
|
|
@ -48,155 +50,152 @@
|
||||||
jalr a2, 1\n\
|
jalr a2, 1\n\
|
||||||
.long 0x00010001\n\
|
.long 0x00010001\n\
|
||||||
.long 0x00010001\n\
|
.long 0x00010001\n\
|
||||||
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2");
|
"\
|
||||||
|
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||||
|
);
|
||||||
|
|
||||||
static void InitTouchADC();
|
|
||||||
void InitTouchADC()
|
static void InitTouchADC( );
|
||||||
|
void InitTouchADC( )
|
||||||
{
|
{
|
||||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||||
RCC->CFGR0 &= ~(0x1F << 11);
|
RCC->CFGR0 &= ~(0x1F<<11);
|
||||||
|
|
||||||
// Set up single conversion on chl 2
|
// Set up single conversion on chl 2
|
||||||
ADC1->RSQR1 = 0;
|
ADC1->RSQR1 = 0;
|
||||||
ADC1->RSQR2 = 0;
|
ADC1->RSQR2 = 0;
|
||||||
|
|
||||||
// turn on ADC and set rule group to sw trig
|
// turn on ADC and set rule group to sw trig
|
||||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||||
|
|
||||||
// Reset calibration
|
// Reset calibration
|
||||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||||
;
|
|
||||||
|
|
||||||
// Calibrate
|
// Calibrate
|
||||||
ADC1->CTLR2 |= ADC_CAL;
|
ADC1->CTLR2 |= ADC_CAL;
|
||||||
while (ADC1->CTLR2 & ADC_CAL)
|
while(ADC1->CTLR2 & ADC_CAL);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run from RAM to get even more stable timing.
|
// Run from RAM to get even more stable timing.
|
||||||
// This function call takes about 8.1uS to execute.
|
// This function call takes about 8.1uS to execute.
|
||||||
static uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||||
uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
FORCEALIGNADC
|
FORCEALIGNADC
|
||||||
ADC1->RSQR3 = adcno;
|
ADC1->RSQR3 = adcno;
|
||||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
||||||
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin)));
|
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE;
|
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | CFGBASE;
|
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
|
||||||
|
|
||||||
|
// If we run multiple times with slightly different wait times, we can
|
||||||
|
// reduce the impact of the ADC's DNL.
|
||||||
|
|
||||||
// If we run multiple times with slightly different wait times, we can
|
|
||||||
// reduce the impact of the ADC's DNL.
|
|
||||||
|
|
||||||
#if TOUCH_FLAT == 1
|
#if TOUCH_FLAT == 1
|
||||||
#define RELEASEIO \
|
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
|
||||||
io->CFGLR = CFGFLOAT;
|
|
||||||
#else
|
#else
|
||||||
#define RELEASEIO \
|
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||||
io->CFGLR = CFGFLOAT; \
|
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INNER_LOOP(n) \
|
#define INNER_LOOP( n ) \
|
||||||
{ \
|
{ \
|
||||||
/* Only lock IRQ for a very narrow window. */ \
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
__disable_irq(); \
|
__disable_irq(); \
|
||||||
FORCEALIGNADC \
|
FORCEALIGNADC \
|
||||||
\
|
\
|
||||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
this We are catching it onthe slope much more effectively. */ \
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
\
|
\
|
||||||
ADD_N_NOPS(n) \
|
ADD_N_NOPS( n ) \
|
||||||
\
|
\
|
||||||
RELEASEIO \
|
RELEASEIO \
|
||||||
\
|
\
|
||||||
/* Sampling actually starts here, somewhere, so we can let other \
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
interrupts run */ \
|
interrupts run */ \
|
||||||
__enable_irq(); \
|
__enable_irq(); \
|
||||||
while (!(ADC1->STATR & ADC_EOC)) \
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
; \
|
io->CFGLR = CFGDRIVE; \
|
||||||
io->CFGLR = CFGDRIVE; \
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
ret += ADC1->RDATAR; \
|
||||||
ret += ADC1->RDATAR; \
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < iterations; i++)
|
for( i = 0; i < iterations; i++ )
|
||||||
{
|
{
|
||||||
// Wait a variable amount of time based on loop iteration, in order
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
// to get a variety of RC points and minimize DNL.
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
INNER_LOOP(0);
|
INNER_LOOP( 0 );
|
||||||
INNER_LOOP(2);
|
INNER_LOOP( 2 );
|
||||||
INNER_LOOP(4);
|
INNER_LOOP( 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run from RAM to get even more stable timing.
|
// Run from RAM to get even more stable timing.
|
||||||
// This function call takes about 8.1uS to execute.
|
// This function call takes about 8.1uS to execute.
|
||||||
static uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||||
uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
{
|
{
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
|
|
||||||
ADC1->RSQR3 = adcno;
|
ADC1->RSQR3 = adcno;
|
||||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
|
|
||||||
// If we run multiple times with slightly different wait times, we can
|
// If we run multiple times with slightly different wait times, we can
|
||||||
// reduce the impact of the ADC's DNL.
|
// reduce the impact of the ADC's DNL.
|
||||||
|
|
||||||
#define INNER_LOOP_SAFE(n) \
|
#define INNER_LOOP_SAFE( n ) \
|
||||||
{ \
|
{ \
|
||||||
/* Only lock IRQ for a very narrow window. */ \
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
__disable_irq(); \
|
__disable_irq(); \
|
||||||
\
|
\
|
||||||
FORCEALIGNADC \
|
FORCEALIGNADC \
|
||||||
\
|
\
|
||||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
this We are catching it onthe slope much more effectively. */ \
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
\
|
\
|
||||||
ADD_N_NOPS(n) \
|
ADD_N_NOPS( n ) \
|
||||||
\
|
\
|
||||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||||
\
|
\
|
||||||
/* Sampling actually starts here, somewhere, so we can let other \
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
interrupts run */ \
|
interrupts run */ \
|
||||||
__enable_irq(); \
|
__enable_irq(); \
|
||||||
while (!(ADC1->STATR & ADC_EOC)) \
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
; \
|
__disable_irq(); \
|
||||||
__disable_irq(); \
|
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
__enable_irq(); \
|
||||||
__enable_irq(); \
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
ret += ADC1->RDATAR; \
|
||||||
ret += ADC1->RDATAR; \
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < iterations; i++)
|
for( i = 0; i < iterations; i++ )
|
||||||
{
|
{
|
||||||
// Wait a variable amount of time based on loop iteration, in order
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
// to get a variety of RC points and minimize DNL.
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
INNER_LOOP_SAFE(0);
|
INNER_LOOP_SAFE( 0 );
|
||||||
INNER_LOOP_SAFE(2);
|
INNER_LOOP_SAFE( 2 );
|
||||||
INNER_LOOP_SAFE(4);
|
INNER_LOOP_SAFE( 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -222,3 +221,4 @@ uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int i
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
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
|
#define _CH32V307GIGABIT_H
|
||||||
|
|
||||||
/* This file is written against the RTL8211E
|
/* This file is written against the RTL8211E
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// #define CH32V307GIGABIT_MCO25 1
|
// #define CH32V307GIGABIT_MCO25 1
|
||||||
// #define CH32V307GIGABIT_PHYADDRESS 0
|
// #define CH32V307GIGABIT_PHYADDRESS 0
|
||||||
|
|
@ -34,515 +34,515 @@
|
||||||
// ETH DMA structure definition (From ch32v30x_eth.c
|
// ETH DMA structure definition (From ch32v30x_eth.c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t volatile Status; /* Status */
|
uint32_t volatile Status; /* Status */
|
||||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||||
} ETH_DMADESCTypeDef;
|
} ETH_DMADESCTypeDef;
|
||||||
|
|
||||||
// You must provide:
|
// You must provide:
|
||||||
|
|
||||||
void ch32v307ethHandleReconfig(int link, int speed, int duplex);
|
void ch32v307ethHandleReconfig( int link, int speed, int duplex );
|
||||||
|
|
||||||
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
|
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
|
||||||
int ch32v307ethInitHandlePacket(uint8_t *data, int frame_length, ETH_DMADESCTypeDef *dmadesc);
|
int ch32v307ethInitHandlePacket( uint8_t * data, int frame_length, ETH_DMADESCTypeDef * dmadesc );
|
||||||
|
|
||||||
void ch32v307ethInitHandleTXC(void);
|
void ch32v307ethInitHandleTXC( void );
|
||||||
|
|
||||||
// This library provides:
|
// This library provides:
|
||||||
static void ch32v307ethGetMacInUC(uint8_t *mac);
|
static void ch32v307ethGetMacInUC( uint8_t * mac );
|
||||||
static int ch32v307ethInit(void);
|
static int ch32v307ethInit( void );
|
||||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy.
|
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||||
static int ch32v307ethTickPhy(void);
|
static int ch32v307ethTickPhy( void );
|
||||||
|
|
||||||
// Data pursuent to ethernet.
|
// Data pursuent to ethernet.
|
||||||
uint8_t ch32v307eth_mac[6] = {0};
|
uint8_t ch32v307eth_mac[6] = { 0 };
|
||||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||||
ETH_DMADESCTypeDef *pDMARxGet;
|
ETH_DMADESCTypeDef * pDMARxGet;
|
||||||
ETH_DMADESCTypeDef *pDMATxSet;
|
ETH_DMADESCTypeDef * pDMATxSet;
|
||||||
|
|
||||||
|
|
||||||
// Internal functions
|
// Internal functions
|
||||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val);
|
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value);
|
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||||
static int ch32v307ethPHYRegRead(uint32_t reg);
|
static int ch32v307ethPHYRegRead( uint32_t reg );
|
||||||
|
|
||||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value)
|
static int ch32v307ethPHYRegAsyncRead( int reg, int * value )
|
||||||
{
|
{
|
||||||
static uint8_t reg_request_count = 0;
|
static uint8_t reg_request_count = 0;
|
||||||
|
|
||||||
uint32_t miiar = ETH->MACMIIAR;
|
uint32_t miiar = ETH->MACMIIAR;
|
||||||
if (miiar & ETH_MACMIIAR_MB)
|
if( miiar & ETH_MACMIIAR_MB )
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2)
|
if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
|
||||||
{
|
{
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||||
reg_request_count++;
|
reg_request_count++;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
reg_request_count = 0;
|
reg_request_count = 0;
|
||||||
*value = ETH->MACMIIDR;
|
*value = ETH->MACMIIDR;
|
||||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethTickPhy(void)
|
static int ch32v307ethTickPhy(void)
|
||||||
{
|
{
|
||||||
int speed, linked, duplex;
|
int speed, linked, duplex;
|
||||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||||
int miidr;
|
int miidr;
|
||||||
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1;
|
if( ch32v307ethPHYRegAsyncRead( reg, &miidr ) ) return -1;
|
||||||
|
|
||||||
printf("REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid);
|
printf( "REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid );
|
||||||
|
|
||||||
if (reg == 0x1a)
|
if( reg == 0x1a )
|
||||||
{
|
{
|
||||||
speed = ((miidr >> 4) & 3);
|
speed = ((miidr>>4)&3);
|
||||||
linked = ((miidr >> 2) & 1);
|
linked = ((miidr>>2)&1);
|
||||||
duplex = ((miidr >> 3) & 1);
|
duplex = ((miidr>>3)&1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
speed = ((miidr >> 14) & 3);
|
speed = ((miidr>>14)&3);
|
||||||
linked = ((miidr >> 10) & 1);
|
linked = ((miidr>>10)&1);
|
||||||
duplex = ((miidr >> 13) & 1);
|
duplex = ((miidr>>13)&1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("LINK INFO: %d %d %d\n", speed, linked, duplex);
|
printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
|
||||||
if (linked)
|
if( linked )
|
||||||
{
|
{
|
||||||
uint32_t oldmaccr = ETH->MACCR;
|
uint32_t oldmaccr = ETH->MACCR;
|
||||||
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11);
|
uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
|
||||||
if (newmaccr != oldmaccr)
|
if( newmaccr != oldmaccr )
|
||||||
{
|
{
|
||||||
ETH->MACCR = newmaccr;
|
ETH->MACCR = newmaccr;
|
||||||
ch32v307ethHandleReconfig(linked, speed, duplex);
|
ch32v307ethHandleReconfig( linked, speed, duplex );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Based on ETH_WritePHYRegister
|
// Based on ETH_WritePHYRegister
|
||||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
|
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
|
||||||
{
|
{
|
||||||
ETH->MACMIIDR = val;
|
ETH->MACMIIDR = val;
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||||
|
|
||||||
uint32_t timeout = 0x100000;
|
uint32_t timeout = 0x100000;
|
||||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||||
;
|
|
||||||
|
|
||||||
// If timeout = 0, is an error.
|
// If timeout = 0, is an error.
|
||||||
return timeout ? 0 : -1;
|
return timeout ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethPHYRegRead(uint32_t reg)
|
static int ch32v307ethPHYRegRead( uint32_t reg )
|
||||||
{
|
{
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||||
|
|
||||||
uint32_t timeout = 0x100000;
|
uint32_t timeout = 0x100000;
|
||||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||||
;
|
|
||||||
|
|
||||||
// If timeout = 0, is an error.
|
// If timeout = 0, is an error.
|
||||||
return timeout ? ETH->MACMIIDR : -1;
|
return timeout ? ETH->MACMIIDR : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ch32v307ethGetMacInUC(uint8_t *mac)
|
|
||||||
|
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||||
{
|
{
|
||||||
// Mac is backwards.
|
// Mac is backwards.
|
||||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5);
|
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
|
||||||
for (int i = 0; i < 6; i++)
|
for( int i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
mac[i] = *(macaddr--);
|
mac[i] = *(macaddr--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethInit(void)
|
static int ch32v307ethInit( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||||
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset)
|
funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
|
||||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW);
|
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Configure strapping.
|
// Configure strapping.
|
||||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||||
funDigitalWrite(PA1, FUN_HIGH);
|
funDigitalWrite( PA1, FUN_HIGH );
|
||||||
funDigitalWrite(PA0, FUN_HIGH);
|
funDigitalWrite( PA0, FUN_HIGH );
|
||||||
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay
|
funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
|
||||||
funDigitalWrite(PC2, FUN_HIGH);
|
funDigitalWrite( PC2, FUN_HIGH );
|
||||||
|
|
||||||
// Pull-up MDIO
|
// Pull-up MDIO
|
||||||
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||||
funDigitalWrite(PD9, FUN_HIGH);
|
funDigitalWrite( PD9, FUN_HIGH );
|
||||||
|
|
||||||
// Will be required later.
|
// Will be required later.
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||||
|
|
||||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||||
// Clock Tree:
|
// Clock Tree:
|
||||||
// 8MHz Input
|
// 8MHz Input
|
||||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||||
// PREDIV1 = 2 (1 in register).
|
// PREDIV1 = 2 (1 in register).
|
||||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||||
// PLL = 18 (0 in register) = 72MHz
|
// PLL = 18 (0 in register) = 72MHz
|
||||||
// PLLVCO = 144MHz
|
// PLLVCO = 144MHz
|
||||||
// SYSCLK = PLLVCO = 144MHz
|
// SYSCLK = PLLVCO = 144MHz
|
||||||
// Use EXT_125M (ETH1G_SRC)
|
// Use EXT_125M (ETH1G_SRC)
|
||||||
|
|
||||||
// Switch processor back to HSI so we don't eat dirt.
|
// Switch processor back to HSI so we don't eat dirt.
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||||
|
|
||||||
// Setup clock tree.
|
// Setup clock tree.
|
||||||
RCC->CFGR2 |=
|
RCC->CFGR2 |=
|
||||||
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
(1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||||
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
(1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||||
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII
|
(2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
|
||||||
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
(7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||||
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
(1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||||
0;
|
0;
|
||||||
|
|
||||||
// Power on PLLs
|
// Power on PLLs
|
||||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
if( timeout == 0 ) return -5;
|
||||||
if (timeout == 0) return -5;
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
if( timeout == 0 ) return -6;
|
||||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
|
||||||
if (timeout == 0) return -6;
|
|
||||||
|
|
||||||
// PLL = x18 (0 in register)
|
// PLL = x18 (0 in register)
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0;
|
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||||
RCC->CTLR |= RCC_PLLON;
|
RCC->CTLR |= RCC_PLLON;
|
||||||
|
|
||||||
for (timeout = 10000; timeout > 0; timeout--)
|
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
if( timeout == 0 ) return -7;
|
||||||
if (timeout == 0) return -7;
|
|
||||||
|
|
||||||
// Switch to PLL.
|
// Switch to PLL.
|
||||||
#ifdef CH32V307GIGABIT_MCO25
|
#ifdef CH32V307GIGABIT_MCO25
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9 << 24); // And output clock on PA8
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9<<24); // And output clock on PA8
|
||||||
#else
|
#else
|
||||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For clock in.
|
// For clock in.
|
||||||
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125
|
funPinMode( PB1, GPIO_CFGLR_IN_FLOAT ); //GMII_CLK125
|
||||||
|
|
||||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||||
|
|
||||||
// Power on and reset.
|
// Power on and reset.
|
||||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||||
RCC->AHBRSTR &= ~RCC_ETHMACRST;
|
RCC->AHBRSTR &=~RCC_ETHMACRST;
|
||||||
|
|
||||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||||
|
|
||||||
// Wait for reset to complete.
|
// Wait for reset to complete.
|
||||||
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--)
|
for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
|
||||||
{
|
{
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use RGMII
|
// Use RGMII
|
||||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL;
|
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
|
||||||
|
|
||||||
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO
|
funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
|
||||||
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC
|
funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
|
||||||
|
|
||||||
// For clock output to Ethernet module.
|
// For clock output to Ethernet module.
|
||||||
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL
|
funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
|
||||||
|
|
||||||
// Release PHY from reset.
|
// Release PHY from reset.
|
||||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH);
|
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||||
|
|
||||||
funPinMode(PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD3
|
funPinMode( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
|
||||||
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2
|
funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
|
||||||
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1
|
funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
|
||||||
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0
|
funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
|
||||||
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL
|
funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
|
||||||
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC
|
funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
|
||||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||||
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL
|
funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
|
||||||
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC
|
funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
|
||||||
|
|
||||||
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V
|
funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
|
||||||
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1
|
funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
|
||||||
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1
|
funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
|
||||||
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1
|
funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
|
||||||
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0]
|
funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
|
||||||
|
|
||||||
// Configure MDC/MDIO
|
// Configure MDC/MDIO
|
||||||
// Conflicting notes - some say /42, others don't.
|
// Conflicting notes - some say /42, others don't.
|
||||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||||
|
|
||||||
// Update MACCR
|
// Update MACCR
|
||||||
ETH->MACCR =
|
ETH->MACCR =
|
||||||
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay
|
( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
|
||||||
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||||
(0 << 22) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
( 0 << 22 ) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||||
(0 << 21) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||||
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||||
(0 << 17) | // IFG = 0, 96-bit guard time.
|
( 0 << 17 ) | // IFG = 0, 96-bit guard time.
|
||||||
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||||
(0 << 12) | // Self Loop = 0
|
( 0 << 12 ) | // Self Loop = 0
|
||||||
(0 << 11) | // Full-Duplex Mode (UNSET TO START)
|
( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
|
||||||
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||||
(1 << 7) | // APCS (automatically strip frames)
|
( 1 << 7 ) | // APCS (automatically strip frames)
|
||||||
(1 << 3) | // TE (Transmit enable!)
|
( 1 << 3 ) | // TE (Transmit enable!)
|
||||||
(1 << 2) | // RE (Receive Enable)
|
( 1 << 2 ) | // RE (Receive Enable)
|
||||||
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong)
|
( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||||
0;
|
0;
|
||||||
|
|
||||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||||
|
|
||||||
// Reset the physical layer
|
// Reset the physical layer
|
||||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||||
PHY_Reset |
|
PHY_Reset |
|
||||||
1 << 12 | // Auto negotiate
|
1<<12 | // Auto negotiate
|
||||||
1 << 8 | // Duplex
|
1<<8 | // Duplex
|
||||||
1 << 6 | // Speed Bit.
|
1<<6 | // Speed Bit.
|
||||||
0);
|
0 );
|
||||||
|
|
||||||
// De-assert reset.
|
// De-assert reset.
|
||||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||||
1 << 12 | // Auto negotiate
|
1<<12 | // Auto negotiate
|
||||||
1 << 8 | // Duplex
|
1<<8 | // Duplex
|
||||||
1 << 6 | // Speed Bit.
|
1<<6 | // Speed Bit.
|
||||||
0);
|
0 );
|
||||||
|
|
||||||
ch32v307ethPHYRegRead(0x03);
|
ch32v307ethPHYRegRead( 0x03 );
|
||||||
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe.
|
ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
|
||||||
if (ch32v307eth_phyid == 0xc916)
|
if( ch32v307eth_phyid == 0xc916 )
|
||||||
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select.
|
ch32v307ethPHYRegWrite( 0x1F, 0x0a43 ); // RTL8211FS needs page select.
|
||||||
|
|
||||||
ch32v307ethGetMacInUC(ch32v307eth_mac);
|
ch32v307ethGetMacInUC( ch32v307eth_mac );
|
||||||
|
|
||||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5] << 8) | ch32v307eth_mac[4]);
|
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5]<<8) | ch32v307eth_mac[4]);
|
||||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1] << 8) | (ch32v307eth_mac[2] << 16) | (ch32v307eth_mac[3] << 24));
|
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1]<<8) | (ch32v307eth_mac[2]<<16) | (ch32v307eth_mac[3]<<24));
|
||||||
|
|
||||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||||
ETH_SourceAddrFilter_Disable |
|
ETH_SourceAddrFilter_Disable |
|
||||||
ETH_PassControlFrames_BlockAll |
|
ETH_PassControlFrames_BlockAll |
|
||||||
ETH_BroadcastFramesReception_Enable |
|
ETH_BroadcastFramesReception_Enable |
|
||||||
ETH_DestinationAddrFilter_Normal |
|
ETH_DestinationAddrFilter_Normal |
|
||||||
ETH_PromiscuousMode_Disable |
|
ETH_PromiscuousMode_Disable |
|
||||||
ETH_MulticastFramesFilter_Perfect |
|
ETH_MulticastFramesFilter_Perfect |
|
||||||
ETH_UnicastFramesFilter_Perfect);
|
ETH_UnicastFramesFilter_Perfect);
|
||||||
|
|
||||||
ETH->MACHTHR = (uint32_t)0;
|
ETH->MACHTHR = (uint32_t)0;
|
||||||
ETH->MACHTLR = (uint32_t)0;
|
ETH->MACHTLR = (uint32_t)0;
|
||||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||||
|
|
||||||
ETH->MACFCR = 0; // No pause frames.
|
ETH->MACFCR = 0; // No pause frames.
|
||||||
|
|
||||||
// Configure RX/TX chains.
|
// Configure RX/TX chains.
|
||||||
ETH_DMADESCTypeDef *tdesc;
|
ETH_DMADESCTypeDef *tdesc;
|
||||||
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||||
{
|
{
|
||||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||||
tdesc->ControlBufferSize = 0;
|
tdesc->ControlBufferSize = 0;
|
||||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||||
}
|
}
|
||||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||||
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||||
{
|
{
|
||||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||||
}
|
}
|
||||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||||
|
|
||||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||||
|
|
||||||
// Receive a good frame half interrupt mask.
|
// Receive a good frame half interrupt mask.
|
||||||
// Receive CRC error frame half interrupt mask.
|
// Receive CRC error frame half interrupt mask.
|
||||||
// For the future: Why do we want this?
|
// For the future: Why do we want this?
|
||||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||||
|
|
||||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||||
ETH_DMA_IT_R | // Receive
|
ETH_DMA_IT_R | // Receive
|
||||||
ETH_DMA_IT_T | // Transmit
|
ETH_DMA_IT_T | // Transmit
|
||||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||||
|
|
||||||
NVIC_EnableIRQ(ETH_IRQn);
|
NVIC_EnableIRQ( ETH_IRQn );
|
||||||
|
|
||||||
// Actually enable receiving process.
|
// Actually enable receiving process.
|
||||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ETH_IRQHandler(void) __attribute__((interrupt));
|
void ETH_IRQHandler( void ) __attribute__((interrupt));
|
||||||
void ETH_IRQHandler(void)
|
void ETH_IRQHandler( void )
|
||||||
{
|
{
|
||||||
uint32_t int_sta;
|
uint32_t int_sta;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int_sta = ETH->DMASR;
|
int_sta = ETH->DMASR;
|
||||||
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0)
|
if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off nominal situations.
|
// Off nominal situations.
|
||||||
if (int_sta & ETH_DMA_IT_AIS)
|
if (int_sta & ETH_DMA_IT_AIS)
|
||||||
{
|
{
|
||||||
// Receive buffer unavailable interrupt enable.
|
// Receive buffer unavailable interrupt enable.
|
||||||
if (int_sta & ETH_DMA_IT_RBU)
|
if (int_sta & ETH_DMA_IT_RBU)
|
||||||
{
|
{
|
||||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||||
if ((INFO->CHIPID & 0xf0) == 0x10)
|
if((INFO->CHIPID & 0xf0) == 0x10)
|
||||||
{
|
{
|
||||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||||
ETH->DMARPDR = 0;
|
ETH->DMARPDR = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nominal interrupts.
|
// Nominal interrupts.
|
||||||
if (int_sta & ETH_DMA_IT_NIS)
|
if( int_sta & ETH_DMA_IT_NIS )
|
||||||
{
|
{
|
||||||
if (int_sta & ETH_DMA_IT_R)
|
if( int_sta & ETH_DMA_IT_R )
|
||||||
{
|
{
|
||||||
// Received a packet, normally.
|
// Received a packet, normally.
|
||||||
// Status is in Table 27-17 Definitions of RDes0
|
// Status is in Table 27-17 Definitions of RDes0
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||||
// XXX TODO: Restructure this to allow for
|
// XXX TODO: Restructure this to allow for
|
||||||
ETH->DMASR = ETH_DMA_IT_R;
|
ETH->DMASR = ETH_DMA_IT_R;
|
||||||
|
|
||||||
uint32_t status = pDMARxGet->Status;
|
uint32_t status = pDMARxGet->Status;
|
||||||
if (status & ETH_DMARxDesc_OWN) break;
|
if( status & ETH_DMARxDesc_OWN ) break;
|
||||||
|
|
||||||
// We only have a valid packet in a specific situation.
|
// We only have a valid packet in a specific situation.
|
||||||
// So, we take the status, then mask off the bits we care about
|
// So, we take the status, then mask off the bits we care about
|
||||||
// And see if they're equal to the ones that need to be set/unset.
|
// And see if they're equal to the ones that need to be set/unset.
|
||||||
const uint32_t mask =
|
const uint32_t mask =
|
||||||
ETH_DMARxDesc_OWN |
|
ETH_DMARxDesc_OWN |
|
||||||
ETH_DMARxDesc_LS |
|
ETH_DMARxDesc_LS |
|
||||||
ETH_DMARxDesc_ES |
|
ETH_DMARxDesc_ES |
|
||||||
ETH_DMARxDesc_FS;
|
ETH_DMARxDesc_FS;
|
||||||
const uint32_t eq =
|
const uint32_t eq =
|
||||||
0 |
|
0 |
|
||||||
ETH_DMARxDesc_LS |
|
ETH_DMARxDesc_LS |
|
||||||
0 |
|
0 |
|
||||||
ETH_DMARxDesc_FS;
|
ETH_DMARxDesc_FS;
|
||||||
|
|
||||||
int suppress_own = 0;
|
int suppress_own = 0;
|
||||||
|
|
||||||
if ((status & mask) == eq)
|
if( ( status & mask ) == eq )
|
||||||
{
|
{
|
||||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||||
if (frame_length > 0)
|
if( frame_length > 0 )
|
||||||
{
|
{
|
||||||
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr;
|
uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
|
||||||
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet);
|
suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, Invalid Packet
|
// Otherwise, Invalid Packet
|
||||||
|
|
||||||
// Relinquish control back to underlying hardware.
|
// Relinquish control back to underlying hardware.
|
||||||
if (!suppress_own)
|
if( !suppress_own )
|
||||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||||
|
|
||||||
// Tricky logic for figuring out the next packet. Originally
|
// Tricky logic for figuring out the next packet. Originally
|
||||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||||
else
|
else
|
||||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||||
}
|
}
|
||||||
} while (1);
|
} while( 1 );
|
||||||
}
|
}
|
||||||
if (int_sta & ETH_DMA_IT_T)
|
if( int_sta & ETH_DMA_IT_T )
|
||||||
{
|
{
|
||||||
ch32v307ethInitHandleTXC();
|
ch32v307ethInitHandleTXC();
|
||||||
ETH->DMASR = ETH_DMA_IT_T;
|
ETH->DMASR = ETH_DMA_IT_T;
|
||||||
}
|
}
|
||||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||||
}
|
}
|
||||||
} while (1);
|
} while( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc)
|
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc)
|
||||||
{
|
{
|
||||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||||
// This also provides a transmit timestamp, which could be
|
// This also provides a transmit timestamp, which could be
|
||||||
// used for PTP.
|
// used for PTP.
|
||||||
// But we don't want to do that.
|
// But we don't want to do that.
|
||||||
// We just want to go. If anyone cares, they can check later.
|
// We just want to go. If anyone cares, they can check later.
|
||||||
|
|
||||||
if (pDMATxSet->Status & ETH_DMATxDesc_OWN)
|
if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
|
||||||
{
|
{
|
||||||
ETH->DMATPDR = 0;
|
ETH->DMATPDR = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
||||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||||
|
|
||||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||||
pDMATxSet->Status =
|
pDMATxSet->Status =
|
||||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||||
enable_txc | // Interrupt when complete
|
enable_txc | // Interrupt when complete
|
||||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||||
|
|
||||||
pDMATxSet = (ETH_DMADESCTypeDef *)pDMATxSet->Buffer2NextDescAddr;
|
pDMATxSet = (ETH_DMADESCTypeDef*)pDMATxSet->Buffer2NextDescAddr;
|
||||||
|
|
||||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||||
ETH->DMATPDR = 0;
|
ETH->DMATPDR = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
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
|
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ch32fun.h"
|
|
||||||
#include "usb_config.h"
|
|
||||||
#include "usb_defines.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "usb_defines.h"
|
||||||
|
#include "usb_config.h"
|
||||||
|
|
||||||
struct _USBState
|
struct _USBState
|
||||||
{
|
{
|
||||||
// Setup Request
|
// Setup Request
|
||||||
uint8_t USBHS_SetupReqCode;
|
uint8_t USBHS_SetupReqCode;
|
||||||
uint8_t USBHS_SetupReqType;
|
uint8_t USBHS_SetupReqType;
|
||||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||||
uint32_t USBHS_IndexValue;
|
uint32_t USBHS_IndexValue;
|
||||||
|
|
||||||
// USB Device Status
|
// USB Device Status
|
||||||
uint16_t USBHS_DevConfig;
|
uint16_t USBHS_DevConfig;
|
||||||
uint16_t USBHS_DevAddr;
|
uint16_t USBHS_DevAddr;
|
||||||
uint8_t USBHS_DevSleepStatus;
|
uint8_t USBHS_DevSleepStatus;
|
||||||
uint8_t USBHS_DevEnumStatus;
|
uint8_t USBHS_DevEnumStatus;
|
||||||
|
|
||||||
uint8_t *pCtrlPayloadPtr;
|
uint8_t * pCtrlPayloadPtr;
|
||||||
|
|
||||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||||
|
|
||||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF)
|
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||||
|
|
||||||
#if HUSB_HID_INTERFACES > 0
|
#if HUSB_HID_INTERFACES > 0
|
||||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||||
#endif
|
#endif
|
||||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Provided functions:
|
// Provided functions:
|
||||||
int HSUSBSetup();
|
int HSUSBSetup();
|
||||||
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||||
|
|
||||||
// Implement the following:
|
// Implement the following:
|
||||||
#if HUSB_HID_USER_REPORTS
|
#if HUSB_HID_USER_REPORTS
|
||||||
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||||
int HandleHidUserSetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||||
void HandleHidUserReportDataOut(struct _USBState *ctx, uint8_t *data, int len);
|
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||||
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len);
|
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||||
void HandleHidUserReportOutComplete(struct _USBState *ctx);
|
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HUSB_BULK_USER_REPORTS
|
#if HUSB_BULK_USER_REPORTS
|
||||||
void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
void HandleGotEPComplete( struct _USBState * ctx, int ep );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct _USBState HSUSBCTX;
|
extern struct _USBState HSUSBCTX;
|
||||||
|
|
||||||
|
|
||||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
||||||
|
|
||||||
static inline uint8_t *USBHS_GetEPBufferIfAvailable(int endp)
|
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||||
{
|
{
|
||||||
if (HSUSBCTX.USBHS_Endp_Busy[endp]) return 0;
|
if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
|
||||||
return USBHSD_UEP_TXBUF(endp);
|
return USBHSD_UEP_TXBUF( endp );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void USBHS_SendEndpoint(int endp, int len, const uint8_t *data)
|
static inline void USBHS_SendEndpoint( int endp, int len, const uint8_t * data )
|
||||||
{
|
{
|
||||||
if (endp)
|
if( endp )
|
||||||
{
|
{
|
||||||
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data;
|
(((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
|
||||||
}
|
}
|
||||||
USBHSD_UEP_TLEN(endp) = len;
|
USBHSD_UEP_TLEN( endp ) = len;
|
||||||
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
|
USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||||
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01;
|
HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
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
|
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||||
* See the GitHub for more information:
|
* See the GitHub for more information:
|
||||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||||
*
|
*
|
||||||
* Ver 1.1 09 Sep 2024
|
* Ver 1.1 09 Sep 2024
|
||||||
*
|
*
|
||||||
* Released under the MIT Licence
|
* Released under the MIT Licence
|
||||||
* Copyright ADBeta (c) 2024
|
* Copyright ADBeta (c) 2024
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
* deal in the Software without restriction, including without limitation the
|
* deal in the Software without restriction, including without limitation the
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#ifndef CH32V003_LIB_RAND
|
#ifndef CH32V003_LIB_RAND
|
||||||
#define CH32V003_LIB_RAND
|
#define CH32V003_LIB_RAND
|
||||||
|
|
||||||
|
|
@ -35,12 +35,13 @@
|
||||||
// Example: #define RANDOM_STRENGTH 2
|
// Example: #define RANDOM_STRENGTH 2
|
||||||
|
|
||||||
#ifndef RANDOM_STRENGTH
|
#ifndef RANDOM_STRENGTH
|
||||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// @brief set the random LFSR values seed by default to a known-good value
|
// @brief set the random LFSR values seed by default to a known-good value
|
||||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||||
|
|
||||||
|
|
||||||
/*** Library specific Functions - Do Not Use *********************************/
|
/*** Library specific Functions - Do Not Use *********************************/
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
||||||
|
|
@ -50,59 +51,63 @@ static uint32_t _rand_lfsr = 0x747AA32F;
|
||||||
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
||||||
uint8_t _rand_lfsr_update(void)
|
uint8_t _rand_lfsr_update(void)
|
||||||
{
|
{
|
||||||
// Shifting to MSB to make calculations more efficient later
|
// Shifting to MSB to make calculations more efficient later
|
||||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||||
|
|
||||||
// Calculate the MSB to be put into the LFSR
|
// Calculate the MSB to be put into the LFSR
|
||||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||||
// Shift the lfsr and append the MSB to it
|
// Shift the lfsr and append the MSB to it
|
||||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||||
// Return the LSB instead of MSB
|
// Return the LSB instead of MSB
|
||||||
return msb >> 31;
|
return msb >> 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||||
/// a random bit from LFSR taps, 32 times.
|
/// a random bit from LFSR taps, 32 times.
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return a (psuedo)random 32-bit value
|
/// @return a (psuedo)random 32-bit value
|
||||||
uint32_t _rand_gen_32b(void)
|
uint32_t _rand_gen_32b(void)
|
||||||
{
|
{
|
||||||
uint32_t rand_out = 0;
|
uint32_t rand_out = 0;
|
||||||
|
|
||||||
uint8_t bits = 32;
|
uint8_t bits = 32;
|
||||||
while (bits--)
|
while(bits--)
|
||||||
{
|
{
|
||||||
// Shift the current rand value for the new LSB
|
// Shift the current rand value for the new LSB
|
||||||
rand_out = rand_out << 1;
|
rand_out = rand_out << 1;
|
||||||
// Append the LSB
|
// Append the LSB
|
||||||
rand_out |= _rand_lfsr_update();
|
rand_out |= _rand_lfsr_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||||
/// a random bit from LFSR taps, n times.
|
/// a random bit from LFSR taps, n times.
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return a (psuedo)random n-bit value
|
/// @return a (psuedo)random n-bit value
|
||||||
uint32_t _rand_gen_nb(int bits)
|
uint32_t _rand_gen_nb( int bits)
|
||||||
{
|
{
|
||||||
uint32_t rand_out = 0;
|
uint32_t rand_out = 0;
|
||||||
|
|
||||||
while (bits--)
|
while(bits--)
|
||||||
{
|
{
|
||||||
// Shift the current rand value for the new LSB
|
// Shift the current rand value for the new LSB
|
||||||
rand_out = rand_out << 1;
|
rand_out = rand_out << 1;
|
||||||
// Append the LSB
|
// Append the LSB
|
||||||
rand_out |= _rand_lfsr_update();
|
rand_out |= _rand_lfsr_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*** API Functions ***********************************************************/
|
/*** API Functions ***********************************************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/// @brief seeds the Random LFSR to the value passed
|
/// @brief seeds the Random LFSR to the value passed
|
||||||
|
|
@ -110,39 +115,40 @@ uint32_t _rand_gen_nb(int bits)
|
||||||
/// @return None
|
/// @return None
|
||||||
void seed(const uint32_t seed_val)
|
void seed(const uint32_t seed_val)
|
||||||
{
|
{
|
||||||
_rand_lfsr = seed_val;
|
_rand_lfsr = seed_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||||
/// you have selected
|
/// you have selected
|
||||||
/// @param None
|
/// @param None
|
||||||
/// @return 32bit Random value
|
/// @return 32bit Random value
|
||||||
uint32_t rand(void)
|
uint32_t rand(void)
|
||||||
{
|
{
|
||||||
uint32_t rand_out = 0;
|
uint32_t rand_out = 0;
|
||||||
|
|
||||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||||
#if RANDOM_STRENGTH == 1
|
#if RANDOM_STRENGTH == 1
|
||||||
// Update the LFSR, discard result, and return _lsfr raw
|
// Update the LFSR, discard result, and return _lsfr raw
|
||||||
(void)_rand_lfsr_update();
|
(void)_rand_lfsr_update();
|
||||||
rand_out = _rand_lfsr;
|
rand_out = _rand_lfsr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||||
// bits from the LFSR
|
// bits from the LFSR
|
||||||
#if RANDOM_STRENGTH == 2
|
#if RANDOM_STRENGTH == 2
|
||||||
rand_out = _rand_gen_32b();
|
rand_out = _rand_gen_32b();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||||
// together
|
// together
|
||||||
#if RANDOM_STRENGTH == 3
|
#if RANDOM_STRENGTH == 3
|
||||||
uint32_t rand_a = _rand_gen_32b();
|
uint32_t rand_a = _rand_gen_32b();
|
||||||
uint32_t rand_b = _rand_gen_32b();
|
uint32_t rand_b = _rand_gen_32b();
|
||||||
rand_out = rand_a ^ rand_b;
|
rand_out = rand_a ^ rand_b;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return rand_out;
|
return rand_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
142
inc/extralibs/register_debug_utilities.h
Normal file
142
inc/extralibs/register_debug_utilities.h
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//! ####################################
|
||||||
|
//! PRINT BITS
|
||||||
|
//! ####################################
|
||||||
|
|
||||||
|
// eg: UTIL_PRINT_BITS(reg, 32, 16);
|
||||||
|
void UTIL_PRINT_BITS(u32 val, u8 len, u8 divider_len) {
|
||||||
|
const char* separator = "\n";
|
||||||
|
|
||||||
|
for (int i = (len)-1; i >= 0; i--) {
|
||||||
|
printf("%d| ", i);
|
||||||
|
if (i > 0) printf(i % divider_len ? "" : "%s", separator);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
for (int i = (len)-1; i >= 0; i--) {
|
||||||
|
printf(i < 10 ? "%2d" : "%3d", ((val) >> i) & 1);
|
||||||
|
if (i > 0) printf(i % divider_len ? " " : " %s", separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! ####################################
|
||||||
|
//! PRINT BITS VALUES
|
||||||
|
//! ####################################
|
||||||
|
|
||||||
|
// eg: UTIL_PRINT_BITS_VALUES(
|
||||||
|
// reg,
|
||||||
|
// "a", 0,
|
||||||
|
// "b", 1,
|
||||||
|
// "c", 2,
|
||||||
|
// );
|
||||||
|
|
||||||
|
void UTIL_PRINT_BITS_VALUES(u32 reg, ...) {
|
||||||
|
struct BitPair { const char* name; int pos; };
|
||||||
|
va_list args;
|
||||||
|
va_start(args, reg);
|
||||||
|
|
||||||
|
// Count how many pairs were passed (until NULL name)
|
||||||
|
int pair_count = 0;
|
||||||
|
va_list count_args;
|
||||||
|
va_copy(count_args, args);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const char* name = va_arg(count_args, const char*);
|
||||||
|
if (name == NULL) break;
|
||||||
|
int pos = va_arg(count_args, int);
|
||||||
|
(void)pos;
|
||||||
|
pair_count++;
|
||||||
|
}
|
||||||
|
va_end(count_args);
|
||||||
|
|
||||||
|
// Read all the pairs
|
||||||
|
struct BitPair pairs[pair_count];
|
||||||
|
for (int i = 0; i < pair_count; i++) {
|
||||||
|
pairs[i].name = va_arg(args, const char*);
|
||||||
|
pairs[i].pos = va_arg(args, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// Print the pairs
|
||||||
|
for (int i = 0; i < pair_count; i++) {
|
||||||
|
if (i > 0) printf(", ");
|
||||||
|
printf("%s=%d", pairs[i].name, (unsigned int)((reg >> pairs[i].pos) & 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! ####################################
|
||||||
|
//! PRINT BITS RANGE
|
||||||
|
//! ####################################
|
||||||
|
|
||||||
|
// eg: UTIL_PRINT_BIT_RANGE(
|
||||||
|
// reg,
|
||||||
|
// "FIELD3", 5, 3,
|
||||||
|
// "FIELD2", 2, 1,
|
||||||
|
// "FIELD1", 0, 0,
|
||||||
|
// NULL
|
||||||
|
// );
|
||||||
|
|
||||||
|
// NOTE: NULL terminated REQUIRED
|
||||||
|
void UTIL_PRINT_BIT_RANGE(u32 reg, ...) {
|
||||||
|
// Define the struct
|
||||||
|
typedef struct { const char* name; int end; int start; } BitField;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, reg);
|
||||||
|
|
||||||
|
// Count how many fields were passed (until NULL name)
|
||||||
|
int field_count = 0;
|
||||||
|
va_list count_args;
|
||||||
|
va_copy(count_args, args);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const char* name = va_arg(count_args, const char*);
|
||||||
|
if (name == NULL) break;
|
||||||
|
int start = va_arg(count_args, int);
|
||||||
|
(void)start;
|
||||||
|
int end = va_arg(count_args, int);
|
||||||
|
(void)end;
|
||||||
|
field_count++;
|
||||||
|
}
|
||||||
|
va_end(count_args);
|
||||||
|
|
||||||
|
// Read all the fields
|
||||||
|
BitField fields[field_count];
|
||||||
|
for (int i = 0; i < field_count; i++) {
|
||||||
|
fields[i].name = va_arg(args, const char*);
|
||||||
|
fields[i].end = va_arg(args, int); // get end first
|
||||||
|
fields[i].start = va_arg(args, int); // then get start
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// Print the fields
|
||||||
|
for (int i = 0; i < field_count; i++) {
|
||||||
|
if (i > 0) printf(", ");
|
||||||
|
int start = fields[i].start;
|
||||||
|
int end = fields[i].end;
|
||||||
|
|
||||||
|
if (end == start) {
|
||||||
|
// Single bit
|
||||||
|
printf("%s = %d [%d]", fields[i].name, (reg >> start) & 1, start);
|
||||||
|
} else {
|
||||||
|
// Multiple bits
|
||||||
|
int mask = ((1 << (end - start + 1)) - 1);
|
||||||
|
printf("%s = 0x%02X [%d:%d]", fields[i].name, (reg >> start) & mask, end, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! ####################################
|
||||||
|
//! PRINT REGS
|
||||||
|
//! ####################################
|
||||||
|
|
||||||
|
#define UTIL_PRINT_REG8(reg, label) printf("%s: 0x%02X\n", label, (unsigned int)(reg));
|
||||||
|
#define UTIL_PRINT_REG16(reg, label) printf("%s: 0x%04X\n", label, (unsigned int)(reg));
|
||||||
|
#define UTIL_PRINT_REG32(reg, label) printf("%s: 0x%08X\n", label, (unsigned int)(reg));
|
||||||
|
|
||||||
|
|
||||||
127
inc/extralibs/rtc_helper.h
Normal file
127
inc/extralibs/rtc_helper.h
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
// MIT License
|
||||||
|
// Copyright (c) 2025 UniTheCat
|
||||||
|
|
||||||
|
#define RTC_TICKS_PER_SECOND 32768
|
||||||
|
|
||||||
|
#define SECONDS_PER_MINUTE 60
|
||||||
|
#define SECONDS_PER_HOUR 3600
|
||||||
|
#define SECONDS_PER_DAY 86400
|
||||||
|
|
||||||
|
#define IS_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
|
||||||
|
|
||||||
|
// Array of days in each month (non-leap year)
|
||||||
|
const u8 DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u16 year;
|
||||||
|
u8 month;
|
||||||
|
u8 day;
|
||||||
|
} rtc_date_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 hr;
|
||||||
|
u8 min;
|
||||||
|
u8 sec;
|
||||||
|
u16 ms;
|
||||||
|
} rtc_time_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rtc_date_t date;
|
||||||
|
rtc_time_t time;
|
||||||
|
} rtc_datetime_t;
|
||||||
|
|
||||||
|
// calculate days of the current year. eg. 2020-02-05 is 36 day
|
||||||
|
u32 RTC_days_of_year(u16 year, u8 month, u8 day) {
|
||||||
|
u32 day_of_year = 0;
|
||||||
|
|
||||||
|
// Add days from January to month-1
|
||||||
|
for (u8 m = 0; m < month - 1; m++) {
|
||||||
|
day_of_year += DAYS_IN_MONTH[m];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add extra day for February (full month) if it's a leap year
|
||||||
|
if (month > 2 && IS_LEAP_YEAR(year)) {
|
||||||
|
day_of_year += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add days in the current month
|
||||||
|
day_of_year += day;
|
||||||
|
|
||||||
|
return day_of_year;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 RTC_get_seconds(u16 year, u8 month, u8 day, u8 hr, u8 min, u8 sec) {
|
||||||
|
//# Validate input
|
||||||
|
if (month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||||
|
hr > 23 || min > 59 || sec > 59 || year < 1970) { return 0; }
|
||||||
|
|
||||||
|
// calculate days of the current year, -1 for 0-based days
|
||||||
|
u32 days = RTC_days_of_year(year, month, day) - 1;
|
||||||
|
|
||||||
|
// add the days count excluding the current year
|
||||||
|
// (start from epoch time 1970-01-01 00:00:00)
|
||||||
|
for (int y=1970; y < year; y++) {
|
||||||
|
days += IS_LEAP_YEAR(y) ? 366 : 365;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate total seconds
|
||||||
|
return days * SECONDS_PER_DAY +
|
||||||
|
hr * SECONDS_PER_HOUR +
|
||||||
|
min * SECONDS_PER_MINUTE + sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_time_t RTC_get_time(u32 total_seconds, u32 ms) {
|
||||||
|
u32 minutes = total_seconds / 60;
|
||||||
|
|
||||||
|
return (rtc_time_t) {
|
||||||
|
.sec = total_seconds % 60,
|
||||||
|
.min = minutes % 60,
|
||||||
|
.hr = (minutes / 60) % 24,
|
||||||
|
.ms = ms
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_date_t RTC_get_date(u32 total_seconds, u16 year_base) {
|
||||||
|
rtc_date_t output = {
|
||||||
|
.year = year_base,
|
||||||
|
.month = 1,
|
||||||
|
.day = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Days since epoch
|
||||||
|
u32 days_remaining = total_seconds / SECONDS_PER_DAY;
|
||||||
|
|
||||||
|
// Find the year
|
||||||
|
while(1) {
|
||||||
|
u32 days_in_year = IS_LEAP_YEAR(output.year) ? 366 : 365;
|
||||||
|
if (days_remaining < days_in_year) break;
|
||||||
|
days_remaining -= days_in_year;
|
||||||
|
output.year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the month
|
||||||
|
for (u8 m = 0; m < 12; m++) {
|
||||||
|
u8 days_in_month = DAYS_IN_MONTH[m];
|
||||||
|
if (m == 1 && IS_LEAP_YEAR(output.year)) days_in_month = 29;
|
||||||
|
if (days_remaining < days_in_month) break;
|
||||||
|
|
||||||
|
days_remaining -= days_in_month;
|
||||||
|
output.month++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add 1 because days_remaining is 0-based
|
||||||
|
output.day = days_remaining + 1;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_print_date(rtc_date_t date, char *delimiter) {
|
||||||
|
printf("%04d", date.year);
|
||||||
|
printf("%s%02d", delimiter, date.month);
|
||||||
|
printf("%s%02d", delimiter, date.day);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_print_time(rtc_time_t time) {
|
||||||
|
printf("%02d:%02d:%02d.%03d",
|
||||||
|
time.hr, time.min, time.sec, time.ms);
|
||||||
|
}
|
||||||
|
|
@ -6,19 +6,19 @@
|
||||||
#ifndef _SSD1306_H
|
#ifndef _SSD1306_H
|
||||||
#define _SSD1306_H
|
#define _SSD1306_H
|
||||||
|
|
||||||
#include "font_8x8.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "font_8x8.h"
|
||||||
|
|
||||||
// comfortable packet size for this OLED
|
// comfortable packet size for this OLED
|
||||||
#define SSD1306_PSZ 32
|
#define SSD1306_PSZ 32
|
||||||
|
|
||||||
#if defined(SSD1306_CUSTOM)
|
#if defined (SSD1306_CUSTOM)
|
||||||
// Let the caller configure the OLED.
|
// Let the caller configure the OLED.
|
||||||
#else
|
#else
|
||||||
// characteristics of each type
|
// characteristics of each type
|
||||||
#if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64) && !defined(SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET))
|
#if !defined (SSD1306_64X32) && !defined (SSD1306_72X40) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET) )
|
||||||
#error "Please define the SSD1306_WXH resolution used in your application"
|
#error "Please define the SSD1306_WXH resolution used in your application"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SSD1306_64X32
|
#ifdef SSD1306_64X32
|
||||||
|
|
@ -28,6 +28,13 @@
|
||||||
#define SSD1306_OFFSET 32
|
#define SSD1306_OFFSET 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SSD1306_72X40
|
||||||
|
#define SSD1306_W 72
|
||||||
|
#define SSD1306_H 40
|
||||||
|
#define SSD1306_FULLUSE
|
||||||
|
#define SSD1306_OFFSET 28
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SSD1306_128X32
|
#ifdef SSD1306_128X32
|
||||||
#define SSD1306_W 128
|
#define SSD1306_W 128
|
||||||
#define SSD1306_H 32
|
#define SSD1306_H 32
|
||||||
|
|
@ -57,7 +64,7 @@
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_cmd(uint8_t cmd)
|
uint8_t ssd1306_cmd(uint8_t cmd)
|
||||||
{
|
{
|
||||||
return ssd1306_pkt_send(&cmd, 1, 1);
|
return ssd1306_pkt_send(&cmd, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -65,7 +72,7 @@ uint8_t ssd1306_cmd(uint8_t cmd)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_data(uint8_t *data, int sz)
|
uint8_t ssd1306_data(uint8_t *data, int sz)
|
||||||
{
|
{
|
||||||
return ssd1306_pkt_send(data, sz, 0);
|
return ssd1306_pkt_send(data, sz, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SSD1306_SETCONTRAST 0x81
|
#define SSD1306_SETCONTRAST 0x81
|
||||||
|
|
@ -87,7 +94,7 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
|
||||||
#define SSD1306_SETSTARTLINE 0x40
|
#define SSD1306_SETSTARTLINE 0x40
|
||||||
#define SSD1306_MEMORYMODE 0x20
|
#define SSD1306_MEMORYMODE 0x20
|
||||||
#define SSD1306_COLUMNADDR 0x21
|
#define SSD1306_COLUMNADDR 0x21
|
||||||
#define SSD1306_PAGEADDR 0x22
|
#define SSD1306_PAGEADDR 0x22
|
||||||
#define SSD1306_COMSCANINC 0xC0
|
#define SSD1306_COMSCANINC 0xC0
|
||||||
#define SSD1306_COMSCANDEC 0xC8
|
#define SSD1306_COMSCANDEC 0xC8
|
||||||
#define SSD1306_CHARGEPUMP 0x8D
|
#define SSD1306_CHARGEPUMP 0x8D
|
||||||
|
|
@ -98,172 +105,130 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
|
||||||
/* choose VCC mode */
|
/* choose VCC mode */
|
||||||
#define SSD1306_EXTERNALVCC 0x1
|
#define SSD1306_EXTERNALVCC 0x1
|
||||||
#define SSD1306_SWITCHCAPVCC 0x2
|
#define SSD1306_SWITCHCAPVCC 0x2
|
||||||
// #define vccstate SSD1306_EXTERNALVCC
|
//#define vccstate SSD1306_EXTERNALVCC
|
||||||
#define vccstate SSD1306_SWITCHCAPVCC
|
#define vccstate SSD1306_SWITCHCAPVCC
|
||||||
|
|
||||||
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
|
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
|
||||||
// OLED initialization commands for 128x32
|
// OLED initialization commands for 128x32
|
||||||
const uint8_t ssd1306_init_array[] =
|
const uint8_t ssd1306_init_array[] =
|
||||||
{
|
{
|
||||||
#ifdef SH1107
|
#ifdef SH1107
|
||||||
SSD1306_DISPLAYOFF, // Turn OLED off
|
SSD1306_DISPLAYOFF, // Turn OLED off
|
||||||
0x00, // Low column
|
0x00, // Low column
|
||||||
0x10, // High column
|
0x10, // High column
|
||||||
0xb0, // Page address
|
0xb0, // Page address
|
||||||
0xdc, 0x00, // Set Display Start Line (Where in memory it reads from)
|
0xdc, 0x00, // Set Display Start Line (Where in memory it reads from)
|
||||||
SSD1306_SETCONTRAST, 0x6f, // Set constrast
|
SSD1306_SETCONTRAST, 0x6f, // Set constrast
|
||||||
SSD1306_COLUMNADDR, // Set memory addressing mode
|
SSD1306_COLUMNADDR, // Set memory addressing mode
|
||||||
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
|
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
|
||||||
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // Iterate over all 128 rows (Multiplex Ratio)
|
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // Iterate over all 128 rows (Multiplex Ratio)
|
||||||
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
|
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
|
||||||
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
|
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
|
||||||
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
|
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
|
||||||
SSD1306_SETVCOMDETECT, 0x35, // Set vcomh
|
SSD1306_SETVCOMDETECT, 0x35, // Set vcomh
|
||||||
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
|
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
|
||||||
0xad, 0x80, // Set Charge pump
|
0xad, 0x80, // Set Charge pump
|
||||||
SSD1306_SEGREMAP, 0x01, // Default mapping
|
SSD1306_SEGREMAP, 0x01, // Default mapping
|
||||||
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
|
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
|
||||||
SSD1306_SETCONTRAST, 0xfe, // Set constrast
|
SSD1306_SETCONTRAST, 0xfe, // Set constrast
|
||||||
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
|
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
|
||||||
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // 128-wide.
|
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // 128-wide.
|
||||||
SSD1306_DISPLAYON, // Display on.
|
SSD1306_DISPLAYON, // Display on.
|
||||||
#else
|
#else
|
||||||
SSD1306_DISPLAYOFF, // 0xAE
|
SSD1306_DISPLAYOFF, // 0xAE
|
||||||
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
|
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
|
||||||
0x80, // the suggested ratio 0x80
|
0x80, // the suggested ratio 0x80
|
||||||
SSD1306_SETMULTIPLEX, // 0xA8
|
SSD1306_SETMULTIPLEX, // 0xA8
|
||||||
#ifdef SSD1306_64X32
|
#if defined(SSD1306_64X32)
|
||||||
0x1F, // for 64-wide displays
|
0x1F, // for 64-wide displays
|
||||||
|
#elif defined(SSD1306_72X40)
|
||||||
|
0x27,
|
||||||
#else
|
#else
|
||||||
0x3F, // for 128-wide displays
|
0x3F, // for 128-wide displays
|
||||||
#endif
|
#endif
|
||||||
SSD1306_SETDISPLAYOFFSET, // 0xD3
|
SSD1306_SETDISPLAYOFFSET, // 0xD3
|
||||||
0x00, // no offset
|
0x00, // no offset
|
||||||
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
|
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
|
||||||
SSD1306_CHARGEPUMP, // 0x8D
|
SSD1306_CHARGEPUMP, // 0x8D
|
||||||
0x14, // enable?
|
0x14, // enable?
|
||||||
SSD1306_MEMORYMODE, // 0x20
|
SSD1306_MEMORYMODE, // 0x20
|
||||||
0x00, // 0x0 act like ks0108
|
0x00, // 0x0 act like ks0108
|
||||||
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
|
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
|
||||||
SSD1306_COMSCANDEC,
|
SSD1306_COMSCANDEC,
|
||||||
SSD1306_SETCOMPINS, // 0xDA
|
SSD1306_SETCOMPINS, // 0xDA
|
||||||
0x12, //
|
#if defined(SSD1306_FULLUSE)
|
||||||
SSD1306_SETCONTRAST, // 0x81
|
0x12, //
|
||||||
0x8F,
|
#else
|
||||||
SSD1306_SETPRECHARGE, // 0xd9
|
0x22, //
|
||||||
0xF1,
|
#endif
|
||||||
SSD1306_SETVCOMDETECT, // 0xDB
|
SSD1306_SETCONTRAST, // 0x81
|
||||||
0x40,
|
#ifdef SSD1306_72X40
|
||||||
SSD1306_DISPLAYALLON_RESUME, // 0xA4
|
0xAF,
|
||||||
|
#else
|
||||||
|
0x8F,
|
||||||
|
#endif
|
||||||
|
SSD1306_SETPRECHARGE, // 0xd9
|
||||||
|
0xF1,
|
||||||
|
SSD1306_SETVCOMDETECT, // 0xDB
|
||||||
|
0x40,
|
||||||
|
SSD1306_DISPLAYALLON_RESUME, // 0xA4
|
||||||
#ifndef SSD1327
|
#ifndef SSD1327
|
||||||
SSD1306_NORMALDISPLAY, // 0xA6
|
SSD1306_NORMALDISPLAY, // 0xA6
|
||||||
#endif
|
#endif
|
||||||
SSD1306_DISPLAYON, // 0xAF --turn on oled panel
|
SSD1306_DISPLAYON, // 0xAF --turn on oled panel
|
||||||
#endif
|
#endif
|
||||||
SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end
|
SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// the display buffer
|
// the display buffer
|
||||||
uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8];
|
uint8_t ssd1306_buffer[SSD1306_W*SSD1306_H/8];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set the buffer to a color
|
* set the buffer to a color
|
||||||
*/
|
*/
|
||||||
void ssd1306_setbuf(uint8_t color)
|
void ssd1306_setbuf(uint8_t color)
|
||||||
{
|
{
|
||||||
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
|
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SSD1306_FULLUSE
|
|
||||||
/*
|
|
||||||
* expansion array for OLED with every other row unused
|
|
||||||
*/
|
|
||||||
const uint8_t expand[16] =
|
|
||||||
{
|
|
||||||
0x00,
|
|
||||||
0x02,
|
|
||||||
0x08,
|
|
||||||
0x0a,
|
|
||||||
0x20,
|
|
||||||
0x22,
|
|
||||||
0x28,
|
|
||||||
0x2a,
|
|
||||||
0x80,
|
|
||||||
0x82,
|
|
||||||
0x88,
|
|
||||||
0x8a,
|
|
||||||
0xa0,
|
|
||||||
0xa2,
|
|
||||||
0xa8,
|
|
||||||
0xaa,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the frame buffer
|
* Send the frame buffer
|
||||||
*/
|
*/
|
||||||
void ssd1306_refresh(void)
|
void ssd1306_refresh(void)
|
||||||
{
|
{
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
#ifdef SH1107
|
#ifdef SH1107
|
||||||
|
|
||||||
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
|
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
|
||||||
|
|
||||||
for (i = 0; i < SSD1306_H / 8; i++)
|
for(i=0;i<SSD1306_H/8;i++)
|
||||||
{
|
{
|
||||||
ssd1306_cmd(0xb0 | i);
|
ssd1306_cmd(0xb0 | i);
|
||||||
ssd1306_cmd(0x00 | (0 & 0xf));
|
ssd1306_cmd( 0x00 | (0&0xf) );
|
||||||
ssd1306_cmd(0x10 | (0 >> 4));
|
ssd1306_cmd( 0x10 | (0>>4) );
|
||||||
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 0 * SSD1306_PSZ], SSD1306_PSZ);
|
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+0*SSD1306_PSZ], SSD1306_PSZ);
|
||||||
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 1 * SSD1306_PSZ], SSD1306_PSZ);
|
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+1*SSD1306_PSZ], SSD1306_PSZ);
|
||||||
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 2 * SSD1306_PSZ], SSD1306_PSZ);
|
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+2*SSD1306_PSZ], SSD1306_PSZ);
|
||||||
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 3 * SSD1306_PSZ], SSD1306_PSZ);
|
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+3*SSD1306_PSZ], SSD1306_PSZ);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ssd1306_cmd(SSD1306_COLUMNADDR);
|
ssd1306_cmd(SSD1306_COLUMNADDR);
|
||||||
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
|
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
|
||||||
ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset)
|
ssd1306_cmd(SSD1306_OFFSET+SSD1306_W-1); // Column end address (127 = reset)
|
||||||
|
|
||||||
ssd1306_cmd(SSD1306_PAGEADDR);
|
ssd1306_cmd(SSD1306_PAGEADDR);
|
||||||
ssd1306_cmd(0); // Page start address (0 = reset)
|
ssd1306_cmd(0); // Page start address (0 = reset)
|
||||||
ssd1306_cmd(7); // Page end address
|
ssd1306_cmd(7); // Page end address
|
||||||
|
|
||||||
#ifdef SSD1306_FULLUSE
|
for(i=0;i<sizeof(ssd1306_buffer);i+=SSD1306_PSZ)
|
||||||
/* for fully used rows just plow thru everything */
|
{
|
||||||
for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ)
|
/* send PSZ block of data */
|
||||||
{
|
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
|
||||||
/* send PSZ block of data */
|
}
|
||||||
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* for displays with odd rows unused expand bytes */
|
|
||||||
uint8_t tbuf[SSD1306_PSZ], j, k;
|
|
||||||
for (i = 0; i < sizeof(ssd1306_buffer); i += 128)
|
|
||||||
{
|
|
||||||
/* low nybble */
|
|
||||||
for (j = 0; j < 128; j += SSD1306_PSZ)
|
|
||||||
{
|
|
||||||
for (k = 0; k < SSD1306_PSZ; k++)
|
|
||||||
tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf];
|
|
||||||
|
|
||||||
/* send PSZ block of data */
|
|
||||||
ssd1306_data(tbuf, SSD1306_PSZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* high nybble */
|
|
||||||
for (j = 0; j < 128; j += SSD1306_PSZ)
|
|
||||||
{
|
|
||||||
for (k = 0; k < SSD1306_PSZ; k++)
|
|
||||||
tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf];
|
|
||||||
|
|
||||||
/* send PSZ block of data */
|
|
||||||
ssd1306_data(tbuf, SSD1306_PSZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -271,22 +236,22 @@ void ssd1306_refresh(void)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
|
void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
|
||||||
{
|
{
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
/* clip */
|
/* clip */
|
||||||
if (x >= SSD1306_W)
|
if(x >= SSD1306_W)
|
||||||
return;
|
return;
|
||||||
if (y >= SSD1306_H)
|
if(y >= SSD1306_H)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* compute buffer address */
|
/* compute buffer address */
|
||||||
addr = x + SSD1306_W * (y / 8);
|
addr = x + SSD1306_W*(y/8);
|
||||||
|
|
||||||
/* set/clear bit in buffer */
|
/* set/clear bit in buffer */
|
||||||
if (color)
|
if(color)
|
||||||
ssd1306_buffer[addr] |= (1 << (y & 7));
|
ssd1306_buffer[addr] |= (1<<(y&7));
|
||||||
else
|
else
|
||||||
ssd1306_buffer[addr] &= ~(1 << (y & 7));
|
ssd1306_buffer[addr] &= ~(1<<(y&7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -294,96 +259,89 @@ void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
|
||||||
*/
|
*/
|
||||||
void ssd1306_xorPixel(uint32_t x, uint32_t y)
|
void ssd1306_xorPixel(uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
/* clip */
|
/* clip */
|
||||||
if (x >= SSD1306_W)
|
if(x >= SSD1306_W)
|
||||||
return;
|
return;
|
||||||
if (y >= SSD1306_H)
|
if(y >= SSD1306_H)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* compute buffer address */
|
/* compute buffer address */
|
||||||
addr = x + SSD1306_W * (y / 8);
|
addr = x + SSD1306_W*(y/8);
|
||||||
|
|
||||||
ssd1306_buffer[addr] ^= (1 << (y & 7));
|
ssd1306_buffer[addr] ^= (1<<(y&7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* draw a an image from an array, directly into to the display buffer
|
* draw a an image from an array, directly into to the display buffer
|
||||||
* the color modes allow for overwriting and even layering (sprites!)
|
* the color modes allow for overwriting and even layering (sprites!)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint32_t width, uint32_t height, uint32_t color_mode)
|
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint32_t width, uint32_t height, uint32_t color_mode) {
|
||||||
{
|
uint32_t x_absolute;
|
||||||
uint32_t x_absolute;
|
uint32_t y_absolute;
|
||||||
uint32_t y_absolute;
|
uint32_t pixel;
|
||||||
uint32_t pixel;
|
uint32_t bytes_to_draw = width / 8;
|
||||||
uint32_t bytes_to_draw = width / 8;
|
uint32_t buffer_addr;
|
||||||
uint32_t buffer_addr;
|
|
||||||
|
|
||||||
for (uint32_t line = 0; line < height; line++)
|
for (uint32_t line = 0; line < height; line++) {
|
||||||
{
|
y_absolute = y + line;
|
||||||
y_absolute = y + line;
|
if (y_absolute >= SSD1306_H) {
|
||||||
if (y_absolute >= SSD1306_H)
|
break;
|
||||||
{
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
|
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
|
||||||
// bitmask for current pixel in vertical (output) byte
|
// bitmask for current pixel in vertical (output) byte
|
||||||
uint32_t v_mask = 1 << (y_absolute & 7);
|
uint32_t v_mask = 1 << (y_absolute & 7);
|
||||||
|
|
||||||
for (uint32_t byte = 0; byte < bytes_to_draw; byte++)
|
for (uint32_t byte = 0; byte < bytes_to_draw; byte++) {
|
||||||
{
|
uint32_t input_byte = input[byte + line * bytes_to_draw];
|
||||||
uint32_t input_byte = input[byte + line * bytes_to_draw];
|
|
||||||
|
|
||||||
for (pixel = 0; pixel < 8; pixel++)
|
for (pixel = 0; pixel < 8; pixel++) {
|
||||||
{
|
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
|
||||||
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
|
if (x_absolute >= SSD1306_W) {
|
||||||
if (x_absolute >= SSD1306_W)
|
break;
|
||||||
{
|
}
|
||||||
break;
|
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
|
||||||
}
|
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
|
||||||
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
|
// state of current pixel
|
||||||
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
|
uint8_t input_pixel = input_byte & (1 << pixel);
|
||||||
// state of current pixel
|
|
||||||
uint8_t input_pixel = input_byte & (1 << pixel);
|
|
||||||
|
|
||||||
switch (color_mode)
|
switch (color_mode) {
|
||||||
{
|
case 0:
|
||||||
case 0:
|
// write pixels as they are
|
||||||
// write pixels as they are
|
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
|
||||||
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
|
break;
|
||||||
break;
|
case 1:
|
||||||
case 1:
|
// write pixels after inversion
|
||||||
// write pixels after inversion
|
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
|
||||||
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
|
break;
|
||||||
break;
|
case 2:
|
||||||
case 2:
|
// 0 clears pixel
|
||||||
// 0 clears pixel
|
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
|
||||||
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
|
break;
|
||||||
break;
|
case 3:
|
||||||
case 3:
|
// 1 sets pixel
|
||||||
// 1 sets pixel
|
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
|
||||||
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
|
break;
|
||||||
break;
|
case 4:
|
||||||
case 4:
|
// 0 sets pixel
|
||||||
// 0 sets pixel
|
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
|
||||||
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
|
break;
|
||||||
break;
|
case 5:
|
||||||
case 5:
|
// 1 clears pixel
|
||||||
// 1 clears pixel
|
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
|
||||||
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
#if SSD1306_LOG_IMAGE == 1
|
||||||
#if SSD1306_LOG_IMAGE == 1
|
printf("%02x ", input_byte);
|
||||||
printf("%02x ", input_byte);
|
#endif
|
||||||
#endif
|
}
|
||||||
}
|
#if SSD1306_LOG_IMAGE == 1
|
||||||
#if SSD1306_LOG_IMAGE == 1
|
printf("\n\r");
|
||||||
printf("\n\r");
|
#endif
|
||||||
#endif
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -391,13 +349,13 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint3
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
||||||
{
|
{
|
||||||
// clipping
|
// clipping
|
||||||
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
|
if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
|
||||||
if ((y + h - 1) >= SSD1306_H) h = SSD1306_H - y;
|
if((y+h-1) >= SSD1306_H) h = SSD1306_H-y;
|
||||||
while (h--)
|
while(h--)
|
||||||
{
|
{
|
||||||
ssd1306_drawPixel(x, y++, color);
|
ssd1306_drawPixel(x, y++, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -405,14 +363,14 @@ void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
|
void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
|
||||||
{
|
{
|
||||||
// clipping
|
// clipping
|
||||||
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
|
if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
|
||||||
if ((x + w - 1) >= SSD1306_W) w = SSD1306_W - x;
|
if((x+w-1) >= SSD1306_W) w = SSD1306_W-x;
|
||||||
|
|
||||||
while (w--)
|
while (w--)
|
||||||
{
|
{
|
||||||
ssd1306_drawPixel(x++, y, color);
|
ssd1306_drawPixel(x++, y, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -420,7 +378,7 @@ void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
|
||||||
*/
|
*/
|
||||||
int gfx_abs(int x)
|
int gfx_abs(int x)
|
||||||
{
|
{
|
||||||
return (x < 0) ? -x : x;
|
return (x<0) ? -x : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -428,9 +386,9 @@ int gfx_abs(int x)
|
||||||
*/
|
*/
|
||||||
void gfx_swap(int *z0, int *z1)
|
void gfx_swap(int *z0, int *z1)
|
||||||
{
|
{
|
||||||
uint16_t temp = *z0;
|
uint16_t temp = *z0;
|
||||||
*z0 = *z1;
|
*z0 = *z1;
|
||||||
*z1 = temp;
|
*z1 = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -438,56 +396,56 @@ void gfx_swap(int *z0, int *z1)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
|
void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
|
||||||
{
|
{
|
||||||
int32_t steep;
|
int32_t steep;
|
||||||
int32_t deltax, deltay, error, ystep, x, y;
|
int32_t deltax, deltay, error, ystep, x, y;
|
||||||
|
|
||||||
/* flip sense 45deg to keep error calc in range */
|
/* flip sense 45deg to keep error calc in range */
|
||||||
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
|
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
|
||||||
|
|
||||||
if (steep)
|
if(steep)
|
||||||
{
|
{
|
||||||
gfx_swap(&x0, &y0);
|
gfx_swap(&x0, &y0);
|
||||||
gfx_swap(&x1, &y1);
|
gfx_swap(&x1, &y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* run low->high */
|
/* run low->high */
|
||||||
if (x0 > x1)
|
if(x0 > x1)
|
||||||
{
|
{
|
||||||
gfx_swap(&x0, &x1);
|
gfx_swap(&x0, &x1);
|
||||||
gfx_swap(&y0, &y1);
|
gfx_swap(&y0, &y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up loop initial conditions */
|
/* set up loop initial conditions */
|
||||||
deltax = x1 - x0;
|
deltax = x1 - x0;
|
||||||
deltay = gfx_abs(y1 - y0);
|
deltay = gfx_abs(y1 - y0);
|
||||||
error = deltax / 2;
|
error = deltax/2;
|
||||||
y = y0;
|
y = y0;
|
||||||
if (y0 < y1)
|
if(y0 < y1)
|
||||||
ystep = 1;
|
ystep = 1;
|
||||||
else
|
else
|
||||||
ystep = -1;
|
ystep = -1;
|
||||||
|
|
||||||
/* loop x */
|
/* loop x */
|
||||||
for (x = x0; x <= x1; x++)
|
for(x=x0;x<=x1;x++)
|
||||||
{
|
{
|
||||||
/* plot point */
|
/* plot point */
|
||||||
if (steep)
|
if(steep)
|
||||||
/* flip point & plot */
|
/* flip point & plot */
|
||||||
ssd1306_drawPixel(y, x, color);
|
ssd1306_drawPixel(y, x, color);
|
||||||
else
|
else
|
||||||
/* just plot */
|
/* just plot */
|
||||||
ssd1306_drawPixel(x, y, color);
|
ssd1306_drawPixel(x, y, color);
|
||||||
|
|
||||||
/* update error */
|
/* update error */
|
||||||
error = error - deltay;
|
error = error - deltay;
|
||||||
|
|
||||||
/* update y */
|
/* update y */
|
||||||
if (error < 0)
|
if(error < 0)
|
||||||
{
|
{
|
||||||
y = y + ystep;
|
y = y + ystep;
|
||||||
error = error + deltax;
|
error = error + deltax;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -498,26 +456,22 @@ void ssd1306_drawCircle(int x, int y, int radius, int color)
|
||||||
/* Bresenham algorithm */
|
/* Bresenham algorithm */
|
||||||
int x_pos = -radius;
|
int x_pos = -radius;
|
||||||
int y_pos = 0;
|
int y_pos = 0;
|
||||||
int err = 2 - 2 * radius;
|
int err = 2 - 2 * radius;
|
||||||
int e2;
|
int e2;
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
||||||
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
||||||
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
||||||
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
|
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
|
||||||
e2 = err;
|
e2 = err;
|
||||||
if (e2 <= y_pos)
|
if (e2 <= y_pos) {
|
||||||
{
|
|
||||||
err += ++y_pos * 2 + 1;
|
err += ++y_pos * 2 + 1;
|
||||||
if (-x_pos == y_pos && e2 <= x_pos)
|
if(-x_pos == y_pos && e2 <= x_pos) {
|
||||||
{
|
e2 = 0;
|
||||||
e2 = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e2 > x_pos)
|
if (e2 > x_pos) {
|
||||||
{
|
|
||||||
err += ++x_pos * 2 + 1;
|
err += ++x_pos * 2 + 1;
|
||||||
}
|
}
|
||||||
} while (x_pos <= 0);
|
} while (x_pos <= 0);
|
||||||
|
|
@ -531,11 +485,10 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
|
||||||
/* Bresenham algorithm */
|
/* Bresenham algorithm */
|
||||||
int x_pos = -radius;
|
int x_pos = -radius;
|
||||||
int y_pos = 0;
|
int y_pos = 0;
|
||||||
int err = 2 - 2 * radius;
|
int err = 2 - 2 * radius;
|
||||||
int e2;
|
int e2;
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
|
||||||
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
|
||||||
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
|
||||||
|
|
@ -543,19 +496,16 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
|
||||||
ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color);
|
ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color);
|
||||||
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
|
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
|
||||||
e2 = err;
|
e2 = err;
|
||||||
if (e2 <= y_pos)
|
if (e2 <= y_pos) {
|
||||||
{
|
|
||||||
err += ++y_pos * 2 + 1;
|
err += ++y_pos * 2 + 1;
|
||||||
if (-x_pos == y_pos && e2 <= x_pos)
|
if(-x_pos == y_pos && e2 <= x_pos) {
|
||||||
{
|
|
||||||
e2 = 0;
|
e2 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e2 > x_pos)
|
if(e2 > x_pos) {
|
||||||
{
|
|
||||||
err += ++x_pos * 2 + 1;
|
err += ++x_pos * 2 + 1;
|
||||||
}
|
}
|
||||||
} while (x_pos <= 0);
|
} while(x_pos <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -563,10 +513,10 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color)
|
void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color)
|
||||||
{
|
{
|
||||||
ssd1306_drawFastVLine(x, y, h, color);
|
ssd1306_drawFastVLine(x, y, h, color);
|
||||||
ssd1306_drawFastVLine(x + w - 1, y, h, color);
|
ssd1306_drawFastVLine(x+w-1, y, h, color);
|
||||||
ssd1306_drawFastHLine(x, y, w, color);
|
ssd1306_drawFastHLine(x, y, w, color);
|
||||||
ssd1306_drawFastHLine(x, y + h - 1, w, color);
|
ssd1306_drawFastHLine(x, y+h-1, w, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -574,21 +524,21 @@ void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t col
|
||||||
*/
|
*/
|
||||||
void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color)
|
void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color)
|
||||||
{
|
{
|
||||||
uint32_t m, n = y, iw = w;
|
uint32_t m, n=y, iw = w;
|
||||||
|
|
||||||
/* scan vertical */
|
/* scan vertical */
|
||||||
while (h--)
|
while(h--)
|
||||||
{
|
{
|
||||||
m = x;
|
m=x;
|
||||||
w = iw;
|
w=iw;
|
||||||
/* scan horizontal */
|
/* scan horizontal */
|
||||||
while (w--)
|
while(w--)
|
||||||
{
|
{
|
||||||
/* invert pixels */
|
/* invert pixels */
|
||||||
ssd1306_drawPixel(m++, n, color);
|
ssd1306_drawPixel(m++, n, color);
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -596,21 +546,21 @@ void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t co
|
||||||
*/
|
*/
|
||||||
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
|
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
|
||||||
{
|
{
|
||||||
uint8_t m, n = y, iw = w;
|
uint8_t m, n=y, iw = w;
|
||||||
|
|
||||||
/* scan vertical */
|
/* scan vertical */
|
||||||
while (h--)
|
while(h--)
|
||||||
{
|
{
|
||||||
m = x;
|
m=x;
|
||||||
w = iw;
|
w=iw;
|
||||||
/* scan horizontal */
|
/* scan horizontal */
|
||||||
while (w--)
|
while(w--)
|
||||||
{
|
{
|
||||||
/* invert pixels */
|
/* invert pixels */
|
||||||
ssd1306_xorPixel(m++, n);
|
ssd1306_xorPixel(m++, n);
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -618,25 +568,25 @@ void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
|
void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
|
||||||
{
|
{
|
||||||
uint16_t i, j, col;
|
uint16_t i, j, col;
|
||||||
uint8_t d;
|
uint8_t d;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for(i=0;i<8;i++)
|
||||||
{
|
{
|
||||||
d = fontdata[(chr << 3) + i];
|
d = fontdata[(chr<<3)+i];
|
||||||
for (j = 0; j < 8; j++)
|
for(j=0;j<8;j++)
|
||||||
{
|
{
|
||||||
if (d & 0x80)
|
if(d&0x80)
|
||||||
col = color;
|
col = color;
|
||||||
else
|
else
|
||||||
col = (~color) & 1;
|
col = (~color)&1;
|
||||||
|
|
||||||
ssd1306_drawPixel(x + j, y + i, col);
|
ssd1306_drawPixel(x+j, y+i, col);
|
||||||
|
|
||||||
// next bit
|
// next bit
|
||||||
d <<= 1;
|
d <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -644,26 +594,25 @@ void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
|
void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
while ((c = *str++))
|
while((c=*str++))
|
||||||
{
|
{
|
||||||
ssd1306_drawchar(x, y, c, color);
|
ssd1306_drawchar(x, y, c, color);
|
||||||
x += 8;
|
x += 8;
|
||||||
if (x > 120)
|
if(x>120)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* enum for font size
|
* enum for font size
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
fontsize_8x8 = 1,
|
||||||
fontsize_8x8 = 1,
|
|
||||||
fontsize_16x16 = 2,
|
fontsize_16x16 = 2,
|
||||||
fontsize_32x32 = 4,
|
fontsize_32x32 = 4,
|
||||||
fontsize_64x64 = 8,
|
fontsize_64x64 = 8,
|
||||||
} font_size_t;
|
} font_size_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -672,7 +621,7 @@ typedef enum
|
||||||
void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_size_t font_size)
|
void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_size_t font_size)
|
||||||
{
|
{
|
||||||
uint16_t i, j, col;
|
uint16_t i, j, col;
|
||||||
uint8_t d;
|
uint8_t d;
|
||||||
|
|
||||||
// Determine the font scale factor based on the font_size parameter
|
// Determine the font scale factor based on the font_size parameter
|
||||||
uint8_t font_scale = (uint8_t)font_size;
|
uint8_t font_scale = (uint8_t)font_size;
|
||||||
|
|
@ -693,10 +642,8 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
|
||||||
col = (~color) & 1;
|
col = (~color) & 1;
|
||||||
|
|
||||||
// Draw the pixel at the original size and scaled size using nested for-loops
|
// Draw the pixel at the original size and scaled size using nested for-loops
|
||||||
for (uint8_t k = 0; k < font_scale; k++)
|
for (uint8_t k = 0; k < font_scale; k++) {
|
||||||
{
|
for (uint8_t l = 0; l < font_scale; l++) {
|
||||||
for (uint8_t l = 0; l < font_scale; l++)
|
|
||||||
{
|
|
||||||
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
|
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -712,15 +659,15 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_size_t font_size)
|
void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_size_t font_size)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
while ((c = *str++))
|
while((c=*str++))
|
||||||
{
|
{
|
||||||
ssd1306_drawchar_sz(x, y, c, color, font_size);
|
ssd1306_drawchar_sz(x, y, c, color, font_size);
|
||||||
x += 8 * font_size;
|
x += 8 * font_size;
|
||||||
if (x > 128 - 8 * font_size)
|
if(x>128 - 8 * font_size)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -728,25 +675,24 @@ void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_siz
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_init(void)
|
uint8_t ssd1306_init(void)
|
||||||
{
|
{
|
||||||
// pulse reset
|
// pulse reset
|
||||||
ssd1306_rst();
|
ssd1306_rst();
|
||||||
|
|
||||||
ssd1306_setbuf(0);
|
ssd1306_setbuf(0);
|
||||||
|
|
||||||
// initialize OLED
|
// initialize OLED
|
||||||
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
|
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
|
||||||
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
|
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
|
||||||
while (*cmd_list != SSD1306_TERMINATE_CMDS)
|
while(*cmd_list != SSD1306_TERMINATE_CMDS)
|
||||||
{
|
{
|
||||||
if (ssd1306_cmd(*cmd_list++))
|
if(ssd1306_cmd(*cmd_list++))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear display
|
ssd1306_refresh();
|
||||||
ssd1306_refresh();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,14 @@
|
||||||
#define TIMEOUT_MAX 100000
|
#define TIMEOUT_MAX 100000
|
||||||
|
|
||||||
// uncomment this to enable IRQ-driven operation
|
// uncomment this to enable IRQ-driven operation
|
||||||
// #define SSD1306_I2C_IRQ
|
//#define SSD1306_I2C_IRQ
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#ifdef SSD1306_I2C_IRQ
|
||||||
// some stuff that IRQ mode needs
|
// some stuff that IRQ mode needs
|
||||||
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
|
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
|
||||||
|
|
||||||
// uncomment this to enable time diags in IRQ
|
// uncomment this to enable time diags in IRQ
|
||||||
// #define IRQ_DIAG
|
//#define IRQ_DIAG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -42,62 +42,62 @@ volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c
|
||||||
*/
|
*/
|
||||||
void ssd1306_i2c_setup(void)
|
void ssd1306_i2c_setup(void)
|
||||||
{
|
{
|
||||||
uint16_t tempreg;
|
uint16_t tempreg;
|
||||||
|
|
||||||
// Reset I2C1 to init all regs
|
// Reset I2C1 to init all regs
|
||||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
// set freq
|
// set freq
|
||||||
tempreg = I2C1->CTLR2;
|
tempreg = I2C1->CTLR2;
|
||||||
tempreg &= ~I2C_CTLR2_FREQ;
|
tempreg &= ~I2C_CTLR2_FREQ;
|
||||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
|
||||||
I2C1->CTLR2 = tempreg;
|
I2C1->CTLR2 = tempreg;
|
||||||
|
|
||||||
// Set clock config
|
// Set clock config
|
||||||
tempreg = 0;
|
tempreg = 0;
|
||||||
#if (SSD1306_I2C_CLKRATE <= 100000)
|
#if (SSD1306_I2C_CLKRATE <= 100000)
|
||||||
// standard mode good to 100kHz
|
// standard mode good to 100kHz
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
#else
|
#else
|
||||||
// fast mode over 100kHz
|
// fast mode over 100kHz
|
||||||
#ifndef SSD1306_I2C_DUTY
|
#ifndef SSD1306_I2C_DUTY
|
||||||
// 33% duty cycle
|
// 33% duty cycle
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
#else
|
#else
|
||||||
// 36% duty cycle
|
// 36% duty cycle
|
||||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||||
tempreg |= I2C_CKCFGR_DUTY;
|
tempreg |= I2C_CKCFGR_DUTY;
|
||||||
#endif
|
#endif
|
||||||
tempreg |= I2C_CKCFGR_FS;
|
tempreg |= I2C_CKCFGR_FS;
|
||||||
#endif
|
#endif
|
||||||
I2C1->CKCFGR = tempreg;
|
I2C1->CKCFGR = tempreg;
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#ifdef SSD1306_I2C_IRQ
|
||||||
// enable IRQ driven operation
|
// enable IRQ driven operation
|
||||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||||
|
|
||||||
// initialize the state
|
// initialize the state
|
||||||
ssd1306_i2c_irq_state = 0;
|
ssd1306_i2c_irq_state = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable I2C
|
// Enable I2C
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||||
|
|
||||||
// set ACK mode
|
// set ACK mode
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* error descriptions
|
* error descriptions
|
||||||
*/
|
*/
|
||||||
char *errstr[] =
|
char *errstr[] =
|
||||||
{
|
{
|
||||||
"not busy",
|
"not busy",
|
||||||
"master mode",
|
"master mode",
|
||||||
"transmit mode",
|
"transmit mode",
|
||||||
"tx empty",
|
"tx empty",
|
||||||
"transmit complete",
|
"transmit complete",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -105,28 +105,28 @@ char *errstr[] =
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_error(uint8_t err)
|
uint8_t ssd1306_i2c_error(uint8_t err)
|
||||||
{
|
{
|
||||||
// report error
|
// report error
|
||||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||||
|
|
||||||
// reset & initialize I2C
|
// reset & initialize I2C
|
||||||
ssd1306_i2c_setup();
|
ssd1306_i2c_setup();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// event codes we use
|
// event codes we use
|
||||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for 32-bit event codes
|
* check for 32-bit event codes
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||||
{
|
{
|
||||||
/* read order matters here! STAR1 before STAR2!! */
|
/* read order matters here! STAR1 before STAR2!! */
|
||||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
|
||||||
return (status & event_mask) == event_mask;
|
return (status & event_mask) == event_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SSD1306_I2C_IRQ
|
#ifdef SSD1306_I2C_IRQ
|
||||||
|
|
@ -135,67 +135,63 @@ uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
||||||
{
|
{
|
||||||
int32_t timeout;
|
int32_t timeout;
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (3));
|
GPIOC->BSHR = (1<<(3));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// error out if buffer under/overflow
|
// error out if buffer under/overflow
|
||||||
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// wait for previous packet to finish
|
// wait for previous packet to finish
|
||||||
while (ssd1306_i2c_irq_state)
|
while(ssd1306_i2c_irq_state);
|
||||||
;
|
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (16 + 3));
|
GPIOC->BSHR = (1<<(16+3));
|
||||||
GPIOC->BSHR = (1 << (4));
|
GPIOC->BSHR = (1<<(4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// init buffer for sending
|
// init buffer for sending
|
||||||
ssd1306_i2c_send_sz = sz;
|
ssd1306_i2c_send_sz = sz;
|
||||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||||
|
|
||||||
// wait for not busy
|
// wait for not busy
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(0);
|
||||||
return ssd1306_i2c_error(0);
|
|
||||||
|
|
||||||
// Set START condition
|
// Set START condition
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||||
|
|
||||||
// wait for master mode select
|
// wait for master mode select
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(1);
|
||||||
return ssd1306_i2c_error(1);
|
|
||||||
|
|
||||||
// send 7-bit address + write flag
|
// send 7-bit address + write flag
|
||||||
I2C1->DATAR = addr << 1;
|
I2C1->DATAR = addr<<1;
|
||||||
|
|
||||||
// wait for transmit condition
|
// wait for transmit condition
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(2);
|
||||||
return ssd1306_i2c_error(2);
|
|
||||||
|
|
||||||
// Enable TXE interrupt
|
// Enable TXE interrupt
|
||||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||||
ssd1306_i2c_irq_state = 1;
|
ssd1306_i2c_irq_state = 1;
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// exit
|
// exit
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -204,43 +200,42 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
||||||
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
|
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
|
||||||
void I2C1_EV_IRQHandler(void)
|
void I2C1_EV_IRQHandler(void)
|
||||||
{
|
{
|
||||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (4));
|
GPIOC->BSHR = (1<<(4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// read status, clear any events
|
// read status, clear any events
|
||||||
STAR1 = I2C1->STAR1;
|
STAR1 = I2C1->STAR1;
|
||||||
STAR2 = I2C1->STAR2;
|
STAR2 = I2C1->STAR2;
|
||||||
|
|
||||||
/* check for TXE */
|
/* check for TXE */
|
||||||
if (STAR1 & I2C_STAR1_TXE)
|
if(STAR1 & I2C_STAR1_TXE)
|
||||||
{
|
{
|
||||||
/* check for remaining data */
|
/* check for remaining data */
|
||||||
if (ssd1306_i2c_send_sz--)
|
if(ssd1306_i2c_send_sz--)
|
||||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||||
|
|
||||||
/* was that the last byte? */
|
/* was that the last byte? */
|
||||||
if (!ssd1306_i2c_send_sz)
|
if(!ssd1306_i2c_send_sz)
|
||||||
{
|
{
|
||||||
// disable TXE interrupt
|
// disable TXE interrupt
|
||||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||||
|
|
||||||
// reset IRQ state
|
// reset IRQ state
|
||||||
ssd1306_i2c_irq_state = 0;
|
ssd1306_i2c_irq_state = 0;
|
||||||
|
|
||||||
// wait for tx complete
|
// wait for tx complete
|
||||||
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||||
;
|
|
||||||
|
|
||||||
// set STOP condition
|
// set STOP condition
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
@ -249,61 +244,56 @@ void I2C1_EV_IRQHandler(void)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
||||||
{
|
{
|
||||||
int32_t timeout;
|
int32_t timeout;
|
||||||
|
|
||||||
// wait for not busy
|
// wait for not busy
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(0);
|
||||||
return ssd1306_i2c_error(0);
|
|
||||||
|
|
||||||
// Set START condition
|
// Set START condition
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||||
|
|
||||||
// wait for master mode select
|
// wait for master mode select
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(1);
|
||||||
return ssd1306_i2c_error(1);
|
|
||||||
|
|
||||||
// send 7-bit address + write flag
|
// send 7-bit address + write flag
|
||||||
I2C1->DATAR = addr << 1;
|
I2C1->DATAR = addr<<1;
|
||||||
|
|
||||||
// wait for transmit condition
|
// wait for transmit condition
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(2);
|
||||||
return ssd1306_i2c_error(2);
|
|
||||||
|
|
||||||
// send data one byte at a time
|
// send data one byte at a time
|
||||||
while (sz--)
|
while(sz--)
|
||||||
{
|
{
|
||||||
// wait for TX Empty
|
// wait for TX Empty
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
|
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(3);
|
||||||
return ssd1306_i2c_error(3);
|
|
||||||
|
|
||||||
// send command
|
// send command
|
||||||
I2C1->DATAR = *data++;
|
I2C1->DATAR = *data++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for tx complete
|
// wait for tx complete
|
||||||
timeout = TIMEOUT_MAX;
|
timeout = TIMEOUT_MAX;
|
||||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--))
|
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
|
||||||
;
|
if(timeout==-1)
|
||||||
if (timeout == -1)
|
return ssd1306_i2c_error(4);
|
||||||
return ssd1306_i2c_error(4);
|
|
||||||
|
|
||||||
// set STOP condition
|
// set STOP condition
|
||||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||||
|
|
||||||
// we're happy
|
// we're happy
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -312,20 +302,20 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
uint8_t pkt[33];
|
uint8_t pkt[33];
|
||||||
|
|
||||||
/* build command or data packets */
|
/* build command or data packets */
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
pkt[0] = 0;
|
pkt[0] = 0;
|
||||||
pkt[1] = *data;
|
pkt[1] = *data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pkt[0] = 0x40;
|
pkt[0] = 0x40;
|
||||||
memcpy(&pkt[1], data, sz);
|
memcpy(&pkt[1], data, sz);
|
||||||
}
|
}
|
||||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1);
|
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -333,51 +323,51 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_i2c_init(void)
|
uint8_t ssd1306_i2c_init(void)
|
||||||
{
|
{
|
||||||
// Enable GPIOC and I2C
|
// Enable GPIOC and I2C
|
||||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||||
|
|
||||||
#ifdef CH32V20x
|
#ifdef CH32V20x
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||||
|
|
||||||
#ifdef SSD1306_REMAP_I2C
|
#ifdef SSD1306_REMAP_I2C
|
||||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||||
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
#else
|
#else
|
||||||
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
|
||||||
|
|
||||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 2));
|
GPIOC->CFGLR &= ~(0xf<<(4*2));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IRQ_DIAG
|
#ifdef IRQ_DIAG
|
||||||
// GPIO diags on PC3/PC4
|
// GPIO diags on PC3/PC4
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
|
||||||
GPIOC->BSHR = (1 << (16 + 3));
|
GPIOC->BSHR = (1<<(16+3));
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
|
||||||
GPIOC->BSHR = (1 << (16 + 4));
|
GPIOC->BSHR = (1<<(16+4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// load I2C regs
|
// load I2C regs
|
||||||
ssd1306_i2c_setup();
|
ssd1306_i2c_setup();
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// test if SSD1306 is on the bus by sending display off command
|
// test if SSD1306 is on the bus by sending display off command
|
||||||
uint8_t command = 0xAF;
|
uint8_t command = 0xAF;
|
||||||
return ssd1306_pkt_send(&command, 1, 1);
|
return ssd1306_pkt_send(&command, 1, 1);
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,115 +26,120 @@
|
||||||
*/
|
*/
|
||||||
void ssd1306_i2c_setup(void)
|
void ssd1306_i2c_setup(void)
|
||||||
{
|
{
|
||||||
funGpioInitAll();
|
funGpioInitAll();
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||||
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||||
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0);
|
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||||
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0);
|
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||||
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA);
|
#define SDA_RELEASE { funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 ); }
|
||||||
|
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
|
||||||
|
#define SDA_DRIVE { funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 ); funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP ); }
|
||||||
|
|
||||||
|
#ifndef I2CSPEEDBASE
|
||||||
#define I2CSPEEDBASE 1
|
#define I2CSPEEDBASE 1
|
||||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1)
|
#endif
|
||||||
// Delay_Us(x*1);
|
#ifndef I2CDELAY_FUNC
|
||||||
|
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ssd1306_i2c_sendstart()
|
static void ssd1306_i2c_sendstart()
|
||||||
{
|
{
|
||||||
SCL_HIGH
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SCL_HIGH
|
||||||
SDA_LOW
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SDA_LOW
|
||||||
SCL_LOW
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SCL_LOW
|
||||||
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssd1306_i2c_sendstop()
|
void ssd1306_i2c_sendstop()
|
||||||
{
|
{
|
||||||
SDA_LOW
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SDA_LOW
|
||||||
SCL_LOW
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SCL_LOW
|
||||||
SCL_HIGH
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SCL_HIGH
|
||||||
SDA_HIGH
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
SDA_HIGH
|
||||||
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return nonzero on failure.
|
//Return nonzero on failure.
|
||||||
unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < 8; i++)
|
for( i = 0; i < 8; i++ )
|
||||||
{
|
{
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
if (data & 0x80)
|
if( data & 0x80 )
|
||||||
{
|
{ SDA_HIGH; }
|
||||||
SDA_HIGH;
|
else
|
||||||
}
|
{ SDA_LOW; }
|
||||||
else
|
data<<=1;
|
||||||
{
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_LOW;
|
SCL_HIGH
|
||||||
}
|
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
|
||||||
data <<= 1;
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
}
|
||||||
SCL_HIGH
|
|
||||||
I2CDELAY_FUNC(2 * I2CSPEEDBASE);
|
|
||||||
SCL_LOW
|
|
||||||
}
|
|
||||||
|
|
||||||
// Immediately after sending last bit, open up DDDR for control.
|
//Immediately after sending last bit, open up DDDR for control.
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
SDA_HIGH
|
||||||
SDA_HIGH
|
SDA_RELEASE
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_HIGH
|
SCL_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
i = SDA_IN;
|
i = SDA_IN;
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SCL_LOW
|
SCL_LOW
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
SDA_HIGH // Maybe?
|
SDA_DRIVE
|
||||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
SDA_HIGH
|
||||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
return !!i;
|
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||||
|
return !!i;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
ssd1306_i2c_sendstart();
|
ssd1306_i2c_sendstart();
|
||||||
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1);
|
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
|
||||||
if (r) return r;
|
if( r ) return r;
|
||||||
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(0x00))
|
if( ssd1306_i2c_sendbyte( 0x00 ) )
|
||||||
return 1; // Control
|
return 1; // Control
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(0x40))
|
if( ssd1306_i2c_sendbyte( 0x40 ) )
|
||||||
return 1; // Data
|
return 1; // Data
|
||||||
}
|
}
|
||||||
for (int i = 0; i < sz; i++)
|
for( int i = 0; i < sz; i++ )
|
||||||
{
|
{
|
||||||
if (ssd1306_i2c_sendbyte(data[i]))
|
if( ssd1306_i2c_sendbyte( data[i] ) )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
ssd1306_i2c_sendstop();
|
ssd1306_i2c_sendstop();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssd1306_rst(void)
|
void ssd1306_rst(void)
|
||||||
{
|
{
|
||||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP);
|
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||||
funDigitalWrite(SSD1306_RST_PIN, 0);
|
funDigitalWrite( SSD1306_RST_PIN, 0 );
|
||||||
Delay_Ms(10);
|
Delay_Ms(10);
|
||||||
funDigitalWrite(SSD1306_RST_PIN, 1);
|
funDigitalWrite( SSD1306_RST_PIN, 1 );
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -24,43 +24,66 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SSD1306_SCK_PIN
|
#ifndef SSD1306_SCK_PIN
|
||||||
#define SSD1306_SCK_PIN PC5
|
#define SSD1306_SCK_PIN PC5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
||||||
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
|
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SSD1306_SOFT_SPI
|
||||||
|
#define SSD1306_SOFT_SPI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* init SPI and GPIO for SSD1306 OLED
|
* init SPI and GPIO for SSD1306 OLED
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_spi_init(void)
|
uint8_t ssd1306_spi_init(void)
|
||||||
{
|
{
|
||||||
// Enable GPIOC and SPI
|
// Enable GPIOC and SPI
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
#ifdef CH5xx
|
||||||
|
#else
|
||||||
|
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||||
|
#endif
|
||||||
|
|
||||||
funGpioInitAll();
|
funGpioInitAll();
|
||||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||||
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||||
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||||
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
#if defined( CH5xx ) || SSD1306_SOFT_SPI
|
||||||
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||||
|
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||||
|
#else
|
||||||
|
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||||
|
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||||
|
#endif
|
||||||
|
|
||||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||||
|
|
||||||
// Configure SPI
|
// Configure SPI
|
||||||
SPI1->CTLR1 =
|
#if SSD1306_SOFT_SPI
|
||||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH );
|
||||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
#elif defined( CH5xx )
|
||||||
SSD1306_BAUD_RATE_PRESCALER;
|
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;
|
||||||
|
|
||||||
// enable SPI port
|
// enable SPI port
|
||||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||||
|
#endif
|
||||||
|
|
||||||
// always succeed
|
// always succeed
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -68,9 +91,9 @@ uint8_t ssd1306_spi_init(void)
|
||||||
*/
|
*/
|
||||||
void ssd1306_rst(void)
|
void ssd1306_rst(void)
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
|
||||||
Delay_Ms(10);
|
Delay_Ms(10);
|
||||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -78,35 +101,56 @@ void ssd1306_rst(void)
|
||||||
*/
|
*/
|
||||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
if (cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
|
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||||
}
|
}
|
||||||
|
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
|
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
while (sz--)
|
while(sz--)
|
||||||
{
|
{
|
||||||
// wait for TXE
|
#if SSD1306_SOFT_SPI
|
||||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
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 byte
|
#elif defined( CH5xx )
|
||||||
SPI1->DATAR = *data++;
|
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
||||||
}
|
R8_SPI0_BUFFER = *data++;
|
||||||
|
#else
|
||||||
|
// wait for TXE
|
||||||
|
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||||
|
|
||||||
// wait for not busy before exiting
|
// Send byte
|
||||||
while (SPI1->STATR & SPI_STATR_BSY) {}
|
SPI1->DATAR = *data++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
// 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
|
||||||
|
|
||||||
// we're happy
|
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||||
return 0;
|
|
||||||
|
// we're happy
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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
|
|
@ -4,26 +4,28 @@
|
||||||
internal bus resources than to do the same thing with timers.
|
internal bus resources than to do the same thing with timers.
|
||||||
|
|
||||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
**For the CH32V003 this means output will be on PORTC Pin 6**
|
||||||
|
**For the CH570/2 - PORTA Pin 7**
|
||||||
|
**For the CH582/3 or CH591/2 PORTA Pin 14**
|
||||||
|
|
||||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||||
|
|
||||||
If you are including this in main, simply
|
If you are including this in main, simply
|
||||||
#define WS2812DMA_IMPLEMENTATION
|
#define WS2812DMA_IMPLEMENTATION
|
||||||
|
|
||||||
Other defines inclue:
|
Other defines inclue:
|
||||||
#define WSRAW
|
#define WSRAW
|
||||||
#define WSRBG
|
#define WSRBG
|
||||||
#define WSGRB
|
#define WSGRB
|
||||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||||
|
|
||||||
You will need to implement the following two functions, as callbacks from the ISR.
|
You will need to implement the following two functions, as callbacks from the ISR.
|
||||||
uint32_t WS2812BLEDCallback( int ledno );
|
uint32_t WS2812BLEDCallback( int ledno );
|
||||||
|
|
||||||
You willalso need to call
|
You willalso need to call
|
||||||
WS2812BDMAInit();
|
WS2812BDMAInit();
|
||||||
|
|
||||||
Then, whenyou want to update the LEDs, call:
|
Then, whenyou want to update the LEDs, call:
|
||||||
WS2812BDMAStart( int num_leds );
|
WS2812BDMAStart( int num_leds );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WS2812_LED_DRIVER_H
|
#ifndef _WS2812_LED_DRIVER_H
|
||||||
|
|
@ -32,11 +34,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
||||||
void WS2812BDMAInit();
|
void WS2812BDMAInit( );
|
||||||
void WS2812BDMAStart(int leds);
|
void WS2812BDMAStart( int leds );
|
||||||
|
|
||||||
// Callbacks that you must implement.
|
// Callbacks that you must implement.
|
||||||
uint32_t WS2812BLEDCallback(int ledno);
|
uint32_t WS2812BLEDCallback( int ledno );
|
||||||
|
|
||||||
#ifdef WS2812DMA_IMPLEMENTATION
|
#ifdef WS2812DMA_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
@ -51,236 +53,288 @@ uint32_t WS2812BLEDCallback(int ledno);
|
||||||
#define WS2812B_RESET_PERIOD 2
|
#define WS2812B_RESET_PERIOD 2
|
||||||
|
|
||||||
#ifdef WSRAW
|
#ifdef WSRAW
|
||||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
|
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
|
||||||
#else
|
#else
|
||||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
|
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||||
static volatile int WS2812LEDs;
|
static volatile int WS2812LEDs;
|
||||||
static volatile int WS2812LEDPlace;
|
static volatile int WS2812LEDPlace;
|
||||||
static volatile int WS2812BLEDInUse;
|
static volatile int WS2812BLEDInUse;
|
||||||
|
|
||||||
|
#ifdef CH5xx
|
||||||
|
#ifdef CH570_CH572
|
||||||
|
#define bMOSI PA7
|
||||||
|
#else
|
||||||
|
#define bMOSI PA14
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||||
// This effectively creates the bitstream that outputs to the LEDs.
|
// This effectively creates the bitstream that outputs to the LEDs.
|
||||||
static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
|
||||||
{
|
{
|
||||||
const static uint16_t bitquartets[16] = {
|
#ifdef CH5xx
|
||||||
0b1000100010001000,
|
// Reversing bit order because CH5xx SPI FIFO is only half of what CH32 have
|
||||||
0b1000100010001110,
|
const static uint16_t bitquartets[16] = {
|
||||||
0b1000100011101000,
|
0b0001000100010001, 0b0111000100010001, 0b0001011100010001, 0b0111011100010001,
|
||||||
0b1000100011101110,
|
0b0001000101110001, 0b0111000101110001, 0b0001011101110001, 0b0111011101110001,
|
||||||
0b1000111010001000,
|
0b0001000100010111, 0b0111000100010111, 0b0001011100010111, 0b0111011100010111,
|
||||||
0b1000111010001110,
|
0b0001000101110111, 0b0111000101110111, 0b0001011101110111, 0b0111011101110111, };
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
while (place < 0 && ptr != end)
|
const static uint16_t bitquartets[16] = {
|
||||||
{
|
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||||
(*ptr++) = 0;
|
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||||
(*ptr++) = 0;
|
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||||
(*ptr++) = 0;
|
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||||
(*ptr++) = 0;
|
|
||||||
(*ptr++) = 0;
|
|
||||||
(*ptr++) = 0;
|
|
||||||
place++;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (ptr != end)
|
int i;
|
||||||
{
|
uint16_t * end = ptr + numhalfwords;
|
||||||
if (place >= ledcount)
|
int ledcount = WS2812LEDs;
|
||||||
{
|
int place = WS2812LEDPlace;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WSRAW
|
#ifdef WSRAW
|
||||||
uint32_t ledval32bit = WS2812BLEDCallback(place++);
|
while( place < 0 && ptr != end )
|
||||||
|
{
|
||||||
ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf];
|
uint32_t * lptr = (uint32_t *)ptr;
|
||||||
ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf];
|
lptr[0] = 0;
|
||||||
ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf];
|
lptr[1] = 0;
|
||||||
ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf];
|
lptr[2] = 0;
|
||||||
ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf];
|
lptr[3] = 0;
|
||||||
ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf];
|
ptr += 8;
|
||||||
ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf];
|
place++;
|
||||||
ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf];
|
}
|
||||||
|
|
||||||
ptr += 8;
|
|
||||||
i += 8;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Use a LUT to figure out how we should set the SPI line.
|
while( place < 0 && ptr != end )
|
||||||
uint32_t ledval24bit = WS2812BLEDCallback(place++);
|
{
|
||||||
|
(*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
|
#ifdef WSRBG
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
#elif defined(WSGRB)
|
#elif defined( WSGRB )
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
#else
|
#else
|
||||||
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
|
ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
|
||||||
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
|
ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
|
||||||
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
|
ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
|
||||||
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
|
ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
|
||||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||||
#endif
|
#endif
|
||||||
ptr += 6;
|
ptr += 6;
|
||||||
i += 6;
|
i += 6;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
WS2812LEDPlace = place;
|
}
|
||||||
|
WS2812LEDPlace = place;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
|
#ifdef CH5xx
|
||||||
void DMA1_Channel3_IRQHandler(void)
|
void SPI0_IRQHandler( void ) __attribute__((interrupt));
|
||||||
|
void SPI0_IRQHandler( void )
|
||||||
{
|
{
|
||||||
// GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
uint8_t intf = R8_SPI0_INT_FLAG;
|
||||||
|
if( (intf & RB_SPI_IF_DMA_END) )
|
||||||
|
{
|
||||||
|
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 1 );
|
||||||
|
R16_SPI0_TOTAL_CNT = DMA_BUFFER_LEN * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
|
||||||
|
void DMA1_Channel3_IRQHandler( void )
|
||||||
|
{
|
||||||
|
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||||
|
|
||||||
// Backup flags.
|
// Backup flags.
|
||||||
volatile int intfr = DMA1->INTFR;
|
volatile int intfr = DMA1->INTFR;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Clear all possible flags.
|
// Clear all possible flags.
|
||||||
DMA1->INTFCR = DMA1_IT_GL3;
|
DMA1->INTFCR = DMA1_IT_GL3;
|
||||||
|
|
||||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||||
// LED jitter. I am henseforth flipping the order.
|
// LED jitter. I am henseforth flipping the order.
|
||||||
|
|
||||||
if (intfr & DMA1_IT_HT3)
|
if( intfr & DMA1_IT_HT3 )
|
||||||
{
|
{
|
||||||
// Halfwaay (Fill in first part)
|
// Halfwaay (Fill in first part)
|
||||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
|
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
|
||||||
}
|
}
|
||||||
if (intfr & DMA1_IT_TC3)
|
if( intfr & DMA1_IT_TC3 )
|
||||||
{
|
{
|
||||||
// Complete (Fill in second part)
|
// Complete (Fill in second part)
|
||||||
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
|
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
|
||||||
}
|
}
|
||||||
intfr = DMA1->INTFR;
|
intfr = DMA1->INTFR;
|
||||||
} while (intfr & DMA1_IT_GL3);
|
} while( intfr & DMA1_IT_GL3 );
|
||||||
|
|
||||||
// GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||||
|
}
|
||||||
|
#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.
|
// Enable DMA + Peripherals
|
||||||
__disable_irq();
|
#ifdef CH5xx
|
||||||
WS2812BLEDInUse = 1;
|
funPinMode( bMOSI, GPIO_CFGLR_OUT_2Mhz_PP );
|
||||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
R8_SPI0_CLOCK_DIV = FUNCONF_SYSTEM_CORE_CLOCK / 3000000; // div = Fsys/3MHz
|
||||||
DMA1_Channel3->CNTR = 0;
|
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
|
||||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_2WIRE_MOD;
|
||||||
WS2812LEDs = leds;
|
R16_SPI0_DMA_END = ( (uint32_t)WS2812dmabuff + (DMA_BUFFER_LEN * 2) );
|
||||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
|
||||||
__enable_irq();
|
|
||||||
|
|
||||||
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.
|
// MOSI, Configure GPIO Pin
|
||||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||||
}
|
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||||
|
|
||||||
void WS2812BDMAInit()
|
// Configure SPI
|
||||||
{
|
SPI1->CTLR1 =
|
||||||
// Enable DMA + Peripherals
|
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||||
|
|
||||||
// MOSI, Configure GPIO Pin
|
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; // Enable Tx buffer DMA
|
||||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
|
||||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
|
||||||
|
|
||||||
// Configure SPI
|
#if defined(CH32V003)
|
||||||
SPI1->CTLR1 =
|
SPI1->HSCR = 1; // Enable high-speed read mode
|
||||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
#endif
|
||||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
|
||||||
3 << 3; // Divisior = 16 (48/16 = 3MHz)
|
|
||||||
|
|
||||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
SPI1->CTLR1 |= CTLR1_SPE_Set; // Enable SPI
|
||||||
SPI1->HSCR = 1;
|
|
||||||
|
|
||||||
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
|
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
NVIC_EnableIRQ( DMA1_Channel3_IRQn );
|
||||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||||
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;
|
|
||||||
|
|
||||||
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
||||||
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
|
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||||
|
|
||||||
If you are including this in main, simply
|
If you are including this in main, simply
|
||||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||||
|
|
||||||
You may also want to define
|
You may also want to define
|
||||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes);
|
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes );
|
||||||
|
|
||||||
#ifdef WS2812BSIMPLE_IMPLEMENTATION
|
#ifdef WS2812BSIMPLE_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
@ -25,58 +25,59 @@ void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_by
|
||||||
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes)
|
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes )
|
||||||
{
|
{
|
||||||
int port_id = (((intptr_t)port - (intptr_t)GPIOA) >> 10);
|
int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
|
||||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled.
|
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
|
||||||
|
|
||||||
int poffset = (pin * 4);
|
int poffset = (pin*4);
|
||||||
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset));
|
port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
|
||||||
|
|
||||||
int maskon = 1 << pin;
|
int maskon = 1<<pin;
|
||||||
int maskoff = 1 << (16 + pin);
|
int maskoff = 1<<(16+pin);
|
||||||
|
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
|
|
||||||
uint8_t *end = data + len_in_bytes;
|
uint8_t * end = data + len_in_bytes;
|
||||||
while (data != end)
|
while( data != end )
|
||||||
{
|
{
|
||||||
uint8_t byte = *data;
|
uint8_t byte = *data;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 8; i++)
|
for( i = 0; i < 8; i++ )
|
||||||
{
|
{
|
||||||
if (byte & 0x80)
|
if( byte & 0x80 )
|
||||||
{
|
{
|
||||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||||
port->BSHR = maskon;
|
port->BSHR = maskon;
|
||||||
DelaySysTick(25);
|
DelaySysTick(25);
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
DelaySysTick(1);
|
DelaySysTick(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
#endif
|
#endif
|
||||||
port->BSHR = maskon;
|
port->BSHR = maskon;
|
||||||
asm volatile("nop\nnop\nnop\nnop");
|
asm volatile( "nop\nnop\nnop\nnop" );
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
#endif
|
#endif
|
||||||
DelaySysTick(15);
|
DelaySysTick(15);
|
||||||
}
|
}
|
||||||
byte <<= 1;
|
byte <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
data++;
|
data++;
|
||||||
}
|
}
|
||||||
|
|
||||||
port->BSHR = maskoff;
|
port->BSHR = maskoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
Ecall_U_Mode_IRQn = 8, /* 8 Ecall U Mode Interrupt */
|
||||||
Break_Point_IRQn = 9, /* 9 Break Point Interrupt */
|
Break_Point_IRQn = 9, /* 9 Break Point Interrupt */
|
||||||
#endif
|
#endif
|
||||||
SysTicK_IRQn = 12, /* 12 System timer Interrupt */
|
SysTick_IRQn = 12, /* 12 System timer Interrupt */
|
||||||
Software_IRQn = 14, /* 14 software Interrupt */
|
Software_IRQn = 14, /* 14 software Interrupt */
|
||||||
|
|
||||||
#if defined(CH32V003) || defined(CH32X03x)
|
#if defined(CH32V003) || defined(CH32X03x)
|
||||||
|
|
@ -1864,8 +1864,6 @@ typedef struct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define USB_PHY_V33 (1<<6)
|
|
||||||
#define USB_IOEN (1<<7)
|
|
||||||
|
|
||||||
|
|
||||||
#define USBFSD_UEP_MOD_BASE 0x4002340C
|
#define USBFSD_UEP_MOD_BASE 0x4002340C
|
||||||
|
|
@ -2266,11 +2264,7 @@ typedef struct
|
||||||
#define ESIG_BASE ((uint32_t)0x1FFFF7E0)
|
#define ESIG_BASE ((uint32_t)0x1FFFF7E0)
|
||||||
#define INFO_BASE ((uint32_t)0x1FFFF704)
|
#define INFO_BASE ((uint32_t)0x1FFFF704)
|
||||||
|
|
||||||
#if defined(CH32V003) || defined(CH32V10x)
|
|
||||||
#define EXTEN_BASE ((uint32_t)0x40023800)
|
|
||||||
#elif defined(CH32V20x) || defined(CH32V30x)
|
|
||||||
#define EXTEN_BASE (AHBPERIPH_BASE + 0x3800)
|
#define EXTEN_BASE (AHBPERIPH_BASE + 0x3800)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PFIC_BASE (CORE_PERIPH_BASE + 0xE000)
|
#define PFIC_BASE (CORE_PERIPH_BASE + 0xE000)
|
||||||
#define SysTick_BASE (CORE_PERIPH_BASE + 0xF000)
|
#define SysTick_BASE (CORE_PERIPH_BASE + 0xF000)
|
||||||
|
|
@ -2283,118 +2277,6 @@ typedef struct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// AFIO CTLR Bits
|
|
||||||
#define PB6_FILT_EN (1<<27)
|
|
||||||
#define PB5_FILT_EN (1<<26)
|
|
||||||
#define PA4_FILT_EN (1<<25)
|
|
||||||
#define PA3_FILT_EN (1<<24)
|
|
||||||
#define UDM_BC_CMPO (1<<19)
|
|
||||||
#define UDP_BC_CMPO (1<<17)
|
|
||||||
#define UDM_BC_VSRC (1<<17)
|
|
||||||
#define UDP_BC_VSRC (1<<16)
|
|
||||||
#define USBPD_IN_HVT (1<<9)
|
|
||||||
#define USBPD_PHY_V33 (1<<8)
|
|
||||||
#define USB_IOEN (1<<7)
|
|
||||||
#define USB_PHY_V33 (1<<6)
|
|
||||||
#define UDP_PUE_00 (0b00<<2)
|
|
||||||
#define UDP_PUE_01 (0b01<<2)
|
|
||||||
#define UDP_PUE_10 (0b10<<2)
|
|
||||||
#define UDP_PUE_11 (0b11<<2)
|
|
||||||
#define UDM_PUE_00 (0b00<<0)
|
|
||||||
#define UDM_PUE_01 (0b01<<0)
|
|
||||||
#define UDM_PUE_10 (0b10<<0)
|
|
||||||
#define UDM_PUE_11 (0b11<<0)
|
|
||||||
#define UDP_PUE_MASK 0x0000000C
|
|
||||||
#define UDP_PUE_DISABLE 0x00000000
|
|
||||||
#define UDP_PUE_35UA 0x00000004
|
|
||||||
#define UDP_PUE_10K 0x00000008
|
|
||||||
#define UDP_PUE_1K5 0x0000000C
|
|
||||||
#define UDM_PUE_MASK 0x00000003
|
|
||||||
#define UDM_PUE_DISABLE 0x00000000
|
|
||||||
#define UDM_PUE_35UA 0x00000001
|
|
||||||
#define UDM_PUE_10K 0x00000002
|
|
||||||
#define UDM_PUE_1K5 0x00000003
|
|
||||||
|
|
||||||
|
|
||||||
// USB PD Bits
|
|
||||||
#define IE_TX_END (1<<15)
|
|
||||||
#define IE_RX_RESET (1<<14)
|
|
||||||
#define IE_RX_ACT (1<<13)
|
|
||||||
#define IE_RX_BYTE (1<<12)
|
|
||||||
#define IE_RX_BIT (1<<11)
|
|
||||||
#define IE_PD_IO (1<<10)
|
|
||||||
#define WAKE_POLAR (1<<5)
|
|
||||||
#define PD_RST_EN (1<<4)
|
|
||||||
#define PD_DMA_EN (1<<3)
|
|
||||||
#define CC_SEL (1<<2)
|
|
||||||
#define PD_ALL_CLR (1<<1)
|
|
||||||
#define PD_FILT_EN (1<<0)
|
|
||||||
#define BMC_CLK_CNT_MASK (0xff)
|
|
||||||
|
|
||||||
//R8_CONTROL
|
|
||||||
#define BMC_BYTE_HI (1<<7)
|
|
||||||
#define TX_BIT_BACK (1<<6)
|
|
||||||
#define DATA_FLAG (1<<5)
|
|
||||||
#define RX_STATE_MASK (0x7<<2)
|
|
||||||
#define RX_STATE_0 (1<<2)
|
|
||||||
#define RX_STATE_1 (1<<3)
|
|
||||||
#define RX_STATE_2 (1<<4)
|
|
||||||
#define BMC_START (1<<1)
|
|
||||||
#define PD_TX_EN (1<<0)
|
|
||||||
|
|
||||||
#define TX_SEL4_MASK (3<<6)
|
|
||||||
#define TX_SEL4_0 (1<<6)
|
|
||||||
#define TX_SEL4_1 (1<<7)
|
|
||||||
|
|
||||||
#define TX_SEL3_MASK (3<<4)
|
|
||||||
#define TX_SEL3_0 (1<<4)
|
|
||||||
#define TX_SEL3_1 (1<<5)
|
|
||||||
|
|
||||||
#define TX_SEL2_MASK (3<<2)
|
|
||||||
#define TX_SEL2_0 (1<<2)
|
|
||||||
#define TX_SEL2_1 (1<<3)
|
|
||||||
|
|
||||||
#define TX_SEL1 (1<<0)
|
|
||||||
|
|
||||||
#define BMC_TX_SZ_MASK (0x1ff)
|
|
||||||
|
|
||||||
//R8_STATUS
|
|
||||||
#define IF_TX_END (1<<7)
|
|
||||||
#define IF_RX_RESET (1<<6)
|
|
||||||
#define IF_RX_ACT (1<<5)
|
|
||||||
#define IF_RX_BYTE (1<<4)
|
|
||||||
#define IF_RX_BIT (1<<3)
|
|
||||||
#define IFBUF_ERR (1<<2)
|
|
||||||
#define BMC_AUX_MASK (3<<0)
|
|
||||||
#define BMC_AUX_1 (1<<1)
|
|
||||||
#define BMC_AUX_0 (1<<0)
|
|
||||||
|
|
||||||
// PORT CC1
|
|
||||||
#define CC1_CE_MASK (7<<5)
|
|
||||||
#define CC1_CE_0 (1<<5)
|
|
||||||
#define CC1_CE_1 (2<<5)
|
|
||||||
#define CC1_CE_2 (4<<5)
|
|
||||||
|
|
||||||
#define CC1_LVE (1<<4)
|
|
||||||
#define CC1_PU_MASK (3<<2)
|
|
||||||
#define CC1_PU_DISABLE (0<<2)
|
|
||||||
#define CC1_PU_330uA (1<<2)
|
|
||||||
#define CC1_PU_180uA (2<<2)
|
|
||||||
#define CC1_PU_80uA (3<<2)
|
|
||||||
#define PA_CC1_AI (1<<0)
|
|
||||||
|
|
||||||
#define CC2_CE_MASK (7<<5)
|
|
||||||
#define CC2_CE_0 (1<<5)
|
|
||||||
#define CC2_CE_1 (2<<5)
|
|
||||||
#define CC2_CE_2 (4<<5)
|
|
||||||
|
|
||||||
#define CC2_LVE (1<<4)
|
|
||||||
#define CC2_PU_MASK (3<<2)
|
|
||||||
#define CC2_PU_DISABLE (0<<2)
|
|
||||||
#define CC2_PU_330uA (1<<2)
|
|
||||||
#define CC2_PU_180uA (2<<2)
|
|
||||||
#define CC2_PU_80uA (3<<2)
|
|
||||||
#define PA_CC2_AI (1<<0)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -5356,33 +5238,33 @@ typedef struct
|
||||||
|
|
||||||
#if defined(CH32V003)
|
#if defined(CH32V003)
|
||||||
/***************** Bit definition for AFIO_EXTICR register *****************/
|
/***************** Bit definition for AFIO_EXTICR register *****************/
|
||||||
#define AFIO_EXTICR_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
#define AFIO_EXTICR1_EXTI0 ((uint16_t)0x0003) /* EXTI 0 configuration */
|
||||||
#define AFIO_EXTICR_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
#define AFIO_EXTICR1_EXTI1 ((uint16_t)0x000C) /* EXTI 1 configuration */
|
||||||
#define AFIO_EXTICR_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
#define AFIO_EXTICR1_EXTI2 ((uint16_t)0x0030) /* EXTI 2 configuration */
|
||||||
#define AFIO_EXTICR_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
#define AFIO_EXTICR1_EXTI3 ((uint16_t)0x00C0) /* EXTI 3 configuration */
|
||||||
#define AFIO_EXTICR_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
#define AFIO_EXTICR1_EXTI4 ((uint16_t)0x0300) /* EXTI 4 configuration */
|
||||||
#define AFIO_EXTICR_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
#define AFIO_EXTICR1_EXTI5 ((uint16_t)0x0C00) /* EXTI 5 configuration */
|
||||||
#define AFIO_EXTICR_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
#define AFIO_EXTICR1_EXTI6 ((uint16_t)0x3000) /* EXTI 6 configuration */
|
||||||
#define AFIO_EXTICR_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
#define AFIO_EXTICR1_EXTI7 ((uint16_t)0xC000) /* EXTI 7 configuration */
|
||||||
|
|
||||||
#define AFIO_EXTICR_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
#define AFIO_EXTICR1_EXTI0_PC ((uint16_t)0x0002) /* PC[0] pin */
|
||||||
#define AFIO_EXTICR_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
#define AFIO_EXTICR1_EXTI0_PD ((uint16_t)0x0003) /* PD[0] pin */
|
||||||
#define AFIO_EXTICR_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
#define AFIO_EXTICR1_EXTI1_PA ((uint16_t)0x0000) /* PA[1] pin */
|
||||||
#define AFIO_EXTICR_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
#define AFIO_EXTICR1_EXTI1_PC ((uint16_t)0x0008) /* PC[1] pin */
|
||||||
#define AFIO_EXTICR_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
#define AFIO_EXTICR1_EXTI1_PD ((uint16_t)0x000C) /* PD[1] pin */
|
||||||
#define AFIO_EXTICR_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
#define AFIO_EXTICR1_EXTI2_PA ((uint16_t)0x0000) /* PA[2] pin */
|
||||||
#define AFIO_EXTICR_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
#define AFIO_EXTICR1_EXTI2_PC ((uint16_t)0x0020) /* PC[2] pin */
|
||||||
#define AFIO_EXTICR_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
#define AFIO_EXTICR1_EXTI2_PD ((uint16_t)0x0030) /* PD[2] pin */
|
||||||
#define AFIO_EXTICR_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
#define AFIO_EXTICR1_EXTI3_PC ((uint16_t)0x0080) /* PC[3] pin */
|
||||||
#define AFIO_EXTICR_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
#define AFIO_EXTICR1_EXTI3_PD ((uint16_t)0x00C0) /* PD[3] pin */
|
||||||
#define AFIO_EXTICR_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
#define AFIO_EXTICR1_EXTI4_PC ((uint16_t)0x0200) /* PC[4] pin */
|
||||||
#define AFIO_EXTICR_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
#define AFIO_EXTICR1_EXTI4_PD ((uint16_t)0x0300) /* PD[4] pin */
|
||||||
#define AFIO_EXTICR_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
#define AFIO_EXTICR1_EXTI5_PC ((uint16_t)0x0800) /* PC[5] pin */
|
||||||
#define AFIO_EXTICR_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
#define AFIO_EXTICR1_EXTI5_PD ((uint16_t)0x0C00) /* PD[5] pin */
|
||||||
#define AFIO_EXTICR_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
#define AFIO_EXTICR1_EXTI6_PC ((uint16_t)0x2000) /* PC[6] pin */
|
||||||
#define AFIO_EXTICR_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
#define AFIO_EXTICR1_EXTI6_PD ((uint16_t)0x3000) /* PD[6] pin */
|
||||||
#define AFIO_EXTICR_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
#define AFIO_EXTICR1_EXTI7_PC ((uint16_t)0x8000) /* PC[7] pin */
|
||||||
#define AFIO_EXTICR_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
#define AFIO_EXTICR1_EXTI7_PD ((uint16_t)0xC000) /* PD[7] pin */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
|
#if defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
|
||||||
|
|
@ -9507,7 +9389,7 @@ typedef enum
|
||||||
#define OB_RST_NoEN ((uint16_t)0x0018) /* Reset IO disable (PD7)*/
|
#define OB_RST_NoEN ((uint16_t)0x0018) /* Reset IO disable (PD7)*/
|
||||||
#define OB_RST_EN_DT12ms ((uint16_t)0x0010) /* Reset IO enable (PD7) and Ignore delay time 12ms */
|
#define OB_RST_EN_DT12ms ((uint16_t)0x0010) /* Reset IO enable (PD7) and Ignore delay time 12ms */
|
||||||
#define OB_RST_EN_DT1ms ((uint16_t)0x0008) /* Reset IO enable (PD7) and Ignore delay time 1ms */
|
#define OB_RST_EN_DT1ms ((uint16_t)0x0008) /* Reset IO enable (PD7) and Ignore delay time 1ms */
|
||||||
#define OB_RST_EN_DT128ms ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128ms */
|
#define OB_RST_EN_DT128us ((uint16_t)0x0000) /* Reset IO enable (PD7) and Ignore delay time 128us */
|
||||||
|
|
||||||
#define OB_STARTMODE_BOOT ((uint16_t)0x0020) /* Start in BOOT area */
|
#define OB_STARTMODE_BOOT ((uint16_t)0x0020) /* Start in BOOT area */
|
||||||
#define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */
|
#define OB_STARTMODE_USER ((uint16_t)0x0000) /* Start in user area */
|
||||||
|
|
@ -12586,6 +12468,349 @@ typedef volatile unsigned long *PUINT32V;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* ch32x035_usbpd.h ----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Register Bit Definition */
|
||||||
|
/* USBPD->CONFIG */
|
||||||
|
#define PD_FILT_ED (1<<0) /* PD pin input filter enable */
|
||||||
|
#define PD_ALL_CLR (1<<1) /* Clear all interrupt flags */
|
||||||
|
#if defined(CH32X03x)
|
||||||
|
#define CC_SEL (1<<2) /* Select PD communication port */
|
||||||
|
#define PD_DMA_EN (1<<3) /* Enable DMA for USBPD */
|
||||||
|
#define PD_RST_EN (1<<4) /* PD mode reset command enable */
|
||||||
|
#define WAKE_POLAR (1<<5) /* PD port wake-up level */
|
||||||
|
#elif defined(CH641)
|
||||||
|
#define CC_ALL_SEL (3<<2) /* Select PD communication port ALL*/
|
||||||
|
#define CC_SEL_Mask (3<<2) /* Clear PD communication port */
|
||||||
|
#define CC_SEL_1 (0<<2) /* Select PD communication port1 */
|
||||||
|
#define CC_SEL_2 (1<<2) /* Select PD communication port2 */
|
||||||
|
#define CC_SEL_3 (2<<2) /* Select PD communication port3 */
|
||||||
|
#define PD_DMA_EN (1<<4) /* Enable DMA for USBPD */
|
||||||
|
#define PD_RST_EN (1<<5) /* PD mode reset command enable */
|
||||||
|
#define WAKE_POLAR (1<<6) /* PD port wake-up level */
|
||||||
|
#endif
|
||||||
|
#define IE_PD_IO (1<<10) /* PD IO interrupt enable */
|
||||||
|
#define IE_RX_BIT (1<<11) /* Receive bit interrupt enable */
|
||||||
|
#define IE_RX_BYTE (1<<12) /* Receive byte interrupt enable */
|
||||||
|
#define IE_RX_ACT (1<<13) /* Receive completion interrupt enable */
|
||||||
|
#define IE_RX_RESET (1<<14) /* Reset interrupt enable */
|
||||||
|
#define IE_TX_END (1<<15) /* Transfer completion interrupt enable */
|
||||||
|
|
||||||
|
/* USBPD->CONTROL */
|
||||||
|
#define PD_TX_EN (1<<0) /* USBPD transceiver mode and transmit enable */
|
||||||
|
#define BMC_START (1<<1) /* BMC send start signal */
|
||||||
|
#define RX_STATE_0 (1<<2) /* PD received state bit 0 */
|
||||||
|
#define RX_STATE_1 (1<<3) /* PD received state bit 1 */
|
||||||
|
#define RX_STATE_2 (1<<4) /* PD received state bit 2 */
|
||||||
|
#define DATA_FLAG (1<<5) /* Cache data valid flag bit */
|
||||||
|
#define TX_BIT_BACK (1<<6) /* Indicates the current bit status of the BMC when sending the code */
|
||||||
|
#define BMC_BYTE_HI (1<<7) /* Indicates the current half-byte status of the PD data being sent and received */
|
||||||
|
|
||||||
|
/* USBPD->TX_SEL */
|
||||||
|
#define TX_SEL1 (0<<0)
|
||||||
|
#define TX_SEL1_SYNC1 (0<<0) /* 0-SYNC1 */
|
||||||
|
#define TX_SEL1_RST1 (1<<0) /* 1-RST1 */
|
||||||
|
#define TX_SEL2_Mask (3<<2)
|
||||||
|
#define TX_SEL2_SYNC1 (0<<2) /* 00-SYNC1 */
|
||||||
|
#define TX_SEL2_SYNC3 (1<<2) /* 01-SYNC3 */
|
||||||
|
#define TX_SEL2_RST1 (2<<2) /* 1x-RST1 */
|
||||||
|
#define TX_SEL3_Mask (3<<4)
|
||||||
|
#define TX_SEL3_SYNC1 (0<<4) /* 00-SYNC1 */
|
||||||
|
#define TX_SEL3_SYNC3 (1<<4) /* 01-SYNC3 */
|
||||||
|
#define TX_SEL3_RST1 (2<<4) /* 1x-RST1 */
|
||||||
|
#define TX_SEL4_Mask (3<<6)
|
||||||
|
#define TX_SEL4_SYNC2 (0<<6) /* 00-SYNC2 */
|
||||||
|
#define TX_SEL4_SYNC3 (1<<6) /* 01-SYNC3 */
|
||||||
|
#define TX_SEL4_RST2 (2<<6) /* 1x-RST2 */
|
||||||
|
|
||||||
|
/* USBPD->STATUS */
|
||||||
|
#define BMC_AUX_Mask (3<<0) /* Clear BMC auxiliary information */
|
||||||
|
#define BMC_AUX_INVALID (0<<0) /* 00-Invalid */
|
||||||
|
#define BMC_AUX_SOP0 (1<<0) /* 01-SOP0 */
|
||||||
|
#define BMC_AUX_SOP1_HRST (2<<0) /* 10-SOP1 hard reset */
|
||||||
|
#define BMC_AUX_SOP2_CRST (3<<0) /* 11-SOP2 cable reset */
|
||||||
|
#define BUF_ERR (1<<2) /* BUFFER or DMA error interrupt flag */
|
||||||
|
#define IF_RX_BIT (1<<3) /* Receive bit or 5bit interrupt flag */
|
||||||
|
#define IF_RX_BYTE (1<<4) /* Receive byte or SOP interrupt flag */
|
||||||
|
#define IF_RX_ACT (1<<5) /* Receive completion interrupt flag */
|
||||||
|
#define IF_RX_RESET (1<<6) /* Receive reset interrupt flag */
|
||||||
|
#define IF_TX_END (1<<7) /* Transfer completion interrupt flag */
|
||||||
|
|
||||||
|
/* USBPD->PORT_CC1 */
|
||||||
|
/* USBPD->PORT_CC2 */
|
||||||
|
#if defined(CH641)
|
||||||
|
/* USBPD->PORT_CC3 */
|
||||||
|
#define CC_CMPO (1<<0) /* CC port comparator analog input */
|
||||||
|
#elif defined(CH32X03x)
|
||||||
|
#define PA_CC_AI (1<<0) /* CC port comparator analogue input */
|
||||||
|
#endif
|
||||||
|
#define CC_PD (1<<1) /* CC port pull-down resistor enable */
|
||||||
|
#define CC_PU_Mask (3<<2) /* Clear CC port pull-up current */
|
||||||
|
#define CC_NO_PU (0<<2) /* 00-Prohibit pull-up current */
|
||||||
|
#define CC_PU_330 (1<<2) /* 01-330uA */
|
||||||
|
#define CC_PU_180 (2<<2) /* 10-180uA */
|
||||||
|
#define CC_PU_80 (3<<2) /* 11-80uA */
|
||||||
|
#define CC_LVE (1<<4) /* CC port output low voltage enable */
|
||||||
|
#if defined(CH32X03x)
|
||||||
|
#define CC_CMP_Mask (7<<5) /* Clear CC_CMP*/
|
||||||
|
#define CC_NO_CMP (0<<5) /* 000-closed */
|
||||||
|
#define CC_CMP_22 (2<<5) /* 010-0.22V */
|
||||||
|
#define CC_CMP_45 (3<<5) /* 011-0.45V */
|
||||||
|
#define CC_CMP_55 (4<<5) /* 100-0.55V */
|
||||||
|
#define CC_CMP_66 (5<<5) /* 101-0.66V */
|
||||||
|
#define CC_CMP_95 (6<<5) /* 110-0.95V */
|
||||||
|
#define CC_CMP_123 (7<<5) /* 111-1.23V */
|
||||||
|
#define USBPD_IN_HVT (1<<9)
|
||||||
|
#elif defined(CH641)
|
||||||
|
#define CC_CVS_Mask (3<<5) /* clear CC_CVS*/
|
||||||
|
#define CC_CVS_55 (0<<5) /* 00-0.55V */
|
||||||
|
#define CC_CVS_22 (1<<5) /* 01-0.22V */
|
||||||
|
#define CC_CVS_66 (2<<5) /* 10-0.66V */
|
||||||
|
#define CC_CVS_123 (3<<5) /* 11-1.23V */
|
||||||
|
#define CC_CE (1<<7) /* Enable the voltage comparator on port CC */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CH32X03x)
|
||||||
|
|
||||||
|
/*********************************************************
|
||||||
|
* PD pin PC14/PC15 high threshold input mode:
|
||||||
|
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||||
|
* 0-Normal GPIO threshold input
|
||||||
|
* *******************************************************/
|
||||||
|
#define USBPD_PHY_V33 (1<<8)
|
||||||
|
/**********************************************************
|
||||||
|
* PD transceiver PHY pull-up limit configuration bits:
|
||||||
|
* 1-Direct use of VDD for GPIO applications or PD applications with VDD voltage of 3.3V
|
||||||
|
* 0-LDO buck enabled, limited to approx 3.3V, for PD applications with VDD more than 4V
|
||||||
|
* ********************************************************/
|
||||||
|
|
||||||
|
#elif defined(CH641)
|
||||||
|
|
||||||
|
/*********************************************************
|
||||||
|
* PD pin PB0/PB1/PB9 high threshold input mode:
|
||||||
|
* 1-High threshold input (2.2V typical), to reduce the I/O power consumption during PD communication
|
||||||
|
* 0-Normal GPIO threshold input
|
||||||
|
* *******************************************************/
|
||||||
|
#define USBPD_HVT (1<<19)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Control Message Types */
|
||||||
|
#define DEF_TYPE_RESERVED 0x00
|
||||||
|
#define DEF_TYPE_GOODCRC 0x01 /* Send By: Source,Sink,Cable Plug */
|
||||||
|
#define DEF_TYPE_GOTOMIN 0x02 /* Send By: Source */
|
||||||
|
#define DEF_TYPE_ACCEPT 0x03 /* Send By: Source,Sink,Cable Plug */
|
||||||
|
#define DEF_TYPE_REJECT 0x04 /* Send By: Source,Sink,Cable Plug */
|
||||||
|
#define DEF_TYPE_PING 0x05 /* Send By: Source */
|
||||||
|
#define DEF_TYPE_PS_RDY 0x06 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_GET_SRC_CAP 0x07 /* Send By: Sink,DRP */
|
||||||
|
#define DEF_TYPE_GET_SNK_CAP 0x08 /* Send By: Source,DRP */
|
||||||
|
#define DEF_TYPE_DR_SWAP 0x09 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_PR_SWAP 0x0A /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_VCONN_SWAP 0x0B /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_WAIT 0x0C /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_SOFT_RESET 0x0D /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_DATA_RESET 0x0E /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_DATA_RESET_CMP 0x0F /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_NOT_SUPPORT 0x10 /* Send By: Source,Sink,Cable Plug */
|
||||||
|
#define DEF_TYPE_GET_SRC_CAP_EX 0x11 /* Send By: Sink,DRP */
|
||||||
|
#define DEF_TYPE_GET_STATUS 0x12 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_GET_STATUS_R 0X02 /* ext=1 */
|
||||||
|
#define DEF_TYPE_FR_SWAP 0x13 /* Send By: Sink */
|
||||||
|
#define DEF_TYPE_GET_PPS_STATUS 0x14 /* Send By: Sink */
|
||||||
|
#define DEF_TYPE_GET_CTY_CODES 0x15 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_GET_SNK_CAP_EX 0x16 /* Send By: Source,DRP */
|
||||||
|
#define DEF_TYPE_GET_SRC_INFO 0x17 /* Send By: Sink,DRP */
|
||||||
|
#define DEF_TYPE_GET_REVISION 0x18 /* Send By: Source,Sink */
|
||||||
|
|
||||||
|
/* Data Message Types */
|
||||||
|
#define DEF_TYPE_SRC_CAP 0x01 /* Send By: Source,Dual-Role Power */
|
||||||
|
#define DEF_TYPE_REQUEST 0x02 /* Send By: Sink */
|
||||||
|
#define DEF_TYPE_BIST 0x03 /* Send By: Tester,Source,Sink */
|
||||||
|
#define DEF_TYPE_SNK_CAP 0x04 /* Send By: Sink,Dual-Role Power */
|
||||||
|
#define DEF_TYPE_BAT_STATUS 0x05 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_ALERT 0x06 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_GET_CTY_INFO 0x07 /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_ENTER_USB 0x08 /* Send By: DFP */
|
||||||
|
#define DEF_TYPE_EPR_REQUEST 0x09 /* Send By: Sink */
|
||||||
|
#define DEF_TYPE_EPR_MODE 0x0A /* Send By: Source,Sink */
|
||||||
|
#define DEF_TYPE_SRC_INFO 0x0B /* Send By: Source */
|
||||||
|
#define DEF_TYPE_REVISION 0x0C /* Send By: Source,Sink,Cable Plug */
|
||||||
|
#define DEF_TYPE_VENDOR_DEFINED 0x0F /* Send By: Source,Sink,Cable Plug */
|
||||||
|
|
||||||
|
/* Vendor Define Message Command */
|
||||||
|
#define DEF_VDM_DISC_IDENT 0x01
|
||||||
|
#define DEF_VDM_DISC_SVID 0x02
|
||||||
|
#define DEF_VDM_DISC_MODE 0x03
|
||||||
|
#define DEF_VDM_ENTER_MODE 0x04
|
||||||
|
#define DEF_VDM_EXIT_MODE 0x05
|
||||||
|
#define DEF_VDM_ATTENTION 0x06
|
||||||
|
#define DEF_VDM_DP_S_UPDATE 0x10
|
||||||
|
#define DEF_VDM_DP_CONFIG 0x11
|
||||||
|
|
||||||
|
/* PD Revision */
|
||||||
|
#define DEF_PD_REVISION_10 0x00
|
||||||
|
#define DEF_PD_REVISION_20 0x01
|
||||||
|
#define DEF_PD_REVISION_30 0x02
|
||||||
|
|
||||||
|
|
||||||
|
/* PD PHY Channel */
|
||||||
|
#if defined(CH32X03x)
|
||||||
|
|
||||||
|
#define DEF_PD_CC1 0x00
|
||||||
|
#define DEF_PD_CC2 0x01
|
||||||
|
|
||||||
|
#define PIN_CC1 GPIO_Pin_14
|
||||||
|
#define PIN_CC2 GPIO_Pin_15
|
||||||
|
|
||||||
|
#elif defined(CH641)
|
||||||
|
#define PIN_CC1 GPIO_Pin_0
|
||||||
|
#define PIN_CC2 GPIO_Pin_1
|
||||||
|
#define PIN_CC3 GPIO_Pin_9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PD Tx Status */
|
||||||
|
#define DEF_PD_TX_OK 0x00
|
||||||
|
#define DEF_PD_TX_FAIL 0x01
|
||||||
|
|
||||||
|
/* PDO INDEX */
|
||||||
|
#define PDO_INDEX_1 1
|
||||||
|
#define PDO_INDEX_2 2
|
||||||
|
#define PDO_INDEX_3 3
|
||||||
|
#define PDO_INDEX_4 4
|
||||||
|
#define PDO_INDEX_5 5
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define UPD_TMR_TX_48M (80-1) /* timer value for USB PD BMC transmittal @Fsys=48MHz */
|
||||||
|
#define UPD_TMR_RX_48M (120-1) /* timer value for USB PD BMC receiving @Fsys=48MHz */
|
||||||
|
#define UPD_TMR_TX_24M (40-1) /* timer value for USB PD BMC transmittal @Fsys=24MHz */
|
||||||
|
#define UPD_TMR_RX_24M (60-1) /* timer value for USB PD BMC receiving @Fsys=24MHz */
|
||||||
|
#define UPD_TMR_TX_12M (20-1) /* timer value for USB PD BMC transmittal @Fsys=12MHz */
|
||||||
|
#define UPD_TMR_RX_12M (30-1) /* timer value for USB PD BMC receiving @Fsys=12MHz */
|
||||||
|
|
||||||
|
#define MASK_PD_STAT 0x03 /* Bit mask for current PD status */
|
||||||
|
#define PD_RX_SOP0 0x01 /* SOP0 received */
|
||||||
|
#define PD_RX_SOP1_HRST 0x02 /* SOP1 or Hard Reset received */
|
||||||
|
#define PD_RX_SOP2_CRST 0x03 /* SOP2 or Cable Reset received */
|
||||||
|
|
||||||
|
#define UPD_SOP0 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC1 | TX_SEL4_SYNC2 ) /* SOP1 */
|
||||||
|
#define UPD_SOP1 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC1 | TX_SEL3_SYNC3 | TX_SEL4_SYNC3 ) /* SOP2 */
|
||||||
|
#define UPD_SOP2 ( TX_SEL1_SYNC1 | TX_SEL2_SYNC3 | TX_SEL3_SYNC1 | TX_SEL4_SYNC3 ) /* SOP3 */
|
||||||
|
#define UPD_HARD_RESET ( TX_SEL1_RST1 | TX_SEL2_RST1 | TX_SEL3_RST1 | TX_SEL4_RST2 ) /* Hard Reset*/
|
||||||
|
#define UPD_CABLE_RESET ( TX_SEL1_RST1 | TX_SEL2_SYNC1 | TX_SEL3_RST1 | TX_SEL4_SYNC3 ) /* Cable Reset*/
|
||||||
|
|
||||||
|
|
||||||
|
#define bCC_CMP_22 0X01
|
||||||
|
#define bCC_CMP_45 0X02
|
||||||
|
#define bCC_CMP_55 0X04
|
||||||
|
#define bCC_CMP_66 0X08
|
||||||
|
#define bCC_CMP_95 0X10
|
||||||
|
#define bCC_CMP_123 0X20
|
||||||
|
#define bCC_CMP_220 0X40
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* PD State Machine */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STA_IDLE = 0, /* 0: No task status */
|
||||||
|
STA_DISCONNECT, /* 1: Disconnection */
|
||||||
|
STA_SRC_CONNECT, /* 2: SRC connect */
|
||||||
|
STA_RX_SRC_CAP_WAIT, /* 3: Waiting to receive SRC_CAP */
|
||||||
|
STA_RX_SRC_CAP, /* 4: SRC_CAP received */
|
||||||
|
STA_TX_REQ, /* 5: Send REQUEST */
|
||||||
|
STA_RX_ACCEPT_WAIT, /* 6: Waiting to receive ACCEPT */
|
||||||
|
STA_RX_ACCEPT, /* 7: ACCEPT received */
|
||||||
|
STA_RX_REJECT, /* 8: REJECT received */
|
||||||
|
STA_RX_PS_RDY_WAIT, /* 9: Waiting to receive PS_RDY */
|
||||||
|
STA_RX_PS_RDY, /* 10: PS_RDY received */
|
||||||
|
STA_SINK_CONNECT, /* 11: SNK access */
|
||||||
|
STA_TX_SRC_CAP, /* 12: Send SRC_CAP */
|
||||||
|
STA_RX_REQ_WAIT, /* 13: Waiting to receive REQUEST */
|
||||||
|
STA_RX_REQ, /* 14: REQUEST received */
|
||||||
|
STA_TX_ACCEPT, /* 15: Send ACCEPT */
|
||||||
|
STA_TX_REJECT, /* 16: Send REJECT */
|
||||||
|
STA_ADJ_VOL, /* 17: Adjustment of output voltage and current */
|
||||||
|
STA_TX_PS_RDY, /* 18: Send PS_RDY */
|
||||||
|
STA_TX_DR_SWAP, /* 19: Send DR_SWAP */
|
||||||
|
STA_RX_DR_SWAP_ACCEPT, /* 20: Waiting to receive the answer ACCEPT from DR_SWAP */
|
||||||
|
STA_TX_PR_SWAP, /* 21: Send PR_SWAP */
|
||||||
|
STA_RX_PR_SWAP_ACCEPT, /* 22: Waiting to receive the answer ACCEPT from PR_SWAP */
|
||||||
|
STA_RX_PR_SWAP_PS_RDY, /* 23: Waiting to receive the answer PS_RDY from PR_SWAP */
|
||||||
|
STA_TX_PR_SWAP_PS_RDY, /* 24: Send answer PS_RDY for PR_SWAP */
|
||||||
|
STA_PR_SWAP_RECON_WAIT, /* 25: Wait for PR_SWAP before reconnecting */
|
||||||
|
STA_SRC_RECON_WAIT, /* 26: Waiting for SRC to reconnect */
|
||||||
|
STA_SINK_RECON_WAIT, /* 27: Waiting for SNK to reconnect */
|
||||||
|
STA_RX_APD_PS_RDY_WAIT, /* 28: Waiting for PS_RDY from the receiving adapter */
|
||||||
|
STA_RX_APD_PS_RDY, /* 29: PS_RDY received from the adapter */
|
||||||
|
STA_MODE_SWITCH, /* 30: Mode switching */
|
||||||
|
STA_TX_SOFTRST, /* 31: Sending a software reset */
|
||||||
|
STA_TX_HRST, /* 32: Send hardware reset */
|
||||||
|
STA_PHY_RST, /* 33: PHY reset */
|
||||||
|
STA_APD_IDLE_WAIT, /* 34: Waiting for the adapter to become idle */
|
||||||
|
} CC_STATUS;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* PD Message Header Struct */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct _Message_Header
|
||||||
|
{
|
||||||
|
UINT8 MsgType: 5; /* Message Type */
|
||||||
|
UINT8 PDRole: 1; /* 0-UFP; 1-DFP */
|
||||||
|
UINT8 SpecRev: 2; /* 00-Rev1.0; 01-Rev2.0; 10-Rev3.0; */
|
||||||
|
UINT8 PRRole: 1; /* 0-Sink; 1-Source */
|
||||||
|
UINT8 MsgID: 3;
|
||||||
|
UINT8 NumDO: 3;
|
||||||
|
UINT8 Ext: 1;
|
||||||
|
}Message_Header;
|
||||||
|
UINT16 Data;
|
||||||
|
}_Message_Header;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Bit definition */
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
struct _BITS_
|
||||||
|
{
|
||||||
|
UINT8 Msg_Recvd: 1; /* Notify the main program of the receipt of a PD packet */
|
||||||
|
UINT8 Connected: 1; /* PD Physical Layer Connected Flag */
|
||||||
|
UINT8 Stop_Det_Chk: 1; /* 0-Enable detection; 1-Disable disconnection detection */
|
||||||
|
UINT8 PD_Role: 1; /* 0-UFP; 1-DFP */
|
||||||
|
UINT8 PR_Role: 1; /* 0-Sink; 1-Source */
|
||||||
|
UINT8 Auto_Ack_PRRole: 1; /* Role used by auto-responder 0:SINK; 1:SOURCE */
|
||||||
|
UINT8 PD_Version: 1; /* PD version 0-PD2.0; 1-PD3.0 */
|
||||||
|
UINT8 VDM_Version: 1; /* VDM Version 0-1.0 1-2.0 */
|
||||||
|
UINT8 HPD_Connected: 1; /* HPD Physical Layer Connected Flag */
|
||||||
|
UINT8 HPD_Det_Chk: 1; /* 0-turn off HPD connection detection; 1-turn on HPD connection detection */
|
||||||
|
UINT8 CC_Sel_En: 1; /* 0-CC channel selection toggle enable; 1-CC channel selection toggle disable */
|
||||||
|
UINT8 CC_Sel_State: 1; /* 0-CC channel selection switches to 0; 1-CC channel selection switches to 1 */
|
||||||
|
UINT8 PD_Comm_Succ: 1; /* 0-PD communication unsuccessful; 1-PD communication successful; */
|
||||||
|
UINT8 Recv: 3;
|
||||||
|
}Bit;
|
||||||
|
UINT16 Bit_Flag;
|
||||||
|
}_BIT_FLAG;
|
||||||
|
|
||||||
|
/* PD control-related structures */
|
||||||
|
typedef struct _PD_CONTROL
|
||||||
|
{
|
||||||
|
CC_STATUS PD_State; /* PD communication status machine */
|
||||||
|
CC_STATUS PD_State_Last; /* PD communication status machine (last value) */
|
||||||
|
UINT8 Msg_ID; /* ID of the message sent */
|
||||||
|
UINT8 Det_Timer; /* PD connection status detection timing */
|
||||||
|
UINT8 Det_Cnt; /* Number of PD connection status detections */
|
||||||
|
UINT8 Det_Sel_Cnt; /* Number of SEL toggles for PD connection status detection */
|
||||||
|
UINT8 HPD_Det_Timer; /* HPD connection detection timing */
|
||||||
|
UINT8 HPD_Det_Cnt; /* HPD pin connection status detection count */
|
||||||
|
UINT16 PD_Comm_Timer; /* PD shared timing variables */
|
||||||
|
UINT8 ReqPDO_Idx; /* Index of the requested PDO, valid values 1-7 */
|
||||||
|
UINT16 PD_BusIdle_Timer; /* Bus Idle Time Timer */
|
||||||
|
UINT8 Mode_Try_Cnt; /* Number of retries for current mode, highest bit marks mode */
|
||||||
|
UINT8 Err_Op_Cnt; /* Exception operation count */
|
||||||
|
UINT8 Adapter_Idle_Cnt; /* Adapter communication idle timing */
|
||||||
|
_BIT_FLAG Flag; /* Flag byte bit definition */
|
||||||
|
}PD_CONTROL, *pPD_CONTROL;
|
||||||
|
|
||||||
/* ch32v00x_wwdg.h -----------------------------------------------------------*/
|
/* ch32v00x_wwdg.h -----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,244 +1,226 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
const char *yes[] = {"SENTINEL_WILL_BE_REPLACED_BY_CMDLINE"}; // "CH32X03x", etc. element 0 is filled in by command-line
|
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||||
const char *no[] = {"CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003"};
|
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||||
|
|
||||||
char *WhitePull(const char **sti)
|
char * WhitePull( const char ** sti )
|
||||||
{
|
{
|
||||||
const char *st = *sti;
|
const char * st = *sti;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
while ((*st == ' ' || *st == '\t' || *st == '(') && *st)
|
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||||
{
|
const char * sts = st;
|
||||||
st++;
|
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||||
}
|
if( *st == ')' ) { st++; }
|
||||||
const char *sts = st;
|
char * ret = malloc( len + 1 );
|
||||||
while (*st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0)
|
memcpy( ret, sts, len );
|
||||||
{
|
ret[len] = 0;
|
||||||
st++;
|
*sti = st;
|
||||||
len++;
|
return ret;
|
||||||
}
|
|
||||||
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;
|
int ret = 2;
|
||||||
char *wp = WhitePull(&s);
|
char * wp = WhitePull( &s );
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < sizeof(yes) / sizeof(yes[0]); i++)
|
for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
|
||||||
if (strcmp(yes[i], wp) == 0) ret = 1;
|
if( strcmp( yes[i], wp ) == 0 ) ret = 1;
|
||||||
if (ret != 1)
|
if( ret != 1 )
|
||||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||||
if (strcmp(no[i], wp) == 0) ret = 0;
|
if( strcmp( no[i], wp ) == 0 ) ret = 0;
|
||||||
free(wp);
|
free( wp );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EvalSpec(const char *spl)
|
int EvalSpec( const char * spl )
|
||||||
{
|
{
|
||||||
int rsofar = 0;
|
int rsofar = 0;
|
||||||
int i;
|
int i;
|
||||||
int lastv = 0;
|
int lastv = 0;
|
||||||
int lasto = -1;
|
int lasto = -1;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
cont:
|
cont:
|
||||||
char *wp = WhitePull(&spl);
|
char * wp = WhitePull( &spl );
|
||||||
int def = -1;
|
int def = -1;
|
||||||
if (strcmp(wp, "defined") == 0) def = 1;
|
if( strcmp( wp, "defined" ) == 0 ) def = 1;
|
||||||
if (strcmp(wp, "!defined") == 0) def = 2;
|
if( strcmp( wp, "!defined" ) == 0 ) def = 2;
|
||||||
if (def < 0) return 2;
|
if( def < 0 ) return 2;
|
||||||
char *wpn = WhitePull(&spl);
|
char * wpn = WhitePull( &spl );
|
||||||
i = NYI(wpn);
|
i = NYI( wpn );
|
||||||
// printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
//printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||||
if (i == 2) return 2;
|
if( i == 2 ) return 2;
|
||||||
|
|
||||||
if (def == 2) i = !i;
|
if( def == 2 ) i = !i;
|
||||||
|
|
||||||
if (lasto == 1)
|
if( lasto == 1 )
|
||||||
{
|
{
|
||||||
ret = lastv || i;
|
ret = lastv || i;
|
||||||
}
|
}
|
||||||
else if (lasto == 2)
|
else if( lasto == 2 )
|
||||||
ret = lastv && i;
|
ret = lastv && i;
|
||||||
else
|
else
|
||||||
ret = i;
|
ret = i;
|
||||||
|
|
||||||
char *wpa = WhitePull(&spl);
|
char * wpa = WhitePull( &spl );
|
||||||
// printf( "WPA: \"%s\"\n", wpa );
|
//printf( "WPA: \"%s\"\n", wpa );
|
||||||
lastv = ret;
|
lastv = ret;
|
||||||
lasto = -1;
|
lasto = -1;
|
||||||
// printf( "RET: %d\n", ret );
|
//printf( "RET: %d\n", ret );
|
||||||
if (strcmp(wpa, "||") == 0)
|
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||||
{
|
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||||
lasto = 1;
|
else return ret;
|
||||||
goto cont;
|
|
||||||
}
|
|
||||||
else if (strcmp(wpa, "&&") == 0)
|
|
||||||
{
|
|
||||||
lasto = 2;
|
|
||||||
goto cont;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 for no
|
// 0 for no
|
||||||
// 1 for yes
|
// 1 for yes
|
||||||
// 2 for indeterminate
|
// 2 for indeterminate
|
||||||
int NoYesInd(const char *preprocc)
|
int NoYesInd( const char * preprocc )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
if (strncmp(preprocc, "#if ", 4) == 0) ofs = 4;
|
if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
|
||||||
if (strncmp(preprocc, "#elif ", 6) == 0) ofs = 6;
|
if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
|
||||||
if (ofs)
|
if( ofs )
|
||||||
{
|
{
|
||||||
ret = EvalSpec(preprocc + ofs);
|
ret = EvalSpec( preprocc + ofs );
|
||||||
// printf( "SPEC: %d\n", ret );
|
//printf( "SPEC: %d\n", ret );
|
||||||
}
|
}
|
||||||
else if (strncmp(preprocc, "#ifdef ", 7) == 0)
|
else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
|
||||||
{
|
{
|
||||||
const char *ep = preprocc + 6;
|
const char * ep = preprocc + 6;
|
||||||
char *wp = WhitePull(&ep);
|
char * wp = WhitePull( &ep );
|
||||||
ret = NYI(wp);
|
ret = NYI( wp );
|
||||||
free(wp);
|
free( wp );
|
||||||
}
|
}
|
||||||
else if (strncmp(preprocc, "#ifndef ", 8) == 0)
|
else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
|
||||||
{
|
{
|
||||||
const char *ep = preprocc + 6;
|
const char * ep = preprocc + 6;
|
||||||
char *wp = WhitePull(&ep);
|
char * wp = WhitePull( &ep );
|
||||||
ret = NYI(wp);
|
ret = NYI( wp );
|
||||||
if (ret < 2) ret = !ret;
|
if( ret < 2 ) ret = !ret;
|
||||||
free(wp);
|
free( wp );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = 2;
|
ret = 2;
|
||||||
// printf( "%d-> %s\n", ret, preprocc );
|
//printf( "%d-> %s\n", ret, preprocc );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sslineis(const char *line, const char *match)
|
const char * sslineis( const char * line, const char * match )
|
||||||
{
|
{
|
||||||
while (*line == ' ' || *line == '\t')
|
while( *line == ' ' || *line == '\t' ) line++;
|
||||||
line++;
|
const char * linestart = line;
|
||||||
const char *linestart = line;
|
while( *line && *match == *line ) { line++; match++; }
|
||||||
while (*line && *match == *line)
|
if( *match == 0 )
|
||||||
{
|
return linestart;
|
||||||
line++;
|
else
|
||||||
match++;
|
return 0;
|
||||||
}
|
|
||||||
if (*match == 0)
|
|
||||||
return linestart;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main( int argc, char ** argv )
|
||||||
{
|
{
|
||||||
if (argc != 3)
|
if( argc != 3 )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n");
|
fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\t%s\n", no[i]);
|
fprintf( stderr, "\t%s\n", no[i] );
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
yes[0] = argv[1];
|
yes[0] = argv[1];
|
||||||
|
|
||||||
FILE *f = fopen(argv[2], "r");
|
FILE * f = fopen( argv[2], "r" );
|
||||||
if (!f)
|
if( !f )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: Could not open \"%s\"\n", argv[2]);
|
fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
char line[1024];
|
char line[1024];
|
||||||
char *l;
|
char * l;
|
||||||
|
|
||||||
int depth = 0;
|
|
||||||
|
|
||||||
// 0 = no
|
int depth = 0;
|
||||||
// 1 = yes
|
|
||||||
// 2 = indeterminate
|
|
||||||
// 3 = super no. (I.e. after a true #if clause)
|
|
||||||
int yesnoind[1024];
|
|
||||||
yesnoind[0] = 1;
|
|
||||||
|
|
||||||
while (l = fgets(line, sizeof(line) - 1, f))
|
// 0 = no
|
||||||
{
|
// 1 = yes
|
||||||
const char *ss = 0;
|
// 2 = indeterminate
|
||||||
int nyi = yesnoind[depth];
|
// 3 = super no. (I.e. after a true #if clause)
|
||||||
int waspre = 0;
|
int yesnoind[1024];
|
||||||
|
yesnoind[0] = 1;
|
||||||
|
|
||||||
if ((ss = sslineis(line, "#if ")) || (ss = sslineis(line, "#ifdef ")) || (ss = sslineis(line, "#ifndef ")))
|
while( l = fgets( line, sizeof(line)-1, f ) )
|
||||||
{
|
{
|
||||||
waspre = 1;
|
const char * ss = 0;
|
||||||
// printf( "CHECK: %d/%s\n", depth, l );
|
int nyi = yesnoind[depth];
|
||||||
nyi = NoYesInd(ss);
|
int waspre = 0;
|
||||||
depth++;
|
|
||||||
yesnoind[depth] = nyi;
|
|
||||||
}
|
|
||||||
else if ((ss = sslineis(line, "#elif ")))
|
|
||||||
{
|
|
||||||
if (nyi != 2)
|
|
||||||
{
|
|
||||||
waspre = 1;
|
|
||||||
if (nyi == 1)
|
|
||||||
{
|
|
||||||
nyi = 3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nyi = NoYesInd(ss);
|
|
||||||
}
|
|
||||||
// printf( "ELIF check: %s %d\n", ss, nyi );
|
|
||||||
yesnoind[depth] = nyi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((ss = sslineis(line, "#else")))
|
|
||||||
{
|
|
||||||
if (nyi != 2)
|
|
||||||
{
|
|
||||||
waspre = 1;
|
|
||||||
if (yesnoind[depth] == 1)
|
|
||||||
nyi = 3;
|
|
||||||
else
|
|
||||||
nyi = !yesnoind[depth];
|
|
||||||
yesnoind[depth] = nyi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((ss = sslineis(line, "#endif")))
|
|
||||||
{
|
|
||||||
waspre = 1;
|
|
||||||
depth--;
|
|
||||||
if (depth < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "UNTERMD IF\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int thisv = nyi;
|
if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
|
||||||
int i;
|
{
|
||||||
for (i = 0; i <= depth; i++)
|
waspre = 1;
|
||||||
{
|
//printf( "CHECK: %d/%s\n", depth, l );
|
||||||
// printf( "%d", yesnoind[i] );
|
nyi = NoYesInd( ss );
|
||||||
if (yesnoind[i] == 0 || yesnoind[i] == 3) thisv = 0;
|
depth++;
|
||||||
}
|
yesnoind[depth] = nyi;
|
||||||
// printf( ">>%s", l );
|
}
|
||||||
|
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))
|
int thisv = nyi;
|
||||||
{
|
int i;
|
||||||
printf("%s", l);
|
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
|
||||||
|
|
||||||
2747
src/ch32fun.c
2747
src/ch32fun.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue