removed uneeded files.
This commit is contained in:
parent
1f17f8dcdf
commit
32a3dcad12
25 changed files with 6911 additions and 20039 deletions
|
|
@ -1,7 +0,0 @@
|
|||
add_library(attic STATIC
|
||||
temp_transition_helper.c
|
||||
)
|
||||
|
||||
target_include_directories(attic PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,226 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||
|
||||
char * WhitePull( const char ** sti )
|
||||
{
|
||||
const char * st = *sti;
|
||||
int len = 0;
|
||||
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||
const char * sts = st;
|
||||
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||
if( *st == ')' ) { st++; }
|
||||
char * ret = malloc( len + 1 );
|
||||
memcpy( ret, sts, len );
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NYI( const char * s )
|
||||
{
|
||||
int ret = 2;
|
||||
char * wp = WhitePull( &s );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
|
||||
if( strcmp( yes[i], wp ) == 0 ) ret = 1;
|
||||
if( ret != 1 )
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
if( strcmp( no[i], wp ) == 0 ) ret = 0;
|
||||
free( wp );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EvalSpec( const char * spl )
|
||||
{
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
cont:
|
||||
char * wp = WhitePull( &spl );
|
||||
int def = -1;
|
||||
if( strcmp( wp, "defined" ) == 0 ) def = 1;
|
||||
if( strcmp( wp, "!defined" ) == 0 ) def = 2;
|
||||
if( def < 0 ) return 2;
|
||||
char * wpn = WhitePull( &spl );
|
||||
i = NYI( wpn );
|
||||
//printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if( i == 2 ) return 2;
|
||||
|
||||
if( def == 2 ) i = !i;
|
||||
|
||||
if( lasto == 1 )
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if( lasto == 2 )
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
|
||||
char * wpa = WhitePull( &spl );
|
||||
//printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
//printf( "RET: %d\n", ret );
|
||||
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||
else return ret;
|
||||
}
|
||||
|
||||
// 0 for no
|
||||
// 1 for yes
|
||||
// 2 for indeterminate
|
||||
int NoYesInd( const char * preprocc )
|
||||
{
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
|
||||
if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
|
||||
if( ofs )
|
||||
{
|
||||
ret = EvalSpec( preprocc + ofs );
|
||||
//printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
free( wp );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
if( ret < 2 ) ret = !ret;
|
||||
free( wp );
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
//printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * sslineis( const char * line, const char * match )
|
||||
{
|
||||
while( *line == ' ' || *line == '\t' ) line++;
|
||||
const char * linestart = line;
|
||||
while( *line && *match == *line ) { line++; match++; }
|
||||
if( *match == 0 )
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
if( argc != 3 )
|
||||
{
|
||||
fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
{
|
||||
fprintf( stderr, "\t%s\n", no[i] );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
yes[0] = argv[1];
|
||||
|
||||
FILE * f = fopen( argv[2], "r" );
|
||||
if( !f )
|
||||
{
|
||||
fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char * l;
|
||||
|
||||
|
||||
int depth = 0;
|
||||
|
||||
// 0 = no
|
||||
// 1 = yes
|
||||
// 2 = indeterminate
|
||||
// 3 = super no. (I.e. after a true #if clause)
|
||||
int yesnoind[1024];
|
||||
yesnoind[0] = 1;
|
||||
|
||||
while( l = fgets( line, sizeof(line)-1, f ) )
|
||||
{
|
||||
const char * ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
|
||||
if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
//printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd( ss );
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if( (ss = sslineis( line, "#elif " ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( nyi == 1 )
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd( ss );
|
||||
}
|
||||
//printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#else" ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( yesnoind[depth] == 1 )
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#endif" ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if( depth < 0 )
|
||||
{
|
||||
fprintf( stderr, "UNTERMD IF\n" );
|
||||
}
|
||||
}
|
||||
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for( i = 0; i <= depth; i++ )
|
||||
{
|
||||
//printf( "%d", yesnoind[i] );
|
||||
if( yesnoind[i] == 0 || yesnoind[i] == 3 ) thisv = 0;
|
||||
}
|
||||
//printf( ">>%s", l );
|
||||
|
||||
if( thisv != 0 && thisv != 3 && ( thisv != 1 || !waspre ) )
|
||||
{
|
||||
printf( "%s", l );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
src/extralibs/.clang-format
Normal file
5
src/extralibs/.clang-format
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"DisableFormat": true,
|
||||
"SortIncludes": "Never"
|
||||
}
|
||||
|
||||
|
|
@ -1,26 +1,22 @@
|
|||
// 2023-06-26 recallmenot
|
||||
|
||||
//######## necessities
|
||||
// ######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_GPIO_BR_H
|
||||
#define CH32V003_GPIO_BR_H
|
||||
|
||||
// includes
|
||||
#include <stdint.h> //uintN_t support
|
||||
#include "../ch32fun/ch32fun.h"
|
||||
|
||||
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
/*######## library description
|
||||
This is a speedy and light GPIO library due to
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
static inlining of most functions
|
||||
compile-time abstraction
|
||||
branchless where it counts
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
||||
first, enable the desired port.
|
||||
|
|
@ -98,78 +94,81 @@ 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)
|
||||
|
||||
//######## ports, pins and states: use these for the functions below!
|
||||
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin )
|
||||
|
||||
enum GPIO_port_n {
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
enum GPIO_port_n
|
||||
{
|
||||
GPIO_port_A = 0b00,
|
||||
GPIO_port_C = 0b10,
|
||||
GPIO_port_D = 0b11,
|
||||
};
|
||||
|
||||
enum GPIO_pinModes {
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
enum GPIO_pinModes
|
||||
{
|
||||
GPIO_pinMode_I_floating,
|
||||
GPIO_pinMode_I_pullUp,
|
||||
GPIO_pinMode_I_pullDown,
|
||||
GPIO_pinMode_I_analog,
|
||||
GPIO_pinMode_O_pushPull,
|
||||
GPIO_pinMode_O_openDrain,
|
||||
GPIO_pinMode_O_pushPullMux,
|
||||
GPIO_pinMode_O_openDrainMux,
|
||||
};
|
||||
|
||||
enum lowhigh {
|
||||
low,
|
||||
high,
|
||||
enum lowhigh
|
||||
{
|
||||
low,
|
||||
high,
|
||||
};
|
||||
|
||||
// analog inputs
|
||||
enum GPIO_analog_inputs {
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
enum GPIO_analog_inputs
|
||||
{
|
||||
GPIO_Ain0_A2,
|
||||
GPIO_Ain1_A1,
|
||||
GPIO_Ain2_C4,
|
||||
GPIO_Ain3_D2,
|
||||
GPIO_Ain4_D3,
|
||||
GPIO_Ain5_D5,
|
||||
GPIO_Ain6_D6,
|
||||
GPIO_Ain7_D4,
|
||||
GPIO_AinVref,
|
||||
GPIO_AinVcal,
|
||||
};
|
||||
|
||||
// how many cycles the ADC shall sample the input for (speed vs precision)
|
||||
enum GPIO_ADC_sampletimes {
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
enum GPIO_ADC_sampletimes
|
||||
{
|
||||
GPIO_ADC_sampletime_3cy,
|
||||
GPIO_ADC_sampletime_9cy,
|
||||
GPIO_ADC_sampletime_15cy,
|
||||
GPIO_ADC_sampletime_30cy,
|
||||
GPIO_ADC_sampletime_43cy,
|
||||
GPIO_ADC_sampletime_57cy,
|
||||
GPIO_ADC_sampletime_73cy,
|
||||
GPIO_ADC_sampletime_241cy_default,
|
||||
};
|
||||
|
||||
enum GPIO_tim1_output_sets {
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
enum GPIO_tim1_output_sets
|
||||
{
|
||||
GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
|
||||
GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
|
||||
GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
|
||||
};
|
||||
|
||||
enum GPIO_tim2_output_sets {
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
enum GPIO_tim2_output_sets
|
||||
{
|
||||
GPIO_tim2_output_set_0__D4_D3_C0_D7,
|
||||
GPIO_tim2_output_set_1__C5_C2_D2_C1,
|
||||
GPIO_tim2_output_set_2__C1_D3_C0_D7,
|
||||
GPIO_tim2_output_set_3__C1_C7_D6_D5,
|
||||
};
|
||||
|
||||
|
||||
|
||||
//######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
// ######## interface function overview: use these!
|
||||
// most functions have been reduced to function-like macros, actual definitions downstairs
|
||||
|
||||
// setup
|
||||
#define GPIO_port_enable(GPIO_port_n)
|
||||
|
|
@ -202,72 +201,66 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_tim1_analogWrite(channel, value)
|
||||
#define GPIO_tim2_analogWrite(channel, value)
|
||||
|
||||
// ######## internal function declarations
|
||||
|
||||
// ######## internal variables
|
||||
|
||||
//######## internal function declarations
|
||||
// ######## preprocessor macros
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
|
||||
#define CONCAT(a, b) a ## b
|
||||
#define CONCAT(a, b) a##b
|
||||
#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
|
||||
|
||||
#undef GPIOv_from_PORT_PIN
|
||||
#define GPIOv_from_PORT_PIN( GPIO_port_n, pin ) ((GPIO_port_n << 4 ) | (pin))
|
||||
#define GPIOv_to_PORT( GPIOv ) (GPIOv >> 4 )
|
||||
#define GPIOv_to_PIN( GPIOv ) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase( GPIOv ) ((GPIO_TypeDef*)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
#define GPIOv_from_PORT_PIN(GPIO_port_n, pin) ((GPIO_port_n << 4) | (pin))
|
||||
#define GPIOv_to_PORT(GPIOv) (GPIOv >> 4)
|
||||
#define GPIOv_to_PIN(GPIOv) (GPIOv & 0b1111)
|
||||
#define GPIOv_to_GPIObase(GPIOv) ((GPIO_TypeDef *)(uintptr_t)((GPIOA_BASE + (0x400 * (GPIOv >> 4)))))
|
||||
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
#define GPIOx_to_port_n2(GPIOx) GPIOx_to_port_n_##GPIOx
|
||||
#define GPIOx_to_port_n(GPIOx) GPIOx_to_port_n2(GPIOx)
|
||||
#define GPIOx_to_port_n_GPIO_port_A 0b00
|
||||
#define GPIOx_to_port_n_GPIO_port_C 0b10
|
||||
#define GPIOx_to_port_n_GPIO_port_D 0b11
|
||||
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
#define GPIO_port_n_to_GPIOx2(GPIO_port_n) GPIO_port_n_to_GPIOx_##GPIO_port_n
|
||||
#define GPIO_port_n_to_GPIOx(GPIO_port_n) GPIO_port_n_to_GPIOx2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_A GPIOA
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_C GPIOC
|
||||
#define GPIO_port_n_to_GPIOx_GPIO_port_D GPIOD
|
||||
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
|
||||
#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n) GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A RCC_APB2Periph_GPIOA
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C RCC_APB2Periph_GPIOC
|
||||
#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D RCC_APB2Periph_GPIOD
|
||||
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed) GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_FLOATING)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_PUPD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed) (GPIO_Speed_In | GPIO_CNF_IN_ANALOG)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_OD)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_OUT_PP_AF)
|
||||
#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed) (GPIO_Speed | GPIO_CNF_IN_ANALOG)
|
||||
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIOv) GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (GPIOv_to_PIN(GPIOv) + 16))
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIOv)
|
||||
#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIOv)
|
||||
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n) GPIO_port_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b11111111
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = 0b00000000
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n)
|
||||
#define GPIO_port_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n)
|
||||
|
|
@ -287,91 +280,74 @@ static inline void GPIO_tim2_init();
|
|||
#endif
|
||||
|
||||
#if !defined(GPIO_timer_prescaler)
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#define GPIO_timer_prescaler TIM_CKD_DIV2 // APB_CLOCK / 1024 / 2 = 23.4kHz
|
||||
#endif
|
||||
|
||||
//######## define requirements / maintenance defines
|
||||
|
||||
|
||||
|
||||
//######## small function definitions, static inline
|
||||
// ######## define requirements / maintenance defines
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
|
||||
#undef GPIO_port_enable
|
||||
#define GPIO_port_enable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
|
||||
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
#define GPIO_port_pinMode(GPIO_port_n, pinMode, GPIO_Speed) ({ \
|
||||
GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR = (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 0)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 1)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 2)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 3)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 4)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 5)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 6)) | \
|
||||
(GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * 7)); \
|
||||
GPIO_port_pinMode_set_PUPD(pinMode, GPIO_port_n); \
|
||||
})
|
||||
|
||||
#undef GPIO_port_digitalWrite
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
#define GPIO_port_digitalWrite(GPIO_port_n, byte) GPIO_port_n_to_GPIOx(GPIO_port_n)->OUTDR = byte
|
||||
|
||||
#undef GPIO_port_digitalRead
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
#define GPIO_port_digitalRead(GPIO_port_n) (GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR & 0b11111111)
|
||||
|
||||
#undef GPIO_pinMode
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
#define GPIO_pinMode(GPIOv, pinMode, GPIO_Speed) ({ \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR &= ~(0b1111 << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIOv_to_GPIObase(GPIOv)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * GPIOv_to_PIN(GPIOv))); \
|
||||
GPIO_pinMode_set_PUPD(pinMode, GPIOv); \
|
||||
})
|
||||
|
||||
#undef GPIO_digitalWrite_hi
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#define GPIO_digitalWrite_hi(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << GPIOv_to_PIN(GPIOv))
|
||||
#undef GPIO_digitalWrite_lo
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
#define GPIO_digitalWrite_lo(GPIOv) GPIOv_to_GPIObase(GPIOv)->BSHR = (1 << (16 + GPIOv_to_PIN(GPIOv)))
|
||||
|
||||
#undef GPIO_digitalWrite
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite(GPIOv, lowhigh) GPIO_digitalWrite_##lowhigh(GPIOv)
|
||||
#define GPIO_digitalWrite_low(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_0(GPIOv) GPIO_digitalWrite_lo(GPIOv)
|
||||
#define GPIO_digitalWrite_high(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
#define GPIO_digitalWrite_1(GPIOv) GPIO_digitalWrite_hi(GPIOv)
|
||||
|
||||
#undef GPIO_digitalWrite_branching
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
#define GPIO_digitalWrite_branching(GPIOv, lowhigh) (lowhigh ? GPIO_digitalWrite_hi(GPIOv) : GPIO_digitalWrite_lo(GPIOv))
|
||||
|
||||
#undef GPIO_digitalRead
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
#define GPIO_digitalRead(GPIOv) ((GPIOv_to_GPIObase(GPIOv)->INDR >> GPIOv_to_PIN(GPIOv)) & 0b1)
|
||||
|
||||
#undef GPIO_ADC_set_sampletime
|
||||
// 0:7 => 3/9/15/30/43/57/73/241 cycles
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input); \
|
||||
ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_sampletimes_all
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3) \
|
||||
| GPIO_ADC_sampletime << (6 * 3) \
|
||||
| GPIO_ADC_sampletime << (7 * 3) \
|
||||
| GPIO_ADC_sampletime << (8 * 3) \
|
||||
| GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) \
|
||||
| GPIO_ADC_sampletime << (1 * 3) \
|
||||
| GPIO_ADC_sampletime << (2 * 3) \
|
||||
| GPIO_ADC_sampletime << (3 * 3) \
|
||||
| GPIO_ADC_sampletime << (4 * 3) \
|
||||
| GPIO_ADC_sampletime << (5 * 3); \
|
||||
#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({ \
|
||||
ADC1->SAMPTR2 &= 0; \
|
||||
ADC1->SAMPTR2 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3) | GPIO_ADC_sampletime << (6 * 3) | GPIO_ADC_sampletime << (7 * 3) | GPIO_ADC_sampletime << (8 * 3) | GPIO_ADC_sampletime << (9 * 3); \
|
||||
ADC1->SAMPTR1 &= 0; \
|
||||
ADC1->SAMPTR1 |= \
|
||||
GPIO_ADC_sampletime << (0 * 3) | GPIO_ADC_sampletime << (1 * 3) | GPIO_ADC_sampletime << (2 * 3) | GPIO_ADC_sampletime << (3 * 3) | GPIO_ADC_sampletime << (4 * 3) | GPIO_ADC_sampletime << (5 * 3); \
|
||||
})
|
||||
|
||||
#undef GPIO_ADC_set_power
|
||||
|
|
@ -381,133 +357,137 @@ static inline void GPIO_tim2_init();
|
|||
#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
|
||||
|
||||
#undef GPIO_ADC_calibrate
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL); \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while(ADC1->CTLR2 & ADC_CAL); \
|
||||
#define GPIO_ADC_calibrate() ({ \
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; \
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL) \
|
||||
; \
|
||||
ADC1->CTLR2 |= ADC_CAL; \
|
||||
while (ADC1->CTLR2 & ADC_CAL) \
|
||||
; \
|
||||
})
|
||||
|
||||
// large but will likely only ever be called once
|
||||
static inline void GPIO_ADCinit() {
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
static inline void GPIO_ADCinit()
|
||||
{
|
||||
// select ADC clock source
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
// enable clock to the ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
|
||||
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
// Reset the ADC to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
|
||||
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
// set sampling time for all inputs to 241 cycles
|
||||
GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
|
||||
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
// set trigger to software
|
||||
ADC1->CTLR2 |= ADC_EXTSEL;
|
||||
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
// pre-clear conversion queue
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
ADC1->RSQR3 = 0;
|
||||
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
// power the ADC
|
||||
GPIO_ADC_set_power(1);
|
||||
GPIO_ADC_calibrate();
|
||||
}
|
||||
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while(!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input)
|
||||
{
|
||||
// set mux to selected input
|
||||
ADC1->RSQR3 = input;
|
||||
// allow everything to precharge
|
||||
Delay_Us(GPIO_ADC_MUX_DELAY);
|
||||
// start sw conversion (auto clears)
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
// wait for conversion complete
|
||||
while (!(ADC1->STATR & ADC_EOC)) {}
|
||||
// get result
|
||||
return ADC1->RDATAR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef GPIO_tim1_map
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
#define GPIO_tim1_map(GPIO_tim1_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6); \
|
||||
})
|
||||
|
||||
#undef GPIO_tim2_map
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
#define GPIO_tim2_map(GPIO_tim2_output_set) ({ \
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO; \
|
||||
AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8); \
|
||||
})
|
||||
|
||||
static inline void GPIO_tim1_init() {
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim1_init()
|
||||
{
|
||||
// enable TIM1
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
|
||||
// reset TIM1 to init all regs
|
||||
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
|
||||
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM1->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM1->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM1->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM1->SWEVGR |= TIM_UG;
|
||||
// disengage brake
|
||||
TIM1->BDTR |= TIM_MOE;
|
||||
// Enable TIM1
|
||||
TIM1->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
static inline void GPIO_tim2_init() {
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
static inline void GPIO_tim2_init()
|
||||
{
|
||||
// enable TIM2
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
|
||||
// reset TIM2 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
|
||||
// SMCFGR: default clk input is CK_INT
|
||||
// set clock prescaler divider
|
||||
TIM2->PSC = GPIO_timer_prescaler;
|
||||
// set PWM total cycle width
|
||||
TIM2->ATRLR = GPIO_timer_resolution;
|
||||
// CTLR1: default is up, events generated, edge align
|
||||
// enable auto-reload of preload
|
||||
TIM2->CTLR1 |= TIM_ARPE;
|
||||
// initialize counter
|
||||
TIM2->SWEVGR |= TIM_UG;
|
||||
// Enable TIM2
|
||||
TIM2->CTLR1 |= TIM_CEN;
|
||||
}
|
||||
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set2(timer, channel) GPIO_timer_channel_set_##channel(timer)
|
||||
#define GPIO_timer_channel_set(timer, channel) GPIO_timer_channel_set2(timer, channel)
|
||||
#define GPIO_timer_channel_set_1(timer) timer->CHCTLR1 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_2(timer) timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
#define GPIO_timer_channel_set_3(timer) timer->CHCTLR2 |= (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
|
||||
#define GPIO_timer_channel_set_4(timer) timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
|
||||
|
||||
#undef GPIO_tim1_enableCH
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim1_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM1, channel); \
|
||||
TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
})
|
||||
#undef GPIO_tim2_enableCH
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1)); \
|
||||
#define GPIO_tim2_enableCH(channel) ({ \
|
||||
GPIO_timer_channel_set(TIM2, channel); \
|
||||
TIM2->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1)); \
|
||||
})
|
||||
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
#define GPIO_timer_CVR(channel) CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
|
||||
|
||||
#undef GPIO_tim1_analogWrite
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim1_analogWrite(channel, value) TIM1->GPIO_timer_CVR(channel) = value;
|
||||
#undef GPIO_tim2_analogWrite
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
#define GPIO_tim2_analogWrite(channel, value) TIM2->GPIO_timer_CVR(channel) = value;
|
||||
|
||||
#endif // CH32V003_GPIO_BR_H
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
//######## necessities
|
||||
// ######## necessities
|
||||
|
||||
// include guards
|
||||
#ifndef CH32V003_SPI_H
|
||||
#define CH32V003_SPI_H
|
||||
|
||||
// includes
|
||||
#include<stdint.h> //uintN_t support
|
||||
#include "ch32fun.h"
|
||||
#include <stdint.h> //uintN_t support
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
/*######## library usage and configuration
|
||||
|
|
@ -20,7 +20,7 @@ SYSTEM_CORE_CLOCK and APB_CLOCK should be defined already as APB_CLOCK is used b
|
|||
|
||||
|
||||
#ifndef APB_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#define APB_CLOCK FUNCONF_SYSTEM_CORE_CLOCK
|
||||
#endif
|
||||
|
||||
to enable using the functions of this library:
|
||||
|
|
@ -47,10 +47,8 @@ then pick the desired setting of each group:
|
|||
#define CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL // toggle manually!
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
// ######## function overview (declarations): use these!
|
||||
// initialize and configure the SPI peripheral
|
||||
static inline void SPI_init();
|
||||
|
||||
// establish / end a connection to the SPI device
|
||||
|
|
@ -67,14 +65,14 @@ static inline void SPI_NSS_software_high();
|
|||
|
||||
// read / write the SPI device
|
||||
// these commands are raw, you'll have to consider all other steps in SPI_transfer!
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint8_t SPI_read_8();
|
||||
static inline uint16_t SPI_read_16();
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
static inline void SPI_write_8(uint8_t data);
|
||||
static inline void SPI_write_16(uint16_t data);
|
||||
|
||||
// send a command and get a response from the SPI device
|
||||
// you'll use this for most devices
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data);
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data);
|
||||
|
||||
// SPI peripheral power enable / disable (default off, init() automatically enables)
|
||||
|
|
@ -87,31 +85,25 @@ static inline void SPI_poweron();
|
|||
static inline void kill_interrrupts();
|
||||
static inline void restore_interrupts();
|
||||
|
||||
|
||||
|
||||
//######## internal function declarations
|
||||
static inline void SPI_wait_TX_complete();
|
||||
// ######## 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();
|
||||
static inline void SPI_wait_RX_available();
|
||||
|
||||
|
||||
|
||||
//######## internal variables
|
||||
// ######## internal variables
|
||||
static uint16_t EXT1_INTENR_backup;
|
||||
|
||||
|
||||
|
||||
//######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
// ######## preprocessor macros
|
||||
// min and max helper macros
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
// stringify for displaying what #defines evaluated to at preprocessor stage
|
||||
#define VALUE_TO_STRING(x) #x
|
||||
#define VALUE(x) VALUE_TO_STRING(x)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
|
||||
//compile-time log2
|
||||
// compile-time log2
|
||||
#define LOG2(x) ((x) == 0 ? -1 : __builtin_ctz(x))
|
||||
|
||||
// compile-time clock prescaler calculation: log2(APB_CLOCK/SPEED_BUS)
|
||||
|
|
@ -120,233 +112,249 @@ static uint16_t EXT1_INTENR_backup;
|
|||
|
||||
// ensure that CLOCK_PRESCALER_VALUE is within the range of 0..7
|
||||
_Static_assert(SPI_CLK_PRESCALER >= 0 && SPI_CLK_PRESCALER <= 7, "SPI_CLK_PRESCALER is out of range (0..7). Please set a different SPI bus speed. prescaler = log2(f_CPU/f_SPI)");
|
||||
//#pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
// #pragma message(VAR_NAME_VALUE(SPI_CLK_PRESCALER))
|
||||
|
||||
|
||||
|
||||
//######## preprocessor #define requirements
|
||||
// ######## preprocessor #define requirements
|
||||
|
||||
#if !defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && !defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "none of the CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX) && defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#warning "both CH32V003_SPI_DIRECTION_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_CLK_MODE_POL0_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL0_PHA1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_CLK_MODE_POL1_PHA1) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_CLK_MODE_ options were defined!"
|
||||
#endif
|
||||
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) > 1
|
||||
#warning "more than one of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
#if ((defined(CH32V003_SPI_NSS_HARDWARE_PC0) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
(defined(CH32V003_SPI_NSS_HARDWARE_PC1) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC3) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_PC4) ? 1 : 0) + \
|
||||
(defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL) ? 1 : 0)) == 0
|
||||
#warning "none of the CH32V003_SPI_NSS_ options were defined!"
|
||||
#endif
|
||||
|
||||
// ######## small function definitions, static inline
|
||||
static inline void SPI_init()
|
||||
{
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
|
||||
//######## small function definitions, static inline
|
||||
static inline void SPI_init() {
|
||||
SPI_poweron();
|
||||
|
||||
// reset control register
|
||||
SPI1->CTLR1 = 0;
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
|
||||
|
||||
// set prescaler
|
||||
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
|
||||
// set clock polarity and phase
|
||||
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
|
||||
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
|
||||
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
|
||||
#endif
|
||||
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
// configure NSS pin, master mode
|
||||
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
|
||||
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 0));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0);
|
||||
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
|
||||
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
|
||||
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1);
|
||||
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
|
||||
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
|
||||
#endif
|
||||
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
|
||||
// SCK on PC5, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 5));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 5);
|
||||
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
// CH32V003 is master
|
||||
SPI1->CTLR1 |= SPI_Mode_Master;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
|
||||
// MISO on PC7, 10MHz input, floating
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*7));
|
||||
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
|
||||
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
|
||||
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
|
||||
// set data direction and configure data pins
|
||||
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
|
||||
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
|
||||
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
#endif
|
||||
// MOSI on PC6, 10MHz Output, alt func, push-pull
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
|
||||
// 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() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_8()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_begin_16() {
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
static inline void SPI_begin_16()
|
||||
{
|
||||
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
|
||||
SPI1->CTLR1 |= SPI_CTLR1_SPE;
|
||||
}
|
||||
static inline void SPI_end() {
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
static inline void SPI_end()
|
||||
{
|
||||
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
|
||||
}
|
||||
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<3);
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 3);
|
||||
}
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
}
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high() {
|
||||
GPIOC->BSHR = (1<<4);
|
||||
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
static inline void SPI_NSS_software_high()
|
||||
{
|
||||
GPIOC->BSHR = (1 << 4);
|
||||
}
|
||||
static inline void SPI_NSS_software_low() {
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
static inline void SPI_NSS_software_low()
|
||||
{
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t SPI_read_8() {
|
||||
return SPI1->DATAR;
|
||||
static inline uint8_t SPI_read_8()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline uint16_t SPI_read_16() {
|
||||
return SPI1->DATAR;
|
||||
static inline uint16_t SPI_read_16()
|
||||
{
|
||||
return SPI1->DATAR;
|
||||
}
|
||||
static inline void SPI_write_8(uint8_t data) {
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_8(uint8_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline void SPI_write_16(uint16_t data) {
|
||||
SPI1->DATAR = data;
|
||||
static inline void SPI_write_16(uint16_t data)
|
||||
{
|
||||
SPI1->DATAR = data;
|
||||
}
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
static inline uint8_t SPI_transfer_8(uint8_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_8(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_8();
|
||||
}
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data) {
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
static inline uint16_t SPI_transfer_16(uint16_t data)
|
||||
{
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_high();
|
||||
#endif
|
||||
SPI_write_16(data);
|
||||
SPI_wait_TX_complete();
|
||||
asm volatile("nop");
|
||||
SPI_wait_RX_available();
|
||||
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3) || defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
|
||||
SPI_NSS_software_low();
|
||||
#endif
|
||||
return SPI_read_16();
|
||||
}
|
||||
|
||||
static inline void SPI_poweroff() {
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweroff()
|
||||
{
|
||||
SPI_end();
|
||||
RCC->APB2PCENR &= ~RCC_APB2Periph_SPI1;
|
||||
}
|
||||
static inline void SPI_poweron() {
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
static inline void SPI_poweron()
|
||||
{
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
}
|
||||
|
||||
static inline void kill_interrrupts() {
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
static inline void kill_interrrupts()
|
||||
{
|
||||
EXT1_INTENR_backup = EXTI->INTENR;
|
||||
// zero the interrupt enable register to disable all interrupts
|
||||
EXTI->INTENR = 0;
|
||||
}
|
||||
static inline void restore_interrupts() {
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
static inline void restore_interrupts()
|
||||
{
|
||||
EXTI->INTENR = EXT1_INTENR_backup;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete() {
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
// ######## small internal function definitions, static inline
|
||||
static inline void SPI_wait_TX_complete()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE)) {}
|
||||
}
|
||||
static inline uint8_t SPI_is_RX_empty() {
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
static inline uint8_t SPI_is_RX_empty()
|
||||
{
|
||||
return SPI1->STATR & SPI_STATR_RXNE;
|
||||
}
|
||||
static inline void SPI_wait_RX_available() {
|
||||
while(!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
static inline void SPI_wait_RX_available()
|
||||
{
|
||||
while (!(SPI1->STATR & SPI_STATR_RXNE)) {}
|
||||
}
|
||||
static inline void SPI_wait_not_busy() {
|
||||
while((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
static inline void SPI_wait_not_busy()
|
||||
{
|
||||
while ((SPI1->STATR & SPI_STATR_BSY) != 0) {}
|
||||
}
|
||||
static inline void SPI_wait_transmit_finished() {
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
static inline void SPI_wait_transmit_finished()
|
||||
{
|
||||
SPI_wait_TX_complete();
|
||||
SPI_wait_not_busy();
|
||||
}
|
||||
|
||||
|
||||
//######## implementation block
|
||||
//#define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
// ######## implementation block
|
||||
// #define CH32V003_SPI_IMPLEMENTATION //enable so LSP can give you text colors while working on the implementation block, disable for normal use of the library
|
||||
#if defined(CH32V003_SPI_IMPLEMENTATION)
|
||||
|
||||
//no functions here because I think all of the functions are small enough to static inline
|
||||
// no functions here because I think all of the functions are small enough to static inline
|
||||
|
||||
#endif // CH32V003_SPI_IMPLEMENTATION
|
||||
#endif // CH32V003_SPI_H
|
||||
|
|
|
|||
|
|
@ -3,44 +3,42 @@
|
|||
|
||||
/** ADC-based Capactive Touch Control.
|
||||
|
||||
see cap_touch_adc.c for an example.
|
||||
see cap_touch_adc.c for an example.
|
||||
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
// Enable GPIOD, C and ADC
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||
InitTouchADC();
|
||||
|
||||
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
// Then do this any time you want to read some touches.
|
||||
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||
|
||||
// Can either be 0 or 1.
|
||||
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
||||
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
||||
#define TOUCH_SLOPE 1
|
||||
#define TOUCH_SLOPE 1
|
||||
|
||||
// If you set this to 1, it will glitch the line, so it will only read
|
||||
// anything reasonable if the capacitance can overcome that initial spike.
|
||||
// Typically, it seems if you use this you probbly don't need to do
|
||||
// any pre-use calibration.
|
||||
#define TOUCH_FLAT 0
|
||||
#define TOUCH_FLAT 0
|
||||
|
||||
// Macro used for force-alingining ADC timing
|
||||
#define FORCEALIGNADC \
|
||||
asm volatile( \
|
||||
"\n\
|
||||
asm volatile( \
|
||||
"\n\
|
||||
.balign 4\n\
|
||||
andi a2, %[cyccnt], 3\n\
|
||||
c.slli a2, 1\n\
|
||||
|
|
@ -50,169 +48,172 @@
|
|||
jalr a2, 1\n\
|
||||
.long 0x00010001\n\
|
||||
.long 0x00010001\n\
|
||||
"\
|
||||
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||
);
|
||||
" ::[cyccnt] "r"(SysTick->CNT) : "a1", "a2");
|
||||
|
||||
|
||||
static void InitTouchADC( );
|
||||
void InitTouchADC( )
|
||||
static void InitTouchADC();
|
||||
void InitTouchADC()
|
||||
{
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F<<11);
|
||||
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||
RCC->CFGR0 &= ~(0x1F << 11);
|
||||
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
// Set up single conversion on chl 2
|
||||
ADC1->RSQR1 = 0;
|
||||
ADC1->RSQR2 = 0;
|
||||
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while(ADC1->CTLR2 & ADC_CAL);
|
||||
// turn on ADC and set rule group to sw trig
|
||||
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||
|
||||
// Reset calibration
|
||||
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||
while (ADC1->CTLR2 & ADC_RSTCAL)
|
||||
;
|
||||
|
||||
// Calibrate
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while (ADC1->CTLR2 & ADC_CAL)
|
||||
;
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
static uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPin(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
__enable_irq();
|
||||
__disable_irq();
|
||||
FORCEALIGNADC
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
__enable_irq();
|
||||
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
uint32_t CFGBASE = io->CFGLR & (~(0xf << (4 * portpin)));
|
||||
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | CFGBASE;
|
||||
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | CFGBASE;
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#if TOUCH_FLAT == 1
|
||||
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||
#define RELEASEIO \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
io->CFGLR = CFGFLOAT;
|
||||
#else
|
||||
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||
#define RELEASEIO \
|
||||
io->CFGLR = CFGFLOAT; \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE);
|
||||
#endif
|
||||
|
||||
#define INNER_LOOP( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
RELEASEIO \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
io->CFGLR = CFGDRIVE; \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP( 0 );
|
||||
INNER_LOOP( 2 );
|
||||
INNER_LOOP( 4 );
|
||||
}
|
||||
INNER_LOOP(0);
|
||||
INNER_LOOP(2);
|
||||
INNER_LOOP(4);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Run from RAM to get even more stable timing.
|
||||
// This function call takes about 8.1uS to execute.
|
||||
static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||
static uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations) __attribute__((noinline, section(".srodata")));
|
||||
uint32_t ReadTouchPinSafe(GPIO_TypeDef *io, int portpin, int adcno, int iterations)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||
ADC1->RSQR3 = adcno;
|
||||
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME << (3 * adcno);
|
||||
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
// If we run multiple times with slightly different wait times, we can
|
||||
// reduce the impact of the ADC's DNL.
|
||||
|
||||
#define INNER_LOOP_SAFE( n ) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS( n ) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while(!(ADC1->STATR & ADC_EOC)); \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
#define INNER_LOOP_SAFE(n) \
|
||||
{ \
|
||||
/* Only lock IRQ for a very narrow window. */ \
|
||||
__disable_irq(); \
|
||||
\
|
||||
FORCEALIGNADC \
|
||||
\
|
||||
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||
this We are catching it onthe slope much more effectively. */ \
|
||||
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||
\
|
||||
ADD_N_NOPS(n) \
|
||||
\
|
||||
io->CFGLR = ((GPIO_CFGLR_IN_PUPD) << (4 * portpin)) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
io->BSHR = 1 << (portpin + 16 * TOUCH_SLOPE); \
|
||||
\
|
||||
/* Sampling actually starts here, somewhere, so we can let other \
|
||||
interrupts run */ \
|
||||
__enable_irq(); \
|
||||
while (!(ADC1->STATR & ADC_EOC)) \
|
||||
; \
|
||||
__disable_irq(); \
|
||||
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP) << (4 * portpin) | (io->CFGLR & (~(0xf << (4 * portpin)))); \
|
||||
__enable_irq(); \
|
||||
io->BSHR = 1 << (portpin + (16 * (1 - TOUCH_SLOPE))); \
|
||||
ret += ADC1->RDATAR; \
|
||||
}
|
||||
|
||||
int i;
|
||||
for( i = 0; i < iterations; i++ )
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
int i;
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
// Wait a variable amount of time based on loop iteration, in order
|
||||
// to get a variety of RC points and minimize DNL.
|
||||
|
||||
INNER_LOOP_SAFE( 0 );
|
||||
INNER_LOOP_SAFE( 2 );
|
||||
INNER_LOOP_SAFE( 4 );
|
||||
}
|
||||
INNER_LOOP_SAFE(0);
|
||||
INNER_LOOP_SAFE(2);
|
||||
INNER_LOOP_SAFE(4);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2023 Valve Corporation
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
|
@ -221,4 +222,3 @@ uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterat
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define _CH32V307GIGABIT_H
|
||||
|
||||
/* This file is written against the RTL8211E
|
||||
*/
|
||||
*/
|
||||
|
||||
// #define CH32V307GIGABIT_MCO25 1
|
||||
// #define CH32V307GIGABIT_PHYADDRESS 0
|
||||
|
|
@ -34,515 +34,515 @@
|
|||
// ETH DMA structure definition (From ch32v30x_eth.c
|
||||
typedef struct
|
||||
{
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
uint32_t volatile Status; /* Status */
|
||||
uint32_t ControlBufferSize; /* Control and Buffer1, Buffer2 lengths */
|
||||
uint32_t Buffer1Addr; /* Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /* Buffer2 or next descriptor address pointer */
|
||||
} ETH_DMADESCTypeDef;
|
||||
|
||||
// You must provide:
|
||||
|
||||
void ch32v307ethHandleReconfig( int link, int speed, int duplex );
|
||||
void ch32v307ethHandleReconfig(int link, int speed, int duplex);
|
||||
|
||||
// Return non-zero to suppress OWN return (for if you are still holding onto the buffer)
|
||||
int ch32v307ethInitHandlePacket( uint8_t * data, int frame_length, ETH_DMADESCTypeDef * dmadesc );
|
||||
int ch32v307ethInitHandlePacket(uint8_t *data, int frame_length, ETH_DMADESCTypeDef *dmadesc);
|
||||
|
||||
void ch32v307ethInitHandleTXC( void );
|
||||
void ch32v307ethInitHandleTXC(void);
|
||||
|
||||
// This library provides:
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac );
|
||||
static int ch32v307ethInit( void );
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy( void );
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac);
|
||||
static int ch32v307ethInit(void);
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc); // Does not copy.
|
||||
static int ch32v307ethTickPhy(void);
|
||||
|
||||
// Data pursuent to ethernet.
|
||||
uint8_t ch32v307eth_mac[6] = { 0 };
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB*CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef * pDMARxGet;
|
||||
ETH_DMADESCTypeDef * pDMATxSet;
|
||||
|
||||
uint8_t ch32v307eth_mac[6] = {0};
|
||||
uint16_t ch32v307eth_phyid = 0; // 0xc916 = RTL8211FS / 0xc915 = RTL8211E-VB
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMARxDscrTab[CH32V307GIGABIT_RXBUFNB] __attribute__((aligned(4))); // MAC receive descriptor, 4-byte aligned
|
||||
ETH_DMADESCTypeDef ch32v307eth_DMATxDscrTab[CH32V307GIGABIT_TXBUFNB] __attribute__((aligned(4))); // MAC send descriptor, 4-byte aligned
|
||||
uint8_t ch32v307eth_MACRxBuf[CH32V307GIGABIT_RXBUFNB * CH32V307GIGABIT_BUFFSIZE] __attribute__((aligned(4))); // MAC receive buffer, 4-byte aligned
|
||||
ETH_DMADESCTypeDef *pDMARxGet;
|
||||
ETH_DMADESCTypeDef *pDMATxSet;
|
||||
|
||||
// Internal functions
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val );
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value );
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg );
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val);
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value);
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg);
|
||||
|
||||
static int ch32v307ethPHYRegAsyncRead( int reg, int * value )
|
||||
static int ch32v307ethPHYRegAsyncRead(int reg, int *value)
|
||||
{
|
||||
static uint8_t reg_request_count = 0;
|
||||
static uint8_t reg_request_count = 0;
|
||||
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if( miiar & ETH_MACMIIAR_MB )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if( ( ( miiar & ETH_MACMIIAR_MR ) >> 6 ) != reg || reg_request_count < 2 )
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
uint32_t miiar = ETH->MACMIIAR;
|
||||
if (miiar & ETH_MACMIIAR_MB)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (((miiar & ETH_MACMIIAR_MR) >> 6) != reg || reg_request_count < 2)
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
reg_request_count++;
|
||||
return -1;
|
||||
}
|
||||
reg_request_count = 0;
|
||||
*value = ETH->MACMIIDR;
|
||||
ETH->MACMIIAR |= ETH_MACMIIAR_MR; // Poison register.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ch32v307ethTickPhy(void)
|
||||
{
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if( ch32v307ethPHYRegAsyncRead( reg, &miidr ) ) return -1;
|
||||
int speed, linked, duplex;
|
||||
const int reg = (ch32v307eth_phyid == 0xc916) ? 0x1a : 0x11; // PHYSR (different on each part)
|
||||
int miidr;
|
||||
if (ch32v307ethPHYRegAsyncRead(reg, &miidr)) return -1;
|
||||
|
||||
printf( "REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid );
|
||||
printf("REG: %02x / %04x / %04x\n", reg, miidr, ch32v307eth_phyid);
|
||||
|
||||
if( reg == 0x1a )
|
||||
{
|
||||
speed = ((miidr>>4)&3);
|
||||
linked = ((miidr>>2)&1);
|
||||
duplex = ((miidr>>3)&1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr>>14)&3);
|
||||
linked = ((miidr>>10)&1);
|
||||
duplex = ((miidr>>13)&1);
|
||||
}
|
||||
if (reg == 0x1a)
|
||||
{
|
||||
speed = ((miidr >> 4) & 3);
|
||||
linked = ((miidr >> 2) & 1);
|
||||
duplex = ((miidr >> 3) & 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = ((miidr >> 14) & 3);
|
||||
linked = ((miidr >> 10) & 1);
|
||||
duplex = ((miidr >> 13) & 1);
|
||||
}
|
||||
|
||||
printf( "LINK INFO: %d %d %d\n", speed, linked, duplex );
|
||||
if( linked )
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~( ( 1<<11 ) | (3<<14) ) ) | (speed<<14) | ( duplex<<11);
|
||||
if( newmaccr != oldmaccr )
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig( linked, speed, duplex );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
printf("LINK INFO: %d %d %d\n", speed, linked, duplex);
|
||||
if (linked)
|
||||
{
|
||||
uint32_t oldmaccr = ETH->MACCR;
|
||||
uint32_t newmaccr = (oldmaccr & ~((1 << 11) | (3 << 14))) | (speed << 14) | (duplex << 11);
|
||||
if (newmaccr != oldmaccr)
|
||||
{
|
||||
ETH->MACCR = newmaccr;
|
||||
ch32v307ethHandleReconfig(linked, speed, duplex);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Based on ETH_WritePHYRegister
|
||||
static int ch32v307ethPHYRegWrite( uint32_t reg, uint32_t val )
|
||||
static int ch32v307ethPHYRegWrite(uint32_t reg, uint32_t val)
|
||||
{
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
(((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11)) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? 0 : -1;
|
||||
}
|
||||
|
||||
static int ch32v307ethPHYRegRead( uint32_t reg )
|
||||
static int ch32v307ethPHYRegRead(uint32_t reg)
|
||||
{
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42 /* = 0, per 27.1.8.1.4 */ |
|
||||
((uint32_t)CH32V307GIGABIT_PHYADDRESS << 11) | // ETH_MACMIIAR_PA
|
||||
(((uint32_t)reg << 6) & ETH_MACMIIAR_MR) |
|
||||
(0 /*!ETH_MACMIIAR_MW*/) | ETH_MACMIIAR_MB;
|
||||
|
||||
uint32_t timeout = 0x100000;
|
||||
while( ( ETH->MACMIIAR & ETH_MACMIIAR_MB ) && --timeout );
|
||||
uint32_t timeout = 0x100000;
|
||||
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) && --timeout)
|
||||
;
|
||||
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
// If timeout = 0, is an error.
|
||||
return timeout ? ETH->MACMIIDR : -1;
|
||||
}
|
||||
|
||||
|
||||
static void ch32v307ethGetMacInUC( uint8_t * mac )
|
||||
static void ch32v307ethGetMacInUC(uint8_t *mac)
|
||||
{
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID+5);
|
||||
for( int i = 0; i < 6; i++ )
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
// Mac is backwards.
|
||||
const uint8_t *macaddr = (const uint8_t *)(ROM_CFG_USERADR_ID + 5);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
mac[i] = *(macaddr--);
|
||||
}
|
||||
}
|
||||
|
||||
static int ch32v307ethInit( void )
|
||||
static int ch32v307ethInit(void)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funPinMode( CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP ); //PHY_RSTB (For reset)
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_LOW );
|
||||
funPinMode(CH32V307GIGABIT_PHY_RSTB, GPIO_CFGLR_OUT_50Mhz_PP); // PHY_RSTB (For reset)
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_LOW);
|
||||
#endif
|
||||
|
||||
// Configure strapping.
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funDigitalWrite( PA1, FUN_HIGH );
|
||||
funDigitalWrite( PA0, FUN_HIGH );
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // No TX Delay
|
||||
funDigitalWrite( PC2, FUN_HIGH );
|
||||
// Configure strapping.
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funDigitalWrite(PA1, FUN_HIGH);
|
||||
funDigitalWrite(PA0, FUN_HIGH);
|
||||
funDigitalWrite(PC3, FUN_HIGH); // No TX Delay
|
||||
funDigitalWrite(PC2, FUN_HIGH);
|
||||
|
||||
// Pull-up MDIO
|
||||
funPinMode( PD9, GPIO_CFGLR_OUT_50Mhz_PP ); //Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite( PD9, FUN_HIGH );
|
||||
// Pull-up MDIO
|
||||
funPinMode(PD9, GPIO_CFGLR_OUT_50Mhz_PP); // Pull-up control (DO NOT CHECK IN, ADD RESISTOR)
|
||||
funDigitalWrite(PD9, FUN_HIGH);
|
||||
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
// Will be required later.
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO;
|
||||
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
// https://cnlohr.github.io/microclockoptimizer/?chipSelect=ch32vx05_7%2Cd8c&HSI=1,8&HSE=0,8&PREDIV2=1,1&PLL2CLK=1,7&PLL2VCO=0,72&PLL3CLK=1,1&PLL3VCO=0,100&PREDIV1SRC=1,0&PREDIV1=1,2&PLLSRC=1,0&PLL=0,4&PLLVCO=1,144&SYSCLK=1,2&
|
||||
// Clock Tree:
|
||||
// 8MHz Input
|
||||
// PREDIV2 = 2 (1 in register) = 4MHz
|
||||
// PLL2 = 9 (7 in register) = 36MHz / PLL2VCO = 72MHz
|
||||
// PLL3CLK = 12.5 (1 in register) = 50MHz = 100MHz VCO
|
||||
// PREDIV1SRC = HSE (1 in register) = 8MHz
|
||||
// PREDIV1 = 2 (1 in register).
|
||||
// PLLSRC = PREDIV1 (0 in register) = 4MHz
|
||||
// PLL = 18 (0 in register) = 72MHz
|
||||
// PLLVCO = 144MHz
|
||||
// SYSCLK = PLLVCO = 144MHz
|
||||
// Use EXT_125M (ETH1G_SRC)
|
||||
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
// Switch processor back to HSI so we don't eat dirt.
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_HSI;
|
||||
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1<<RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1<<RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2<<RCC_ETH1GSRC_OFFSET)| // External source for RGMII
|
||||
(7<<RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1<<RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
// Setup clock tree.
|
||||
RCC->CFGR2 |=
|
||||
(1 << RCC_PREDIV2_OFFSET) | // PREDIV = /2; Prediv Freq = 4MHz
|
||||
(1 << RCC_PLL3MUL_OFFSET) | // PLL3 = x12.5 (PLL3 = 50MHz)
|
||||
(2 << RCC_ETH1GSRC_OFFSET) | // External source for RGMII
|
||||
(7 << RCC_PLL2MUL_OFFSET) | // PLL2 = x9 (PLL2 = 36MHz)
|
||||
(1 << RCC_PREDIV1_OFFSET) | // PREDIV1 = /2; Prediv freq = 50MHz
|
||||
0;
|
||||
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
// Power on PLLs
|
||||
RCC->CTLR |= RCC_PLL3ON | RCC_PLL2ON;
|
||||
int timeout;
|
||||
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if( timeout == 0 ) return -5;
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if( timeout == 0 ) return -6;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL3RDY) break;
|
||||
if (timeout == 0) return -5;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLL2RDY) break;
|
||||
if (timeout == 0) return -6;
|
||||
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = ( RCC->CFGR0 & ~(0xf<<18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
// PLL = x18 (0 in register)
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~(0xf << 18)) | 0;
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
|
||||
for( timeout = 10000; timeout > 0; timeout--) if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if( timeout == 0 ) return -7;
|
||||
for (timeout = 10000; timeout > 0; timeout--)
|
||||
if (RCC->CTLR & RCC_PLLRDY) break;
|
||||
if (timeout == 0) return -7;
|
||||
|
||||
// Switch to PLL.
|
||||
// Switch to PLL.
|
||||
#ifdef CH32V307GIGABIT_MCO25
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9<<24); // And output clock on PA8
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL | (9 << 24); // And output clock on PA8
|
||||
#else
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | RCC_SW_PLL;
|
||||
#endif
|
||||
|
||||
// For clock in.
|
||||
funPinMode( PB1, GPIO_CFGLR_IN_FLOAT ); //GMII_CLK125
|
||||
// For clock in.
|
||||
funPinMode(PB1, GPIO_CFGLR_IN_FLOAT); // GMII_CLK125
|
||||
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
RCC->CFGR2 |= RCC_ETH1G_125M_EN; // Enable 125MHz clock.
|
||||
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &=~RCC_ETHMACRST;
|
||||
// Power on and reset.
|
||||
RCC->AHBPCENR |= RCC_ETHMACEN | RCC_ETHMACTXEN | RCC_ETHMACRXEN;
|
||||
RCC->AHBRSTR |= RCC_ETHMACRST;
|
||||
RCC->AHBRSTR &= ~RCC_ETHMACRST;
|
||||
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
ETH->DMABMR |= ETH_DMABMR_SR;
|
||||
|
||||
// Wait for reset to complete.
|
||||
for( timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout-- )
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
// Wait for reset to complete.
|
||||
for (timeout = 10000; timeout > 0 && (ETH->DMABMR & ETH_DMABMR_SR); timeout--)
|
||||
{
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; //EXTEN_ETH_RGMII_SEL;
|
||||
// Use RGMII
|
||||
EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL; // EXTEN_ETH_RGMII_SEL;
|
||||
|
||||
funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDIO
|
||||
funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); //GMII_MDC
|
||||
funPinMode(PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDIO
|
||||
funPinMode(PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_MDC
|
||||
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // PHY_CKTAL
|
||||
// For clock output to Ethernet module.
|
||||
funPinMode(PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP); // PHY_CKTAL
|
||||
|
||||
// Release PHY from reset.
|
||||
// Release PHY from reset.
|
||||
#ifdef CH32V307GIGABIT_PHY_RSTB
|
||||
funDigitalWrite( CH32V307GIGABIT_PHY_RSTB, FUN_HIGH );
|
||||
funDigitalWrite(CH32V307GIGABIT_PHY_RSTB, FUN_HIGH);
|
||||
#endif
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 23ms (But only on the RTL8211FS) None is needed on the RTL8211E
|
||||
|
||||
funPinMode( PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD3
|
||||
funPinMode( PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD2
|
||||
funPinMode( PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD1
|
||||
funPinMode( PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXD0
|
||||
funPinMode( PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXCTL
|
||||
funPinMode( PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // GMII_TXC
|
||||
funPinMode( PA1, GPIO_CFGLR_IN_PUPD ); // GMII_RXD3
|
||||
funPinMode( PA0, GPIO_CFGLR_IN_PUPD ); // GMII_RXD2
|
||||
funPinMode( PC3, GPIO_CFGLR_IN_PUPD ); // GMII_RXD1
|
||||
funPinMode( PC2, GPIO_CFGLR_IN_PUPD ); // GMII_RXD0
|
||||
funPinMode( PC1, GPIO_CFGLR_IN_PUPD ); // GMII_RXCTL
|
||||
funPinMode( PC0, GPIO_CFGLR_IN_FLOAT ); // GMII_RXC
|
||||
funPinMode(PB0, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD3
|
||||
funPinMode(PC5, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD2
|
||||
funPinMode(PC4, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD1
|
||||
funPinMode(PA7, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXD0
|
||||
funPinMode(PA3, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXCTL
|
||||
funPinMode(PA2, GPIO_CFGLR_OUT_50Mhz_AF_PP); // GMII_TXC
|
||||
funPinMode(PA1, GPIO_CFGLR_IN_PUPD); // GMII_RXD3
|
||||
funPinMode(PA0, GPIO_CFGLR_IN_PUPD); // GMII_RXD2
|
||||
funPinMode(PC3, GPIO_CFGLR_IN_PUPD); // GMII_RXD1
|
||||
funPinMode(PC2, GPIO_CFGLR_IN_PUPD); // GMII_RXD0
|
||||
funPinMode(PC1, GPIO_CFGLR_IN_PUPD); // GMII_RXCTL
|
||||
funPinMode(PC0, GPIO_CFGLR_IN_FLOAT); // GMII_RXC
|
||||
|
||||
funDigitalWrite( PA1, FUN_HIGH ); // SELGRV = 3.3V
|
||||
funDigitalWrite( PA0, FUN_HIGH ); // TXDelay = 1
|
||||
funDigitalWrite( PC3, FUN_HIGH ); // AN[0] = 1
|
||||
funDigitalWrite( PC2, FUN_HIGH ); // AN[1] = 1
|
||||
funDigitalWrite( PC1, FUN_LOW ); // PHYAD[0]
|
||||
funDigitalWrite(PA1, FUN_HIGH); // SELGRV = 3.3V
|
||||
funDigitalWrite(PA0, FUN_HIGH); // TXDelay = 1
|
||||
funDigitalWrite(PC3, FUN_HIGH); // AN[0] = 1
|
||||
funDigitalWrite(PC2, FUN_HIGH); // AN[1] = 1
|
||||
funDigitalWrite(PC1, FUN_LOW); // PHYAD[0]
|
||||
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
// Configure MDC/MDIO
|
||||
// Conflicting notes - some say /42, others don't.
|
||||
ETH->MACMIIAR = ETH_MACMIIAR_CR_Div42;
|
||||
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
( CH32V307GIGABIT_CFG_CLOCK_DELAY << 29 ) | // No clock delay
|
||||
( 0 << 23 ) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 22 ) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
( 0 << 21 ) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
( 1 << 20 ) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
( 0 << 17 ) | // IFG = 0, 96-bit guard time.
|
||||
( 0 << 14 ) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
( 0 << 12 ) | // Self Loop = 0
|
||||
( 0 << 11 ) | // Full-Duplex Mode (UNSET TO START)
|
||||
( 1 << 10 ) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
( 1 << 7 ) | // APCS (automatically strip frames)
|
||||
( 1 << 3 ) | // TE (Transmit enable!)
|
||||
( 1 << 2 ) | // RE (Receive Enable)
|
||||
( CH32V307GIGABIT_CFG_CLOCK_PHASE << 1 ) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
// Update MACCR
|
||||
ETH->MACCR =
|
||||
(CH32V307GIGABIT_CFG_CLOCK_DELAY << 29) | // No clock delay
|
||||
(0 << 23) | // Max RX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 22) | // Max TX = 2kB (Revisit if looking into jumbo frames)
|
||||
(0 << 21) | // Rated Drive (instead of energy savings mode) (10M PHY only)
|
||||
(1 << 20) | // Bizarre re-use of termination resistor terminology? (10M PHY Only)
|
||||
(0 << 17) | // IFG = 0, 96-bit guard time.
|
||||
(0 << 14) | // FES = 2 = GBE, 1=100MBit/s (UNSET TO START)
|
||||
(0 << 12) | // Self Loop = 0
|
||||
(0 << 11) | // Full-Duplex Mode (UNSET TO START)
|
||||
(1 << 10) | // IPCO = 1, Check TCP, UDP, ICMP header checksums.
|
||||
(1 << 7) | // APCS (automatically strip frames)
|
||||
(1 << 3) | // TE (Transmit enable!)
|
||||
(1 << 2) | // RE (Receive Enable)
|
||||
(CH32V307GIGABIT_CFG_CLOCK_PHASE << 1) | // TCF = 0 (Potentailly change if clocking is wrong)
|
||||
0;
|
||||
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
Delay_Ms(25); // Waiting for PHY to exit sleep. This is inconsistent at 19ms.
|
||||
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
PHY_Reset |
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
// Reset the physical layer
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
PHY_Reset |
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite( PHY_BCR,
|
||||
1<<12 | // Auto negotiate
|
||||
1<<8 | // Duplex
|
||||
1<<6 | // Speed Bit.
|
||||
0 );
|
||||
// De-assert reset.
|
||||
ch32v307ethPHYRegWrite(PHY_BCR,
|
||||
1 << 12 | // Auto negotiate
|
||||
1 << 8 | // Duplex
|
||||
1 << 6 | // Speed Bit.
|
||||
0);
|
||||
|
||||
ch32v307ethPHYRegRead( 0x03 );
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead( 0x03 ); // Read twice to be safe.
|
||||
if( ch32v307eth_phyid == 0xc916 )
|
||||
ch32v307ethPHYRegWrite( 0x1F, 0x0a43 ); // RTL8211FS needs page select.
|
||||
ch32v307ethPHYRegRead(0x03);
|
||||
ch32v307eth_phyid = ch32v307ethPHYRegRead(0x03); // Read twice to be safe.
|
||||
if (ch32v307eth_phyid == 0xc916)
|
||||
ch32v307ethPHYRegWrite(0x1F, 0x0a43); // RTL8211FS needs page select.
|
||||
|
||||
ch32v307ethGetMacInUC( ch32v307eth_mac );
|
||||
ch32v307ethGetMacInUC(ch32v307eth_mac);
|
||||
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5]<<8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1]<<8) | (ch32v307eth_mac[2]<<16) | (ch32v307eth_mac[3]<<24));
|
||||
ETH->MACA0HR = (uint32_t)((ch32v307eth_mac[5] << 8) | ch32v307eth_mac[4]);
|
||||
ETH->MACA0LR = (uint32_t)(ch32v307eth_mac[0] | (ch32v307eth_mac[1] << 8) | (ch32v307eth_mac[2] << 16) | (ch32v307eth_mac[3] << 24));
|
||||
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
ETH->MACFFR = (uint32_t)(ETH_ReceiveAll_Disable |
|
||||
ETH_SourceAddrFilter_Disable |
|
||||
ETH_PassControlFrames_BlockAll |
|
||||
ETH_BroadcastFramesReception_Enable |
|
||||
ETH_DestinationAddrFilter_Normal |
|
||||
ETH_PromiscuousMode_Disable |
|
||||
ETH_MulticastFramesFilter_Perfect |
|
||||
ETH_UnicastFramesFilter_Perfect);
|
||||
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
ETH->MACHTHR = (uint32_t)0;
|
||||
ETH->MACHTLR = (uint32_t)0;
|
||||
ETH->MACVLANTR = (uint32_t)(ETH_VLANTagComparison_16Bit);
|
||||
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
ETH->MACFCR = 0; // No pause frames.
|
||||
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for(i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for(i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
// Configure RX/TX chains.
|
||||
ETH_DMADESCTypeDef *tdesc;
|
||||
for (i = 0; i < CH32V307GIGABIT_TXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMATxDscrTab + i;
|
||||
tdesc->ControlBufferSize = 0;
|
||||
tdesc->Status = ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC | ETH_DMATxDesc_FS;
|
||||
tdesc->Buffer1Addr = (uint32_t)0; // Populate with data.
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_TXBUFNB - 1) ? ((uint32_t)(ch32v307eth_DMATxDscrTab + i + 1)) : (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
}
|
||||
ETH->DMATDLAR = (uint32_t)ch32v307eth_DMATxDscrTab;
|
||||
for (i = 0; i < CH32V307GIGABIT_RXBUFNB; i++)
|
||||
{
|
||||
tdesc = ch32v307eth_DMARxDscrTab + i;
|
||||
tdesc->Status = ETH_DMARxDesc_OWN;
|
||||
tdesc->ControlBufferSize = ETH_DMARxDesc_RCH | (uint32_t)CH32V307GIGABIT_BUFFSIZE;
|
||||
tdesc->Buffer1Addr = (uint32_t)(&ch32v307eth_MACRxBuf[i * CH32V307GIGABIT_BUFFSIZE]);
|
||||
tdesc->Buffer2NextDescAddr = (i < CH32V307GIGABIT_RXBUFNB - 1) ? (uint32_t)(ch32v307eth_DMARxDscrTab + i + 1) : (uint32_t)(ch32v307eth_DMARxDscrTab);
|
||||
}
|
||||
ETH->DMARDLAR = (uint32_t)ch32v307eth_DMARxDscrTab;
|
||||
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
pDMARxGet = ch32v307eth_DMARxDscrTab;
|
||||
pDMATxSet = ch32v307eth_DMATxDscrTab;
|
||||
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
// Receive a good frame half interrupt mask.
|
||||
// Receive CRC error frame half interrupt mask.
|
||||
// For the future: Why do we want this?
|
||||
ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
|
||||
ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;
|
||||
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
ETH->DMAIER = ETH_DMA_IT_NIS | // Normal interrupt enable.
|
||||
ETH_DMA_IT_R | // Receive
|
||||
ETH_DMA_IT_T | // Transmit
|
||||
ETH_DMA_IT_AIS | // Abnormal interrupt
|
||||
ETH_DMA_IT_RBU; // Receive buffer unavailable interrupt enable
|
||||
|
||||
NVIC_EnableIRQ( ETH_IRQn );
|
||||
NVIC_EnableIRQ(ETH_IRQn);
|
||||
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
// Actually enable receiving process.
|
||||
ETH->DMAOMR = ETH_DMAOMR_SR | ETH_DMAOMR_ST | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ETH_IRQHandler( void ) __attribute__((interrupt));
|
||||
void ETH_IRQHandler( void )
|
||||
void ETH_IRQHandler(void) __attribute__((interrupt));
|
||||
void ETH_IRQHandler(void)
|
||||
{
|
||||
uint32_t int_sta;
|
||||
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ( ( int_sta & ( ETH_DMA_IT_AIS | ETH_DMA_IT_NIS ) ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
do
|
||||
{
|
||||
int_sta = ETH->DMASR;
|
||||
if ((int_sta & (ETH_DMA_IT_AIS | ETH_DMA_IT_NIS)) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
// Off nominal situations.
|
||||
if (int_sta & ETH_DMA_IT_AIS)
|
||||
{
|
||||
// Receive buffer unavailable interrupt enable.
|
||||
if (int_sta & ETH_DMA_IT_RBU)
|
||||
{
|
||||
ETH->DMASR = ETH_DMA_IT_RBU;
|
||||
if ((INFO->CHIPID & 0xf0) == 0x10)
|
||||
{
|
||||
((ETH_DMADESCTypeDef *)(((ETH_DMADESCTypeDef *)(ETH->DMACHRDR))->Buffer2NextDescAddr))->Status = ETH_DMARxDesc_OWN;
|
||||
ETH->DMARPDR = 0;
|
||||
}
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_AIS;
|
||||
}
|
||||
|
||||
// Nominal interrupts.
|
||||
if( int_sta & ETH_DMA_IT_NIS )
|
||||
{
|
||||
if( int_sta & ETH_DMA_IT_R )
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
// Nominal interrupts.
|
||||
if (int_sta & ETH_DMA_IT_NIS)
|
||||
{
|
||||
if (int_sta & ETH_DMA_IT_R)
|
||||
{
|
||||
// Received a packet, normally.
|
||||
// Status is in Table 27-17 Definitions of RDes0
|
||||
do
|
||||
{
|
||||
// XXX TODO: Is this a good place to acknowledge? REVISIT: Should this go lower?
|
||||
// XXX TODO: Restructure this to allow for
|
||||
ETH->DMASR = ETH_DMA_IT_R;
|
||||
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if( status & ETH_DMARxDesc_OWN ) break;
|
||||
uint32_t status = pDMARxGet->Status;
|
||||
if (status & ETH_DMARxDesc_OWN) break;
|
||||
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
// We only have a valid packet in a specific situation.
|
||||
// So, we take the status, then mask off the bits we care about
|
||||
// And see if they're equal to the ones that need to be set/unset.
|
||||
const uint32_t mask =
|
||||
ETH_DMARxDesc_OWN |
|
||||
ETH_DMARxDesc_LS |
|
||||
ETH_DMARxDesc_ES |
|
||||
ETH_DMARxDesc_FS;
|
||||
const uint32_t eq =
|
||||
0 |
|
||||
ETH_DMARxDesc_LS |
|
||||
0 |
|
||||
ETH_DMARxDesc_FS;
|
||||
|
||||
int suppress_own = 0;
|
||||
int suppress_own = 0;
|
||||
|
||||
if( ( status & mask ) == eq )
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if( frame_length > 0 )
|
||||
{
|
||||
uint8_t * data = (uint8_t*)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket( data, frame_length, pDMARxGet );
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
if ((status & mask) == eq)
|
||||
{
|
||||
int32_t frame_length = ((status & ETH_DMARxDesc_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
|
||||
if (frame_length > 0)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)pDMARxGet->Buffer1Addr;
|
||||
suppress_own = ch32v307ethInitHandlePacket(data, frame_length, pDMARxGet);
|
||||
}
|
||||
}
|
||||
// Otherwise, Invalid Packet
|
||||
|
||||
// Relinquish control back to underlying hardware.
|
||||
if( !suppress_own )
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
// Relinquish control back to underlying hardware.
|
||||
if (!suppress_own)
|
||||
pDMARxGet->Status = ETH_DMARxDesc_OWN;
|
||||
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while( 1 );
|
||||
}
|
||||
if( int_sta & ETH_DMA_IT_T )
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while( 1 );
|
||||
// Tricky logic for figuring out the next packet. Originally
|
||||
// discussed in ch32v30x_eth.c in ETH_DropRxPkt
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RCH) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(pDMARxGet->Buffer2NextDescAddr);
|
||||
else
|
||||
{
|
||||
if ((pDMARxGet->ControlBufferSize & ETH_DMARxDesc_RER) != (uint32_t)RESET)
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)(ETH->DMARDLAR);
|
||||
else
|
||||
pDMARxGet = (ETH_DMADESCTypeDef *)((uint32_t)pDMARxGet + 0x10 + ((ETH->DMABMR & ETH_DMABMR_DSL) >> 2));
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
if (int_sta & ETH_DMA_IT_T)
|
||||
{
|
||||
ch32v307ethInitHandleTXC();
|
||||
ETH->DMASR = ETH_DMA_IT_T;
|
||||
}
|
||||
ETH->DMASR = ETH_DMA_IT_NIS;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int ch32v307ethTransmitStatic(uint8_t * buffer, uint32_t length, int enable_txc)
|
||||
static int ch32v307ethTransmitStatic(uint8_t *buffer, uint32_t length, int enable_txc)
|
||||
{
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
// The official SDK waits until ETH_DMATxDesc_TTSS is set.
|
||||
// This also provides a transmit timestamp, which could be
|
||||
// used for PTP.
|
||||
// But we don't want to do that.
|
||||
// We just want to go. If anyone cares, they can check later.
|
||||
|
||||
if( pDMATxSet->Status & ETH_DMATxDesc_OWN )
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
if (pDMATxSet->Status & ETH_DMATxDesc_OWN)
|
||||
{
|
||||
ETH->DMATPDR = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pDMATxSet->ControlBufferSize = (length & ETH_DMATxDesc_TBS1);
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
pDMATxSet->Buffer1Addr = (uint32_t)buffer;
|
||||
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
// Status is in Table 27-12 "Definitions of TDes0 bits"
|
||||
enable_txc = enable_txc ? ETH_DMATxDesc_IC : 0;
|
||||
pDMATxSet->Status =
|
||||
ETH_DMATxDesc_LS | // Last Segment (This is all you need to have to transmit)
|
||||
ETH_DMATxDesc_FS | // First Segment (Beginning of transmission)
|
||||
enable_txc | // Interrupt when complete
|
||||
ETH_DMATxDesc_TCH | // Next Descriptor Address Valid
|
||||
ETH_DMATxDesc_CIC_TCPUDPICMP_Full | // Do all header checksums.
|
||||
ETH_DMATxDesc_OWN; // Own back to hardware
|
||||
|
||||
pDMATxSet = (ETH_DMADESCTypeDef*)pDMATxSet->Buffer2NextDescAddr;
|
||||
pDMATxSet = (ETH_DMADESCTypeDef *)pDMATxSet->Buffer2NextDescAddr;
|
||||
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
ETH->DMASR = ETH_DMASR_TBUS; // This resets the transmit process (or "starts" it)
|
||||
ETH->DMATPDR = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -7,75 +7,74 @@
|
|||
This is referenced in Chapter 22 USB Host/Device Controller (USBHD) of CH32FV2x_V3xRM.pdf
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ch32fun.h"
|
||||
#include "usb_defines.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb_defines.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct _USBState
|
||||
{
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
// Setup Request
|
||||
uint8_t USBHS_SetupReqCode;
|
||||
uint8_t USBHS_SetupReqType;
|
||||
uint16_t USBHS_SetupReqLen; // Used for tracking place along send.
|
||||
uint32_t USBHS_IndexValue;
|
||||
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
// USB Device Status
|
||||
uint16_t USBHS_DevConfig;
|
||||
uint16_t USBHS_DevAddr;
|
||||
uint8_t USBHS_DevSleepStatus;
|
||||
uint8_t USBHS_DevEnumStatus;
|
||||
|
||||
uint8_t * pCtrlPayloadPtr;
|
||||
uint8_t *pCtrlPayloadPtr;
|
||||
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
uint8_t ENDPOINTS[HUSB_CONFIG_EPS][64];
|
||||
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||
#define CTRL0BUFF (HSUSBCTX.ENDPOINTS[0])
|
||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t *)CTRL0BUFF)
|
||||
|
||||
#if HUSB_HID_INTERFACES > 0
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidIdle[HUSB_HID_INTERFACES];
|
||||
uint8_t USBHS_HidProtocol[HUSB_HID_INTERFACES];
|
||||
#endif
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
volatile uint8_t USBHS_Endp_Busy[HUSB_CONFIG_EPS];
|
||||
};
|
||||
|
||||
// Provided functions:
|
||||
int HSUSBSetup();
|
||||
int HSUSBSetup();
|
||||
uint8_t USBHS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||
|
||||
// Implement the following:
|
||||
#if HUSB_HID_USER_REPORTS
|
||||
int HandleHidUserGetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
int HandleHidUserSetReportSetup( struct _USBState * ctx, tusb_control_request_t * req );
|
||||
void HandleHidUserReportDataOut( struct _USBState * ctx, uint8_t * data, int len );
|
||||
int HandleHidUserReportDataIn( struct _USBState * ctx, uint8_t * data, int len );
|
||||
void HandleHidUserReportOutComplete( struct _USBState * ctx );
|
||||
int HandleHidUserGetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
int HandleHidUserSetReportSetup(struct _USBState *ctx, tusb_control_request_t *req);
|
||||
void HandleHidUserReportDataOut(struct _USBState *ctx, uint8_t *data, int len);
|
||||
int HandleHidUserReportDataIn(struct _USBState *ctx, uint8_t *data, int len);
|
||||
void HandleHidUserReportOutComplete(struct _USBState *ctx);
|
||||
#endif
|
||||
|
||||
#if HUSB_BULK_USER_REPORTS
|
||||
void HandleGotEPComplete( struct _USBState * ctx, int ep );
|
||||
void HandleGotEPComplete(struct _USBState *ctx, int ep);
|
||||
#endif
|
||||
|
||||
extern struct _USBState HSUSBCTX;
|
||||
|
||||
|
||||
// To TX, you can use USBFS_GetEPBufferIfAvailable or USBHSD_UEP_TXBUF( endp )
|
||||
|
||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||
static inline uint8_t *USBHS_GetEPBufferIfAvailable(int endp)
|
||||
{
|
||||
if( HSUSBCTX.USBHS_Endp_Busy[ endp ] ) return 0;
|
||||
return USBHSD_UEP_TXBUF( endp );
|
||||
if (HSUSBCTX.USBHS_Endp_Busy[endp]) return 0;
|
||||
return USBHSD_UEP_TXBUF(endp);
|
||||
}
|
||||
|
||||
static inline void USBHS_SendEndpoint( int endp, int len, const uint8_t * data )
|
||||
static inline void USBHS_SendEndpoint(int endp, int len, const uint8_t *data)
|
||||
{
|
||||
if( endp )
|
||||
{
|
||||
(((uint32_t*)(&USBHSD->UEP1_TX_DMA))[2-1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN( endp ) = len;
|
||||
USBHSD_UEP_TXCTRL( endp ) = ( USBHSD_UEP_TXCTRL( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[ endp ] = 0x01;
|
||||
if (endp)
|
||||
{
|
||||
(((uint32_t *)(&USBHSD->UEP1_TX_DMA))[2 - 1]) = (uintptr_t)data;
|
||||
}
|
||||
USBHSD_UEP_TLEN(endp) = len;
|
||||
USBHSD_UEP_TXCTRL(endp) = (USBHSD_UEP_TXCTRL(endp) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
|
||||
HSUSBCTX.USBHS_Endp_Busy[endp] = 0x01;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
/******************************************************************************
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
* Psuedo Random Number Generator using a Linear Feedback Shift Register
|
||||
* See the GitHub for more information:
|
||||
* https://github.com/ADBeta/CH32V003_lib_rand
|
||||
*
|
||||
* Ver 1.1 09 Sep 2024
|
||||
*
|
||||
* Released under the MIT Licence
|
||||
* Copyright ADBeta (c) 2024
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
#ifndef CH32V003_LIB_RAND
|
||||
#define CH32V003_LIB_RAND
|
||||
|
||||
|
|
@ -34,14 +34,13 @@
|
|||
// Strength 3: Genetate two 32bit values using the LFSR, then XOR them together
|
||||
// Example: #define RANDOM_STRENGTH 2
|
||||
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#ifndef RANDOM_STRENGTH
|
||||
#error "Error in lib_rand. Must define RANDOM_STRENGTH"
|
||||
#endif
|
||||
|
||||
// @brief set the random LFSR values seed by default to a known-good value
|
||||
static uint32_t _rand_lfsr = 0x747AA32F;
|
||||
|
||||
|
||||
/*** Library specific Functions - Do Not Use *********************************/
|
||||
/****************************************************************************/
|
||||
/// @brief Updates the LFSR by getting a new tap bit, for MSB, then shifting
|
||||
|
|
@ -51,63 +50,59 @@ static uint32_t _rand_lfsr = 0x747AA32F;
|
|||
/// @return 0x01 or 0x00, as a LSB translation of the tapped MSB for the LFSR
|
||||
uint8_t _rand_lfsr_update(void)
|
||||
{
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
// Shifting to MSB to make calculations more efficient later
|
||||
uint32_t bit_31 = _rand_lfsr & 0x80000000;
|
||||
uint32_t bit_21 = (_rand_lfsr << 10) & 0x80000000;
|
||||
uint32_t bit_01 = (_rand_lfsr << 30) & 0x80000000;
|
||||
uint32_t bit_00 = (_rand_lfsr << 31) & 0x80000000;
|
||||
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
// Calculate the MSB to be put into the LFSR
|
||||
uint32_t msb = bit_31 ^ bit_21 ^ bit_01 ^ bit_00;
|
||||
// Shift the lfsr and append the MSB to it
|
||||
_rand_lfsr = (_rand_lfsr >> 1) | msb;
|
||||
// Return the LSB instead of MSB
|
||||
return msb >> 31;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random 32-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, 32 times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random 32-bit value
|
||||
uint32_t _rand_gen_32b(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
uint8_t bits = 32;
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Generates a Random n-bit number, using the LFSR - by generating
|
||||
/// a random bit from LFSR taps, n times.
|
||||
/// @param None
|
||||
/// @return a (psuedo)random n-bit value
|
||||
uint32_t _rand_gen_nb( int bits)
|
||||
uint32_t _rand_gen_nb(int bits)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
while(bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
while (bits--)
|
||||
{
|
||||
// Shift the current rand value for the new LSB
|
||||
rand_out = rand_out << 1;
|
||||
// Append the LSB
|
||||
rand_out |= _rand_lfsr_update();
|
||||
}
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
|
||||
/*** API Functions ***********************************************************/
|
||||
/*****************************************************************************/
|
||||
/// @brief seeds the Random LFSR to the value passed
|
||||
|
|
@ -115,40 +110,39 @@ uint32_t _rand_gen_nb( int bits)
|
|||
/// @return None
|
||||
void seed(const uint32_t seed_val)
|
||||
{
|
||||
_rand_lfsr = seed_val;
|
||||
_rand_lfsr = seed_val;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Generates a Random (32-bit) Number, based on the RANDOM_STRENGTH
|
||||
/// you have selected
|
||||
/// you have selected
|
||||
/// @param None
|
||||
/// @return 32bit Random value
|
||||
uint32_t rand(void)
|
||||
{
|
||||
uint32_t rand_out = 0;
|
||||
uint32_t rand_out = 0;
|
||||
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 1, Update LFSR Once, then return it
|
||||
#if RANDOM_STRENGTH == 1
|
||||
// Update the LFSR, discard result, and return _lsfr raw
|
||||
(void)_rand_lfsr_update();
|
||||
rand_out = _rand_lfsr;
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 2, generate a 32-bit output, using 32 random
|
||||
// bits from the LFSR
|
||||
#if RANDOM_STRENGTH == 2
|
||||
rand_out = _rand_gen_32b();
|
||||
#endif
|
||||
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
// If RANDOM_STRENGTH is level 3, generate 2 32-bit outputs, then XOR them
|
||||
// together
|
||||
#if RANDOM_STRENGTH == 3
|
||||
uint32_t rand_a = _rand_gen_32b();
|
||||
uint32_t rand_b = _rand_gen_32b();
|
||||
rand_out = rand_a ^ rand_b;
|
||||
#endif
|
||||
|
||||
return rand_out;
|
||||
return rand_out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,14 +27,14 @@
|
|||
#define TIMEOUT_MAX 100000
|
||||
|
||||
// uncomment this to enable IRQ-driven operation
|
||||
//#define SSD1306_I2C_IRQ
|
||||
// #define SSD1306_I2C_IRQ
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// some stuff that IRQ mode needs
|
||||
volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state;
|
||||
|
||||
// uncomment this to enable time diags in IRQ
|
||||
//#define IRQ_DIAG
|
||||
// #define IRQ_DIAG
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -42,62 +42,62 @@ volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
uint16_t tempreg;
|
||||
|
||||
// Reset I2C1 to init all regs
|
||||
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
|
||||
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
|
||||
|
||||
// set freq
|
||||
tempreg = I2C1->CTLR2;
|
||||
tempreg &= ~I2C_CTLR2_FREQ;
|
||||
tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK / SSD1306_I2C_PRERATE) & I2C_CTLR2_FREQ;
|
||||
I2C1->CTLR2 = tempreg;
|
||||
|
||||
// Set clock config
|
||||
tempreg = 0;
|
||||
#if (SSD1306_I2C_CLKRATE <= 100000)
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
// standard mode good to 100kHz
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (2 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// fast mode over 100kHz
|
||||
// fast mode over 100kHz
|
||||
#ifndef SSD1306_I2C_DUTY
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
// 33% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (3 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
#else
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
// 36% duty cycle
|
||||
tempreg = (FUNCONF_SYSTEM_CORE_CLOCK / (25 * SSD1306_I2C_CLKRATE)) & I2C_CKCFGR_CCR;
|
||||
tempreg |= I2C_CKCFGR_DUTY;
|
||||
#endif
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
tempreg |= I2C_CKCFGR_FS;
|
||||
#endif
|
||||
I2C1->CKCFGR = tempreg;
|
||||
I2C1->CKCFGR = tempreg;
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
#endif
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
// enable IRQ driven operation
|
||||
NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
// initialize the state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
#endif
|
||||
|
||||
// Enable I2C
|
||||
I2C1->CTLR1 |= I2C_CTLR1_PE;
|
||||
|
||||
// set ACK mode
|
||||
I2C1->CTLR1 |= I2C_CTLR1_ACK;
|
||||
}
|
||||
|
||||
/*
|
||||
* error descriptions
|
||||
*/
|
||||
char *errstr[] =
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
{
|
||||
"not busy",
|
||||
"master mode",
|
||||
"transmit mode",
|
||||
"tx empty",
|
||||
"transmit complete",
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -105,28 +105,28 @@ char *errstr[] =
|
|||
*/
|
||||
uint8_t ssd1306_i2c_error(uint8_t err)
|
||||
{
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
// report error
|
||||
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
|
||||
|
||||
return 1;
|
||||
// reset & initialize I2C
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// event codes we use
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
|
||||
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
|
||||
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
|
||||
|
||||
/*
|
||||
* check for 32-bit event codes
|
||||
*/
|
||||
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
||||
{
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
|
||||
return (status & event_mask) == event_mask;
|
||||
/* read order matters here! STAR1 before STAR2!! */
|
||||
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
|
||||
return (status & event_mask) == event_mask;
|
||||
}
|
||||
|
||||
#ifdef SSD1306_I2C_IRQ
|
||||
|
|
@ -135,63 +135,67 @@ uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(3));
|
||||
#endif
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while(ssd1306_i2c_irq_state);
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
int32_t timeout;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
GPIOC->BSHR = (1 << (3));
|
||||
#endif
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
|
||||
// error out if buffer under/overflow
|
||||
if ((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
|
||||
return 2;
|
||||
|
||||
// wait for previous packet to finish
|
||||
while (ssd1306_i2c_irq_state)
|
||||
;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
#endif
|
||||
|
||||
// init buffer for sending
|
||||
ssd1306_i2c_send_sz = sz;
|
||||
ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer;
|
||||
memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz);
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// Enable TXE interrupt
|
||||
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
|
||||
ssd1306_i2c_irq_state = 1;
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
#endif
|
||||
|
||||
// exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -200,42 +204,43 @@ uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz)
|
|||
void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
|
||||
void I2C1_EV_IRQHandler(void)
|
||||
{
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
uint16_t STAR1, STAR2 __attribute__((unused));
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(4));
|
||||
GPIOC->BSHR = (1 << (4));
|
||||
#endif
|
||||
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
|
||||
/* check for TXE */
|
||||
if(STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if(ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
// read status, clear any events
|
||||
STAR1 = I2C1->STAR1;
|
||||
STAR2 = I2C1->STAR2;
|
||||
|
||||
/* was that the last byte? */
|
||||
if(!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||
/* check for TXE */
|
||||
if (STAR1 & I2C_STAR1_TXE)
|
||||
{
|
||||
/* check for remaining data */
|
||||
if (ssd1306_i2c_send_sz--)
|
||||
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
/* was that the last byte? */
|
||||
if (!ssd1306_i2c_send_sz)
|
||||
{
|
||||
// disable TXE interrupt
|
||||
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
|
||||
|
||||
// reset IRQ state
|
||||
ssd1306_i2c_irq_state = 0;
|
||||
|
||||
// wait for tx complete
|
||||
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
||||
;
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
|
@ -244,56 +249,61 @@ void I2C1_EV_IRQHandler(void)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
||||
{
|
||||
int32_t timeout;
|
||||
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(0);
|
||||
int32_t timeout;
|
||||
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr<<1;
|
||||
// wait for not busy
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(0);
|
||||
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(2);
|
||||
// Set START condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_START;
|
||||
|
||||
// send data one byte at a time
|
||||
while(sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
// wait for master mode select
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(1);
|
||||
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--));
|
||||
if(timeout==-1)
|
||||
return ssd1306_i2c_error(4);
|
||||
// send 7-bit address + write flag
|
||||
I2C1->DATAR = addr << 1;
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
// wait for transmit condition
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(2);
|
||||
|
||||
// send data one byte at a time
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TX Empty
|
||||
timeout = TIMEOUT_MAX;
|
||||
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(3);
|
||||
|
||||
// send command
|
||||
I2C1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for tx complete
|
||||
timeout = TIMEOUT_MAX;
|
||||
while ((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--))
|
||||
;
|
||||
if (timeout == -1)
|
||||
return ssd1306_i2c_error(4);
|
||||
|
||||
// set STOP condition
|
||||
I2C1->CTLR1 |= I2C_CTLR1_STOP;
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -302,20 +312,20 @@ uint8_t ssd1306_i2c_send(uint8_t addr, const uint8_t *data, int sz)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if(cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1);
|
||||
uint8_t pkt[33];
|
||||
|
||||
/* build command or data packets */
|
||||
if (cmd)
|
||||
{
|
||||
pkt[0] = 0;
|
||||
pkt[1] = *data;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt[0] = 0x40;
|
||||
memcpy(&pkt[1], data, sz);
|
||||
}
|
||||
return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -323,51 +333,51 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
|||
*/
|
||||
uint8_t ssd1306_i2c_init(void)
|
||||
{
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
// Enable GPIOC and I2C
|
||||
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
|
||||
|
||||
#ifdef CH32V20x
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO;
|
||||
|
||||
#ifdef SSD1306_REMAP_I2C
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode( PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
AFIO->PCFR1 |= AFIO_PCFR1_I2C1_REMAP;
|
||||
funPinMode(PB8, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB9, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
#else
|
||||
funPinMode( PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode( PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD );
|
||||
funPinMode(PB6, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
funPinMode(PB7, GPIO_CFGLR_OUT_10Mhz_AF_OD);
|
||||
#endif
|
||||
|
||||
#else
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||
// PC1 is SDA, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 1));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 1);
|
||||
|
||||
// PC2 is SCL, 10MHz Output, alt func, open-drain
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 2));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF) << (4 * 2);
|
||||
#endif
|
||||
|
||||
#ifdef IRQ_DIAG
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3);
|
||||
GPIOC->BSHR = (1<<(16+3));
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
|
||||
GPIOC->BSHR = (1<<(16+4));
|
||||
// GPIO diags on PC3/PC4
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 3));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 3);
|
||||
GPIOC->BSHR = (1 << (16 + 3));
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 4));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * 4);
|
||||
GPIOC->BSHR = (1 << (16 + 4));
|
||||
#endif
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
// load I2C regs
|
||||
ssd1306_i2c_setup();
|
||||
|
||||
#if 0
|
||||
// test if SSD1306 is on the bus by sending display off command
|
||||
uint8_t command = 0xAF;
|
||||
return ssd1306_pkt_send(&command, 1, 1);
|
||||
#else
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,111 +26,115 @@
|
|||
*/
|
||||
void ssd1306_i2c_setup(void)
|
||||
{
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
}
|
||||
|
||||
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
|
||||
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
|
||||
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
|
||||
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
|
||||
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
|
||||
#define SDA_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 1);
|
||||
#define SCL_HIGH funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 1);
|
||||
#define SDA_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SDA, 0);
|
||||
#define SCL_LOW funDigitalWrite(SSD1306_I2C_BITBANG_SCL, 0);
|
||||
#define SDA_IN funDigitalRead(SSD1306_I2C_BITBANG_SDA);
|
||||
#define I2CSPEEDBASE 1
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
|
||||
//Delay_Us(x*1);
|
||||
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x * 1)
|
||||
// Delay_Us(x*1);
|
||||
|
||||
static void ssd1306_i2c_sendstart()
|
||||
{
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
}
|
||||
|
||||
void ssd1306_i2c_sendstop()
|
||||
{
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
}
|
||||
|
||||
//Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
|
||||
// Return nonzero on failure.
|
||||
unsigned char ssd1306_i2c_sendbyte(unsigned char data)
|
||||
{
|
||||
unsigned int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
if( data & 0x80 )
|
||||
{ SDA_HIGH; }
|
||||
else
|
||||
{ SDA_LOW; }
|
||||
data<<=1;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
}
|
||||
unsigned int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
if (data & 0x80)
|
||||
{
|
||||
SDA_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDA_LOW;
|
||||
}
|
||||
data <<= 1;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(2 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
}
|
||||
|
||||
//Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD );
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
SDA_HIGH // Maybe?
|
||||
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
|
||||
return !!i;
|
||||
// Immediately after sending last bit, open up DDDR for control.
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD);
|
||||
SDA_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_HIGH
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
i = SDA_IN;
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SCL_LOW
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
SDA_HIGH // Maybe?
|
||||
funPinMode(SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
I2CDELAY_FUNC(1 * I2CSPEEDBASE);
|
||||
return !!i;
|
||||
}
|
||||
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
|
||||
if( r ) return r;
|
||||
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if(cmd)
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x00 ) )
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( 0x40 ) )
|
||||
return 1; // Data
|
||||
}
|
||||
for( int i = 0; i < sz; i++ )
|
||||
{
|
||||
if( ssd1306_i2c_sendbyte( data[i] ) )
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
ssd1306_i2c_sendstart();
|
||||
int r = ssd1306_i2c_sendbyte(SSD1306_I2C_ADDR << 1);
|
||||
if (r) return r;
|
||||
// ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
|
||||
if (cmd)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x00))
|
||||
return 1; // Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(0x40))
|
||||
return 1; // Data
|
||||
}
|
||||
for (int i = 0; i < sz; i++)
|
||||
{
|
||||
if (ssd1306_i2c_sendbyte(data[i]))
|
||||
return 1;
|
||||
}
|
||||
ssd1306_i2c_sendstop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
|
||||
funDigitalWrite( SSD1306_RST_PIN, 0 );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, 1 );
|
||||
Delay_Us(10);
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 0);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, 1);
|
||||
Delay_Us(10);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef SSD1306_SCK_PIN
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#define SSD1306_SCK_PIN PC5
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_BAUD_RATE_PRESCALER
|
||||
|
|
@ -36,31 +36,31 @@
|
|||
*/
|
||||
uint8_t ssd1306_spi_init(void)
|
||||
{
|
||||
// Enable GPIOC and SPI
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
|
||||
funGpioInitAll();
|
||||
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
|
||||
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
|
||||
// Enable GPIOC and SPI
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
|
||||
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
funGpioInitAll();
|
||||
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
|
||||
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
SSD1306_BAUD_RATE_PRESCALER;
|
||||
|
||||
// enable SPI port
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
// always succeed
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -68,9 +68,9 @@ uint8_t ssd1306_spi_init(void)
|
|||
*/
|
||||
void ssd1306_rst(void)
|
||||
{
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
|
||||
Delay_Ms(10);
|
||||
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -78,34 +78,35 @@ void ssd1306_rst(void)
|
|||
*/
|
||||
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||
{
|
||||
if(cmd)
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||
}
|
||||
if (cmd)
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
|
||||
}
|
||||
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||
|
||||
// send data
|
||||
while(sz--)
|
||||
{
|
||||
// wait for TXE
|
||||
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
while(SPI1->STATR & SPI_STATR_BSY) { }
|
||||
|
||||
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
|
||||
|
||||
// send data
|
||||
while (sz--)
|
||||
{
|
||||
// wait for TXE
|
||||
while (!(SPI1->STATR & SPI_STATR_TXE))
|
||||
;
|
||||
|
||||
// Send byte
|
||||
SPI1->DATAR = *data++;
|
||||
}
|
||||
|
||||
// wait for not busy before exiting
|
||||
while (SPI1->STATR & SPI_STATR_BSY) {}
|
||||
|
||||
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
|
||||
|
||||
// we're happy
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,28 +2,28 @@
|
|||
I may write another version of this to use DMA to timer ports, but, the SPI port can be used
|
||||
to generate outputs very efficiently. So, for now, SPI Port. Additionally, it uses FAR less
|
||||
internal bus resources than to do the same thing with timers.
|
||||
|
||||
|
||||
**For the CH32V003 this means output will be on PORTC Pin 6**
|
||||
|
||||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
If you are including this in main, simply
|
||||
#define WS2812DMA_IMPLEMENTATION
|
||||
|
||||
Other defines inclue:
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
#define WSRAW
|
||||
#define WSRBG
|
||||
#define WSGRB
|
||||
#define WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
|
||||
You will need to implement the following two functions, as callbacks from the ISR.
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
|
||||
You willalso need to call
|
||||
WS2812BDMAInit();
|
||||
WS2812BDMAInit();
|
||||
|
||||
Then, whenyou want to update the LEDs, call:
|
||||
WS2812BDMAStart( int num_leds );
|
||||
WS2812BDMAStart( int num_leds );
|
||||
*/
|
||||
|
||||
#ifndef _WS2812_LED_DRIVER_H
|
||||
|
|
@ -32,11 +32,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
|
||||
void WS2812BDMAInit( );
|
||||
void WS2812BDMAStart( int leds );
|
||||
void WS2812BDMAInit();
|
||||
void WS2812BDMAStart(int leds);
|
||||
|
||||
// Callbacks that you must implement.
|
||||
uint32_t WS2812BLEDCallback( int ledno );
|
||||
uint32_t WS2812BLEDCallback(int ledno);
|
||||
|
||||
#ifdef WS2812DMA_IMPLEMENTATION
|
||||
|
||||
|
|
@ -46,230 +46,241 @@ uint32_t WS2812BLEDCallback( int ledno );
|
|||
#endif
|
||||
|
||||
// Note first n LEDs of DMA Buffer are 0's as a "break"
|
||||
// Need one extra LED at end to leave line high.
|
||||
// Need one extra LED at end to leave line high.
|
||||
// This must be greater than WS2812B_RESET_PERIOD.
|
||||
#define WS2812B_RESET_PERIOD 2
|
||||
|
||||
#ifdef WSRAW
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
|
||||
#else
|
||||
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6)
|
||||
#define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
|
||||
#endif
|
||||
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
|
||||
static volatile int WS2812LEDs;
|
||||
static volatile int WS2812LEDPlace;
|
||||
static volatile int WS2812BLEDInUse;
|
||||
// This is the code that updates a portion of the WS2812dmabuff with new data.
|
||||
// This effectively creates the bitstream that outputs to the LEDs.
|
||||
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
|
||||
static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
|
||||
{
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
|
||||
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
|
||||
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
|
||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
|
||||
const static uint16_t bitquartets[16] = {
|
||||
0b1000100010001000,
|
||||
0b1000100010001110,
|
||||
0b1000100011101000,
|
||||
0b1000100011101110,
|
||||
0b1000111010001000,
|
||||
0b1000111010001110,
|
||||
0b1000111011101000,
|
||||
0b1000111011101110,
|
||||
0b1110100010001000,
|
||||
0b1110100010001110,
|
||||
0b1110100011101000,
|
||||
0b1110100011101110,
|
||||
0b1110111010001000,
|
||||
0b1110111010001110,
|
||||
0b1110111011101000,
|
||||
0b1110111011101110,
|
||||
};
|
||||
|
||||
int i;
|
||||
uint16_t * end = ptr + numhalfwords;
|
||||
int ledcount = WS2812LEDs;
|
||||
int place = WS2812LEDPlace;
|
||||
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++;
|
||||
}
|
||||
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
|
||||
while( place < 0 && ptr != end )
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
while (place < 0 && ptr != end)
|
||||
{
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
(*ptr++) = 0;
|
||||
place++;
|
||||
}
|
||||
#endif
|
||||
|
||||
while( ptr != end )
|
||||
{
|
||||
if( place >= ledcount )
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while( ptr != end )
|
||||
(*ptr++) = 0;//0xffff;
|
||||
while (ptr != end)
|
||||
{
|
||||
if (place >= ledcount)
|
||||
{
|
||||
// Optionally, leave line high.
|
||||
while (ptr != end)
|
||||
(*ptr++) = 0; // 0xffff;
|
||||
|
||||
// Only safe to do this when we're on the second leg.
|
||||
if( tce )
|
||||
{
|
||||
if( place == ledcount )
|
||||
{
|
||||
// Take the DMA out of circular mode and let it expire.
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
WS2812BLEDInUse = 0;
|
||||
}
|
||||
place++;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WSRAW
|
||||
uint32_t ledval32bit = WS2812BLEDCallback( place++ );
|
||||
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[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;
|
||||
ptr += 8;
|
||||
i += 8;
|
||||
|
||||
#else
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback( place++ );
|
||||
// Use a LUT to figure out how we should set the SPI line.
|
||||
uint32_t ledval24bit = WS2812BLEDCallback(place++);
|
||||
|
||||
#ifdef WSRBG
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
#elif defined( WSGRB )
|
||||
ptr[0] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
#elif defined(WSGRB)
|
||||
ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
#else
|
||||
ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
|
||||
ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
|
||||
ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
|
||||
ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
|
||||
ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
|
||||
ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
|
||||
ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
|
||||
#endif
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
ptr += 6;
|
||||
i += 6;
|
||||
#endif
|
||||
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
}
|
||||
WS2812LEDPlace = place;
|
||||
}
|
||||
|
||||
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler( void )
|
||||
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
|
||||
void DMA1_Channel3_IRQHandler(void)
|
||||
{
|
||||
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||
// GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
|
||||
|
||||
// Backup flags.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
// Backup flags.
|
||||
volatile int intfr = DMA1->INTFR;
|
||||
do
|
||||
{
|
||||
// Clear all possible flags.
|
||||
DMA1->INTFCR = DMA1_IT_GL3;
|
||||
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
// Strange note: These are backwards. DMA1_IT_HT3 should be HALF and
|
||||
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
|
||||
// LED jitter. I am henseforth flipping the order.
|
||||
|
||||
if( intfr & DMA1_IT_HT3 )
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 );
|
||||
}
|
||||
if( intfr & DMA1_IT_TC3 )
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 );
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while( intfr & DMA1_IT_GL3 );
|
||||
if (intfr & DMA1_IT_HT3)
|
||||
{
|
||||
// Halfwaay (Fill in first part)
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
|
||||
}
|
||||
if (intfr & DMA1_IT_TC3)
|
||||
{
|
||||
// Complete (Fill in second part)
|
||||
WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
|
||||
}
|
||||
intfr = DMA1->INTFR;
|
||||
} while (intfr & DMA1_IT_GL3);
|
||||
|
||||
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
// GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
|
||||
}
|
||||
|
||||
void WS2812BDMAStart( int leds )
|
||||
void WS2812BDMAStart(int leds)
|
||||
{
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
// Enter critical section.
|
||||
__disable_irq();
|
||||
WS2812BLEDInUse = 1;
|
||||
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = 0;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
WS2812LEDs = leds;
|
||||
WS2812LEDPlace = -WS2812B_RESET_PERIOD;
|
||||
__enable_irq();
|
||||
|
||||
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
|
||||
WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN, 0);
|
||||
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
|
||||
DMA1_Channel3->CFGR |= DMA_Mode_Circular;
|
||||
}
|
||||
|
||||
void WS2812BDMAInit( )
|
||||
void WS2812BDMAInit()
|
||||
{
|
||||
// Enable DMA + Peripherals
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
// Enable DMA + Peripherals
|
||||
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
|
||||
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf<<(4*6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
|
||||
// MOSI, Configure GPIO Pin
|
||||
GPIOC->CFGLR &= ~(0xf << (4 * 6));
|
||||
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
|
||||
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3<<3; // Divisior = 16 (48/16 = 3MHz)
|
||||
// Configure SPI
|
||||
SPI1->CTLR1 =
|
||||
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
|
||||
SPI_Mode_Master | SPI_Direction_1Line_Tx |
|
||||
3 << 3; // Divisior = 16 (48/16 = 3MHz)
|
||||
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
|
||||
SPI1->HSCR = 1;
|
||||
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
SPI1->CTLR1 |= CTLR1_SPE_Set;
|
||||
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
SPI1->DATAR = 0; // Set SPI line Low.
|
||||
|
||||
//DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
// DMA1_Channel3 is for SPI1TX
|
||||
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
|
||||
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
|
||||
DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
|
||||
DMA1_Channel3->CFGR =
|
||||
DMA_M2M_Disable |
|
||||
DMA_Priority_VeryHigh |
|
||||
DMA_MemoryDataSize_HalfWord |
|
||||
DMA_PeripheralDataSize_HalfWord |
|
||||
DMA_MemoryInc_Enable |
|
||||
DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
|
||||
DMA_DIR_PeripheralDST |
|
||||
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
|
||||
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ( DMA1_Channel3_IRQn );
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
|
||||
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
||||
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
|
||||
|
||||
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING
|
||||
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
__set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
|
||||
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
|
||||
|
||||
If you are including this in main, simply
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
#define WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
You may also want to define
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
#define WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes );
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes);
|
||||
|
||||
#ifdef WS2812BSIMPLE_IMPLEMENTATION
|
||||
|
||||
|
|
@ -25,59 +25,58 @@ void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in
|
|||
#error WS2812B Driver Requires FUNCONF_SYSTICK_USE_HCLK
|
||||
#endif
|
||||
|
||||
void WS2812BSimpleSend( GPIO_TypeDef * port, int pin, uint8_t * data, int len_in_bytes )
|
||||
void WS2812BSimpleSend(GPIO_TypeDef *port, int pin, uint8_t *data, int len_in_bytes)
|
||||
{
|
||||
int port_id = (((intptr_t)port-(intptr_t)GPIOA)>>10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA<<port_id); // Make sure port is enabled.
|
||||
int port_id = (((intptr_t)port - (intptr_t)GPIOA) >> 10);
|
||||
RCC->APB2PCENR |= (RCC_APB2Periph_GPIOA << port_id); // Make sure port is enabled.
|
||||
|
||||
int poffset = (pin*4);
|
||||
port->CFGLR = ( port->CFGLR & (~(0xf<<poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP)<<(poffset));
|
||||
int poffset = (pin * 4);
|
||||
port->CFGLR = (port->CFGLR & (~(0xf << poffset))) | ((GPIO_Speed_2MHz | GPIO_CNF_OUT_PP) << (poffset));
|
||||
|
||||
int maskon = 1<<pin;
|
||||
int maskoff = 1<<(16+pin);
|
||||
int maskon = 1 << pin;
|
||||
int maskoff = 1 << (16 + pin);
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
|
||||
uint8_t * end = data + len_in_bytes;
|
||||
while( data != end )
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
uint8_t *end = data + len_in_bytes;
|
||||
while (data != end)
|
||||
{
|
||||
uint8_t byte = *data;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
if( byte & 0x80 )
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (byte & 0x80)
|
||||
{
|
||||
// WS2812B's need AT LEAST 625ns for a logical "1"
|
||||
port->BSHR = maskon;
|
||||
DelaySysTick(25);
|
||||
port->BSHR = maskoff;
|
||||
DelaySysTick(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WS2812B's need BETWEEN 62.5 to about 500 ns for a logical "0"
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__disable_irq();
|
||||
__disable_irq();
|
||||
#endif
|
||||
port->BSHR = maskon;
|
||||
asm volatile( "nop\nnop\nnop\nnop" );
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskon;
|
||||
asm volatile("nop\nnop\nnop\nnop");
|
||||
port->BSHR = maskoff;
|
||||
#ifndef WS2812BSIMPLE_NO_IRQ_TWEAKING
|
||||
__enable_irq();
|
||||
__enable_irq();
|
||||
#endif
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
DelaySysTick(15);
|
||||
}
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
data++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
port->BSHR = maskoff;
|
||||
port->BSHR = maskoff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
5
src/misc/attic/.clang-format
Normal file
5
src/misc/attic/.clang-format
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"DisableFormat": true,
|
||||
"SortIncludes": "Never"
|
||||
}
|
||||
|
||||
|
|
@ -1,226 +1,244 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
const char * yes[] = { "SENTINEL_WILL_BE_REPLACED_BY_CMDLINE" }; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char * no[] = { "CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003" };
|
||||
const char *yes[] = {"SENTINEL_WILL_BE_REPLACED_BY_CMDLINE"}; // "CH32X03x", etc. element 0 is filled in by command-line
|
||||
const char *no[] = {"CH32V10x", "CH32V30x", "CH32V20x", "CH32X03x", "CH32V003"};
|
||||
|
||||
char * WhitePull( const char ** sti )
|
||||
char *WhitePull(const char **sti)
|
||||
{
|
||||
const char * st = *sti;
|
||||
int len = 0;
|
||||
while( ( *st == ' ' || *st == '\t' || *st == '(' ) && *st ) { st++; }
|
||||
const char * sts = st;
|
||||
while( *st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0 ) { st++; len++; }
|
||||
if( *st == ')' ) { st++; }
|
||||
char * ret = malloc( len + 1 );
|
||||
memcpy( ret, sts, len );
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
const char *st = *sti;
|
||||
int len = 0;
|
||||
while ((*st == ' ' || *st == '\t' || *st == '(') && *st)
|
||||
{
|
||||
st++;
|
||||
}
|
||||
const char *sts = st;
|
||||
while (*st != ' ' && *st != '\t' && *st != '\n' && *st != ')' && *st != '(' && *st != 0)
|
||||
{
|
||||
st++;
|
||||
len++;
|
||||
}
|
||||
if (*st == ')') { st++; }
|
||||
char *ret = malloc(len + 1);
|
||||
memcpy(ret, sts, len);
|
||||
ret[len] = 0;
|
||||
*sti = st;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NYI( const char * s )
|
||||
int NYI(const char *s)
|
||||
{
|
||||
int ret = 2;
|
||||
char * wp = WhitePull( &s );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(yes)/sizeof(yes[0]); i++ )
|
||||
if( strcmp( yes[i], wp ) == 0 ) ret = 1;
|
||||
if( ret != 1 )
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
if( strcmp( no[i], wp ) == 0 ) ret = 0;
|
||||
free( wp );
|
||||
return ret;
|
||||
int ret = 2;
|
||||
char *wp = WhitePull(&s);
|
||||
int i;
|
||||
for (i = 0; i < sizeof(yes) / sizeof(yes[0]); i++)
|
||||
if (strcmp(yes[i], wp) == 0) ret = 1;
|
||||
if (ret != 1)
|
||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
||||
if (strcmp(no[i], wp) == 0) ret = 0;
|
||||
free(wp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EvalSpec( const char * spl )
|
||||
int EvalSpec(const char *spl)
|
||||
{
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
int rsofar = 0;
|
||||
int i;
|
||||
int lastv = 0;
|
||||
int lasto = -1;
|
||||
int ret = 0;
|
||||
cont:
|
||||
char * wp = WhitePull( &spl );
|
||||
int def = -1;
|
||||
if( strcmp( wp, "defined" ) == 0 ) def = 1;
|
||||
if( strcmp( wp, "!defined" ) == 0 ) def = 2;
|
||||
if( def < 0 ) return 2;
|
||||
char * wpn = WhitePull( &spl );
|
||||
i = NYI( wpn );
|
||||
//printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if( i == 2 ) return 2;
|
||||
char *wp = WhitePull(&spl);
|
||||
int def = -1;
|
||||
if (strcmp(wp, "defined") == 0) def = 1;
|
||||
if (strcmp(wp, "!defined") == 0) def = 2;
|
||||
if (def < 0) return 2;
|
||||
char *wpn = WhitePull(&spl);
|
||||
i = NYI(wpn);
|
||||
// printf( "SPIN: %s/%s/%d/%d/%d\n", wp, wpn, i, def, lasto );
|
||||
if (i == 2) return 2;
|
||||
|
||||
if( def == 2 ) i = !i;
|
||||
if (def == 2) i = !i;
|
||||
|
||||
if( lasto == 1 )
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if( lasto == 2 )
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
if (lasto == 1)
|
||||
{
|
||||
ret = lastv || i;
|
||||
}
|
||||
else if (lasto == 2)
|
||||
ret = lastv && i;
|
||||
else
|
||||
ret = i;
|
||||
|
||||
char * wpa = WhitePull( &spl );
|
||||
//printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
//printf( "RET: %d\n", ret );
|
||||
if( strcmp( wpa, "||" ) == 0 ) { lasto = 1; goto cont; }
|
||||
else if( strcmp( wpa, "&&" ) == 0 ) { lasto = 2; goto cont; }
|
||||
else return ret;
|
||||
char *wpa = WhitePull(&spl);
|
||||
// printf( "WPA: \"%s\"\n", wpa );
|
||||
lastv = ret;
|
||||
lasto = -1;
|
||||
// printf( "RET: %d\n", ret );
|
||||
if (strcmp(wpa, "||") == 0)
|
||||
{
|
||||
lasto = 1;
|
||||
goto cont;
|
||||
}
|
||||
else if (strcmp(wpa, "&&") == 0)
|
||||
{
|
||||
lasto = 2;
|
||||
goto cont;
|
||||
}
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 0 for no
|
||||
// 1 for yes
|
||||
// 2 for indeterminate
|
||||
int NoYesInd( const char * preprocc )
|
||||
int NoYesInd(const char *preprocc)
|
||||
{
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if( strncmp( preprocc, "#if ", 4 ) == 0 ) ofs = 4;
|
||||
if( strncmp( preprocc, "#elif ", 6 ) == 0 ) ofs = 6;
|
||||
if( ofs )
|
||||
{
|
||||
ret = EvalSpec( preprocc + ofs );
|
||||
//printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifdef ", 7 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
free( wp );
|
||||
}
|
||||
else if( strncmp( preprocc, "#ifndef ", 8 ) == 0 )
|
||||
{
|
||||
const char * ep = preprocc + 6;
|
||||
char * wp = WhitePull( &ep );
|
||||
ret = NYI( wp );
|
||||
if( ret < 2 ) ret = !ret;
|
||||
free( wp );
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
//printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
int ret;
|
||||
int ofs = 0;
|
||||
if (strncmp(preprocc, "#if ", 4) == 0) ofs = 4;
|
||||
if (strncmp(preprocc, "#elif ", 6) == 0) ofs = 6;
|
||||
if (ofs)
|
||||
{
|
||||
ret = EvalSpec(preprocc + ofs);
|
||||
// printf( "SPEC: %d\n", ret );
|
||||
}
|
||||
else if (strncmp(preprocc, "#ifdef ", 7) == 0)
|
||||
{
|
||||
const char *ep = preprocc + 6;
|
||||
char *wp = WhitePull(&ep);
|
||||
ret = NYI(wp);
|
||||
free(wp);
|
||||
}
|
||||
else if (strncmp(preprocc, "#ifndef ", 8) == 0)
|
||||
{
|
||||
const char *ep = preprocc + 6;
|
||||
char *wp = WhitePull(&ep);
|
||||
ret = NYI(wp);
|
||||
if (ret < 2) ret = !ret;
|
||||
free(wp);
|
||||
}
|
||||
else
|
||||
ret = 2;
|
||||
// printf( "%d-> %s\n", ret, preprocc );
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * sslineis( const char * line, const char * match )
|
||||
const char *sslineis(const char *line, const char *match)
|
||||
{
|
||||
while( *line == ' ' || *line == '\t' ) line++;
|
||||
const char * linestart = line;
|
||||
while( *line && *match == *line ) { line++; match++; }
|
||||
if( *match == 0 )
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
while (*line == ' ' || *line == '\t')
|
||||
line++;
|
||||
const char *linestart = line;
|
||||
while (*line && *match == *line)
|
||||
{
|
||||
line++;
|
||||
match++;
|
||||
}
|
||||
if (*match == 0)
|
||||
return linestart;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if( argc != 3 )
|
||||
{
|
||||
fprintf( stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n" );
|
||||
int i;
|
||||
for( i = 0; i < sizeof(no)/sizeof(no[0]); i++ )
|
||||
{
|
||||
fprintf( stderr, "\t%s\n", no[i] );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr, "Syntax: transition [#define to trigger on] [file to convert]\nNo'd architectures:\n");
|
||||
int i;
|
||||
for (i = 0; i < sizeof(no) / sizeof(no[0]); i++)
|
||||
{
|
||||
fprintf(stderr, "\t%s\n", no[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
yes[0] = argv[1];
|
||||
yes[0] = argv[1];
|
||||
|
||||
FILE * f = fopen( argv[2], "r" );
|
||||
if( !f )
|
||||
{
|
||||
fprintf( stderr, "Error: Could not open \"%s\"\n", argv[2] );
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char * l;
|
||||
FILE *f = fopen(argv[2], "r");
|
||||
if (!f)
|
||||
{
|
||||
fprintf(stderr, "Error: Could not open \"%s\"\n", argv[2]);
|
||||
return -2;
|
||||
}
|
||||
char line[1024];
|
||||
char *l;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
int depth = 0;
|
||||
// 0 = no
|
||||
// 1 = yes
|
||||
// 2 = indeterminate
|
||||
// 3 = super no. (I.e. after a true #if clause)
|
||||
int yesnoind[1024];
|
||||
yesnoind[0] = 1;
|
||||
|
||||
// 0 = no
|
||||
// 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))
|
||||
{
|
||||
const char *ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
|
||||
while( l = fgets( line, sizeof(line)-1, f ) )
|
||||
{
|
||||
const char * ss = 0;
|
||||
int nyi = yesnoind[depth];
|
||||
int waspre = 0;
|
||||
if ((ss = sslineis(line, "#if ")) || (ss = sslineis(line, "#ifdef ")) || (ss = sslineis(line, "#ifndef ")))
|
||||
{
|
||||
waspre = 1;
|
||||
// printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd(ss);
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if ((ss = sslineis(line, "#elif ")))
|
||||
{
|
||||
if (nyi != 2)
|
||||
{
|
||||
waspre = 1;
|
||||
if (nyi == 1)
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd(ss);
|
||||
}
|
||||
// printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if ((ss = sslineis(line, "#else")))
|
||||
{
|
||||
if (nyi != 2)
|
||||
{
|
||||
waspre = 1;
|
||||
if (yesnoind[depth] == 1)
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if ((ss = sslineis(line, "#endif")))
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if (depth < 0)
|
||||
{
|
||||
fprintf(stderr, "UNTERMD IF\n");
|
||||
}
|
||||
}
|
||||
|
||||
if( (ss = sslineis( line, "#if " ) ) || (ss = sslineis( line, "#ifdef " ) ) || (ss = sslineis( line, "#ifndef " ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
//printf( "CHECK: %d/%s\n", depth, l );
|
||||
nyi = NoYesInd( ss );
|
||||
depth++;
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
else if( (ss = sslineis( line, "#elif " ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( nyi == 1 )
|
||||
{
|
||||
nyi = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
nyi = NoYesInd( ss );
|
||||
}
|
||||
//printf( "ELIF check: %s %d\n", ss, nyi );
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#else" ) ) )
|
||||
{
|
||||
if( nyi != 2 )
|
||||
{
|
||||
waspre = 1;
|
||||
if( yesnoind[depth] == 1 )
|
||||
nyi = 3;
|
||||
else
|
||||
nyi = !yesnoind[depth];
|
||||
yesnoind[depth] = nyi;
|
||||
}
|
||||
}
|
||||
else if( (ss = sslineis( line, "#endif" ) ) )
|
||||
{
|
||||
waspre = 1;
|
||||
depth--;
|
||||
if( depth < 0 )
|
||||
{
|
||||
fprintf( stderr, "UNTERMD IF\n" );
|
||||
}
|
||||
}
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for (i = 0; i <= depth; i++)
|
||||
{
|
||||
// printf( "%d", yesnoind[i] );
|
||||
if (yesnoind[i] == 0 || yesnoind[i] == 3) thisv = 0;
|
||||
}
|
||||
// printf( ">>%s", l );
|
||||
|
||||
int thisv = nyi;
|
||||
int i;
|
||||
for( i = 0; i <= depth; i++ )
|
||||
{
|
||||
//printf( "%d", yesnoind[i] );
|
||||
if( yesnoind[i] == 0 || yesnoind[i] == 3 ) thisv = 0;
|
||||
}
|
||||
//printf( ">>%s", l );
|
||||
|
||||
if( thisv != 0 && thisv != 3 && ( thisv != 1 || !waspre ) )
|
||||
{
|
||||
printf( "%s", l );
|
||||
}
|
||||
}
|
||||
if (thisv != 0 && thisv != 3 && (thisv != 1 || !waspre))
|
||||
{
|
||||
printf("%s", l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
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.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,23 +0,0 @@
|
|||
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
|
||||
|
||||
Loading…
Add table
Reference in a new issue