removed uneeded files.

This commit is contained in:
Jake Goodwin 2025-03-08 17:09:58 -08:00
parent 1f17f8dcdf
commit 32a3dcad12
25 changed files with 6911 additions and 20039 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
// set prescaler
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER << 3);
// reset control register
SPI1->CTLR1 = 0;
// set clock polarity and phase
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL0_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
#elif defined(CH32V003_SPI_CLK_MODE_POL1_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
#endif
// set prescaler
SPI1->CTLR1 |= SPI_CTLR1_BR & (SPI_CLK_PRESCALER<<3);
// configure NSS pin, master mode
#if defined(CH32V003_SPI_NSS_HARDWARE_PC0)
// _NSS (negative slave select) on PC0, 10MHz Output, alt func, push-pull1
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
GPIOC->CFGLR &= ~(0xf << (4 * 0));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 0);
AFIO->PCFR1 |= GPIO_Remap_SPI1; // remap NSS (C1) to _NSS (C0)
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
#elif defined(CH32V003_SPI_NSS_HARDWARE_PC1)
// NSS (negative slave select) on PC1, 10MHz Output, alt func, push-pull1
SPI1->CTLR1 |= SPI_NSS_Hard; // NSS hardware control mode
GPIOC->CFGLR &= ~(0xf << (4 * 1));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 1);
SPI1->CTLR2 |= SPI_CTLR2_SSOE; // pull _NSS high
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
GPIOC->CFGLR &= ~(0xf << (4 * 3));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 3);
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
GPIOC->CFGLR &= ~(0xf << (4 * 4));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 4);
#elif defined(CH32V003_SPI_NSS_SOFTWARE_ANY_MANUAL)
SPI1->CTLR1 |= SPI_NSS_Soft; // SSM NSS software control mode
#endif
// set clock polarity and phase
#if defined(CH32V003_SPI_CLK_MODE_POL0_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_1Edge);
#elif defined (CH32V003_SPI_CLK_MODE_POL0_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_Low | SPI_CPHA_2Edge);
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA0)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_1Edge);
#elif defined (CH32V003_SPI_CLK_MODE_POL1_PHA1)
SPI1->CTLR1 |= (SPI_CPOL_High | SPI_CPHA_2Edge);
#endif
// 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);
// 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
// CH32V003 is master
SPI1->CTLR1 |= SPI_Mode_Master;
// 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);
// 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);
// set data direction and configure data pins
#if defined(CH32V003_SPI_DIRECTION_2LINE_TXRX)
SPI1->CTLR1 |= SPI_Direction_2Lines_FullDuplex;
// MISO on PC7, 10MHz input, floating
GPIOC->CFGLR &= ~(0xf << (4 * 7));
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING << (4 * 7);
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
// MOSI on PC6, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf<<(4*6));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
// MISO on PC7, 10MHz input, floating
GPIOC->CFGLR &= ~(0xf<<(4*7));
GPIOC->CFGLR |= GPIO_CNF_IN_FLOATING<<(4*7);
#elif defined(CH32V003_SPI_DIRECTION_1LINE_TX)
SPI1->CTLR1 |= SPI_Direction_1Line_Tx;
// MOSI on PC6, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf<<(4*6));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
#endif
// MOSI on PC6, 10MHz Output, alt func, push-pull
GPIOC->CFGLR &= ~(0xf << (4 * 6));
GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
#endif
}
static inline void SPI_begin_8() {
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE;
static inline void SPI_begin_8()
{
SPI1->CTLR1 &= ~(SPI_CTLR1_DFF); // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE;
}
static inline void SPI_begin_16() {
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE;
static inline void SPI_begin_16()
{
SPI1->CTLR1 |= SPI_CTLR1_DFF; // DFF 16bit data-length enable, writable only when SPE is 0
SPI1->CTLR1 |= SPI_CTLR1_SPE;
}
static inline void SPI_end() {
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
static inline void SPI_end()
{
SPI1->CTLR1 &= ~(SPI_CTLR1_SPE);
}
#if defined(CH32V003_SPI_NSS_SOFTWARE_PC3)
static inline void SPI_NSS_software_high() {
GPIOC->BSHR = (1<<3);
static inline void SPI_NSS_software_high()
{
GPIOC->BSHR = (1 << 3);
}
static inline void SPI_NSS_software_low() {
GPIOC->BSHR = (1<<(16+3));
static inline void SPI_NSS_software_low()
{
GPIOC->BSHR = (1 << (16 + 3));
}
#elif defined(CH32V003_SPI_NSS_SOFTWARE_PC4)
static inline void SPI_NSS_software_high() {
GPIOC->BSHR = (1<<4);
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

View file

@ -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,152 +48,155 @@
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;
// 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);
// Reset calibration
ADC1->CTLR2 |= ADC_RSTCAL;
while (ADC1->CTLR2 & ADC_RSTCAL)
;
// Calibrate
ADC1->CTLR2 |= ADC_CAL;
while(ADC1->CTLR2 & ADC_CAL);
// 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
/*
@ -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.
*/

View file

@ -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;
// 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
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

View file

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

View file

@ -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
@ -35,13 +35,12 @@
// Example: #define RANDOM_STRENGTH 2
#ifndef RANDOM_STRENGTH
#error "Error in lib_rand. Must define 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;
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();
}
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;
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
/// @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

View file

@ -6,19 +6,19 @@
#ifndef _SSD1306_H
#define _SSD1306_H
#include "font_8x8.h"
#include <stdint.h>
#include <string.h>
#include "font_8x8.h"
// comfortable packet size for this OLED
#define SSD1306_PSZ 32
#if defined (SSD1306_CUSTOM)
#if defined(SSD1306_CUSTOM)
// Let the caller configure the OLED.
#else
// characteristics of each type
#if !defined (SSD1306_64X32) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET) )
#error "Please define the SSD1306_WXH resolution used in your application"
#if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64) && !defined(SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET))
#error "Please define the SSD1306_WXH resolution used in your application"
#endif
#ifdef SSD1306_64X32
@ -57,7 +57,7 @@
*/
uint8_t ssd1306_cmd(uint8_t cmd)
{
return ssd1306_pkt_send(&cmd, 1, 1);
return ssd1306_pkt_send(&cmd, 1, 1);
}
/*
@ -65,7 +65,7 @@ uint8_t ssd1306_cmd(uint8_t cmd)
*/
uint8_t ssd1306_data(uint8_t *data, int sz)
{
return ssd1306_pkt_send(data, sz, 0);
return ssd1306_pkt_send(data, sz, 0);
}
#define SSD1306_SETCONTRAST 0x81
@ -87,7 +87,7 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
#define SSD1306_SETSTARTLINE 0x40
#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22
#define SSD1306_PAGEADDR 0x22
#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8
#define SSD1306_CHARGEPUMP 0x8D
@ -98,81 +98,81 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
/* choose VCC mode */
#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2
//#define vccstate SSD1306_EXTERNALVCC
// #define vccstate SSD1306_EXTERNALVCC
#define vccstate SSD1306_SWITCHCAPVCC
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
// OLED initialization commands for 128x32
const uint8_t ssd1306_init_array[] =
{
{
#ifdef SH1107
SSD1306_DISPLAYOFF, // Turn OLED off
0x00, // Low column
0x10, // High column
0xb0, // Page address
0xdc, 0x00, // Set Display Start Line (Where in memory it reads from)
SSD1306_SETCONTRAST, 0x6f, // Set constrast
SSD1306_COLUMNADDR, // Set memory addressing mode
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // Iterate over all 128 rows (Multiplex Ratio)
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
SSD1306_SETVCOMDETECT, 0x35, // Set vcomh
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
0xad, 0x80, // Set Charge pump
SSD1306_SEGREMAP, 0x01, // Default mapping
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
SSD1306_SETCONTRAST, 0xfe, // Set constrast
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // 128-wide.
SSD1306_DISPLAYON, // Display on.
SSD1306_DISPLAYOFF, // Turn OLED off
0x00, // Low column
0x10, // High column
0xb0, // Page address
0xdc, 0x00, // Set Display Start Line (Where in memory it reads from)
SSD1306_SETCONTRAST, 0x6f, // Set constrast
SSD1306_COLUMNADDR, // Set memory addressing mode
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // Iterate over all 128 rows (Multiplex Ratio)
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
SSD1306_SETVCOMDETECT, 0x35, // Set vcomh
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
0xad, 0x80, // Set Charge pump
SSD1306_SEGREMAP, 0x01, // Default mapping
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
SSD1306_SETCONTRAST, 0xfe, // Set constrast
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // 128-wide.
SSD1306_DISPLAYON, // Display on.
#else
SSD1306_DISPLAYOFF, // 0xAE
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
0x80, // the suggested ratio 0x80
SSD1306_SETMULTIPLEX, // 0xA8
SSD1306_DISPLAYOFF, // 0xAE
SSD1306_SETDISPLAYCLOCKDIV, // 0xD5
0x80, // the suggested ratio 0x80
SSD1306_SETMULTIPLEX, // 0xA8
#ifdef SSD1306_64X32
0x1F, // for 64-wide displays
0x1F, // for 64-wide displays
#else
0x3F, // for 128-wide displays
0x3F, // for 128-wide displays
#endif
SSD1306_SETDISPLAYOFFSET, // 0xD3
0x00, // no offset
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
SSD1306_CHARGEPUMP, // 0x8D
0x14, // enable?
SSD1306_MEMORYMODE, // 0x20
0x00, // 0x0 act like ks0108
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
SSD1306_COMSCANDEC,
SSD1306_SETCOMPINS, // 0xDA
0x12, //
SSD1306_SETCONTRAST, // 0x81
0x8F,
SSD1306_SETPRECHARGE, // 0xd9
0xF1,
SSD1306_SETVCOMDETECT, // 0xDB
0x40,
SSD1306_DISPLAYALLON_RESUME, // 0xA4
SSD1306_SETDISPLAYOFFSET, // 0xD3
0x00, // no offset
SSD1306_SETSTARTLINE | 0x0, // 0x40 | line
SSD1306_CHARGEPUMP, // 0x8D
0x14, // enable?
SSD1306_MEMORYMODE, // 0x20
0x00, // 0x0 act like ks0108
SSD1306_SEGREMAP | 0x1, // 0xA0 | bit
SSD1306_COMSCANDEC,
SSD1306_SETCOMPINS, // 0xDA
0x12, //
SSD1306_SETCONTRAST, // 0x81
0x8F,
SSD1306_SETPRECHARGE, // 0xd9
0xF1,
SSD1306_SETVCOMDETECT, // 0xDB
0x40,
SSD1306_DISPLAYALLON_RESUME, // 0xA4
#ifndef SSD1327
SSD1306_NORMALDISPLAY, // 0xA6
SSD1306_NORMALDISPLAY, // 0xA6
#endif
SSD1306_DISPLAYON, // 0xAF --turn on oled panel
SSD1306_DISPLAYON, // 0xAF --turn on oled panel
#endif
SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end
SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end
};
#endif
// the display buffer
uint8_t ssd1306_buffer[SSD1306_W*SSD1306_H/8];
uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8];
/*
* set the buffer to a color
*/
void ssd1306_setbuf(uint8_t color)
{
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer));
}
#ifndef SSD1306_FULLUSE
@ -180,11 +180,23 @@ void ssd1306_setbuf(uint8_t color)
* expansion array for OLED with every other row unused
*/
const uint8_t expand[16] =
{
0x00,0x02,0x08,0x0a,
0x20,0x22,0x28,0x2a,
0x80,0x82,0x88,0x8a,
0xa0,0xa2,0xa8,0xaa,
{
0x00,
0x02,
0x08,
0x0a,
0x20,
0x22,
0x28,
0x2a,
0x80,
0x82,
0x88,
0x8a,
0xa0,
0xa2,
0xa8,
0xaa,
};
#endif
@ -193,66 +205,65 @@ const uint8_t expand[16] =
*/
void ssd1306_refresh(void)
{
uint16_t i;
uint16_t i;
#ifdef SH1107
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
for(i=0;i<SSD1306_H/8;i++)
{
ssd1306_cmd(0xb0 | i);
ssd1306_cmd( 0x00 | (0&0xf) );
ssd1306_cmd( 0x10 | (0>>4) );
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+0*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+1*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+2*SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+3*SSD1306_PSZ], SSD1306_PSZ);
}
for (i = 0; i < SSD1306_H / 8; i++)
{
ssd1306_cmd(0xb0 | i);
ssd1306_cmd(0x00 | (0 & 0xf));
ssd1306_cmd(0x10 | (0 >> 4));
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 0 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 1 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 2 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 3 * SSD1306_PSZ], SSD1306_PSZ);
}
#else
ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(SSD1306_OFFSET+SSD1306_W-1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address
ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset)
ssd1306_cmd(7); // Page end address
#ifdef SSD1306_FULLUSE
/* for fully used rows just plow thru everything */
for(i=0;i<sizeof(ssd1306_buffer);i+=SSD1306_PSZ)
{
/* send PSZ block of data */
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
}
/* for fully used rows just plow thru everything */
for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ)
{
/* send PSZ block of data */
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
}
#else
/* for displays with odd rows unused expand bytes */
uint8_t tbuf[SSD1306_PSZ], j, k;
for(i=0;i<sizeof(ssd1306_buffer);i+=128)
{
/* low nybble */
for(j=0;j<128;j+=SSD1306_PSZ)
{
for(k=0;k<SSD1306_PSZ;k++)
tbuf[k] = expand[ssd1306_buffer[i+j+k]&0xf];
/* for displays with odd rows unused expand bytes */
uint8_t tbuf[SSD1306_PSZ], j, k;
for (i = 0; i < sizeof(ssd1306_buffer); i += 128)
{
/* low nybble */
for (j = 0; j < 128; j += SSD1306_PSZ)
{
for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf];
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
/* high nybble */
for(j=0;j<128;j+=SSD1306_PSZ)
{
for(k=0;k<SSD1306_PSZ;k++)
tbuf[k] = expand[(ssd1306_buffer[i+j+k]>>4)&0xf];
/* high nybble */
for (j = 0; j < 128; j += SSD1306_PSZ)
{
for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf];
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
}
/* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ);
}
}
#endif
#endif
}
/*
@ -260,22 +271,22 @@ void ssd1306_refresh(void)
*/
void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
{
uint32_t addr;
uint32_t addr;
/* clip */
if(x >= SSD1306_W)
return;
if(y >= SSD1306_H)
return;
/* clip */
if (x >= SSD1306_W)
return;
if (y >= SSD1306_H)
return;
/* compute buffer address */
addr = x + SSD1306_W*(y/8);
/* compute buffer address */
addr = x + SSD1306_W * (y / 8);
/* set/clear bit in buffer */
if(color)
ssd1306_buffer[addr] |= (1<<(y&7));
else
ssd1306_buffer[addr] &= ~(1<<(y&7));
/* set/clear bit in buffer */
if (color)
ssd1306_buffer[addr] |= (1 << (y & 7));
else
ssd1306_buffer[addr] &= ~(1 << (y & 7));
}
/*
@ -283,89 +294,96 @@ void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
*/
void ssd1306_xorPixel(uint32_t x, uint32_t y)
{
uint32_t addr;
uint32_t addr;
/* clip */
if(x >= SSD1306_W)
return;
if(y >= SSD1306_H)
return;
/* clip */
if (x >= SSD1306_W)
return;
if (y >= SSD1306_H)
return;
/* compute buffer address */
addr = x + SSD1306_W*(y/8);
/* compute buffer address */
addr = x + SSD1306_W * (y / 8);
ssd1306_buffer[addr] ^= (1<<(y&7));
ssd1306_buffer[addr] ^= (1 << (y & 7));
}
/*
* draw a an image from an array, directly into to the display buffer
* the color modes allow for overwriting and even layering (sprites!)
*/
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint32_t width, uint32_t height, uint32_t color_mode) {
uint32_t x_absolute;
uint32_t y_absolute;
uint32_t pixel;
uint32_t bytes_to_draw = width / 8;
uint32_t buffer_addr;
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint32_t width, uint32_t height, uint32_t color_mode)
{
uint32_t x_absolute;
uint32_t y_absolute;
uint32_t pixel;
uint32_t bytes_to_draw = width / 8;
uint32_t buffer_addr;
for (uint32_t line = 0; line < height; line++) {
y_absolute = y + line;
if (y_absolute >= SSD1306_H) {
break;
}
for (uint32_t line = 0; line < height; line++)
{
y_absolute = y + line;
if (y_absolute >= SSD1306_H)
{
break;
}
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
// bitmask for current pixel in vertical (output) byte
uint32_t v_mask = 1 << (y_absolute & 7);
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
// bitmask for current pixel in vertical (output) byte
uint32_t v_mask = 1 << (y_absolute & 7);
for (uint32_t byte = 0; byte < bytes_to_draw; byte++) {
uint32_t input_byte = input[byte + line * bytes_to_draw];
for (uint32_t byte = 0; byte < bytes_to_draw; byte++)
{
uint32_t input_byte = input[byte + line * bytes_to_draw];
for (pixel = 0; pixel < 8; pixel++) {
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W) {
break;
}
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
// state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel);
for (pixel = 0; pixel < 8; pixel++)
{
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W)
{
break;
}
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
// state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel);
switch (color_mode) {
case 0:
// write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
break;
case 1:
// write pixels after inversion
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
break;
case 2:
// 0 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
break;
case 3:
// 1 sets pixel
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
break;
case 4:
// 0 sets pixel
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
break;
case 5:
// 1 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
break;
}
}
#if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte);
#endif
}
#if SSD1306_LOG_IMAGE == 1
printf("\n\r");
#endif
}
switch (color_mode)
{
case 0:
// write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
break;
case 1:
// write pixels after inversion
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
break;
case 2:
// 0 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
break;
case 3:
// 1 sets pixel
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
break;
case 4:
// 0 sets pixel
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
break;
case 5:
// 1 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
break;
}
}
#if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte);
#endif
}
#if SSD1306_LOG_IMAGE == 1
printf("\n\r");
#endif
}
}
/*
@ -373,13 +391,13 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
*/
void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{
// clipping
if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if((y+h-1) >= SSD1306_H) h = SSD1306_H-y;
while(h--)
{
// clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if ((y + h - 1) >= SSD1306_H) h = SSD1306_H - y;
while (h--)
{
ssd1306_drawPixel(x, y++, color);
}
}
}
/*
@ -387,14 +405,14 @@ void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
*/
void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
{
// clipping
if((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if((x+w-1) >= SSD1306_W) w = SSD1306_W-x;
// clipping
if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if ((x + w - 1) >= SSD1306_W) w = SSD1306_W - x;
while (w--)
{
while (w--)
{
ssd1306_drawPixel(x++, y, color);
}
}
}
/*
@ -402,7 +420,7 @@ void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
*/
int gfx_abs(int x)
{
return (x<0) ? -x : x;
return (x < 0) ? -x : x;
}
/*
@ -410,9 +428,9 @@ int gfx_abs(int x)
*/
void gfx_swap(int *z0, int *z1)
{
uint16_t temp = *z0;
*z0 = *z1;
*z1 = temp;
uint16_t temp = *z0;
*z0 = *z1;
*z1 = temp;
}
/*
@ -420,56 +438,56 @@ void gfx_swap(int *z0, int *z1)
*/
void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
{
int32_t steep;
int32_t deltax, deltay, error, ystep, x, y;
int32_t steep;
int32_t deltax, deltay, error, ystep, x, y;
/* flip sense 45deg to keep error calc in range */
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
/* flip sense 45deg to keep error calc in range */
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
if(steep)
{
gfx_swap(&x0, &y0);
gfx_swap(&x1, &y1);
}
if (steep)
{
gfx_swap(&x0, &y0);
gfx_swap(&x1, &y1);
}
/* run low->high */
if(x0 > x1)
{
gfx_swap(&x0, &x1);
gfx_swap(&y0, &y1);
}
/* run low->high */
if (x0 > x1)
{
gfx_swap(&x0, &x1);
gfx_swap(&y0, &y1);
}
/* set up loop initial conditions */
deltax = x1 - x0;
deltay = gfx_abs(y1 - y0);
error = deltax/2;
y = y0;
if(y0 < y1)
ystep = 1;
else
ystep = -1;
/* set up loop initial conditions */
deltax = x1 - x0;
deltay = gfx_abs(y1 - y0);
error = deltax / 2;
y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
/* loop x */
for(x=x0;x<=x1;x++)
{
/* plot point */
if(steep)
/* flip point & plot */
ssd1306_drawPixel(y, x, color);
else
/* just plot */
ssd1306_drawPixel(x, y, color);
/* loop x */
for (x = x0; x <= x1; x++)
{
/* plot point */
if (steep)
/* flip point & plot */
ssd1306_drawPixel(y, x, color);
else
/* just plot */
ssd1306_drawPixel(x, y, color);
/* update error */
error = error - deltay;
/* update error */
error = error - deltay;
/* update y */
if(error < 0)
{
y = y + ystep;
error = error + deltax;
}
}
/* update y */
if (error < 0)
{
y = y + ystep;
error = error + deltax;
}
}
}
/*
@ -480,22 +498,26 @@ void ssd1306_drawCircle(int x, int y, int radius, int color)
/* Bresenham algorithm */
int x_pos = -radius;
int y_pos = 0;
int err = 2 - 2 * radius;
int err = 2 - 2 * radius;
int e2;
do {
do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
ssd1306_drawPixel(x - x_pos, y - y_pos, color);
e2 = err;
if (e2 <= y_pos) {
if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1;
if(-x_pos == y_pos && e2 <= x_pos) {
e2 = 0;
if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0;
}
}
if (e2 > x_pos) {
if (e2 > x_pos)
{
err += ++x_pos * 2 + 1;
}
} while (x_pos <= 0);
@ -509,10 +531,11 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
/* Bresenham algorithm */
int x_pos = -radius;
int y_pos = 0;
int err = 2 - 2 * radius;
int err = 2 - 2 * radius;
int e2;
do {
do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color);
@ -520,16 +543,19 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color);
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
e2 = err;
if (e2 <= y_pos) {
if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1;
if(-x_pos == y_pos && e2 <= x_pos) {
if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0;
}
}
if(e2 > x_pos) {
if (e2 > x_pos)
{
err += ++x_pos * 2 + 1;
}
} while(x_pos <= 0);
} while (x_pos <= 0);
}
/*
@ -537,10 +563,10 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
*/
void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color)
{
ssd1306_drawFastVLine(x, y, h, color);
ssd1306_drawFastVLine(x+w-1, y, h, color);
ssd1306_drawFastHLine(x, y, w, color);
ssd1306_drawFastHLine(x, y+h-1, w, color);
ssd1306_drawFastVLine(x, y, h, color);
ssd1306_drawFastVLine(x + w - 1, y, h, color);
ssd1306_drawFastHLine(x, y, w, color);
ssd1306_drawFastHLine(x, y + h - 1, w, color);
}
/*
@ -548,21 +574,21 @@ void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t col
*/
void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color)
{
uint32_t m, n=y, iw = w;
uint32_t m, n = y, iw = w;
/* scan vertical */
while(h--)
{
m=x;
w=iw;
/* scan horizontal */
while(w--)
{
/* invert pixels */
ssd1306_drawPixel(m++, n, color);
}
n++;
}
/* scan vertical */
while (h--)
{
m = x;
w = iw;
/* scan horizontal */
while (w--)
{
/* invert pixels */
ssd1306_drawPixel(m++, n, color);
}
n++;
}
}
/*
@ -570,21 +596,21 @@ void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t co
*/
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{
uint8_t m, n=y, iw = w;
uint8_t m, n = y, iw = w;
/* scan vertical */
while(h--)
{
m=x;
w=iw;
/* scan horizontal */
while(w--)
{
/* invert pixels */
ssd1306_xorPixel(m++, n);
}
n++;
}
/* scan vertical */
while (h--)
{
m = x;
w = iw;
/* scan horizontal */
while (w--)
{
/* invert pixels */
ssd1306_xorPixel(m++, n);
}
n++;
}
}
/*
@ -592,25 +618,25 @@ void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
*/
void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
{
uint16_t i, j, col;
uint8_t d;
uint16_t i, j, col;
uint8_t d;
for(i=0;i<8;i++)
{
d = fontdata[(chr<<3)+i];
for(j=0;j<8;j++)
{
if(d&0x80)
col = color;
else
col = (~color)&1;
for (i = 0; i < 8; i++)
{
d = fontdata[(chr << 3) + i];
for (j = 0; j < 8; j++)
{
if (d & 0x80)
col = color;
else
col = (~color) & 1;
ssd1306_drawPixel(x+j, y+i, col);
ssd1306_drawPixel(x + j, y + i, col);
// next bit
d <<= 1;
}
}
// next bit
d <<= 1;
}
}
}
/*
@ -618,25 +644,26 @@ void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
*/
void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
{
uint8_t c;
uint8_t c;
while((c=*str++))
{
ssd1306_drawchar(x, y, c, color);
x += 8;
if(x>120)
break;
}
while ((c = *str++))
{
ssd1306_drawchar(x, y, c, color);
x += 8;
if (x > 120)
break;
}
}
/*
* enum for font size
*/
typedef enum {
fontsize_8x8 = 1,
typedef enum
{
fontsize_8x8 = 1,
fontsize_16x16 = 2,
fontsize_32x32 = 4,
fontsize_64x64 = 8,
fontsize_64x64 = 8,
} font_size_t;
/*
@ -645,7 +672,7 @@ typedef enum {
void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_size_t font_size)
{
uint16_t i, j, col;
uint8_t d;
uint8_t d;
// Determine the font scale factor based on the font_size parameter
uint8_t font_scale = (uint8_t)font_size;
@ -666,8 +693,10 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
col = (~color) & 1;
// Draw the pixel at the original size and scaled size using nested for-loops
for (uint8_t k = 0; k < font_scale; k++) {
for (uint8_t l = 0; l < font_scale; l++) {
for (uint8_t k = 0; k < font_scale; k++)
{
for (uint8_t l = 0; l < font_scale; l++)
{
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
}
}
@ -683,15 +712,15 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
*/
void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_size_t font_size)
{
uint8_t c;
uint8_t c;
while((c=*str++))
{
ssd1306_drawchar_sz(x, y, c, color, font_size);
x += 8 * font_size;
if(x>128 - 8 * font_size)
break;
}
while ((c = *str++))
{
ssd1306_drawchar_sz(x, y, c, color, font_size);
x += 8 * font_size;
if (x > 128 - 8 * font_size)
break;
}
}
/*
@ -699,25 +728,25 @@ void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_siz
*/
uint8_t ssd1306_init(void)
{
// pulse reset
ssd1306_rst();
// pulse reset
ssd1306_rst();
ssd1306_setbuf(0);
ssd1306_setbuf(0);
// initialize OLED
// initialize OLED
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while(*cmd_list != SSD1306_TERMINATE_CMDS)
{
if(ssd1306_cmd(*cmd_list++))
return 1;
}
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while (*cmd_list != SSD1306_TERMINATE_CMDS)
{
if (ssd1306_cmd(*cmd_list++))
return 1;
}
// clear display
ssd1306_refresh();
// clear display
ssd1306_refresh();
#endif
return 0;
return 0;
}
#endif

View file

@ -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;
uint16_t tempreg;
// Reset I2C1 to init all regs
RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
// 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 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;
// 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);
// enable IRQ driven operation
NVIC_EnableIRQ(I2C1_EV_IRQn);
// initialize the state
ssd1306_i2c_irq_state = 0;
// initialize the state
ssd1306_i2c_irq_state = 0;
#endif
// Enable I2C
I2C1->CTLR1 |= I2C_CTLR1_PE;
// Enable I2C
I2C1->CTLR1 |= I2C_CTLR1_PE;
// set ACK mode
I2C1->CTLR1 |= I2C_CTLR1_ACK;
// set ACK mode
I2C1->CTLR1 |= I2C_CTLR1_ACK;
}
/*
* error descriptions
*/
char *errstr[] =
{
"not busy",
"master mode",
"transmit mode",
"tx empty",
"transmit complete",
{
"not busy",
"master mode",
"transmit mode",
"tx empty",
"transmit complete",
};
/*
@ -105,28 +105,28 @@ char *errstr[] =
*/
uint8_t ssd1306_i2c_error(uint8_t err)
{
// report error
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
// report error
printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]);
// reset & initialize I2C
ssd1306_i2c_setup();
// reset & initialize I2C
ssd1306_i2c_setup();
return 1;
return 1;
}
// event codes we use
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */
#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */
#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */
/*
* check for 32-bit event codes
*/
uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask)
{
/* read order matters here! STAR1 before STAR2!! */
uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16);
return (status & event_mask) == event_mask;
/* read order matters here! STAR1 before STAR2!! */
uint32_t status = I2C1->STAR1 | (I2C1->STAR2 << 16);
return (status & event_mask) == event_mask;
}
#ifdef SSD1306_I2C_IRQ
@ -135,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;
int32_t timeout;
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(3));
GPIOC->BSHR = (1 << (3));
#endif
// error out if buffer under/overflow
if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz)
return 2;
// 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);
// wait for previous packet to finish
while (ssd1306_i2c_irq_state)
;
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+3));
GPIOC->BSHR = (1<<(4));
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);
// 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);
// 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;
// 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);
// 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;
// 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);
// 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;
// Enable TXE interrupt
I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN;
ssd1306_i2c_irq_state = 1;
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+4));
GPIOC->BSHR = (1 << (16 + 4));
#endif
// exit
return 0;
// 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;
// read status, clear any events
STAR1 = I2C1->STAR1;
STAR2 = I2C1->STAR2;
/* check for TXE */
if(STAR1 & I2C_STAR1_TXE)
{
/* check for remaining data */
if(ssd1306_i2c_send_sz--)
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
/* check for TXE */
if (STAR1 & I2C_STAR1_TXE)
{
/* check for remaining data */
if (ssd1306_i2c_send_sz--)
I2C1->DATAR = *ssd1306_i2c_send_ptr++;
/* was that the last byte? */
if(!ssd1306_i2c_send_sz)
{
// disable TXE interrupt
I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN);
/* 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;
// reset IRQ state
ssd1306_i2c_irq_state = 0;
// wait for tx complete
while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// wait for tx complete
while (!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED))
;
// set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP;
}
}
// set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP;
}
}
#ifdef IRQ_DIAG
GPIOC->BSHR = (1<<(16+4));
GPIOC->BSHR = (1 << (16 + 4));
#endif
}
#else
@ -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;
int32_t timeout;
// wait for not busy
timeout = TIMEOUT_MAX;
while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--));
if(timeout==-1)
return ssd1306_i2c_error(0);
// wait for not busy
timeout = TIMEOUT_MAX;
while ((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--))
;
if (timeout == -1)
return ssd1306_i2c_error(0);
// Set START condition
I2C1->CTLR1 |= I2C_CTLR1_START;
// 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);
// 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;
// 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);
// 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 data one byte at a time
while (sz--)
{
// wait for TX Empty
timeout = TIMEOUT_MAX;
while (!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--))
;
if (timeout == -1)
return ssd1306_i2c_error(3);
// send command
I2C1->DATAR = *data++;
}
// send 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);
// 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;
// set STOP condition
I2C1->CTLR1 |= I2C_CTLR1_STOP;
// we're happy
return 0;
// 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];
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);
/* 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);
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);
// 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
}

View file

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

View file

@ -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;
// 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 );
funGpioInitAll();
funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
funPinMode(SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
// Configure SPI
SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
SPI_Mode_Master | SPI_Direction_1Line_Tx |
SSD1306_BAUD_RATE_PRESCALER;
// Configure SPI
SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
SPI_Mode_Master | SPI_Direction_1Line_Tx |
SSD1306_BAUD_RATE_PRESCALER;
// enable SPI port
SPI1->CTLR1 |= CTLR1_SPE_Set;
// enable SPI port
SPI1->CTLR1 |= CTLR1_SPE_Set;
// always succeed
return 0;
// 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 );
funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
// send data
while(sz--)
{
// wait for TXE
while(!(SPI1->STATR & SPI_STATR_TXE));
// send data
while (sz--)
{
// wait for TXE
while (!(SPI1->STATR & SPI_STATR_TXE))
;
// Send byte
SPI1->DATAR = *data++;
}
// Send byte
SPI1->DATAR = *data++;
}
// wait for not busy before exiting
while(SPI1->STATR & SPI_STATR_BSY) { }
// wait for not busy before exiting
while (SPI1->STATR & SPI_STATR_BSY) {}
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
// we're happy
return 0;
// we're happy
return 0;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -8,22 +8,22 @@
Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
If you are including this in main, simply
#define WS2812DMA_IMPLEMENTATION
#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
@ -51,225 +51,236 @@ uint32_t WS2812BLEDCallback( int ledno );
#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

View file

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

View file

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

View file

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

View file

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

View file

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