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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,19 +6,19 @@
#ifndef _SSD1306_H #ifndef _SSD1306_H
#define _SSD1306_H #define _SSD1306_H
#include "font_8x8.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "font_8x8.h"
// comfortable packet size for this OLED // comfortable packet size for this OLED
#define SSD1306_PSZ 32 #define SSD1306_PSZ 32
#if defined (SSD1306_CUSTOM) #if defined(SSD1306_CUSTOM)
// Let the caller configure the OLED. // Let the caller configure the OLED.
#else #else
// characteristics of each type // characteristics of each type
#if !defined (SSD1306_64X32) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET) ) #if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64) && !defined(SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET))
#error "Please define the SSD1306_WXH resolution used in your application" #error "Please define the SSD1306_WXH resolution used in your application"
#endif #endif
#ifdef SSD1306_64X32 #ifdef SSD1306_64X32
@ -98,13 +98,13 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
/* choose VCC mode */ /* choose VCC mode */
#define SSD1306_EXTERNALVCC 0x1 #define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2 #define SSD1306_SWITCHCAPVCC 0x2
//#define vccstate SSD1306_EXTERNALVCC // #define vccstate SSD1306_EXTERNALVCC
#define vccstate SSD1306_SWITCHCAPVCC #define vccstate SSD1306_SWITCHCAPVCC
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY #if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
// OLED initialization commands for 128x32 // OLED initialization commands for 128x32
const uint8_t ssd1306_init_array[] = const uint8_t ssd1306_init_array[] =
{ {
#ifdef SH1107 #ifdef SH1107
SSD1306_DISPLAYOFF, // Turn OLED off SSD1306_DISPLAYOFF, // Turn OLED off
0x00, // Low column 0x00, // Low column
@ -114,7 +114,7 @@ const uint8_t ssd1306_init_array[] =
SSD1306_SETCONTRAST, 0x6f, // Set constrast SSD1306_SETCONTRAST, 0x6f, // Set constrast
SSD1306_COLUMNADDR, // Set memory addressing mode SSD1306_COLUMNADDR, // Set memory addressing mode
SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.) SSD1306_DISPLAYALLON_RESUME, // normal (as opposed to invert colors, always on or off.)
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // Iterate over all 128 rows (Multiplex Ratio) SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // Iterate over all 128 rows (Multiplex Ratio)
SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different) SSD1306_SETDISPLAYOFFSET, 0x00, // Set display offset // Where this appears on-screen (Some displays will be different)
SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr SSD1306_SETDISPLAYCLOCKDIV, 0xf0, // Set precharge properties. THIS IS A LIE This has todo with timing. <<< This makes it go brrrrrrrrr
SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness) SSD1306_SETPRECHARGE, 0x1d, // Set pre-charge period (This controls brightness)
@ -125,7 +125,7 @@ const uint8_t ssd1306_init_array[] =
SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best. SSD1306_SETPRECHARGE, 0x06, // ???? No idea what this does, but this looks best.
SSD1306_SETCONTRAST, 0xfe, // Set constrast SSD1306_SETCONTRAST, 0xfe, // Set constrast
SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh SSD1306_SETVCOMDETECT, 0xfe, // Set vcomh
SSD1306_SETMULTIPLEX, (SSD1306_H-1), // 128-wide. SSD1306_SETMULTIPLEX, (SSD1306_H - 1), // 128-wide.
SSD1306_DISPLAYON, // Display on. SSD1306_DISPLAYON, // Display on.
#else #else
SSD1306_DISPLAYOFF, // 0xAE SSD1306_DISPLAYOFF, // 0xAE
@ -165,7 +165,7 @@ const uint8_t ssd1306_init_array[] =
#endif #endif
// the display buffer // the display buffer
uint8_t ssd1306_buffer[SSD1306_W*SSD1306_H/8]; uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8];
/* /*
* set the buffer to a color * set the buffer to a color
@ -180,11 +180,23 @@ void ssd1306_setbuf(uint8_t color)
* expansion array for OLED with every other row unused * expansion array for OLED with every other row unused
*/ */
const uint8_t expand[16] = const uint8_t expand[16] =
{ {
0x00,0x02,0x08,0x0a, 0x00,
0x20,0x22,0x28,0x2a, 0x02,
0x80,0x82,0x88,0x8a, 0x08,
0xa0,0xa2,0xa8,0xaa, 0x0a,
0x20,
0x22,
0x28,
0x2a,
0x80,
0x82,
0x88,
0x8a,
0xa0,
0xa2,
0xa8,
0xaa,
}; };
#endif #endif
@ -199,20 +211,20 @@ void ssd1306_refresh(void)
ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode. ssd1306_cmd(SSD1306_MEMORYMODE); // vertical addressing mode.
for(i=0;i<SSD1306_H/8;i++) for (i = 0; i < SSD1306_H / 8; i++)
{ {
ssd1306_cmd(0xb0 | i); ssd1306_cmd(0xb0 | i);
ssd1306_cmd( 0x00 | (0&0xf) ); ssd1306_cmd(0x00 | (0 & 0xf));
ssd1306_cmd( 0x10 | (0>>4) ); ssd1306_cmd(0x10 | (0 >> 4));
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+0*SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 0 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+1*SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 1 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+2*SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 2 * SSD1306_PSZ], SSD1306_PSZ);
ssd1306_data(&ssd1306_buffer[i*4*SSD1306_PSZ+3*SSD1306_PSZ], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i * 4 * SSD1306_PSZ + 3 * SSD1306_PSZ], SSD1306_PSZ);
} }
#else #else
ssd1306_cmd(SSD1306_COLUMNADDR); ssd1306_cmd(SSD1306_COLUMNADDR);
ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset) ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset)
ssd1306_cmd(SSD1306_OFFSET+SSD1306_W-1); // Column end address (127 = reset) ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset)
ssd1306_cmd(SSD1306_PAGEADDR); ssd1306_cmd(SSD1306_PAGEADDR);
ssd1306_cmd(0); // Page start address (0 = reset) ssd1306_cmd(0); // Page start address (0 = reset)
@ -220,7 +232,7 @@ void ssd1306_refresh(void)
#ifdef SSD1306_FULLUSE #ifdef SSD1306_FULLUSE
/* for fully used rows just plow thru everything */ /* for fully used rows just plow thru everything */
for(i=0;i<sizeof(ssd1306_buffer);i+=SSD1306_PSZ) for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ)
{ {
/* send PSZ block of data */ /* send PSZ block of data */
ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ); ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ);
@ -228,23 +240,23 @@ void ssd1306_refresh(void)
#else #else
/* for displays with odd rows unused expand bytes */ /* for displays with odd rows unused expand bytes */
uint8_t tbuf[SSD1306_PSZ], j, k; uint8_t tbuf[SSD1306_PSZ], j, k;
for(i=0;i<sizeof(ssd1306_buffer);i+=128) for (i = 0; i < sizeof(ssd1306_buffer); i += 128)
{ {
/* low nybble */ /* low nybble */
for(j=0;j<128;j+=SSD1306_PSZ) for (j = 0; j < 128; j += SSD1306_PSZ)
{ {
for(k=0;k<SSD1306_PSZ;k++) for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[ssd1306_buffer[i+j+k]&0xf]; tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf];
/* send PSZ block of data */ /* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ); ssd1306_data(tbuf, SSD1306_PSZ);
} }
/* high nybble */ /* high nybble */
for(j=0;j<128;j+=SSD1306_PSZ) for (j = 0; j < 128; j += SSD1306_PSZ)
{ {
for(k=0;k<SSD1306_PSZ;k++) for (k = 0; k < SSD1306_PSZ; k++)
tbuf[k] = expand[(ssd1306_buffer[i+j+k]>>4)&0xf]; tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf];
/* send PSZ block of data */ /* send PSZ block of data */
ssd1306_data(tbuf, SSD1306_PSZ); ssd1306_data(tbuf, SSD1306_PSZ);
@ -252,7 +264,6 @@ void ssd1306_refresh(void)
} }
#endif #endif
#endif #endif
} }
/* /*
@ -263,19 +274,19 @@ void ssd1306_drawPixel(uint32_t x, uint32_t y, int color)
uint32_t addr; uint32_t addr;
/* clip */ /* clip */
if(x >= SSD1306_W) if (x >= SSD1306_W)
return; return;
if(y >= SSD1306_H) if (y >= SSD1306_H)
return; return;
/* compute buffer address */ /* compute buffer address */
addr = x + SSD1306_W*(y/8); addr = x + SSD1306_W * (y / 8);
/* set/clear bit in buffer */ /* set/clear bit in buffer */
if(color) if (color)
ssd1306_buffer[addr] |= (1<<(y&7)); ssd1306_buffer[addr] |= (1 << (y & 7));
else else
ssd1306_buffer[addr] &= ~(1<<(y&7)); ssd1306_buffer[addr] &= ~(1 << (y & 7));
} }
/* /*
@ -286,31 +297,34 @@ void ssd1306_xorPixel(uint32_t x, uint32_t y)
uint32_t addr; uint32_t addr;
/* clip */ /* clip */
if(x >= SSD1306_W) if (x >= SSD1306_W)
return; return;
if(y >= SSD1306_H) if (y >= SSD1306_H)
return; return;
/* compute buffer address */ /* compute buffer address */
addr = x + SSD1306_W*(y/8); addr = x + SSD1306_W * (y / 8);
ssd1306_buffer[addr] ^= (1<<(y&7)); ssd1306_buffer[addr] ^= (1 << (y & 7));
} }
/* /*
* draw a an image from an array, directly into to the display buffer * draw a an image from an array, directly into to the display buffer
* the color modes allow for overwriting and even layering (sprites!) * the color modes allow for overwriting and even layering (sprites!)
*/ */
void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint32_t width, uint32_t height, uint32_t color_mode) { void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char *input, uint32_t width, uint32_t height, uint32_t color_mode)
{
uint32_t x_absolute; uint32_t x_absolute;
uint32_t y_absolute; uint32_t y_absolute;
uint32_t pixel; uint32_t pixel;
uint32_t bytes_to_draw = width / 8; uint32_t bytes_to_draw = width / 8;
uint32_t buffer_addr; uint32_t buffer_addr;
for (uint32_t line = 0; line < height; line++) { for (uint32_t line = 0; line < height; line++)
{
y_absolute = y + line; y_absolute = y + line;
if (y_absolute >= SSD1306_H) { if (y_absolute >= SSD1306_H)
{
break; break;
} }
@ -318,12 +332,15 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
// bitmask for current pixel in vertical (output) byte // bitmask for current pixel in vertical (output) byte
uint32_t v_mask = 1 << (y_absolute & 7); uint32_t v_mask = 1 << (y_absolute & 7);
for (uint32_t byte = 0; byte < bytes_to_draw; byte++) { for (uint32_t byte = 0; byte < bytes_to_draw; byte++)
{
uint32_t input_byte = input[byte + line * bytes_to_draw]; uint32_t input_byte = input[byte + line * bytes_to_draw];
for (pixel = 0; pixel < 8; pixel++) { for (pixel = 0; pixel < 8; pixel++)
{
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel; x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W) { if (x_absolute >= SSD1306_W)
{
break; break;
} }
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8 // looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
@ -331,7 +348,8 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
// state of current pixel // state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel); uint8_t input_pixel = input_byte & (1 << pixel);
switch (color_mode) { switch (color_mode)
{
case 0: case 0:
// write pixels as they are // write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0); ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
@ -358,13 +376,13 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
break; break;
} }
} }
#if SSD1306_LOG_IMAGE == 1 #if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte); printf("%02x ", input_byte);
#endif #endif
} }
#if SSD1306_LOG_IMAGE == 1 #if SSD1306_LOG_IMAGE == 1
printf("\n\r"); printf("\n\r");
#endif #endif
} }
} }
@ -374,9 +392,9 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
{ {
// clipping // clipping
if((x >= SSD1306_W) || (y >= SSD1306_H)) return; if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if((y+h-1) >= SSD1306_H) h = SSD1306_H-y; if ((y + h - 1) >= SSD1306_H) h = SSD1306_H - y;
while(h--) while (h--)
{ {
ssd1306_drawPixel(x, y++, color); ssd1306_drawPixel(x, y++, color);
} }
@ -388,8 +406,8 @@ void ssd1306_drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color) void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
{ {
// clipping // clipping
if((x >= SSD1306_W) || (y >= SSD1306_H)) return; if ((x >= SSD1306_W) || (y >= SSD1306_H)) return;
if((x+w-1) >= SSD1306_W) w = SSD1306_W-x; if ((x + w - 1) >= SSD1306_W) w = SSD1306_W - x;
while (w--) while (w--)
{ {
@ -402,7 +420,7 @@ void ssd1306_drawFastHLine(uint32_t x, uint32_t y, uint32_t w, uint32_t color)
*/ */
int gfx_abs(int x) int gfx_abs(int x)
{ {
return (x<0) ? -x : x; return (x < 0) ? -x : x;
} }
/* /*
@ -426,14 +444,14 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
/* flip sense 45deg to keep error calc in range */ /* flip sense 45deg to keep error calc in range */
steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0)); steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0));
if(steep) if (steep)
{ {
gfx_swap(&x0, &y0); gfx_swap(&x0, &y0);
gfx_swap(&x1, &y1); gfx_swap(&x1, &y1);
} }
/* run low->high */ /* run low->high */
if(x0 > x1) if (x0 > x1)
{ {
gfx_swap(&x0, &x1); gfx_swap(&x0, &x1);
gfx_swap(&y0, &y1); gfx_swap(&y0, &y1);
@ -442,18 +460,18 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
/* set up loop initial conditions */ /* set up loop initial conditions */
deltax = x1 - x0; deltax = x1 - x0;
deltay = gfx_abs(y1 - y0); deltay = gfx_abs(y1 - y0);
error = deltax/2; error = deltax / 2;
y = y0; y = y0;
if(y0 < y1) if (y0 < y1)
ystep = 1; ystep = 1;
else else
ystep = -1; ystep = -1;
/* loop x */ /* loop x */
for(x=x0;x<=x1;x++) for (x = x0; x <= x1; x++)
{ {
/* plot point */ /* plot point */
if(steep) if (steep)
/* flip point & plot */ /* flip point & plot */
ssd1306_drawPixel(y, x, color); ssd1306_drawPixel(y, x, color);
else else
@ -464,7 +482,7 @@ void ssd1306_drawLine(int x0, int y0, int x1, int y1, uint32_t color)
error = error - deltay; error = error - deltay;
/* update y */ /* update y */
if(error < 0) if (error < 0)
{ {
y = y + ystep; y = y + ystep;
error = error + deltax; error = error + deltax;
@ -483,19 +501,23 @@ void ssd1306_drawCircle(int x, int y, int radius, int color)
int err = 2 - 2 * radius; int err = 2 - 2 * radius;
int e2; int e2;
do { do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color); ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color); ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color); ssd1306_drawPixel(x + x_pos, y - y_pos, color);
ssd1306_drawPixel(x - x_pos, y - y_pos, color); ssd1306_drawPixel(x - x_pos, y - y_pos, color);
e2 = err; e2 = err;
if (e2 <= y_pos) { if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1; err += ++y_pos * 2 + 1;
if(-x_pos == y_pos && e2 <= x_pos) { if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0; e2 = 0;
} }
} }
if (e2 > x_pos) { if (e2 > x_pos)
{
err += ++x_pos * 2 + 1; err += ++x_pos * 2 + 1;
} }
} while (x_pos <= 0); } while (x_pos <= 0);
@ -512,7 +534,8 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
int err = 2 - 2 * radius; int err = 2 - 2 * radius;
int e2; int e2;
do { do
{
ssd1306_drawPixel(x - x_pos, y + y_pos, color); ssd1306_drawPixel(x - x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y + y_pos, color); ssd1306_drawPixel(x + x_pos, y + y_pos, color);
ssd1306_drawPixel(x + x_pos, y - y_pos, color); ssd1306_drawPixel(x + x_pos, y - y_pos, color);
@ -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);
ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color); ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color);
e2 = err; e2 = err;
if (e2 <= y_pos) { if (e2 <= y_pos)
{
err += ++y_pos * 2 + 1; err += ++y_pos * 2 + 1;
if(-x_pos == y_pos && e2 <= x_pos) { if (-x_pos == y_pos && e2 <= x_pos)
{
e2 = 0; e2 = 0;
} }
} }
if(e2 > x_pos) { if (e2 > x_pos)
{
err += ++x_pos * 2 + 1; err += ++x_pos * 2 + 1;
} }
} while(x_pos <= 0); } while (x_pos <= 0);
} }
/* /*
@ -538,9 +564,9 @@ void ssd1306_fillCircle(int x, int y, int radius, int color)
void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color) void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t color)
{ {
ssd1306_drawFastVLine(x, y, h, color); ssd1306_drawFastVLine(x, y, h, color);
ssd1306_drawFastVLine(x+w-1, y, h, color); ssd1306_drawFastVLine(x + w - 1, y, h, color);
ssd1306_drawFastHLine(x, y, w, color); ssd1306_drawFastHLine(x, y, w, color);
ssd1306_drawFastHLine(x, y+h-1, w, color); ssd1306_drawFastHLine(x, y + h - 1, w, color);
} }
/* /*
@ -548,15 +574,15 @@ void ssd1306_drawRect(int32_t x, int32_t y, uint32_t w, uint32_t h, uint32_t col
*/ */
void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color) void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t color)
{ {
uint32_t m, n=y, iw = w; uint32_t m, n = y, iw = w;
/* scan vertical */ /* scan vertical */
while(h--) while (h--)
{ {
m=x; m = x;
w=iw; w = iw;
/* scan horizontal */ /* scan horizontal */
while(w--) while (w--)
{ {
/* invert pixels */ /* invert pixels */
ssd1306_drawPixel(m++, n, color); ssd1306_drawPixel(m++, n, color);
@ -570,15 +596,15 @@ void ssd1306_fillRect(uint32_t x, uint32_t y, uint8_t w, uint32_t h, uint32_t co
*/ */
void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h) void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{ {
uint8_t m, n=y, iw = w; uint8_t m, n = y, iw = w;
/* scan vertical */ /* scan vertical */
while(h--) while (h--)
{ {
m=x; m = x;
w=iw; w = iw;
/* scan horizontal */ /* scan horizontal */
while(w--) while (w--)
{ {
/* invert pixels */ /* invert pixels */
ssd1306_xorPixel(m++, n); ssd1306_xorPixel(m++, n);
@ -595,17 +621,17 @@ void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
uint16_t i, j, col; uint16_t i, j, col;
uint8_t d; uint8_t d;
for(i=0;i<8;i++) for (i = 0; i < 8; i++)
{ {
d = fontdata[(chr<<3)+i]; d = fontdata[(chr << 3) + i];
for(j=0;j<8;j++) for (j = 0; j < 8; j++)
{ {
if(d&0x80) if (d & 0x80)
col = color; col = color;
else else
col = (~color)&1; col = (~color) & 1;
ssd1306_drawPixel(x+j, y+i, col); ssd1306_drawPixel(x + j, y + i, col);
// next bit // next bit
d <<= 1; d <<= 1;
@ -620,11 +646,11 @@ void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
{ {
uint8_t c; uint8_t c;
while((c=*str++)) while ((c = *str++))
{ {
ssd1306_drawchar(x, y, c, color); ssd1306_drawchar(x, y, c, color);
x += 8; x += 8;
if(x>120) if (x > 120)
break; break;
} }
} }
@ -632,7 +658,8 @@ void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
/* /*
* enum for font size * enum for font size
*/ */
typedef enum { typedef enum
{
fontsize_8x8 = 1, fontsize_8x8 = 1,
fontsize_16x16 = 2, fontsize_16x16 = 2,
fontsize_32x32 = 4, fontsize_32x32 = 4,
@ -666,8 +693,10 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
col = (~color) & 1; col = (~color) & 1;
// Draw the pixel at the original size and scaled size using nested for-loops // Draw the pixel at the original size and scaled size using nested for-loops
for (uint8_t k = 0; k < font_scale; k++) { for (uint8_t k = 0; k < font_scale; k++)
for (uint8_t l = 0; l < font_scale; l++) { {
for (uint8_t l = 0; l < font_scale; l++)
{
ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col); ssd1306_drawPixel(x + (j * font_scale) + k, y + (i * font_scale) + l, col);
} }
} }
@ -685,11 +714,11 @@ void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_siz
{ {
uint8_t c; uint8_t c;
while((c=*str++)) while ((c = *str++))
{ {
ssd1306_drawchar_sz(x, y, c, color, font_size); ssd1306_drawchar_sz(x, y, c, color, font_size);
x += 8 * font_size; x += 8 * font_size;
if(x>128 - 8 * font_size) if (x > 128 - 8 * font_size)
break; break;
} }
} }
@ -707,9 +736,9 @@ uint8_t ssd1306_init(void)
// initialize OLED // initialize OLED
#if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY #if !defined(SSD1306_CUSTOM_INIT_ARRAY) || !SSD1306_CUSTOM_INIT_ARRAY
uint8_t *cmd_list = (uint8_t *)ssd1306_init_array; uint8_t *cmd_list = (uint8_t *)ssd1306_init_array;
while(*cmd_list != SSD1306_TERMINATE_CMDS) while (*cmd_list != SSD1306_TERMINATE_CMDS)
{ {
if(ssd1306_cmd(*cmd_list++)) if (ssd1306_cmd(*cmd_list++))
return 1; return 1;
} }

View file

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

View file

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

View file

@ -40,15 +40,15 @@ uint8_t ssd1306_spi_init(void)
RCC->APB2PCENR |= RCC_APB2Periph_SPI1; RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
funGpioInitAll(); funGpioInitAll();
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP ); funPinMode(SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP ); funPinMode(SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP ); funPinMode(SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP);
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP ); funPinMode(SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP);
funPinMode( SSD1306_SCK_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_RST_PIN, FUN_HIGH);
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH ); funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW ); funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
// Configure SPI // Configure SPI
SPI1->CTLR1 = SPI1->CTLR1 =
@ -68,9 +68,9 @@ uint8_t ssd1306_spi_init(void)
*/ */
void ssd1306_rst(void) void ssd1306_rst(void)
{ {
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW ); funDigitalWrite(SSD1306_RST_PIN, FUN_LOW);
Delay_Ms(10); Delay_Ms(10);
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH ); funDigitalWrite(SSD1306_RST_PIN, FUN_HIGH);
} }
/* /*
@ -78,31 +78,32 @@ void ssd1306_rst(void)
*/ */
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd) uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
{ {
if(cmd) if (cmd)
{ {
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW ); funDigitalWrite(SSD1306_DC_PIN, FUN_LOW);
} }
else else
{ {
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH ); funDigitalWrite(SSD1306_DC_PIN, FUN_HIGH);
} }
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW ); funDigitalWrite(SSD1306_CS_PIN, FUN_LOW);
// send data // send data
while(sz--) while (sz--)
{ {
// wait for TXE // wait for TXE
while(!(SPI1->STATR & SPI_STATR_TXE)); while (!(SPI1->STATR & SPI_STATR_TXE))
;
// Send byte // Send byte
SPI1->DATAR = *data++; SPI1->DATAR = *data++;
} }
// wait for not busy before exiting // wait for not busy before exiting
while(SPI1->STATR & SPI_STATR_BSY) { } while (SPI1->STATR & SPI_STATR_BSY) {}
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH ); funDigitalWrite(SSD1306_CS_PIN, FUN_HIGH);
// we're happy // we're happy
return 0; return 0;

File diff suppressed because it is too large Load diff

View file

@ -32,11 +32,11 @@
#include <stdint.h> #include <stdint.h>
// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin. // Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
void WS2812BDMAInit( ); void WS2812BDMAInit();
void WS2812BDMAStart( int leds ); void WS2812BDMAStart(int leds);
// Callbacks that you must implement. // Callbacks that you must implement.
uint32_t WS2812BLEDCallback( int ledno ); uint32_t WS2812BLEDCallback(int ledno);
#ifdef WS2812DMA_IMPLEMENTATION #ifdef WS2812DMA_IMPLEMENTATION
@ -51,9 +51,9 @@ uint32_t WS2812BLEDCallback( int ledno );
#define WS2812B_RESET_PERIOD 2 #define WS2812B_RESET_PERIOD 2
#ifdef WSRAW #ifdef WSRAW
#define DMA_BUFFER_LEN (((DMALEDS)/2)*8) #define DMA_BUFFER_LEN (((DMALEDS) / 2) * 8)
#else #else
#define DMA_BUFFER_LEN (((DMALEDS)/2)*6) #define DMA_BUFFER_LEN (((DMALEDS) / 2) * 6)
#endif #endif
static uint16_t WS2812dmabuff[DMA_BUFFER_LEN]; static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
@ -62,23 +62,36 @@ static volatile int WS2812LEDPlace;
static volatile int WS2812BLEDInUse; static volatile int WS2812BLEDInUse;
// This is the code that updates a portion of the WS2812dmabuff with new data. // This is the code that updates a portion of the WS2812dmabuff with new data.
// This effectively creates the bitstream that outputs to the LEDs. // This effectively creates the bitstream that outputs to the LEDs.
static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce ) static void WS2812FillBuffSec(uint16_t *ptr, int numhalfwords, int tce)
{ {
const static uint16_t bitquartets[16] = { const static uint16_t bitquartets[16] = {
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, 0b1000100010001000,
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, 0b1000100010001110,
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, 0b1000100011101000,
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, }; 0b1000100011101110,
0b1000111010001000,
0b1000111010001110,
0b1000111011101000,
0b1000111011101110,
0b1110100010001000,
0b1110100010001110,
0b1110100011101000,
0b1110100011101110,
0b1110111010001000,
0b1110111010001110,
0b1110111011101000,
0b1110111011101110,
};
int i; int i;
uint16_t * end = ptr + numhalfwords; uint16_t *end = ptr + numhalfwords;
int ledcount = WS2812LEDs; int ledcount = WS2812LEDs;
int place = WS2812LEDPlace; int place = WS2812LEDPlace;
#ifdef WSRAW #ifdef WSRAW
while( place < 0 && ptr != end ) while (place < 0 && ptr != end)
{ {
uint32_t * lptr = (uint32_t *)ptr; uint32_t *lptr = (uint32_t *)ptr;
lptr[0] = 0; lptr[0] = 0;
lptr[1] = 0; lptr[1] = 0;
lptr[2] = 0; lptr[2] = 0;
@ -88,7 +101,7 @@ static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
} }
#else #else
while( place < 0 && ptr != end ) while (place < 0 && ptr != end)
{ {
(*ptr++) = 0; (*ptr++) = 0;
(*ptr++) = 0; (*ptr++) = 0;
@ -100,18 +113,18 @@ static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
} }
#endif #endif
while( ptr != end ) while (ptr != end)
{ {
if( place >= ledcount ) if (place >= ledcount)
{ {
// Optionally, leave line high. // Optionally, leave line high.
while( ptr != end ) while (ptr != end)
(*ptr++) = 0;//0xffff; (*ptr++) = 0; // 0xffff;
// Only safe to do this when we're on the second leg. // Only safe to do this when we're on the second leg.
if( tce ) if (tce)
{ {
if( place == ledcount ) if (place == ledcount)
{ {
// Take the DMA out of circular mode and let it expire. // Take the DMA out of circular mode and let it expire.
DMA1_Channel3->CFGR &= ~DMA_Mode_Circular; DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
@ -124,58 +137,57 @@ static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int tce )
} }
#ifdef WSRAW #ifdef WSRAW
uint32_t ledval32bit = WS2812BLEDCallback( place++ ); uint32_t ledval32bit = WS2812BLEDCallback(place++);
ptr[6] = bitquartets[(ledval32bit>>28)&0xf]; ptr[6] = bitquartets[(ledval32bit >> 28) & 0xf];
ptr[7] = bitquartets[(ledval32bit>>24)&0xf]; ptr[7] = bitquartets[(ledval32bit >> 24) & 0xf];
ptr[4] = bitquartets[(ledval32bit>>20)&0xf]; ptr[4] = bitquartets[(ledval32bit >> 20) & 0xf];
ptr[5] = bitquartets[(ledval32bit>>16)&0xf]; ptr[5] = bitquartets[(ledval32bit >> 16) & 0xf];
ptr[2] = bitquartets[(ledval32bit>>12)&0xf]; ptr[2] = bitquartets[(ledval32bit >> 12) & 0xf];
ptr[3] = bitquartets[(ledval32bit>>8)&0xf]; ptr[3] = bitquartets[(ledval32bit >> 8) & 0xf];
ptr[0] = bitquartets[(ledval32bit>>4)&0xf]; ptr[0] = bitquartets[(ledval32bit >> 4) & 0xf];
ptr[1] = bitquartets[(ledval32bit>>0)&0xf]; ptr[1] = bitquartets[(ledval32bit >> 0) & 0xf];
ptr += 8; ptr += 8;
i += 8; i += 8;
#else #else
// Use a LUT to figure out how we should set the SPI line. // Use a LUT to figure out how we should set the SPI line.
uint32_t ledval24bit = WS2812BLEDCallback( place++ ); uint32_t ledval24bit = WS2812BLEDCallback(place++);
#ifdef WSRBG #ifdef WSRBG
ptr[0] = bitquartets[(ledval24bit>>12)&0xf]; ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
ptr[1] = bitquartets[(ledval24bit>>8)&0xf]; ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
ptr[2] = bitquartets[(ledval24bit>>20)&0xf]; ptr[2] = bitquartets[(ledval24bit >> 20) & 0xf];
ptr[3] = bitquartets[(ledval24bit>>16)&0xf]; ptr[3] = bitquartets[(ledval24bit >> 16) & 0xf];
ptr[4] = bitquartets[(ledval24bit>>4)&0xf]; ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
ptr[5] = bitquartets[(ledval24bit>>0)&0xf]; ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
#elif defined( WSGRB ) #elif defined(WSGRB)
ptr[0] = bitquartets[(ledval24bit>>12)&0xf]; ptr[0] = bitquartets[(ledval24bit >> 12) & 0xf];
ptr[1] = bitquartets[(ledval24bit>>8)&0xf]; ptr[1] = bitquartets[(ledval24bit >> 8) & 0xf];
ptr[2] = bitquartets[(ledval24bit>>4)&0xf]; ptr[2] = bitquartets[(ledval24bit >> 4) & 0xf];
ptr[3] = bitquartets[(ledval24bit>>0)&0xf]; ptr[3] = bitquartets[(ledval24bit >> 0) & 0xf];
ptr[4] = bitquartets[(ledval24bit>>20)&0xf]; ptr[4] = bitquartets[(ledval24bit >> 20) & 0xf];
ptr[5] = bitquartets[(ledval24bit>>16)&0xf]; ptr[5] = bitquartets[(ledval24bit >> 16) & 0xf];
#else #else
ptr[0] = bitquartets[(ledval24bit>>20)&0xf]; ptr[0] = bitquartets[(ledval24bit >> 20) & 0xf];
ptr[1] = bitquartets[(ledval24bit>>16)&0xf]; ptr[1] = bitquartets[(ledval24bit >> 16) & 0xf];
ptr[2] = bitquartets[(ledval24bit>>12)&0xf]; ptr[2] = bitquartets[(ledval24bit >> 12) & 0xf];
ptr[3] = bitquartets[(ledval24bit>>8)&0xf]; ptr[3] = bitquartets[(ledval24bit >> 8) & 0xf];
ptr[4] = bitquartets[(ledval24bit>>4)&0xf]; ptr[4] = bitquartets[(ledval24bit >> 4) & 0xf];
ptr[5] = bitquartets[(ledval24bit>>0)&0xf]; ptr[5] = bitquartets[(ledval24bit >> 0) & 0xf];
#endif #endif
ptr += 6; ptr += 6;
i += 6; i += 6;
#endif #endif
} }
WS2812LEDPlace = place; WS2812LEDPlace = place;
} }
void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt)); void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt));
void DMA1_Channel3_IRQHandler( void ) void DMA1_Channel3_IRQHandler(void)
{ {
//GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling // GPIOD->BSHR = 1; // Turn on GPIOD0 for profiling
// Backup flags. // Backup flags.
volatile int intfr = DMA1->INTFR; volatile int intfr = DMA1->INTFR;
@ -188,23 +200,23 @@ void DMA1_Channel3_IRQHandler( void )
// DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes // DMA1_IT_TC3 should be COMPLETE. But for some reason, doing this causes
// LED jitter. I am henseforth flipping the order. // LED jitter. I am henseforth flipping the order.
if( intfr & DMA1_IT_HT3 ) if (intfr & DMA1_IT_HT3)
{ {
// Halfwaay (Fill in first part) // Halfwaay (Fill in first part)
WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 1 ); WS2812FillBuffSec(WS2812dmabuff, DMA_BUFFER_LEN / 2, 1);
} }
if( intfr & DMA1_IT_TC3 ) if (intfr & DMA1_IT_TC3)
{ {
// Complete (Fill in second part) // Complete (Fill in second part)
WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0 ); WS2812FillBuffSec(WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 0);
} }
intfr = DMA1->INTFR; intfr = DMA1->INTFR;
} while( intfr & DMA1_IT_GL3 ); } while (intfr & DMA1_IT_GL3);
//GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling // GPIOD->BSHR = 1<<16; // Turn off GPIOD0 for profiling
} }
void WS2812BDMAStart( int leds ) void WS2812BDMAStart(int leds)
{ {
// Enter critical section. // Enter critical section.
__disable_irq(); __disable_irq();
@ -216,27 +228,27 @@ void WS2812BDMAStart( int leds )
WS2812LEDPlace = -WS2812B_RESET_PERIOD; WS2812LEDPlace = -WS2812B_RESET_PERIOD;
__enable_irq(); __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->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
DMA1_Channel3->CFGR |= DMA_Mode_Circular; DMA1_Channel3->CFGR |= DMA_Mode_Circular;
} }
void WS2812BDMAInit( ) void WS2812BDMAInit()
{ {
// Enable DMA + Peripherals // Enable DMA + Peripherals
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1; RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
// MOSI, Configure GPIO Pin // MOSI, Configure GPIO Pin
GPIOC->CFGLR &= ~(0xf<<(4*6)); GPIOC->CFGLR &= ~(0xf << (4 * 6));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6); GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF) << (4 * 6);
// Configure SPI // Configure SPI
SPI1->CTLR1 = SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b | SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
SPI_Mode_Master | SPI_Direction_1Line_Tx | SPI_Mode_Master | SPI_Direction_1Line_Tx |
3<<3; // Divisior = 16 (48/16 = 3MHz) 3 << 3; // Divisior = 16 (48/16 = 3MHz)
SPI1->CTLR2 = SPI_CTLR2_TXDMAEN; SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
SPI1->HSCR = 1; SPI1->HSCR = 1;
@ -245,10 +257,10 @@ void WS2812BDMAInit( )
SPI1->DATAR = 0; // Set SPI line Low. SPI1->DATAR = 0; // Set SPI line Low.
//DMA1_Channel3 is for SPI1TX // DMA1_Channel3 is for SPI1TX
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR; DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff; DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
DMA1_Channel3->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!) DMA1_Channel3->CNTR = 0; // sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!)
DMA1_Channel3->CFGR = DMA1_Channel3->CFGR =
DMA_M2M_Disable | DMA_M2M_Disable |
DMA_Priority_VeryHigh | DMA_Priority_VeryHigh |
@ -259,12 +271,12 @@ void WS2812BDMAInit( )
DMA_DIR_PeripheralDST | DMA_DIR_PeripheralDST |
DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts. DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
// NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority. // NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); //We don't need to tweak priority.
NVIC_EnableIRQ( DMA1_Channel3_IRQn ); NVIC_EnableIRQ(DMA1_Channel3_IRQn);
DMA1_Channel3->CFGR |= DMA_CFGR1_EN; DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
#ifdef WS2812B_ALLOW_INTERRUPT_NESTING #ifdef WS2812B_ALLOW_INTERRUPT_NESTING
__set_INTSYSCR( __get_INTSYSCR() | 2 ); // Enable interrupt nesting. __set_INTSYSCR(__get_INTSYSCR() | 2); // Enable interrupt nesting.
PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3 PFIC->IPRIOR[24] = 0b10000000; // Turn on preemption for DMA1Ch3
#endif #endif
} }
@ -272,4 +284,3 @@ void WS2812BDMAInit( )
#endif #endif
#endif #endif

View file

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

View file

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

View file

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

View file

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